def multi_image_tarball(tag_to_image, tar, tag_to_v1_image=None): """Produce a "docker save" compatible tarball from the DockerImages. Args: tag_to_image: A dictionary of tags to the images they label. tar: the open tarfile into which we are writing the image tarball. tag_to_v1_image: A dictionary of tags to the v1 form of the images they label. If this isn't provided, the image is simply converted. """ def add_file(filename, contents): info = tarfile.TarInfo(filename) info.size = len(contents) tar.addfile(tarinfo=info, fileobj=io.BytesIO(contents)) tag_to_v1_image = tag_to_v1_image or {} # The manifest.json file contains a list of the images to load # and how to tag them. Each entry consists of three fields: # - Config: the name of the image's config_file() within the # saved tarball. # - Layers: the list of filenames for the blobs constituting # this image. The order is the reverse of the v1 # ancestry ordering. # - RepoTags: the list of tags to apply to this image once it # is loaded. manifests = [] for (tag, image) in six.iteritems(tag_to_image): # The config file is stored in a blob file named with its digest. digest = hashlib.sha256(image.config_file()).hexdigest() add_file(digest + '.json', image.config_file()) cfg = json.loads(image.config_file()) diffs = set(cfg.get('rootfs', {}).get('diff_ids', [])) v1_img = tag_to_v1_image.get(tag) if not v1_img: v2_img = v2_compat.V2FromV22(image) v1_img = v1_compat.V1FromV2(v2_img) tag_to_v1_image[tag] = v1_img # Add the manifests entry for this image. manifests.append({ 'Config': digest + '.json', 'Layers': [ layer_id + '/layer.tar' # We don't just exclude the empty tar because we leave its diff_id # in the set when coming through v2_compat.V22FromV2 for layer_id in reversed(v1_img.ancestry(v1_img.top())) if _diff_id(v1_img, layer_id) in diffs ], 'RepoTags': [str(tag)] }) # v2.2 tarballs are a superset of v1 tarballs, so delegate # to v1 to save itself. v1_save.multi_image_tarball(tag_to_v1_image, tar) add_file('manifest.json', json.dumps(manifests, sort_keys=True))
def multi_image_tarball( tag_to_image, tar, tag_to_v1_image = None ): """Produce a "docker save" compatible tarball from the DockerImages. Args: tag_to_image: A dictionary of tags to the images they label. tar: the open tarfile into which we are writing the image tarball. tag_to_v1_image: A dictionary of tags to the v1 form of the images they label. If this isn't provided, the image is simply converted. """ def add_file(filename, contents): contents_bytes = contents.encode('utf8') info = tarfile.TarInfo(filename) info.size = len(contents_bytes) tar.addfile(tarinfo=info, fileobj=io.BytesIO(contents_bytes)) tag_to_v1_image = tag_to_v1_image or {} # The manifest.json file contains a list of the images to load # and how to tag them. Each entry consists of three fields: # - Config: the name of the image's config_file() within the # saved tarball. # - Layers: the list of filenames for the blobs constituting # this image. The order is the reverse of the v1 # ancestry ordering. # - RepoTags: the list of tags to apply to this image once it # is loaded. manifests = [] for (tag, image) in six.iteritems(tag_to_image): # The config file is stored in a blob file named with its digest. digest = docker_digest.SHA256(image.config_file().encode('utf8'), '') add_file(digest + '.json', image.config_file()) cfg = json.loads(image.config_file()) diffs = set(cfg.get('rootfs', {}).get('diff_ids', [])) v1_img = tag_to_v1_image.get(tag) if not v1_img: v2_img = v2_compat.V2FromV22(image) v1_img = v1_compat.V1FromV2(v2_img) tag_to_v1_image[tag] = v1_img # Add the manifests entry for this image. manifests.append({ 'Config': digest + '.json', 'Layers': [ layer_id + '/layer.tar' # We don't just exclude the empty tar because we leave its diff_id # in the set when coming through v2_compat.V22FromV2 for layer_id in reversed(v1_img.ancestry(v1_img.top())) if _diff_id(v1_img, layer_id) in diffs ], 'RepoTags': [str(tag)] }) # v2.2 tarballs are a superset of v1 tarballs, so delegate # to v1 to save itself. v1_save.multi_image_tarball(tag_to_v1_image, tar) add_file('manifest.json', json.dumps(manifests, sort_keys=True))