Skip to content

Commit a4a8745

Browse files
aufimburns72h
authored andcommitted
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
1 parent 6972c34 commit a4a8745

File tree

4 files changed

+193
-4
lines changed

4 files changed

+193
-4
lines changed

doc/source/command-objects/flavor.rst

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,43 @@ Display flavor details
123123
.. describe:: <flavor>
124124

125125
Flavor to display (name or ID)
126+
127+
flavor set
128+
----------
129+
130+
Set flavor properties
131+
132+
.. program:: flavor set
133+
.. code:: bash
134+
135+
os flavor set
136+
[--property <key=value> [...] ]
137+
<flavor>
138+
139+
.. option:: --property <key=value>
140+
141+
Property to add or modify for this flavor (repeat option to set multiple properties)
142+
143+
.. describe:: <flavor>
144+
145+
Flavor to modify (name or ID)
146+
147+
flavor unset
148+
------------
149+
150+
Unset flavor properties
151+
152+
.. program:: flavor unset
153+
.. code:: bash
154+
155+
os flavor unset
156+
[--property <key> [...] ]
157+
<flavor>
158+
159+
.. option:: --property <key>
160+
161+
Property to remove from flavor (repeat option to remove multiple properties)
162+
163+
.. describe:: <flavor>
164+
165+
Flavor to modify (name or ID)

openstackclient/compute/v2/flavor.py

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from cliff import lister
2323
from cliff import show
2424

25+
from openstackclient.common import parseractions
2526
from openstackclient.common import utils
2627

2728

@@ -237,8 +238,79 @@ def get_parser(self, prog_name):
237238
def take_action(self, parsed_args):
238239
self.log.debug("take_action(%s)", parsed_args)
239240
compute_client = self.app.client_manager.compute
240-
flavor = utils.find_resource(compute_client.flavors,
241-
parsed_args.flavor)._info.copy()
242-
flavor.pop("links")
241+
resource_flavor = utils.find_resource(compute_client.flavors,
242+
parsed_args.flavor)
243+
flavor = resource_flavor._info.copy()
244+
flavor.pop("links", None)
245+
246+
flavor['properties'] = utils.format_dict(resource_flavor.get_keys())
247+
248+
return zip(*sorted(six.iteritems(flavor)))
249+
250+
251+
class SetFlavor(show.ShowOne):
252+
"""Set flavor properties"""
253+
254+
log = logging.getLogger(__name__ + ".SetFlavor")
255+
256+
def get_parser(self, prog_name):
257+
parser = super(SetFlavor, self).get_parser(prog_name)
258+
parser.add_argument(
259+
"--property",
260+
metavar="<key=value>",
261+
action=parseractions.KeyValueAction,
262+
help='Property to add or modify for this flavor '
263+
'(repeat option to set multiple properties)',
264+
)
265+
parser.add_argument(
266+
"flavor",
267+
metavar="<flavor>",
268+
help="Flavor to modify (name or ID)",
269+
)
270+
return parser
271+
272+
def take_action(self, parsed_args):
273+
self.log.debug("take_action(%s)", parsed_args)
274+
compute_client = self.app.client_manager.compute
275+
resource_flavor = compute_client.flavors.find(name=parsed_args.flavor)
276+
277+
resource_flavor.set_keys(parsed_args.property)
278+
279+
flavor = resource_flavor._info.copy()
280+
flavor['properties'] = utils.format_dict(resource_flavor.get_keys())
281+
flavor.pop("links", None)
282+
return zip(*sorted(six.iteritems(flavor)))
283+
284+
285+
class UnsetFlavor(show.ShowOne):
286+
"""Unset flavor properties"""
287+
288+
log = logging.getLogger(__name__ + ".UnsetFlavor")
289+
290+
def get_parser(self, prog_name):
291+
parser = super(UnsetFlavor, self).get_parser(prog_name)
292+
parser.add_argument(
293+
"--property",
294+
metavar="<key>",
295+
action='append',
296+
help='Property to remove from flavor '
297+
'(repeat option to unset multiple properties)',
298+
)
299+
parser.add_argument(
300+
"flavor",
301+
metavar="<flavor>",
302+
help="Flavor to modify (name or ID)",
303+
)
304+
return parser
305+
306+
def take_action(self, parsed_args):
307+
self.log.debug("take_action(%s)", parsed_args)
308+
compute_client = self.app.client_manager.compute
309+
resource_flavor = compute_client.flavors.find(name=parsed_args.flavor)
310+
311+
resource_flavor.unset_keys(parsed_args.property)
243312

313+
flavor = resource_flavor._info.copy()
314+
flavor['properties'] = utils.format_dict(resource_flavor.get_keys())
315+
flavor.pop("links", None)
244316
return zip(*sorted(six.iteritems(flavor)))

openstackclient/tests/compute/v2/test_flavor.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@
2222

2323
class FakeFlavorResource(fakes.FakeResource):
2424

25+
_keys = {'property': 'value'}
26+
27+
def set_keys(self, args):
28+
self._keys.update(args)
29+
30+
def unset_keys(self, keys):
31+
for key in keys:
32+
self._keys.pop(key, None)
33+
2534
def get_keys(self):
26-
return {'property': 'value'}
35+
return self._keys
2736

2837

2938
class TestFlavor(compute_fakes.TestComputev2):
@@ -272,3 +281,69 @@ def test_flavor_list_long(self):
272281
'property=\'value\''
273282
), )
274283
self.assertEqual(datalist, tuple(data))
284+
285+
286+
class TestFlavorSet(TestFlavor):
287+
288+
def setUp(self):
289+
super(TestFlavorSet, self).setUp()
290+
291+
self.flavors_mock.find.return_value = FakeFlavorResource(
292+
None,
293+
copy.deepcopy(compute_fakes.FLAVOR),
294+
loaded=True,
295+
)
296+
297+
self.cmd = flavor.SetFlavor(self.app, None)
298+
299+
def test_flavor_set(self):
300+
arglist = [
301+
'--property', 'FOO="B A R"',
302+
'baremetal'
303+
]
304+
verifylist = [
305+
('property', {'FOO': '"B A R"'}),
306+
('flavor', 'baremetal')
307+
]
308+
309+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
310+
311+
columns, data = self.cmd.take_action(parsed_args)
312+
313+
self.flavors_mock.find.assert_called_with(name='baremetal')
314+
315+
self.assertEqual('properties', columns[2])
316+
self.assertIn('FOO=\'"B A R"\'', data[2])
317+
318+
319+
class TestFlavorUnset(TestFlavor):
320+
321+
def setUp(self):
322+
super(TestFlavorUnset, self).setUp()
323+
324+
self.flavors_mock.find.return_value = FakeFlavorResource(
325+
None,
326+
copy.deepcopy(compute_fakes.FLAVOR),
327+
loaded=True,
328+
)
329+
330+
self.cmd = flavor.UnsetFlavor(self.app, None)
331+
332+
def test_flavor_unset(self):
333+
arglist = [
334+
'--property', 'property',
335+
'baremetal'
336+
]
337+
verifylist = [
338+
('property', ['property']),
339+
('flavor', 'baremetal'),
340+
]
341+
342+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
343+
344+
columns, data = self.cmd.take_action(parsed_args)
345+
346+
self.flavors_mock.find.assert_called_with(name='baremetal')
347+
348+
self.assertEqual('properties', columns[2])
349+
self.assertNotIn('property', data[2])

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ openstack.compute.v2 =
7575
flavor_delete = openstackclient.compute.v2.flavor:DeleteFlavor
7676
flavor_list = openstackclient.compute.v2.flavor:ListFlavor
7777
flavor_show = openstackclient.compute.v2.flavor:ShowFlavor
78+
flavor_set = openstackclient.compute.v2.flavor:SetFlavor
79+
flavor_unset = openstackclient.compute.v2.flavor:UnsetFlavor
7880

7981
host_list = openstackclient.compute.v2.host:ListHost
8082
host_show = openstackclient.compute.v2.host:ShowHost

0 commit comments

Comments
 (0)