Add the ValidateTemplate API.

Implementing the validate is still a TODO.

Re: issue #1

Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
This commit is contained in:
Angus Salkeld 2012-03-28 19:36:18 +11:00
parent 3b49124ee3
commit 3bc820fba4
8 changed files with 110 additions and 17 deletions

View File

@ -87,7 +87,18 @@ def catch_error(action):
def template_validate(options, arguments):
'''
'''
pass
parameters = {}
if options.template_file:
parameters['TemplateBody'] = open(options.template_file).read()
elif options.template_url:
parameters['TemplateUrl'] = options.template_url
else:
print 'Please specify a template file or url'
return FAILURE
c = get_client(options)
result = c.validate_template(**parameters)
print json.dumps(result, indent=2)
@catch_error('gettemplate')
def get_template(options, arguments):

View File

@ -48,5 +48,7 @@ class API(wsgi.Router):
action="update", conditions=dict(method=["PUT"]))
mapper.connect("/DescribeStackEvents", controller=stacks_resource,
action="events_list", conditions=dict(method=["GET"]))
mapper.connect("/ValidateTemplate", controller=stacks_resource,
action="validate_template", conditions=dict(method=["GET"]))
super(API, self).__init__(mapper)

View File

@ -123,6 +123,28 @@ class StackController(object):
return c.create_stack(stack, **req.params)
def validate_template(self, req):
c = engine.get_engine_client(req.context)
try:
templ = self._get_template(req)
except socket.gaierror:
msg = _('Invalid Template URL')
return webob.exc.HTTPBadRequest(explanation=msg)
if templ is None:
msg = _("TemplateBody or TemplateUrl were not given.")
return webob.exc.HTTPBadRequest(explanation=msg)
try:
stack = json.loads(templ)
except ValueError:
msg = _("The Template must be a JSON document.")
return webob.exc.HTTPBadRequest(explanation=msg)
logger.info('validate_template')
return c.validate_template(stack, **req.params)
def delete(self, req):
"""
Returns the following information for all stacks:

View File

@ -88,6 +88,14 @@ class V1Client(base_client.BaseClient):
data = json.loads(res.read())
return data
def validate_template(self, **kwargs):
params = self._extract_params(kwargs, SUPPORTED_PARAMS)
self._insert_common_parameters(params)
res = self.do_request("GET", "/ValidateTemplate", params=params)
data = json.loads(res.read())
return data
HeatClient = V1Client

View File

@ -29,6 +29,9 @@ class API(wsgi.Router):
mapper.resource("stack", "stacks", controller=stacks_resource,
collection={'detail': 'GET'})
mapper.connect("/", controller=stacks_resource, action="index")
mapper.connect("/validate_template", controller=stacks_resource,
action="validate_template", conditions=dict(method=["POST"]))
events_resource = events.create_resource(conf)
mapper.resource("event", "events", controller=events_resource,

View File

@ -100,6 +100,18 @@ class StacksController(object):
return {'stack': {'id': body['StackName']}}
def validate_template(self, req, body=None):
logger.info('validate_template')
if body is None:
msg = _("No Template provided.")
return webob.exc.HTTPBadRequest(explanation=msg)
s = parser.Stack('validate', body, req.params)
res = s.validate()
return res
def delete(self, req, id):
if not stack_db.has_key(id):
return webob.exc.HTTPNotFound('No stack by that name')

View File

@ -87,6 +87,20 @@ class EngineClient(BaseClient):
data = json.loads(res.read())['stacks']
return data
def validate_template(self, template, **kwargs):
"""
Validate the template
"""
headers = {
'Content-Type': 'application/json',
}
logger.info(template)
res = self.do_request("POST", "/validate_template", body=json.dumps(template),
headers=headers, params=kwargs)
data = json.loads(res.read())
logger.info(data)
return data
def create_stack(self, template, **kwargs):
"""

View File

@ -20,7 +20,6 @@ from heat.engine import resources
logger = logging.getLogger('heat.engine.parser')
class Stack:
def __init__(self, stack_name, template, parms=None):
@ -62,6 +61,34 @@ class Stack:
self.calulate_dependancies(self.t['Resources'][r], self.resources[r])
def validate(self):
'''
If you are wondering where the actual validation is, me too.
it is just not obvious how to respond to validation failures.
http://docs.amazonwebservices.com/AWSCloudFormation/latest/APIReference/API_ValidateTemplate.html
'''
response = { 'ValidateTemplateResult': {
'Description': 'bla',
'Parameters': []
}
}
for p in self.parms:
jp = {'member': {}}
res = jp['member']
res['NoEcho'] = 'false'
res['ParameterKey'] = p
if self.parms[p].has_key('Description'):
res['Description'] = self.parms[p]['Description']
else:
res['Description'] = ''
if self.parms[p].has_key('Default'):
res['DefaultValue'] = self.parms[p]['Default']
else:
res['DefaultValue'] = ''
response['ValidateTemplateResult']['Parameters'].append(res)
return response
def start(self):
# start Volumes first.
for r in self.t['Resources']:
@ -91,16 +118,12 @@ class Stack:
for index, item in enumerate(s):
self.calulate_dependancies(item, r)
def _apply_user_parameter(self, key, value):
logger.info('_apply_user_parameter %s=%s ' % (key, value))
if not self.t.has_key('Parameters'):
self.t['Parameters'] = {}
logger.debug('appling user parameter %s=%s ' % (key, value))
if not self.t['Parameters'].has_key(key):
self.t['Parameters'][key] = {}
self.t['Parameters'][key]['Value'] = value
if not self.parms.has_key(key):
self.parms[key] = {}
self.parms[key]['Value'] = value
def _apply_user_parameters(self, parms):
for p in parms:
@ -111,21 +134,19 @@ class Stack:
value_name = 'Parameters.member.%s.ParameterValue' % s[2]
self._apply_user_parameter(parms[key_name], parms[value_name])
except:
logger.error('could not apply parameter %s' % p)
logger.error('Could not apply parameter %s' % p)
def parameter_get(self, key):
if self.parms[key] == None:
#print 'None Ref: %s' % key
return '=EMPTY='
logger.warn('Trying to reference parameter: %s, but it is empty' % key)
return ''
elif self.parms[key].has_key('Value'):
return self.parms[key]['Value']
elif self.parms[key].has_key('Default'):
return self.parms[key]['Default']
else:
#print 'Missing Ref: %s' % key
return '=EMPTY='
logger.warn('Trying to reference parameter: %s, but no Value or Default' % key)
return ''
def resolve_static_refs(self, s):
'''