12
12
# License for the specific language governing permissions and limitations
13
13
# under the License.
19
from nose.plugins.attrib import attr
15
from testtools import skipIf
21
17
from heat.common import context
22
18
from heat.common import exception
23
19
from heat.common import template_format
24
20
from heat.engine import parser
25
import heat.engine.resources # pyflakes_bypass review 23102
21
from heat.engine import resource
22
from heat.tests.common import HeatTestCase
23
from heat.tests import utils
24
from heat.tests.utils import setup_dummy_db
28
27
from quantumclient.common.exceptions import QuantumClientException
29
28
from quantumclient.v2_0 import client as quantumclient
30
29
except ImportError:
31
from nose.exc import SkipTest
35
class VPCTestBase(unittest.TestCase):
33
class VPCTestBase(HeatTestCase):
35
@skipIf(quantumclient is None, 'quantumclient unavaialble')
37
super(VPCTestBase, self).setUp()
39
39
self.m.StubOutWithMock(quantumclient.Client, 'add_interface_router')
40
40
self.m.StubOutWithMock(quantumclient.Client, 'add_gateway_router')
41
41
self.m.StubOutWithMock(quantumclient.Client, 'create_network')
87
93
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
96
quantumclient.Client.show_network(
98
).AndReturn({"network": {
101
"name": self.vpc_name,
102
"admin_state_up": False,
104
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
108
quantumclient.Client.show_network(
110
).MultipleTimes().AndReturn({"network": {
113
"name": self.vpc_name,
114
"admin_state_up": False,
116
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
90
119
quantumclient.Client.create_router(
91
{'router': {'name': 'test_stack.the_vpc'}}).AndReturn({'router': {
94
'admin_state_up': True,
95
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
120
{'router': {'name': self.vpc_name}}).AndReturn({
123
'name': self.vpc_name,
124
'admin_state_up': True,
125
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
128
quantumclient.Client.list_routers(name=self.vpc_name).AndReturn({
131
"external_gateway_info": None,
132
"name": self.vpc_name,
133
"admin_state_up": True,
134
"tenant_id": "3e21026f2dc94372b105808c0e721661",
139
self.mock_router_for_vpc()
99
141
def mock_create_subnet(self):
142
self.subnet_name = utils.PhysName('test_stack', 'the_subnet')
100
143
quantumclient.Client.create_subnet(
102
145
'network_id': u'aaaa',
103
146
'cidr': u'10.0.0.0/24',
105
'name': u'test_stack.the_subnet'}}).AndReturn({
148
'name': self.subnet_name}}).AndReturn({
107
150
'status': 'ACTIVE',
108
'name': 'test_stack.the_subnet',
151
'name': self.subnet_name,
109
152
'admin_state_up': True,
110
153
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
155
self.mock_router_for_vpc()
112
156
quantumclient.Client.add_interface_router(
114
158
{'subnet_id': 'cccc'}).AndReturn(None)
160
def mock_show_subnet(self):
161
quantumclient.Client.show_subnet('cccc').AndReturn({
163
'name': self.subnet_name,
164
'network_id': 'aaaa',
165
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
166
'allocation_pools': [{'start': '10.0.0.2',
167
'end': '10.0.0.254'}],
168
'gateway_ip': '10.0.0.1',
170
'cidr': '10.0.0.0/24',
172
'enable_dhcp': False,
175
def mock_create_security_group(self):
176
self.sg_name = utils.PhysName('test_stack', 'the_sg')
177
quantumclient.Client.create_security_group({
179
'name': self.sg_name,
180
'description': 'SSH access'
184
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
185
'name': self.sg_name,
186
'description': 'SSH access',
187
'security_group_rules': [],
192
quantumclient.Client.create_security_group_rule({
193
'security_group_rule': {
194
'direction': 'ingress',
195
'remote_ip_prefix': '0.0.0.0/0',
196
'port_range_min': 22,
198
'port_range_max': 22,
200
'security_group_id': 'eeee'
203
'security_group_rule': {
204
'direction': 'ingress',
205
'remote_ip_prefix': '0.0.0.0/0',
206
'port_range_min': 22,
208
'port_range_max': 22,
210
'security_group_id': 'eeee',
215
def mock_delete_security_group(self):
216
sg_name = utils.PhysName('test_stack', 'the_sg')
217
quantumclient.Client.show_security_group('eeee').AndReturn({
219
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
222
'security_group_rules': [{
223
'direction': 'ingress',
225
'port_range_max': 22,
228
'security_group_id': 'eeee',
229
'remote_ip_prefix': '0.0.0.0/0',
230
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
234
quantumclient.Client.delete_security_group_rule('bbbb').AndReturn(None)
235
quantumclient.Client.delete_security_group('eeee').AndReturn(None)
237
def mock_router_for_vpc(self):
238
quantumclient.Client.list_routers(name=self.vpc_name).AndReturn({
241
"external_gateway_info": {
242
"network_id": "zzzz",
243
"enable_snat": True},
244
"name": self.vpc_name,
245
"admin_state_up": True,
246
"tenant_id": "3e21026f2dc94372b105808c0e721661",
116
252
def mock_delete_network(self):
253
self.mock_router_for_vpc()
117
254
quantumclient.Client.delete_router('bbbb').AndReturn(None)
118
255
quantumclient.Client.delete_network('aaaa').AndReturn(None)
120
257
def mock_delete_subnet(self):
258
self.mock_router_for_vpc()
121
259
quantumclient.Client.remove_interface_router(
123
261
{'subnet_id': 'cccc'}).AndReturn(None)
124
262
quantumclient.Client.delete_subnet('cccc').AndReturn(None)
126
def assertResourceState(self, resource, ref_id, metadata={}):
264
def mock_create_route_table(self):
265
self.rt_name = utils.PhysName('test_stack', 'the_route_table')
266
quantumclient.Client.create_router({
267
'router': {'name': self.rt_name}}).AndReturn({
270
'name': self.rt_name,
271
'admin_state_up': True,
272
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
276
quantumclient.Client.show_router('ffff').AndReturn({
279
'name': self.rt_name,
280
'admin_state_up': True,
281
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
285
quantumclient.Client.show_router('ffff').AndReturn({
288
'name': self.rt_name,
289
'admin_state_up': True,
290
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
294
self.mock_router_for_vpc()
295
quantumclient.Client.add_gateway_router(
296
'ffff', {'network_id': 'zzzz'}).AndReturn(None)
298
def mock_create_association(self):
299
self.mock_show_subnet()
300
self.mock_router_for_vpc()
301
quantumclient.Client.remove_interface_router(
303
{'subnet_id': u'cccc'}).AndReturn(None)
304
quantumclient.Client.add_interface_router(
306
{'subnet_id': 'cccc'}).AndReturn(None)
308
def mock_delete_association(self):
309
self.mock_show_subnet()
310
self.mock_router_for_vpc()
311
quantumclient.Client.remove_interface_router(
313
{'subnet_id': u'cccc'}).AndReturn(None)
314
quantumclient.Client.add_interface_router(
316
{'subnet_id': 'cccc'}).AndReturn(None)
318
def mock_delete_route_table(self):
319
quantumclient.Client.delete_router('ffff').AndReturn(None)
320
quantumclient.Client.remove_gateway_router('ffff').AndReturn(None)
322
def assertResourceState(self, resource, ref_id):
127
323
self.assertEqual(None, resource.validate())
128
self.assertEqual(resource.CREATE_COMPLETE, resource.state)
324
self.assertEqual((resource.CREATE, resource.COMPLETE), resource.state)
129
325
self.assertEqual(ref_id, resource.FnGetRefId())
130
self.assertEqual(metadata, dict(resource.metadata))
133
@attr(tag=['unit', 'resource'])
135
328
class VPCTest(VPCTestBase):
137
330
test_template = '''
193
384
self.m.ReplayAll()
194
385
stack = self.create_stack(self.test_template)
196
resource = stack['the_subnet']
197
self.assertResourceState(resource, 'cccc', {
199
'default_router_id': 'bbbb'})
387
subnet = stack['the_subnet']
388
self.assertResourceState(subnet, 'cccc')
201
self.assertEqual(resource.UPDATE_REPLACE, resource.handle_update({}))
390
self.assertRaises(resource.UpdateReplace,
391
subnet.handle_update, {}, {}, {})
202
392
self.assertRaises(
203
393
exception.InvalidTemplateAttribute,
207
self.assertEqual('moon', resource.FnGetAtt('AvailabilityZone'))
397
self.assertEqual('moon', subnet.FnGetAtt('AvailabilityZone'))
209
self.assertEqual(None, resource.delete())
210
resource.state_set(resource.CREATE_COMPLETE, 'to delete again')
211
self.assertEqual(None, resource.delete())
399
self.assertEqual(None, subnet.delete())
400
subnet.state_set(subnet.CREATE, subnet.COMPLETE, 'to delete again')
401
self.assertEqual(None, subnet.delete())
212
402
self.assertEqual(None, stack['the_vpc'].delete())
213
403
self.m.VerifyAll()
216
@attr(tag=['unit', 'resource'])
218
406
class NetworkInterfaceTest(VPCTestBase):
220
408
test_template = '''
221
409
HeatTemplateFormatVersion: '2012-12-12'
225
Properties: {CidrBlock: '10.0.0.0/16'}
227
Type: AWS::EC2::Subnet
229
CidrBlock: 10.0.0.0/24
230
VpcId: {Ref: the_vpc}
231
AvailabilityZone: moon
233
Type: AWS::EC2::NetworkInterface
235
PrivateIpAddress: 10.0.0.100
236
SubnetId: {Ref: the_subnet}
239
def mock_create_network_interface(self):
240
quantumclient.Client.create_port({
242
'network_id': 'aaaa', 'fixed_ips': [{
412
Type: AWS::EC2::SecurityGroup
414
VpcId: {Ref: the_vpc}
415
GroupDescription: SSH access
416
SecurityGroupIngress:
423
Properties: {CidrBlock: '10.0.0.0/16'}
425
Type: AWS::EC2::Subnet
427
CidrBlock: 10.0.0.0/24
428
VpcId: {Ref: the_vpc}
429
AvailabilityZone: moon
431
Type: AWS::EC2::NetworkInterface
433
PrivateIpAddress: 10.0.0.100
434
SubnetId: {Ref: the_subnet}
439
test_template_no_groupset = '''
440
HeatTemplateFormatVersion: '2012-12-12'
444
Properties: {CidrBlock: '10.0.0.0/16'}
446
Type: AWS::EC2::Subnet
448
CidrBlock: 10.0.0.0/24
449
VpcId: {Ref: the_vpc}
450
AvailabilityZone: moon
452
Type: AWS::EC2::NetworkInterface
454
PrivateIpAddress: 10.0.0.100
455
SubnetId: {Ref: the_subnet}
458
test_template_error = '''
459
HeatTemplateFormatVersion: '2012-12-12'
462
Type: AWS::EC2::SecurityGroup
464
VpcId: {Ref: the_vpc}
465
GroupDescription: SSH access
466
SecurityGroupIngress:
473
Properties: {CidrBlock: '10.0.0.0/16'}
475
Type: AWS::EC2::Subnet
477
CidrBlock: 10.0.0.0/24
478
VpcId: {Ref: the_vpc}
479
AvailabilityZone: moon
481
Type: AWS::EC2::NetworkInterface
483
PrivateIpAddress: 10.0.0.100
484
SubnetId: {Ref: the_subnet}
486
- Ref: INVALID-REF-IN-TEMPLATE
489
test_template_error_no_ref = '''
490
HeatTemplateFormatVersion: '2012-12-12'
494
Properties: {CidrBlock: '10.0.0.0/16'}
496
Type: AWS::EC2::Subnet
498
CidrBlock: 10.0.0.0/24
499
VpcId: {Ref: the_vpc}
500
AvailabilityZone: moon
502
Type: AWS::EC2::NetworkInterface
504
PrivateIpAddress: 10.0.0.100
505
SubnetId: {Ref: the_subnet}
510
def mock_create_network_interface(self, security_groups=['eeee']):
511
self.nic_name = utils.PhysName('test_stack', 'the_nic')
512
port = {'network_id': 'aaaa',
243
514
'subnet_id': u'cccc',
244
515
'ip_address': u'10.0.0.100'
246
'name': u'test_stack.the_nic',
247
'admin_state_up': True
250
'admin_state_up': True,
255
'ip_address': '10.0.0.100',
260
'mac_address': 'fa:16:3e:25:32:5d',
261
'name': 'test_stack.the_nic',
262
'network_id': 'aaaa',
264
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f'
517
'name': self.nic_name,
518
'admin_state_up': True}
520
port['security_groups'] = security_groups
522
quantumclient.Client.create_port({'port': port}).AndReturn({
524
'admin_state_up': True,
529
'ip_address': '10.0.0.100',
534
'mac_address': 'fa:16:3e:25:32:5d',
535
'name': self.nic_name,
536
'network_id': 'aaaa',
538
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f'
268
542
def mock_delete_network_interface(self):
269
543
quantumclient.Client.delete_port('dddd').AndReturn(None)
271
545
def test_network_interface(self):
546
self.mock_create_security_group()
272
547
self.mock_create_network()
273
548
self.mock_create_subnet()
549
self.mock_show_subnet()
274
550
self.mock_create_network_interface()
275
551
self.mock_delete_network_interface()
276
552
self.mock_delete_subnet()
277
553
self.mock_delete_network()
554
self.mock_delete_security_group()
279
556
self.m.ReplayAll()
281
558
stack = self.create_stack(self.test_template)
282
resource = stack['the_nic']
283
self.assertResourceState(resource, 'dddd')
285
self.assertEqual(resource.UPDATE_REPLACE, resource.handle_update({}))
560
self.assertEqual((stack.CREATE, stack.COMPLETE), stack.state)
561
rsrc = stack['the_nic']
562
self.assertResourceState(rsrc, 'dddd')
564
self.assertRaises(resource.UpdateReplace,
565
rsrc.handle_update, {}, {}, {})
572
def test_network_interface_no_groupset(self):
573
self.mock_create_network()
574
self.mock_create_subnet()
575
self.mock_show_subnet()
576
self.mock_create_network_interface(security_groups=None)
577
self.mock_delete_network_interface()
578
self.mock_delete_subnet()
579
self.mock_delete_network()
583
stack = self.create_stack(self.test_template_no_groupset)
291
@attr(tag=['unit', 'resource'])
588
def test_network_interface_error(self):
589
real_exception = self.assertRaises(
590
exception.InvalidTemplateReference,
592
self.test_template_error)
593
expected_exception = exception.InvalidTemplateReference(
594
resource='INVALID-REF-IN-TEMPLATE',
597
self.assertEquals(str(expected_exception), str(real_exception))
599
def test_network_interface_error_no_ref(self):
600
self.mock_create_network()
601
self.mock_create_subnet()
602
self.mock_show_subnet()
603
self.mock_delete_subnet()
604
self.mock_delete_network()
608
stack = self.create_stack(self.test_template_error_no_ref)
610
self.assertEqual((stack.CREATE, stack.FAILED), stack.state)
611
rsrc = stack['the_nic']
612
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
613
reason = rsrc.status_reason
614
self.assertTrue(reason.startswith('InvalidTemplateAttribute:'))
293
621
class InternetGatewayTest(VPCTestBase):
295
623
test_template = '''