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'])