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:
parent
31ae635ffe
commit
629eb33c4d
doc/source/cli/command-objects
openstackclient
tests
functional/volume
unit/volume
volume
releasenotes/notes
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add ``--no-property`` option in ``volume qos set``.
|
Loading…
x
Reference in New Issue
Block a user