Add IntelIPMIHardware

IntelIPMIHardware is a hardware that supports configuring Intel Speed Select
Performance Profile using ipmitool.

Change-Id: I49abccb4735b43aed3155ea7e24b2fa0416c83b2
Story: 2005390
Task: 30484
This commit is contained in:
Madhuri Kumari 2019-05-16 12:40:33 +00:00 committed by Madhuri Kumari
parent 0a3b1968aa
commit 5127b6f6dd
9 changed files with 342 additions and 0 deletions

View File

@ -0,0 +1,27 @@
# 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 ironic.drivers import ipmi
from ironic.drivers.modules.intel_ipmi import management
class IntelIPMIHardware(ipmi.IPMIHardware):
"""Intel IPMI hardware type.
Uses ``ipmitool`` to implement power and management.
Provides serial console implementations via ``shellinabox`` or ``socat``.
Supports Intel SST-PP feature.
"""
@property
def supported_management_interfaces(self):
"""List of supported management interfaces."""
return [management.IntelIPMIManagement]

View File

@ -0,0 +1,86 @@
# coding=utf-8
# 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.
"""
Intel IPMI Hardware.
Supports Intel Speed Select Performance Profile.
"""
from oslo_log import log as logging
from ironic.common import exception
from ironic.common.i18n import _
from ironic.drivers import base
from ironic.drivers.modules import ipmitool
LOG = logging.getLogger(__name__)
INTEL_SST_PP_CONFIG_HEXA_CODES = ['0x00', '0x01', '0x02']
class IntelIPMIManagement(ipmitool.IPMIManagement):
def _validate_input(self, config, sockets):
if config not in INTEL_SST_PP_CONFIG_HEXA_CODES:
raise exception.InvalidParameterValue(_(
"Invalid Intel SST-PP configuration value %(config)s "
"specified. Valid values are %(config_list)s.")
% {"config": config,
"config_list": INTEL_SST_PP_CONFIG_HEXA_CODES})
try:
socket_count = int(sockets)
if socket_count <= 0:
raise ValueError
except ValueError:
raise exception.InvalidParameterValue(_(
"Invalid number of socket %(socket)s value specified. "
"Expected a positive integer.") % {"socket": sockets})
@base.deploy_step(priority=200, argsinfo={
'intel_speedselect_config': {
'description': (
"Hexadecimal code of Intel SST-PP configuration provided. "
"Input value should be string. Accepted values are "
"['0x00', '0x01', '0x02']. "
),
'required': True
},
'socket_count': {
'description': (
"Number of sockets. Input value should be a positive integer."
)
}
})
def configure_intel_speedselect(self, task, **kwargs):
config = kwargs.get('intel_speedselect_config')
socket_count = kwargs.get('socket_count', 1)
self._validate_input(config, socket_count)
LOG.debug("Going to set Intel SST-PP configuration level %(config)s "
"for node %(node)s with socket count %(socket)s",
{"config": config, "node": task.node.uuid,
"socket": socket_count})
self._configure_intel_speed_select(task, config, socket_count)
def _configure_intel_speed_select(self, task, config, socket_count):
iss_conf = "0x2c 0x41 0x04 0x00 0x0%s %s"
for socket in range(socket_count):
hexa_code = iss_conf % (socket, config)
try:
ipmitool.send_raw(task, hexa_code)
except exception.IPMIFailure as e:
msg = ("Failed to set Intel SST-PP configuration level "
"%(cfg)s on socket number %(skt)s due to reason "
"%(exc)s." % {"cfg": config, "skt": socket, "exc": e})
LOG.exception(msg)
raise exception.IPMIFailure(message=msg)

View File

@ -0,0 +1,29 @@
#
# 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.
"""Test base class for iBMC Driver."""
from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.db import utils as db_utils
from ironic.tests.unit.objects import utils as obj_utils
class IntelIPMITestCase(db_base.DbTestCase):
def setUp(self):
super(IntelIPMITestCase, self).setUp()
self.driver_info = db_utils.get_test_ipmi_info()
self.config(enabled_hardware_types=['intel-ipmi'],
enabled_management_interfaces=['intel-ipmitool'],
enabled_power_interfaces=['ipmitool'])
self.node = obj_utils.create_test_node(
self.context, driver='intel-ipmi', driver_info=self.driver_info)

View File

@ -0,0 +1,103 @@
# 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 ironic.conductor import task_manager
from ironic.drivers.modules import agent
from ironic.drivers.modules.intel_ipmi import management as intel_management
from ironic.drivers.modules import ipmitool
from ironic.drivers.modules import iscsi_deploy
from ironic.drivers.modules import noop
from ironic.drivers.modules import pxe
from ironic.drivers.modules.storage import cinder
from ironic.drivers.modules.storage import noop as noop_storage
from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.objects import utils as obj_utils
class IntelIPMIHardwareTestCase(db_base.DbTestCase):
def setUp(self):
super(IntelIPMIHardwareTestCase, self).setUp()
self.config(enabled_hardware_types=['intel-ipmi'],
enabled_power_interfaces=['ipmitool'],
enabled_management_interfaces=['intel-ipmitool',
'noop'],
enabled_raid_interfaces=['no-raid', 'agent'],
enabled_console_interfaces=['no-console'],
enabled_vendor_interfaces=['ipmitool', 'no-vendor'])
def _validate_interfaces(self, task, **kwargs):
self.assertIsInstance(
task.driver.management,
kwargs.get('management', intel_management.IntelIPMIManagement))
self.assertIsInstance(
task.driver.power,
kwargs.get('power', ipmitool.IPMIPower))
self.assertIsInstance(
task.driver.boot,
kwargs.get('boot', pxe.PXEBoot))
self.assertIsInstance(
task.driver.deploy,
kwargs.get('deploy', iscsi_deploy.ISCSIDeploy))
self.assertIsInstance(
task.driver.console,
kwargs.get('console', noop.NoConsole))
self.assertIsInstance(
task.driver.raid,
kwargs.get('raid', noop.NoRAID))
self.assertIsInstance(
task.driver.vendor,
kwargs.get('vendor', ipmitool.VendorPassthru))
self.assertIsInstance(
task.driver.storage,
kwargs.get('storage', noop_storage.NoopStorage))
self.assertIsInstance(
task.driver.rescue,
kwargs.get('rescue', noop.NoRescue))
def test_default_interfaces(self):
node = obj_utils.create_test_node(self.context, driver='intel-ipmi')
with task_manager.acquire(self.context, node.id) as task:
self._validate_interfaces(task)
def test_override_with_shellinabox(self):
self.config(enabled_console_interfaces=['ipmitool-shellinabox',
'ipmitool-socat'])
node = obj_utils.create_test_node(
self.context, driver='intel-ipmi',
deploy_interface='direct',
raid_interface='agent',
console_interface='ipmitool-shellinabox',
vendor_interface='no-vendor')
with task_manager.acquire(self.context, node.id) as task:
self._validate_interfaces(
task,
deploy=agent.AgentDeploy,
console=ipmitool.IPMIShellinaboxConsole,
raid=agent.AgentRAID,
vendor=noop.NoVendor)
def test_override_with_cinder_storage(self):
self.config(enabled_storage_interfaces=['noop', 'cinder'])
node = obj_utils.create_test_node(
self.context, driver='intel-ipmi',
storage_interface='cinder')
with task_manager.acquire(self.context, node.id) as task:
self._validate_interfaces(task, storage=cinder.CinderStorage)
def test_override_with_agent_rescue(self):
self.config(enabled_rescue_interfaces=['no-rescue', 'agent'])
node = obj_utils.create_test_node(
self.context, driver='intel-ipmi',
rescue_interface='agent')
with task_manager.acquire(self.context, node.id) as task:
self._validate_interfaces(task, rescue=agent.AgentRescue)

View File

@ -0,0 +1,86 @@
# Copyright 2015, Cisco Systems.
#
# 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 ironic.common import exception
from ironic.conductor import task_manager
from ironic.drivers.modules import ipmitool
from ironic.tests.unit.drivers.modules.intel_ipmi import base
class IntelIPMIManagementTestCase(base.IntelIPMITestCase):
def test_configure_intel_speedselect_empty(self):
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.InvalidParameterValue,
task.driver.management.configure_intel_speedselect,
task)
@mock.patch.object(ipmitool, "send_raw", spec_set=True,
autospec=True)
def test_configure_intel_speedselect(self, send_raw_mock):
send_raw_mock.return_value = [None, None]
config = {"intel_speedselect_config": "0x02", "socket_count": 1}
with task_manager.acquire(self.context, self.node.uuid) as task:
ret = task.driver.management.configure_intel_speedselect(task,
**config)
self.assertIsNone(ret)
send_raw_mock.assert_called_once_with(task,
'0x2c 0x41 0x04 0x00 0x00 0x02')
@mock.patch.object(ipmitool, "send_raw", spec_set=True,
autospec=True)
def test_configure_intel_speedselect_more_socket(self, send_raw_mock):
send_raw_mock.return_value = [None, None]
config = {"intel_speedselect_config": "0x02", "socket_count": 4}
with task_manager.acquire(self.context, self.node.uuid) as task:
ret = task.driver.management.configure_intel_speedselect(task,
**config)
self.assertIsNone(ret)
self.assertEqual(send_raw_mock.call_count, 4)
calls = [
mock.call(task, '0x2c 0x41 0x04 0x00 0x00 0x02'),
mock.call(task, '0x2c 0x41 0x04 0x00 0x01 0x02'),
mock.call(task, '0x2c 0x41 0x04 0x00 0x02 0x02'),
mock.call(task, '0x2c 0x41 0x04 0x00 0x03 0x02')
]
send_raw_mock.assert_has_calls(calls)
@mock.patch.object(ipmitool, "send_raw", spec_set=True,
autospec=True)
def test_configure_intel_speedselect_error(self, send_raw_mock):
send_raw_mock.side_effect = exception.IPMIFailure('err')
config = {"intel_speedselect_config": "0x02", "socket_count": 1}
with task_manager.acquire(self.context, self.node.uuid) as task:
e = self.assertRaises(
exception.IPMIFailure,
task.driver.management.configure_intel_speedselect,
task, **config)
self.assertIn("Failed to set Intel SST-PP configuration", str(e))
def test_configure_intel_speedselect_invalid_input(self):
config = {"intel_speedselect_config": "0", "socket_count": 1}
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.InvalidParameterValue,
task.driver.management.configure_intel_speedselect,
task, **config)
config = {"intel_speedselect_config": "0x00", "socket_count": -1}
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.InvalidParameterValue,
task.driver.management.configure_intel_speedselect,
task, **config)

View File

@ -0,0 +1,9 @@
---
features:
- |
Adds support for the Intel IPMI Hardware with hardware type
``intel-ipmitool``. This hardware type is same as ``ipmi`` hardware type
with additional support of `Intel Speed Select Performance Profile
Technology <https://www.intel.com/content/www/us/en/architecture-and-technology/speed-select-technology-article.html>`.
It uses management interface ``intel-ipmitool``. It supports setting
the desired configuration level for Intel SST-PP.

View File

@ -98,6 +98,7 @@ ironic.hardware.interfaces.management =
ibmc = ironic.drivers.modules.ibmc.management:IBMCManagement
idrac = ironic.drivers.modules.drac.management:DracManagement
ilo = ironic.drivers.modules.ilo.management:IloManagement
intel-ipmitool = ironic.drivers.modules.intel_ipmi.management:IntelIPMIManagement
ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement
irmc = ironic.drivers.modules.irmc.management:IRMCManagement
noop = ironic.drivers.modules.noop_mgmt:NoopManagement
@ -158,6 +159,7 @@ ironic.hardware.types =
idrac = ironic.drivers.drac:IDRACHardware
ilo = ironic.drivers.ilo:IloHardware
ilo5 = ironic.drivers.ilo:Ilo5Hardware
intel-ipmi = ironic.drivers.intel_ipmi:IntelIPMIHardware
ipmi = ironic.drivers.ipmi:IPMIHardware
irmc = ironic.drivers.irmc:IRMCHardware
manual-management = ironic.drivers.generic:ManualManagementHardware