Example #1
0
    def _ValidateAndGetConfigValues(self):
        """Parses the user's config file to aggregate non-PII config values.

    Returns:
      A comma-delimited string of config values explicitly set by the user in
      key:value pairs, sorted alphabetically by key.
    """
        config_values = []

        # If a user has an invalid config value set, we will mark it as such with
        # this value. If a user did not enter a value, we will not report it.
        invalid_value_string = 'INVALID'

        def GetAndValidateConfigValue(section, category, validation_fn):
            try:
                config_value = boto.config.get_value(section, category)
                if config_value and validation_fn(config_value):
                    config_values.append((category, config_value))
                # If the user entered a non-valid config value, store it as invalid.
                elif config_value:
                    config_values.append((category, invalid_value_string))
            # This function gets called during initialization of the MetricsCollector.
            # If any of the logic fails, we do not want to hinder the gsutil command
            # being run, and thus ignore any exceptions.
            except:  # pylint: disable=bare-except
                config_values.append((category, invalid_value_string))

        # Validate boolean values.
        for section, bool_category in (('Boto', 'https_validate_certificates'),
                                       ('GSUtil', 'disable_analytics_prompt'),
                                       ('GSUtil', 'use_magicfile'),
                                       ('GSUtil', 'tab_completion_time_logs')):
            GetAndValidateConfigValue(
                section=section,
                category=bool_category,
                validation_fn=lambda val: str(val).lower() in
                ('true', 'false'))

        # Define a threshold for some config values which should be reasonably low.
        small_int_threshold = 2000
        # Validate small integers.
        for section, small_int_category in (
            ('Boto', 'debug'), ('Boto', 'http_socket_timeout'),
            ('Boto', 'num_retries'), ('Boto', 'max_retry_delay'),
            ('GSUtil',
             'default_api_version'), ('GSUtil',
                                      'sliced_object_download_max_components'),
            ('GSUtil', 'parallel_process_count'), ('GSUtil',
                                                   'parallel_thread_count'),
            ('GSUtil', 'software_update_check_period'),
            ('GSUtil', 'tab_completion_timeout'), ('OAuth2',
                                                   'oauth2_refresh_retries')):
            GetAndValidateConfigValue(
                section=section,
                category=small_int_category,
                validation_fn=lambda val: str(val).isdigit() and int(
                    val) < small_int_threshold)

        # Validate large integers.
        for section, large_int_category in (('GSUtil', 'resumable_threshold'),
                                            ('GSUtil', 'rsync_buffer_lines'),
                                            ('GSUtil',
                                             'task_estimation_threshold')):
            GetAndValidateConfigValue(
                section=section,
                category=large_int_category,
                validation_fn=lambda val: str(val).isdigit())

        # Validate data sizes.
        for section, data_size_category in (
            ('GSUtil', 'parallel_composite_upload_component_size'),
            ('GSUtil', 'parallel_composite_upload_threshold'),
            ('GSUtil', 'sliced_object_download_component_size'),
            ('GSUtil', 'sliced_object_download_threshold')):
            config_value = boto.config.get_value(section, data_size_category)
            if config_value:
                try:
                    size_in_bytes = HumanReadableToBytes(config_value)
                    config_values.append((data_size_category, size_in_bytes))
                except ValueError:
                    config_values.append(
                        (data_size_category, invalid_value_string))

        # Validate specific options.
        # pylint: disable=g-long-lambda
        GetAndValidateConfigValue(
            section='GSUtil',
            category='check_hashes',
            validation_fn=lambda val: val in
            ('if_fast_else_fail', 'if_fast_else_skip', 'always', 'never'))
        # pylint: enable=g-long-lambda
        GetAndValidateConfigValue(
            section='GSUtil',
            category='content_language',
            validation_fn=lambda val: val.isalpha() and len(val) <= 3)
        GetAndValidateConfigValue(section='GSUtil',
                                  category='json_api_version',
                                  validation_fn=lambda val: val[0].lower() ==
                                  'v' and val[1:].isdigit())
        GetAndValidateConfigValue(section='GSUtil',
                                  category='prefer_api',
                                  validation_fn=lambda val: val in
                                  ('json', 'xml'))
        GetAndValidateConfigValue(section='OAuth2',
                                  category='token_cache',
                                  validation_fn=lambda val: val in
                                  ('file_system', 'in_memory'))

        return ','.join(
            sorted([
                '{0}:{1}'.format(config[0], config[1])
                for config in config_values
            ]))
Example #2
0
  def _ParseArgs(self):
    """Parses arguments for perfdiag command."""
    # From -n.
    self.num_iterations = 5
    # From -c.
    self.processes = 1
    # From -k.
    self.threads = 1
    # From -s.
    self.thru_filesize = 1048576
    # From -t.
    self.diag_tests = self.ALL_DIAG_TESTS
    # From -o.
    self.output_file = None
    # From -i.
    self.input_file = None
    # From -m.
    self.metadata_keys = {}

    if self.sub_opts:
      for o, a in self.sub_opts:
        if o == '-n':
          self.num_iterations = self._ParsePositiveInteger(
              a, 'The -n parameter must be a positive integer.')
        if o == '-c':
          self.processes = self._ParsePositiveInteger(
              a, 'The -c parameter must be a positive integer.')
        if o == '-k':
          self.threads = self._ParsePositiveInteger(
              a, 'The -k parameter must be a positive integer.')
        if o == '-s':
          try:
            self.thru_filesize = HumanReadableToBytes(a)
          except ValueError:
            raise CommandException('Invalid -s parameter.')
          if self.thru_filesize > (20 * 1024 ** 3):  # Max 20 GB.
            raise CommandException(
                'Maximum throughput file size parameter (-s) is 20GB.')
        if o == '-t':
          self.diag_tests = []
          for test_name in a.strip().split(','):
            if test_name.lower() not in self.ALL_DIAG_TESTS:
              raise CommandException("List of test names (-t) contains invalid "
                                     "test name '%s'." % test_name)
            self.diag_tests.append(test_name)
        if o == '-m':
          pieces = a.split(':')
          if len(pieces) != 2:
            raise CommandException(
                "Invalid metadata key-value combination '%s'." % a)
          key, value = pieces
          self.metadata_keys[key] = value
        if o == '-o':
          self.output_file = os.path.abspath(a)
        if o == '-i':
          self.input_file = os.path.abspath(a)
          if not os.path.isfile(self.input_file):
            raise CommandException("Invalid input file (-i): '%s'." % a)
          try:
            with open(self.input_file, 'r') as f:
              self.results = json.load(f)
              self.logger.info("Read input file: '%s'.", self.input_file)
          except ValueError:
            raise CommandException("Could not decode input file (-i): '%s'." %
                                   a)
          return

    if not self.args:
      raise CommandException('Wrong number of arguments for "perfdiag" '
                             'command.')
    self.bucket_uri = self.suri_builder.StorageUri(self.args[0])
    if not self.bucket_uri.names_bucket():
      raise CommandException('The perfdiag command requires a URI that '
                             'specifies a bucket.\n"%s" is not '
                             'valid.' % self.bucket_uri)
    self.bucket = self.bucket_uri.get_bucket()

    # TODO: Add MD5 argument support to get_contents_to_file()
    # and pass the file md5 as a parameter to avoid any unnecessary
    # computation.
    self.get_contents_to_file_args = {}
    if self.bucket_uri.scheme == 'gs':
      self.get_contents_to_file_args = {'hash_algs': {}}