Merge "Instrumenting redfish into proliantutils' client"

This commit is contained in:
Jenkins 2017-05-08 15:29:06 +00:00 committed by Gerrit Code Review
commit 93f6d17bd9
2 changed files with 238 additions and 10 deletions

View File

@ -20,6 +20,7 @@ from proliantutils.ilo import ribcl
from proliantutils.ilo import ris
from proliantutils.ilo.snmp import snmp_cpqdisk_sizes as snmp
from proliantutils import log
from proliantutils.redfish import redfish
SUPPORTED_RIS_METHODS = [
'activate_license',
@ -56,27 +57,73 @@ SUPPORTED_RIS_METHODS = [
'update_persistent_boot',
]
SUPPORTED_REDFISH_METHODS = [
'get_product_name',
'get_host_power_status',
]
LOG = log.get_logger(__name__)
class IloClient(operations.IloOperations):
def __init__(self, host, login, password, timeout=60, port=443,
bios_password=None, cacert=None, snmp_credentials=None):
bios_password=None, cacert=None, snmp_credentials=None,
use_redfish_only=False):
self.ribcl = ribcl.RIBCLOperations(host, login, password, timeout,
port, cacert=cacert)
self.ris = ris.RISOperations(host, login, password,
bios_password=bios_password,
cacert=cacert)
self.info = {'address': host, 'username': login, 'password': password}
self.host = host
self.model = self.ribcl.get_product_name()
self.ribcl.init_model_based_tags(self.model)
self.use_redfish_only = use_redfish_only
if use_redfish_only:
self._init_redfish_object(None, host, login, password,
bios_password=bios_password,
cacert=cacert)
LOG.debug(self._("Forced to use 'redfish' way to interact "
"with iLO. Model: %(model)s"),
{'model': self.model})
else:
try:
self.model = self.ribcl.get_product_name()
except exception.IloError:
# Note(deray): This can be a potential scenario where
# RIBCL is disabled on a Gen10 (iLO 5) hardware.
# So, trying out the redfish operation object instantiation.
# If that passes we know that our assumption is right.
# If that errors out, then alas! we are left with no other
# choice.
self._init_redfish_object(False, host, login, password,
bios_password=bios_password,
cacert=cacert)
else:
self.ribcl.init_model_based_tags(self.model)
if ('Gen10' in self.model):
self._init_redfish_object(True, host, login, password,
bios_password=bios_password,
cacert=cacert,
should_set_model=False)
else:
# Gen9
self.ris = ris.RISOperations(
host, login, password, bios_password=bios_password,
cacert=cacert)
self.snmp_credentials = snmp_credentials
self._validate_snmp()
LOG.debug(self._("IloClient object created. "
"Model: %(model)s"), {'model': self.model})
def _init_redfish_object(self, is_ribcl_enabled, redfish_controller_ip,
username, password, bios_password=None,
cacert=None, should_set_model=True):
self.redfish = redfish.RedfishOperations(
redfish_controller_ip, username, password,
bios_password=bios_password, cacert=cacert)
self.is_ribcl_enabled = is_ribcl_enabled
if should_set_model:
self.model = self.redfish.get_product_name()
def _validate_snmp(self):
"""Validates SNMP credentials.
@ -130,10 +177,29 @@ class IloClient(operations.IloOperations):
'inspection will not be performed.'))
def _call_method(self, method_name, *args, **kwargs):
"""Call the corresponding method using either RIBCL or RIS."""
the_operation_object = self.ribcl
if ('Gen9' in self.model) and (method_name in SUPPORTED_RIS_METHODS):
the_operation_object = self.ris
"""Call the corresponding method using RIBCL, RIS or REDFISH
Make the decision to invoke the corresponding method using RIBCL,
RIS or REDFISH way. In case of none, throw out ``NotImplementedError``
"""
if self.use_redfish_only:
if method_name in SUPPORTED_REDFISH_METHODS:
the_operation_object = self.redfish
else:
raise NotImplementedError()
else:
the_operation_object = self.ribcl
if 'Gen10' in self.model:
if method_name in SUPPORTED_REDFISH_METHODS:
the_operation_object = self.redfish
else:
if (self.is_ribcl_enabled is not None
and not self.is_ribcl_enabled):
raise NotImplementedError()
elif ('Gen9' in self.model) and (method_name in
SUPPORTED_RIS_METHODS):
the_operation_object = self.ris
method = getattr(the_operation_object, method_name)
LOG.debug(self._("Using %(class)s for method %(method)s."),

View File

@ -23,6 +23,7 @@ from proliantutils.ilo import ipmi
from proliantutils.ilo import ribcl
from proliantutils.ilo import ris
from proliantutils.ilo.snmp import snmp_cpqdisk_sizes
from proliantutils.redfish import redfish
class IloClientInitTestCase(testtools.TestCase):
@ -49,6 +50,82 @@ class IloClientInitTestCase(testtools.TestCase):
c.info)
self.assertEqual('product', c.model)
@mock.patch.object(ribcl, 'RIBCLOperations')
@mock.patch.object(redfish, 'RedfishOperations')
def test_init_for_redfish_with_ribcl_enabled(
self, redfish_mock, ribcl_mock):
ribcl_obj_mock = mock.MagicMock()
ribcl_mock.return_value = ribcl_obj_mock
ribcl_obj_mock.get_product_name.return_value = 'ProLiant DL180 Gen10'
c = client.IloClient("1.2.3.4", "admin", "Admin",
timeout=120, port=4430,
bios_password='foo',
cacert='/somewhere')
ribcl_mock.assert_called_once_with(
"1.2.3.4", "admin", "Admin", 120, 4430, cacert='/somewhere')
redfish_mock.assert_called_once_with(
"1.2.3.4", "admin", "Admin", bios_password='foo',
cacert='/somewhere')
self.assertEqual(
{'address': "1.2.3.4", 'username': "admin", 'password': "Admin"},
c.info)
self.assertEqual('ProLiant DL180 Gen10', c.model)
self.assertIsNotNone(c.redfish)
self.assertTrue(c.is_ribcl_enabled)
self.assertFalse(hasattr(c, 'ris'))
@mock.patch.object(ribcl, 'RIBCLOperations')
@mock.patch.object(redfish, 'RedfishOperations')
def test_init_for_redfish_with_ribcl_disabled(
self, redfish_mock, ribcl_mock):
ribcl_obj_mock = mock.MagicMock()
ribcl_mock.return_value = ribcl_obj_mock
ribcl_obj_mock.get_product_name.side_effect = (
exception.IloError('RIBCL is disabled'))
c = client.IloClient("1.2.3.4", "admin", "Admin",
timeout=120, port=4430,
bios_password='foo',
cacert='/somewhere')
ribcl_mock.assert_called_once_with(
"1.2.3.4", "admin", "Admin", 120, 4430, cacert='/somewhere')
redfish_mock.assert_called_once_with(
"1.2.3.4", "admin", "Admin", bios_password='foo',
cacert='/somewhere')
self.assertEqual(
{'address': "1.2.3.4", 'username': "admin", 'password': "Admin"},
c.info)
self.assertIsNotNone(c.model)
self.assertIsNotNone(c.redfish)
self.assertFalse(c.is_ribcl_enabled)
self.assertFalse(hasattr(c, 'ris'))
@mock.patch.object(ribcl, 'RIBCLOperations')
@mock.patch.object(redfish, 'RedfishOperations')
def test_init_with_use_redfish_only_set(
self, redfish_mock, ribcl_mock):
c = client.IloClient("1.2.3.4", "admin", "Admin",
timeout=120, port=4430,
bios_password='foo', cacert='/somewhere',
use_redfish_only=True)
ribcl_mock.assert_called_once_with(
"1.2.3.4", "admin", "Admin", 120, 4430, cacert='/somewhere')
redfish_mock.assert_called_once_with(
"1.2.3.4", "admin", "Admin", bios_password='foo',
cacert='/somewhere')
self.assertEqual(
{'address': "1.2.3.4", 'username': "admin", 'password': "Admin"},
c.info)
self.assertIsNotNone(c.model)
self.assertIsNotNone(c.redfish)
self.assertIsNone(c.is_ribcl_enabled)
self.assertFalse(hasattr(c, 'ris'))
self.assertTrue(c.use_redfish_only)
@mock.patch.object(client.IloClient, '_validate_snmp')
@mock.patch.object(ribcl, 'RIBCLOperations')
@mock.patch.object(ris, 'RISOperations')
@ -193,6 +270,91 @@ class IloClientTestCase(testtools.TestCase):
self.client._call_method('reset_ilo')
ilo_mock.assert_called_once_with()
"""
Testing ``_call_method`` with Redfish support.
Testing the redfish methods based on the following scenarios,
which are depicted in this table::
redfish | ribcl | method implemented | name of test method
supported? | enabled? | on redfish? |
===========|==========|====================|=============================
true | true | true | test__call_method_redfish_1
true | true | false | test__call_method_redfish_2
true | false | true | test__call_method_redfish_3
true | false | false | test__call_method_redfish_4
===========|==========|====================|=============================
"""
@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name')
@mock.patch.object(redfish, 'RedfishOperations')
def test__call_method_redfish_1(self, redfish_mock,
ribcl_product_name_mock):
ribcl_product_name_mock.return_value = 'Gen10'
self.client = client.IloClient("1.2.3.4", "admin", "secret")
redfish_get_host_power_mock = (redfish.RedfishOperations.return_value.
get_host_power_status)
self.client._call_method('get_host_power_status')
redfish_get_host_power_mock.assert_called_once_with()
@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name')
@mock.patch.object(redfish, 'RedfishOperations')
@mock.patch.object(ribcl.RIBCLOperations, 'reset_ilo')
def test__call_method_redfish_2(self, ribcl_reset_ilo_mock,
redfish_mock, ribcl_product_name_mock):
ribcl_product_name_mock.return_value = 'Gen10'
self.client = client.IloClient("1.2.3.4", "admin", "secret")
self.client._call_method('reset_ilo')
ribcl_reset_ilo_mock.assert_called_once_with()
@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name')
@mock.patch.object(redfish, 'RedfishOperations')
def test__call_method_redfish_3(self, redfish_mock,
ribcl_product_name_mock):
ribcl_product_name_mock.side_effect = (
exception.IloError('RIBCL is disabled'))
redfish_mock.return_value.get_product_name.return_value = 'Gen10'
self.client = client.IloClient("1.2.3.4", "admin", "secret")
redfish_get_host_power_mock = (redfish.RedfishOperations.return_value.
get_host_power_status)
self.client._call_method('get_host_power_status')
redfish_get_host_power_mock.assert_called_once_with()
@mock.patch.object(ribcl.RIBCLOperations, 'get_product_name')
@mock.patch.object(redfish, 'RedfishOperations')
def test__call_method_redfish_4(self, redfish_mock,
ribcl_product_name_mock):
ribcl_product_name_mock.side_effect = (
exception.IloError('RIBCL is disabled'))
redfish_mock.return_value.get_product_name.return_value = 'Gen10'
self.client = client.IloClient("1.2.3.4", "admin", "secret")
self.assertRaises(NotImplementedError,
self.client._call_method, 'reset_ilo')
@mock.patch.object(redfish, 'RedfishOperations',
spec_set=True, autospec=True)
def test__call_method_with_use_redfish_only_set(self, redfish_mock):
self.client = client.IloClient("1.2.3.4", "admin", "secret",
use_redfish_only=True)
redfish_get_host_power_mock = (redfish.RedfishOperations.return_value.
get_host_power_status)
self.client._call_method('get_host_power_status')
redfish_get_host_power_mock.assert_called_once_with()
@mock.patch.object(redfish, 'RedfishOperations',
spec_set=True, autospec=True)
def test__call_method_use_redfish_only_set_but_not_implemented(
self, redfish_mock):
self.client = client.IloClient("1.2.3.4", "admin", "secret",
use_redfish_only=True)
self.assertRaises(NotImplementedError,
self.client._call_method, 'reset_ilo')
@mock.patch.object(client.IloClient, '_call_method')
def test_set_http_boot_url(self, call_mock):
self.client.set_http_boot_url('fake-url')