diff options
Diffstat (limited to 'moon_manager/moon_manager/plugins/moon_openstack_plugin.py')
-rw-r--r-- | moon_manager/moon_manager/plugins/moon_openstack_plugin.py | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/moon_manager/moon_manager/plugins/moon_openstack_plugin.py b/moon_manager/moon_manager/plugins/moon_openstack_plugin.py new file mode 100644 index 00000000..a4b8a237 --- /dev/null +++ b/moon_manager/moon_manager/plugins/moon_openstack_plugin.py @@ -0,0 +1,203 @@ +# Software Name: MOON + +# Version: 5.4 + +# SPDX-FileCopyrightText: Copyright (c) 2018-2020 Orange and its contributors +# SPDX-License-Identifier: Apache-2.0 + +# This software is distributed under the 'Apache License 2.0', +# the text of which is available at 'http://www.apache.org/licenses/LICENSE-2.0.txt' +# or see the "LICENSE" file for more details. + +""" +Abstract plugin to request OpenStack infrastructure +""" + +import json +import logging +import time +import requests +from moon_manager.pip_driver import InformationDriver +from moon_manager.api.configuration import get_configuration +from moon_utilities.exceptions import MoonError + +LOGGER = logging.getLogger("moon.manager.plugins.moon_openstack_plugin") + +PLUGIN_TYPE = "information" +_ = str + + +# Keystone exceptions + + +class KeystoneError(MoonError): + description = _("There is an error connecting to Keystone.") + code = 400 + title = 'Keystone error' + logger = "ERROR" + + +class KeystoneProjectError(KeystoneError): + description = _("There is an error retrieving projects from the Keystone service.") + code = 400 + title = 'Keystone project error' + logger = "ERROR" + + +class KeystoneUserError(KeystoneError): + description = _("There is an error retrieving users from the Keystone service.") + code = 400 + title = 'Keystone user error' + logger = "ERROR" + + +class KeystoneUserConflict(KeystoneUserError): + description = _("A user with that name already exist.") + code = 400 + title = 'Keystone user error' + logger = "ERROR" + + +class OpenStackConnector(InformationDriver): + + def __init__(self, driver_name, engine_name, conf): + self.driver_name = driver_name + self.engine_name = engine_name + self.opst_conf = get_configuration("information") + + if not self.opst_conf: + raise Exception("Cannot find OpenStack configuration in configuration file") + + self.__headers = {} + self.__user = conf.get("user", self.opst_conf['user']) + self.__password = conf.get("password", self.opst_conf['password']) + self.__domain = conf.get("domain", self.opst_conf['domain']) + self.__project = conf.get("project", self.opst_conf['project']) + self.__url = conf.get("url", self.opst_conf['url']) + + def set_auth(self, **kwargs): + start_time = time.time() + user = kwargs.get("user", self.opst_conf['user']) + password = kwargs.get("password", self.opst_conf['password']) + domain = kwargs.get("domain", self.opst_conf['domain']) + project = kwargs.get("project", self.opst_conf['project']) + url = kwargs.get("url", self.opst_conf['url']) + headers = { + "Content-Type": "application/json" + } + data_auth = { + "auth": { + "identity": { + "methods": [ + "password" + ], + "password": { + "user": { + "domain": { + "id": domain + }, + "name": user, + "password": password + } + } + }, + "scope": { + "project": { + "domain": { + "id": domain + }, + "name": project + } + } + } + } + + while True: + req = requests.post("{}/auth/tokens".format(url), + json=data_auth, headers=headers, + verify=kwargs.get("certificate", self.opst_conf['certificate'])) + + if req.status_code in (200, 201, 204): + self.__headers['X-Auth-Token'] = req.headers['X-Subject-Token'] + return self.__headers + LOGGER.warning("Waiting for Keystone...") + if time.time() - start_time == 100: + LOGGER.error(req.text) + raise KeystoneError + time.sleep(5) + + def unset_auth(self, **kwargs): + url = kwargs.get("url", self.opst_conf['url']) + self.__headers['X-Subject-Token'] = self.__headers['X-Auth-Token'] + req = requests.delete("{}/auth/tokens".format(url), headers=self.__headers, + verify=kwargs.get("certificate", self.opst_conf['certificate'])) + if req.status_code in (200, 201, 204): + return + LOGGER.error(req.text) + raise KeystoneError + + def _get(self, endpoint, url=None, _exception=KeystoneError): + if not url: + if not self.__url: + LOGGER.warning("Cannot retrieve the URL for the OpenStack endpoint") + return {'users': []} + url = self.__url + + req = requests.get("{}{}".format(url, endpoint), + headers=self.__headers) + if req.status_code not in (200, 201): + LOGGER.error(req.text) + raise _exception + data = req.json() + return data + + def _post(self, endpoint, url=None, data=None, _exception=KeystoneError): + if not url: + if not self.__url: + LOGGER.warning("Cannot retrieve the URL for the OpenStack endpoint") + return {'users': []} + url = self.__url + + req = requests.post("{}{}".format(url, endpoint), + data=json.dumps(data), + headers=self.__headers) + if req.status_code == 409: + LOGGER.warning(req.text) + raise KeystoneUserConflict + if req.status_code not in (200, 201): + LOGGER.error(req.text) + raise _exception + data = req.json() + return data + + def create_project(self, **tenant_dict): + if "name" not in tenant_dict: + raise KeystoneProjectError("Cannot get the project name.") + _project = { + "project": { + "description": tenant_dict['description'], + "domain_id": tenant_dict['domain'], + "enabled": tenant_dict['enabled'], + "is_domain": tenant_dict['is_domain'], + "name": tenant_dict['name'] + } + } + return self._post(endpoint="/projects/", + url=self.opst_conf["url"], + data=_project, + _exception=KeystoneProjectError) + + def get_projects(self): + return self._get(endpoint="/projects/", url=self.opst_conf["url"], _exception=KeystoneProjectError) + + def get_items(self, item_id=None, **kwargs): + raise NotImplementedError() # pragma: no cover + + def add_item(self, item_id=None, **kwargs): + raise NotImplementedError() # pragma: no cover + + def update_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover + + def delete_item(self, item_id, **kwargs): + raise NotImplementedError() # pragma: no cover |