Improve image.v2.tag
While looking into create_by_id usage, I came across image.v2.tag as
something that needed to be adjusted. It was a bit cumbersome to use and
is doesn't benefit from a lot of the usual resource things since it
it just needs to join a string to the base_path and doesn't send or
receive anything else.
t = tag.Tag({"image": image_resource_or_id})
t.create(conn.session, "new tag")
t.delete(conn.session, "old tag")
Building a proxy will be trivial for this. Viewing tags isn't offered by
this resource, but you can see them via image.Image.tags
Change-Id: I2bd549c55a8c21ac292752509122896a6fd51fe8
This commit is contained in:
@@ -11,25 +11,45 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from openstack.image import image_service
|
from openstack.image import image_service
|
||||||
|
from openstack.image.v2 import image
|
||||||
from openstack import resource
|
from openstack import resource
|
||||||
|
from openstack import utils
|
||||||
|
|
||||||
|
|
||||||
class Tag(resource.Resource):
|
class Tag(resource.Resource):
|
||||||
id_attribute = 'tag'
|
id_attribute = "image"
|
||||||
resources_key = 'tags'
|
base_path = "/images/%(image)s/tags"
|
||||||
base_path = '/images/%(image_id)s/tags'
|
|
||||||
service = image_service.ImageService()
|
service = image_service.ImageService()
|
||||||
|
|
||||||
# capabilities
|
# capabilities
|
||||||
allow_create = True
|
allow_create = True
|
||||||
allow_delete = True
|
allow_delete = True
|
||||||
|
|
||||||
# Properties
|
#: The image to manipulate
|
||||||
image_id = resource.prop('image_id')
|
image = resource.prop("image", type=image.Image)
|
||||||
|
|
||||||
def create(self, session):
|
def create(self, session, tag):
|
||||||
"""Create a remote resource from this instance."""
|
"""Set a tag on the image
|
||||||
# Service expects a naked PUT. Omit properties.
|
|
||||||
self.create_by_id(session, None, self.id, path_args=self)
|
:param session: The session to use for making this request.
|
||||||
self._reset_dirty()
|
:type session: :class:`~openstack.session.Session`
|
||||||
return self
|
:param string tag: A tag to set on the image
|
||||||
|
|
||||||
|
:return: ``None``
|
||||||
|
"""
|
||||||
|
url = utils.urljoin(self.base_path %
|
||||||
|
{"image": self.image.id}, tag)
|
||||||
|
session.put(url, service=self.service, accept=None)
|
||||||
|
|
||||||
|
def delete(self, session, tag):
|
||||||
|
"""Delete a tag on the image
|
||||||
|
|
||||||
|
:param session: The session to use for making this request.
|
||||||
|
:type session: :class:`~openstack.session.Session`
|
||||||
|
:param string tag: The tag to delete on the image
|
||||||
|
|
||||||
|
:return: ``None``
|
||||||
|
"""
|
||||||
|
url = utils.urljoin(self.base_path %
|
||||||
|
{"image": self.image.id}, tag)
|
||||||
|
session.delete(url, service=self.service, accept=None)
|
||||||
|
|||||||
@@ -13,23 +13,27 @@
|
|||||||
import mock
|
import mock
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
|
from openstack.image.v2 import image
|
||||||
from openstack.image.v2 import tag
|
from openstack.image.v2 import tag
|
||||||
|
|
||||||
IDENTIFIER = 'IDENTIFIER'
|
|
||||||
EXAMPLE = {
|
|
||||||
'image_id': 'IMAGE_ID',
|
|
||||||
'tag': IDENTIFIER,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TestTag(testtools.TestCase):
|
class TestTag(testtools.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestTag, self).setUp()
|
||||||
|
|
||||||
|
self.session = mock.Mock()
|
||||||
|
self.session.put = mock.Mock()
|
||||||
|
self.session.delete = mock.Mock()
|
||||||
|
|
||||||
|
self.img = image.Image({"id": "123"})
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
sot = tag.Tag()
|
sot = tag.Tag()
|
||||||
self.assertIsNone(sot.resource_key)
|
self.assertIsNone(sot.resource_key)
|
||||||
self.assertEqual('tags', sot.resources_key)
|
self.assertEqual('/images/%(image)s/tags', sot.base_path)
|
||||||
self.assertEqual('/images/%(image_id)s/tags', sot.base_path)
|
|
||||||
self.assertEqual('image', sot.service.service_type)
|
self.assertEqual('image', sot.service.service_type)
|
||||||
self.assertEqual('tag', sot.id_attribute)
|
self.assertEqual('image', sot.id_attribute)
|
||||||
self.assertTrue(sot.allow_create)
|
self.assertTrue(sot.allow_create)
|
||||||
self.assertFalse(sot.allow_retrieve)
|
self.assertFalse(sot.allow_retrieve)
|
||||||
self.assertFalse(sot.allow_update)
|
self.assertFalse(sot.allow_update)
|
||||||
@@ -37,14 +41,23 @@ class TestTag(testtools.TestCase):
|
|||||||
self.assertFalse(sot.allow_list)
|
self.assertFalse(sot.allow_list)
|
||||||
|
|
||||||
def test_make_it(self):
|
def test_make_it(self):
|
||||||
sot = tag.Tag(EXAMPLE)
|
sot = tag.Tag({"image": self.img})
|
||||||
self.assertEqual(IDENTIFIER, sot.id)
|
self.assertEqual(self.img, sot.image)
|
||||||
self.assertEqual(EXAMPLE['image_id'], sot.image_id)
|
|
||||||
|
def _test_action(self, sot_method, session_method):
|
||||||
|
test_tag = "testing"
|
||||||
|
|
||||||
|
sot = tag.Tag({"image": self.img})
|
||||||
|
rv = getattr(sot, sot_method)(self.session, test_tag)
|
||||||
|
|
||||||
|
url = 'images/%(image)s/tags/%(tag)s' % {
|
||||||
|
"image": self.img.get_id(self.img), "tag": test_tag}
|
||||||
|
self.assertIsNone(rv)
|
||||||
|
session_method.assert_called_with(url, service=sot.service,
|
||||||
|
accept=None)
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
sess = mock.Mock()
|
self._test_action("create", self.session.put)
|
||||||
resp = mock.Mock()
|
|
||||||
sess.put = mock.Mock(return_value=resp)
|
def test_delete(self):
|
||||||
url = 'images/{image_id}/tags/{tag}'.format(**EXAMPLE)
|
self._test_action("delete", self.session.delete)
|
||||||
tag.Tag(EXAMPLE).create(sess)
|
|
||||||
sess.put.assert_called_with(url, service=tag.Tag.service, json=None)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user