Merge "Add IntelIPMIHardware"
This commit is contained in:
commit
6cf49dad6c
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
|
||||
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
|
||||
@ -153,6 +154,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
|
||||
|
Loading…
Reference in New Issue
Block a user