From cb48af0fe8e8019b0f94e4ff4c4f73c624034db5 Mon Sep 17 00:00:00 2001 From: Stan Lagun Date: Mon, 19 Aug 2013 18:26:08 +0400 Subject: [PATCH] OpenStack Heat plugin that exposes Murano environment as a resource (alpha) Change-Id: I4f361541bf3a5146f010659ce80e3038d3fbab86 --- heatplugin/README | 9 +++ heatplugin/murano/__init__.py | 0 heatplugin/murano/environment.py | 105 +++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 heatplugin/README create mode 100644 heatplugin/murano/__init__.py create mode 100644 heatplugin/murano/environment.py diff --git a/heatplugin/README b/heatplugin/README new file mode 100644 index 0000000..520c911 --- /dev/null +++ b/heatplugin/README @@ -0,0 +1,9 @@ +OpenStack Heat plugin for Murano + +Copy murano directory to resources directory of your Heat installation +(/opt/stack/heat/heat/engine/resources for DevStack) + +Plugin exposes new Heat resource of type Murano::Environment with two properties: +1. Body - JSON-encoded Murano environment definition +2. MuranoApiEndpoint - optional Murano API endpoint URL. + If not specified then it aumatically discovered via Keystone \ No newline at end of file diff --git a/heatplugin/murano/__init__.py b/heatplugin/murano/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/heatplugin/murano/environment.py b/heatplugin/murano/environment.py new file mode 100644 index 0000000..a748d8d --- /dev/null +++ b/heatplugin/murano/environment.py @@ -0,0 +1,105 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import eventlet +from heat.openstack.common import log as logging +from heat.engine import resource +from muranoclient.v1.client import Client +from muranoclient.common.exceptions import HTTPNotFound +logger = logging.getLogger(__name__) + + +class MuranoEnvironment(resource.Resource): + properties_schema = { + 'Body': {'Type': 'Map', 'Required': True}, + 'MuranoApiEndpoint': {'Type': 'String'} + } + update_allowed_keys = ('Metadata', 'Properties') + update_allowed_properties = ('Definition', 'MuranoApiEndpoint') + attributes_schema = {} + + def __init__(self, name, json_snippet, stack): + super(MuranoEnvironment, self).__init__(name, json_snippet, stack) + + def handle_create(self): + self._update_environment() + + def handle_delete(self): + client = self._muranoclient() + environment_id = self._find_environment(client) + if environment_id: + client.environments.delete(environment_id) + try: + self._wait_deployed(client, environment_id) + except HTTPNotFound: + pass + + + def _find_environment(self, client): + environments = client.environments.list() + for environment in environments: + if environment.name == self.name: + return environment.id + return None + + def _update_environment(self): + client = self._muranoclient() + environment_id = self._find_environment(client) + if not environment_id: + environment_id = client.environments.create(self.name).id + + session_id = client.sessions.configure(environment_id).id + environment = self.properties.get('Body') + client.services.post(environment_id, + path='/', + data=environment.get('services', []), + session_id=session_id) + client.sessions.deploy(environment_id, session_id) + self._wait_deployed(client, environment_id) + + def _wait_deployed(self, client, environment_id): + i = 0 + delay = 2 + while True: + environment = client.environments.get(environment_id) + if environment.status == 'pending' and i > 5*60: + raise EnvironmentError( + "Environment deployment hasn't started") + elif environment.status == 'deploying' and i > 65*60: + raise EnvironmentError( + "Environment deployment takes too long") + elif environment.status == 'ready': + break + eventlet.sleep(delay) + i += delay + + def _muranoclient(self): + endpoint = self._get_endpoint() + token = self.stack.clients.auth_token + return Client(endpoint=endpoint, token=token) + + def _get_endpoint(self): + #prefer location specified in settings for dev purposes + endpoint = self.properties.get('MuranoApiEndpoint') + if not endpoint: + endpoint = self.stack.clients.url_for(service_type='murano') + return endpoint + + +def resource_mapping(): + return { + 'Murano::Environment': MuranoEnvironment + }