2c7bdf3f6520c0d8bf920ba5bb1dc83eb49b27a2
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
11 LOG
= logging
.getLogger("api.openstack.heat")
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
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
})
34 @self.app
.after_request
35 def add_access_control_header(response
):
36 response
.headers
['Access-Control-Allow-Origin'] = '*'
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)
47 class Shutdown(Resource
):
49 A get request to /shutdown will shut down this endpoint.
53 LOG
.debug(("%s is beeing shut down") % (__name__
))
54 func
= request
.environ
.get('werkzeug.server.shutdown')
56 raise RuntimeError('Not running with the Werkzeug Server')
60 class HeatListAPIVersions(Resource
):
61 def __init__(self
, api
):
65 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
68 resp
['versions'] = dict()
74 "href": "http://%s:%d/v2.0" % (self
.api
.ip
, self
.api
.port
),
80 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
83 class HeatCreateStack(Resource
):
84 def __init__(self
, api
):
87 def post(self
, tenant_id
):
89 Create and deploy a new stack.
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.
97 LOG
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
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']:
105 stack
.stack_name
= stack_dict
['stack_name']
106 reader
= HeatParser(self
.api
.compute
)
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
114 stack
.creation_time
= str(datetime
.now())
115 stack
.status
= "CREATE_COMPLETE"
117 return_dict
= {"stack": {"id": stack
.id,
120 "href": "http://%s:%s/v1/%s/stacks/%s"
121 % (self
.api
.ip
, self
.api
.port
, tenant_id
, stack
.id),
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")
129 except Exception as ex
:
130 LOG
.exception("Heat: Create Stack exception.")
131 return ex
.message
, 500
133 def get(self
, tenant_id
):
135 Calculates information about the requested stack.
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.
142 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
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,
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
,
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
165 class HeatShowStack(Resource
):
166 def __init__(self
, api
):
169 def get(self
, tenant_id
, stack_name_or_id
, stack_id
=None):
171 Calculates detailed information about the requested stack.
174 :param stack_name_or_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.
180 LOG
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
183 if stack_name_or_id
in self
.api
.compute
.stacks
:
184 stack
= self
.api
.compute
.stacks
[stack_name_or_id
]
186 for tmp_stack
in self
.api
.compute
.stacks
.values():
187 if tmp_stack
.stack_name
== stack_name_or_id
:
190 return 'Could not resolve Stack - ID', 404
195 "creation_time": stack
.creation_time
,
196 "description": "desc of " + stack
.stack_name
,
197 "disable_rollback": True,
201 "href": "http://%s:%s/v1/%s/stacks/%s"
202 % (self
.api
.ip
, self
.api
.port
, tenant_id
, stack
.id),
206 "notification_topics": [],
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
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.",
226 return Response(json
.dumps(return_stack
), status
=200, mimetype
="application/json")
228 except Exception as ex
:
229 LOG
.exception("Heat: Show stack exception.")
230 return ex
.message
, 500
233 class HeatUpdateStack(Resource
):
234 def __init__(self
, api
):
237 def put(self
, tenant_id
, stack_name_or_id
, stack_id
=None):
239 Updates an existing stack with a new heat template.
242 :param stack_name_or_id: Specifies the stack, which should be updated.
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.
249 LOG
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
252 if stack_name_or_id
in self
.api
.compute
.stacks
:
253 old_stack
= self
.api
.compute
.stacks
[stack_name_or_id
]
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
261 stack_dict
= json
.loads(request
.data
)
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"
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
276 if not self
.api
.compute
.update_stack(old_stack
.id, stack
):
277 return 'Could not update stack.', 400
279 return Response(status
=202, mimetype
="application/json")
281 except Exception as ex
:
282 LOG
.exception("Heat: Update Stack exception")
283 return ex
.message
, 500
286 class HeatDeleteStack(Resource
):
287 def __init__(self
, api
):
290 def delete(self
, tenant_id
, stack_name_or_id
, stack_id
=None):
292 Deletes an existing stack.
295 :param stack_name_or_id: Specifies the stack, which should be deleted.
297 :return: 500, if any exception occurred while deletion.
298 204, if everything worked out.
300 LOG
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
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)
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)
311 except Exception as ex
:
312 LOG
.exception("Heat: Delete Stack exception")
313 return ex
.message
, 500