Mini Shell
# Copyright (c) 2014 Kontron Europe GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from __future__ import absolute_import
from enum import Enum
from .msgs import create_request_by_name
from .utils import check_completion_code, check_rsp_completion_code, ByteBuffer
from .state import State
from .msgs.chassis import \
CONTROL_POWER_DOWN, CONTROL_POWER_UP, CONTROL_POWER_CYCLE, \
CONTROL_HARD_RESET, CONTROL_DIAGNOSTIC_INTERRUPT, \
CONTROL_SOFT_SHUTDOWN
BOOT_PARAMETER_SET_IN_PROGRESS = 0
BOOT_PARAMETER_SERVICE_PARTITION_SELECTOR = 1
BOOT_PARAMETER_SERVICE_PARTITION_SCAN = 2
BOOT_PARAMETER_BMC_BOOT_FLAG_VALID_BIT_CLEARING = 3
BOOT_PARAMETER_BOOT_INFO_ACKNOWLEDGE = 4
BOOT_PARAMETER_BOOT_FLAGS = 5
BOOT_PARAMETER_BOOT_INITIATOR_INFO = 6
BOOT_PARAMETER_BOOT_INITIATOR_MAILBOX = 7
class BootDevice(str, Enum):
NO_OVERRIDE = "no override",
PXE = "pxe",
DEFAULT_HDD = "default hard drive",
DEFAULT_HDD_SAFE = "default hard drive safe mode",
DIAGNOSTIC = "diagnostic partition",
CD = "cd",
BIOS = "bios setup",
REMOTE_USB = "remote removable media",
PRIMARY_REMOTE = "primary remote media",
REMOTE_CD = "remote cd",
REMOTE_HDD = "remote hard drive",
PRIMARY_USB = "primary removable media (usb)"
CONVERT_RAW_TO_BOOT_DEVICE = {
0: BootDevice.NO_OVERRIDE,
1: BootDevice.PXE,
2: BootDevice.DEFAULT_HDD,
3: BootDevice.DEFAULT_HDD_SAFE,
4: BootDevice.DIAGNOSTIC,
5: BootDevice.CD,
6: BootDevice.BIOS,
7: BootDevice.REMOTE_USB,
8: BootDevice.PRIMARY_REMOTE,
9: BootDevice.REMOTE_CD,
11: BootDevice.REMOTE_HDD,
15: BootDevice.PRIMARY_USB
}
CONVERT_BOOT_DEVICE_TO_RAW = {
BootDevice.NO_OVERRIDE: 0b0000,
BootDevice.PXE: 0b0001,
BootDevice.DEFAULT_HDD: 0b0010,
BootDevice.DEFAULT_HDD_SAFE: 0b0011,
BootDevice.DIAGNOSTIC: 0b0100,
BootDevice.CD: 0b0101,
BootDevice.BIOS: 0b0110,
BootDevice.REMOTE_USB: 0b0111,
BootDevice.PRIMARY_REMOTE: 0b1001,
BootDevice.REMOTE_CD: 0b1000,
BootDevice.REMOTE_HDD: 0b1011,
BootDevice.PRIMARY_USB: 0b1111
}
def data_to_boot_mode(data):
"""
Convert a `GetSystemBootOptions(BOOT_PARAMETER_BOOT_FLAGS)` response data
into the string representation of the encoded boot mode.
"""
boot_mode_raw = (data[0] >> 5) & 1
boot_mode = "legacy" if boot_mode_raw == 0 else "efi"
return boot_mode
def data_to_boot_persistency(data):
"""
Convert a `GetSystemBootOptions(BOOT_PARAMETER_BOOT_FLAGS)` response data
into the boolean representation of the encoded boot persistency.
"""
boot_persistent_raw = (data[0] >> 6) & 1
return boot_persistent_raw == 1
def data_to_boot_device(data):
"""
Convert a `GetSystemBootOptions(BOOT_PARAMETER_BOOT_FLAGS)` response data
into the string representation of the encoded boot device.
"""
boot_device_raw = (data[1] >> 2) & 0b1111
return CONVERT_RAW_TO_BOOT_DEVICE[boot_device_raw]
def boot_options_to_data(boot_device, boot_mode, boot_persistency):
"""
Convert a boot mode (string), boot device (string) and boot persistency (bool)
into a `SetSystemBootOptions(BOOT_PARAMETER_BOOT_FLAGS)` request data.
"""
if not isinstance(boot_persistency, bool):
raise TypeError(f"Wrong type for boot_persistency argument: {type(boot_persistency)}, expected bool.")
# Construct the boot mode byte
if boot_mode == "efi":
boot_mode_raw = 0b100000
elif boot_mode == "legacy":
boot_mode_raw = 0
else:
raise ValueError(f"Unknown value for boot_mode argument: {boot_mode}. Possible values are : legacy, efi.")
# Construct the boot persistency + boot flags valid bits
if boot_persistency:
boot_persistent_raw = 0b11000000
else:
boot_persistent_raw = 0b10000000
# Construct the boot device byte
device_raw = CONVERT_BOOT_DEVICE_TO_RAW.get(boot_device, None)
if device_raw is None:
raise ValueError(f"Unknown value for boot_device argument: {boot_device}")
# Construct the final data bytearray
data = ByteBuffer([boot_mode_raw | boot_persistent_raw, device_raw << 2, 0, 0, 0])
return data
class Chassis(object):
def get_chassis_status(self):
return ChassisStatus(self.send_message_with_name('GetChassisStatus'))
def chassis_control(self, option):
req = create_request_by_name('ChassisControl')
req.control.option = option
rsp = self.send_message(req)
check_completion_code(rsp.completion_code)
def chassis_control_power_down(self):
self.chassis_control(CONTROL_POWER_DOWN)
def chassis_control_power_up(self):
self.chassis_control(CONTROL_POWER_UP)
def chassis_control_power_cycle(self):
self.chassis_control(CONTROL_POWER_CYCLE)
def chassis_control_hard_reset(self):
self.chassis_control(CONTROL_HARD_RESET)
def chassis_control_diagnostic_interrupt(self):
self.chassis_control(CONTROL_DIAGNOSTIC_INTERRUPT)
def chassis_control_soft_shutdown(self):
self.chassis_control(CONTROL_SOFT_SHUTDOWN)
def get_system_boot_options(self, parameter_selector=0,
set_selector=0, block_selector=0):
req = create_request_by_name('GetSystemBootOptions')
req.parameter_selector.boot_option_parameter_selector = parameter_selector
req.set_selector = set_selector
req.block_selector = block_selector
rsp = self.send_message(req)
check_rsp_completion_code(rsp)
return rsp.data
def set_system_boot_options(self, parameter_selector, data,
mark_parameter_invalid=0):
req = create_request_by_name('SetSystemBootOptions')
req.parameter_selector.parameter_validity = mark_parameter_invalid
req.parameter_selector.boot_option_parameter_selector = parameter_selector
req.data = data
rsp = self.send_message(req)
check_rsp_completion_code(rsp)
def get_boot_mode(self):
"""
Return a string corresponding to the device boot mode.
Possible values are: legacy, efi.
"""
rsp = self.get_system_boot_options(BOOT_PARAMETER_BOOT_FLAGS)
return data_to_boot_mode(rsp)
def get_boot_persistency(self):
"""
Return True if the boot configuration is to be applied to every future
boot, Fale if it only will applied to the next boot.
"""
rsp = self.get_system_boot_options(BOOT_PARAMETER_BOOT_FLAGS)
return data_to_boot_persistency(rsp)
def get_boot_device(self):
"""
Return a string corresponding to the target boot device.
Possible values are listed in the `BootDevice` class.
"""
rsp = self.get_system_boot_options(BOOT_PARAMETER_BOOT_FLAGS)
return data_to_boot_device(rsp)
def set_boot_options(self, boot_device, boot_mode, boot_persistency):
data = boot_options_to_data(boot_device, boot_mode, boot_persistency)
self.set_system_boot_options(BOOT_PARAMETER_BOOT_FLAGS, data)
class ChassisStatus(State):
power_on = None
overload = None
interlock = None
fault = None
control_fault = None
restore_policy = None
id_cmd_state_info_support = None
chassis_id_state = None
front_panel_button_capabilities = None
last_event = []
chassis_state = []
def _from_response(self, rsp):
self.power_on = bool(rsp.current_power_state.power_on)
self.overload = bool(rsp.current_power_state.power_overload)
self.interlock = bool(rsp.current_power_state.interlock)
self.fault = bool(rsp.current_power_state.power_fault)
self.control_fault = bool(rsp.current_power_state.power_control_fault)
self.restore_policy = rsp.current_power_state.power_restore_policy
self.id_cmd_state_info_support = \
bool(rsp.misc_chassis_state.id_cmd_state_info_support) # noqa:E127
self.chassis_id_state = rsp.misc_chassis_state.chassis_id_state
if rsp.front_panel_button_capabilities is not None:
self.front_panel_button_capabilities = \
rsp.front_panel_button_capabilities
if rsp.last_power_event.ac_failed:
self.last_event.append('ac_failed')
if rsp.last_power_event.power_overload:
self.last_event.append('overload')
if rsp.last_power_event.power_interlock:
self.last_event.append('interlock')
if rsp.last_power_event.power_fault:
self.last_event.append('fault')
if rsp.last_power_event.power_is_on_via_ipmi_command:
self.last_event.append('power_on_via_ipmi')
if rsp.misc_chassis_state.chassis_intrusion_active:
self.chassis_state.append('intrusion')
if rsp.misc_chassis_state.front_panel_lockout_active:
self.chassis_state.append('front_panel_lockout')
if rsp.misc_chassis_state.drive_fault:
self.chassis_state.append('drive_fault')
if rsp.misc_chassis_state.cooling_fault_detected:
self.chassis_state.append('cooling_fault')
Zerion Mini Shell 1.0