18
18
from heat.engine import environment
19
19
from heat.common import exception
20
20
from heat.common import template_format
21
from heat.common import urlfetch
21
22
from heat.engine import clients
22
23
from heat.engine import resource
23
24
from heat.engine import parser
519
520
parent_resource.metadata = '{"foo": "bar"}'
520
521
parent_resource.t = {'DeletionPolicy': 'Retain',
521
522
'UpdatePolicy': '{"foo": "bar"}'}
523
parent_resource.stack = parser.Stack(self.ctx, 'toplevel_stack',
522
525
stack = parser.Stack(self.ctx, 'test_stack',
523
526
parser.Template({}),
524
527
parent_resource=parent_resource)
548
551
parent_resource = DummyClass()
549
552
parent_resource.metadata = '{"foo": "bar"}'
550
553
parent_resource.t = {}
554
parent_resource.stack = parser.Stack(self.ctx, 'toplevel_stack',
551
556
stack = parser.Stack(self.ctx, 'test_stack',
552
557
parser.Template({}),
553
558
parent_resource=parent_resource)
582
587
ctx = utils.dummy_context()
583
588
ctx.auth_token = None
584
589
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
585
clients.OpenStackClients.keystone().AndReturn(FakeKeystoneClient())
590
clients.OpenStackClients.keystone().MultipleTimes().AndReturn(
591
FakeKeystoneClient())
587
593
self.m.ReplayAll()
588
594
stack = parser.Stack(ctx, 'test_stack', parser.Template({}))
626
632
self.assertRaises(exception.NotFound, parser.Stack.load,
635
def test_total_resources_empty(self):
636
stack = parser.Stack(self.ctx, 'test_stack', parser.Template({}),
637
status_reason='flimflam')
638
self.assertEqual(0, stack.total_resources())
640
def test_total_resources_generic(self):
642
{'A': {'Type': 'GenericResourceType'}}}
643
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
644
status_reason='blarg')
645
self.assertEqual(1, stack.total_resources())
647
def _setup_nested(self, name):
648
nested_tpl = ('{"Resources":{'
649
'"A": {"Type": "GenericResourceType"},'
650
'"B": {"Type": "GenericResourceType"}}}')
652
{'A': {'Type': 'AWS::CloudFormation::Stack',
654
{'TemplateURL': 'http://server.test/nested.json'}},
655
'B': {'Type': 'GenericResourceType'}}}
656
self.m.StubOutWithMock(urlfetch, 'get')
657
urlfetch.get('http://server.test/nested.json').AndReturn(nested_tpl)
659
self.stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
664
@utils.stack_delete_after
665
def test_total_resources_nested(self):
666
self._setup_nested('zyzzyx')
667
self.assertEqual(4, self.stack.total_resources())
668
self.assertNotEqual(None, self.stack.resources['A'].nested())
670
2, self.stack.resources['A'].nested().total_resources())
673
self.stack.resources['A'].nested().root_stack.total_resources())
675
@utils.stack_delete_after
676
def test_root_stack(self):
677
self._setup_nested('toor')
678
self.assertEqual(self.stack, self.stack.root_stack)
679
self.assertNotEqual(None, self.stack.resources['A'].nested())
681
self.stack, self.stack.resources['A'].nested().root_stack)
629
683
@utils.stack_delete_after
630
684
def test_load_parent_resource(self):
631
685
self.stack = parser.Stack(self.ctx, 'load_parent_resource',
914
968
rsrc = self.stack['AResource']
915
969
rsrc.resource_id_set('aaaa')
916
970
self.assertNotEqual(None, resource)
917
self.assertEqual(rsrc, self.stack.resource_by_refid('aaaa'))
972
for action, status in (
973
(rsrc.CREATE, rsrc.IN_PROGRESS),
974
(rsrc.CREATE, rsrc.COMPLETE),
975
(rsrc.RESUME, rsrc.IN_PROGRESS),
976
(rsrc.RESUME, rsrc.COMPLETE),
977
(rsrc.UPDATE, rsrc.IN_PROGRESS),
978
(rsrc.UPDATE, rsrc.COMPLETE)):
979
rsrc.state_set(action, status)
980
self.assertEqual(rsrc, self.stack.resource_by_refid('aaaa'))
919
982
rsrc.state_set(rsrc.DELETE, rsrc.IN_PROGRESS)
1567
1630
self.m.VerifyAll()
1632
def test_stack_delete_timeout(self):
1633
stack = parser.Stack(self.ctx, 'delete_test',
1634
parser.Template({}))
1635
stack_id = stack.store()
1637
db_s = db_api.stack_get(self.ctx, stack_id)
1638
self.assertNotEqual(db_s, None)
1640
self.m.StubOutWithMock(scheduler.DependencyTaskGroup, '__call__')
1641
self.m.StubOutWithMock(scheduler, 'wallclock')
1647
start_time = time.time()
1648
scheduler.wallclock().AndReturn(start_time)
1649
scheduler.wallclock().AndReturn(start_time + 1)
1650
scheduler.DependencyTaskGroup.__call__().AndReturn(dummy_task())
1651
scheduler.wallclock().AndReturn(start_time + stack.timeout_secs() + 1)
1655
self.assertEqual(stack.state,
1656
(parser.Stack.DELETE, parser.Stack.FAILED))
1657
self.assertEqual(stack.status_reason, 'Delete timed out')
1661
def test_stack_delete_resourcefailure(self):
1662
tmpl = {'Resources': {'AResource': {'Type': 'GenericResourceType'}}}
1663
self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_delete')
1664
exc = Exception('foo')
1665
generic_rsrc.GenericResource.handle_delete().AndRaise(exc)
1668
self.stack = parser.Stack(self.ctx, 'delete_test_fail',
1669
parser.Template(tmpl))
1671
stack_id = self.stack.store()
1673
self.assertEqual(self.stack.state,
1674
(self.stack.CREATE, self.stack.COMPLETE))
1678
self.assertEqual(self.stack.state,
1679
(self.stack.DELETE, self.stack.FAILED))
1680
self.assertEqual(self.stack.status_reason,
1681
'Resource delete failed: Exception: foo')
1569
1684
def test_stack_name_valid(self):
1570
1685
stack = parser.Stack(self.ctx, 's', parser.Template({}))
1571
1686
stack = parser.Stack(self.ctx, 'stack123', parser.Template({}))
1631
1746
for action, status in (
1632
1747
(rsrc.CREATE, rsrc.IN_PROGRESS),
1633
1748
(rsrc.CREATE, rsrc.COMPLETE),
1749
(rsrc.RESUME, rsrc.IN_PROGRESS),
1750
(rsrc.RESUME, rsrc.COMPLETE),
1634
1751
(rsrc.UPDATE, rsrc.IN_PROGRESS),
1635
1752
(rsrc.UPDATE, rsrc.COMPLETE)):
1636
1753
rsrc.state_set(action, status)
1718
1835
saved_stack = parser.Stack.load(self.ctx, stack_id=stack_ownee.id)
1719
1836
self.assertEqual(saved_stack.owner_id, self.stack.id)
1838
@utils.stack_delete_after
1839
def test_requires_deferred_auth(self):
1840
tmpl = {'Resources': {'AResource': {'Type': 'GenericResourceType'},
1841
'BResource': {'Type': 'GenericResourceType'},
1842
'CResource': {'Type': 'GenericResourceType'}}}
1844
self.stack = parser.Stack(self.ctx, 'update_test_stack',
1845
template.Template(tmpl),
1846
disable_rollback=False)
1848
self.assertFalse(self.stack.requires_deferred_auth())
1850
self.stack['CResource'].requires_deferred_auth = True
1851
self.assertTrue(self.stack.requires_deferred_auth())