X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Femuvim%2Fapi%2Fopenstack%2Fopenstack_dummies%2Fheat_dummy_api.py;fp=src%2Femuvim%2Fapi%2Fopenstack%2Fopenstack_dummies%2Fheat_dummy_api.py;h=f696442b74cddc19a7a0b3f32d4113ef022fbc14;hb=00199782de7042b51927bbbac5540d6f671597bb;hp=0000000000000000000000000000000000000000;hpb=0d8066654408ea1994d599c12c61b13709055a2d;p=osm%2Fvim-emu.git diff --git a/src/emuvim/api/openstack/openstack_dummies/heat_dummy_api.py b/src/emuvim/api/openstack/openstack_dummies/heat_dummy_api.py new file mode 100644 index 0000000..f696442 --- /dev/null +++ b/src/emuvim/api/openstack/openstack_dummies/heat_dummy_api.py @@ -0,0 +1,310 @@ +from flask import request, Response +from flask_restful import Resource +from emuvim.api.openstack.resources import Stack +from emuvim.api.openstack.openstack_dummies.base_openstack_dummy import BaseOpenstackDummy +from datetime import datetime +from emuvim.api.openstack.heat_parser import HeatParser +import logging +import json + + +class HeatDummyApi(BaseOpenstackDummy): + def __init__(self, in_ip, in_port, compute): + super(HeatDummyApi, self).__init__(in_ip, in_port) + self.compute = compute + + self.api.add_resource(Shutdown, "/shutdown") + self.api.add_resource(HeatListAPIVersions, "/", + resource_class_kwargs={'api': self}) + self.api.add_resource(HeatCreateStack, "/v1//stacks", + resource_class_kwargs={'api': self}) + self.api.add_resource(HeatShowStack, "/v1//stacks/", + "/v1//stacks//", + resource_class_kwargs={'api': self}) + self.api.add_resource(HeatUpdateStack, "/v1//stacks/", + "/v1//stacks//", + resource_class_kwargs={'api': self}) + self.api.add_resource(HeatDeleteStack, "/v1//stacks/", + "/v1//stacks//", + resource_class_kwargs={'api': self}) + + @self.app.after_request + def add_access_control_header(response): + response.headers['Access-Control-Allow-Origin'] = '*' + return response + + + def _start_flask(self): + logging.info("Starting %s endpoint @ http://%s:%d" % (__name__, self.ip, self.port)) + if self.app is not None: + self.app.before_request(self.dump_playbook) + self.app.run(self.ip, self.port, debug=True, use_reloader=False) + + +class Shutdown(Resource): + """ + A get request to /shutdown will shut down this endpoint. + """ + + def get(self): + logging.debug(("%s is beeing shut down") % (__name__)) + func = request.environ.get('werkzeug.server.shutdown') + if func is None: + raise RuntimeError('Not running with the Werkzeug Server') + func() + + +class HeatListAPIVersions(Resource): + def __init__(self, api): + self.api = api + + def get(self): + logging.debug("API CALL: %s GET" % str(self.__class__.__name__)) + resp = dict() + + resp['versions'] = dict() + resp['versions'] = [{ + "status": "CURRENT", + "id": "v1.0", + "links": [ + { + "href": "http://%s:%d/v2.0" % (self.api.ip, self.api.port), + "rel": "self" + } + ] + }] + + return Response(json.dumps(resp), status=200, mimetype="application/json") + + +class HeatCreateStack(Resource): + def __init__(self, api): + self.api = api + + def post(self, tenant_id): + """ + Create and deploy a new stack. + + :param tenant_id: + :return: 409, if the stack name was already used. + 400, if the heat template could not be parsed properly. + 500, if any exception occurred while creation. + 201, if everything worked out. + """ + logging.debug("API CALL: %s POST" % str(self.__class__.__name__)) + + try: + stack_dict = json.loads(request.data) + for stack in self.api.compute.stacks.values(): + if stack.stack_name == stack_dict['stack_name']: + return [], 409 + stack = Stack() + stack.stack_name = stack_dict['stack_name'] + reader = HeatParser(self.api.compute) + + if isinstance(stack_dict['template'], str) or isinstance(stack_dict['template'], unicode): + stack_dict['template'] = json.loads(stack_dict['template']) + if not reader.parse_input(stack_dict['template'], stack, self.api.compute.dc.label): + self.api.compute.clean_broken_stack(stack) + return 'Could not create stack.', 400 + + stack.creation_time = str(datetime.now()) + stack.status = "CREATE_COMPLETE" + + return_dict = {"stack": {"id": stack.id, + "links": [ + { + "href": "http://%s:%s/v1/%s/stacks/%s" + % (self.api.ip, self.api.port, tenant_id, stack.id), + "rel": "self" + }]}} + + self.api.compute.add_stack(stack) + self.api.compute.deploy_stack(stack.id) + return Response(json.dumps(return_dict), status=201, mimetype="application/json") + + except Exception as ex: + logging.exception("Heat: Create Stack exception.") + return ex.message, 500 + + def get(self, tenant_id): + """ + Calculates information about the requested stack. + + :param tenant_id: + :return: Returns a json response which contains information like the stack id, name, status, creation time. + 500, if any exception occurred. + 200, if everything worked out. + """ + logging.debug("API CALL: %s GET" % str(self.__class__.__name__)) + try: + return_stacks = dict() + return_stacks['stacks'] = list() + for stack in self.api.compute.stacks.values(): + return_stacks['stacks'].append( + {"creation_time": stack.creation_time, + "description": "desc of " + stack.id, + "id": stack.id, + "links": [], + "stack_name": stack.stack_name, + "stack_status": stack.status, + "stack_status_reason": "Stack CREATE completed successfully", + "updated_time": stack.update_time, + "tags": "" + }) + + return Response(json.dumps(return_stacks), status=200, mimetype="application/json") + except Exception as ex: + logging.exception("Heat: List Stack exception.") + return ex.message, 500 + + +class HeatShowStack(Resource): + def __init__(self, api): + self.api = api + + def get(self, tenant_id, stack_name_or_id, stack_id=None): + """ + Calculates detailed information about the requested stack. + + :param tenant_id: + :param stack_name_or_id: + :param stack_id: + :return: Returns a json response which contains information like the stack id, name, status, creation time. + 500, if any exception occurred. + 200, if everything worked out. + """ + logging.debug("API CALL: %s GET" % str(self.__class__.__name__)) + try: + stack = None + if stack_name_or_id in self.api.compute.stacks: + stack = self.api.compute.stacks[stack_name_or_id] + else: + for tmp_stack in self.api.compute.stacks.values(): + if tmp_stack.stack_name == stack_name_or_id: + stack = tmp_stack + if stack is None: + return 'Could not resolve Stack - ID', 404 + + return_stack = { + "stack": { + "capabilities": [], + "creation_time": stack.creation_time, + "description": "desc of " + stack.stack_name, + "disable_rollback": True, + "id": stack.id, + "links": [ + { + "href": "http://%s:%s/v1/%s/stacks/%s" + % (self.api.ip, self.api.port, tenant_id, stack.id), + "rel": "self" + } + ], + "notification_topics": [], + "outputs": [], + "parameters": { + "OS::project_id": "3ab5b02f-a01f-4f95-afa1-e254afc4a435", # add real project id + "OS::stack_id": stack.id, + "OS::stack_name": stack.stack_name + }, + "stack_name": stack.stack_name, + "stack_owner": "The owner of the stack.", # add stack owner + "stack_status": stack.status, + "stack_status_reason": "The reason for the current status of the stack.", # add status reason + "template_description": "The description of the stack template.", + "stack_user_project_id": "The project UUID of the stack user.", + "timeout_mins": "", + "updated_time": "", + "parent": "", + "tags": "" + } + } + + return Response(json.dumps(return_stack), status=200, mimetype="application/json") + + except Exception as ex: + logging.exception("Heat: Show stack exception.") + return ex.message, 500 + + +class HeatUpdateStack(Resource): + def __init__(self, api): + self.api = api + + def put(self, tenant_id, stack_name_or_id, stack_id=None): + """ + Updates an existing stack with a new heat template. + + :param tenant_id: + :param stack_name_or_id: Specifies the stack, which should be updated. + :param stack_id: + :return: 404, if the requested stack could not be found. + 400, if the stack creation (because of errors in the heat template) or the stack update failed. + 500, if any exception occurred while updating. + 202, if everything worked out. + """ + logging.debug("API CALL: %s PUT" % str(self.__class__.__name__)) + try: + old_stack = None + if stack_name_or_id in self.api.compute.stacks: + old_stack = self.api.compute.stacks[stack_name_or_id] + else: + for tmp_stack in self.api.compute.stacks.values(): + if tmp_stack.stack_name == stack_name_or_id: + old_stack = tmp_stack + if old_stack is None: + return 'Could not resolve Stack - ID', 404 + + stack_dict = json.loads(request.data) + + stack = Stack() + stack.stack_name = old_stack.stack_name + stack.id = old_stack.id + stack.creation_time = old_stack.creation_time + stack.update_time = str(datetime.now()) + stack.status = "UPDATE_COMPLETE" + + reader = HeatParser(self.api.compute) + if isinstance(stack_dict['template'], str) or isinstance(stack_dict['template'], unicode): + stack_dict['template'] = json.loads(stack_dict['template']) + if not reader.parse_input(stack_dict['template'], stack, self.api.compute.dc.label, stack_update=True): + return 'Could not create stack.', 400 + + if not self.api.compute.update_stack(old_stack.id, stack): + return 'Could not update stack.', 400 + + return Response(status=202, mimetype="application/json") + + except Exception as ex: + logging.exception("Heat: Update Stack exception") + return ex.message, 500 + + +class HeatDeleteStack(Resource): + def __init__(self, api): + self.api = api + + def delete(self, tenant_id, stack_name_or_id, stack_id=None): + """ + Deletes an existing stack. + + :param tenant_id: + :param stack_name_or_id: Specifies the stack, which should be deleted. + :param stack_id: + :return: 500, if any exception occurred while deletion. + 204, if everything worked out. + """ + logging.debug("API CALL: %s DELETE" % str(self.__class__.__name__)) + try: + if stack_name_or_id in self.api.compute.stacks: + self.api.compute.delete_stack(stack_name_or_id) + return Response('Deleted Stack: ' + stack_name_or_id, 204) + + for stack in self.api.compute.stacks.values(): + if stack.stack_name == stack_name_or_id: + self.api.compute.delete_stack(stack.id) + return Response('Deleted Stack: ' + stack_name_or_id, 204) + + except Exception as ex: + logging.exception("Heat: Delete Stack exception") + return ex.message, 500