def Run(self, args): """Deploy a container to Cloud Run.""" job_ref = args.CONCEPTS.job.Parse() flags.ValidateResource(job_ref) conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack(), version_override='v1alpha1') changes = flags.GetConfigurationChanges(args) changes.append( config_changes.SetLaunchStageAnnotationChange(self.ReleaseTrack())) with serverless_operations.Connect(conn_context) as operations: pretty_print.Info( messages_util.GetStartDeployMessage(conn_context, job_ref, 'job')) header_msg = 'Creating and {} job...'.format( 'running' if args.wait_for_completion else 'starting') with progress_tracker.StagedProgressTracker( header_msg, stages.JobStages(include_completion=args.wait_for_completion), failure_message='Job failed', suppress_output=args.async_) as tracker: job = operations.CreateJob( job_ref, changes, args.wait_for_completion, tracker, asyn=args.async_) if args.async_: pretty_print.Success('Job [{{bold}}{job}{{reset}}] is being created ' 'asynchronously.'.format(job=job.name)) else: job = operations.GetJob(job_ref) pretty_print.Success( 'Job [{{bold}}{job}{{reset}}] has successfully ' '{operation}.'.format( job=job.name, operation=('completed' if args.wait_for_completion else 'started running'))) return job
def Run(self, args): """Update a Job on Cloud Run.""" job_ref = args.CONCEPTS.job.Parse() flags.ValidateResource(job_ref) conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack()) changes = flags.GetJobConfigurationChanges(args) changes.append( config_changes.SetLaunchStageAnnotationChange(self.ReleaseTrack())) with serverless_operations.Connect(conn_context) as operations: pretty_print.Info( messages_util.GetStartDeployMessage(conn_context, job_ref, 'Updating', 'job')) header_msg = 'Updating job...' with progress_tracker.StagedProgressTracker( header_msg, stages.JobStages(), failure_message='Job failed to deploy', suppress_output=args.async_) as tracker: job = operations.UpdateJob(job_ref, changes, tracker, asyn=args.async_) if args.async_: pretty_print.Success( 'Job [{{bold}}{job}{{reset}}] is being updated ' 'asynchronously.'.format(job=job.name)) else: job = operations.GetJob(job_ref) pretty_print.Success( 'Job [{{bold}}{job}{{reset}}] has been successfully updated' .format(job=job.name)) log.status.Print( messages_util.GetRunJobMessage(self.ReleaseTrack(), job.name)) return job
def Run(self, args): """Deploy a container to Cloud Run.""" service_ref = flags.GetService(args) build_op_ref = None messages = None build_log_url = None image = args.image include_build = flags.FlagIsExplicitlySet(args, 'source') # Build an image from source if source specified. if include_build: # Create a tag for the image creation if image is None and not args.IsSpecified('config'): image = 'gcr.io/{projectID}/cloud-run-source-deploy/{service}:{tag}'.format( projectID=properties.VALUES.core.project.Get( required=True), service=service_ref.servicesId, tag=uuid.uuid4().hex) messages = cloudbuild_util.GetMessagesModule() build_config = submit_util.CreateBuildConfig( image, args.no_cache, messages, args.substitutions, args.config, args.IsSpecified('source'), False, args.source, args.gcs_source_staging_dir, args.ignore_file, args.gcs_log_dir, args.machine_type, args.disk_size) build, build_op = submit_util.Build(messages, True, build_config, True) build_op_ref = resources.REGISTRY.ParseRelativeName( build_op.name, 'cloudbuild.operations') build_log_url = build.logUrl # Deploy a container with an image conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack()) config_changes = flags.GetConfigurationChanges(args) with serverless_operations.Connect(conn_context) as operations: image_change = config_changes_mod.ImageChange(image) changes = [image_change] if config_changes: changes.extend(config_changes) service = operations.GetService(service_ref) allow_unauth = GetAllowUnauth(args, operations, service_ref, service) pretty_print.Info( messages_util.GetStartDeployMessage(conn_context, service_ref)) has_latest = (service is None or traffic.LATEST_REVISION_KEY in service.spec_traffic) deployment_stages = stages.ServiceStages( include_iam_policy_set=allow_unauth is not None, include_route=has_latest, include_build=include_build) header = 'Deploying' if include_build: header += ' and building' if service is None: header += ' new service' header += '...' with progress_tracker.StagedProgressTracker( header, deployment_stages, failure_message='Deployment failed', suppress_output=args.async_) as tracker: operations.ReleaseService(service_ref, changes, tracker, asyn=args.async_, allow_unauthenticated=allow_unauth, prefetch=service, build_op_ref=build_op_ref, build_log_url=build_log_url) if args.async_: pretty_print.Success( 'Service [{{bold}}{serv}{{reset}}] is deploying ' 'asynchronously.'.format(serv=service_ref.servicesId)) else: pretty_print.Success( messages_util.GetSuccessMessageForSynchronousDeploy( operations, service_ref))
def Run(self, args): """Create or Update service from YAML.""" conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack()) with serverless_operations.Connect(conn_context) as client: try: new_service = service.Service( messages_util.DictToMessageWithErrorCheck( args.FILE, client.messages_module.Service), client.messages_module) except messages_util.ScalarTypeMismatchError as e: exceptions.MaybeRaiseCustomFieldMismatch(e) # If managed, namespace must match project (or will default to project if # not specified). # If not managed, namespace simply must not conflict if specified in # multiple places (or will default to "default" if not specified). namespace = args.CONCEPTS.namespace.Parse().Name( ) # From flag or default if new_service.metadata.namespace is not None: if (args.IsSpecified('namespace') and namespace != new_service.metadata.namespace): raise exceptions.ConfigurationError( 'Namespace specified in file does not match passed flag.' ) namespace = new_service.metadata.namespace if flags.GetPlatform() == flags.PLATFORM_MANAGED: project = properties.VALUES.core.project.Get() project_number = projects_util.GetProjectNumber(project) if namespace != project and namespace != str( project_number): raise exceptions.ConfigurationError( 'Namespace must be project ID [{}] or quoted number [{}] for ' 'Cloud Run (fully managed).'.format( project, project_number)) new_service.metadata.namespace = namespace changes = [ config_changes.ReplaceServiceChange(new_service), config_changes.SetLaunchStageAnnotationChange( self.ReleaseTrack()) ] service_ref = resources.REGISTRY.Parse( new_service.metadata.name, params={'namespacesId': new_service.metadata.namespace}, collection='run.namespaces.services') service_obj = client.GetService(service_ref) pretty_print.Info( run_messages_util.GetStartDeployMessage( conn_context, service_ref, operation='Applying new configuration')) deployment_stages = stages.ServiceStages() header = ('Deploying...' if service_obj else 'Deploying new service...') with progress_tracker.StagedProgressTracker( header, deployment_stages, failure_message='Deployment failed', suppress_output=args.async_) as tracker: service_obj = client.ReleaseService(service_ref, changes, tracker, asyn=args.async_, allow_unauthenticated=None, for_replace=True) if args.async_: pretty_print.Success( 'New configuration for [{{bold}}{serv}{{reset}}] is being applied ' 'asynchronously.'.format(serv=service_obj.name)) else: service_obj = client.GetService(service_ref) pretty_print.Success( 'New configuration has been applied to service ' '[{{bold}}{serv}{{reset}}].\n' 'URL: {{bold}}{url}{{reset}}'.format( serv=service_obj.name, url=service_obj.domain)) return service_obj
def Run(self, args): """Deploy a Job to Cloud Run.""" job_ref = args.CONCEPTS.job.Parse() flags.ValidateResource(job_ref) conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack()) changes = flags.GetJobConfigurationChanges(args) changes.append( config_changes.SetLaunchStageAnnotationChange(self.ReleaseTrack())) execute_now = args.execute_now or args.wait execution = None with serverless_operations.Connect(conn_context) as operations: pretty_print.Info( messages_util.GetStartDeployMessage(conn_context, job_ref, 'Creating', 'job')) if execute_now: header_msg = 'Creating and running job...' else: header_msg = 'Creating job...' with progress_tracker.StagedProgressTracker( header_msg, stages.JobStages(execute_now=execute_now, include_completion=args.wait), failure_message='Job failed to deploy', suppress_output=args.async_) as tracker: job = operations.CreateJob(job_ref, changes, tracker, asyn=(args.async_ and not execute_now)) if execute_now: execution = operations.RunJob(job_ref, args.wait, tracker, args.async_) if args.async_ and not execute_now: pretty_print.Success( 'Job [{{bold}}{job}{{reset}}] is being created ' 'asynchronously.'.format(job=job.name)) else: job = operations.GetJob(job_ref) operation = 'been created' if args.wait: operation += ' and completed execution [{}]'.format( execution.name) elif execute_now: operation += ' and started running execution [{}]'.format( execution.name) pretty_print.Success( 'Job [{{bold}}{job}{{reset}}] has successfully ' '{operation}.'.format(job=job.name, operation=operation)) msg = '' if execute_now: msg += messages_util.GetExecutionCreatedMessage( self.ReleaseTrack(), execution) msg += '\n' msg += messages_util.GetRunJobMessage(self.ReleaseTrack(), job.name, repeat=execute_now) log.status.Print(msg) return job
def Run(self, args): """Deploy a container to Cloud Run.""" platform = flags.GetAndValidatePlatform(args, self.ReleaseTrack(), flags.Product.RUN) include_build = flags.FlagIsExplicitlySet(args, 'source') if not include_build and not args.IsSpecified('image'): if console_io.CanPrompt(): args.source = flags.PromptForDefaultSource() include_build = True else: raise c_exceptions.RequiredArgumentException( '--image', 'Requires a container image to deploy (e.g. ' '`gcr.io/cloudrun/hello:latest`) if no build source is provided.' ) service_ref = args.CONCEPTS.service.Parse() flags.ValidateResource(service_ref) # Obtaining the connection context prompts the user to select a region if # one hasn't been provided. We want to do this prior to preparing a source # deploy so that we can use that region for the Artifact Registry repo. conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack()) build_type = None image = None pack = None source = None operation_message = 'Deploying container to' repo_to_create = None # Build an image from source if source specified if include_build: source = args.source ar_repo = docker_util.DockerRepo( project_id=properties.VALUES.core.project.Get(required=True), location_id=artifact_registry.RepoRegion( args, cluster_location=(conn_context.cluster_location if platform == platforms.PLATFORM_GKE else None)), repo_id='cloud-run-source-deploy') if artifact_registry.ShouldCreateRepository(ar_repo): repo_to_create = ar_repo # The image is built with latest tag. After build, the image digest # from the build result will be added to the image of the service spec. args.image = '{repo}/{service}'.format( repo=ar_repo.GetDockerString(), service=service_ref.servicesId) # Use GCP Buildpacks if Dockerfile doesn't exist docker_file = source + '/Dockerfile' if os.path.exists(docker_file): build_type = BuildType.DOCKERFILE else: pack = [{'image': args.image}] build_type = BuildType.BUILDPACKS image = None if pack else args.image operation_message = ( 'Building using {build_type} and deploying container' ' to').format(build_type=build_type.value) pretty_print.Info( messages_util.GetBuildEquivalentForSourceRunMessage( service_ref.servicesId, pack, source)) # Deploy a container with an image changes = flags.GetServiceConfigurationChanges(args) changes.insert( 0, config_changes.DeleteAnnotationChange( k8s_object.BINAUTHZ_BREAKGLASS_ANNOTATION)) changes.append( config_changes.SetLaunchStageAnnotationChange(self.ReleaseTrack())) with serverless_operations.Connect(conn_context) as operations: service = operations.GetService(service_ref) allow_unauth = GetAllowUnauth(args, operations, service_ref, service) resource_change_validators.ValidateClearVpcConnector(service, args) pretty_print.Info( messages_util.GetStartDeployMessage(conn_context, service_ref, operation_message)) has_latest = (service is None or traffic.LATEST_REVISION_KEY in service.spec_traffic) deployment_stages = stages.ServiceStages( include_iam_policy_set=allow_unauth is not None, include_route=has_latest, include_build=include_build, include_create_repo=repo_to_create is not None, ) header = None if include_build: header = 'Building and deploying' else: header = 'Deploying' if service is None: header += ' new service' header += '...' with progress_tracker.StagedProgressTracker( header, deployment_stages, failure_message='Deployment failed', suppress_output=args.async_) as tracker: service = operations.ReleaseService( service_ref, changes, tracker, asyn=args.async_, allow_unauthenticated=allow_unauth, prefetch=service, build_image=image, build_pack=pack, build_source=source, repo_to_create=repo_to_create) if args.async_: pretty_print.Success( 'Service [{{bold}}{serv}{{reset}}] is deploying ' 'asynchronously.'.format(serv=service.name)) else: service = operations.GetService(service_ref) pretty_print.Success( messages_util.GetSuccessMessageForSynchronousDeploy( service)) return service
def Run(self, args): """Deploy a container to Cloud Run.""" flags.GetAndValidatePlatform(args, self.ReleaseTrack(), flags.Product.RUN) service_ref = args.CONCEPTS.service.Parse() flags.ValidateResource(service_ref) build_type = None image = None pack = None source = None include_build = flags.FlagIsExplicitlySet(args, 'source') operation_message = 'Deploying container' # Build an image from source if source specified if include_build: # Create a tag for the image creation source = args.source if not args.IsSpecified('image'): args.image = 'gcr.io/{projectID}/cloud-run-source-deploy/{service}:{tag}'.format( projectID=properties.VALUES.core.project.Get( required=True), service=service_ref.servicesId, tag=uuid.uuid4().hex) # Use GCP Buildpacks if Dockerfile doesn't exist docker_file = args.source + '/Dockerfile' if os.path.exists(docker_file): build_type = BuildType.DOCKERFILE else: pack = [{'image': args.image}] build_type = BuildType.BUILDPACKS image = None if pack else args.image operation_message = 'Building using {build_type} and deploying container'.format( build_type=build_type.value) elif not args.IsSpecified('image'): raise c_exceptions.RequiredArgumentException( '--image', 'Requires a container image to deploy (e.g. ' '`gcr.io/cloudrun/hello:latest`) if no build source is provided.' ) # Deploy a container with an image conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack()) changes = flags.GetConfigurationChanges(args) changes.insert( 0, config_changes.DeleteAnnotationChange( k8s_object.BINAUTHZ_BREAKGLASS_ANNOTATION)) changes.append( config_changes.SetLaunchStageAnnotationChange(self.ReleaseTrack())) with serverless_operations.Connect(conn_context) as operations: service = operations.GetService(service_ref) allow_unauth = GetAllowUnauth(args, operations, service_ref, service) resource_change_validators.ValidateClearVpcConnector(service, args) pretty_print.Info( messages_util.GetStartDeployMessage(conn_context, service_ref, operation_message)) has_latest = (service is None or traffic.LATEST_REVISION_KEY in service.spec_traffic) deployment_stages = stages.ServiceStages( include_iam_policy_set=allow_unauth is not None, include_route=has_latest, include_build=include_build) header = None if include_build: header = 'Building and deploying' else: header = 'Deploying' if service is None: header += ' new service' header += '...' with progress_tracker.StagedProgressTracker( header, deployment_stages, failure_message='Deployment failed', suppress_output=args.async_) as tracker: service = operations.ReleaseService( service_ref, changes, tracker, asyn=args.async_, allow_unauthenticated=allow_unauth, prefetch=service, build_image=image, build_pack=pack, build_source=source) if args.async_: pretty_print.Success( 'Service [{{bold}}{serv}{{reset}}] is deploying ' 'asynchronously.'.format(serv=service.name)) else: service = operations.GetService(service_ref) pretty_print.Success( messages_util.GetSuccessMessageForSynchronousDeploy( service)) return service
def Run(self, args): """Create or Update service from YAML.""" run_messages = apis.GetMessagesModule( global_methods.SERVERLESS_API_NAME, global_methods.SERVERLESS_API_VERSION) service_dict = dict(args.FILE) # Clear the status to make migration from k8s deployments easier. # Since a Deployment status will have several fields that Cloud Run doesn't # support, trying to convert it to a message as-is will fail even though # status is ignored by the server. if 'status' in service_dict: del service_dict['status'] # For cases where YAML contains the project number as metadata.namespace, # preemptively convert them to a string to avoid validation failures. namespace = service_dict.get('metadata', {}).get('namespace', None) if namespace is not None and not isinstance(namespace, str): service_dict['metadata']['namespace'] = str(namespace) try: raw_service = messages_util.DictToMessageWithErrorCheck( service_dict, run_messages.Service) new_service = service.Service(raw_service, run_messages) except messages_util.ScalarTypeMismatchError as e: exceptions.MaybeRaiseCustomFieldMismatch( e, help_text= 'Please make sure that the YAML file matches the Knative ' 'service definition spec in https://kubernetes.io/docs/' 'reference/kubernetes-api/services-resources/service-v1/' '#Service.') # If managed, namespace must match project (or will default to project if # not specified). # If not managed, namespace simply must not conflict if specified in # multiple places (or will default to "default" if not specified). namespace = args.CONCEPTS.namespace.Parse().Name( ) # From flag or default if new_service.metadata.namespace is not None: if (args.IsSpecified('namespace') and namespace != new_service.metadata.namespace): raise exceptions.ConfigurationError( 'Namespace specified in file does not match passed flag.') namespace = new_service.metadata.namespace if platforms.GetPlatform() == platforms.PLATFORM_MANAGED: project = properties.VALUES.core.project.Get() project_number = projects_util.GetProjectNumber(project) if namespace != project and namespace != str(project_number): raise exceptions.ConfigurationError( 'Namespace must be project ID [{}] or quoted number [{}] for ' 'Cloud Run (fully managed).'.format( project, project_number)) new_service.metadata.namespace = namespace changes = [ config_changes.ReplaceServiceChange(new_service), config_changes.SetLaunchStageAnnotationChange(self.ReleaseTrack()) ] service_ref = resources.REGISTRY.Parse( new_service.metadata.name, params={'namespacesId': new_service.metadata.namespace}, collection='run.namespaces.services') region_label = new_service.region if new_service.is_managed else None conn_context = connection_context.GetConnectionContext( args, flags.Product.RUN, self.ReleaseTrack(), region_label=region_label) with serverless_operations.Connect(conn_context) as client: service_obj = client.GetService(service_ref) pretty_print.Info( run_messages_util.GetStartDeployMessage( conn_context, service_ref, operation='Applying new configuration to')) deployment_stages = stages.ServiceStages() header = ('Deploying...' if service_obj else 'Deploying new service...') with progress_tracker.StagedProgressTracker( header, deployment_stages, failure_message='Deployment failed', suppress_output=args.async_) as tracker: service_obj = client.ReleaseService(service_ref, changes, tracker, asyn=args.async_, allow_unauthenticated=None, for_replace=True) if args.async_: pretty_print.Success( 'New configuration for [{{bold}}{serv}{{reset}}] is being applied ' 'asynchronously.'.format(serv=service_obj.name)) else: service_obj = client.GetService(service_ref) pretty_print.Success( 'New configuration has been applied to service ' '[{{bold}}{serv}{{reset}}].\n' 'URL: {{bold}}{url}{{reset}}'.format( serv=service_obj.name, url=service_obj.domain)) return service_obj