Add interface to convert disks to RAID mode

A new function, convert_physical_disks, converts disks to and from
RAID mode.  This function enables a Dell system at factory defaults
to be initialised with a RAID configuration by python-dracclient.

Change-Id: Ice40bfb47485056428a22c216990cf0a026c73d2
This commit is contained in:
Stig Telfer 2016-06-02 08:51:01 +01:00
parent a696dcd94d
commit 3e9d66173b
6 changed files with 242 additions and 0 deletions

View File

@ -326,6 +326,25 @@ class DRACClient(object):
"""
return self._raid_mgmt.list_physical_disks()
def convert_physical_disks(self, raid_controller, physical_disks,
raid_enable=True):
"""Changes the operational mode of a physical disk.
Disks can be enabled or disabled for RAID mode.
:param raid_controller: the FQDD ID of the RAID controller
:param physical_disks: list of FQDD ID strings of the physical disks
to update
:param raid_enable: boolean flag, set to True if the disk is to
become part of the RAID. The same flag is applied to all
listed disks
:returns: a dictionary containing the commit_required key with a
boolean value indicating whether a config job must be
created for the values to be applied.
"""
return self._raid_mgmt.convert_physical_disks(
physical_disks, raid_enable)
def create_virtual_disk(self, raid_controller, physical_disks, raid_level,
size_mb, disk_name=None, span_length=None,
span_depth=None):

View File

@ -234,6 +234,36 @@ class RAIDManagement(object):
return utils.get_wsman_resource_attr(
drac_disk, uris.DCIM_PhysicalDiskView, attr_name)
def convert_physical_disks(self, physical_disks, raid_enable):
"""Converts a list of physical disks into or out of RAID mode.
Disks can be enabled or disabled for RAID mode.
:param physical_disks: list of FQDD ID strings of the physical disks
to update
:param raid_enable: boolean flag, set to True if the disk is to
become part of the RAID. The same flag is applied to all
listed disks
:returns: a dictionary containing the commit_needed key with a boolean
value indicating whether a config job must be created for the
values to be applied.
"""
invocation = 'ConvertToRAID' if raid_enable else 'ConvertToNonRAID'
selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'CreationClassName': 'DCIM_RAIDService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:RAIDService'}
properties = {'PDArray': physical_disks}
doc = self.client.invoke(uris.DCIM_RAIDService, invocation,
selectors, properties,
expected_return_value=utils.RET_SUCCESS)
return {'commit_required':
utils.is_reboot_required(doc, uris.DCIM_RAIDService)}
def create_virtual_disk(self, raid_controller, physical_disks, raid_level,
size_mb, disk_name=None, span_length=None,
span_depth=None):

View File

@ -15,6 +15,7 @@ import re
import lxml.etree
import mock
import random
import requests_mock
import dracclient.client
@ -702,6 +703,162 @@ class ClientRAIDManagementTestCase(base.BaseTest):
self.assertIn(expected_physical_disk,
self.drac_client.list_physical_disks())
# Verify that various client convert_physical_disks calls to dracclient
# result in a WSMan.invoke with appropriate parameters
def _random_term(self):
return "".join(random.sample('ABCDEFGHabcdefgh0123456',
random.randint(4, 12)))
def _random_fqdd(self):
result = self._random_term()
for i in range(0, random.randint(6, 10)):
result += random.sample('.:-', 1)[0] + self._random_term()
return result
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_convert_physical_disks_1(self, mock_requests, mock_invoke):
'''Convert a single disk to RAID mode'''
device_fqdd = self._random_fqdd()
expected_invocation = 'ConvertToRAID'
expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'CreationClassName': 'DCIM_RAIDService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:RAIDService'}
expected_properties = {'PDArray': [device_fqdd]}
result = self.drac_client.convert_physical_disks(
raid_controller='controller',
physical_disks=[device_fqdd],
raid_enable=True)
self.assertEqual({'commit_required': False}, result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_RAIDService, expected_invocation,
expected_selectors, expected_properties,
expected_return_value=utils.RET_SUCCESS)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_convert_physical_disks_n(self, mock_requests, mock_invoke):
'''Convert a number of disks to RAID mode'''
device_list = []
for i in range(0, random.randint(2, 10)):
device_list += self._random_fqdd()
expected_invocation = 'ConvertToRAID'
expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'CreationClassName': 'DCIM_RAIDService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:RAIDService'}
expected_properties = {'PDArray': device_list}
result = self.drac_client.convert_physical_disks(
raid_controller='controller',
physical_disks=device_list,
raid_enable=True)
self.assertEqual({'commit_required': False}, result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_RAIDService, expected_invocation,
expected_selectors, expected_properties,
expected_return_value=utils.RET_SUCCESS)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_convert_physical_disks_nonraid_1(self, mock_requests,
mock_invoke):
'''Convert a single disk to non-RAID mode'''
device_fqdd = self._random_fqdd()
expected_invocation = 'ConvertToNonRAID'
expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'CreationClassName': 'DCIM_RAIDService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:RAIDService'}
expected_properties = {'PDArray': [device_fqdd]}
result = self.drac_client.convert_physical_disks(
raid_controller='controller',
physical_disks=[device_fqdd],
raid_enable=False)
self.assertEqual({'commit_required': False}, result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_RAIDService, expected_invocation,
expected_selectors, expected_properties,
expected_return_value=utils.RET_SUCCESS)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_convert_physical_disks_nonraid_n(self, mock_requests,
mock_invoke):
'''Convert a number of disks to non-RAID mode'''
device_list = []
for i in range(0, random.randint(2, 10)):
device_list += self._random_fqdd()
expected_invocation = 'ConvertToNonRAID'
expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'CreationClassName': 'DCIM_RAIDService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:RAIDService'}
expected_properties = {'PDArray': device_list}
result = self.drac_client.convert_physical_disks(
raid_controller='controller',
physical_disks=device_list,
raid_enable=False)
self.assertEqual({'commit_required': False}, result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_RAIDService, expected_invocation,
expected_selectors, expected_properties,
expected_return_value=utils.RET_SUCCESS)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_convert_physical_disks_ok(self, mock_requests, mock_invoke):
'''Convert a number of disks to RAID mode and check the return value'''
device_list = []
for i in range(0, random.randint(2, 10)):
device_list += self._random_fqdd()
expected_invocation = 'ConvertToRAID'
expected_selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'CreationClassName': 'DCIM_RAIDService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:RAIDService'}
expected_properties = {'PDArray': device_list}
mock_invoke.return_value = lxml.etree.fromstring(
test_utils.RAIDInvocations[uris.DCIM_RAIDService][
expected_invocation]['ok'])
result = self.drac_client.convert_physical_disks(
raid_controller='controller',
physical_disks=device_list,
raid_enable=True)
self.assertEqual({'commit_required': True}, result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_RAIDService, expected_invocation,
expected_selectors, expected_properties,
expected_return_value=utils.RET_SUCCESS)
def test_convert_physical_disks_fail(self, mock_requests):
mock_requests.post(
'https://1.2.3.4:443/wsman',
text=test_utils.RAIDInvocations[
uris.DCIM_RAIDService]['ConvertToRAID']['error'])
self.assertRaises(
exceptions.DRACOperationFailed,
self.drac_client.convert_physical_disks,
raid_controller='controller',
physical_disks=['Disk0:Enclosure-1:RAID-1',
'Disk1:Enclosure-1:RAID-1'],
raid_enable=True)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_create_virtual_disk(self, mock_requests, mock_invoke):

View File

@ -164,6 +164,12 @@ RAIDInvocations = {
'raid_service-invoke-delete_virtual_disk-ok'),
'error': load_wsman_xml(
'raid_service-invoke-delete_virtual_disk-error'),
},
'ConvertToRAID': {
'ok': load_wsman_xml(
'raid_service-invoke-convert_physical_disks-ok'),
'error': load_wsman_xml(
'raid_service-invoke-convert_physical_disks-error'),
}
}
}

View File

@ -0,0 +1,16 @@
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:n1="http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService">
<s:Header>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:Action>http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ConvertToRAIDResponse</wsa:Action>
<wsa:RelatesTo>uuid:6364e38d-4e3c-4769-8c67-ff4332ea603a</wsa:RelatesTo>
<wsa:MessageID>uuid:ad08919a-34b2-14b2-a4b0-ea19c46a0064</wsa:MessageID>
</s:Header>
<s:Body>
<n1:ConvertToRAID_OUTPUT>
<n1:Message>Invalid parameter value</n1:Message>
<n1:MessageArguments>NULL</n1:MessageArguments>
<n1:MessageID>STOR004</n1:MessageID>
<n1:ReturnValue>2</n1:ReturnValue>
</n1:ConvertToRAID_OUTPUT>
</s:Body>
</s:Envelope>

View File

@ -0,0 +1,14 @@
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:n1="http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService">
<s:Header>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:Action>http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_RAIDService/ConvertToRAIDResponse</wsa:Action>
<wsa:RelatesTo>uuid:c6c4bcf6-c340-4f0b-9aef-3c7be94f0d61</wsa:RelatesTo>
<wsa:MessageID>uuid:3223ac5b-3439-1439-9855-ea19c46a0064</wsa:MessageID>
</s:Header>
<s:Body>
<n1:ConvertToRAID_OUTPUT>
<n1:RebootRequired>YES</n1:RebootRequired>
<n1:ReturnValue>0</n1:ReturnValue>
</n1:ConvertToRAID_OUTPUT>
</s:Body>
</s:Envelope>