191 lines
7.5 KiB
Python
191 lines
7.5 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2017 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Register gcloud as a Docker credential helper."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import json
|
|
|
|
from googlecloudsdk.calliope import base
|
|
from googlecloudsdk.core import exceptions
|
|
from googlecloudsdk.core import log
|
|
from googlecloudsdk.core import properties
|
|
from googlecloudsdk.core.console import console_io
|
|
from googlecloudsdk.core.docker import credential_utils as cred_utils
|
|
from googlecloudsdk.core.util import files as file_utils
|
|
|
|
|
|
class ConfigureDockerError(exceptions.Error):
|
|
"""General command error class."""
|
|
|
|
|
|
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
|
|
base.ReleaseTrack.GA)
|
|
@base.UniverseCompatible
|
|
class ConfigureDocker(base.Command):
|
|
# pylint: disable=line-too-long
|
|
r"""Register `gcloud` as a Docker credential helper.
|
|
|
|
{command} adds the Docker `credHelper` entry to Docker's configuration file,
|
|
or creates the file if it doesn't exist. This will register `gcloud` as the
|
|
credential helper for all Google-supported Docker registries. If the Docker
|
|
configuration already contains a `credHelper` entry, it will be overwritten.
|
|
|
|
Note: `docker` and `gcloud` need to be on the same system `PATH` to work
|
|
correctly.
|
|
|
|
Note: This command will not work for `docker` installed via Snap, as the
|
|
`docker` snap package does not currently provide an interface for credential
|
|
helpers.
|
|
|
|
For more details on Docker registries, see
|
|
[](https://docs.docker.com/registry/).
|
|
|
|
For more details on how to authenticate to Google Container Registry using
|
|
this command, see
|
|
[](https://cloud.google.com/container-registry/docs/advanced-authentication#gcloud-helper).
|
|
|
|
For more details on Google Container Registry's standalone credential helpers,
|
|
see [](https://github.com/GoogleCloudPlatform/docker-credential-gcr).
|
|
|
|
For more details on Docker credential helpers, see
|
|
[](https://docs.docker.com/engine/reference/commandline/login/#credential-helpers).
|
|
|
|
|
|
## EXAMPLES
|
|
|
|
To configure docker authentication after logging into gcloud, run:
|
|
|
|
$ {command}
|
|
|
|
To configure docker authentication with Container Registry, e.g., `gcr.io`,
|
|
run:
|
|
|
|
$ {command} gcr.io
|
|
"""
|
|
# pylint: enable=line-too-long
|
|
|
|
def DockerCredentialGcloudExists(self):
|
|
return file_utils.SearchForExecutableOnPath(
|
|
'docker-credential-gcloud') or file_utils.SearchForExecutableOnPath(
|
|
'docker-credential-gcloud.cmd')
|
|
|
|
def DockerExists(self):
|
|
return file_utils.SearchForExecutableOnPath(
|
|
'docker') or file_utils.SearchForExecutableOnPath('docker.exe')
|
|
|
|
@staticmethod
|
|
def Args(parser):
|
|
"""Set args for configure-docker."""
|
|
parser.add_argument(
|
|
'registries',
|
|
nargs='?',
|
|
help='The comma-separated list of registries to configure the credential'
|
|
' helper for. Container Registry is a service for storing private '
|
|
'container images. For available registries, see '
|
|
'[](https://cloud.google.com/container-registry/docs/pushing-and-pulling#add-registry).'
|
|
)
|
|
parser.add_argument(
|
|
'--include-artifact-registry',
|
|
action='store_true',
|
|
help='Whether to include all Artifact Registry domains.',
|
|
hidden=True)
|
|
|
|
def Run(self, args):
|
|
"""Run the configure-docker command."""
|
|
if not self.DockerCredentialGcloudExists():
|
|
log.warning('`docker-credential-gcloud` not in system PATH.\n'
|
|
'gcloud\'s Docker credential helper can be configured but '
|
|
'it will not work until this is corrected.')
|
|
|
|
current_config = cred_utils.Configuration.ReadFromDisk()
|
|
|
|
if self.DockerExists():
|
|
if not current_config.SupportsRegistryHelpers():
|
|
raise ConfigureDockerError(
|
|
'Invalid Docker version: The version of your Docker client is '
|
|
'[{}]; version [{}] or higher is required to support Docker '
|
|
'credential helpers.'.format(
|
|
current_config.DockerVersion(),
|
|
cred_utils.MIN_DOCKER_CONFIG_HELPER_VERSION))
|
|
else:
|
|
log.warning(
|
|
'`docker` not in system PATH.\n'
|
|
'`docker` and `docker-credential-gcloud` need to be in the same PATH '
|
|
'in order to work correctly together.\n'
|
|
'gcloud\'s Docker credential helper can be configured but '
|
|
'it will not work until this is corrected.')
|
|
|
|
current_helpers = current_config.GetRegisteredCredentialHelpers()
|
|
current_helper_map = {}
|
|
if current_helpers:
|
|
log.warning('Your config file at [{0}] contains these credential helper '
|
|
'entries:\n\n{1}'.format(
|
|
current_config.path,
|
|
json.dumps(current_helpers, indent=2)))
|
|
current_helper_map = current_helpers[cred_utils.CREDENTIAL_HELPER_KEY]
|
|
|
|
# Use the value from the argument, otherwise the default list.
|
|
if args.registries:
|
|
log.status.Print('Adding credentials for: {0}'.format(args.registries))
|
|
registries_list = args.registries.split(',')
|
|
if properties.VALUES.artifacts.allow_unrecognized_registry.GetBool():
|
|
new_helpers = cred_utils.GetGcloudCredentialHelperConfig(
|
|
registries_list
|
|
)
|
|
else:
|
|
registries = filter(self.CheckValidRegistry, registries_list)
|
|
new_helpers = cred_utils.GetGcloudCredentialHelperConfig(registries)
|
|
else:
|
|
# If include-artifact-registry is set, add all GCR and AR repos, otherwise
|
|
# just GCR repos.
|
|
if args.include_artifact_registry:
|
|
log.status.Print('Adding credentials for all GCR and AR repositories.')
|
|
else:
|
|
log.status.Print('Adding credentials for all GCR repositories.')
|
|
log.warning('A long list of credential helpers may cause delays running '
|
|
'\'docker build\'. We recommend passing the registry name to '
|
|
'configure only the registry you are using.')
|
|
new_helpers = cred_utils.GetGcloudCredentialHelperConfig(
|
|
None, args.include_artifact_registry)
|
|
|
|
# Merge in the new settings so that existing configs are preserved.
|
|
merged_helper_map = current_helper_map.copy()
|
|
merged_helper_map.update(new_helpers[cred_utils.CREDENTIAL_HELPER_KEY])
|
|
|
|
if current_helper_map == merged_helper_map:
|
|
log.status.Print(
|
|
'gcloud credential helpers already registered correctly.')
|
|
return
|
|
|
|
merged_helpers = {cred_utils.CREDENTIAL_HELPER_KEY: merged_helper_map}
|
|
console_io.PromptContinue(
|
|
message='After update, the following will be written to your Docker '
|
|
'config file located at [{0}]:\n {1}'.format(
|
|
current_config.path, json.dumps(merged_helpers, indent=2)),
|
|
cancel_on_no=True)
|
|
|
|
current_config.RegisterCredentialHelpers(merged_helper_map)
|
|
log.status.Print('Docker configuration file updated.')
|
|
|
|
def CheckValidRegistry(self, registry):
|
|
if registry not in cred_utils.SupportedRegistries():
|
|
log.warning('{0} is not a supported registry'.format(registry))
|
|
return False
|
|
return True
|