Write out /v2/_catalog file after image export

A GET request to this path is part of the registry API[1] and writing
out this file provides further parity with the docker-distribution
service which image-serve replaces.

Blueprint: podman-support

[1] https://docs.docker.com/registry/spec/api/#catalog

Change-Id: I533b668048191bb3f8f236e92ae2bb2c350647b9
This commit is contained in:
Steve Baker 2019-03-13 09:57:42 +13:00
parent 99155d992c
commit 3e0e9498bd
2 changed files with 32 additions and 6 deletions

View File

@ -138,8 +138,8 @@ def export_manifest_config(target_url,
config_digest = manifest['config']['digest'] config_digest = manifest['config']['digest']
config_path = os.path.join(blob_dir_path, config_digest) config_path = os.path.join(blob_dir_path, config_digest)
with open(config_path, 'w+') as f: with open(config_path, 'w+b') as f:
f.write(config_str) f.write(config_str.encode('utf-8'))
calc_digest = hashlib.sha256() calc_digest = hashlib.sha256()
calc_digest.update(manifest_str.encode('utf-8')) calc_digest.update(manifest_str.encode('utf-8'))
@ -156,6 +156,7 @@ def export_manifest_config(target_url,
make_dir(manifest_dir_path) make_dir(manifest_dir_path)
make_dir(tags_dir_path) make_dir(tags_dir_path)
build_catalog()
headers = collections.OrderedDict() headers = collections.OrderedDict()
headers['Content-Type'] = manifest_type headers['Content-Type'] = manifest_type
@ -165,8 +166,8 @@ def export_manifest_config(target_url,
for header in headers.items(): for header in headers.items():
f.write('Header set %s "%s"\n' % header) f.write('Header set %s "%s"\n' % header)
with open(manifest_path, 'w+') as f: with open(manifest_path, 'w+b') as f:
f.write(manifest_str) f.write(manifest_str.encode('utf-8'))
if os.path.exists(manifest_symlink_path): if os.path.exists(manifest_symlink_path):
os.remove(manifest_symlink_path) os.remove(manifest_symlink_path)
@ -182,5 +183,23 @@ def export_manifest_config(target_url,
"name": image, "name": image,
"tags": tags "tags": tags
} }
with open(tags_list_path, 'w+') as f: with open(tags_list_path, 'w+b') as f:
json.dump(tags_data, f) f.write(json.dumps(tags_data, ensure_ascii=False).encode('utf-8'))
def build_catalog():
catalog_path = os.path.join(IMAGE_EXPORT_DIR, 'v2', '_catalog')
catalog_entries = []
LOG.debug('Rebuilding %s' % catalog_path)
images_path = os.path.join(IMAGE_EXPORT_DIR, 'v2')
for namespace in os.listdir(images_path):
namespace_path = os.path.join(images_path, namespace)
if not os.path.isdir(namespace_path):
continue
for image in os.listdir(namespace_path):
catalog_entries.append('%s/%s' % (namespace, image))
catalog = {'repositories': catalog_entries}
with open(catalog_path, 'w+b') as f:
f.write(json.dumps(catalog, ensure_ascii=False).encode('utf-8'))

View File

@ -175,6 +175,7 @@ class TestImageExport(base.TestCase):
'mediaType': 'application/vnd.docker.' 'mediaType': 'application/vnd.docker.'
'distribution.manifest.v2+json', 'distribution.manifest.v2+json',
} }
catalog = {'repositories': ['t/nova-api']}
manifest_str = json.dumps(manifest) manifest_str = json.dumps(manifest)
calc_digest = hashlib.sha256() calc_digest = hashlib.sha256()
@ -186,6 +187,10 @@ class TestImageExport(base.TestCase):
image_uploader.MEDIA_MANIFEST_V2, config_str image_uploader.MEDIA_MANIFEST_V2, config_str
) )
catalog_path = os.path.join(
image_export.IMAGE_EXPORT_DIR,
'v2/_catalog'
)
config_path = os.path.join( config_path = os.path.join(
image_export.IMAGE_EXPORT_DIR, image_export.IMAGE_EXPORT_DIR,
'v2/t/nova-api/blobs/sha256:1234' 'v2/t/nova-api/blobs/sha256:1234'
@ -211,6 +216,8 @@ Header set ETag "%s"
manifest_digest manifest_digest
) )
with open(catalog_path, 'r') as f:
self.assertEqual(catalog, json.load(f))
with open(config_path, 'r') as f: with open(config_path, 'r') as f:
self.assertEqual(config_str, f.read()) self.assertEqual(config_str, f.read())
with open(manifest_path, 'r') as f: with open(manifest_path, 'r') as f: