import json from data import model from image.docker.v1 import DockerV1Metadata from endpoints.verbs.models_interface import ( Blob, DerivedImage, ImageWithBlob, Repository, RepositoryReference, TorrentInfo, VerbsDataInterface,) class PreOCIModel(VerbsDataInterface): """ PreOCIModel implements the data model for the registry's custom HTTP verbs using a database schema before it was changed to support the OCI specification. """ def get_repository(self, namespace_name, repo_name): repo = model.repository.get_repository(namespace_name, repo_name) if repo is None: return None return _repository_for_repo(repo) def get_manifest_layers_with_blobs(self, repo_image): repo_image_record = model.image.get_image_by_id( repo_image.repository.namespace_name, repo_image.repository.name, repo_image.image_id) parents = model.image.get_parent_images( repo_image.repository.namespace_name, repo_image.repository.name, repo_image_record) placements_map = model.image.get_placements_for_images(parents) yield repo_image for parent in parents: metadata = {} try: metadata = json.loads(parent.v1_json_metadata) except ValueError: pass locations = [placement.location.name for placement in placements_map[parent.storage.id]] yield ImageWithBlob( image_id=parent.docker_image_id, blob=_blob(parent.storage, locations=locations), repository=repo_image.repository, compat_metadata=metadata, v1_metadata=_docker_v1_metadata(repo_image.repository.namespace_name, repo_image.repository.name, parent), internal_db_id=parent.id,) def get_derived_image_signature(self, derived_image, signer_name): storage = model.storage.get_storage_by_uuid(derived_image.blob.uuid) signature_entry = model.storage.lookup_storage_signature(storage, signer_name) if signature_entry is None: return None return signature_entry.signature def set_derived_image_signature(self, derived_image, signer_name, signature): storage = model.storage.get_storage_by_uuid(derived_image.blob.uuid) signature_entry = model.storage.find_or_create_storage_signature(storage, signer_name) signature_entry.signature = signature signature_entry.uploading = False signature_entry.save() def delete_derived_image(self, derived_image): model.image.delete_derived_storage_by_uuid(derived_image.blob.uuid) def set_blob_size(self, blob, size): storage_entry = model.storage.get_storage_by_uuid(blob.uuid) storage_entry.image_size = size storage_entry.uploading = False storage_entry.save() def get_blob_path(self, blob): blob_record = model.storage.get_storage_by_uuid(blob.uuid) return model.storage.get_layer_path(blob_record) def get_repo_blob_by_digest(self, namespace_name, repo_name, digest): try: blob_record = model.blob.get_repo_blob_by_digest(namespace_name, repo_name, digest) except model.BlobDoesNotExist: return None return _blob(blob_record) def get_torrent_info(self, blob): blob_record = model.storage.get_storage_by_uuid(blob.uuid) try: torrent_info = model.storage.get_torrent_info(blob_record) except model.TorrentInfoDoesNotExist: return None return TorrentInfo( pieces=torrent_info.pieces, piece_length=torrent_info.piece_length,) def set_torrent_info(self, blob, piece_length, pieces): blob_record = model.storage.get_storage_by_uuid(blob.uuid) model.storage.save_torrent_info(blob_record, piece_length, pieces) def lookup_derived_image(self, repo_image, verb, varying_metadata=None): blob_record = model.image.find_derived_storage_for_image(repo_image.internal_db_id, verb, varying_metadata) if blob_record is None: return None return _derived_image(blob_record, repo_image) def lookup_or_create_derived_image(self, repo_image, verb, location, varying_metadata=None): blob_record = model.image.find_or_create_derived_storage(repo_image.internal_db_id, verb, location, varying_metadata) return _derived_image(blob_record, repo_image) def get_tag_image(self, namespace_name, repo_name, tag_name): try: found = model.tag.get_tag_image(namespace_name, repo_name, tag_name, include_storage=True) except model.DataModelException: return None metadata = {} try: metadata = json.loads(found.v1_json_metadata) except ValueError: pass return ImageWithBlob( image_id=found.docker_image_id, blob=_blob(found.storage), repository=RepositoryReference( namespace_name=namespace_name, name=repo_name, id=found.repository_id,), compat_metadata=metadata, v1_metadata=_docker_v1_metadata(namespace_name, repo_name, found), internal_db_id=found.id,) pre_oci_model = PreOCIModel() def _docker_v1_metadata(namespace_name, repo_name, repo_image): """ Returns a DockerV1Metadata object for the given Pre-OCI repo_image under the repository with the given namespace and name. Note that the namespace and name are passed here as an optimization, and are *not checked* against the image. """ return DockerV1Metadata( namespace_name=namespace_name, repo_name=repo_name, image_id=repo_image.docker_image_id, checksum=repo_image.v1_checksum, compat_json=repo_image.v1_json_metadata, created=repo_image.created, comment=repo_image.comment, command=repo_image.command, # Note: These are not needed in verbs and are expensive to load, so we just skip them. content_checksum=None, parent_image_id=None,) def _derived_image(blob_record, repo_image): """ Returns a DerivedImage object for the given Pre-OCI data model blob and repo_image instance. """ return DerivedImage( ref=repo_image.internal_db_id, blob=_blob(blob_record), internal_source_image_db_id=repo_image.internal_db_id,) def _blob(blob_record, locations=None): """ Returns a Blob object for the given Pre-OCI data model blob instance. """ locations = locations or model.storage.get_storage_locations(blob_record.uuid) return Blob( uuid=blob_record.uuid, size=blob_record.image_size, uncompressed_size=blob_record.uncompressed_size, uploading=blob_record.uploading, locations=locations,) def _repository_for_repo(repo): """ Returns a Repository object representing the Pre-OCI data model repo instance given. """ return Repository( id=repo.id, name=repo.name, namespace_name=repo.namespace_user.username, description=repo.description, is_public=model.repository.is_repository_public(repo), kind=model.repository.get_repo_kind_name(repo),)