diff --git a/doc/source/cli/command-objects/volume-qos.rst b/doc/source/cli/command-objects/volume-qos.rst index 8fdbc12284..52c1f2d484 100644 --- a/doc/source/cli/command-objects/volume-qos.rst +++ b/doc/source/cli/command-objects/volume-qos.rst @@ -116,9 +116,16 @@ Set QoS specification properties .. code:: bash openstack volume qos set + [--no-property] [--property [...] ] +.. option:: --no-property + + Remove all properties from :ref:`\ ` + (specify both :option:`--no-property` and :option:`--property` to + remove the current properties before setting new properties.) + .. option:: --property Property to add or modify for this QoS specification (repeat option to set multiple properties) diff --git a/openstackclient/tests/functional/volume/v1/test_qos.py b/openstackclient/tests/functional/volume/v1/test_qos.py index cabcd19e80..5d0aa41f67 100644 --- a/openstackclient/tests/functional/volume/v1/test_qos.py +++ b/openstackclient/tests/functional/volume/v1/test_qos.py @@ -52,8 +52,10 @@ class QosTests(common.BaseVolumeTests): name = uuid.uuid4().hex cmd_output = self.openstack( - 'volume qos create ' + '--consumer front-end ' - '--property Alpha=a ' + name, + 'volume qos create ' + + '--consumer front-end ' + + '--property Alpha=a ' + + name, parse_output=True, ) self.addCleanup(self.openstack, 'volume qos delete ' + name) @@ -64,8 +66,9 @@ class QosTests(common.BaseVolumeTests): # Test volume qos set raw_output = self.openstack( 'volume qos set ' - + '--property Alpha=c ' + + '--no-property ' + '--property Beta=b ' + + '--property Charlie=c ' + name, ) self.assertOutput('', raw_output) @@ -76,11 +79,14 @@ class QosTests(common.BaseVolumeTests): parse_output=True, ) 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 raw_output = self.openstack( - 'volume qos unset ' + '--property Alpha ' + name, + 'volume qos unset ' + '--property Charlie ' + name, ) self.assertOutput('', raw_output) diff --git a/openstackclient/tests/functional/volume/v2/test_qos.py b/openstackclient/tests/functional/volume/v2/test_qos.py index 4f07084ad7..fc4c52de2e 100644 --- a/openstackclient/tests/functional/volume/v2/test_qos.py +++ b/openstackclient/tests/functional/volume/v2/test_qos.py @@ -52,8 +52,10 @@ class QosTests(common.BaseVolumeTests): name = uuid.uuid4().hex cmd_output = self.openstack( - 'volume qos create ' + '--consumer front-end ' - '--property Alpha=a ' + name, + 'volume qos create ' + + '--consumer front-end ' + + '--property Alpha=a ' + + name, parse_output=True, ) self.addCleanup(self.openstack, 'volume qos delete ' + name) @@ -65,8 +67,9 @@ class QosTests(common.BaseVolumeTests): # Test volume qos set raw_output = self.openstack( 'volume qos set ' - + '--property Alpha=c ' + + '--no-property ' + '--property Beta=b ' + + '--property Charlie=c ' + name, ) self.assertOutput('', raw_output) @@ -77,11 +80,14 @@ class QosTests(common.BaseVolumeTests): parse_output=True, ) 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 raw_output = self.openstack( - 'volume qos unset ' + '--property Alpha ' + name, + 'volume qos unset ' + '--property Charlie ' + name, ) self.assertOutput('', raw_output) diff --git a/openstackclient/tests/functional/volume/v3/test_qos.py b/openstackclient/tests/functional/volume/v3/test_qos.py index 2a09e549b6..54dffbc0e7 100644 --- a/openstackclient/tests/functional/volume/v3/test_qos.py +++ b/openstackclient/tests/functional/volume/v3/test_qos.py @@ -52,8 +52,10 @@ class QosTests(common.BaseVolumeTests): name = uuid.uuid4().hex cmd_output = self.openstack( - 'volume qos create ' + '--consumer front-end ' - '--property Alpha=a ' + name, + 'volume qos create ' + + '--consumer front-end ' + + '--property Alpha=a ' + + name, parse_output=True, ) self.addCleanup(self.openstack, 'volume qos delete ' + name) @@ -65,8 +67,9 @@ class QosTests(common.BaseVolumeTests): # Test volume qos set raw_output = self.openstack( 'volume qos set ' - + '--property Alpha=c ' + + '--no-property ' + '--property Beta=b ' + + '--property Charlie=c ' + name, ) self.assertOutput('', raw_output) @@ -77,11 +80,14 @@ class QosTests(common.BaseVolumeTests): parse_output=True, ) 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 raw_output = self.openstack( - 'volume qos unset ' + '--property Alpha ' + name, + 'volume qos unset ' + '--property Charlie ' + name, ) self.assertOutput('', raw_output) diff --git a/openstackclient/tests/unit/volume/v1/test_qos_specs.py b/openstackclient/tests/unit/volume/v1/test_qos_specs.py index 7e26e22374..cbfd1fa4ce 100644 --- a/openstackclient/tests/unit/volume/v1/test_qos_specs.py +++ b/openstackclient/tests/unit/volume/v1/test_qos_specs.py @@ -366,22 +366,30 @@ class TestQosSet(TestQos): def test_qos_set_with_properties_with_id(self): arglist = [ + '--no-property', '--property', - 'foo=bar', + 'a=b', '--property', - 'iops=9001', + 'c=d', self.qos_spec.id, ] + new_property = {"a": "b", "c": "d"} verifylist = [ - ('property', self.qos_spec.specs), + ('no_property', True), + ('property', new_property), ('qos_spec', self.qos_spec.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) 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_spec.id, self.qos_spec.specs + self.qos_spec.id, + {"a": "b", "c": "d"}, ) self.assertIsNone(result) diff --git a/openstackclient/tests/unit/volume/v2/test_qos_specs.py b/openstackclient/tests/unit/volume/v2/test_qos_specs.py index 994bcf9646..54a13efcdf 100644 --- a/openstackclient/tests/unit/volume/v2/test_qos_specs.py +++ b/openstackclient/tests/unit/volume/v2/test_qos_specs.py @@ -362,22 +362,29 @@ class TestQosSet(TestQos): def test_qos_set_with_properties_with_id(self): arglist = [ + '--no-property', '--property', - 'foo=bar', + 'a=b', '--property', - 'iops=9001', + 'c=d', self.qos_spec.id, ] + new_property = {"a": "b", "c": "d"} verifylist = [ - ('property', self.qos_spec.specs), + ('no_property', True), + ('property', new_property), ('qos_spec', self.qos_spec.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) 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_spec.id, self.qos_spec.specs + self.qos_spec.id, {"a": "b", "c": "d"} ) self.assertIsNone(result) diff --git a/openstackclient/volume/v1/qos_specs.py b/openstackclient/volume/v1/qos_specs.py index 87e32ff45d..830d5d8276 100644 --- a/openstackclient/volume/v1/qos_specs.py +++ b/openstackclient/volume/v1/qos_specs.py @@ -255,6 +255,16 @@ class SetQos(command.Command): metavar='', help=_('QoS specification to modify (name or ID)'), ) + parser.add_argument( + '--no-property', + dest='no_property', + action='store_true', + help=_( + 'Remove all properties from ' + '(specify both --no-property and --property to remove the ' + 'current properties before setting new properties)' + ), + ) parser.add_argument( '--property', metavar='', @@ -272,8 +282,29 @@ class SetQos(command.Command): 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: - 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): diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py index 2c06ee3418..0454ecae84 100644 --- a/openstackclient/volume/v2/qos_specs.py +++ b/openstackclient/volume/v2/qos_specs.py @@ -257,6 +257,16 @@ class SetQos(command.Command): metavar='', help=_('QoS specification to modify (name or ID)'), ) + parser.add_argument( + '--no-property', + dest='no_property', + action='store_true', + help=_( + 'Remove all properties from ' + '(specify both --no-property and --property to remove the ' + 'current properties before setting new properties)' + ), + ) parser.add_argument( '--property', metavar='', @@ -274,8 +284,29 @@ class SetQos(command.Command): 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: - 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): diff --git a/releasenotes/notes/add-volume-qos-set-no-property-option-348480dfc42a0a64.yaml b/releasenotes/notes/add-volume-qos-set-no-property-option-348480dfc42a0a64.yaml new file mode 100644 index 0000000000..51b2145068 --- /dev/null +++ b/releasenotes/notes/add-volume-qos-set-no-property-option-348480dfc42a0a64.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Add ``--no-property`` option in ``volume qos set``.