Support pulling of schema2 manifests directly via a manifest list tag
This change ensures that if a manifest list is requested with an accepts header for a *schema 2* manifest, the legacy manifest (if any) is returned as schema 2 if it was pushed as a schema 2 manifest (rather than being auto-converted to schema 1)
This commit is contained in:
		
							parent
							
								
									a35982f2be
								
							
						
					
					
						commit
						3c2e050593
					
				
					 14 changed files with 215 additions and 15 deletions
				
			
		|  | @ -322,3 +322,10 @@ class RegistryDataInterface(object): | |||
|     """ Returns a cached set of ISO country codes blacklisted for pulls for the namespace | ||||
|         or None if the list could not be loaded. | ||||
|     """ | ||||
| 
 | ||||
|   @abstractmethod | ||||
|   def convert_manifest(self, manifest, namespace_name, repo_name, tag_name, allowed_mediatypes, | ||||
|                        storage): | ||||
|     """ Attempts to convert the specified into a parsed manifest with a media type | ||||
|         in the allowed_mediatypes set. If not possible, or an error occurs, returns None. | ||||
|     """ | ||||
|  |  | |||
|  | @ -482,6 +482,22 @@ class OCIModel(SharedModel, RegistryDataInterface): | |||
|     retriever = RepositoryContentRetriever(manifest_row.repository_id, storage) | ||||
|     return parsed.get_schema1_manifest(namespace_name, repo_name, tag_name, retriever) | ||||
| 
 | ||||
|   def convert_manifest(self, manifest, namespace_name, repo_name, tag_name, allowed_mediatypes, | ||||
|                        storage): | ||||
|     try: | ||||
|       parsed = manifest.get_parsed_manifest() | ||||
|     except ManifestException: | ||||
|       return None | ||||
| 
 | ||||
|     try: | ||||
|       manifest_row = database.Manifest.get(id=manifest._db_id) | ||||
|     except database.Manifest.DoesNotExist: | ||||
|       return None | ||||
| 
 | ||||
|     retriever = RepositoryContentRetriever(manifest_row.repository_id, storage) | ||||
|     return parsed.convert_manifest(allowed_mediatypes, namespace_name, repo_name, tag_name, | ||||
|                                    retriever) | ||||
| 
 | ||||
|   def create_manifest_with_temp_tag(self, repository_ref, manifest_interface_instance, | ||||
|                                     expiration_sec, storage): | ||||
|     """ Creates a manifest under the repository and sets a temporary tag to point to it. | ||||
|  |  | |||
|  | @ -549,6 +549,18 @@ class PreOCIModel(SharedModel, RegistryDataInterface): | |||
|     except ManifestException: | ||||
|       return None | ||||
| 
 | ||||
|   def convert_manifest(self, manifest, namespace_name, repo_name, tag_name, allowed_mediatypes, | ||||
|                        storage): | ||||
|     try: | ||||
|       parsed = manifest.get_parsed_manifest() | ||||
|     except ManifestException: | ||||
|       return None | ||||
| 
 | ||||
|     try: | ||||
|       return parsed.convert_manifest(allowed_mediatypes, namespace_name, repo_name, tag_name, None) | ||||
|     except ManifestException: | ||||
|       return None | ||||
| 
 | ||||
|   def create_manifest_with_temp_tag(self, repository_ref, manifest_interface_instance, | ||||
|                                     expiration_sec, storage): | ||||
|     """ Creates a manifest under the repository and sets a temporary tag to point to it. | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ from data.registry_model.datatypes import RepositoryReference | |||
| from data.registry_model.blobuploader import upload_blob, BlobUploadSettings | ||||
| from data.registry_model.modelsplitter import SplitModel | ||||
| from image.docker.types import ManifestImageLayer | ||||
| from image.docker.schema1 import DockerSchema1ManifestBuilder | ||||
| from image.docker.schema1 import DockerSchema1ManifestBuilder, DOCKER_SCHEMA1_CONTENT_TYPES | ||||
| from image.docker.schema2.manifest import DockerSchema2ManifestBuilder | ||||
| 
 | ||||
| from test.fixtures import * | ||||
|  | @ -780,6 +780,18 @@ def test_get_schema1_parsed_manifest(registry_model): | |||
|   assert registry_model.get_schema1_parsed_manifest(manifest, '', '', '', storage) | ||||
| 
 | ||||
| 
 | ||||
| def test_convert_manifest(registry_model): | ||||
|   repository_ref = registry_model.lookup_repository('devtable', 'simple') | ||||
|   latest_tag = registry_model.get_repo_tag(repository_ref, 'latest', include_legacy_image=True) | ||||
|   manifest = registry_model.get_manifest_for_tag(latest_tag) | ||||
| 
 | ||||
|   mediatypes = DOCKER_SCHEMA1_CONTENT_TYPES | ||||
|   assert registry_model.convert_manifest(manifest, '', '', '', mediatypes, storage) | ||||
| 
 | ||||
|   mediatypes = [] | ||||
|   assert registry_model.convert_manifest(manifest, '', '', '', mediatypes, storage) is None | ||||
| 
 | ||||
| 
 | ||||
| def test_create_manifest_and_retarget_tag_with_labels(registry_model): | ||||
|   repository_ref = registry_model.lookup_repository('devtable', 'simple') | ||||
|   latest_tag = registry_model.get_repo_tag(repository_ref, 'latest', include_legacy_image=True) | ||||
|  |  | |||
		Reference in a new issue