diff --git a/doc/source/cli/command-objects/flavor.rst b/doc/source/cli/command-objects/flavor.rst index 1cbd2df3bb..2d946de308 100644 --- a/doc/source/cli/command-objects/flavor.rst +++ b/doc/source/cli/command-objects/flavor.rst @@ -24,6 +24,7 @@ Create new flavor [--property [...] ] [--project ] [--project-domain ] + [--description ] .. option:: --id @@ -76,6 +77,10 @@ Create new flavor Domain the project belongs to (name or ID). This can be used in case collisions between project names exist. +.. option:: --description + + Description to add for this flavor + .. _flavor_create-flavor-name: .. describe:: @@ -148,6 +153,7 @@ Set flavor properties [--property [...] ] [--project ] [--project-domain ] + [--description ] .. option:: --property @@ -168,6 +174,10 @@ Set flavor properties Remove all properties from this flavor (specify both --no-property and --property to remove the current properties before setting new properties.) +.. option:: --description + + Set description to this flavor + .. describe:: Flavor to modify (name or ID) diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py index 0f5dd7421e..2cc5f1e891 100644 --- a/openstackclient/compute/v2/flavor.py +++ b/openstackclient/compute/v2/flavor.py @@ -17,6 +17,7 @@ import logging +from novaclient import api_versions from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions @@ -134,6 +135,12 @@ class CreateFlavor(command.ShowOne): help=_("Allow to access private flavor (name or ID) " "(Must be used with --private option)"), ) + parser.add_argument( + '--description', + metavar='', + help=_("Description for the flavor.(Supported by API versions " + "'2.55' - '2.latest'") + ) identity_common.add_project_domain_option_to_parser(parser) return parser @@ -145,6 +152,11 @@ class CreateFlavor(command.ShowOne): msg = _("--project is only allowed with --private") raise exceptions.CommandError(msg) + if parsed_args.description: + if compute_client.api_version < api_versions.APIVersion("2.55"): + msg = _("--os-compute-api-version 2.55 or later is required") + raise exceptions.CommandError(msg) + args = ( parsed_args.name, parsed_args.ram, @@ -154,7 +166,8 @@ class CreateFlavor(command.ShowOne): parsed_args.ephemeral, parsed_args.swap, parsed_args.rxtx_factor, - parsed_args.public + parsed_args.public, + parsed_args.description ) flavor = compute_client.flavors.create(*args) @@ -332,6 +345,12 @@ class SetFlavor(command.Command): help=_('Set flavor access to project (name or ID) ' '(admin only)'), ) + parser.add_argument( + '--description', + metavar='', + help=_("Set description for the flavor.(Supported by API " + "versions '2.55' - '2.latest'") + ) identity_common.add_project_domain_option_to_parser(parser) return parser @@ -380,6 +399,13 @@ class SetFlavor(command.Command): raise exceptions.CommandError(_("Command Failed: One or more of" " the operations failed")) + if parsed_args.description: + if compute_client.api_version < api_versions.APIVersion("2.55"): + msg = _("--os-compute-api-version 2.55 or later is required") + raise exceptions.CommandError(msg) + compute_client.flavors.update(flavor=parsed_args.flavor, + description=parsed_args.description) + class ShowFlavor(command.ShowOne): _description = _("Display flavor details") diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py index 46fa599284..9a065be13d 100644 --- a/openstackclient/tests/unit/compute/v2/fakes.py +++ b/openstackclient/tests/unit/compute/v2/fakes.py @@ -765,6 +765,7 @@ class FakeFlavor(object): 'rxtx_factor': 1.0, 'OS-FLV-DISABLED:disabled': False, 'os-flavor-access:is_public': True, + 'description': 'description', 'OS-FLV-EXT-DATA:ephemeral': 0, 'properties': {'property': 'value'}, } diff --git a/openstackclient/tests/unit/compute/v2/test_flavor.py b/openstackclient/tests/unit/compute/v2/test_flavor.py index 4cdbb25ba0..a112fc1fae 100644 --- a/openstackclient/tests/unit/compute/v2/test_flavor.py +++ b/openstackclient/tests/unit/compute/v2/test_flavor.py @@ -16,6 +16,7 @@ import mock from mock import call +import novaclient from osc_lib import exceptions from osc_lib import utils @@ -50,6 +51,7 @@ class TestFlavorCreate(TestFlavor): columns = ( 'OS-FLV-DISABLED:disabled', 'OS-FLV-EXT-DATA:ephemeral', + 'description', 'disk', 'id', 'name', @@ -63,6 +65,7 @@ class TestFlavorCreate(TestFlavor): data = ( flavor.disabled, flavor.ephemeral, + flavor.description, flavor.disk, flavor.id, flavor.name, @@ -101,7 +104,8 @@ class TestFlavorCreate(TestFlavor): 0, 0, 1.0, - True + True, + None, ) columns, data = self.cmd.take_action(parsed_args) self.flavors_mock.create.assert_called_once_with(*default_args) @@ -120,6 +124,7 @@ class TestFlavorCreate(TestFlavor): '--vcpus', str(self.flavor.vcpus), '--rxtx-factor', str(self.flavor.rxtx_factor), '--public', + '--description', str(self.flavor.description), '--property', 'property=value', self.flavor.name, ] @@ -132,6 +137,7 @@ class TestFlavorCreate(TestFlavor): ('vcpus', self.flavor.vcpus), ('rxtx_factor', self.flavor.rxtx_factor), ('public', True), + ('description', self.flavor.description), ('property', {'property': 'value'}), ('name', self.flavor.name), ] @@ -147,8 +153,13 @@ class TestFlavorCreate(TestFlavor): self.flavor.swap, self.flavor.rxtx_factor, self.flavor.is_public, + self.flavor.description, ) - columns, data = self.cmd.take_action(parsed_args) + self.app.client_manager.compute.api_version = 2.55 + with mock.patch.object(novaclient.api_versions, + 'APIVersion', + return_value=2.55): + columns, data = self.cmd.take_action(parsed_args) self.flavors_mock.create.assert_called_once_with(*args) self.flavor.set_keys.assert_called_once_with({'property': 'value'}) self.flavor.get_keys.assert_called_once_with() @@ -168,6 +179,7 @@ class TestFlavorCreate(TestFlavor): '--vcpus', str(self.flavor.vcpus), '--rxtx-factor', str(self.flavor.rxtx_factor), '--private', + '--description', str(self.flavor.description), '--project', self.project.id, '--property', 'key1=value1', '--property', 'key2=value2', @@ -181,6 +193,7 @@ class TestFlavorCreate(TestFlavor): ('vcpus', self.flavor.vcpus), ('rxtx_factor', self.flavor.rxtx_factor), ('public', False), + ('description', 'description'), ('project', self.project.id), ('property', {'key1': 'value1', 'key2': 'value2'}), ('name', self.flavor.name), @@ -197,8 +210,13 @@ class TestFlavorCreate(TestFlavor): self.flavor.swap, self.flavor.rxtx_factor, self.flavor.is_public, + self.flavor.description, ) - columns, data = self.cmd.take_action(parsed_args) + self.app.client_manager.compute.api_version = 2.55 + with mock.patch.object(novaclient.api_versions, + 'APIVersion', + return_value=2.55): + columns, data = self.cmd.take_action(parsed_args) self.flavors_mock.create.assert_called_once_with(*args) self.flavor_access_mock.add_tenant_access.assert_called_with( self.flavor.id, @@ -234,6 +252,79 @@ class TestFlavorCreate(TestFlavor): arglist, verifylist) + def test_flavor_create_with_description_api_newer(self): + arglist = [ + '--id', self.flavor.id, + '--ram', str(self.flavor.ram), + '--disk', str(self.flavor.disk), + '--ephemeral', str(self.flavor.ephemeral), + '--swap', str(self.flavor.swap), + '--vcpus', str(self.flavor.vcpus), + '--rxtx-factor', str(self.flavor.rxtx_factor), + '--private', + '--description', 'fake description', + self.flavor.name, + ] + verifylist = [ + ('id', self.flavor.id), + ('ram', self.flavor.ram), + ('disk', self.flavor.disk), + ('ephemeral', self.flavor.ephemeral), + ('swap', self.flavor.swap), + ('vcpus', self.flavor.vcpus), + ('rxtx_factor', self.flavor.rxtx_factor), + ('public', False), + ('description', 'fake description'), + ('name', self.flavor.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.app.client_manager.compute.api_version = 2.55 + with mock.patch.object(novaclient.api_versions, + 'APIVersion', + return_value=2.55): + columns, data = self.cmd.take_action(parsed_args) + + args = ( + self.flavor.name, + self.flavor.ram, + self.flavor.vcpus, + self.flavor.disk, + self.flavor.id, + self.flavor.ephemeral, + self.flavor.swap, + self.flavor.rxtx_factor, + False, + 'fake description', + ) + + self.flavors_mock.create.assert_called_once_with(*args) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_flavor_create_with_description_api_older(self): + arglist = [ + '--id', self.flavor.id, + '--ram', str(self.flavor.ram), + '--vcpus', str(self.flavor.vcpus), + '--description', 'description', + self.flavor.name, + ] + verifylist = [ + ('ram', self.flavor.ram), + ('vcpus', self.flavor.vcpus), + ('description', 'description'), + ('name', self.flavor.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.app.client_manager.compute.api_version = 2.54 + with mock.patch.object(novaclient.api_versions, + 'APIVersion', + return_value=2.55): + self.assertRaises(exceptions.CommandError, self.cmd.take_action, + parsed_args) + class TestFlavorDelete(TestFlavor): @@ -622,6 +713,42 @@ class TestFlavorSet(TestFlavor): self.flavor_access_mock.add_tenant_access.assert_not_called() self.assertIsNone(result) + def test_flavor_set_description_api_newer(self): + arglist = [ + '--description', 'description', + self.flavor.id, + ] + verifylist = [ + ('description', 'description'), + ('flavor', self.flavor.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.app.client_manager.compute.api_version = 2.55 + with mock.patch.object(novaclient.api_versions, + 'APIVersion', + return_value=2.55): + result = self.cmd.take_action(parsed_args) + self.flavors_mock.update.assert_called_with( + flavor=self.flavor.id, description='description') + self.assertIsNone(result) + + def test_flavor_set_description_api_older(self): + arglist = [ + '--description', 'description', + self.flavor.id, + ] + verifylist = [ + ('description', 'description'), + ('flavor', self.flavor.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.app.client_manager.compute.api_version = 2.54 + with mock.patch.object(novaclient.api_versions, + 'APIVersion', + return_value=2.55): + self.assertRaises(exceptions.CommandError, self.cmd.take_action, + parsed_args) + class TestFlavorShow(TestFlavor): @@ -633,6 +760,7 @@ class TestFlavorShow(TestFlavor): 'OS-FLV-DISABLED:disabled', 'OS-FLV-EXT-DATA:ephemeral', 'access_project_ids', + 'description', 'disk', 'id', 'name', @@ -648,6 +776,7 @@ class TestFlavorShow(TestFlavor): flavor.disabled, flavor.ephemeral, None, + flavor.description, flavor.disk, flavor.id, flavor.name, @@ -710,6 +839,7 @@ class TestFlavorShow(TestFlavor): private_flavor.disabled, private_flavor.ephemeral, self.flavor_access.tenant_id, + private_flavor.description, private_flavor.disk, private_flavor.id, private_flavor.name, diff --git a/releasenotes/notes/flavor-add-description-b618abd4a7fb6545.yaml b/releasenotes/notes/flavor-add-description-b618abd4a7fb6545.yaml new file mode 100644 index 0000000000..f148175f79 --- /dev/null +++ b/releasenotes/notes/flavor-add-description-b618abd4a7fb6545.yaml @@ -0,0 +1,6 @@ +--- +features: + - Add ``--description`` option to ``flavor set`` command to update the + description of the server. + - Add ``--description`` option to ``flavor create`` command to set the + description of the server.