# -*- 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