Add a Timeout (-t) to the heat options (and make -f for templates).

This makes the cli more consistent with AWS and implements
the timeout feature.

Note: the timeout is in minutes and defaults to 60 minutes.

Change-Id: I41dea75170c871c1ee47948643311752d9d5e41e
Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
This commit is contained in:
Angus Salkeld 2012-06-07 11:41:03 +10:00
parent 7e02a65f79
commit aca71be770
6 changed files with 65 additions and 24 deletions

View File

@ -137,6 +137,8 @@ def stack_create(options, arguments):
parameters['Parameters.member.%d.ParameterValue' % count] = v
count = count + 1
parameters['Timeout'] = options.timeout
if options.template_file:
parameters['TemplateBody'] = open(options.template_file).read()
elif options.template_url:
@ -367,8 +369,11 @@ def create_options(parser):
parser.add_option('-u', '--template-url', metavar="template_url",
default=None, help="URL of template. Default: None")
parser.add_option('-t', '--template-file', metavar="template_file",
parser.add_option('-f', '--template-file', metavar="template_file",
default=None, help="Path to the template. Default: None")
parser.add_option('-t', '--timeout', metavar="timeout",
default='60',
help='Stack creation timeout in minutes. Default: 60')
parser.add_option('-P', '--parameters', metavar="parameters", default=None,
help="Parameter values used to create the stack.")

View File

@ -34,7 +34,7 @@ heat command\&.
.RE
.SH "OPTIONS"
.PP
\fB\-t\fR, \fB\-\-template\fR
\fB\-f\fR, \fB\-\-template\fR
.RS 4
The template to use set up a stack\&.
.RE

View File

@ -138,6 +138,8 @@ class StackController(object):
msg = _("The Template must be a JSON document.")
return webob.exc.HTTPBadRequest(explanation=msg)
stack['StackName'] = req.params['StackName']
if 'Timeout' in req.params:
stack['Timeout'] = req.params['Timeout']
try:
return rpc.call(con, 'engine',

View File

@ -16,4 +16,4 @@
SUPPORTED_PARAMS = ('StackName', 'TemplateBody', 'TemplateUrl',
'NotificationARNs', 'Parameters', 'Version',
'SignatureVersion', 'Timestamp', 'AWSAccessKeyId',
'Signature', 'KeyStoneCreds')
'Signature', 'KeyStoneCreds', 'Timeout')

View File

@ -115,11 +115,12 @@ class EngineManager(manager.Manager):
mem['updated_at'] = str(s.updated_at)
mem['NotificationARNs'] = 'TODO'
mem['Parameters'] = ps.t['Parameters']
mem['StackStatusReason'] = 'TODO'
mem['TimeoutInMinutes'] = 'TODO'
mem['TimeoutInMinutes'] = ps.t.get('Timeout', '60')
mem['TemplateDescription'] = ps.t.get('Description',
'No description')
mem['StackStatus'] = ps.t.get('stack_status', 'unknown')
mem['StackStatusReason'] = ps.t.get('stack_status_reason',
'State changed')
# only show the outputs on a completely created stack
if ps.t['stack_status'] == ps.CREATE_COMPLETE:

View File

@ -40,6 +40,7 @@ class Stack(object):
self.t = template
self.maps = self.t.get('Mappings', {})
self.outputs = self.t.get('Outputs', {})
self.timeout = self.t.get('Timeout', None)
self.res = {}
self.doc = None
self.name = stack_name
@ -174,6 +175,7 @@ class Stack(object):
def status_set(self, new_status, reason='change in resource state'):
self.t['stack_status'] = new_status
self.t['stack_status_reason'] = reason
self.update_parsed_template()
def create_blocking(self):
@ -181,28 +183,51 @@ class Stack(object):
create all the resources in the order specified by get_create_order
'''
order = self.get_create_order()
failed = False
self.status_set(self.IN_PROGRESS)
self.status_set(self.IN_PROGRESS, 'Stack creation started')
for r in order:
res = self.resources[r]
if not failed:
try:
res.create()
except Exception as ex:
logger.exception('create')
failed = True
res.state_set(res.CREATE_FAILED, str(ex))
stack_status = self.CREATE_COMPLETE
reason = 'Stack successfully created'
try:
self.update_parsed_template()
except Exception as ex:
logger.exception('update_parsed_template')
# Timeout is in minutes (default to 1 hour)
secs_tmo = 60 * 60
if self.timeout:
try:
secs_tmo = int(self.timeout) * 60
except ValueError as ve:
logger.exception('create timeout conversion')
tmo = eventlet.Timeout(secs_tmo)
try:
for r in order:
res = self.resources[r]
if stack_status != self.CREATE_FAILED:
try:
res.create()
except Exception as ex:
logger.exception('create')
stack_status = self.CREATE_FAILED
reason = 'resource %s failed with: %s' % (res.name,
str(ex))
res.state_set(res.CREATE_FAILED, str(ex))
try:
self.update_parsed_template()
except Exception as ex:
logger.exception('update_parsed_template')
else:
res.state_set(res.CREATE_FAILED)
except eventlet.Timeout, t:
if t is not tmo:
# not my timeout
raise
else:
res.state_set(res.CREATE_FAILED)
stack_status = self.CREATE_FAILED
reason = 'Timed out waiting for %s' % (res.name)
finally:
tmo.cancel()
self.status_set(failed and self.CREATE_FAILED or self.CREATE_COMPLETE)
self.status_set(stack_status, reason)
def create(self):
@ -222,12 +247,20 @@ class Stack(object):
res = self.resources[r]
try:
res.delete()
re = db_api.resource_get(self.context, self.resources[r].id)
re.delete()
except Exception as ex:
failed = True
res.state_set(res.DELETE_FAILED)
logger.error('delete: %s' % str(ex))
try:
re = db_api.resource_get(self.context, self.resources[r].id)
re.delete()
except Exception as ex:
# don't fail the delete if the db entry has
# not been created yet.
if 'not found' not in str(ex):
failed = True
res.state_set(res.DELETE_FAILED)
logger.error('delete: %s' % str(ex))
self.status_set(failed and self.DELETE_FAILED or self.DELETE_COMPLETE)
if not failed: