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_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 _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_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_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_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_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 _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 _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 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 _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 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 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)