compute: Allow adding, removing multiple SGs
We also ensure we call neutron rather than the deprecated nova proxy API in the event that neutron is available. Change-Id: I8315ea164fd3fa6c1d759f16677bfd6c24c4ef63 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
parent
45ac2b62fb
commit
ece30e8f70
@ -670,7 +670,7 @@ class AddNetwork(command.Command):
|
||||
|
||||
|
||||
class AddServerSecurityGroup(command.Command):
|
||||
_description = _("Add security group to server")
|
||||
_description = _("Add security group(s) to server")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
@ -680,9 +680,13 @@ class AddServerSecurityGroup(command.Command):
|
||||
help=_('Server (name or ID)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'group',
|
||||
metavar='<group>',
|
||||
help=_('Security group to add (name or ID)'),
|
||||
'security_groups',
|
||||
metavar='<security-group>',
|
||||
nargs='+',
|
||||
help=_(
|
||||
'Security group(s) to add to the server (name or ID) '
|
||||
'(repeat option to add multiple groups)'
|
||||
),
|
||||
)
|
||||
return parser
|
||||
|
||||
@ -694,14 +698,43 @@ class AddServerSecurityGroup(command.Command):
|
||||
)
|
||||
if self.app.client_manager.is_network_endpoint_enabled():
|
||||
# the server handles both names and IDs for neutron SGs, so just
|
||||
# pass things through
|
||||
security_group = parsed_args.group
|
||||
# pass things through if using neutron
|
||||
security_groups = parsed_args.security_groups
|
||||
else:
|
||||
# however, if using nova-network then it needs a name, not an ID
|
||||
security_group = compute_v2.find_security_group(
|
||||
compute_client, parsed_args.group
|
||||
)['name']
|
||||
compute_client.add_security_group_to_server(server, security_group)
|
||||
# however, if using nova-network then it needs names, not IDs
|
||||
security_groups = []
|
||||
for security_group in parsed_args.security_groups:
|
||||
security_groups.append(
|
||||
compute_v2.find_security_group(
|
||||
compute_client, security_group
|
||||
)['name']
|
||||
)
|
||||
|
||||
errors = 0
|
||||
for security_group in security_groups:
|
||||
try:
|
||||
compute_client.add_security_group_to_server(
|
||||
server, security_group
|
||||
)
|
||||
except sdk_exceptions.HttpException as e:
|
||||
errors += 1
|
||||
LOG.error(
|
||||
_(
|
||||
"Failed to add security group with name or ID "
|
||||
"'%(security_group)s' to server '%(server)s': %(e)s"
|
||||
),
|
||||
{
|
||||
'security_group': security_group,
|
||||
'server': server.id,
|
||||
'e': e,
|
||||
},
|
||||
)
|
||||
|
||||
if errors > 0:
|
||||
msg = _(
|
||||
"%(errors)d of %(total)d security groups were not added."
|
||||
) % {'errors': errors, 'total': len(security_groups)}
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
|
||||
class AddServerVolume(command.ShowOne):
|
||||
@ -1328,6 +1361,7 @@ class CreateServer(command.ShowOne):
|
||||
metavar='<security-group>',
|
||||
action='append',
|
||||
default=[],
|
||||
dest='security_groups',
|
||||
help=_(
|
||||
'Security group to assign to this server (name or ID) '
|
||||
'(repeat option to set multiple groups)'
|
||||
@ -1948,21 +1982,22 @@ class CreateServer(command.ShowOne):
|
||||
# 'auto' to maintain legacy behavior if a nic wasn't specified.
|
||||
networks = 'auto'
|
||||
|
||||
# Check security group exist and convert ID to name
|
||||
# Check security group(s) exist and convert ID to name
|
||||
security_groups = []
|
||||
if self.app.client_manager.is_network_endpoint_enabled():
|
||||
network_client = self.app.client_manager.network
|
||||
for each_sg in parsed_args.security_group:
|
||||
for security_group in parsed_args.security_groups:
|
||||
sg = network_client.find_security_group(
|
||||
each_sg, ignore_missing=False
|
||||
security_group, ignore_missing=False
|
||||
)
|
||||
# Use security group ID to avoid multiple security group have
|
||||
# same name in neutron networking backend
|
||||
security_groups.append({'name': sg.id})
|
||||
else:
|
||||
# Handle nova-network case
|
||||
for each_sg in parsed_args.security_group:
|
||||
sg = compute_v2.find_security_group(compute_client, each_sg)
|
||||
else: # nova-network
|
||||
for security_group in parsed_args.security_groups:
|
||||
sg = compute_v2.find_security_group(
|
||||
compute_client, security_group
|
||||
)
|
||||
security_groups.append({'name': sg['name']})
|
||||
|
||||
hints = {}
|
||||
@ -4016,9 +4051,13 @@ class RemoveServerSecurityGroup(command.Command):
|
||||
help=_('Server (name or ID)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'group',
|
||||
metavar='<group>',
|
||||
help=_('Security group to remove (name or ID)'),
|
||||
'security_groups',
|
||||
metavar='<security-group>',
|
||||
nargs='+',
|
||||
help=_(
|
||||
'Security group(s) to remove from server (name or ID) '
|
||||
'(repeat option to remove multiple groups)'
|
||||
),
|
||||
)
|
||||
return parser
|
||||
|
||||
@ -4031,15 +4070,42 @@ class RemoveServerSecurityGroup(command.Command):
|
||||
if self.app.client_manager.is_network_endpoint_enabled():
|
||||
# the server handles both names and IDs for neutron SGs, so just
|
||||
# pass things through
|
||||
security_group = parsed_args.group
|
||||
security_groups = parsed_args.security_groups
|
||||
else:
|
||||
# however, if using nova-network then it needs a name, not an ID
|
||||
security_group = compute_v2.find_security_group(
|
||||
compute_client, parsed_args.group
|
||||
)['name']
|
||||
compute_client.remove_security_group_from_server(
|
||||
server, security_group
|
||||
)
|
||||
# however, if using nova-network then it needs names, not IDs
|
||||
security_groups = []
|
||||
for security_group in parsed_args.security_groups:
|
||||
security_groups.append(
|
||||
compute_v2.find_security_group(
|
||||
compute_client, security_group
|
||||
)['name']
|
||||
)
|
||||
|
||||
errors = 0
|
||||
for security_group in security_groups:
|
||||
try:
|
||||
compute_client.remove_security_group_from_server(
|
||||
server, security_group
|
||||
)
|
||||
except sdk_exceptions.HttpException as e:
|
||||
errors += 1
|
||||
LOG.error(
|
||||
_(
|
||||
"Failed to remove security group with name or ID "
|
||||
"'%(security_group)s' from server '%(server)s': %(e)s"
|
||||
),
|
||||
{
|
||||
'security_group': security_group,
|
||||
'server': server.id,
|
||||
'e': e,
|
||||
},
|
||||
)
|
||||
|
||||
if errors > 0:
|
||||
msg = _(
|
||||
"%(errors)d of %(total)d security groups were not removed."
|
||||
) % {'errors': errors, 'total': len(security_groups)}
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
|
||||
class RemoveServerVolume(command.Command):
|
||||
|
@ -21,7 +21,7 @@ class HelpTests(base.TestCase):
|
||||
"""Functional tests for openstackclient help output."""
|
||||
|
||||
SERVER_COMMANDS = [
|
||||
('server add security group', 'Add security group to server'),
|
||||
('server add security group', 'Add security group(s) to server'),
|
||||
('server add volume', 'Add volume to server'),
|
||||
('server backup create', 'Create a server backup image'),
|
||||
('server create', 'Create a new server'),
|
||||
|
@ -1166,7 +1166,7 @@ class TestServerAddSecurityGroup(compute_fakes.TestComputev2):
|
||||
arglist = [self.server.id, 'fake_sg']
|
||||
verifylist = [
|
||||
('server', self.server.id),
|
||||
('group', 'fake_sg'),
|
||||
('security_groups', ['fake_sg']),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
@ -1197,7 +1197,7 @@ class TestServerAddSecurityGroup(compute_fakes.TestComputev2):
|
||||
arglist = [self.server.id, 'fake_sg']
|
||||
verifylist = [
|
||||
('server', self.server.id),
|
||||
('group', 'fake_sg'),
|
||||
('security_groups', ['fake_sg']),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
@ -1429,7 +1429,7 @@ class TestServerCreate(TestServer):
|
||||
('flavor', self.flavor.id),
|
||||
('key_name', 'keyname'),
|
||||
('properties', {'Beta': 'b'}),
|
||||
('security_group', [security_group.id]),
|
||||
('security_groups', [security_group.id]),
|
||||
('hints', {'a': ['b', 'c']}),
|
||||
('server_group', server_group.id),
|
||||
('config_drive', True),
|
||||
@ -1499,7 +1499,7 @@ class TestServerCreate(TestServer):
|
||||
('image', self.image.id),
|
||||
('flavor', self.flavor.id),
|
||||
('key_name', 'keyname'),
|
||||
('security_group', ['not_exist_sg']),
|
||||
('security_groups', ['not_exist_sg']),
|
||||
('server_name', self.server.name),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
@ -1525,7 +1525,7 @@ class TestServerCreate(TestServer):
|
||||
verifylist = [
|
||||
('image', self.image.id),
|
||||
('flavor', self.flavor.id),
|
||||
('security_group', [sg_name]),
|
||||
('security_groups', [sg_name]),
|
||||
('server_name', self.server.name),
|
||||
]
|
||||
|
||||
@ -7416,7 +7416,7 @@ class TestServerRemoveSecurityGroup(TestServer):
|
||||
arglist = [self.server.id, 'fake_sg']
|
||||
verifylist = [
|
||||
('server', self.server.id),
|
||||
('group', 'fake_sg'),
|
||||
('security_groups', ['fake_sg']),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
@ -7447,7 +7447,7 @@ class TestServerRemoveSecurityGroup(TestServer):
|
||||
arglist = [self.server.id, 'fake_sg']
|
||||
verifylist = [
|
||||
('server', self.server.id),
|
||||
('group', 'fake_sg'),
|
||||
('security_groups', ['fake_sg']),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The ``server add security group`` and ``server remove security group``
|
||||
commands now accept multiple security groups.
|
Loading…
Reference in New Issue
Block a user