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:
parent
9766eb23e7
commit
4a68ba625c
@ -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)
|
||||||
|
@ -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")
|
||||||
|
@ -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'},
|
||||||
}
|
}
|
||||||
|
@ -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,8 +153,13 @@ 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,
|
||||||
)
|
)
|
||||||
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.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'})
|
||||||
self.flavor.get_keys.assert_called_once_with()
|
self.flavor.get_keys.assert_called_once_with()
|
||||||
@ -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,8 +210,13 @@ 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,
|
||||||
)
|
)
|
||||||
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.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(
|
||||||
self.flavor.id,
|
self.flavor.id,
|
||||||
@ -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,
|
||||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user