def GetOperationStatus(sql_client, operation_ref, progress_tracker=None): """Helper function for getting the status of an operation for V1Beta3 API. Args: sql_client: apitools.BaseApiClient, The client used to make requests. operation_ref: resources.Resource, A reference for the operation to poll. progress_tracker: console_io.ProgressTracker, A reference for the progress tracker to tick, in case this function is used in a Retryer. Returns: True: if the operation succeeded without error. False: if the operation is not yet done. OperationError: If the operation has an error code or is in UNKNOWN state. Exception: Any other exception that can occur when calling Get """ if progress_tracker: progress_tracker.Tick() try: op = sql_client.operations.Get(operation_ref.Request()) except Exception as e: # pylint:disable=broad-except # Since we use this function in a retryer.RetryOnResult block, where we # retry for different exceptions up to different amounts of time, we # have to catch all exceptions here and return them. return e if op.error: return errors.OperationError(op.error[0].code) if op.state == 'UNKNOWN': return errors.OperationError(op.state) if op.state == 'DONE': return True return False
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 300s. 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 300s. """ 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_progress_tracker.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)))