def WaitForOpV2(operation, spinner_text): """Wait for a longrunning.Operation to complete, using the V2 API. Currently broken pending fix of b/29563942. Args: operation: a longrunning.Operation message. spinner_text: message text to display on the console. Returns: true if completed successfully, false if timed out """ tick_freq = 1 # poll every second tick_limit = 600 # timeout after ten minutes cli = GetAdminClient() msg = GetAdminMessages().BigtableadminOperationsGetRequest( operationsId=operation.name[11:]) with console_io.ProgressTracker(spinner_text, autotick=False) as pt: while tick_limit > 0: resp = cli.operations.Get(msg) if resp.error: raise sdk_ex.HttpException(resp.error.message) if resp.done: break pt.Tick() tick_limit -= tick_freq time.sleep(tick_freq) return resp.done
def Run(self, args): # TODO(user): This fails with "module/version does not exist" even # when it exists if the scaling mode is set to auto. It would be good # to improve that error message. api_client = appengine_api_client.GetApiClient() services = api_client.ListServices() versions = version_util.GetMatchingVersions( api_client.ListVersions(services), args.versions, args.service) if not versions: log.warn('No matching versions found.') return fmt = 'list[title="Starting the following versions:"]' resource_printer.Print(versions, fmt, out=log.status) console_io.PromptContinue(cancel_on_no=True) errors = {} for version in versions: try: with console_io.ProgressTracker('Starting [{0}]'.format(version)): api_client.StartVersion(version.service, version.id) except (calliope_exceptions.HttpException, operations.OperationError, operations.OperationTimeoutError) as err: errors[version] = str(err) if errors: printable_errors = {} for version, error_msg in errors.items(): short_name = '[{0}/{1}]'.format(version.service, version.id) printable_errors[short_name] = '{0}: {1}'.format(short_name, error_msg) raise VersionsStartError( 'Issues starting version(s): {0}\n\n'.format( ', '.join(printable_errors.keys())) + '\n\n'.join(printable_errors.values()))
def Run(self, args): # TODO(markpell): This fails with "module/version does not exist" even # when it exists if the scaling mode is set to auto. It would be good # to improve that error message. client = appengine_client.AppengineClient() versions = version_util.GetMatchingVersions(client.ListVersions(), args.versions, args.service, client.project) if not versions: log.warn('No matching versions found.') return printer = console_io.ListPrinter('Starting the following versions:') printer.Print(versions, output_stream=log.status) console_io.PromptContinue(cancel_on_no=True) errors = {} for version in versions: try: with console_io.ProgressTracker('Starting [{0}]'.format(version)): client.StartModule(module=version.service, version=version.version) except util.RPCError as err: errors[version] = str(err) if errors: printable_errors = {} for version, error_msg in errors.items(): short_name = '[{0}/{1}]'.format(version.service, version.version) printable_errors[short_name] = '{0}: {1}'.format(short_name, error_msg) raise VersionsStartError( 'Issues starting version(s): {0}\n\n'.format( ', '.join(printable_errors.keys())) + '\n\n'.join(printable_errors.values()))
def Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Returns: Some value that we want to have printed later. """ # TODO(b/31062835): remove CloneAndSwitchAPI and extract API code to api_lib client = apis.GetClientInstance('ml', 'v1beta1') msgs = apis.GetMessagesModule('ml', 'v1beta1') reg = resources.REGISTRY.CloneAndSwitchAPIs(client) res = reg.Parse(args.version, params={'modelsId': args.model}, collection='ml.projects.models.versions') req = msgs.MlProjectsModelsVersionsCreateRequest( projectsId=res.projectsId, modelsId=res.modelsId, googleCloudMlV1beta1Version=msgs.GoogleCloudMlV1beta1Version( name=res.Name(), deploymentUri=args.origin)) op = client.projects_models_versions.Create(req) if args. async: return op with console_io.ProgressTracker('Creating version...'): operations.WaitForOperation(client.projects_operations, op, registry=reg) return op.response
def Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Returns: Some value that we want to have printed later. """ client = apis.GetClientInstance('ml', 'v1alpha3') msgs = apis.GetMessagesModule('ml', 'v1alpha3') res = resources.REGISTRY.Parse( args.version, params={'modelsId': args.model}, collection='ml.projects.models.versions') req = msgs.MlProjectsModelsCreateVersionRequest( projectsId=res.projectsId, modelsId=res.modelsId, googleCloudMlV1alpha3Version=msgs.GoogleCloudMlV1alpha3Version( name=res.Name(), originUri=args.origin)) op = client.projects_models.CreateVersion(req) if args. async: return op with console_io.ProgressTracker('Creating version...'): operations.WaitForOperation(client.projects_operations, op) return op.response
def Run(self, args): # TODO(user): This fails with "module/version does not exist" even # when it exists if the scaling mode is set to auto. It would be good # to improve that error message. api_client = appengine_api_client.GetApiClient() services = api_client.ListServices() versions = version_util.GetMatchingVersions( api_client.ListVersions(services), args.versions, args.service) if versions: printer = console_io.ListPrinter( 'Stopping the following versions:') printer.Print(versions, output_stream=log.status) console_io.PromptContinue(cancel_on_no=True) else: log.warn('No matching versions found.') errors = [] for version in sorted(versions): try: with console_io.ProgressTracker( 'Stopping [{0}]'.format(version)): api_client.StopVersion(version.service, version.id) except (calliope_exceptions.HttpException, operations.OperationError, operations.OperationTimeoutError) as err: errors.append(str(err)) if errors: raise VersionsStopError('\n\n'.join(errors))
def Run(self, args): # TODO(markpell): This fails with "module/version does not exist" even # when it exists if the scaling mode is set to auto. It would be good # to improve that error message. client = appengine_client.AppengineClient() versions = version_util.GetMatchingVersions(client.ListVersions(), args.versions, args.service, client.project) if versions: printer = console_io.ListPrinter( 'Stopping the following versions:') printer.Print(versions, output_stream=log.status) console_io.PromptContinue(cancel_on_no=True) else: log.warn('No matching versions found.') errors = [] for version in sorted(versions): try: with console_io.ProgressTracker( 'Stopping [{0}]'.format(version)): client.StopModule(module=version.service, version=version.version) except util.RPCError as err: errors.append(str(err)) if errors: raise VersionsStopError('\n\n'.join(errors))
def _WaitForOperation(client, get_request, message): """Wait for an operation to complete. No operation is done instantly. Wait for it to finish following this logic: * we wait 1s (jitter is also 1s) * we query service * if the operation is not finished we loop to first point * wait limit is 620s - if we get to that point it means something is wrong and we can throw an exception Args: client: The client used to make requests. get_request: A GetOperatioRequest message. message: str, The string to print while polling. Returns: True if the operation succeeded without error. Raises: FunctionsError: If the operation takes more than 620s. """ with console_io.ProgressTracker(message, autotick=False) as pt: # This is actually linear retryer. retryer = retry.Retryer(exponential_sleep_multiplier=1, max_wait_ms=MAX_WAIT_MS, wait_ceiling_ms=WAIT_CEILING_MS) try: retryer.RetryOnResult(_GetOperationStatus, [client, get_request], {'progress_tracker': pt}, should_retry_if=None, sleep_ms=SLEEP_MS) except retry.WaitException: raise exceptions.FunctionsError( 'Operation {0} is taking too long'.format(get_request.name))
def _CheckNetworkConnection(urls, http_client, first_run=True): """Checks network connection to urls and prints status to console. Args: urls: iterable(str), The list of urls to check connection to. http_client: httplib2.Http, an object used by gcloud to make http and https connections. first_run: bool, Whether this is the first time checking network connections on this invocation. Affects the message presented to the user. Returns: bool: Whether the network connection check passed. """ with console_io.ProgressTracker('{0} network connection'.format( 'Checking' if first_run else 'Rechecking')): network_issues = CheckReachability(urls, http_client) log.status.Print() # newline to separate progress tracker from results if not network_issues: log.status.Print('Network diagnostic {0}.\n'.format( 'passed' if first_run else 'now passes')) return True log.status.Print('Network diagnostic {0}.'.format( 'failed' if first_run else 'still does not pass')) if first_run: for issue in network_issues: log.status.Print(' {0}'.format(issue.message)) log.status.Print() # newline to separate results from proxy setup prompts return False
def WaitForComputeOperations(self, project, zone, operation_ids, message, timeout_s=1200, poll_period_s=5): """Poll Compute Operations until their status is done or timeout reached. Args: project: project on which the operation is performed zone: zone on which the operation is performed operation_ids: list/set of ids of the compute operations to wait for message: str, message to display to user while polling. timeout_s: number, seconds to poll with retries before timing out. poll_period_s: number, delay in seconds between requests. Returns: Operations: list of the last successful operations.getrequest for each op. Raises: Error: if the operation times out or finishes with an error. """ operation_ids = deque(operation_ids) operations = {} errors = [] with console_io.ProgressTracker(message, autotick=True): start_time = time.clock() ops_to_retry = [] while timeout_s > (time.clock() - start_time) and operation_ids: op_id = operation_ids.popleft() try: operation = self.GetComputeOperation(project, zone, op_id) operations[op_id] = operation if not self.IsComputeOperationFinished(operation): # Operation is still in progress. ops_to_retry.append(op_id) continue log.debug('Operation %s succeeded after %.3f seconds', operation, (time.clock() - start_time)) error = self.GetOperationError(operation) if error: # Operation Failed! msg = 'Operation [{0}] finished with error: {1}'.format(op_id, error) log.debug(msg) errors.append(msg) except apitools_exceptions.HttpError as error: log.debug('GetComputeOperation failed: %s', error) # Keep trying until we timeout in case error is transient. # TODO(user): add additional backoff if server is returning 500s if not operation_ids and ops_to_retry: operation_ids = deque(ops_to_retry) ops_to_retry = [] time.sleep(poll_period_s) operation_ids.extend(ops_to_retry) for op_id in operation_ids: errors.append('Operation [{0}] is still running'.format(op_id)) if errors: raise util.Error(linesep.join(errors)) return operations.values()
def WaitForOp(context, op_id, text): cli = context['clusteradmin'] msg = context['clusteradmin-msgs'].BigtableclusteradminOperationsGetRequest( name=op_id) with console_io.ProgressTracker(text, autotick=False) as pt: while not cli.operations.Get(msg).done: pt.Tick() time.sleep(0.5)
def Run(self, args): project = properties.VALUES.core.project.Get(required=True) api_client = appengine_api_client.GetApiClient() message = 'Creating App Engine application in project [{0}]'.format(project) with console_io.ProgressTracker(message): api_client.CreateApp(args.region) log.status.Print('Success! The app is now created. Please use ' '`gcloud app deploy` to deploy your first app.')
def WaitForOperation(operation_name, project, context, operation_description, timeout=None): """Wait for an operation to complete. Polls the operation requested approximately every second, showing a progress indicator. Returns when the operation has completed. Args: operation_name: The name of the operation to wait on, as returned by operations.list. project: The name of the project that this operation belongs to. context: Context object with messages and client to access the deploymentmanager service. operation_description: A short description of the operation to wait on, such as 'create' or 'delete'. Will be displayed to the user. timeout: Optional (approximate) timeout in seconds, after which wait will return failure. Raises: HttpException: A http error response was received while executing api request. Will be raised if the operation cannot be found. DeploymentManagerError: The operation finished with error(s) or exceeded the timeout without completing. """ client = context['deploymentmanager-client'] messages = context['deploymentmanager-messages'] ticks = 0 message = ('Waiting for ' + ('{0} '.format(operation_description) if operation_description else '') + operation_name) with console_io.ProgressTracker(message, autotick=False) as ticker: while timeout is None or ticks < timeout: ticks += 1 try: operation = client.operations.Get( messages.DeploymentmanagerOperationsGetRequest( project=project, operation=operation_name, )) except apitools_exceptions.HttpError as error: raise HttpException(GetError(error)) ticker.Tick() # Operation status will be one of PENDING, RUNNING, DONE if operation.status == 'DONE': if operation.error: raise DeploymentManagerError('Error in Operation ' + operation_name + ': ' + str(operation.error)) else: # Operation succeeded return time.sleep(1) # wait one second and try again # Timeout exceeded raise DeploymentManagerError('Wait for Operation ' + operation_name + ' exceeded timeout.')
def Run(self, args): """Run a command that watches a variable. Args: args: argparse.Namespace, The arguments that this command was invoked with. Returns: The WatchVariable response. Raises: HttpException: An http error response was received while executing api request. """ # Disable retries and configure the timeout. variable_client = util.VariableClient(num_retries=0, timeout=args.max_wait) messages = util.Messages() var_resource = util.ParseVariableName(args.name, args) project = var_resource.projectsId config = var_resource.configsId name = var_resource.Name() if args.newer_than: # TODO(user): better way to handle UTC suffix? newer_than = args.newer_than.isoformat() + 'Z' else: newer_than = None with console_io.ProgressTracker( 'Waiting for variable [{0}] to change'.format(name)): try: return util.FormatVariable( variable_client.Watch( messages. RuntimeconfigProjectsConfigsVariablesWatchRequest( projectsId=project, configsId=config, variablesId=name, watchVariableRequest=messages.WatchVariableRequest( newerThan=newer_than, )))) except apitools_exceptions.HttpError as error: # For deadline exceeded or bad gateway errors, # we return a status code of 2. # In some cases, the GFE will timeout before the backend # responds with a 504 Gateway Timeout (DEADLINE_EXCEEDED). # In that scenario, GFE responds first with a 502 BAD GATEWAY error. if util.IsDeadlineExceededError( error) or util.IsBadGatewayError(error): _RaiseTimeout() raise except socket.error as error: if util.IsSocketTimeout(error): _RaiseTimeout() raise
def ExecuteCloudBuild(project, source_uri, output_image, cloudbuild_client): """Execute a call to Argo CloudBuild service and wait for it to finish. Args: project: the cloud project ID. source_uri: GCS object containing source to build; eg, gs://my-bucket/v1/foo/some.version.stuff. output_image: GCR location for the output docker image; eg, gcr.io/test-argo/hardcoded-output-tag. cloudbuild_client: client to the Argo Cloud Build service. Raises: BuildFailedError: when the build fails. """ (source_bucket, source_object) = cloud_storage.ParseGcsUri(source_uri) # TODO(user): Consider building multiple output images in a single call # to Argo Cloud Builder. build_op = cloudbuild_client.projects_builds.Create( cloudbuild_v1.CloudbuildProjectsBuildsCreateRequest( projectId=project, build=cloudbuild_v1.Build( source=cloudbuild_v1.Source( storageSource=cloudbuild_v1.StorageSource( bucket=source_bucket, object=source_object, ), ), steps=[ cloudbuild_v1.BuildStep(name=CLOUDBUILD_BUILDER, args=[output_image]) ], images=[output_image], ), )) # Build ops are named "operation/build/{project_id}/{build_id}". build_id = build_op.name.split('/')[-1] log.status.Print( 'Started cloud build [{build_id}].'.format(build_id=build_id)) logs_uri = CLOUDBUILD_LOGS_URI_TEMPLATE.format(project_id=project, build_id=build_id) # TODO(user): wait for job to be scheduled before printing logs uri. # Alternatively, it would be nice if we wrote a single line to the logs prior # to returning from the Create call. log.status.Print('Logs at: ' + logs_uri) message = 'Waiting for cloud build [{build_id}]'.format(build_id=build_id) with console_io.ProgressTracker(message): op = operations.WaitForOperation(cloudbuild_client.operations, build_op) final_status = _GetStatusFromOp(op) if final_status != CLOUDBUILD_SUCCESS: raise BuildFailedError( 'Your Google Cloud Builder build failed with status ' + final_status + '. Check logs at ' + logs_uri)
def WaitForOperation(cls, sql_client, operation_ref, message): """Wait for a Cloud SQL operation to complete. No operation is done instantly. Wait for it to finish following this logic: First wait 1s, then query, then retry waiting exponentially more from 2s. We want to limit to 20s between retries to maintain some responsiveness. Finally, we want to limit the whole process to a conservative 180s. If we get to that point it means something is wrong and we can throw an exception. Args: sql_client: apitools.BaseApiClient, The client used to make requests. operation_ref: resources.Resource, A reference for the operation to poll. message: str, The string to print while polling. Returns: True if the operation succeeded without error. Raises: OperationError: If the operation has an error code, is in UNKNOWN state, or if the operation takes more than 180s. """ def ShouldRetryFunc(result, state): # In case of HttpError, retry for up to _HTTP_MAX_RETRY_MS at most. if isinstance(result, exceptions.HttpError): if state.time_passed_ms > _BaseOperations._HTTP_MAX_RETRY_MS: raise result return True # In case of other Exceptions, raise them immediately. if isinstance(result, Exception): raise result # Otherwise let the retryer do it's job until the Operation is done. return not result with console_io.ProgressTracker(message, autotick=False) as pt: time.sleep(_BaseOperations._PRE_START_SLEEP_SEC) retryer = retry.Retryer( exponential_sleep_multiplier=2, max_wait_ms=_BaseOperations._MAX_WAIT_MS, wait_ceiling_ms=_BaseOperations._WAIT_CEILING_MS) try: retryer.RetryOnResult( cls.GetOperationStatus, [sql_client, operation_ref], {'progress_tracker': pt}, should_retry_if=ShouldRetryFunc, sleep_ms=_BaseOperations._INITIAL_SLEEP_MS) except retry.WaitException: raise errors.OperationError(( 'Operation {0} is taking longer than expected. You can continue ' 'waiting for the operation by running `{1}`').format( operation_ref, cls.GetOperationWaitCommand(operation_ref)))
def WaitForOperation(operation, context, message, timeout_s=2100, poll_period_s=5): """Poll dataproc Operation until its status is done or timeout reached. Args: operation: Operation, message of the operation to be polled. context: dict, dataproc Command context. message: str, message to display to user while polling. timeout_s: number, seconds to poll with retries before timing out. poll_period_s: number, delay in seconds between requests. Returns: Operation: the return value of the last successful operations.get request. Raises: ToolException: if the operation times out or finishes with an error. """ client = context['dataproc_client'] messages = context['dataproc_messages'] request = messages.DataprocProjectsRegionsOperationsGetRequest( name=operation.name) log.status.Print('Waiting on operation [{0}].'.format(operation.name)) start_time = time.time() with console_io.ProgressTracker(message, autotick=True): while timeout_s > (time.time() - start_time): try: operation = client.projects_regions_operations.Get(request) if operation.done: break except apitools_exceptions.HttpError as error: log.debug('GetOperation failed:\n' + FormatHttpError(error)) # Keep trying until we timeout in case error is transient. time.sleep(poll_period_s) # TODO(user): Parse operation metadata. log.debug('Operation:\n' + encoding.MessageToJson(operation)) if not operation.done: raise exceptions.ToolException('Operation [{0}] timed out.'.format( operation.name)) elif operation.error: raise exceptions.ToolException('Operation [{0}] failed: {1}.'.format( operation.name, FormatRpcError(operation.error))) log.info('Operation [%s] finished after %.3f seconds', operation.name, (time.time() - start_time)) return operation
def Run(self, args): client = appengine_client.AppengineClient() versions = version_util.GetMatchingVersions(client.ListVersions(), args.versions, args.service, client.project) for version in versions: if version.traffic_allocation: # TODO(zjn): mention `set-traffic` after b/24008284 is fixed. # TODO(zjn): mention `migrate` it's implemented. # TODO(zjn): mention `services delete` after it's implemented. raise VersionsDeleteError( 'Version [{version}] is currently serving {allocation}% of traffic ' 'for service [{service}].\n\n' 'Please move all traffic away by using the by deploying a new ' 'version with the `--promote` argument.'.format( version=version.version, allocation=version.traffic_allocation, service=version.service)) if versions: printer = console_io.ListPrinter( 'Deleting the following versions:') printer.Print(versions, output_stream=log.status) console_io.PromptContinue(cancel_on_no=True) else: log.warn('No matching versions found.') api_client = appengine_api_client.GetApiClient(self.Http(timeout=None)) errors = {} for version in sorted(versions): try: with console_io.ProgressTracker( 'Deleting [{0}]'.format(version)): api_client.DeleteVersion(version.service, version.version) except (calliope_exceptions.HttpException, operations.OperationError, operations.OperationTimeoutError) as err: errors[version] = str(err) if errors: printable_errors = {} for version, error_msg in errors.items(): short_name = '[{0}/{1}]'.format(version.service, version.version) printable_errors[short_name] = '{0}: {1}'.format( short_name, error_msg) raise VersionsDeleteError( 'Issues deleting version(s): {0}\n\n'.format(', '.join( printable_errors.keys())) + '\n\n'.join(printable_errors.values()))
def WaitForComputeOperation(self, project, zone, operation_id, message, timeout_s=1200, poll_period_s=5): """Poll container Operation until its status is done or timeout reached. Args: project: project on which the operation is performed zone: zone on which the operation is performed operation_id: id of the compute operation to wait for message: str, message to display to user while polling. timeout_s: number, seconds to poll with retries before timing out. poll_period_s: number, delay in seconds between requests. Returns: Operation: the return value of the last successful operations.get request. Raises: Error: if the operation times out or finishes with an error. """ with console_io.ProgressTracker(message, autotick=True): start_time = time.clock() while timeout_s > (time.clock() - start_time): try: operation = self.GetComputeOperation( project, zone, operation_id) if self.IsComputeOperationFinished(operation): # Success! log.info('Operation %s succeeded after %.3f seconds', operation, (time.clock() - start_time)) break except apitools_exceptions.HttpError as error: log.debug('GetComputeOperation failed: %s', error) # Keep trying until we timeout in case error is transient. # TODO(user): add additional backoff if server is returning 500s time.sleep(poll_period_s) if not self.IsComputeOperationFinished(operation): log.err.Print( 'Timed out waiting for operation {0}'.format(operation)) raise util.Error( 'Operation [{0}] is still running'.format(operation)) if self.GetOperationError(operation): raise util.Error('Operation [{0}] finished with error: {1}'.format( operation, self.GetOperationError(operation))) return operation
def WaitForOp(context, op_id, text): cli = context['clusteradmin'] msg = context[ 'clusteradmin-msgs'].BigtableclusteradminOperationsGetRequest( name=op_id) with console_io.ProgressTracker(text, autotick=False) as pt: while True: # TODO(user): set reasonable timeout with input from API team resp = cli.operations.Get(msg) if resp.error: raise sdk_ex.HttpException(resp.error.message) if resp.done: break pt.Tick() time.sleep(0.5)
def GetToolResultsIds(matrix, testing_api_helper, status_interval=STATUS_INTERVAL_SECS): """Gets the Tool Results history ID and execution ID for a test matrix. Sometimes the IDs are available immediately after a test matrix is created. If not, we keep checking the matrix until the Testing and Tool Results services have had enough time to create/assign the IDs, giving the user continuous feedback using gcloud core's ProgressTracker class. Args: matrix: a TestMatrix which was just created by the Testing service. testing_api_helper: a TestingApiHelper object. status_interval: float, number of seconds to sleep between status checks. Returns: A ToolResultsIds tuple containing the history ID and execution ID, which are shared by all TestExecutions in the TestMatrix. Raises: BadMatrixException: if the matrix finishes without both ToolResults IDs. """ history_id = None execution_id = None msg = 'Creating individual test executions' with console_io.ProgressTracker(msg, autotick=True): while True: if matrix.resultStorage.toolResultsExecution: history_id = matrix.resultStorage.toolResultsExecution.historyId execution_id = matrix.resultStorage.toolResultsExecution.executionId if history_id and execution_id: break if matrix.state in testing_api_helper.completed_matrix_states: raise BadMatrixException( '\nMatrix [{m}] unexpectedly reached final status {s} without ' 'returning a URL to any test results in the Developers Console. ' 'Please re-check the validity of your APK file(s) and test ' 'parameters and try again.'.format(m=matrix.testMatrixId, s=matrix.state)) time.sleep(status_interval) matrix = testing_api_helper.GetTestMatrixStatus( matrix.testMatrixId) return ToolResultsIds(history_id=history_id, execution_id=execution_id)
def wait_for_operation(self, operation_name, operation_description=None): """Wait for an operation to complete. Polls the operation requested approximately every second, showing a progress indicator. Returns when the operation has completed. Args: operation_name: The name of the operation to wait on, as returned by operations.list. operation_description: A short description of the operation to wait on, such as 'create' or 'delete'. Will be displayed to the user. Raises: HttpException: A http error response was received while executing api request. Will be raised if the operation cannot be found. ServiceRegistryError: The operation finished with error(s) or exceeded the timeout without completing. """ tick_increment = 1 # every seconds ticks = 0 message = ('Waiting for {0}[{1}]'.format( operation_description + ' ' if operation_description else '', operation_name)) with console_io.ProgressTracker(message, autotick=False) as ticker: while ticks < self.OPERATION_TIMEOUT: operation = self.client.operations.Get( self.messages.ServiceregistryOperationsGetRequest( project=self.project, operation=operation_name, )) # Operation status is one of PENDING, RUNNING, DONE if operation.status == 'DONE': if operation.error: raise ServiceRegistryError( 'Error in Operation [{0}]: {1}'.format( operation_name, str(operation.error))) else: # Operation succeeded return ticks += tick_increment ticker.Tick() time.sleep(tick_increment) # Timeout exceeded raise ServiceRegistryError('Wait for Operation [' + operation_name + '] exceeded timeout.')
def WaitForWaiter(waiter_resource, sleep=None, max_wait=None): """Wait for a waiter to finish. Args: waiter_resource: The waiter resource to wait for. sleep: The number of seconds to sleep between status checks. max_wait: The maximum number of seconds to wait before an error is raised. Returns: The last retrieved value of the Waiter. Raises: WaitTimeoutError: If the wait operation takes longer than the maximum wait time. """ sleep = sleep if sleep is not None else DEFAULT_WAITER_SLEEP max_wait = max_wait if max_wait is not None else MAX_WAITER_TIMEOUT waiter_client = WaiterClient() retryer = retry.Retryer(max_wait_ms=max_wait * 1000) with console_io.ProgressTracker( 'Waiting for waiter [{0}] to finish'.format( waiter_resource.Name())): try: result = retryer.RetryOnResult( waiter_client.Get, args=[waiter_resource.Request()], sleep_ms=sleep * 1000, should_retry_if=lambda w, s: not w.done) except retry.WaitException: raise rtc_exceptions.WaitTimeoutError( 'Waiter [{0}] did not finish within {1} seconds.'.format( waiter_resource.Name(), max_wait)) if result.error is not None: if result.error.message is not None: message = 'Waiter [{0}] finished with an error: {1}'.format( waiter_resource.Name(), result.error.message) else: message = 'Waiter [{0}] finished with an error.'.format( waiter_resource.Name()) log.error(message) return result
def Run(self, args): api_client = appengine_api_client.GetApiClient() all_instances = api_client.GetAllInstances(args.service, args.version) # Only VM instances can be placed in debug mode for now. all_instances = filter(operator.attrgetter('instance.vmName'), all_instances) instance = instances_util.GetMatchingInstance(all_instances, service=args.service, version=args.version, instance=args.instance) console_io.PromptContinue( 'About to enable debug mode for instance [{0}].'.format(instance), cancel_on_no=True) message = 'Enabling debug mode for instance [{0}]'.format(instance) with console_io.ProgressTracker(message): api_client.DebugInstance(service=instance.service, version=instance.version, instance=instance.id)
def DeleteServices(api_client, services): """Delete the given services.""" errors = {} for service in services: try: with console_io.ProgressTracker('Deleting [{0}]'.format(service.id)): api_client.DeleteService(service.id) except (calliope_exceptions.HttpException, operations.OperationError, operations.OperationTimeoutError) as err: errors[service.id] = str(err) if errors: printable_errors = {} for service_id, error_msg in errors.items(): printable_errors[service_id] = '[{0}]: {1}'.format(service_id, error_msg) raise ServicesDeleteError( 'Issue deleting {0}: [{1}]\n\n'.format( text.Pluralize(len(printable_errors), 'service'), ', '.join(printable_errors.keys())) + '\n\n'.join(printable_errors.values()))
def WaitForResourceDeletion(request_method, resource_ref, message, timeout_s=60, poll_period_s=5): """Poll Dataproc resource until it no longer exists.""" request = resource_ref.Request() with console_io.ProgressTracker(message, autotick=True): start_time = time.time() while timeout_s > (time.time() - start_time): try: request_method(request) except apitools_exceptions.HttpError as error: if error.status_code == 404: # Object deleted return log.debug('Request [{0}] failed:\n{1}', request, error) # Keep trying until we timeout in case error is transient. time.sleep(poll_period_s) raise exceptions.ToolException( 'Deleting resource [{0}] timed out.'.format(resource_ref))
def Run(self, args): api_client = appengine_api_client.GetApiClient() all_instances = api_client.GetAllInstances(args.service, args.version) # Only VM instances can be placed in debug mode for now. all_instances = filter(operator.attrgetter('instance.vmName'), all_instances) instance = instances_util.GetMatchingInstance(all_instances, service=args.service, version=args.version, instance=args.instance) console_io.PromptContinue( 'About to disable debug mode for instance [{0}].\n\n' 'Any local changes will be LOST. New instance(s) may spawn depending ' 'on the app\'s scaling settings.'.format(instance), cancel_on_no=True) message = 'Disabling debug mode for instance [{0}]'.format(instance) with console_io.ProgressTracker(message): api_client.DeleteInstance(service=instance.service, version=instance.version, instance=instance.id)
def WaitForOperation(client, operation_ref, message): """Waits until the given operation finishes. Wait loop terminates when the operation's status becomes 'DONE'. Args: client: interface to the Cloud Updater API operation_ref: operation to poll message: message to be displayed by progress tracker Returns: True iff the operation finishes with success """ with console_io.ProgressTracker(message, autotick=False) as pt: while True: operation = client.zoneOperations.Get(operation_ref.Request()) if operation.error: return False if operation.status == 'DONE': return True pt.Tick() time_utils.Sleep(2)
def DeleteVersions(api_client, versions): """Delete the given version of the given services.""" errors = {} for version in versions: version_path = '{0}/{1}'.format(version.service, version.id) try: with console_io.ProgressTracker('Deleting [{0}]'.format(version_path)): api_client.DeleteVersion(version.service, version.id) except (calliope_exceptions.HttpException, operations.OperationError, operations.OperationTimeoutError) as err: errors[version_path] = str(err) if errors: printable_errors = {} for version_path, error_msg in errors.items(): printable_errors[version_path] = '[{0}]: {1}'.format(version_path, error_msg) raise VersionsDeleteError( 'Issue deleting {0}: [{1}]\n\n'.format( text.Pluralize(len(printable_errors), 'version'), ', '.join(printable_errors.keys())) + '\n\n'.join(printable_errors.values()))
def WaitForOperation(autoscaler_client, operation_ref, message): """Waits for operation to finish, displays a progress bar. Args: autoscaler_client: Client used to fetch operation. operation_ref: Operation for completion of which the function will wait. message: message Displayed with progress bar. Returns: True iff operation was completed. False otherwise. Forked from //cloud/sdk/sql/util.py """ with console_io.ProgressTracker(message, autotick=False) as pt: while True: op = autoscaler_client.zoneOperations.Get(operation_ref.Request()) pt.Tick() # TODO(user): Make sure we recognize operation failures as well. if op.status == 'DONE': return True if op.status == 'UNKNOWN': return False time.sleep(2)