Refactor list_bios_settings and set_bios_settings
This patch factors the code in list_bios_settings and set_bios_settings out into utility methods that can be used by other code that has the same functionality. Change-Id: I310fc0cb1c8372b1391d085078686e616890eb6f
This commit is contained in:
parent
72ea2323e5
commit
ee0ca6f1f6
|
@ -20,7 +20,6 @@ from dracclient import exceptions
|
||||||
from dracclient.resources import lifecycle_controller
|
from dracclient.resources import lifecycle_controller
|
||||||
from dracclient.resources import uris
|
from dracclient.resources import uris
|
||||||
from dracclient import utils
|
from dracclient import utils
|
||||||
from dracclient import wsman
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -463,6 +462,10 @@ class BIOSIntegerAttribute(BIOSAttribute):
|
||||||
|
|
||||||
class BIOSConfiguration(object):
|
class BIOSConfiguration(object):
|
||||||
|
|
||||||
|
NAMESPACES = [(uris.DCIM_BIOSEnumeration, BIOSEnumerableAttribute),
|
||||||
|
(uris.DCIM_BIOSString, BIOSStringAttribute),
|
||||||
|
(uris.DCIM_BIOSInteger, BIOSIntegerAttribute)]
|
||||||
|
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
"""Creates BIOSConfiguration object
|
"""Creates BIOSConfiguration object
|
||||||
|
|
||||||
|
@ -484,33 +487,7 @@ class BIOSConfiguration(object):
|
||||||
interface
|
interface
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = {}
|
return utils.list_settings(self.client, self.NAMESPACES, by_name)
|
||||||
namespaces = [(uris.DCIM_BIOSEnumeration, BIOSEnumerableAttribute),
|
|
||||||
(uris.DCIM_BIOSString, BIOSStringAttribute),
|
|
||||||
(uris.DCIM_BIOSInteger, BIOSIntegerAttribute)]
|
|
||||||
for (namespace, attr_cls) in namespaces:
|
|
||||||
attribs = self._get_config(namespace, attr_cls, by_name)
|
|
||||||
if not set(result).isdisjoint(set(attribs)):
|
|
||||||
raise exceptions.DRACOperationFailed(
|
|
||||||
drac_messages=('Colliding attributes %r' % (
|
|
||||||
set(result) & set(attribs))))
|
|
||||||
result.update(attribs)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _get_config(self, resource, attr_cls, by_name):
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
doc = self.client.enumerate(resource)
|
|
||||||
items = doc.find('.//{%s}Items' % wsman.NS_WSMAN)
|
|
||||||
|
|
||||||
for item in items:
|
|
||||||
attribute = attr_cls.parse(item)
|
|
||||||
if by_name:
|
|
||||||
result[attribute.name] = attribute
|
|
||||||
else:
|
|
||||||
result[attribute.instance_id] = attribute
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def set_bios_settings(self, new_settings):
|
def set_bios_settings(self, new_settings):
|
||||||
"""Sets the BIOS configuration
|
"""Sets the BIOS configuration
|
||||||
|
@ -542,70 +519,11 @@ class BIOSConfiguration(object):
|
||||||
:raises: InvalidParameterValue on invalid BIOS attribute
|
:raises: InvalidParameterValue on invalid BIOS attribute
|
||||||
"""
|
"""
|
||||||
|
|
||||||
current_settings = self.list_bios_settings(by_name=True)
|
return utils.set_settings('BIOS',
|
||||||
# BIOS settings are returned as dict indexed by InstanceID.
|
self.client,
|
||||||
# However DCIM_BIOSService requires attribute name, not instance id
|
self.NAMESPACES,
|
||||||
# so recreate this as a dict indexed by attribute name
|
new_settings,
|
||||||
# TODO(anish) : Enable this code if/when by_name gets deprecated
|
uris.DCIM_BIOSService,
|
||||||
# bios_settings = self.list_bios_settings(by_name=False)
|
"DCIM_BIOSService",
|
||||||
# current_settings = dict((value.name, value)
|
"DCIM:BIOSService",
|
||||||
# for key, value in bios_settings.items())
|
'BIOS.Setup.1-1')
|
||||||
unknown_keys = set(new_settings) - set(current_settings)
|
|
||||||
if unknown_keys:
|
|
||||||
msg = ('Unknown BIOS attributes found: %(unknown_keys)r' %
|
|
||||||
{'unknown_keys': unknown_keys})
|
|
||||||
raise exceptions.InvalidParameterValue(reason=msg)
|
|
||||||
|
|
||||||
read_only_keys = []
|
|
||||||
unchanged_attribs = []
|
|
||||||
invalid_attribs_msgs = []
|
|
||||||
attrib_names = []
|
|
||||||
candidates = set(new_settings)
|
|
||||||
|
|
||||||
for attr in candidates:
|
|
||||||
if str(new_settings[attr]) == str(
|
|
||||||
current_settings[attr].current_value):
|
|
||||||
unchanged_attribs.append(attr)
|
|
||||||
elif current_settings[attr].read_only:
|
|
||||||
read_only_keys.append(attr)
|
|
||||||
else:
|
|
||||||
validation_msg = current_settings[attr].validate(
|
|
||||||
new_settings[attr])
|
|
||||||
if validation_msg is None:
|
|
||||||
attrib_names.append(attr)
|
|
||||||
else:
|
|
||||||
invalid_attribs_msgs.append(validation_msg)
|
|
||||||
|
|
||||||
if unchanged_attribs:
|
|
||||||
LOG.warning('Ignoring unchanged BIOS attributes: %r',
|
|
||||||
unchanged_attribs)
|
|
||||||
|
|
||||||
if invalid_attribs_msgs or read_only_keys:
|
|
||||||
if read_only_keys:
|
|
||||||
read_only_msg = ['Cannot set read-only BIOS attributes: %r.'
|
|
||||||
% read_only_keys]
|
|
||||||
else:
|
|
||||||
read_only_msg = []
|
|
||||||
|
|
||||||
drac_messages = '\n'.join(invalid_attribs_msgs + read_only_msg)
|
|
||||||
raise exceptions.DRACOperationFailed(
|
|
||||||
drac_messages=drac_messages)
|
|
||||||
|
|
||||||
if not attrib_names:
|
|
||||||
return utils.build_return_dict(
|
|
||||||
None, uris.DCIM_BIOSService, is_commit_required_value=False,
|
|
||||||
is_reboot_required_value=constants.RebootRequired.false,
|
|
||||||
commit_required_value=False)
|
|
||||||
|
|
||||||
selectors = {'CreationClassName': 'DCIM_BIOSService',
|
|
||||||
'Name': 'DCIM:BIOSService',
|
|
||||||
'SystemCreationClassName': 'DCIM_ComputerSystem',
|
|
||||||
'SystemName': 'DCIM:ComputerSystem'}
|
|
||||||
properties = {'Target': 'BIOS.Setup.1-1',
|
|
||||||
'AttributeName': attrib_names,
|
|
||||||
'AttributeValue': [new_settings[attr] for attr
|
|
||||||
in attrib_names]}
|
|
||||||
doc = self.client.invoke(uris.DCIM_BIOSService, 'SetAttributes',
|
|
||||||
selectors, properties)
|
|
||||||
|
|
||||||
return utils.build_return_dict(doc, uris.DCIM_BIOSService)
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
from dracclient.resources import uris
|
from dracclient.resources import uris
|
||||||
from dracclient import utils
|
from dracclient import utils
|
||||||
from dracclient import wsman
|
|
||||||
|
|
||||||
|
|
||||||
class iDRACCardConfiguration(object):
|
class iDRACCardConfiguration(object):
|
||||||
|
@ -37,27 +36,11 @@ class iDRACCardConfiguration(object):
|
||||||
:raises: DRACOperationFailed on error reported back by the DRAC
|
:raises: DRACOperationFailed on error reported back by the DRAC
|
||||||
interface
|
interface
|
||||||
"""
|
"""
|
||||||
result = {}
|
|
||||||
namespaces = [(uris.DCIM_iDRACCardEnumeration,
|
namespaces = [(uris.DCIM_iDRACCardEnumeration,
|
||||||
iDRACCardEnumerableAttribute),
|
iDRACCardEnumerableAttribute),
|
||||||
(uris.DCIM_iDRACCardString, iDRACCardStringAttribute),
|
(uris.DCIM_iDRACCardString, iDRACCardStringAttribute),
|
||||||
(uris.DCIM_iDRACCardInteger, iDRACCardIntegerAttribute)]
|
(uris.DCIM_iDRACCardInteger, iDRACCardIntegerAttribute)]
|
||||||
for (namespace, attr_cls) in namespaces:
|
return utils.list_settings(self.client, namespaces, by_name=False)
|
||||||
attribs = self._get_config(namespace, attr_cls)
|
|
||||||
result.update(attribs)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _get_config(self, resource, attr_cls):
|
|
||||||
result = {}
|
|
||||||
doc = self.client.enumerate(resource)
|
|
||||||
|
|
||||||
items = doc.find('.//{%s}Items' % wsman.NS_WSMAN)
|
|
||||||
|
|
||||||
if items:
|
|
||||||
for item in items:
|
|
||||||
attribute = attr_cls.parse(item)
|
|
||||||
result[attribute.instance_id] = attribute
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class iDRACCardAttribute(object):
|
class iDRACCardAttribute(object):
|
||||||
|
|
|
@ -16,7 +16,12 @@ Common functionalities shared between different DRAC modules.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from dracclient import constants
|
from dracclient import constants
|
||||||
|
import logging
|
||||||
|
|
||||||
from dracclient import exceptions
|
from dracclient import exceptions
|
||||||
|
from dracclient import wsman
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
NS_XMLSchema_Instance = 'http://www.w3.org/2001/XMLSchema-instance'
|
NS_XMLSchema_Instance = 'http://www.w3.org/2001/XMLSchema-instance'
|
||||||
|
|
||||||
|
@ -239,3 +244,158 @@ def validate_integer_value(value, attr_name, error_msgs):
|
||||||
int(value)
|
int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
error_msgs.append("'%s' is not an integer value" % attr_name)
|
error_msgs.append("'%s' is not an integer value" % attr_name)
|
||||||
|
|
||||||
|
|
||||||
|
def list_settings(client, namespaces, by_name=True):
|
||||||
|
"""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.
|
||||||
|
:returns: a dictionary with the settings using name or instance_id as
|
||||||
|
the key.
|
||||||
|
:raises: WSManRequestFailure on request failures
|
||||||
|
:raises: WSManInvalidResponse when receiving invalid response
|
||||||
|
:raises: DRACOperationFailed on error reported back by the DRAC
|
||||||
|
interface
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
for (namespace, attr_cls) in namespaces:
|
||||||
|
attribs = _get_config(client, namespace, attr_cls, by_name)
|
||||||
|
if not set(result).isdisjoint(set(attribs)):
|
||||||
|
raise exceptions.DRACOperationFailed(
|
||||||
|
drac_messages=('Colliding attributes %r' % (
|
||||||
|
set(result) & set(attribs))))
|
||||||
|
result.update(attribs)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _get_config(client, resource, attr_cls, by_name):
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
doc = client.enumerate(resource)
|
||||||
|
items = doc.find('.//{%s}Items' % wsman.NS_WSMAN)
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
attribute = attr_cls.parse(item)
|
||||||
|
if by_name:
|
||||||
|
result[attribute.name] = attribute
|
||||||
|
else:
|
||||||
|
result[attribute.instance_id] = attribute
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def set_settings(settings_type,
|
||||||
|
client,
|
||||||
|
namespaces,
|
||||||
|
new_settings,
|
||||||
|
resource_uri,
|
||||||
|
cim_creation_class_name,
|
||||||
|
cim_name,
|
||||||
|
target):
|
||||||
|
"""Generically handles setting various types of settings on the iDRAC
|
||||||
|
|
||||||
|
This method pulls the current list of settings from the iDRAC then compares
|
||||||
|
that list against the passed new settings to determine if there are any
|
||||||
|
errors. If no errors exist then the settings are sent to the iDRAC using
|
||||||
|
the passed resource, target, etc.
|
||||||
|
|
||||||
|
:param settings_type: a string indicating the settings type
|
||||||
|
:param client: an instance of WSManClient
|
||||||
|
:param namespaces: a list of URI/class pairs to retrieve.
|
||||||
|
:param new_settings: a dictionary containing the proposed values, with
|
||||||
|
each key being the name of attribute and the
|
||||||
|
value being the proposed value.
|
||||||
|
:param resource_uri: URI of resource to invoke
|
||||||
|
:param cim_creation_class_name: creation class name of the CIM object
|
||||||
|
:param cim_name: name of the CIM object
|
||||||
|
:param target: target device
|
||||||
|
: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. This key actually has a value that indicates if
|
||||||
|
a reboot is required. This key has been deprecated and
|
||||||
|
will be removed in a future release.
|
||||||
|
- 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 new settings with invalid values or
|
||||||
|
attempting to set read-only settings or when an error is reported
|
||||||
|
back by the iDRAC interface
|
||||||
|
:raises: DRACUnexpectedReturnValue on return value mismatch
|
||||||
|
:raises: InvalidParameterValue on invalid new setting
|
||||||
|
"""
|
||||||
|
|
||||||
|
current_settings = list_settings(client, namespaces, by_name=True)
|
||||||
|
|
||||||
|
unknown_keys = set(new_settings) - set(current_settings)
|
||||||
|
if unknown_keys:
|
||||||
|
msg = ('Unknown %(settings_type)s attributes found: %(unknown_keys)r' %
|
||||||
|
{'settings_type': settings_type, 'unknown_keys': unknown_keys})
|
||||||
|
raise exceptions.InvalidParameterValue(reason=msg)
|
||||||
|
|
||||||
|
read_only_keys = []
|
||||||
|
unchanged_attribs = []
|
||||||
|
invalid_attribs_msgs = []
|
||||||
|
attrib_names = []
|
||||||
|
candidates = set(new_settings)
|
||||||
|
|
||||||
|
for attr in candidates:
|
||||||
|
if str(new_settings[attr]) == str(
|
||||||
|
current_settings[attr].current_value):
|
||||||
|
unchanged_attribs.append(attr)
|
||||||
|
elif current_settings[attr].read_only:
|
||||||
|
read_only_keys.append(attr)
|
||||||
|
else:
|
||||||
|
validation_msg = current_settings[attr].validate(
|
||||||
|
new_settings[attr])
|
||||||
|
if not validation_msg:
|
||||||
|
attrib_names.append(attr)
|
||||||
|
else:
|
||||||
|
invalid_attribs_msgs.append(validation_msg)
|
||||||
|
|
||||||
|
if unchanged_attribs:
|
||||||
|
LOG.debug('Ignoring unchanged %(settings_type)s attributes: '
|
||||||
|
'%(unchanged_attribs)r' %
|
||||||
|
{'settings_type': settings_type,
|
||||||
|
'unchanged_attribs': unchanged_attribs})
|
||||||
|
|
||||||
|
if invalid_attribs_msgs or read_only_keys:
|
||||||
|
if read_only_keys:
|
||||||
|
read_only_msg = ['Cannot set read-only %(settings_type)s '
|
||||||
|
'attributes: %(read_only_keys)r.' %
|
||||||
|
{'settings_type': settings_type,
|
||||||
|
'read_only_keys': read_only_keys}]
|
||||||
|
else:
|
||||||
|
read_only_msg = []
|
||||||
|
|
||||||
|
drac_messages = '\n'.join(invalid_attribs_msgs + read_only_msg)
|
||||||
|
raise exceptions.DRACOperationFailed(
|
||||||
|
drac_messages=drac_messages)
|
||||||
|
|
||||||
|
if not attrib_names:
|
||||||
|
return build_return_dict(
|
||||||
|
None, resource_uri, is_commit_required_value=False,
|
||||||
|
is_reboot_required_value=constants.RebootRequired.false,
|
||||||
|
commit_required_value=False)
|
||||||
|
|
||||||
|
selectors = {'CreationClassName': cim_creation_class_name,
|
||||||
|
'Name': cim_name,
|
||||||
|
'SystemCreationClassName': 'DCIM_ComputerSystem',
|
||||||
|
'SystemName': 'DCIM:ComputerSystem'}
|
||||||
|
properties = {'Target': target,
|
||||||
|
'AttributeName': attrib_names,
|
||||||
|
'AttributeValue': [new_settings[attr] for attr
|
||||||
|
in attrib_names]}
|
||||||
|
doc = client.invoke(resource_uri, 'SetAttributes',
|
||||||
|
selectors, properties)
|
||||||
|
|
||||||
|
return build_return_dict(doc, resource_uri)
|
||||||
|
|
Loading…
Reference in New Issue