def walk_string(s): try: as_tag = docker_name.Tag(s) if as_tag in overrides: return str(overrides[as_tag]) # Resolve the tag to digest using the standard # Docker keychain logic. creds = docker_creds.DefaultKeychain.Resolve(as_tag) with v2_2_image.FromRegistry(as_tag, creds, transport) as img: if img.exists(): digest = str( docker_name.Digest('{repository}@{digest}'.format( repository=as_tag.as_repository(), digest=util.Digest(img.manifest())))) else: # If the tag doesn't exists as v2.2, then try as v2. with v2_image.FromRegistry(as_tag, creds, transport) as img: digest = str( docker_name.Digest('{repository}@{digest}'.format( repository=as_tag.as_repository(), digest=v2_util.Digest(img.manifest())))) # Make sure we consistently resolve all instances of a tag, # since it is technically possible to have a race here. overrides[as_tag] = digest return digest except: return s
def images(self): """Returns a list of tuples whose elements are (name, platform, image). Raises: InvalidMediaTypeError: a child with an unexpected media type was found. """ manifests = json.loads(self.manifest())['manifests'] results = [] for entry in manifests: digest = entry['digest'] name = docker_name.Digest('{base}@{digest}'.format( base=self._name.as_repository(), digest=digest)) # TODO(user): Support Image Index. if entry['mediaType'] == docker_http.MANIFEST_LIST_MIME: image = FromRegistry(name, self._creds, self._original_transport) elif entry['mediaType'] == docker_http.MANIFEST_SCHEMA2_MIME: image = v2_2_image.FromRegistry(name, self._creds, self._original_transport) else: raise InvalidMediaTypeError('Invalid media type: ' + entry['mediaType']) platform = Platform(entry['platform']) if 'platform' in entry else None results.append((name, platform, image)) return results
def main(): args = parser.parse_args() if not args.name or not args.directory: raise Exception('--name and --directory are required arguments.') transport = transport_pool.Http(httplib2.Http, size=_THREADS) if '@' in args.name: name = docker_name.Digest(args.name) else: name = docker_name.Tag(args.name) # Resolve the appropriate credential to use based on the standard Docker # client logic. creds = docker_creds.DefaultKeychain.Resolve(name) with v2_2_image.FromRegistry(name, creds, transport) as v2_2_img: if v2_2_img.exists(): save.fast(v2_2_img, args.directory, threads=_THREADS) return with v2_image.FromRegistry(name, creds, transport) as v2_img: with v2_compat.V22FromV2(v2_img) as v2_2_img: save.fast(v2_2_img, args.directory, threads=_THREADS) return
def images(self): """Returns a list of tuples whose elements are (name, platform, image). Raises: InvalidMediaTypeError: a child with an unexpected media type was found. """ manifests = json.loads(self.manifest())['manifests'] results = [] for entry in manifests: digest = entry['digest'] base = self._name.as_repository() # pytype: disable=attribute-error name = docker_name.Digest('{base}@{digest}'.format(base=base, digest=digest)) media_type = entry['mediaType'] if media_type in docker_http.MANIFEST_LIST_MIMES: image = FromRegistry(name, self._creds, self._original_transport) elif media_type in docker_http.SUPPORTED_MANIFEST_MIMES: image = v2_2_image.FromRegistry(name, self._creds, self._original_transport, [media_type]) else: raise InvalidMediaTypeError('Invalid media type: ' + media_type) platform = Platform( entry['platform']) if 'platform' in entry else None results.append((name, platform, image)) return results
def main(): args = parser.parse_args() if not args.name or not args.directory: raise Exception('--name and --directory are required arguments.') transport = transport_pool.Http(httplib2.Http, size=_THREADS) if '@' in args.name: name = docker_name.Digest(args.name) else: name = docker_name.Tag(args.name) # OCI Image Manifest is compatible with Docker Image Manifest Version 2, # Schema 2. We indicate support for both formats by passing both media types # as 'Accept' headers. # # For reference: # OCI: https://github.com/opencontainers/image-spec # Docker: https://docs.docker.com/registry/spec/manifest-v2-2/ accept = docker_http.SUPPORTED_MANIFEST_MIMES # Resolve the appropriate credential to use based on the standard Docker # client logic. creds = docker_creds.DefaultKeychain.Resolve(name) with v2_2_image.FromRegistry(name, creds, transport, accept) as v2_2_img: if v2_2_img.exists(): save.fast(v2_2_img, args.directory, threads=_THREADS) return with v2_image.FromRegistry(name, creds, transport) as v2_img: with v2_compat.V22FromV2(v2_img) as v2_2_img: save.fast(v2_2_img, args.directory, threads=_THREADS) return
def __iter__(self): results = [] for (platform, manifest) in self._images: name = docker_name.Digest('{base}@{digest}'.format( base=self._name.as_repository(), digest=manifest.digest())) results.append((name, platform, manifest)) return iter(results)
def main(): args = parser.parse_args() if not args.name or not args.tarball: raise Exception('--name and --tarball are required arguments.') transport = transport_pool.Http(httplib2.Http, size=8) if '@' in args.name: name = docker_name.Digest(args.name) else: name = docker_name.Tag(args.name) # Resolve the appropriate credential to use based on the standard Docker # client logic. creds = docker_creds.DefaultKeychain.Resolve(name) with tarfile.open(name=args.tarball, mode='w') as tar: with v2_2_image.FromRegistry(name, creds, transport) as v2_2_img: if v2_2_img.exists(): save.tarball(_make_tag_if_digest(name), v2_2_img, tar) return with v2_image.FromRegistry(name, creds, transport) as v2_img: with v2_compat.V22FromV2(v2_img) as v2_2_img: save.tarball(_make_tag_if_digest(name), v2_2_img, tar) return
def MakeSignaturePayloadDict(container_image_url): """Creates a dict representing a JSON signature object to sign. Args: container_image_url: See `containerregistry.client.docker_name.Digest` for artifact URL validation and parsing details. `container_image_url` must be a fully qualified image URL with a valid sha256 digest. Returns: Dictionary of nested dictionaries and strings, suitable for passing to `json.dumps` or similar. """ url = _ReplaceImageUrlScheme(image_url=container_image_url, scheme='') try: repo_digest = docker_name.Digest(url) except docker_name.BadNameException as e: raise BadImageUrlError(e) return { 'critical': { 'identity': { 'docker-reference': six.text_type(repo_digest.as_repository()), }, 'image': { 'docker-manifest-digest': repo_digest.digest, }, 'type': 'Google cloud binauthz container signature', }, }
def GetDigestFromName(image_name): """Gets a digest object given a repository, tag or digest. Args: image_name: A docker image reference, possibly underqualified. Returns: a docker_name.Digest object. Raises: InvalidImageNameError: If no digest can be resolved. """ tag_or_digest = GetDockerImageFromTagOrDigest(image_name) # If we got a digest, then just return it. if isinstance(tag_or_digest, docker_name.Digest): return tag_or_digest # If we got a tag, resolve it to a digest. def ResolveV2Tag(tag): with v2_image.FromRegistry( basic_creds=CredentialProvider(), name=tag, transport=http.Http()) as v2_img: if v2_img.exists(): return v2_img.digest() return None def ResolveV22Tag(tag): with v2_2_image.FromRegistry( basic_creds=CredentialProvider(), name=tag, transport=http.Http(), accepted_mimes=v2_2_docker_http.SUPPORTED_MANIFEST_MIMES) as v2_2_img: if v2_2_img.exists(): return v2_2_img.digest() return None def ResolveManifestListTag(tag): with docker_image_list.FromRegistry( basic_creds=CredentialProvider(), name=tag, transport=http.Http()) as manifest_list: if manifest_list.exists(): return manifest_list.digest() return None # Resolve as manifest list, then v2.2, then v2.1 because for compatibility: # - manifest lists can be rewritten to v2.2 "default" images. # - v2.2 manifests can be rewritten to v2.1 manifests. sha256 = ( ResolveManifestListTag(tag_or_digest) or ResolveV22Tag(tag_or_digest) or ResolveV2Tag(tag_or_digest)) if not sha256: raise InvalidImageNameError( '[{0}] is not a valid name. Expected tag in the form "base:tag" or ' '"tag" or digest in the form "sha256:<digest>"'.format(image_name)) return docker_name.Digest('{registry}/{repository}@{sha256}'.format( registry=tag_or_digest.registry, repository=tag_or_digest.repository, sha256=sha256))
def testDigest(self): repo = 'gcr.io/google-appengine/java-compat' hex_str = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b' expected_digest = docker_name.Digest('{repo}@sha256:{hex_str}'.format( repo=repo, hex_str=hex_str)) digest = util.GetDigestFromName(str(expected_digest)) self.assertEqual(expected_digest, digest)
def Publish(transport, image_chroot, name=None, tarball=None, config=None, digest=None, layer=None): if not name: raise Exception('Expected "name" kwarg') if not config and (layer or digest): raise Exception( name + ': Using "layer" or "digest" requires "config" to be specified.') if config: with open(config, 'r') as reader: config = reader.read() elif tarball: with v2_2_image.FromTarball(tarball) as base: config = base.config_file() else: raise Exception(name + ': Either "config" or "tarball" must be specified.') if digest or layer: digest = digest.split(',') layer = layer.split(',') if len(digest) != len(layer): raise Exception( name + ': "digest" and "layer" must have matching lengths.') else: digest = [] layer = [] name_to_replace = name if image_chroot: name_to_publish = docker_name.Tag(os.path.join(image_chroot, name), strict=False) else: # Without a chroot, the left-hand-side must be a valid tag. name_to_publish = docker_name.Tag(name, strict=False) # Resolve the appropriate credential to use based on the standard Docker # client logic. creds = docker_creds.DefaultKeychain.Resolve(name_to_publish) with v2_2_session.Push(name_to_publish, creds, transport, threads=_THREADS) as session: with v2_2_image.FromDisk(config, zip(digest or [], layer or []), legacy_base=tarball) as v2_2_img: session.upload(v2_2_img) return (name_to_replace, docker_name.Digest('{repository}@{digest}'.format( repository=name_to_publish.as_repository(), digest=v2_2_img.digest())))
def _parse_image_reference(image_reference): util.check_type(image_reference, str) if '@' in image_reference: name = docker_name.Digest(image_reference) else: name = docker_name.Tag(image_reference) return name
def NormalizeArtifactUrl(artifact_url): """Normalizes given URL by ensuring the scheme is https.""" url_without_scheme = _ReplaceImageUrlScheme(artifact_url, scheme='') try: # The validation logic in `docker_name` silently produces incorrect results # if the passed URL has a scheme. docker_name.Digest(url_without_scheme) except docker_name.BadNameException as e: raise BadImageUrlError(e) return _ReplaceImageUrlScheme(artifact_url, scheme='https')
def _get_tags(self, repo, digest): full_digest = repo + '@sha256:' + digest name = docker_name.Digest(full_digest) creds = docker_creds.DefaultKeychain.Resolve(name) transport = transport_pool.Http(httplib2.Http) with docker_image.FromRegistry(name, creds, transport) as img: return img.tags() raise AssertionError('Unable to get tags from {0}'.format(full_digest))
def NormalizeArtifactUrl(artifact_url): """Normalizes given URL by ensuring the scheme is https.""" if '//' not in artifact_url: artifact_url = '//' + artifact_url parsed_url = urlparse.urlparse(artifact_url) url = urlparse.ParseResult('https', *parsed_url[1:]).geturl() try: docker_name.Digest(url) # Just check over the URL. except docker_name.BadNameException as e: raise BadImageUrlError(e) return url
def main(): logging_setup.DefineCommandLineArgs(parser) args = parser.parse_args() logging_setup.Init(args=args) if not args.name or not args.tarball: logging.fatal('--name and --tarball are required arguments.') sys.exit(1) retry_factory = retry.Factory() retry_factory = retry_factory.WithSourceTransportCallable(httplib2.Http) transport = transport_pool.Http(retry_factory.Build, size=8) if '@' in args.name: name = docker_name.Digest(args.name) else: name = docker_name.Tag(args.name) # OCI Image Manifest is compatible with Docker Image Manifest Version 2, # Schema 2. We indicate support for both formats by passing both media types # as 'Accept' headers. # # For reference: # OCI: https://github.com/opencontainers/image-spec # Docker: https://docs.docker.com/registry/spec/manifest-v2-2/ accept = docker_http.SUPPORTED_MANIFEST_MIMES # Resolve the appropriate credential to use based on the standard Docker # client logic. try: creds = docker_creds.DefaultKeychain.Resolve(name) # pylint: disable=broad-except except Exception as e: logging.fatal('Error resolving credentials for %s: %s', name, e) sys.exit(1) try: with tarfile.open(name=args.tarball, mode='w') as tar: logging.info('Pulling v2.2 image from %r ...', name) with v2_2_image.FromRegistry(name, creds, transport, accept) as v2_2_img: if v2_2_img.exists(): save.tarball(_make_tag_if_digest(name), v2_2_img, tar) return logging.info('Pulling v2 image from %r ...', name) with v2_image.FromRegistry(name, creds, transport) as v2_img: with v2_compat.V22FromV2(v2_img) as v2_2_img: save.tarball(_make_tag_if_digest(name), v2_2_img, tar) return # pylint: disable=broad-except except Exception as e: logging.fatal('Error pulling and saving image %s: %s', name, e) sys.exit(1)
def main(): digest = 'fake.gcr.io/test/test@sha256:' + DIGEST tag = 'fake.gcr.io/test/test:tag' src_name = docker_name.Digest(digest) dest_name = docker_name.Tag(tag) creds = docker_creds.DefaultKeychain.Resolve(src_name) transport = transport_pool.Http(httplib2.Http) with docker_image.FromRegistry(src_name, creds, transport) as src_img: if src_img.exists(): creds = docker_creds.DefaultKeychain.Resolve(dest_name) with docker_session.Push(dest_name, creds, transport) as push: push.upload(src_img)
def get_existing_tags(self, full_repo, digest): full_digest = full_repo + '@sha256:' + digest existing_tags = [] name = docker_name.Digest(full_digest) creds = docker_creds.DefaultKeychain.Resolve(name) transport = transport_pool.Http(httplib2.Http) with docker_image.FromRegistry(name, creds, transport) as img: if img.exists(): existing_tags = img.tags() else: logging.debug("""Unable to get existing tags for {0} as the image can't be found""".format(full_digest)) return existing_tags
def testRepoV22(self, list_registry, v2_2_registry, v2_registry): repo = 'gcr.io/google-appengine/java-compat' hex_str = '01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b' expected_digest = docker_name.Digest('{repo}@sha256:{hex_str}'.format( repo=repo, hex_str=hex_str)) v2_registry.return_value.__enter__.return_value.exists.return_value = False v2_2_registry.return_value.__enter__.return_value.exists.return_value = True v2_2_registry.return_value.__enter__.return_value.digest.return_value = ( expected_digest.digest) list_registry.return_value.__enter__.return_value.exists.return_value = ( False) digest = util.GetDigestFromName(repo) self.assertEqual(expected_digest, digest)
def _del_img_from_gcr(self, img_name): img_tag = docker_name.Tag(img_name) creds = docker_creds.DefaultKeychain.Resolve(img_tag) transport = transport_pool.Http(httplib2.Http, size=_THREADS) with docker_image.FromRegistry(img_tag, creds, transport) as base_image: img_digest = docker_name.Digest(''.join( [self._name.split(":")[0], "@", str(base_image.digest())])) logging.info('Deleting tag {0}'.format(img_tag)) docker_session.Delete(img_tag, creds, transport) logging.info('Deleting image {0}'.format(img_digest)) docker_session.Delete(img_digest, creds, transport) return
def test_tag_to_digest_not_cached(self): with v2_2_image.FromTarball( TestData( 'io_bazel_rules_k8s/examples/hellogrpc/cc/server/server.tar' )) as img: # Add a fake exists method to look like FromRegistry img.exists = lambda: True with mock.patch.object(v2_2_image, 'FromRegistry', return_value=img): tag = docker_name.Tag('gcr.io/foo/bar:baz') expected_digest = docker_name.Digest('gcr.io/foo/bar@' + img.digest()) actual_digest = resolver.TagToDigest(tag, {}, _BAD_TRANSPORT) self.assertEqual(actual_digest, str(expected_digest))
def main(): args = parser.parse_args() if not args.name: raise Exception('--name is a required arguments.') # This library can support push-by-digest, but the likelihood of a user # correctly providing us with the digest without using this library # directly is essentially nil. name = Tag(args.name, args.stamp_info_file) if not args.config and (args.layer or args.digest): raise Exception( 'Using --layer or --digest requires --config to be specified.') if not args.config and not args.tarball: raise Exception('Either --config or --tarball must be specified.') # If config is specified, use that. Otherwise, fallback on reading # the config from the tarball. config = args.config if args.config: with open(args.config, 'r') as reader: config = reader.read() elif args.tarball: with v2_2_image.FromTarball(args.tarball) as base: config = base.config_file() if len(args.digest or []) != len(args.layer or []): raise Exception('--digest and --layer must have matching lengths.') transport = transport_pool.Http(httplib2.Http, size=_THREADS) # Resolve the appropriate credential to use based on the standard Docker # client logic. creds = docker_creds.DefaultKeychain.Resolve(name) with docker_session.Push(name, creds, transport, threads=_THREADS) as session: with v2_2_image.FromDisk(config, zip(args.digest or [], args.layer or []), legacy_base=args.tarball) as v2_2_img: session.upload(v2_2_img) print '%s=%s' % ( name, docker_name.Digest('{repository}@{digest}'.format( repository=name.as_repository(), digest=util.Digest(v2_2_img.manifest()))))
def GetDigestFromName(image_name): """Gets a digest object given a repository, tag or digest. Args: image_name: A docker image reference, possibly underqualified. Returns: a docker_name.Digest object. Raises: InvalidImageNameError: If no digest can be resolved. """ tag_or_digest = GetDockerImageFromTagOrDigest(image_name) # If we got a digest, then just return it. if isinstance(tag_or_digest, docker_name.Digest): return tag_or_digest # If we got a tag, resolve it to a digest. def ResolveV2Tag(tag): with v2_image.FromRegistry(basic_creds=CredentialProvider(), name=tag, transport=http.Http()) as v2_img: if v2_img.exists(): return v2_img.digest() return None def ResolveV22Tag(tag): with v2_2_image.FromRegistry(basic_creds=CredentialProvider(), name=tag, transport=http.Http()) as v2_2_img: if v2_2_img.exists(): return v2_2_img.digest() return None # Resolve v2.2 first because we will exist via a compatibility layer. sha256 = ResolveV22Tag(tag_or_digest) or ResolveV2Tag(tag_or_digest) if not sha256: raise InvalidImageNameError( '[{0}] is not a valid name.'.format(image_name)) return docker_name.Digest('{registry}/{repository}@{sha256}'.format( registry=tag_or_digest.registry, repository=tag_or_digest.repository, sha256=sha256))
def GetDockerImageFromTagOrDigest(image_name): """Gets an image object given either a tag or a digest. Args: image_name: Either a fully qualified tag or a fully qualified digest. Defaults to latest if no tag specified. Returns: Either a docker_name.Tag or a docker_name.Digest object. Raises: InvalidImageNameError: Given digest could not be resolved to a full digest. """ if not IsFullySpecified(image_name): image_name += ':latest' try: return ValidateImagePathAndReturn(docker_name.Tag(image_name)) except docker_name.BadNameException: pass parts = image_name.split('@', 1) if len(parts) == 2: if not parts[1].startswith('sha256:'): raise InvalidImageNameError( '[{0}] digest must be of the form "sha256:<digest>".'.format( image_name)) # If the full digest wasn't specified, check if what was passed # in is a valid digest prefix. # 7 for 'sha256:' and 64 for the full digest if len(parts[1]) < 7 + 64: resolved = GetDockerDigestFromPrefix(image_name) if resolved == image_name: raise InvalidImageNameError( '[{0}] could not be resolved to a full digest.'.format( image_name)) image_name = resolved try: return ValidateImagePathAndReturn(docker_name.Digest(image_name)) except docker_name.BadNameException: raise InvalidImageNameError( '[{0}] digest must be of the form "sha256:<digest>".'.format( image_name))
def add_tags(self, digest, tag, dry_run): if dry_run: logging.debug('Would have tagged {0} with {1}'.format(digest, tag)) return src_name = docker_name.Digest(digest) dest_name = docker_name.Tag(tag) creds = docker_creds.DefaultKeychain.Resolve(src_name) transport = transport_pool.Http(httplib2.Http) with docker_image.FromRegistry(src_name, creds, transport) as src_img: if src_img.exists(): creds = docker_creds.DefaultKeychain.Resolve(dest_name) logging.debug('Tagging {0} with {1}'.format(digest, tag)) with docker_session.Push(dest_name, creds, transport) as push: push.upload(src_img) else: logging.debug("""Unable to tag {0} as the image can't be found""".format(digest))
def GetDockerImageFromTagOrDigest(image_name): """Gets an image object given either a tag or a digest. Args: image_name: Either a fully qualified tag or a fully qualified digest. Defaults to latest if no tag specified. Returns: Either a docker_name.Tag or a docker_name.Digest object. """ if not IsFullySpecified(image_name): image_name += ':latest' try: return docker_name.Tag(image_name) except docker_name.BadNameException: pass # If the full digest wasn't specified, check if what was passed # in is a valid digest prefix. # 7 for 'sha256:' and 64 for the full digest parts = image_name.split('@', 1) if len(parts) == 2 and len(parts[1]) < 7 + 64: image_name = GetDockerDigestFromPrefix(image_name) return docker_name.Digest(image_name)
def main(): logging_setup.DefineCommandLineArgs(parser) args = parser.parse_args() logging_setup.Init(args=args) if not args.name or not args.directory: logging.fatal('--name and --directory are required arguments.') retry_factory = retry.Factory() retry_factory = retry_factory.WithSourceTransportCallable(httplib2.Http) transport = transport_pool.Http(retry_factory.Build, size=_THREADS) if '@' in args.name: name = docker_name.Digest(args.name) else: name = docker_name.Tag(args.name) # OCI Image Manifest is compatible with Docker Image Manifest Version 2, # Schema 2. We indicate support for both formats by passing both media types # as 'Accept' headers. # # For reference: # OCI: https://github.com/opencontainers/image-spec # Docker: https://docs.docker.com/registry/spec/manifest-v2-2/ accept = docker_http.SUPPORTED_MANIFEST_MIMES # Resolve the appropriate credential to use based on the standard Docker # client logic. try: creds = docker_creds.DefaultKeychain.Resolve(name) # pylint: disable=broad-except except Exception as e: logging.fatal('Error resolving credentials for %s: %s', name, e) sys.exit(1) try: logging.info('Pulling manifest list from %r ...', name) with image_list.FromRegistry(name, creds, transport) as img_list: if img_list.exists(): platform = image_list.Platform({ 'architecture': _PROCESSOR_ARCHITECTURE, 'os': _OPERATING_SYSTEM, }) # pytype: disable=wrong-arg-types with img_list.resolve(platform) as default_child: save.fast(default_child, args.directory, threads=_THREADS) return # pytype: enable=wrong-arg-types logging.info('Pulling v2.2 image from %r ...', name) with v2_2_image.FromRegistry(name, creds, transport, accept) as v2_2_img: if v2_2_img.exists(): save.fast(v2_2_img, args.directory, threads=_THREADS) return logging.info('Pulling v2 image from %r ...', name) with v2_image.FromRegistry(name, creds, transport) as v2_img: with v2_compat.V22FromV2(v2_img) as v2_2_img: save.fast(v2_2_img, args.directory, threads=_THREADS) return # pylint: disable=broad-except except Exception as e: logging.fatal('Error pulling and saving image %s: %s', name, e) sys.exit(1)
def main(): logging_setup.DefineCommandLineArgs(parser) args = parser.parse_args() logging_setup.Init(args=args) # retry if error acc to retry plan retry_factory = retry.Factory() retry_factory = retry_factory.WithSourceTransportCallable(httplib2.Http) transport = transport_pool.Http(retry_factory.Build, size=_THREADS) if '@' in args.name: name = docker_name.Digest(args.name) else: name = docker_name.Tag(args.name) # If the user provided a client config directory, instruct the keychain # resolver to use it to look for the docker client config if args.client_config_dir is not None: docker_creds.DefaultKeychain.setCustomConfigDir(args.client_config_dir) # OCI Image Manifest is compatible with Docker Image Manifest Version 2, # Schema 2. We indicate support for both formats by passing both media types # as 'Accept' headers. # # For reference: # OCI: https://github.com/opencontainers/image-spec # Docker: https://docs.docker.com/registry/spec/manifest-v2-2/ accept = docker_http.SUPPORTED_MANIFEST_MIMES # Resolve the appropriate credential to use based on the standard Docker # client logic. try: # check username/paswd match up creds = docker_creds.DefaultKeychain.Resolve(name) # pylint: disable=broad-except except Exception as e: logging.fatal('Error resolving credentials for %s: %s', name, e) sys.exit(1) try: logging.info('Pulling manifest list from %r ...', name) # (image, [(.sha, tar)]) with image_list.FromRegistry(name, creds, transport) as img_list: if img_list.exists(): # populate docker_image_list.Platform object (runtime requirements for an object) # from the provided args # see: docker image manifest list platform = platform_args.FromArgs(args) # pytype: disable=wrong-arg-types with img_list.resolve(platform) as default_child: # save.fast( # create new filesystem (directory) with config files and sha/tars (_save.py) default_child, args.directory, threads=_THREADS, cache_directory=args.cache) return # pytype: enable=wrong-arg-types logging.info('Pulling v2.2 image from %r ...', name) with v2_2_image.FromRegistry(name, creds, transport, accept) as v2_2_img: if v2_2_img.exists(): save.fast(v2_2_img, args.directory, threads=_THREADS, cache_directory=args.cache) return logging.info('Pulling v2 image from %r ...', name) with v2_image.FromRegistry(name, creds, transport) as v2_img: with v2_compat.V22FromV2(v2_img) as v2_2_img: save.fast(v2_2_img, args.directory, threads=_THREADS, cache_directory=args.cache) return # pylint: disable=broad-except except Exception as e: logging.fatal('Error pulling and saving image %s: %s', name, e) sys.exit(1)
def reconcile_tags(self, data, dry_run): for project in data['projects']: default_registry = project['base_registry'] registries = project.get('additional_registries', []) registries.append(default_registry) default_repo = os.path.join(default_registry, project['repository']) for image in project['images']: digest = self.get_digest_from_prefix(default_repo, image['digest']) default_digest = default_repo + '@sha256:' + digest default_name = docker_name.Digest(default_digest) default_creds = ( docker_creds.DefaultKeychain.Resolve(default_name)) transport = transport_pool.Http(httplib2.Http) # Bail out if the digest in the config file doesn't exist. with docker_image.FromRegistry(default_name, default_creds, transport) as img: if not img.exists(): logging.debug('Could not retrieve ' + '{0}'.format(default_digest)) return for registry in registries: full_repo = os.path.join(registry, project['repository']) full_digest = full_repo + '@sha256:' + digest name = docker_name.Digest(full_digest) creds = docker_creds.DefaultKeychain.Resolve(name) with docker_image.FromRegistry(name, creds, transport) as img: if img.exists(): existing_tags = img.tags() logging.debug('Existing Tags: ' + '{0}'.format(existing_tags)) manifests = img.manifests() tagged_digest = self.get_tagged_digest( manifests, image['tag']) # Don't retag an image if the tag already exists if tagged_digest.startswith('sha256:'): tagged_digest = tagged_digest[len('sha256:'):] if tagged_digest.startswith(digest): logging.debug( 'Skipping tagging %s with %s as ' 'that tag already exists.', digest, image['tag']) continue # We can safely retag now. full_tag = full_repo + ':' + image['tag'] self.add_tags(default_digest, full_tag, dry_run) logging.debug(self.get_existing_tags(default_repo, digest))
def fully_qualify_digest(digest): return docker_name.Digest('{registry}/{repo}@{digest}'.format( registry=tag.registry, repo=tag.repository, digest=digest))