Add constituent physical disks to RAID virtual disk object
This change adds a new attribute - physical_disks - to dracclient.resources.raid.VirtualDisk objects. The attribute is a list of IDs of the physical disks that a virtual disk is composed of. This allows clients of the library to obtain a more complete view of the current RAID configuration. Change-Id: If4f762d3bc115a971d0392af8270f5440ef43913 Closes-bug: #1651702
This commit is contained in:
parent
aa25303e3d
commit
2a80dbb2c9
dracclient
@ -113,7 +113,7 @@ VirtualDiskTuple = collections.namedtuple(
|
||||
'VirtualDisk',
|
||||
['id', 'name', 'description', 'controller', 'raid_level', 'size_mb',
|
||||
'status', 'raid_status', 'span_depth', 'span_length',
|
||||
'pending_operations'])
|
||||
'pending_operations', 'physical_disks'])
|
||||
|
||||
|
||||
class VirtualDisk(VirtualDiskTuple):
|
||||
@ -239,13 +239,19 @@ class RAIDManagement(object):
|
||||
span_length=int(self._get_virtual_disk_attr(drac_disk,
|
||||
'SpanLength')),
|
||||
pending_operations=(
|
||||
VIRTUAL_DISK_PENDING_OPERATIONS[drac_pending_operations]))
|
||||
VIRTUAL_DISK_PENDING_OPERATIONS[drac_pending_operations]),
|
||||
physical_disks=self._get_virtual_disk_attrs(drac_disk,
|
||||
'PhysicalDiskIDs'))
|
||||
|
||||
def _get_virtual_disk_attr(self, drac_disk, attr_name, nullable=False):
|
||||
return utils.get_wsman_resource_attr(
|
||||
drac_disk, uris.DCIM_VirtualDiskView, attr_name,
|
||||
nullable=nullable)
|
||||
|
||||
def _get_virtual_disk_attrs(self, drac_disk, attr_name):
|
||||
return utils.get_all_wsman_resource_attrs(
|
||||
drac_disk, uris.DCIM_VirtualDiskView, attr_name, nullable=False)
|
||||
|
||||
def list_physical_disks(self):
|
||||
"""Returns the list of physical disks
|
||||
|
||||
|
@ -62,7 +62,11 @@ class ClientRAIDManagementTestCase(base.BaseTest):
|
||||
raid_status='online',
|
||||
span_depth=1,
|
||||
span_length=2,
|
||||
pending_operations=None)
|
||||
pending_operations=None,
|
||||
physical_disks=[
|
||||
'Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1',
|
||||
'Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1'
|
||||
])
|
||||
|
||||
mock_requests.post(
|
||||
'https://1.2.3.4:443/wsman',
|
||||
@ -452,7 +456,7 @@ class ClientRAIDManagementTestCase(base.BaseTest):
|
||||
|
||||
@mock.patch.object(dracclient.resources.job.JobManagement,
|
||||
'delete_pending_config', spec_set=True, autospec=True)
|
||||
def test_abandon_pending_bios_changes(self, mock_requests,
|
||||
def test_abandon_pending_raid_changes(self, mock_requests,
|
||||
mock_delete_pending_config):
|
||||
self.drac_client.abandon_pending_raid_changes('controller')
|
||||
|
||||
|
@ -27,6 +27,28 @@ class UtilsTestCase(base.BaseTest):
|
||||
def setUp(self):
|
||||
super(UtilsTestCase, self).setUp()
|
||||
|
||||
def test__is_attr_non_nil_True(self):
|
||||
doc = etree.fromstring(
|
||||
test_utils.RAIDEnumerations[
|
||||
uris.DCIM_ControllerView]['ok'])
|
||||
controllers = utils.find_xml(doc, 'DCIM_ControllerView',
|
||||
uris.DCIM_ControllerView, find_all=True)
|
||||
version = utils.find_xml(controllers[0], 'Bus',
|
||||
uris.DCIM_ControllerView)
|
||||
|
||||
self.assertTrue(utils._is_attr_non_nil(version))
|
||||
|
||||
def test__is_attr_non_nil_False(self):
|
||||
doc = etree.fromstring(
|
||||
test_utils.RAIDEnumerations[
|
||||
uris.DCIM_ControllerView]['ok'])
|
||||
controllers = utils.find_xml(doc, 'DCIM_ControllerView',
|
||||
uris.DCIM_ControllerView, find_all=True)
|
||||
version = utils.find_xml(controllers[0], 'DriverVersion',
|
||||
uris.DCIM_ControllerView)
|
||||
|
||||
self.assertFalse(utils._is_attr_non_nil(version))
|
||||
|
||||
def test_get_wsman_resource_attr(self):
|
||||
doc = etree.fromstring(
|
||||
test_utils.InventoryEnumerations[uris.DCIM_CPUView]['ok'])
|
||||
@ -79,3 +101,68 @@ class UtilsTestCase(base.BaseTest):
|
||||
exceptions.DRACEmptyResponseField, re.escape(expected_message),
|
||||
utils.get_wsman_resource_attr, cpus[0], uris.DCIM_CPUView,
|
||||
'HyperThreadingEnabled', allow_missing=False)
|
||||
|
||||
def test_get_wsman_resource_attr_missing_text_allowed(self):
|
||||
doc = etree.fromstring(
|
||||
test_utils.RAIDEnumerations[
|
||||
uris.DCIM_ControllerView]['ok'])
|
||||
controllers = utils.find_xml(doc, 'DCIM_ControllerView',
|
||||
uris.DCIM_ControllerView, find_all=True)
|
||||
|
||||
result = utils.get_wsman_resource_attr(
|
||||
controllers[0], uris.DCIM_ControllerView, 'DriverVersion',
|
||||
allow_missing=False, nullable=True)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_get_all_wsman_resource_attrs(self):
|
||||
doc = etree.fromstring(
|
||||
test_utils.RAIDEnumerations[uris.DCIM_VirtualDiskView]['ok'])
|
||||
vdisks = utils.find_xml(doc, 'DCIM_VirtualDiskView',
|
||||
uris.DCIM_VirtualDiskView, find_all=True)
|
||||
|
||||
vals = utils.get_all_wsman_resource_attrs(
|
||||
vdisks[0], uris.DCIM_VirtualDiskView, 'PhysicalDiskIDs')
|
||||
|
||||
expected_pdisks = [
|
||||
'Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1',
|
||||
'Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1'
|
||||
]
|
||||
self.assertListEqual(expected_pdisks, vals)
|
||||
|
||||
def test_get_all_wsman_resource_attrs_missing_attr_allowed(self):
|
||||
doc = etree.fromstring(
|
||||
test_utils.InventoryEnumerations[
|
||||
uris.DCIM_CPUView]['missing_flags'])
|
||||
cpus = utils.find_xml(doc, 'DCIM_CPUView', uris.DCIM_CPUView,
|
||||
find_all=True)
|
||||
|
||||
vals = utils.get_all_wsman_resource_attrs(
|
||||
cpus[0], uris.DCIM_CPUView, 'HyperThreadingEnabled')
|
||||
|
||||
self.assertListEqual([], vals)
|
||||
|
||||
def test_get_all_wsman_resource_attrs_missing_text(self):
|
||||
expected_message = ("Attribute 'HyperThreadingEnabled' is not nullable"
|
||||
", but no value received")
|
||||
doc = etree.fromstring(
|
||||
test_utils.InventoryEnumerations[
|
||||
uris.DCIM_CPUView]['empty_flag'])
|
||||
cpus = utils.find_xml(doc, 'DCIM_CPUView', uris.DCIM_CPUView,
|
||||
find_all=True)
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
exceptions.DRACEmptyResponseField, re.escape(expected_message),
|
||||
utils.get_all_wsman_resource_attrs, cpus[0], uris.DCIM_CPUView,
|
||||
'HyperThreadingEnabled')
|
||||
|
||||
def test_get_all_wsman_resource_attrs_missing_text_allowed(self):
|
||||
doc = etree.fromstring(
|
||||
test_utils.RAIDEnumerations[
|
||||
uris.DCIM_ControllerView]['ok'])
|
||||
controllers = utils.find_xml(doc, 'DCIM_ControllerView',
|
||||
uris.DCIM_ControllerView, find_all=True)
|
||||
|
||||
result = utils.get_all_wsman_resource_attrs(
|
||||
controllers[0], uris.DCIM_ControllerView, 'DriverVersion',
|
||||
nullable=True)
|
||||
self.assertEqual(result, [])
|
||||
|
@ -30,7 +30,8 @@
|
||||
<n1:OperationName>Background Intialization</n1:OperationName>
|
||||
<n1:OperationPercentComplete>8</n1:OperationPercentComplete>
|
||||
<n1:PendingOperations>0</n1:PendingOperations>
|
||||
<n1:PhysicalDiskIDs xsi:nil="true"/>
|
||||
<n1:PhysicalDiskIDs>Disk.Bay.0:Enclosure.Internal.0-1:RAID.Integrated.1-1</n1:PhysicalDiskIDs>
|
||||
<n1:PhysicalDiskIDs>Disk.Bay.1:Enclosure.Internal.0-1:RAID.Integrated.1-1</n1:PhysicalDiskIDs>
|
||||
<n1:PrimaryStatus>1</n1:PrimaryStatus>
|
||||
<n1:RAIDStatus>2</n1:RAIDStatus>
|
||||
<n1:RAIDTypes>4</n1:RAIDTypes>
|
||||
@ -51,4 +52,4 @@
|
||||
<wsman:EndOfSequence/>
|
||||
</wsen:EnumerateResponse>
|
||||
</s:Body>
|
||||
</s:Envelope>
|
||||
</s:Envelope>
|
||||
|
@ -46,6 +46,15 @@ def find_xml(doc, item, namespace, find_all=False):
|
||||
return doc.find(query)
|
||||
|
||||
|
||||
def _is_attr_non_nil(elem):
|
||||
"""Return whether an element is non-nil.
|
||||
|
||||
:param elem: the element object.
|
||||
:returns: whether the element is nil.
|
||||
"""
|
||||
return elem.attrib.get('{%s}nil' % NS_XMLSchema_Instance) != 'true'
|
||||
|
||||
|
||||
def get_wsman_resource_attr(doc, resource_uri, attr_name, nullable=False,
|
||||
allow_missing=False):
|
||||
"""Find an attribute of a resource in an ElementTree object.
|
||||
@ -78,11 +87,37 @@ def get_wsman_resource_attr(doc, resource_uri, attr_name, nullable=False,
|
||||
raise exceptions.DRACEmptyResponseField(attr=attr_name)
|
||||
return item.text.strip()
|
||||
else:
|
||||
nil_attr = item.attrib.get('{%s}nil' % NS_XMLSchema_Instance)
|
||||
if nil_attr != 'true':
|
||||
if _is_attr_non_nil(item):
|
||||
return item.text.strip()
|
||||
|
||||
|
||||
def get_all_wsman_resource_attrs(doc, resource_uri, attr_name, nullable=False):
|
||||
"""Find all instances of an attribute of a resource in an ElementTree.
|
||||
|
||||
:param doc: the element tree object.
|
||||
:param resource_uri: the resource URI of the namespace.
|
||||
:param attr_name: the name of the attribute.
|
||||
:param nullable: enables checking if any of the elements contain an
|
||||
XMLSchema-instance namespaced nil attribute that has a
|
||||
value of True. In this case, these elements will not be
|
||||
returned.
|
||||
:raises: DRACEmptyResponseField if any of the attributes in the XML doc
|
||||
have no text and nullable is False.
|
||||
:returns: a list containing the value of each of the instances of the
|
||||
attribute.
|
||||
"""
|
||||
items = find_xml(doc, attr_name, resource_uri, find_all=True)
|
||||
|
||||
if not nullable:
|
||||
for item in items:
|
||||
if item.text is None:
|
||||
raise exceptions.DRACEmptyResponseField(attr=attr_name)
|
||||
return [item.text.strip() for item in items]
|
||||
else:
|
||||
|
||||
return [item.text.strip() for item in items if _is_attr_non_nil(item)]
|
||||
|
||||
|
||||
def is_reboot_required(doc, resource_uri):
|
||||
"""Check the response document if reboot is requested.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user