From 6290ce993838037a91e71884f1c214878c2c075b Mon Sep 17 00:00:00 2001 From: Ramakrishnan G Date: Sun, 5 Jul 2015 23:06:48 -0700 Subject: [PATCH] IPA: Update proliant hardware manager This commit updates proliant hardware manager as per the latest Ironic: * Every clean step and get_clean_steps() must accept the arguments node and ports which are dictionaries. * Removes erase clean step using shred because it is already supported in IPA. * Register create_configuration and delete_configuration as clean steps. * Make delete_configuration() return the current raid configuration on the system. Change-Id: Ia8f0139e9b86abdee7566e352788b1fa53ad09d9 --- proliantutils/hpssa/manager.py | 7 +- .../ipa_hw_manager/hardware_manager.py | 68 ++++++++++++++----- proliantutils/tests/hpssa/test_manager.py | 23 +++++-- .../ipa_hw_manager/test_hardware_manager.py | 42 +++++------- 4 files changed, 91 insertions(+), 49 deletions(-) diff --git a/proliantutils/hpssa/manager.py b/proliantutils/hpssa/manager.py index 59cf0cf..5c54054 100644 --- a/proliantutils/hpssa/manager.py +++ b/proliantutils/hpssa/manager.py @@ -163,13 +163,18 @@ def create_configuration(raid_config): def delete_configuration(): - """Delete a RAID configuration on this server.""" + """Delete a RAID configuration on this server. + + :returns: the current RAID configuration after deleting all + the logical disks. + """ server = objects.Server() for controller in server.controllers: # Trigger delete only if there is some RAID array, otherwise # hpssacli will fail saying "no logical drives found." if controller.raid_arrays: controller.delete_all_logical_drives() + return get_configuration() def get_configuration(): diff --git a/proliantutils/ipa_hw_manager/hardware_manager.py b/proliantutils/ipa_hw_manager/hardware_manager.py index f97f420..f033859 100644 --- a/proliantutils/ipa_hw_manager/hardware_manager.py +++ b/proliantutils/ipa_hw_manager/hardware_manager.py @@ -13,7 +13,6 @@ # under the License. from ironic_python_agent import hardware -from oslo_concurrency import processutils from proliantutils.hpssa import manager as hpssa_manager @@ -22,25 +21,62 @@ class ProliantHardwareManager(hardware.GenericHardwareManager): HARDWARE_MANAGER_VERSION = "3" - def get_clean_steps(self): - pass + def get_clean_steps(self, node, ports): + """Return the clean steps supported by this hardware manager. + + This method returns the clean steps that are supported by + proliant hardware manager. This method is invoked on every + hardware manager by Ironic Python Agent to give this information + back to Ironic. + + :param node: A dictionary of the node object + :param ports: A list of dictionaries containing information of ports + for the node + :returns: A list of dictionaries, each item containing the step name, + interface and priority for the clean step. + """ + return [{'step': 'create_configuration', + 'interface': 'raid', + 'priority': 0}, + {'step': 'delete_configuration', + 'interface': 'raid', + 'priority': 0}] def evaluate_hardware_support(cls): return hardware.HardwareSupport.SERVICE_PROVIDER - def erase_block_device(self, block_device): - npass = 3 - cmd = ('shred', '--force', '--zero', '--verbose', - '--iterations', npass, block_device.name) - processutils.execute(*cmd) + def create_configuration(self, node, ports): + """Create RAID configuration on the bare metal. - def erase_devices(self): - block_devices = self.list_block_devices() - for block_device in block_devices: - self.erase_block_device(block_device) + This method creates the desired RAID configuration as read from + node['target_raid_config']. - def create_raid_configuration(self, raid_config): - return hpssa_manager.create_configuration(raid_config=raid_config) + :param node: A dictionary of the node object + :param ports: A list of dictionaries containing information of ports + for the node + :returns: The current RAID configuration of the below format. + raid_config = { + 'logical_disks': [{ + 'size_gb': 100, + 'raid_level': 1, + 'physical_disks': [ + '5I:0:1', + '5I:0:2'], + 'controller': 'Smart array controller' + }, + ] + } + """ + target_raid_config = node.get('target_raid_config', {}).copy() + return hpssa_manager.create_configuration( + raid_config=target_raid_config) - def delete_raid_configuration(self): - hpssa_manager.delete_configuration() + def delete_configuration(self, node, ports): + """Deletes RAID configuration on the bare metal. + + This method deletes all the RAID disks on the bare metal. + :param node: A dictionary of the node object + :param ports: A list of dictionaries containing information of ports + for the node + """ + return hpssa_manager.delete_configuration() diff --git a/proliantutils/tests/hpssa/test_manager.py b/proliantutils/tests/hpssa/test_manager.py index 9a02a43..97e65d5 100644 --- a/proliantutils/tests/hpssa/test_manager.py +++ b/proliantutils/tests/hpssa/test_manager.py @@ -201,27 +201,36 @@ class ManagerTestCases(testtools.TestCase): 'array', 'A', 'create', 'type=logicaldrive', 'raid=1', 'size=51200') + @mock.patch.object(manager, 'get_configuration') @mock.patch.object(objects.Controller, 'execute_cmd') def test_delete_configuration(self, controller_exec_cmd_mock, + get_configuration_mock, get_all_details_mock): get_all_details_mock.return_value = raid_constants.HPSSA_ONE_DRIVE + get_configuration_mock.return_value = 'foo' - manager.delete_configuration() + ret = manager.delete_configuration() - controller_exec_cmd_mock.assert_called_with("logicaldrive", - "all", - "delete", - "forced") + controller_exec_cmd_mock.assert_called_with( + "logicaldrive", "all", "delete", "forced") + get_configuration_mock.assert_called_once_with() + self.assertEqual('foo', ret) + @mock.patch.object(manager, 'get_configuration') @mock.patch.object(objects.Controller, 'execute_cmd') def test_delete_configuration_no_arrays( - self, controller_exec_cmd_mock, get_all_details_mock): + self, controller_exec_cmd_mock, + get_configuration_mock, get_all_details_mock): get_all_details_mock.return_value = raid_constants.HPSSA_NO_DRIVES + get_configuration_mock.return_value = 'foo' + + ret = manager.delete_configuration() - manager.delete_configuration() self.assertFalse(controller_exec_cmd_mock.called) + get_configuration_mock.assert_called_once_with() + self.assertEqual('foo', ret) def test_get_configuration(self, get_all_details_mock): diff --git a/proliantutils/tests/ipa_hw_manager/test_hardware_manager.py b/proliantutils/tests/ipa_hw_manager/test_hardware_manager.py index 43b5591..7cffa52 100644 --- a/proliantutils/tests/ipa_hw_manager/test_hardware_manager.py +++ b/proliantutils/tests/ipa_hw_manager/test_hardware_manager.py @@ -13,7 +13,6 @@ # under the License. import mock -from oslo_concurrency import processutils import testtools from proliantutils.hpssa import manager as hpssa_manager @@ -26,35 +25,28 @@ class ProliantHardwareManagerTestCase(testtools.TestCase): self.hardware_manager = hardware_manager.ProliantHardwareManager() super(ProliantHardwareManagerTestCase, self).setUp() - @mock.patch.object(processutils, 'execute') - def test_erase_block_device(self, processutils_mock): - device = mock.MagicMock() - p = mock.PropertyMock(return_value='/dev/sda') - type(device).name = p - cmd_expected = ('shred', '--force', '--zero', '--verbose', - '--iterations', 3, '/dev/sda') - self.hardware_manager.erase_block_device(device) - processutils_mock.assert_called_once_with(*cmd_expected) - - @mock.patch.object(hardware_manager.ProliantHardwareManager, - 'erase_block_device') - def test_erase_devices(self, erase_block_device_mock): - disks = ['/dev/sda', '/dev/sdb'] - self.hardware_manager.list_block_devices.return_value = disks - self.hardware_manager.erase_devices() - self.hardware_manager.list_block_devices.assert_called_once_with() - erase_block_device_mock.assert_any_call('/dev/sda') - erase_block_device_mock.assert_any_call('/dev/sdb') + def test_get_clean_steps(self): + self.assertEqual( + [{'step': 'create_configuration', + 'interface': 'raid', + 'priority': 0}, + {'step': 'delete_configuration', + 'interface': 'raid', + 'priority': 0}], + self.hardware_manager.get_clean_steps("", "")) @mock.patch.object(hpssa_manager, 'create_configuration') - def test_create_raid_configuration(self, create_mock): + def test_create_configuration(self, create_mock): create_mock.return_value = 'current-config' manager = self.hardware_manager - ret = manager.create_raid_configuration(raid_config='target') - create_mock.assert_called_once_with(raid_config='target') + node = {'target_raid_config': {'foo': 'bar'}} + ret = manager.create_configuration(node, []) + create_mock.assert_called_once_with(raid_config={'foo': 'bar'}) self.assertEqual('current-config', ret) @mock.patch.object(hpssa_manager, 'delete_configuration') - def test_delete_raid_configuration(self, delete_mock): - self.hardware_manager.delete_raid_configuration() + def test_delete_configuration(self, delete_mock): + delete_mock.return_value = 'current-config' + ret = self.hardware_manager.delete_configuration("", "") delete_mock.assert_called_once_with() + self.assertEqual('current-config', ret)