#!/usr/bin/env python # # Copyright 2013 Google Inc. All Rights Reserved. # """A convenience wrapper for starting gsutil.""" from __future__ import absolute_import from __future__ import unicode_literals import json import os import bootstrapping from googlecloudsdk.calliope import exceptions from googlecloudsdk.core import config from googlecloudsdk.core import context_aware from googlecloudsdk.core import log from googlecloudsdk.core import metrics from googlecloudsdk.core import properties from googlecloudsdk.core.credentials import gce as c_gce from googlecloudsdk.core.util import encoding from googlecloudsdk.core.util import files def _MaybeAddBotoOption(args, section, name, value): if value is None: return args.append('-o') args.append('{section}:{name}={value}'.format( section=section, name=name, value=value)) def _GetCertProviderCommand(context_config): """Returns the cert provider command from the context config.""" # TODO(b/190102217) - Cleanup code that handles both version of context_config if hasattr(context_config, 'cert_provider_command'): return context_config.cert_provider_command try: contents = files.ReadFileContents(context_config.config_path) json_out = json.loads(contents) if 'cert_provider_command' in json_out: return json_out['cert_provider_command'] except files.Error as e: log.debug('context aware settings discovery file %s - %s', context_config.config_path, e) def _AddContextAwareOptions(args): """Adds device certificate settings for mTLS.""" context_config = context_aware.Config() # Enterprise certificate is not yet supported for gsutil. if ( context_config and context_config.config_type == context_aware.ConfigType.ENTERPRISE_CERTIFICATE ): return # TODO(b/190102217) - Cleanup code that handles both version of context_config use_client_certificate = ( context_config and getattr(context_config, 'use_client_certificate', True)) _MaybeAddBotoOption(args, 'Credentials', 'use_client_certificate', use_client_certificate) if context_config: cert_provider_command = _GetCertProviderCommand(context_config) if isinstance(cert_provider_command, list): # e.g. cert_provider_command = ['*/apihelper', '--print_certificate'] cert_provider_command = ' '.join(cert_provider_command) # Don't need to pass mTLS data if gsutil shouldn't be using it. _MaybeAddBotoOption(args, 'Credentials', 'cert_provider_command', cert_provider_command) def main(): """Launches gsutil.""" args = [] project, account = bootstrapping.GetActiveProjectAndAccount() pass_credentials = ( properties.VALUES.core.pass_credentials_to_gsutil.GetBool() and not properties.VALUES.auth.disable_credentials.GetBool()) _MaybeAddBotoOption(args, 'GSUtil', 'default_project_id', project) if pass_credentials: # Allow gsutil to only check for the '1' string value, as is done # with regard to the 'CLOUDSDK_WRAPPER' environment variable. encoding.SetEncodedValue( os.environ, 'CLOUDSDK_CORE_PASS_CREDENTIALS_TO_GSUTIL', '1') if account in c_gce.Metadata().Accounts(): # Tell gsutil that it should obtain credentials from the GCE metadata # server for the instance's configured service account. _MaybeAddBotoOption(args, 'GoogleCompute', 'service_account', 'default') # For auth'n debugging purposes, allow gsutil to reason about whether the # configured service account was set in a boto file or passed from here. encoding.SetEncodedValue( os.environ, 'CLOUDSDK_PASSED_GCE_SERVICE_ACCOUNT_TO_GSUTIL', '1') else: legacy_config_path = config.Paths().LegacyCredentialsGSUtilPath(account) # We construct a BOTO_PATH that tacks the config containing our # credentials options onto the end of the list of config paths. We ensure # the other credential options are loaded first so that ours will take # precedence and overwrite them. boto_config = encoding.GetEncodedValue(os.environ, 'BOTO_CONFIG', '') boto_path = encoding.GetEncodedValue(os.environ, 'BOTO_PATH', '') if boto_config: boto_path = os.pathsep.join([boto_config, legacy_config_path]) elif boto_path: boto_path = os.pathsep.join([boto_path, legacy_config_path]) else: path_parts = ['/etc/boto.cfg', os.path.expanduser(os.path.join('~', '.boto')), legacy_config_path] boto_path = os.pathsep.join(path_parts) encoding.SetEncodedValue(os.environ, 'BOTO_CONFIG', None) encoding.SetEncodedValue(os.environ, 'BOTO_PATH', boto_path) # Tell gsutil whether gcloud analytics collection is enabled. encoding.SetEncodedValue( os.environ, 'GA_CID', metrics.GetCIDIfMetricsEnabled()) # Set proxy settings. Note that if these proxy settings are configured in a # boto config file, the options here will be loaded afterward, overriding # them. proxy_params = properties.VALUES.proxy proxy_address = proxy_params.address.Get() if proxy_address: _MaybeAddBotoOption(args, 'Boto', 'proxy', proxy_address) _MaybeAddBotoOption(args, 'Boto', 'proxy_port', proxy_params.port.Get()) _MaybeAddBotoOption(args, 'Boto', 'proxy_rdns', proxy_params.rdns.GetBool()) _MaybeAddBotoOption(args, 'Boto', 'proxy_user', proxy_params.username.Get()) _MaybeAddBotoOption(args, 'Boto', 'proxy_pass', proxy_params.password.Get()) # Set SSL-related settings. disable_ssl = properties.VALUES.auth.disable_ssl_validation.GetBool() _MaybeAddBotoOption(args, 'Boto', 'https_validate_certificates', None if disable_ssl is None else not disable_ssl) _MaybeAddBotoOption(args, 'Boto', 'ca_certificates_file', properties.VALUES.core.custom_ca_certs_file.Get()) # Sync device certificate settings for mTLS. _AddContextAwareOptions(args) # Note that the original args to gsutil will be appended after the args we've # supplied here. bootstrapping.ExecutePythonTool('platform/gsutil', 'gsutil', *args) if __name__ == '__main__': try: version = bootstrapping.ReadFileContents('platform/gsutil', 'VERSION') bootstrapping.CommandStart('gsutil', version=version) blocked_commands = { 'update': 'To update, run: gcloud components update', } argv = bootstrapping.GetDecodedArgv() bootstrapping.WarnAndExitOnBlockedCommand(argv, blocked_commands) # Don't call bootstrapping.PreRunChecks because anonymous access is # supported for some endpoints. gsutil will output the appropriate # error message upon receiving an authentication error. bootstrapping.CheckUpdates('gsutil') main() except Exception as e: # pylint: disable=broad-except exceptions.HandleError(e, 'gsutil')