Compute: Add description support for flavor

Co-Authored-By: Fan Zhang <zh.f@outlook.com>
Change-Id: I0dc80bee3ba6ff4ec8cc3fc113b6de7807e0bf2a
Story: 2002196
Task: 21681
This commit is contained in:
tianhui 2018-06-14 18:20:04 +08:00
parent 9766eb23e7
commit 4a68ba625c
5 changed files with 177 additions and 4 deletions

View File

@ -24,6 +24,7 @@ Create new flavor
[--property <key=value> [...] ] [--property <key=value> [...] ]
[--project <project>] [--project <project>]
[--project-domain <project-domain>] [--project-domain <project-domain>]
[--description <description>]
<flavor-name> <flavor-name>
.. option:: --id <id> .. option:: --id <id>
@ -76,6 +77,10 @@ Create new flavor
Domain the project belongs to (name or ID). Domain the project belongs to (name or ID).
This can be used in case collisions between project names exist. This can be used in case collisions between project names exist.
.. option:: --description <description>
Description to add for this flavor
.. _flavor_create-flavor-name: .. _flavor_create-flavor-name:
.. describe:: <flavor-name> .. describe:: <flavor-name>
@ -148,6 +153,7 @@ Set flavor properties
[--property <key=value> [...] ] [--property <key=value> [...] ]
[--project <project>] [--project <project>]
[--project-domain <project-domain>] [--project-domain <project-domain>]
[--description <description>]
<flavor> <flavor>
.. option:: --property <key=value> .. option:: --property <key=value>
@ -168,6 +174,10 @@ Set flavor properties
Remove all properties from this flavor (specify both --no-property and --property Remove all properties from this flavor (specify both --no-property and --property
to remove the current properties before setting new properties.) to remove the current properties before setting new properties.)
.. option:: --description <description>
Set description to this flavor
.. describe:: <flavor> .. describe:: <flavor>
Flavor to modify (name or ID) Flavor to modify (name or ID)

View File

@ -17,6 +17,7 @@
import logging import logging
from novaclient import api_versions
from osc_lib.cli import parseractions from osc_lib.cli import parseractions
from osc_lib.command import command from osc_lib.command import command
from osc_lib import exceptions from osc_lib import exceptions
@ -134,6 +135,12 @@ class CreateFlavor(command.ShowOne):
help=_("Allow <project> to access private flavor (name or ID) " help=_("Allow <project> to access private flavor (name or ID) "
"(Must be used with --private option)"), "(Must be used with --private option)"),
) )
parser.add_argument(
'--description',
metavar='<description>',
help=_("Description for the flavor.(Supported by API versions "
"'2.55' - '2.latest'")
)
identity_common.add_project_domain_option_to_parser(parser) identity_common.add_project_domain_option_to_parser(parser)
return parser return parser
@ -145,6 +152,11 @@ class CreateFlavor(command.ShowOne):
msg = _("--project is only allowed with --private") msg = _("--project is only allowed with --private")
raise exceptions.CommandError(msg) 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 = ( args = (
parsed_args.name, parsed_args.name,
parsed_args.ram, parsed_args.ram,
@ -154,7 +166,8 @@ class CreateFlavor(command.ShowOne):
parsed_args.ephemeral, parsed_args.ephemeral,
parsed_args.swap, parsed_args.swap,
parsed_args.rxtx_factor, parsed_args.rxtx_factor,
parsed_args.public parsed_args.public,
parsed_args.description
) )
flavor = compute_client.flavors.create(*args) flavor = compute_client.flavors.create(*args)
@ -332,6 +345,12 @@ class SetFlavor(command.Command):
help=_('Set flavor access to project (name or ID) ' help=_('Set flavor access to project (name or ID) '
'(admin only)'), '(admin only)'),
) )
parser.add_argument(
'--description',
metavar='<description>',
help=_("Set description for the flavor.(Supported by API "
"versions '2.55' - '2.latest'")
)
identity_common.add_project_domain_option_to_parser(parser) identity_common.add_project_domain_option_to_parser(parser)
return parser return parser
@ -380,6 +399,13 @@ class SetFlavor(command.Command):
raise exceptions.CommandError(_("Command Failed: One or more of" raise exceptions.CommandError(_("Command Failed: One or more of"
" the operations failed")) " 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): class ShowFlavor(command.ShowOne):
_description = _("Display flavor details") _description = _("Display flavor details")

View File

@ -765,6 +765,7 @@ class FakeFlavor(object):
'rxtx_factor': 1.0, 'rxtx_factor': 1.0,
'OS-FLV-DISABLED:disabled': False, 'OS-FLV-DISABLED:disabled': False,
'os-flavor-access:is_public': True, 'os-flavor-access:is_public': True,
'description': 'description',
'OS-FLV-EXT-DATA:ephemeral': 0, 'OS-FLV-EXT-DATA:ephemeral': 0,
'properties': {'property': 'value'}, 'properties': {'property': 'value'},
} }

View File

@ -16,6 +16,7 @@
import mock import mock
from mock import call from mock import call
import novaclient
from osc_lib import exceptions from osc_lib import exceptions
from osc_lib import utils from osc_lib import utils
@ -50,6 +51,7 @@ class TestFlavorCreate(TestFlavor):
columns = ( columns = (
'OS-FLV-DISABLED:disabled', 'OS-FLV-DISABLED:disabled',
'OS-FLV-EXT-DATA:ephemeral', 'OS-FLV-EXT-DATA:ephemeral',
'description',
'disk', 'disk',
'id', 'id',
'name', 'name',
@ -63,6 +65,7 @@ class TestFlavorCreate(TestFlavor):
data = ( data = (
flavor.disabled, flavor.disabled,
flavor.ephemeral, flavor.ephemeral,
flavor.description,
flavor.disk, flavor.disk,
flavor.id, flavor.id,
flavor.name, flavor.name,
@ -101,7 +104,8 @@ class TestFlavorCreate(TestFlavor):
0, 0,
0, 0,
1.0, 1.0,
True True,
None,
) )
columns, data = self.cmd.take_action(parsed_args) columns, data = self.cmd.take_action(parsed_args)
self.flavors_mock.create.assert_called_once_with(*default_args) self.flavors_mock.create.assert_called_once_with(*default_args)
@ -120,6 +124,7 @@ class TestFlavorCreate(TestFlavor):
'--vcpus', str(self.flavor.vcpus), '--vcpus', str(self.flavor.vcpus),
'--rxtx-factor', str(self.flavor.rxtx_factor), '--rxtx-factor', str(self.flavor.rxtx_factor),
'--public', '--public',
'--description', str(self.flavor.description),
'--property', 'property=value', '--property', 'property=value',
self.flavor.name, self.flavor.name,
] ]
@ -132,6 +137,7 @@ class TestFlavorCreate(TestFlavor):
('vcpus', self.flavor.vcpus), ('vcpus', self.flavor.vcpus),
('rxtx_factor', self.flavor.rxtx_factor), ('rxtx_factor', self.flavor.rxtx_factor),
('public', True), ('public', True),
('description', self.flavor.description),
('property', {'property': 'value'}), ('property', {'property': 'value'}),
('name', self.flavor.name), ('name', self.flavor.name),
] ]
@ -147,7 +153,12 @@ class TestFlavorCreate(TestFlavor):
self.flavor.swap, self.flavor.swap,
self.flavor.rxtx_factor, self.flavor.rxtx_factor,
self.flavor.is_public, self.flavor.is_public,
self.flavor.description,
) )
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) columns, data = self.cmd.take_action(parsed_args)
self.flavors_mock.create.assert_called_once_with(*args) self.flavors_mock.create.assert_called_once_with(*args)
self.flavor.set_keys.assert_called_once_with({'property': 'value'}) self.flavor.set_keys.assert_called_once_with({'property': 'value'})
@ -168,6 +179,7 @@ class TestFlavorCreate(TestFlavor):
'--vcpus', str(self.flavor.vcpus), '--vcpus', str(self.flavor.vcpus),
'--rxtx-factor', str(self.flavor.rxtx_factor), '--rxtx-factor', str(self.flavor.rxtx_factor),
'--private', '--private',
'--description', str(self.flavor.description),
'--project', self.project.id, '--project', self.project.id,
'--property', 'key1=value1', '--property', 'key1=value1',
'--property', 'key2=value2', '--property', 'key2=value2',
@ -181,6 +193,7 @@ class TestFlavorCreate(TestFlavor):
('vcpus', self.flavor.vcpus), ('vcpus', self.flavor.vcpus),
('rxtx_factor', self.flavor.rxtx_factor), ('rxtx_factor', self.flavor.rxtx_factor),
('public', False), ('public', False),
('description', 'description'),
('project', self.project.id), ('project', self.project.id),
('property', {'key1': 'value1', 'key2': 'value2'}), ('property', {'key1': 'value1', 'key2': 'value2'}),
('name', self.flavor.name), ('name', self.flavor.name),
@ -197,7 +210,12 @@ class TestFlavorCreate(TestFlavor):
self.flavor.swap, self.flavor.swap,
self.flavor.rxtx_factor, self.flavor.rxtx_factor,
self.flavor.is_public, self.flavor.is_public,
self.flavor.description,
) )
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) columns, data = self.cmd.take_action(parsed_args)
self.flavors_mock.create.assert_called_once_with(*args) self.flavors_mock.create.assert_called_once_with(*args)
self.flavor_access_mock.add_tenant_access.assert_called_with( self.flavor_access_mock.add_tenant_access.assert_called_with(
@ -234,6 +252,79 @@ class TestFlavorCreate(TestFlavor):
arglist, arglist,
verifylist) 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): class TestFlavorDelete(TestFlavor):
@ -622,6 +713,42 @@ class TestFlavorSet(TestFlavor):
self.flavor_access_mock.add_tenant_access.assert_not_called() self.flavor_access_mock.add_tenant_access.assert_not_called()
self.assertIsNone(result) 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): class TestFlavorShow(TestFlavor):
@ -633,6 +760,7 @@ class TestFlavorShow(TestFlavor):
'OS-FLV-DISABLED:disabled', 'OS-FLV-DISABLED:disabled',
'OS-FLV-EXT-DATA:ephemeral', 'OS-FLV-EXT-DATA:ephemeral',
'access_project_ids', 'access_project_ids',
'description',
'disk', 'disk',
'id', 'id',
'name', 'name',
@ -648,6 +776,7 @@ class TestFlavorShow(TestFlavor):
flavor.disabled, flavor.disabled,
flavor.ephemeral, flavor.ephemeral,
None, None,
flavor.description,
flavor.disk, flavor.disk,
flavor.id, flavor.id,
flavor.name, flavor.name,
@ -710,6 +839,7 @@ class TestFlavorShow(TestFlavor):
private_flavor.disabled, private_flavor.disabled,
private_flavor.ephemeral, private_flavor.ephemeral,
self.flavor_access.tenant_id, self.flavor_access.tenant_id,
private_flavor.description,
private_flavor.disk, private_flavor.disk,
private_flavor.id, private_flavor.id,
private_flavor.name, private_flavor.name,

View File

@ -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.