205 lines
6.9 KiB
Python
205 lines
6.9 KiB
Python
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,)
|
|
|
|
def is_namespace_enabled(self, namespace_name):
|
|
namespace = model.user.get_namespace_user(namespace_name)
|
|
return namespace is not None and namespace.enabled
|
|
|
|
|
|
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),)
|