def _check_for_config_job(node): """Check if a configuration job is already created. :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :raises: DracPendingConfigJobExists if the job is already created. """ client = drac_client.get_wsman_client(node) try: doc = client.wsman_enumerate(resource_uris.DCIM_LifecycleJob) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to list the configuration jobs ' 'for node %(node_uuid)s. Reason: %(error)s.'), {'node_uuid': node.uuid, 'error': exc}) items = drac_common.find_xml(doc, 'DCIM_LifecycleJob', resource_uris.DCIM_LifecycleJob, find_all=True) for i in items: name = drac_common.find_xml(i, 'Name', resource_uris.DCIM_LifecycleJob) if TARGET_DEVICE not in name.text: continue job_status = drac_common.find_xml(i, 'JobStatus', resource_uris.DCIM_LifecycleJob).text # If job is already completed or failed we can # create another one. # Job Control Documentation: http://goo.gl/o1dDD3 (Section 7.2.3.2) if job_status.lower() not in ('completed', 'failed'): job_id = drac_common.find_xml(i, 'InstanceID', resource_uris.DCIM_LifecycleJob).text raise exception.DracPendingConfigJobExists(job_id=job_id, target=TARGET_DEVICE)
def _check_for_config_job(node): """Check if a configuration job is already created. :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :raises: DracPendingConfigJobExists if the job is already created. """ client = drac_client.get_wsman_client(node) try: doc = client.wsman_enumerate(resource_uris.DCIM_LifecycleJob) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE("DRAC driver failed to list the configuration jobs " "for node %(node_uuid)s. Reason: %(error)s."), {"node_uuid": node.uuid, "error": exc}, ) items = drac_common.find_xml(doc, "DCIM_LifecycleJob", resource_uris.DCIM_LifecycleJob, find_all=True) for i in items: name = drac_common.find_xml(i, "Name", resource_uris.DCIM_LifecycleJob) if TARGET_DEVICE not in name.text: continue job_status = drac_common.find_xml(i, "JobStatus", resource_uris.DCIM_LifecycleJob).text # If job is already completed or failed we can # create another one. # The 'Completed with Errors' JobStatus can be returned by # configuration jobs that set NIC or BIOS attributes. # Job Control Documentation: http://goo.gl/o1dDD3 (Section 7.2.3.2) if job_status.lower() not in ("completed", "completed with errors", "failed"): job_id = drac_common.find_xml(i, "InstanceID", resource_uris.DCIM_LifecycleJob).text raise exception.DracPendingConfigJobExists(job_id=job_id, target=TARGET_DEVICE)
def _create_config_job(node): """Create a configuration job. This method is used to apply the pending values created by set_boot_device(). :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :raises: DracConfigJobCreationError on an error when creating the job. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() options.add_selector('CreationClassName', 'DCIM_BIOSService') options.add_selector('Name', 'DCIM:BIOSService') options.add_selector('SystemCreationClassName', 'DCIM_ComputerSystem') options.add_selector('SystemName', 'DCIM:ComputerSystem') options.add_property('Target', 'BIOS.Setup.1-1') options.add_property('ScheduledStartTime', 'TIME_NOW') doc = client.wsman_invoke(resource_uris.DCIM_BIOSService, options, 'CreateTargetedConfigJob') return_value = drac_common.find_xml(doc, 'ReturnValue', resource_uris.DCIM_BIOSService).text # NOTE(lucasagomes): Possible return values are: RET_ERROR for error # or RET_CREATED job created (but changes will be # applied after the reboot) # Boot Management Documentation: http://goo.gl/aEsvUH (Section 8.4) if return_value == drac_common.RET_ERROR: error_message = drac_common.find_xml(doc, 'Message', resource_uris.DCIM_BIOSService).text raise exception.DracConfigJobCreationError(error=error_message)
def _create_config_job(node): """Create a configuration job. This method is used to apply the pending values created by set_boot_device(). :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :raises: DracConfigJobCreationError on an error when creating the job. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() options.add_selector('CreationClassName', 'DCIM_BIOSService') options.add_selector('Name', 'DCIM:BIOSService') options.add_selector('SystemCreationClassName', 'DCIM_ComputerSystem') options.add_selector('SystemName', 'DCIM:ComputerSystem') options.add_property('Target', 'BIOS.Setup.1-1') options.add_property('ScheduledStartTime', 'TIME_NOW') doc = client.wsman_invoke(resource_uris.DCIM_BIOSService, options, 'CreateTargetedConfigJob') return_value = drac_common.find_xml(doc, 'ReturnValue', resource_uris.DCIM_BIOSService).text # NOTE(lucasagomes): Possible return values are: RET_ERROR for error # or RET_CREATED job created (but changes will be # applied after the reboot) # Boot Management Documentation: http://goo.gl/aEsvUH (Section 8.4) if return_value == drac_common.RET_ERROR: error_message = drac_common.find_xml( doc, 'Message', resource_uris.DCIM_BIOSService).text raise exception.DracConfigJobCreationError(error=error_message)
def _get_boot_list_for_boot_device(node, device, controller_version): """Get the boot list for a given boot device. The DCIM_BootConfigSetting resource represents each boot list (eg. IPL/BIOS, BCV, UEFI, vFlash Partition, One Time Boot). The DCIM_BootSourceSetting resource represents each of the boot list boot devices or sources that are shown under their corresponding boot list. :param node: ironic node object. :param device: boot device. :param controller_version: version of the Lifecycle controller. :raises: DracClientError on an error from pywsman library. :returns: dictionary containing: :boot_list: boot list. :boot_device_id: boot device id. """ client = drac_client.get_wsman_client(node) if controller_version < '2.0.0': filter_query = None else: filter_query = ("select * from DCIM_BootSourceSetting where " "InstanceID like '%%#%s%%'" % _BOOT_DEVICES_MAP[device]) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to set the boot device ' 'for node %(node_uuid)s. Can\'t find the ID ' 'for the %(device)s type. Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc, 'device': device }) if controller_version < '2.0.0': boot_devices = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting, find_all=True) for boot_device in boot_devices: if _BOOT_DEVICES_MAP[device] in boot_device.text: boot_device_id = boot_device.text boot_list = boot_device_id.split(':')[0] break else: boot_device_id = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text boot_list = drac_common.find_xml( doc, 'BootSourceType', resource_uris.DCIM_BootSourceSetting).text return {'boot_list': boot_list, 'boot_device_id': boot_device_id}
def _get_boot_list_for_boot_device(node, device, controller_version): """Get the boot list for a given boot device. The DCIM_BootConfigSetting resource represents each boot list (eg. IPL/BIOS, BCV, UEFI, vFlash Partition, One Time Boot). The DCIM_BootSourceSetting resource represents each of the boot list boot devices or sources that are shown under their corresponding boot list. :param node: ironic node object. :param device: boot device. :param controller_version: version of the Lifecycle controller. :raises: DracClientError on an error from pywsman library. :returns: dictionary containing: :boot_list: boot list. :boot_device_id: boot device id. """ client = drac_client.get_wsman_client(node) if controller_version < '2.0.0': filter_query = None else: filter_query = ("select * from DCIM_BootSourceSetting where " "InstanceID like '%%#%s%%'" % _BOOT_DEVICES_MAP[device]) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to set the boot device ' 'for node %(node_uuid)s. Can\'t find the ID ' 'for the %(device)s type. Reason: %(error)s.'), {'node_uuid': node.uuid, 'error': exc, 'device': device}) if controller_version < '2.0.0': boot_devices = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting, find_all=True) for boot_device in boot_devices: if _BOOT_DEVICES_MAP[device] in boot_device.text: boot_device_id = boot_device.text boot_list = boot_device_id.split(':')[0] break else: boot_device_id = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text boot_list = drac_common.find_xml( doc, 'BootSourceType', resource_uris.DCIM_BootSourceSetting).text return {'boot_list': boot_list, 'boot_device_id': boot_device_id}
def _get_next_boot_mode(node): """Get the next boot mode. To see a list of supported boot modes see: http://goo.gl/aEsvUH (Section 7.2) :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :returns: a dictionary containing: :instance_id: the instance id of the boot device. :is_next: whether it's the next device to boot or not. One of PERSISTENT, NOT_NEXT, ONE_TIME_BOOT constants. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() filter_query = ('select * from DCIM_BootConfigSetting where IsNext=%s ' 'or IsNext=%s' % (PERSISTENT, ONE_TIME_BOOT)) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootConfigSetting, options, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to get next boot mode for ' 'node %(node_uuid)s. Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc }) items = drac_common.find_xml(doc, 'DCIM_BootConfigSetting', resource_uris.DCIM_BootConfigSetting, find_all=True) # This list will have 2 items maximum, one for the persistent element # and another one for the OneTime if set boot_mode = None for i in items: instance_id = drac_common.find_xml( i, 'InstanceID', resource_uris.DCIM_BootConfigSetting).text is_next = drac_common.find_xml( i, 'IsNext', resource_uris.DCIM_BootConfigSetting).text boot_mode = {'instance_id': instance_id, 'is_next': is_next} # If OneTime is set we should return it, because that's # where the next boot device is if is_next == ONE_TIME_BOOT: break return boot_mode
def _get_next_boot_list(node): """Get the next boot list. The DCIM_BootConfigSetting resource represents each boot list (eg. IPL/BIOS, BCV, UEFI, vFlash Partition, One Time Boot). The DCIM_BootSourceSetting resource represents each of the boot list boot devices or sources that are shown under their corresponding boot list. :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :returns: a dictionary containing: :instance_id: the instance id of the boot list. :is_next: whether it's the next device to boot or not. One of PERSISTENT, ONE_TIME_BOOT constants. """ client = drac_client.get_wsman_client(node) filter_query = ('select * from DCIM_BootConfigSetting where IsNext=%s ' 'or IsNext=%s' % (PERSISTENT, ONE_TIME_BOOT)) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootConfigSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to get next boot mode for ' 'node %(node_uuid)s. Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc }) items = drac_common.find_xml(doc, 'DCIM_BootConfigSetting', resource_uris.DCIM_BootConfigSetting, find_all=True) # This list will have 2 items maximum, one for the persistent element # and another one for the OneTime if set boot_list = None for i in items: boot_list_id = drac_common.find_xml( i, 'InstanceID', resource_uris.DCIM_BootConfigSetting).text is_next = drac_common.find_xml( i, 'IsNext', resource_uris.DCIM_BootConfigSetting).text boot_list = {'instance_id': boot_list_id, 'is_next': is_next} # If OneTime is set we should return it, because that's # where the next boot device is if is_next == ONE_TIME_BOOT: break return boot_list
def _get_boot_device_for_boot_list(node, boot_list_id, controller_version): """Get the next boot device for a given boot list. The DCIM_BootConfigSetting resource represents each boot list (eg. IPL/BIOS, BCV, UEFI, vFlash Partition, One Time Boot). The DCIM_BootSourceSetting resource represents each of the boot list boot devices or sources that are shown under their corresponding boot list. :param node: ironic node object. :param boot_list_id: boot list id. :param controller_version: version of the Lifecycle controller. :raises: DracClientError on an error from pywsman library. :returns: boot device id. """ client = drac_client.get_wsman_client(node) if controller_version < '2.0.0': filter_query = ('select * from DCIM_BootSourceSetting where ' 'PendingAssignedSequence=0') else: filter_query = ('select * from DCIM_BootSourceSetting where ' 'PendingAssignedSequence=0 and ' 'BootSourceType="%s"' % boot_list_id) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to get the current boot ' 'device for node %(node_uuid)s. ' 'Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc }) if controller_version < '2.0.0': boot_devices = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting, find_all=True) for device in boot_devices: if device.text.startswith(boot_list_id): boot_device_id = device.text break else: boot_device_id = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text return boot_device_id
def _get_next_boot_mode(node): """Get the next boot mode. To see a list of supported boot modes see: http://goo.gl/aEsvUH (Section 7.2) :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :returns: a dictionary containing: :instance_id: the instance id of the boot device. :is_next: whether it's the next device to boot or not. One of PERSISTENT, NOT_NEXT, ONE_TIME_BOOT constants. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() filter_query = ('select * from DCIM_BootConfigSetting where IsNext=%s ' 'or IsNext=%s' % (PERSISTENT, ONE_TIME_BOOT)) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootConfigSetting, options, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to get next boot mode for ' 'node %(node_uuid)s. Reason: %(error)s.'), {'node_uuid': node.uuid, 'error': exc}) items = drac_common.find_xml(doc, 'DCIM_BootConfigSetting', resource_uris.DCIM_BootConfigSetting, find_all=True) # This list will have 2 items maximum, one for the persistent element # and another one for the OneTime if set boot_mode = None for i in items: instance_id = drac_common.find_xml(i, 'InstanceID', resource_uris.DCIM_BootConfigSetting).text is_next = drac_common.find_xml(i, 'IsNext', resource_uris.DCIM_BootConfigSetting).text boot_mode = {'instance_id': instance_id, 'is_next': is_next} # If OneTime is set we should return it, because that's # where the next boot device is if is_next == ONE_TIME_BOOT: break return boot_mode
def _get_next_boot_list(node): """Get the next boot list. The DCIM_BootConfigSetting resource represents each boot list (eg. IPL/BIOS, BCV, UEFI, vFlash Partition, One Time Boot). The DCIM_BootSourceSetting resource represents each of the boot list boot devices or sources that are shown under their corresponding boot list. :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :returns: a dictionary containing: :instance_id: the instance id of the boot list. :is_next: whether it's the next device to boot or not. One of PERSISTENT, ONE_TIME_BOOT constants. """ client = drac_client.get_wsman_client(node) filter_query = ('select * from DCIM_BootConfigSetting where IsNext=%s ' 'or IsNext=%s' % (PERSISTENT, ONE_TIME_BOOT)) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootConfigSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to get next boot mode for ' 'node %(node_uuid)s. Reason: %(error)s.'), {'node_uuid': node.uuid, 'error': exc}) items = drac_common.find_xml(doc, 'DCIM_BootConfigSetting', resource_uris.DCIM_BootConfigSetting, find_all=True) # This list will have 2 items maximum, one for the persistent element # and another one for the OneTime if set boot_list = None for i in items: boot_list_id = drac_common.find_xml( i, 'InstanceID', resource_uris.DCIM_BootConfigSetting).text is_next = drac_common.find_xml( i, 'IsNext', resource_uris.DCIM_BootConfigSetting).text boot_list = {'instance_id': boot_list_id, 'is_next': is_next} # If OneTime is set we should return it, because that's # where the next boot device is if is_next == ONE_TIME_BOOT: break return boot_list
def _get_power_state(node): """Returns the current power state of the node :param node: The node. :returns: power state, one of :mod: `ironic.common.states`. :raises: DracClientError if the client received unexpected response. :raises: InvalidParameterValue if required DRAC credentials are missing. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() filter_query = ('select EnabledState,ElementName from CIM_ComputerSystem ' 'where Name="srv:system"') try: doc = client.wsman_enumerate(resource_uris.DCIM_ComputerSystem, options, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to get power state for node ' '%(node_uuid)s. Reason: %(error)s.'), {'node_uuid': node.uuid, 'error': exc}) enabled_state = drac_common.find_xml(doc, 'EnabledState', resource_uris.DCIM_ComputerSystem) return POWER_STATES[enabled_state.text]
def _get_lifecycle_controller_version(node): """Returns the Lifecycle controller version of the DRAC card of the node :param node: the node. :returns: the Lifecycle controller version. :raises: DracClientError if the client received unexpected response. :raises: InvalidParameterValue if required DRAC credentials are missing. """ client = drac_client.get_wsman_client(node) filter_query = ('select LifecycleControllerVersion from DCIM_SystemView') try: doc = client.wsman_enumerate(resource_uris.DCIM_SystemView, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to get power state for node ' '%(node_uuid)s. Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc }) version = drac_common.find_xml(doc, 'LifecycleControllerVersion', resource_uris.DCIM_SystemView).text return version
def _get_power_state(node): """Returns the current power state of the node :param node: The node. :returns: power state, one of :mod: `ironic.common.states`. :raises: DracClientError if the client received unexpected response. :raises: InvalidParameterValue if required DRAC credentials are missing. """ client = drac_client.get_wsman_client(node) filter_query = ('select EnabledState,ElementName from DCIM_ComputerSystem ' 'where Name="srv:system"') try: doc = client.wsman_enumerate(resource_uris.DCIM_ComputerSystem, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to get power state for node ' '%(node_uuid)s. Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc }) enabled_state = drac_common.find_xml(doc, 'EnabledState', resource_uris.DCIM_ComputerSystem) return POWER_STATES[enabled_state.text]
def _get_boot_device_for_boot_list(node, boot_list_id, controller_version): """Get the next boot device for a given boot list. The DCIM_BootConfigSetting resource represents each boot list (eg. IPL/BIOS, BCV, UEFI, vFlash Partition, One Time Boot). The DCIM_BootSourceSetting resource represents each of the boot list boot devices or sources that are shown under their corresponding boot list. :param node: ironic node object. :param boot_list_id: boot list id. :param controller_version: version of the Lifecycle controller. :raises: DracClientError on an error from pywsman library. :returns: boot device id. """ client = drac_client.get_wsman_client(node) if controller_version < '2.0.0': filter_query = ('select * from DCIM_BootSourceSetting where ' 'PendingAssignedSequence=0') else: filter_query = ('select * from DCIM_BootSourceSetting where ' 'PendingAssignedSequence=0 and ' 'BootSourceType="%s"' % boot_list_id) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to get the current boot ' 'device for node %(node_uuid)s. ' 'Reason: %(error)s.'), {'node_uuid': node.uuid, 'error': exc}) if controller_version < '2.0.0': boot_devices = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting, find_all=True) for device in boot_devices: if device.text.startswith(boot_list_id): boot_device_id = device.text break else: boot_device_id = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text return boot_device_id
def _set_power_state(node, target_state): """Turns the server power on/off or do a reboot. :param node: an ironic node object. :param target_state: target state of the node. :raises: DracClientError if the client received unexpected response. :raises: InvalidParameterValue if an invalid power state was specified. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() options.add_selector('CreationClassName', 'DCIM_ComputerSystem') options.add_selector('Name', 'srv:system') options.add_property('RequestedState', REVERSE_POWER_STATES[target_state]) try: root = client.wsman_invoke(resource_uris.DCIM_ComputerSystem, options, 'RequestStateChange') except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to set power state for node ' '%(node_uuid)s to %(target_power_state)s. ' 'Reason: %(error)s.'), { 'node_uuid': node.uuid, 'target_power_state': target_state, 'error': exc }) return_value = drac_common.find_xml(root, 'ReturnValue', resource_uris.DCIM_ComputerSystem).text if return_value != drac_common.RET_SUCCESS: message = drac_common.find_xml(root, 'Message', resource_uris.DCIM_ComputerSystem).text LOG.error( _LE('DRAC driver failed to set power state for node ' '%(node_uuid)s to %(target_power_state)s. ' 'Reason: %(error)s.'), { 'node_uuid': node.uuid, 'target_power_state': target_state, 'error': message }) raise exception.DracOperationError(operation='set_power_state', error=message)
def _check_for_config_job(node): """Check if a configuration job is already created. :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :raises: DracConfigJobCreationError if the job is already created. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() try: doc = client.wsman_enumerate(resource_uris.DCIM_LifecycleJob, options) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to list the configuration jobs ' 'for node %(node_uuid)s. Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc }) items = drac_common.find_xml(doc, 'DCIM_LifecycleJob', resource_uris.DCIM_LifecycleJob, find_all=True) for i in items: name = drac_common.find_xml(i, 'Name', resource_uris.DCIM_LifecycleJob) if 'BIOS.Setup.1-1' not in name.text: continue job_status = drac_common.find_xml(i, 'JobStatus', resource_uris.DCIM_LifecycleJob).text # If job is already completed or failed we can # create another one. # Job Control Documentation: http://goo.gl/o1dDD3 (Section 7.2.3.2) if job_status.lower() not in ('completed', 'failed'): job_id = drac_common.find_xml(i, 'InstanceID', resource_uris.DCIM_LifecycleJob).text reason = (_('Another job with ID "%s" is already created ' 'to configure the BIOS. Wait until existing job ' 'is completed or is cancelled') % job_id) raise exception.DracConfigJobCreationError(error=reason)
def _check_for_config_job(node): """Check if a configuration job is already created. :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :raises: DracPendingConfigJobExists if the job is already created. """ client = drac_client.get_wsman_client(node) try: doc = client.wsman_enumerate(resource_uris.DCIM_LifecycleJob) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to list the configuration jobs ' 'for node %(node_uuid)s. Reason: %(error)s.'), { 'node_uuid': node.uuid, 'error': exc }) items = drac_common.find_xml(doc, 'DCIM_LifecycleJob', resource_uris.DCIM_LifecycleJob, find_all=True) for i in items: name = drac_common.find_xml(i, 'Name', resource_uris.DCIM_LifecycleJob) if TARGET_DEVICE not in name.text: continue job_status = drac_common.find_xml(i, 'JobStatus', resource_uris.DCIM_LifecycleJob).text # If job is already completed or failed we can # create another one. # The 'Completed with Errors' JobStatus can be returned by # configuration jobs that set NIC or BIOS attributes. # Job Control Documentation: http://goo.gl/o1dDD3 (Section 7.2.3.2) if job_status.lower() not in ('completed', 'completed with errors', 'failed'): job_id = drac_common.find_xml(i, 'InstanceID', resource_uris.DCIM_LifecycleJob).text raise exception.DracPendingConfigJobExists(job_id=job_id, target=TARGET_DEVICE)
def test_find_xml(self): namespace = 'http://fake' value = 'fake_value' test_doc = ElementTree.fromstring("""<Envelope xmlns:ns1="%(ns)s"> <Body> <ns1:test_element>%(value)s</ns1:test_element> </Body> </Envelope>""" % {'ns': namespace, 'value': value}) result = drac_common.find_xml(test_doc, 'test_element', namespace) self.assertEqual(value, result.text)
def _set_power_state(node, target_state): """Turns the server power on/off or do a reboot. :param node: an ironic node object. :param target_state: target state of the node. :raises: DracClientError if the client received unexpected response. :raises: InvalidParameterValue if an invalid power state was specified. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() options.add_selector('CreationClassName', 'DCIM_ComputerSystem') options.add_selector('Name', 'srv:system') options.add_property('RequestedState', REVERSE_POWER_STATES[target_state]) try: root = client.wsman_invoke(resource_uris.DCIM_ComputerSystem, options, 'RequestStateChange') except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to set power state for node ' '%(node_uuid)s to %(target_power_state)s. ' 'Reason: %(error)s.'), {'node_uuid': node.uuid, 'target_power_state': target_state, 'error': exc}) return_value = drac_common.find_xml(root, 'ReturnValue', resource_uris.DCIM_ComputerSystem).text if return_value != drac_common.RET_SUCCESS: message = drac_common.find_xml(root, 'Message', resource_uris.DCIM_ComputerSystem).text LOG.error(_LE('DRAC driver failed to set power state for node ' '%(node_uuid)s to %(target_power_state)s. ' 'Reason: %(error)s.'), {'node_uuid': node.uuid, 'target_power_state': target_state, 'error': message}) raise exception.DracOperationError(operation='set_power_state', error=message)
def _check_for_config_job(node): """Check if a configuration job is already created. :param node: an ironic node object. :raises: DracClientError on an error from pywsman library. :raises: DracConfigJobCreationError if the job is already created. """ client = drac_common.get_wsman_client(node) options = pywsman.ClientOptions() try: doc = client.wsman_enumerate(resource_uris.DCIM_LifecycleJob, options) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to list the configuration jobs ' 'for node %(node_uuid)s. Reason: %(error)s.'), {'node_uuid': node.uuid, 'error': exc}) items = drac_common.find_xml(doc, 'DCIM_LifecycleJob', resource_uris.DCIM_LifecycleJob, find_all=True) for i in items: name = drac_common.find_xml(i, 'Name', resource_uris.DCIM_LifecycleJob) if 'BIOS.Setup.1-1' not in name.text: continue job_status = drac_common.find_xml(i, 'JobStatus', resource_uris.DCIM_LifecycleJob).text # If job is already completed or failed we can # create another one. # Job Control Documentation: http://goo.gl/o1dDD3 (Section 7.2.3.2) if job_status.lower() not in ('completed', 'failed'): job_id = drac_common.find_xml(i, 'InstanceID', resource_uris.DCIM_LifecycleJob).text reason = (_('Another job with ID "%s" is already created ' 'to configure the BIOS. Wait until existing job ' 'is completed or is cancelled') % job_id) raise exception.DracConfigJobCreationError(error=reason)
def test_find_xml(self): namespace = 'http://fake' value = 'fake_value' test_doc = ElementTree.fromstring("""<Envelope xmlns:ns1="%(ns)s"> <Body> <ns1:test_element>%(value)s</ns1:test_element> </Body> </Envelope>""" % { 'ns': namespace, 'value': value }) result = drac_common.find_xml(test_doc, 'test_element', namespace) self.assertEqual(value, result.text)
def get_boot_device(self, task): """Get the current boot device for a node. Returns the current boot device of the node. :param task: a task from TaskManager. :raises: DracClientError on an error from pywsman library. :returns: a dictionary containing: :boot_device: the boot device, one of :mod:`ironic.common.boot_devices` or None if it is unknown. :persistent: Whether the boot device will persist to all future boots or not, None if it is unknown. """ client = drac_common.get_wsman_client(task.node) boot_mode = _get_next_boot_mode(task.node) persistent = boot_mode['is_next'] == PERSISTENT instance_id = boot_mode['instance_id'] options = pywsman.ClientOptions() filter_query = ('select * from DCIM_BootSourceSetting where ' 'PendingAssignedSequence=0 and ' 'BootSourceType="%s"' % instance_id) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, options, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to get the current boot ' 'device for node %(node_uuid)s. ' 'Reason: %(error)s.'), { 'node_uuid': task.node.uuid, 'error': exc }) instance_id = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text boot_device = next((key for (key, value) in _BOOT_DEVICES_MAP.items() if value in instance_id), None) return {'boot_device': boot_device, 'persistent': persistent}
def test_find_xml_find_all(self): namespace = 'http://fake' value1 = 'fake_value1' value2 = 'fake_value2' test_doc = ElementTree.fromstring("""<Envelope xmlns:ns1="%(ns)s"> <Body> <ns1:test_element>%(value1)s</ns1:test_element> <ns1:cat>meow</ns1:cat> <ns1:test_element>%(value2)s</ns1:test_element> <ns1:dog>bark</ns1:dog> </Body> </Envelope>""" % {'ns': namespace, 'value1': value1, 'value2': value2}) result = drac_common.find_xml(test_doc, 'test_element', namespace, find_all=True) self.assertThat(result, HasLength(2)) result_text = [v.text for v in result] self.assertEqual(sorted([value1, value2]), sorted(result_text))
def _get_lifecycle_controller_version(node): """Returns the Lifecycle controller version of the DRAC card of the node :param node: the node. :returns: the Lifecycle controller version. :raises: DracClientError if the client received unexpected response. :raises: InvalidParameterValue if required DRAC credentials are missing. """ client = drac_client.get_wsman_client(node) filter_query = "select LifecycleControllerVersion from DCIM_SystemView" try: doc = client.wsman_enumerate(resource_uris.DCIM_SystemView, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE("DRAC driver failed to get power state for node " "%(node_uuid)s. Reason: %(error)s."), {"node_uuid": node.uuid, "error": exc}, ) version = drac_common.find_xml(doc, "LifecycleControllerVersion", resource_uris.DCIM_SystemView).text return version
def get_boot_device(self, task): """Get the current boot device for a node. Returns the current boot device of the node. :param task: a task from TaskManager. :raises: DracClientError on an error from pywsman library. :returns: a dictionary containing: :boot_device: the boot device, one of :mod:`ironic.common.boot_devices` or None if it is unknown. :persistent: Whether the boot device will persist to all future boots or not, None if it is unknown. """ client = drac_common.get_wsman_client(task.node) boot_mode = _get_next_boot_mode(task.node) persistent = boot_mode['is_next'] == PERSISTENT instance_id = boot_mode['instance_id'] options = pywsman.ClientOptions() filter_query = ('select * from DCIM_BootSourceSetting where ' 'PendingAssignedSequence=0 and ' 'BootSourceType="%s"' % instance_id) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, options, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to get the current boot ' 'device for node %(node_uuid)s. ' 'Reason: %(error)s.'), {'node_uuid': task.node.uuid, 'error': exc}) instance_id = drac_common.find_xml(doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text boot_device = next((key for (key, value) in _BOOT_DEVICES_MAP.items() if value in instance_id), None) return {'boot_device': boot_device, 'persistent': persistent}
def test_find_xml_find_all(self): namespace = 'http://fake' value1 = 'fake_value1' value2 = 'fake_value2' test_doc = ElementTree.fromstring("""<Envelope xmlns:ns1="%(ns)s"> <Body> <ns1:test_element>%(value1)s</ns1:test_element> <ns1:cat>meow</ns1:cat> <ns1:test_element>%(value2)s</ns1:test_element> <ns1:dog>bark</ns1:dog> </Body> </Envelope>""" % { 'ns': namespace, 'value1': value1, 'value2': value2 }) result = drac_common.find_xml(test_doc, 'test_element', namespace, find_all=True) self.assertThat(result, HasLength(2)) result_text = [v.text for v in result] self.assertEqual(sorted([value1, value2]), sorted(result_text))
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. Set the boot device to use on next reboot of the node. :param task: a task from TaskManager. :param device: the boot device, one of :mod:`ironic.common.boot_devices`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: DracClientError if the client received unexpected response. :raises: DracOperationFailed if the client received response with an error message. :raises: DracUnexpectedReturnValue if the client received a response with unexpected return value. :raises: InvalidParameterValue if an invalid boot device is specified. :raises: DracPendingConfigJobExists on an error when creating the job. """ # Check for an existing configuration job _check_for_config_job(task.node) client = drac_client.get_wsman_client(task.node) filter_query = ("select * from DCIM_BootSourceSetting where " "InstanceID like '%%#%s%%'" % _BOOT_DEVICES_MAP[device]) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to set the boot device ' 'for node %(node_uuid)s. Can\'t find the ID ' 'for the %(device)s type. Reason: %(error)s.'), {'node_uuid': task.node.uuid, 'error': exc, 'device': device}) instance_id = drac_common.find_xml(doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text source = 'OneTime' if persistent: source = drac_common.find_xml(doc, 'BootSourceType', resource_uris.DCIM_BootSourceSetting).text # NOTE(lucasagomes): Don't ask me why 'BootSourceType' is set # for 'InstanceID' and 'InstanceID' is set for 'source'! You # know enterprisey... selectors = {'InstanceID': source} properties = {'source': instance_id} try: client.wsman_invoke(resource_uris.DCIM_BootConfigSetting, 'ChangeBootOrderByInstanceID', selectors, properties) except exception.DracRequestFailed as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to set the boot device for ' 'node %(node_uuid)s to %(target_boot_device)s. ' 'Reason: %(error)s.'), {'node_uuid': task.node.uuid, 'target_boot_device': device, 'error': exc}) # Create a configuration job _create_config_job(task.node)
def wsman_invoke(self, resource_uri, method, selectors=None, properties=None, expected_return=None): """Invokes a remote WS-Man method. :param resource_uri: URI of the resource. :param method: name of the method to invoke. :param selectors: dictionary of selectors. :param properties: dictionary of properties. :param expected_return: expected return value. :raises: DracClientError on an error from pywsman library. :raises: DracOperationFailed on error reported back by DRAC. :raises: DracUnexpectedReturnValue on return value mismatch. :returns: an ElementTree object of the response received. """ if selectors is None: selectors = {} if properties is None: properties = {} options = pywsman.ClientOptions() for name, value in selectors.items(): options.add_selector(name, value) # NOTE(ifarkas): manually constructing the XML doc should be deleted # once pywsman supports passing a list as a property. # For now this is only a fallback method: in case no # list provided, the supported pywsman API will be used. list_included = any( [isinstance(prop_item, list) for prop_item in properties.values()]) if list_included: xml_doc = pywsman.XmlDoc('%s_INPUT' % method, resource_uri) xml_root = xml_doc.root() for name, value in properties.items(): if isinstance(value, list): for item in value: xml_root.add(resource_uri, str(name), str(item)) else: xml_root.add(resource_uri, name, value) LOG.debug( ('WSMAN invoking: %(resource_uri)s:%(method)s' '\nselectors: %(selectors)r\nxml: %(xml)s'), { 'resource_uri': resource_uri, 'method': method, 'selectors': selectors, 'xml': xml_root.string() }) else: xml_doc = None for name, value in properties.items(): options.add_property(name, value) LOG.debug( ('WSMAN invoking: %(resource_uri)s:%(method)s' '\nselectors: %(selectors)r\properties: %(props)r') % { 'resource_uri': resource_uri, 'method': method, 'selectors': selectors, 'props': properties }) doc = retry_on_empty_response(self.client, 'invoke', options, resource_uri, method, xml_doc) root = self._get_root(doc) LOG.debug("WSMAN invoke returned raw XML: %s", ElementTree.tostring(root)) return_value = drac_common.find_xml(root, 'ReturnValue', resource_uri).text if return_value == RET_ERROR: messages = drac_common.find_xml(root, 'Message', resource_uri, True) message_args = drac_common.find_xml(root, 'MessageArguments', resource_uri, True) if message_args: messages = [ m.text % p.text for (m, p) in zip(messages, message_args) ] else: messages = [m.text for m in messages] raise exception.DracOperationFailed(message='%r' % messages) if expected_return and return_value != expected_return: raise exception.DracUnexpectedReturnValue( expected_return_value=expected_return, actual_return_value=return_value) return root
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. Set the boot device to use on next reboot of the node. :param task: a task from TaskManager. :param device: the boot device, one of :mod:`ironic.common.boot_devices`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: DracClientError on an error from pywsman library. :raises: InvalidParameterValue if an invalid boot device is specified. :raises: DracConfigJobCreationError on an error when creating the job. """ # Check for an existing configuration job _check_for_config_job(task.node) client = drac_common.get_wsman_client(task.node) options = pywsman.ClientOptions() filter_query = ("select * from DCIM_BootSourceSetting where " "InstanceID like '%%#%s%%'" % _BOOT_DEVICES_MAP[device]) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, options, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to set the boot device ' 'for node %(node_uuid)s. Can\'t find the ID ' 'for the %(device)s type. Reason: %(error)s.'), { 'node_uuid': task.node.uuid, 'error': exc, 'device': device }) instance_id = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text source = 'OneTime' if persistent: source = drac_common.find_xml( doc, 'BootSourceType', resource_uris.DCIM_BootSourceSetting).text # NOTE(lucasagomes): Don't ask me why 'BootSourceType' is set # for 'InstanceID' and 'InstanceID' is set for 'source'! You # know enterprisey... options = pywsman.ClientOptions() options.add_selector('InstanceID', source) options.add_property('source', instance_id) doc = client.wsman_invoke(resource_uris.DCIM_BootConfigSetting, options, 'ChangeBootOrderByInstanceID') return_value = drac_common.find_xml( doc, 'ReturnValue', resource_uris.DCIM_BootConfigSetting).text # NOTE(lucasagomes): Possible return values are: RET_ERROR for error, # RET_SUCCESS for success or RET_CREATED job # created (but changes will be applied after # the reboot) # Boot Management Documentation: http://goo.gl/aEsvUH (Section 8.7) if return_value == drac_common.RET_ERROR: error_message = drac_common.find_xml( doc, 'Message', resource_uris.DCIM_BootConfigSetting).text raise exception.DracOperationError(operation='set_boot_device', error=error_message) # Create a configuration job _create_config_job(task.node)
def wsman_invoke(self, resource_uri, method, selectors=None, properties=None, expected_return_value=RET_SUCCESS): """Invokes a remote WS-Man method. :param resource_uri: URI of the resource. :param method: name of the method to invoke. :param selectors: dictionary of selectors. :param properties: dictionary of properties. :param expected_return_value: expected return value. :raises: DracClientError on an error from pywsman library. :raises: DracOperationFailed on error reported back by DRAC. :raises: DracUnexpectedReturnValue on return value mismatch. :returns: an ElementTree object of the response received. """ if selectors is None: selectors = {} if properties is None: properties = {} options = pywsman.ClientOptions() for name, value in selectors.items(): options.add_selector(name, value) # NOTE(ifarkas): manually constructing the XML doc should be deleted # once pywsman supports passing a list as a property. # For now this is only a fallback method: in case no # list provided, the supported pywsman API will be used. list_included = any([isinstance(prop_item, list) for prop_item in properties.values()]) if list_included: xml_doc = pywsman.XmlDoc('%s_INPUT' % method, resource_uri) xml_root = xml_doc.root() for name, value in properties.items(): if isinstance(value, list): for item in value: xml_root.add(resource_uri, name, item) else: xml_root.add(resource_uri, name, value) else: xml_doc = None for name, value in properties.items(): options.add_property(name, value) doc = self.client.invoke(options, resource_uri, method, xml_doc) root = self._get_root(doc) return_value = drac_common.find_xml(root, 'ReturnValue', resource_uri).text if return_value != expected_return_value: if return_value == RET_ERROR: message = drac_common.find_xml(root, 'Message', resource_uri).text raise exception.DracOperationFailed(message=message) else: raise exception.DracUnexpectedReturnValue( expected_return_value=expected_return_value, actual_return_value=return_value) return root
def wsman_invoke(self, resource_uri, method, selectors=None, properties=None, expected_return_value=RET_SUCCESS): """Invokes a remote WS-Man method. :param resource_uri: URI of the resource. :param method: name of the method to invoke. :param selectors: dictionary of selectors. :param properties: dictionary of properties. :param expected_return_value: expected return value. :raises: DracClientError on an error from pywsman library. :raises: DracOperationFailed on error reported back by DRAC. :raises: DracUnexpectedReturnValue on return value mismatch. :returns: an ElementTree object of the response received. """ if selectors is None: selectors = {} if properties is None: properties = {} options = pywsman.ClientOptions() for name, value in selectors.items(): options.add_selector(name, value) # NOTE(ifarkas): manually constructing the XML doc should be deleted # once pywsman supports passing a list as a property. # For now this is only a fallback method: in case no # list provided, the supported pywsman API will be used. list_included = any( [isinstance(prop_item, list) for prop_item in properties.values()]) if list_included: xml_doc = pywsman.XmlDoc('%s_INPUT' % method, resource_uri) xml_root = xml_doc.root() for name, value in properties.items(): if isinstance(value, list): for item in value: xml_root.add(resource_uri, name, item) else: xml_root.add(resource_uri, name, value) else: xml_doc = None for name, value in properties.items(): options.add_property(name, value) doc = retry_on_empty_response(self.client, 'invoke', options, resource_uri, method, xml_doc) root = self._get_root(doc) return_value = drac_common.find_xml(root, 'ReturnValue', resource_uri).text if return_value != expected_return_value: if return_value == RET_ERROR: message = drac_common.find_xml(root, 'Message', resource_uri).text raise exception.DracOperationFailed(message=message) else: raise exception.DracUnexpectedReturnValue( expected_return_value=expected_return_value, actual_return_value=return_value) return root
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. Set the boot device to use on next reboot of the node. :param task: a task from TaskManager. :param device: the boot device, one of :mod:`ironic.common.boot_devices`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: DracClientError if the client received unexpected response. :raises: DracOperationFailed if the client received response with an error message. :raises: DracUnexpectedReturnValue if the client received a response with unexpected return value. :raises: InvalidParameterValue if an invalid boot device is specified. :raises: DracPendingConfigJobExists on an error when creating the job. """ # Check for an existing configuration job _check_for_config_job(task.node) client = drac_client.get_wsman_client(task.node) filter_query = ("select * from DCIM_BootSourceSetting where " "InstanceID like '%%#%s%%'" % _BOOT_DEVICES_MAP[device]) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to set the boot device ' 'for node %(node_uuid)s. Can\'t find the ID ' 'for the %(device)s type. Reason: %(error)s.'), { 'node_uuid': task.node.uuid, 'error': exc, 'device': device }) instance_id = drac_common.find_xml( doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text source = 'OneTime' if persistent: source = drac_common.find_xml( doc, 'BootSourceType', resource_uris.DCIM_BootSourceSetting).text # NOTE(lucasagomes): Don't ask me why 'BootSourceType' is set # for 'InstanceID' and 'InstanceID' is set for 'source'! You # know enterprisey... selectors = {'InstanceID': source} properties = {'source': instance_id} try: client.wsman_invoke(resource_uris.DCIM_BootConfigSetting, 'ChangeBootOrderByInstanceID', selectors, properties) except exception.DracRequestFailed as exc: with excutils.save_and_reraise_exception(): LOG.error( _LE('DRAC driver failed to set the boot device for ' 'node %(node_uuid)s to %(target_boot_device)s. ' 'Reason: %(error)s.'), { 'node_uuid': task.node.uuid, 'target_boot_device': device, 'error': exc }) # Create a configuration job _create_config_job(task.node)
def wsman_invoke(self, resource_uri, method, selectors=None, properties=None, expected_return=None): """Invokes a remote WS-Man method. :param resource_uri: URI of the resource. :param method: name of the method to invoke. :param selectors: dictionary of selectors. :param properties: dictionary of properties. :param expected_return: expected return value. :raises: DracClientError on an error from pywsman library. :raises: DracOperationFailed on error reported back by DRAC. :raises: DracUnexpectedReturnValue on return value mismatch. :returns: an ElementTree object of the response received. """ if selectors is None: selectors = {} if properties is None: properties = {} options = pywsman.ClientOptions() for name, value in selectors.items(): options.add_selector(name, value) # NOTE(ifarkas): manually constructing the XML doc should be deleted # once pywsman supports passing a list as a property. # For now this is only a fallback method: in case no # list provided, the supported pywsman API will be used. list_included = any([isinstance(prop_item, list) for prop_item in properties.values()]) if list_included: xml_doc = pywsman.XmlDoc("%s_INPUT" % method, resource_uri) xml_root = xml_doc.root() for name, value in properties.items(): if isinstance(value, list): for item in value: xml_root.add(resource_uri, str(name), str(item)) else: xml_root.add(resource_uri, name, value) LOG.debug( ("WSMAN invoking: %(resource_uri)s:%(method)s" "\nselectors: %(selectors)r\nxml: %(xml)s"), {"resource_uri": resource_uri, "method": method, "selectors": selectors, "xml": xml_root.string()}, ) else: xml_doc = None for name, value in properties.items(): options.add_property(name, value) LOG.debug( ("WSMAN invoking: %(resource_uri)s:%(method)s" "\nselectors: %(selectors)r\properties: %(props)r") % {"resource_uri": resource_uri, "method": method, "selectors": selectors, "props": properties} ) doc = retry_on_empty_response(self.client, "invoke", options, resource_uri, method, xml_doc) root = self._get_root(doc) LOG.debug("WSMAN invoke returned raw XML: %s", ElementTree.tostring(root)) return_value = drac_common.find_xml(root, "ReturnValue", resource_uri).text if return_value == RET_ERROR: messages = drac_common.find_xml(root, "Message", resource_uri, True) message_args = drac_common.find_xml(root, "MessageArguments", resource_uri, True) if message_args: messages = [m.text % p.text for (m, p) in zip(messages, message_args)] else: messages = [m.text for m in messages] raise exception.DracOperationFailed(message="%r" % messages) if expected_return and return_value != expected_return: raise exception.DracUnexpectedReturnValue( expected_return_value=expected_return, actual_return_value=return_value ) return root
def set_boot_device(self, task, device, persistent=False): """Set the boot device for a node. Set the boot device to use on next reboot of the node. :param task: a task from TaskManager. :param device: the boot device, one of :mod:`ironic.common.boot_devices`. :param persistent: Boolean value. True if the boot device will persist to all future boots, False if not. Default: False. :raises: DracClientError on an error from pywsman library. :raises: InvalidParameterValue if an invalid boot device is specified. :raises: DracConfigJobCreationError on an error when creating the job. """ # Check for an existing configuration job _check_for_config_job(task.node) client = drac_common.get_wsman_client(task.node) options = pywsman.ClientOptions() filter_query = ("select * from DCIM_BootSourceSetting where " "InstanceID like '%%#%s%%'" % _BOOT_DEVICES_MAP[device]) try: doc = client.wsman_enumerate(resource_uris.DCIM_BootSourceSetting, options, filter_query=filter_query) except exception.DracClientError as exc: with excutils.save_and_reraise_exception(): LOG.error(_LE('DRAC driver failed to set the boot device ' 'for node %(node_uuid)s. Can\'t find the ID ' 'for the %(device)s type. Reason: %(error)s.'), {'node_uuid': task.node.uuid, 'error': exc, 'device': device}) instance_id = drac_common.find_xml(doc, 'InstanceID', resource_uris.DCIM_BootSourceSetting).text source = 'OneTime' if persistent: source = drac_common.find_xml(doc, 'BootSourceType', resource_uris.DCIM_BootSourceSetting).text # NOTE(lucasagomes): Don't ask me why 'BootSourceType' is set # for 'InstanceID' and 'InstanceID' is set for 'source'! You # know enterprisey... options = pywsman.ClientOptions() options.add_selector('InstanceID', source) options.add_property('source', instance_id) doc = client.wsman_invoke(resource_uris.DCIM_BootConfigSetting, options, 'ChangeBootOrderByInstanceID') return_value = drac_common.find_xml(doc, 'ReturnValue', resource_uris.DCIM_BootConfigSetting).text # NOTE(lucasagomes): Possible return values are: RET_ERROR for error, # RET_SUCCESS for success or RET_CREATED job # created (but changes will be applied after # the reboot) # Boot Management Documentation: http://goo.gl/aEsvUH (Section 8.7) if return_value == drac_common.RET_ERROR: error_message = drac_common.find_xml(doc, 'Message', resource_uris.DCIM_BootConfigSetting).text raise exception.DracOperationError(operation='set_boot_device', error=error_message) # Create a configuration job _create_config_job(task.node)