Merge "Instrumenting redfish into proliantutils' client"
This commit is contained in:
commit
93f6d17bd9
|
@ -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."),
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue