Skip to content

Commit b92291f

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "compute: Allow adding, removing multiple SGs"
2 parents 415f680 + ece30e8 commit b92291f

4 files changed

Lines changed: 108 additions & 37 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 95 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ def take_action(self, parsed_args):
670670

671671

672672
class AddServerSecurityGroup(command.Command):
673-
_description = _("Add security group to server")
673+
_description = _("Add security group(s) to server")
674674

675675
def get_parser(self, prog_name):
676676
parser = super().get_parser(prog_name)
@@ -680,9 +680,13 @@ def get_parser(self, prog_name):
680680
help=_('Server (name or ID)'),
681681
)
682682
parser.add_argument(
683-
'group',
684-
metavar='<group>',
685-
help=_('Security group to add (name or ID)'),
683+
'security_groups',
684+
metavar='<security-group>',
685+
nargs='+',
686+
help=_(
687+
'Security group(s) to add to the server (name or ID) '
688+
'(repeat option to add multiple groups)'
689+
),
686690
)
687691
return parser
688692

@@ -694,14 +698,43 @@ def take_action(self, parsed_args):
694698
)
695699
if self.app.client_manager.is_network_endpoint_enabled():
696700
# the server handles both names and IDs for neutron SGs, so just
697-
# pass things through
698-
security_group = parsed_args.group
701+
# pass things through if using neutron
702+
security_groups = parsed_args.security_groups
699703
else:
700-
# however, if using nova-network then it needs a name, not an ID
701-
security_group = compute_v2.find_security_group(
702-
compute_client, parsed_args.group
703-
)['name']
704-
compute_client.add_security_group_to_server(server, security_group)
704+
# however, if using nova-network then it needs names, not IDs
705+
security_groups = []
706+
for security_group in parsed_args.security_groups:
707+
security_groups.append(
708+
compute_v2.find_security_group(
709+
compute_client, security_group
710+
)['name']
711+
)
712+
713+
errors = 0
714+
for security_group in security_groups:
715+
try:
716+
compute_client.add_security_group_to_server(
717+
server, security_group
718+
)
719+
except sdk_exceptions.HttpException as e:
720+
errors += 1
721+
LOG.error(
722+
_(
723+
"Failed to add security group with name or ID "
724+
"'%(security_group)s' to server '%(server)s': %(e)s"
725+
),
726+
{
727+
'security_group': security_group,
728+
'server': server.id,
729+
'e': e,
730+
},
731+
)
732+
733+
if errors > 0:
734+
msg = _(
735+
"%(errors)d of %(total)d security groups were not added."
736+
) % {'errors': errors, 'total': len(security_groups)}
737+
raise exceptions.CommandError(msg)
705738

706739

707740
class AddServerVolume(command.ShowOne):
@@ -1328,6 +1361,7 @@ def get_parser(self, prog_name):
13281361
metavar='<security-group>',
13291362
action='append',
13301363
default=[],
1364+
dest='security_groups',
13311365
help=_(
13321366
'Security group to assign to this server (name or ID) '
13331367
'(repeat option to set multiple groups)'
@@ -1945,21 +1979,22 @@ def _match_image(image_api, wanted_properties):
19451979
# 'auto' to maintain legacy behavior if a nic wasn't specified.
19461980
networks = 'auto'
19471981

1948-
# Check security group exist and convert ID to name
1982+
# Check security group(s) exist and convert ID to name
19491983
security_groups = []
19501984
if self.app.client_manager.is_network_endpoint_enabled():
19511985
network_client = self.app.client_manager.network
1952-
for each_sg in parsed_args.security_group:
1986+
for security_group in parsed_args.security_groups:
19531987
sg = network_client.find_security_group(
1954-
each_sg, ignore_missing=False
1988+
security_group, ignore_missing=False
19551989
)
19561990
# Use security group ID to avoid multiple security group have
19571991
# same name in neutron networking backend
19581992
security_groups.append({'name': sg.id})
1959-
else:
1960-
# Handle nova-network case
1961-
for each_sg in parsed_args.security_group:
1962-
sg = compute_v2.find_security_group(compute_client, each_sg)
1993+
else: # nova-network
1994+
for security_group in parsed_args.security_groups:
1995+
sg = compute_v2.find_security_group(
1996+
compute_client, security_group
1997+
)
19631998
security_groups.append({'name': sg['name']})
19641999

19652000
hints = {}
@@ -4014,9 +4049,13 @@ def get_parser(self, prog_name):
40144049
help=_('Server (name or ID)'),
40154050
)
40164051
parser.add_argument(
4017-
'group',
4018-
metavar='<group>',
4019-
help=_('Security group to remove (name or ID)'),
4052+
'security_groups',
4053+
metavar='<security-group>',
4054+
nargs='+',
4055+
help=_(
4056+
'Security group(s) to remove from server (name or ID) '
4057+
'(repeat option to remove multiple groups)'
4058+
),
40204059
)
40214060
return parser
40224061

@@ -4029,15 +4068,42 @@ def take_action(self, parsed_args):
40294068
if self.app.client_manager.is_network_endpoint_enabled():
40304069
# the server handles both names and IDs for neutron SGs, so just
40314070
# pass things through
4032-
security_group = parsed_args.group
4071+
security_groups = parsed_args.security_groups
40334072
else:
4034-
# however, if using nova-network then it needs a name, not an ID
4035-
security_group = compute_v2.find_security_group(
4036-
compute_client, parsed_args.group
4037-
)['name']
4038-
compute_client.remove_security_group_from_server(
4039-
server, security_group
4040-
)
4073+
# however, if using nova-network then it needs names, not IDs
4074+
security_groups = []
4075+
for security_group in parsed_args.security_groups:
4076+
security_groups.append(
4077+
compute_v2.find_security_group(
4078+
compute_client, security_group
4079+
)['name']
4080+
)
4081+
4082+
errors = 0
4083+
for security_group in security_groups:
4084+
try:
4085+
compute_client.remove_security_group_from_server(
4086+
server, security_group
4087+
)
4088+
except sdk_exceptions.HttpException as e:
4089+
errors += 1
4090+
LOG.error(
4091+
_(
4092+
"Failed to remove security group with name or ID "
4093+
"'%(security_group)s' from server '%(server)s': %(e)s"
4094+
),
4095+
{
4096+
'security_group': security_group,
4097+
'server': server.id,
4098+
'e': e,
4099+
},
4100+
)
4101+
4102+
if errors > 0:
4103+
msg = _(
4104+
"%(errors)d of %(total)d security groups were not removed."
4105+
) % {'errors': errors, 'total': len(security_groups)}
4106+
raise exceptions.CommandError(msg)
40414107

40424108

40434109
class RemoveServerVolume(command.Command):

openstackclient/tests/functional/common/test_help.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class HelpTests(base.TestCase):
2121
"""Functional tests for openstackclient help output."""
2222

2323
SERVER_COMMANDS = [
24-
('server add security group', 'Add security group to server'),
24+
('server add security group', 'Add security group(s) to server'),
2525
('server add volume', 'Add volume to server'),
2626
('server backup create', 'Create a server backup image'),
2727
('server create', 'Create a new server'),

openstackclient/tests/unit/compute/v2/test_server.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,7 @@ def test_server_add_security_group__nova_network(self):
11451145
arglist = [self.server.id, 'fake_sg']
11461146
verifylist = [
11471147
('server', self.server.id),
1148-
('group', 'fake_sg'),
1148+
('security_groups', ['fake_sg']),
11491149
]
11501150

11511151
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1176,7 +1176,7 @@ def test_server_add_security_group(self):
11761176
arglist = [self.server.id, 'fake_sg']
11771177
verifylist = [
11781178
('server', self.server.id),
1179-
('group', 'fake_sg'),
1179+
('security_groups', ['fake_sg']),
11801180
]
11811181

11821182
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1408,7 +1408,7 @@ def test_server_create_with_options(self):
14081408
('flavor', self.flavor.id),
14091409
('key_name', 'keyname'),
14101410
('properties', {'Beta': 'b'}),
1411-
('security_group', [security_group.id]),
1411+
('security_groups', [security_group.id]),
14121412
('hints', {'a': ['b', 'c']}),
14131413
('server_group', server_group.id),
14141414
('config_drive', True),
@@ -1478,7 +1478,7 @@ def test_server_create_with_not_exist_security_group(self):
14781478
('image', self.image.id),
14791479
('flavor', self.flavor.id),
14801480
('key_name', 'keyname'),
1481-
('security_group', ['not_exist_sg']),
1481+
('security_groups', ['not_exist_sg']),
14821482
('server_name', self.server.name),
14831483
]
14841484
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1504,7 +1504,7 @@ def test_server_create_with_security_group_in_nova_network(self):
15041504
verifylist = [
15051505
('image', self.image.id),
15061506
('flavor', self.flavor.id),
1507-
('security_group', [sg_name]),
1507+
('security_groups', [sg_name]),
15081508
('server_name', self.server.name),
15091509
]
15101510

@@ -7380,7 +7380,7 @@ def test_server_remove_security_group__nova_network(self):
73807380
arglist = [self.server.id, 'fake_sg']
73817381
verifylist = [
73827382
('server', self.server.id),
7383-
('group', 'fake_sg'),
7383+
('security_groups', ['fake_sg']),
73847384
]
73857385

73867386
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -7411,7 +7411,7 @@ def test_server_remove_security_group(self):
74117411
arglist = [self.server.id, 'fake_sg']
74127412
verifylist = [
74137413
('server', self.server.id),
7414-
('group', 'fake_sg'),
7414+
('security_groups', ['fake_sg']),
74157415
]
74167416

74177417
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features:
3+
- |
4+
The ``server add security group`` and ``server remove security group``
5+
commands now accept multiple security groups.

0 commit comments

Comments
 (0)