diff --git a/doc/source/command-objects/volume.rst b/doc/source/command-objects/volume.rst index 021518be7f..8efa8a6697 100644 --- a/doc/source/command-objects/volume.rst +++ b/doc/source/command-objects/volume.rst @@ -180,6 +180,7 @@ Set volume properties [--description ] [--property [...] ] [--image-property [...] ] + [--state ] .. option:: --name @@ -209,6 +210,14 @@ Set volume properties *Volume version 2 only* +.. option:: --state + + New volume state + ("available", "error", "creating", "deleting", "in-use", + "attaching", "detaching", "error_deleting" or "maintenance") + + *Volume version 2 only* + .. _volume_set-volume: .. describe:: diff --git a/functional/tests/volume/v2/test_volume.py b/functional/tests/volume/v2/test_volume.py index 019f0c6f52..02324a1e43 100644 --- a/functional/tests/volume/v2/test_volume.py +++ b/functional/tests/volume/v2/test_volume.py @@ -43,9 +43,16 @@ class VolumeTests(common.BaseVolumeTests): 'volume set --name ' + cls.OTHER_NAME + ' ' + cls.NAME) cls.assertOutput('', raw_output) + # Set volume state + cls.openstack('volume set --state error ' + cls.OTHER_NAME) + opts = cls.get_opts(["status"]) + raw_output_status = cls.openstack( + 'volume show ' + cls.OTHER_NAME + opts) + # Delete test volume raw_output = cls.openstack('volume delete ' + cls.OTHER_NAME) cls.assertOutput('', raw_output) + cls.assertOutput('error\n', raw_output_status) def test_volume_list(self): opts = self.get_opts(self.HEADERS) diff --git a/openstackclient/tests/volume/v2/test_volume.py b/openstackclient/tests/volume/v2/test_volume.py index 6f552ad61b..c2740cab77 100644 --- a/openstackclient/tests/volume/v2/test_volume.py +++ b/openstackclient/tests/volume/v2/test_volume.py @@ -814,6 +814,53 @@ class TestVolumeList(TestVolume): self.assertEqual(datalist, tuple(data)) +class TestVolumeSet(TestVolume): + + def setUp(self): + super(TestVolumeSet, self).setUp() + + self.new_volume = volume_fakes.FakeVolume.create_one_volume() + self.volumes_mock.get.return_value = self.new_volume + + # Get the command object to test + self.cmd = volume.SetVolume(self.app, None) + + def test_volume_set_image_property(self): + arglist = [ + '--image-property', 'Alpha=a', + '--image-property', 'Beta=b', + self.new_volume.id, + ] + verifylist = [ + ('image_property', {'Alpha': 'a', 'Beta': 'b'}), + ('volume', self.new_volume.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # In base command class ShowOne in cliff, abstract method take_action() + # returns nothing + self.cmd.take_action(parsed_args) + self.volumes_mock.set_image_metadata.assert_called_with( + self.volumes_mock.get().id, parsed_args.image_property) + + def test_volume_set_state(self): + arglist = [ + '--state', 'error', + self.new_volume.id + ] + verifylist = [ + ('state', 'error'), + ('volume', self.new_volume.id) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.volumes_mock.reset_state.assert_called_with( + self.new_volume.id, 'error') + self.assertIsNone(result) + + class TestVolumeShow(TestVolume): def setUp(self): @@ -845,36 +892,6 @@ class TestVolumeShow(TestVolume): data) -class TestVolumeSet(TestVolume): - - def setUp(self): - super(TestVolumeSet, self).setUp() - - self.new_volume = volume_fakes.FakeVolume.create_one_volume() - self.volumes_mock.create.return_value = self.new_volume - - # Get the command object to test - self.cmd = volume.SetVolume(self.app, None) - - def test_volume_set_image_property(self): - arglist = [ - '--image-property', 'Alpha=a', - '--image-property', 'Beta=b', - self.new_volume.id, - ] - verifylist = [ - ('image_property', {'Alpha': 'a', 'Beta': 'b'}), - ('volume', self.new_volume.id), - ] - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - # In base command class ShowOne in cliff, abstract method take_action() - # returns nothing - self.cmd.take_action(parsed_args) - self.volumes_mock.set_image_metadata.assert_called_with( - self.volumes_mock.get().id, parsed_args.image_property) - - class TestVolumeUnset(TestVolume): def setUp(self): diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index 6f055922f0..aee18e4f26 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -378,6 +378,16 @@ class SetVolume(command.Command): help=_('Set an image property on this volume ' '(repeat option to set multiple image properties)'), ) + parser.add_argument( + "--state", + metavar="", + choices=['available', 'error', 'creating', 'deleting', + 'in-use', 'attaching', 'detaching', 'error_deleting', + 'maintenance'], + help=_('New volume state ("available", "error", "creating", ' + '"deleting", "in-use", "attaching", "detaching", ' + '"error_deleting" or "maintenance")'), + ) return parser def take_action(self, parsed_args): @@ -400,6 +410,8 @@ class SetVolume(command.Command): if parsed_args.image_property: volume_client.volumes.set_image_metadata( volume.id, parsed_args.image_property) + if parsed_args.state: + volume_client.volumes.reset_state(volume.id, parsed_args.state) kwargs = {} if parsed_args.name: diff --git a/releasenotes/notes/bug-1535213-c91133586e07d71c.yaml b/releasenotes/notes/bug-1535213-c91133586e07d71c.yaml new file mode 100644 index 0000000000..d3f36e3981 --- /dev/null +++ b/releasenotes/notes/bug-1535213-c91133586e07d71c.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Support a new ``--state`` option for ``volume set`` command that + changes the state of a volume. + [Bug `1535213 `_]