From 9679ec91ecdd66723f7f6745c4172b08775f6bf2 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Mon, 17 Jul 2017 16:36:05 +0300 Subject: [PATCH] Fix for hard merge --- endpoints/api/tag.py | 18 ++++++++------ endpoints/api/tag_models_interface.py | 24 +++++++++++++++---- endpoints/api/tag_models_pre_oci.py | 21 ++++++++++++---- endpoints/api/test/test_tag_models_pre_oci.py | 17 ++++++------- endpoints/v2/labelhandlers.py | 2 +- endpoints/v2/manifest.py | 1 - 6 files changed, 54 insertions(+), 29 deletions(-) diff --git a/endpoints/api/tag.py b/endpoints/api/tag.py index 42e375de2..106d051f0 100644 --- a/endpoints/api/tag.py +++ b/endpoints/api/tag.py @@ -10,7 +10,7 @@ from endpoints.api import (resource, nickname, require_repo_read, require_repo_w parse_args, query_param, truthy_bool, disallow_for_app_repositories) from endpoints.api.tag_models_interface import Repository from endpoints.api.tag_models_pre_oci import pre_oci_model as model -from endpoints.exception import NotFound +from endpoints.exception import NotFound, InvalidRequest from endpoints.v2.manifest import _generate_and_store_manifest from util.names import TAG_ERROR, TAG_REGEX @@ -53,7 +53,7 @@ class ListRepositoryTags(RepositoryParamResource): class RepositoryTag(RepositoryParamResource): """ Resource for managing repository tags. """ schemas = { - 'MoveTag': { + 'ChangeTag': { 'type': 'object', 'description': 'Makes changes to a specific tag', 'properties': { @@ -61,7 +61,7 @@ class RepositoryTag(RepositoryParamResource): 'type': ['string', 'null'], 'description': '(If specified) Image identifier to which the tag should point', }, - 'image': { + 'expiration': { 'type': ['number', 'null'], 'description': '(If specified) The expiration for the image', }, @@ -71,8 +71,8 @@ class RepositoryTag(RepositoryParamResource): @require_repo_write @disallow_for_app_repositories - @nickname('changeTagImage') - @validate_json_request('MoveTag') + @nickname('changeTag') + @validate_json_request('ChangeTag') def put(self, namespace, repository, tag): """ Change which image a tag points to or create a new tag.""" @@ -106,12 +106,16 @@ class RepositoryTag(RepositoryParamResource): 'namespace': namespace, 'expiration_date': expiration_date, 'old_expiration_date': existing_end_ts - }, repo=repo) + }, repo_name=repository) else: - abort(400, 'Could not update tag expiration; Tag has probably changed') + raise InvalidRequest('Could not update tag expiration; Tag has probably changed') if 'image' in request.get_json(): image_id = request.get_json()['image'] + image = model.get_repository_image(namespace, repository, image_id) + if image is None: + raise NotFound() + original_image_id = model.get_repo_tag_image(repo, tag) model.create_or_update_tag(namespace, repository, tag, image_id) diff --git a/endpoints/api/tag_models_interface.py b/endpoints/api/tag_models_interface.py index c54a4cd86..a005aed9b 100644 --- a/endpoints/api/tag_models_interface.py +++ b/endpoints/api/tag_models_interface.py @@ -61,7 +61,7 @@ class Repository(namedtuple('Repository', ['namespace_name', 'repository_name']) class Image( namedtuple('Image', [ 'docker_image_id', 'created', 'comment', 'command', 'storage_image_size', - 'storage_uploading', 'ancestor_length', 'ancestor_id_list' + 'storage_uploading', 'ancestor_id_list' ])): """ Image @@ -71,7 +71,6 @@ class Image( :type command: string :type storage_image_size: int :type storage_uploading: boolean - :type ancestor_length: int :type ancestor_id_list: [int] """ @@ -91,7 +90,7 @@ class Image( 'command': json.loads(command) if command else None, 'size': self.storage_image_size, 'uploading': self.storage_uploading, - 'sort_index': self.ancestor_length, + 'sort_index': len(self.ancestor_id_list), } if include_ancestors: @@ -116,9 +115,9 @@ class TagDataInterface(object): """ @abstractmethod - def get_repo(self, namespace_name, repository_name, docker_image_id): + def get_repo(self, namespace_name, repository_name): """ - Returns a repository associated with the given namespace, repository, and docker_image_id + Returns a repository associated with the given namespace and repository name. """ @abstractmethod @@ -157,6 +156,13 @@ class TagDataInterface(object): Returns the repository associated with the namespace_name and repository_name """ + @abstractmethod + def get_repository_image(self, namespace_name, repository_name, docker_image_id): + """ + Returns the repository image associated with the namespace_name, repository_name, and docker + image ID. + """ + @abstractmethod def restore_tag_to_manifest(self, repository_name, tag_name, manifest_digest): """ @@ -170,3 +176,11 @@ class TagDataInterface(object): Returns the existing repo tag image if it exists or else returns None Side effects include adding the tag with associated name to the image with the associated id in the named repo. """ + + @abstractmethod + def change_repository_tag_expiration(self, namespace_name, repository_name, tag_name, + expiration_date): + """ Sets the expiration date of the tag under the matching repository to that given. If the + expiration date is None, then the tag will not expire. Returns a tuple of the previous + expiration timestamp in seconds (if any), and whether the operation succeeded. + """ diff --git a/endpoints/api/tag_models_pre_oci.py b/endpoints/api/tag_models_pre_oci.py index 1002c78c8..99adf9a57 100644 --- a/endpoints/api/tag_models_pre_oci.py +++ b/endpoints/api/tag_models_pre_oci.py @@ -27,12 +27,12 @@ class PreOCIModel(TagDataInterface): return RepositoryTagHistory(tags=repository_tag_history, more=more) - def get_repo(self, namespace_name, repository_name, docker_image_id): - image = model.image.get_repo_image(namespace_name, repository_name, docker_image_id) - if image is None: + def get_repo(self, namespace_name, repository_name): + repo = model.repository.get_repository(namespace_name, repository_name) + if repo is None: return None - return Repository(image.repository.namespace_user, image.repository.name) + return Repository(repo.namespace_user, repo.name) def get_repo_tag_image(self, repository, tag_name): repo = model.repository.get_repository(str(repository.namespace_name), str(repository.repository_name)) @@ -73,6 +73,13 @@ class PreOCIModel(TagDataInterface): new_tags.append(convert_tag(tag)) return new_tags + def get_repository_image(self, namespace_name, repository_name, docker_image_id): + image = model.image.get_repo_image(namespace_name, repository_name, docker_image_id) + if image is None: + return None + + return convert_image(image) + def get_repository(self, namespace_name, repository_name): repo = model.repository.get_repository(namespace_name, repository_name) if repo is None: @@ -102,13 +109,17 @@ class PreOCIModel(TagDataInterface): return convert_image(image) + def change_repository_tag_expiration(self, namespace_name, repository_name, tag_name, + expiration_date): + return model.tag.change_repository_tag_expiration(namespace_name, repository_name, tag_name, + expiration_date) + def convert_image(database_image): return Image(docker_image_id=database_image.docker_image_id, created=database_image.created, comment=database_image.comment, command=database_image.command, storage_image_size=database_image.storage.image_size, storage_uploading=database_image.storage.uploading, - ancestor_length=len(database_image.ancestors), ancestor_id_list=database_image.ancestor_id_list()) diff --git a/endpoints/api/test/test_tag_models_pre_oci.py b/endpoints/api/test/test_tag_models_pre_oci.py index b7c750854..5ddb34ab3 100644 --- a/endpoints/api/test/test_tag_models_pre_oci.py +++ b/endpoints/api/test/test_tag_models_pre_oci.py @@ -106,20 +106,18 @@ def test_list_repository_tag_history(expected, namespace_name, repository_name, specific_tag) == expected -def get_repo_image_mock(monkeypatch, return_value): - def return_return_value(namespace_name, repository_name, image_id): +def get_repo_mock(monkeypatch, return_value): + def return_return_value(namespace_name, repository_name): return return_value - monkeypatch.setattr(model.image, 'get_repo_image', return_return_value) + monkeypatch.setattr(model.repository, 'get_repository', return_return_value) def test_get_repo_not_exists(get_monkeypatch): namespace_name = 'namespace_name' repository_name = 'repository_name' - image_id = 'image_id' - get_repo_image_mock(get_monkeypatch, None) - - repo = pre_oci_model.get_repo(namespace_name, repository_name, image_id) + get_repo_mock(get_monkeypatch, None) + repo = pre_oci_model.get_repo(namespace_name, repository_name) assert repo is None @@ -127,14 +125,13 @@ def test_get_repo_not_exists(get_monkeypatch): def test_get_repo_exists(get_monkeypatch): namespace_name = 'namespace_name' repository_name = 'repository_name' - image_id = 'image_id' mock = Mock() mock.namespace_user = namespace_name mock.name = repository_name mock.repository = mock - get_repo_image_mock(get_monkeypatch, mock) + get_repo_mock(get_monkeypatch, mock) - repo = pre_oci_model.get_repo(namespace_name, repository_name, image_id) + repo = pre_oci_model.get_repo(namespace_name, repository_name) assert repo is not None assert repo.repository_name == repository_name diff --git a/endpoints/v2/labelhandlers.py b/endpoints/v2/labelhandlers.py index d179ff4bc..67596f404 100644 --- a/endpoints/v2/labelhandlers.py +++ b/endpoints/v2/labelhandlers.py @@ -1,7 +1,7 @@ import logging from app import app -from endpoints.v2.models_pre_oci import pre_oci_model as model +from endpoints.v2.models_pre_oci import data_model as model from util.timedeltastring import convert_to_timedelta logger = logging.getLogger(__name__) diff --git a/endpoints/v2/manifest.py b/endpoints/v2/manifest.py index 6a1fc801d..b79111f39 100644 --- a/endpoints/v2/manifest.py +++ b/endpoints/v2/manifest.py @@ -17,7 +17,6 @@ from endpoints.v2.models_interface import Label from endpoints.v2.models_pre_oci import data_model as model from endpoints.v2.errors import (BlobUnknown, ManifestInvalid, ManifestUnknown, TagInvalid, NameInvalid, TagExpired) ->>>>>>> Change error message when trying to pull a deleted or expired tag from endpoints.v2.labelhandlers import handle_label from image.docker import ManifestException from image.docker.schema1 import DockerSchema1Manifest, DockerSchema1ManifestBuilder