Merge "Convert Stack to separate action/status"

This commit is contained in:
Jenkins 2013-06-19 23:46:08 +00:00 committed by Gerrit Code Review
commit 2ef73ad631
17 changed files with 259 additions and 154 deletions

View File

@ -125,13 +125,16 @@ class StackController(object):
engine_api.STACK_UPDATED_TIME: 'LastUpdatedTime',
engine_api.STACK_ID: 'StackId',
engine_api.STACK_NAME: 'StackName',
engine_api.STACK_STATUS: 'StackStatus',
engine_api.STACK_STATUS_DATA: 'StackStatusReason',
engine_api.STACK_TMPL_DESCRIPTION: 'TemplateDescription',
}
result = api_utils.reformat_dict_keys(keymap, s)
action = s[engine_api.STACK_ACTION]
status = s[engine_api.STACK_STATUS]
result['StackStatus'] = '_'.join((action, status))
# AWS docs indicate DeletionTime is ommitted for current stacks
# This is still TODO(unknown) in the engine, we don't keep data for
# stacks after they are deleted
@ -195,13 +198,16 @@ class StackController(object):
engine_api.STACK_PARAMETERS: 'Parameters',
engine_api.STACK_ID: 'StackId',
engine_api.STACK_NAME: 'StackName',
engine_api.STACK_STATUS: 'StackStatus',
engine_api.STACK_STATUS_DATA: 'StackStatusReason',
engine_api.STACK_TIMEOUT: 'TimeoutInMinutes',
}
result = api_utils.reformat_dict_keys(keymap, s)
action = s[engine_api.STACK_ACTION]
status = s[engine_api.STACK_STATUS]
result['StackStatus'] = '_'.join((action, status))
# Reformat outputs, these are handled separately as they are
# only present in the engine output for a completely created
# stack

View File

@ -152,6 +152,14 @@ def format_stack(req, stack, keys=[]):
if key == engine_api.STACK_ID:
yield ('id', value['stack_id'])
yield ('links', [util.make_link(req, value)])
elif key == engine_api.STACK_ACTION:
return
elif (key == engine_api.STACK_STATUS and
engine_api.STACK_ACTION in stack):
# To avoid breaking API compatibility, we join RES_ACTION
# and RES_STATUS, so the API format doesn't expose the
# internal split of state into action/status
yield (key, '_'.join((stack[engine_api.STACK_ACTION], value)))
else:
# TODO(zaneb): ensure parameters can be formatted for XML
#elif key == engine_api.STACK_PARAMETERS:

View File

@ -0,0 +1,37 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
from sqlalchemy import *
from migrate import *
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
stack = Table('stack', meta, autoload=True)
# Align with action/status now used in the event/resource tables
Column('action', String(length=255,
convert_unicode=False,
assert_unicode=None,
unicode_error=None,
_warn_on_bytestring=False)).create(stack)
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
stack = Table('stack', meta, autoload=True)
stack.c.action.drop()

View File

@ -155,6 +155,7 @@ class Stack(BASE, HeatBase):
raw_template = relationship(RawTemplate, backref=backref('stack'))
username = Column(String)
tenant = Column(String)
action = Column('action', String)
status = Column('status', String)
status_reason = Column('status_reason', String)
parameters = Column('parameters', Json)

View File

@ -76,15 +76,16 @@ def format_stack(stack):
STACK_PARAMETERS: stack.parameters.map(str),
STACK_DESCRIPTION: stack.t[template.DESCRIPTION],
STACK_TMPL_DESCRIPTION: stack.t[template.DESCRIPTION],
STACK_STATUS: stack.state,
STACK_STATUS_DATA: stack.state_description,
STACK_ACTION: stack.action or '',
STACK_STATUS: stack.status or '',
STACK_STATUS_DATA: stack.status_reason,
STACK_CAPABILITIES: [], # TODO Not implemented yet
STACK_DISABLE_ROLLBACK: stack.disable_rollback,
STACK_TIMEOUT: stack.timeout_mins,
}
# only show the outputs on a completely created or updated stack
if stack.state in (stack.CREATE_COMPLETE, stack.UPDATE_COMPLETE):
if (stack.action != stack.DELETE and stack.status == stack.COMPLETE):
info[STACK_OUTPUTS] = format_stack_outputs(stack, stack.outputs)
return info

View File

@ -44,21 +44,8 @@ class Stack(object):
ACTIONS = (CREATE, DELETE, UPDATE, ROLLBACK
) = ('CREATE', 'DELETE', 'UPDATE', 'ROLLBACK')
CREATE_IN_PROGRESS = 'CREATE_IN_PROGRESS'
CREATE_FAILED = 'CREATE_FAILED'
CREATE_COMPLETE = 'CREATE_COMPLETE'
DELETE_IN_PROGRESS = 'DELETE_IN_PROGRESS'
DELETE_FAILED = 'DELETE_FAILED'
DELETE_COMPLETE = 'DELETE_COMPLETE'
UPDATE_IN_PROGRESS = 'UPDATE_IN_PROGRESS'
UPDATE_COMPLETE = 'UPDATE_COMPLETE'
UPDATE_FAILED = 'UPDATE_FAILED'
ROLLBACK_IN_PROGRESS = 'ROLLBACK_IN_PROGRESS'
ROLLBACK_COMPLETE = 'ROLLBACK_COMPLETE'
ROLLBACK_FAILED = 'ROLLBACK_FAILED'
STATUSES = (IN_PROGRESS, FAILED, COMPLETE
) = ('IN_PROGRESS', 'FAILED', 'COMPLETE')
created_time = timestamp.Timestamp(db_api.stack_get, 'created_at')
updated_time = timestamp.Timestamp(db_api.stack_get, 'updated_at')
@ -66,8 +53,9 @@ class Stack(object):
_zones = None
def __init__(self, context, stack_name, tmpl, env=None,
stack_id=None, state=None, state_description='',
timeout_mins=60, resolve_data=True, disable_rollback=True):
stack_id=None, action=None, status=None,
status_reason='', timeout_mins=60, resolve_data=True,
disable_rollback=True):
'''
Initialise from a context, name, Template object and (optionally)
Environment object. The database ID may also be initialised, if the
@ -85,8 +73,9 @@ class Stack(object):
self.clients = Clients(context)
self.t = tmpl
self.name = stack_name
self.state = state
self.state_description = state_description
self.action = action
self.status = status
self.status_reason = status_reason
self.timeout_mins = timeout_mins
self.disable_rollback = disable_rollback
@ -145,8 +134,8 @@ class Stack(object):
template = Template.load(context, stack.raw_template_id)
env = environment.Environment(stack.parameters)
stack = cls(context, stack.name, template, env,
stack.id, stack.status, stack.status_reason, stack.timeout,
resolve_data, stack.disable_rollback)
stack.id, stack.action, stack.status, stack.status_reason,
stack.timeout, resolve_data, stack.disable_rollback)
return stack
@ -165,8 +154,9 @@ class Stack(object):
'user_creds_id': new_creds.id,
'username': self.context.username,
'tenant': self.context.tenant_id,
'status': self.state,
'status_reason': self.state_description,
'action': self.action,
'status': self.status,
'status_reason': self.status_reason,
'timeout': self.timeout_mins,
'disable_rollback': self.disable_rollback,
}
@ -254,18 +244,31 @@ class Stack(object):
if result:
raise StackValidationFailed(message=result)
def state_set(self, new_status, reason):
def state_set(self, action, status, reason):
'''Update the stack state in the database.'''
self.state = new_status
self.state_description = reason
if action not in self.ACTIONS:
raise ValueError("Invalid action %s" % action)
if status not in self.STATUSES:
raise ValueError("Invalid status %s" % status)
self.action = action
self.status = status
self.status_reason = reason
if self.id is None:
return
stack = db_api.stack_get(self.context, self.id)
stack.update_and_save({'status': new_status,
stack.update_and_save({'action': action,
'status': status,
'status_reason': reason})
@property
def state(self):
'''Returns state, tuple of action, status.'''
return (self.action, self.status)
def timeout_secs(self):
'''
Return the stack creation timeout in seconds, or None if no timeout
@ -288,9 +291,9 @@ class Stack(object):
'''
A task to create the stack and all of the resources.
'''
self.state_set(self.CREATE_IN_PROGRESS, 'Stack creation started')
self.state_set(self.CREATE, self.IN_PROGRESS, 'Stack creation started')
stack_status = self.CREATE_COMPLETE
stack_status = self.COMPLETE
reason = 'Stack successfully created'
res = None
@ -303,15 +306,15 @@ class Stack(object):
try:
yield create_task()
except exception.ResourceFailure as ex:
stack_status = self.CREATE_FAILED
stack_status = self.FAILED
reason = 'Resource failed: %s' % str(ex)
except scheduler.Timeout:
stack_status = self.CREATE_FAILED
stack_status = self.FAILED
reason = 'Timed out'
self.state_set(stack_status, reason)
self.state_set(self.CREATE, stack_status, reason)
if stack_status == self.CREATE_FAILED and not self.disable_rollback:
if stack_status == self.FAILED and not self.disable_rollback:
self.delete(action=self.ROLLBACK)
def update(self, newstack, action=UPDATE):
@ -328,27 +331,21 @@ class Stack(object):
'''
if action not in (self.UPDATE, self.ROLLBACK):
logger.error("Unexpected action %s passed to update!" % action)
self.state_set(self.UPDATE_FAILED, "Invalid action %s" % action)
self.state_set(self.UPDATE, self.FAILED,
"Invalid action %s" % action)
return
if self.state not in (self.CREATE_COMPLETE, self.UPDATE_COMPLETE,
self.ROLLBACK_COMPLETE):
if self.status != self.COMPLETE:
if (action == self.ROLLBACK and
self.state == self.UPDATE_IN_PROGRESS):
self.state == (self.UPDATE, self.IN_PROGRESS)):
logger.debug("Starting update rollback for %s" % self.name)
else:
if action == self.UPDATE:
self.state_set(self.UPDATE_FAILED,
'State invalid for update')
else:
self.state_set(self.ROLLBACK_FAILED,
'State invalid for rollback')
self.state_set(action, self.FAILED,
'State invalid for %s' % action)
return
if action == self.UPDATE:
self.state_set(self.UPDATE_IN_PROGRESS, 'Stack update started')
else:
self.state_set(self.ROLLBACK_IN_PROGRESS, 'Stack rollback started')
self.state_set(self.UPDATE, self.IN_PROGRESS,
'Stack %s started' % action)
# cache all the resources runtime data.
for r in self:
@ -416,15 +413,14 @@ class Stack(object):
(res.name, self.name))
if action == self.UPDATE:
stack_status = self.UPDATE_COMPLETE
reason = 'Stack successfully updated'
else:
stack_status = self.ROLLBACK_COMPLETE
reason = 'Stack rollback completed'
stack_status = self.COMPLETE
except eventlet.Timeout as t:
if t is tmo:
stack_status = self.UPDATE_FAILED
stack_status = self.FAILED
reason = 'Timed out waiting for %s' % str(res)
else:
# not my timeout
@ -432,21 +428,17 @@ class Stack(object):
except exception.ResourceFailure as e:
reason = str(e) or "Error : %s" % type(e)
stack_status = self.FAILED
if action == self.UPDATE:
stack_status = self.UPDATE_FAILED
# If rollback is enabled, we do another update, with the
# existing template, so we roll back to the original state
if self.disable_rollback:
stack_status = self.UPDATE_FAILED
else:
if not self.disable_rollback:
oldstack = Stack(self.context, self.name, self.t,
self.env)
self.update(oldstack, action=self.ROLLBACK)
return
else:
stack_status = self.ROLLBACK_FAILED
self.state_set(stack_status, reason)
self.state_set(action, stack_status, reason)
# flip the template & environment to the newstack values
# Note we do this on success and failure, so the current
@ -466,15 +458,14 @@ class Stack(object):
create, which amount to the same thing, but the states are recorded
differently.
'''
if action == self.DELETE:
self.state_set(self.DELETE_IN_PROGRESS, 'Stack deletion started')
elif action == self.ROLLBACK:
self.state_set(self.ROLLBACK_IN_PROGRESS, 'Stack rollback started')
else:
if action not in (self.DELETE, self.ROLLBACK):
logger.error("Unexpected action %s passed to delete!" % action)
self.state_set(self.DELETE_FAILED, "Invalid action %s" % action)
self.state_set(self.DELETE, self.FAILED,
"Invalid action %s" % action)
return
self.state_set(action, self.IN_PROGRESS, 'Stack %s started' % action)
failures = []
for res in reversed(self):
try:
@ -485,17 +476,10 @@ class Stack(object):
failures.append(str(res))
if failures:
if action == self.DELETE:
self.state_set(self.DELETE_FAILED,
'Failed to delete ' + ', '.join(failures))
elif action == self.ROLLBACK:
self.state_set(self.ROLLBACK_FAILED,
'Failed to rollback ' + ', '.join(failures))
self.state_set(action, self.FAILED,
'Failed to %s : %s' % (action, ', '.join(failures)))
else:
if action == self.DELETE:
self.state_set(self.DELETE_COMPLETE, 'Deleted successfully')
elif action == self.ROLLBACK:
self.state_set(self.ROLLBACK_COMPLETE, 'Rollback completed')
self.state_set(action, self.COMPLETE, '%s completed' % action)
db_api.stack_delete(self.context, self.id)
self.id = None

View File

@ -73,7 +73,8 @@ class StackResource(resource.Resource):
def check_create_complete(self, stack_creator):
done = stack_creator.step()
if done:
if self._nested.state != self._nested.CREATE_COMPLETE:
if self._nested.state != (self._nested.CREATE,
self._nested.COMPLETE):
raise exception.Error(self._nested.state_description)
return done

View File

@ -235,9 +235,9 @@ class WatchRule(object):
new_state)
else:
s = db_api.stack_get(self.context, self.stack_id)
if s and s.status in (parser.Stack.CREATE_COMPLETE,
parser.Stack.UPDATE_COMPLETE):
stack = parser.Stack.load(self.context, stack=s)
stack = parser.Stack.load(self.context, stack=s)
if (stack.action != stack.DELETE
and stack.status == stack.COMPLETE):
for a in self.rule[self.ACTION_MAP[new_state]]:
actions.append(stack[a].alarm)
else:

View File

@ -25,7 +25,7 @@ STACK_KEYS = (
STACK_CREATION_TIME, STACK_UPDATED_TIME, STACK_DELETION_TIME,
STACK_NOTIFICATION_TOPICS,
STACK_DESCRIPTION, STACK_TMPL_DESCRIPTION,
STACK_PARAMETERS, STACK_OUTPUTS,
STACK_PARAMETERS, STACK_OUTPUTS, STACK_ACTION,
STACK_STATUS, STACK_STATUS_DATA, STACK_CAPABILITIES,
STACK_DISABLE_ROLLBACK, STACK_TIMEOUT,
) = (
@ -33,7 +33,7 @@ STACK_KEYS = (
'creation_time', 'updated_time', 'deletion_time',
'notification_topics',
'description', 'template_description',
'parameters', 'outputs',
'parameters', 'outputs', 'stack_action',
'stack_status', 'stack_status_reason', 'capabilities',
'disable_rollback', 'timeout_mins'
)

View File

@ -122,7 +122,8 @@ class CfnStackControllerTest(HeatTestCase):
u'stack_status_reason': u'Stack successfully created',
u'creation_time': u'2012-07-09T09:12:45Z',
u'stack_name': u'wordpress',
u'stack_status': u'CREATE_COMPLETE'}]
u'stack_action': u'CREATE',
u'stack_status': u'COMPLETE'}]
self.m.StubOutWithMock(rpc, 'call')
rpc.call(dummy_req.context, self.topic,
{'namespace': None,
@ -220,7 +221,8 @@ class CfnStackControllerTest(HeatTestCase):
u'creation_time': u'2012-07-09T09:12:45Z',
u'stack_name': u'wordpress',
u'notification_topics': [],
u'stack_status': u'CREATE_COMPLETE',
u'stack_action': u'CREATE',
u'stack_status': u'COMPLETE',
u'description': u'blah',
u'disable_rollback': 'true',
u'timeout_mins':60,
@ -309,7 +311,8 @@ class CfnStackControllerTest(HeatTestCase):
u'creation_time': u'2012-07-09T09:12:45Z',
u'stack_name': u'wordpress',
u'notification_topics': [],
u'stack_status': u'CREATE_COMPLETE',
u'stack_action': u'CREATE',
u'stack_status': u'COMPLETE',
u'description': u'blah',
u'disable_rollback': 'true',
u'timeout_mins':60,

View File

@ -267,7 +267,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
u'stack_status_reason': u'Stack successfully created',
u'creation_time': u'2012-07-09T09:12:45Z',
u'stack_name': identity.stack_name,
u'stack_status': u'CREATE_COMPLETE',
u'stack_action': u'CREATE',
u'stack_status': u'COMPLETE',
u'parameters': {},
u'outputs': [],
u'notification_topics': [],
@ -645,7 +646,8 @@ class StackControllerTest(ControllerTest, HeatTestCase):
u'creation_time': u'2012-07-09T09:12:45Z',
u'stack_name': identity.stack_name,
u'notification_topics': [],
u'stack_status': u'CREATE_COMPLETE',
u'stack_action': u'CREATE',
u'stack_status': u'COMPLETE',
u'description': u'blah',
u'disable_rollback': True,
u'timeout_mins':60,

View File

@ -220,8 +220,10 @@ class stackCreateTest(HeatTestCase):
rsrc = stack.resources['WebServer']
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
self.assertEqual((stack.DELETE, stack.COMPLETE), rsrc.state)
self.assertEqual(db_api.stack_get(ctx, stack_id), None)
self.assertEqual(db_s.status, 'DELETE_COMPLETE')
self.assertEqual(db_s.action, 'DELETE')
self.assertEqual(db_s.status, 'COMPLETE')
class stackServiceCreateUpdateDeleteTest(HeatTestCase):

View File

@ -174,7 +174,8 @@ class MetadataRefreshTest(HeatTestCase):
self.m.ReplayAll()
self.stack.create()
self.assertEqual(self.stack.state, self.stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(self.stack.CREATE, self.stack.COMPLETE))
s1 = self.stack.resources['S1']
s2 = self.stack.resources['S2']
@ -267,7 +268,8 @@ class WaitCondMetadataUpdateTest(HeatTestCase):
self.m.ReplayAll()
self.stack.create()
self.assertEqual(self.stack.state, self.stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(self.stack.CREATE, self.stack.COMPLETE))
self.assertEqual(watch.FnGetAtt('Data'), '{"123": "foo"}')
self.assertEqual(inst.metadata['test'], '{"123": "foo"}')

View File

@ -55,7 +55,7 @@ Outputs:
t = template_format.parse(template)
stack = self.parse_stack(t)
stack.create()
self.assertEqual(stack.state, stack.CREATE_COMPLETE)
self.assertEqual(stack.state, (stack.CREATE, stack.COMPLETE))
return stack
def parse_stack(self, t):

View File

@ -462,22 +462,40 @@ class StackTest(HeatTestCase):
def test_state_defaults(self):
stack = parser.Stack(None, 'test_stack', parser.Template({}))
self.assertEqual(stack.state, None)
self.assertEqual(stack.state_description, '')
self.assertEqual(stack.state, (None, None))
self.assertEqual(stack.status_reason, '')
def test_state(self):
stack = parser.Stack(None, 'test_stack', parser.Template({}),
state='foo')
self.assertEqual(stack.state, 'foo')
stack.state_set('bar', '')
self.assertEqual(stack.state, 'bar')
action=parser.Stack.CREATE,
status=parser.Stack.IN_PROGRESS)
self.assertEqual(stack.state,
(parser.Stack.CREATE, parser.Stack.IN_PROGRESS))
stack.state_set(parser.Stack.CREATE, parser.Stack.COMPLETE, 'test')
self.assertEqual(stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
stack.state_set(parser.Stack.DELETE, parser.Stack.COMPLETE, 'test')
self.assertEqual(stack.state,
(parser.Stack.DELETE, parser.Stack.COMPLETE))
def test_state_description(self):
def test_state_bad(self):
stack = parser.Stack(None, 'test_stack', parser.Template({}),
state_description='quux')
self.assertEqual(stack.state_description, 'quux')
stack.state_set('blarg', 'wibble')
self.assertEqual(stack.state_description, 'wibble')
action=parser.Stack.CREATE,
status=parser.Stack.IN_PROGRESS)
self.assertEqual(stack.state,
(parser.Stack.CREATE, parser.Stack.IN_PROGRESS))
self.assertRaises(ValueError, stack.state_set,
'baad', parser.Stack.COMPLETE, 'test')
self.assertRaises(ValueError, stack.state_set,
parser.Stack.CREATE, 'oops', 'test')
def test_status_reason(self):
stack = parser.Stack(None, 'test_stack', parser.Template({}),
status_reason='quux')
self.assertEqual(stack.status_reason, 'quux')
stack.state_set(parser.Stack.CREATE, parser.Stack.IN_PROGRESS,
'wibble')
self.assertEqual(stack.status_reason, 'wibble')
def test_load_nonexistant_id(self):
self.assertRaises(exception.NotFound, parser.Stack.load,
@ -542,7 +560,7 @@ class StackTest(HeatTestCase):
self.assertEqual(self.stack.updated_time, None)
self.stack.store()
stored_time = self.stack.updated_time
self.stack.state_set(self.stack.CREATE_IN_PROGRESS, 'testing')
self.stack.state_set(self.stack.CREATE, self.stack.IN_PROGRESS, 'test')
self.assertNotEqual(self.stack.updated_time, None)
self.assertNotEqual(self.stack.updated_time, stored_time)
@ -559,7 +577,8 @@ class StackTest(HeatTestCase):
db_s = db_api.stack_get(self.ctx, stack_id)
self.assertEqual(db_s, None)
self.assertEqual(self.stack.state, self.stack.DELETE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.DELETE, parser.Stack.COMPLETE))
@stack_delete_after
def test_delete_rollback(self):
@ -574,7 +593,8 @@ class StackTest(HeatTestCase):
db_s = db_api.stack_get(self.ctx, stack_id)
self.assertEqual(db_s, None)
self.assertEqual(self.stack.state, self.stack.ROLLBACK_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.ROLLBACK, parser.Stack.COMPLETE))
@stack_delete_after
def test_delete_badaction(self):
@ -589,16 +609,20 @@ class StackTest(HeatTestCase):
db_s = db_api.stack_get(self.ctx, stack_id)
self.assertNotEqual(db_s, None)
self.assertEqual(self.stack.state, self.stack.DELETE_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.DELETE, parser.Stack.FAILED))
@stack_delete_after
def test_update_badstate(self):
self.stack = parser.Stack(self.ctx, 'test_stack', parser.Template({}),
state=parser.Stack.CREATE_FAILED)
action=parser.Stack.CREATE,
status=parser.Stack.FAILED)
stack_id = self.stack.store()
self.assertEqual(self.stack.state, parser.Stack.CREATE_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.FAILED))
self.stack.update({})
self.assertEqual(self.stack.state, parser.Stack.UPDATE_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.FAILED))
@stack_delete_after
def test_resource_by_refid(self):
@ -608,7 +632,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
self.assertTrue('AResource' in self.stack)
rsrc = self.stack['AResource']
rsrc.resource_id_set('aaaa')
@ -630,7 +655,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {
'AResource': {'Type': 'GenericResourceType'},
@ -638,7 +664,8 @@ class StackTest(HeatTestCase):
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(tmpl2))
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.COMPLETE))
self.assertTrue('BResource' in self.stack)
@stack_delete_after
@ -651,14 +678,16 @@ class StackTest(HeatTestCase):
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {'AResource': {'Type': 'GenericResourceType'}}}
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(tmpl2))
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.COMPLETE))
self.assertFalse('BResource' in self.stack)
@stack_delete_after
@ -670,7 +699,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Description': 'BTemplate',
'Resources': {'AResource': {'Type': 'GenericResourceType'}}}
@ -678,7 +708,8 @@ class StackTest(HeatTestCase):
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(tmpl2))
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.COMPLETE))
self.assertEqual(self.stack.t[template.DESCRIPTION], 'BTemplate')
@stack_delete_after
@ -694,7 +725,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {'AResource': {'Type': 'GenericResourceType',
'Properties': {'Foo': 'xyz'}}}}
@ -708,7 +740,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'xyz')
self.m.VerifyAll()
@ -726,7 +759,8 @@ class StackTest(HeatTestCase):
disable_rollback=True)
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
res = self.stack['AResource']
res.update_allowed_keys = ('Properties',)
@ -748,7 +782,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.FAILED))
self.m.VerifyAll()
@stack_delete_after
@ -765,7 +800,8 @@ class StackTest(HeatTestCase):
disable_rollback=True)
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {'AResource': {'Type': 'GenericResourceType',
'Properties': {'Foo': 'xyz'}}}}
@ -784,7 +820,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.FAILED))
self.m.VerifyAll()
# Unset here so destroy() is not stubbed for stack.delete cleanup
self.m.UnsetStubs()
@ -803,7 +840,8 @@ class StackTest(HeatTestCase):
disable_rollback=True)
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {'AResource': {'Type': 'GenericResourceType',
'Properties': {'Foo': 'xyz'}}}}
@ -821,7 +859,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.FAILED))
self.m.VerifyAll()
@stack_delete_after
@ -832,7 +871,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {
'AResource': {'Type': 'GenericResourceType'},
@ -846,7 +886,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.FAILED))
self.assertTrue('BResource' in self.stack)
# Reload the stack from the DB and prove that it contains the failed
@ -869,7 +910,8 @@ class StackTest(HeatTestCase):
disable_rollback=False)
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {'AResource': {'Type': 'GenericResourceType',
'Properties': {'Foo': 'xyz'}}}}
@ -889,7 +931,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.ROLLBACK_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.ROLLBACK, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'abc')
self.m.VerifyAll()
@ -907,7 +950,8 @@ class StackTest(HeatTestCase):
disable_rollback=False)
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {'AResource': {'Type': 'GenericResourceType',
'Properties': {'Foo': 'xyz'}}}}
@ -927,7 +971,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.ROLLBACK_FAILED)
self.assertEqual(self.stack.state,
(parser.Stack.ROLLBACK, parser.Stack.FAILED))
self.m.VerifyAll()
@stack_delete_after
@ -939,7 +984,8 @@ class StackTest(HeatTestCase):
disable_rollback=False)
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {
'AResource': {'Type': 'GenericResourceType'},
@ -955,7 +1001,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.ROLLBACK_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.ROLLBACK, parser.Stack.COMPLETE))
self.assertFalse('BResource' in self.stack)
self.m.VerifyAll()
@ -970,7 +1017,8 @@ class StackTest(HeatTestCase):
disable_rollback=False)
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
tmpl2 = {'Resources': {'AResource': {'Type': 'GenericResourceType'}}}
@ -984,7 +1032,8 @@ class StackTest(HeatTestCase):
self.m.ReplayAll()
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.ROLLBACK_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.ROLLBACK, parser.Stack.COMPLETE))
self.assertTrue('BResource' in self.stack)
self.m.VerifyAll()
# Unset here so delete() is not stubbed for stack.delete cleanup
@ -1023,7 +1072,8 @@ class StackTest(HeatTestCase):
self.stack.store()
self.stack.create()
self.m.VerifyAll()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'abc')
self.assertEqual(self.stack['BResource'].properties['Foo'],
'AResource')
@ -1042,7 +1092,8 @@ class StackTest(HeatTestCase):
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(tmpl2))
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.UPDATE, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'smelly')
self.assertEqual(self.stack['BResource'].properties['Foo'], 'inst-007')
self.m.VerifyAll()
@ -1082,7 +1133,8 @@ class StackTest(HeatTestCase):
self.stack.create()
self.m.VerifyAll()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'abc')
self.assertEqual(self.stack['BResource'].properties['Foo'],
'AResource')
@ -1110,7 +1162,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl2),
disable_rollback=False)
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.ROLLBACK_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.ROLLBACK, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'abc')
self.m.VerifyAll()
@ -1150,7 +1203,8 @@ class StackTest(HeatTestCase):
self.stack.create()
self.m.VerifyAll()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'abc')
self.assertEqual(self.stack['BResource'].properties['Foo'],
'AResource')
@ -1166,19 +1220,19 @@ class StackTest(HeatTestCase):
'AResource')
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
# self.state_set(self.UPDATE_IN_PROGRESS)
# self.state_set(self.UPDATE, self.IN_PROGRESS)
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
# self.state_set(self.DELETE_IN_PROGRESS)
# self.state_set(self.DELETE, self.IN_PROGRESS)
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
# self.state_set(self.DELETE_COMPLETE)
# self.state_set(self.DELETE, self.COMPLETE)
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
# self.properties.validate()
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
# self.state_set(self.CREATE_IN_PROGRESS)
# self.state_set(self.CREATE, self.IN_PROGRESS)
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
@ -1191,10 +1245,10 @@ class StackTest(HeatTestCase):
# resource.UpdateReplace because we've not specified the modified
# key/property in update_allowed_keys/update_allowed_properties
# self.state_set(self.DELETE_IN_PROGRESS)
# self.state_set(self.DELETE, self.IN_PROGRESS)
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
# self.state_set(self.DELETE_IN_PROGRESS)
# self.state_set(self.DELETE, self.IN_PROGRESS)
generic_rsrc.GenericResource.FnGetRefId().AndReturn(
'inst-007')
@ -1211,7 +1265,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl2),
disable_rollback=False)
self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.ROLLBACK_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.ROLLBACK, parser.Stack.COMPLETE))
self.assertEqual(self.stack['AResource'].properties['Foo'], 'abc')
self.m.VerifyAll()
@ -1236,8 +1291,9 @@ class StackTest(HeatTestCase):
stack.create()
self.assertEqual(stack.state, stack.CREATE_FAILED)
self.assertEqual(stack.state_description, 'Timed out')
self.assertEqual(stack.state,
(parser.Stack.CREATE, parser.Stack.FAILED))
self.assertEqual(stack.status_reason, 'Timed out')
self.m.VerifyAll()
@ -1296,7 +1352,8 @@ class StackTest(HeatTestCase):
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)
self.assertEqual(self.stack.state,
(parser.Stack.CREATE, parser.Stack.COMPLETE))
self.assertTrue('AResource' in self.stack)
rsrc = self.stack['AResource']
rsrc.resource_id_set('aaaa')

View File

@ -460,7 +460,7 @@ Resources:
stack = self.create_stack(self.test_template)
try:
self.assertEqual(stack.CREATE_COMPLETE, stack.state)
self.assertEqual((stack.CREATE, stack.COMPLETE), stack.state)
rsrc = stack['the_nic']
self.assertResourceState(rsrc, 'dddd')
@ -510,7 +510,7 @@ Resources:
stack = self.create_stack(self.test_template_error_no_ref)
try:
self.assertEqual(stack.CREATE_FAILED, stack.state)
self.assertEqual((stack.CREATE, stack.FAILED), stack.state)
rsrc = stack['the_nic']
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
reason = rsrc.status_reason

View File

@ -53,7 +53,8 @@ class WatchRuleTest(HeatTestCase):
tmpl = parser.Template(empty_tmpl)
stack_name = 'dummystack'
dummy_stack = parser.Stack(ctx, stack_name, tmpl)
dummy_stack.state_set(dummy_stack.CREATE_COMPLETE, 'Testing')
dummy_stack.state_set(dummy_stack.CREATE, dummy_stack.COMPLETE,
'Testing')
dummy_stack.store()
cls.stack_id = dummy_stack.id