Beispiel #1
0
    def Run(self, args):
        api_client = appengine_api_client.GetApiClientForTrack(
            self.ReleaseTrack())
        all_instances = list(
            api_client.GetAllInstances(args.service,
                                       args.version,
                                       version_filter=lambda v: v.environment
                                       in [env.FLEX, env.MANAGED_VMS]))
        try:
            res = resources.REGISTRY.Parse(args.instance)
        except Exception:  # pylint:disable=broad-except
            # Either the commandline argument is an instance ID, or is empty.
            # If empty, use interactive selection to choose an instance.
            instance = instances_util.GetMatchingInstance(
                all_instances,
                service=args.service,
                version=args.version,
                instance=args.instance)
        else:
            instance = instances_util.GetMatchingInstance(
                all_instances,
                service=res.servicesId,
                version=res.versionsId,
                instance=res.instancesId)

        console_io.PromptContinue(
            'About to disable debug mode for instance [{0}].\n\n'
            'Any local changes will be LOST. New instance(s) may spawn depending '
            'on the app\'s scaling settings.'.format(instance),
            cancel_on_no=True)
        message = 'Disabling debug mode for instance [{0}]'.format(instance)

        res = resources.REGISTRY.Parse(
            instance.id,
            params={
                'appsId': properties.VALUES.core.project.GetOrFail,
                'servicesId': instance.service,
                'versionsId': instance.version,
            },
            collection='appengine.apps.services.versions.instances')
        with progress_tracker.ProgressTracker(message):
            api_client.DeleteInstance(res)
Beispiel #2
0
def _CreateApp(project_ref):
  """Walks the user through creating an AppEngine app."""

  project = properties.VALUES.core.project.GetOrFail()
  if console_io.PromptContinue(
      message=('There is no App Engine app in project [{}].'.format(project)),
      prompt_string=('Would you like to create one'),
      default=False,
      throw_if_unattended=True):
    try:
      app_engine_api_client = app_engine_api.GetApiClientForTrack(
          calliope_base.ReleaseTrack.GA)
      create_util.CreateAppInteractively(app_engine_api_client, project)
    except create_util.AppAlreadyExistsError:
      raise create_util.AppAlreadyExistsError(
          'App already exists in project [{}]. This may be due a race '
          'condition. Please try again.'.format(project))
    else:
      return _GetLocation(project_ref)
  return None
Beispiel #3
0
 def Run(self, args):
     project = properties.VALUES.core.project.Get(required=True)
     api_client = appengine_api_client.GetApiClientForTrack(
         self.ReleaseTrack())
     if args.region:
         create_util.CreateApp(api_client,
                               project,
                               args.region,
                               service_account=args.service_account)
     elif console_io.CanPrompt():
         create_util.CheckAppNotExists(api_client, project)
         create_util.CreateAppInteractively(
             api_client, project, service_account=args.service_account)
     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.')
Beispiel #4
0
    def Run(self, args):
        api_client = appengine_api_client.GetApiClientForTrack(
            self.ReleaseTrack())
        all_instances = list(
            api_client.GetAllInstances(args.service,
                                       args.version,
                                       version_filter=lambda v: util.
                                       Environment.IsFlexible(v.environment)))
        try:
            res = resources.REGISTRY.Parse(args.instance)
        except Exception:  # pylint:disable=broad-except
            # If parsing fails, use interactive selection or provided instance ID.
            instance = instances_util.GetMatchingInstance(
                all_instances,
                service=args.service,
                version=args.version,
                instance=args.instance)
        else:
            instance = instances_util.GetMatchingInstance(
                all_instances,
                service=res.servicesId,
                version=res.versionsId,
                instance=res.instancesId)

        console_io.PromptContinue(
            'About to enable debug mode for instance [{0}].'.format(instance),
            cancel_on_no=True)
        message = 'Enabling debug mode for instance [{0}]'.format(instance)
        res = resources.REGISTRY.Parse(
            instance.id,
            params={
                'appsId': properties.VALUES.core.project.GetOrFail,
                'versionsId': instance.version,
                'instancesId': instance.id,
                'servicesId': instance.service,
            },
            collection='appengine.apps.services.versions.instances')
        with progress_tracker.ProgressTracker(message):
            api_client.DebugInstance(res)
Beispiel #5
0
    def Run(self, args):
        # TODO(b/36052475): This fails with "module/version does not exist" even
        # when it exists if the scaling mode is set to auto.  It would be good
        # to improve that error message.
        api_client = appengine_api_client.GetApiClientForTrack(
            self.ReleaseTrack())
        services = api_client.ListServices()
        versions = version_util.GetMatchingVersions(
            api_client.ListVersions(services), args.versions, args.service)

        if not versions:
            log.warn('No matching versions found.')
            return

        fmt = 'list[title="Starting the following versions:"]'
        resource_printer.Print(versions, fmt, out=log.status)
        console_io.PromptContinue(cancel_on_no=True)

        errors = {}
        # Sort versions to make behavior deterministic enough for unit testing.
        for version in sorted(versions):
            try:
                with progress_tracker.ProgressTracker(
                        'Starting [{0}]'.format(version)):
                    api_client.StartVersion(version.service, version.id)
            except (calliope_exceptions.HttpException,
                    operations_util.OperationError,
                    operations_util.OperationTimeoutError) as err:
                errors[version] = str(err)
        if errors:
            printable_errors = {}
            for version, error_msg in errors.items():
                short_name = '[{0}/{1}]'.format(version.service, version.id)
                printable_errors[short_name] = '{0}: {1}'.format(
                    short_name, error_msg)
            raise VersionsStartError(
                'Issues starting version(s): {0}\n\n'.format(', '.join(
                    printable_errors.keys())) +
                '\n\n'.join(printable_errors.values()))
Beispiel #6
0
 def _CreateApp(self, project):
     """Walks the user through creating an AppEngine app."""
     if properties.VALUES.core.disable_prompts.Get():
         log.warning('Cannot create new App Engine app in quiet mode')
         return None
     if console_io.PromptContinue(message=(
             'There is no App Engine app in project [{}].'.format(project)),
                                  prompt_string=(
                                      'Would you like to create one'),
                                  throw_if_unattended=True):
         try:
             app_engine_api_client = app_engine_api.GetApiClientForTrack(
                 calliope_base.ReleaseTrack.GA)
             create_util.CreateAppInteractively(app_engine_api_client,
                                                project)
         except create_util.AppAlreadyExistsError:
             raise create_util.AppAlreadyExistsError(
                 'App already exists in project [{}]. This may be due a race '
                 'condition. Please try again.'.format(project))
         else:
             return self._GetLocation(project)
     return None
Beispiel #7
0
  def Run(self, args):
    api_client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
    services = api_client.ListServices()
    service_ids = [s.id for s in services]
    log.debug('All services: {0}'.format(service_ids))

    if args.service and args.service not in service_ids:
      raise ServiceNotFoundError(
          'Service [{0}] not found.'.format(args.service))

    # Filter the services list to make fewer ListVersions calls.
    if args.service:
      services = [s for s in services if s.id == args.service]

    versions = api_client.ListVersions(services)
    # Filter for service.
    if args.service:
      versions = [v for v in versions if v.service == args.service]

    # Filter for traffic.
    if args.hide_no_traffic:
      versions = [v for v in versions if v.traffic_split]
    return sorted(versions, key=str)
def AppEngineAppExists():
    """Returns whether an AppEngine app exists for the current project.

  Previously we were relying on the output of ListLocations for Cloud Tasks &
  Cloud Scheduler to determine if an AppEngine exists. Previous behaviour was
  to return only one location which would be the AppEngine app location and an
  empty list otherwise if no app existed. Now with AppEngine dependency removal,
  ListLocations will return an actual list of valid regions. If an AppEngine app
  does exist, that location will be returned indexed at 0 in the result list.
  Note: We also return False if the user does not have the necessary permissions
  to determine if the project has an AppEngine app or not.

  Returns:
    Boolean representing whether an app exists or not.
  """
    app_engine_api_client = app_engine_api.GetApiClientForTrack(
        calliope_base.ReleaseTrack.GA)
    try:
        # Should raise NotFoundError if no app exists.
        app_engine_api_client.GetApplication()
        found_app = True
    except Exception:  # pylint: disable=broad-except
        found_app = False
    return found_app
Beispiel #9
0
  def Run(self, args):
    api_client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
    # Why do this? It lets us know if we're missing services up front (fail
    # fast), and we get to control the error messages
    all_services = api_client.ListServices()

    services = service_util.GetMatchingServices(all_services, args.services)

    if args.version:
      console_io.PromptContinue(
          'Deleting version [{0}] of {1} [{2}].'.format(
              args.version, text.Pluralize(len(services), 'service'),
              ', '.join(moves.map(str, services))),
          cancel_on_no=True)
      versions = [version_util.Version(api_client.project, s.id, args.version)
                  for s in services]
      version_util.DeleteVersions(api_client, versions)
    else:
      console_io.PromptContinue(
          'Deleting {0} [{1}].'.format(
              text.Pluralize(len(services), 'service'),
              ', '.join(moves.map(str, services))),
          cancel_on_no=True)
      service_util.DeleteServices(api_client, services)
 def Run(self, args):
     api_client = appengine_api_client.GetApiClientForTrack(
         self.ReleaseTrack())
     return api_client.GetOperation(args.operation)
Beispiel #11
0
    def Run(self, args):
        client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
        if args.service:
            service = client.GetServiceResource(args.service)
            traffic_split = {}
            if service.split:
                for split in service.split.allocations.additionalProperties:
                    traffic_split[split.key] = split.value
            services = [
                service_util.Service(client.project, service.id, traffic_split)
            ]
        else:
            services = client.ListServices()
        all_versions = client.ListVersions(services)
        if args.version not in {v.id for v in all_versions}:
            if args.service:
                raise VersionsMigrateError(
                    'Version [{0}/{1}] does not exist.'.format(
                        args.service, args.version))
            else:
                raise VersionsMigrateError(
                    'Version [{0}] does not exist.'.format(args.version))
        service_names = {
            v.service
            for v in all_versions if v.id == args.version
        }

        def WillBeMigrated(v):
            return (v.service in service_names and v.traffic_split
                    and v.traffic_split > 0 and v.id != args.version)

        # All versions that will stop receiving traffic.
        versions_to_migrate = filter(WillBeMigrated, all_versions)

        for version in versions_to_migrate:
            short_name = '{0}/{1}'.format(version.service, version.id)
            promoted_name = '{0}/{1}'.format(version.service, args.version)
            log.status.Print('Migrating all traffic from version '
                             '[{0}] to [{1}]'.format(short_name,
                                                     promoted_name))

        console_io.PromptContinue(cancel_on_no=True)

        errors = {}
        for service in sorted(set([v.service for v in versions_to_migrate])):
            allocations = {args.version: 1.0}
            try:
                client.SetTrafficSplit(service,
                                       allocations,
                                       shard_by='ip',
                                       migrate=True)
            except (api_exceptions.HttpException,
                    operations_util.OperationError,
                    operations_util.OperationTimeoutError, util.RPCError) as e:
                errors[service] = str(e)

        if errors:
            error_string = ('Issues migrating all traffic of '
                            'service(s): [{0}]\n\n{1}'.format(
                                ', '.join(errors.keys()),
                                '\n\n'.join(errors.values())))
            raise VersionsMigrateError(error_string)
Beispiel #12
0
 def Run(self, args):
     api_client = appengine_api_client.GetApiClientForTrack(
         self.ReleaseTrack())
     return sorted(api_client.ListRegions())
Beispiel #13
0
 def Run(self, args):
     return Describe(
         appengine_api_client.GetApiClientForTrack(self.ReleaseTrack()))
 def Run(self, args):
   api_client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
   return api_client.GetServiceResource(args.service)
Beispiel #15
0
 def Run(self, args):
   api_client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
   return api_client.GetAllInstances(args.service, args.version)
Beispiel #16
0
 def Run(self, args):
   api_client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
   return api_client.GetVersionResource(service=args.service,
                                        version=args.version)
Beispiel #17
0
def create(args, product_name, enum_value):
  """Helper for implementing Firestore database create comamnds.

  Guides the user through the gcloud app creation process and then updates the
  database type to the requested type.

  Args:
    args: Arguments from gcloud
    product_name: The product name of the database trying to be created.
    enum_value: Enum value representing the product name in the API.

  Raises:
    AppEngineAppDoesNotExist: If no app has been created.
    AppEngineAppRegionDoesNotMatch: If app created but region doesn't match the
     --region flag.
    RegionNotSpecified: User didn't specify --region.
  """
  api_client = appengine_api_client.GetApiClientForTrack(base.ReleaseTrack.GA)

  app = None
  try:
    app = api_client.GetApplication()
  except apitools_exceptions.HttpNotFoundError:
    if args.region is None:
      raise AppEngineAppDoesNotExist(
          'You must first create a'
          ' Google App Engine app by running:\n'
          'gcloud app create\n'
          'The region you create the App Engine app in is '
          'the same region that the Firestore database will be created in. '
          'Once an App Engine region has been chosen it cannot be changed.')
    else:
      raise AppEngineAppDoesNotExist(
          'You must first create an'
          ' Google App Engine app in the corresponding region by running:\n'
          'gcloud app create --region={region}'.format(region=args.region))

  current_region = app.locationId

  if not args.region:
    raise RegionNotSpecified(
        'You must specify a region using the --region flag to use this '
        'command. The region needs to match the Google App Engine region: '
        '--region={app_region}'.format(app_region=current_region))

  if current_region != args.region:
    raise AppEngineAppRegionDoesNotMatch(
        'The app engine region is {app_region} which is not the same as '
        '{args_region}. Right now the Firestore region must match '
        'the App Engine region.\n'
        'Try running this command with --region={app_region}'.format(
            app_region=current_region, args_region=args.region))
  # Set the DB Type to the desired type (if needed)
  if app.databaseType != enum_value:
    api_client.UpdateDatabaseType(enum_value)
  else:
    log.status.Print(
        'Success! Confirmed selection of a {product_name} database for {project}'
        .format(
            product_name=product_name,
            project=properties.VALUES.core.project.Get(required=True)))
    return

  log.status.Print(
      'Success! Selected {product_name} database for {project}'.format(
          product_name=product_name,
          project=properties.VALUES.core.project.Get(required=True)))
Beispiel #18
0
 def Run(self, args):
   api_client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
   if args.pending:
     return api_client.ListOperations(op_filter='done:false')
   else:
     return api_client.ListOperations()
Beispiel #19
0
    def Run(self, args):
        client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())

        services = client.ListServices()

        # If a service is supplied, only list versions for that service
        if args.service:
            services = [s for s in services if s.id == args.service]

        all_versions = client.ListVersions(services)
        # Sort versions to make behavior deterministic enough for unit testing.
        versions = sorted(version_util.GetMatchingVersions(
            all_versions, args.versions, args.service),
                          key=str)

        services_to_delete = []
        for service in sorted(services):
            service_versions = len(
                [v for v in all_versions if v.service == service.id])
            versions_to_delete = len(
                [v for v in versions if v.service == service.id])
            if service_versions == versions_to_delete and service_versions > 0:
                if service.id == 'default':
                    raise VersionsDeleteError(
                        'The default service (module) may not be deleted, and must '
                        'comprise at least one version.')
                else:
                    services_to_delete.append(service)
                for version in copy.copy(versions):
                    if version.service == service.id:
                        versions.remove(version)

        for version in versions:
            if version.traffic_split:
                # TODO(b/32869800): collect info on all versions before raising.
                raise VersionsDeleteError(
                    'Version [{version}] is currently serving {allocation:.2f}% of '
                    'traffic for service [{service}].\n\n'
                    'Please move all traffic away via one of the following methods:\n'
                    ' - deploying a new version with the `--promote` argument\n'
                    ' - running `gcloud app services set-traffic`\n'
                    ' - running `gcloud app versions migrate`'.format(
                        version=version.id,
                        allocation=version.traffic_split * 100,
                        service=version.service))

        if services_to_delete:
            word = text.Pluralize(len(services_to_delete), 'service')
            log.warning(
                'Requested deletion of all existing versions for the following {0}:'
                .format(word))
            resource_printer.Print(services_to_delete, 'list', out=log.status)
            console_io.PromptContinue(prompt_string=(
                '\nYou cannot delete all versions of a service. Would you like to '
                'delete the entire {0} instead?').format(word),
                                      cancel_on_no=True)
            service_util.DeleteServices(client, services_to_delete)

        if versions:
            fmt = 'list[title="Deleting the following versions:"]'
            resource_printer.Print(versions, fmt, out=log.status)
            console_io.PromptContinue(cancel_on_no=True)
        else:
            if not services_to_delete:
                log.warning('No matching versions found.')

        version_util.DeleteVersions(client, versions)