def _DetermineImageFromArgs(self, args): """Gets the image to use for the build, given the user args. Args: args: argsparse object from the DeployGKE command. Returns: Full image string representation. """ if args.tag: if (properties.VALUES.builds.check_tag.GetBool() and 'gcr.io/' not in args.tag): raise c_exceptions.InvalidArgumentException( '--tag', 'Tag value must be in the gcr.io/* or *.gcr.io/* namespace.' ) return args.tag elif args.image: if (properties.VALUES.builds.check_tag.GetBool() and 'gcr.io/' not in args.image): raise c_exceptions.InvalidArgumentException( '--image', 'Image value must be in the gcr.io/* or *.gcr.io/* namespace.' ) return args.image else: # Default tag if args.app_name: default_name = args.app_name elif os.path.isdir( args.source): # I.e., the source is not a tarball default_name = os.path.basename(os.path.abspath(args.source)) else: raise c_exceptions.OneOfArgumentsRequiredException( ['--app-name', '--tag'], 'Cannot resolve default container image. Provide an app name with ' '--app-name to use as the container image, or provide a full ' 'tag using --tag.') if args.app_version: default_tag = args.app_version elif git.IsGithubRepository( args.source) and not git.HasPendingChanges(args.source): default_tag = git.GetGitHeadRevision(args.source) if not default_tag: raise c_exceptions.OneOfArgumentsRequiredException( ['--app-version', '--tag'], 'Cannot resolve default container tag using the Git commit SHA. ' 'Provide an app version with --app-version to use as the ' 'container tag, or provide a full tag using --tag.') else: raise c_exceptions.OneOfArgumentsRequiredException( ['--app-version', '--tag'], 'Cannot resolve default container tag. ' 'Provide an app version with --app-version to use as the ' 'container tag, or provide a full tag using --tag.') return 'gcr.io/$PROJECT_ID/{name}:{tag}'.format(name=default_name, tag=default_tag)
def _DetermineImageFromArgs(self, args): """Gets the image to use for the build, given the user args. Args: args: argsparse object from the DeployGKE command. Returns: Full image string representation. """ if args.tag_default: if args.app_name: default_name = args.app_name elif os.path.isdir(args.source): default_name = os.path.basename(os.path.abspath(args.source)) else: raise c_exceptions.InvalidArgumentException( '--tag-default', 'No default container image name available. Provide an ' 'app name with --app-name, or provide a valid --tag.') if args.app_version: default_tag = args.app_version elif git.IsGithubRepository( args.source) and not git.HasPendingChanges(args.source): default_tag = git.GetShortGitHeadRevision(args.source) if not default_tag: raise c_exceptions.InvalidArgumentException( '--tag-default', 'No default tag available, no commit sha at HEAD of source ' 'repository available for tag. Provide an app version ' 'with --app-version, or provide a valid --tag.') else: raise c_exceptions.InvalidArgumentException( '--tag-default', 'No default container image tag available. Provide an app ' 'version with --app-version, or provide a valid --tag.') return 'gcr.io/$PROJECT_ID/{name}:{tag}'.format(name=default_name, tag=default_tag) if args.tag: if (properties.VALUES.builds.check_tag.GetBool() and 'gcr.io/' not in args.tag): raise c_exceptions.InvalidArgumentException( '--tag', 'Tag value must be in the gcr.io/* or *.gcr.io/* namespace.' ) return args.tag if args.image: if (properties.VALUES.builds.check_tag.GetBool() and 'gcr.io/' not in args.image): raise c_exceptions.InvalidArgumentException( '--image', 'Image value must be in the gcr.io/* or *.gcr.io/* namespace.' ) return args.image
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. Raises: FailedDeployException: If the build is completed and not 'SUCCESS'. """ if not args.source and not args.no_source: raise c_exceptions.InvalidArgumentException( '--no-source', 'To omit source, use the --no-source flag.') if args.no_source: if args.tag: raise c_exceptions.RequiredArgumentException( 'SOURCE', 'Source is required to build container image.') if args.config: raise c_exceptions.RequiredArgumentException( 'SOURCE', 'Source is required when specifying --config because it is a ' 'relative path in the source directory.') do_build_and_push = args.image is None if not do_build_and_push and not args.config: args.no_source = True image = self._DetermineImageFromArgs(args) # Determine app_name if args.app_name: app_name = args.app_name else: app_name = self._ImageName(image) # Determine app_version app_version = None image_has_tag = '@' not in image and ':' in image if args.app_version: app_version = args.app_version elif image_has_tag: app_version = image.split(':')[-1] # Set version to tag elif args.source: if git.IsGithubRepository( args.source) and not git.HasPendingChanges(args.source): commit_sha = git.GetGitHeadRevision(args.source) if commit_sha: app_version = commit_sha # Validate expose if args.expose and args.expose < 0: raise c_exceptions.InvalidArgumentException( '--expose', 'port number is invalid') # Determine gcs_staging_dir_bucket and gcs_staging_dir_object if args.gcs_staging_dir is None: gcs_staging_dir_bucket = staging_bucket_util.GetDefaultStagingBucket( ) gcs_staging_dir_object = 'deploy' else: try: gcs_staging_dir_ref = resources.REGISTRY.Parse( args.gcs_staging_dir, collection='storage.objects') gcs_staging_dir_object = gcs_staging_dir_ref.object except resources.WrongResourceCollectionException: gcs_staging_dir_ref = resources.REGISTRY.Parse( args.gcs_staging_dir, collection='storage.buckets') gcs_staging_dir_object = None gcs_staging_dir_bucket = gcs_staging_dir_ref.bucket gcs_client = storage_api.StorageClient() try: gcs_client.CreateBucketIfNotExists( gcs_staging_dir_bucket, check_ownership=args.gcs_staging_dir is None) except storage_api.BucketInWrongProjectError: # If we're using the default bucket but it already exists in a different # project, then it could belong to a malicious attacker (b/33046325). raise c_exceptions.RequiredArgumentException( '--gcs-staging-dir', 'A bucket with name {} already exists and is owned by ' 'another project. Specify a bucket using ' '--gcs-staging-dir.'.format(gcs_staging_dir_bucket)) if gcs_staging_dir_object: gcs_config_staging_path = '{}/{}/config'.format( gcs_staging_dir_bucket, gcs_staging_dir_object) else: gcs_config_staging_path = gcs_staging_dir_bucket if not args.no_source: staged_source = self._StageSource(args.source, gcs_staging_dir_bucket, gcs_staging_dir_object) else: staged_source = None messages = cloudbuild_util.GetMessagesModule() build_config = build_util.CreateBuild( messages, build_timeout=properties.VALUES.builds.timeout.Get(), build_and_push=do_build_and_push, staged_source=staged_source, image=image, dockerfile_path='Dockerfile', app_name=app_name, app_version=app_version, config_path=args.config, namespace=args.namespace, expose_port=args.expose, gcs_config_staging_path=gcs_config_staging_path, cluster=args.cluster, location=args.location, build_tags=([] if not args.app_name else [args.app_name])) client = cloudbuild_util.GetClientInstance() self._SubmitBuild(client, messages, build_config, gcs_config_staging_path, args.config is None, args.async_)
def _CreateBuildFromArgs(self, args, messages): """Creates the Cloud Build config from the arguments. Args: args: argsparse object from the DeployGKE command. messages: Cloud Build messages module. Returns: messages.Build, the Cloud Build config. """ build = messages.Build(steps=[], tags=_CLOUD_BUILD_DEPLOY_TAGS) if args.app_name: build.tags.append(args.app_name) build_timeout = properties.VALUES.builds.timeout.Get() if build_timeout is not None: try: # A bare number is interpreted as seconds. build_timeout_secs = int(build_timeout) except ValueError: build_timeout_duration = times.ParseDuration(build_timeout) build_timeout_secs = int(build_timeout_duration.total_seconds) build.timeout = six.text_type(build_timeout_secs) + 's' if args.source is None: if args.tag or args.tag_default: raise c_exceptions.RequiredArgumentException( 'SOURCE', 'required to build container image provided by --tag or --tag-default.' ) if args.config: raise c_exceptions.RequiredArgumentException( 'SOURCE', 'required because --config is a relative path in the ' 'source directory.') if args.source and args.image and not args.config: raise c_exceptions.InvalidArgumentException( 'SOURCE', 'Source should not be provided when no Kubernetes ' 'configs and no docker builds are required.') if args.tag_default: if args.app_name: default_name = args.app_name elif os.path.isdir(args.source): default_name = os.path.basename(os.path.abspath(args.source)) else: raise c_exceptions.InvalidArgumentException( '--tag-default', 'No default container image name available. Please provide an ' 'app name with --app-name, or provide a valid --tag.') if args.app_version: default_tag = args.app_version elif git.IsGithubRepository( args.source) and not git.HasPendingChanges(args.source): default_tag = git.GetShortGitHeadRevision(args.source) if not default_tag: raise c_exceptions.InvalidArgumentException( '--tag-default', 'No default tag available, no commit sha at HEAD of source ' 'repository available for tag. Please provide an app version ' 'with --app-version, or provide a valid --tag.') else: raise c_exceptions.InvalidArgumentException( '--tag-default', 'No default container image tag available. Please provide an app ' 'version with --app-version, or provide a valid --tag.') args.tag = 'gcr.io/$PROJECT_ID/{name}:{tag}'.format( name=default_name, tag=default_tag) if args.tag: if (properties.VALUES.builds.check_tag.GetBool() and 'gcr.io/' not in args.tag): raise c_exceptions.InvalidArgumentException( '--tag', 'Tag value must be in the gcr.io/* or *.gcr.io/* namespace.' ) build.steps.append( messages.BuildStep( name='gcr.io/cloud-builders/docker', args=[ 'build', '--network', 'cloudbuild', '--no-cache', '-t', args.tag, '.' ], )) build.steps.append( messages.BuildStep(name='gcr.io/cloud-builders/docker', args=['push', args.tag])) if args.image and (properties.VALUES.builds.check_tag.GetBool() and 'gcr.io/' not in args.image): raise c_exceptions.InvalidArgumentException( '--image', 'Image value must be in the gcr.io/* or *.gcr.io/* namespace.') if args.expose and args.expose < 0: raise c_exceptions.InvalidArgumentException( 'EXPOSE', 'port number is invalid') self._StageSourceAndConfigFiles(args, messages, build) image = args.image if args.image else args.tag deploy_step = messages.BuildStep( name=_GKE_DEPLOY_PROD, args=[ 'run', '--image={}'.format(image), '--cluster={}'.format(args.cluster), '--location={}'.format(args.location), '--namespace={}'.format(args.namespace), '--output=output', '--label=gcb-build-id=$BUILD_ID', ], ) image_name = image.split('/')[-1] image_with_digest = image_name.split('@') image_with_tag = image_name.split(':') if args.app_name: deploy_step.args.append('--app={}'.format(args.app_name)) else: if len(image_with_digest) > 1: deploy_step.args.append('--app={}'.format( image_with_digest[0])) else: deploy_step.args.append('--app={}'.format(image_with_tag[0])) if args.app_version: deploy_step.args.append('--version={}'.format(args.app_version)) elif len(image_with_digest) == 1 and len(image_with_tag) > 1: deploy_step.args.append('--version={}'.format(image_with_tag[1])) elif args.source: if git.IsGithubRepository( args.source) and not git.HasPendingChanges(args.source): short_sha = git.GetShortGitHeadRevision(args.source) if short_sha: deploy_step.args.append('--version={}'.format(short_sha)) if args.config: deploy_step.args.append('--filename={}'.format(args.config)) if args.expose: deploy_step.args.append('--expose={}'.format(args.expose)) if build.timeout is not None: deploy_step.args.append('--timeout={}'.format(build.timeout)) # Append before the gsutil copy step build.steps.insert(-1, deploy_step) return build