Example #1
0
    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_)
Example #2
0
    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)]
Example #3
0
    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]
Example #4
0
def _ValidateProject(flag_value):
    if not re.match('^[a-z0-9-]+$', flag_value):
        raise exceptions.InvalidArgumentException('project', flag_value)
Example #5
0
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)
Example #7
0
    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
Example #8
0
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)
Example #10
0
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.')
Example #11
0
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)
Example #12
0
    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)
Example #13
0
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
Example #16
0
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.')
Example #17
0
    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
Example #18
0
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)
Example #20
0
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)
Example #22
0
    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
Example #23
0
def _ValidateFolder(flag_value):
    if not re.match('^[0-9]+$', flag_value):
        raise exceptions.InvalidArgumentException('folder', flag_value)
Example #24
0
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))
Example #25
0
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']))
Example #26
0
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))))
Example #27
0
    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')
Example #29
0
    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)
Example #30
0
 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.')