175 lines
6.8 KiB
Python
Executable File
175 lines
6.8 KiB
Python
Executable File
#!/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')
|