Esempio n. 1
0
def _CheckForRubyRuntime(path, appinfo):
    """Determines whether to treat this application as runtime:ruby.

  Honors the appinfo runtime setting; otherwise looks at the contents of the
  current directory and confirms with the user.

  Args:
    path: (str) Application path.
    appinfo: (apphosting.api.appinfo.AppInfoExternal or None) The parsed
      app.yaml file for the module if it exists.

  Returns:
    (bool) Whether this app should be treated as runtime:ruby.
  """
    if appinfo and appinfo.GetEffectiveRuntime() == 'ruby':
        return True

    log.info('Checking for Ruby.')

    gemfile_path = os.path.join(path, 'Gemfile')
    if not os.path.isfile(gemfile_path):
        return False

    got_ruby_message = 'This looks like a Ruby application.'
    if console_io.CanPrompt():
        return console_io.PromptContinue(
            message=got_ruby_message,
            prompt_string='Proceed to configure deployment for Ruby?')
    else:
        log.info(got_ruby_message)
        return True
def _PossiblyCreateApp(api_client, project, app_create):
    """Returns an app resource, and creates it if the stars are aligned.

  App creation happens only if the current project is app-less,
  app_create is True, we are running in interactive mode and the user
  explicitly wants to.

  Args:
    api_client: Admin API client.
    project: The GCP project/app id.
    app_create: True if interactive app creation should be allowed.

  Returns:
    An app object (never returns None).

  Raises:
    MissingApplicationError: If an app does not exist and cannot be created.
  """
    try:
        return api_client.GetApplication()
    except api_lib_exceptions.NotFoundError:
        # Invariant: GCP Project does exist but (singleton) GAE app is not yet
        # created. Offer to create one if the following conditions are true:
        # 1. `app_create` is True (currently `beta` only)
        # 2. We are currently running in interactive mode
        msg = output_helpers.CREATE_APP_PROMPT.format(project=project)
        if (app_create and console_io.CanPrompt()
                and console_io.PromptContinue(message=msg)):
            # Equivalent to running `gcloud beta app create`
            create_util.CreateAppInteractively(api_client, project)
            # App resource must be fetched again
            return api_client.GetApplication()
        raise exceptions.MissingApplicationError(project)
Esempio n. 3
0
def GetPlatform():
  """Returns the platform to run on.

  If not set by the user, this prompts the user to choose a platform and sets
  the property so future calls to this method do continue to prompt.

  Raises:
    ArgumentError: if not platform is specified and prompting is not allowed.
  """
  platform = properties.VALUES.run.platform.Get()
  if platform is None:
    if console_io.CanPrompt():
      platform_descs = [_PLATFORM_SHORT_DESCRIPTIONS[k] for k in _PLATFORMS]
      index = console_io.PromptChoice(
          platform_descs,
          message='Please choose a target platform:',
          cancel_option=True)
      platform = list(_PLATFORMS.keys())[index]
      # Set platform so we don't re-prompt on future calls to this method
      # and so it's available to anyone who wants to know the platform.
      properties.VALUES.run.platform.Set(platform)
      log.status.Print(
          'To specify the platform yourself, pass `--platform {0}`. '
          'Or, to make this the default target platform, run '
          '`gcloud config set run/platform {0}`.\n'.format(platform))
    else:
      raise ArgumentError(
          'No platform specified. Pass the `--platform` flag or set '
          'the [run/platform] property to specify a target platform.\n'
          'Available platforms:\n{}'.format(
              '\n'.join(
                  ['- {}: {}'.format(k, v) for k, v in _PLATFORMS.items()])))
  return platform
Esempio n. 4
0
def PromptForOpRegion():
    """Prompt for region from list of online prediction available regions.

  This method is referenced by the declaritive iam commands as a fallthrough
  for getting the region.

  Returns:
    The region specified by the user, str

  Raises:
    RequiredArgumentException: If can not prompt a console for region.
  """

    if console_io.CanPrompt():
        all_regions = list(constants.SUPPORTED_OP_REGIONS)
        idx = console_io.PromptChoice(all_regions,
                                      message='Please specify a region:\n',
                                      cancel_option=True)
        region = all_regions[idx]
        log.status.Print('To make this the default region, run '
                         '`gcloud config set ai/region {}`.\n'.format(region))
        return region
    raise exceptions.RequiredArgumentException(
        '--region', ('Cannot prompt a console for region. Region is required. '
                     'Please specify `--region` to select a region.'))
Esempio n. 5
0
def _PossiblyCreateApp(api_client, project):
    """Returns an app resource, and creates it if the stars are aligned.

  App creation happens only if the current project is app-less, we are running
  in interactive mode and the user explicitly wants to.

  Args:
    api_client: Admin API client.
    project: The GCP project/app id.

  Returns:
    An app object (never returns None).

  Raises:
    MissingApplicationError: If an app does not exist and cannot be created.
  """
    try:
        return api_client.GetApplication()
    except api_lib_exceptions.NotFoundError:
        # Invariant: GCP Project does exist but (singleton) GAE app is not yet
        # created.
        #
        # Check for interactive mode, since this action is irreversible and somewhat
        # surprising. CreateAppInteractively will provide a cancel option for
        # interactive users, and MissingApplicationException includes instructions
        # for non-interactive users to fix this.
        log.debug('No app found:', exc_info=True)
        if console_io.CanPrompt():

            # Equivalent to running `gcloud app create`
            create_util.CreateAppInteractively(api_client, project)
            # App resource must be fetched again
            return api_client.GetApplication()
        raise exceptions.MissingApplicationError(project)
Esempio n. 6
0
def GetRegion(args, prompt=False):
    """Prompt for region if not provided.

  Region is decided in the following order:
  - region argument;
  - local config file;
  - run/region gcloud config;
  - compute/region gcloud config;
  - prompt user.

  Args:
    args: Namespace, The args namespace.
    prompt: bool, whether to attempt to prompt.

  Returns:
    A str representing region.
  """
    if getattr(args, 'region', None):
        return args.region
    conf = GetLocalConfig(args)
    if conf and conf.region:
        return conf.region
    if properties.VALUES.run.region.IsExplicitlySet():
        return properties.VALUES.run.region.Get()
    if properties.VALUES.compute.region.IsExplicitlySet():
        return properties.VALUES.compute.region.Get()
    if prompt and console_io.CanPrompt():
        all_regions = global_methods.ListRegions()
        idx = console_io.PromptChoice(all_regions,
                                      message='Please specify a region:\n',
                                      cancel_option=True)
        region = all_regions[idx]
        log.status.Print('To make this the default region, run '
                         '`gcloud config set run/region {}`.\n'.format(region))
        return region
Esempio n. 7
0
def BindMissingRolesWithPrompt(service_account_ref, required_roles):
  """Binds any required project roles to the provided service account.

  If the service account has the owner role, no roles will be bound.

  This will promt the user should any required roles be missing.

  Args:
    service_account_ref: The service account to add roles to.
    required_roles: The roles which will be added if they are missing.
  """
  roles = _GetProjectRolesForServiceAccount(service_account_ref)
  if _OWNER_ROLE in roles:
    return

  # This prevents us from binding both roles to the same service account.
  # Events init requires admin, while broker create requires editor.
  if 'roles/pubsub.admin' in roles or 'roles/editor' in roles:
    roles.add('roles/pubsub.editor')

  missing_roles = set(required_roles) - roles
  if not missing_roles:
    return

  formatted_roles = '\n'.join(
      ['- {}'.format(r) for r in sorted(missing_roles)])
  if console_io.CanPrompt():
    message = (
        '\nThis will bind the following project roles to this service '
        'account:\n{}'.format(formatted_roles))
    console_io.PromptContinue(message=message, cancel_on_no=True)
  _BindProjectRolesForServiceAccount(service_account_ref, missing_roles)
  log.status.Print('Roles successfully bound.')
Esempio n. 8
0
  def Build(self, env=None):
    """Construct the actual command according to the given environment.

    Args:
      env: Environment, to construct the command for (or current if None).

    Raises:
      MissingCommandError: If keygen command was not found.

    Returns:
      [str], the command args (where the first arg is the command itself).
    """
    env = env or Environment.Current()
    if not env.keygen:
      raise MissingCommandError('Keygen command not found in the current '
                                'environment.')
    args = [env.keygen]
    if env.suite is Suite.OPENSSH:
      prompt_passphrase = self.allow_passphrase and console_io.CanPrompt()
      if not prompt_passphrase:
        args.extend(['-P', ''])  # Empty passphrase
      args.extend(['-t', 'rsa', '-f', self.identity_file])
    else:
      args.append(self.identity_file)

    return args
Esempio n. 9
0
def _GetEnvironment(args):
    """Prompt for environment if not provided.

  Environment is decided in the following order:
  - environment argument;
  - kuberun/environment gcloud config;
  - prompt user.

  Args:
    args: Environment, The args environment.

  Returns:
    A str representing the environment name.

  Raises:
    A ValueError if no environment is specified.
  """
    env = None
    if getattr(args, 'environment', None):
        env = args.environment
    elif properties.VALUES.kuberun.environment.IsExplicitlySet():
        env = properties.VALUES.kuberun.environment.Get()
    elif console_io.CanPrompt():
        env = console_io.PromptWithDefault('Environment name', default=None)
        log.status.Print(
            'To make this the default environment, run '
            '`gcloud config set kuberun/environment {}`.\n'.format(env))
    if env:
        return env
    raise ValueError('Please specify an ENVIRONMENT to use this command.')
Esempio n. 10
0
def GetRegion(args, prompt=False):
    """Prompt for region if not provided.

  Region is decided in the following order:
  - region argument;
  - run/region gcloud config;
  - compute/region gcloud config;
  - prompt user.

  Args:
    args: Namespace, The args namespace.
    prompt: bool, whether to attempt to prompt.

  Returns:
    A str representing region.
  """
    if getattr(args, 'region', None):
        return args.region
    if properties.VALUES.run.region.IsExplicitlySet():
        return properties.VALUES.run.region.Get()
    if properties.VALUES.compute.region.IsExplicitlySet():
        return properties.VALUES.compute.region.Get()
    if prompt and console_io.CanPrompt():
        client = global_methods.GetServerlessClientInstance()
        all_regions = global_methods.ListRegions(client)
        idx = console_io.PromptChoice(all_regions,
                                      message='Please specify a region:\n',
                                      cancel_option=True)
        region = all_regions[idx]
        # set the region on args, so we're not embarassed the next time we call
        # GetRegion
        args.region = region
        log.status.Print('To make this the default region, run '
                         '`gcloud config set run/region {}`.\n'.format(region))
        return region
Esempio n. 11
0
  def Run(self, args):
    scope = (properties.Scope.INSTALLATION if args.installation
             else properties.Scope.USER)

    prop = properties.FromString(args.property)
    if not prop:
      raise c_exc.InvalidArgumentException(
          'property', 'Must be in the form: [SECTION/]PROPERTY')

    scope_msg = ''
    if args.installation:
      scope_msg = 'installation '

    if prop == properties.VALUES.context_aware.use_client_certificate:
      config_validators.WarnIfActivateUseClientCertificate(args.value)

    showed_warning = False
    if prop == properties.VALUES.core.project:
      showed_warning = config_validators.WarnIfSettingProjectWithNoAccess(
          scope, args.value)
    if prop == properties.VALUES.compute.zone:
      showed_warning = config_validators.WarnIfSettingNonExistentRegionZone(
          args.value, zonal=True)
    if prop == properties.VALUES.compute.region:
      showed_warning = config_validators.WarnIfSettingNonExistentRegionZone(
          args.value, zonal=False)
    if showed_warning and not args.quiet and console_io.CanPrompt():
      if not console_io.PromptContinue(
          'Are you sure you wish to set {0}property [{1}] to {2}?'.format(
              scope_msg, prop, args.value)):
        return

    properties.PersistProperty(prop, args.value, scope=scope)
    log.status.Print('Updated {0}property [{1}].'.format(scope_msg, prop))
Esempio n. 12
0
    def Run(self, args):
        """Create a domain mapping."""
        # domains.cloudrun.com api group only supports v1alpha1 on clusters.
        conn_context = connection_context.GetConnectionContext(
            args,
            flags.Product.RUN,
            self.ReleaseTrack(),
            version_override=('v1alpha1' if platforms.GetPlatform() !=
                              platforms.PLATFORM_MANAGED else None))
        domain_mapping_ref = args.CONCEPTS.domain.Parse()
        changes = [
            config_changes.SetLaunchStageAnnotationChange(self.ReleaseTrack())
        ]

        # Check if the provided domain has already been verified
        # if mapping to a non-CRoGKE service
        if platforms.GetPlatform() == platforms.PLATFORM_MANAGED:
            client = global_methods.GetServerlessClientInstance()
            all_domains = global_methods.ListVerifiedDomains(client)
            # If not already verified, explain and error out
            if all(d.id not in domain_mapping_ref.Name() for d in all_domains):
                if not all_domains:
                    domains_text = 'You currently have no verified domains.'
                else:
                    domains = ['* {}'.format(d.id) for d in all_domains]
                    domains_text = ('Currently verified domains:\n{}'.format(
                        '\n'.join(domains)))
                raise exceptions.DomainMappingCreationError(
                    'The provided domain does not appear to be verified '
                    'for the current account so a domain mapping '
                    'cannot be created. Visit [{help}] for more information.'
                    '\n{domains}'.format(help=DOMAIN_MAPPINGS_HELP_DOCS_URL,
                                         domains=domains_text))

        with serverless_operations.Connect(conn_context) as client:
            try:
                mapping = client.CreateDomainMapping(domain_mapping_ref,
                                                     args.service, changes,
                                                     args.force_override)
            except exceptions.DomainMappingAlreadyExistsError as e:
                if console_io.CanPrompt() and console_io.PromptContinue(
                    ('This domain is already being used as a mapping elsewhere. '
                     'The existing mapping can be overriden by passing '
                     '`--force-override` or by continuing at the prompt below.'
                     ),
                        prompt_string='Override the existing mapping'):
                    deletion.Delete(domain_mapping_ref,
                                    client.GetDomainMapping,
                                    client.DeleteDomainMapping,
                                    async_=False)
                    mapping = client.CreateDomainMapping(
                        domain_mapping_ref, args.service, changes, True)
                else:
                    raise e

            for record in mapping.records:
                record.name = record.name or mapping.route_name
            return mapping.records
Esempio n. 13
0
    def _ResolveUnderspecifiedNames(self,
                                    underspecified_names,
                                    default_scope,
                                    scope_lister,
                                    project,
                                    api_resource_registry,
                                    with_project=True):
        """Attempt to resolve scope for unresolved names.

    If unresolved_names was generated with _GetRefsAndUnderspecifiedNames
    changing them will change corresponding elements of refs list.

    Args:
      underspecified_names: list of one-items lists containing str
      default_scope: default scope for the resources
      scope_lister: callback used to list potential scopes for the resources
      project: str, id of the project
      api_resource_registry: resources Registry
      with_project: indicates whether or not project is associated. It should be
        False for flexible resource APIs

    Raises:
      UnderSpecifiedResourceError: when resource scope can't be resolved.
    """
        if not underspecified_names:
            return

        names = [n[0] for n in underspecified_names]

        if not console_io.CanPrompt():
            raise UnderSpecifiedResourceError(names,
                                              [s.flag for s in self.scopes])

        resource_scope_enum, scope_value = scope_prompter.PromptForScope(
            self.resource_name, names, [s.scope_enum for s in self.scopes],
            default_scope.scope_enum if default_scope is not None else None,
            scope_lister)
        if resource_scope_enum is None:
            raise UnderSpecifiedResourceError(names,
                                              [s.flag for s in self.scopes])

        resource_scope = self.scopes[resource_scope_enum]
        if with_project:
            params = {
                'project': project,
            }
        else:
            params = {}

        if resource_scope.scope_enum != compute_scope.ScopeEnum.GLOBAL:
            params[resource_scope.scope_enum.param_name] = scope_value

        for name in underspecified_names:
            name[0] = api_resource_registry.Parse(
                name[0],
                params=params,
                collection=resource_scope.collection,
                enforce_collection=True)
Esempio n. 14
0
 def Run(self, args):
   project = properties.VALUES.core.project.Get(required=True)
   api_client = appengine_api_client.GetApiClient()
   if args.region:
     create_util.CreateApp(api_client, project, args.region)
   elif console_io.CanPrompt():
     create_util.CreateAppInteractively(api_client, project)
   else:
     raise create_util.UnspecifiedRegionError(
         'Prompts are disabled. Region must be specified either by the '
         '`--region` flag or interactively. Use `gcloud app regions '
         'list` to list available regions.')
   log.status.Print('Success! The app is now created. Please use '
                    '`gcloud app deploy` to deploy your first app.')
Esempio n. 15
0
 def _Call(self, parsed_args):
   if not console_io.CanPrompt():
     return None
   source_ref = None
   if hasattr(parsed_args, 'source') or hasattr(parsed_args, 'image'):
     source_ref = flags.GetSourceRef(parsed_args.source, parsed_args.image)
   message = 'Service name:'
   if source_ref:
     default_name = GenerateServiceName(source_ref)
     service_name = console_io.PromptWithDefault(
         message=message, default=default_name)
   else:
     service_name = console_io.PromptResponse(message=message)
   return service_name
Esempio n. 16
0
def _ChooseEntrypoint(default_entrypoint, appinfo):
    """Prompt the user for an entrypoint.

  Args:
    default_entrypoint: (str) Default entrypoint determined from the app.
    appinfo: (apphosting.api.appinfo.AppInfoExternal or None) The parsed
      app.yaml file for the module if it exists.

  Returns:
    (str) The actual entrypoint to use.

  Raises:
    RubyConfigError: Unable to get entrypoint from the user.
  """
    if console_io.CanPrompt():
        if default_entrypoint:
            prompt = (
                '\nPlease enter the command to run this Ruby app in '
                'production, or leave blank to accept the default:\n[{0}] ')
            entrypoint = console_io.PromptResponse(
                prompt.format(default_entrypoint))
        else:
            entrypoint = console_io.PromptResponse(
                '\nPlease enter the command to run this Ruby app in production: '
            )
        entrypoint = entrypoint.strip()
        if not entrypoint:
            if not default_entrypoint:
                raise RubyConfigError('Entrypoint command is required.')
            entrypoint = default_entrypoint
        if appinfo:
            # We've got an entrypoint and the user had an app.yaml that didn't
            # specify it.
            # TODO(mmuller): Offer to edit the user's app.yaml
            msg = (
                '\nTo avoid being asked for an entrypoint in the future, please '
                'add it to your app.yaml. e.g.\n  entrypoint: {0}'.format(
                    entrypoint))
            log.status.Print(msg)
        return entrypoint
    else:
        msg = (
            "This appears to be a Ruby app. You'll need to provide the full "
            'command to run the app in production, but gcloud is not running '
            'interactively and cannot ask for the entrypoint{0}. Please either '
            'run gcloud interactively, or create an app.yaml with '
            '"runtime:ruby" and an "entrypoint" field.'.format(
                ext_runtime_adapter.GetNonInteractiveErrorMessage()))
        raise RubyConfigError(msg)
Esempio n. 17
0
def EventTypeFromTypeString(source_crds, type_string, source=None):
  """Returns the matching event type object given a list of source crds.

  Return an EventType object given a type string and list of source CRDs.
  Optionally, can also pass a source string to further restrict matching event
  types across multiple sources.

  If multiple event type are found to match the given input, the user is
  prompted to pick one, or an error is raised if prompting is not available.

  Args:
    source_crds: list[SourceCustomResourceDefinition]
    type_string: str, matching an event type string
      (e.g. "google.cloud.pubsub.topic.v1.messagePublished").
    source: str, optional source to further specify which event type in the case
      of multiple sources having event types with the same type string.
  """
  possible_matches = []
  for crd in source_crds:
    # Only match the specified source, if provided
    if source is not None and source != crd.source_kind:
      continue
    for event_type in crd.event_types:
      if type_string == event_type.type:
        possible_matches.append(event_type)

  # No matches
  if not possible_matches:
    raise exceptions.EventTypeNotFound(
        "Unknown event type: {}. If you're trying to use a custom event type, "
        'add the "--custom-type" flag.'.format(type_string))

  # Single match
  if len(possible_matches) == 1:
    return possible_matches[0]

  # Multiple matches
  if not console_io.CanPrompt():
    raise exceptions.MultipleEventTypesFound(
        'Multiple matching event types found: {}.'.format(type_string))
  index = console_io.PromptChoice(
      [
          '{} from {}'.format(et.type, et.crd.source_kind)
          for et in possible_matches
      ],
      message=('Multiple matching event types found. '
               'Please choose an event type:'),
      cancel_option=True)
  return possible_matches[index]
def _prompt_and_add_valid_scheme(url):
    """Has user select a valid scheme from a list and returns new URL."""
    if not console_io.CanPrompt():
        raise errors.InvalidUrlError('Did you mean "posix://{}"'.format(
            url.object_name))
    scheme_index = console_io.PromptChoice(
        [scheme.value + '://' for scheme in VALID_TRANSFER_SCHEMES],
        cancel_option=True,
        message=('Storage Transfer does not support direct file URLs: {}\n'
                 'Did you mean to use "posix://"?\n'
                 'Run this command with "--help" for more info,\n'
                 'or select a valid scheme below.').format(url))

    new_scheme = VALID_TRANSFER_SCHEMES[scheme_index]
    return storage_url.switch_scheme(url, new_scheme)
Esempio n. 19
0
def GetOrCreateEventingServiceAccountWithPrompt():
  """Returns or creates a default eventing service account."""

  project_ref = projects_util.ParseProject(properties.VALUES.core.project.Get())
  account = _GetServiceAccount(DEFAULT_EVENTS_SERVICE_ACCOUNT)
  if account is None:
    if console_io.CanPrompt():
      message = '\nThis will create service account [{}]'.format(
          _ProjectAndAccountNameToEmail(
              project_ref.Name(), DEFAULT_EVENTS_SERVICE_ACCOUNT))
      console_io.PromptContinue(message=message, cancel_on_no=True)
    account = _CreateServiceAccount(
        DEFAULT_EVENTS_SERVICE_ACCOUNT, 'Cloud Run Events for Anthos',
        'Cloud Run Events on-cluster infrastructure')
  return account.email
Esempio n. 20
0
    def Run(self, args):
        """Executes when the user runs the delete command."""
        if serverless_flags.GetPlatform() == serverless_flags.PLATFORM_MANAGED:
            raise exceptions.UnsupportedArgumentError(
                'This command is only available with Cloud Run for Anthos.')

        if args.BROKER != _DEFAULT_BROKER_NAME:
            raise exceptions.UnsupportedArgumentError(
                'Only brokers named "default" may be created.')

        conn_context = connection_context.GetConnectionContext(
            args, product=serverless_flags.Product.EVENTS)

        service_account_ref = resources.REGISTRY.Parse(
            args.service_account,
            params={'projectsId': '-'},
            collection=core_iam_util.SERVICE_ACCOUNTS_COLLECTION)
        namespace_ref = args.CONCEPTS.namespace.Parse()
        secret_ref = resources.REGISTRY.Parse(
            _DATA_PLANE_SECRET_NAME,
            params={'namespacesId': namespace_ref.Name()},
            collection='run.api.v1.namespaces.secrets',
            api_version='v1')

        # Validate the service account has the necessary roles
        roles = iam_util.GetProjectRolesForServiceAccount(service_account_ref)
        if not (_OWNER_ROLE in roles
                or _DATA_PLANE_SECRET_MIN_REQUIRED_ROLES.issubset(roles)):
            missing_roles = _DATA_PLANE_SECRET_MIN_REQUIRED_ROLES - roles
            raise exceptions.ServiceAccountMissingRequiredPermissions(
                'Service account [{}] does not have necessary role(s): {}'.
                format(service_account_ref.Name(), ', '.join(missing_roles)))

        with eventflow_operations.Connect(conn_context) as client:
            if console_io.CanPrompt():
                console_io.PromptContinue(
                    message='This will create a new key for the provided '
                    'service account.',
                    cancel_on_no=True)
            _, key_ref = client.CreateOrReplaceServiceAccountSecret(
                secret_ref, service_account_ref)
            client.UpdateNamespaceWithLabels(namespace_ref, _INJECTION_LABELS)

        log.status.Print('Created broker [{}] in namespace [{}] with '
                         'key [{}] for service account [{}].'.format(
                             args.BROKER, namespace_ref.Name(), key_ref.Name(),
                             service_account_ref.Name()))
Esempio n. 21
0
def ValidateClearVpcConnector(service, args):
    """Validates that the VPC connector can be safely removed.

  Does nothing if 'clear_vpc_connector' is not present in args with value True.

  Args:
    service: A Cloud Run service object.
    args: Namespace object containing the specified command line arguments.

  Raises:
    exceptions.ConfigurationError: If the command cannot prompt and
      VPC egress is set to 'all' or 'all-traffic'.
    console_io.OperationCancelledError: If the user answers no to the
      confirmation prompt.
  """
    if (service is None
            or not flags.FlagIsExplicitlySet(args, 'clear_vpc_connector')
            or not args.clear_vpc_connector):
        return

    if flags.FlagIsExplicitlySet(args, 'vpc_egress'):
        egress = args.vpc_egress
    elif container_resource.EGRESS_SETTINGS_ANNOTATION in service.template_annotations:
        egress = service.template_annotations[
            container_resource.EGRESS_SETTINGS_ANNOTATION]
    else:
        # --vpc-egress flag not specified and egress settings not set on service.
        return

    if (egress != container_resource.EGRESS_SETTINGS_ALL
            and egress != container_resource.EGRESS_SETTINGS_ALL_TRAFFIC):
        return

    if console_io.CanPrompt():
        console_io.PromptContinue(
            message=
            'Removing the VPC connector from this service will clear the '
            'VPC egress setting and route outbound traffic to the public internet.',
            default=False,
            cancel_on_no=True)
    else:
        raise exceptions.ConfigurationError(
            'Cannot remove VPC connector with VPC egress set to "{}". Set'
            ' `--vpc-egress=private-ranges-only` or run this command '
            'interactively and provide confirmation to continue.'.format(
                egress))
Esempio n. 22
0
    def Run(self, args):
        """Executes when the user runs the create command."""
        if serverless_flags.GetPlatform() == serverless_flags.PLATFORM_MANAGED:
            raise exceptions.UnsupportedArgumentError(
                'This command is only available with Cloud Run for Anthos.')

        if args.BROKER != _DEFAULT_BROKER_NAME:
            raise exceptions.UnsupportedArgumentError(
                'Only brokers named "default" may be created.')

        conn_context = connection_context.GetConnectionContext(
            args, serverless_flags.Product.EVENTS, self.ReleaseTrack())

        if not args.IsSpecified('service_account'):
            sa_email = iam_util.GetOrCreateEventingServiceAccountWithPrompt()
        else:
            sa_email = args.service_account

        service_account_ref = resources.REGISTRY.Parse(
            sa_email,
            params={'projectsId': '-'},
            collection=core_iam_util.SERVICE_ACCOUNTS_COLLECTION)
        namespace_ref = args.CONCEPTS.namespace.Parse()
        secret_ref = resources.REGISTRY.Parse(
            _DATA_PLANE_SECRET_NAME,
            params={'namespacesId': namespace_ref.Name()},
            collection='run.api.v1.namespaces.secrets',
            api_version='v1')

        with eventflow_operations.Connect(conn_context) as client:
            iam_util.BindMissingRolesWithPrompt(
                service_account_ref, _DATA_PLANE_SECRET_MIN_REQUIRED_ROLES)
            if console_io.CanPrompt():
                console_io.PromptContinue(
                    message='This will create a new key for the provided '
                    'service account.',
                    cancel_on_no=True)
            _, key_ref = client.CreateOrReplaceServiceAccountSecret(
                secret_ref, service_account_ref)
            client.UpdateNamespaceWithLabels(namespace_ref, _INJECTION_LABELS)

        log.status.Print('Created broker [{}] in namespace [{}] with '
                         'key [{}] for service account [{}].'.format(
                             args.BROKER, namespace_ref.Name(), key_ref.Name(),
                             service_account_ref.Name()))
Esempio n. 23
0
def RemoveBindingFromIamPolicyWithCondition(policy,
                                            member,
                                            role,
                                            condition,
                                            all_conditions=False):
    """Given an IAM policy, remove bindings as specified by the args.

  An IAM binding is a pair of role and member with an optional condition.
  Check if the arguments passed define both the role and member attribute,
  search the policy for a binding that contains this role, member and condition,
  and remove it from the policy.

  Args:
    policy: IAM policy from which we want to remove bindings.
    member: The member to remove from the IAM policy.
    role: The role of the member should be removed from.
    condition: The condition of the binding to be removed.
    all_conditions: If true, all bindings with the specified member and role
    will be removed, regardless of the condition.

  Raises:
    IamPolicyBindingNotFound: If specified binding is not found.
    IamPolicyBindingIncompleteError: when user removes a binding without
      specifying --condition to a policy containing conditions in the
      non-interactive mode.
  """
    if not all_conditions and _PolicyContainsCondition(
            policy) and not _ConditionIsSpecified(condition):
        if not console_io.CanPrompt():
            message = (
                'Removing a binding without specifying a condition from a '
                'policy containing conditions is prohibited in non-interactive '
                'mode. Run the command again with `--condition=None` to remove a '
                'binding without condition or run command with `--all` to remove all '
                'bindings of the specified member and role.')
            raise IamPolicyBindingIncompleteError(message)
        condition = _PromptForConditionRemoveBindingFromIamPolicy(
            policy, member, role)

    if all_conditions or _IsAllConditions(condition):
        _RemoveBindingFromIamPolicyAllConditions(policy, member, role)
    else:
        condition = None if _IsNoneCondition(condition) else condition
        _RemoveBindingFromIamPolicyWithCondition(policy, member, role,
                                                 condition)
Esempio n. 24
0
def PromptForRegion():
  """Prompt for region from list of available regions.

  This method is referenced by the declaritive iam commands as a fallthrough
  for getting the region.

  Returns:
    The region specified by the user, str
  """
  if console_io.CanPrompt():
    client = global_methods.GetServerlessClientInstance()
    all_regions = global_methods.ListRegions(client)
    idx = console_io.PromptChoice(
        all_regions, message='Please specify a region:\n', cancel_option=True)
    region = all_regions[idx]
    log.status.Print('To make this the default region, run '
                     '`gcloud config set run/region {}`.\n'.format(region))
    return region
Esempio n. 25
0
def _PromptForRegion():
    """Prompt for region from list of available regions.

  Returns:
    The region specified by the user, str
  """

    if not console_io.CanPrompt():
        return None
    all_regions = constants.SUPPORTED_REGIONS_WITH_GLOBAL
    idx = console_io.PromptChoice(all_regions,
                                  message='Please specify a region:\n',
                                  cancel_option=True)
    region = all_regions[idx]
    log.status.Print(
        'To make this the default region, run '
        '`gcloud config set ai_platform/region {}`.\n'.format(region))
    return region
Esempio n. 26
0
def PrintOrBindMissingRolesWithPrompt(service_account_ref, recommended_roles,
                                      bind):
    """Binds any recommended project roles to the provided service account.

  If the service account has the owner role, no roles will be bound. If the bind
  argument is False, this function will only print out the missing recommended
  roles.

  This will prompt the user should any roles be missing before binding.

  Args:
    service_account_ref: The service account to add roles to.
    recommended_roles: The roles which will be added if they are missing.
    bind: A boolean indicating if the roles should be bound or not.
  """
    existing_roles = _GetProjectRolesForServiceAccount(service_account_ref)
    if _OWNER_ROLE in existing_roles:
        return

    # This prevents us from binding both roles to the same service account.
    # Events init requires admin, while broker create requires editor.
    if 'roles/pubsub.admin' in existing_roles or 'roles/editor' in existing_roles:
        existing_roles.add('roles/pubsub.editor')

    missing_roles = set(recommended_roles) - existing_roles
    if not missing_roles:
        return

    formatted_roles = '\n'.join(
        ['- {}'.format(role) for role in sorted(missing_roles)])

    log.status.Print(
        'Service account [{}] is missing the following recommended roles:\n'
        '{}'.format(service_account_ref.Name(), formatted_roles))

    if bind and console_io.CanPrompt():
        bind = console_io.PromptContinue(
            prompt_string='\nWould you like to bind these roles?',
            cancel_on_no=False)
    if bind:
        _BindProjectRolesForServiceAccount(service_account_ref, missing_roles)
        log.status.Print('Roles successfully bound.')
    else:
        log.warning('Manual binding of above roles may be necessary.')
Esempio n. 27
0
def PromptForRegion():
    """Prompt for region from list of available regions.

  This method is referenced by the declaritive iam commands as a fallthrough
  for getting the region.

  Returns:
    The region specified by the user, str
  """

    if console_io.CanPrompt():
        all_regions = constants.SUPPORTED_REGION
        idx = console_io.PromptChoice(all_regions,
                                      message='Please specify a region:\n',
                                      cancel_option=True)
        region = all_regions[idx]
        log.status.Print('To make this the default region, run '
                         '`gcloud config set ai/region {}`.\n'.format(region))
        return region
def _PossiblyCreateApp(api_client, project):
    """Returns an app resource, and creates it if the stars are aligned.

  App creation happens only if the current project is app-less, we are running
  in interactive mode and the user explicitly wants to.

  Args:
    api_client: Admin API client.
    project: The GCP project/app id.

  Returns:
    An app object (never returns None).

  Raises:
    MissingApplicationError: If an app does not exist and cannot be created.
  """
    try:
        return api_client.GetApplication()
    except apitools_exceptions.HttpNotFoundError:
        # Invariant: GCP Project does exist but (singleton) GAE app is not yet
        # created.
        #
        # Check for interactive mode, since this action is irreversible and somewhat
        # surprising. CreateAppInteractively will provide a cancel option for
        # interactive users, and MissingApplicationException includes instructions
        # for non-interactive users to fix this.
        log.debug('No app found:', exc_info=True)
        if console_io.CanPrompt():

            # Equivalent to running `gcloud app create`
            create_util.CreateAppInteractively(api_client, project)
            # App resource must be fetched again
            return api_client.GetApplication()
        raise exceptions.MissingApplicationError(project)
    except apitools_exceptions.HttpForbiddenError:
        active_account = properties.VALUES.core.account.Get()
        # pylint: disable=protected-access
        raise core_api_exceptions.HttpException(
            ('Permissions error fetching application [{}]. Please '
             'make sure that you have permission to view applications on the '
             'project and that {} has the App Engine Deployer '
             '(roles/appengine.deployer) role.'.format(api_client._FormatApp(),
                                                       active_account)))
Esempio n. 29
0
def ParseMemberships(args):
  """Returns a list of memberships to which to apply the command, given the arguments.

  Args:
    args: object containing arguments passed as flags with the command

  Returns:
    memberships: A list of membership name strings
  """
  memberships = []
  all_memberships = base.ListMemberships()

  if not all_memberships:
    raise exceptions.Error('No Memberships available in the fleet.')

  if hasattr(args, 'membership') and args.membership:
    memberships.append(args.membership)
  elif args.memberships:
    memberships = args.memberships.split(',')
  else:
    if console_io.CanPrompt():
      index = console_io.PromptChoice(
          options=all_memberships,
          message='Please specify a Membership:\n',
          cancel_option=True)
      memberships.append(all_memberships[index])
    else:
      raise calliope_exceptions.RequiredArgumentException(
          '--membership',
          ('Cannot prompt a console for membership. Membership is required. '
           'Please specify `--memberships` to select at least one membership.'))

  if not memberships:
    raise exceptions.Error(
        'At least one membership is required for this command.')

  for membership in memberships:
    if membership not in all_memberships:
      raise exceptions.Error(
          'Membership {} does not exist in the fleet.'.format(membership))

  return memberships
Esempio n. 30
0
def AddBindingToIamPolicyWithCondition(binding_message_type,
                                       condition_message_type, policy, member,
                                       role, condition):
    """Given an IAM policy, add a new role/member binding with condition.

  An IAM binding is a pair of role and member with an optional condition.
  Check if the arguments passed define both the role and member attribute,
  create a binding out of their values, and append it to the policy.

  Args:
    binding_message_type: The protorpc.Message of the Binding to create.
    condition_message_type: the protorpc.Message of the Expr.
    policy: IAM policy to which we want to add the bindings.
    member: The member of the binding.
    role: The role the member should have.
    condition: The condition of the role/member binding.

  Raises:
    IamPolicyBindingIncompleteError: when user adds a binding without specifying
      --condition to a policy containing conditions in the non-interactive mode.
  """
    if _PolicyContainsCondition(
            policy) and not _ConditionIsSpecified(condition):
        if not console_io.CanPrompt():
            message = (
                'Adding a binding without specifying a condition to a '
                'policy containing conditions is prohibited in non-interactive '
                'mode. Run the command again with `--condition=None`')
            raise IamPolicyBindingIncompleteError(message)
        condition = _PromptForConditionAddBindingToIamPolicy(policy)
        ValidateConditionArgument(condition)
    if (not _PolicyContainsCondition(policy)
            and _ConditionIsSpecified(condition)
            and not _IsNoneCondition(condition)):
        log.warning(
            'Adding binding with condition to a policy without condition '
            'will change the behavior of add-iam-policy-binding and '
            'remove-iam-policy-binding commands.')
    condition = None if _IsNoneCondition(condition) else condition
    _AddBindingToIamPolicyWithCondition(binding_message_type,
                                        condition_message_type, policy, member,
                                        role, condition)