diff --git a/ironic/drivers/cisco_ucs.py b/ironic/drivers/cisco_ucs.py new file mode 100644 index 0000000000..33a6cb02d7 --- /dev/null +++ b/ironic/drivers/cisco_ucs.py @@ -0,0 +1,55 @@ +# 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. + +""" +Hardware types for Cisco UCS Servers +""" + +from ironic.drivers import ipmi + +from ironic.drivers.modules.cimc import management as cimc_mgmt +from ironic.drivers.modules.cimc import power as cimc_power + +from ironic.drivers.modules.ucs import management as ucs_mgmt +from ironic.drivers.modules.ucs import power as ucs_power + + +class CiscoUCSStandalone(ipmi.IPMIHardware): + """Cisco UCS in standalone mode""" + + @property + def supported_management_interfaces(self): + """List of supported management interfaces.""" + mgmt = super(CiscoUCSStandalone, self).supported_management_interfaces + return [cimc_mgmt.CIMCManagement] + mgmt + + @property + def supported_power_interfaces(self): + """List of supported power interfaces.""" + power = super(CiscoUCSStandalone, self).supported_power_interfaces + return [cimc_power.Power] + power + + +class CiscoUCSManaged(CiscoUCSStandalone): + """Cisco UCS under UCSM management""" + + @property + def supported_management_interfaces(self): + """List of supported management interfaces.""" + mgmt = super(CiscoUCSManaged, self).supported_management_interfaces + return [ucs_mgmt.UcsManagement] + mgmt + + @property + def supported_power_interfaces(self): + """List of supported power interfaces.""" + power = super(CiscoUCSManaged, self).supported_power_interfaces + return [ucs_power.Power] + power diff --git a/ironic/tests/unit/drivers/test_cisco.py b/ironic/tests/unit/drivers/test_cisco.py new file mode 100644 index 0000000000..50630d901f --- /dev/null +++ b/ironic/tests/unit/drivers/test_cisco.py @@ -0,0 +1,153 @@ +# 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 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 noop as noop_storage +from ironic.tests.unit.db import base as db_base +from ironic.tests.unit.objects import utils as obj_utils + +from ironic.drivers.modules.cimc import management as cimc_mgmt +from ironic.drivers.modules.cimc import power as cimc_power + +from ironic.drivers.modules.ucs import management as ucs_mgmt +from ironic.drivers.modules.ucs import power as ucs_power + + +class CiscoUCSStandaloneHardwareTestCase(db_base.DbTestCase): + + def setUp(self): + super(CiscoUCSStandaloneHardwareTestCase, self).setUp() + self.config(enabled_hardware_types=['cisco-ucs-standalone'], + enabled_power_interfaces=['cimc', 'ipmitool'], + enabled_management_interfaces=['cimc', 'ipmitool'], + 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', cimc_mgmt.CIMCManagement)) + self.assertIsInstance( + task.driver.power, + kwargs.get('power', cimc_power.Power)) + 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)) + + def test_default_interfaces(self): + node = obj_utils.create_test_node(self.context, + driver='cisco-ucs-standalone') + with task_manager.acquire(self.context, node.id) as task: + self._validate_interfaces(task) + + def test_override_with_ipmi_interfaces(self): + node = obj_utils.create_test_node( + self.context, driver='cisco-ucs-standalone', + power_interface='ipmitool', + management_interface='ipmitool', + deploy_interface='direct', + raid_interface='agent', + console_interface='no-console', + vendor_interface='no-vendor') + with task_manager.acquire(self.context, node.id) as task: + self._validate_interfaces( + task, + deploy=agent.AgentDeploy, + console=noop.NoConsole, + raid=agent.AgentRAID, + vendor=noop.NoVendor, + power=ipmitool.IPMIPower, + management=ipmitool.IPMIManagement) + + +class CiscoUCSManagedHardwareTestCase(db_base.DbTestCase): + + def setUp(self): + super(CiscoUCSManagedHardwareTestCase, self).setUp() + self.config(enabled_hardware_types=['cisco-ucs-managed'], + enabled_power_interfaces=['ucsm', 'cimc'], + enabled_management_interfaces=['ucsm', 'cimc'], + 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', ucs_mgmt.UcsManagement)) + self.assertIsInstance( + task.driver.power, + kwargs.get('power', ucs_power.Power)) + 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)) + + def test_default_interfaces(self): + node = obj_utils.create_test_node(self.context, + driver='cisco-ucs-managed') + with task_manager.acquire(self.context, node.id) as task: + self._validate_interfaces(task) + + def test_override_with_cimc_interfaces(self): + node = obj_utils.create_test_node( + self.context, driver='cisco-ucs-managed', + power_interface='cimc', + management_interface='cimc', + deploy_interface='direct', + raid_interface='agent', + console_interface='no-console', + vendor_interface='no-vendor') + with task_manager.acquire(self.context, node.id) as task: + self._validate_interfaces( + task, + deploy=agent.AgentDeploy, + console=noop.NoConsole, + raid=agent.AgentRAID, + vendor=noop.NoVendor, + power=cimc_power.Power, + management=cimc_mgmt.CIMCManagement) diff --git a/releasenotes/notes/add-cisco-ucs-hardware-types-ee597ff0416f158f.yaml b/releasenotes/notes/add-cisco-ucs-hardware-types-ee597ff0416f158f.yaml new file mode 100644 index 0000000000..56979345f1 --- /dev/null +++ b/releasenotes/notes/add-cisco-ucs-hardware-types-ee597ff0416f158f.yaml @@ -0,0 +1,23 @@ +--- +features: + - | + Adds two new hardware types to support Cisco UCS Servers, + ``cisco-ucs-standalone`` and ``cisco-ucs-managed``. + ``cisco-ucs-standalone`` supports driver interfaces for controlling UCS + servers in standalone mode via either CIMC APIs or via IPMI. + ``cisco-ucs-managed`` is a superset of ``cisco-ucs-standalone`` and + supports additional driver interfaces for controlling the UCS server via + UCSM. + + To support these hardware types the following Ironic driver interfaces were + made available to be configured on a node: + + * ``node.power_interface`` can be set to: + + * ``cimc`` for CIMC API power control (power on/off, reboot etc) + * ``ucsm`` for UCSM API power control (power on/off, reboot etc) + + * ``node.management_interface`` can be set to: + + * ``cimc`` for CIMC API management control (setting the boot device etc) + * ``ucsm`` for UCSM API management control (setting the boot device etc) diff --git a/setup.cfg b/setup.cfg index b84fb4b7a6..c5ff2e928b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -110,12 +110,14 @@ ironic.hardware.interfaces.inspect = oneview = ironic.drivers.modules.oneview.inspect:OneViewInspect ironic.hardware.interfaces.management = + cimc = ironic.drivers.modules.cimc.management:CIMCManagement fake = ironic.drivers.modules.fake:FakeManagement ilo = ironic.drivers.modules.ilo.management:IloManagement ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement irmc = ironic.drivers.modules.irmc.management:IRMCManagement oneview = ironic.drivers.modules.oneview.management:OneViewManagement redfish = ironic.drivers.modules.redfish.management:RedfishManagement + ucsm = ironic.drivers.modules.ucs.management:UcsManagement ironic.hardware.interfaces.network = flat = ironic.drivers.modules.network.flat:FlatNetwork @@ -123,6 +125,7 @@ ironic.hardware.interfaces.network = noop = ironic.drivers.modules.network.noop:NoopNetwork ironic.hardware.interfaces.power = + cimc = ironic.drivers.modules.cimc.power:Power fake = ironic.drivers.modules.fake:FakePower ilo = ironic.drivers.modules.ilo.power:IloPower ipmitool = ironic.drivers.modules.ipmitool:IPMIPower @@ -130,6 +133,7 @@ ironic.hardware.interfaces.power = oneview = ironic.drivers.modules.oneview.power:OneViewPower redfish = ironic.drivers.modules.redfish.power:RedfishPower snmp = ironic.drivers.modules.snmp:SNMPPower + ucsm = ironic.drivers.modules.ucs.power:Power ironic.hardware.interfaces.raid = agent = ironic.drivers.modules.agent:AgentRAID @@ -150,6 +154,8 @@ ironic.hardware.interfaces.vendor = no-vendor = ironic.drivers.modules.noop:NoVendor ironic.hardware.types = + cisco-ucs-managed = ironic.drivers.cisco_ucs:CiscoUCSManaged + cisco-ucs-standalone = ironic.drivers.cisco_ucs:CiscoUCSStandalone fake-hardware = ironic.drivers.fake_hardware:FakeHardware ilo = ironic.drivers.ilo:IloHardware ipmi = ironic.drivers.ipmi:IPMIHardware