Merge "Add SDK support for adding/removing metadef tags"

This commit is contained in:
Zuul
2025-12-08 19:26:03 +00:00
committed by Gerrit Code Review
5 changed files with 204 additions and 8 deletions

View File

@@ -1042,9 +1042,8 @@ class Proxy(proxy.Proxy):
"""Add a tag to an image
:param image: The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:param str tag: The tag to be added
:class:`~openstack.image.v2.image.Image` instance.
:param tag: The tag to be added.
:returns: None
"""
@@ -1052,12 +1051,11 @@ class Proxy(proxy.Proxy):
image.add_tag(self, tag)
def remove_tag(self, image, tag):
"""Remove a tag to an image
"""Remove a tag from an image
:param image: The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:param str tag: The tag to be removed
:class:`~openstack.image.v2.image.Image` instance.
:param tag: The tag to be removed.
:returns: None
"""
@@ -1278,6 +1276,50 @@ class Proxy(proxy.Proxy):
**attrs,
)
def add_tag_to_metadef_namespace(self, namespace, tag):
"""Add a tag to a metadef namespace
:param metadef_namespace: Either the name of a metadef namespace or an
:class:`~openstack.image.v2.metadef_namespace.MetadefNamespace`
instance.
:param str tag: The tag to be added.
:returns: None
"""
namespace = self._get_resource(
_metadef_namespace.MetadefNamespace, namespace
)
namespace.add_tag(self, tag)
def remove_tag_from_metadef_namespace(self, namespace, tag):
"""Remove a tag from a metadef namespace
:param metadef_namespace: Either the name of a metadef namespace or an
:class:`~openstack.image.v2.metadef_namespace.MetadefNamespace`
instance.
:param str tag: The tag to be removed.
:returns: None
"""
namespace = self._get_resource(
_metadef_namespace.MetadefNamespace, namespace
)
namespace.remove_tag(self, tag)
def remove_tags_from_metadef_namespace(self, namespace):
"""Remove all tags from a metadef namespace
:param metadef_namespace: Either the name of a metadef namespace or an
:class:`~openstack.image.v2.metadef_namespace.MetadefNamespace`
instance.
:returns: None
"""
namespace = self._get_resource(
_metadef_namespace.MetadefNamespace, namespace
)
namespace.remove_all_tags(self)
# ====== METADEF OBJECT ======
def create_metadef_object(self, namespace, **attrs):
"""Create a new object from namespace

View File

@@ -10,12 +10,16 @@
# License for the specific language governing permissions and limitations
# under the License.
import typing_extensions as ty_ext
from openstack.common import tag
from openstack import exceptions
from openstack import resource
from openstack import utils
class MetadefNamespace(resource.Resource):
class MetadefNamespace(resource.Resource, tag.TagMixin):
resources_key = 'namespaces'
base_path = '/metadefs/namespaces'
@@ -98,3 +102,50 @@ class MetadefNamespace(resource.Resource):
"""
url = utils.urljoin(self.base_path, self.id, 'objects')
return self._delete_all(session, url)
# NOTE(mrjoshi): This method is re-implemented as we require a ``POST``
# call while the original method does a ``PUT`` call.
def add_tag(self, session: resource.AdapterT, tag: str) -> ty_ext.Self:
"""Adds a single tag to the resource.
:param session: The session to use for making this request.
:param tag: The tag as a string.
"""
url = utils.urljoin(self.base_path, self.id, 'tags', tag)
session = self._get_session(session)
response = session.post(url)
exceptions.raise_from_response(response)
# we do not want to update tags directly
tags = self.tags
tags.append(tag)
self._body.attributes.update({'tags': tags})
return self
# NOTE(mrjoshi): This method is re-implemented to add support for the
# 'append' option. This method uses a ``POST`` call rather than the
# standard ``PUT`` call.
def set_tags(
self, session: resource.AdapterT, tags: list[str], append: bool = False
) -> ty_ext.Self:
"""Sets/Replaces all tags on the resource.
:param session: The session to use for making this request.
:param list tags: List with tags to be set on the resource
:param append: If set to true, adds new tags to existing tags,
else overwrites the existing tags with new ones.
"""
url = utils.urljoin(self.base_path, self.id, 'tags')
session = self._get_session(session)
headers = {'X-OpenStack-Append': 'False'}
if append:
headers['X-Openstack-Append'] = 'True'
response = session.post(
url, headers=headers, json={'tags': [{'name': x} for x in tags]}
)
exceptions.raise_from_response(response)
self._body.attributes.update({'tags': tags})
return self

View File

@@ -90,3 +90,48 @@ class TestMetadefNamespace(base.BaseImageTest):
metadef_namespace_description,
metadef_namespace.description,
)
def test_tags(self):
# add tag
metadef_namespace = self.operator_cloud.image.get_metadef_namespace(
self.metadef_namespace.namespace
)
metadef_namespace.add_tag(self.operator_cloud.image, 't1')
metadef_namespace.add_tag(self.operator_cloud.image, 't2')
# list tags
metadef_namespace.fetch_tags(self.operator_cloud.image)
md_tags = [tag['name'] for tag in metadef_namespace.tags]
self.assertIn('t1', md_tags)
self.assertIn('t2', md_tags)
# remove tag
metadef_namespace.remove_tag(self.operator_cloud.image, 't1')
metadef_namespace = self.operator_cloud.image.get_metadef_namespace(
self.metadef_namespace.namespace
)
md_tags = [tag['name'] for tag in metadef_namespace.tags]
self.assertIn('t2', md_tags)
self.assertNotIn('t1', md_tags)
# add tags without append
metadef_namespace.set_tags(self.operator_cloud.image, ["t1", "t2"])
metadef_namespace.fetch_tags(self.operator_cloud.image)
md_tags = [tag['name'] for tag in metadef_namespace.tags]
self.assertIn('t1', md_tags)
self.assertIn('t2', md_tags)
# add tags with append
metadef_namespace.set_tags(
self.operator_cloud.image, ["t3", "t4"], append=True
)
metadef_namespace.fetch_tags(self.operator_cloud.image)
md_tags = [tag['name'] for tag in metadef_namespace.tags]
self.assertIn('t1', md_tags)
self.assertIn('t2', md_tags)
self.assertIn('t3', md_tags)
self.assertIn('t4', md_tags)
# remove all tags
metadef_namespace.remove_all_tags(self.operator_cloud.image)
self.assertEqual([], metadef_namespace.tags)

View File

@@ -18,6 +18,7 @@ from keystoneauth1 import adapter
from openstack import exceptions
from openstack.image.v2 import metadef_namespace
from openstack.tests.unit import base
from openstack.tests.unit.test_resource import FakeResponse
EXAMPLE = {
@@ -97,3 +98,55 @@ class TestMetadefNamespace(base.TestCase):
session.delete.assert_called_with(
'metadefs/namespaces/OS::Cinder::Volumetype/objects'
)
class TestMetadefNamespaceTags(base.TestCase):
# The tests in this class are very similar to those provided by
# TestTagMixin. The main differences are:
# - test_add_tag uses a ``PUT`` call instead of a ``POST`` call
# - test_set_tag uses a ``PUT`` call instead of a ``POST`` call
# - test_set_tag uses an optional ``X-OpenStack-Append`` header
def setUp(self):
super().setUp()
self.base_path = 'metadefs/namespaces'
self.response = FakeResponse({})
self.session = mock.Mock(spec=adapter.Adapter)
self.session.post = mock.Mock(return_value=self.response)
def test_add_tag(self):
res = metadef_namespace.MetadefNamespace(**EXAMPLE)
sess = self.session
# Set some initial value to check add
res.tags = ['blue', 'green']
result = res.add_tag(sess, 'lila')
# Check tags attribute is updated
self.assertEqual(['blue', 'green', 'lila'], res.tags)
# Check the passed resource is returned
self.assertEqual(res, result)
url = self.base_path + '/' + res.id + '/tags/lila'
sess.post.assert_called_once_with(url)
def test_set_tags(self):
res = metadef_namespace.MetadefNamespace(**EXAMPLE)
sess = self.session
# Set some initial value to check rewrite
res.tags = ['blue_old', 'green_old']
result = res.set_tags(sess, ['blue', 'green'])
# Check tags attribute is updated
self.assertEqual(['blue', 'green'], res.tags)
# Check the passed resource is returned
self.assertEqual(res, result)
url = self.base_path + '/' + res.id + '/tags'
headers = {'X-OpenStack-Append': 'False'}
jsonargs = {
'tags': [
{'name': 'blue'},
{'name': 'green'},
]
}
sess.post.assert_called_once_with(url, headers=headers, json=jsonargs)

View File

@@ -0,0 +1,5 @@
---
features:
- |
Add support for Image Metadef Tags to create, remove
create-multiple, update tags.