volume: Add 'volume qos set --no-property' option

Supporting "--no-property" option will apply user a convenient way to
clean all properties of volume qos in a short command. The patch adds
"--no-property" option in "volume qos set" command and update related
test cases and docs.

Change-Id: I1fb5b4f0a923bbf557a3af3f63809bde9e84ffd4
This commit is contained in:
Stephen Finucane 2023-05-17 12:27:45 +01:00
parent 31ae635ffe
commit 629eb33c4d
9 changed files with 131 additions and 25 deletions

View File

@ -116,9 +116,16 @@ Set QoS specification properties
.. code:: bash .. code:: bash
openstack volume qos set openstack volume qos set
[--no-property]
[--property <key=value> [...] ] [--property <key=value> [...] ]
<qos-spec> <qos-spec>
.. option:: --no-property
Remove all properties from :ref:`\<snapshot\> <volume_qos_set-qos-spec>`
(specify both :option:`--no-property` and :option:`--property` to
remove the current properties before setting new properties.)
.. option:: --property <key=value> .. option:: --property <key=value>
Property to add or modify for this QoS specification (repeat option to set multiple properties) Property to add or modify for this QoS specification (repeat option to set multiple properties)

View File

@ -52,8 +52,10 @@ class QosTests(common.BaseVolumeTests):
name = uuid.uuid4().hex name = uuid.uuid4().hex
cmd_output = self.openstack( cmd_output = self.openstack(
'volume qos create ' + '--consumer front-end ' 'volume qos create '
'--property Alpha=a ' + name, + '--consumer front-end '
+ '--property Alpha=a '
+ name,
parse_output=True, parse_output=True,
) )
self.addCleanup(self.openstack, 'volume qos delete ' + name) self.addCleanup(self.openstack, 'volume qos delete ' + name)
@ -64,8 +66,9 @@ class QosTests(common.BaseVolumeTests):
# Test volume qos set # Test volume qos set
raw_output = self.openstack( raw_output = self.openstack(
'volume qos set ' 'volume qos set '
+ '--property Alpha=c ' + '--no-property '
+ '--property Beta=b ' + '--property Beta=b '
+ '--property Charlie=c '
+ name, + name,
) )
self.assertOutput('', raw_output) self.assertOutput('', raw_output)
@ -76,11 +79,14 @@ class QosTests(common.BaseVolumeTests):
parse_output=True, parse_output=True,
) )
self.assertEqual(name, cmd_output['name']) self.assertEqual(name, cmd_output['name'])
self.assertEqual({'Alpha': 'c', 'Beta': 'b'}, cmd_output['properties']) self.assertEqual(
{'Beta': 'b', 'Charlie': 'c'},
cmd_output['properties'],
)
# Test volume qos unset # Test volume qos unset
raw_output = self.openstack( raw_output = self.openstack(
'volume qos unset ' + '--property Alpha ' + name, 'volume qos unset ' + '--property Charlie ' + name,
) )
self.assertOutput('', raw_output) self.assertOutput('', raw_output)

View File

@ -52,8 +52,10 @@ class QosTests(common.BaseVolumeTests):
name = uuid.uuid4().hex name = uuid.uuid4().hex
cmd_output = self.openstack( cmd_output = self.openstack(
'volume qos create ' + '--consumer front-end ' 'volume qos create '
'--property Alpha=a ' + name, + '--consumer front-end '
+ '--property Alpha=a '
+ name,
parse_output=True, parse_output=True,
) )
self.addCleanup(self.openstack, 'volume qos delete ' + name) self.addCleanup(self.openstack, 'volume qos delete ' + name)
@ -65,8 +67,9 @@ class QosTests(common.BaseVolumeTests):
# Test volume qos set # Test volume qos set
raw_output = self.openstack( raw_output = self.openstack(
'volume qos set ' 'volume qos set '
+ '--property Alpha=c ' + '--no-property '
+ '--property Beta=b ' + '--property Beta=b '
+ '--property Charlie=c '
+ name, + name,
) )
self.assertOutput('', raw_output) self.assertOutput('', raw_output)
@ -77,11 +80,14 @@ class QosTests(common.BaseVolumeTests):
parse_output=True, parse_output=True,
) )
self.assertEqual(name, cmd_output['name']) self.assertEqual(name, cmd_output['name'])
self.assertEqual({'Alpha': 'c', 'Beta': 'b'}, cmd_output['properties']) self.assertEqual(
{'Beta': 'b', 'Charlie': 'c'},
cmd_output['properties'],
)
# Test volume qos unset # Test volume qos unset
raw_output = self.openstack( raw_output = self.openstack(
'volume qos unset ' + '--property Alpha ' + name, 'volume qos unset ' + '--property Charlie ' + name,
) )
self.assertOutput('', raw_output) self.assertOutput('', raw_output)

View File

@ -52,8 +52,10 @@ class QosTests(common.BaseVolumeTests):
name = uuid.uuid4().hex name = uuid.uuid4().hex
cmd_output = self.openstack( cmd_output = self.openstack(
'volume qos create ' + '--consumer front-end ' 'volume qos create '
'--property Alpha=a ' + name, + '--consumer front-end '
+ '--property Alpha=a '
+ name,
parse_output=True, parse_output=True,
) )
self.addCleanup(self.openstack, 'volume qos delete ' + name) self.addCleanup(self.openstack, 'volume qos delete ' + name)
@ -65,8 +67,9 @@ class QosTests(common.BaseVolumeTests):
# Test volume qos set # Test volume qos set
raw_output = self.openstack( raw_output = self.openstack(
'volume qos set ' 'volume qos set '
+ '--property Alpha=c ' + '--no-property '
+ '--property Beta=b ' + '--property Beta=b '
+ '--property Charlie=c '
+ name, + name,
) )
self.assertOutput('', raw_output) self.assertOutput('', raw_output)
@ -77,11 +80,14 @@ class QosTests(common.BaseVolumeTests):
parse_output=True, parse_output=True,
) )
self.assertEqual(name, cmd_output['name']) self.assertEqual(name, cmd_output['name'])
self.assertEqual({'Alpha': 'c', 'Beta': 'b'}, cmd_output['properties']) self.assertEqual(
{'Beta': 'b', 'Charlie': 'c'},
cmd_output['properties'],
)
# Test volume qos unset # Test volume qos unset
raw_output = self.openstack( raw_output = self.openstack(
'volume qos unset ' + '--property Alpha ' + name, 'volume qos unset ' + '--property Charlie ' + name,
) )
self.assertOutput('', raw_output) self.assertOutput('', raw_output)

View File

@ -366,22 +366,30 @@ class TestQosSet(TestQos):
def test_qos_set_with_properties_with_id(self): def test_qos_set_with_properties_with_id(self):
arglist = [ arglist = [
'--no-property',
'--property', '--property',
'foo=bar', 'a=b',
'--property', '--property',
'iops=9001', 'c=d',
self.qos_spec.id, self.qos_spec.id,
] ]
new_property = {"a": "b", "c": "d"}
verifylist = [ verifylist = [
('property', self.qos_spec.specs), ('no_property', True),
('property', new_property),
('qos_spec', self.qos_spec.id), ('qos_spec', self.qos_spec.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args) result = self.cmd.take_action(parsed_args)
self.qos_mock.unset_keys.assert_called_with(
self.qos_spec.id,
list(self.qos_spec.specs.keys()),
)
self.qos_mock.set_keys.assert_called_with( self.qos_mock.set_keys.assert_called_with(
self.qos_spec.id, self.qos_spec.specs self.qos_spec.id,
{"a": "b", "c": "d"},
) )
self.assertIsNone(result) self.assertIsNone(result)

View File

@ -362,22 +362,29 @@ class TestQosSet(TestQos):
def test_qos_set_with_properties_with_id(self): def test_qos_set_with_properties_with_id(self):
arglist = [ arglist = [
'--no-property',
'--property', '--property',
'foo=bar', 'a=b',
'--property', '--property',
'iops=9001', 'c=d',
self.qos_spec.id, self.qos_spec.id,
] ]
new_property = {"a": "b", "c": "d"}
verifylist = [ verifylist = [
('property', self.qos_spec.specs), ('no_property', True),
('property', new_property),
('qos_spec', self.qos_spec.id), ('qos_spec', self.qos_spec.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args) result = self.cmd.take_action(parsed_args)
self.qos_mock.unset_keys.assert_called_with(
self.qos_spec.id,
list(self.qos_spec.specs.keys()),
)
self.qos_mock.set_keys.assert_called_with( self.qos_mock.set_keys.assert_called_with(
self.qos_spec.id, self.qos_spec.specs self.qos_spec.id, {"a": "b", "c": "d"}
) )
self.assertIsNone(result) self.assertIsNone(result)

View File

@ -255,6 +255,16 @@ class SetQos(command.Command):
metavar='<qos-spec>', metavar='<qos-spec>',
help=_('QoS specification to modify (name or ID)'), help=_('QoS specification to modify (name or ID)'),
) )
parser.add_argument(
'--no-property',
dest='no_property',
action='store_true',
help=_(
'Remove all properties from <qos-spec> '
'(specify both --no-property and --property to remove the '
'current properties before setting new properties)'
),
)
parser.add_argument( parser.add_argument(
'--property', '--property',
metavar='<key=value>', metavar='<key=value>',
@ -272,8 +282,29 @@ class SetQos(command.Command):
volume_client.qos_specs, parsed_args.qos_spec volume_client.qos_specs, parsed_args.qos_spec
) )
result = 0
if parsed_args.no_property:
try:
key_list = list(qos_spec._info['specs'].keys())
volume_client.qos_specs.unset_keys(qos_spec.id, key_list)
except Exception as e:
LOG.error(_("Failed to clean qos properties: %s"), e)
result += 1
if parsed_args.property: if parsed_args.property:
volume_client.qos_specs.set_keys(qos_spec.id, parsed_args.property) try:
volume_client.qos_specs.set_keys(
qos_spec.id,
parsed_args.property,
)
except Exception as e:
LOG.error(_("Failed to set qos property: %s"), e)
result += 1
if result > 0:
raise exceptions.CommandError(
_("One or more of the set operations failed")
)
class ShowQos(command.ShowOne): class ShowQos(command.ShowOne):

View File

@ -257,6 +257,16 @@ class SetQos(command.Command):
metavar='<qos-spec>', metavar='<qos-spec>',
help=_('QoS specification to modify (name or ID)'), help=_('QoS specification to modify (name or ID)'),
) )
parser.add_argument(
'--no-property',
dest='no_property',
action='store_true',
help=_(
'Remove all properties from <qos-spec> '
'(specify both --no-property and --property to remove the '
'current properties before setting new properties)'
),
)
parser.add_argument( parser.add_argument(
'--property', '--property',
metavar='<key=value>', metavar='<key=value>',
@ -274,8 +284,29 @@ class SetQos(command.Command):
volume_client.qos_specs, parsed_args.qos_spec volume_client.qos_specs, parsed_args.qos_spec
) )
result = 0
if parsed_args.no_property:
try:
key_list = list(qos_spec._info['specs'].keys())
volume_client.qos_specs.unset_keys(qos_spec.id, key_list)
except Exception as e:
LOG.error(_("Failed to clean qos properties: %s"), e)
result += 1
if parsed_args.property: if parsed_args.property:
volume_client.qos_specs.set_keys(qos_spec.id, parsed_args.property) try:
volume_client.qos_specs.set_keys(
qos_spec.id,
parsed_args.property,
)
except Exception as e:
LOG.error(_("Failed to set qos property: %s"), e)
result += 1
if result > 0:
raise exceptions.CommandError(
_("One or more of the set operations failed")
)
class ShowQos(command.ShowOne): class ShowQos(command.ShowOne):

View File

@ -0,0 +1,4 @@
---
features:
- |
Add ``--no-property`` option in ``volume qos set``.