Пример #1
0
    def Run(self, args):
        api_client = appengine_api_client.GetApiClient()
        # 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(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(map(str, services))),
                                      cancel_on_no=True)
            service_util.DeleteServices(api_client, services)
  def _Update(self):
    """Update() helper method. Returns the number of changed help text files."""
    with file_utils.TemporaryDirectory() as temp_dir:
      walker_util.HelpTextGenerator(self._cli, temp_dir).Walk(hidden=True)
      diff = HelpTextAccumulator()
      DirDiff(self._help_dir, temp_dir, diff)
      if diff.invalid_file_count:
        # Bail out early on invalid content errors. These must be corrected
        # before proceeding.
        raise HelpTextUpdateError(
            '{0} help text {1} with invalid content must be fixed.'.format(
                diff.invalid_file_count,
                text.Pluralize(diff.invalid_file_count, 'file')))

      ops = {}
      for op in ['add', 'delete', 'edit']:
        ops[op] = []

      changes = 0
      for op, path in sorted(diff.GetChanges()):
        changes += 1
        if not self._test or changes < TEST_CHANGES_DISPLAY_MAX:
          log.status.Print('{0} {1}'.format(op, path))
        ops[op].append(path)

      if self._test:
        if changes:
          if changes >= TEST_CHANGES_DISPLAY_MAX:
            log.status.Print('...')
          log.status.Print('{0} help test {1} changed'.format(
              changes, text.Pluralize(changes, 'file')))
        return changes

      op = 'add'
      if ops[op]:
        for path in ops[op]:
          dest_path = os.path.join(self._help_dir, path)
          subdir = os.path.dirname(dest_path)
          if subdir:
            file_utils.MakeDir(subdir)
          temp_path = os.path.join(temp_dir, path)
          shutil.copyfile(temp_path, dest_path)

      op = 'edit'
      if ops[op]:
        for path in ops[op]:
          dest_path = os.path.join(self._help_dir, path)
          temp_path = os.path.join(temp_dir, path)
          shutil.copyfile(temp_path, dest_path)

      op = 'delete'
      if ops[op]:
        for path in ops[op]:
          dest_path = os.path.join(self._help_dir, path)
          try:
            os.remove(dest_path)
          except OSError:
            pass

      return changes
def ClusterUpgradeMessage(name,
                          cluster=None,
                          master=False,
                          node_pool_name=None,
                          new_version=None,
                          concurrent_node_count=None):
    """Get a message to print during gcloud container clusters upgrade.

  Args:
    name: str, the name of the cluster being upgraded.
    cluster: the cluster object.
    master: bool, if the upgrade applies to the master version.
    node_pool_name: str, the name of the node pool if the upgrade is for a
        specific node pool.
    new_version: str, the name of the new version, if given.
    concurrent_node_count: int, the number of nodes to upgrade concurrently.

  Raises:
    NodePoolError: if the node pool name can't be found in the cluster.

  Returns:
    str, a message about which nodes in the cluster will be upgraded and
        to which version.
  """
    current_version = None
    if new_version:
        new_version_message = 'version [{}]'.format(new_version)
    else:
        new_version_message = 'master version'
    if master:
        node_message = 'Master'
        if cluster:
            current_version = cluster.currentMasterVersion
    elif node_pool_name:
        node_message = 'All nodes in node pool [{}]'.format(node_pool_name)
        if cluster:
            current_version = _NodePoolFromCluster(cluster,
                                                   node_pool_name).version
    else:
        if cluster:
            node_message = 'All nodes ({} {})'.format(
                cluster.currentNodeCount,
                text.Pluralize(cluster.currentNodeCount, 'node'))
            current_version = cluster.currentNodeVersion
        else:
            node_message = 'All nodes'
    concurrent_message = ''
    if not master and concurrent_node_count:
        concurrent_message = '{} {} will be upgraded at a time. '.format(
            concurrent_node_count, text.Pluralize(concurrent_node_count,
                                                  'node'))
    if current_version:
        version_message = 'version [{}]'.format(current_version)
    else:
        version_message = 'its current version'
    return ('{} of cluster [{}] will be upgraded from {} to {}. {}'
            'This operation is long-running and will block other operations '
            'on the cluster (including delete) until it has run to completion.'
            .format(node_message, name, version_message, new_version_message,
                    concurrent_message))
def _NodeUpgradeMessage(name, cluster, node_pool_name, new_version,
                        concurrent_node_count):
    """Returns the prompt message during a node upgrade.

  Args:
    name: str, the name of the cluster being upgraded.
    cluster: the cluster object.
    node_pool_name: str, the name of the node pool if the upgrade is for a
        specific node pool.
    new_version: str, the name of the new version, if given.
    concurrent_node_count: int, the number of nodes to upgrade concurrently.

  Raises:
    NodePoolError: if the node pool name can't be found in the cluster.

  Returns:
    str, a message about which nodes in the cluster will be upgraded and
        to which version.
  """
    node_message = 'All nodes'
    current_version = None
    if node_pool_name:
        node_message = '{} in node pool [{}]'.format(node_message,
                                                     node_pool_name)
        if cluster:
            current_version = _NodePoolFromCluster(cluster,
                                                   node_pool_name).version
    elif cluster:
        node_message = '{} ({} {})'.format(
            node_message, cluster.currentNodeCount,
            text.Pluralize(cluster.currentNodeCount, 'node'))
        current_version = cluster.currentNodeVersion

    if current_version:
        version_message = 'version [{}]'.format(current_version)
    else:
        version_message = 'its current version'

    if not new_version and cluster:
        new_version = cluster.currentMasterVersion

    if new_version:
        new_version_message = 'version [{}]'.format(new_version)
    else:
        new_version_message = 'the master version'

    concurrent_message = ''
    if concurrent_node_count:
        concurrent_message = ' {} {} will be upgraded at a time.'.format(
            concurrent_node_count, text.Pluralize(concurrent_node_count,
                                                  'node'))

    return ('{} of cluster [{}] will be upgraded from {} to {}.{}'.format(
        node_message, name, version_message, new_version_message,
        concurrent_message))
Пример #5
0
    def Run(self, args):
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())

        project = properties.VALUES.core.project.Get(required=True)
        igm_refs = (instance_groups_flags.
                    MULTISCOPE_INSTANCE_GROUP_MANAGERS_ARG.ResolveAsResource)(
                        args,
                        holder.resources,
                        default_scope=compute_scope.ScopeEnum.ZONE,
                        scope_lister=flags.GetDefaultScopeLister(
                            holder.client, project))

        scope_name = self._GetCommonScopeNameForRefs(igm_refs)

        utils.PromptForDeletion(igm_refs,
                                scope_name=scope_name,
                                prompt_title=None)

        requests = list(
            self._CreateDeleteRequests(holder.client.apitools_client,
                                       igm_refs))

        resources = []
        # Delete autoscalers first.
        errors = []
        autoscaler_delete_requests = self._GenerateAutoscalerDeleteRequests(
            holder, project, mig_requests=requests)
        if autoscaler_delete_requests:
            with progress_tracker.ProgressTracker(
                    'Deleting ' + text.Pluralize(
                        len(autoscaler_delete_requests), 'autoscaler'),
                    autotick=False,
            ) as tracker:
                resources = holder.client.MakeRequests(
                    autoscaler_delete_requests,
                    errors,
                    progress_tracker=tracker)
            if errors:
                utils.RaiseToolException(errors)

        # Now delete instance group managers.
        errors = []
        with progress_tracker.ProgressTracker(
                'Deleting ' +
                text.Pluralize(len(requests), 'Managed Instance Group'),
                autotick=False,
        ) as tracker:
            resources += holder.client.MakeRequests(requests,
                                                    errors,
                                                    progress_tracker=tracker)
        if errors:
            utils.RaiseToolException(errors)
        return resources
Пример #6
0
def _PromptSuggestedScopeChoice(resource_name, underspecified_names,
                                scope_enum, suggested_resource):
    if scope_enum == compute_scope.ScopeEnum.GLOBAL:
        log.status.Print(
            'No scope specified. Using [{0}] for {1}: [{2}].'.format(
                scope_enum.flag_name,
                text.Pluralize(len(underspecified_names), resource_name),
                ', '.join(underspecified_names)))
    else:
        log.status.Print(
            'No {0} specified. Using {0} [{1}] for {2}: [{3}].'.format(
                scope_enum.flag_name, suggested_resource,
                text.Pluralize(len(underspecified_names), resource_name),
                ', '.join(underspecified_names)))
Пример #7
0
def DeleteVersions(api_client, versions):
    """Delete the given version of the given services."""
    errors = {}
    for version in versions:
        version_path = '{0}/{1}'.format(version.service, version.id)
        # TODO(b/37279801): Use the core gcloud pollers instead.
        try:
            with progress_tracker.ProgressTracker(
                    'Deleting [{0}]'.format(version_path)):
                api_client.DeleteVersion(version.service, version.id)
        except (calliope_exceptions.HttpException,
                operations_util.OperationError,
                operations_util.OperationTimeoutError,
                app_exceptions.Error) as err:
            errors[version_path] = str(err)

    if errors:
        printable_errors = {}
        for version_path, error_msg in errors.items():
            printable_errors[version_path] = '[{0}]: {1}'.format(
                version_path, error_msg)
        raise VersionsDeleteError('Issue deleting {0}: [{1}]\n\n'.format(
            text.Pluralize(len(printable_errors), 'version'), ', '.join(
                printable_errors.keys())) +
                                  '\n\n'.join(printable_errors.values()))
Пример #8
0
  def Run(self, args):
    client = appengine_api_client.GetApiClientForTrack(self.ReleaseTrack())
    services = client.ListServices()
    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))

    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)
Пример #9
0
def AddRegionFlag(parser, resource_type, operation_type,
                  flag_prefix=None,
                  explanation=REGION_PROPERTY_EXPLANATION,
                  hidden=False, plural=False, custom_plural=None):
  """Adds a --region flag to the given parser.

  Args:
    parser: argparse parser.
    resource_type: str, human readable name for the resource type this flag is
                   qualifying, for example "instance group".
    operation_type: str, human readable name for the operation, for example
                    "update" or "delete".
    flag_prefix: str, flag will be named --{flag_prefix}-region.
    explanation: str, detailed explanation of the flag.
    hidden: bool, If True, --region argument help will be hidden.
    plural: bool, resource_type will be pluralized or not depending on value.
    custom_plural: str, If plural is True then this string will be used as
                        resource types, otherwise resource_types will be
                        pluralized by appending 's'.
  """
  short_help = 'The region of the {0} to {1}.'.format(
      text.Pluralize(
          int(plural) + 1, resource_type or '', custom_plural), operation_type)
  flag_name = 'region'
  if flag_prefix is not None:
    flag_name = flag_prefix + '-' + flag_name
  parser.add_argument(
      '--' + flag_name,
      completer=completers.RegionsCompleter,
      action=actions.StoreProperty(properties.VALUES.compute.region),
      hidden=hidden,
      help='{0} {1}'.format(short_help, explanation))
Пример #10
0
def ValidateFieldConfig(unused_ref, args, request):
    """Python hook to validate the field configuration of the given request.

  Note that this hook is only called after the request has been formed based on
  the spec. Thus, the validation of the user's choices for order and
  array-config, as well as the check for the required field-path attribute, have
  already been performed. As such the only remaining things to verify are that
  the user has specified at least 2 fields, and that exactly one of order or
  array-config was specified for each field.

  Args:
    unused_ref: The resource ref (unused).
    args: The parsed arg namespace.
    request: The request formed based on the spec.
  Returns:
    The original request assuming the field configuration is valid.
  Raises:
    InvalidArgumentException: If the field configuration is invalid.
  """
    if len(args.field_config) < 2:
        raise exceptions.InvalidArgumentException(
            '--field-config',
            'Composite indexes must be configured with at least 2 fields. For '
            'single-field index management, use the commands under `gcloud '
            'firestore indexes fields`.')

    invalid_field_configs = []
    for field_config in args.field_config:
        # Because of the way declarative ArgDict parsing works, the type of
        # field_config here is already an apitools message, as opposed to an
        # ArgDict.
        order = field_config.order
        array_config = field_config.arrayConfig
        if (order and array_config) or (not order and not array_config):
            invalid_field_configs.append(field_config)

    if invalid_field_configs:
        raise exceptions.InvalidArgumentException(
            '--field-config',
            "Exactly one of 'order' or 'array-config' must be specified for the "
            "{field_word} with the following {path_word}: [{paths}].".format(
                field_word=text.Pluralize(len(invalid_field_configs), 'field'),
                path_word=text.Pluralize(len(invalid_field_configs), 'path'),
                paths=', '.join(field_config.fieldPath
                                for field_config in invalid_field_configs)))

    return request
def UpdateCliTrees(cli=None, commands=None, directory=None,
                   verbose=False, warn_on_exceptions=False):
  """(re)generates the CLI trees in directory if non-existent or out ot date.

  This function uses the progress tracker because some of the updates can
  take ~minutes.

  Args:
    cli: The default CLI. If not None then the default CLI is also updated.
    commands: Update only the commands in this list.
    directory: The directory containing the CLI tree JSON files. If None
      then the default installation directories are used.
    verbose: Display a status line for up to date CLI trees if True.
    warn_on_exceptions: Emits warning messages in lieu of exceptions. Used
      during installation.

  Raises:
    NoCliTreeGeneratorForCommand: A command in commands is not supported
      (doesn't have a generator).
  """
  # Initialize the list of directories to search for CLI tree files. The default
  # CLI tree is only searched for and generated in directories[0]. Other
  # existing trees are updated in the directory in which they were found. New
  # trees are generated in directories[-1].
  directories = []
  if directory:
    directories.append(directory)
  else:
    try:
      directories.append(cli_tree.CliTreeDir())
    except cli_tree.SdkRootNotFoundError as e:
      if not warn_on_exceptions:
        raise
      log.warn(str(e))
    directories.append(cli_tree.CliTreeConfigDir())

  if not commands:
    commands = set([cli_tree.DEFAULT_CLI_NAME] + GENERATORS.keys())

  failed = []
  for command in sorted(commands):
    if command != cli_tree.DEFAULT_CLI_NAME:
      generator = GetCliTreeGenerator(command)
      try:
        generator.LoadOrGenerate(directories=directories, verbose=verbose,
                                 warn_on_exceptions=warn_on_exceptions)
      except subprocess.CalledProcessError:
        failed.append(command)
    elif cli:
      cli_tree.Load(cli=cli,
                    path=cli_tree.CliTreePath(directory=directories[0]),
                    verbose=verbose)
  if failed:
    message = 'No CLI tree {} for [{}].'.format(
        text_utils.Pluralize(len(failed), 'generator'),
        ', '.join(sorted(failed)))
    if not warn_on_exceptions:
      raise NoCliTreeGeneratorForCommand(message)
    log.warn(message)
Пример #12
0
    def Run(self, args):
        client = appengine_api_client.GetApiClient(self.Http(timeout=None))
        services = client.ListServices()
        all_versions = client.ListVersions(services)
        versions = version_util.GetMatchingVersions(all_versions,
                                                    args.versions,
                                                    args.service,
                                                    client.project)

        services_to_delete = []
        for service in services:
            if (len([v for v in all_versions
                     if v.service == service.id]) == len(
                         [v for v in versions if v.service == service.id])):
                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(user): mention `migrate` once it's implemented.
                raise VersionsDeleteError(
                    'Version [{version}] is currently serving {allocation:.2f}% of '
                    'traffic for service [{service}].\n\n'
                    'Please move all traffic away by deploying a new version with the'
                    '`--promote` argument or running `gcloud preview app services '
                    'set-traffic`.'.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.warn(
                'Requested deletion of all existing versions for the following '
                '{0}:'.format(word))
            printer = console_io.ListPrinter('')
            printer.Print(services_to_delete, output_stream=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:
            printer = console_io.ListPrinter(
                'Deleting the following versions:')
            printer.Print(versions, output_stream=log.status)
            console_io.PromptContinue(cancel_on_no=True)
        else:
            if not services_to_delete:
                log.warn('No matching versions found.')

        version_util.DeleteVersions(client, versions)
    def _GetHelpTextForAttribute(self, attribute):
        """Helper to get the help text for the attribute arg."""
        if self._IsAnchor(attribute):
            help_text = ANCHOR_HELP if not self.plural else PLURAL_ANCHOR_HELP
        else:
            help_text = attribute.help_text

        expansion_name = text.Pluralize(2 if self.plural else 1,
                                        self.resource_spec.name,
                                        plural=getattr(self.resource_spec,
                                                       'plural_name', None))
        return help_text.format(resource=expansion_name)
  def _Update(self, restrict):
    """Update() helper method. Returns the number of changed help doc files."""
    with file_utils.TemporaryDirectory() as temp_dir:
      pb = console_io.ProgressBar(label='Generating Help Document Files')
      with TimeIt('Creating walker'):
        walker = self._generator(
            self._cli, temp_dir, pb.SetProgress, restrict=restrict)
      start = time.time()
      pb.Start()
      walker.Walk(hidden=True)
      pb.Finish()
      elapsed_time = time.time() - start
      log.info('Generating Help Document Files took {}'.format(elapsed_time))

      diff = HelpAccumulator(restrict=restrict)
      with TimeIt('Diffing'):
        DirDiff(self._directory, temp_dir, diff)
      ops = collections.defaultdict(list)

      changes = 0
      with TimeIt('Getting diffs'):
        for op, path in sorted(diff.GetChanges()):
          changes += 1
          if not self._test or changes < TEST_CHANGES_DISPLAY_MAX:
            log.status.Print('{0} {1}'.format(op, path))
          ops[op].append(path)

      if self._test:
        if changes:
          if changes >= TEST_CHANGES_DISPLAY_MAX:
            log.status.Print('...')
          log.status.Print('{0} help text {1} changed'.format(
              changes, text.Pluralize(changes, 'file')))
        return changes

      with TimeIt('Updating destination files'):
        for op in ('add', 'edit', 'delete'):
          for path in ops[op]:
            dest_path = os.path.join(self._directory, path)
            if op in ('add', 'edit'):
              if op == 'add':
                subdir = os.path.dirname(dest_path)
                if subdir:
                  file_utils.MakeDir(subdir)
              temp_path = os.path.join(temp_dir, path)
              shutil.copyfile(temp_path, dest_path)
            elif op == 'delete':
              try:
                os.remove(dest_path)
              except OSError:
                pass

      return changes
Пример #15
0
def UpdateCliTrees(cli=None,
                   commands=None,
                   directory=None,
                   force=False,
                   verbose=False,
                   warn_on_exceptions=False):
    """(re)generates the CLI trees in directory if non-existent or out ot date.

  This function uses the progress tracker because some of the updates can
  take ~minutes.

  Args:
    cli: The default CLI. If not None then the default CLI is also updated.
    commands: Update only the commands in this list.
    directory: The directory containing the CLI tree JSON files. If None
      then the default installation directories are used.
    force: Update all exitsing trees by forcing them to be out of date if True.
    verbose: Display a status line for up to date CLI trees if True.
    warn_on_exceptions: Emits warning messages in lieu of exceptions. Used
      during installation.

  Raises:
    NoCliTreeGeneratorForCommand: A command in commands is not supported
      (doesn't have a generator).
  """
    directories = _GetDirectories(directory=directory,
                                  warn_on_exceptions=warn_on_exceptions)
    if not commands:
        commands = set([cli_tree.DEFAULT_CLI_NAME] + list(GENERATORS.keys()))

    failed = []
    for command in sorted(commands):
        if command != cli_tree.DEFAULT_CLI_NAME:
            tree = LoadOrGenerate(command,
                                  directories=directories,
                                  force=force,
                                  verbose=verbose,
                                  warn_on_exceptions=warn_on_exceptions)
            if not tree:
                failed.append(command)
        elif cli:
            cli_tree.Load(cli=cli,
                          path=cli_tree.CliTreePath(directory=directories[0]),
                          force=force,
                          verbose=verbose)
    if failed:
        message = 'No CLI tree {} for [{}].'.format(
            text_utils.Pluralize(len(failed), 'generator'),
            ', '.join(sorted(failed)))
        if not warn_on_exceptions:
            raise NoCliTreeGeneratorForCommand(message)
        log.warning(message)
Пример #16
0
    def Display(self, args, result):
        """This method is called to print the result of the Run() method.

    Args:
      args: The arguments that command was run with.
      result: The value returned from the Run() method.
    """
        succeeded, failed = result
        successes = len(succeeded)
        failures = len(failed)

        if successes:
            fmt = 'list[title="{0} {1} deleted successfully"]'.format(
                successes, text.Pluralize(successes, 'subscription'))
            resource_printer.Print(
                [subscription for subscription in succeeded], fmt)

        if failures:
            fmt = 'list[title="{0} {1} failed"]'.format(
                failures, text.Pluralize(failures, 'subscription'))
            resource_printer.Print([
                '{0} (reason: {1})'.format(subs, reason)
                for subs, reason in failed
            ], fmt)
Пример #17
0
def _PromptWithScopeChoices(resource_name, underspecified_names,
                            scope_value_choices, choice_names, choice_mapping):
    """Queries user to choose scope and its value."""
    title = ('For the following {0}:\n {1}\n'.format(
        text.Pluralize(len(underspecified_names), resource_name),
        '\n '.join('- [{0}]'.format(n) for n in sorted(underspecified_names))))
    flags = ' or '.join(
        sorted([s.prefix + s.flag_name for s in scope_value_choices.keys()]))

    idx = console_io.PromptChoice(options=choice_names,
                                  message='{0}choose {1}:'.format(
                                      title, flags))
    if idx is None:
        return None, None
    else:
        return choice_mapping[idx]
Пример #18
0
    def FromServiceLists(cls, requested_services, all_services):
        """Format a ServiceNotFoundError.

    Args:
      requested_services: list of str, IDs of services that were not found.
      all_services: list of str, IDs of all available services

    Returns:
      ServicesNotFoundError, error with properly formatted message
    """
        return cls('The following {0} not found: [{1}]\n\n'
                   'All services: [{2}]'.format(
                       text.Pluralize(len(requested_services),
                                      'service was',
                                      plural='services were'),
                       ', '.join(requested_services), ', '.join(all_services)))
Пример #19
0
    def _GetHelpTextForAttribute(self, attribute):
        """Helper to get the help text for the attribute arg."""
        if self._IsAnchor(attribute):
            help_text = ANCHOR_HELP if not self.plural else PLURAL_ANCHOR_HELP
        else:
            help_text = attribute.help_text

        expansion_name = text.Pluralize(2 if self.plural else 1,
                                        self.resource_spec.name,
                                        plural=getattr(self.resource_spec,
                                                       'plural_name', None))
        hints = self.GetHints(attribute.name)
        if hints:
            hint = ' To set the [{}] attribute: {}.'.format(
                attribute.name, '; '.join(hints))
            help_text += hint
        return help_text.format(resource=expansion_name)
Пример #20
0
 def GetNotesHelpSection(self, contents=None):
   """Returns the NOTES section with explicit and generated help."""
   if not contents:
     contents = self.detailed_help.get('NOTES')
   notes = _Notes(contents)
   if self.IsHidden():
     notes.AddLine('This command is an internal implementation detail and may '
                   'change or disappear without notice.')
   notes.AddLine(self.ReleaseTrack().help_note)
   alternates = self.GetExistingAlternativeReleaseTracks()
   if alternates:
     notes.AddLine('{} also available:'.format(
         text.Pluralize(
             len(alternates), 'This variant is', 'These variants are')))
     notes.AddLine('')
     for alternate in alternates:
       notes.AddLine('  $ ' + alternate)
   return notes.GetContents()
Пример #21
0
def UploadFiles(files_to_upload, num_threads=DEFAULT_NUM_THREADS,
                show_progress_bar=False):
  """Upload the given files to the given Cloud Storage URLs.

  Uses the appropriate parallelism (multi-process, multi-thread, both, or
  synchronous).

  Args:
    files_to_upload: list of FileUploadTask
    num_threads: int (optional), the number of threads to use.
    show_progress_bar: bool. If true, show a progress bar to the users when
      uploading files.
  """
  num_files = len(files_to_upload)
  label = 'Uploading {} {} to Google Cloud Storage'.format(
      num_files, text.Pluralize(num_files, 'file'))
  _DoParallelOperation(num_threads, files_to_upload, _UploadFile, label,
                       show_progress_bar)
Пример #22
0
def DeleteObjects(objects_to_delete, num_threads=DEFAULT_NUM_THREADS,
                  show_progress_bar=False):
  """Delete the given Cloud Storage objects.

  Uses the appropriate parallelism (multi-process, multi-thread, both, or
  synchronous).

  Args:
    objects_to_delete: list of ObjectDeleteTask
    num_threads: int (optional), the number of threads to use.
    show_progress_bar: bool. If true, show a progress bar to the users when
      deleting files.
  """
  num_objects = len(objects_to_delete)
  label = 'Deleting {} {} from Google Cloud Storage'.format(
      num_objects, text.Pluralize(num_objects, 'object'))
  _DoParallelOperation(num_threads, objects_to_delete, _DeleteObject,
                       label, show_progress_bar)
Пример #23
0
def DeleteServices(api_client, services):
    """Delete the given services."""
    errors = {}
    for service in services:
        try:
            operations_util.CallAndCollectOpErrors(api_client.DeleteService,
                                                   service.id)
        except operations_util.MiscOperationError as err:
            errors[service.id] = str(err)

    if errors:
        printable_errors = {}
        for service_id, error_msg in errors.items():
            printable_errors[service_id] = '[{0}]: {1}'.format(
                service_id, error_msg)
        raise ServicesDeleteError('Issue deleting {0}: [{1}]\n\n'.format(
            text.Pluralize(len(printable_errors), 'service'), ', '.join(
                list(printable_errors.keys()))) +
                                  '\n\n'.join(list(printable_errors.values())))
    def _DisplayExecutionStats(self, out, prepend, beneath_stub):
        """Prints the relevant execution statistics for a node.

    More specifically, print out latency information and the number of
    executions. This information only exists when query is run in 'PROFILE'
    mode.

    Args:
      out: Output stream to which we print.
      prepend: String that precedes any information about this node to maintain
        a visible hierarchy.
      beneath_stub: String that preserves the indentation of the vertical lines.
    """
        if not self.properties.executionStats:
            return None

        stat_props = []

        num_executions = self._GetNestedStatProperty('execution_summary',
                                                     'num_executions')
        if num_executions:
            num_executions = int(num_executions)
            executions_str = '{} {}'.format(
                num_executions, text.Pluralize(num_executions, 'execution'))
            stat_props.append(executions_str)

        # Total latency and latency unit are always expected to be present when
        # latency exists. Latency exists when the query is run in PROFILE mode.
        mean_latency = self._GetNestedStatProperty('latency', 'mean')
        total_latency = self._GetNestedStatProperty('latency', 'total')
        unit = self._GetNestedStatProperty('latency', 'unit')
        if mean_latency:
            stat_props.append('{} {} average latency'.format(
                mean_latency, unit))
        elif total_latency:
            stat_props.append('{} {} total latency'.format(
                total_latency, unit))

        if stat_props:
            executions_stats_str = '{}{} ({})'.format(prepend, beneath_stub,
                                                      ', '.join(stat_props))
            out.Print(executions_stats_str)
Пример #25
0
def DeleteVersions(api_client, versions):
    """Delete the given version of the given services."""
    errors = {}
    for version in versions:
        version_path = '{0}/{1}'.format(version.service, version.id)
        try:
            operations_util.CallAndCollectOpErrors(api_client.DeleteVersion,
                                                   version.service, version.id)
        except operations_util.MiscOperationError as err:
            errors[version_path] = str(err)

    if errors:
        printable_errors = {}
        for version_path, error_msg in errors.items():
            printable_errors[version_path] = '[{0}]: {1}'.format(
                version_path, error_msg)
        raise VersionsDeleteError('Issue deleting {0}: [{1}]\n\n'.format(
            text.Pluralize(len(printable_errors), 'version'), ', '.join(
                list(printable_errors.keys()))) +
                                  '\n\n'.join(list(printable_errors.values())))
Пример #26
0
def DeleteServices(api_client, services):
  """Delete the given services."""
  errors = {}
  for service in services:
    try:
      api_client.DeleteService(service.id)
    except (core_api_exceptions.HttpException, operations_util.OperationError,
            operations_util.OperationTimeoutError, app_exceptions.Error) as err:
      errors[service.id] = str(err)

  if errors:
    printable_errors = {}
    for service_id, error_msg in errors.items():
      printable_errors[service_id] = '[{0}]: {1}'.format(service_id,
                                                         error_msg)
    raise ServicesDeleteError(
        'Issue deleting {0}: [{1}]\n\n'.format(
            text.Pluralize(len(printable_errors), 'service'),
            ', '.join(printable_errors.keys())) +
        '\n\n'.join(printable_errors.values()))
Пример #27
0
def ClusterUpgradeMessage(cluster,
                          master=False,
                          node_pool=None,
                          new_version=None):
    """Get a message to print during gcloud container clusters upgrade.

  Args:
    cluster: the cluster object.
    master: bool, if the upgrade applies to the master version.
    node_pool: str, the name of the node pool if the upgrade is for a specific
        node pool.
    new_version: str, the name of the new version, if given.

  Raises:
    NodePoolError: if the node pool name can't be found in the cluster.

  Returns:
    str, a message about which nodes in the cluster will be upgraded and
        to which version.
  """
    if new_version:
        new_version_message = 'version [{}]'.format(new_version)
    else:
        new_version_message = 'master version'
    if master:
        node_message = 'Master'
        current_version = cluster.currentMasterVersion
    elif node_pool:
        node_message = 'All nodes in node pool [{}]'.format(node_pool)
        node_pool = _NodePoolFromCluster(cluster, node_pool)
        current_version = node_pool.version
    else:
        node_message = 'All nodes ({} {})'.format(
            cluster.currentNodeCount,
            text.Pluralize(cluster.currentNodeCount, 'node'))
        current_version = cluster.currentNodeVersion
    return ('{} of cluster [{}] will be upgraded from version [{}] to {}. '
            'This operation is long-running and will block other operations '
            'on the cluster (including delete) until it has run to completion.'
            .format(node_message, cluster.name, current_version,
                    new_version_message))
Пример #28
0
def DeleteVersions(api_client, versions):
    """Delete the given version of the given services."""
    errors = {}
    for version in versions:
        version_path = '{0}/{1}'.format(version.service, version.id)
        try:
            api_client.DeleteVersion(version.service, version.id)
        except (core_api_exceptions.HttpException,
                operations_util.OperationError,
                operations_util.OperationTimeoutError,
                app_exceptions.Error) as err:
            errors[version_path] = str(err)

    if errors:
        printable_errors = {}
        for version_path, error_msg in errors.items():
            printable_errors[version_path] = '[{0}]: {1}'.format(
                version_path, error_msg)
        raise VersionsDeleteError('Issue deleting {0}: [{1}]\n\n'.format(
            text.Pluralize(len(printable_errors), 'version'), ', '.join(
                printable_errors.keys())) +
                                  '\n\n'.join(printable_errors.values()))
Пример #29
0
    def ReadConfig(self, path, allowed_fields):
        """Read a config file and return Version object with the values.

    The object is based on a YAML configuration file. The file may only
    have the fields given in `allowed_fields`.

    Args:
      path: str, the path to the YAML file.
      allowed_fields: Collection, the fields allowed in the YAML.

    Returns:
      A Version object (for the corresponding API version).

    Raises:
      InvalidVersionConfigFile: If the file contains unexpected fields.
    """
        try:
            data = yaml.load_path(path)
        except (yaml.Error) as err:
            raise InvalidVersionConfigFile(
                'Could not read Version configuration file [{path}]:\n\n'
                '{err}'.format(path=path, err=six.text_type(err.inner_error)))
        if data:
            version = encoding.DictToMessage(data, self.version_class)

        specified_fields = set(
            [f.name for f in version.all_fields() if getattr(version, f.name)])
        invalid_fields = (specified_fields - allowed_fields
                          | set(version.all_unrecognized_fields()))
        if invalid_fields:
            raise InvalidVersionConfigFile(
                'Invalid {noun} [{fields}] in configuration file [{path}]. '
                'Allowed fields: [{allowed}].'.format(
                    noun=text.Pluralize(len(invalid_fields), 'field'),
                    fields=', '.join(sorted(invalid_fields)),
                    path=path,
                    allowed=', '.join(sorted(allowed_fields))))
        return version
Пример #30
0
    def AddInstance(self,
                    positional=True,
                    required=True,
                    multiple=False,
                    additional_help=None):
        """Add argument for instance ID to parser."""
        help_text = 'ID of the {}.'.format(
            text.Pluralize(2 if multiple else 1, 'instance'))
        if additional_help:
            help_text = ' '.join([help_text, additional_help])
        name = 'instance' if positional else '--instance'
        args = {'completer': InstanceCompleter, 'help': help_text}
        if multiple:
            if positional:
                args['nargs'] = '+'
            else:
                name = '--instances'
                args['type'] = arg_parsers.ArgList()
                args['metavar'] = 'INSTANCE'
        if not positional:
            args['required'] = required

        self.parser.add_argument(name, **args)
        return self