1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
# not use this file except in compliance with the License. You may obtain
5
# a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
# License for the specific language governing permissions and limitations
17
from heat.engine import clients
18
from heat.common import context
19
from heat.common import template_format
20
from heat.engine import parser
21
from heat.engine import resource
22
from heat.tests.common import HeatTestCase
23
from heat.tests.utils import setup_dummy_db
24
from heat.tests.v1_1 import fakes
25
from heat.tests import utils
26
from heat.tests.utils import stack_delete_after
28
from novaclient.v1_1 import security_groups as nova_sg
29
from novaclient.v1_1 import security_group_rules as nova_sgr
30
from quantumclient.common.exceptions import QuantumClientException
31
from quantumclient.v2_0 import client as quantumclient
33
NovaSG = collections.namedtuple('NovaSG',
42
class SecurityGroupTest(HeatTestCase):
44
test_template_nova = '''
45
HeatTemplateFormatVersion: '2012-12-12'
48
Type: AWS::EC2::SecurityGroup
50
GroupDescription: HTTP and SSH access
62
test_template_quantum = '''
63
HeatTemplateFormatVersion: '2012-12-12'
66
Type: AWS::EC2::SecurityGroup
68
GroupDescription: HTTP and SSH access
87
super(SecurityGroupTest, self).setUp()
88
self.fc = fakes.FakeClient()
89
self.m.StubOutWithMock(clients.OpenStackClients, 'nova')
90
self.m.StubOutWithMock(nova_sgr.SecurityGroupRuleManager, 'create')
91
self.m.StubOutWithMock(nova_sgr.SecurityGroupRuleManager, 'delete')
92
self.m.StubOutWithMock(nova_sg.SecurityGroupManager, 'create')
93
self.m.StubOutWithMock(nova_sg.SecurityGroupManager, 'delete')
94
self.m.StubOutWithMock(nova_sg.SecurityGroupManager, 'get')
95
self.m.StubOutWithMock(nova_sg.SecurityGroupManager, 'list')
97
self.m.StubOutWithMock(quantumclient.Client, 'create_security_group')
98
self.m.StubOutWithMock(
99
quantumclient.Client, 'create_security_group_rule')
100
self.m.StubOutWithMock(quantumclient.Client, 'show_security_group')
101
self.m.StubOutWithMock(
102
quantumclient.Client, 'delete_security_group_rule')
103
self.m.StubOutWithMock(quantumclient.Client, 'delete_security_group')
105
def create_stack(self, template):
106
t = template_format.parse(template)
107
self.stack = self.parse_stack(t)
108
self.assertEqual(None, self.stack.create())
111
def parse_stack(self, t):
112
ctx = context.RequestContext.from_dict({
113
'tenant': 'test_tenant',
114
'username': 'test_username',
115
'password': 'password',
116
'auth_url': 'http://localhost:5000/v2.0'})
117
stack_name = 'test_stack'
118
tmpl = parser.Template(t)
119
stack = parser.Stack(ctx, stack_name, tmpl)
123
def assertResourceState(self, rsrc, ref_id, metadata={}):
124
self.assertEqual(None, rsrc.validate())
125
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
126
self.assertEqual(ref_id, rsrc.FnGetRefId())
127
self.assertEqual(metadata, dict(rsrc.metadata))
130
def test_security_group_nova(self):
132
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
133
nova_sg.SecurityGroupManager.list().AndReturn([NovaSG(
136
description='FAKE_SECURITY_GROUP',
139
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
140
sg_name = utils.PhysName('test_stack', 'the_sg')
141
nova_sg.SecurityGroupManager.create(
143
'HTTP and SSH access').AndReturn(NovaSG(
146
description='HTTP and SSH access',
149
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
150
nova_sgr.SecurityGroupRuleManager.create(
151
2, 'tcp', 22, 22, '0.0.0.0/0').AndReturn(None)
152
nova_sgr.SecurityGroupRuleManager.create(
153
2, 'tcp', 80, 80, '0.0.0.0/0').AndReturn(None)
156
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
157
nova_sg.SecurityGroupManager.get(2).AndReturn(NovaSG(
160
description='HTTP and SSH access',
164
"ip_protocol": "tcp",
166
"parent_group_id": 2,
174
'ip_protocol': 'tcp',
176
'parent_group_id': 2,
183
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
184
nova_sgr.SecurityGroupRuleManager.delete(130).AndReturn(None)
185
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
186
nova_sgr.SecurityGroupRuleManager.delete(131).AndReturn(None)
187
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
188
nova_sg.SecurityGroupManager.delete(2).AndReturn(None)
191
stack = self.create_stack(self.test_template_nova)
194
self.assertRaises(resource.UpdateReplace, sg.handle_update, {}, {}, {})
196
self.assertResourceState(sg, utils.PhysName('test_stack', 'the_sg'))
202
def test_security_group_nova_exception(self):
204
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
205
sg_name = utils.PhysName('test_stack', 'the_sg')
206
nova_sg.SecurityGroupManager.list().AndReturn([NovaSG(
209
description='HTTP and SSH access',
213
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
214
nova_sgr.SecurityGroupRuleManager.create(
215
2, 'tcp', 22, 22, '0.0.0.0/0').AndRaise(
216
clients.novaclient.exceptions.BadRequest(
217
400, 'Rule already exists'))
218
nova_sgr.SecurityGroupRuleManager.create(
219
2, 'tcp', 80, 80, '0.0.0.0/0').AndReturn(
220
clients.novaclient.exceptions.BadRequest(
221
400, 'Rule already exists'))
224
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
225
nova_sg.SecurityGroupManager.get(2).AndReturn(NovaSG(
228
description='HTTP and SSH access',
232
"ip_protocol": "tcp",
234
"parent_group_id": 2,
242
'ip_protocol': 'tcp',
244
'parent_group_id': 2,
251
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
252
nova_sgr.SecurityGroupRuleManager.delete(130).AndRaise(
253
clients.novaclient.exceptions.NotFound('goneburger'))
254
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
255
nova_sgr.SecurityGroupRuleManager.delete(131).AndRaise(
256
clients.novaclient.exceptions.NotFound('goneburger'))
257
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
258
nova_sg.SecurityGroupManager.delete(2).AndReturn(None)
260
clients.OpenStackClients.nova('compute').AndReturn(self.fc)
261
nova_sg.SecurityGroupManager.get(2).AndRaise(
262
clients.novaclient.exceptions.NotFound('goneburger'))
265
stack = self.create_stack(self.test_template_nova)
268
self.assertRaises(resource.UpdateReplace, sg.handle_update, {}, {}, {})
270
self.assertResourceState(sg, utils.PhysName('test_stack', 'the_sg'))
272
self.assertEqual(None, sg.delete())
274
sg.state_set(sg.CREATE, sg.COMPLETE, 'to delete again')
281
def test_security_group_quantum(self):
283
sg_name = utils.PhysName('test_stack', 'the_sg')
284
quantumclient.Client.create_security_group({
287
'description': 'HTTP and SSH access'
291
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
293
'description': 'HTTP and SSH access',
294
'security_group_rules': [],
299
quantumclient.Client.create_security_group_rule({
300
'security_group_rule': {
301
'direction': 'ingress',
302
'remote_ip_prefix': '0.0.0.0/0',
303
'port_range_min': 22,
305
'port_range_max': 22,
307
'security_group_id': 'aaaa'
310
'security_group_rule': {
311
'direction': 'ingress',
312
'remote_ip_prefix': '0.0.0.0/0',
313
'port_range_min': 22,
315
'port_range_max': 22,
317
'security_group_id': 'aaaa',
321
quantumclient.Client.create_security_group_rule({
322
'security_group_rule': {
323
'direction': 'ingress',
324
'remote_ip_prefix': '0.0.0.0/0',
325
'port_range_min': 80,
327
'port_range_max': 80,
329
'security_group_id': 'aaaa'
332
'security_group_rule': {
333
'direction': 'ingress',
334
'remote_ip_prefix': '0.0.0.0/0',
335
'port_range_min': 80,
337
'port_range_max': 80,
339
'security_group_id': 'aaaa',
343
quantumclient.Client.create_security_group_rule({
344
'security_group_rule': {
345
'direction': 'egress',
346
'remote_ip_prefix': '10.0.1.0/24',
347
'port_range_min': 22,
349
'port_range_max': 22,
351
'security_group_id': 'aaaa'
354
'security_group_rule': {
355
'direction': 'egress',
356
'remote_ip_prefix': '10.0.1.0/24',
357
'port_range_min': 22,
359
'port_range_max': 22,
361
'security_group_id': 'aaaa',
367
quantumclient.Client.show_security_group('aaaa').AndReturn({
369
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
372
'security_group_rules': [{
373
'direction': 'ingress',
375
'port_range_max': 22,
378
'security_group_id': 'aaaa',
379
'remote_ip_prefix': '0.0.0.0/0',
380
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
383
'direction': 'ingress',
385
'port_range_max': 80,
388
'security_group_id': 'aaaa',
389
'remote_ip_prefix': '0.0.0.0/0',
390
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
393
'direction': 'egress',
395
'port_range_max': 22,
398
'security_group_id': 'aaaa',
399
'remote_ip_prefix': '10.0.1.0/24',
400
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
404
quantumclient.Client.delete_security_group_rule('bbbb').AndReturn(None)
405
quantumclient.Client.delete_security_group_rule('cccc').AndReturn(None)
406
quantumclient.Client.delete_security_group_rule('dddd').AndReturn(None)
407
quantumclient.Client.delete_security_group('aaaa').AndReturn(None)
410
stack = self.create_stack(self.test_template_quantum)
413
self.assertRaises(resource.UpdateReplace, sg.handle_update, {}, {}, {})
415
self.assertResourceState(sg, 'aaaa')
421
def test_security_group_quantum_exception(self):
423
sg_name = utils.PhysName('test_stack', 'the_sg')
424
quantumclient.Client.create_security_group({
427
'description': 'HTTP and SSH access'
431
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
433
'description': 'HTTP and SSH access',
434
'security_group_rules': [],
439
quantumclient.Client.create_security_group_rule({
440
'security_group_rule': {
441
'direction': 'ingress',
442
'remote_ip_prefix': '0.0.0.0/0',
443
'port_range_min': 22,
445
'port_range_max': 22,
447
'security_group_id': 'aaaa'
450
QuantumClientException(status_code=409))
451
quantumclient.Client.create_security_group_rule({
452
'security_group_rule': {
453
'direction': 'ingress',
454
'remote_ip_prefix': '0.0.0.0/0',
455
'port_range_min': 80,
457
'port_range_max': 80,
459
'security_group_id': 'aaaa'
462
QuantumClientException(status_code=409))
463
quantumclient.Client.create_security_group_rule({
464
'security_group_rule': {
465
'direction': 'egress',
466
'remote_ip_prefix': '10.0.1.0/24',
467
'port_range_min': 22,
469
'port_range_max': 22,
471
'security_group_id': 'aaaa'
474
QuantumClientException(status_code=409))
477
quantumclient.Client.show_security_group('aaaa').AndReturn({
479
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
482
'security_group_rules': [{
483
'direction': 'ingress',
485
'port_range_max': 22,
488
'security_group_id': 'aaaa',
489
'remote_ip_prefix': '0.0.0.0/0',
490
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
493
'direction': 'ingress',
495
'port_range_max': 80,
498
'security_group_id': 'aaaa',
499
'remote_ip_prefix': '0.0.0.0/0',
500
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
503
'direction': 'egress',
505
'port_range_max': 22,
508
'security_group_id': 'aaaa',
509
'remote_ip_prefix': '10.0.1.0/24',
510
'tenant_id': 'f18ca530cc05425e8bac0a5ff92f7e88',
514
quantumclient.Client.delete_security_group_rule('bbbb').AndRaise(
515
QuantumClientException(status_code=404))
516
quantumclient.Client.delete_security_group_rule('cccc').AndRaise(
517
QuantumClientException(status_code=404))
518
quantumclient.Client.delete_security_group_rule('dddd').AndRaise(
519
QuantumClientException(status_code=404))
520
quantumclient.Client.delete_security_group('aaaa').AndRaise(
521
QuantumClientException(status_code=404))
523
quantumclient.Client.show_security_group('aaaa').AndRaise(
524
QuantumClientException(status_code=404))
527
stack = self.create_stack(self.test_template_quantum)
530
self.assertRaises(resource.UpdateReplace, sg.handle_update, {}, {}, {})
532
self.assertResourceState(sg, 'aaaa')
534
self.assertEqual(None, sg.delete())
536
sg.state_set(sg.CREATE, sg.COMPLETE, 'to delete again')
537
sg.resource_id = 'aaaa'