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 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 must not be provided when no Kubernetes ' 'configs and no docker builds are required.') 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): short_sha = git.GetShortGitHeadRevision(args.source) if short_sha: app_version = short_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() gcs_client.CreateBucketIfNotExists(gcs_staging_dir_bucket) # If we are using a default bucket check that it is owned by user project # (b/33046325) if (args.gcs_staging_dir is None and not staging_bucket_util.BucketIsInProject( gcs_client, gcs_staging_dir_bucket)): 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 args.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=(args.tag_default or args.tag), 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.async_)
def _CreateGlobalRequests(self, client, resources, args, forwarding_rule_ref): """Create a globally scoped request.""" is_psc_google_apis = False if hasattr(args, 'target_google_apis_bundle' ) and args.target_google_apis_bundle: if not self._support_psc_google_apis: raise exceptions.InvalidArgumentException( '--target-google-apis-bundle', 'Private Service Connect for Google APIs (the target-google-apis-bundle option ' 'for forwarding rules) is not supported in this API version.' ) else: is_psc_google_apis = True ports_all_specified, range_list = _ExtractPortsAndAll(args.ports) port_range = _ResolvePortRange(args.port_range, range_list) if ports_all_specified and not is_psc_google_apis: raise exceptions.ToolException( '[--ports] can not be specified to all for global forwarding rules.' ) if is_psc_google_apis and port_range: raise exceptions.ToolException( '[--ports] is not allowed for PSC-GoogleApis forwarding rules.' ) if not is_psc_google_apis and not port_range: raise exceptions.ToolException( '[--ports] is required for global forwarding rules.') if is_psc_google_apis: if args.target_google_apis_bundle in flags.PSC_GOOGLE_APIS_BUNDLES: target_as_str = args.target_google_apis_bundle else: bundles_list = ', '.join(flags.PSC_GOOGLE_APIS_BUNDLES) raise exceptions.InvalidArgumentException( '--target-google-apis-bundle', 'The valid values for target-google-apis-bundle are: ' + bundles_list) else: target_ref = utils.GetGlobalTarget(resources, args, self._support_target_grpc_proxy) target_as_str = target_ref.SelfLink() protocol = self.ConstructProtocol(client.messages, args) if args.address is None or args.ip_version: ip_version = client.messages.ForwardingRule.IpVersionValueValuesEnum( args.ip_version or 'IPV4') else: ip_version = None address = self._ResolveAddress( resources, args, compute_flags.compute_scope.ScopeEnum.GLOBAL, forwarding_rule_ref) forwarding_rule = client.messages.ForwardingRule( description=args.description, name=forwarding_rule_ref.Name(), IPAddress=address, IPProtocol=protocol, portRange=port_range, target=target_as_str, ipVersion=ip_version, networkTier=_ConstructNetworkTier(client.messages, args), loadBalancingScheme=_GetLoadBalancingScheme(args, client.messages)) if args.IsSpecified('network'): forwarding_rule.network = flags.NetworkArg( self._support_l7_internal_load_balancing).ResolveAsResource( args, resources).SelfLink() if self._support_global_access and args.IsSpecified( 'allow_global_access'): forwarding_rule.allowGlobalAccess = args.allow_global_access request = client.messages.ComputeGlobalForwardingRulesInsertRequest( forwardingRule=forwarding_rule, project=forwarding_rule_ref.project) return [(client.apitools_client.globalForwardingRules, 'Insert', request)]
def Run(self, args): # We explicitly want to allow --networks='' as a valid option and we need # to differentiate between that option and not passing --networks at all. if args.visibility == 'public' and args.IsSpecified('networks'): raise exceptions.InvalidArgumentException( '--networks', 'If --visibility is set to public (default), setting networks is ' 'not allowed.') if args.visibility == 'private' and args.networks is None: raise exceptions.RequiredArgumentException('--networks', (""" If --visibility is set to private, a list of networks must be provided.' NOTE: You can provide an empty value ("") for private zones that have NO network binding. """)) dns = util.GetApiClient('v1') messages = apis.GetMessagesModule('dns', 'v1') registry = util.GetRegistry('v1') zone_ref = registry.Parse(args.dns_zone, params={ 'project': properties.VALUES.core.project.GetOrFail, }, collection='dns.managedZones') visibility = messages.ManagedZone.VisibilityValueValuesEnum( args.visibility) visibility_config = None if visibility == messages.ManagedZone.VisibilityValueValuesEnum.private: # Handle explicitly empty networks case (--networks='') networks = args.networks if args.networks != [''] else [] def GetNetworkSelfLink(network): return registry.Parse(network, collection='compute.networks', params={ 'project': zone_ref.project }).SelfLink() network_urls = [GetNetworkSelfLink(n) for n in networks] network_configs = [ messages.ManagedZonePrivateVisibilityConfigNetwork( networkUrl=nurl) for nurl in network_urls ] visibility_config = messages.ManagedZonePrivateVisibilityConfig( networks=network_configs) if args.IsSpecified('forwarding_targets') or args.IsSpecified( 'private_forwarding_targets'): forwarding_config = command_util.ParseManagedZoneForwardingConfigWithForwardingPath( messages=messages, server_list=args.forwarding_targets, private_server_list=args.private_forwarding_targets) else: forwarding_config = None dnssec_config = _MakeDnssecConfig(args, messages) labels = labels_util.ParseCreateArgs(args, messages.ManagedZone.LabelsValue) peering_config = None if args.target_project and args.target_network: peering_network = 'https://www.googleapis.com/compute/v1/projects/{}/global/networks/{}'.format( args.target_project, args.target_network) peering_config = messages.ManagedZonePeeringConfig() peering_config.targetNetwork = messages.ManagedZonePeeringConfigTargetNetwork( networkUrl=peering_network) reverse_lookup_config = None if args.IsSpecified( 'managed_reverse_lookup') and args.managed_reverse_lookup: reverse_lookup_config = messages.ManagedZoneReverseLookupConfig() service_directory_config = None if args.IsSpecified('service_directory_namespace' ) and args.service_directory_namespace: service_directory_config = messages.ManagedZoneServiceDirectoryConfig( namespace=messages.ManagedZoneServiceDirectoryConfigNamespace( namespaceUrl=args.service_directory_namespace)) zone = messages.ManagedZone( name=zone_ref.managedZone, dnsName=util.AppendTrailingDot(args.dns_name), description=args.description, dnssecConfig=dnssec_config, labels=labels, visibility=visibility, forwardingConfig=forwarding_config, privateVisibilityConfig=visibility_config, peeringConfig=peering_config, reverseLookupConfig=reverse_lookup_config, serviceDirectoryConfig=service_directory_config) result = dns.managedZones.Create( messages.DnsManagedZonesCreateRequest(managedZone=zone, project=zone_ref.project)) log.CreatedResource(zone_ref) return [result]
def _ValidateProject(flag_value): if not re.match('^[a-z0-9-]+$', flag_value): raise exceptions.InvalidArgumentException('project', flag_value)
def _ValidateOrganization(flag_value): if not re.match('^[0-9]+$', flag_value): raise exceptions.InvalidArgumentException('organization', flag_value)
def _ValidBuildArgsOfLocalRun(args): """Validates the arguments related to image building and normalize them.""" build_args_specified = _ImageBuildArgSpecified(args) if not build_args_specified: return if not args.script and not args.python_module: raise exceptions.MinimumArgumentException( ['--script', '--python-module'], 'They are required to build a training container image. ' 'Otherwise, please remove flags [{}] to directly run the `executor-image-uri`.' .format(', '.join(sorted(build_args_specified)))) # Validate main script's existence: if args.script: arg_name = '--script' else: args.script = local_util.ModuleToPath(args.python_module) arg_name = '--python-module' script_path = os.path.normpath( os.path.join(args.local_package_path, args.script)) if not os.path.exists(script_path) or not os.path.isfile(script_path): raise exceptions.InvalidArgumentException( arg_name, r"File '{}' is not found under the package: '{}'.".format( args.script, args.local_package_path)) # Validate extra custom packages specified: for package in (args.extra_packages or []): package_path = os.path.normpath( os.path.join(args.local_package_path, package)) if not os.path.exists(package_path) or not os.path.isfile( package_path): raise exceptions.InvalidArgumentException( '--extra-packages', r"Package file '{}' is not found under the package: '{}'.". format(package, args.local_package_path)) # Validate extra directories specified: for directory in (args.extra_dirs or []): dir_path = os.path.normpath( os.path.join(args.local_package_path, directory)) if not os.path.exists(dir_path) or not os.path.isdir(dir_path): raise exceptions.InvalidArgumentException( '--extra-dirs', r"Directory '{}' is not found under the package: '{}'.".format( directory, args.local_package_path)) # Validate output image uri is in valid format if args.output_image_uri: output_image = args.output_image_uri try: docker_utils.ValidateRepositoryAndTag(output_image) except ValueError as e: raise exceptions.InvalidArgumentException( '--output-image-uri', r"'{}' is not a valid container image uri: {}".format( output_image, e)) else: args.output_image_uri = docker_utils.GenerateImageName( base_name=args.script)
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: FailedBuildException: If the build is completed and not 'SUCCESS'. """ project = properties.VALUES.core.project.Get(required=True) safe_project = project.replace(':', '_') safe_project = safe_project.replace('.', '_') # The string 'google' is not allowed in bucket names. safe_project = safe_project.replace('google', 'elgoog') default_bucket_name = '{}_cloudbuild'.format(safe_project) default_gcs_source = False if args.gcs_source_staging_dir is None: default_gcs_source = True args.gcs_source_staging_dir = 'gs://{}/source'.format( default_bucket_name) client = cloudbuild_util.GetClientInstance() messages = cloudbuild_util.GetMessagesModule() gcs_client = storage_api.StorageClient() # First, create the build request. build_timeout = properties.VALUES.container.build_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) timeout_str = str(build_timeout_secs) + 's' else: timeout_str = None if args.tag: if (properties.VALUES.container.build_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_config = messages.Build( images=[args.tag], steps=[ messages.BuildStep( name='gcr.io/cloud-builders/docker', args=['build', '--no-cache', '-t', args.tag, '.'], ), ], timeout=timeout_str, substitutions=cloudbuild_util.EncodeSubstitutions( args.substitutions, messages)) elif args.config: build_config = config.LoadCloudbuildConfigFromPath( args.config, messages, params=args.substitutions) # If timeout was set by flag, overwrite the config file. if timeout_str: build_config.timeout = timeout_str # --no-source overrides the default --source. if not args.IsSpecified('source') and args.no_source: args.source = None gcs_source_staging = None if args.source: suffix = '.tgz' if args.source.startswith('gs://') or os.path.isfile(args.source): _, suffix = os.path.splitext(args.source) # Next, stage the source to Cloud Storage. staged_object = '{stamp}-{uuid}{suffix}'.format( stamp=times.GetTimeStampFromDateTime(times.Now()), uuid=uuid.uuid4().hex, suffix=suffix, ) gcs_source_staging_dir = resources.REGISTRY.Parse( args.gcs_source_staging_dir, collection='storage.objects') # We create the bucket (if it does not exist) first. If we do an existence # check and then create the bucket ourselves, it would be possible for an # attacker to get lucky and beat us to creating the bucket. Block on this # creation to avoid this race condition. gcs_client.CreateBucketIfNotExists(gcs_source_staging_dir.bucket) # If no bucket is specified (for the source `default_gcs_source`), check # that the default bucket is also owned by the project (b/33046325). if default_gcs_source: # This request returns only the buckets owned by the project. bucket_list_req = gcs_client.messages.StorageBucketsListRequest( project=project, prefix=default_bucket_name) bucket_list = gcs_client.client.buckets.List(bucket_list_req) found_bucket = False for bucket in bucket_list.items: if bucket.id == default_bucket_name: found_bucket = True break if not found_bucket: if default_gcs_source: raise c_exceptions.RequiredArgumentException( 'gcs_source_staging_dir', 'A bucket with name {} already exists and is owned by ' 'another project. Specify a bucket using ' '--gcs_source_staging_dir.'.format( default_bucket_name)) if gcs_source_staging_dir.object: staged_object = gcs_source_staging_dir.object + '/' + staged_object gcs_source_staging = resources.REGISTRY.Create( collection='storage.objects', bucket=gcs_source_staging_dir.bucket, object=staged_object) if args.source.startswith('gs://'): gcs_source = resources.REGISTRY.Parse( args.source, collection='storage.objects') staged_source_obj = gcs_client.Rewrite(gcs_source, gcs_source_staging) build_config.source = messages.Source( storageSource=messages.StorageSource( bucket=staged_source_obj.bucket, object=staged_source_obj.name, generation=staged_source_obj.generation, )) else: if not os.path.exists(args.source): raise c_exceptions.BadFileException( 'could not find source [{src}]'.format( src=args.source)) if os.path.isdir(args.source): source_snapshot = snapshot.Snapshot(args.source) size_str = resource_transform.TransformSize( source_snapshot.uncompressed_size) log.status.Print( 'Creating temporary tarball archive of {num_files} file(s)' ' totalling {size} before compression.'.format( num_files=len(source_snapshot.files), size=size_str)) staged_source_obj = source_snapshot.CopyTarballToGCS( gcs_client, gcs_source_staging) build_config.source = messages.Source( storageSource=messages.StorageSource( bucket=staged_source_obj.bucket, object=staged_source_obj.name, generation=staged_source_obj.generation, )) elif os.path.isfile(args.source): unused_root, ext = os.path.splitext(args.source) if ext not in _ALLOWED_SOURCE_EXT: raise c_exceptions.BadFileException( 'Local file [{src}] is none of ' + ', '.join(_ALLOWED_SOURCE_EXT)) log.status.Print('Uploading local file [{src}] to ' '[gs://{bucket}/{object}].'.format( src=args.source, bucket=gcs_source_staging.bucket, object=gcs_source_staging.object, )) staged_source_obj = gcs_client.CopyFileToGCS( storage_util.BucketReference.FromBucketUrl( gcs_source_staging.bucket), args.source, gcs_source_staging.object) build_config.source = messages.Source( storageSource=messages.StorageSource( bucket=staged_source_obj.bucket, object=staged_source_obj.name, generation=staged_source_obj.generation, )) else: # No source if not args.no_source: raise c_exceptions.InvalidArgumentException( '--no-source', 'To omit source, use the --no-source flag.') if args.gcs_log_dir: gcs_log_dir = resources.REGISTRY.Parse( args.gcs_log_dir, collection='storage.objects') build_config.logsBucket = ('gs://' + gcs_log_dir.bucket + '/' + gcs_log_dir.object) # Machine type. if args.machine_type is not None: machine_type = Submit._machine_type_flag_map.GetEnumForChoice( args.machine_type) if not build_config.options: build_config.options = messages.BuildOptions() build_config.options.machineType = machine_type # Disk size. if args.disk_size is not None: disk_size = compute_utils.BytesToGb(args.disk_size) if not build_config.options: build_config.options = messages.BuildOptions() build_config.options.diskSizeGb = disk_size log.debug('submitting build: ' + repr(build_config)) # Start the build. op = client.projects_builds.Create( messages.CloudbuildProjectsBuildsCreateRequest( build=build_config, projectId=properties.VALUES.core.project.Get())) json = encoding.MessageToJson(op.metadata) build = encoding.JsonToMessage(messages.BuildOperationMetadata, json).build build_ref = resources.REGISTRY.Create( collection='cloudbuild.projects.builds', projectId=build.projectId, id=build.id) log.CreatedResource(build_ref) if build.logUrl: log.status.Print('Logs are available at [{log_url}].'.format( log_url=build.logUrl)) else: log.status.Print('Logs are available in the Cloud Console.') # If the command is run --async, we just print out a reference to the build. if args. async: return build mash_handler = execution.MashHandler( execution.GetCancelBuildHandler(client, messages, build_ref)) # Otherwise, logs are streamed from GCS. with execution_utils.CtrlCSection(mash_handler): build = cb_logs.CloudBuildClient(client, messages).Stream(build_ref) if build.status == messages.Build.StatusValueValuesEnum.TIMEOUT: log.status.Print( 'Your build timed out. Use the [--timeout=DURATION] flag to change ' 'the timeout threshold.') if build.status != messages.Build.StatusValueValuesEnum.SUCCESS: raise FailedBuildException(build) return build
def RunConnectCommand(args, supports_database=False): """Connects to a Cloud SQL instance. Args: args: argparse.Namespace, The arguments that this command was invoked with. supports_database: Whether or not the `--database` flag needs to be accounted for. Returns: If no exception is raised this method does not return. A new process is started and the original one is killed. Raises: HttpException: An http error response was received while executing api request. UpdateError: An error occurred while updating an instance. SqlClientNotFoundError: A local SQL client could not be found. ConnectionError: An error occurred while trying to connect to the instance. """ client = api_util.SqlClient(api_util.API_VERSION_DEFAULT) sql_client = client.sql_client sql_messages = client.sql_messages validate.ValidateInstanceName(args.instance) instance_ref = client.resource_parser.Parse( args.instance, params={'project': properties.VALUES.core.project.GetOrFail}, collection='sql.instances') acl_name = _WhitelistClientIP(instance_ref, sql_client, sql_messages, client.resource_parser) # Get the client IP that the server sees. Sadly we can only do this by # checking the name of the authorized network rule. retryer = retry.Retryer(max_retrials=2, exponential_sleep_multiplier=2) try: instance_info, client_ip = retryer.RetryOnResult( _GetClientIP, [instance_ref, sql_client, acl_name], should_retry_if=lambda x, s: x[1] is None, # client_ip is None sleep_ms=500) except retry.RetryException: raise exceptions.UpdateError( 'Could not whitelist client IP. Server did ' 'not reply with the whitelisted IP.') # Check for the mysql or psql executable based on the db version. db_type = instance_info.databaseVersion.split('_')[0] exe_name = constants.DB_EXE.get(db_type, 'mysql') exe = files.FindExecutableOnPath(exe_name) if not exe: raise exceptions.SqlClientNotFoundError( '{0} client not found. Please install a {1} client and make sure ' 'it is in PATH to be able to connect to the database instance.'. format(exe_name.title(), exe_name)) # Check the version of IP and decide if we need to add ipv4 support. ip_type = network.GetIpVersion(client_ip) if ip_type == network.IP_VERSION_4: if instance_info.settings.ipConfiguration.ipv4Enabled: ip_address = instance_info.ipAddresses[0].ipAddress else: # TODO(b/36049930): ask user if we should enable ipv4 addressing message = ( 'It seems your client does not have ipv6 connectivity and ' 'the database instance does not have an ipv4 address. ' 'Please request an ipv4 address for this database instance.') raise exceptions.ConnectionError(message) elif ip_type == network.IP_VERSION_6: ip_address = instance_info.ipv6Address else: raise exceptions.ConnectionError('Could not connect to SQL server.') # Determine what SQL user to connect with. sql_user = constants.DEFAULT_SQL_USER[exe_name] if args.user: sql_user = args.user # We have everything we need, time to party! flags = constants.EXE_FLAGS[exe_name] sql_args = [exe_name, flags['hostname'], ip_address] sql_args.extend([flags['user'], sql_user]) sql_args.append(flags['password']) # Check for database name. if supports_database and args.IsSpecified('database'): try: sql_args.extend([flags['database'], args.database]) except KeyError: raise calliope_exceptions.InvalidArgumentException( '--database', 'This instance does not support the database argument.') try: log.status.write( 'Connecting to database with SQL user [{0}].'.format(sql_user)) execution_utils.Exec(sql_args) except OSError: log.error('Failed to execute command "{0}"'.format(' '.join(sql_args))) log.Print(info_holder.InfoHolder())
def GetAddress(self, messages, args, address, address_ref, resource_parser): """Override.""" network_tier = self.ConstructNetworkTier(messages, args) if args.ip_version or (address is None and address_ref.Collection() == 'compute.globalAddresses'): ip_version = messages.Address.IpVersionValueValuesEnum( args.ip_version or 'IPV4') else: # IP version is only specified in global requests if an address is not # specified to determine whether an ipv4 or ipv6 address should be # allocated. ip_version = None if args.subnet and args.network: raise exceptions.ConflictingArgumentsException( '--network', '--subnet') purpose = None if args.purpose and not args.network and not args.subnet: raise exceptions.MinimumArgumentException( ['--network', '--subnet'], ' if --purpose is specified') # TODO(b/36862747): get rid of args.subnet check if args.subnet: if address_ref.Collection() == 'compute.globalAddresses': raise exceptions.ToolException( '[--subnet] may not be specified for global addresses.') if not args.subnet_region: args.subnet_region = address_ref.region subnetwork_url = flags.SubnetworkArgument().ResolveAsResource( args, resource_parser).SelfLink() purpose = messages.Address.PurposeValueValuesEnum( args.purpose or 'GCE_ENDPOINT') if purpose != messages.Address.PurposeValueValuesEnum.GCE_ENDPOINT: raise exceptions.InvalidArgumentException( '--purpose', 'must be GCE_ENDPOINT for regional internal addresses.') else: subnetwork_url = None network_url = None if args.network: if address_ref.Collection() == 'compute.addresses': raise exceptions.InvalidArgumentException( '--network', 'network may not be specified for regional addresses.') network_url = flags.NetworkArgument().ResolveAsResource( args, resource_parser).SelfLink() purpose = messages.Address.PurposeValueValuesEnum(args.purpose or 'VPC_PEERING') if purpose != messages.Address.PurposeValueValuesEnum.VPC_PEERING: raise exceptions.InvalidArgumentException( '--purpose', 'must be VPC_PEERING for global internal addresses.') if not args.prefix_length: raise exceptions.RequiredArgumentException( '--prefix-length', 'prefix length is needed for reserving IP ranges.') if args.prefix_length: if purpose != messages.Address.PurposeValueValuesEnum.VPC_PEERING: raise exceptions.InvalidArgumentException( '--prefix-length', 'can only be used with [--purpose VPC_PEERING].') return messages.Address( address=address, prefixLength=args.prefix_length, description=args.description, networkTier=network_tier, ipVersion=ip_version, name=address_ref.Name(), addressType=(messages.Address.AddressTypeValueValuesEnum.INTERNAL if subnetwork_url or network_url else None), purpose=purpose, subnetwork=subnetwork_url, network=network_url)
def _ValidateCycleFrequencyArgs(args): """Validates cycle frequency args.""" if args.IsSpecified('daily_cycle') and not args.daily_cycle: raise exceptions.InvalidArgumentException( args.GetFlag('daily_cycle'), 'cannot request a non-daily cycle.')
def MakeAnalyzeIamPolicyHttpRequests(args, api_version=V1P4ALPHA1_API_VERSION): """Manually make the analyze IAM policy request.""" http_client = http.Http() if api_version == V1P4ALPHA1_API_VERSION: folder = None project = None else: folder = args.folder project = args.project parent = asset_utils.GetParentNameForAnalyzeIamPolicy( args.organization, project, folder) endpoint = apis.GetEffectiveApiEndpoint(API_NAME, api_version) url = '{0}{1}/{2}:{3}'.format(endpoint, api_version, parent, 'analyzeIamPolicy') params = [] if args.IsSpecified('full_resource_name'): params.extend([( _IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['resource_selector'] + '.fullResourceName', args.full_resource_name)]) if args.IsSpecified('identity'): params.extend([( _IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['identity_selector'] + '.identity', args.identity)]) if args.IsSpecified('roles'): params.extend([( _IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['access_selector'] + '.roles', r) for r in args.roles]) if args.IsSpecified('permissions'): params.extend([( _IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['access_selector'] + '.permissions', p) for p in args.permissions]) if args.expand_groups: params.extend([ (_IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['options'] + '.expandGroups', args.expand_groups) ]) if args.expand_resources: params.extend([ (_IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['options'] + '.expandResources', args.expand_resources) ]) if args.expand_roles: params.extend([ (_IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['options'] + '.expandRoles', args.expand_roles) ]) if args.output_resource_edges: if (api_version == V1P4BETA1_API_VERSION or api_version == DEFAULT_API_VERSION) and (not args.show_response): raise gcloud_exceptions.InvalidArgumentException( '--output-resource-edges', 'Must be set together with --show-response to take effect.') params.extend([ (_IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['options'] + '.outputResourceEdges', args.output_resource_edges) ]) if args.output_group_edges: if (api_version == V1P4BETA1_API_VERSION or api_version == DEFAULT_API_VERSION) and (not args.show_response): raise gcloud_exceptions.InvalidArgumentException( '--output-group-edges', 'Must be set together with --show-response to take effect.') params.extend([ (_IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['options'] + '.outputGroupEdges', args.output_group_edges) ]) if api_version == V1P4ALPHA1_API_VERSION and args.IsSpecified( 'output_partial_result_before_timeout'): params.extend([('options.outputPartialResultBeforeTimeout', args.output_partial_result_before_timeout)]) if (api_version == V1P4BETA1_API_VERSION or api_version == DEFAULT_API_VERSION) and args.IsSpecified('execution_timeout'): params.extend([(_IAM_POLICY_ANALYZER_VERSION_DICT[api_version] ['execution_timeout'], six.text_type(args.execution_timeout) + 's')]) if (api_version == V1P4BETA1_API_VERSION or api_version == DEFAULT_API_VERSION ) and args.analyze_service_account_impersonation: params.extend([ (_IAM_POLICY_ANALYZER_VERSION_DICT[api_version]['options'] + '.analyzeServiceAccountImpersonation', args.analyze_service_account_impersonation) ]) encoded_params = six.moves.urllib.parse.urlencode(params) response, raw_content = http_client.request(uri=url, headers=_HEADERS, method='POST', body=encoded_params) content = core_encoding.Decode(raw_content) if int(response['status']) != httplib.OK: http_error = api_exceptions.HttpError(response, content, url) raise exceptions.HttpException(http_error) response_message_class = GetMessages(api_version).AnalyzeIamPolicyResponse try: response = encoding.JsonToMessage(response_message_class, content) if (api_version == V1P4BETA1_API_VERSION or api_version == DEFAULT_API_VERSION) and (not args.show_response): return _RenderResponseforAnalyzeIamPolicy( response, args.analyze_service_account_impersonation) else: return response except ValueError as e: err_msg = ('Failed receiving proper response from server, cannot' 'parse received assets. Error details: ' + six.text_type(e)) raise MessageDecodeError(err_msg)
def _Run(self, args): """Returns a list of requests necessary for snapshotting disks.""" holder = base_classes.ComputeApiHolder(self.ReleaseTrack()) disk_refs = SnapshotDisks.disks_arg.ResolveAsResource( args, holder.resources, scope_lister=flags.GetDefaultScopeLister(holder.client)) if args.snapshot_names: if len(disk_refs) != len(args.snapshot_names): raise exceptions.InvalidArgumentException( '--snapshot-names', '[--snapshot-names] must have the same number of values as disks ' 'being snapshotted.') snapshot_names = args.snapshot_names else: # Generates names like "d52jsqy3db4q". snapshot_names = [ name_generator.GenerateRandomName() for _ in disk_refs ] snapshot_refs = [ holder.resources.Parse( snapshot_name, params={ 'project': properties.VALUES.core.project.GetOrFail, }, collection='compute.snapshots') for snapshot_name in snapshot_names ] client = holder.client.apitools_client messages = holder.client.messages requests = [] for disk_ref, snapshot_ref in zip(disk_refs, snapshot_refs): # This feature is only exposed in alpha/beta allow_rsa_encrypted = self.ReleaseTrack() in [ base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA ] csek_keys = csek_utils.CsekKeyStore.FromArgs( args, allow_rsa_encrypted) disk_key_or_none = csek_utils.MaybeLookupKeyMessage( csek_keys, disk_ref, client) snapshot_message = messages.Snapshot( name=snapshot_ref.Name(), description=args.description, sourceDiskEncryptionKey=disk_key_or_none, chainName=args.chain_name) if (hasattr(args, 'storage_location') and args.IsSpecified('storage_location')): snapshot_message.storageLocations = [args.storage_location] if (hasattr(args, 'labels') and args.IsSpecified('labels')): snapshot_message.labels = labels_util.ParseCreateArgs( args, messages.Snapshot.LabelsValue) if disk_ref.Collection() == 'compute.disks': request = messages.ComputeDisksCreateSnapshotRequest( disk=disk_ref.Name(), snapshot=snapshot_message, project=disk_ref.project, zone=disk_ref.zone, guestFlush=args.guest_flush) requests.append((client.disks, 'CreateSnapshot', request)) elif disk_ref.Collection() == 'compute.regionDisks': request = messages.ComputeRegionDisksCreateSnapshotRequest( disk=disk_ref.Name(), snapshot=snapshot_message, project=disk_ref.project, region=disk_ref.region) if hasattr(request, 'guestFlush'): # only available in alpha API guest_flush = getattr(args, 'guest_flush', None) if guest_flush is not None: request.guestFlush = guest_flush requests.append( (client.regionDisks, 'CreateSnapshot', request)) errors_to_collect = [] responses = holder.client.BatchRequests(requests, errors_to_collect) for r in responses: err = getattr(r, 'error', None) if err: errors_to_collect.append(poller.OperationErrors(err.errors)) if errors_to_collect: raise core_exceptions.MultiError(errors_to_collect) operation_refs = [ holder.resources.Parse(r.selfLink) for r in responses ] if args.async_: for operation_ref in operation_refs: log.status.Print('Disk snapshot in progress for [{}].'.format( operation_ref.SelfLink())) log.status.Print( 'Use [gcloud compute operations describe URI] command ' 'to check the status of the operation(s).') return responses operation_poller = poller.BatchPoller(holder.client, client.snapshots, snapshot_refs) return waiter.WaitFor(operation_poller, poller.OperationBatch(operation_refs), 'Creating snapshot(s) {0}'.format(', '.join( s.Name() for s in snapshot_refs)), max_wait_ms=None)
def ValidateResourcesArg(resources_arg): if (resources_arg is None or sorted(resources_arg.keys()) != _REQUIRED_RESOURCES): raise exceptions.InvalidArgumentException( '--resources', 'You must specify the following resources: {}.'.format( ', '.join(_REQUIRED_RESOURCES)))
wait_was_set = wait is not None if wait_was_set: log.warning('\nThe --wait flag is deprecated and will be removed in a ' 'future release. Use --async or --no-async instead.\n') if not async_was_set and not wait_was_set: return False # Waiting is the 'default' value for cloud sdk elif async_was_set and not wait_was_set: return async elif not async_was_set and wait_was_set: return not wait else: # async_was_set and wait_was_set if (async and wait) or (not async and not wait): raise exceptions.InvalidArgumentException('--async', 'You cannot set both the ' '--async and --wait flags.') elif async and not wait: return True else: # not async or wait return False def AddClustersWaitAndAsyncFlags(parser): """Adds the --wait and --async flags to the given parser.""" parser.add_argument( '--wait', action='store_true', default=None, # The default value is wait=True but the logic is done in # GetAsyncValueFromAsyncAndWaitFlags as there are wait and async flags
def GetIAP(iap_arg, messages, existing_iap_settings=None): """Returns IAP settings from arguments.""" # --iap is specified as str in flags.py. We do that and then re-parse # here instead of just setting the flag to ArgDict in the first place # to fix the autogenerated help text. TODO(b/34479878): Clean this up. subargs = iap_arg.split(',') iap_arg_parsed = {} for subarg in subargs: if not subarg: continue if '=' in subarg: subarg, value = subarg.split('=', 1) else: value = True def _Repr(s): r = repr(s) if r.startswith('u'): r = r[1:] return r if subarg in ('enabled', 'disabled', 'oauth2-client-id', 'oauth2-client-secret'): if subarg in iap_arg_parsed: raise exceptions.InvalidArgumentException( '--iap', 'Sub-argument %s specified multiple times' % _Repr(subarg)) iap_arg_parsed[subarg] = value else: raise exceptions.InvalidArgumentException( '--iap', 'Invalid sub-argument %s' % _Repr(subarg)) if not iap_arg_parsed or not iap_arg: raise exceptions.InvalidArgumentException( '--iap', 'Must provide value when specifying --iap') if 'enabled' in iap_arg_parsed and 'disabled' in iap_arg_parsed: raise exceptions.InvalidArgumentException( '--iap', 'Must specify only one of [enabled] or [disabled]') iap_settings = messages.BackendServiceIAP() if 'enabled' in iap_arg_parsed: iap_settings.enabled = True elif 'disabled' in iap_arg_parsed: iap_settings.enabled = False elif existing_iap_settings is None: iap_settings.enabled = False else: iap_settings.enabled = existing_iap_settings.enabled if ('oauth2-client-id' in iap_arg_parsed or 'oauth2-client-secret' in iap_arg_parsed): iap_settings.oauth2ClientId = iap_arg_parsed.get('oauth2-client-id') iap_settings.oauth2ClientSecret = iap_arg_parsed.get('oauth2-client-secret') # If either oauth2-client-id or oauth2-client-secret is specified, # then the other should also be specified. if not iap_settings.oauth2ClientId or not iap_settings.oauth2ClientSecret: raise exceptions.InvalidArgumentException( '--iap', 'Both [oauth2-client-id] and [oauth2-client-secret] must be ' 'specified together') return iap_settings
def ParseIapIamResource(release_track, args): """Parse an IAP IAM resource from the input arguments. Args: release_track: base.ReleaseTrack, release track of command. args: an argparse namespace. All the arguments that were provided to this command invocation. Raises: calliope_exc.InvalidArgumentException: if a provided argument does not apply to the specified resource type. iap_exc.InvalidIapIamResourceError: if an IapIamResource could not be parsed from the arguments. Returns: The specified IapIamResource """ project = properties.VALUES.core.project.GetOrFail() if not args.resource_type: if args.service: raise calliope_exc.InvalidArgumentException( '--service', '`--service` cannot be specified without `--resource-type`.') if args.version: raise calliope_exc.InvalidArgumentException( '--version', '`--version` cannot be specified without `--resource-type`.') return iap_api.IAPWeb( release_track, project) elif args.resource_type == APP_ENGINE_RESOURCE_TYPE: if args.service and args.version: return iap_api.AppEngineServiceVersion( release_track, project, args.service, args.version) elif args.service: return iap_api.AppEngineService( release_track, project, args.service) if args.version: raise calliope_exc.InvalidArgumentException( '--version', '`--version` cannot be specified without `--service`.') return iap_api.AppEngineApplication( release_track, project) elif args.resource_type == BACKEND_SERVICES_RESOURCE_TYPE: if args.version: raise calliope_exc.InvalidArgumentException( '--version', '`--version` cannot be specified for ' '`--resource-type=backend-services`.') if args.service: return iap_api.BackendService( release_track, project, args.service) return iap_api.BackendServices( release_track, project) # This shouldn't be reachable, based on the IAP IAM resource parsing logic. raise iap_exc.InvalidIapIamResourceError('Could not parse IAP IAM resource.')
def Run(self, args): messages = secrets_api.GetMessages() secret_ref = args.CONCEPTS.secret.Parse() data = secrets_util.ReadFileOrStdin(args.data_file) labels = labels_util.ParseCreateArgs(args, messages.Secret.LabelsValue) replication_policy = args.replication_policy if not replication_policy: replication_policy = properties.VALUES.secrets.replication_policy.Get( ) if not replication_policy: raise exceptions.RequiredArgumentException( 'replication-policy', self.MISSING_POLICY_MESSAGE) if replication_policy not in {'user-managed', 'automatic'}: if args.replication_policy: raise exceptions.InvalidArgumentException( 'replication-policy', self.INVALID_POLICY_MESSAGE) raise exceptions.InvalidArgumentException( 'replication-policy', self.INVALID_POLICY_PROP_MESSAGE) locations = args.locations if not locations: # if locations weren't given, try to get them from properties locations = properties.VALUES.secrets.locations.Get() if locations: locations = locations.split(',') if replication_policy == 'user-managed' and not locations: raise exceptions.RequiredArgumentException( 'locations', self.MANAGED_BUT_NO_LOCATIONS_MESSAGE) if replication_policy == 'automatic': if args.locations: # check args.locations separately from locations because we have # different error messages depending on whether the user used the # --locations flag or the secrets/locations property if args.replication_policy: raise exceptions.InvalidArgumentException( 'locations', self.AUTOMATIC_AND_LOCATIONS_MESSAGE) raise exceptions.InvalidArgumentException( 'locations', self.AUTOMATIC_PROP_AND_LOCATIONS_MESSAGE) if locations: raise exceptions.InvalidArgumentException( 'replication-policy', self.AUTOMATIC_AND_LOCATIONS_PROP_MESSAGE) locations = [] # Differentiate between the flag being provided with an empty value and the # flag being omitted. See b/138796299 for info. if args.data_file == '': # pylint: disable=g-explicit-bool-comparison raise exceptions.BadFileException(self.EMPTY_DATA_FILE_MESSAGE) # Create the secret response = secrets_api.Secrets().Create(secret_ref, labels=labels, locations=locations, policy=replication_policy) if data: version = secrets_api.Secrets().AddVersion(secret_ref, data) version_ref = secrets_args.ParseVersionRef(version.name) secrets_log.Versions().Created(version_ref) else: secrets_log.Secrets().Created(secret_ref) return response
def ParseIapSettingsResource(release_track, args): """Parse an IAP setting resource from the input arguments. Args: release_track: base.ReleaseTrack, release track of command. args: an argparse namespace. All the arguments that were provided to this command invocation. Raises: calliope_exc.InvalidArgumentException: if `--version` was specified with resource type 'backend-services'. Returns: The specified IapSettingsResource """ if args.organization: if args.resource_type: raise calliope_exc.InvalidArgumentException( '--resource-type', '`--resource-type` should not be specified at organization level') if args.project: raise calliope_exc.InvalidArgumentException( '--project', '`--project` should not be specified at organization level') return iap_api.IapSettingsResource( release_track, 'organizations/{0}'.format(args.organization)) if args.folder: if args.resource_type: raise calliope_exc.InvalidArgumentException( '--resource-type', '`--resource-type` should not be specified at folder level') if args.project: raise calliope_exc.InvalidArgumentException( '--project', '`--project` should not be specified at folder level') return iap_api.IapSettingsResource(release_track, 'folders/{0}'.format(args.folder)) if args.project: if not args.resource_type: return iap_api.IapSettingsResource(release_track, 'projects/{0}'.format(args.project)) else: if args.resource_type == WEB_RESOURCE_TYPE: return iap_api.IapSettingsResource( release_track, 'projects/{0}/iap_web'.format(args.project)) elif args.resource_type == APP_ENGINE_RESOURCE_TYPE: if not args.service: return iap_api.IapSettingsResource( release_track, 'projects/{0}/iap_web/appengine-{1}'.format( args.project, args.project)) else: if args.version: return iap_api.IapSettingsResource( release_track, 'projects/{0}/iap_web/appengine-{1}/services/{2}/versions/{3}' .format(args.project, args.project, args.service, args.version)) else: return iap_api.IapSettingsResource( release_track, 'projects/{0}/iap_web/appengine-{1}/services/{2}'.format( args.project, args.project, args.service)) elif args.resource_type == COMPUTE_RESOURCE_TYPE: if args.service: return iap_api.IapSettingsResource( release_track, 'projects/{0}/iap_web/compute/services/{1}'.format( args.project, args.service)) else: return iap_api.IapSettingsResource( release_track, 'projects/{0}/iap_web/compute'.format(args.project)) else: raise iap_exc.InvalidIapIamResourceError( 'Unsupported IAP settings resource type.') raise iap_exc.InvalidIapIamResourceError( 'Could not parse IAP settings resource.')
def RaiseInvalidArgument(message): raise exceptions.InvalidArgumentException( '--queue-scaling-cloud-pub-sub:{0}'.format(expected_resource_type), message)
def _SetSource(release_config, source, gcs_source_staging_dir, gcs_render_dir, ignore_file, hide_logs=False): """Set the source for the release config.""" safe_project_id = staging_bucket_util.GetSafeProject() default_gcs_source = False default_bucket_name = staging_bucket_util.GetDefaultStagingBucket( safe_project_id) if gcs_source_staging_dir is None: default_gcs_source = True gcs_source_staging_dir = _SKAFFOLD_CONFIG_PATH.format( default_bucket_name) if not gcs_source_staging_dir.startswith('gs://'): raise c_exceptions.InvalidArgumentException('--gcs-source-staging-dir', 'must be a GCS bucket') if gcs_render_dir: if not gcs_render_dir.startswith('gs://'): raise c_exceptions.InvalidArgumentException( '--gcs-render-dir', 'must be a GCS bucket') # Leave this field unset as default. The server will create a new bucket. release_config.manifestBucket = gcs_render_dir gcs_client = storage_api.StorageClient() suffix = '.tgz' if source.startswith('gs://') or os.path.isfile(source): _, suffix = os.path.splitext(source) # Next, stage the source to Cloud Storage. staged_object = '{stamp}-{uuid}{suffix}'.format( stamp=times.GetTimeStampFromDateTime(times.Now()), uuid=uuid.uuid4().hex, suffix=suffix, ) gcs_source_staging_dir = resources.REGISTRY.Parse( gcs_source_staging_dir, collection='storage.objects') try: gcs_client.CreateBucketIfNotExists(gcs_source_staging_dir.bucket, check_ownership=default_gcs_source) 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-source-staging-dir', 'A bucket with name {} already exists and is owned by ' 'another project. Specify a bucket using ' '--gcs-source-staging-dir.'.format(default_bucket_name)) if gcs_source_staging_dir.object: staged_object = gcs_source_staging_dir.object + '/' + staged_object gcs_source_staging = resources.REGISTRY.Create( collection='storage.objects', bucket=gcs_source_staging_dir.bucket, object=staged_object) if source.startswith('gs://'): gcs_source = resources.REGISTRY.Parse(source, collection='storage.objects') staged_source_obj = gcs_client.Rewrite(gcs_source, gcs_source_staging) release_config.skaffoldConfigUri = 'gs://{bucket}/{object}'.format( bucket=staged_source_obj.bucket, object=staged_source_obj.name) else: if not os.path.exists(source): raise c_exceptions.BadFileException( 'could not find source [{src}]'.format(src=source)) if os.path.isdir(source): source_snapshot = snapshot.Snapshot(source, ignore_file=ignore_file) size_str = resource_transform.TransformSize( source_snapshot.uncompressed_size) if not hide_logs: log.status.Print( 'Creating temporary tarball archive of {num_files} file(s)' ' totalling {size} before compression.'.format( num_files=len(source_snapshot.files), size=size_str)) staged_source_obj = source_snapshot.CopyTarballToGCS( gcs_client, gcs_source_staging, ignore_file=ignore_file, hide_logs=hide_logs) release_config.skaffoldConfigUri = 'gs://{bucket}/{object}'.format( bucket=staged_source_obj.bucket, object=staged_source_obj.name) elif os.path.isfile(source): _, ext = os.path.splitext(source) if ext not in _ALLOWED_SOURCE_EXT: raise c_exceptions.BadFileException( 'local file [{src}] is none of ' + ', '.join(_ALLOWED_SOURCE_EXT)) if not hide_logs: log.status.Print('Uploading local file [{src}] to ' '[gs://{bucket}/{object}].'.format( src=source, bucket=gcs_source_staging.bucket, object=gcs_source_staging.object, )) staged_source_obj = gcs_client.CopyFileToGCS( source, gcs_source_staging) release_config.skaffoldConfigUri = 'gs://{bucket}/{object}'.format( bucket=staged_source_obj.bucket, object=staged_source_obj.name) return release_config
def GetAddress(self, messages, args, address, address_ref, resource_parser): network_tier = self.ConstructNetworkTier(messages, args) if args.ip_version or (address is None and address_ref.Collection() == 'compute.globalAddresses'): ip_version = messages.Address.IpVersionValueValuesEnum( args.ip_version or 'IPV4') else: # IP version is only specified in global and regional external Ipv6 # requests if an address is not specified to determine whether an ipv4 or # ipv6 address should be allocated. ip_version = None if args.subnet and args.network: raise exceptions.ConflictingArgumentsException( '--network', '--subnet') purpose = None if args.purpose and not args.network and not args.subnet: raise exceptions.MinimumArgumentException( ['--network', '--subnet'], ' if --purpose is specified') # TODO(b/36862747): get rid of args.subnet check if args.subnet: if address_ref.Collection() == 'compute.globalAddresses': raise exceptions.BadArgumentException( '--subnet', '[--subnet] may not be specified for global addresses.') if not args.subnet_region: args.subnet_region = address_ref.region subnetwork_url = flags.SubnetworkArgument().ResolveAsResource( args, resource_parser).SelfLink() if not (self._support_ipv6_reservation and args.endpoint_type): # External IPv6 reservation does not need purpose field. purpose = messages.Address.PurposeValueValuesEnum( args.purpose or 'GCE_ENDPOINT') self.CheckPurposeInSubnetwork(messages, purpose) else: subnetwork_url = None network_url = None if args.network: purpose = messages.Address.PurposeValueValuesEnum(args.purpose or 'VPC_PEERING') network_url = flags.NetworkArgument().ResolveAsResource( args, resource_parser).SelfLink() if purpose != messages.Address.PurposeValueValuesEnum.IPSEC_INTERCONNECT: if address_ref.Collection() == 'compute.addresses': raise exceptions.InvalidArgumentException( '--network', 'network may not be specified for regional addresses.') supported_purposes = { 'VPC_PEERING': messages.Address.PurposeValueValuesEnum.VPC_PEERING } if self._support_psc_google_apis: supported_purposes[ 'PRIVATE_SERVICE_CONNECT'] = messages.Address.PurposeValueValuesEnum.PRIVATE_SERVICE_CONNECT if purpose not in supported_purposes.values(): raise exceptions.InvalidArgumentException( '--purpose', 'must be {} for ' 'global internal addresses.'.format(' or '.join( supported_purposes.keys()))) ipv6_endpoint_type = None if self._support_ipv6_reservation and args.endpoint_type: ipv6_endpoint_type = messages.Address.Ipv6EndpointTypeValueValuesEnum( args.endpoint_type) address_type = None if self._support_ipv6_reservation and args.endpoint_type: address_type = messages.Address.AddressTypeValueValuesEnum.EXTERNAL elif subnetwork_url or network_url: address_type = messages.Address.AddressTypeValueValuesEnum.INTERNAL if args.prefix_length: if self._support_ipv6_reservation and address and not address_type: # This is address promotion. address_type = messages.Address.AddressTypeValueValuesEnum.EXTERNAL elif (purpose != messages.Address.PurposeValueValuesEnum.VPC_PEERING and purpose != messages.Address.PurposeValueValuesEnum.IPSEC_INTERCONNECT): raise exceptions.InvalidArgumentException( '--prefix-length', 'can only be used with ' '[--purpose VPC_PEERING/IPSEC_INTERCONNECT] or External IPv6 reservation. Found {e}' .format(e=purpose)) if not args.prefix_length: if purpose == messages.Address.PurposeValueValuesEnum.VPC_PEERING: raise exceptions.RequiredArgumentException( '--prefix-length', 'prefix length is needed for reserving VPC peering IP ranges.' ) if purpose == messages.Address.PurposeValueValuesEnum.IPSEC_INTERCONNECT: raise exceptions.RequiredArgumentException( '--prefix-length', 'prefix length is needed for reserving IP ranges' ' for IPsec-encrypted Cloud Interconnect.') if self._support_ipv6_reservation: return messages.Address(address=address, prefixLength=args.prefix_length, description=args.description, networkTier=network_tier, ipVersion=ip_version, name=address_ref.Name(), addressType=address_type, purpose=purpose, subnetwork=subnetwork_url, network=network_url, ipv6EndpointType=ipv6_endpoint_type) else: return messages.Address( address=address, prefixLength=args.prefix_length, description=args.description, networkTier=network_tier, ipVersion=ip_version, name=address_ref.Name(), addressType=( messages.Address.AddressTypeValueValuesEnum.INTERNAL if subnetwork_url or network_url else None), purpose=purpose, subnetwork=subnetwork_url, network=network_url)
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
def _ValidateFolder(flag_value): if not re.match('^[0-9]+$', flag_value): raise exceptions.InvalidArgumentException('folder', flag_value)
def _ConditionFileFormatException(filename): return gcloud_exceptions.InvalidArgumentException( 'condition-from-file', '{filename} must be a path to a YAML or JSON file containing the ' 'condition. `expression` and `title` are required keys. `description` is ' 'optional.'.format(filename=filename))
def _ParseSubnetFields(args, compute_holder): """Parses arguments related to subnets to use for NAT.""" subnetworks = list() messages = compute_holder.client.messages if args.subnet_option == nat_flags.SubnetOption.ALL_RANGES: ranges_to_nat = ( messages.RouterNat.SourceSubnetworkIpRangesToNatValueValuesEnum. ALL_SUBNETWORKS_ALL_IP_RANGES) elif args.subnet_option == nat_flags.SubnetOption.PRIMARY_RANGES: ranges_to_nat = ( messages.RouterNat.SourceSubnetworkIpRangesToNatValueValuesEnum. ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES) else: ranges_to_nat = ( messages.RouterNat.SourceSubnetworkIpRangesToNatValueValuesEnum. LIST_OF_SUBNETWORKS) # Mapping of subnet names to SubnetUsage. subnet_usages = dict() for custom_subnet_arg in args.nat_custom_subnet_ip_ranges: colons = custom_subnet_arg.count(':') secondary_range = None if colons > 1: raise calliope_exceptions.InvalidArgumentException( '--nat-custom-subnet-ip-ranges', ('Each specified subnet must be of the form SUBNETWORK ' 'or SUBNETWORK:RANGE_NAME')) elif colons == 1: subnet_name, secondary_range = custom_subnet_arg.split(':') else: subnet_name = custom_subnet_arg if subnet_name not in subnet_usages: subnet_usages[subnet_name] = SubnetUsage() if secondary_range is not None: subnet_usages[subnet_name].secondary_ranges.append( secondary_range) else: subnet_usages[subnet_name].using_primary = True for subnet_name in subnet_usages: subnet_ref = subnet_flags.SubnetworkResolver().ResolveResources( [subnet_name], compute_scope.ScopeEnum.REGION, args.region, compute_holder.resources, scope_lister=compute_flags.GetDefaultScopeLister( compute_holder.client)) subnet_usage = subnet_usages[subnet_name] options = [] if subnet_usage.using_primary: options.append(messages.RouterNatSubnetworkToNat. SourceIpRangesToNatValueListEntryValuesEnum. PRIMARY_IP_RANGE) if subnet_usage.secondary_ranges: options.append(messages.RouterNatSubnetworkToNat. SourceIpRangesToNatValueListEntryValuesEnum. LIST_OF_SECONDARY_IP_RANGES) subnetworks.append({ 'name': six.text_type(subnet_ref[0]), 'sourceIpRangesToNat': options, 'secondaryIpRangeNames': subnet_usage.secondary_ranges }) # Sorted for test stability. return (ranges_to_nat, sorted(subnetworks, key=lambda subnet: subnet['name']))
def ValidateMigStatefulFlagsForInstanceConfigs(args, for_update=False, need_disk_source=False): """Validates the values of stateful flags for instance configs.""" if for_update: stateful_disks = args.update_stateful_disk flag_name = '--update-stateful-disk' else: stateful_disks = args.stateful_disk flag_name = '--stateful-disk' device_names = set() for stateful_disk in stateful_disks or []: if not stateful_disk.get('device-name'): raise exceptions.InvalidArgumentException( parameter_name=flag_name, message='[device-name] is required') if stateful_disk.get('device-name') in device_names: raise exceptions.InvalidArgumentException( parameter_name=flag_name, message='[device-name] `{0}` is not unique in the collection'. format(stateful_disk.get('device-name'))) device_names.add(stateful_disk.get('device-name')) mode_value = stateful_disk.get('mode') if mode_value and mode_value not in ('rw', 'ro'): raise exceptions.InvalidArgumentException( parameter_name=flag_name, message='Value for [mode] must be [rw] or [ro], not [{0}]'. format(mode_value)) if need_disk_source and not stateful_disk.get('source'): raise exceptions.InvalidArgumentException( parameter_name=flag_name, message='[source] is required for all stateful disks') if mode_value and not stateful_disk.get('source'): raise exceptions.InvalidArgumentException( parameter_name=flag_name, message= '[mode] can be set then and only then when [source] is given') if for_update: remove_stateful_disks_set = set(args.remove_stateful_disks or []) for stateful_disk_to_update in args.update_stateful_disk or []: if stateful_disk_to_update.get( 'device-name') in remove_stateful_disks_set: raise exceptions.InvalidArgumentException( parameter_name=flag_name, message=( 'the same [device-name] `{0}` cannot be updated and' ' removed in one command call'.format( stateful_disk_to_update.get('device-name')))) remove_stateful_metadata_set = set(args.remove_stateful_metadata or []) update_stateful_metadata_set = set( args.update_stateful_metadata.keys()) keys_intersection = remove_stateful_metadata_set.intersection( update_stateful_metadata_set) if keys_intersection: raise exceptions.InvalidArgumentException( parameter_name=flag_name, message=('the same metadata key(s) `{0}` cannot be updated and' ' removed in one command call'.format( ', '.join(keys_intersection))))
def _CreateRegionalRequests(self, client, resources, args, forwarding_rule_ref): """Create a regionally scoped request.""" target_ref, region_ref = utils.GetRegionalTarget( client, resources, args, forwarding_rule_ref, include_l7_internal_load_balancing=self. _support_l7_internal_load_balancing) if not args.region and region_ref: args.region = region_ref protocol = self.ConstructProtocol(client.messages, args) address = self._ResolveAddress( resources, args, compute_flags.compute_scope.ScopeEnum.REGION, forwarding_rule_ref) forwarding_rule = client.messages.ForwardingRule( description=args.description, name=forwarding_rule_ref.Name(), IPAddress=address, IPProtocol=protocol, networkTier=_ConstructNetworkTier(client.messages, args), loadBalancingScheme=_GetLoadBalancingScheme(args, client.messages)) ports_all_specified, range_list = _ExtractPortsAndAll(args.ports) if (target_ref.Collection() == 'compute.regionBackendServices') or ( target_ref.Collection() == 'compute.targetInstances' and args.load_balancing_scheme == 'INTERNAL'): forwarding_rule.portRange = (six.text_type(args.port_range) if args.port_range else None) if target_ref.Collection() == 'compute.regionBackendServices': forwarding_rule.backendService = target_ref.SelfLink() else: forwarding_rule.target = target_ref.SelfLink() if ports_all_specified: forwarding_rule.allPorts = True if range_list: forwarding_rule.portRange = None forwarding_rule.ports = [ six.text_type(p) for p in _GetPortList(range_list) ] if args.subnet is not None: if not args.subnet_region: args.subnet_region = forwarding_rule_ref.region forwarding_rule.subnetwork = flags.SUBNET_ARG.ResolveAsResource( args, resources).SelfLink() if args.network is not None: forwarding_rule.network = flags.NetworkArg( self._support_l7_internal_load_balancing ).ResolveAsResource(args, resources).SelfLink() elif ( (target_ref.Collection() == 'compute.regionTargetHttpProxies' or target_ref.Collection() == 'compute.regionTargetHttpsProxies') and args.load_balancing_scheme == 'INTERNAL'): forwarding_rule.ports = [ six.text_type(p) for p in _GetPortList(range_list) ] if args.subnet is not None: if not args.subnet_region: args.subnet_region = forwarding_rule_ref.region forwarding_rule.subnetwork = flags.SUBNET_ARG.ResolveAsResource( args, resources).SelfLink() if args.network is not None: forwarding_rule.network = flags.NetworkArg( self._support_l7_internal_load_balancing ).ResolveAsResource(args, resources).SelfLink() forwarding_rule.target = target_ref.SelfLink() elif args.load_balancing_scheme == 'INTERNAL': raise exceptions.InvalidArgumentException( '--load-balancing-scheme', 'Only target instances and backend services should be specified as ' 'a target for internal load balancing.') elif args.load_balancing_scheme == 'INTERNAL_MANAGED': forwarding_rule.portRange = (_ResolvePortRange( args.port_range, range_list)) if args.subnet is not None: if not args.subnet_region: args.subnet_region = forwarding_rule_ref.region forwarding_rule.subnetwork = flags.SUBNET_ARG.ResolveAsResource( args, resources).SelfLink() if args.network is not None: forwarding_rule.network = flags.NetworkArg( self._support_l7_internal_load_balancing ).ResolveAsResource(args, resources).SelfLink() forwarding_rule.target = target_ref.SelfLink() else: forwarding_rule.portRange = (_ResolvePortRange( args.port_range, range_list)) forwarding_rule.target = target_ref.SelfLink() if hasattr(args, 'service_label'): forwarding_rule.serviceLabel = args.service_label if self._support_global_access and args.IsSpecified( 'allow_global_access'): forwarding_rule.allowGlobalAccess = args.allow_global_access if hasattr(args, 'is_mirroring_collector'): forwarding_rule.isMirroringCollector = args.is_mirroring_collector request = client.messages.ComputeForwardingRulesInsertRequest( forwardingRule=forwarding_rule, project=forwarding_rule_ref.project, region=forwarding_rule_ref.region) return [(client.apitools_client.forwardingRules, 'Insert', request)]
def ValidateBalancingModeArgs(messages, add_or_update_backend_args, current_balancing_mode=None, supports_neg=False): """Check whether the setup of the backend LB related fields is valid. Args: messages: API messages class, determined by release track. add_or_update_backend_args: argparse Namespace. The arguments provided to add-backend or update-backend commands. current_balancing_mode: BalancingModeValueValuesEnum. The balancing mode of the existing backend, in case of update-backend command. Must be None otherwise. supports_neg: bool, if the args contains network endpoint group related args. """ balancing_mode_enum = messages.Backend.BalancingModeValueValuesEnum balancing_mode = current_balancing_mode if add_or_update_backend_args.balancing_mode: balancing_mode = balancing_mode_enum( add_or_update_backend_args.balancing_mode) if supports_neg: # Validate flags are specified with the correct group. _ValidateGroupMatchesArgs(add_or_update_backend_args) invalid_arg = None if balancing_mode == balancing_mode_enum.RATE: if add_or_update_backend_args.max_utilization is not None: invalid_arg = '--max-utilization' elif add_or_update_backend_args.max_connections is not None: invalid_arg = '--max-connections' elif add_or_update_backend_args.max_connections_per_instance is not None: invalid_arg = '--max-connections-per-instance' elif (supports_neg and add_or_update_backend_args.max_connections_per_endpoint is not None): invalid_arg = '--max-connections-per-endpoint' if invalid_arg is not None: raise exceptions.InvalidArgumentException( invalid_arg, 'cannot be set with RATE balancing mode') elif balancing_mode == balancing_mode_enum.CONNECTION: if add_or_update_backend_args.max_utilization is not None: invalid_arg = '--max-utilization' elif add_or_update_backend_args.max_rate is not None: invalid_arg = '--max-rate' elif add_or_update_backend_args.max_rate_per_instance is not None: invalid_arg = '--max-rate-per-instance' elif (supports_neg and add_or_update_backend_args.max_rate_per_endpoint is not None): invalid_arg = '--max-rate-per-endpoint' if invalid_arg is not None: raise exceptions.InvalidArgumentException( invalid_arg, 'cannot be set with CONNECTION balancing mode') elif balancing_mode == balancing_mode_enum.UTILIZATION: if (supports_neg and add_or_update_backend_args.network_endpoint_group is not None): raise exceptions.InvalidArgumentException( '--network-endpoint-group', 'cannot be set with UTILIZATION balancing mode')
def _Run(self, args, supports_kms_keys=False, supports_physical_block=False, support_shared_disk=False, support_vss_erase=False): compute_holder = base_classes.ComputeApiHolder(self.ReleaseTrack()) client = compute_holder.client self.show_unformated_message = not ( args.IsSpecified('image') or args.IsSpecified('image_family') or args.IsSpecified('source_snapshot')) disk_refs = self.ValidateAndParseDiskRefs(args, compute_holder) from_image = self.GetFromImage(args) size_gb = self.GetDiskSizeGb(args, from_image) self.WarnAboutScopeDeprecationsAndMaintenance(disk_refs, client) project_to_source_image = self.GetProjectToSourceImageDict( args, disk_refs, compute_holder, from_image) snapshot_uri = self.GetSnapshotUri(args, compute_holder) # Those features are only exposed in alpha/beta, it would be nice to have # code supporting them only in alpha and beta versions of the command. labels = self.GetLabels(args, client) allow_rsa_encrypted = self.ReleaseTrack() in [ base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA ] csek_keys = csek_utils.CsekKeyStore.FromArgs(args, allow_rsa_encrypted) for project in project_to_source_image: source_image_uri = project_to_source_image[project].uri project_to_source_image[project].keys = ( csek_utils.MaybeLookupKeyMessagesByUri( csek_keys, compute_holder.resources, [source_image_uri, snapshot_uri], client.apitools_client)) # end of alpha/beta features. guest_os_feature_messages = _ParseGuestOsFeaturesToMessages( args, client.messages) requests = [] for disk_ref in disk_refs: type_uri = self.GetDiskTypeUri(args, disk_ref, compute_holder) # Those features are only exposed in alpha/beta, it would be nice to have # code supporting them only in alpha and beta versions of the command. # TODO(b/65161039): Stop checking release path in the middle of GA code. kwargs = {} if csek_keys: disk_key_or_none = csek_keys.LookupKey( disk_ref, args.require_csek_key_create) disk_key_message_or_none = csek_utils.MaybeToMessage( disk_key_or_none, client.apitools_client) kwargs['diskEncryptionKey'] = disk_key_message_or_none kwargs['sourceImageEncryptionKey'] = ( project_to_source_image[disk_ref.project].keys[0]) kwargs['sourceSnapshotEncryptionKey'] = ( project_to_source_image[disk_ref.project].keys[1]) if labels: kwargs['labels'] = labels if supports_kms_keys: kwargs['diskEncryptionKey'] = kms_utils.MaybeGetKmsKey( args, client.messages, kwargs.get('diskEncryptionKey', None)) # end of alpha/beta features. if supports_physical_block and args.IsSpecified( 'physical_block_size'): physical_block_size_bytes = int(args.physical_block_size) else: physical_block_size_bytes = None resource_policies = getattr(args, 'resource_policies', None) if resource_policies: if disk_ref.Collection() == 'compute.regionDisks': disk_region = disk_ref.region else: disk_region = utils.ZoneNameToRegionName(disk_ref.zone) parsed_resource_policies = [] for policy in resource_policies: resource_policy_ref = resource_util.ParseResourcePolicy( compute_holder.resources, policy, project=disk_ref.project, region=disk_region) parsed_resource_policies.append( resource_policy_ref.SelfLink()) kwargs['resourcePolicies'] = parsed_resource_policies disk = client.messages.Disk( name=disk_ref.Name(), description=args.description, sizeGb=size_gb, sourceSnapshot=snapshot_uri, type=type_uri, physicalBlockSizeBytes=physical_block_size_bytes, **kwargs) if (support_shared_disk and disk_ref.Collection() == 'compute.regionDisks' and args.IsSpecified('multi_writer')): raise exceptions.InvalidArgumentException( '--multi-writer', ('--multi-writer can be used only with --zone flag')) if (support_shared_disk and disk_ref.Collection() == 'compute.disks' and args.IsSpecified('multi_writer')): disk.multiWriter = args.multi_writer if guest_os_feature_messages: disk.guestOsFeatures = guest_os_feature_messages if support_vss_erase and args.IsSpecified( 'erase_windows_vss_signature'): disk.eraseWindowsVssSignature = args.erase_windows_vss_signature disk.licenses = self.ParseLicenses(args) if disk_ref.Collection() == 'compute.disks': request = client.messages.ComputeDisksInsertRequest( disk=disk, project=disk_ref.project, sourceImage=project_to_source_image[disk_ref.project].uri, zone=disk_ref.zone) request = (client.apitools_client.disks, 'Insert', request) elif disk_ref.Collection() == 'compute.regionDisks': disk.replicaZones = self.GetReplicaZones( args, compute_holder, disk_ref) request = client.messages.ComputeRegionDisksInsertRequest( disk=disk, project=disk_ref.project, sourceImage=project_to_source_image[disk_ref.project].uri, region=disk_ref.region) request = (client.apitools_client.regionDisks, 'Insert', request) requests.append(request) return client.MakeRequests(requests)
def _ValidateArgs(self, args): if not args.clear_target_pools and args.target_pools is None: raise exceptions.InvalidArgumentException( '--target-pools', 'not passed but --clear-target-pools not present ' 'either.')