Implement parallel delete

This is first patch in the series to implement parallel delete
and it includes following changes:

1. changing Stack.delete to use stack_task
2. In Resource.delete polling for check_delete_complete
3. Updating unit tests to use TaskRunner for resource.delete and
   resource.destroy

Blueprint parallel-delete

Change-Id: I8a96b1a956388372c29f9f45445f397467667110
This commit is contained in:
Vijendar Komalla 2013-08-29 08:59:46 -05:00
parent 9a46d0a330
commit 49d414e445
18 changed files with 111 additions and 89 deletions

View File

@ -481,30 +481,34 @@ class Stack(object):
"Invalid action %s" % action)
return
stack_status = self.COMPLETE
reason = 'Stack %s completed successfully' % action.lower()
self.state_set(action, self.IN_PROGRESS, 'Stack %s started' % action)
failures = []
backup_stack = self._backup_stack(False)
if backup_stack is not None:
backup_stack.delete()
if backup_stack.status != backup_stack.COMPLETE:
errs = backup_stack.status_reason
failures.append('Error deleting backup resources: %s' % errs)
failure = 'Error deleting backup resources: %s' % errs
self.state_set(action, self.FAILED,
'Failed to %s : %s' % (action, failure))
return
for res in reversed(self):
try:
res.destroy()
except exception.ResourceFailure as ex:
logger.error('Failed to delete %s error: %s' % (str(res),
str(ex)))
failures.append(str(res))
action_task = scheduler.DependencyTaskGroup(self.dependencies,
resource.Resource.destroy,
reverse=True)
try:
scheduler.TaskRunner(action_task)(timeout=self.timeout_secs())
except exception.ResourceFailure as ex:
stack_status = self.FAILED
reason = 'Resource %s failed: %s' % (action.lower(), str(ex))
except scheduler.Timeout:
stack_status = self.FAILED
reason = '%s timed out' % action.title()
if failures:
self.state_set(action, self.FAILED,
'Failed to %s : %s' % (action, ', '.join(failures)))
else:
self.state_set(action, self.COMPLETE, '%s completed' % action)
self.state_set(action, stack_status, reason)
if stack_status != self.FAILED:
db_api.stack_delete(self.context, self.id)
self.id = None
@ -553,7 +557,7 @@ class Stack(object):
for res in reversed(deps):
try:
res.destroy()
scheduler.TaskRunner(res.destroy)()
except exception.ResourceFailure as ex:
failed = True
logger.error('delete: %s' % str(ex))

View File

@ -22,6 +22,7 @@ from heat.openstack.common import excutils
from heat.db import api as db_api
from heat.common import identifier
from heat.common import short_id
from heat.engine import scheduler
from heat.engine import resources
from heat.engine import timestamp
# import class to avoid name collisions and ugly aliasing
@ -515,12 +516,21 @@ class Resource(object):
self.state_set(action, self.IN_PROGRESS)
deletion_policy = self.t.get('DeletionPolicy', 'Delete')
handle_data = None
if deletion_policy == 'Delete':
if callable(getattr(self, 'handle_delete', None)):
self.handle_delete()
handle_data = self.handle_delete()
yield
elif deletion_policy == 'Snapshot':
if callable(getattr(self, 'handle_snapshot_delete', None)):
self.handle_snapshot_delete(initial_state)
handle_data = self.handle_snapshot_delete(initial_state)
yield
if (deletion_policy != 'Retain' and
callable(getattr(self, 'check_delete_complete', None))):
while not self.check_delete_complete(handle_data):
yield
except Exception as ex:
logger.exception('Delete %s', str(self))
failure = exception.ResourceFailure(ex, self, self.action)
@ -536,11 +546,12 @@ class Resource(object):
else:
self.state_set(action, self.COMPLETE)
@scheduler.wrappertask
def destroy(self):
'''
Delete the resource and remove it from the database.
'''
self.delete()
yield self.delete()
if self.id is None:
return

View File

@ -92,7 +92,7 @@ class CloudWatchAlarmTest(HeatTestCase):
scheduler.TaskRunner(rsrc.update, snippet)()
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_mem_alarm_high_update_replace(self):
@ -119,7 +119,7 @@ class CloudWatchAlarmTest(HeatTestCase):
updater = scheduler.TaskRunner(rsrc.update, snippet)
self.assertRaises(resource.UpdateReplace, updater)
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_suspend_resume(self):
@ -146,5 +146,5 @@ class CloudWatchAlarmTest(HeatTestCase):
self.assertEqual(wr.state, watchrule.WatchRule.NODATA)
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()

View File

@ -181,7 +181,7 @@ class EIPTest(HeatTestCase):
rsrc.FnGetAtt, 'Foo')
finally:
rsrc.destroy()
scheduler.TaskRunner(rsrc.destroy)()
self.m.VerifyAll()
@ -200,8 +200,8 @@ class EIPTest(HeatTestCase):
# TODO(sbaker), figure out why this is an empty string
#self.assertEqual('', association.FnGetRefId())
association.delete()
rsrc.delete()
scheduler.TaskRunner(association.delete)()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -420,7 +420,7 @@ class AllocTest(HeatTestCase):
rsrc.FnGetAtt, 'Foo')
finally:
rsrc.destroy()
scheduler.TaskRunner(rsrc.destroy)()
self.m.VerifyAll()
@ -448,7 +448,7 @@ class AllocTest(HeatTestCase):
rsrc = self.create_eip(t, stack, 'the_eip')
association = self.create_association(t, stack, 'IPAssoc')
association.delete()
rsrc.delete()
scheduler.TaskRunner(association.delete)()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()

View File

@ -295,7 +295,7 @@ class InstancesTest(HeatTestCase):
get().AndRaise(instances.clients.novaclient.exceptions.NotFound(404))
mox.Replay(get)
instance.delete()
scheduler.TaskRunner(instance.delete)()
self.assertTrue(instance.resource_id is None)
self.assertEqual(instance.state, (instance.DELETE, instance.COMPLETE))
self.m.VerifyAll()

View File

@ -259,7 +259,8 @@ class WaitCondMetadataUpdateTest(HeatTestCase):
scheduler.TaskRunner._sleep(mox.IsA(int)).WithSideEffects(check_empty)
scheduler.TaskRunner._sleep(mox.IsA(int)).WithSideEffects(post_success)
scheduler.TaskRunner._sleep(mox.IsA(int)).AndReturn(None)
scheduler.TaskRunner._sleep(mox.IsA(int)).MultipleTimes().AndReturn(
None)
self.m.ReplayAll()
self.stack.create()

View File

@ -519,7 +519,7 @@ class NeutronSubnetTest(HeatTestCase):
ref_id = rsrc.FnGetRefId()
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
self.assertEqual(False, rsrc.FnGetAtt('enable_dhcp'))
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -698,9 +698,9 @@ class NeutronRouterTest(HeatTestCase):
'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'
})
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_gateway_router(self):
@ -731,9 +731,9 @@ class NeutronRouterTest(HeatTestCase):
'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
})
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -808,9 +808,9 @@ class NeutronFloatingIPTest(HeatTestCase):
fip.FnGetAtt('id'))
self.assertRaises(resource.UpdateReplace,
fip.handle_update, {}, {}, {})
self.assertEqual(fip.delete(), None)
scheduler.TaskRunner(fip.delete)()
fip.state_set(fip.CREATE, fip.COMPLETE, 'to delete again')
self.assertEqual(fip.delete(), None)
scheduler.TaskRunner(fip.delete)()
self.m.VerifyAll()
@ -976,16 +976,16 @@ class NeutronFloatingIPTest(HeatTestCase):
self.assertRaises(resource.UpdateReplace,
fipa.handle_update, {}, {}, {})
self.assertEqual(fipa.delete(), None)
self.assertEqual(scheduler.TaskRunner(p.delete)(), None)
self.assertEqual(fip.delete(), None)
scheduler.TaskRunner(fipa.delete)()
scheduler.TaskRunner(p.delete)()
scheduler.TaskRunner(fip.delete)()
fipa.state_set(fipa.CREATE, fipa.COMPLETE, 'to delete again')
fip.state_set(fip.CREATE, fip.COMPLETE, 'to delete again')
p.state_set(p.CREATE, p.COMPLETE, 'to delete again')
self.assertEqual(fipa.delete(), None)
scheduler.TaskRunner(fipa.delete)()
self.assertEqual(scheduler.TaskRunner(p.delete)(), None)
self.assertEqual(fip.delete(), None)
scheduler.TaskRunner(fip.delete)()
self.m.VerifyAll()

View File

@ -300,7 +300,7 @@ class RackspaceCloudServerTest(HeatTestCase):
get().AndRaise(novaclient.exceptions.NotFound(404))
mox.Replay(get)
cs.delete()
scheduler.TaskRunner(cs.delete)()
self.assertTrue(cs.resource_id is None)
self.assertEqual(cs.state, (cs.DELETE, cs.COMPLETE))
self.m.VerifyAll()

View File

@ -319,7 +319,7 @@ class ResourceTest(HeatTestCase):
res.id = 'test_res_id'
(res.action, res.status) = (res.INIT, res.DELETE)
self.assertRaises(exception.ResourceFailure, res.create)
res.destroy()
scheduler.TaskRunner(res.destroy)()
res.state_reset()
scheduler.TaskRunner(res.create)()
self.assertEqual((res.CREATE, res.COMPLETE), res.state)

View File

@ -116,7 +116,7 @@ class s3Test(HeatTestCase):
self.assertRaises(resource.UpdateReplace,
rsrc.handle_update, {}, {}, {})
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_public_read(self):
@ -136,7 +136,7 @@ class s3Test(HeatTestCase):
properties['AccessControl'] = 'PublicRead'
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'S3Bucket')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_public_read_write(self):
@ -156,7 +156,7 @@ class s3Test(HeatTestCase):
properties['AccessControl'] = 'PublicReadWrite'
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'S3Bucket')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_authenticated_read(self):
@ -175,7 +175,7 @@ class s3Test(HeatTestCase):
properties['AccessControl'] = 'AuthenticatedRead'
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'S3Bucket')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_website(self):
@ -194,7 +194,7 @@ class s3Test(HeatTestCase):
t = template_format.parse(swift_template)
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'S3BucketWebsite')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_delete_exception(self):
@ -212,7 +212,7 @@ class s3Test(HeatTestCase):
t = template_format.parse(swift_template)
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'S3Bucket')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -233,7 +233,7 @@ class s3Test(HeatTestCase):
bucket['DeletionPolicy'] = 'Retain'
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'S3Bucket')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
self.m.VerifyAll()

View File

@ -19,6 +19,7 @@ from heat.common import exception
from heat.common import template_format
from heat.engine import parser
from heat.engine import resource
from heat.engine import scheduler
from heat.tests.common import HeatTestCase
from heat.tests.fakes import FakeKeystoneClient
from heat.tests.v1_1 import fakes
@ -359,7 +360,7 @@ Resources:
self.assertResourceState(sg, utils.PhysName('test_stack', 'the_sg'))
self.assertEqual(None, sg.delete())
scheduler.TaskRunner(sg.delete)()
sg.state_set(sg.CREATE, sg.COMPLETE, 'to delete again')
sg.resource_id = 2
@ -797,7 +798,7 @@ Resources:
self.assertResourceState(sg, 'aaaa')
self.assertEqual(None, sg.delete())
scheduler.TaskRunner(sg.delete)()
sg.state_set(sg.CREATE, sg.COMPLETE, 'to delete again')
sg.resource_id = 'aaaa'

View File

@ -334,13 +334,13 @@ class ServersTest(HeatTestCase):
get().AndRaise(servers.clients.novaclient.exceptions.NotFound(404))
mox.Replay(get)
server.delete()
scheduler.TaskRunner(server.delete)()
self.assertTrue(server.resource_id is None)
self.assertEqual(server.state, (server.DELETE, server.COMPLETE))
self.m.VerifyAll()
server.state_set(server.CREATE, server.COMPLETE, 'to delete again')
server.delete()
scheduler.TaskRunner(server.delete)()
self.assertEqual(server.state, (server.DELETE, server.COMPLETE))
self.m.VerifyAll()

View File

@ -20,6 +20,7 @@ from heat.common import exception
from heat.common import template_format
from heat.engine.resources import instance as instances
from heat.engine import parser
from heat.engine import scheduler
from heat.openstack.common import uuidutils
from heat.tests.common import HeatTestCase
from heat.tests import utils
@ -136,7 +137,7 @@ class SqlAlchemyTest(HeatTestCase):
self.assertNotEqual(encrypted_key, "fake secret")
decrypted_key = cs.my_secret
self.assertEqual(decrypted_key, "fake secret")
cs.destroy()
scheduler.TaskRunner(cs.destroy)()
def test_resource_data_delete(self):
stack = self._setup_test_stack('stack', UUID1)[1]

View File

@ -160,7 +160,7 @@ class swiftTest(HeatTestCase):
self.assertRaises(resource.UpdateReplace,
rsrc.handle_update, {}, {}, {})
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_public_read(self):
@ -179,7 +179,7 @@ class swiftTest(HeatTestCase):
properties['X-Container-Read'] = '.r:*'
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'SwiftContainer')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_public_read_write(self):
@ -199,7 +199,7 @@ class swiftTest(HeatTestCase):
properties['X-Container-Write'] = '.r:*'
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'SwiftContainer')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_website(self):
@ -218,7 +218,7 @@ class swiftTest(HeatTestCase):
t = template_format.parse(swift_template)
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'SwiftContainerWebsite')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_delete_exception(self):
@ -236,7 +236,7 @@ class swiftTest(HeatTestCase):
t = template_format.parse(swift_template)
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'SwiftContainer')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -257,7 +257,7 @@ class swiftTest(HeatTestCase):
container['DeletionPolicy'] = 'Retain'
stack = utils.parse_stack(t)
rsrc = self.create_resource(t, stack, 'SwiftContainer')
rsrc.delete()
scheduler.TaskRunner(rsrc.delete)()
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
self.m.VerifyAll()

View File

@ -129,20 +129,20 @@ class UserTest(UserPolicyTestCase):
self.assertEqual(None, rsrc.handle_resume())
rsrc.resource_id = None
self.assertEqual(None, rsrc.delete())
scheduler.TaskRunner(rsrc.delete)()
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
rsrc.resource_id = self.fc.access
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE)
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
self.assertEqual(None, rsrc.delete())
scheduler.TaskRunner(rsrc.delete)()
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE)
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
self.assertEqual(None, rsrc.delete())
scheduler.TaskRunner(rsrc.delete)()
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
self.m.VerifyAll()
@ -303,7 +303,7 @@ class AccessKeyTest(UserPolicyTestCase):
self.assertRaises(exception.InvalidTemplateAttribute,
rsrc.FnGetAtt, 'Foo')
self.assertEqual(None, rsrc.delete())
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_access_key_deleted(self):
@ -326,7 +326,7 @@ class AccessKeyTest(UserPolicyTestCase):
self.fc.delete_ec2_keypair(self.fc.user_id,
rsrc.resource_id).AndRaise(NotFound('Gone'))
self.m.ReplayAll()
self.assertEqual(None, rsrc.delete())
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -346,7 +346,7 @@ class AccessKeyTest(UserPolicyTestCase):
self.assertRaises(exception.ResourceFailure, create)
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
self.assertEqual(None, rsrc.delete())
scheduler.TaskRunner(rsrc.delete)()
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
self.m.VerifyAll()

View File

@ -146,13 +146,14 @@ class VolumeTest(HeatTestCase):
rsrc.handle_update, {}, {}, {})
fv.status = 'in-use'
self.assertRaises(exception.ResourceFailure, rsrc.destroy)
self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(rsrc.destroy))
fv.status = 'available'
self.assertEqual(rsrc.destroy(), None)
scheduler.TaskRunner(rsrc.destroy)()
# Test when volume already deleted
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE)
self.assertEqual(rsrc.destroy(), None)
scheduler.TaskRunner(rsrc.destroy)()
self.m.VerifyAll()
@ -194,7 +195,7 @@ class VolumeTest(HeatTestCase):
scheduler.TaskRunner(stack.create)()
self.assertEqual(rsrc.state, (rsrc.CREATE, rsrc.COMPLETE))
self.assertEqual(stack.delete(), None)
scheduler.TaskRunner(stack.delete)()
self.m.VerifyAll()
@ -271,7 +272,7 @@ class VolumeTest(HeatTestCase):
self.assertRaises(resource.UpdateReplace,
rsrc.handle_update, {}, {}, {})
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -317,7 +318,7 @@ class VolumeTest(HeatTestCase):
self.assertRaises(resource.UpdateReplace,
rsrc.handle_update, {}, {}, {})
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -343,7 +344,7 @@ class VolumeTest(HeatTestCase):
scheduler.TaskRunner(stack['DataVolume'].create)()
rsrc = self.create_attachment(t, stack, 'MountPoint')
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -373,7 +374,7 @@ class VolumeTest(HeatTestCase):
self.assertEqual(fv.status, 'available')
rsrc = self.create_attachment(t, stack, 'MountPoint')
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
@ -428,7 +429,7 @@ class VolumeTest(HeatTestCase):
rsrc = self.create_volume(t, stack, 'DataVolume')
self.assertEqual(rsrc.destroy(), None)
scheduler.TaskRunner(rsrc.destroy)()
self.m.VerifyAll()
@ -452,7 +453,8 @@ class VolumeTest(HeatTestCase):
rsrc = self.create_volume(t, stack, 'DataVolume')
self.assertRaises(exception.ResourceFailure, rsrc.destroy)
self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(rsrc.destroy))
self.m.VerifyAll()
@ -479,7 +481,7 @@ class VolumeTest(HeatTestCase):
create = scheduler.TaskRunner(rsrc.create)
self.assertRaises(exception.ResourceFailure, create)
self.assertEqual(rsrc.destroy(), None)
scheduler.TaskRunner(rsrc.destroy)()
self.m.VerifyAll()
@ -713,7 +715,7 @@ class VolumeTest(HeatTestCase):
self.assertRaises(resource.UpdateReplace, rsrc.handle_update,
{}, {}, {})
self.assertEqual(rsrc.delete(), None)
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()

View File

@ -19,6 +19,7 @@ from heat.common import template_format
from heat.engine import parser
from heat.engine import clients
from heat.engine import resource
from heat.engine import scheduler
from heat.tests.common import HeatTestCase
from heat.tests import fakes
from heat.tests import utils
@ -363,7 +364,7 @@ Resources:
self.assertRaises(resource.UpdateReplace,
vpc.handle_update, {}, {}, {})
self.assertEqual(None, vpc.delete())
scheduler.TaskRunner(vpc.delete)()
self.m.VerifyAll()
@ -414,10 +415,10 @@ Resources:
self.assertEqual('moon', subnet.FnGetAtt('AvailabilityZone'))
self.assertEqual(None, subnet.delete())
scheduler.TaskRunner(subnet.delete)()
subnet.state_set(subnet.CREATE, subnet.COMPLETE, 'to delete again')
self.assertEqual(None, subnet.delete())
self.assertEqual(None, stack['the_vpc'].delete())
scheduler.TaskRunner(subnet.delete)()
scheduler.TaskRunner(stack['the_vpc'].delete)()
self.m.VerifyAll()
@ -584,7 +585,7 @@ Resources:
rsrc.handle_update, {}, {}, {})
finally:
stack.delete()
scheduler.TaskRunner(stack.delete)()
self.m.VerifyAll()
@ -679,6 +680,7 @@ Resources:
self.mock_show_subnet()
self.mock_show_security_group(group='INVALID-NO-REF')
self.mock_delete_subnet()
neutronclient.Client.delete_port(None).AndReturn(None)
self.mock_delete_network()
self.m.ReplayAll()
@ -691,7 +693,7 @@ Resources:
reason = rsrc.status_reason
self.assertTrue(reason.startswith('InvalidTemplateAttribute:'))
finally:
stack.delete()
scheduler.TaskRunner(stack.delete)()
self.m.VerifyAll()
@ -837,8 +839,8 @@ Resources:
resource.UpdateReplace,
association.handle_update, {}, {}, {})
association.delete()
route_table.delete()
scheduler.TaskRunner(association.delete)()
scheduler.TaskRunner(route_table.delete)()
stack.delete()
self.m.VerifyAll()

View File

@ -216,7 +216,7 @@ class WaitConditionTest(HeatTestCase):
# Avoid the stack create exercising the timeout code at the same time
self.m.StubOutWithMock(self.stack, 'timeout_secs')
self.stack.timeout_secs().AndReturn(None)
self.stack.timeout_secs().MultipleTimes().AndReturn(None)
self.m.StubOutWithMock(scheduler, 'wallclock')