def DockerLogin(server, username, access_token): """Register the username / token for the given server on Docker's keyring.""" # Sanitize and normalize the server input. parsed_url = client_lib.GetNormalizedURL(server) server = parsed_url.geturl() # 'docker login' must be used due to the change introduced in # https://github.com/docker/docker/pull/20107 . docker_args = ['login'] docker_args.append('--username='******'--password='******'Docker CLI operation failed:') log.out.Print(stdoutdata) log.status.Print(stderrdata) raise client_lib.DockerError('Docker login failed.')
def _UpdateDockerConfig(server, username, access_token): """Register the username / token for the given server on Docker's keyring.""" # NOTE: using "docker login" doesn't work as they're quite strict on what # is allowed in username/password. try: dockercfg_contents = ReadDockerAuthConfig() except (IOError, client_lib.InvalidDockerConfigError): # If the file doesn't exist, start with an empty map. dockercfg_contents = {} # Add the entry for our server. auth = username + ':' + access_token auth = base64.b64encode(auth.encode('ascii')).decode('ascii') # Sanitize and normalize the server input. parsed_url = client_lib.GetNormalizedURL(server) server = parsed_url.geturl() server_unqualified = parsed_url.hostname # Clear out any unqualified stale entry for this server if server_unqualified in dockercfg_contents: del dockercfg_contents[server_unqualified] dockercfg_contents[server] = {'auth': auth, 'email': _EMAIL} WriteDockerAuthConfig(dockercfg_contents)
def UpdateDockerCredentials(server, refresh=True): """Updates the docker config to have fresh credentials. This reads the current contents of Docker's keyring, and extends it with a fresh entry for the provided 'server', based on the active gcloud credential. If a credential exists for 'server' this replaces it. Args: server: The hostname of the registry for which we're freshening the credential. refresh: Whether to force a token refresh on the active credential. Raises: store.Error: There was an error loading the credentials. """ # Loading credentials will ensure that we're logged in. # And prompt/abort to 'run gcloud auth login' otherwise. # Disable refreshing, since we'll do this ourself. cred = store.Load(prevent_refresh=True) if refresh: # Ensure our credential has a valid access token, # which has the full duration available. store.Refresh(cred) if not cred.access_token: raise exceptions.Error( 'No access token could be obtained from the current credentials.') url = client_lib.GetNormalizedURL(server) # Strip the port, if it exists. It's OK to butcher IPv6, this is only an # optimization for hostnames in constants.ALL_SUPPORTED_REGISTRIES. hostname = url.hostname.split(':')[0] third_party_cred_helper = (_CredentialHelperConfigured() and not _GCRCredHelperConfigured()) if (third_party_cred_helper or hostname not in constants.ALL_SUPPORTED_REGISTRIES): # If this is a custom host or if there's a third-party credential helper... try: # Update the credentials stored by docker, passing the access token # as a password, and benign values as the email and username. DockerLogin(server, _EMAIL, _USERNAME, cred.access_token) except client_lib.DockerError as e: # Only catch docker-not-found error if str(e) != client_lib.DOCKER_NOT_FOUND_ERROR: raise # Fall back to the previous manual .dockercfg manipulation # in order to support gcloud app's docker-binaryless use case. _UpdateDockerConfig(server, _USERNAME, cred.access_token) log.warn( "'docker' was not discovered on the path. Credentials have been " 'stored, but are not guaranteed to work with the Docker client ' ' if an external credential store is configured.') elif not _GCRCredHelperConfigured(): # If this is not a custom host and no third-party cred helper... _UpdateDockerConfig(server, _USERNAME, cred.access_token)
def testGetNormalizedURLNoScheme(self): input_url = 'gcr.io' expected_url = urllib.parse.urlparse('https://gcr.io') self.assertEqual(expected_url, client_lib.GetNormalizedURL(input_url))
def testGetNormalizedURLFromLocalHost(self): input_url = 'localhost' expected_url = urllib.parse.urlparse('http://localhost') self.assertEqual(expected_url, client_lib.GetNormalizedURL(input_url))