# # 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 from neutronclient.common import exceptions as qe from neutronclient.v2_0 import client as neutronclient from heat.common import exception from heat.common import template_format from heat.engine.resources.openstack.neutron import net 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 network Neutron resource resources: network: type: OS::Neutron::Net properties: name: the_network tenant_id: c1210485b2424d48804aad5d39c61b8f shared: true dhcp_agent_ids: - 28c25a04-3f73-45a7-a2b4-59e183943ddc port_security_enabled: False subnet: type: OS::Neutron::Subnet properties: network: { get_resource: network } tenant_id: c1210485b2424d48804aad5d39c61b8f ip_version: 4 cidr: 10.0.3.0/24 allocation_pools: - start: 10.0.3.20 end: 10.0.3.150 host_routes: - destination: 10.0.4.0/24 nexthop: 10.0.3.20 dns_nameservers: - 8.8.8.8 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: { get_resource : subnet } gateway: type: OS::Neutron::RouterGateway properties: router_id: { get_resource : router } network: { get_resource : network } ''' class NeutronNetTest(common.HeatTestCase): def setUp(self): super(NeutronNetTest, self).setUp() self.m.StubOutWithMock(neutronclient.Client, 'create_network') self.m.StubOutWithMock(neutronclient.Client, 'delete_network') self.m.StubOutWithMock(neutronclient.Client, 'show_network') self.m.StubOutWithMock(neutronclient.Client, 'update_network') self.m.StubOutWithMock(neutronclient.Client, 'add_network_to_dhcp_agent') self.m.StubOutWithMock(neutronclient.Client, 'remove_network_from_dhcp_agent') self.m.StubOutWithMock(neutronclient.Client, 'list_dhcp_agent_hosting_networks') def create_net(self, t, stack, resource_name): resource_defns = stack.t.resource_definitions(stack) rsrc = net.Net('test_net', resource_defns[resource_name], stack) scheduler.TaskRunner(rsrc.create)() self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) return rsrc def test_net(self): # Create script neutronclient.Client.create_network({ 'network': { 'name': u'the_network', 'admin_state_up': True, 'tenant_id': 'c1210485b2424d48804aad5d39c61b8f', 'port_security_enabled': False, 'shared': True} }).AndReturn({"network": { "status": "BUILD", "subnets": [], "name": "name", "admin_state_up": True, "shared": True, "tenant_id": "c1210485b2424d48804aad5d39c61b8f", "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766", "mtu": 0 }}) neutronclient.Client.list_dhcp_agent_hosting_networks( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn({"agents": []}) neutronclient.Client.add_network_to_dhcp_agent( '28c25a04-3f73-45a7-a2b4-59e183943ddc', {'network_id': u'fc68ea2c-b60b-4b4f-bd82-94ec81110766'} ).AndReturn(None) neutronclient.Client.show_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn({"network": { "status": "BUILD", "subnets": [], "name": "name", "admin_state_up": True, "shared": True, "tenant_id": "c1210485b2424d48804aad5d39c61b8f", "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766", "mtu": 0 }}) neutronclient.Client.show_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn({"network": { "status": "ACTIVE", "subnets": [], "name": "name", "admin_state_up": True, "shared": True, "tenant_id": "c1210485b2424d48804aad5d39c61b8f", "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766", "mtu": 0 }}) neutronclient.Client.show_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndRaise(qe.NetworkNotFoundClient(status_code=404)) neutronclient.Client.show_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn({"network": { "status": "ACTIVE", "subnets": [], "name": "name", "admin_state_up": True, "shared": True, "tenant_id": "c1210485b2424d48804aad5d39c61b8f", "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766", "mtu": 0 }}) neutronclient.Client.show_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn({"network": { "status": "ACTIVE", "subnets": [], "name": "name", "admin_state_up": True, "shared": True, "tenant_id": "c1210485b2424d48804aad5d39c61b8f", "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766", "mtu": 0 }}) # Update script neutronclient.Client.list_dhcp_agent_hosting_networks( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn({ "agents": [{ "admin_state_up": True, "agent_type": "DHCP agent", "alive": True, "binary": "neutron-dhcp-agent", "configurations": { "dhcp_driver": "DummyDriver", "dhcp_lease_duration": 86400, "networks": 0, "ports": 0, "subnets": 0, "use_namespaces": True}, "created_at": "2014-03-20 05:12:34", "description": None, "heartbeat_timestamp": "2014-03-20 05:12:34", "host": "hostname", "id": "28c25a04-3f73-45a7-a2b4-59e183943ddc", "started_at": "2014-03-20 05:12:34", "topic": "dhcp_agent" }] }) neutronclient.Client.add_network_to_dhcp_agent( 'bb09cfcd-5277-473d-8336-d4ed8628ae68', {'network_id': u'fc68ea2c-b60b-4b4f-bd82-94ec81110766'} ).AndReturn(None) neutronclient.Client.remove_network_from_dhcp_agent( '28c25a04-3f73-45a7-a2b4-59e183943ddc', 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn(None) neutronclient.Client.update_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', {'network': { 'shared': True, 'name': 'mynet', 'admin_state_up': True, 'port_security_enabled': False }}).AndReturn(None) # Delete script neutronclient.Client.delete_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn(None) neutronclient.Client.show_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndRaise(qe.NetworkNotFoundClient(status_code=404)) neutronclient.Client.delete_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndRaise(qe.NetworkNotFoundClient(status_code=404)) self.m.ReplayAll() t = template_format.parse(neutron_template) stack = utils.parse_stack(t) rsrc = self.create_net(t, stack, 'network') # assert the implicit dependency between the gateway and the interface deps = stack.dependencies[stack['router_interface']] self.assertIn(stack['gateway'], deps) # assert the implicit dependency between the gateway and the subnet deps = stack.dependencies[stack['subnet']] self.assertIn(stack['gateway'], deps) rsrc.validate() ref_id = rsrc.FnGetRefId() self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id) self.assertIsNone(rsrc.FnGetAtt('status')) self.assertEqual('ACTIVE', rsrc.FnGetAtt('status')) self.assertEqual(0, rsrc.FnGetAtt('mtu')) self.assertRaises( exception.InvalidTemplateAttribute, rsrc.FnGetAtt, 'Foo') prop_diff = { "name": "mynet", "dhcp_agent_ids": [ "bb09cfcd-5277-473d-8336-d4ed8628ae68" ] } 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) scheduler.TaskRunner(rsrc.delete)() rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again') scheduler.TaskRunner(rsrc.delete)() self.m.VerifyAll()