initial import for Open Source 🎉

This commit is contained in:
Jimmy Zelinskie 2019-11-12 11:09:47 -05:00
parent 1898c361f3
commit 9c0dd3b722
2048 changed files with 218743 additions and 0 deletions

View file

@ -0,0 +1,9 @@
from data.appr_model import (
blob,
channel,
manifest,
manifest_list,
package,
release,
tag,
)

76
data/appr_model/blob.py Normal file
View file

@ -0,0 +1,76 @@
import logging
from peewee import IntegrityError
from data.model import db_transaction
logger = logging.getLogger(__name__)
def _ensure_sha256_header(digest):
if digest.startswith('sha256:'):
return digest
return 'sha256:' + digest
def get_blob(digest, models_ref):
""" Find a blob by its digest. """
Blob = models_ref.Blob
return Blob.select().where(Blob.digest == _ensure_sha256_header(digest)).get()
def get_or_create_blob(digest, size, media_type_name, locations, models_ref):
""" Try to find a blob by its digest or create it. """
Blob = models_ref.Blob
BlobPlacement = models_ref.BlobPlacement
# Get or create the blog entry for the digest.
try:
blob = get_blob(digest, models_ref)
logger.debug('Retrieved blob with digest %s', digest)
except Blob.DoesNotExist:
blob = Blob.create(digest=_ensure_sha256_header(digest),
media_type_id=Blob.media_type.get_id(media_type_name),
size=size)
logger.debug('Created blob with digest %s', digest)
# Add the locations to the blob.
for location_name in locations:
location_id = BlobPlacement.location.get_id(location_name)
try:
BlobPlacement.create(blob=blob, location=location_id)
except IntegrityError:
logger.debug('Location %s already existing for blob %s', location_name, blob.id)
return blob
def get_blob_locations(digest, models_ref):
""" Find all locations names for a blob. """
Blob = models_ref.Blob
BlobPlacement = models_ref.BlobPlacement
BlobPlacementLocation = models_ref.BlobPlacementLocation
return [x.name for x in
BlobPlacementLocation
.select()
.join(BlobPlacement)
.join(Blob)
.where(Blob.digest == _ensure_sha256_header(digest))]
def ensure_blob_locations(models_ref, *names):
BlobPlacementLocation = models_ref.BlobPlacementLocation
with db_transaction():
locations = BlobPlacementLocation.select().where(BlobPlacementLocation.name << names)
insert_names = list(names)
for location in locations:
insert_names.remove(location.name)
if not insert_names:
return
data = [{'name': name} for name in insert_names]
BlobPlacementLocation.insert_many(data).execute()

View file

@ -0,0 +1,64 @@
from data.appr_model import tag as tag_model
def get_channel_releases(repo, channel, models_ref):
""" Return all previously linked tags.
This works based upon Tag lifetimes.
"""
Channel = models_ref.Channel
Tag = models_ref.Tag
tag_kind_id = Channel.tag_kind.get_id('channel')
channel_name = channel.name
return (Tag
.select(Tag, Channel)
.join(Channel, on=(Tag.id == Channel.linked_tag))
.where(Channel.repository == repo,
Channel.name == channel_name,
Channel.tag_kind == tag_kind_id, Channel.lifetime_end != None)
.order_by(Tag.lifetime_end))
def get_channel(repo, channel_name, models_ref):
""" Find a Channel by name. """
channel = tag_model.get_tag(repo, channel_name, models_ref, "channel")
return channel
def get_tag_channels(repo, tag_name, models_ref, active=True):
""" Find the Channels associated with a Tag. """
Tag = models_ref.Tag
tag = tag_model.get_tag(repo, tag_name, models_ref, "release")
query = tag.tag_parents
if active:
query = tag_model.tag_is_alive(query, Tag)
return query
def delete_channel(repo, channel_name, models_ref):
""" Delete a channel by name. """
return tag_model.delete_tag(repo, channel_name, models_ref, "channel")
def create_or_update_channel(repo, channel_name, tag_name, models_ref):
""" Creates or updates a channel to include a particular tag. """
tag = tag_model.get_tag(repo, tag_name, models_ref, 'release')
return tag_model.create_or_update_tag(repo, channel_name, models_ref, linked_tag=tag,
tag_kind="channel")
def get_repo_channels(repo, models_ref):
""" Creates or updates a channel to include a particular tag. """
Channel = models_ref.Channel
Tag = models_ref.Tag
tag_kind_id = Channel.tag_kind.get_id('channel')
query = (Channel
.select(Channel, Tag)
.join(Tag, on=(Tag.id == Channel.linked_tag))
.where(Channel.repository == repo,
Channel.tag_kind == tag_kind_id))
return tag_model.tag_is_alive(query, Channel)

View file

@ -0,0 +1,67 @@
import logging
import hashlib
import json
from cnr.models.package_base import get_media_type
from data.database import db_transaction, MediaType
from data.appr_model import tag as tag_model
logger = logging.getLogger(__name__)
def _ensure_sha256_header(digest):
if digest.startswith('sha256:'):
return digest
return 'sha256:' + digest
def _digest(manifestjson):
return _ensure_sha256_header(hashlib.sha256(json.dumps(manifestjson, sort_keys=True)).hexdigest())
def get_manifest_query(digest, media_type, models_ref):
Manifest = models_ref.Manifest
return Manifest.select().where(Manifest.digest == _ensure_sha256_header(digest),
Manifest.media_type == Manifest.media_type.get_id(media_type))
def get_manifest_with_blob(digest, media_type, models_ref):
Blob = models_ref.Blob
query = get_manifest_query(digest, media_type, models_ref)
return query.join(Blob).get()
def get_or_create_manifest(manifest_json, media_type_name, models_ref):
Manifest = models_ref.Manifest
digest = _digest(manifest_json)
try:
manifest = get_manifest_query(digest, media_type_name, models_ref).get()
except Manifest.DoesNotExist:
with db_transaction():
manifest = Manifest.create(digest=digest,
manifest_json=manifest_json,
media_type=Manifest.media_type.get_id(media_type_name))
return manifest
def get_manifest_types(repo, models_ref, release=None):
""" Returns an array of MediaTypes.name for a repo, can filter by tag """
Tag = models_ref.Tag
ManifestListManifest = models_ref.ManifestListManifest
query = tag_model.tag_is_alive(Tag
.select(MediaType.name)
.join(ManifestListManifest,
on=(ManifestListManifest.manifest_list == Tag.manifest_list))
.join(MediaType,
on=(ManifestListManifest.media_type == MediaType.id))
.where(Tag.repository == repo,
Tag.tag_kind == Tag.tag_kind.get_id('release')), Tag)
if release:
query = query.where(Tag.name == release)
manifests = set()
for m in query.distinct().tuples():
manifests.add(get_media_type(m[0]))
return manifests

View file

@ -0,0 +1,67 @@
import logging
import hashlib
import json
from data.database import db_transaction
logger = logging.getLogger(__name__)
def _ensure_sha256_header(digest):
if digest.startswith('sha256:'):
return digest
return 'sha256:' + digest
def _digest(manifestjson):
return _ensure_sha256_header(hashlib.sha256(json.dumps(manifestjson, sort_keys=True)).hexdigest())
def get_manifest_list(digest, models_ref):
ManifestList = models_ref.ManifestList
return ManifestList.select().where(ManifestList.digest == _ensure_sha256_header(digest)).get()
def get_or_create_manifest_list(manifest_list_json, media_type_name, schema_version, models_ref):
ManifestList = models_ref.ManifestList
digest = _digest(manifest_list_json)
media_type_id = ManifestList.media_type.get_id(media_type_name)
try:
return get_manifest_list(digest, models_ref)
except ManifestList.DoesNotExist:
with db_transaction():
manifestlist = ManifestList.create(digest=digest, manifest_list_json=manifest_list_json,
schema_version=schema_version, media_type=media_type_id)
return manifestlist
def create_manifestlistmanifest(manifestlist, manifest_ids, manifest_list_json, models_ref):
""" From a manifestlist, manifests, and the manifest list blob,
create if doesn't exist the manfiestlistmanifest for each manifest """
for pos in xrange(len(manifest_ids)):
manifest_id = manifest_ids[pos]
manifest_json = manifest_list_json[pos]
get_or_create_manifestlistmanifest(manifest=manifest_id,
manifestlist=manifestlist,
media_type_name=manifest_json['mediaType'],
models_ref=models_ref)
def get_or_create_manifestlistmanifest(manifest, manifestlist, media_type_name, models_ref):
ManifestListManifest = models_ref.ManifestListManifest
media_type_id = ManifestListManifest.media_type.get_id(media_type_name)
try:
ml = (ManifestListManifest
.select()
.where(ManifestListManifest.manifest == manifest,
ManifestListManifest.media_type == media_type_id,
ManifestListManifest.manifest_list == manifestlist)).get()
except ManifestListManifest.DoesNotExist:
ml = ManifestListManifest.create(manifest_list=manifestlist, media_type=media_type_id,
manifest=manifest)
return ml

15
data/appr_model/models.py Normal file
View file

@ -0,0 +1,15 @@
from collections import namedtuple
from data.database import (ApprTag, ApprTagKind, ApprBlobPlacementLocation, ApprManifestList,
ApprManifestBlob, ApprBlob, ApprManifestListManifest, ApprManifest,
ApprBlobPlacement, ApprChannel)
ModelsRef = namedtuple('ModelsRef', ['Tag', 'TagKind', 'BlobPlacementLocation', 'ManifestList',
'ManifestBlob', 'Blob', 'ManifestListManifest', 'Manifest',
'BlobPlacement', 'Channel', 'manifestlistmanifest_set_name',
'tag_set_prefetch_name'])
NEW_MODELS = ModelsRef(ApprTag, ApprTagKind, ApprBlobPlacementLocation, ApprManifestList,
ApprManifestBlob, ApprBlob, ApprManifestListManifest, ApprManifest,
ApprBlobPlacement, ApprChannel, 'apprmanifestlistmanifest_set',
'apprtag_set')

View file

@ -0,0 +1,67 @@
from cnr.models.package_base import get_media_type, manifest_media_type
from peewee import prefetch
from data import model
from data.database import Repository, Namespace
from data.appr_model import tag as tag_model
def list_packages_query(models_ref, namespace=None, media_type=None, search_query=None,
username=None):
""" List and filter repository by search query. """
Tag = models_ref.Tag
if username and not search_query:
repositories = model.repository.get_visible_repositories(username,
kind_filter='application',
include_public=True,
namespace=namespace,
limit=50)
if not repositories:
return []
repo_query = (Repository
.select(Repository, Namespace.username)
.join(Namespace, on=(Repository.namespace_user == Namespace.id))
.where(Repository.id << [repo.rid for repo in repositories]))
if namespace:
repo_query = (repo_query
.where(Namespace.username == namespace))
else:
if search_query is not None:
fields = [model.repository.SEARCH_FIELDS.name.name]
repositories = model.repository.get_app_search(search_query,
username=username,
search_fields=fields,
limit=50)
if not repositories:
return []
repo_query = (Repository
.select(Repository, Namespace.username)
.join(Namespace, on=(Repository.namespace_user == Namespace.id))
.where(Repository.id << [repo.id for repo in repositories]))
else:
repo_query = (Repository
.select(Repository, Namespace.username)
.join(Namespace, on=(Repository.namespace_user == Namespace.id))
.where(Repository.visibility == model.repository.get_public_repo_visibility(),
Repository.kind == Repository.kind.get_id('application')))
if namespace:
repo_query = (repo_query
.where(Namespace.username == namespace))
tag_query = (Tag
.select()
.where(Tag.tag_kind == Tag.tag_kind.get_id('release'))
.order_by(Tag.lifetime_start))
if media_type:
tag_query = tag_model.filter_tags_by_media_type(tag_query, media_type, models_ref)
tag_query = tag_model.tag_is_alive(tag_query, Tag)
query = prefetch(repo_query, tag_query)
return query

152
data/appr_model/release.py Normal file
View file

@ -0,0 +1,152 @@
import bisect
from cnr.exception import PackageAlreadyExists
from cnr.models.package_base import manifest_media_type
from data.database import db_transaction, get_epoch_timestamp
from data.appr_model import (blob as blob_model, manifest as manifest_model,
manifest_list as manifest_list_model,
tag as tag_model)
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):
""" 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')
media_type_id = ManifestListManifest.media_type.get_id(manifest_media_type(media_type))
manifestlistmanifest = (getattr(tag.manifest_list, manifestlistmanifest_set_name)
.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
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)
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)
.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)
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,
tag_kind="release")
return tag
def create_app_release(repo, tag_name, manifest_data, digest, models_ref, force=False):
""" 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
with db_transaction():
# Create/get the package manifest
manifest = manifest_model.get_or_create_manifest(manifest_data, manifest_data['mediaType'],
models_ref)
# get the tag
tag = tag_model.get_or_initialize_tag(repo, tag_name, models_ref)
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=[], )
elif tag_model.tag_media_type_exists(tag, manifest.media_type, models_ref):
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)
else:
raise PackageAlreadyExists("package exists already")
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)
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)
tag = tag_model.create_or_update_tag(repo, tag_name, models_ref, manifest_list=manifestlist,
tag_kind="release")
blob_digest = digest
try:
(ManifestBlob
.select()
.join(Blob)
.where(ManifestBlob.manifest == manifest,
Blob.digest == _ensure_sha256_header(blob_digest)).get())
except ManifestBlob.DoesNotExist:
blob = blob_model.get_blob(blob_digest, models_ref)
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
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)]

99
data/appr_model/tag.py Normal file
View file

@ -0,0 +1,99 @@
import logging
from cnr.models.package_base import manifest_media_type
from peewee import IntegrityError
from data.model import (db_transaction, TagAlreadyCreatedException)
from data.database import get_epoch_timestamp_ms, db_for_update
logger = logging.getLogger(__name__)
def tag_is_alive(query, cls, now_ts=None):
return query.where((cls.lifetime_end >> None) |
(cls.lifetime_end > now_ts))
def tag_media_type_exists(tag, media_type, models_ref):
ManifestListManifest = models_ref.ManifestListManifest
manifestlistmanifest_set_name = models_ref.manifestlistmanifest_set_name
return (getattr(tag.manifest_list, manifestlistmanifest_set_name)
.where(ManifestListManifest.media_type == media_type).count() > 0)
def create_or_update_tag(repo, tag_name, models_ref, manifest_list=None, linked_tag=None,
tag_kind="release"):
Tag = models_ref.Tag
now_ts = get_epoch_timestamp_ms()
tag_kind_id = Tag.tag_kind.get_id(tag_kind)
with db_transaction():
try:
tag = db_for_update(tag_is_alive(Tag
.select()
.where(Tag.repository == repo,
Tag.name == tag_name,
Tag.tag_kind == tag_kind_id), Tag, now_ts)).get()
if tag.manifest_list == manifest_list and tag.linked_tag == linked_tag:
return tag
tag.lifetime_end = now_ts
tag.save()
except Tag.DoesNotExist:
pass
try:
return Tag.create(repository=repo, manifest_list=manifest_list, linked_tag=linked_tag,
name=tag_name, lifetime_start=now_ts, lifetime_end=None,
tag_kind=tag_kind_id)
except IntegrityError:
msg = 'Tag with name %s and lifetime start %s under repository %s/%s already exists'
raise TagAlreadyCreatedException(msg % (tag_name, now_ts, repo.namespace_user, repo.name))
def get_or_initialize_tag(repo, tag_name, models_ref, tag_kind="release"):
Tag = models_ref.Tag
try:
return tag_is_alive(Tag.select().where(Tag.repository == repo, Tag.name == tag_name), Tag).get()
except Tag.DoesNotExist:
return Tag(repo=repo, name=tag_name, tag_kind=Tag.tag_kind.get_id(tag_kind))
def get_tag(repo, tag_name, models_ref, tag_kind="release"):
Tag = models_ref.Tag
return tag_is_alive(Tag.select()
.where(Tag.repository == repo,
Tag.name == tag_name,
Tag.tag_kind == Tag.tag_kind.get_id(tag_kind)), Tag).get()
def delete_tag(repo, tag_name, models_ref, tag_kind="release"):
Tag = models_ref.Tag
tag_kind_id = Tag.tag_kind.get_id(tag_kind)
tag = tag_is_alive(Tag.select()
.where(Tag.repository == repo,
Tag.name == tag_name, Tag.tag_kind == tag_kind_id), Tag).get()
tag.lifetime_end = get_epoch_timestamp_ms()
tag.save()
return tag
def tag_exists(repo, tag_name, models_ref, tag_kind="release"):
Tag = models_ref.Tag
try:
get_tag(repo, tag_name, models_ref, tag_kind)
return True
except Tag.DoesNotExist:
return False
def filter_tags_by_media_type(tag_query, media_type, models_ref):
""" Return only available tag for a media_type. """
ManifestListManifest = models_ref.ManifestListManifest
Tag = models_ref.Tag
media_type = manifest_media_type(media_type)
t = (tag_query
.join(ManifestListManifest, on=(ManifestListManifest.manifest_list == Tag.manifest_list))
.where(ManifestListManifest.media_type == ManifestListManifest.media_type.get_id(media_type)))
return t