Skip to content

Bigtable: 'test_create_instance_with_two_clusters' flakes modifying profile. #7900

Description

@tseaver

Similar to #5928, but the failure occurs while re-modifying the instance's app profile.

From this Kokoro failure:

___________TestInstanceAdminAPI.test_create_instance_w_two_clusters___________target=functools.partial(<boundmethodPollingFuture._done_or_raiseof<google.api_core.operation.Operationobjectat0x7f7c280cee80>>)
predicate=<functionif_exception_type.<locals>.if_exception_type_predicateat0x7f7c299b70d0>sleep_generator=<generatorobjectexponential_sleep_generatorat0x7f7c297d3a98>deadline=10, on_error=Nonedefretry_target(target, predicate, sleep_generator, deadline, on_error=None):
"""Call a function and retry if it fails. This is the lowest-level retry helper. Generally, you'll use the higher-level retry helper :class:`Retry`. Args: target(Callable): The function to call and retry. This must be a nullary function - apply arguments with `functools.partial`. predicate (Callable[Exception]): A callable used to determine if an exception raised by the target should be considered retryable. It should return True to retry or False otherwise. sleep_generator (Iterable[float]): An infinite iterator that determines how long to sleep between retries. deadline (float): How long to keep retrying the target. on_error (Callable): A function to call while processing a retryable exception. Any error raised by this function will *not* be caught. Returns: Any: the return value of the target function. Raises: google.api_core.RetryError: If the deadline is exceeded while retrying. ValueError: If the sleep generator stops yielding values. Exception: If the target raises a method that isn't retryable. """ifdeadlineisnotNone:
deadline_datetime=datetime_helpers.utcnow() +datetime.timedelta(
seconds=deadline
)
else:
deadline_datetime=Nonelast_exc=Noneforsleepinsleep_generator:
try:
>returntarget()
../api_core/google/api_core/retry.py:179:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self=<google.api_core.operation.Operationobjectat0x7f7c280cee80>def_done_or_raise(self):
"""Check if the future is done and raise if it's not."""ifnotself.done():
>raise_OperationNotComplete()
Egoogle.api_core.future.polling._OperationNotComplete
../api_core/google/api_core/future/polling.py:81: _OperationNotCompleteTheaboveexceptionwasthedirectcauseofthefollowingexception:
self=<google.api_core.operation.Operationobjectat0x7f7c280cee80>timeout=10def_blocking_poll(self, timeout=None):
"""Poll and wait for the Future to be resolved. Args: timeout (int): How long (in seconds) to wait for the operation to complete. If None, wait indefinitely. """ifself._result_set:
returnretry_=self._retry.with_deadline(timeout)
try:>retry_(self._done_or_raise)()
../api_core/google/api_core/future/polling.py:101:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args= (), kwargs= {}
target=functools.partial(<boundmethodPollingFuture._done_or_raiseof<google.api_core.operation.Operationobjectat0x7f7c280cee80>>)
sleep_generator=<generatorobjectexponential_sleep_generatorat0x7f7c297d3a98>@general_helpers.wraps(func)defretry_wrapped_func(*args, **kwargs):
"""A wrapper that calls target function with retry."""target=functools.partial(func, *args, **kwargs)
sleep_generator=exponential_sleep_generator(
self._initial, self._maximum, multiplier=self._multiplier
)
returnretry_target(
target,
self._predicate,
sleep_generator,
self._deadline,
>on_error=on_error,
)
../api_core/google/api_core/retry.py:270:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
target=functools.partial(<boundmethodPollingFuture._done_or_raiseof<google.api_core.operation.Operationobjectat0x7f7c280cee80>>)
predicate=<functionif_exception_type.<locals>.if_exception_type_predicateat0x7f7c299b70d0>sleep_generator=<generatorobjectexponential_sleep_generatorat0x7f7c297d3a98>deadline=10, on_error=Nonedefretry_target(target, predicate, sleep_generator, deadline, on_error=None):
"""Call a function and retry if it fails. This is the lowest-level retry helper. Generally, you'll use the higher-level retry helper :class:`Retry`. Args: target(Callable): The function to call and retry. This must be a nullary function - apply arguments with `functools.partial`. predicate (Callable[Exception]): A callable used to determine if an exception raised by the target should be considered retryable. It should return True to retry or False otherwise. sleep_generator (Iterable[float]): An infinite iterator that determines how long to sleep between retries. deadline (float): How long to keep retrying the target. on_error (Callable): A function to call while processing a retryable exception. Any error raised by this function will *not* be caught. Returns: Any: the return value of the target function. Raises: google.api_core.RetryError: If the deadline is exceeded while retrying. ValueError: If the sleep generator stops yielding values. Exception: If the target raises a method that isn't retryable. """ifdeadlineisnotNone:
deadline_datetime=datetime_helpers.utcnow() +datetime.timedelta(
seconds=deadline
)
else:
deadline_datetime=Nonelast_exc=Noneforsleepinsleep_generator:
try:
returntarget()
# pylint: disable=broad-except# This function explicitly must deal with broad exceptions.exceptExceptionasexc:
ifnotpredicate(exc):
raiselast_exc=excifon_errorisnotNone:
on_error(exc)
now=datetime_helpers.utcnow()
ifdeadline_datetimeisnotNoneanddeadline_datetime<now:
six.raise_from(
exceptions.RetryError(
"Deadline of {:.1f}s exceeded while calling {}".format(
deadline, target
),
last_exc,
),>last_exc,
)
../api_core/google/api_core/retry.py:199:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
value=None, from_value=_OperationNotComplete()
> ???
Egoogle.api_core.exceptions.RetryError: Deadlineof10.0sexceededwhilecallingfunctools.partial(<boundmethodPollingFuture._done_or_raiseof<google.api_core.operation.Operationobjectat0x7f7c280cee80>>), lastexception:
<string>:3: RetryErrorDuringhandlingoftheaboveexception, anotherexceptionoccurred:
self=<tests.system.TestInstanceAdminAPItestMethod=test_create_instance_w_two_clusters>deftest_create_instance_w_two_clusters(self):
fromgoogle.cloud.bigtableimportenumsfromgoogle.cloud.bigtable.tableimportClusterState_PRODUCTION=enums.Instance.Type.PRODUCTIONALT_INSTANCE_ID="dif"+unique_resource_id("-")
instance=Config.CLIENT.instance(
ALT_INSTANCE_ID, instance_type=_PRODUCTION, labels=LABELS
)
ALT_CLUSTER_ID_1=ALT_INSTANCE_ID+"-c1"ALT_CLUSTER_ID_2=ALT_INSTANCE_ID+"-c2"LOCATION_ID_2="us-central1-f"STORAGE_TYPE=enums.StorageType.HDDcluster_1=instance.cluster(
ALT_CLUSTER_ID_1,
location_id=LOCATION_ID,
serve_nodes=SERVE_NODES,
default_storage_type=STORAGE_TYPE,
)
cluster_2=instance.cluster(
ALT_CLUSTER_ID_2,
location_id=LOCATION_ID_2,
serve_nodes=SERVE_NODES,
default_storage_type=STORAGE_TYPE,
)
operation=instance.create(clusters=[cluster_1, cluster_2])
# Make sure this instance gets deleted after the test case.self.instances_to_delete.append(instance)
# We want to make sure the operation completes.operation.result(timeout=10)
# Create a new instance instance and make sure it is the same.instance_alt=Config.CLIENT.instance(ALT_INSTANCE_ID)
instance_alt.reload()
self.assertEqual(instance, instance_alt)
self.assertEqual(instance.display_name, instance_alt.display_name)
self.assertEqual(instance.type_, instance_alt.type_)
clusters, failed_locations=instance_alt.list_clusters()
self.assertEqual(failed_locations, [])
clusters.sort(key=lambdax: x.name)
alt_cluster_1, alt_cluster_2=clustersself.assertEqual(cluster_1.location_id, alt_cluster_1.location_id)
self.assertEqual(alt_cluster_1.state, enums.Cluster.State.READY)
self.assertEqual(cluster_1.serve_nodes, alt_cluster_1.serve_nodes)
self.assertEqual(
cluster_1.default_storage_type, alt_cluster_1.default_storage_type
)
self.assertEqual(cluster_2.location_id, alt_cluster_2.location_id)
self.assertEqual(alt_cluster_2.state, enums.Cluster.State.READY)
self.assertEqual(cluster_2.serve_nodes, alt_cluster_2.serve_nodes)
self.assertEqual(
cluster_2.default_storage_type, alt_cluster_2.default_storage_type
)
# Test list clusters in project via 'client.list_clusters'clusters, failed_locations=Config.CLIENT.list_clusters()
self.assertFalse(failed_locations)
found=set([cluster.nameforclusterinclusters])
self.assertTrue(
{alt_cluster_1.name, alt_cluster_2.name, Config.CLUSTER.name}.issubset(
found
)
)
temp_table_id="test-get-cluster-states"temp_table=instance.table(temp_table_id)
temp_table.create()
result=temp_table.get_cluster_states()
ReplicationState=enums.Table.ReplicationStateexpected_results= [
ClusterState(ReplicationState.STATE_NOT_KNOWN),
ClusterState(ReplicationState.INITIALIZING),
ClusterState(ReplicationState.PLANNED_MAINTENANCE),
ClusterState(ReplicationState.UNPLANNED_MAINTENANCE),
ClusterState(ReplicationState.READY),
]
cluster_id_list=result.keys()
self.assertEqual(len(cluster_id_list), 2)
self.assertIn(ALT_CLUSTER_ID_1, cluster_id_list)
self.assertIn(ALT_CLUSTER_ID_2, cluster_id_list)
forclusterstateinresult.values():
self.assertIn(clusterstate, expected_results)
# Test create app profile with multi_cluster_routing policyapp_profiles_to_delete= []
description="routing policy-multy"app_profile_id_1="app_profile_id_1"routing=enums.RoutingPolicyType.ANYself._test_create_app_profile_helper(
app_profile_id_1,
instance,
routing_policy_type=routing,
description=description,
ignore_warnings=True,
)
app_profiles_to_delete.append(app_profile_id_1)
# Test list app profilesself._test_list_app_profiles_helper(instance, [app_profile_id_1])
# Test modify app profile app_profile_id_1# routing policy to single cluster policy,# cluster -> ALT_CLUSTER_ID_1,# allow_transactional_writes -> disallowed# modify descriptiondescription="to routing policy-single"routing=enums.RoutingPolicyType.SINGLEself._test_modify_app_profile_helper(
app_profile_id_1,
instance,
routing_policy_type=routing,
description=description,
cluster_id=ALT_CLUSTER_ID_1,
allow_transactional_writes=False,
)
# Test modify app profile app_profile_id_1# cluster -> ALT_CLUSTER_ID_2,# allow_transactional_writes -> allowedself._test_modify_app_profile_helper(
app_profile_id_1,
instance,
routing_policy_type=routing,
description=description,
cluster_id=ALT_CLUSTER_ID_2,
allow_transactional_writes=True,
ignore_warnings=True,
)
# Test create app profile with single cluster routing policydescription="routing policy-single"app_profile_id_2="app_profile_id_2"routing=enums.RoutingPolicyType.SINGLEself._test_create_app_profile_helper(
app_profile_id_2,
instance,
routing_policy_type=routing,
description=description,
cluster_id=ALT_CLUSTER_ID_2,
allow_transactional_writes=False,
)
app_profiles_to_delete.append(app_profile_id_2)
# Test list app profilesself._test_list_app_profiles_helper(
instance, [app_profile_id_1, app_profile_id_2]
)
# Test modify app profile app_profile_id_2 to# allow transactional writes# Note: no need to set ``ignore_warnings`` to True# since we are not restrictings anything with this modification.self._test_modify_app_profile_helper(
app_profile_id_2,
instance,
routing_policy_type=routing,
description=description,
cluster_id=ALT_CLUSTER_ID_2,
>allow_transactional_writes=True,
)
tests/system.py:409:
__ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests/system.py:613: in_test_modify_app_profile_helperoperation.result(timeout=10)
../api_core/google/api_core/future/polling.py:122: inresultself._blocking_poll(timeout=timeout)
__ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self=<google.api_core.operation.Operationobjectat0x7f7c280cee80>timeout=10def_blocking_poll(self, timeout=None):
"""Poll and wait for the Future to be resolved. Args: timeout (int): How long (in seconds) to wait for the operation to complete. If None, wait indefinitely. """ifself._result_set:
returnretry_=self._retry.with_deadline(timeout)
try:
retry_(self._done_or_raise)()
exceptexceptions.RetryError:
raiseconcurrent.futures.TimeoutError(
>"Operation did not complete within the designated ""timeout."
)
Econcurrent.futures._base.TimeoutError: Operationdidnotcompletewithinthedesignatedtimeout.
../api_core/google/api_core/future/polling.py:104: TimeoutError

Metadata

Metadata

Assignees

Labels

api: bigtableIssues related to the Bigtable API.flakytestingtype: processA process-related concern. May include testing, release, or the like.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions