Compute: Add tags support for server

Change-Id: If065602792958ff0145ae9f2e05f5b7a3177905c
Story: 2002006
Task: 19641
This commit is contained in:
tianhui 2018-05-18 18:59:37 +08:00 committed by Stephen Finucane
parent 6216025e9d
commit 2f76bfa3a6
3 changed files with 388 additions and 1 deletions

View File

@ -828,6 +828,18 @@ class CreateServer(command.ShowOne):
action='store_true', action='store_true',
help=_('Wait for build to complete'), help=_('Wait for build to complete'),
) )
parser.add_argument(
'--tag',
metavar='<tag>',
action='append',
default=[],
dest='tags',
help=_(
'Tags for the server. '
'Specify multiple times to add multiple tags. '
'(supported by --os-compute-api-version 2.52 or above)'
),
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -1141,6 +1153,16 @@ class CreateServer(command.ShowOne):
if parsed_args.description: if parsed_args.description:
boot_kwargs['description'] = parsed_args.description boot_kwargs['description'] = parsed_args.description
if parsed_args.tags:
if compute_client.api_version < api_versions.APIVersion('2.52'):
msg = _(
'--os-compute-api-version 2.52 or greater is required to '
'support the --tag option'
)
raise exceptions.CommandError(msg)
boot_kwargs['tags'] = parsed_args.tags
if parsed_args.host: if parsed_args.host:
if compute_client.api_version < api_versions.APIVersion("2.74"): if compute_client.api_version < api_versions.APIVersion("2.74"):
msg = _("Specifying --host is not supported for " msg = _("Specifying --host is not supported for "
@ -1408,6 +1430,30 @@ class ListServer(command.Lister):
help=_('Only display unlocked servers. ' help=_('Only display unlocked servers. '
'Requires ``--os-compute-api-version`` 2.73 or greater.'), 'Requires ``--os-compute-api-version`` 2.73 or greater.'),
) )
parser.add_argument(
'--tags',
metavar='<tag>',
action='append',
default=[],
dest='tags',
help=_(
'Only list servers with the specified tag. '
'Specify multiple times to filter on multiple tags. '
'(supported by --os-compute-api-version 2.26 or above)'
),
)
parser.add_argument(
'--not-tags',
metavar='<tag>',
action='append',
default=[],
dest='not_tags',
help=_(
'Only list servers without the specified tag. '
'Specify multiple times to filter on multiple tags. '
'(supported by --os-compute-api-version 2.26 or above)'
),
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -1463,6 +1509,27 @@ class ListServer(command.Lister):
'changes-before': parsed_args.changes_before, 'changes-before': parsed_args.changes_before,
'changes-since': parsed_args.changes_since, 'changes-since': parsed_args.changes_since,
} }
if parsed_args.tags:
if compute_client.api_version < api_versions.APIVersion('2.26'):
msg = _(
'--os-compute-api-version 2.26 or greater is required to '
'support the --tag option'
)
raise exceptions.CommandError(msg)
search_opts['tags'] = parsed_args.tags
if parsed_args.not_tags:
if compute_client.api_version < api_versions.APIVersion('2.26'):
msg = _(
'--os-compute-api-version 2.26 or greater is required to '
'support the --not-tag option'
)
raise exceptions.CommandError(msg)
search_opts['not-tags'] = parsed_args.not_tags
support_locked = (compute_client.api_version >= support_locked = (compute_client.api_version >=
api_versions.APIVersion('2.73')) api_versions.APIVersion('2.73'))
if not support_locked and (parsed_args.locked or parsed_args.unlocked): if not support_locked and (parsed_args.locked or parsed_args.unlocked):
@ -2795,6 +2862,18 @@ class SetServer(command.Command):
help=_('New server description (supported by ' help=_('New server description (supported by '
'--os-compute-api-version 2.19 or above)'), '--os-compute-api-version 2.19 or above)'),
) )
parser.add_argument(
'--tag',
metavar='<tag>',
action='append',
default=[],
dest='tags',
help=_(
'Tag for the server. '
'Specify multiple times to add multiple tags. '
'(supported by --os-compute-api-version 2.26 or above)'
),
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -2833,6 +2912,17 @@ class SetServer(command.Command):
raise exceptions.CommandError(msg) raise exceptions.CommandError(msg)
server.update(description=parsed_args.description) server.update(description=parsed_args.description)
if parsed_args.tags:
if server.api_version < api_versions.APIVersion('2.26'):
msg = _(
'--os-compute-api-version 2.26 or greater is required to '
'support the --tag option'
)
raise exceptions.CommandError(msg)
for tag in parsed_args.tags:
server.add_tag(tag=tag)
class ShelveServer(command.Command): class ShelveServer(command.Command):
_description = _("Shelve server(s)") _description = _("Shelve server(s)")
@ -3174,7 +3264,7 @@ class UnrescueServer(command.Command):
class UnsetServer(command.Command): class UnsetServer(command.Command):
_description = _("Unset server properties") _description = _("Unset server properties and tags")
def get_parser(self, prog_name): def get_parser(self, prog_name):
parser = super(UnsetServer, self).get_parser(prog_name) parser = super(UnsetServer, self).get_parser(prog_name)
@ -3198,6 +3288,18 @@ class UnsetServer(command.Command):
help=_('Unset server description (supported by ' help=_('Unset server description (supported by '
'--os-compute-api-version 2.19 or above)'), '--os-compute-api-version 2.19 or above)'),
) )
parser.add_argument(
'--tag',
metavar='<tag>',
action='append',
default=[],
dest='tags',
help=_(
'Tag to remove from the server. '
'Specify multiple times to remove multiple tags. '
'(supported by --os-compute-api-version 2.26 or later'
),
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -3223,6 +3325,17 @@ class UnsetServer(command.Command):
description="", description="",
) )
if parsed_args.tags:
if compute_client.api_version < api_versions.APIVersion('2.26'):
msg = _(
'--os-compute-api-version 2.26 or greater is required to '
'support the --tag option'
)
raise exceptions.CommandError(msg)
for tag in parsed_args.tags:
compute_client.servers.delete_tag(server, tag=tag)
class UnshelveServer(command.Command): class UnshelveServer(command.Command):
_description = _("Unshelve server(s)") _description = _("Unshelve server(s)")

View File

@ -2434,6 +2434,87 @@ class TestServerCreate(TestServer):
self.assertRaises(exceptions.CommandError, self.cmd.take_action, self.assertRaises(exceptions.CommandError, self.cmd.take_action,
parsed_args) parsed_args)
def test_server_create_with_tag(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.52')
arglist = [
'--image', 'image1',
'--flavor', 'flavor1',
'--tag', 'tag1',
'--tag', 'tag2',
self.new_server.name,
]
verifylist = [
('image', 'image1'),
('flavor', 'flavor1'),
('tags', ['tag1', 'tag2']),
('config_drive', False),
('server_name', self.new_server.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'meta': None,
'files': {},
'reservation_id': None,
'min_count': 1,
'max_count': 1,
'security_groups': [],
'userdata': None,
'key_name': None,
'availability_zone': None,
'block_device_mapping_v2': [],
'admin_pass': None,
'nics': 'auto',
'scheduler_hints': {},
'config_drive': None,
'tags': ['tag1', 'tag2'],
}
# ServerManager.create(name, image, flavor, **kwargs)
self.servers_mock.create.assert_called_with(
self.new_server.name,
self.image,
self.flavor,
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist(), data)
self.assertFalse(self.images_mock.called)
self.assertFalse(self.flavors_mock.called)
def test_server_create_with_tag_pre_v252(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.51')
arglist = [
'--image', 'image1',
'--flavor', 'flavor1',
'--tag', 'tag1',
'--tag', 'tag2',
self.new_server.name,
]
verifylist = [
('image', 'image1'),
('flavor', 'flavor1'),
('tags', ['tag1', 'tag2']),
('config_drive', False),
('server_name', self.new_server.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
ex = self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args)
self.assertIn(
'--os-compute-api-version 2.52 or greater is required',
str(ex))
def test_server_create_with_host_v274(self): def test_server_create_with_host_v274(self):
# Explicit host is supported for nova api version 2.74 or above # Explicit host is supported for nova api version 2.74 or above
@ -3206,6 +3287,7 @@ class TestServerList(TestServer):
self.search_opts['changes-before'] = '2016-03-05T06:27:59Z' self.search_opts['changes-before'] = '2016-03-05T06:27:59Z'
self.search_opts['deleted'] = True self.search_opts['deleted'] = True
self.servers_mock.list.assert_called_with(**self.kwargs) self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
@ -3298,6 +3380,92 @@ class TestServerList(TestServer):
'UNKNOWN', '', '', '') 'UNKNOWN', '', '', '')
self.assertEqual(expected_row, partial_server) self.assertEqual(expected_row, partial_server)
def test_server_list_with_tag(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.26')
arglist = [
'--tag', 'tag1',
'--tag', 'tag2',
]
verifylist = [
('tags', ['tag1', 'tag2']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.search_opts['tags'] = ['tag1', 'tag2']
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
self.assertEqual(tuple(self.data), tuple(data))
def test_server_list_with_tag_pre_v225(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.25')
arglist = [
'--tag', 'tag1',
'--tag', 'tag2',
]
verifylist = [
('tags', ['tag1', 'tag2']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
ex = self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args)
self.assertIn(
'--os-compute-api-version 2.26 or greater is required',
str(ex))
def test_server_list_with_not_tag(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.26')
arglist = [
'--not-tag', 'tag1',
'--not-tag', 'tag2',
]
verifylist = [
('not_tags', ['tag1', 'tag2']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.search_opts['not-tags'] = ['tag1', 'tag2']
self.servers_mock.list.assert_called_with(**self.kwargs)
self.assertEqual(self.columns, columns)
self.assertEqual(tuple(self.data), tuple(data))
def test_server_list_with_not_tag_pre_v226(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.25')
arglist = [
'--not-tag', 'tag1',
'--not-tag', 'tag2',
]
verifylist = [
('not_tags', ['tag1', 'tag2']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
ex = self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args)
self.assertIn(
'--os-compute-api-version 2.26 or greater is required',
str(ex))
class TestServerLock(TestServer): class TestServerLock(TestServer):
@ -5388,6 +5556,8 @@ class TestServerSet(TestServer):
'update': None, 'update': None,
'reset_state': None, 'reset_state': None,
'change_password': None, 'change_password': None,
'add_tag': None,
'set_tags': None,
} }
self.fake_servers = self.setup_servers_mock(2) self.fake_servers = self.setup_servers_mock(2)
@ -5528,6 +5698,50 @@ class TestServerSet(TestServer):
self.assertRaises(exceptions.CommandError, self.cmd.take_action, self.assertRaises(exceptions.CommandError, self.cmd.take_action,
parsed_args) parsed_args)
def test_server_set_with_tag(self):
self.fake_servers[0].api_version = api_versions.APIVersion('2.26')
arglist = [
'--tag', 'tag1',
'--tag', 'tag2',
'foo_vm',
]
verifylist = [
('tags', ['tag1', 'tag2']),
('server', 'foo_vm'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.fake_servers[0].add_tag.assert_has_calls([
mock.call(tag='tag1'),
mock.call(tag='tag2'),
])
self.assertIsNone(result)
def test_server_set_with_tag_pre_v226(self):
self.fake_servers[0].api_version = api_versions.APIVersion('2.25')
arglist = [
'--tag', 'tag1',
'--tag', 'tag2',
'foo_vm',
]
verifylist = [
('tags', ['tag1', 'tag2']),
('server', 'foo_vm'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
ex = self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args)
self.assertIn(
'--os-compute-api-version 2.26 or greater is required',
str(ex))
class TestServerShelve(TestServer): class TestServerShelve(TestServer):
@ -5853,6 +6067,52 @@ class TestServerUnset(TestServer):
self.assertRaises(exceptions.CommandError, self.cmd.take_action, self.assertRaises(exceptions.CommandError, self.cmd.take_action,
parsed_args) parsed_args)
def test_server_unset_with_tag(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.26')
arglist = [
'--tag', 'tag1',
'--tag', 'tag2',
'foo_vm',
]
verifylist = [
('tags', ['tag1', 'tag2']),
('server', 'foo_vm'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.assertIsNone(result)
self.servers_mock.delete_tag.assert_has_calls([
mock.call(self.fake_server, tag='tag1'),
mock.call(self.fake_server, tag='tag2'),
])
def test_server_unset_with_tag_pre_v226(self):
self.app.client_manager.compute.api_version = api_versions.APIVersion(
'2.25')
arglist = [
'--tag', 'tag1',
'--tag', 'tag2',
'foo_vm',
]
verifylist = [
('tags', ['tag1', 'tag2']),
('server', 'foo_vm'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
ex = self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args)
self.assertIn(
'--os-compute-api-version 2.26 or greater is required',
str(ex))
class TestServerUnshelve(TestServer): class TestServerUnshelve(TestServer):

View File

@ -0,0 +1,14 @@
---
features:
- Add ``--tag`` option to ``server create`` command to add tags when creating
a server.
Only available starting with ``--os-compute-api-version 2.52``.
- Add ``--tag`` option to ``server set`` command to add a tag to an
existing server.
Only available starting with ``--os-compute-api-version 2.26``.
- Add ``--tag`` options to ``server unset`` command to remove a tag from an
existing server.
Only available starting with ``--os-compute-api-version 2.26``.
- Add ``--tags`` and ``--not-tags`` options to ``server list`` command to
list instances with and without the specified tag(s), respectively.
Only available starting with ``--os-compute-api-version 2.26``.