Add ability to set iDRAC card settings

This patch adds the ability to set iDRAC card settings.

Change-Id: I117e5ed0af1469dc316a30abcfa384d3c773ed1f
This commit is contained in:
Christopher Dearborn 2017-11-17 15:41:29 -05:00
parent ee0ca6f1f6
commit b327b0811f
9 changed files with 504 additions and 54 deletions

View File

@ -40,6 +40,7 @@ class DRACClient(object):
"""Client for managing DRAC nodes"""
BIOS_DEVICE_FQDD = 'BIOS.Setup.1-1'
IDRAC_FQDD = 'iDRAC.Embedded.1'
def __init__(
self, host, username, password, port=443, path='/wsman',
@ -191,19 +192,94 @@ class DRACClient(object):
"""
return self._bios_cfg.set_bios_settings(settings)
def list_idrac_settings(self):
def list_idrac_settings(self, by_name=False, fqdd_filter=IDRAC_FQDD):
"""List the iDRAC configuration settings
:returns: a dictionary with the iDRAC settings using InstanceID as the
key. The attributes are either iDRACCArdEnumerableAttribute,
iDRACCardStringAttribute or iDRACCardIntegerAttribute
objects.
:param by_name: Controls whether returned dictionary uses iDRAC card
attribute name as key. If set to False, instance_id
will be used. If set to True the keys will be of the
form "group_id#name".
:param fqdd_filter: An FQDD used to filter the instances. Note that
this is only used when by_name is True.
:returns: a dictionary with the iDRAC settings using instance_id as the
key except when by_name is True. The attributes are either
iDRACCardEnumerableAttribute, iDRACCardStringAttribute or
iDRACCardIntegerAttribute objects.
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC
interface
"""
return self._idrac_cfg.list_idrac_settings()
return self._idrac_cfg.list_idrac_settings(by_name=by_name,
fqdd_filter=fqdd_filter)
def set_idrac_settings(self, settings, idrac_fqdd=IDRAC_FQDD):
"""Sets the iDRAC configuration settings
To be more precise, it sets the pending_value parameter for each of the
attributes passed in. For the values to be applied, a config job may
need to be created and the node may need to be rebooted.
:param settings: a dictionary containing the proposed values, with
each key being the name of attribute qualified with
the group ID in the form "group_id#name" and the value
being the proposed value.
:param idrac_fqdd: the FQDD of the iDRAC.
:returns: a dictionary containing:
- The is_commit_required key with a boolean value indicating
whether a config job must be created for the values to be
applied.
- The is_reboot_required key with a RebootRequired enumerated
value indicating whether the server must be rebooted for the
values to be applied. Possible values are true and false.
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC
interface
:raises: DRACUnexpectedReturnValue on return value mismatch
:raises: InvalidParameterValue on invalid attribute
"""
return self._idrac_cfg.set_idrac_settings(settings, idrac_fqdd)
def commit_pending_idrac_changes(
self,
idrac_fqdd=IDRAC_FQDD,
reboot=False):
"""Creates a config job for applying all pending changes to an iDRAC
:param idrac_fqdd: the FQDD of the iDRAC.
:param reboot: indication of whether to also create a reboot job
:returns: id of the created configuration job
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the iDRAC
interface
:raises: DRACUnexpectedReturnValue on return value mismatch
"""
return self._job_mgmt.create_config_job(
resource_uri=uris.DCIM_iDRACCardService,
cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService',
target=idrac_fqdd,
reboot=reboot)
def abandon_pending_idrac_changes(self, idrac_fqdd=IDRAC_FQDD):
"""Abandon all pending changes to an iDRAC
Once a config job has been submitted, it can no longer be abandoned.
:param idrac_fqdd: the FQDD of the iDRAC.
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the iDRAC
interface
:raises: DRACUnexpectedReturnValue on return value mismatch
"""
self._job_mgmt.delete_pending_config(
resource_uri=uris.DCIM_iDRACCardService,
cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService',
target=idrac_fqdd)
def list_lifecycle_settings(self):
"""List the Lifecycle Controller configuration settings

View File

@ -526,4 +526,5 @@ class BIOSConfiguration(object):
uris.DCIM_BIOSService,
"DCIM_BIOSService",
"DCIM:BIOSService",
'BIOS.Setup.1-1')
'BIOS.Setup.1-1',
include_commit_required=True)

View File

@ -15,34 +15,6 @@ from dracclient.resources import uris
from dracclient import utils
class iDRACCardConfiguration(object):
def __init__(self, client):
"""Creates iDRACCardManagement object
:param client: an instance of WSManClient
"""
self.client = client
def list_idrac_settings(self):
"""List the iDRACCard configuration settings
:returns: a dictionary with the iDRACCard settings using its name as
the key. The attributes are either
iDRACCardEnumerableAttribute, iDRACCardStringAttribute
or iDRACCardIntegerAttribute objects.
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC
interface
"""
namespaces = [(uris.DCIM_iDRACCardEnumeration,
iDRACCardEnumerableAttribute),
(uris.DCIM_iDRACCardString, iDRACCardStringAttribute),
(uris.DCIM_iDRACCardInteger, iDRACCardIntegerAttribute)]
return utils.list_settings(self.client, namespaces, by_name=False)
class iDRACCardAttribute(object):
"""Generic iDRACCard attribute class"""
@ -195,6 +167,20 @@ class iDRACCardStringAttribute(iDRACCardAttribute):
idrac_attr.read_only, idrac_attr.fqdd, idrac_attr.group_id,
min_length, max_length)
def validate(self, new_value):
"""Validates new value"""
val_len = len(new_value)
if val_len < self.min_length or val_len > self.max_length:
msg = ("Attribute '%(attr)s' cannot be set to value '%(val)s'."
" It must be between %(lower)d and %(upper)d characters in "
"length.") % {
'attr': self.name,
'val': new_value,
'lower': self.min_length,
'upper': self.max_length}
return msg
class iDRACCardIntegerAttribute(iDRACCardAttribute):
"""Integer iDRACCard attribute class"""
@ -258,3 +244,83 @@ class iDRACCardIntegerAttribute(iDRACCardAttribute):
'lower': self.lower_bound,
'upper': self.upper_bound}
return msg
class iDRACCardConfiguration(object):
NAMESPACES = [(uris.DCIM_iDRACCardEnumeration,
iDRACCardEnumerableAttribute),
(uris.DCIM_iDRACCardString, iDRACCardStringAttribute),
(uris.DCIM_iDRACCardInteger, iDRACCardIntegerAttribute)]
def __init__(self, client):
"""Creates an iDRACCardConfiguration object
:param client: an instance of WSManClient
"""
self.client = client
def list_idrac_settings(self, by_name=False, fqdd_filter=None):
"""List the iDRACCard configuration settings
:param by_name: Controls whether returned dictionary uses iDRAC card
attribute name as key. If set to False, instance_id
will be used. If set to True the keys will be of the
form "group_id#name".
:param fqdd_filter: An FQDD used to filter the instances. Note that
this is only used when by_name is True.
:returns: a dictionary with the iDRAC settings using instance_id as the
key except when by_name is True. The attributes are either
iDRACCArdEnumerableAttribute, iDRACCardStringAttribute or
iDRACCardIntegerAttribute objects.
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC
interface
"""
return utils.list_settings(self.client,
self.NAMESPACES,
by_name=by_name,
fqdd_filter=fqdd_filter,
name_formatter=_name_formatter)
def set_idrac_settings(self, new_settings, idrac_fqdd):
"""Set the iDRACCard configuration settings
To be more precise, it sets the pending_value parameter for each of the
attributes passed in. For the values to be applied, a config job may
need to be created and the node may need to be rebooted.
:param new_settings: a dictionary containing the proposed values, with
each key being the name of attribute qualified
with the group ID in the form "group_id#name" and
the value being the proposed value.
:param idrac_fqdd: the FQDD of the iDRAC.
:returns: a dictionary containing:
- The is_commit_required key with a boolean value indicating
whether a config job must be created for the values to be
applied.
- The is_reboot_required key with a RebootRequired enumerated
value indicating whether the server must be rebooted for the
values to be applied. Possible values are true and false.
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC
interface
:raises: DRACUnexpectedReturnValue on return value mismatch
:raises: InvalidParameterValue on invalid attribute
"""
return utils.set_settings('iDRAC Card',
self.client,
self.NAMESPACES,
new_settings,
uris.DCIM_iDRACCardService,
"DCIM_iDRACCardService",
"DCIM:iDRACCardService",
idrac_fqdd,
name_formatter=_name_formatter)
def _name_formatter(attribute):
return "{}#{}".format(attribute.group_id, attribute.name)

View File

@ -345,6 +345,7 @@ class RAIDManagement(object):
expected_return_value=utils.RET_SUCCESS)
return utils.build_return_dict(doc, uris.DCIM_RAIDService,
include_commit_required=True,
is_commit_required_value=True)
def create_virtual_disk(self, raid_controller, physical_disks, raid_level,
@ -445,6 +446,7 @@ class RAIDManagement(object):
expected_return_value=utils.RET_SUCCESS)
return utils.build_return_dict(doc, uris.DCIM_RAIDService,
include_commit_required=True,
is_commit_required_value=True)
def delete_virtual_disk(self, virtual_disk):
@ -484,4 +486,5 @@ class RAIDManagement(object):
expected_return_value=utils.RET_SUCCESS)
return utils.build_return_dict(doc, uris.DCIM_RAIDService,
include_commit_required=True,
is_commit_required_value=True)

View File

@ -11,16 +11,25 @@
# License for the specific language governing permissions and limitations
# under the License.
import lxml.etree
import mock
import re
import requests_mock
import dracclient.client
from dracclient import constants
from dracclient import exceptions
from dracclient.resources import idrac_card
from dracclient.resources import job
from dracclient.resources import uris
from dracclient.tests import base
from dracclient.tests import utils as test_utils
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
class ClientiDRACCardConfigurationTestCase(base.BaseTest):
def setUp(self):
@ -28,12 +37,8 @@ class ClientiDRACCardConfigurationTestCase(base.BaseTest):
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
@requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True,
autospec=True)
def test_list_idrac_settings(self, mock_requests,
mock_wait_until_idrac_is_ready):
def test_list_idrac_settings_by_instance_id(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_enum_attr = idrac_card.iDRACCardEnumerableAttribute(
name='Type',
instance_id='iDRAC.Embedded.1#Info.1#Type',
@ -75,7 +80,7 @@ class ClientiDRACCardConfigurationTestCase(base.BaseTest):
idrac_settings = self.drac_client.list_idrac_settings()
self.assertEqual(630, len(idrac_settings))
self.assertEqual(631, len(idrac_settings))
# enumerable attribute
self.assertIn('iDRAC.Embedded.1#Info.1#Type', idrac_settings)
self.assertEqual(expected_enum_attr, idrac_settings[
@ -88,3 +93,222 @@ class ClientiDRACCardConfigurationTestCase(base.BaseTest):
self.assertIn('iDRAC.Embedded.1#SSH.1#Port', idrac_settings)
self.assertEqual(expected_integer_attr, idrac_settings[
'iDRAC.Embedded.1#SSH.1#Port'])
def test_list_idrac_settings_by_name(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_enum_attr = idrac_card.iDRACCardEnumerableAttribute(
name='Type',
instance_id='iDRAC.Embedded.1#Info.1#Type',
read_only=True,
current_value='13G Monolithic',
pending_value=None,
fqdd='iDRAC.Embedded.1',
group_id='Info.1',
possible_values=['12G/13G', '12G Monolithic', '12G Modular',
'13G Monolithic', '13G Modular', '12G DCS',
'13G DCS'])
expected_string_attr = idrac_card.iDRACCardStringAttribute(
name='Version',
instance_id='iDRAC.Embedded.1#Info.1#Version',
read_only=True,
current_value='2.40.40.40',
pending_value=None,
fqdd='iDRAC.Embedded.1',
group_id='Info.1',
min_length=0,
max_length=63)
expected_integer_attr = idrac_card.iDRACCardIntegerAttribute(
name='Port',
instance_id='iDRAC.Embedded.1#SSH.1#Port',
read_only=False,
current_value=22,
pending_value=None,
fqdd='iDRAC.Embedded.1',
group_id='SSH.1',
lower_bound=1,
upper_bound=65535)
mock_requests.post('https://1.2.3.4:443/wsman', [
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardEnumeration]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardString]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardInteger]['ok']}])
idrac_settings = self.drac_client.list_idrac_settings(by_name=True)
self.assertEqual(630, len(idrac_settings))
# enumerable attribute
self.assertIn('Info.1#Type', idrac_settings)
self.assertEqual(expected_enum_attr, idrac_settings[
'Info.1#Type'])
# string attribute
self.assertIn('Info.1#Version', idrac_settings)
self.assertEqual(expected_string_attr,
idrac_settings['Info.1#Version'])
# integer attribute
self.assertIn('SSH.1#Port', idrac_settings)
self.assertEqual(expected_integer_attr, idrac_settings[
'SSH.1#Port'])
def test_list_multi_idrac_settings_by_name(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_enum_attr = idrac_card.iDRACCardEnumerableAttribute(
name='Type',
instance_id='iDRAC.Embedded.2#Info.1#Type',
read_only=True,
current_value='13G Monolithic',
pending_value=None,
fqdd='iDRAC.Embedded.2',
group_id='Info.1',
possible_values=['12G/13G', '12G Monolithic', '12G Modular',
'13G Monolithic', '13G Modular', '12G DCS',
'13G DCS'])
mock_requests.post('https://1.2.3.4:443/wsman', [
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardEnumeration]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardString]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardInteger]['ok']}])
idrac_settings = self.drac_client.list_idrac_settings(
by_name=True, fqdd_filter='iDRAC.Embedded.2')
self.assertEqual(1, len(idrac_settings))
# enumerable attribute
self.assertIn('Info.1#Type', idrac_settings)
self.assertEqual(expected_enum_attr, idrac_settings[
'Info.1#Type'])
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_set_idrac_settings(
self, mock_requests, mock_invoke, mock_wait_until_idrac_is_ready):
expected_selectors = {'CreationClassName': 'DCIM_iDRACCardService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:iDRACCardService',
'SystemCreationClassName': 'DCIM_ComputerSystem'}
expected_properties = {'Target': 'iDRAC.Embedded.1',
'AttributeName': ['LDAP.1#GroupAttributeIsDN'],
'AttributeValue': ['Disabled']}
mock_requests.post('https://1.2.3.4:443/wsman', [
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardEnumeration]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardString]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardInteger]['ok']}])
mock_invoke.return_value = lxml.etree.fromstring(
test_utils.iDracCardInvocations[uris.DCIM_iDRACCardService][
'SetAttributes']['ok'])
result = self.drac_client.set_idrac_settings(
{'LDAP.1#GroupAttributeIsDN': 'Disabled'})
self.assertEqual({'is_commit_required': True,
'is_reboot_required':
constants.RebootRequired.false},
result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_iDRACCardService, 'SetAttributes',
expected_selectors, expected_properties)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_set_idrac_settings_with_valid_length_string(
self, mock_requests, mock_invoke, mock_wait_until_idrac_is_ready):
expected_selectors = {'CreationClassName': 'DCIM_iDRACCardService',
'SystemName': 'DCIM:ComputerSystem',
'Name': 'DCIM:iDRACCardService',
'SystemCreationClassName': 'DCIM_ComputerSystem'}
expected_properties = {'Target': 'iDRAC.Embedded.1',
'AttributeName': ['Users.16#Password'],
'AttributeValue': ['12345678901234567890']}
mock_requests.post('https://1.2.3.4:443/wsman', [
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardEnumeration]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardString]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardInteger]['ok']}])
mock_invoke.return_value = lxml.etree.fromstring(
test_utils.iDracCardInvocations[uris.DCIM_iDRACCardService][
'SetAttributes']['ok'])
result = self.drac_client.set_idrac_settings(
{'Users.16#Password': '12345678901234567890'})
self.assertEqual({'is_commit_required': True,
'is_reboot_required':
constants.RebootRequired.false},
result)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_iDRACCardService, 'SetAttributes',
expected_selectors, expected_properties)
def test_set_idrac_settings_with_too_long_string(
self, mock_requests, mock_wait_until_idrac_is_ready):
expected_message = ("Attribute 'Password' cannot be set to "
"value '123456789012345678901'. It must be "
"between 0 and 20 characters in length.")
mock_requests.post('https://1.2.3.4:443/wsman', [
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardEnumeration]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardString]['ok']},
{'text': test_utils.iDracCardEnumerations[
uris.DCIM_iDRACCardInteger]['ok']}])
self.assertRaisesRegexp(
exceptions.DRACOperationFailed, re.escape(expected_message),
self.drac_client.set_idrac_settings,
{'Users.16#Password': '123456789012345678901'})
class ClientiDRACCardChangesTestCase(base.BaseTest):
def setUp(self):
super(ClientiDRACCardChangesTestCase, self).setUp()
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
@mock.patch.object(job.JobManagement, 'create_config_job', spec_set=True,
autospec=True)
def test_commit_pending_idrac_changes(self, mock_create_config_job):
self.drac_client.commit_pending_idrac_changes()
mock_create_config_job.assert_called_once_with(
mock.ANY,
resource_uri=uris.DCIM_iDRACCardService,
cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService',
target=dracclient.client.DRACClient.IDRAC_FQDD,
reboot=False)
@mock.patch.object(job.JobManagement, 'create_config_job', spec_set=True,
autospec=True)
def test_commit_pending_idrac_changes_with_reboot(
self, mock_create_config_job):
self.drac_client.commit_pending_idrac_changes(
reboot=True)
mock_create_config_job.assert_called_once_with(
mock.ANY,
resource_uri=uris.DCIM_iDRACCardService,
cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService',
target=dracclient.client.DRACClient.IDRAC_FQDD,
reboot=True)
@mock.patch.object(job.JobManagement, 'delete_pending_config',
spec_set=True, autospec=True)
def test_abandon_pending_idrac_changes(self, mock_delete_pending_config):
self.drac_client.abandon_pending_idrac_changes()
mock_delete_pending_config.assert_called_once_with(
mock.ANY,
resource_uri=uris.DCIM_iDRACCardService,
cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService',
target=dracclient.client.DRACClient.IDRAC_FQDD)

View File

@ -147,6 +147,15 @@ iDracCardEnumerations = {
},
}
iDracCardInvocations = {
uris.DCIM_iDRACCardService: {
'SetAttributes': {
'ok': load_wsman_xml(
'idrac_service-invoke-set_attributes-ok')
}
}
}
LifecycleControllerEnumerations = {
uris.DCIM_SystemView: {
'ok': load_wsman_xml('system_view-enum-ok')

View File

@ -0,0 +1,19 @@
<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_iDRACCardService">
<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_iDRACCardService/SetAttributesResponse</wsa:Action>
<wsa:RelatesTo>uuid:305ed6f4-2269-43c5-8c28-00b85e81099d</wsa:RelatesTo>
<wsa:MessageID>uuid:683c34bc-53c4-13c4-8064-17c1f0d9bed4</wsa:MessageID>
</s:Header>
<s:Body>
<n1:SetAttributes_OUTPUT>
<n1:Message>The command was successful</n1:Message>
<n1:MessageID>RAC001</n1:MessageID>
<n1:RebootRequired>No</n1:RebootRequired>
<n1:ReturnValue>0</n1:ReturnValue>
<n1:SetResult>Set PendingValue</n1:SetResult>
</n1:SetAttributes_OUTPUT>
</s:Body>
</s:Envelope>

View File

@ -13,6 +13,27 @@
<s:Body>
<wsen:EnumerateResponse>
<wsman:Items>
<n1:DCIM_iDRACCardEnumeration>
<n1:AttributeDisplayName>iDRAC Type</n1:AttributeDisplayName>
<n1:AttributeName>Type</n1:AttributeName>
<n1:CurrentValue>13G Monolithic</n1:CurrentValue>
<n1:DefaultValue>12G/13G</n1:DefaultValue>
<n1:Dependency xsi:nil="true"/>
<n1:DisplayOrder>6</n1:DisplayOrder>
<n1:FQDD>iDRAC.Embedded.2</n1:FQDD>
<n1:GroupDisplayName>RAC Information</n1:GroupDisplayName>
<n1:GroupID>Info.1</n1:GroupID>
<n1:InstanceID>iDRAC.Embedded.2#Info.1#Type</n1:InstanceID>
<n1:IsReadOnly>true</n1:IsReadOnly>
<n1:PendingValue xsi:nil="true"/>
<n1:PossibleValues>12G/13G</n1:PossibleValues>
<n1:PossibleValues>12G Monolithic</n1:PossibleValues>
<n1:PossibleValues>12G Modular</n1:PossibleValues>
<n1:PossibleValues>13G Monolithic</n1:PossibleValues>
<n1:PossibleValues>13G Modular</n1:PossibleValues>
<n1:PossibleValues>12G DCS</n1:PossibleValues>
<n1:PossibleValues>13G DCS</n1:PossibleValues>
</n1:DCIM_iDRACCardEnumeration>
<n1:DCIM_iDRACCardEnumeration>
<n1:AttributeDisplayName>iDRAC Type</n1:AttributeDisplayName>
<n1:AttributeName>Type</n1:AttributeName>

View File

@ -133,7 +133,8 @@ def get_all_wsman_resource_attrs(doc, resource_uri, attr_name, nullable=False):
def build_return_dict(doc, resource_uri,
is_commit_required_value=None,
is_reboot_required_value=None,
commit_required_value=None):
commit_required_value=None,
include_commit_required=False):
"""Builds a dictionary to be returned
Build a dictionary to be returned from WSMAN operations that are not
@ -150,6 +151,8 @@ def build_return_dict(doc, resource_uri,
:param commit_required_value: The value to be returned for
commit_required, or None if the value should be determined
from the doc.
:parm include_commit_required: Indicates if the deprecated commit_required
should be returned in the result.
:returns: a dictionary containing:
- is_commit_required: indicates if a commit is required.
- is_reboot_required: indicates if a reboot is required.
@ -179,10 +182,11 @@ def build_return_dict(doc, resource_uri,
# Include commit_required in the response for backwards compatibility
# TBD: Remove this parameter in the future
if commit_required_value is None:
commit_required_value = is_reboot_required(doc, resource_uri)
if include_commit_required:
if commit_required_value is None:
commit_required_value = is_reboot_required(doc, resource_uri)
result['commit_required'] = commit_required_value
result['commit_required'] = commit_required_value
return result
@ -246,13 +250,19 @@ def validate_integer_value(value, attr_name, error_msgs):
error_msgs.append("'%s' is not an integer value" % attr_name)
def list_settings(client, namespaces, by_name=True):
def list_settings(client, namespaces, by_name=True, fqdd_filter=None,
name_formatter=None):
"""List the configuration settings
:param client: an instance of WSManClient.
:param namespaces: a list of URI/class pairs to retrieve.
:param by_name: controls whether returned dictionary uses
attribute name or instance_id as key.
:param fqdd_filter: An FQDD used to filter the instances. Note that
this is only used when by_name is True.
:param name_formatter: a method used to format the keys in the
returned dictionary. By default,
attribute.name will be used.
:returns: a dictionary with the settings using name or instance_id as
the key.
:raises: WSManRequestFailure on request failures
@ -263,7 +273,8 @@ def list_settings(client, namespaces, by_name=True):
result = {}
for (namespace, attr_cls) in namespaces:
attribs = _get_config(client, namespace, attr_cls, by_name)
attribs = _get_config(client, namespace, attr_cls, by_name,
fqdd_filter, name_formatter)
if not set(result).isdisjoint(set(attribs)):
raise exceptions.DRACOperationFailed(
drac_messages=('Colliding attributes %r' % (
@ -272,7 +283,8 @@ def list_settings(client, namespaces, by_name=True):
return result
def _get_config(client, resource, attr_cls, by_name):
def _get_config(client, resource, attr_cls, by_name, fqdd_filter,
name_formatter):
result = {}
doc = client.enumerate(resource)
@ -281,7 +293,14 @@ def _get_config(client, resource, attr_cls, by_name):
for item in items:
attribute = attr_cls.parse(item)
if by_name:
result[attribute.name] = attribute
# Filter out all instances without a matching FQDD
if fqdd_filter is None or fqdd_filter == attribute.fqdd:
if name_formatter is None:
name = attribute.name
else:
name = name_formatter(attribute)
result[name] = attribute
else:
result[attribute.instance_id] = attribute
@ -295,7 +314,9 @@ def set_settings(settings_type,
resource_uri,
cim_creation_class_name,
cim_name,
target):
target,
name_formatter=None,
include_commit_required=False):
"""Generically handles setting various types of settings on the iDRAC
This method pulls the current list of settings from the iDRAC then compares
@ -313,6 +334,11 @@ def set_settings(settings_type,
:param cim_creation_class_name: creation class name of the CIM object
:param cim_name: name of the CIM object
:param target: target device
:param name_formatter: a method used to format the keys in the
returned dictionary. By default,
attribute.name will be used.
:parm include_commit_required: Indicates if the deprecated commit_required
should be returned in the result.
: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
@ -334,7 +360,8 @@ def set_settings(settings_type,
:raises: InvalidParameterValue on invalid new setting
"""
current_settings = list_settings(client, namespaces, by_name=True)
current_settings = list_settings(client, namespaces, by_name=True,
name_formatter=name_formatter)
unknown_keys = set(new_settings) - set(current_settings)
if unknown_keys:
@ -383,7 +410,10 @@ def set_settings(settings_type,
if not attrib_names:
return build_return_dict(
None, resource_uri, is_commit_required_value=False,
None,
resource_uri,
include_commit_required=include_commit_required,
is_commit_required_value=False,
is_reboot_required_value=constants.RebootRequired.false,
commit_required_value=False)
@ -398,4 +428,5 @@ def set_settings(settings_type,
doc = client.invoke(resource_uri, 'SetAttributes',
selectors, properties)
return build_return_dict(doc, resource_uri)
return build_return_dict(doc, resource_uri,
include_commit_required=include_commit_required)