def _execute_nm_command(task, data, command_func, parse_func=None):
    """Execute Intel Node Manager command via send_raw().

    :param task: a TaskManager instance.
    :param data: a dict with data passed to vendor's method.
    :param command_func: a function that returns raw command bytes.
    :param parse_func: a function that parses returned raw bytes.
    :raises: IPMIFailure if Intel Node Manager is not detected on a node or if
             an error happens during command execution.
    :returns: a dict with parsed output or None if command does not return
              user's info.
    """
    try:
        channel, address = _get_nm_address(task)
    except exception.IPMIFailure as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE('Can not obtain Intel Node Manager address for '
                              'node %(node)s: %(err)s'),
                          {'node': task.node.uuid, 'err': six.text_type(e)})
    driver_info = task.node.driver_info
    driver_info['ipmi_bridging'] = 'single'
    driver_info['ipmi_target_channel'] = channel
    driver_info['ipmi_target_address'] = address
    cmd = _command_to_string(command_func(data))
    out = ipmi.send_raw(task, cmd)[0]
    if parse_func:
        try:
            return parse_func(out.split())
        except exception.IPMIFailure as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(_LE('Error in returned data for node %(node)s: '
                                  '%(err)s'), {'node': task.node.uuid,
                                               'err': six.text_type(e)})
示例#2
0
def awake_amt_interface(node):
    """Wake up AMT interface.

    AMT interface goes to sleep after a period of time if the host is off.
    This method will ping AMT interface to wake it up. Because there is
    no guarantee that the AMT address in driver_info is correct, only
    ping the IP five times which is enough to wake it up.

    :param node: an Ironic node object.
    :raises: AMTConnectFailure if unable to connect to the server.
    """
    awake_interval = CONF.amt_driver.awake_interval
    if awake_interval == 0:
        return

    now = time.time()
    last_awake = AMT_AWAKE_CACHE.get(node.uuid, 0)
    if now - last_awake > awake_interval:
        cmd_args = [
            'ping', '-i', 0.2, '-c', 5, node.driver_info['amt_address']
        ]
        try:
            ironic_utils.execute(*cmd_args)
        except processutils.ProcessExecutionError as err:
            LOG.error(
                _LE('Unable to awake AMT interface on node '
                    '%(node_id)s. Error: %(error)s'), {
                        'node_id': node.uuid,
                        'error': err
                    })
            raise exception.AMTConnectFailure()
        else:
            LOG.debug(('Successfully awakened AMT interface on node '
                       '%(node_id)s.'), {'node_id': node.uuid})
            AMT_AWAKE_CACHE[node.uuid] = now
示例#3
0
    def wsman_invoke(self, options, resource_uri, method, data=None):
        """Invoke method on target server

        :param options: client options
        :param resource_uri: a URI to an XML schema
        :param method: invoke method
        :param data: a XmlDoc as invoke input
        :returns: XmlDoc object
        :raises: AMTFailure if get unexpected response.
        :raises: AMTConnectFailure if unable to connect to the server.
        """
        if data is None:
            doc = self.client.invoke(options, resource_uri, method)
        else:
            doc = self.client.invoke(options, resource_uri, method, data)
        item = "ReturnValue"
        return_value = xml_find(doc, resource_uri, item).text
        if return_value != RET_SUCCESS:
            LOG.error(
                _LE("Call to AMT with URI %(uri)s and "
                    "method %(method)s failed: return value "
                    "was %(value)s"), {
                        'uri': resource_uri,
                        'method': method,
                        'value': return_value
                    })
            raise exception.AMTFailure(cmd='wsman_invoke')
        return doc
def awake_amt_interface(node):
    """Wake up AMT interface.

    AMT interface goes to sleep after a period of time if the host is off.
    This method will ping AMT interface to wake it up. Because there is
    no guarantee that the AMT address in driver_info is correct, only
    ping the IP five times which is enough to wake it up.

    :param node: an Ironic node object.
    :raises: AMTConnectFailure if unable to connect to the server.
    """
    awake_interval = CONF.amt_driver.awake_interval
    if awake_interval == 0:
        return

    now = time.time()
    last_awake = AMT_AWAKE_CACHE.get(node.uuid, 0)
    if now - last_awake > awake_interval:
        cmd_args = ['ping', '-i', 0.2, '-c', 5,
                    node.driver_info['amt_address']]
        try:
            ironic_utils.execute(*cmd_args)
        except processutils.ProcessExecutionError as err:
            LOG.error(_LE('Unable to awake AMT interface on node '
                          '%(node_id)s. Error: %(error)s'),
                      {'node_id': node.uuid, 'error': err})
            raise exception.AMTConnectFailure()
        else:
            LOG.debug(('Successfully awakened AMT interface on node '
                       '%(node_id)s.'), {'node_id': node.uuid})
            AMT_AWAKE_CACHE[node.uuid] = now
示例#5
0
def _set_power_state(node, target_state):
    """Set power state of the AMT Client.

    :param node: a node object.
    :param target_state: desired power state.
    :raises: AMTFailure
    :raises: AMTConnectFailure
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)

    method = 'RequestPowerStateChange'
    options = pywsman.ClientOptions()
    options.add_selector('Name', 'Intel(r) AMT Power Management Service')

    doc = _generate_power_action_input(AMT_POWER_MAP[target_state])
    try:
        client.wsman_invoke(options, resource_uris.CIM_PowerManagementService,
                            method, doc)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(
                _LE("Failed to set power state %(state)s for "
                    "node %(node_id)s with error: %(error)s."), {
                        'state': target_state,
                        'node_id': node.uuid,
                        'error': e
                    })
    else:
        LOG.info(_LI("Power state set to %(state)s for node %(node_id)s"), {
            'state': target_state,
            'node_id': node.uuid
        })
def _set_boot_device_order(node, boot_device):
    """Set boot device order configuration of AMT Client.

    :param node: a node object
    :param boot_device: the boot device
    :raises: AMTFailure
    :raises: AMTConnectFailure
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)
    device = amt_common.BOOT_DEVICES_MAPPING[boot_device]
    doc = _generate_change_boot_order_input(device)

    method = 'ChangeBootOrder'

    options = pywsman.ClientOptions()
    options.add_selector('InstanceID', 'Intel(r) AMT: Boot Configuration 0')

    try:
        client.wsman_invoke(options, resource_uris.CIM_BootConfigSetting,
                            method, doc)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE("Failed to set boot device %(boot_device)s for "
                              "node %(node_id)s with error: %(error)s."),
                          {'boot_device': boot_device, 'node_id': node.uuid,
                           'error': e})
    else:
        LOG.info(_LI("Successfully set boot device %(boot_device)s for "
                     "node %(node_id)s"),
                 {'boot_device': boot_device, 'node_id': node.uuid})
def _set_power_state(node, target_state):
    """Set power state of the AMT Client.

    :param node: a node object.
    :param target_state: desired power state.
    :raises: AMTFailure
    :raises: AMTConnectFailure
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)

    method = 'RequestPowerStateChange'
    options = pywsman.ClientOptions()
    options.add_selector('Name', 'Intel(r) AMT Power Management Service')

    doc = _generate_power_action_input(AMT_POWER_MAP[target_state])
    try:
        client.wsman_invoke(options, resource_uris.CIM_PowerManagementService,
                            method, doc)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE("Failed to set power state %(state)s for "
                              "node %(node_id)s with error: %(error)s."),
                          {'state': target_state, 'node_id': node.uuid,
                           'error': e})
    else:
        LOG.info(_LI("Power state set to %(state)s for node %(node_id)s"),
                 {'state': target_state, 'node_id': node.uuid})
def _enable_boot_config(node):
    """Enable boot configuration of AMT Client.

    :param node: a node object
    :raises: AMTFailure
    :raises: AMTConnectFailure
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)
    method = 'SetBootConfigRole'
    doc = _generate_enable_boot_config_input()
    options = pywsman.ClientOptions()
    options.add_selector('Name', 'Intel(r) AMT Boot Service')
    try:
        client.wsman_invoke(options, resource_uris.CIM_BootService, method,
                            doc)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(
                _LE("Failed to enable boot config for node "
                    "%(node_id)s with error: %(error)s."), {
                        'node_id': node.uuid,
                        'error': e
                    })
    else:
        LOG.info(_LI("Successfully enabled boot config for node %(node_id)s."),
                 {'node_id': node.uuid})
def _power_status(node):
    """Get the power status for a node.

    :param node: a node object.
    :returns: one of ironic.common.states POWER_OFF, POWER_ON or ERROR.
    :raises: AMTFailure.
    :raises: AMTConnectFailure.
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)
    namespace = resource_uris.CIM_AssociatedPowerManagementService
    try:
        doc = client.wsman_get(namespace)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE("Failed to get power state for node %(node_id)s "
                              "with error: %(error)s."),
                          {'node_id': node.uuid, 'error': e})

    item = "PowerState"
    power_state = amt_common.xml_find(doc, namespace, item).text
    for state in AMT_POWER_MAP:
        if power_state == AMT_POWER_MAP[state]:
            return state
    return states.ERROR
示例#10
0
def dump_sdr(task, file_path):
    """Dump SDR data to a file.

    :param task: a TaskManager instance.
    :param file_path: the path to SDR dump file.
    :raises: IPMIFailure on an error from ipmitool.
    :raises: MissingParameterValue if a required parameter is missing.
    :raises: InvalidParameterValue when an invalid value is specified.

    """
    node_uuid = task.node.uuid
    LOG.debug('Dump SDR data for node %(node)s to file %(name)s',
              {'name': file_path, 'node': node_uuid})
    driver_info = ipmitool._parse_driver_info(task.node)
    cmd = 'sdr dump %s' % file_path

    try:
        out, err = ipmitool._exec_ipmitool(driver_info, cmd)
        LOG.debug('dump SDR returned stdout: %(stdout)s, stderr:'
                  ' %(stderr)s', {'stdout': out, 'stderr': err})
    except (exception.PasswordFileFailedToCreate,
            processutils.ProcessExecutionError) as e:
        LOG.exception(_LE('IPMI "sdr dump" failed for node %(node_id)s '
                      'with error: %(error)s.'),
                      {'node_id': node_uuid, 'error': e})
        raise exception.IPMIFailure(cmd=cmd)
示例#11
0
def send_raw(task, raw_bytes):
    """Send raw bytes to the BMC. Bytes should be a string of bytes.

    :param task: a TaskManager instance.
    :param raw_bytes: a string of raw bytes to send, e.g. '0x00 0x01'
    :returns: a tuple with stdout and stderr.
    :raises: IPMIFailure on an error from ipmitool.
    :raises: MissingParameterValue if a required parameter is missing.
    :raises: InvalidParameterValue when an invalid value is specified.

    """
    node_uuid = task.node.uuid
    LOG.debug('Sending node %(node)s raw bytes %(bytes)s',
              {'bytes': raw_bytes, 'node': node_uuid})
    driver_info = ipmitool._parse_driver_info(task.node)
    cmd = 'raw %s' % raw_bytes

    try:
        out, err = ipmitool._exec_ipmitool(driver_info, cmd)
        LOG.debug('send raw bytes returned stdout: %(stdout)s, stderr:'
                  ' %(stderr)s', {'stdout': out, 'stderr': err})
    except (exception.PasswordFileFailedToCreate,
            processutils.ProcessExecutionError) as e:
        LOG.exception(_LE('IPMI "raw bytes" failed for node %(node_id)s '
                      'with error: %(error)s.'),
                      {'node_id': node_uuid, 'error': e})
        raise exception.IPMIFailure(cmd=cmd)

    return out, err
示例#12
0
    def wsman_invoke(self, options, resource_uri, method, data=None):
        """Invoke method on target server

        :param options: client options
        :param resource_uri: a URI to an XML schema
        :param method: invoke method
        :param data: a XmlDoc as invoke input
        :returns: XmlDoc object
        :raises: AMTFailure if get unexpected response.
        :raises: AMTConnectFailure if unable to connect to the server.
        """
        if data is None:
            doc = self.client.invoke(options, resource_uri, method)
        else:
            doc = self.client.invoke(options, resource_uri, method, data)
        item = "ReturnValue"
        return_value = xml_find(doc, resource_uri, item).text
        if return_value != RET_SUCCESS:
            LOG.error(_LE("Call to AMT with URI %(uri)s and "
                          "method %(method)s failed: return value "
                          "was %(value)s"),
                      {'uri': resource_uri, 'method': method,
                       'value': return_value})
            raise exception.AMTFailure(cmd='wsman_invoke')
        return doc
示例#13
0
def _power_status(node):
    """Get the power status for a node.

    :param node: a node object.
    :returns: one of ironic.common.states POWER_OFF, POWER_ON or ERROR.
    :raises: AMTFailure.
    :raises: AMTConnectFailure.
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)
    namespace = resource_uris.CIM_AssociatedPowerManagementService
    try:
        doc = client.wsman_get(namespace)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(
                _LE("Failed to get power state for node %(node_id)s "
                    "with error: %(error)s."), {
                        'node_id': node.uuid,
                        'error': e
                    })

    item = "PowerState"
    power_state = amt_common.xml_find(doc, namespace, item).text
    for state in AMT_POWER_MAP:
        if power_state == AMT_POWER_MAP[state]:
            return state
    return states.ERROR
def _execute_nm_command(task, data, command_func, parse_func=None):
    """Execute Intel Node Manager command via send_raw().

    :param task: a TaskManager instance.
    :param data: a dict with data passed to vendor's method.
    :param command_func: a function that returns raw command bytes.
    :param parse_func: a function that parses returned raw bytes.
    :raises: IPMIFailure if Intel Node Manager is not detected on a node or if
             an error happens during command execution.
    :returns: a dict with parsed output or None if command does not return
              user's info.
    """
    try:
        channel, address = _get_nm_address(task)
    except exception.IPMIFailure as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(
                _LE('Can not obtain Intel Node Manager address for '
                    'node %(node)s: %(err)s'), {
                        'node': task.node.uuid,
                        'err': six.text_type(e)
                    })
    driver_info = task.node.driver_info
    driver_info['ipmi_bridging'] = 'single'
    driver_info['ipmi_target_channel'] = channel
    driver_info['ipmi_target_address'] = address
    cmd = _command_to_string(command_func(data))
    out = ipmitool.send_raw(task, cmd)[0]
    if parse_func:
        try:
            return parse_func(out.split())
        except exception.IPMIFailure as e:
            with excutils.save_and_reraise_exception():
                LOG.exception(
                    _LE('Error in returned data for node %(node)s: '
                        '%(err)s'), {
                            'node': task.node.uuid,
                            'err': six.text_type(e)
                        })
示例#15
0
    def wsman_get(self, resource_uri, options=None):
        """Get target server info

        :param options: client options
        :param resource_uri: a URI to an XML schema
        :returns: XmlDoc object
        :raises: AMTFailure if get unexpected response.
        :raises: AMTConnectFailure if unable to connect to the server.
        """
        if options is None:
            options = pywsman.ClientOptions()
        doc = self.client.get(options, resource_uri)
        item = 'Fault'
        fault = xml_find(doc, _SOAP_ENVELOPE, item)
        if fault is not None:
            LOG.error(_LE('Call to AMT with URI %(uri)s failed: '
                          'got Fault %(fault)s'),
                      {'uri': resource_uri, 'fault': fault.text})
            raise exception.AMTFailure(cmd='wsman_get')
        return doc
示例#16
0
    def wsman_get(self, resource_uri, options=None):
        """Get target server info

        :param options: client options
        :param resource_uri: a URI to an XML schema
        :returns: XmlDoc object
        :raises: AMTFailure if get unexpected response.
        :raises: AMTConnectFailure if unable to connect to the server.
        """
        if options is None:
            options = pywsman.ClientOptions()
        doc = self.client.get(options, resource_uri)
        item = 'Fault'
        fault = xml_find(doc, _SOAP_ENVELOPE, item)
        if fault is not None:
            LOG.error(
                _LE('Call to AMT with URI %(uri)s failed: '
                    'got Fault %(fault)s'), {
                        'uri': resource_uri,
                        'fault': fault.text
                    })
            raise exception.AMTFailure(cmd='wsman_get')
        return doc
def _set_boot_device_order(node, boot_device):
    """Set boot device order configuration of AMT Client.

    :param node: a node object
    :param boot_device: the boot device
    :raises: AMTFailure
    :raises: AMTConnectFailure
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)
    device = amt_common.BOOT_DEVICES_MAPPING[boot_device]
    doc = _generate_change_boot_order_input(device)

    method = 'ChangeBootOrder'

    options = pywsman.ClientOptions()
    options.add_selector('InstanceID', 'Intel(r) AMT: Boot Configuration 0')

    try:
        client.wsman_invoke(options, resource_uris.CIM_BootConfigSetting,
                            method, doc)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(
                _LE("Failed to set boot device %(boot_device)s for "
                    "node %(node_id)s with error: %(error)s."), {
                        'boot_device': boot_device,
                        'node_id': node.uuid,
                        'error': e
                    })
    else:
        LOG.info(
            _LI("Successfully set boot device %(boot_device)s for "
                "node %(node_id)s"), {
                    'boot_device': boot_device,
                    'node_id': node.uuid
                })
def _enable_boot_config(node):
    """Enable boot configuration of AMT Client.

    :param node: a node object
    :raises: AMTFailure
    :raises: AMTConnectFailure
    """
    amt_common.awake_amt_interface(node)
    client = amt_common.get_wsman_client(node)
    method = 'SetBootConfigRole'
    doc = _generate_enable_boot_config_input()
    options = pywsman.ClientOptions()
    options.add_selector('Name', 'Intel(r) AMT Boot Service')
    try:
        client.wsman_invoke(options, resource_uris.CIM_BootService,
                            method, doc)
    except (exception.AMTFailure, exception.AMTConnectFailure) as e:
        with excutils.save_and_reraise_exception():
            LOG.exception(_LE("Failed to enable boot config for node "
                              "%(node_id)s with error: %(error)s."),
                          {'node_id': node.uuid, 'error': e})
    else:
        LOG.info(_LI("Successfully enabled boot config for node %(node_id)s."),
                 {'node_id': node.uuid})