Skip to content

Commit 22c60f3

Browse files
author
Huanxuan Ao
committed
Add support for removing flavor-access
Add "--project" and "--project-domain" options in "flavor unset" command to remove flavor access. Change-Id: Ia5c5a80d9890d5af066b75b4e202647c18c7d915 Partial-Bug: #1575461
1 parent ca58ab9 commit 22c60f3

4 files changed

Lines changed: 150 additions & 7 deletions

File tree

doc/source/command-objects/flavor.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,23 @@ Unset flavor properties
175175
176176
os flavor unset
177177
[--property <key> [...] ]
178+
[--project <project>]
179+
[--project-domain <project-domain>]
178180
<flavor>
179181
180182
.. option:: --property <key>
181183

182184
Property to remove from flavor (repeat option to remove multiple properties)
183185

186+
.. option:: --project <project>
187+
188+
Remove flavor access from project (name or ID) (admin only)
189+
190+
.. option:: --project-domain <project-domain>
191+
192+
Domain the project belongs to (name or ID).
193+
This can be used in case collisions between project names exist.
194+
184195
.. describe:: <flavor>
185196

186197
Flavor to modify (name or ID)

openstackclient/compute/v2/flavor.py

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,22 +337,64 @@ class UnsetFlavor(command.Command):
337337

338338
def get_parser(self, prog_name):
339339
parser = super(UnsetFlavor, self).get_parser(prog_name)
340+
parser.add_argument(
341+
"flavor",
342+
metavar="<flavor>",
343+
help=_("Flavor to modify (name or ID)")
344+
)
340345
parser.add_argument(
341346
"--property",
342347
metavar="<key>",
343348
action='append',
344-
required=True,
345349
help=_("Property to remove from flavor "
346350
"(repeat option to unset multiple properties)")
347351
)
348352
parser.add_argument(
349-
"flavor",
350-
metavar="<flavor>",
351-
help=_("Flavor to modify (name or ID)")
353+
'--project',
354+
metavar='<project>',
355+
help=_('Remove flavor access from project (name or ID) '
356+
'(admin only)'),
352357
)
358+
identity_common.add_project_domain_option_to_parser(parser)
359+
353360
return parser
354361

355362
def take_action(self, parsed_args):
356363
compute_client = self.app.client_manager.compute
364+
identity_client = self.app.client_manager.identity
365+
357366
flavor = _find_flavor(compute_client, parsed_args.flavor)
358-
flavor.unset_keys(parsed_args.property)
367+
368+
if not parsed_args.property and not parsed_args.project:
369+
raise exceptions.CommandError(_("Nothing specified to be unset."))
370+
371+
result = 0
372+
if parsed_args.property:
373+
try:
374+
flavor.unset_keys(parsed_args.property)
375+
except Exception as e:
376+
self.app.log.error(
377+
_("Failed to unset flavor property: %s") % str(e))
378+
result += 1
379+
380+
if parsed_args.project:
381+
try:
382+
if flavor.is_public:
383+
msg = _("Cannot remove access for a public flavor")
384+
raise exceptions.CommandError(msg)
385+
else:
386+
project_id = identity_common.find_project(
387+
identity_client,
388+
parsed_args.project,
389+
parsed_args.project_domain,
390+
).id
391+
compute_client.flavor_access.remove_tenant_access(
392+
flavor.id, project_id)
393+
except Exception as e:
394+
self.app.log.error(_("Failed to remove flavor access from"
395+
" project: %s") % str(e))
396+
result += 1
397+
398+
if result > 0:
399+
raise exceptions.CommandError(_("Command Failed: One or more of"
400+
" the operations failed"))

openstackclient/tests/compute/v2/test_flavor.py

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,16 +616,23 @@ def test_flavor_show(self):
616616
class TestFlavorUnset(TestFlavor):
617617

618618
# Return value of self.flavors_mock.find().
619-
flavor = compute_fakes.FakeFlavor.create_one_flavor()
619+
flavor = compute_fakes.FakeFlavor.create_one_flavor(
620+
attrs={'os-flavor-access:is_public': False})
620621

621622
def setUp(self):
622623
super(TestFlavorUnset, self).setUp()
623624

624625
self.flavors_mock.find.return_value = self.flavor
625626
self.flavors_mock.get.side_effect = exceptions.NotFound(None)
627+
# Return a project
628+
self.projects_mock.get.return_value = fakes.FakeResource(
629+
None,
630+
copy.deepcopy(identity_fakes.PROJECT),
631+
loaded=True,
632+
)
626633
self.cmd = flavor.UnsetFlavor(self.app, None)
627634

628-
def test_flavor_unset(self):
635+
def test_flavor_unset_property(self):
629636
arglist = [
630637
'--property', 'property',
631638
'baremetal'
@@ -640,3 +647,80 @@ def test_flavor_unset(self):
640647
self.flavors_mock.find.assert_called_with(name=parsed_args.flavor,
641648
is_public=None)
642649
self.assertIsNone(result)
650+
651+
def test_flavor_unset_project(self):
652+
arglist = [
653+
'--project', identity_fakes.project_id,
654+
self.flavor.id,
655+
]
656+
verifylist = [
657+
('project', identity_fakes.project_id),
658+
('flavor', self.flavor.id),
659+
]
660+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
661+
662+
result = self.cmd.take_action(parsed_args)
663+
self.assertIsNone(result)
664+
665+
self.flavor_access_mock.remove_tenant_access.assert_called_with(
666+
self.flavor.id,
667+
identity_fakes.project_id,
668+
)
669+
670+
def test_flavor_unset_no_project(self):
671+
arglist = [
672+
'--project', '',
673+
self.flavor.id,
674+
]
675+
verifylist = [
676+
('project', ''),
677+
('flavor', self.flavor.id),
678+
]
679+
680+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
681+
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
682+
parsed_args)
683+
684+
def test_flavor_unset_no_flavor(self):
685+
arglist = [
686+
'--project', identity_fakes.project_id,
687+
]
688+
verifylist = [
689+
('project', identity_fakes.project_id),
690+
]
691+
692+
self.assertRaises(tests_utils.ParserException,
693+
self.check_parser,
694+
self.cmd,
695+
arglist,
696+
verifylist)
697+
698+
def test_flavor_unset_with_unexist_flavor(self):
699+
self.flavors_mock.get.side_effect = exceptions.NotFound(None)
700+
self.flavors_mock.find.side_effect = exceptions.NotFound(None)
701+
702+
arglist = [
703+
'--project', identity_fakes.project_id,
704+
'unexist_flavor',
705+
]
706+
verifylist = [
707+
('project', identity_fakes.project_id),
708+
('flavor', 'unexist_flavor'),
709+
]
710+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
711+
712+
self.assertRaises(exceptions.CommandError,
713+
self.cmd.take_action,
714+
parsed_args)
715+
716+
def test_flavor_unset_nothing(self):
717+
arglist = [
718+
self.flavor.id,
719+
]
720+
verifylist = [
721+
('flavor', self.flavor.id),
722+
]
723+
724+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
725+
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
726+
parsed_args)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
features:
3+
- |
4+
Added support for removing flavor access from project by using below command
5+
``flavor unset <flavor> --project <project> --project-domain <project-domain>``
6+
[Bug `1575461 <https://bugs.launchpad.net/python-openstackclient/+bug/1575461>`_]

0 commit comments

Comments
 (0)