Example #1
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
Example #2
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
Example #3
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
Example #4
0
    def _UpdateOrCreateService(self,
                               service_ref,
                               config_changes,
                               with_code,
                               private_endpoint=None):
        """Apply config_changes to the service. Create it if necessary.

    Arguments:
      service_ref: Reference to the service to create or update
      config_changes: list of ConfigChanger to modify the service with
      with_code: bool, True if the config_changes contains code to deploy.
        We can't create the service if we're not deploying code.
      private_endpoint: bool, True if creating a new Service for
        Cloud Run on GKE that should only be addressable from within the
        cluster. False if it should be publicly addressable. None if
        its existing visibility should remain unchanged.

    Returns:
      The Service object we created or modified.
    """
        nonce = _Nonce()
        config_changes = [_NewRevisionForcingChange(nonce)] + config_changes
        messages = self._messages_module
        # GET the Service
        serv = self.GetService(service_ref)
        try:
            if serv:
                if not with_code:
                    # Avoid changing the running code by making the new revision by digest
                    self._EnsureImageDigest(serv, config_changes)

                if private_endpoint is None:
                    # Don't change the existing service visibility
                    pass
                elif private_endpoint:
                    serv.labels[
                        service.ENDPOINT_VISIBILITY] = service.CLUSTER_LOCAL
                else:
                    del serv.labels[service.ENDPOINT_VISIBILITY]

                # PUT the changed Service
                for config_change in config_changes:
                    config_change.AdjustConfiguration(serv.configuration,
                                                      serv.metadata)
                serv_name = service_ref.RelativeName()
                serv_update_req = (
                    messages.RunNamespacesServicesReplaceServiceRequest(
                        service=serv.Message(), name=serv_name))
                with metrics.RecordDuration(metric_names.UPDATE_SERVICE):
                    updated = self._client.namespaces_services.ReplaceService(
                        serv_update_req)
                return service.Service(updated, messages)

            else:
                if not with_code:
                    raise serverless_exceptions.ServiceNotFoundError(
                        'Service [{}] could not be found.'.format(
                            service_ref.servicesId))
                # POST a new Service
                new_serv = service.Service.New(self._client,
                                               service_ref.namespacesId,
                                               private_endpoint)
                new_serv.name = service_ref.servicesId
                parent = service_ref.Parent().RelativeName()
                for config_change in config_changes:
                    config_change.AdjustConfiguration(new_serv.configuration,
                                                      new_serv.metadata)
                serv_create_req = (messages.RunNamespacesServicesCreateRequest(
                    service=new_serv.Message(), parent=parent))
                with metrics.RecordDuration(metric_names.CREATE_SERVICE):
                    raw_service = self._client.namespaces_services.Create(
                        serv_create_req)
                return service.Service(raw_service, messages)
        except api_exceptions.HttpBadRequestError as e:
            error_payload = exceptions_util.HttpErrorPayload(e)
            if error_payload.field_violations:
                if (serverless_exceptions.BadImageError.IMAGE_ERROR_FIELD
                        in error_payload.field_violations):
                    exceptions.reraise(serverless_exceptions.BadImageError(e))
            exceptions.reraise(e)
        except api_exceptions.HttpNotFoundError as e:
            error_msg = 'Deployment endpoint was not found.'
            if not self._region:
                all_clusters = global_methods.ListClusters()
                clusters = [
                    '* {} in {}'.format(c.name, c.zone) for c in all_clusters
                ]
                error_msg += (
                    ' Perhaps the provided cluster was invalid or '
                    'does not have Cloud Run enabled. Pass the '
                    '`--cluster` and `--cluster-location` flags or set the '
                    '`run/cluster` and `run/cluster_location` properties to '
                    'a valid cluster and zone and retry.'
                    '\nAvailable clusters:\n{}'.format('\n'.join(clusters)))
            else:
                all_regions = global_methods.ListRegions(self._op_client)
                if self._region not in all_regions:
                    regions = ['* {}'.format(r) for r in all_regions]
                    error_msg += (
                        ' The provided region was invalid. '
                        'Pass the `--region` flag or set the '
                        '`run/region` property to a valid region and retry.'
                        '\nAvailable regions:\n{}'.format('\n'.join(regions)))
            raise serverless_exceptions.DeploymentFailedError(error_msg)
  def _UpdateOrCreateService(
      self, service_ref, config_changes, with_code, serv):
    """Apply config_changes to the service. Create it if necessary.

    Arguments:
      service_ref: Reference to the service to create or update
      config_changes: list of ConfigChanger to modify the service with
      with_code: bool, True if the config_changes contains code to deploy.
        We can't create the service if we're not deploying code.
      serv: service.Service, For update the Service to update and for
        create None.

    Returns:
      The Service object we created or modified.
    """
    messages = self.messages_module
    try:
      if serv:
        # PUT the changed Service
        for config_change in config_changes:
          serv = config_change.Adjust(serv)
        serv_name = service_ref.RelativeName()
        serv_update_req = (
            messages.RunNamespacesServicesReplaceServiceRequest(
                service=serv.Message(),
                name=serv_name))
        with metrics.RecordDuration(metric_names.UPDATE_SERVICE):
          updated = self._client.namespaces_services.ReplaceService(
              serv_update_req)
        return service.Service(updated, messages)

      else:
        if not with_code:
          raise serverless_exceptions.ServiceNotFoundError(
              'Service [{}] could not be found.'.format(service_ref.servicesId))
        # POST a new Service
        new_serv = service.Service.New(self._client, service_ref.namespacesId)
        new_serv.name = service_ref.servicesId
        parent = service_ref.Parent().RelativeName()
        for config_change in config_changes:
          new_serv = config_change.Adjust(new_serv)
        serv_create_req = (
            messages.RunNamespacesServicesCreateRequest(
                service=new_serv.Message(),
                parent=parent))
        with metrics.RecordDuration(metric_names.CREATE_SERVICE):
          raw_service = self._client.namespaces_services.Create(
              serv_create_req)
        return service.Service(raw_service, messages)
    except api_exceptions.HttpBadRequestError as e:
      exceptions.reraise(serverless_exceptions.HttpError(e))
    except api_exceptions.HttpNotFoundError as e:
      platform = properties.VALUES.run.platform.Get()
      error_msg = 'Deployment endpoint was not found.'
      if platform == 'gke':
        all_clusters = global_methods.ListClusters()
        clusters = ['* {} in {}'.format(c.name, c.zone) for c in all_clusters]
        error_msg += (' Perhaps the provided cluster was invalid or '
                      'does not have Cloud Run enabled. Pass the '
                      '`--cluster` and `--cluster-location` flags or set the '
                      '`run/cluster` and `run/cluster_location` properties to '
                      'a valid cluster and zone and retry.'
                      '\nAvailable clusters:\n{}'.format('\n'.join(clusters)))
      elif platform == 'managed':
        all_regions = global_methods.ListRegions(self._op_client)
        if self._region not in all_regions:
          regions = ['* {}'.format(r) for r in all_regions]
          error_msg += (' The provided region was invalid. '
                        'Pass the `--region` flag or set the '
                        '`run/region` property to a valid region and retry.'
                        '\nAvailable regions:\n{}'.format('\n'.join(regions)))
      elif platform == 'kubernetes':
        error_msg += (' Perhaps the provided cluster was invalid or '
                      'does not have Cloud Run enabled. Ensure in your '
                      'kubeconfig file that the cluster referenced in '
                      'the current context or the specified context '
                      'is a valid cluster and retry.')
      raise serverless_exceptions.DeploymentFailedError(error_msg)
    except api_exceptions.HttpError as e:
      platform = properties.VALUES.run.platform.Get()
      if platform == 'managed':
        exceptions.reraise(e)
      k8s_error = serverless_exceptions.KubernetesExceptionParser(e)
      causes = '\n\n'.join([c['message'] for c in k8s_error.causes])
      if not causes:
        causes = k8s_error.error
      raise serverless_exceptions.KubernetesError('Error{}:\n{}\n'.format(
          's' if len(k8s_error.causes) > 1 else '', causes))
    def _UpdateOrCreateService(self, service_ref, config_changes, with_code):
        """Apply config_changes to the service. Create it if necessary.

    Arguments:
      service_ref: Reference to the service to create or update
      config_changes: list of ConfigChanger to modify the service with
      with_code: bool, True if the config_changes contains code to deploy.
        We can't create the service if we're not deploying code.

    Returns:
      The Service object we created or modified.
    """
        nonce = _Nonce()
        config_changes = [
            _NewRevisionForcingChange(nonce),
            _SetClientNameAndVersion()
        ] + config_changes
        messages = self._messages_module
        # GET the Service
        serv = self.GetService(service_ref)
        try:
            if serv:
                if not with_code:
                    # Avoid changing the running code by making the new revision by digest
                    self._EnsureImageDigest(serv, config_changes)

                # Revision names must be unique across the namespace.
                # To prevent the revision name being unchanged from the last revision,
                # we reset the value so the default naming scheme will be used instead.
                serv.template.name = None

                # PUT the changed Service
                for config_change in config_changes:
                    config_change.Adjust(serv)
                serv_name = service_ref.RelativeName()
                serv_update_req = (
                    messages.RunNamespacesServicesReplaceServiceRequest(
                        service=serv.Message(), name=serv_name))
                with metrics.RecordDuration(metric_names.UPDATE_SERVICE):
                    updated = self._client.namespaces_services.ReplaceService(
                        serv_update_req)
                return service.Service(updated, messages)

            else:
                if not with_code:
                    raise serverless_exceptions.ServiceNotFoundError(
                        'Service [{}] could not be found.'.format(
                            service_ref.servicesId))
                # POST a new Service
                new_serv = service.Service.New(self._client,
                                               service_ref.namespacesId)
                new_serv.name = service_ref.servicesId
                parent = service_ref.Parent().RelativeName()
                for config_change in config_changes:
                    config_change.Adjust(new_serv)
                serv_create_req = (messages.RunNamespacesServicesCreateRequest(
                    service=new_serv.Message(), parent=parent))
                with metrics.RecordDuration(metric_names.CREATE_SERVICE):
                    raw_service = self._client.namespaces_services.Create(
                        serv_create_req)
                return service.Service(raw_service, messages)
        except api_exceptions.HttpBadRequestError as e:
            error_payload = exceptions_util.HttpErrorPayload(e)
            if error_payload.field_violations:
                if (serverless_exceptions.BadImageError.IMAGE_ERROR_FIELD
                        in error_payload.field_violations):
                    exceptions.reraise(serverless_exceptions.BadImageError(e))
                elif (serverless_exceptions.MalformedLabelError.
                      LABEL_ERROR_FIELD in error_payload.field_violations):
                    exceptions.reraise(
                        serverless_exceptions.MalformedLabelError(e))
            exceptions.reraise(e)
        except api_exceptions.HttpNotFoundError as e:
            platform = properties.VALUES.run.platform.Get()
            error_msg = 'Deployment endpoint was not found.'
            if platform == 'gke':
                all_clusters = global_methods.ListClusters()
                clusters = [
                    '* {} in {}'.format(c.name, c.zone) for c in all_clusters
                ]
                error_msg += (
                    ' Perhaps the provided cluster was invalid or '
                    'does not have Cloud Run enabled. Pass the '
                    '`--cluster` and `--cluster-location` flags or set the '
                    '`run/cluster` and `run/cluster_location` properties to '
                    'a valid cluster and zone and retry.'
                    '\nAvailable clusters:\n{}'.format('\n'.join(clusters)))
            elif platform == 'managed':
                all_regions = global_methods.ListRegions(self._op_client)
                if self._region not in all_regions:
                    regions = ['* {}'.format(r) for r in all_regions]
                    error_msg += (
                        ' The provided region was invalid. '
                        'Pass the `--region` flag or set the '
                        '`run/region` property to a valid region and retry.'
                        '\nAvailable regions:\n{}'.format('\n'.join(regions)))
            elif platform == 'kubernetes':
                error_msg += (
                    ' Perhaps the provided cluster was invalid or '
                    'does not have Cloud Run enabled. Ensure in your '
                    'kubeconfig file that the cluster referenced in '
                    'the current context or the specified context '
                    'is a valid cluster and retry.')
            raise serverless_exceptions.DeploymentFailedError(error_msg)
        except api_exceptions.HttpError as e:
            k8s_error = serverless_exceptions.KubernetesExceptionParser(e)
            raise serverless_exceptions.KubernetesError(
                'Error{}:\n{}\n'.format(
                    's' if len(k8s_error.causes) > 1 else '',
                    '\n\n'.join([c['message'] for c in k8s_error.causes])))