Add RAID clear foreign config method
Change-Id: If1669e7a666d0897557bc96554a2e403b2ccecf8
This commit is contained in:
parent
79d4ecb587
commit
c63e28113a
@ -1,3 +1,5 @@
|
|||||||
|
# Copyright (c) 2021 Dell Inc. or its subsidiaries.
|
||||||
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -12,3 +14,4 @@
|
|||||||
|
|
||||||
IDRAC_CONFIG_PENDING = 'LC068'
|
IDRAC_CONFIG_PENDING = 'LC068'
|
||||||
IDRAC_JOB_RUNNING = 'RAC0679'
|
IDRAC_JOB_RUNNING = 'RAC0679'
|
||||||
|
NO_FOREIGN_CONFIG = 'STOR018'
|
||||||
|
@ -19,6 +19,8 @@ from sushy.resources import base
|
|||||||
from sushy.resources import common
|
from sushy.resources import common
|
||||||
from sushy import taskmonitor
|
from sushy import taskmonitor
|
||||||
|
|
||||||
|
from sushy_oem_idrac import constants
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -26,6 +28,8 @@ class ActionsField(base.CompositeField):
|
|||||||
convert_to_raid = common.ActionField("#DellRaidService.ConvertToRAID")
|
convert_to_raid = common.ActionField("#DellRaidService.ConvertToRAID")
|
||||||
convert_to_nonraid = common.ActionField(
|
convert_to_nonraid = common.ActionField(
|
||||||
"#DellRaidService.ConvertToNonRAID")
|
"#DellRaidService.ConvertToNonRAID")
|
||||||
|
clear_foreign_config = common.ActionField(
|
||||||
|
"#DellRaidService.ClearForeignConfig")
|
||||||
|
|
||||||
|
|
||||||
class DellRaidService(base.ResourceBase):
|
class DellRaidService(base.ResourceBase):
|
||||||
@ -78,6 +82,41 @@ class DellRaidService(base.ResourceBase):
|
|||||||
LOG.info('Converting to non-RAID mode: %s', physical_disk_fqdds)
|
LOG.info('Converting to non-RAID mode: %s', physical_disk_fqdds)
|
||||||
return task_monitor
|
return task_monitor
|
||||||
|
|
||||||
|
def clear_foreign_config(self, controller_fqdd):
|
||||||
|
"""Clears foreign configuration
|
||||||
|
|
||||||
|
Prepares any foreign physical disks for inclusion in the local
|
||||||
|
configuration
|
||||||
|
|
||||||
|
:param controller_fqdd: FQDD of controller to clear foreign
|
||||||
|
config
|
||||||
|
|
||||||
|
:returns: Sushy's TaskMonitor instance for TaskService task if
|
||||||
|
there are foreign drives to clear, otherwise None.
|
||||||
|
"""
|
||||||
|
target_uri = self._actions.clear_foreign_config.target_uri
|
||||||
|
payload = {'TargetFQDD': controller_fqdd}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self._conn.post(target_uri, data=payload)
|
||||||
|
except exceptions.BadRequestError as ex:
|
||||||
|
# Check if failed for no foreign drives
|
||||||
|
errors = ex.body and ex.body.get('@Message.ExtendedInfo') or []
|
||||||
|
|
||||||
|
no_foreign_conf = [x for x in errors if constants.NO_FOREIGN_CONFIG
|
||||||
|
in x.get('MessageId')]
|
||||||
|
|
||||||
|
if len(no_foreign_conf) == 0:
|
||||||
|
raise ex
|
||||||
|
else:
|
||||||
|
LOG.debug('%s: %s', no_foreign_conf[0].get('Message'),
|
||||||
|
controller_fqdd)
|
||||||
|
return
|
||||||
|
|
||||||
|
task_mon = self._get_task_monitor_from_dell_job(response)
|
||||||
|
LOG.info('Clearing foreign config: %s', controller_fqdd)
|
||||||
|
return task_mon
|
||||||
|
|
||||||
def _get_task_monitor_from_dell_job(self, response):
|
def _get_task_monitor_from_dell_job(self, response):
|
||||||
"""From OEM job response returns generic Task monitor
|
"""From OEM job response returns generic Task monitor
|
||||||
|
|
||||||
|
@ -108,6 +108,25 @@ class DellSystemExtension(oem_base.OEMResourceBase):
|
|||||||
|
|
||||||
return task_monitors
|
return task_monitors
|
||||||
|
|
||||||
|
def clear_foreign_config(self, storage_list=None):
|
||||||
|
"""Clears foreign config on given controllers
|
||||||
|
|
||||||
|
:param storage_list: List of storage objects, each of which
|
||||||
|
corresponds to a controller
|
||||||
|
:returns: List of task monitors, where each entry is for a
|
||||||
|
controller that has foreign config to clear
|
||||||
|
"""
|
||||||
|
if storage_list is None:
|
||||||
|
storage_list = self._get_storage_list()
|
||||||
|
|
||||||
|
task_monitors = []
|
||||||
|
for storage in storage_list:
|
||||||
|
task_mon = self.raid_service.clear_foreign_config(storage.identity)
|
||||||
|
if task_mon:
|
||||||
|
task_monitors.append(task_mon)
|
||||||
|
|
||||||
|
return task_monitors
|
||||||
|
|
||||||
def _get_controller_to_disks(self):
|
def _get_controller_to_disks(self):
|
||||||
"""Gets all RAID controllers and their disks on system
|
"""Gets all RAID controllers and their disks on system
|
||||||
|
|
||||||
@ -122,6 +141,20 @@ class DellSystemExtension(oem_base.OEMResourceBase):
|
|||||||
controller_to_disks[controller] = storage.drives
|
controller_to_disks[controller] = storage.drives
|
||||||
return controller_to_disks
|
return controller_to_disks
|
||||||
|
|
||||||
|
def _get_storage_list(self):
|
||||||
|
"""Gets all storage items corresponding to RAID controllers
|
||||||
|
|
||||||
|
:returns: list of storage items
|
||||||
|
"""
|
||||||
|
storage_list = []
|
||||||
|
for storage in self._parent_resource.storage.get_members():
|
||||||
|
controller = (storage.storage_controllers[0]
|
||||||
|
if storage.storage_controllers else None)
|
||||||
|
if not controller or controller and not controller.raid_types:
|
||||||
|
continue
|
||||||
|
storage_list.append(storage)
|
||||||
|
return storage_list
|
||||||
|
|
||||||
|
|
||||||
def get_extension(*args, **kwargs):
|
def get_extension(*args, **kwargs):
|
||||||
return DellSystemExtension
|
return DellSystemExtension
|
||||||
|
@ -80,6 +80,93 @@ class DellRaidService(BaseTestCase):
|
|||||||
data={'PDArray': fqdds})
|
data={'PDArray': fqdds})
|
||||||
self.assertEqual(mock_task_mon, task_mon)
|
self.assertEqual(mock_task_mon, task_mon)
|
||||||
|
|
||||||
|
@mock.patch.object(raid_service.DellRaidService,
|
||||||
|
'_get_task_monitor_from_dell_job', autospec=True)
|
||||||
|
def test_clear_foreign_config(self, mock_get_task_mon):
|
||||||
|
mock_task_mon = mock.Mock()
|
||||||
|
mock_get_task_mon.return_value = mock_task_mon
|
||||||
|
|
||||||
|
result = self.raid_service.clear_foreign_config('RAID.Integrated.1-1')
|
||||||
|
|
||||||
|
self.conn.post.assert_called_once_with(
|
||||||
|
'/redfish/v1/Systems/System.Embedded.1/Oem/Dell/DellRaidService/'
|
||||||
|
'Actions/DellRaidService.ClearForeignConfig',
|
||||||
|
data={'TargetFQDD': 'RAID.Integrated.1-1'})
|
||||||
|
self.assertEqual(mock_task_mon, result)
|
||||||
|
|
||||||
|
def test_clear_foreign_config_no_config(self):
|
||||||
|
mock_response = mock.Mock()
|
||||||
|
mock_response.status_code = 400
|
||||||
|
mock_response.json.return_value = {
|
||||||
|
"error": {
|
||||||
|
"@Message.ExtendedInfo": [
|
||||||
|
{
|
||||||
|
"Message": "No foreign configurations detected.",
|
||||||
|
"MessageArgs": [],
|
||||||
|
"MessageArgs@odata.count": 0,
|
||||||
|
"MessageId": "IDRAC.2.5.STOR018",
|
||||||
|
"RelatedProperties": [],
|
||||||
|
"RelatedProperties@odata.count": 0,
|
||||||
|
"Resolution": "If the only foreign drives present are "
|
||||||
|
"in a secured locked state, run a "
|
||||||
|
"secure erase operation on the drives "
|
||||||
|
"to securely erase data or unlock these "
|
||||||
|
"drives and retry the operation. "
|
||||||
|
"Otherwise the operation was not "
|
||||||
|
"successful because there are no "
|
||||||
|
"foreign drives.",
|
||||||
|
"Severity": "Warning"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": "Base.1.8.GeneralError",
|
||||||
|
"message": "A general error has occurred. See ExtendedInfo "
|
||||||
|
"for more information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
no_config_error = exceptions.BadRequestError(
|
||||||
|
'POST', '/redfish/v1/Dell/Systems/System.Embedded.1/'
|
||||||
|
'DellRaidService/Actions/DellRaidService.ClearForeignConfig',
|
||||||
|
mock_response)
|
||||||
|
self.conn.post.side_effect = no_config_error
|
||||||
|
|
||||||
|
result = self.raid_service.clear_foreign_config('RAID.Integrated.1-1')
|
||||||
|
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
def test_clear_foreign_config_bad_request(self):
|
||||||
|
mock_response = mock.Mock()
|
||||||
|
mock_response.status_code = 400
|
||||||
|
mock_response.json.return_value = {
|
||||||
|
"error": {
|
||||||
|
"@Message.ExtendedInfo": [
|
||||||
|
{
|
||||||
|
"Message": "Controller not found.",
|
||||||
|
"MessageArgs": [],
|
||||||
|
"MessageArgs@odata.count": 0,
|
||||||
|
"MessageId": "IDRAC.2.4.STOR030",
|
||||||
|
"RelatedProperties": [],
|
||||||
|
"RelatedProperties@odata.count": 0,
|
||||||
|
"Resolution": "Provide a valid controller FQDD (Fully "
|
||||||
|
"Qualified Device Descriptor) and retry "
|
||||||
|
"the operation.",
|
||||||
|
"Severity": "Warning"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": "Base.1.7.GeneralError",
|
||||||
|
"message": "A general error has occurred. See ExtendedInfo "
|
||||||
|
"for more information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
no_config_error = exceptions.BadRequestError(
|
||||||
|
'POST', '/redfish/v1/Dell/Systems/System.Embedded.1/'
|
||||||
|
'DellRaidService/Actions/DellRaidService.ClearForeignConfig',
|
||||||
|
mock_response)
|
||||||
|
self.conn.post.side_effect = no_config_error
|
||||||
|
|
||||||
|
self.assertRaises(exceptions.BadRequestError,
|
||||||
|
self.raid_service.clear_foreign_config,
|
||||||
|
'RAID.Integrated.999')
|
||||||
|
|
||||||
def test__get_task_monitor_from_dell_job(self):
|
def test__get_task_monitor_from_dell_job(self):
|
||||||
mock_task1 = mock.Mock(identity='JID_111222333444',
|
mock_task1 = mock.Mock(identity='JID_111222333444',
|
||||||
path='/TaskService/Task/JID_111222333444')
|
path='/TaskService/Task/JID_111222333444')
|
||||||
|
@ -110,3 +110,14 @@ class SystemTestCase(BaseTestCase):
|
|||||||
mock_raid.assert_not_called()
|
mock_raid.assert_not_called()
|
||||||
mock_nonraid.assert_called_once_with(
|
mock_nonraid.assert_called_once_with(
|
||||||
['Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1'])
|
['Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1'])
|
||||||
|
|
||||||
|
def test_clear_foreign_config(self):
|
||||||
|
mock_taskmon = mock.Mock()
|
||||||
|
mock_clear_foreign_config = mock.Mock()
|
||||||
|
mock_clear_foreign_config.side_effect = [None, mock_taskmon]
|
||||||
|
self.oem_system.raid_service.clear_foreign_config =\
|
||||||
|
mock_clear_foreign_config
|
||||||
|
|
||||||
|
task_mons = self.oem_system.clear_foreign_config()
|
||||||
|
|
||||||
|
self.assertEqual([mock_taskmon], task_mons)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user