Merge branch 'master' of https://bitbucket.org/yackob03/quay
This commit is contained in:
commit
d87dc232e2
10 changed files with 51 additions and 36 deletions
|
@ -14,4 +14,4 @@ class MailConfig(object):
|
||||||
|
|
||||||
|
|
||||||
class ProductionConfig(FlaskConfig, MailConfig):
|
class ProductionConfig(FlaskConfig, MailConfig):
|
||||||
pass
|
REGISTRY_SERVER = 'localhost:5000'
|
||||||
|
|
|
@ -89,6 +89,9 @@ class Image(BaseModel):
|
||||||
comment = CharField(null=True)
|
comment = CharField(null=True)
|
||||||
repository = ForeignKeyField(Repository)
|
repository = ForeignKeyField(Repository)
|
||||||
|
|
||||||
|
# '/' separated list of ancestory ids, e.g. /1/2/6/7/10/
|
||||||
|
ancestors = CharField(index=True, default='/', max_length=65535)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
database = db
|
database = db
|
||||||
indexes = (
|
indexes = (
|
||||||
|
|
|
@ -198,7 +198,7 @@ def set_image_checksum(image_id, repository, checksum):
|
||||||
|
|
||||||
|
|
||||||
def set_image_metadata(image_id, namespace_name, repository_name,
|
def set_image_metadata(image_id, namespace_name, repository_name,
|
||||||
created_date_str, comment):
|
created_date_str, comment, parent=None):
|
||||||
joined = Image.select().join(Repository)
|
joined = Image.select().join(Repository)
|
||||||
image_list = list(joined.where(Repository.name == repository_name,
|
image_list = list(joined.where(Repository.name == repository_name,
|
||||||
Repository.namespace == namespace_name,
|
Repository.namespace == namespace_name,
|
||||||
|
@ -210,6 +210,10 @@ def set_image_metadata(image_id, namespace_name, repository_name,
|
||||||
fetched = image_list[0]
|
fetched = image_list[0]
|
||||||
fetched.created = dateutil.parser.parse(created_date_str)
|
fetched.created = dateutil.parser.parse(created_date_str)
|
||||||
fetched.comment = comment
|
fetched.comment = comment
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
fetched.ancestors = '%s%s/' % (parent.ancestors, parent.id)
|
||||||
|
|
||||||
fetched.save()
|
fetched.save()
|
||||||
return fetched
|
return fetched
|
||||||
|
|
||||||
|
@ -220,15 +224,6 @@ def get_repository_images(namespace_name, repository_name):
|
||||||
Repository.namespace == namespace_name)
|
Repository.namespace == namespace_name)
|
||||||
|
|
||||||
|
|
||||||
def get_tag_images(namespace_name, repository_name, tag_name):
|
|
||||||
joined = Image.select().join(RepositoryTag).join(Repository)
|
|
||||||
fetched = list(joined.where(Repository.name == repository_name,
|
|
||||||
Repository.namespace == namespace_name,
|
|
||||||
RepositoryTag.name == tag_name))
|
|
||||||
|
|
||||||
return fetched
|
|
||||||
|
|
||||||
|
|
||||||
def list_repository_tags(namespace_name, repository_name):
|
def list_repository_tags(namespace_name, repository_name):
|
||||||
select = RepositoryTag.select(RepositoryTag, Image)
|
select = RepositoryTag.select(RepositoryTag, Image)
|
||||||
with_repo = select.join(Repository)
|
with_repo = select.join(Repository)
|
||||||
|
@ -238,13 +233,33 @@ def list_repository_tags(namespace_name, repository_name):
|
||||||
|
|
||||||
|
|
||||||
def get_tag_image(namespace_name, repository_name, tag_name):
|
def get_tag_image(namespace_name, repository_name, tag_name):
|
||||||
fetched = get_tag_images(namespace_name, repository_name, tag_name)
|
joined = Image.select().join(RepositoryTag).join(Repository)
|
||||||
|
fetched = joined.where(Repository.name == repository_name,
|
||||||
|
Repository.namespace == namespace_name,
|
||||||
|
RepositoryTag.name == tag_name)
|
||||||
|
|
||||||
if not fetched:
|
if not fetched:
|
||||||
raise DataModelException('Unable to find image for tag.')
|
raise DataModelException('Unable to find image for tag.')
|
||||||
|
|
||||||
return fetched[0]
|
return fetched[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_image_by_id(image_id):
|
||||||
|
return Image.get(Image.image_id == image_id)
|
||||||
|
|
||||||
|
|
||||||
|
def get_parent_images(image_obj):
|
||||||
|
""" Returns a list of parent Image objects in chronilogical order. """
|
||||||
|
parents = image_obj.ancestors
|
||||||
|
parent_db_ids = parents.strip('/').split('/')
|
||||||
|
|
||||||
|
or_clauses = [(Image.id == db_id) for db_id in parent_db_ids]
|
||||||
|
parent_images = Image.select().where(reduce(operator.or_, or_clauses))
|
||||||
|
id_to_image = {unicode(image.id): image for image in parent_images}
|
||||||
|
|
||||||
|
return [id_to_image[parent_id] for parent_id in parent_db_ids]
|
||||||
|
|
||||||
|
|
||||||
def create_or_update_tag(namespace_name, repository_name, tag_name,
|
def create_or_update_tag(namespace_name, repository_name, tag_name,
|
||||||
tag_image_id):
|
tag_image_id):
|
||||||
repo = Repository.get(Repository.name == repository_name,
|
repo = Repository.get(Repository.name == repository_name,
|
||||||
|
|
|
@ -188,10 +188,15 @@ def role_view(repo_perm_obj):
|
||||||
def list_tag_images(namespace, repository, tag):
|
def list_tag_images(namespace, repository, tag):
|
||||||
permission = ReadRepositoryPermission(namespace, repository)
|
permission = ReadRepositoryPermission(namespace, repository)
|
||||||
if permission.can() or model.repository_is_public(namespace, repository):
|
if permission.can() or model.repository_is_public(namespace, repository):
|
||||||
images = model.get_tag_images(namespace, repository, tag)
|
tag_image = model.get_tag_image(namespace, repository, tag)
|
||||||
|
parent_images = model.get_parent_images(tag_image)
|
||||||
|
|
||||||
|
parents = list(parent_images)
|
||||||
|
parents.reverse()
|
||||||
|
all_images = [tag_image] + parents
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'images': [image_view(image) for image in images]
|
'images': [image_view(image) for image in all_images]
|
||||||
})
|
})
|
||||||
|
|
||||||
abort(403) # Permission denied
|
abort(403) # Permission denied
|
||||||
|
|
|
@ -19,15 +19,12 @@ from auth.permissions import (ModifyRepositoryPermission,
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
REGISTRY_SERVER = 'localhost:5003'
|
|
||||||
|
|
||||||
|
|
||||||
def generate_headers(f):
|
def generate_headers(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapper(namespace, repository, *args, **kwargs):
|
def wrapper(namespace, repository, *args, **kwargs):
|
||||||
response = f(namespace, repository, *args, **kwargs)
|
response = f(namespace, repository, *args, **kwargs)
|
||||||
|
|
||||||
response.headers['X-Docker-Endpoints'] = REGISTRY_SERVER
|
response.headers['X-Docker-Endpoints'] = app.config['REGISTRY_SERVER']
|
||||||
|
|
||||||
has_token_request = request.headers.get('X-Docker-Token', '')
|
has_token_request = request.headers.get('X-Docker-Token', '')
|
||||||
|
|
||||||
|
|
|
@ -290,8 +290,14 @@ def put_image_json(namespace, repository, image_id):
|
||||||
# If we reach that point, it means that this is a new image or a retry
|
# If we reach that point, it means that this is a new image or a retry
|
||||||
# on a failed push
|
# on a failed push
|
||||||
# save the metadata
|
# save the metadata
|
||||||
|
if parent_id:
|
||||||
|
parent_obj = model.get_image_by_id(parent_id)
|
||||||
|
else:
|
||||||
|
parent_obj = None
|
||||||
|
|
||||||
model.set_image_metadata(image_id, namespace, repository,
|
model.set_image_metadata(image_id, namespace, repository,
|
||||||
data.get('created'), data.get('comment'))
|
data.get('created'), data.get('comment'),
|
||||||
|
parent_obj)
|
||||||
store.put_content(mark_path, 'true')
|
store.put_content(mark_path, 'true')
|
||||||
store.put_content(json_path, request.data)
|
store.put_content(json_path, request.data)
|
||||||
generate_ancestry(namespace, repository, image_id, parent_id)
|
generate_ancestry(namespace, repository, image_id, parent_id)
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import logging
|
|
||||||
|
|
||||||
from app import app
|
|
||||||
|
|
||||||
import endpoints.registry
|
|
||||||
import endpoints.tags
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
FORMAT = '%(asctime)-15s - %(levelname)s - %(pathname)s - ' + \
|
|
||||||
'%(funcName)s - %(message)s'
|
|
||||||
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
|
|
||||||
|
|
||||||
app.run(port=5000, debug=True)
|
|
|
@ -61,7 +61,7 @@
|
||||||
<div class="repo-access-state" ng-show="!repo.is_public">
|
<div class="repo-access-state" ng-show="!repo.is_public">
|
||||||
<div class="state-icon"><i class="icon-lock"></i></div>
|
<div class="state-icon"><i class="icon-lock"></i></div>
|
||||||
|
|
||||||
This repository is currently <b>private</b>. Only users on the above access list may interact with it.
|
This repository is currently <b>private</b>. Only users on the above access list may view and interact with it.
|
||||||
|
|
||||||
<div class="change-access">
|
<div class="change-access">
|
||||||
<button class="btn btn-danger" ng-click="askChangeAccess('public')">Make Public</button>
|
<button class="btn btn-danger" ng-click="askChangeAccess('public')">Make Public</button>
|
||||||
|
@ -71,10 +71,10 @@
|
||||||
<div class="repo-access-state" ng-show="repo.is_public">
|
<div class="repo-access-state" ng-show="repo.is_public">
|
||||||
<div class="state-icon"><i class="icon-unlock-alt"></i></div>
|
<div class="state-icon"><i class="icon-unlock-alt"></i></div>
|
||||||
|
|
||||||
This repository is currently <b>public</b> and visible to all users.
|
This repository is currently <b>public</b> and is visible to all users, and may be pulled by all users.
|
||||||
|
|
||||||
<div class="change-access">
|
<div class="change-access">
|
||||||
<button class="btn btn-success" ng-click="askChangeAccess('private')">Make Private</button>
|
<button class="btn btn-danger" ng-click="askChangeAccess('private')">Make Private</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
BIN
test.db
BIN
test.db
Binary file not shown.
4
wsgi.py
4
wsgi.py
|
@ -5,10 +5,12 @@ from app import app
|
||||||
import endpoints.index
|
import endpoints.index
|
||||||
import endpoints.api
|
import endpoints.api
|
||||||
import endpoints.web
|
import endpoints.web
|
||||||
|
import endpoints.tags
|
||||||
|
import endpoints.registry
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
FORMAT = '%(asctime)-15s - %(levelname)s - %(pathname)s - ' + \
|
FORMAT = '%(asctime)-15s - %(levelname)s - %(pathname)s - ' + \
|
||||||
'%(funcName)s - %(message)s'
|
'%(funcName)s - %(message)s'
|
||||||
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
|
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
|
||||||
|
|
||||||
app.run(port=5002, debug=True)
|
app.run(port=5001, debug=True)
|
||||||
|
|
Reference in a new issue