Esempio n. 1
0
def GetConnectionContext(args,
                         product=flags.Product.RUN,
                         release_track=base.ReleaseTrack.GA,
                         version_override=None,
                         platform=None):
  """Gets the regional, kubeconfig, or GKE connection context.

  Args:
    args: Namespace, the args namespace.
    product: Which product is requesting connection context.
    release_track: Release track of the command being run.
    version_override: If specified, the given api version will be used no matter
      the other parameters.
    platform: 'gke', 'kubernetes', or 'managed'. If not specified, the value of
      the --platform flag will be used instead.

  Raises:
    ArgumentError if region or cluster is not specified.

  Returns:
    A GKE or regional ConnectionInfo object.
  """
  if platform is None:
    platform = platforms.GetPlatform()
  if platform == platforms.PLATFORM_KUBERNETES:
    kubeconfig = flags.GetKubeconfig(getattr(args, 'kubeconfig', None))
    api_name = _GetApiName(product, release_track, is_cluster=True)
    api_version = _GetApiVersion(
        product,
        release_track,
        is_cluster=True,
        version_override=version_override)
    return KubeconfigConnectionContext(kubeconfig, api_name, api_version,
                                       args.context)

  if platform == platforms.PLATFORM_GKE:
    cluster_ref = args.CONCEPTS.cluster.Parse()
    if not cluster_ref:
      raise serverless_exceptions.ArgumentError(
          'You must specify a cluster in a given location. '
          'Either use the `--cluster` and `--cluster-location` flags '
          'or set the run/cluster and run/cluster_location properties.')
    api_name = _GetApiName(product, release_track, is_cluster=True)
    api_version = _GetApiVersion(
        product,
        release_track,
        is_cluster=True,
        version_override=version_override)
    return GKEConnectionContext(cluster_ref, api_name, api_version)

  if platform == platforms.PLATFORM_MANAGED:
    region = flags.GetRegion(args, prompt=True)
    if not region:
      raise serverless_exceptions.ArgumentError(
          'You must specify a region. Either use the `--region` flag '
          'or set the run/region property.')
    api_name = _GetApiName(product, release_track)
    api_version = _GetApiVersion(
        product, release_track, version_override=version_override)
    return _RegionalConnectionContext(region, api_name, api_version)
    def _GetResourceConfig(self, res_type, parameters, add_service,
                           remove_service, res_config):
        """Returns a new resource config according to the parameters.

    Args:
      res_type: type of the resource.
      parameters: parameter dictionary from args.
      add_service: the service to attach to the integration.
      remove_service: the service to remove from the integration.
      res_config: previous resource config. If given, changes will be made based
        on it.

    Returns:
      A new resource config
    """
        if res_config is not None and res_type in res_config:
            config = dict(res_config[res_type])
        else:
            config = {}

        if res_type == 'router':
            if 'dns-zone' in parameters:
                config['dns-zone'] = parameters['dns-zone']
            if 'domain' in parameters:
                config['domain'] = parameters['domain']
            if remove_service:
                ref = 'service/{}'.format(remove_service)
                if 'default-route' in config and ref in config[
                        'default-route']['ref']:
                    raise exceptions.ArgumentError(
                        'Cannot remove service associated with the default path (/*)'
                    )

                config['routes'] = [
                    x for x in config.get('routes', []) if x['ref'] != ref
                ]
            if add_service:
                route = {'ref': 'service/{}'.format(add_service)}
                if 'paths' in parameters:
                    route['paths'] = parameters['paths']
                    if 'routes' not in config:
                        config['routes'] = []
                    config['routes'].append(route)
                else:
                    config['default-route'] = route
        elif res_type == 'redis':
            instance = config.setdefault('instance', {})
            if 'memory-size-gb' in parameters:
                instance['memory-size-gb'] = parameters['memory-size-gb']
            if 'tier' in parameters:
                instance['tier'] = parameters['tier']
            if 'version' in parameters:
                instance['version'] = parameters['version']

        else:
            raise exceptions.ArgumentError(
                'Unsupported integration type [{}]'.format(res_type))

        return {res_type: config}
Esempio n. 3
0
def RepoRegion(args, cluster_location=None):
    """Returns the region for the Artifact Registry repo.

   The intended behavior is platform-specific:
   * managed: Same region as the service (run/region or --region)
   * gke: Appropriate region based on cluster zone (cluster_location arg)
   * kubernetes: The run/region config value will be used or an exception
     raised when unset.

  Args:
    args: Namespace, the args namespace.
    cluster_location: The zone which a Cloud Run for Anthos cluster resides.
      When specified, this will result in the region for this zone being
      returned.

  Returns:
    The appropriate region for the repository.
  """
    if cluster_location:
        return _RegionFromZone(cluster_location)

    region = flags.GetRegion(args, prompt=False)
    if region:
        return region

    raise exceptions.ArgumentError(
        'To deploy from source with this platform, you must set run/region via '
        '"gcloud config set run/region REGION".')
    def Run(self, args):
        self._CheckPlatform()

        conn_context = connection_context.GetConnectionContext(
            args, flags.Product.RUN, self.ReleaseTrack())
        service_ref = args.CONCEPTS.service.Parse()
        flags.ValidateResource(service_ref)
        with serverless_operations.Connect(conn_context) as client:
            serv = client.GetService(service_ref)
        if not serv:
            raise exceptions.ArgumentError('Cannot find service [{}]'.format(
                service_ref.servicesId))

        bind = '127.0.0.1:' + (args.port if args.port else '8080')
        host = self._GetUrl(serv, args.tag, service_ref.servicesId)

        command_executor = proxy.ProxyWrapper()
        log.Print('Proxying service [{}] in region [{}] locally...'.format(
            service_ref.servicesId, serv.region))
        log.Print('http://{} proxies to {}'.format(bind, host))

        if args.token:
            response = command_executor(host=host, token=args.token, bind=bind)
        else:
            # Keep restarting the proxy with fresh token before the token expires (1h)
            # until hitting a failure.
            while True:
                response = command_executor(host=host,
                                            token=_GetFreshIdToken(),
                                            bind=bind,
                                            duration='55m')
                if response.failed:
                    break

        return self._DefaultOperationResponseHandler(response)
    def _NewIntegrationName(self, integration_type, service, parameters,
                            app_dict):
        """Returns a new name for an integration.

    It makes sure the new name does not exist in the given app_dict.

    Args:
      integration_type:  str, name of the integration type.
      service: str, name of the service.
      parameters: parameter dictionary from args.
      app_dict: dict, the dictionary that represents the application.

    Returns:
      str, the new name.

    """
        if integration_type == 'custom-domain':
            domain = parameters['domain']
            if not domain:
                raise exceptions.ArgumentError(
                    'domain is required in "PARAMETERS" '
                    'for integration type "custom-domain"')
            return 'domain-{}'.format(domain.replace('.', '-'))

        name = '{}-{}'.format(integration_type, service)
        while name in app_dict[_CONFIG_KEY][_RESOURCES_KEY]:
            count = 1
            match = re.search(r'(.+)-(\d+)$', name)
            if match:
                name = match.group(1)
                count = int(match.group(2)) + 1
            name = '{}-{}'.format(name, count)
        return name
    def _CreateDeployment(self,
                          appname,
                          create_selector=None,
                          delete_selector=None):
        """Create a deployment, waits for operation to finish.

    Args:
      appname:  name of the application.
      create_selector: create selector for the deployment.
      delete_selector: delete selector for the deployment.
    """
        app_ref = self.GetAppRef(appname)
        deployment_name = self._GetDeploymentName(app_ref.Name())
        # TODO(b/217573594): remove this when oneof constraint is removed.
        if create_selector and delete_selector:
            raise exceptions.ArgumentError(
                'create_selector and delete_selector '
                'cannot be specified at the same time.')
        deployment = self.messages.Deployment(name=deployment_name,
                                              createSelector=create_selector,
                                              deleteSelector=delete_selector)
        deployment_ops = api_utils.CreateDeployment(self._client, app_ref,
                                                    deployment)

        dep_response = api_utils.WaitForDeploymentOperation(
            self._client, deployment_ops)
        self.CheckDeploymentState(dep_response)
 def _GetUrl(self, serv, tag, serv_id):
     if not serv.status:
         raise exceptions.ArgumentError(
             'Status of service [{}] is not ready'.format(serv_id))
     if tag:
         for t in serv.status.traffic:
             if t.tag == tag:
                 if not t.url:
                     raise exceptions.ArgumentError(
                         'URL for tag [{}] in service [{}] is not ready'.
                         format(tag, serv_id))
                 return t.url
         raise exceptions.ArgumentError(
             'Cannot find tag [{}] in service [{}].'.format(tag, serv_id))
     # If not tag provided, use the default service URL.
     if not serv.status.url:
         raise exceptions.ArgumentError(
             'URL for service [{}] is not ready'.format(serv_id))
     return serv.status.url
Esempio n. 8
0
 def Run(self, args):
     """Obtain details about a given route."""
     conn_context = connection_context.GetConnectionContext(
         args, flags.Product.RUN, self.ReleaseTrack())
     route_ref = args.CONCEPTS.route.Parse()
     with serverless_operations.Connect(conn_context) as client:
         conf = client.GetRoute(route_ref)
     if not conf:
         raise exceptions.ArgumentError('Cannot find route [{}]'.format(
             route_ref.routesId))
     return conf
    def _ValidateProvidedParams(self):
        """Checks that the user provided parameters exist in the mapping."""
        invalid_params = []
        for param in self.user_provided_params:
            if param not in self.integration['parameters']:
                invalid_params.append(param)

        if invalid_params:
            raise exceptions.ArgumentError(
                'The following parameters: {} are not allowed'.format(
                    self._RemoveEncoding(invalid_params)))
Esempio n. 10
0
def CheckValidIntegrationType(integration_type):
    """Checks if IntegrationType is supported.

  Args:
    integration_type: str, integration type to validate.
  Rasies: ArgumentError
  """
    if integration_type not in [
            integration['name'] for integration in _INTEGRATION_TYPES
    ]:
        raise exceptions.ArgumentError(
            'Integration of type {} is not supported'.format(integration_type))
Esempio n. 11
0
 def Run(self, args):
     """Obtain details about a given service."""
     conn_context = connection_context.GetConnectionContext(
         args, flags.Product.RUN, self.ReleaseTrack())
     service_ref = args.CONCEPTS.service.Parse()
     flags.ValidateResource(service_ref)
     with serverless_operations.Connect(conn_context) as client:
         serv = client.GetService(service_ref)
     if not serv:
         raise exceptions.ArgumentError('Cannot find service [{}]'.format(
             service_ref.servicesId))
     return serv
Esempio n. 12
0
    def Run(self, args):
        """Show details about a revision."""
        conn_context = connection_context.GetConnectionContext(
            args, flags.Product.RUN, self.ReleaseTrack())
        revision_ref = args.CONCEPTS.revision.Parse()

        with serverless_operations.Connect(conn_context) as client:
            wrapped_revision = client.GetRevision(revision_ref)

        if not wrapped_revision:
            raise exceptions.ArgumentError('Cannot find revision [{}]'.format(
                revision_ref.revisionsId))
        return wrapped_revision
 def _Call(self, parsed_args):
     if (platforms.GetPlatform() == platforms.PLATFORM_GKE
             or platforms.GetPlatform() == platforms.PLATFORM_KUBERNETES):
         return 'default'
     elif not (getattr(parsed_args, 'project', None)
               or properties.VALUES.core.project.Get()):
         # HACK: Compensate for how "namespace" is actually "project" in Cloud Run
         # by providing an error message explicitly early here.
         raise exceptions.ArgumentError(
             'The [project] resource is not properly specified. '
             'Please specify the argument [--project] on the command line or '
             'set the property [core/project].')
     return None
Esempio n. 14
0
 def _validateServiceNameAgainstIntegrations(self, client, integration_type,
                                             integration_name, service):
     """Checks if the service name matches an integration name."""
     error = exceptions.ArgumentError(
         'Service name cannot be the same as ' +
         'the provided integration name or an ' +
         'existing integration name')
     if service == integration_name:
         raise error
     integrations = client.ListIntegrations(integration_type, None)
     for integration in integrations:
         if integration['name'] == service:
             raise error
    def _CheckForInvalidUpdateParameters(self):
        """Raises an exception that lists the parameters that can't be changed."""
        invalid_params = []
        for param_name, param in self.integration['parameters'].items():
            update_allowed = param.get('update_allowed', True)
            if not update_allowed and param_name in self.user_provided_params:
                invalid_params.append(param_name)

        if invalid_params:
            raise exceptions.ArgumentError(
                ('The following parameters: {} cannot be changed once the ' +
                 'integration has been created').format(
                     self._RemoveEncoding(invalid_params)))
    def _ValidateRequiredParams(self):
        """Checks that required parameters are provided by the user."""
        missing_required_params = []
        for param_name, param in self.integration['parameters'].items():
            required = param.get('required', False)

            if required and param_name not in self.user_provided_params:
                missing_required_params.append(param_name)

        if missing_required_params:
            raise exceptions.ArgumentError(
                ('The following parameters: {} are required to create an ' +
                 'integration of type [{}]').format(
                     self._RemoveEncoding(missing_required_params),
                     self.integration['name']))
    def Run(self, args):
        """Show details about a job execution."""
        conn_context = connection_context.GetConnectionContext(
            args,
            flags.Product.RUN,
            self.ReleaseTrack(),
            version_override='v1')
        job_ref = args.CONCEPTS.job.Parse()

        with serverless_operations.Connect(conn_context) as client:
            job = client.GetJob(job_ref)

        if not job:
            raise exceptions.ArgumentError('Cannot find job [{}].'.format(
                job_ref.Name()))
        return job
    def Run(self, args):
        """Show details about a job task."""
        conn_context = connection_context.GetConnectionContext(
            args,
            flags.Product.RUN,
            self.ReleaseTrack(),
            version_override='v1')
        task_ref = args.CONCEPTS.task.Parse()

        with serverless_operations.Connect(conn_context) as client:
            task = client.GetTask(task_ref)

        if not task:
            raise exceptions.ArgumentError('Cannot find task [{}].'.format(
                task_ref.Name()))
        return task
Esempio n. 19
0
 def Run(self, args):
     """Describe 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()
     with serverless_operations.Connect(conn_context) as client:
         domain_mapping = client.GetDomainMapping(domain_mapping_ref)
         if not domain_mapping:
             raise exceptions.ArgumentError(
                 'Cannot find domain mapping for domain name [{}]'.format(
                     domain_mapping_ref.domainmappingsId))
         return domain_mapping
Esempio n. 20
0
def GetPlatform(prompt_if_unset=True):
  """Returns the platform to run on.

  If set by the user, returns whatever value they specified without any
  validation. If not set by the user, this may prompt the user to choose a
  platform and sets the property so future calls to this method do continue to
  prompt.

  Args:
    prompt_if_unset: bool, if True, will try to prompt for the platform

  Raises:
    ArgumentError: if no platform is specified, prompt_if_unset is True, and
      prompting is not allowed.
  """
  platform = properties.VALUES.run.platform.Get()
  if platform is None and prompt_if_unset:
    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 exceptions.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. 21
0
def _ParseResourcesParameters(args):
    """Parses --resources flag."""

    resources_flag = getattr(args, _RESOURCES_FLAG_NAME)

    if resources_flag is None:
        return {}

    result = []
    for api_version_kind_string in resources_flag:
        avk_selector = api_version_kind_string.split(':')
        if len(avk_selector) != 3 and len(avk_selector) != 2:
            raise run_exceptions.ArgumentError(
                'parameter flag resources expects Kind:'
                'ApiVersion:LabelName=value, notation.')
        elif len(avk_selector) == 2:
            result.append({
                'kind': avk_selector[0],
                'apiVersion': avk_selector[1],
            })
        elif len(avk_selector) == 3:
            match_labels_obj = {}
            for match_labels_string in avk_selector[2].split(','):
                key, value = match_labels_string.split('=')
                match_labels_obj[key] = value
            result.append({
                'kind': avk_selector[0],
                'apiVersion': avk_selector[1],
                'selector': {
                    'matchLabels': match_labels_obj,
                }
            })

    resources_params = {}
    if result:
        resources_params['resources'] = result
    return resources_params
    def CreateIntegration(self,
                          tracker,
                          integration_type,
                          parameters,
                          service,
                          name=None):
        """Create an integration.

    Args:
      tracker: StagedProgressTracker, to report on the progress of releasing.
      integration_type:  type of the integration.
      parameters: parameter dictionary from args.
      service: the service to attach to the new integration.
      name: name of the integration, if empty, a defalt one will be generated.

    Returns:
      The name of the integration.
    """
        app_dict = self._GetDefaultAppDict()
        resources_map = app_dict[_CONFIG_KEY][_RESOURCES_KEY]
        if not name:
            name = self._NewIntegrationName(integration_type, service,
                                            parameters, app_dict)

        resource_type = self._GetResourceType(integration_type)

        if name in resources_map:
            raise exceptions.ArgumentError(
                'Integration with name [{}] already exists.'.format(name))

        resource_config = self._GetResourceConfig(resource_type, parameters,
                                                  service, None, {})
        resources_map[name] = resource_config
        match_type_names = self._GetCreateSelectors(name, resource_type,
                                                    service)
        if service:
            self._EnsureServiceConfig(resources_map, service)
            self._AddServiceToIntegrationRef(name, resource_type,
                                             resources_map[service])

        self.CheckCloudRunServices([service])

        deploy_message = messages_util.GetDeployMessage(resource_type,
                                                        create=True)
        application = encoding.DictToMessage(app_dict,
                                             self.messages.Application)
        try:
            self.ApplyAppConfig(tracker=tracker,
                                appname=_DEFAULT_APP_NAME,
                                appconfig=application.config,
                                integration_name=name,
                                deploy_message=deploy_message,
                                match_type_names=match_type_names,
                                etag=application.etag)
        except exceptions.IntegrationsOperationError as err:
            tracker.AddWarning(
                'To retry the deployment, use update command ' +
                'gcloud alpha run integrations update {}'.format(name))
            raise err

        return name
Esempio n. 23
0
def _AllowedKeyString(key):
    if key in _DISALLOWED_SPECIAL_KEYS:
        raise run_exceptions.ArgumentError('Filter {} not allowed'.format(key))
    return key