Skip to content

Commit 7903e53

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Refactor security group delete to use SDK"
2 parents 3763d75 + 580b0af commit 7903e53

9 files changed

Lines changed: 385 additions & 25 deletions

File tree

doc/source/command-objects/security-group-rule.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
security group rule
33
===================
44

5-
Compute v2
5+
Compute v2, Network v2
66

77
security group rule create
88
--------------------------

doc/source/command-objects/security-group.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
security group
33
==============
44

5-
Compute v2
5+
Compute v2, Network v2
66

77
security group create
88
---------------------

openstackclient/compute/v2/security_group.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -169,28 +169,6 @@ def take_action(self, parsed_args):
169169
return zip(*sorted(six.iteritems(info)))
170170

171171

172-
class DeleteSecurityGroup(command.Command):
173-
"""Delete a security group"""
174-
175-
def get_parser(self, prog_name):
176-
parser = super(DeleteSecurityGroup, self).get_parser(prog_name)
177-
parser.add_argument(
178-
'group',
179-
metavar='<group>',
180-
help='Security group to delete (name or ID)',
181-
)
182-
return parser
183-
184-
def take_action(self, parsed_args):
185-
186-
compute_client = self.app.client_manager.compute
187-
data = utils.find_resource(
188-
compute_client.security_groups,
189-
parsed_args.group,
190-
)
191-
compute_client.security_groups.delete(data.id)
192-
193-
194172
class DeleteSecurityGroupRule(command.Command):
195173
"""Delete a security group rule"""
196174

openstackclient/network/common.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
import abc
15+
import six
16+
17+
from openstackclient.common import command
18+
19+
20+
@six.add_metaclass(abc.ABCMeta)
21+
class NetworkAndComputeCommand(command.Command):
22+
"""Network and Compute Command"""
23+
24+
def take_action(self, parsed_args):
25+
if self.app.client_manager.is_network_endpoint_enabled():
26+
return self.take_action_network(self.app.client_manager.network,
27+
parsed_args)
28+
else:
29+
return self.take_action_compute(self.app.client_manager.compute,
30+
parsed_args)
31+
32+
def get_parser(self, prog_name):
33+
self.log.debug('get_parser(%s)', prog_name)
34+
parser = super(NetworkAndComputeCommand, self).get_parser(prog_name)
35+
parser = self.update_parser_common(parser)
36+
self.log.debug('common parser: %s', parser)
37+
if self.app.client_manager.is_network_endpoint_enabled():
38+
return self.update_parser_network(parser)
39+
else:
40+
return self.update_parser_compute(parser)
41+
42+
def update_parser_common(self, parser):
43+
"""Default is no updates to parser."""
44+
return parser
45+
46+
def update_parser_network(self, parser):
47+
"""Default is no updates to parser."""
48+
return parser
49+
50+
def update_parser_compute(self, parser):
51+
"""Default is no updates to parser."""
52+
return parser
53+
54+
@abc.abstractmethod
55+
def take_action_network(self, client, parsed_args):
56+
"""Override to do something useful."""
57+
pass
58+
59+
@abc.abstractmethod
60+
def take_action_compute(self, client, parsed_args):
61+
"""Override to do something useful."""
62+
pass
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
"""Security Group action implementations"""
15+
16+
from openstackclient.common import utils
17+
from openstackclient.network import common
18+
19+
20+
class DeleteSecurityGroup(common.NetworkAndComputeCommand):
21+
"""Delete a security group"""
22+
23+
def update_parser_common(self, parser):
24+
parser.add_argument(
25+
'group',
26+
metavar='<group>',
27+
help='Security group to delete (name or ID)',
28+
)
29+
return parser
30+
31+
def take_action_network(self, client, parsed_args):
32+
obj = client.find_security_group(parsed_args.group)
33+
client.delete_security_group(obj)
34+
35+
def take_action_compute(self, client, parsed_args):
36+
data = utils.find_resource(
37+
client.security_groups,
38+
parsed_args.group,
39+
)
40+
client.security_groups.delete(data.id)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
import argparse
15+
import mock
16+
17+
from openstackclient.network import common
18+
from openstackclient.tests import utils
19+
20+
21+
class FakeNetworkAndComputeCommand(common.NetworkAndComputeCommand):
22+
def update_parser_common(self, parser):
23+
parser.add_argument(
24+
'common',
25+
metavar='<common>',
26+
help='Common argument',
27+
)
28+
return parser
29+
30+
def update_parser_network(self, parser):
31+
parser.add_argument(
32+
'network',
33+
metavar='<network>',
34+
help='Network argument',
35+
)
36+
return parser
37+
38+
def update_parser_compute(self, parser):
39+
parser.add_argument(
40+
'compute',
41+
metavar='<compute>',
42+
help='Compute argument',
43+
)
44+
return parser
45+
46+
def take_action_network(self, client, parsed_args):
47+
client.network_action(parsed_args)
48+
return 'take_action_network'
49+
50+
def take_action_compute(self, client, parsed_args):
51+
client.compute_action(parsed_args)
52+
return 'take_action_compute'
53+
54+
55+
class TestNetworkAndComputeCommand(utils.TestCommand):
56+
def setUp(self):
57+
super(TestNetworkAndComputeCommand, self).setUp()
58+
59+
self.namespace = argparse.Namespace()
60+
61+
# Create network client mocks.
62+
self.app.client_manager.network = mock.Mock()
63+
self.network = self.app.client_manager.network
64+
self.network.network_action = mock.Mock(return_value=None)
65+
66+
# Create compute client mocks.
67+
self.app.client_manager.compute = mock.Mock()
68+
self.compute = self.app.client_manager.compute
69+
self.compute.compute_action = mock.Mock(return_value=None)
70+
71+
# Get the command object to test
72+
self.cmd = FakeNetworkAndComputeCommand(self.app, self.namespace)
73+
74+
def test_take_action_network(self):
75+
arglist = [
76+
'common',
77+
'network'
78+
]
79+
verifylist = [
80+
('common', 'common'),
81+
('network', 'network')
82+
]
83+
84+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
85+
result = self.cmd.take_action(parsed_args)
86+
self.network.network_action.assert_called_with(parsed_args)
87+
self.assertEqual('take_action_network', result)
88+
89+
def test_take_action_compute(self):
90+
arglist = [
91+
'common',
92+
'compute'
93+
]
94+
verifylist = [
95+
('common', 'common'),
96+
('compute', 'compute')
97+
]
98+
99+
self.app.client_manager.network_endpoint_enabled = False
100+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
101+
result = self.cmd.take_action(parsed_args)
102+
self.compute.compute_action.assert_called_with(parsed_args)
103+
self.assertEqual('take_action_compute', result)

openstackclient/tests/network/v2/fakes.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,84 @@ def get_routers(routers=None, count=2):
356356
return mock.MagicMock(side_effect=routers)
357357

358358

359+
class FakeSecurityGroup(object):
360+
"""Fake one or more security groups."""
361+
362+
@staticmethod
363+
def create_one_security_group(attrs={}, methods={}):
364+
"""Create a fake security group.
365+
366+
:param Dictionary attrs:
367+
A dictionary with all attributes
368+
:param Dictionary methods:
369+
A dictionary with all methods
370+
:return:
371+
A FakeResource object, with id, name, etc.
372+
"""
373+
# Set default attributes.
374+
security_group_attrs = {
375+
'id': 'security-group-id-' + uuid.uuid4().hex,
376+
'name': 'security-group-name-' + uuid.uuid4().hex,
377+
'description': 'security-group-description-' + uuid.uuid4().hex,
378+
'tenant_id': 'project-id-' + uuid.uuid4().hex,
379+
'security_group_rules': [],
380+
}
381+
382+
# Overwrite default attributes.
383+
security_group_attrs.update(attrs)
384+
385+
# Set default methods.
386+
security_group_methods = {}
387+
388+
# Overwrite default methods.
389+
security_group_methods.update(methods)
390+
391+
security_group = fakes.FakeResource(
392+
info=copy.deepcopy(security_group_attrs),
393+
methods=copy.deepcopy(security_group_methods),
394+
loaded=True)
395+
return security_group
396+
397+
@staticmethod
398+
def create_security_groups(attrs={}, methods={}, count=2):
399+
"""Create multiple fake security groups.
400+
401+
:param Dictionary attrs:
402+
A dictionary with all attributes
403+
:param Dictionary methods:
404+
A dictionary with all methods
405+
:param int count:
406+
The number of security groups to fake
407+
:return:
408+
A list of FakeResource objects faking the security groups
409+
"""
410+
security_groups = []
411+
for i in range(0, count):
412+
security_groups.append(
413+
FakeRouter.create_one_security_group(attrs, methods))
414+
415+
return security_groups
416+
417+
@staticmethod
418+
def get_security_groups(security_groups=None, count=2):
419+
"""Get an iterable MagicMock object with a list of faked security groups.
420+
421+
If security group list is provided, then initialize the Mock object
422+
with the list. Otherwise create one.
423+
424+
:param List security groups:
425+
A list of FakeResource objects faking security groups
426+
:param int count:
427+
The number of security groups to fake
428+
:return:
429+
An iterable Mock object with side_effect set to a list of faked
430+
security groups
431+
"""
432+
if security_groups is None:
433+
security_groups = FakeRouter.create_security_groups(count)
434+
return mock.MagicMock(side_effect=security_groups)
435+
436+
359437
class FakeSubnet(object):
360438
"""Fake one or more subnets."""
361439

0 commit comments

Comments
 (0)