This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/data/appr_model/release.py

153 lines
6.8 KiB
Python
Raw Normal View History

2017-03-23 01:51:28 +00:00
import bisect
from cnr.exception import PackageAlreadyExists
from cnr.models.package_base import manifest_media_type
2017-03-23 01:51:28 +00:00
from data.database import db_transaction, get_epoch_timestamp
2018-05-23 21:08:00 +00:00
from data.appr_model import (blob as blob_model, manifest as manifest_model,
2017-03-23 04:21:21 +00:00
manifest_list as manifest_list_model,
tag as tag_model)
2017-03-23 01:51:28 +00:00
LIST_MEDIA_TYPE = 'application/vnd.cnr.manifest.list.v0.json'
SCHEMA_VERSION = 'v0'
def _ensure_sha256_header(digest):
if digest.startswith('sha256:'):
return digest
return 'sha256:' + digest
def get_app_release(repo, tag_name, media_type, models_ref):
2017-03-23 01:51:28 +00:00
""" Returns (tag, manifest, blob) given a repo object, tag_name, and media_type). """
ManifestListManifest = models_ref.ManifestListManifest
Manifest = models_ref.Manifest
Blob = models_ref.Blob
ManifestBlob = models_ref.ManifestBlob
manifestlistmanifest_set_name = models_ref.manifestlistmanifest_set_name
tag = tag_model.get_tag(repo, tag_name, models_ref, tag_kind='release')
2017-03-23 01:51:28 +00:00
media_type_id = ManifestListManifest.media_type.get_id(manifest_media_type(media_type))
manifestlistmanifest = (getattr(tag.manifest_list, manifestlistmanifest_set_name)
2017-03-23 01:51:28 +00:00
.join(Manifest)
.where(ManifestListManifest.media_type == media_type_id).get())
manifest = manifestlistmanifest.manifest
blob = Blob.select().join(ManifestBlob).where(ManifestBlob.manifest == manifest).get()
return (tag, manifest, blob)
def delete_app_release(repo, tag_name, media_type, models_ref):
""" Terminate a Tag/media-type couple
It find the corresponding tag/manifest and remove from the manifestlistmanifest the manifest
1. it terminates the current tag (in all-cases)
2. if the new manifestlist is not empty, it creates a new tag for it
"""
ManifestListManifest = models_ref.ManifestListManifest
manifestlistmanifest_set_name = models_ref.manifestlistmanifest_set_name
2017-03-23 21:50:07 +00:00
media_type_id = ManifestListManifest.media_type.get_id(manifest_media_type(media_type))
with db_transaction():
tag = tag_model.get_tag(repo, tag_name, models_ref)
2017-03-23 21:50:07 +00:00
manifest_list = tag.manifest_list
list_json = manifest_list.manifest_list_json
mlm_query = (ManifestListManifest
.select()
.where(ManifestListManifest.manifest_list == tag.manifest_list))
list_manifest_ids = sorted([mlm.manifest_id for mlm in mlm_query])
manifestlistmanifest = (getattr(tag.manifest_list, manifestlistmanifest_set_name)
2017-03-23 21:50:07 +00:00
.where(ManifestListManifest.media_type == media_type_id).get())
index = list_manifest_ids.index(manifestlistmanifest.manifest_id)
list_manifest_ids.pop(index)
list_json.pop(index)
if not list_json:
tag.lifetime_end = get_epoch_timestamp()
tag.save()
else:
manifestlist = manifest_list_model.get_or_create_manifest_list(list_json, LIST_MEDIA_TYPE,
SCHEMA_VERSION, models_ref)
2017-03-23 21:50:07 +00:00
manifest_list_model.create_manifestlistmanifest(manifestlist, list_manifest_ids,
list_json, models_ref)
tag = tag_model.create_or_update_tag(repo, tag_name, models_ref, manifest_list=manifestlist,
2017-03-23 21:50:07 +00:00
tag_kind="release")
return tag
def create_app_release(repo, tag_name, manifest_data, digest, models_ref, force=False):
2017-03-23 01:51:28 +00:00
""" Create a new application release, it includes creating a new Tag, ManifestList,
ManifestListManifests, Manifest, ManifestBlob.
To deduplicate the ManifestList, the manifestlist_json is kept ordered by the manifest.id.
To find the insert point in the ManifestList it uses bisect on the manifest-ids list.
"""
ManifestList = models_ref.ManifestList
ManifestListManifest = models_ref.ManifestListManifest
Blob = models_ref.Blob
ManifestBlob = models_ref.ManifestBlob
2017-03-23 01:51:28 +00:00
with db_transaction():
# Create/get the package manifest
manifest = manifest_model.get_or_create_manifest(manifest_data, manifest_data['mediaType'],
models_ref)
2017-03-23 01:51:28 +00:00
# get the tag
tag = tag_model.get_or_initialize_tag(repo, tag_name, models_ref)
2017-03-23 01:51:28 +00:00
if tag.manifest_list is None:
tag.manifest_list = ManifestList(media_type=ManifestList.media_type.get_id(LIST_MEDIA_TYPE),
schema_version=SCHEMA_VERSION,
manifest_list_json=[], )
2017-03-23 01:51:28 +00:00
elif tag_model.tag_media_type_exists(tag, manifest.media_type, models_ref):
2017-03-23 21:50:07 +00:00
if force:
delete_app_release(repo, tag_name, manifest.media_type.name, models_ref)
return create_app_release(repo, tag_name, manifest_data, digest, models_ref, force=False)
2017-03-23 21:50:07 +00:00
else:
raise PackageAlreadyExists("package exists already")
2017-03-23 01:51:28 +00:00
list_json = tag.manifest_list.manifest_list_json
mlm_query = (ManifestListManifest
.select()
.where(ManifestListManifest.manifest_list == tag.manifest_list))
list_manifest_ids = sorted([mlm.manifest_id for mlm in mlm_query])
insert_point = bisect.bisect_left(list_manifest_ids, manifest.id)
list_json.insert(insert_point, manifest.manifest_json)
list_manifest_ids.insert(insert_point, manifest.id)
2017-03-23 04:21:21 +00:00
manifestlist = manifest_list_model.get_or_create_manifest_list(list_json, LIST_MEDIA_TYPE,
SCHEMA_VERSION, models_ref)
manifest_list_model.create_manifestlistmanifest(manifestlist, list_manifest_ids, list_json,
models_ref)
2017-03-23 01:51:28 +00:00
tag = tag_model.create_or_update_tag(repo, tag_name, models_ref, manifest_list=manifestlist,
2017-03-23 04:21:21 +00:00
tag_kind="release")
2017-03-23 01:51:28 +00:00
blob_digest = digest
try:
(ManifestBlob
.select()
.join(Blob)
.where(ManifestBlob.manifest == manifest,
Blob.digest == _ensure_sha256_header(blob_digest)).get())
2017-03-23 01:51:28 +00:00
except ManifestBlob.DoesNotExist:
blob = blob_model.get_blob(blob_digest, models_ref)
2017-03-23 01:51:28 +00:00
ManifestBlob.create(manifest=manifest, blob=blob)
return tag
def get_release_objs(repo, models_ref, media_type=None):
""" Returns an array of Tag for a repo, with optional filtering by media_type. """
Tag = models_ref.Tag
2017-03-23 01:51:28 +00:00
release_query = (Tag
.select()
.where(Tag.repository == repo,
Tag.tag_kind == Tag.tag_kind.get_id("release")))
if media_type:
release_query = tag_model.filter_tags_by_media_type(release_query, media_type, models_ref)
return tag_model.tag_is_alive(release_query, Tag)
def get_releases(repo, model_refs, media_type=None):
""" Returns an array of Tag.name for a repo, can filter by media_type. """
return [t.name for t in get_release_objs(repo, model_refs, media_type)]