From 55460600b5ce7345d1aae32d6fb8b228912862a6 Mon Sep 17 00:00:00 2001 From: huangtianhua Date: Fri, 19 Sep 2014 11:56:18 +0800 Subject: [PATCH] Fix subnet residue when resource deletion Should set resource_id immediately after creating subnet successful, otherwise the subnet resource will residue when deletion. Change-Id: I7974272d6a4b394775d971e2636bd1d4d5b78562 Closes-bug: #1370973 --- heat/engine/resources/subnet.py | 5 +++- heat/tests/test_vpc.py | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/heat/engine/resources/subnet.py b/heat/engine/resources/subnet.py index 287bcbe9f..d36f14d2d 100644 --- a/heat/engine/resources/subnet.py +++ b/heat/engine/resources/subnet.py @@ -91,15 +91,18 @@ class Subnet(resource.Resource): 'ip_version': 4 } subnet = client.create_subnet({'subnet': props})['subnet'] + self.resource_id_set(subnet['id']) router = VPC.router_for_vpc(self.neutron(), network_id) if router: client.add_interface_router( router['id'], {'subnet_id': subnet['id']}) - self.resource_id_set(subnet['id']) def handle_delete(self): + if self.resource_id is None: + return + client = self.neutron() network_id = self.properties.get(self.VPC_ID) subnet_id = self.resource_id diff --git a/heat/tests/test_vpc.py b/heat/tests/test_vpc.py index c1a08a494..a65c29217 100644 --- a/heat/tests/test_vpc.py +++ b/heat/tests/test_vpc.py @@ -11,9 +11,12 @@ # License for the specific language governing permissions and limitations # under the License. +import uuid + from heat.common import exception from heat.common import template_format from heat.engine import parser +from heat.engine.resources import subnet as sn from heat.engine import scheduler from heat.engine import template from heat.tests.common import HeatTestCase @@ -428,6 +431,49 @@ Resources: scheduler.TaskRunner(stack['the_vpc'].delete)() self.m.VerifyAll() + def _mock_create_subnet_failed(self): + self.subnet_name = utils.PhysName('test_stack', 'the_subnet') + neutronclient.Client.create_subnet( + {'subnet': { + 'network_id': u'aaaa', + 'cidr': u'10.0.0.0/24', + 'ip_version': 4, + 'name': self.subnet_name}}).AndReturn({ + 'subnet': { + 'status': 'ACTIVE', + 'name': self.subnet_name, + 'admin_state_up': True, + 'tenant_id': 'c1210485b2424d48804aad5d39c61b8f', + 'id': 'cccc'}}) + + neutronclient.Client.show_network( + 'aaaa' + ).MultipleTimes().AndRaise(NeutronClientException(status_code=404)) + + def test_create_failed_delete_success(self): + self._mock_create_subnet_failed() + neutronclient.Client.delete_subnet('cccc').AndReturn(None) + self.m.ReplayAll() + + t = template_format.parse(self.test_template) + tmpl = parser.Template(t) + stack = parser.Stack(utils.dummy_context(), 'test_subnet_', tmpl, + stack_id=str(uuid.uuid4())) + tmpl.t['Resources']['the_subnet']['Properties']['VpcId'] = 'aaaa' + resource_defns = tmpl.resource_definitions(stack) + rsrc = sn.Subnet('the_subnet', + resource_defns['the_subnet'], + stack) + rsrc.validate() + self.assertRaises(exception.ResourceFailure, + scheduler.TaskRunner(rsrc.create)) + self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) + ref_id = rsrc.FnGetRefId() + self.assertEqual(u'cccc', ref_id) + self.assertIsNone(scheduler.TaskRunner(rsrc.delete)()) + self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) + self.m.VerifyAll() + class NetworkInterfaceTest(VPCTestBase):