From 4aa10e818a323056cc8679384da36827af313f9d Mon Sep 17 00:00:00 2001 From: Marek Aufart Date: Tue, 17 Mar 2015 15:38:24 +0100 Subject: [PATCH] Add the ability to set and unset flavor properties Added flavor set and unset command which allow manage flavor properties called extra_specs. Command flavor show output was extended with these properties. Closes-Bug: 1434137 Change-Id: Ie469bade802de18aab9d58eda3fff46064008163 (cherry picked from commit 621434451f561e7ef7c549a134f3bfadcf10520f) --- doc/source/command-objects/flavor.rst | 40 +++++++++++++ openstackclient/compute/v2/flavor.py | 78 ++++++++++++++++++++++++- openstackclient/tests/compute/v2/test_flavor.py | 77 +++++++++++++++++++++++- setup.cfg | 2 + 4 files changed, 193 insertions(+), 4 deletions(-) diff --git a/doc/source/command-objects/flavor.rst b/doc/source/command-objects/flavor.rst index fa9fd80..5254b12 100644 --- a/doc/source/command-objects/flavor.rst +++ b/doc/source/command-objects/flavor.rst @@ -123,3 +123,43 @@ Display flavor details .. describe:: Flavor to display (name or ID) + +flavor set +---------- + +Set flavor properties + +.. program:: flavor set +.. code:: bash + + os flavor set + [--property [...] ] + + +.. option:: --property + + Property to add or modify for this flavor (repeat option to set multiple properties) + +.. describe:: + + Flavor to modify (name or ID) + +flavor unset +------------ + +Unset flavor properties + +.. program:: flavor unset +.. code:: bash + + os flavor unset + [--property [...] ] + + +.. option:: --property + + Property to remove from flavor (repeat option to remove multiple properties) + +.. describe:: + + Flavor to modify (name or ID) diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py index 195c9a0..eb18a43 100644 --- a/openstackclient/compute/v2/flavor.py +++ b/openstackclient/compute/v2/flavor.py @@ -22,6 +22,7 @@ from cliff import command from cliff import lister from cliff import show +from openstackclient.common import parseractions from openstackclient.common import utils @@ -237,8 +238,79 @@ class ShowFlavor(show.ShowOne): def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute - flavor = utils.find_resource(compute_client.flavors, - parsed_args.flavor)._info.copy() - flavor.pop("links") + resource_flavor = utils.find_resource(compute_client.flavors, + parsed_args.flavor) + flavor = resource_flavor._info.copy() + flavor.pop("links", None) + + flavor['properties'] = utils.format_dict(resource_flavor.get_keys()) + + return zip(*sorted(six.iteritems(flavor))) + + +class SetFlavor(show.ShowOne): + """Set flavor properties""" + + log = logging.getLogger(__name__ + ".SetFlavor") + + def get_parser(self, prog_name): + parser = super(SetFlavor, self).get_parser(prog_name) + parser.add_argument( + "--property", + metavar="", + action=parseractions.KeyValueAction, + help='Property to add or modify for this flavor ' + '(repeat option to set multiple properties)', + ) + parser.add_argument( + "flavor", + metavar="", + help="Flavor to modify (name or ID)", + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + compute_client = self.app.client_manager.compute + resource_flavor = compute_client.flavors.find(name=parsed_args.flavor) + + resource_flavor.set_keys(parsed_args.property) + + flavor = resource_flavor._info.copy() + flavor['properties'] = utils.format_dict(resource_flavor.get_keys()) + flavor.pop("links", None) + return zip(*sorted(six.iteritems(flavor))) + + +class UnsetFlavor(show.ShowOne): + """Unset flavor properties""" + + log = logging.getLogger(__name__ + ".UnsetFlavor") + + def get_parser(self, prog_name): + parser = super(UnsetFlavor, self).get_parser(prog_name) + parser.add_argument( + "--property", + metavar="", + action='append', + help='Property to remove from flavor ' + '(repeat option to unset multiple properties)', + ) + parser.add_argument( + "flavor", + metavar="", + help="Flavor to modify (name or ID)", + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + compute_client = self.app.client_manager.compute + resource_flavor = compute_client.flavors.find(name=parsed_args.flavor) + + resource_flavor.unset_keys(parsed_args.property) + flavor = resource_flavor._info.copy() + flavor['properties'] = utils.format_dict(resource_flavor.get_keys()) + flavor.pop("links", None) return zip(*sorted(six.iteritems(flavor))) diff --git a/openstackclient/tests/compute/v2/test_flavor.py b/openstackclient/tests/compute/v2/test_flavor.py index 8f33ccf..19be812 100644 --- a/openstackclient/tests/compute/v2/test_flavor.py +++ b/openstackclient/tests/compute/v2/test_flavor.py @@ -22,8 +22,17 @@ from openstackclient.tests import fakes class FakeFlavorResource(fakes.FakeResource): + _keys = {'property': 'value'} + + def set_keys(self, args): + self._keys.update(args) + + def unset_keys(self, keys): + for key in keys: + self._keys.pop(key, None) + def get_keys(self): - return {'property': 'value'} + return self._keys class TestFlavor(compute_fakes.TestComputev2): @@ -272,3 +281,69 @@ class TestFlavorList(TestFlavor): 'property=\'value\'' ), ) self.assertEqual(datalist, tuple(data)) + + +class TestFlavorSet(TestFlavor): + + def setUp(self): + super(TestFlavorSet, self).setUp() + + self.flavors_mock.find.return_value = FakeFlavorResource( + None, + copy.deepcopy(compute_fakes.FLAVOR), + loaded=True, + ) + + self.cmd = flavor.SetFlavor(self.app, None) + + def test_flavor_set(self): + arglist = [ + '--property', 'FOO="B A R"', + 'baremetal' + ] + verifylist = [ + ('property', {'FOO': '"B A R"'}), + ('flavor', 'baremetal') + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.flavors_mock.find.assert_called_with(name='baremetal') + + self.assertEqual('properties', columns[2]) + self.assertIn('FOO=\'"B A R"\'', data[2]) + + +class TestFlavorUnset(TestFlavor): + + def setUp(self): + super(TestFlavorUnset, self).setUp() + + self.flavors_mock.find.return_value = FakeFlavorResource( + None, + copy.deepcopy(compute_fakes.FLAVOR), + loaded=True, + ) + + self.cmd = flavor.UnsetFlavor(self.app, None) + + def test_flavor_unset(self): + arglist = [ + '--property', 'property', + 'baremetal' + ] + verifylist = [ + ('property', ['property']), + ('flavor', 'baremetal'), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.flavors_mock.find.assert_called_with(name='baremetal') + + self.assertEqual('properties', columns[2]) + self.assertNotIn('property', data[2]) diff --git a/setup.cfg b/setup.cfg index 444981d..91effc9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,6 +65,8 @@ openstack.compute.v2 = flavor_delete = openstackclient.compute.v2.flavor:DeleteFlavor flavor_list = openstackclient.compute.v2.flavor:ListFlavor flavor_show = openstackclient.compute.v2.flavor:ShowFlavor + flavor_set = openstackclient.compute.v2.flavor:SetFlavor + flavor_unset = openstackclient.compute.v2.flavor:UnsetFlavor host_list = openstackclient.compute.v2.host:ListHost host_show = openstackclient.compute.v2.host:ShowHost hypervisor_list = openstackclient.compute.v2.hypervisor:ListHypervisor