17
from testtools import skipIf
18
from neutronclient.common import exceptions as qe
19
from neutronclient.v2_0 import client as neutronclient
19
21
from heat.common import exception
20
22
from heat.common import template_format
21
from heat.engine import clients
23
from heat.engine.cfn import functions as cfn_funcs
24
from heat.engine.clients.os import neutron
22
25
from heat.engine import properties
23
26
from heat.engine.resources.neutron import net
24
27
from heat.engine.resources.neutron.neutron import NeutronResource as qr
26
29
from heat.engine.resources.neutron import provider_net
27
30
from heat.engine.resources.neutron import router
28
31
from heat.engine.resources.neutron import subnet
32
from heat.engine import rsrc_defn
29
33
from heat.engine import scheduler
30
from heat.openstack.common.importutils import try_import
31
34
from heat.tests.common import HeatTestCase
32
from heat.tests import fakes
33
35
from heat.tests import utils
35
neutronclient = try_import('neutronclient.v2_0.client')
36
qe = try_import('neutronclient.common.exceptions')
38
38
neutron_template = '''
515
515
'status': 'FROBULATING'
519
@skipIf(neutronclient is None, 'neutronclient unavailable')
518
def test_resolve_attribute(self):
519
class SomeNeutronResource(qr):
520
properties_schema = {}
522
tmpl = rsrc_defn.ResourceDefinition('test_res', 'Foo')
523
stack = mock.MagicMock()
524
res = SomeNeutronResource('aresource', tmpl, stack)
526
mock_show_resource = mock.MagicMock()
527
mock_show_resource.side_effect = [{'attr1': 'val1', 'attr2': 'val2'},
528
{'attr1': 'val1', 'attr2': 'val2'},
529
{'attr1': 'val1', 'attr2': 'val2'},
530
qe.NeutronClientException]
531
res._show_resource = mock_show_resource
533
self.assertEqual({'attr1': 'val1', 'attr2': 'val2'},
534
res._resolve_attribute('show'))
535
self.assertEqual('val2', res._resolve_attribute('attr2'))
536
self.assertRaises(KeyError, res._resolve_attribute, 'attr3')
537
self.assertIsNone(res._resolve_attribute('attr2'))
520
540
class NeutronNetTest(HeatTestCase):
531
551
'remove_network_from_dhcp_agent')
532
552
self.m.StubOutWithMock(neutronclient.Client,
533
553
'list_dhcp_agent_hosting_networks')
534
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
554
self.stub_keystoneclient()
536
556
def create_net(self, t, stack, resource_name):
537
557
resource_defns = stack.t.resource_definitions(stack)
701
718
self.assertEqual('ACTIVE', rsrc.FnGetAtt('status'))
702
719
self.assertRaises(
703
720
exception.InvalidTemplateAttribute, rsrc.FnGetAtt, 'Foo')
705
"Type": "OS::Neutron::Net",
709
"admin_state_up": True,
711
"bb09cfcd-5277-473d-8336-d4ed8628ae68"
717
723
"dhcp_agent_ids": [
718
724
"bb09cfcd-5277-473d-8336-d4ed8628ae68"
727
props = copy.copy(rsrc.properties.data)
728
props.update(prop_diff)
729
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
721
731
rsrc.handle_update(update_snippet, {}, prop_diff)
723
733
scheduler.TaskRunner(rsrc.delete)()
735
744
self.m.StubOutWithMock(neutronclient.Client, 'show_network')
736
745
self.m.StubOutWithMock(neutronclient.Client, 'delete_network')
737
746
self.m.StubOutWithMock(neutronclient.Client, 'update_network')
738
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
747
self.stub_keystoneclient()
740
749
def create_provider_net(self):
741
clients.OpenStackClients.keystone().AndReturn(
742
fakes.FakeKeystoneClient())
745
751
neutronclient.Client.create_network({
834
840
scheduler.TaskRunner(rsrc.create)()
835
841
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
838
"Type": "OS::Neutron::ProviderNet",
842
"admin_state_up": True,
843
"network_type": "vlan",
844
"physical_network": "physnet_1",
845
"segmentation_id": "102"
846
"admin_state_up": True,
847
"network_type": "vlan",
848
"physical_network": "physnet_1",
849
"segmentation_id": "102"
851
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
848
853
self.assertIsNone(rsrc.handle_update(update_snippet, {}, {}))
849
854
self.m.VerifyAll()
852
@skipIf(neutronclient is None, 'neutronclient unavailable')
853
857
class NeutronSubnetTest(HeatTestCase):
860
864
self.m.StubOutWithMock(neutronclient.Client, 'update_subnet')
861
865
self.m.StubOutWithMock(neutron_utils.neutronV20,
862
866
'find_resourceid_by_name_or_id')
863
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
867
self.stub_keystoneclient()
865
869
def create_subnet(self, t, stack, resource_name):
866
870
resource_defns = stack.t.resource_definitions(stack)
894
898
self.assertIn(stack['port'], stack.dependencies[stack['subnet']])
895
899
self.assertIn(stack['port2'], stack.dependencies[stack['subnet']])
897
"Type": "OS::Neutron::Subnet",
900
"network": {"Ref": "network"},
901
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
903
"cidr": "10.0.3.0/24",
904
"allocation_pools": [
905
{"start": "10.0.3.20", "end": "10.0.3.150"}],
906
"dns_nameservers": ["8.8.8.8", "192.168.1.254"]
902
"network_id": cfn_funcs.ResourceRef(stack, "Ref", "network"),
903
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
905
"cidr": "10.0.3.0/24",
906
"allocation_pools": [
907
{"start": "10.0.3.20", "end": "10.0.3.150"}],
908
"dns_nameservers": ["8.8.8.8", "192.168.1.254"],
909
rsrc.handle_update(stack.resolve_static_data(update_snippet), {}, {})
910
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
912
rsrc.handle_update(update_snippet, {}, {})
911
914
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
912
915
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
939
942
self.m.VerifyAll()
941
944
def _test_subnet(self, resolve_neutron=True):
942
clients.OpenStackClients.keystone().AndReturn(
943
fakes.FakeKeystoneClient())
944
945
neutronclient.Client.create_subnet({
946
947
'name': utils.PhysName('test_stack', 'test_subnet'),
1032
1033
def test_subnet_disable_dhcp(self):
1034
clients.OpenStackClients.keystone().AndReturn(
1035
fakes.FakeKeystoneClient())
1036
1034
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
1037
1035
mox.IsA(neutronclient.Client),
1160
@skipIf(neutronclient is None, 'neutronclient unavailable')
1161
1158
class NeutronRouterTest(HeatTestCase):
1163
@skipIf(neutron_utils.neutronV20 is None, "Missing Neutron v2_0")
1164
1160
def setUp(self):
1165
1161
super(NeutronRouterTest, self).setUp()
1166
1162
self.m.StubOutWithMock(neutronclient.Client, 'create_router')
1179
1175
'list_l3_agent_hosting_routers')
1180
1176
self.m.StubOutWithMock(neutron_utils.neutronV20,
1181
1177
'find_resourceid_by_name_or_id')
1182
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
1178
self.stub_keystoneclient()
1184
1180
def create_router(self, t, stack, resource_name):
1185
1181
resource_defns = stack.t.resource_definitions(stack)
1188
1184
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
1191
def create_router_interface(self, t, stack, resource_name, properties={}):
1187
def create_router_interface(self, t, stack, resource_name,
1189
properties = properties or {}
1192
1190
t['Resources'][resource_name]['Properties'] = properties
1193
1191
resource_defns = stack.t.resource_definitions(stack)
1194
1192
rsrc = router.RouterInterface(
1199
1197
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
1202
def create_gateway_router(self, t, stack, resource_name, properties={}):
1200
def create_gateway_router(self, t, stack, resource_name, properties=None):
1201
properties = properties or {}
1203
1202
t['Resources'][resource_name]['Properties'] = properties
1204
1203
resource_defns = stack.t.resource_definitions(stack)
1205
1204
rsrc = router.RouterGateway(
1213
1212
def test_router(self):
1214
clients.OpenStackClients.keystone().AndReturn(
1215
fakes.FakeKeystoneClient())
1216
1213
neutronclient.Client.create_router({
1218
1215
'name': utils.PhysName('test_stack', 'router'),
1357
1354
self.assertEqual('3e21026f2dc94372b105808c0e721661',
1358
1355
rsrc.FnGetAtt('tenant_id'))
1361
"Type": "OS::Neutron::Router",
1363
"admin_state_up": False,
1365
"l3_agent_id": "63b3fd83-2c5f-4dad-b3ae-e0f83a40f216"
1369
1358
"admin_state_up": False,
1370
1359
"name": "myrouter",
1371
1360
"l3_agent_id": "63b3fd83-2c5f-4dad-b3ae-e0f83a40f216"
1362
props = copy.copy(rsrc.properties.data)
1363
props.update(prop_diff)
1364
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
1373
1366
rsrc.handle_update(update_snippet, {}, prop_diff)
1375
1368
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
1393
1386
self._test_router_interface(resolve_neutron=False)
1395
1388
def _test_router_interface(self, resolve_neutron=True):
1396
clients.OpenStackClients.keystone().AndReturn(
1397
fakes.FakeKeystoneClient())
1398
1389
neutronclient.Client.add_interface_router(
1399
1390
'3e46229d-8fce-4733-819a-b5fe630550f8',
1400
1391
{'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'}
1434
1425
self.m.VerifyAll()
1436
1427
def test_router_interface_with_old_data(self):
1437
clients.OpenStackClients.keystone().AndReturn(
1438
fakes.FakeKeystoneClient())
1439
1428
neutronclient.Client.add_interface_router(
1440
1429
'3e46229d-8fce-4733-819a-b5fe630550f8',
1441
1430
{'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'}
1472
1461
self.m.VerifyAll()
1474
1463
def test_router_interface_with_port_id(self):
1475
clients.OpenStackClients.keystone().AndReturn(
1476
fakes.FakeKeystoneClient())
1477
1464
neutronclient.Client.add_interface_router(
1478
1465
'ae478782-53c0-4434-ab16-49900c88016c',
1479
1466
{'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'}
1546
1533
def test_gateway_router(self):
1547
clients.OpenStackClients.keystone().AndReturn(
1548
fakes.FakeKeystoneClient())
1549
1534
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
1550
1535
mox.IsA(neutronclient.Client),
1577
1562
self.m.VerifyAll()
1579
1564
def _create_router_with_gateway(self):
1580
clients.OpenStackClients.keystone().AndReturn(
1581
fakes.FakeKeystoneClient())
1583
1565
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
1584
1566
mox.IsA(neutronclient.Client),
1659
1641
self.m.VerifyAll()
1661
1643
def test_create_router_gateway_enable_snat(self):
1662
clients.OpenStackClients.keystone().AndReturn(
1663
fakes.FakeKeystoneClient())
1665
1644
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
1666
1645
mox.IsA(neutronclient.Client),
1794
1773
self.m.VerifyAll()
1797
@skipIf(neutronclient is None, 'neutronclient unavailable')
1798
1776
class NeutronFloatingIPTest(HeatTestCase):
1800
@skipIf(net.clients.neutronclient is None, "Missing Neutron Client")
1801
1778
def setUp(self):
1802
1779
super(NeutronFloatingIPTest, self).setUp()
1803
1780
self.m.StubOutWithMock(neutronclient.Client, 'create_floatingip')
1810
1787
self.m.StubOutWithMock(neutronclient.Client, 'show_port')
1811
1788
self.m.StubOutWithMock(neutron_utils.neutronV20,
1812
1789
'find_resourceid_by_name_or_id')
1813
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
1790
self.stub_keystoneclient()
1815
1792
def test_floating_ip(self):
1816
1793
self._test_floating_ip()
1819
1796
self._test_floating_ip(resolve_neutron=False)
1821
1798
def _test_floating_ip(self, resolve_neutron=True):
1823
clients.OpenStackClients.keystone().AndReturn(
1824
fakes.FakeKeystoneClient())
1825
1799
neutronclient.Client.create_floatingip({
1826
1800
'floatingip': {'floating_network_id': u'abcd1234'}
1827
1801
}).AndReturn({'floatingip': {
1967
1938
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766',
1971
"Type": "OS::Neutron::Port",
1973
"network": "xyz1234",
1975
"subnet_id": "sub1234",
1976
"ip_address": "10.0.0.11"
1978
"name": "test_port",
1979
"device_id": "d6b4d3a5-c700-476f-b609-1493dd9dadc2",
1980
'device_owner': 'network:floatingip'
1942
"network": "xyz1234",
1944
"subnet_id": "sub1234",
1945
"ip_address": "10.0.0.11"
1947
"name": "test_port",
1948
"device_id": "d6b4d3a5-c700-476f-b609-1493dd9dadc2",
1949
'device_owner': 'network:floatingip'
1951
update_snippet = rsrc_defn.ResourceDefinition(p.name, p.type(), props)
1984
1953
p.handle_update(update_snippet, {}, {})
1986
1955
self.m.VerifyAll()
1988
1957
def test_floatip_port(self):
1990
clients.OpenStackClients.keystone().AndReturn(
1991
fakes.FakeKeystoneClient())
1992
1958
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
1993
1959
mox.IsA(neutronclient.Client),
2139
2105
self.assertEqual('%s:%s' % (fip_id, port_id), fipa_id)
2141
2107
# test update FloatingIpAssociation with port_id
2142
update_snippet = copy.deepcopy(fipa.parsed_template())
2108
props = copy.deepcopy(fipa.properties.data)
2143
2109
update_port_id = '2146dfbf-ba77-4083-8e86-d052f671ece5'
2144
update_snippet['Properties']['port_id'] = update_port_id
2110
props['port_id'] = update_port_id
2111
update_snippet = rsrc_defn.ResourceDefinition(fipa.name, fipa.type(),
2112
stack.t.parse(stack,
2146
2115
scheduler.TaskRunner(fipa.update, update_snippet)()
2147
2116
self.assertEqual((fipa.UPDATE, fipa.COMPLETE), fipa.state)
2149
2118
# test update FloatingIpAssociation with floatingip_id
2150
update_snippet = copy.deepcopy(fipa.parsed_template())
2119
props = copy.deepcopy(fipa.properties.data)
2151
2120
update_flip_id = '2146dfbf-ba77-4083-8e86-d052f671ece5'
2152
update_snippet['Properties']['floatingip_id'] = update_flip_id
2121
props['floatingip_id'] = update_flip_id
2122
update_snippet = rsrc_defn.ResourceDefinition(fipa.name, fipa.type(),
2154
2125
scheduler.TaskRunner(fipa.update, update_snippet)()
2155
2126
self.assertEqual((fipa.UPDATE, fipa.COMPLETE), fipa.state)
2157
2128
# test update FloatingIpAssociation with port_id and floatingip_id
2158
update_snippet = copy.deepcopy(fipa.parsed_template())
2129
props = copy.deepcopy(fipa.properties.data)
2159
2130
update_flip_id = 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
2160
2131
update_port_id = 'ade6fcac-7d47-416e-a3d7-ad12efe445c1'
2161
update_snippet['Properties']['floatingip_id'] = update_flip_id
2162
update_snippet['Properties']['port_id'] = update_port_id
2132
props['floatingip_id'] = update_flip_id
2133
props['port_id'] = update_port_id
2134
update_snippet = rsrc_defn.ResourceDefinition(fipa.name, fipa.type(),
2164
2137
scheduler.TaskRunner(fipa.update, update_snippet)()
2165
2138
self.assertEqual((fipa.UPDATE, fipa.COMPLETE), fipa.state)
2179
2152
self.m.VerifyAll()
2182
@skipIf(neutronclient is None, 'neutronclient unavailable')
2183
2155
class NeutronPortTest(HeatTestCase):
2185
@skipIf(net.clients.neutronclient is None, "Missing Neutron Client")
2186
2157
def setUp(self):
2187
2158
super(NeutronPortTest, self).setUp()
2188
2159
self.m.StubOutWithMock(neutronclient.Client, 'create_port')
2189
2160
self.m.StubOutWithMock(neutronclient.Client, 'show_port')
2161
self.m.StubOutWithMock(neutronclient.Client, 'update_port')
2190
2162
self.m.StubOutWithMock(neutron_utils.neutronV20,
2191
2163
'find_resourceid_by_name_or_id')
2192
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
2164
self.stub_keystoneclient()
2194
2166
def test_missing_subnet_id(self):
2195
clients.OpenStackClients.keystone().AndReturn(
2196
fakes.FakeKeystoneClient())
2197
2167
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
2198
2168
mox.IsA(neutronclient.Client),
2230
2200
self.m.VerifyAll()
2232
2202
def test_missing_ip_address(self):
2233
clients.OpenStackClients.keystone().AndReturn(
2234
fakes.FakeKeystoneClient())
2235
2203
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
2236
2204
mox.IsA(neutronclient.Client),
2273
2241
self.m.VerifyAll()
2275
2243
def test_missing_fixed_ips(self):
2276
clients.OpenStackClients.keystone().AndReturn(
2277
fakes.FakeKeystoneClient())
2278
2244
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
2279
2245
mox.IsA(neutronclient.Client),
2311
2277
self.m.VerifyAll()
2313
2279
def test_allowed_address_pair(self):
2314
clients.OpenStackClients.keystone().AndReturn(
2315
fakes.FakeKeystoneClient())
2316
2280
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
2317
2281
mox.IsA(neutronclient.Client),
2347
2311
self.m.VerifyAll()
2349
2313
def test_missing_mac_address(self):
2350
clients.OpenStackClients.keystone().AndReturn(
2351
fakes.FakeKeystoneClient())
2352
2314
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
2353
2315
mox.IsA(neutronclient.Client),
2385
2347
self.m.VerifyAll()
2387
2349
def test_security_groups(self):
2388
clients.OpenStackClients.keystone().AndReturn(
2389
fakes.FakeKeystoneClient())
2390
2350
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
2391
2351
mox.IsA(neutronclient.Client),
2432
2392
self.m.VerifyAll()
2435
@skipIf(neutronclient is None, 'neutronclient unavailable')
2394
def test_create_and_update_port(self):
2395
props = {'network_id': u'net1234',
2396
'name': utils.PhysName('test_stack', 'port'),
2397
'admin_state_up': True,
2398
'device_owner': u'network:dhcp'}
2399
new_props = props.copy()
2400
new_props['name'] = "new_name"
2401
new_props_update = new_props.copy()
2402
new_props_update.pop('network_id')
2404
neutron_utils.neutronV20.find_resourceid_by_name_or_id(
2405
mox.IsA(neutronclient.Client),
2408
).AndReturn('net1234')
2409
neutronclient.Client.create_port(
2411
).AndReturn({'port': {
2413
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766"
2415
neutronclient.Client.show_port(
2416
'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
2417
).AndReturn({'port': {
2419
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766",
2421
"subnet_id": "d0e971a6-a6b4-4f4c-8c88-b75e9c120b7e",
2422
"ip_address": "10.0.0.2"
2425
neutronclient.Client.update_port(
2426
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
2427
{'port': new_props_update}
2433
t = template_format.parse(neutron_port_template)
2434
t['Resources']['port']['Properties'].pop('fixed_ips')
2435
stack = utils.parse_stack(t)
2437
port = stack['port']
2438
scheduler.TaskRunner(port.create)()
2441
update_snippet = rsrc_defn.ResourceDefinition(port.name, port.type(),
2443
self.assertIsNone(port.handle_update(update_snippet, {}, {}))
2436
2448
class NetworkConstraintTest(HeatTestCase):
2438
2450
def test_validate(self):
2439
self.m.StubOutWithMock(clients.OpenStackClients, 'neutron')
2440
clients.OpenStackClients.neutron().MultipleTimes().AndReturn(None)
2451
self.m.StubOutWithMock(neutron.NeutronClientPlugin, '_create')
2452
neutron.NeutronClientPlugin._create().MultipleTimes().AndReturn(None)
2441
2453
self.m.StubOutWithMock(net.neutronV20, 'find_resourceid_by_name_or_id')
2442
2454
net.neutronV20.find_resourceid_by_name_or_id(
2443
2455
None, 'network', 'foo'