Allow for OCI manifests

We always convert to docker metadata for the undercloud, but we need to
be able to handle OCI source manifests from a remote registry.  We
previously added support to handle the conversion however it wasn't
complete since we only request docker manifests from remote registries.

Change-Id: I3ca3d7c08d08525ead15c50d2e44c9db310859e7
Related-Bug: #1860585
This commit is contained in:
Alex Schultz 2021-09-21 13:31:10 -06:00
parent 1b1ef04b3e
commit e252328bf5
2 changed files with 50 additions and 11 deletions

View File

@ -89,7 +89,10 @@ MEDIA_TYPES = (
MEDIA_MANIFEST_V2,
MEDIA_MANIFEST_V2_LIST,
MEDIA_OCI_MANIFEST_V1,
MEDIA_OCI_CONFIG_V1,
MEDIA_OCI_INDEX_V1,
MEDIA_OCI_LAYER,
MEDIA_OCI_LAYER_COMPRESSED,
MEDIA_CONFIG,
MEDIA_BLOB,
MEDIA_BLOB_COMPRESSED
@ -99,7 +102,10 @@ MEDIA_TYPES = (
'application/vnd.docker.distribution.manifest.v2+json',
'application/vnd.docker.distribution.manifest.list.v2+json',
'application/vnd.oci.image.manifest.v1+json',
'application/vnd.oci.image.config.v1+json',
'application/vnd.oci.image.index.v1+json',
'application/vnd.oci.image.layer.v1.tar',
'application/vnd.oci.image.layer.v1.tar+gzip',
'application/vnd.docker.container.image.v1+json',
'application/vnd.docker.image.rootfs.diff.tar',
'application/vnd.docker.image.rootfs.diff.tar.gzip'
@ -894,7 +900,9 @@ class BaseImageUploader(object):
manifest_url = cls._build_url(
image_url, CALL_MANIFEST % parts
)
manifest_headers = {'Accept': MEDIA_MANIFEST_V2}
# prefer docker manifest over oci
manifest_headers = {'Accept': ", ".join([
MEDIA_MANIFEST_V2 + ";q=1", MEDIA_OCI_MANIFEST_V1 + ";q=0.5"])}
try:
manifest_r = RegistrySessionHelper.get(
@ -1630,7 +1638,9 @@ class PythonImageUploader(BaseImageUploader):
if multi_arch:
manifest_headers = {'Accept': MEDIA_MANIFEST_V2_LIST}
else:
manifest_headers = {'Accept': MEDIA_MANIFEST_V2}
# prefer docker manifest over oci
manifest_headers = {'Accept': ", ".join([
MEDIA_MANIFEST_V2 + ";q=1", MEDIA_OCI_MANIFEST_V1 + ";q=0.5"])}
try:
r = RegistrySessionHelper.get(
session,
@ -1654,12 +1664,16 @@ class PythonImageUploader(BaseImageUploader):
)
manifests_str.append(manifest_str)
manifest = json.loads(manifest_str)
media_type = manifest.get('mediaType',
manifest.get('config', {}).get('mediaType'))
if manifest.get('schemaVersion', 2) == 1:
layers.extend(reversed([x['blobSum']
for x in manifest['fsLayers']]))
elif manifest.get('mediaType') == MEDIA_MANIFEST_V2:
elif not media_type or media_type in [MEDIA_MANIFEST_V2,
MEDIA_OCI_MANIFEST_V1,
MEDIA_OCI_CONFIG_V1]:
layers.extend(x['digest'] for x in manifest['layers'])
elif manifest.get('mediaType') == MEDIA_MANIFEST_V2_LIST:
elif media_type == MEDIA_MANIFEST_V2_LIST:
image, _, tag = image_url.geturl().rpartition(':')
for man in manifest.get('manifests', []):
# replace image tag with the manifest hash in the list
@ -1867,7 +1881,12 @@ class PythonImageUploader(BaseImageUploader):
for source_manifest in source_manifests:
manifest = json.loads(source_manifest)
config_str = None
if manifest.get('mediaType') == MEDIA_MANIFEST_V2:
media_type = manifest.get('mediaType',
manifest.get('config',
{}).get('mediaType'))
if not media_type or media_type in [MEDIA_MANIFEST_V2,
MEDIA_OCI_MANIFEST_V1,
MEDIA_OCI_CONFIG_V1]:
config_digest = manifest['config']['digest']
LOG.debug('[%s] Uploading config with digest: %s' %
(image, config_digest))
@ -1919,8 +1938,27 @@ class PythonImageUploader(BaseImageUploader):
# is explicitly OCI because buildah uses OCI by default but we
# convert the metadata to Docker format in the uploader.
# See LP#1860585
manifest_type = manifest.get('mediaType', False)
if not manifest_type or manifest_type == MEDIA_OCI_MANIFEST_V1:
manifest_type = manifest.get('mediaType',
manifest.get('config',
{}).get('mediaType'))
if not manifest_type or manifest_type in [MEDIA_OCI_MANIFEST_V1,
MEDIA_OCI_CONFIG_V1]:
manifest_type = MEDIA_MANIFEST_V2
# convert config mediaType to docker.container.image
manifest['config']['mediaType'] = MEDIA_CONFIG
layers = manifest.get('layers')
# convert layer type to docker layer type
if layers:
new_layers = []
for layer in layers:
layer_type = layer.get('mediaType')
if layer_type == MEDIA_OCI_LAYER_COMPRESSED:
layer['mediaType'] = MEDIA_BLOB_COMPRESSED
elif layer_type == MEDIA_OCI_LAYER:
layer['mediaType'] = MEDIA_BLOB
new_layers.append(layer)
manifest['layers'] = new_layers
elif manifest_type == MEDIA_CONFIG:
manifest_type = MEDIA_MANIFEST_V2
elif manifest_type == MEDIA_OCI_INDEX_V1:
manifest_type = MEDIA_MANIFEST_V2_LIST

View File

@ -1830,8 +1830,10 @@ class TestPythonImageUploader(base.TestCase):
'nova-api/manifests/tripleo-current',
timeout=30,
headers={
'Accept': 'application/vnd.docker.distribution'
'.manifest.v2+json'
'Accept': 'application/'
'vnd.docker.distribution.manifest.v2+json;q=1, '
'application/'
'vnd.oci.image.manifest.v1+json;q=0.5'
}
)
@ -2189,13 +2191,12 @@ class TestPythonImageUploader(base.TestCase):
'config': {
'digest': 'sha256:1234',
'size': 2,
'mediaType': image_uploader.MEDIA_CONFIG
'mediaType': image_uploader.MEDIA_OCI_CONFIG_V1
},
'layers': [
{'digest': 'sha256:aaaa'},
{'digest': 'sha256:bbbb'},
],
'mediaType': image_uploader.MEDIA_OCI_MANIFEST_V1
})
expected_manifest = {
'config': {