"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "ironic/drivers/modules/ipmitool.py" between
ironic-16.0.2.tar.gz and ironic-16.0.3.tar.gz

About: OpenStack Ironic (Optional Service: Bare-Metal Provisioning) aims to provision bare metal machines instead of virtual machines, forked from the Nova baremetal driver.
The "Victoria" series (latest release).

ipmitool.py  (ironic-16.0.2):ipmitool.py  (ironic-16.0.3)
skipping to change at line 158 skipping to change at line 158
# of locale. # of locale.
IPMITOOL_RETRYABLE_FAILURES = ['insufficient resources for session', IPMITOOL_RETRYABLE_FAILURES = ['insufficient resources for session',
# Generic completion codes considered retryable # Generic completion codes considered retryable
'Node busy', 'Node busy',
'Timeout', 'Timeout',
'Out of space', 'Out of space',
'BMC initialization in progress'] 'BMC initialization in progress']
# NOTE(lucasagomes): A mapping for the boot devices and their hexadecimal # NOTE(lucasagomes): A mapping for the boot devices and their hexadecimal
# value. For more information about these values see the "Set System Boot # value. For more information about these values see the "Set System Boot
# Options Command" section of the link below (page 418) # Options Command" section 28.13 of the link below (page 392)
# http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-second-gen-interface- spec-v2-rev1-1.html # noqa # http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-second-gen-interface- spec-v2-rev1-1.html # noqa
BOOT_DEVICE_HEXA_MAP = { BOOT_DEVICE_HEXA_MAP = {
boot_devices.PXE: '0x04', boot_devices.PXE: '0x04',
boot_devices.DISK: '0x08', boot_devices.DISK: '0x08',
boot_devices.CDROM: '0x14', boot_devices.CDROM: '0x14',
boot_devices.BIOS: '0x18', boot_devices.BIOS: '0x18',
boot_devices.SAFE: '0x0c' boot_devices.SAFE: '0x0c'
} }
# NOTE(TheJulia): Inline notes for ipmi raw boot device commands.
# Per spec (intel 2nd gen ipmi interface, v2, rev1-1)
# - bit 7 is CMOS clear
# - bit 6 is Keyboard lock
# - bit 5-2 is the boot device selector
# * where 0000b is to do nothing
# * where 0001b is to force pxe
# * where 0010b is boot from hard drive
# * And anything above 1100b is listed reserved
# which is 0x30 for ipmitool raw commands!
# - bit 1 is screen blank
# - bit 0 is lock out reset button
#
# Effectively this results in
# 00000100b == 0x04 for booting from PXE
# 00001000b == 0x08 for booting from the primary hard disk.
# 00100000b == 0x20 is remotely connected virtual media
# 00100100b == 0x24 which is primary remote boot media as set
# via the OEM initiator mailbox information.
# Like.. iscsi?
# However! Supermicro uses this as the UEFI
# hard disk. See: https://www.supermicro.com/support/faqs/faq.
cfm?faq=25559 # noqa
# 00010000b == 0x30 Enters the reserved territory, and should not
# be expected in use.
def _vendor_aware_boot_device_map(task):
"""Returns an altered vendor boot device map based upon vendor."""
node = task.node
vendor = node.properties.get('vendor', None)
boot_dev_map = BOOT_DEVICE_HEXA_MAP.copy()
boot_mode = boot_mode_utils.get_boot_mode(node)
if vendor:
vendor = str(vendor).lower()
if boot_mode == 'uefi' and vendor == "supermicro":
# This difference is only known on UEFI mode for supermicro
# hardware.
boot_dev_map[boot_devices.DISK] = '0x24'
# NOTE(TheJulia): Similar differences may exist with Cisco UCS
# hardware when using IPMI, however at present we don't know
# what the setting would be.
# NOTE(TheJulia) I've observed "mc info" manufacter name of a cisco
# c-series machine to return "Unknown (0x168B)"
return boot_dev_map
def _check_option_support(options): def _check_option_support(options):
"""Checks if the specific ipmitool options are supported on host. """Checks if the specific ipmitool options are supported on host.
This method updates the module-level variables indicating whether This method updates the module-level variables indicating whether
an option is supported so that it is accessible by any driver an option is supported so that it is accessible by any driver
interface class in this module. It is intended to be called from interface class in this module. It is intended to be called from
the __init__ method of such classes only. the __init__ method of such classes only.
:param options: list of ipmitool options to be checked :param options: list of ipmitool options to be checked
skipping to change at line 857 skipping to change at line 900
"""Get the current power state of the task's node. """Get the current power state of the task's node.
:param task: a TaskManager instance containing the node to act on. :param task: a TaskManager instance containing the node to act on.
:returns: one of ironic.common.states POWER_OFF, POWER_ON or ERROR. :returns: one of ironic.common.states POWER_OFF, POWER_ON or ERROR.
:raises: InvalidParameterValue if required ipmi parameters are missing. :raises: InvalidParameterValue if required ipmi parameters are missing.
:raises: MissingParameterValue if a required parameter is missing. :raises: MissingParameterValue if a required parameter is missing.
:raises: IPMIFailure on an error from ipmitool (from _power_status :raises: IPMIFailure on an error from ipmitool (from _power_status
call). call).
""" """
# NOTE(TheJulia): Temporary until we promote detect_vendor as
# a higher level management method and able to automatically
# run detection upon either power state sync or in the enrollment
# to management step.
try:
properties = task.node.properties
if not properties.get('vendor'):
# We have no vendor stored, so we'll go ahead and
# call to store it.
vendor = task.driver.management.detect_vendor(task)
if vendor:
task.upgrade_lock()
props = task.node.properties
props['vendor'] = vendor
task.node.properties = props
task.node.save()
except exception.UnsupportedDriverExtension:
pass
driver_info = _parse_driver_info(task.node) driver_info = _parse_driver_info(task.node)
return _power_status(driver_info) return _power_status(driver_info)
@METRICS.timer('IPMIPower.set_power_state') @METRICS.timer('IPMIPower.set_power_state')
@task_manager.require_exclusive_lock @task_manager.require_exclusive_lock
def set_power_state(self, task, power_state, timeout=None): def set_power_state(self, task, power_state, timeout=None):
"""Turn the power on, off, soft reboot, or soft power off. """Turn the power on, off, soft reboot, or soft power off.
:param task: a TaskManager instance containing the node to act on. :param task: a TaskManager instance containing the node to act on.
:param power_state: desired power state. :param power_state: desired power state.
skipping to change at line 1019 skipping to change at line 1081
ifbd = task.node.driver_info.get('ipmi_force_boot_device', False) ifbd = task.node.driver_info.get('ipmi_force_boot_device', False)
if strutils.bool_from_string(ifbd): if strutils.bool_from_string(ifbd):
driver_utils.force_persistent_boot(task, driver_utils.force_persistent_boot(task,
device, device,
persistent) persistent)
# Reset persistent to False, in case of BMC does not support # Reset persistent to False, in case of BMC does not support
# persistent or we do not have admin rights. # persistent or we do not have admin rights.
persistent = False persistent = False
# FIXME(lucasagomes): Older versions of the ipmitool utility # NOTE(lucasagomes): Older versions of the ipmitool utility
# are not able to set the options "efiboot" and "persistent" # are not able to set the options "efiboot" and "persistent"
# at the same time, combining other options seems to work fine, # at the same time, combining other options seems to work fine,
# except efiboot. Newer versions of ipmitool (1.8.17) does fix # except efiboot. Newer versions of ipmitool (1.8.17) does fix
# this problem but (some) distros still packaging an older version. # this problem but (some) distros still packaging an older version.
# To workaround this problem for now we can make use of sending # To workaround this problem for now we can make use of sending
# raw bytes to set the boot device for a node in persistent + # raw bytes to set the boot device for a node in persistent +
# uefi mode, this will work with newer and older versions of the # uefi mode, this will work with newer and older versions of the
# ipmitool utility. Also see: # ipmitool utility. Also see:
# https://bugs.launchpad.net/ironic/+bug/1611306 # https://bugs.launchpad.net/ironic/+bug/1611306
# NOTE(TheJulia): Previously we added raw device support because
# most distributions are carrying older downstream patched versions
# of ipmitool where "efiboot" and "persistent" do not work. However,
# using the embedded support assumes that every vendor out there uses
# the same device numbers all the time. Reality is not so kind.
# It should also be noted that the ipmitool chassis bootparm get
# command also just interprets back the same fields, so if the vendor
# has set a different value as default, then ipmitool is not going
# to understand it and may be listing the wrong boot flag as a result.
# See: https://storyboard.openstack.org/#!/story/2008241
boot_mode = boot_mode_utils.get_boot_mode(task.node) boot_mode = boot_mode_utils.get_boot_mode(task.node)
if persistent and boot_mode == 'uefi': if boot_mode == 'uefi':
raw_cmd = ('0x00 0x08 0x05 0xe0 %s 0x00 0x00 0x00' % # Long story short: UEFI was added to IPMI after the final spec
BOOT_DEVICE_HEXA_MAP[device]) # release occured. This means BMCs may actually NEED to be
# explicitly told if the boot is persistant because the
# BMC may return a value which is explicitly parsed as
# no change, BUT the BMC may treat that as operational default.
efi_persistence = '0xe0' if persistent else '0xa0'
# 0xe0 is persistent UEFI boot, 0xa0 is one-time UEFI boot.
boot_device_map = _vendor_aware_boot_device_map(task)
raw_cmd = ('0x00 0x08 0x05 %s %s 0x00 0x00 0x00' %
(efi_persistence, boot_device_map[device]))
send_raw(task, raw_cmd) send_raw(task, raw_cmd)
return return
options = [] options = []
if persistent: if persistent:
options.append('persistent') options.append('persistent')
if boot_mode == 'uefi': # NOTE(TheJulia): Once upon a time we had efiboot here. It doesn't
options.append('efiboot') # work in all cases and directs us to unhappy places if the values
# are incorrect.
cmd = "chassis bootdev %s" % device cmd = "chassis bootdev %s" % device
if options: if options:
cmd = cmd + " options=%s" % ','.join(options) cmd = cmd + " options=%s" % ','.join(options)
driver_info = _parse_driver_info(task.node) driver_info = _parse_driver_info(task.node)
try: try:
out, err = _exec_ipmitool(driver_info, cmd) out, err = _exec_ipmitool(driver_info, cmd)
except (exception.PasswordFileFailedToCreate, except (exception.PasswordFileFailedToCreate,
processutils.ProcessExecutionError) as e: processutils.ProcessExecutionError) as e:
LOG.warning('IPMI set boot device failed for node %(node)s ' LOG.warning('IPMI set boot device failed for node %(node)s '
'when executing "ipmitool %(cmd)s". ' 'when executing "ipmitool %(cmd)s". '
skipping to change at line 1079 skipping to change at line 1159
:boot_device: the boot device, one of :boot_device: the boot device, one of
:mod:`ironic.common.boot_devices` or None if it is unknown. :mod:`ironic.common.boot_devices` or None if it is unknown.
:persistent: Whether the boot device will persist to all :persistent: Whether the boot device will persist to all
future boots or not, None if it is unknown. future boots or not, None if it is unknown.
""" """
driver_info = task.node.driver_info driver_info = task.node.driver_info
driver_internal_info = task.node.driver_internal_info driver_internal_info = task.node.driver_internal_info
ifbd = driver_info.get('ipmi_force_boot_device', False) ifbd = driver_info.get('ipmi_force_boot_device', False)
driver_info = _parse_driver_info(task.node)
if (strutils.bool_from_string(ifbd) if (strutils.bool_from_string(ifbd)
and driver_internal_info.get('persistent_boot_device') and driver_internal_info.get('persistent_boot_device')
and driver_internal_info.get('is_next_boot_persistent', True)): and driver_internal_info.get('is_next_boot_persistent', True)):
return { return {
'boot_device': driver_internal_info['persistent_boot_device'], 'boot_device': driver_internal_info['persistent_boot_device'],
'persistent': True 'persistent': True
} }
cmd = "chassis bootparam get 5" cmd = "chassis bootparam get 5"
driver_info = _parse_driver_info(task.node)
response = {'boot_device': None, 'persistent': None} response = {'boot_device': None, 'persistent': None}
try: try:
out, err = _exec_ipmitool(driver_info, cmd) out, err = _exec_ipmitool(driver_info, cmd)
except (exception.PasswordFileFailedToCreate, except (exception.PasswordFileFailedToCreate,
processutils.ProcessExecutionError) as e: processutils.ProcessExecutionError) as e:
LOG.warning('IPMI get boot device failed for node %(node)s ' LOG.warning('IPMI get boot device failed for node %(node)s '
'when executing "ipmitool %(cmd)s". ' 'when executing "ipmitool %(cmd)s". '
'Error: %(error)s', 'Error: %(error)s',
{'node': driver_info['uuid'], 'cmd': cmd, 'error': e}) {'node': driver_info['uuid'], 'cmd': cmd, 'error': e})
raise exception.IPMIFailure(cmd=cmd) raise exception.IPMIFailure(cmd=cmd)
# FIXME(TheJulia): This whole thing needs to be refactored to be based
# upon the response generated by the "Boot parameter data".
# See: https://storyboard.openstack.org/#!/story/2008241
re_obj = re.search('Boot Device Selector : (.+)?\n', out) re_obj = re.search('Boot Device Selector : (.+)?\n', out)
if re_obj: if re_obj:
boot_selector = re_obj.groups('')[0] boot_selector = re_obj.groups('')[0]
if 'PXE' in boot_selector: if 'PXE' in boot_selector:
response['boot_device'] = boot_devices.PXE response['boot_device'] = boot_devices.PXE
elif 'Hard-Drive' in boot_selector: elif 'Hard-Drive' in boot_selector:
if 'Safe-Mode' in boot_selector: if 'Safe-Mode' in boot_selector:
response['boot_device'] = boot_devices.SAFE response['boot_device'] = boot_devices.SAFE
else: else:
response['boot_device'] = boot_devices.DISK response['boot_device'] = boot_devices.DISK
elif 'BIOS' in boot_selector: elif 'BIOS' in boot_selector:
response['boot_device'] = boot_devices.BIOS response['boot_device'] = boot_devices.BIOS
elif 'CD/DVD' in boot_selector: elif 'CD/DVD' in boot_selector:
response['boot_device'] = boot_devices.CDROM response['boot_device'] = boot_devices.CDROM
response['persistent'] = 'Options apply to all future boots' in out response['persistent'] = 'Options apply to all future boots' in out
return response return response
@METRICS.timer('IPMIManagement.detect_vendor')
def detect_vendor(self, task):
"""Detects, stores, and returns the hardware vendor.
If the Node object ``properties`` field does not already contain
a ``vendor`` field, then this method is intended to query
Detects the BMC hardware vendor and stores the returned value
with-in the Node object ``properties`` field if detected.
:param task: A task from TaskManager.
:raises: InvalidParameterValue if an invalid component, indicator
or state is specified.
:raises: MissingParameterValue if a required parameter is missing
:returns: String representing the BMC reported Vendor or
Manufacturer, otherwise returns None.
"""
try:
driver_info = _parse_driver_info(task.node)
out, err = _exec_ipmitool(driver_info, "mc info")
re_obj = re.search("Manufacturer Name .*: (.+)", out)
if re_obj:
bmc_vendor = str(re_obj.groups('')[0]).lower().split(':')
# Pull unparsed data and save the vendor
return bmc_vendor[-1]
except (exception.PasswordFileFailedToCreate,
processutils.ProcessExecutionError) as e:
LOG.warning('IPMI get boot device failed to detect vendor '
'of bmc for %(node)s. Error %(err)s',
{'node': task.node.uuid,
'err': e})
@METRICS.timer('IPMIManagement.get_sensors_data') @METRICS.timer('IPMIManagement.get_sensors_data')
def get_sensors_data(self, task): def get_sensors_data(self, task):
"""Get sensors data. """Get sensors data.
:param task: a TaskManager instance. :param task: a TaskManager instance.
:raises: FailedToGetSensorData when getting the sensor data fails. :raises: FailedToGetSensorData when getting the sensor data fails.
:raises: FailedToParseSensorData when parsing sensor data fails. :raises: FailedToParseSensorData when parsing sensor data fails.
:raises: InvalidParameterValue if required ipmi parameters are missing :raises: InvalidParameterValue if required ipmi parameters are missing
:raises: MissingParameterValue if a required parameter is missing. :raises: MissingParameterValue if a required parameter is missing.
:returns: returns a dict of sensor data group by sensor type. :returns: returns a dict of sensor data group by sensor type.
 End of changes. 11 change blocks. 
10 lines changed or deleted 125 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)