Refactor RedfishVirtualMediaBoot

- Move staticmethods and classmethods to functions, since
in py36 we have a bug when ussing unittest.mock [1]
The only classmethod we are keeping is `_set_boot_device`
since it's used by `DracRedfishVirtualMediaBoot`

[1] https://bugs.python.org/issue23078

Change-Id: I6e51bb956890a01535c62f8a378756e65d438ac3
This commit is contained in:
Iury Gregory Melo Ferreira 2020-04-30 16:54:16 +02:00
parent 2afbd77c12
commit 2ffbfb4b46
2 changed files with 683 additions and 746 deletions

View File

@ -83,56 +83,11 @@ KERNEL_RAMDISK_LABELS = {
'rescue': RESCUE_PROPERTIES
}
IMAGE_SUBDIR = 'redfish'
sushy = importutils.try_import('sushy')
class RedfishVirtualMediaBoot(base.BootInterface):
"""Virtual media boot interface over Redfish.
Virtual Media allows booting the system from the "virtual"
CD/DVD drive containing the user image that BMC "inserts"
into the drive.
The CD/DVD images must be in ISO format and (depending on
BMC implementation) could be pulled over HTTP, served as
iSCSI targets or NFS volumes.
The baseline boot workflow looks like this:
1. Pull kernel, ramdisk and ESP (FAT partition image with EFI boot
loader) images (ESP is only needed for UEFI boot)
2. Create bootable ISO out of images (#1), push it to Glance and
pass to the BMC as Swift temporary URL
3. Optionally create floppy image with desired system configuration data,
push it to Glance and pass to the BMC as Swift temporary URL
4. Insert CD/DVD and (optionally) floppy images and set proper boot mode
For building deploy or rescue ISO, redfish boot interface uses
`deploy_kernel`/`deploy_ramdisk` or `rescue_kernel`/`rescue_ramdisk`
properties from `[instance_info]` or `[driver_info]`.
For building boot (user) ISO, redfish boot interface seeks `kernel_id`
and `ramdisk_id` properties in the Glance image metadata found in
`[instance_info]image_source` node property.
"""
IMAGE_SUBDIR = 'redfish'
capabilities = ['iscsi_volume_boot', 'ramdisk_boot']
def __init__(self):
"""Initialize the Redfish virtual media boot interface.
:raises: DriverLoadError if the driver can't be loaded due to
missing dependencies
"""
super(RedfishVirtualMediaBoot, self).__init__()
if not sushy:
raise exception.DriverLoadError(
driver='redfish',
reason=_('Unable to import the sushy library'))
@staticmethod
def _parse_driver_info(node):
"""Gets the driver specific Node deployment info.
@ -175,7 +130,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
return deploy_info
@staticmethod
def _parse_instance_info(node):
"""Gets the instance specific Node deployment info.
@ -193,29 +148,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
# NOTE(etingof): this method is currently no-op, here for completeness
return deploy_info
@classmethod
def _parse_deploy_info(cls, node):
"""Gets the instance and driver specific Node deployment info.
This method validates whether the 'instance_info' and 'driver_info'
property of the supplied node contains the required information for
this driver to deploy images to the node.
:param node: a target node of the deployment
:returns: a dict with the instance_info and driver_info values.
:raises: MissingParameterValue, if any of the required parameters are
missing.
:raises: InvalidParameterValue, if any of the parameters have invalid
value.
"""
deploy_info = {}
deploy_info.update(deploy_utils.get_image_instance_info(node))
deploy_info.update(cls._parse_driver_info(node))
deploy_info.update(cls._parse_instance_info(node))
return deploy_info
@staticmethod
def _append_filename_param(url, filename):
"""Append 'filename=<file>' parameter to given URL.
@ -245,63 +178,120 @@ class RedfishVirtualMediaBoot(base.BootInterface):
return urlparse.urlunparse(parsed_url)
@classmethod
def _publish_image(cls, image_file, object_name):
"""Make image file downloadable.
Depending on ironic settings, pushes given file into Swift or copies
it over to local HTTP server's document root and returns publicly
accessible URL leading to the given file.
def _get_floppy_image_name(node):
"""Returns the floppy image name for a given node.
:param image_file: path to file to publish
:param object_name: name of the published file
:return: a URL to download published file
:param node: the node for which image name is to be provided.
"""
return "image-%s" % node.uuid
if CONF.redfish.use_swift:
container = CONF.redfish.swift_container
timeout = CONF.redfish.swift_object_expiry_timeout
object_headers = {'X-Delete-After': str(timeout)}
def _get_iso_image_name(node):
"""Returns the boot iso image name for a given node.
swift_api = swift.SwiftAPI()
:param node: the node for which image name is to be provided.
"""
return "boot-%s" % node.uuid
swift_api.create_object(container, object_name, image_file,
object_headers=object_headers)
image_url = swift_api.get_temp_url(container, object_name, timeout)
def _insert_vmedia(task, boot_url, boot_device):
"""Insert bootable ISO image into virtual CD or DVD
else:
public_dir = os.path.join(CONF.deploy.http_root, cls.IMAGE_SUBDIR)
:param task: A task from TaskManager.
:param boot_url: URL to a bootable ISO image
:param boot_device: sushy boot device e.g. `VIRTUAL_MEDIA_CD`,
`VIRTUAL_MEDIA_DVD` or `VIRTUAL_MEDIA_FLOPPY`
:raises: InvalidParameterValue, if no suitable virtual CD or DVD is
found on the node.
"""
system = redfish_utils.get_system(task.node)
if not os.path.exists(public_dir):
os.mkdir(public_dir, 0x755)
for manager in system.managers:
for v_media in manager.virtual_media.get_members():
if boot_device not in v_media.media_types:
continue
published_file = os.path.join(public_dir, object_name)
if v_media.inserted:
if v_media.image == boot_url:
LOG.debug("Boot media %(boot_url)s is already "
"inserted into %(boot_device)s for node "
"%(node)s", {'node': task.node.uuid,
'boot_url': boot_url,
'boot_device': boot_device})
return
try:
os.link(image_file, published_file)
continue
except OSError as exc:
LOG.debug(
"Could not hardlink image file %(image)s to public "
"location %(public)s (will copy it over): "
"%(error)s", {'image': image_file,
'public': published_file,
'error': exc})
v_media.insert_media(boot_url, inserted=True,
write_protected=True)
shutil.copyfile(image_file, published_file)
LOG.info("Inserted boot media %(boot_url)s into "
"%(boot_device)s for node "
"%(node)s", {'node': task.node.uuid,
'boot_url': boot_url,
'boot_device': boot_device})
return
image_url = os.path.join(
CONF.deploy.http_url, cls.IMAGE_SUBDIR, object_name)
raise exception.InvalidParameterValue(
_('No suitable virtual media device found'))
image_url = cls._append_filename_param(
image_url, os.path.basename(image_file))
return image_url
def _eject_vmedia(task, boot_device=None):
"""Eject virtual CDs and DVDs
@classmethod
def _unpublish_image(cls, object_name):
:param task: A task from TaskManager.
:param boot_device: sushy boot device e.g. `VIRTUAL_MEDIA_CD`,
`VIRTUAL_MEDIA_DVD` or `VIRTUAL_MEDIA_FLOPPY` or `None` to
eject everything (default).
:raises: InvalidParameterValue, if no suitable virtual CD or DVD is
found on the node.
"""
system = redfish_utils.get_system(task.node)
for manager in system.managers:
for v_media in manager.virtual_media.get_members():
if boot_device and boot_device not in v_media.media_types:
continue
inserted = v_media.inserted
if inserted:
v_media.eject_media()
LOG.info("Boot media is%(already)s ejected from "
"%(boot_device)s for node %(node)s"
"", {'node': task.node.uuid,
'already': '' if inserted else ' already',
'boot_device': v_media.name})
def _has_vmedia_device(task, boot_device):
"""Indicate if device exists at any of the managers
:param task: A task from TaskManager.
:param boot_device: sushy boot device e.g. `VIRTUAL_MEDIA_CD`,
`VIRTUAL_MEDIA_DVD` or `VIRTUAL_MEDIA_FLOPPY`.
"""
system = redfish_utils.get_system(task.node)
for manager in system.managers:
for v_media in manager.virtual_media.get_members():
if boot_device in v_media.media_types:
return True
def _cleanup_iso_image(task):
"""Deletes the ISO if it was created for the instance.
:param task: A task from TaskManager.
"""
iso_object_name = _get_iso_image_name(task.node)
_unpublish_image(iso_object_name)
def _unpublish_image(object_name):
"""Withdraw the image previously made downloadable.
Depending on ironic settings, removes previously published file
@ -329,30 +319,12 @@ class RedfishVirtualMediaBoot(base.BootInterface):
else:
published_file = os.path.join(
CONF.deploy.http_root, cls.IMAGE_SUBDIR, object_name)
CONF.deploy.http_root, IMAGE_SUBDIR, object_name)
ironic_utils.unlink_without_raise(published_file)
@staticmethod
def _get_floppy_image_name(node):
"""Returns the floppy image name for a given node.
:param node: the node for which image name is to be provided.
"""
return "image-%s" % node.uuid
@classmethod
def _cleanup_floppy_image(cls, task):
"""Deletes the floppy image if it was created for the node.
:param task: an ironic node object.
"""
floppy_object_name = cls._get_floppy_image_name(task.node)
cls._unpublish_image(floppy_object_name)
@classmethod
def _prepare_floppy_image(cls, task, params=None):
def _prepare_floppy_image(task, params=None):
"""Prepares the floppy image for passing the parameters.
This method prepares a temporary VFAT filesystem image and adds
@ -371,7 +343,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
:raises: SwiftOperationError, if any operation with Swift fails.
:returns: image URL for the floppy image.
"""
object_name = cls._get_floppy_image_name(task.node)
object_name = _get_floppy_image_name(task.node)
LOG.debug("Trying to create floppy image for node "
"%(node)s", {'node': task.node.uuid})
@ -382,7 +354,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
vfat_image_tmpfile = vfat_image_tmpfile_obj.name
images.create_vfat_image(vfat_image_tmpfile, parameters=params)
image_url = cls._publish_image(vfat_image_tmpfile, object_name)
image_url = _publish_image(vfat_image_tmpfile, object_name)
LOG.debug("Created floppy image %(name)s in Swift for node %(node)s, "
"exposed as temporary URL "
@ -392,26 +364,95 @@ class RedfishVirtualMediaBoot(base.BootInterface):
return image_url
@staticmethod
def _get_iso_image_name(node):
"""Returns the boot iso image name for a given node.
:param node: the node for which image name is to be provided.
def _publish_image(image_file, object_name):
"""Make image file downloadable.
Depending on ironic settings, pushes given file into Swift or copies
it over to local HTTP server's document root and returns publicly
accessible URL leading to the given file.
:param image_file: path to file to publish
:param object_name: name of the published file
:return: a URL to download published file
"""
return "boot-%s" % node.uuid
@classmethod
def _cleanup_iso_image(cls, task):
"""Deletes the ISO if it was created for the instance.
if CONF.redfish.use_swift:
container = CONF.redfish.swift_container
timeout = CONF.redfish.swift_object_expiry_timeout
object_headers = {'X-Delete-After': str(timeout)}
swift_api = swift.SwiftAPI()
swift_api.create_object(container, object_name, image_file,
object_headers=object_headers)
image_url = swift_api.get_temp_url(container, object_name, timeout)
else:
public_dir = os.path.join(CONF.deploy.http_root, IMAGE_SUBDIR)
if not os.path.exists(public_dir):
os.mkdir(public_dir, 0x755)
published_file = os.path.join(public_dir, object_name)
try:
os.link(image_file, published_file)
except OSError as exc:
LOG.debug(
"Could not hardlink image file %(image)s to public "
"location %(public)s (will copy it over): "
"%(error)s", {'image': image_file,
'public': published_file,
'error': exc})
shutil.copyfile(image_file, published_file)
image_url = os.path.join(
CONF.deploy.http_url, IMAGE_SUBDIR, object_name)
image_url = _append_filename_param(
image_url, os.path.basename(image_file))
return image_url
def _cleanup_floppy_image(task):
"""Deletes the floppy image if it was created for the node.
:param task: an ironic node object.
"""
iso_object_name = cls._get_iso_image_name(task.node)
floppy_object_name = _get_floppy_image_name(task.node)
cls._unpublish_image(iso_object_name)
_unpublish_image(floppy_object_name)
@classmethod
def _prepare_iso_image(cls, task, kernel_href, ramdisk_href,
def _parse_deploy_info(node):
"""Gets the instance and driver specific Node deployment info.
This method validates whether the 'instance_info' and 'driver_info'
property of the supplied node contains the required information for
this driver to deploy images to the node.
:param node: a target node of the deployment
:returns: a dict with the instance_info and driver_info values.
:raises: MissingParameterValue, if any of the required parameters are
missing.
:raises: InvalidParameterValue, if any of the parameters have invalid
value.
"""
deploy_info = {}
deploy_info.update(deploy_utils.get_image_instance_info(node))
deploy_info.update(_parse_driver_info(node))
deploy_info.update(_parse_instance_info(node))
return deploy_info
def _prepare_iso_image(task, kernel_href, ramdisk_href,
bootloader_href=None, configdrive=None,
root_uuid=None, params=None):
"""Prepare an ISO to boot the node.
@ -504,9 +545,9 @@ class RedfishVirtualMediaBoot(base.BootInterface):
kernel_params=kernel_params,
boot_mode=boot_mode)
iso_object_name = cls._get_iso_image_name(task.node)
iso_object_name = _get_iso_image_name(task.node)
image_url = cls._publish_image(
image_url = _publish_image(
boot_iso_tmp_file, iso_object_name)
LOG.debug("Created ISO %(name)s in object store for node %(node)s, "
@ -517,8 +558,8 @@ class RedfishVirtualMediaBoot(base.BootInterface):
return image_url
@classmethod
def _prepare_deploy_iso(cls, task, params, mode):
def _prepare_deploy_iso(task, params, mode):
"""Prepare deploy or rescue ISO image
Build bootable ISO out of
@ -540,17 +581,17 @@ class RedfishVirtualMediaBoot(base.BootInterface):
"""
node = task.node
d_info = cls._parse_driver_info(node)
d_info = _parse_driver_info(node)
kernel_href = d_info.get('%s_kernel' % mode)
ramdisk_href = d_info.get('%s_ramdisk' % mode)
bootloader_href = d_info.get('bootloader')
return cls._prepare_iso_image(
return _prepare_iso_image(
task, kernel_href, ramdisk_href, bootloader_href, params=params)
@classmethod
def _prepare_boot_iso(cls, task, root_uuid=None):
def _prepare_boot_iso(task, root_uuid=None):
"""Prepare boot ISO image
Build bootable ISO out of `[instance_info]/kernel`,
@ -571,7 +612,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
"""
node = task.node
d_info = cls._parse_deploy_info(node)
d_info = _parse_deploy_info(node)
kernel_href = node.instance_info.get('kernel')
ramdisk_href = node.instance_info.get('ramdisk')
@ -598,10 +639,55 @@ class RedfishVirtualMediaBoot(base.BootInterface):
bootloader_href = d_info.get('bootloader')
return cls._prepare_iso_image(
return _prepare_iso_image(
task, kernel_href, ramdisk_href, bootloader_href,
root_uuid=root_uuid)
class RedfishVirtualMediaBoot(base.BootInterface):
"""Virtual media boot interface over Redfish.
Virtual Media allows booting the system from the "virtual"
CD/DVD drive containing the user image that BMC "inserts"
into the drive.
The CD/DVD images must be in ISO format and (depending on
BMC implementation) could be pulled over HTTP, served as
iSCSI targets or NFS volumes.
The baseline boot workflow looks like this:
1. Pull kernel, ramdisk and ESP (FAT partition image with EFI boot
loader) images (ESP is only needed for UEFI boot)
2. Create bootable ISO out of images (#1), push it to Glance and
pass to the BMC as Swift temporary URL
3. Optionally create floppy image with desired system configuration data,
push it to Glance and pass to the BMC as Swift temporary URL
4. Insert CD/DVD and (optionally) floppy images and set proper boot mode
For building deploy or rescue ISO, redfish boot interface uses
`deploy_kernel`/`deploy_ramdisk` or `rescue_kernel`/`rescue_ramdisk`
properties from `[instance_info]` or `[driver_info]`.
For building boot (user) ISO, redfish boot interface seeks `kernel_id`
and `ramdisk_id` properties in the Glance image metadata found in
`[instance_info]image_source` node property.
"""
capabilities = ['iscsi_volume_boot', 'ramdisk_boot']
def __init__(self):
"""Initialize the Redfish virtual media boot interface.
:raises: DriverLoadError if the driver can't be loaded due to
missing dependencies
"""
super(RedfishVirtualMediaBoot, self).__init__()
if not sushy:
raise exception.DriverLoadError(
driver='redfish',
reason=_('Unable to import the sushy library'))
def get_properties(self):
"""Return the properties of the interface.
@ -609,8 +695,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
"""
return REQUIRED_PROPERTIES
@classmethod
def _validate_driver_info(cls, task):
def _validate_driver_info(self, task):
"""Validate the prerequisites for virtual media based boot.
This method validates whether the 'driver_info' property of the
@ -623,10 +708,9 @@ class RedfishVirtualMediaBoot(base.BootInterface):
"""
node = task.node
cls._parse_driver_info(node)
_parse_driver_info(node)
@classmethod
def _validate_instance_info(cls, task):
def _validate_instance_info(self, task):
"""Validate instance image information for the task's node.
This method validates whether the 'instance_info' property of the
@ -639,7 +723,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
"""
node = task.node
d_info = cls._parse_deploy_info(node)
d_info = _parse_deploy_info(node)
if node.driver_internal_info.get('is_whole_disk_image'):
props = []
@ -720,7 +804,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
manager_utils.node_power_action(task, states.POWER_OFF)
d_info = self._parse_driver_info(node)
d_info = _parse_driver_info(node)
config_via_floppy = d_info.get('config_via_floppy')
@ -731,16 +815,16 @@ class RedfishVirtualMediaBoot(base.BootInterface):
if config_via_floppy:
if self._has_vmedia_device(task, sushy.VIRTUAL_MEDIA_FLOPPY):
if _has_vmedia_device(task, sushy.VIRTUAL_MEDIA_FLOPPY):
# NOTE (etingof): IPA will read the diskette only if
# we tell it to
ramdisk_params['boot_method'] = 'vmedia'
floppy_ref = self._prepare_floppy_image(
floppy_ref = _prepare_floppy_image(
task, params=ramdisk_params)
self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_FLOPPY)
self._insert_vmedia(
_eject_vmedia(task, sushy.VIRTUAL_MEDIA_FLOPPY)
_insert_vmedia(
task, floppy_ref, sushy.VIRTUAL_MEDIA_FLOPPY)
LOG.debug('Inserted virtual floppy with configuration for '
@ -753,10 +837,10 @@ class RedfishVirtualMediaBoot(base.BootInterface):
mode = deploy_utils.rescue_or_deploy_mode(node)
iso_ref = self._prepare_deploy_iso(task, ramdisk_params, mode)
iso_ref = _prepare_deploy_iso(task, ramdisk_params, mode)
self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
self._insert_vmedia(task, iso_ref, sushy.VIRTUAL_MEDIA_CD)
_eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
_insert_vmedia(task, iso_ref, sushy.VIRTUAL_MEDIA_CD)
boot_mode_utils.sync_boot_mode(task)
@ -775,22 +859,21 @@ class RedfishVirtualMediaBoot(base.BootInterface):
:param task: A task from TaskManager.
:returns: None
"""
node = task.node
d_info = self._parse_driver_info(node)
d_info = _parse_driver_info(task.node)
config_via_floppy = d_info.get('config_via_floppy')
LOG.debug("Cleaning up deploy boot for "
"%(node)s", {'node': task.node.uuid})
self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
self._cleanup_iso_image(task)
_eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
_cleanup_iso_image(task)
if (config_via_floppy
and self._has_vmedia_device(task, sushy.VIRTUAL_MEDIA_FLOPPY)):
self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_FLOPPY)
self._cleanup_floppy_image(task)
and _has_vmedia_device(task, sushy.VIRTUAL_MEDIA_FLOPPY)):
_eject_vmedia(task, sushy.VIRTUAL_MEDIA_FLOPPY)
_cleanup_floppy_image(task)
def prepare_instance(self, task):
"""Prepares the boot of instance over virtual media.
@ -815,12 +898,10 @@ class RedfishVirtualMediaBoot(base.BootInterface):
node = task.node
boot_option = deploy_utils.get_boot_option(node)
self.clean_up_instance(task)
iwdi = node.driver_internal_info.get('is_whole_disk_image')
if boot_option == "local" or iwdi:
self._set_boot_device(
task, boot_devices.DISK, persistent=True)
self._set_boot_device(task, boot_devices.DISK, persistent=True)
LOG.debug("Node %(node)s is set to permanently boot from local "
"%(device)s", {'node': task.node.uuid,
@ -831,28 +912,24 @@ class RedfishVirtualMediaBoot(base.BootInterface):
if boot_option != 'ramdisk':
root_uuid = node.driver_internal_info.get('root_uuid_or_disk_id')
if not root_uuid and task.driver.storage.should_write_image(task):
LOG.warning(
"The UUID of the root partition could not be found for "
"node %s. Booting instance from disk anyway.", node.uuid)
self._set_boot_device(
task, boot_devices.DISK, persistent=True)
self._set_boot_device(task, boot_devices.DISK, persistent=True)
return
params.update(root_uuid=root_uuid)
iso_ref = self._prepare_boot_iso(task, **params)
self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
self._insert_vmedia(task, iso_ref, sushy.VIRTUAL_MEDIA_CD)
iso_ref = _prepare_boot_iso(task, **params)
_eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
_insert_vmedia(task, iso_ref, sushy.VIRTUAL_MEDIA_CD)
boot_mode_utils.sync_boot_mode(task)
self._set_boot_device(
task, boot_devices.CDROM, persistent=True)
self._set_boot_device(task, boot_devices.CDROM, persistent=True)
LOG.debug("Node %(node)s is set to permanently boot from "
"%(device)s", {'node': task.node.uuid,
@ -870,99 +947,13 @@ class RedfishVirtualMediaBoot(base.BootInterface):
LOG.debug("Cleaning up instance boot for "
"%(node)s", {'node': task.node.uuid})
self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
_eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
d_info = task.node.driver_info
config_via_floppy = d_info.get('config_via_floppy')
if config_via_floppy:
self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_FLOPPY)
_eject_vmedia(task, sushy.VIRTUAL_MEDIA_FLOPPY)
self._cleanup_iso_image(task)
@staticmethod
def _insert_vmedia(task, boot_url, boot_device):
"""Insert bootable ISO image into virtual CD or DVD
:param task: A task from TaskManager.
:param boot_url: URL to a bootable ISO image
:param boot_device: sushy boot device e.g. `VIRTUAL_MEDIA_CD`,
`VIRTUAL_MEDIA_DVD` or `VIRTUAL_MEDIA_FLOPPY`
:raises: InvalidParameterValue, if no suitable virtual CD or DVD is
found on the node.
"""
system = redfish_utils.get_system(task.node)
for manager in system.managers:
for v_media in manager.virtual_media.get_members():
if boot_device not in v_media.media_types:
continue
if v_media.inserted:
if v_media.image == boot_url:
LOG.debug("Boot media %(boot_url)s is already "
"inserted into %(boot_device)s for node "
"%(node)s", {'node': task.node.uuid,
'boot_url': boot_url,
'boot_device': boot_device})
return
continue
v_media.insert_media(boot_url, inserted=True,
write_protected=True)
LOG.info("Inserted boot media %(boot_url)s into "
"%(boot_device)s for node "
"%(node)s", {'node': task.node.uuid,
'boot_url': boot_url,
'boot_device': boot_device})
return
raise exception.InvalidParameterValue(
_('No suitable virtual media device found'))
@staticmethod
def _eject_vmedia(task, boot_device=None):
"""Eject virtual CDs and DVDs
:param task: A task from TaskManager.
:param boot_device: sushy boot device e.g. `VIRTUAL_MEDIA_CD`,
`VIRTUAL_MEDIA_DVD` or `VIRTUAL_MEDIA_FLOPPY` or `None` to
eject everything (default).
:raises: InvalidParameterValue, if no suitable virtual CD or DVD is
found on the node.
"""
system = redfish_utils.get_system(task.node)
for manager in system.managers:
for v_media in manager.virtual_media.get_members():
if boot_device and boot_device not in v_media.media_types:
continue
inserted = v_media.inserted
if inserted:
v_media.eject_media()
LOG.info("Boot media is%(already)s ejected from "
"%(boot_device)s for node %(node)s"
"", {'node': task.node.uuid,
'already': '' if inserted else ' already',
'boot_device': v_media.name})
@staticmethod
def _has_vmedia_device(task, boot_device):
"""Indicate if device exists at any of the managers
:param task: A task from TaskManager.
:param boot_device: sushy boot device e.g. `VIRTUAL_MEDIA_CD`,
`VIRTUAL_MEDIA_DVD` or `VIRTUAL_MEDIA_FLOPPY`.
"""
system = redfish_utils.get_system(task.node)
for manager in system.managers:
for v_media in manager.virtual_media.get_members():
if boot_device in v_media.media_types:
return True
_cleanup_iso_image(task)
@classmethod
def _set_boot_device(cls, task, device, persistent=False):

View File

@ -67,7 +67,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
'bootloader': 'bootloader'}
)
actual_driver_info = task.driver.boot._parse_driver_info(task.node)
actual_driver_info = redfish_boot._parse_driver_info(task.node)
self.assertIn('kernel', actual_driver_info['deploy_kernel'])
self.assertIn('ramdisk', actual_driver_info['deploy_ramdisk'])
@ -83,7 +83,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
'bootloader': 'bootloader'}
)
actual_driver_info = task.driver.boot._parse_driver_info(task.node)
actual_driver_info = redfish_boot._parse_driver_info(task.node)
self.assertIn('kernel', actual_driver_info['rescue_kernel'])
self.assertIn('ramdisk', actual_driver_info['rescue_ramdisk'])
@ -93,7 +93,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.MissingParameterValue,
task.driver.boot._parse_driver_info,
redfish_boot._parse_driver_info,
task.node)
def _test_parse_driver_info_from_conf(self, mode='deploy'):
@ -109,7 +109,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
self.config(group='conductor', **expected)
image_info = task.driver.boot._parse_driver_info(task.node)
image_info = redfish_boot._parse_driver_info(task.node)
for key, value in expected.items():
self.assertEqual(value, image_info[key])
@ -139,7 +139,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
task.node.driver_info.update(ramdisk_config)
self.assertRaises(exception.MissingParameterValue,
task.driver.boot._parse_driver_info, task.node)
redfish_boot._parse_driver_info, task.node)
def test_parse_driver_info_mixed_source_deploy(self):
self._test_parse_driver_info_mixed_source()
@ -161,8 +161,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
'kernel': 'http://kernel/img',
'ramdisk': 'http://ramdisk/img'})
actual_instance_info = task.driver.boot._parse_deploy_info(
task.node)
actual_instance_info = redfish_boot._parse_deploy_info(task.node)
self.assertEqual(
'http://boot/iso', actual_instance_info['image_source'])
@ -175,41 +174,33 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.MissingParameterValue,
task.driver.boot._parse_deploy_info,
redfish_boot._parse_deploy_info,
task.node)
def test__append_filename_param_without_qs(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
res = task.driver.boot._append_filename_param(
res = redfish_boot._append_filename_param(
'http://a.b/c', 'b.img')
expected = 'http://a.b/c?filename=b.img'
self.assertEqual(expected, res)
def test__append_filename_param_with_qs(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
res = task.driver.boot._append_filename_param(
res = redfish_boot._append_filename_param(
'http://a.b/c?d=e&f=g', 'b.img')
expected = 'http://a.b/c?d=e&f=g&filename=b.img'
self.assertEqual(expected, res)
def test__append_filename_param_with_filename(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
res = task.driver.boot._append_filename_param(
res = redfish_boot._append_filename_param(
'http://a.b/c?filename=bootme.img', 'b.img')
expected = 'http://a.b/c?filename=bootme.img'
self.assertEqual(expected, res)
@mock.patch.object(redfish_boot, 'swift', autospec=True)
def test__publish_image_swift(self, mock_swift):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
mock_swift_api = mock_swift.SwiftAPI.return_value
mock_swift_api.get_temp_url.return_value = 'https://a.b/c.f?e=f'
url = task.driver.boot._publish_image('file.iso', 'boot.iso')
url = redfish_boot._publish_image('file.iso', 'boot.iso')
self.assertEqual(
'https://a.b/c.f?e=f&filename=file.iso', url)
@ -228,7 +219,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
shared=True) as task:
object_name = 'image-%s' % task.node.uuid
task.driver.boot._unpublish_image(object_name)
redfish_boot._unpublish_image(object_name)
mock_swift.SwiftAPI.assert_called_once_with()
mock_swift_api = mock_swift.SwiftAPI.return_value
@ -244,10 +235,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
self.config(use_swift=False, group='redfish')
self.config(http_url='http://localhost', group='deploy')
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
url = task.driver.boot._publish_image('file.iso', 'boot.iso')
url = redfish_boot._publish_image('file.iso', 'boot.iso')
self.assertEqual(
'http://localhost/redfish/boot.iso?filename=file.iso', url)
@ -266,10 +254,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_link.side_effect = OSError()
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
url = task.driver.boot._publish_image('file.iso', 'boot.iso')
url = redfish_boot._publish_image('file.iso', 'boot.iso')
self.assertEqual(
'http://localhost/redfish/boot.iso?filename=file.iso', url)
@ -289,24 +274,22 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
expected_file = '/httpboot/redfish/' + object_name
task.driver.boot._unpublish_image(object_name)
redfish_boot._unpublish_image(object_name)
mock_ironic_utils.unlink_without_raise.assert_called_once_with(
expected_file)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_unpublish_image', autospec=True)
@mock.patch.object(redfish_boot, '_unpublish_image', autospec=True)
def test__cleanup_floppy_image(self, mock_unpublish):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.driver.boot._cleanup_floppy_image(task)
redfish_boot._cleanup_floppy_image(task)
object_name = 'image-%s' % task.node.uuid
mock_unpublish.assert_called_once_with(object_name)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_publish_image', autospec=True)
@mock.patch.object(redfish_boot, '_publish_image', autospec=True)
@mock.patch.object(images, 'create_vfat_image', autospec=True)
def test__prepare_floppy_image(
self, mock_create_vfat_image, mock__publish_image):
@ -316,7 +299,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock__publish_image.return_value = expected_url
url = task.driver.boot._prepare_floppy_image(task)
url = redfish_boot._prepare_floppy_image(task)
object_name = 'image-%s' % task.node.uuid
@ -328,19 +311,17 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
self.assertEqual(expected_url, url)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_unpublish_image', autospec=True)
@mock.patch.object(redfish_boot, '_unpublish_image', autospec=True)
def test__cleanup_iso_image(self, mock_unpublish):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.driver.boot._cleanup_iso_image(task)
redfish_boot._cleanup_iso_image(task)
object_name = 'boot-%s' % task.node.uuid
mock_unpublish.assert_called_once_with(object_name)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_publish_image', autospec=True)
@mock.patch.object(redfish_boot, '_publish_image', autospec=True)
@mock.patch.object(images, 'create_boot_iso', autospec=True)
def test__prepare_iso_image_uefi(
self, mock_create_boot_iso, mock__publish_image):
@ -352,7 +333,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock__publish_image.return_value = expected_url
url = task.driver.boot._prepare_iso_image(
url = redfish_boot._prepare_iso_image(
task, 'http://kernel/img', 'http://ramdisk/img',
'http://bootloader/img', root_uuid=task.node.uuid)
@ -370,8 +351,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
self.assertEqual(expected_url, url)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_publish_image', autospec=True)
@mock.patch.object(redfish_boot, '_publish_image', autospec=True)
@mock.patch.object(images, 'create_boot_iso', autospec=True)
def test__prepare_iso_image_bios(
self, mock_create_boot_iso, mock__publish_image):
@ -382,7 +362,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock__publish_image.return_value = expected_url
url = task.driver.boot._prepare_iso_image(
url = redfish_boot._prepare_iso_image(
task, 'http://kernel/img', 'http://ramdisk/img',
bootloader_href=None, root_uuid=task.node.uuid)
@ -400,8 +380,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
self.assertEqual(expected_url, url)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_publish_image', autospec=True)
@mock.patch.object(redfish_boot, '_publish_image', autospec=True)
@mock.patch.object(images, 'create_boot_iso', autospec=True)
def test__prepare_iso_image_kernel_params(
self, mock_create_boot_iso, mock__publish_image):
@ -411,7 +390,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
task.node.instance_info.update(kernel_append_params=kernel_params)
task.driver.boot._prepare_iso_image(
redfish_boot._prepare_iso_image(
task, 'http://kernel/img', 'http://ramdisk/img',
bootloader_href=None, root_uuid=task.node.uuid)
@ -422,8 +401,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
kernel_params=kernel_params,
root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123')
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_iso_image', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_iso_image', autospec=True)
def test__prepare_deploy_iso(self, mock__prepare_iso_image):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
@ -436,13 +414,12 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
task.node.instance_info.update(deploy_boot_mode='uefi')
task.driver.boot._prepare_deploy_iso(task, {}, 'deploy')
redfish_boot._prepare_deploy_iso(task, {}, 'deploy')
mock__prepare_iso_image.assert_called_once_with(
mock.ANY, 'kernel', 'ramdisk', 'bootloader', params={})
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_iso_image', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_iso_image', autospec=True)
@mock.patch.object(images, 'create_boot_iso', autospec=True)
def test__prepare_boot_iso(self, mock_create_boot_iso,
mock__prepare_iso_image):
@ -459,7 +436,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
'kernel': 'http://kernel/img',
'ramdisk': 'http://ramdisk/img'})
task.driver.boot._prepare_boot_iso(
redfish_boot._prepare_boot_iso(
task, root_uuid=task.node.uuid)
mock__prepare_iso_image.assert_called_once_with(
@ -557,14 +534,10 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
@mock.patch.object(redfish_boot.manager_utils, 'node_set_boot_device',
autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_deploy_iso', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_deploy_iso', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot.manager_utils, 'node_power_action',
autospec=True)
@mock.patch.object(redfish_boot, 'boot_mode_utils', autospec=True)
@ -607,14 +580,10 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
@mock.patch.object(redfish_boot.manager_utils, 'node_set_boot_device',
autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_deploy_iso', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_deploy_iso', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot.manager_utils, 'node_power_action',
autospec=True)
@mock.patch.object(redfish_boot, 'boot_mode_utils', autospec=True)
@ -656,18 +625,12 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
@mock.patch.object(redfish_boot.manager_utils, 'node_set_boot_device',
autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_floppy_image', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_deploy_iso', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_has_vmedia_device', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_floppy_image', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_deploy_iso', autospec=True)
@mock.patch.object(redfish_boot, '_has_vmedia_device', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot.manager_utils, 'node_power_action',
autospec=True)
@mock.patch.object(redfish_boot, 'boot_mode_utils', autospec=True)
@ -728,16 +691,11 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_boot_mode_utils.sync_boot_mode.assert_called_once_with(task)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_has_vmedia_device', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_cleanup_iso_image', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_cleanup_floppy_image', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, '_has_vmedia_device', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_cleanup_iso_image', autospec=True)
@mock.patch.object(redfish_boot, '_cleanup_floppy_image', autospec=True)
@mock.patch.object(redfish_boot, '_parse_driver_info', autospec=True)
def test_clean_up_ramdisk(
self, mock__parse_driver_info, mock__cleanup_floppy_image,
mock__cleanup_iso_image, mock__eject_vmedia,
@ -768,14 +726,10 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'clean_up_instance', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_boot_iso', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_boot_iso', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, 'manager_utils', autospec=True)
@mock.patch.object(redfish_boot, 'deploy_utils', autospec=True)
@mock.patch.object(redfish_boot, 'boot_mode_utils', autospec=True)
@ -817,14 +771,10 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'clean_up_instance', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_prepare_boot_iso', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, '_prepare_boot_iso', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_insert_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_parse_driver_info', autospec=True)
@mock.patch.object(redfish_boot, 'manager_utils', autospec=True)
@mock.patch.object(redfish_boot, 'deploy_utils', autospec=True)
@mock.patch.object(redfish_boot, 'boot_mode_utils', autospec=True)
@ -858,10 +808,8 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_boot_mode_utils.sync_boot_mode.assert_called_once_with(task)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_cleanup_iso_image', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_cleanup_iso_image', autospec=True)
@mock.patch.object(redfish_boot, 'manager_utils', autospec=True)
def _test_prepare_instance_local_boot(
self, mock_manager_utils,
@ -893,10 +841,8 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
self.node.save()
self._test_prepare_instance_local_boot()
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot.RedfishVirtualMediaBoot,
'_cleanup_iso_image', autospec=True)
@mock.patch.object(redfish_boot, '_eject_vmedia', autospec=True)
@mock.patch.object(redfish_boot, '_cleanup_iso_image', autospec=True)
def _test_clean_up_instance(self, mock__cleanup_iso_image,
mock__eject_vmedia):
@ -942,7 +888,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_redfish_utils.get_system.return_value.managers = [
mock_manager]
task.driver.boot._insert_vmedia(
redfish_boot._insert_vmedia(
task, 'img-url', sushy.VIRTUAL_MEDIA_CD)
mock_vmedia_cd.insert_media.assert_called_once_with(
@ -967,7 +913,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_redfish_utils.get_system.return_value.managers = [
mock_manager]
task.driver.boot._insert_vmedia(
redfish_boot._insert_vmedia(
task, 'img-url', sushy.VIRTUAL_MEDIA_CD)
self.assertFalse(mock_vmedia_cd.insert_media.call_count)
@ -990,7 +936,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
self.assertRaises(
exception.InvalidParameterValue,
task.driver.boot._insert_vmedia,
redfish_boot._insert_vmedia,
task, 'img-url', sushy.VIRTUAL_MEDIA_CD)
@mock.patch.object(redfish_boot, 'redfish_utils', autospec=True)
@ -1013,7 +959,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_redfish_utils.get_system.return_value.managers = [
mock_manager]
task.driver.boot._eject_vmedia(task)
redfish_boot._eject_vmedia(task)
mock_vmedia_cd.eject_media.assert_called_once_with()
mock_vmedia_floppy.eject_media.assert_called_once_with()
@ -1038,7 +984,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_redfish_utils.get_system.return_value.managers = [
mock_manager]
task.driver.boot._eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
redfish_boot._eject_vmedia(task, sushy.VIRTUAL_MEDIA_CD)
mock_vmedia_cd.eject_media.assert_called_once_with()
self.assertFalse(mock_vmedia_floppy.eject_media.call_count)
@ -1063,7 +1009,7 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_redfish_utils.get_system.return_value.managers = [
mock_manager]
task.driver.boot._eject_vmedia(task)
redfish_boot._eject_vmedia(task)
self.assertFalse(mock_vmedia_cd.eject_media.call_count)
self.assertFalse(mock_vmedia_floppy.eject_media.call_count)
@ -1085,6 +1031,6 @@ class RedfishVirtualMediaBootTestCase(db_base.DbTestCase):
mock_redfish_utils.get_system.return_value.managers = [
mock_manager]
task.driver.boot._eject_vmedia(task)
redfish_boot._eject_vmedia(task)
self.assertFalse(mock_vmedia_cd.eject_media.call_count)