Add a very rough-and-ready conversion from json to xml for cape
This needs lots of improvements. And is only tested with templates/WordPress_Single_Instance.template Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
This commit is contained in:
parent
a5ea8a4c55
commit
a321e3c880
|
@ -19,6 +19,7 @@
|
|||
|
||||
import httplib
|
||||
import json
|
||||
import libxml2
|
||||
import logging
|
||||
import sys
|
||||
import urlparse
|
||||
|
@ -29,12 +30,209 @@ from webob.exc import (HTTPNotFound,
|
|||
HTTPBadRequest)
|
||||
|
||||
from heat.common import exception
|
||||
from heat.common import utils
|
||||
from heat.common import wsgi
|
||||
|
||||
logger = logging.getLogger('heat.api.v1.stacks')
|
||||
|
||||
stack_db = {}
|
||||
|
||||
|
||||
class Json2CapeXml:
|
||||
def __init__(self, template, stack_name):
|
||||
|
||||
self.t = template
|
||||
self.parms = self.t['Parameters']
|
||||
self.maps = self.t['Mappings']
|
||||
self.res = {}
|
||||
|
||||
self.parms['AWS::Region'] = {"Description" : "AWS Regions", "Type" : "String", "Default" : "ap-southeast-1",
|
||||
"AllowedValues" : ["us-east-1","us-west-1","us-west-2","sa-east-1","eu-west-1","ap-southeast-1","ap-northeast-1"],
|
||||
"ConstraintDescription" : "must be a valid EC2 instance type." }
|
||||
|
||||
# expected user parameters
|
||||
self.parms['AWS::StackName'] = {'Default': stack_name}
|
||||
self.parms['KeyName'] = {'Default': 'harry-45-5-34-5'}
|
||||
|
||||
for r in self.t['Resources']:
|
||||
# fake resource instance references
|
||||
self.parms[r] = {'Default': utils.generate_uuid()}
|
||||
|
||||
self.resolve_static_refs(self.t['Resources'])
|
||||
self.resolve_find_in_map(self.t['Resources'])
|
||||
#self.resolve_attributes(self.t['Resources'])
|
||||
self.resolve_joins(self.t['Resources'])
|
||||
self.resolve_base64(self.t['Resources'])
|
||||
#print json.dumps(self.t['Resources'], indent=2)
|
||||
|
||||
|
||||
def convert_and_write(self):
|
||||
|
||||
name = self.parms['AWS::StackName']['Default']
|
||||
|
||||
doc = libxml2.newDoc("1.0")
|
||||
dep = doc.newChild(None, "deployable", None)
|
||||
dep.setProp("name", name)
|
||||
dep.setProp("uuid", 'bogus')
|
||||
dep.setProp("monitor", 'active')
|
||||
dep.setProp("username", 'nobody-yet')
|
||||
n_asses = dep.newChild(None, "assemblies", None)
|
||||
|
||||
for r in self.t['Resources']:
|
||||
type = self.t['Resources'][r]['Type']
|
||||
if type != 'AWS::EC2::Instance':
|
||||
print 'ignoring Resource %s (%s)' % (r, type)
|
||||
continue
|
||||
|
||||
n_ass = n_asses.newChild(None, 'assembly', None)
|
||||
n_ass.setProp("name", r)
|
||||
n_ass.setProp("uuid", self.parms[r]['Default'])
|
||||
props = self.t['Resources'][r]['Properties']
|
||||
for p in props:
|
||||
if p == 'ImageId':
|
||||
n_ass.setProp("image_name", props[p])
|
||||
elif p == 'UserData':
|
||||
new_script = []
|
||||
script_lines = props[p].split('\n')
|
||||
for l in script_lines:
|
||||
if '#!/' in l:
|
||||
new_script.append(l)
|
||||
self.insert_package_and_services(self.t['Resources'][r], new_script)
|
||||
else:
|
||||
new_script.append(l)
|
||||
|
||||
startup = n_ass.newChild(None, 'startup', '\n'.join(new_script))
|
||||
|
||||
|
||||
con = self.t['Resources'][r]['Metadata']["AWS::CloudFormation::Init"]['config']
|
||||
|
||||
n_services = n_ass.newChild(None, 'services', None)
|
||||
for st in con['services']:
|
||||
for s in con['services'][st]:
|
||||
n_service = n_services.newChild(None, 'service', None)
|
||||
n_service.setProp("name", '%s_%s' % (r, s))
|
||||
n_service.setProp("type", s)
|
||||
n_service.setProp("provider", 'pacemaker')
|
||||
n_service.setProp("class", 'lsb')
|
||||
n_service.setProp("monitor_interval", '30s')
|
||||
n_service.setProp("escalation_period", '1000')
|
||||
n_service.setProp("escalation_failures", '3')
|
||||
|
||||
filename = '/var/run/%s.xml' % name
|
||||
open(filename, 'w').write(doc.serialize(None, 1))
|
||||
doc.freeDoc()
|
||||
|
||||
def insert_package_and_services(self, r, new_script):
|
||||
|
||||
con = r['Metadata']["AWS::CloudFormation::Init"]['config']
|
||||
|
||||
for pt in con['packages']:
|
||||
if pt == 'yum':
|
||||
for p in con['packages']['yum']:
|
||||
new_script.append('yum install -y %s' % p)
|
||||
for st in con['services']:
|
||||
if st == 'systemd':
|
||||
for s in con['services']['systemd']:
|
||||
v = con['services']['systemd'][s]
|
||||
if v['enabled'] == 'true':
|
||||
new_script.append('systemctl enable %s.service' % s)
|
||||
if v['ensureRunning'] == 'true':
|
||||
new_script.append('systemctl start %s.service' % s)
|
||||
elif st == 'sysvinit':
|
||||
for s in con['services']['sysvinit']:
|
||||
v = con['services']['systemd'][s]
|
||||
if v['enabled'] == 'true':
|
||||
new_script.append('chkconfig %s on' % s)
|
||||
if v['ensureRunning'] == 'true':
|
||||
new_script.append('/etc/init.d/start %s' % s)
|
||||
|
||||
def resolve_static_refs(self, s):
|
||||
'''
|
||||
looking for { "Ref": "str" }
|
||||
'''
|
||||
if isinstance(s, dict):
|
||||
for i in s:
|
||||
if i == 'Ref' and isinstance(s[i], (basestring, unicode)) and \
|
||||
self.parms.has_key(s[i]):
|
||||
if self.parms[s[i]] == None:
|
||||
print 'None Ref: %s' % str(s[i])
|
||||
elif self.parms[s[i]].has_key('Default'):
|
||||
# note the "ref: values" are in a dict of
|
||||
# size one, so return is fine.
|
||||
#print 'Ref: %s == %s' % (s[i], self.parms[s[i]]['Default'])
|
||||
return self.parms[s[i]]['Default']
|
||||
else:
|
||||
print 'missing Ref: %s' % str(s[i])
|
||||
else:
|
||||
s[i] = self.resolve_static_refs(s[i])
|
||||
elif isinstance(s, list):
|
||||
for index, item in enumerate(s):
|
||||
#print 'resolve_static_refs %d %s' % (index, item)
|
||||
s[index] = self.resolve_static_refs(item)
|
||||
return s
|
||||
|
||||
def resolve_find_in_map(self, s):
|
||||
'''
|
||||
looking for { "Ref": "str" }
|
||||
'''
|
||||
if isinstance(s, dict):
|
||||
for i in s:
|
||||
if i == 'Fn::FindInMap':
|
||||
obj = self.maps
|
||||
if isinstance(s[i], list):
|
||||
#print 'map list: %s' % s[i]
|
||||
for index, item in enumerate(s[i]):
|
||||
if isinstance(item, dict):
|
||||
item = self.resolve_find_in_map(item)
|
||||
#print 'map item dict: %s' % (item)
|
||||
else:
|
||||
pass
|
||||
#print 'map item str: %s' % (item)
|
||||
obj = obj[item]
|
||||
else:
|
||||
obj = obj[s[i]]
|
||||
return obj
|
||||
else:
|
||||
s[i] = self.resolve_find_in_map(s[i])
|
||||
elif isinstance(s, list):
|
||||
for index, item in enumerate(s):
|
||||
s[index] = self.resolve_find_in_map(item)
|
||||
return s
|
||||
|
||||
|
||||
def resolve_joins(self, s):
|
||||
'''
|
||||
looking for { "Fn::join": [] }
|
||||
'''
|
||||
if isinstance(s, dict):
|
||||
for i in s:
|
||||
if i == 'Fn::Join':
|
||||
return s[i][0].join(s[i][1])
|
||||
else:
|
||||
s[i] = self.resolve_joins(s[i])
|
||||
elif isinstance(s, list):
|
||||
for index, item in enumerate(s):
|
||||
s[index] = self.resolve_joins(item)
|
||||
return s
|
||||
|
||||
|
||||
def resolve_base64(self, s):
|
||||
'''
|
||||
looking for { "Fn::join": [] }
|
||||
'''
|
||||
if isinstance(s, dict):
|
||||
for i in s:
|
||||
if i == 'Fn::Base64':
|
||||
return s[i]
|
||||
else:
|
||||
s[i] = self.resolve_base64(s[i])
|
||||
elif isinstance(s, list):
|
||||
for index, item in enumerate(s):
|
||||
s[index] = self.resolve_base64(item)
|
||||
return s
|
||||
|
||||
|
||||
|
||||
class StackController(object):
|
||||
|
||||
"""
|
||||
|
@ -141,6 +339,9 @@ class StackController(object):
|
|||
self._apply_user_parameters(req, stack)
|
||||
stack_db[req.params['StackName']] = stack
|
||||
|
||||
cape_transformer = Json2CapeXml(stack, req.params['StackName'])
|
||||
cape_transformer.convert_and_write()
|
||||
|
||||
return {'CreateStackResult': {'StackId': my_id}}
|
||||
|
||||
def update(self, req):
|
||||
|
|
Loading…
Reference in New Issue