def _GetSource(source_arg): """Parse the source bucket and object from the --source flag.""" if not source_arg: raise exceptions.FunctionsError(SOURCE_ERROR_MESSAGE) source_match = SOURCE_REGEX.match(source_arg) if not source_match: raise exceptions.FunctionsError(SOURCE_ERROR_MESSAGE) return (source_match.group(1), source_match.group(2))
def _GetRetry(args, messages, event_trigger): """Constructs an RetryPolicy enum from --(no-)retry flag. Args: args: argparse.Namespace, arguments that this command was invoked with messages: messages module, the GCFv2 message stubs event_trigger: cloudfunctions_v2alpha_messages.EventTrigger, used to request events sent from another service Returns: EventTrigger.RetryPolicyValueValuesEnum( 'RETRY_POLICY_RETRY' | 'RETRY_POLICY_DO_NOT_RETRY') frozenset, set of update mask fields """ if event_trigger is None: raise exceptions.FunctionsError(_INVALID_RETRY_FLAG_ERROR_MESSAGE) if args.retry: return messages.EventTrigger.RetryPolicyValueValuesEnum( 'RETRY_POLICY_RETRY'), frozenset(['eventTrigger.retryPolicy']) else: # explicitly using --no-retry flag return messages.EventTrigger.RetryPolicyValueValuesEnum( 'RETRY_POLICY_DO_NOT_RETRY'), frozenset( ['eventTrigger.retryPolicy'])
def _GetSourceCSR(messages, source): """Constructs a `Source` message from a Cloud Source Repository reference. Args: messages: messages module, the GCFv2 message stubs source: str, the Cloud Source Repository reference Returns: function_source: cloud.functions.v2main.Source """ match = _CSR_SOURCE_REGEX.match(source) if match is None: raise exceptions.FunctionsError(_CSR_SOURCE_ERROR_MESSAGE) repo_source = messages.RepoSource( projectId=match.group('project_id'), repoName=match.group('repo_name'), dir=match.group('path'), # Optional ) # Optional oneof revision field commit = match.group('commit') branch = match.group('branch') tag = match.group('tag') if commit: repo_source.commitSha = commit elif tag: repo_source.tagName = tag else: # Default to 'master' branch if no revision/alias provided. repo_source.branchName = branch or 'master' return messages.Source(repoSource=repo_source)
def WaitForOperation(client, messages, operation, description, extra_stages=None): """Wait for a long-running operation (LRO) to complete. Args: client: The GCFv2 API client. messages: The GCFv2 message stubs. operation: The operation message response. description: str, the description of the waited operation. extra_stages: List[progress_tracker.Stage]|None, list of optional stages for the progress tracker to watch. The GCF 2nd api returns unexpected stages in the case of rollbacks. """ request = messages.CloudfunctionsProjectsLocationsOperationsGetRequest( name=operation.name) # Wait for stages to be loaded. with progress_tracker.ProgressTracker('Preparing function') as tracker: retryer = retry.Retryer(max_wait_ms=MAX_WAIT_MS) try: # List[progress_tracker.Stage] stages = retryer.RetryOnResult(_GetStages, args=[client, request, messages], should_retry_if=None, sleep_ms=SLEEP_MS) except retry.WaitException: raise exceptions.FunctionsError( 'Operation {0} is taking too long'.format(request.name)) if extra_stages is not None: stages += extra_stages # Wait for LRO to complete. description += '...' with progress_tracker.StagedProgressTracker(description, stages) as tracker: retryer = retry.Retryer(max_wait_ms=MAX_WAIT_MS) try: retryer.RetryOnResult(_GetOperationStatus, args=[client, request, tracker, messages], should_retry_if=False, sleep_ms=SLEEP_MS) except retry.WaitException: raise exceptions.FunctionsError( 'Operation {0} is taking too long'.format(request.name))
def _GetOperationStatus(client, request, tracker): """Returns a Boolean indicating whether the request has completed.""" if tracker: tracker.Tick() op = client.projects_locations_operations.Get(request) if op.error: raise exceptions.FunctionsError(op) return op.done
def _GetSourceGCS(messages, source): """Constructs a `Source` message from a Cloud Storage object. Args: messages: messages module, the GCFv2 message stubs source: str, the Cloud Storage URL Returns: function_source: cloud.functions.v2main.Source """ match = _GCS_SOURCE_REGEX.match(source) if not match: raise exceptions.FunctionsError(_GCS_SOURCE_ERROR_MESSAGE) return messages.Source(storageSource=messages.StorageSource( bucket=match.group(1), object=match.group(2)))
def Run(args, release_track): """Delete a Google Cloud Function.""" client = api_util.GetClientInstance(release_track=release_track) messages = api_util.GetMessagesModule(release_track=release_track) function_ref = args.CONCEPTS.name.Parse() function_relative_name = function_ref.RelativeName() prompt_message = 'Function [{0}] will be deleted.'.format( function_relative_name) if not console_io.PromptContinue(message=prompt_message): raise exceptions.FunctionsError('Deletion aborted by user.') operation = client.projects_locations_functions.Delete( messages.CloudfunctionsProjectsLocationsFunctionsDeleteRequest( name=function_relative_name)) api_util.WaitForOperation(client, messages, operation, 'Deleting function') log.DeletedResource(function_relative_name)
def _UploadToGeneratedUrl(zip_file_path, url): """Uploads a ZIP file to a signed Cloud Storage URL. Args: zip_file_path: str, the path to the ZIP file url: str, the signed Cloud Storage URL """ upload = transfer.Upload.FromFile(zip_file_path, mime_type=_ZIP_MIME_TYPE) try: request = http_wrapper.Request( url, http_method='PUT', headers={'content-type': upload.mime_type}) request.body = upload.stream.read() upload.stream.close() response = http_wrapper.MakeRequest(transports.GetApitoolsTransport(), request) finally: upload.stream.close() if response.status_code // 100 != 2: raise exceptions.FunctionsError(_SIGNED_URL_UPLOAD_ERROR_MESSSAGE)
def WaitForOperation(client, messages, operation, description): """Wait for a long-running operation (LRO) to complete.""" request = messages.CloudfunctionsProjectsLocationsOperationsGetRequest( name=operation.name) with progress_tracker.ProgressTracker(description, autotick=False) as tracker: # 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, args=[client, request, tracker], should_retry_if=False, sleep_ms=SLEEP_MS) except retry.WaitException: raise exceptions.FunctionsError( 'Operation {0} is taking too long'.format(request.name))
def _ValidateLegacyV1Flags(args): for flag_variable, flag_name in LEGACY_V1_FLAGS: if args.IsSpecified(flag_variable): raise exceptions.FunctionsError(LEGACY_V1_FLAG_ERROR % flag_name)
def _ValidateUnsupportedV2Flags(args): for flag_variable, flag_name in _UNSUPPORTED_V2_FLAGS: if args.IsSpecified(flag_variable): raise exceptions.FunctionsError(_UNSUPPORTED_V2_FLAG_ERROR % flag_name)
def _Run(args, release_track): """Display log entries produced by Google Cloud Functions.""" if args.execution_id: raise exceptions.FunctionsError(EXECUTION_ID_NOT_SUPPORTED) region = properties.VALUES.functions.region.GetOrFail() log_filter = [ 'resource.type="cloud_run_revision"', 'resource.labels.location="%s"' % region, 'logName:"run.googleapis.com"' ] if args.name: log_filter.append('resource.labels.service_name="%s"' % args.name) if args.min_log_level: log_filter.append('severity>=%s' % args.min_log_level.upper()) log_filter.append('timestamp>="%s"' % logging_util.FormatTimestamp( args.start_time or datetime.datetime.utcnow() - datetime.timedelta(days=7))) if args.end_time: log_filter.append('timestamp<="%s"' % logging_util.FormatTimestamp(args.end_time)) log_filter = ' '.join(log_filter) entries = list( logging_common.FetchLogs(log_filter, order_by='DESC', limit=args.limit)) if args.name and not entries: # Check if the function even exists in the given region. try: client = api_util.GetClientInstance(release_track=release_track) messages = api_util.GetMessagesModule(release_track=release_track) client.projects_locations_functions.Get( messages.CloudfunctionsProjectsLocationsFunctionsGetRequest( name='projects/%s/locations/%s/functions/%s' % (properties.VALUES.core.project.GetOrFail(), region, args.name))) except (HttpForbiddenError, HttpNotFoundError): # The function doesn't exist in the given region. log.warning( 'There is no function named `%s` in region `%s`. Perhaps you ' 'meant to specify `--region` or update the `functions/region` ' 'configuration property?' % (args.name, region)) for entry in entries: message = entry.textPayload if entry.jsonPayload: props = [ prop.value for prop in entry.jsonPayload.additionalProperties if prop.key == 'message' ] if len(props) == 1 and hasattr(props[0], 'string_value'): message = props[0].string_value row = {'log': message} if entry.severity: severity = six.text_type(entry.severity) if severity in flags.SEVERITIES: # Use short form (first letter) for expected severities. row['level'] = severity[0] else: # Print full form of unexpected severities. row['level'] = severity if entry.resource and entry.resource.labels: for label in entry.resource.labels.additionalProperties: if label.key == 'service_name': row['name'] = label.value if entry.timestamp: row['time_utc'] = api_util.FormatTimestamp(entry.timestamp) yield row