blob: 82659519c0590cb166308c71653f0d631299860a [file] [log] [blame]
Filip Pytloun923d8692015-10-06 16:28:32 +02001# -*- coding: utf-8 -*-
2'''
3Module for handling Heat stacks.
4
5:depends: - python-heatclient>=0.2.3 Python module
6:configuration: This module is not usable until the following are specified
7 either in a pillar or in the minion's config file::
8
9 keystone.user: admin
10 keystone.password: verybadpass
11 keystone.tenant: admin
12 keystone.tenant_id: f80919baedab48ec8931f200c65a50df
13 keystone.insecure: False #(optional)
14 keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
15
16 If configuration for multiple openstack accounts is required, they can be
17 set up as different configuration profiles:
18 For example::
19
20 openstack1:
21 keystone.user: admin
22 keystone.password: verybadpass
23 keystone.tenant: admin
24 keystone.tenant_id: f80919baedab48ec8931f200c65a50df
25 keystone.auth_url: 'http://127.0.0.1:5000/v2.0/'
26
27 openstack2:
28 keystone.user: admin
29 keystone.password: verybadpass
30 keystone.tenant: admin
31 keystone.tenant_id: f80919baedab48ec8931f200c65a50df
32 keystone.auth_url: 'http://127.0.0.2:5000/v2.0/'
33
34 With this configuration in place, any of the heat functions can make
35 use of a configuration profile by declaring it explicitly.
36 For example::
37
38 salt '*' heat.stack_list profile=openstack1
39
40'''
41
42from __future__ import absolute_import
43import logging
44LOG = logging.getLogger(__name__)
45
46# Import third party libs
47HAS_HEAT = False
48try:
49 from heatclient.v1 import client
50 HAS_HEAT = True
51except Exception, e:
52 LOG.trace("heatclient or keystone is not installed %s" % e)
53
54import json
55import glob
56from os.path import basename
57from yaml import load, dump
58
59HEAT_ROOT = "/srv/heat/env"
60
61TEMPLATE_PATH = "template"
62ENV_PATH ="env"
63
64HOT = ".hot"
65ENV = ".env"
66
67HOT_MASK = "*%s" % HOT
68ENV_MASK = "*%s" % ENV
69
70
71def _autheticate(func_name):
72 '''
73 Authenticate requests with the salt keystone module and format return data
74 '''
75 @wraps(func_name)
76 def decorator_method(*args, **kwargs):
77 '''
78 Authenticate request and format return data
79 '''
80 connection_args = {'profile': kwargs.get('profile', None)}
81 nkwargs = {}
82 for kwarg in kwargs:
83 if 'connection_' in kwarg:
84 connection_args.update({kwarg: kwargs[kwarg]})
85 elif '__' not in kwarg:
86 nkwargs.update({kwarg: kwargs[kwarg]})
87 kstone = __salt__['keystone.auth'](**connection_args)
88 token = kstone.auth_token
89 endpoint = kstone.service_catalog.url_for(
90 service_type='orchestration',
91 endpoint_type='publicURL')
92 heat_interface = client.Client(
93 endpoint_url=endpoint, token=token)
94 return_data = func_name(heat_interface, *args, **nkwargs)
95 if isinstance(return_data, list):
96 # format list as a dict for rendering
97 return {data.get('name', None) or data['id']: data
98 for data in return_data}
99 return return_data
100 return decorator_method
101
102
103def _filename(path):
104 """
105 helper
106 return filename without extension
107 """
108 return basename(path).split(".")[0]
109
110
111def _get_templates(choices=True):
112 """
113 if choices is False return array of full path
114 """
115
116 path = "/".join([HEAT_ROOT, TEMPLATE_PATH])
117
118 templates = []
119
120 for path in glob.glob("/".join([path, HOT_MASK])):
121 name = filename(path)
122 templates.append((name, name.replace("_", " ").capitalize()))
123
124 return sorted(templates)
125
126
127def _get_environments(template_name=None):
128 """return environments choices
129 """
130 path = "/".join([HEAT_ROOT, ENV_PATH])
131
132 environments = []
133
134 if template_name:
135 join = [path, template_name, ENV_MASK]
136 else:
137 join = [path, ENV_MASK]
138
139 for path in glob.glob("/".join(join)):
140 name = filename(path)
141 environments.append((name, name.replace("_", " ").capitalize()))
142
143 return sorted(environments)
144
145
146def _get_template_data(name):
147 """
148 load and return template data
149 """
150
151 path = "/".join([
152 HEAT_ROOT,
153 TEMPLATE_PATH,
154 "".join([name, HOT])
155 ])
156
157 try:
158 f = open(path, 'r')
159 data = load(f)
160 except Exception, e:
161 raise e
162
163 return data
164
165
166def _get_environment_data(template_name, name):
167 """
168 load and return parameters data
169 """
170
171 path = "/".join([
172 HEAT_ROOT,
173 ENV_PATH,
174 template_name,
175 "".join([name, ENV])
176 ])
177
178 try:
179 f = open(path, 'r')
180 data = load(f)
181 except Exception, e:
182 raise e
183
184 return data
185
186
187def __virtual__():
188 '''
189 Only load this module if Heat
190 is installed on this minion.
191 '''
192 if HAS_HEAT:
193 return 'heat'
194 return False
195
196__opts__ = {}
197
198
199def stack_list(tenant=None, **kwargs):
200
201 heat = heatclient()
202
203 ret = {}
204 ret["result"] = heat.stacks.list()
205
206 return ret
207
208
209def stack_create(template, environment=None, name=None, parameters=None, timeout_mins=5,
210 enable_rollback=True, **kwargs):
211 '''
212 Return a specific endpoint (gitlab endpoint-get)
213
214 :params template: template name
215 :params name: if not provided template will be used
216
217 CLI Example:
218
219 .. code-block:: bash
220
221 salt '*' heat.stack_create template_name
222 '''
223
224 heat = heatclient()
225
226 # get template
227
228 template_data = get_template_data(template)
229
230 # Validate the template and get back the params.
231 kwargs = {}
232 kwargs['template'] = str(json.dumps(template_data, cls=CustomEncoder))
233
234 try:
235 validated = heat.stacks.validate(**kwargs)
236 except Exception as e:
237 LOG.error("Template not valid %s" % e)
238
239 fields = {
240 'stack_name': name,
241 'template': json.dumps(template_data, cls=CustomEncoder),
242 'environment': parameters,
243 'parameters': parameters,
244 'timeout_mins': timeout_mins,
245 'disable_rollback': enable_rollback,
246 }
247 #LOG.debug(dir(heat))
248
249 heat.stacks.create(**fields)
250
251 return {'status': result}
252
253
254def stack_delete(template, name=None, parameters=None, **kwargs):
255
256 return {'Error': 'Could not delete stack.'}
257