2c7bdf3f6520c0d8bf920ba5bb1dc83eb49b27a2
[osm/vim-emu.git] / src / emuvim / api / openstack / openstack_dummies / heat_dummy_api.py
1 from flask import request, Response
2 from flask_restful import Resource
3 from emuvim.api.openstack.resources import Stack
4 from emuvim.api.openstack.openstack_dummies.base_openstack_dummy import BaseOpenstackDummy
5 from datetime import datetime
6 from emuvim.api.openstack.heat_parser import HeatParser
7 import logging
8 import json
9
10
11 LOG = logging.getLogger("api.openstack.heat")
12
13
14 class HeatDummyApi(BaseOpenstackDummy):
15 def __init__(self, in_ip, in_port, compute):
16 super(HeatDummyApi, self).__init__(in_ip, in_port)
17 self.compute = compute
18
19 self.api.add_resource(Shutdown, "/shutdown")
20 self.api.add_resource(HeatListAPIVersions, "/",
21 resource_class_kwargs={'api': self})
22 self.api.add_resource(HeatCreateStack, "/v1/<tenant_id>/stacks",
23 resource_class_kwargs={'api': self})
24 self.api.add_resource(HeatShowStack, "/v1/<tenant_id>/stacks/<stack_name_or_id>",
25 "/v1/<tenant_id>/stacks/<stack_name_or_id>/<stack_id>",
26 resource_class_kwargs={'api': self})
27 self.api.add_resource(HeatUpdateStack, "/v1/<tenant_id>/stacks/<stack_name_or_id>",
28 "/v1/<tenant_id>/stacks/<stack_name_or_id>/<stack_id>",
29 resource_class_kwargs={'api': self})
30 self.api.add_resource(HeatDeleteStack, "/v1/<tenant_id>/stacks/<stack_name_or_id>",
31 "/v1/<tenant_id>/stacks/<stack_name_or_id>/<stack_id>",
32 resource_class_kwargs={'api': self})
33
34 @self.app.after_request
35 def add_access_control_header(response):
36 response.headers['Access-Control-Allow-Origin'] = '*'
37 return response
38
39
40 def _start_flask(self):
41 LOG.info("Starting %s endpoint @ http://%s:%d" % (__name__, self.ip, self.port))
42 if self.app is not None:
43 self.app.before_request(self.dump_playbook)
44 self.app.run(self.ip, self.port, debug=True, use_reloader=False)
45
46
47 class Shutdown(Resource):
48 """
49 A get request to /shutdown will shut down this endpoint.
50 """
51
52 def get(self):
53 LOG.debug(("%s is beeing shut down") % (__name__))
54 func = request.environ.get('werkzeug.server.shutdown')
55 if func is None:
56 raise RuntimeError('Not running with the Werkzeug Server')
57 func()
58
59
60 class HeatListAPIVersions(Resource):
61 def __init__(self, api):
62 self.api = api
63
64 def get(self):
65 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
66 resp = dict()
67
68 resp['versions'] = dict()
69 resp['versions'] = [{
70 "status": "CURRENT",
71 "id": "v1.0",
72 "links": [
73 {
74 "href": "http://%s:%d/v2.0" % (self.api.ip, self.api.port),
75 "rel": "self"
76 }
77 ]
78 }]
79
80 return Response(json.dumps(resp), status=200, mimetype="application/json")
81
82
83 class HeatCreateStack(Resource):
84 def __init__(self, api):
85 self.api = api
86
87 def post(self, tenant_id):
88 """
89 Create and deploy a new stack.
90
91 :param tenant_id:
92 :return: 409, if the stack name was already used.
93 400, if the heat template could not be parsed properly.
94 500, if any exception occurred while creation.
95 201, if everything worked out.
96 """
97 LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
98
99 try:
100 stack_dict = json.loads(request.data)
101 for stack in self.api.compute.stacks.values():
102 if stack.stack_name == stack_dict['stack_name']:
103 return [], 409
104 stack = Stack()
105 stack.stack_name = stack_dict['stack_name']
106 reader = HeatParser(self.api.compute)
107
108 if isinstance(stack_dict['template'], str) or isinstance(stack_dict['template'], unicode):
109 stack_dict['template'] = json.loads(stack_dict['template'])
110 if not reader.parse_input(stack_dict['template'], stack, self.api.compute.dc.label):
111 self.api.compute.clean_broken_stack(stack)
112 return 'Could not create stack.', 400
113
114 stack.creation_time = str(datetime.now())
115 stack.status = "CREATE_COMPLETE"
116
117 return_dict = {"stack": {"id": stack.id,
118 "links": [
119 {
120 "href": "http://%s:%s/v1/%s/stacks/%s"
121 % (self.api.ip, self.api.port, tenant_id, stack.id),
122 "rel": "self"
123 }]}}
124
125 self.api.compute.add_stack(stack)
126 self.api.compute.deploy_stack(stack.id)
127 return Response(json.dumps(return_dict), status=201, mimetype="application/json")
128
129 except Exception as ex:
130 LOG.exception("Heat: Create Stack exception.")
131 return ex.message, 500
132
133 def get(self, tenant_id):
134 """
135 Calculates information about the requested stack.
136
137 :param tenant_id:
138 :return: Returns a json response which contains information like the stack id, name, status, creation time.
139 500, if any exception occurred.
140 200, if everything worked out.
141 """
142 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
143 try:
144 return_stacks = dict()
145 return_stacks['stacks'] = list()
146 for stack in self.api.compute.stacks.values():
147 return_stacks['stacks'].append(
148 {"creation_time": stack.creation_time,
149 "description": "desc of " + stack.id,
150 "id": stack.id,
151 "links": [],
152 "stack_name": stack.stack_name,
153 "stack_status": stack.status,
154 "stack_status_reason": "Stack CREATE completed successfully",
155 "updated_time": stack.update_time,
156 "tags": ""
157 })
158
159 return Response(json.dumps(return_stacks), status=200, mimetype="application/json")
160 except Exception as ex:
161 LOG.exception("Heat: List Stack exception.")
162 return ex.message, 500
163
164
165 class HeatShowStack(Resource):
166 def __init__(self, api):
167 self.api = api
168
169 def get(self, tenant_id, stack_name_or_id, stack_id=None):
170 """
171 Calculates detailed information about the requested stack.
172
173 :param tenant_id:
174 :param stack_name_or_id:
175 :param stack_id:
176 :return: Returns a json response which contains information like the stack id, name, status, creation time.
177 500, if any exception occurred.
178 200, if everything worked out.
179 """
180 LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
181 try:
182 stack = None
183 if stack_name_or_id in self.api.compute.stacks:
184 stack = self.api.compute.stacks[stack_name_or_id]
185 else:
186 for tmp_stack in self.api.compute.stacks.values():
187 if tmp_stack.stack_name == stack_name_or_id:
188 stack = tmp_stack
189 if stack is None:
190 return 'Could not resolve Stack - ID', 404
191
192 return_stack = {
193 "stack": {
194 "capabilities": [],
195 "creation_time": stack.creation_time,
196 "description": "desc of " + stack.stack_name,
197 "disable_rollback": True,
198 "id": stack.id,
199 "links": [
200 {
201 "href": "http://%s:%s/v1/%s/stacks/%s"
202 % (self.api.ip, self.api.port, tenant_id, stack.id),
203 "rel": "self"
204 }
205 ],
206 "notification_topics": [],
207 "outputs": [],
208 "parameters": {
209 "OS::project_id": "3ab5b02f-a01f-4f95-afa1-e254afc4a435", # add real project id
210 "OS::stack_id": stack.id,
211 "OS::stack_name": stack.stack_name
212 },
213 "stack_name": stack.stack_name,
214 "stack_owner": "The owner of the stack.", # add stack owner
215 "stack_status": stack.status,
216 "stack_status_reason": "The reason for the current status of the stack.", # add status reason
217 "template_description": "The description of the stack template.",
218 "stack_user_project_id": "The project UUID of the stack user.",
219 "timeout_mins": "",
220 "updated_time": "",
221 "parent": "",
222 "tags": ""
223 }
224 }
225
226 return Response(json.dumps(return_stack), status=200, mimetype="application/json")
227
228 except Exception as ex:
229 LOG.exception("Heat: Show stack exception.")
230 return ex.message, 500
231
232
233 class HeatUpdateStack(Resource):
234 def __init__(self, api):
235 self.api = api
236
237 def put(self, tenant_id, stack_name_or_id, stack_id=None):
238 """
239 Updates an existing stack with a new heat template.
240
241 :param tenant_id:
242 :param stack_name_or_id: Specifies the stack, which should be updated.
243 :param stack_id:
244 :return: 404, if the requested stack could not be found.
245 400, if the stack creation (because of errors in the heat template) or the stack update failed.
246 500, if any exception occurred while updating.
247 202, if everything worked out.
248 """
249 LOG.debug("API CALL: %s PUT" % str(self.__class__.__name__))
250 try:
251 old_stack = None
252 if stack_name_or_id in self.api.compute.stacks:
253 old_stack = self.api.compute.stacks[stack_name_or_id]
254 else:
255 for tmp_stack in self.api.compute.stacks.values():
256 if tmp_stack.stack_name == stack_name_or_id:
257 old_stack = tmp_stack
258 if old_stack is None:
259 return 'Could not resolve Stack - ID', 404
260
261 stack_dict = json.loads(request.data)
262
263 stack = Stack()
264 stack.stack_name = old_stack.stack_name
265 stack.id = old_stack.id
266 stack.creation_time = old_stack.creation_time
267 stack.update_time = str(datetime.now())
268 stack.status = "UPDATE_COMPLETE"
269
270 reader = HeatParser(self.api.compute)
271 if isinstance(stack_dict['template'], str) or isinstance(stack_dict['template'], unicode):
272 stack_dict['template'] = json.loads(stack_dict['template'])
273 if not reader.parse_input(stack_dict['template'], stack, self.api.compute.dc.label, stack_update=True):
274 return 'Could not create stack.', 400
275
276 if not self.api.compute.update_stack(old_stack.id, stack):
277 return 'Could not update stack.', 400
278
279 return Response(status=202, mimetype="application/json")
280
281 except Exception as ex:
282 LOG.exception("Heat: Update Stack exception")
283 return ex.message, 500
284
285
286 class HeatDeleteStack(Resource):
287 def __init__(self, api):
288 self.api = api
289
290 def delete(self, tenant_id, stack_name_or_id, stack_id=None):
291 """
292 Deletes an existing stack.
293
294 :param tenant_id:
295 :param stack_name_or_id: Specifies the stack, which should be deleted.
296 :param stack_id:
297 :return: 500, if any exception occurred while deletion.
298 204, if everything worked out.
299 """
300 LOG.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
301 try:
302 if stack_name_or_id in self.api.compute.stacks:
303 self.api.compute.delete_stack(stack_name_or_id)
304 return Response('Deleted Stack: ' + stack_name_or_id, 204)
305
306 for stack in self.api.compute.stacks.values():
307 if stack.stack_name == stack_name_or_id:
308 self.api.compute.delete_stack(stack.id)
309 return Response('Deleted Stack: ' + stack_name_or_id, 204)
310
311 except Exception as ex:
312 LOG.exception("Heat: Delete Stack exception")
313 return ex.message, 500