diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-03-31 17:02:57 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-03-31 17:02:57 +0000 |
commit | 051cb7a015f5129bdb405d25b266406a83cd0b27 (patch) | |
tree | 99cc8634630e74d8f3509a0eff1aa3cb7a03d724 | |
parent | e1fe38f8cd14dad746418ef2a2a0fe358ada0877 (diff) | |
parent | ca070c73752d890243a003d39251e14480b9531a (diff) | |
download | heat-051cb7a015f5129bdb405d25b266406a83cd0b27.tar.gz |
Merge "Move router tests to separate file"
-rw-r--r-- | heat/tests/neutron/test_neutron_resources.py | 838 | ||||
-rw-r--r-- | heat/tests/neutron/test_neutron_router.py | 866 |
2 files changed, 866 insertions, 838 deletions
diff --git a/heat/tests/neutron/test_neutron_resources.py b/heat/tests/neutron/test_neutron_resources.py index ecf89a6e7..efe71db39 100644 --- a/heat/tests/neutron/test_neutron_resources.py +++ b/heat/tests/neutron/test_neutron_resources.py @@ -24,7 +24,6 @@ from heat.common import template_format from heat.engine.cfn import functions as cfn_funcs from heat.engine.resources.openstack.neutron import net from heat.engine.resources.openstack.neutron import provider_net -from heat.engine.resources.openstack.neutron import router from heat.engine.resources.openstack.neutron import subnet from heat.engine import rsrc_defn from heat.engine import scheduler @@ -212,78 +211,6 @@ provider_network_template = ''' } ''' -neutron_external_gateway_template = ''' -{ - "AWSTemplateFormatVersion" : "2010-09-09", - "Description" : "Template to test Neutron resources", - "Parameters" : {}, - "Resources" : { - "router": { - "Type": "OS::Neutron::Router", - "Properties": { - "name": "Test Router", - "external_gateway_info": { - "network": "public", - "enable_snat": true - } - } - } - } -} -''' - -neutron_subnet_and_external_gateway_template = ''' -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Resources": { - "net_external": { - "Type": "OS::Neutron::Net", - "Properties": { - "name": "net_external", - "admin_state_up": true, - "value_specs": { - "provider:network_type": "flat", - "provider:physical_network": "default", - "router:external": true - } - } - }, - "subnet_external": { - "Type": "OS::Neutron::Subnet", - "Properties": { - "name": "subnet_external", - "network_id": { - "Ref": "net_external" - }, - "ip_version": 4, - "cidr": "192.168.10.0/24", - "gateway_ip": "192.168.10.11", - "enable_dhcp": false - } - }, - "floating_ip": { - "Type": "OS::Neutron::FloatingIP", - "Properties": { - "floating_network": { - "Ref": "net_external" - }, - } - }, - "router": { - "Type": "OS::Neutron::Router", - "Properties": { - "name": "router_heat", - "external_gateway_info": { - "network": { - "Ref": "net_external" - } - } - } - } - } -} -''' - stpna = { "network": { "status": "ACTIVE", @@ -1004,768 +931,3 @@ class NeutronSubnetTest(common.HeatTestCase): rsrc.validate) self.assertEqual("ipv6_ra_mode and ipv6_address_mode are not " "supported for ipv4.", six.text_type(ex)) - - -class NeutronRouterTest(common.HeatTestCase): - - def setUp(self): - super(NeutronRouterTest, self).setUp() - self.m.StubOutWithMock(neutronclient.Client, 'create_router') - self.m.StubOutWithMock(neutronclient.Client, 'delete_router') - self.m.StubOutWithMock(neutronclient.Client, 'show_router') - self.m.StubOutWithMock(neutronclient.Client, 'update_router') - self.m.StubOutWithMock(neutronclient.Client, 'add_interface_router') - self.m.StubOutWithMock(neutronclient.Client, 'remove_interface_router') - self.m.StubOutWithMock(neutronclient.Client, 'add_gateway_router') - self.m.StubOutWithMock(neutronclient.Client, 'remove_gateway_router') - self.m.StubOutWithMock(neutronclient.Client, - 'add_router_to_l3_agent') - self.m.StubOutWithMock(neutronclient.Client, - 'remove_router_from_l3_agent') - self.m.StubOutWithMock(neutronclient.Client, - 'list_l3_agent_hosting_routers') - self.m.StubOutWithMock(neutronV20, 'find_resourceid_by_name_or_id') - - def create_router(self, t, stack, resource_name): - resource_defns = stack.t.resource_definitions(stack) - rsrc = router.Router('router', resource_defns[resource_name], stack) - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - return rsrc - - def create_router_interface(self, t, stack, resource_name, - properties=None): - properties = properties or {} - t['Resources'][resource_name]['Properties'] = properties - resource_defns = stack.t.resource_definitions(stack) - rsrc = router.RouterInterface( - 'router_interface', - resource_defns[resource_name], - stack) - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - return rsrc - - def create_gateway_router(self, t, stack, resource_name, properties=None): - properties = properties or {} - t['Resources'][resource_name]['Properties'] = properties - resource_defns = stack.t.resource_definitions(stack) - rsrc = router.RouterGateway( - 'gateway', - resource_defns[resource_name], - stack) - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - return rsrc - - def test_router_validate_distribute_l3_agents(self): - t = template_format.parse(neutron_template) - props = t['Resources']['router']['Properties'] - - # test distributed can not specify l3_agent_id - props['distributed'] = True - stack = utils.parse_stack(t) - rsrc = stack['router'] - exc = self.assertRaises(exception.ResourcePropertyConflict, - rsrc.validate) - self.assertIn('distributed, l3_agent_id/l3_agent_ids', - six.text_type(exc)) - # test distributed can not specify l3_agent_ids - props['l3_agent_ids'] = ['id1', 'id2'] - stack = utils.parse_stack(t) - rsrc = stack['router'] - rsrc.t['Properties'].pop('l3_agent_id') - exc = self.assertRaises(exception.ResourcePropertyConflict, - rsrc.validate) - self.assertIn('distributed, l3_agent_id/l3_agent_ids', - six.text_type(exc)) - - def test_router_validate_l3_agents(self): - t = template_format.parse(neutron_template) - props = t['Resources']['router']['Properties'] - - # test l3_agent_id and l3_agent_ids can not specify at the same time - props['l3_agent_ids'] = ['id1', 'id2'] - stack = utils.parse_stack(t) - rsrc = stack['router'] - exc = self.assertRaises(exception.ResourcePropertyConflict, - rsrc.validate) - self.assertIn('l3_agent_id, l3_agent_ids', six.text_type(exc)) - - def test_router_validate_ha_distribute(self): - t = template_format.parse(neutron_template) - props = t['Resources']['router']['Properties'] - - # test distributed and ha can not specify at the same time - props['ha'] = True - props['distributed'] = True - stack = utils.parse_stack(t) - rsrc = stack['router'] - rsrc.t['Properties'].pop('l3_agent_id') - exc = self.assertRaises(exception.ResourcePropertyConflict, - rsrc.validate) - self.assertIn('distributed, ha', six.text_type(exc)) - - def test_router_validate_ha_l3_agents(self): - t = template_format.parse(neutron_template) - props = t['Resources']['router']['Properties'] - # test non ha can not specify more than one l3 agent id - props['ha'] = False - props['l3_agent_ids'] = ['id1', 'id2'] - stack = utils.parse_stack(t) - rsrc = stack['router'] - rsrc.t['Properties'].pop('l3_agent_id') - exc = self.assertRaises(exception.StackValidationFailed, - rsrc.validate) - self.assertIn('Non HA routers can only have one L3 agent.', - six.text_type(exc)) - - def test_router(self): - neutronclient.Client.create_router({ - 'router': { - 'name': utils.PhysName('test_stack', 'router'), - 'admin_state_up': True, - } - }).AndReturn({ - "router": { - "status": "BUILD", - "external_gateway_info": None, - "name": utils.PhysName('test_stack', 'router'), - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "id": "3e46229d-8fce-4733-819a-b5fe630550f8", - } - }) - neutronclient.Client.list_l3_agent_hosting_routers( - u'3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn({"agents": []}) - neutronclient.Client.add_router_to_l3_agent( - u'792ff887-6c85-4a56-b518-23f24fa65581', - {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} - ).AndReturn(None) - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ - "router": { - "status": "BUILD", - "external_gateway_info": None, - "name": utils.PhysName('test_stack', 'router'), - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ - "router": { - "status": "ACTIVE", - "external_gateway_info": None, - "name": utils.PhysName('test_stack', 'router'), - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndRaise( - qe.NeutronClientException(status_code=404)) - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ - "router": { - "status": "ACTIVE", - "external_gateway_info": None, - "name": utils.PhysName('test_stack', 'router'), - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ - "router": { - "status": "ACTIVE", - "external_gateway_info": None, - "name": utils.PhysName('test_stack', 'router'), - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - - # Update script - neutronclient.Client.list_l3_agent_hosting_routers( - u'3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn({ - "agents": [{ - "admin_state_up": True, - "agent_type": "L3 agent", - "alive": True, - "binary": "neutron-l3-agent", - "configurations": { - "ex_gw_ports": 1, - "floating_ips": 0, - "gateway_external_network_id": "", - "handle_internal_only_routers": True, - "interface_driver": "DummyDriver", - "interfaces": 1, - "router_id": "", - "routers": 1, - "use_namespaces": True}, - "created_at": "2014-03-11 05:00:05", - "description": None, - "heartbeat_timestamp": "2014-03-11 05:01:49", - "host": "l3_agent_host", - "id": "792ff887-6c85-4a56-b518-23f24fa65581", - "started_at": "2014-03-11 05:00:05", - "topic": "l3_agent" - }] - }) - neutronclient.Client.remove_router_from_l3_agent( - u'792ff887-6c85-4a56-b518-23f24fa65581', - u'3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn(None) - neutronclient.Client.add_router_to_l3_agent( - u'63b3fd83-2c5f-4dad-b3ae-e0f83a40f216', - {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} - ).AndReturn(None) - neutronclient.Client.update_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'router': { - 'name': 'myrouter', - 'admin_state_up': False - }} - ) - # Update again script - neutronclient.Client.list_l3_agent_hosting_routers( - u'3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn({ - "agents": [{ - "admin_state_up": True, - "agent_type": "L3 agent", - "alive": True, - "binary": "neutron-l3-agent", - "configurations": { - "ex_gw_ports": 1, - "floating_ips": 0, - "gateway_external_network_id": "", - "handle_internal_only_routers": True, - "interface_driver": "DummyDriver", - "interfaces": 1, - "router_id": "", - "routers": 1, - "use_namespaces": True}, - "created_at": "2014-03-11 05:00:05", - "description": None, - "heartbeat_timestamp": "2014-03-11 05:01:49", - "host": "l3_agent_host", - "id": "63b3fd83-2c5f-4dad-b3ae-e0f83a40f216", - "started_at": "2014-03-11 05:00:05", - "topic": "l3_agent" - }] - }) - neutronclient.Client.remove_router_from_l3_agent( - u'63b3fd83-2c5f-4dad-b3ae-e0f83a40f216', - u'3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn(None) - neutronclient.Client.add_router_to_l3_agent( - u'4c692423-2c5f-4dad-b3ae-e2339f58539f', - {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} - ).AndReturn(None) - neutronclient.Client.add_router_to_l3_agent( - u'8363b3fd-2c5f-4dad-b3ae-0f216e0f83a4', - {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} - ).AndReturn(None) - # Delete script - neutronclient.Client.delete_router( - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn(None) - - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndRaise(qe.NeutronClientException(status_code=404)) - - neutronclient.Client.delete_router( - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndRaise(qe.NeutronClientException(status_code=404)) - - self.m.ReplayAll() - t = template_format.parse(neutron_template) - stack = utils.parse_stack(t) - rsrc = self.create_router(t, stack, 'router') - - rsrc.validate() - - ref_id = rsrc.FnGetRefId() - self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8', ref_id) - self.assertIsNone(rsrc.FnGetAtt('tenant_id')) - self.assertEqual('3e21026f2dc94372b105808c0e721661', - rsrc.FnGetAtt('tenant_id')) - - prop_diff = { - "admin_state_up": False, - "name": "myrouter", - "l3_agent_id": "63b3fd83-2c5f-4dad-b3ae-e0f83a40f216" - } - props = copy.copy(rsrc.properties.data) - props.update(prop_diff) - update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), - props) - rsrc.handle_update(update_snippet, {}, prop_diff) - - prop_diff = { - "l3_agent_ids": ["4c692423-2c5f-4dad-b3ae-e2339f58539f", - "8363b3fd-2c5f-4dad-b3ae-0f216e0f83a4"] - } - props = copy.copy(rsrc.properties.data) - props.update(prop_diff) - update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), - props) - rsrc.handle_update(update_snippet, {}, prop_diff) - - self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) - rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') - self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) - self.m.VerifyAll() - - def test_router_dependence(self): - # assert the implicit dependency between the router - # and subnet - t = template_format.parse( - neutron_subnet_and_external_gateway_template) - stack = utils.parse_stack(t) - deps = stack.dependencies[stack['subnet_external']] - self.assertIn(stack['router'], deps) - required_by = set(stack.dependencies.required_by(stack['router'])) - self.assertIn(stack['floating_ip'], required_by) - - def test_router_interface(self): - self._test_router_interface() - - def test_router_interface_depr_router(self): - self._test_router_interface(resolve_router=False) - - def test_router_interface_depr_subnet(self): - self._test_router_interface(resolve_subnet=False) - - def test_router_interface_depr_router_and_subnet(self): - self._test_router_interface(resolve_router=False, resolve_subnet=False) - - def _test_router_interface(self, resolve_subnet=True, - resolve_router=True): - neutronclient.Client.add_interface_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} - ).AndReturn(None) - neutronclient.Client.remove_interface_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} - ).AndReturn(None) - neutronclient.Client.remove_interface_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} - ).AndRaise(qe.NeutronClientException(status_code=404)) - t = template_format.parse(neutron_template) - stack = utils.parse_stack(t) - subnet_key = 'subnet_id' - router_key = 'router_id' - self.stub_SubnetConstraint_validate() - self.stub_RouterConstraint_validate() - if resolve_router: - neutronV20.find_resourceid_by_name_or_id( - mox.IsA(neutronclient.Client), - 'router', - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn('3e46229d-8fce-4733-819a-b5fe630550f8') - router_key = 'router' - if resolve_subnet: - neutronV20.find_resourceid_by_name_or_id( - mox.IsA(neutronclient.Client), - 'subnet', - '91e47a57-7508-46fe-afc9-fc454e8580e1' - ).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1') - subnet_key = 'subnet' - - self.m.ReplayAll() - rsrc = self.create_router_interface( - t, stack, 'router_interface', properties={ - router_key: '3e46229d-8fce-4733-819a-b5fe630550f8', - subnet_key: '91e47a57-7508-46fe-afc9-fc454e8580e1' - }) - scheduler.TaskRunner(rsrc.delete)() - rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') - scheduler.TaskRunner(rsrc.delete)() - self.m.VerifyAll() - - def test_router_interface_with_old_data(self): - self.stub_SubnetConstraint_validate() - self.stub_RouterConstraint_validate() - neutronclient.Client.add_interface_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} - ).AndReturn(None) - neutronclient.Client.remove_interface_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} - ).AndReturn(None) - neutronclient.Client.remove_interface_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} - ).AndRaise(qe.NeutronClientException(status_code=404)) - - self.m.ReplayAll() - t = template_format.parse(neutron_template) - stack = utils.parse_stack(t) - - rsrc = self.create_router_interface( - t, stack, 'router_interface', properties={ - 'router_id': '3e46229d-8fce-4733-819a-b5fe630550f8', - 'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1' - }) - self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8' - ':subnet_id=91e47a57-7508-46fe-afc9-fc454e8580e1', - rsrc.resource_id) - (rsrc.resource_id) = ('3e46229d-8fce-4733-819a-b5fe630550f8:' - '91e47a57-7508-46fe-afc9-fc454e8580e1') - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8' - ':91e47a57-7508-46fe-afc9-fc454e8580e1', - rsrc.resource_id) - rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') - scheduler.TaskRunner(rsrc.delete)() - self.m.VerifyAll() - - def test_router_interface_with_port(self): - self._test_router_interface_with_port() - - def test_router_interface_with_deprecated_port(self): - self._test_router_interface_with_port(resolve_port=False) - - def _test_router_interface_with_port(self, resolve_port=True): - port_key = 'port_id' - neutronclient.Client.add_interface_router( - 'ae478782-53c0-4434-ab16-49900c88016c', - {'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} - ).AndReturn(None) - if resolve_port: - port_key = 'port' - neutronV20.find_resourceid_by_name_or_id( - mox.IsA(neutronclient.Client), - 'port', - '9577cafd-8e98-4059-a2e6-8a771b4d318e' - ).AndReturn('9577cafd-8e98-4059-a2e6-8a771b4d318e') - - neutronclient.Client.remove_interface_router( - 'ae478782-53c0-4434-ab16-49900c88016c', - {'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} - ).AndReturn(None) - neutronclient.Client.remove_interface_router( - 'ae478782-53c0-4434-ab16-49900c88016c', - {'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} - ).AndRaise(qe.NeutronClientException(status_code=404)) - self.stub_PortConstraint_validate() - self.stub_RouterConstraint_validate() - - self.m.ReplayAll() - t = template_format.parse(neutron_template) - stack = utils.parse_stack(t) - - rsrc = self.create_router_interface( - t, stack, 'router_interface', properties={ - 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', - port_key: '9577cafd-8e98-4059-a2e6-8a771b4d318e' - }) - scheduler.TaskRunner(rsrc.delete)() - rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') - scheduler.TaskRunner(rsrc.delete)() - self.m.VerifyAll() - - def test_router_interface_validate(self): - t = template_format.parse(neutron_template) - json = t['Resources']['router_interface'] - json['Properties'] = { - 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', - 'subnet_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e', - 'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} - stack = utils.parse_stack(t) - resource_defns = stack.t.resource_definitions(stack) - res = router.RouterInterface('router_interface', - resource_defns['router_interface'], - stack) - self.assertRaises(exception.ResourcePropertyConflict, res.validate) - json['Properties'] = { - 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', - 'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} - stack = utils.parse_stack(t) - resource_defns = stack.t.resource_definitions(stack) - res = router.RouterInterface('router_interface', - resource_defns['router_interface'], - stack) - self.assertIsNone(res.validate()) - json['Properties'] = { - 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', - 'subnet_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} - stack = utils.parse_stack(t) - resource_defns = stack.t.resource_definitions(stack) - res = router.RouterInterface('router_interface', - resource_defns['router_interface'], - stack) - self.assertIsNone(res.validate()) - json['Properties'] = { - 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c'} - stack = utils.parse_stack(t) - resource_defns = stack.t.resource_definitions(stack) - res = router.RouterInterface('router_interface', - resource_defns['router_interface'], - stack) - ex = self.assertRaises(exception.PropertyUnspecifiedError, - res.validate) - self.assertEqual("At least one of the following properties " - "must be specified: subnet, port", - six.text_type(ex)) - - def test_gateway_router(self): - neutronV20.find_resourceid_by_name_or_id( - mox.IsA(neutronclient.Client), - 'network', - 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' - ).MultipleTimes().AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766') - neutronclient.Client.add_gateway_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'} - ).AndReturn(None) - neutronclient.Client.remove_gateway_router( - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn(None) - neutronclient.Client.remove_gateway_router( - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndRaise(qe.NeutronClientException(status_code=404)) - self.stub_RouterConstraint_validate() - - self.m.ReplayAll() - t = template_format.parse(neutron_template) - stack = utils.parse_stack(t) - - rsrc = self.create_gateway_router( - t, stack, 'gateway', properties={ - 'router_id': '3e46229d-8fce-4733-819a-b5fe630550f8', - 'network': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' - }) - - scheduler.TaskRunner(rsrc.delete)() - rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') - scheduler.TaskRunner(rsrc.delete)() - self.m.VerifyAll() - - def _create_router_with_gateway(self): - neutronV20.find_resourceid_by_name_or_id( - mox.IsA(neutronclient.Client), - 'network', - 'public' - ).MultipleTimes().AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766') - - neutronclient.Client.create_router({ - "router": { - "name": "Test Router", - "external_gateway_info": { - 'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', - 'enable_snat': True - }, - "admin_state_up": True, - } - }).AndReturn({ - "router": { - "status": "BUILD", - "external_gateway_info": None, - "name": "Test Router", - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "id": "3e46229d-8fce-4733-819a-b5fe630550f8", - } - }) - - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ - "router": { - "status": "ACTIVE", - "external_gateway_info": { - "network_id": - "fc68ea2c-b60b-4b4f-bd82-94ec81110766", - "enable_snat": True - }, - "name": "Test Router", - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - - def test_create_router_gateway_as_property(self): - self._create_router_with_gateway() - - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ - "router": { - "status": "ACTIVE", - "external_gateway_info": { - "network_id": - "fc68ea2c-b60b-4b4f-bd82-94ec81110766", - "enable_snat": True - }, - "name": "Test Router", - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - - self.m.ReplayAll() - t = template_format.parse(neutron_external_gateway_template) - stack = utils.parse_stack(t) - rsrc = self.create_router(t, stack, 'router') - - rsrc.validate() - - ref_id = rsrc.FnGetRefId() - self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8', ref_id) - gateway_info = rsrc.FnGetAtt('external_gateway_info') - self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', - gateway_info.get('network_id')) - self.assertTrue(gateway_info.get('enable_snat')) - self.m.VerifyAll() - - def test_create_router_gateway_enable_snat(self): - neutronV20.find_resourceid_by_name_or_id( - mox.IsA(neutronclient.Client), - 'network', - 'public' - ).AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766') - - neutronclient.Client.create_router({ - "router": { - "name": "Test Router", - "external_gateway_info": { - 'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', - }, - "admin_state_up": True, - } - }).AndReturn({ - "router": { - "status": "BUILD", - "external_gateway_info": None, - "name": "Test Router", - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "id": "3e46229d-8fce-4733-819a-b5fe630550f8", - } - }) - - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').MultipleTimes().AndReturn({ - "router": { - "status": "ACTIVE", - "external_gateway_info": { - "network_id": - "fc68ea2c-b60b-4b4f-bd82-94ec81110766", - "enable_snat": True - }, - "name": "Test Router", - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - - self.m.ReplayAll() - t = template_format.parse(neutron_external_gateway_template) - t["Resources"]["router"]["Properties"]["external_gateway_info"].pop( - "enable_snat") - stack = utils.parse_stack(t) - rsrc = self.create_router(t, stack, 'router') - - rsrc.validate() - - ref_id = rsrc.FnGetRefId() - self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8', ref_id) - gateway_info = rsrc.FnGetAtt('external_gateway_info') - self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', - gateway_info.get('network_id')) - self.m.VerifyAll() - - def test_update_router_gateway_as_property(self): - self._create_router_with_gateway() - - neutronV20.find_resourceid_by_name_or_id( - mox.IsA(neutronclient.Client), - 'network', - 'other_public' - ).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1') - - neutronclient.Client.update_router( - '3e46229d-8fce-4733-819a-b5fe630550f8', - {'router': { - "name": "Test Router", - "external_gateway_info": { - 'network_id': '91e47a57-7508-46fe-afc9-fc454e8580e1', - 'enable_snat': False - }, - "admin_state_up": True}} - ).AndReturn(None) - - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ - "router": { - "status": "ACTIVE", - "external_gateway_info": { - "network_id": "91e47a57-7508-46fe-afc9-fc454e8580e1", - "enable_snat": False - }, - "name": "Test Router", - "admin_state_up": True, - "tenant_id": "3e21026f2dc94372b105808c0e721661", - "routes": [], - "id": "3e46229d-8fce-4733-819a-b5fe630550f8" - } - }) - - self.m.ReplayAll() - t = template_format.parse(neutron_external_gateway_template) - stack = utils.parse_stack(t) - rsrc = self.create_router(t, stack, 'router') - - update_template = copy.deepcopy(rsrc.t) - update_template['Properties']['external_gateway_info'] = { - "network": "other_public", - "enable_snat": False - } - scheduler.TaskRunner(rsrc.update, update_template)() - self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state) - - gateway_info = rsrc.FnGetAtt('external_gateway_info') - self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', - gateway_info.get('network_id')) - self.assertFalse(gateway_info.get('enable_snat')) - - self.m.VerifyAll() - - def test_delete_router_gateway_as_property(self): - self._create_router_with_gateway() - neutronclient.Client.delete_router( - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndReturn(None) - - neutronclient.Client.show_router( - '3e46229d-8fce-4733-819a-b5fe630550f8' - ).AndRaise(qe.NeutronClientException(status_code=404)) - - self.m.ReplayAll() - t = template_format.parse(neutron_external_gateway_template) - stack = utils.parse_stack(t) - rsrc = self.create_router(t, stack, 'router') - self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) - self.m.VerifyAll() diff --git a/heat/tests/neutron/test_neutron_router.py b/heat/tests/neutron/test_neutron_router.py new file mode 100644 index 000000000..232e42103 --- /dev/null +++ b/heat/tests/neutron/test_neutron_router.py @@ -0,0 +1,866 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import copy + +import mox +from neutronclient.common import exceptions as qe +from neutronclient.neutron import v2_0 as neutronV20 +from neutronclient.v2_0 import client as neutronclient +import six + +from heat.common import exception +from heat.common import template_format +from heat.engine.resources.openstack.neutron import router +from heat.engine import rsrc_defn +from heat.engine import scheduler +from heat.tests import common +from heat.tests import utils + + +neutron_template = ''' +heat_template_version: 2015-04-30 +description: Template to test router related Neutron resources +resources: + router: + type: OS::Neutron::Router + properties: + l3_agent_id: 792ff887-6c85-4a56-b518-23f24fa65581 + + router_interface: + type: OS::Neutron::RouterInterface + properties: + router_id: { get_resource: router } + subnet: sub1234 + + gateway: + type: OS::Neutron::RouterGateway + properties: + router_id: { get_resource: router } + network: net1234 +''' + +neutron_external_gateway_template = ''' +heat_template_version: 2015-04-30 +description: Template to test gateway Neutron resource +resources: + router: + type: OS::Neutron::Router + properties: + name: Test Router + external_gateway_info: + network: public + enable_snat: true +''' + +neutron_subnet_and_external_gateway_template = ''' +heat_template_version: 2015-04-30 +description: Template to test gateway Neutron resource +resources: + net_external: + type: OS::Neutron::Net + properties: + name: net_external + admin_state_up: true + value_specs: + provider:network_type: flat + provider:physical_network: default + router:external: true + + subnet_external: + type: OS::Neutron::Subnet + properties: + name: subnet_external + network_id: { get_resource: net_external} + ip_version: 4 + cidr: 192.168.10.0/24 + gateway_ip: 192.168.10.11 + enable_dhcp: false + + floating_ip: + type: OS::Neutron::FloatingIP + properties: + floating_network: { get_resource: net_external} + + router: + type: OS::Neutron::Router + properties: + name: router_heat + external_gateway_info: + network: { get_resource: net_external} +''' + + +class NeutronRouterTest(common.HeatTestCase): + + def setUp(self): + super(NeutronRouterTest, self).setUp() + self.m.StubOutWithMock(neutronclient.Client, 'create_router') + self.m.StubOutWithMock(neutronclient.Client, 'delete_router') + self.m.StubOutWithMock(neutronclient.Client, 'show_router') + self.m.StubOutWithMock(neutronclient.Client, 'update_router') + self.m.StubOutWithMock(neutronclient.Client, 'add_interface_router') + self.m.StubOutWithMock(neutronclient.Client, 'remove_interface_router') + self.m.StubOutWithMock(neutronclient.Client, 'add_gateway_router') + self.m.StubOutWithMock(neutronclient.Client, 'remove_gateway_router') + self.m.StubOutWithMock(neutronclient.Client, + 'add_router_to_l3_agent') + self.m.StubOutWithMock(neutronclient.Client, + 'remove_router_from_l3_agent') + self.m.StubOutWithMock(neutronclient.Client, + 'list_l3_agent_hosting_routers') + self.m.StubOutWithMock(neutronV20, 'find_resourceid_by_name_or_id') + + def create_router(self, t, stack, resource_name): + resource_defns = stack.t.resource_definitions(stack) + rsrc = router.Router('router', resource_defns[resource_name], stack) + scheduler.TaskRunner(rsrc.create)() + self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) + return rsrc + + def create_router_interface(self, t, stack, resource_name, + properties=None): + properties = properties or {} + t['resources'][resource_name]['properties'] = properties + resource_defns = stack.t.resource_definitions(stack) + rsrc = router.RouterInterface( + 'router_interface', + resource_defns[resource_name], + stack) + scheduler.TaskRunner(rsrc.create)() + self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) + return rsrc + + def create_gateway_router(self, t, stack, resource_name, properties=None): + properties = properties or {} + t['resources'][resource_name]['properties'] = properties + resource_defns = stack.t.resource_definitions(stack) + rsrc = router.RouterGateway( + 'gateway', + resource_defns[resource_name], + stack) + scheduler.TaskRunner(rsrc.create)() + self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) + return rsrc + + def test_router_validate_distribute_l3_agents(self): + t = template_format.parse(neutron_template) + props = t['resources']['router']['properties'] + + # test distributed can not specify l3_agent_id + props['distributed'] = True + stack = utils.parse_stack(t) + rsrc = stack['router'] + exc = self.assertRaises(exception.ResourcePropertyConflict, + rsrc.validate) + self.assertIn('distributed, l3_agent_id/l3_agent_ids', + six.text_type(exc)) + # test distributed can not specify l3_agent_ids + props['l3_agent_ids'] = ['id1', 'id2'] + stack = utils.parse_stack(t) + rsrc = stack['router'] + rsrc.t['Properties'].pop('l3_agent_id') + exc = self.assertRaises(exception.ResourcePropertyConflict, + rsrc.validate) + self.assertIn('distributed, l3_agent_id/l3_agent_ids', + six.text_type(exc)) + + def test_router_validate_l3_agents(self): + t = template_format.parse(neutron_template) + props = t['resources']['router']['properties'] + + # test l3_agent_id and l3_agent_ids can not specify at the same time + props['l3_agent_ids'] = ['id1', 'id2'] + stack = utils.parse_stack(t) + rsrc = stack['router'] + exc = self.assertRaises(exception.ResourcePropertyConflict, + rsrc.validate) + self.assertIn('l3_agent_id, l3_agent_ids', six.text_type(exc)) + + def test_router_validate_ha_distribute(self): + t = template_format.parse(neutron_template) + props = t['resources']['router']['properties'] + + # test distributed and ha can not specify at the same time + props['ha'] = True + props['distributed'] = True + stack = utils.parse_stack(t) + rsrc = stack['router'] + rsrc.t['Properties'].pop('l3_agent_id') + exc = self.assertRaises(exception.ResourcePropertyConflict, + rsrc.validate) + self.assertIn('distributed, ha', six.text_type(exc)) + + def test_router_validate_ha_l3_agents(self): + t = template_format.parse(neutron_template) + props = t['resources']['router']['properties'] + # test non ha can not specify more than one l3 agent id + props['ha'] = False + props['l3_agent_ids'] = ['id1', 'id2'] + stack = utils.parse_stack(t) + rsrc = stack['router'] + rsrc.t['Properties'].pop('l3_agent_id') + exc = self.assertRaises(exception.StackValidationFailed, + rsrc.validate) + self.assertIn('Non HA routers can only have one L3 agent.', + six.text_type(exc)) + + def test_router(self): + neutronclient.Client.create_router({ + 'router': { + 'name': utils.PhysName('test_stack', 'router'), + 'admin_state_up': True, + } + }).AndReturn({ + "router": { + "status": "BUILD", + "external_gateway_info": None, + "name": utils.PhysName('test_stack', 'router'), + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "id": "3e46229d-8fce-4733-819a-b5fe630550f8", + } + }) + neutronclient.Client.list_l3_agent_hosting_routers( + u'3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn({"agents": []}) + neutronclient.Client.add_router_to_l3_agent( + u'792ff887-6c85-4a56-b518-23f24fa65581', + {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} + ).AndReturn(None) + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ + "router": { + "status": "BUILD", + "external_gateway_info": None, + "name": utils.PhysName('test_stack', 'router'), + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ + "router": { + "status": "ACTIVE", + "external_gateway_info": None, + "name": utils.PhysName('test_stack', 'router'), + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndRaise( + qe.NeutronClientException(status_code=404)) + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ + "router": { + "status": "ACTIVE", + "external_gateway_info": None, + "name": utils.PhysName('test_stack', 'router'), + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ + "router": { + "status": "ACTIVE", + "external_gateway_info": None, + "name": utils.PhysName('test_stack', 'router'), + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + + # Update script + neutronclient.Client.list_l3_agent_hosting_routers( + u'3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn({ + "agents": [{ + "admin_state_up": True, + "agent_type": "L3 agent", + "alive": True, + "binary": "neutron-l3-agent", + "configurations": { + "ex_gw_ports": 1, + "floating_ips": 0, + "gateway_external_network_id": "", + "handle_internal_only_routers": True, + "interface_driver": "DummyDriver", + "interfaces": 1, + "router_id": "", + "routers": 1, + "use_namespaces": True}, + "created_at": "2014-03-11 05:00:05", + "description": None, + "heartbeat_timestamp": "2014-03-11 05:01:49", + "host": "l3_agent_host", + "id": "792ff887-6c85-4a56-b518-23f24fa65581", + "started_at": "2014-03-11 05:00:05", + "topic": "l3_agent" + }] + }) + neutronclient.Client.remove_router_from_l3_agent( + u'792ff887-6c85-4a56-b518-23f24fa65581', + u'3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn(None) + neutronclient.Client.add_router_to_l3_agent( + u'63b3fd83-2c5f-4dad-b3ae-e0f83a40f216', + {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} + ).AndReturn(None) + neutronclient.Client.update_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'router': { + 'name': 'myrouter', + 'admin_state_up': False + }} + ) + # Update again script + neutronclient.Client.list_l3_agent_hosting_routers( + u'3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn({ + "agents": [{ + "admin_state_up": True, + "agent_type": "L3 agent", + "alive": True, + "binary": "neutron-l3-agent", + "configurations": { + "ex_gw_ports": 1, + "floating_ips": 0, + "gateway_external_network_id": "", + "handle_internal_only_routers": True, + "interface_driver": "DummyDriver", + "interfaces": 1, + "router_id": "", + "routers": 1, + "use_namespaces": True}, + "created_at": "2014-03-11 05:00:05", + "description": None, + "heartbeat_timestamp": "2014-03-11 05:01:49", + "host": "l3_agent_host", + "id": "63b3fd83-2c5f-4dad-b3ae-e0f83a40f216", + "started_at": "2014-03-11 05:00:05", + "topic": "l3_agent" + }] + }) + neutronclient.Client.remove_router_from_l3_agent( + u'63b3fd83-2c5f-4dad-b3ae-e0f83a40f216', + u'3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn(None) + neutronclient.Client.add_router_to_l3_agent( + u'4c692423-2c5f-4dad-b3ae-e2339f58539f', + {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} + ).AndReturn(None) + neutronclient.Client.add_router_to_l3_agent( + u'8363b3fd-2c5f-4dad-b3ae-0f216e0f83a4', + {'router_id': u'3e46229d-8fce-4733-819a-b5fe630550f8'} + ).AndReturn(None) + # Delete script + neutronclient.Client.delete_router( + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn(None) + + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndRaise(qe.NeutronClientException(status_code=404)) + + neutronclient.Client.delete_router( + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndRaise(qe.NeutronClientException(status_code=404)) + + self.m.ReplayAll() + t = template_format.parse(neutron_template) + stack = utils.parse_stack(t) + rsrc = self.create_router(t, stack, 'router') + + rsrc.validate() + + ref_id = rsrc.FnGetRefId() + self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8', ref_id) + self.assertIsNone(rsrc.FnGetAtt('tenant_id')) + self.assertEqual('3e21026f2dc94372b105808c0e721661', + rsrc.FnGetAtt('tenant_id')) + + prop_diff = { + "admin_state_up": False, + "name": "myrouter", + "l3_agent_id": "63b3fd83-2c5f-4dad-b3ae-e0f83a40f216" + } + props = copy.copy(rsrc.properties.data) + props.update(prop_diff) + update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), + props) + rsrc.handle_update(update_snippet, {}, prop_diff) + + prop_diff = { + "l3_agent_ids": ["4c692423-2c5f-4dad-b3ae-e2339f58539f", + "8363b3fd-2c5f-4dad-b3ae-0f216e0f83a4"] + } + props = copy.copy(rsrc.properties.data) + props.update(prop_diff) + update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), + props) + rsrc.handle_update(update_snippet, {}, prop_diff) + + self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) + rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') + self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) + self.m.VerifyAll() + + def test_router_dependence(self): + # assert the implicit dependency between the router + # and subnet + t = template_format.parse( + neutron_subnet_and_external_gateway_template) + stack = utils.parse_stack(t) + deps = stack.dependencies[stack['subnet_external']] + self.assertIn(stack['router'], deps) + required_by = set(stack.dependencies.required_by(stack['router'])) + self.assertIn(stack['floating_ip'], required_by) + + def test_router_interface(self): + self._test_router_interface() + + def test_router_interface_depr_router(self): + self._test_router_interface(resolve_router=False) + + def test_router_interface_depr_subnet(self): + self._test_router_interface(resolve_subnet=False) + + def test_router_interface_depr_router_and_subnet(self): + self._test_router_interface(resolve_router=False, resolve_subnet=False) + + def _test_router_interface(self, resolve_subnet=True, + resolve_router=True): + neutronclient.Client.add_interface_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} + ).AndReturn(None) + neutronclient.Client.remove_interface_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} + ).AndReturn(None) + neutronclient.Client.remove_interface_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} + ).AndRaise(qe.NeutronClientException(status_code=404)) + t = template_format.parse(neutron_template) + stack = utils.parse_stack(t) + subnet_key = 'subnet_id' + router_key = 'router_id' + self.stub_SubnetConstraint_validate() + self.stub_RouterConstraint_validate() + if resolve_router: + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'router', + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn('3e46229d-8fce-4733-819a-b5fe630550f8') + router_key = 'router' + if resolve_subnet: + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'subnet', + '91e47a57-7508-46fe-afc9-fc454e8580e1' + ).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1') + subnet_key = 'subnet' + + self.m.ReplayAll() + rsrc = self.create_router_interface( + t, stack, 'router_interface', properties={ + router_key: '3e46229d-8fce-4733-819a-b5fe630550f8', + subnet_key: '91e47a57-7508-46fe-afc9-fc454e8580e1' + }) + scheduler.TaskRunner(rsrc.delete)() + rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') + scheduler.TaskRunner(rsrc.delete)() + self.m.VerifyAll() + + def test_router_interface_with_old_data(self): + self.stub_SubnetConstraint_validate() + self.stub_RouterConstraint_validate() + neutronclient.Client.add_interface_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} + ).AndReturn(None) + neutronclient.Client.remove_interface_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} + ).AndReturn(None) + neutronclient.Client.remove_interface_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} + ).AndRaise(qe.NeutronClientException(status_code=404)) + + self.m.ReplayAll() + t = template_format.parse(neutron_template) + stack = utils.parse_stack(t) + + rsrc = self.create_router_interface( + t, stack, 'router_interface', properties={ + 'router_id': '3e46229d-8fce-4733-819a-b5fe630550f8', + 'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1' + }) + self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8' + ':subnet_id=91e47a57-7508-46fe-afc9-fc454e8580e1', + rsrc.resource_id) + (rsrc.resource_id) = ('3e46229d-8fce-4733-819a-b5fe630550f8:' + '91e47a57-7508-46fe-afc9-fc454e8580e1') + scheduler.TaskRunner(rsrc.delete)() + self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8' + ':91e47a57-7508-46fe-afc9-fc454e8580e1', + rsrc.resource_id) + rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') + scheduler.TaskRunner(rsrc.delete)() + self.m.VerifyAll() + + def test_router_interface_with_port(self): + self._test_router_interface_with_port() + + def test_router_interface_with_deprecated_port(self): + self._test_router_interface_with_port(resolve_port=False) + + def _test_router_interface_with_port(self, resolve_port=True): + port_key = 'port_id' + neutronclient.Client.add_interface_router( + 'ae478782-53c0-4434-ab16-49900c88016c', + {'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} + ).AndReturn(None) + if resolve_port: + port_key = 'port' + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'port', + '9577cafd-8e98-4059-a2e6-8a771b4d318e' + ).AndReturn('9577cafd-8e98-4059-a2e6-8a771b4d318e') + + neutronclient.Client.remove_interface_router( + 'ae478782-53c0-4434-ab16-49900c88016c', + {'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} + ).AndReturn(None) + neutronclient.Client.remove_interface_router( + 'ae478782-53c0-4434-ab16-49900c88016c', + {'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} + ).AndRaise(qe.NeutronClientException(status_code=404)) + self.stub_PortConstraint_validate() + self.stub_RouterConstraint_validate() + + self.m.ReplayAll() + t = template_format.parse(neutron_template) + stack = utils.parse_stack(t) + + rsrc = self.create_router_interface( + t, stack, 'router_interface', properties={ + 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', + port_key: '9577cafd-8e98-4059-a2e6-8a771b4d318e' + }) + scheduler.TaskRunner(rsrc.delete)() + rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') + scheduler.TaskRunner(rsrc.delete)() + self.m.VerifyAll() + + def test_router_interface_validate(self): + t = template_format.parse(neutron_template) + json = t['resources']['router_interface'] + json['properties'] = { + 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', + 'subnet_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e', + 'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} + stack = utils.parse_stack(t) + resource_defns = stack.t.resource_definitions(stack) + res = router.RouterInterface('router_interface', + resource_defns['router_interface'], + stack) + self.assertRaises(exception.ResourcePropertyConflict, res.validate) + json['properties'] = { + 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', + 'port_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} + stack = utils.parse_stack(t) + resource_defns = stack.t.resource_definitions(stack) + res = router.RouterInterface('router_interface', + resource_defns['router_interface'], + stack) + self.assertIsNone(res.validate()) + json['properties'] = { + 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c', + 'subnet_id': '9577cafd-8e98-4059-a2e6-8a771b4d318e'} + stack = utils.parse_stack(t) + resource_defns = stack.t.resource_definitions(stack) + res = router.RouterInterface('router_interface', + resource_defns['router_interface'], + stack) + self.assertIsNone(res.validate()) + json['properties'] = { + 'router_id': 'ae478782-53c0-4434-ab16-49900c88016c'} + stack = utils.parse_stack(t) + resource_defns = stack.t.resource_definitions(stack) + res = router.RouterInterface('router_interface', + resource_defns['router_interface'], + stack) + ex = self.assertRaises(exception.PropertyUnspecifiedError, + res.validate) + self.assertEqual("At least one of the following properties " + "must be specified: subnet, port", + six.text_type(ex)) + + def test_gateway_router(self): + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'network', + 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' + ).MultipleTimes().AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766') + neutronclient.Client.add_gateway_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'} + ).AndReturn(None) + neutronclient.Client.remove_gateway_router( + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn(None) + neutronclient.Client.remove_gateway_router( + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndRaise(qe.NeutronClientException(status_code=404)) + self.stub_RouterConstraint_validate() + + self.m.ReplayAll() + t = template_format.parse(neutron_template) + stack = utils.parse_stack(t) + + rsrc = self.create_gateway_router( + t, stack, 'gateway', properties={ + 'router_id': '3e46229d-8fce-4733-819a-b5fe630550f8', + 'network': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' + }) + + scheduler.TaskRunner(rsrc.delete)() + rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') + scheduler.TaskRunner(rsrc.delete)() + self.m.VerifyAll() + + def _create_router_with_gateway(self): + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'network', + 'public' + ).MultipleTimes().AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766') + + neutronclient.Client.create_router({ + "router": { + "name": "Test Router", + "external_gateway_info": { + 'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', + 'enable_snat': True + }, + "admin_state_up": True, + } + }).AndReturn({ + "router": { + "status": "BUILD", + "external_gateway_info": None, + "name": "Test Router", + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "id": "3e46229d-8fce-4733-819a-b5fe630550f8", + } + }) + + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ + "router": { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": + "fc68ea2c-b60b-4b4f-bd82-94ec81110766", + "enable_snat": True + }, + "name": "Test Router", + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + + def test_create_router_gateway_as_property(self): + self._create_router_with_gateway() + + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ + "router": { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": + "fc68ea2c-b60b-4b4f-bd82-94ec81110766", + "enable_snat": True + }, + "name": "Test Router", + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + + self.m.ReplayAll() + t = template_format.parse(neutron_external_gateway_template) + stack = utils.parse_stack(t) + rsrc = self.create_router(t, stack, 'router') + + rsrc.validate() + + ref_id = rsrc.FnGetRefId() + self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8', ref_id) + gateway_info = rsrc.FnGetAtt('external_gateway_info') + self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', + gateway_info.get('network_id')) + self.assertTrue(gateway_info.get('enable_snat')) + self.m.VerifyAll() + + def test_create_router_gateway_enable_snat(self): + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'network', + 'public' + ).AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766') + + neutronclient.Client.create_router({ + "router": { + "name": "Test Router", + "external_gateway_info": { + 'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', + }, + "admin_state_up": True, + } + }).AndReturn({ + "router": { + "status": "BUILD", + "external_gateway_info": None, + "name": "Test Router", + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "id": "3e46229d-8fce-4733-819a-b5fe630550f8", + } + }) + + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').MultipleTimes().AndReturn({ + "router": { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": + "fc68ea2c-b60b-4b4f-bd82-94ec81110766", + "enable_snat": True + }, + "name": "Test Router", + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + + self.m.ReplayAll() + t = template_format.parse(neutron_external_gateway_template) + t["resources"]["router"]["properties"]["external_gateway_info"].pop( + "enable_snat") + stack = utils.parse_stack(t) + rsrc = self.create_router(t, stack, 'router') + + rsrc.validate() + + ref_id = rsrc.FnGetRefId() + self.assertEqual('3e46229d-8fce-4733-819a-b5fe630550f8', ref_id) + gateway_info = rsrc.FnGetAtt('external_gateway_info') + self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', + gateway_info.get('network_id')) + self.m.VerifyAll() + + def test_update_router_gateway_as_property(self): + self._create_router_with_gateway() + + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'network', + 'other_public' + ).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1') + + neutronclient.Client.update_router( + '3e46229d-8fce-4733-819a-b5fe630550f8', + {'router': { + "name": "Test Router", + "external_gateway_info": { + 'network_id': '91e47a57-7508-46fe-afc9-fc454e8580e1', + 'enable_snat': False + }, + "admin_state_up": True}} + ).AndReturn(None) + + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({ + "router": { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": "91e47a57-7508-46fe-afc9-fc454e8580e1", + "enable_snat": False + }, + "name": "Test Router", + "admin_state_up": True, + "tenant_id": "3e21026f2dc94372b105808c0e721661", + "routes": [], + "id": "3e46229d-8fce-4733-819a-b5fe630550f8" + } + }) + + self.m.ReplayAll() + t = template_format.parse(neutron_external_gateway_template) + stack = utils.parse_stack(t) + rsrc = self.create_router(t, stack, 'router') + + update_template = copy.deepcopy(rsrc.t) + update_template['Properties']['external_gateway_info'] = { + "network": "other_public", + "enable_snat": False + } + scheduler.TaskRunner(rsrc.update, update_template)() + self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state) + + gateway_info = rsrc.FnGetAtt('external_gateway_info') + self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', + gateway_info.get('network_id')) + self.assertFalse(gateway_info.get('enable_snat')) + + self.m.VerifyAll() + + def test_delete_router_gateway_as_property(self): + self._create_router_with_gateway() + neutronclient.Client.delete_router( + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndReturn(None) + + neutronclient.Client.show_router( + '3e46229d-8fce-4733-819a-b5fe630550f8' + ).AndRaise(qe.NeutronClientException(status_code=404)) + + self.m.ReplayAll() + t = template_format.parse(neutron_external_gateway_template) + stack = utils.parse_stack(t) + rsrc = self.create_router(t, stack, 'router') + self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) + self.m.VerifyAll() |