[APIv2] Update registry images tagging
The endpoint of image tag should be changed to follow guidelines on tag[*]. Main ideas are: 1. To add, remove, or change tags, a PUT request should be sent to the root tags URL, the server responds with a 200 status code. 2. To delete the entire tag list associated with a resource, a DELETE request must be sent to the root tags URL. 3. the resource identified by URL must expose its tags with root URL like: http://example.com:8386/servers/1234567890/tags. 4. There also add a get tags method and a dozen of unit test *: http://specs.openstack.org/openstack/api-wg/guidelines/tags.html Partial-Implements: bp v2-api-experimental-impl Change-Id: Ia70322538f966ad032ae804c99f6f07463461e7d
This commit is contained in:
parent
5490475b69
commit
5fdba5c322
|
@ -32,6 +32,7 @@
|
|||
"data-processing:images:register": "",
|
||||
"data-processing:images:unregister": "",
|
||||
"data-processing:images:add_tags": "",
|
||||
"data-processing:images:set_tags": "",
|
||||
"data-processing:images:remove_tags": "",
|
||||
|
||||
"data-processing:job-executions:get_all": "",
|
||||
|
|
|
@ -54,17 +54,25 @@ def images_unset(image_id):
|
|||
return u.render()
|
||||
|
||||
|
||||
@rest.post('/images/<image_id>/tag')
|
||||
@acl.enforce("data-processing:images:add_tags")
|
||||
@rest.get('/images/<image_id>/tags')
|
||||
@acl.enforce("data-processing:images:get_tags")
|
||||
@v.check_exists(api.get_image, id='image_id')
|
||||
def image_tags_get(image_id):
|
||||
return u.render(api.get_image_tags(image_id))
|
||||
|
||||
|
||||
@rest.put('/images/<image_id>/tags', status_code=200)
|
||||
@acl.enforce("data-processing:images:set_tags")
|
||||
@v.check_exists(api.get_image, id='image_id')
|
||||
@v.validate(v_images.image_tags_schema, v_images.check_tags)
|
||||
def image_tags_add(image_id, data):
|
||||
return u.render(api.add_image_tags(image_id, **data).wrapped_dict)
|
||||
def image_tags_update(image_id, data):
|
||||
return u.render(api.set_image_tags(image_id, **data).wrapped_dict)
|
||||
|
||||
|
||||
@rest.post('/images/<image_id>/untag')
|
||||
@rest.delete('/images/<image_id>/tags')
|
||||
@acl.enforce("data-processing:images:remove_tags")
|
||||
@v.check_exists(api.get_image, id='image_id')
|
||||
@v.validate(v_images.image_tags_schema)
|
||||
def image_tags_delete(image_id, data):
|
||||
return u.render(api.remove_image_tags(image_id, **data).wrapped_dict)
|
||||
def image_tags_delete(image_id):
|
||||
api.remove_image_tags(image_id)
|
||||
return u.render()
|
||||
|
|
|
@ -56,13 +56,32 @@ def unregister_image(image_id):
|
|||
return b.execute_with_retries(manager.get, image_id)
|
||||
|
||||
|
||||
def add_image_tags(image_id, tags):
|
||||
def get_image_tags(image_id):
|
||||
return b.execute_with_retries(
|
||||
sahara_images.image_manager().get, image_id).tags
|
||||
|
||||
|
||||
def set_image_tags(image_id, tags):
|
||||
manager = sahara_images.image_manager()
|
||||
b.execute_with_retries(manager.tag, image_id, tags)
|
||||
image_obj = b.execute_with_retries(manager.get, image_id)
|
||||
org_tags = frozenset(image_obj.tags)
|
||||
new_tags = frozenset(tags)
|
||||
|
||||
to_add = list(new_tags - org_tags)
|
||||
to_remove = list(org_tags - new_tags)
|
||||
|
||||
if to_add:
|
||||
b.execute_with_retries(manager.tag, image_id, to_add)
|
||||
|
||||
if to_remove:
|
||||
b.execute_with_retries(manager.untag, image_id, to_remove)
|
||||
|
||||
return b.execute_with_retries(manager.get, image_id)
|
||||
|
||||
|
||||
def remove_image_tags(image_id, tags):
|
||||
def remove_image_tags(image_id):
|
||||
manager = sahara_images.image_manager()
|
||||
image_obj = b.execute_with_retries(manager.get, image_id)
|
||||
tags = image_obj.tags
|
||||
b.execute_with_retries(manager.untag, image_id, tags)
|
||||
return b.execute_with_retries(manager.get, image_id)
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
# Copyright (c) 2017 EasyStack Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from sahara.service.api.v2 import images
|
||||
from sahara.tests.unit import base
|
||||
|
||||
|
||||
class TestImageApi(base.SaharaTestCase):
|
||||
def SetUp(self):
|
||||
super(TestImageApi, self).SetUp()
|
||||
|
||||
@mock.patch('sahara.utils.openstack.images.SaharaImageManager')
|
||||
def test_get_image_tags(self, mock_manager):
|
||||
image = mock.Mock()
|
||||
manager = mock.Mock()
|
||||
manager.get.return_value = mock.Mock(tags=['foo', 'bar', 'baz'])
|
||||
mock_manager.return_value = manager
|
||||
self.assertEqual(['foo', 'bar', 'baz'], images.get_image_tags(image))
|
||||
|
||||
@mock.patch('sahara.utils.openstack.images.SaharaImageManager')
|
||||
def test_set_image_tags(self, mock_manager):
|
||||
def _tag(image, to_add):
|
||||
return tags.append('qux')
|
||||
|
||||
def _untag(image, to_remove):
|
||||
return tags.remove('bar')
|
||||
|
||||
expected_tags = ['foo', 'baz', 'qux']
|
||||
tags = ['foo', 'bar', 'baz']
|
||||
image = mock.Mock()
|
||||
manager = mock.Mock()
|
||||
manager.get.return_value = mock.Mock(tags=tags)
|
||||
manager.tag.side_effect = _tag
|
||||
manager.untag.side_effect = _untag
|
||||
mock_manager.return_value = manager
|
||||
|
||||
self.assertEqual(expected_tags,
|
||||
images.set_image_tags(image, expected_tags).tags)
|
||||
|
||||
@mock.patch('sahara.utils.openstack.images.SaharaImageManager')
|
||||
def test_remove_image_tags(self, mock_manager):
|
||||
def _untag(image, to_remove):
|
||||
for i in range(len(to_remove)):
|
||||
actual_tags.pop()
|
||||
return actual_tags
|
||||
|
||||
actual_tags = ['foo', 'bar', 'baz']
|
||||
image = mock.Mock()
|
||||
manager = mock.Mock()
|
||||
manager.get.return_value = mock.Mock(tags=actual_tags)
|
||||
manager.untag.side_effect = _untag
|
||||
mock_manager.return_value = manager
|
||||
|
||||
self.assertEqual([], images.remove_image_tags(image).tags)
|
Loading…
Reference in New Issue