Add iDrac virtual cd/floppy

iDRAC does not support standard
redfish boot devices, provide oem override
in such case to use the OEM interface.

Change-Id: I53d7bb1d82035e621802c20f46000760cc8631a8
This commit is contained in:
Jarrod Johnson 2022-01-06 12:13:01 -05:00
parent 51eebd39fc
commit 4cfaf03d6c
7 changed files with 148 additions and 43 deletions

View File

@ -51,22 +51,6 @@ powerstates = {
'boot': None,
}
boot_devices_write = {
'net': 'Pxe',
'network': 'Pxe',
'pxe': 'Pxe',
'hd': 'Hdd',
'usb': 'Usb',
'cd': 'Cd',
'cdrom': 'Cd',
'optical': 'Cd',
'dvd': 'Cd',
'floppy': 'Floppy',
'default': 'None',
'setup': 'BiosSetup',
'bios': 'BiosSetup',
'f1': 'BiosSetup',
}
boot_devices_read = {
'BiosSetup': 'setup',
@ -684,31 +668,7 @@ class Command(object):
:raises: PyghmiException on an error.
:returns: dict or True -- If callback is not provided, the response
"""
reqbootdev = bootdev
if (bootdev not in boot_devices_write
and bootdev not in boot_devices_read):
raise exc.InvalidParameterValue('Unsupported device %s'
% repr(bootdev))
bootdev = boot_devices_write.get(bootdev, bootdev)
if bootdev == 'None':
payload = {'Boot': {'BootSourceOverrideEnabled': 'Disabled'}}
else:
payload = {'Boot': {
'BootSourceOverrideEnabled': 'Continuous' if persist
else 'Once',
'BootSourceOverrideTarget': bootdev,
}}
if uefiboot is not None:
uefiboot = 'UEFI' if uefiboot else 'Legacy'
payload['BootSourceOverrideMode'] = uefiboot
try:
self._do_web_request(self.sysurl, payload, method='PATCH')
return {'bootdev': reqbootdev}
except Exception:
del payload['BootSourceOverrideMode']
thetag = self.sysinfo.get('@odata.etag', None)
self._do_web_request(self.sysurl, payload, method='PATCH', etag=thetag)
return {'bootdev': reqbootdev}
return self.oem.set_bootdev(bootdev, persist, uefiboot, self)
@property
def _biosurl(self):

View File

View File

@ -0,0 +1,47 @@
# Copyright 2022 Lenovo Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pyghmi.redfish.oem.generic as generic
class OEMHandler(generic.OEMHandler):
def __init__(self, sysinfo, sysurl, webclient, cache, gpool=None):
super(OEMHandler, self).__init__(sysinfo, sysurl, webclient, cache,
gpool)
def set_bootdev(self, bootdev, persist=False, uefiboot=None,
fishclient=None):
# gleaned from web console, under configuration, system settings,
# hardware, first boot device. iDrac presumes that the standard
# explicitly refers only to physical devices. I think the intent
# is the exact opposite for 'removable' media, and thus redirect
# the 'physical' standard to the vFDD/VCD-DVD seen in the idrac
# web gui
if bootdev not in ('floppy', 'cd'):
return super(OEMHandler, self).set_bootdev(bootdev, persist,
uefiboot, fishclient)
payload = {'Attributes': {}}
if persist:
payload['Attributes']['ServerBoot.1.BootOnce'] = 'Disabled'
else:
payload['Attributes']['ServerBoot.1.BootOnce'] = 'Enabled'
if bootdev == 'floppy':
payload['Attributes']['ServerBoot.1.FirstBootDevice'] = 'vFDD'
elif bootdev == 'cd':
payload['Attributes']['ServerBoot.1.FirstBootDevice'] = 'VCD-DVD'
fishclient._do_web_request(
'/redfish/v1/Managers/iDRAC.Embedded.1/Attributes',
payload, method='PATCH')
return {'bootdev': bootdev}

View File

@ -0,0 +1,20 @@
# Copyright 2022 Lenovo Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pyghmi.redfish.oem.dell import idrac
def get_handler(sysinfo, sysurl, webclient, cache, cmd):
return idrac.OEMHandler(sysinfo, sysurl, webclient, cache,
gpool=cmd._gpool)

View File

@ -1,4 +1,4 @@
# Copyright 2019 Lenovo Corporation
# Copyright 2019-2022 Lenovo Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -18,6 +18,34 @@ import os
import pyghmi.exceptions as exc
import pyghmi.media as media
boot_devices_write = {
'net': 'Pxe',
'network': 'Pxe',
'pxe': 'Pxe',
'hd': 'Hdd',
'usb': 'Usb',
'cd': 'Cd',
'cdrom': 'Cd',
'optical': 'Cd',
'dvd': 'Cd',
'floppy': 'Floppy',
'default': 'None',
'setup': 'BiosSetup',
'bios': 'BiosSetup',
'f1': 'BiosSetup',
}
boot_devices_read = {
'BiosSetup': 'setup',
'Cd': 'optical',
'Floppy': 'floppy',
'Hdd': 'hd',
'None': 'default',
'Pxe': 'network',
'Usb': 'usb',
'SDCard': 'sdcard',
}
class OEMHandler(object):
hostnic = None
@ -29,6 +57,54 @@ class OEMHandler(object):
self._urlcache = cache
self.webclient = webclient
def set_bootdev(self, bootdev, persist=False, uefiboot=None,
fishclient=None):
"""Set boot device to use on next reboot
:param bootdev:
*network -- Request network boot
*hd -- Boot from hard drive
*safe -- Boot from hard drive, requesting 'safe mode'
*optical -- boot from CD/DVD/BD drive
*setup -- Boot into setup utility
*default -- remove any directed boot device request
:param persist: If true, ask that system firmware use this device
beyond next boot. Be aware many systems do not honor
this
:param uefiboot: If true, request UEFI boot explicitly. If False,
request BIOS style boot.
None (default) does not modify the boot mode.
:raises: PyghmiException on an error.
:returns: dict or True -- If callback is not provided, the response
"""
reqbootdev = bootdev
if (bootdev not in boot_devices_write
and bootdev not in boot_devices_read):
raise exc.InvalidParameterValue('Unsupported device %s'
% repr(bootdev))
bootdev = boot_devices_write.get(bootdev, bootdev)
if bootdev == 'None':
payload = {'Boot': {'BootSourceOverrideEnabled': 'Disabled'}}
else:
payload = {'Boot': {
'BootSourceOverrideEnabled': 'Continuous' if persist
else 'Once',
'BootSourceOverrideTarget': bootdev,
}}
if uefiboot is not None:
uefiboot = 'UEFI' if uefiboot else 'Legacy'
payload['BootSourceOverrideMode'] = uefiboot
try:
fishclient._do_web_request(self.sysurl, payload,
method='PATCH')
return {'bootdev': reqbootdev}
except Exception:
del payload['BootSourceOverrideMode']
thetag = fishclient.sysinfo.get('@odata.etag', None)
fishclient._do_web_request(fishclient.sysurl, payload, method='PATCH',
etag=thetag)
return {'bootdev': reqbootdev}
def _get_cache(self, url):
now = os.times()[4]
cachent = self._urlcache.get(url, None)

View File

@ -12,11 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import pyghmi.redfish.oem.dell.main as dell
import pyghmi.redfish.oem.generic as generic
import pyghmi.redfish.oem.lenovo.main as lenovo
OEMMAP = {
'Lenovo': lenovo,
'Dell': dell,
}

View File

@ -26,6 +26,6 @@ setuptools.setup(
packages=['pyghmi', 'pyghmi.util', 'pyghmi.ipmi', 'pyghmi.cmd',
'pyghmi.redfish', 'pyghmi.ipmi.private', 'pyghmi.ipmi.oem',
'pyghmi.ipmi.oem.lenovo', 'pyghmi.redfish.oem',
'pyghmi.redfish.oem.lenovo'],
'pyghmi.redfish.oem.dell', 'pyghmi.redfish.oem.lenovo'],
license='Apache License, Version 2.0')