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 class HeatDummyApi(BaseOpenstackDummy
):
12 def __init__(self
, in_ip
, in_port
, compute
):
13 super(HeatDummyApi
, self
).__init
__(in_ip
, in_port
)
14 self
.compute
= compute
16 self
.api
.add_resource(Shutdown
, "/shutdown")
17 self
.api
.add_resource(HeatListAPIVersions
, "/",
18 resource_class_kwargs
={'api': self
})
19 self
.api
.add_resource(HeatCreateStack
, "/v1/<tenant_id>/stacks",
20 resource_class_kwargs
={'api': self
})
21 self
.api
.add_resource(HeatShowStack
, "/v1/<tenant_id>/stacks/<stack_name_or_id>",
22 "/v1/<tenant_id>/stacks/<stack_name_or_id>/<stack_id>",
23 resource_class_kwargs
={'api': self
})
24 self
.api
.add_resource(HeatUpdateStack
, "/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(HeatDeleteStack
, "/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
})
31 @self.app
.after_request
32 def add_access_control_header(response
):
33 response
.headers
['Access-Control-Allow-Origin'] = '*'
37 def _start_flask(self
):
38 logging
.info("Starting %s endpoint @ http://%s:%d" % (__name__
, self
.ip
, self
.port
))
39 if self
.app
is not None:
40 self
.app
.before_request(self
.dump_playbook
)
41 self
.app
.run(self
.ip
, self
.port
, debug
=True, use_reloader
=False)
44 class Shutdown(Resource
):
46 A get request to /shutdown will shut down this endpoint.
50 logging
.debug(("%s is beeing shut down") % (__name__
))
51 func
= request
.environ
.get('werkzeug.server.shutdown')
53 raise RuntimeError('Not running with the Werkzeug Server')
57 class HeatListAPIVersions(Resource
):
58 def __init__(self
, api
):
62 logging
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
65 resp
['versions'] = dict()
71 "href": "http://%s:%d/v2.0" % (self
.api
.ip
, self
.api
.port
),
77 return Response(json
.dumps(resp
), status
=200, mimetype
="application/json")
80 class HeatCreateStack(Resource
):
81 def __init__(self
, api
):
84 def post(self
, tenant_id
):
86 Create and deploy a new stack.
89 :return: 409, if the stack name was already used.
90 400, if the heat template could not be parsed properly.
91 500, if any exception occurred while creation.
92 201, if everything worked out.
94 logging
.debug("API CALL: %s POST" % str(self
.__class
__.__name
__))
97 stack_dict
= json
.loads(request
.data
)
98 for stack
in self
.api
.compute
.stacks
.values():
99 if stack
.stack_name
== stack_dict
['stack_name']:
102 stack
.stack_name
= stack_dict
['stack_name']
103 reader
= HeatParser(self
.api
.compute
)
105 if isinstance(stack_dict
['template'], str) or isinstance(stack_dict
['template'], unicode):
106 stack_dict
['template'] = json
.loads(stack_dict
['template'])
107 if not reader
.parse_input(stack_dict
['template'], stack
, self
.api
.compute
.dc
.label
):
108 self
.api
.compute
.clean_broken_stack(stack
)
109 return 'Could not create stack.', 400
111 stack
.creation_time
= str(datetime
.now())
112 stack
.status
= "CREATE_COMPLETE"
114 return_dict
= {"stack": {"id": stack
.id,
117 "href": "http://%s:%s/v1/%s/stacks/%s"
118 % (self
.api
.ip
, self
.api
.port
, tenant_id
, stack
.id),
122 self
.api
.compute
.add_stack(stack
)
123 self
.api
.compute
.deploy_stack(stack
.id)
124 return Response(json
.dumps(return_dict
), status
=201, mimetype
="application/json")
126 except Exception as ex
:
127 logging
.exception("Heat: Create Stack exception.")
128 return ex
.message
, 500
130 def get(self
, tenant_id
):
132 Calculates information about the requested stack.
135 :return: Returns a json response which contains information like the stack id, name, status, creation time.
136 500, if any exception occurred.
137 200, if everything worked out.
139 logging
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
141 return_stacks
= dict()
142 return_stacks
['stacks'] = list()
143 for stack
in self
.api
.compute
.stacks
.values():
144 return_stacks
['stacks'].append(
145 {"creation_time": stack
.creation_time
,
146 "description": "desc of " + stack
.id,
149 "stack_name": stack
.stack_name
,
150 "stack_status": stack
.status
,
151 "stack_status_reason": "Stack CREATE completed successfully",
152 "updated_time": stack
.update_time
,
156 return Response(json
.dumps(return_stacks
), status
=200, mimetype
="application/json")
157 except Exception as ex
:
158 logging
.exception("Heat: List Stack exception.")
159 return ex
.message
, 500
162 class HeatShowStack(Resource
):
163 def __init__(self
, api
):
166 def get(self
, tenant_id
, stack_name_or_id
, stack_id
=None):
168 Calculates detailed information about the requested stack.
171 :param stack_name_or_id:
173 :return: Returns a json response which contains information like the stack id, name, status, creation time.
174 500, if any exception occurred.
175 200, if everything worked out.
177 logging
.debug("API CALL: %s GET" % str(self
.__class
__.__name
__))
180 if stack_name_or_id
in self
.api
.compute
.stacks
:
181 stack
= self
.api
.compute
.stacks
[stack_name_or_id
]
183 for tmp_stack
in self
.api
.compute
.stacks
.values():
184 if tmp_stack
.stack_name
== stack_name_or_id
:
187 return 'Could not resolve Stack - ID', 404
192 "creation_time": stack
.creation_time
,
193 "description": "desc of " + stack
.stack_name
,
194 "disable_rollback": True,
198 "href": "http://%s:%s/v1/%s/stacks/%s"
199 % (self
.api
.ip
, self
.api
.port
, tenant_id
, stack
.id),
203 "notification_topics": [],
206 "OS::project_id": "3ab5b02f-a01f-4f95-afa1-e254afc4a435", # add real project id
207 "OS::stack_id": stack
.id,
208 "OS::stack_name": stack
.stack_name
210 "stack_name": stack
.stack_name
,
211 "stack_owner": "The owner of the stack.", # add stack owner
212 "stack_status": stack
.status
,
213 "stack_status_reason": "The reason for the current status of the stack.", # add status reason
214 "template_description": "The description of the stack template.",
215 "stack_user_project_id": "The project UUID of the stack user.",
223 return Response(json
.dumps(return_stack
), status
=200, mimetype
="application/json")
225 except Exception as ex
:
226 logging
.exception("Heat: Show stack exception.")
227 return ex
.message
, 500
230 class HeatUpdateStack(Resource
):
231 def __init__(self
, api
):
234 def put(self
, tenant_id
, stack_name_or_id
, stack_id
=None):
236 Updates an existing stack with a new heat template.
239 :param stack_name_or_id: Specifies the stack, which should be updated.
241 :return: 404, if the requested stack could not be found.
242 400, if the stack creation (because of errors in the heat template) or the stack update failed.
243 500, if any exception occurred while updating.
244 202, if everything worked out.
246 logging
.debug("API CALL: %s PUT" % str(self
.__class
__.__name
__))
249 if stack_name_or_id
in self
.api
.compute
.stacks
:
250 old_stack
= self
.api
.compute
.stacks
[stack_name_or_id
]
252 for tmp_stack
in self
.api
.compute
.stacks
.values():
253 if tmp_stack
.stack_name
== stack_name_or_id
:
254 old_stack
= tmp_stack
255 if old_stack
is None:
256 return 'Could not resolve Stack - ID', 404
258 stack_dict
= json
.loads(request
.data
)
261 stack
.stack_name
= old_stack
.stack_name
262 stack
.id = old_stack
.id
263 stack
.creation_time
= old_stack
.creation_time
264 stack
.update_time
= str(datetime
.now())
265 stack
.status
= "UPDATE_COMPLETE"
267 reader
= HeatParser(self
.api
.compute
)
268 if isinstance(stack_dict
['template'], str) or isinstance(stack_dict
['template'], unicode):
269 stack_dict
['template'] = json
.loads(stack_dict
['template'])
270 if not reader
.parse_input(stack_dict
['template'], stack
, self
.api
.compute
.dc
.label
, stack_update
=True):
271 return 'Could not create stack.', 400
273 if not self
.api
.compute
.update_stack(old_stack
.id, stack
):
274 return 'Could not update stack.', 400
276 return Response(status
=202, mimetype
="application/json")
278 except Exception as ex
:
279 logging
.exception("Heat: Update Stack exception")
280 return ex
.message
, 500
283 class HeatDeleteStack(Resource
):
284 def __init__(self
, api
):
287 def delete(self
, tenant_id
, stack_name_or_id
, stack_id
=None):
289 Deletes an existing stack.
292 :param stack_name_or_id: Specifies the stack, which should be deleted.
294 :return: 500, if any exception occurred while deletion.
295 204, if everything worked out.
297 logging
.debug("API CALL: %s DELETE" % str(self
.__class
__.__name
__))
299 if stack_name_or_id
in self
.api
.compute
.stacks
:
300 self
.api
.compute
.delete_stack(stack_name_or_id
)
301 return Response('Deleted Stack: ' + stack_name_or_id
, 204)
303 for stack
in self
.api
.compute
.stacks
.values():
304 if stack
.stack_name
== stack_name_or_id
:
305 self
.api
.compute
.delete_stack(stack
.id)
306 return Response('Deleted Stack: ' + stack_name_or_id
, 204)
308 except Exception as ex
:
309 logging
.exception("Heat: Delete Stack exception")
310 return ex
.message
, 500