Skip to content

Commit 4efa7ac

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Adds CLI support for glance md-tags"
2 parents 158bf88 + fef4f38 commit 4efa7ac

5 files changed

Lines changed: 202 additions & 12 deletions

File tree

doc/source/cli/data/glance.csv

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ md-namespace-objects-delete,image metadef object delete,Delete all metadata defi
3030
md-namespace-properties-delete,image metadef property delete,Delete all metadata definitions property inside a specific namespace.
3131
md-namespace-resource-type-list,image metadef resource type association list,List resource types associated to specific namespace.
3232
md-namespace-show,image metadef namespace show,Describe a specific metadata definitions namespace.
33-
md-namespace-tags-delete,,Delete all metadata definitions tags inside a specific namespace.
33+
md-namespace-tags-delete,image metadef namespace unset --all,Delete all metadata definitions tags inside a specific namespace.
3434
md-namespace-update,,Update an existing metadata definitions namespace.
3535
md-object-create,image metadef object create,Create a new metadata definitions object inside a namespace.
3636
md-object-show,image metadef object show,Describe a specific metadata definitions object inside a namespace.
@@ -46,12 +46,12 @@ md-property-update,image metadef property set,Update metadata definitions proper
4646
md-resource-type-associate,image metadef resource type association create,Associate resource type with a metadata definitions namespace.
4747
md-resource-type-deassociate,image metadef resource type association delete,Deassociate resource type with a metadata definitions namespace.
4848
md-resource-type-list,image metadef resource type list,List available resource type names.
49-
md-tag-create,,Add a new metadata definitions tag inside a namespace.
49+
md-tag-create,image metadef namespace set --tag,Add a new metadata definitions tag inside a namespace.
5050
md-tag-create-multiple,,Create new metadata definitions tags inside a namespace.
51-
md-tag-delete,,Delete a specific metadata definitions tag inside a namespace.
52-
md-tag-list,,List metadata definitions tags inside a specific namespace.
53-
md-tag-show,,Describe a specific metadata definitions tag inside a namespace.
54-
md-tag-update,,Rename a metadata definitions tag inside a namespace.
51+
md-tag-delete,image metadef namespace unset --tag,Delete a specific metadata definitions tag inside a namespace.
52+
md-tag-list,image metadef namespace show,List metadata definitions tags inside a specific namespace.
53+
md-tag-show,image metadef namespace show,Describe a specific metadata definitions tag inside a namespace.
54+
md-tag-update,image metadef namespace set --tag,Rename a metadata definitions tag inside a namespace.
5555
member-create,image add project,Create member for a given image.
5656
member-delete,image remove project,Delete image member.
5757
member-get,image member get,Show details of an image member

openstackclient/image/v2/metadef_namespaces.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def _format_namespace(namespace: Any) -> dict[str, Any]:
4444
'namespace',
4545
'owner',
4646
'protected',
47+
'tags',
4748
'schema',
4849
'updated_at',
4950
'visibility',
@@ -278,6 +279,17 @@ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
278279
dest="is_protected",
279280
help=_("Allow metadef namespace to be deleted (default)"),
280281
)
282+
parser.add_argument(
283+
"--tag",
284+
metavar="<tag>",
285+
action='append',
286+
default=[],
287+
dest='tags',
288+
help=_(
289+
"Set a tag on this metadef namespace "
290+
"(repeat option to set multiple tags)"
291+
),
292+
)
281293
return parser
282294

283295
def take_action(self, parsed_args: argparse.Namespace) -> None:
@@ -301,6 +313,21 @@ def take_action(self, parsed_args: argparse.Namespace) -> None:
301313

302314
image_client.update_metadef_namespace(namespace, **kwargs)
303315

316+
errors = 0
317+
for tag in parsed_args.tags:
318+
try:
319+
image_client.add_tag_to_metadef_namespace(namespace, tag)
320+
except Exception:
321+
LOG.error(_("Tag set failed for tag %s"), tag)
322+
errors += 1
323+
324+
if errors > 0:
325+
msg = _("Failed to set %(errors)s of %(total)s tags.") % {
326+
'errors': errors,
327+
'total': len(parsed_args.tags),
328+
}
329+
raise exceptions.CommandError(msg)
330+
304331

305332
class ShowMetadefNamespace(command.ShowOne):
306333
_description = _("Show a metadef namespace")
@@ -326,3 +353,61 @@ def take_action(
326353

327354
col_headers, col_data = zip(*sorted(info.items()))
328355
return col_headers, col_data
356+
357+
358+
class UnsetMetadefNamespace(command.Command):
359+
_description = _("Unset metadef namespace tags")
360+
361+
def get_parser(self, prog_name):
362+
parser = super().get_parser(prog_name)
363+
parser.add_argument(
364+
"namespace",
365+
metavar="<namespace>",
366+
help=_("Metadef namespace to modify (name)"),
367+
)
368+
tag_group = parser.add_mutually_exclusive_group(required=True)
369+
tag_group.add_argument(
370+
"--tag",
371+
metavar="<tag>",
372+
action='append',
373+
default=[],
374+
dest='tags',
375+
help=_(
376+
"Unset a tag on this metadef namespace "
377+
"(repeat option to unset multiple tags)"
378+
),
379+
)
380+
tag_group.add_argument(
381+
"--all-tags",
382+
action="store_true",
383+
default=False,
384+
help=_("Unset all metadef tags"),
385+
)
386+
return parser
387+
388+
def take_action(self, parsed_args):
389+
image_client = self.app.client_manager.image
390+
391+
namespace = image_client.get_metadef_namespace(parsed_args.namespace)
392+
393+
errors = 0
394+
if parsed_args.all_tags:
395+
namespace = image_client.remove_tags_from_metadef_namespace(
396+
namespace
397+
)
398+
elif parsed_args.tags:
399+
for tag in parsed_args.tags:
400+
try:
401+
image_client.remove_tag_from_metadef_namespace(
402+
namespace, tag
403+
)
404+
except Exception:
405+
LOG.error(_("tag unset failed for tag %s"), tag)
406+
errors += 1
407+
408+
if errors > 0:
409+
msg = _("Failed to unset %(errors)s of %(total)s tags.") % {
410+
'errors': errors,
411+
'total': len(parsed_args.tags),
412+
}
413+
raise exceptions.CommandError(msg)

openstackclient/tests/unit/image/v2/test_metadef_namespaces.py

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# License for the specific language governing permissions and limitations
1313
# under the License.
1414

15+
from unittest import mock
16+
1517
from openstackclient.image.v2 import metadef_namespaces
1618
from openstackclient.tests.unit.image.v2 import fakes as image_fakes
1719

@@ -24,13 +26,15 @@ class TestMetadefNamespaceCreate(image_fakes.TestImagev2):
2426
'display_name',
2527
'namespace',
2628
'owner',
29+
'tags',
2730
'visibility',
2831
)
2932
expected_data = (
3033
_metadef_namespace.created_at,
3134
_metadef_namespace.display_name,
3235
_metadef_namespace.namespace,
3336
_metadef_namespace.owner,
37+
_metadef_namespace.tags,
3438
_metadef_namespace.visibility,
3539
)
3640

@@ -114,21 +118,25 @@ def test_namespace_list_no_options(self):
114118

115119

116120
class TestMetadefNamespaceSet(image_fakes.TestImagev2):
117-
_metadef_namespace = image_fakes.create_one_metadef_namespace()
118-
119121
def setUp(self):
120122
super().setUp()
121123

124+
self.metadef_namespace = image_fakes.create_one_metadef_namespace()
125+
126+
self.image_client.get_metadef_namespace.return_value = (
127+
self.metadef_namespace
128+
)
122129
self.image_client.update_metadef_namespace.return_value = (
123-
self._metadef_namespace
130+
self.metadef_namespace
124131
)
132+
self.image_client.add_tag_to_metadef_namespace.return_value = None
133+
125134
self.cmd = metadef_namespaces.SetMetadefNamespace(self.app, None)
126-
self.datalist = self._metadef_namespace
127135

128136
def test_namespace_set_no_options(self):
129-
arglist = [self._metadef_namespace.namespace]
137+
arglist = [self.metadef_namespace.namespace]
130138
verifylist = [
131-
('namespace', self._metadef_namespace.namespace),
139+
('namespace', self.metadef_namespace.namespace),
132140
]
133141

134142
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -137,6 +145,95 @@ def test_namespace_set_no_options(self):
137145

138146
self.assertIsNone(result)
139147

148+
def test_namespace_set_tag(self):
149+
arglist = [
150+
self.metadef_namespace.namespace,
151+
'--tag',
152+
't1',
153+
'--tag',
154+
't2',
155+
]
156+
verifylist = [
157+
('namespace', self.metadef_namespace.namespace),
158+
('tags', ['t1', 't2']),
159+
]
160+
161+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
162+
163+
self.cmd.take_action(parsed_args)
164+
165+
self.image_client.add_tag_to_metadef_namespace.assert_has_calls(
166+
[
167+
mock.call(self.metadef_namespace.namespace, 't1'),
168+
mock.call(self.metadef_namespace.namespace, 't2'),
169+
]
170+
)
171+
172+
173+
class TestMetadefNamespaceUnset(image_fakes.TestImagev2):
174+
def setUp(self):
175+
super().setUp()
176+
177+
self.metadef_namespace = image_fakes.create_one_metadef_namespace(
178+
attrs={'tags': [{'name': 't1'}]}
179+
)
180+
181+
self.image_client.get_metadef_namespace.return_value = (
182+
self.metadef_namespace
183+
)
184+
self.image_client.update_metadef_namespace.return_value = (
185+
self.metadef_namespace
186+
)
187+
self.image_client.remove_tag_from_metadef_namespace.return_value = None
188+
self.image_client.remove_tags_from_metadef_namespace.return_value = (
189+
None
190+
)
191+
192+
self.cmd = metadef_namespaces.UnsetMetadefNamespace(self.app, None)
193+
194+
def test_namespace_unset_tag(self):
195+
arglist = [
196+
self.metadef_namespace.namespace,
197+
'--tag',
198+
't1',
199+
'--tag',
200+
't2',
201+
]
202+
verifylist = [
203+
('namespace', self.metadef_namespace.namespace),
204+
('tags', ['t1', 't2']),
205+
]
206+
207+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
208+
209+
self.cmd.take_action(parsed_args)
210+
211+
self.image_client.remove_tag_from_metadef_namespace.assert_has_calls(
212+
[
213+
mock.call(self.metadef_namespace, 't1'),
214+
mock.call(self.metadef_namespace, 't2'),
215+
]
216+
)
217+
self.image_client.remove_tags_from_metadef_namespace.assert_not_called()
218+
219+
def test_namespace_unset_all_tag(self):
220+
arglist = [
221+
self.metadef_namespace.namespace,
222+
'--all-tags',
223+
]
224+
verifylist = [
225+
('namespace', self.metadef_namespace.namespace),
226+
]
227+
228+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
229+
230+
self.cmd.take_action(parsed_args)
231+
232+
self.image_client.remove_tags_from_metadef_namespace.assert_called_once_with(
233+
self.metadef_namespace
234+
)
235+
self.image_client.remove_tag_from_metadef_namespace.assert_not_called()
236+
140237

141238
class TestMetadefNamespaceShow(image_fakes.TestImagev2):
142239
_metadef_namespace = image_fakes.create_one_metadef_namespace()
@@ -146,13 +243,15 @@ class TestMetadefNamespaceShow(image_fakes.TestImagev2):
146243
'display_name',
147244
'namespace',
148245
'owner',
246+
'tags',
149247
'visibility',
150248
)
151249
expected_data = (
152250
_metadef_namespace.created_at,
153251
_metadef_namespace.display_name,
154252
_metadef_namespace.namespace,
155253
_metadef_namespace.owner,
254+
_metadef_namespace.tags,
156255
_metadef_namespace.visibility,
157256
)
158257

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ image_metadef_namespace_delete = "openstackclient.image.v2.metadef_namespaces:De
359359
image_metadef_namespace_list = "openstackclient.image.v2.metadef_namespaces:ListMetadefNamespace"
360360
image_metadef_namespace_set = "openstackclient.image.v2.metadef_namespaces:SetMetadefNamespace"
361361
image_metadef_namespace_show = "openstackclient.image.v2.metadef_namespaces:ShowMetadefNamespace"
362+
image_metadef_namespace_unset = "openstackclient.image.v2.metadef_namespaces:UnsetMetadefNamespace"
362363
image_metadef_object_create = "openstackclient.image.v2.metadef_objects:CreateMetadefObjects"
363364
image_metadef_object_show = "openstackclient.image.v2.metadef_objects:ShowMetadefObjects"
364365
image_metadef_object_list = "openstackclient.image.v2.metadef_objects:ListMetadefObjects"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features:
3+
- |
4+
Add support for metadef-tags associated to namespace for adding, updating,
5+
removing a tag.

0 commit comments

Comments
 (0)