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:
parent
0a3b1968aa
commit
5127b6f6dd
27
ironic/drivers/intel_ipmi.py
Normal file
27
ironic/drivers/intel_ipmi.py
Normal 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]
|
0
ironic/drivers/modules/intel_ipmi/__init__.py
Normal file
0
ironic/drivers/modules/intel_ipmi/__init__.py
Normal file
86
ironic/drivers/modules/intel_ipmi/management.py
Normal file
86
ironic/drivers/modules/intel_ipmi/management.py
Normal 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)
|
29
ironic/tests/unit/drivers/modules/intel_ipmi/base.py
Normal file
29
ironic/tests/unit/drivers/modules/intel_ipmi/base.py
Normal 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)
|
103
ironic/tests/unit/drivers/modules/intel_ipmi/test_intel_ipmi.py
Normal file
103
ironic/tests/unit/drivers/modules/intel_ipmi/test_intel_ipmi.py
Normal 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)
|
@ -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)
|
@ -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.
|
@ -98,6 +98,7 @@ ironic.hardware.interfaces.management =
|
|||||||
ibmc = ironic.drivers.modules.ibmc.management:IBMCManagement
|
ibmc = ironic.drivers.modules.ibmc.management:IBMCManagement
|
||||||
idrac = ironic.drivers.modules.drac.management:DracManagement
|
idrac = ironic.drivers.modules.drac.management:DracManagement
|
||||||
ilo = ironic.drivers.modules.ilo.management:IloManagement
|
ilo = ironic.drivers.modules.ilo.management:IloManagement
|
||||||
|
intel-ipmitool = ironic.drivers.modules.intel_ipmi.management:IntelIPMIManagement
|
||||||
ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement
|
ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement
|
||||||
irmc = ironic.drivers.modules.irmc.management:IRMCManagement
|
irmc = ironic.drivers.modules.irmc.management:IRMCManagement
|
||||||
noop = ironic.drivers.modules.noop_mgmt:NoopManagement
|
noop = ironic.drivers.modules.noop_mgmt:NoopManagement
|
||||||
@ -158,6 +159,7 @@ ironic.hardware.types =
|
|||||||
idrac = ironic.drivers.drac:IDRACHardware
|
idrac = ironic.drivers.drac:IDRACHardware
|
||||||
ilo = ironic.drivers.ilo:IloHardware
|
ilo = ironic.drivers.ilo:IloHardware
|
||||||
ilo5 = ironic.drivers.ilo:Ilo5Hardware
|
ilo5 = ironic.drivers.ilo:Ilo5Hardware
|
||||||
|
intel-ipmi = ironic.drivers.intel_ipmi:IntelIPMIHardware
|
||||||
ipmi = ironic.drivers.ipmi:IPMIHardware
|
ipmi = ironic.drivers.ipmi:IPMIHardware
|
||||||
irmc = ironic.drivers.irmc:IRMCHardware
|
irmc = ironic.drivers.irmc:IRMCHardware
|
||||||
manual-management = ironic.drivers.generic:ManualManagementHardware
|
manual-management = ironic.drivers.generic:ManualManagementHardware
|
||||||
|
Loading…
Reference in New Issue
Block a user