From 570086d34aa696c50016a682964563a0ad0ed884 Mon Sep 17 00:00:00 2001 From: Anusha Ramineni Date: Wed, 9 Aug 2017 16:52:25 +0530 Subject: [PATCH] Add manager.py to redirect to respective podmanager This commit is add new module manager.py to redirect the controller requests to respective podmanager based on 'driver' field. This commit takes reference of multi-podm patch proposed here: https://review.openstack.org/#/c/445360/10 and extends the same. Partially-Implements blueprint add-vendor-extensible-framework Change-Id: I92efd4c18c75613a6365c750b09390cbe1fedc2e --- setup.cfg | 3 + valence/common/exception.py | 4 ++ valence/common/utils.py | 16 +++++- valence/podmanagers/manager.py | 57 +++++++++++++++++++ valence/redfish/sushy/sushy_instance.py | 2 +- valence/tests/unit/fakes/podmanager_fakes.py | 34 +++++++++++ valence/tests/unit/podmanagers/__init__.py | 0 .../tests/unit/podmanagers/test_manager.py | 49 ++++++++++++++++ 8 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 valence/podmanagers/manager.py create mode 100644 valence/tests/unit/fakes/podmanager_fakes.py create mode 100644 valence/tests/unit/podmanagers/__init__.py create mode 100644 valence/tests/unit/podmanagers/test_manager.py diff --git a/setup.cfg b/setup.cfg index 85875d8..0cc3e3a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,3 +65,6 @@ oslo.config.opts = valence.provision.driver = ironic = valence.provision.ironic.driver:IronicDriver + +valence.podmanager.driver = + redfishv1 = valence.podmanagers.podm_base:PodManagerBase diff --git a/valence/common/exception.py b/valence/common/exception.py index c1da052..c088839 100644 --- a/valence/common/exception.py +++ b/valence/common/exception.py @@ -120,6 +120,10 @@ class NotFound(ValenceError): _msg_fmt = "Resource could not be found" +class DriverNotFound(NotFound): + _msg_fmt = "Unsupported Driver Specified" + + class BadRequest(ValenceError): status = http_client.BAD_REQUEST _msg_fmt = "Bad Request" diff --git a/valence/common/utils.py b/valence/common/utils.py index aeea241..7260186 100644 --- a/valence/common/utils.py +++ b/valence/common/utils.py @@ -17,12 +17,13 @@ """ - import logging import flask from oslo_utils import uuidutils +from valence.common import constants + LOG = logging.getLogger(__name__) @@ -111,3 +112,16 @@ def make_response(status_code, content="", headers=None): def generate_uuid(): """Generate uniform format uuid""" return uuidutils.generate_uuid() + + +def get_basic_auth_credentials(authentication): + """parse out the basic auth from podm's authentication array properties + + :param authentication: podm's authentication + :return: username, password to connect to the podm + """ + for auth_property in authentication: + if auth_property['type'] == constants.PODM_AUTH_BASIC_TYPE: + username = auth_property['auth_items']['username'] + password = auth_property['auth_items']['password'] + return username, password diff --git a/valence/podmanagers/manager.py b/valence/podmanagers/manager.py new file mode 100644 index 0000000..a1ab21e --- /dev/null +++ b/valence/podmanagers/manager.py @@ -0,0 +1,57 @@ +import logging + +import stevedore + +from valence.common import exception +from valence.common import utils +from valence.db import api as db_api + +LOG = logging.getLogger(__name__) + +# cache podmanager connections, one connection per podmanager +podm_connections = {} + +# cache podmanager modules, to be loaded only once per driver +# If same driver used by 2 podmanagers (eg:redfishv1), podm_base module will be +# loaded only once, but 2 instances of class would be created. +podm_modules = {} + + +def get_podm_connection(podm_id): + podm_connection = podm_connections.get(podm_id, None) + if podm_connection: + return podm_connection + podm_db = db_api.Connection.get_podmanager_by_uuid(podm_id).as_dict() + username, password = utils.get_basic_auth_credentials( + podm_db['authentication']) + podm_connection = Manager(podm_db['url'], username, password, + podm_db['driver']) + podm_connections[podm_id] = podm_connection + return podm_connection + + +class Manager(object): + + def __init__(self, url, username, password, driver='redfishv1'): + self.podm = self._get_podm_instance(driver, url, username, password) + + def _get_podm_instance(self, driver, url, username, password): + podm = self.load_podm(driver) + return podm(username, password, url) + + @classmethod + def load_podm(cls, driver): + # get module if already loaded + podm = podm_modules.get(driver, None) + if not podm: + try: + podm = stevedore.driver.DriverManager( + 'valence.podmanager.driver', + driver, invoke_on_load=False).driver + except RuntimeError: + msg = "podmanager could not be loaded with specified driver %s" + LOG.exception(msg % driver) + raise exception.DriverNotFound(msg % driver) + + podm_modules[driver] = podm + return podm diff --git a/valence/redfish/sushy/sushy_instance.py b/valence/redfish/sushy/sushy_instance.py index 80033f3..f215150 100644 --- a/valence/redfish/sushy/sushy_instance.py +++ b/valence/redfish/sushy/sushy_instance.py @@ -16,7 +16,7 @@ import sushy from sushy import exceptions -from resources import chassis +from valence.redfish.sushy.resources import chassis class RedfishInstance(sushy.Sushy): diff --git a/valence/tests/unit/fakes/podmanager_fakes.py b/valence/tests/unit/fakes/podmanager_fakes.py new file mode 100644 index 0000000..ac0f67f --- /dev/null +++ b/valence/tests/unit/fakes/podmanager_fakes.py @@ -0,0 +1,34 @@ +# 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. + +from valence.db import models + + +def fake_podmanager(): + return { + "name": "fake-podm", + "podm_id": "fake-id", + "url": "https://10.240.212.123", + "driver": "redfishv1", + "authentication": [ + { + "type": "basic", + "auth_items": { + "username": "fake-user", + "password": "fake-pass" + } + }] + } + + +def fake_podm_object(): + return models.PodManager(**fake_podmanager()) diff --git a/valence/tests/unit/podmanagers/__init__.py b/valence/tests/unit/podmanagers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/valence/tests/unit/podmanagers/test_manager.py b/valence/tests/unit/podmanagers/test_manager.py new file mode 100644 index 0000000..4d38c5c --- /dev/null +++ b/valence/tests/unit/podmanagers/test_manager.py @@ -0,0 +1,49 @@ +# Copyright 2017 NEC, Corp. +# +# 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 mock + +from oslotest import base + +from valence.common import exception +from valence.podmanagers import manager +from valence.podmanagers import podm_base +from valence.tests.unit.fakes import podmanager_fakes + + +class TestManager(base.BaseTestCase): + def setUp(self): + super(TestManager, self).setUp() + + def test_load_podm_failure(self): + self.assertRaises(exception.DriverNotFound, manager.Manager.load_podm, + 'UnknownDriver') + + def test_load_podm(self): + podm = manager.Manager.load_podm('redfishv1') + self.assertEqual(manager.podm_modules['redfishv1'], podm) + + @mock.patch("valence.redfish.sushy.sushy_instance.RedfishInstance") + def test_get_podm_instance(self, mock_redfish): + mng = manager.Manager('http://fake-url', 'fake-user', 'fake-pass') + self.assertTrue(isinstance(mng.podm, podm_base.PodManagerBase)) + + @mock.patch("valence.db.api.Connection.get_podmanager_by_uuid") + @mock.patch("valence.redfish.sushy.sushy_instance.RedfishInstance") + def test_get_podm_connection(self, redfish_mock, get_podm_mock): + get_podm_mock.return_value = podmanager_fakes.fake_podm_object() + inst = manager.get_podm_connection("fake-id") + self.assertTrue(isinstance(inst, manager.Manager)) + self.assertTrue(isinstance(inst.podm, podm_base.PodManagerBase)) + self.assertTrue(manager.podm_connections['fake-id'])