def prepare(self, task): """Prepare the deployment environment for this task's node. Generates the TFTP configuration for PXE-booting both the deployment and user images, fetches the TFTP image from Glance and add it to the local cache. :param task: a TaskManager instance containing the node to act on. :raises: NetworkError: if the previous cleaning ports cannot be removed or if new cleaning ports cannot be created. :raises: InvalidParameterValue when the wrong power state is specified or the wrong driver info is specified for power management. :raises: StorageError If the storage driver is unable to attach the configured volumes. :raises: other exceptions by the node's power driver if something wrong occurred during the power action. :raises: any boot interface's prepare_ramdisk exceptions. """ node = task.node deploy_utils.populate_storage_driver_internal_info(task) if node.provision_state in [states.ACTIVE, states.ADOPTING]: task.driver.boot.prepare_instance(task) else: if node.provision_state == states.DEPLOYING: fast_track_deploy = manager_utils.is_fast_track(task) if fast_track_deploy: # The agent has already recently checked in and we are # configured to take that as an indicator that we can # skip ahead. LOG.debug( 'The agent for node %(node)s has recently ' 'checked in, and the node power will remain ' 'unmodified.', {'node': task.node.uuid}) else: # Adding the node to provisioning network so that the dhcp # options get added for the provisioning port. manager_utils.node_power_action(task, states.POWER_OFF) # NOTE(vdrok): in case of rebuild, we have tenant network # already configured, unbind tenant ports if present if task.driver.storage.should_write_image(task): if not fast_track_deploy: power_state_to_restore = ( manager_utils.power_on_node_if_needed(task)) task.driver.network.unconfigure_tenant_networks(task) task.driver.network.add_provisioning_network(task) if not fast_track_deploy: manager_utils.restore_power_state_if_needed( task, power_state_to_restore) task.driver.storage.attach_volumes(task) if (not task.driver.storage.should_write_image(task) or fast_track_deploy): # We have nothing else to do as this is handled in the # backend storage system, and we can return to the caller # as we do not need to boot the agent to deploy. # Alternatively, we are in a fast track deployment # and have nothing else to do. return deploy_opts = deploy_utils.build_agent_options(node) task.driver.boot.prepare_ramdisk(task, deploy_opts)
def tear_down_inband_cleaning(task, manage_boot=True): """Tears down the environment setup for in-band cleaning. This method does the following: 1. Powers off the bare metal node (unless the node is fast tracked or there was a cleaning failure). 2. If 'manage_boot' parameter is set to true, it also calls the 'clean_up_ramdisk' method of boot interface to clean up the environment that was set for booting agent ramdisk. 3. Deletes the cleaning ports which were setup as part of cleaning. :param task: a TaskManager object containing the node :param manage_boot: If this is set to True, this method calls the 'clean_up_ramdisk' method of boot interface to boot the agent ramdisk. If False, it skips this step. :raises: NetworkError, NodeCleaningFailure if the cleaning ports cannot be removed. """ fast_track = manager_utils.is_fast_track(task) node = task.node cleaning_failure = (node.fault == faults.CLEAN_FAILURE) if not (fast_track or cleaning_failure): manager_utils.node_power_action(task, states.POWER_OFF) if manage_boot: task.driver.boot.clean_up_ramdisk(task) power_state_to_restore = manager_utils.power_on_node_if_needed(task) task.driver.network.remove_cleaning_network(task) if not (fast_track or cleaning_failure): manager_utils.restore_power_state_if_needed(task, power_state_to_restore)
def deploy(self, task): """Start deployment of the task's node. Fetches instance image, updates the DHCP port options for next boot, and issues a reboot request to the power driver. This causes the node to boot into the deployment ramdisk and triggers the next phase of PXE-based deployment via agent heartbeats. :param task: a TaskManager instance containing the node to act on. :returns: deploy state DEPLOYWAIT. """ node = task.node if manager_utils.is_fast_track(task): # NOTE(mgoddard): For fast track we can mostly skip this step and # proceed to the next step (i.e. write_image). LOG.debug('Performing a fast track deployment for %(node)s.', {'node': task.node.uuid}) deploy_utils.cache_instance_image(task.context, node) check_image_size(task) elif task.driver.storage.should_write_image(task): # Standard deploy process deploy_utils.cache_instance_image(task.context, node) check_image_size(task) # Check if the driver has already performed a reboot in a previous # deploy step. if not task.node.driver_internal_info.get('deployment_reboot', False): manager_utils.node_power_action(task, states.REBOOT) info = task.node.driver_internal_info info.pop('deployment_reboot', None) info.pop('deployment_uuids', None) task.node.driver_internal_info = info task.node.save() return states.DEPLOYWAIT
def deploy(self, task): """Perform a deployment to a node. Perform the necessary work to deploy an image onto the specified node. This method will be called after prepare(), which may have already performed any preparatory steps, such as pre-caching some data for the node. :param task: a TaskManager instance. :returns: status of the deploy. One of ironic.common.states. """ if manager_utils.is_fast_track(task): # NOTE(mgoddard): For fast track we can skip this step and proceed # immediately to the next deploy step. LOG.debug('Performing a fast track deployment for %(node)s.', {'node': task.node.uuid}) elif task.driver.storage.should_write_image(task): # Check if the driver has already performed a reboot in a previous # deploy step. if not task.node.driver_internal_info.get('deployment_reboot'): manager_utils.node_power_action(task, states.REBOOT) info = task.node.driver_internal_info info.pop('deployment_reboot', None) task.node.driver_internal_info = info task.node.save() return states.DEPLOYWAIT
def prepare(self, task): """Prepare the deployment environment for this task's node. Generates the TFTP configuration for PXE-booting both the deployment and user images, fetches the TFTP image from Glance and add it to the local cache. :param task: a TaskManager instance containing the node to act on. :raises: NetworkError: if the previous cleaning ports cannot be removed or if new cleaning ports cannot be created. :raises: InvalidParameterValue when the wrong power state is specified or the wrong driver info is specified for power management. :raises: StorageError If the storage driver is unable to attach the configured volumes. :raises: other exceptions by the node's power driver if something wrong occurred during the power action. :raises: any boot interface's prepare_ramdisk exceptions. """ node = task.node deploy_utils.populate_storage_driver_internal_info(task) if node.provision_state in [states.ACTIVE, states.ADOPTING]: task.driver.boot.prepare_instance(task) else: if node.provision_state == states.DEPLOYING: fast_track_deploy = manager_utils.is_fast_track(task) if fast_track_deploy: # The agent has already recently checked in and we are # configured to take that as an indicator that we can # skip ahead. LOG.debug('The agent for node %(node)s has recently ' 'checked in, and the node power will remain ' 'unmodified.', {'node': task.node.uuid}) else: # Adding the node to provisioning network so that the dhcp # options get added for the provisioning port. manager_utils.node_power_action(task, states.POWER_OFF) # NOTE(vdrok): in case of rebuild, we have tenant network # already configured, unbind tenant ports if present if task.driver.storage.should_write_image(task): if not fast_track_deploy: power_state_to_restore = ( manager_utils.power_on_node_if_needed(task)) task.driver.network.unconfigure_tenant_networks(task) task.driver.network.add_provisioning_network(task) if not fast_track_deploy: manager_utils.restore_power_state_if_needed( task, power_state_to_restore) task.driver.storage.attach_volumes(task) if (not task.driver.storage.should_write_image(task) or fast_track_deploy): # We have nothing else to do as this is handled in the # backend storage system, and we can return to the caller # as we do not need to boot the agent to deploy. # Alternatively, we are in a fast track deployment # and have nothing else to do. return deploy_opts = deploy_utils.build_agent_options(node) task.driver.boot.prepare_ramdisk(task, deploy_opts)
def prepare_cleaning(self, task): """Boot into the ramdisk to prepare for cleaning. :param task: a TaskManager object containing the node :raises NodeCleaningFailure: if the previous cleaning ports cannot be removed or if new cleaning ports cannot be created :returns: None or states.CLEANWAIT for async prepare. """ node = task.node conductor_steps.set_node_cleaning_steps(task) if not node.driver_internal_info['clean_steps']: # no clean steps configured, nothing to do. return fast_track = manager_utils.is_fast_track(task) power_state_to_restore = None if not fast_track: power_state_to_restore = manager_utils.power_on_node_if_needed( task) task.driver.network.add_cleaning_network(task) manager_utils.restore_power_state_if_needed(task, power_state_to_restore) boot_opt = deploy_utils.build_agent_options(node) task.driver.boot.prepare_ramdisk(task, boot_opt) if not fast_track: manager_utils.node_power_action(task, states.REBOOT) return states.CLEANWAIT
def deploy(self, task): """Start deployment of the task's node. Fetches instance image, updates the DHCP port options for next boot, and issues a reboot request to the power driver. This causes the node to boot into the deployment ramdisk and triggers the next phase of PXE-based deployment via agent heartbeats. :param task: a TaskManager instance containing the node to act on. :returns: deploy state DEPLOYWAIT. """ node = task.node if manager_utils.is_fast_track(task): LOG.debug('Performing a fast track deployment for %(node)s.', {'node': task.node.uuid}) deploy_utils.cache_instance_image(task.context, node) check_image_size(task) # Update the database for the API and the task tracking resumes # the state machine state going from DEPLOYWAIT -> DEPLOYING task.process_event('wait') self.continue_deploy(task) elif task.driver.storage.should_write_image(task): # Standard deploy process deploy_utils.cache_instance_image(task.context, node) check_image_size(task) # Check if the driver has already performed a reboot in a previous # deploy step. if not task.node.driver_internal_info.get('deployment_reboot', False): manager_utils.node_power_action(task, states.REBOOT) info = task.node.driver_internal_info info.pop('deployment_reboot', None) task.node.driver_internal_info = info task.node.save() return states.DEPLOYWAIT else: # Boot to an Storage Volume # TODO(TheJulia): At some point, we should de-dupe this code # as it is nearly identical to the agent deploy interface. # This is not being done now as it is expected to be # refactored in the near future. manager_utils.node_power_action(task, states.POWER_OFF) power_state_to_restore = ( manager_utils.power_on_node_if_needed(task)) task.driver.network.remove_provisioning_network(task) task.driver.network.configure_tenant_networks(task) manager_utils.restore_power_state_if_needed( task, power_state_to_restore) task.driver.boot.prepare_instance(task) manager_utils.node_power_action(task, states.POWER_ON) return None
def prepare_inband_cleaning(task, manage_boot=True): """Prepares the node to boot into agent for in-band cleaning. This method does the following: 1. Prepares the cleaning ports for the bare metal node and updates the clean parameters in node's driver_internal_info. 2. If 'manage_boot' parameter is set to true, it also calls the 'prepare_ramdisk' method of boot interface to boot the agent ramdisk. 3. Reboots the bare metal node. :param task: a TaskManager object containing the node :param manage_boot: If this is set to True, this method calls the 'prepare_ramdisk' method of boot interface to boot the agent ramdisk. If False, it skips preparing the boot agent ramdisk using boot interface, and assumes that the environment is setup to automatically boot agent ramdisk every time bare metal node is rebooted. :returns: states.CLEANWAIT to signify an asynchronous prepare. :raises: NetworkError, NodeCleaningFailure if the previous cleaning ports cannot be removed or if new cleaning ports cannot be created. :raises: InvalidParameterValue if cleaning network UUID config option has an invalid value. """ fast_track = manager_utils.is_fast_track(task) if not fast_track: power_state_to_restore = manager_utils.power_on_node_if_needed(task) # WARNING(TheJulia): When fast track is available, trying to plug the # cleaning network is problematic and in practice this may fail if # cleaning/provisioning/discovery all take place on different # networks when.. # Translation: Here be a realistically unavoidable footgun # fast track support. # TODO(TheJulia): Lets improve this somehow such that the agent host # gracefully handles these sorts of changes. task.driver.network.add_cleaning_network(task) if not fast_track: manager_utils.restore_power_state_if_needed(task, power_state_to_restore) # Append required config parameters to node's driver_internal_info # to pass to IPA. agent_add_clean_params(task) if manage_boot: ramdisk_opts = build_agent_options(task.node) task.driver.boot.prepare_ramdisk(task, ramdisk_opts) if not fast_track: manager_utils.node_power_action(task, states.REBOOT) # Tell the conductor we are waiting for the agent to boot. return states.CLEANWAIT
def deploy(self, task): """Start deployment of the task's node. Fetches instance image, updates the DHCP port options for next boot, and issues a reboot request to the power driver. This causes the node to boot into the deployment ramdisk and triggers the next phase of PXE-based deployment via agent heartbeats. :param task: a TaskManager instance containing the node to act on. :returns: deploy state DEPLOYWAIT. """ node = task.node if manager_utils.is_fast_track(task): LOG.debug('Performing a fast track deployment for %(node)s.', {'node': task.node.uuid}) deploy_utils.cache_instance_image(task.context, node) check_image_size(task) # Update the database for the API and the task tracking resumes # the state machine state going from DEPLOYWAIT -> DEPLOYING task.process_event('wait') self.continue_deploy(task) elif task.driver.storage.should_write_image(task): # Standard deploy process deploy_utils.cache_instance_image(task.context, node) check_image_size(task) manager_utils.node_power_action(task, states.REBOOT) return states.DEPLOYWAIT else: # Boot to an Storage Volume # TODO(TheJulia): At some point, we should de-dupe this code # as it is nearly identical to the agent deploy interface. # This is not being done now as it is expected to be # refactored in the near future. manager_utils.node_power_action(task, states.POWER_OFF) power_state_to_restore = ( manager_utils.power_on_node_if_needed(task)) task.driver.network.remove_provisioning_network(task) task.driver.network.configure_tenant_networks(task) manager_utils.restore_power_state_if_needed( task, power_state_to_restore) task.driver.boot.prepare_instance(task) manager_utils.node_power_action(task, states.POWER_ON) return None
def tear_down_cleaning(self, task): """Clean up the PXE and DHCP files after cleaning. :param task: a TaskManager object containing the node :raises NodeCleaningFailure: if the cleaning ports cannot be removed """ fast_track = manager_utils.is_fast_track(task) node = task.node cleaning_failure = (node.fault == faults.CLEAN_FAILURE) if not (fast_track or cleaning_failure): manager_utils.node_power_action(task, states.POWER_OFF) task.driver.boot.clean_up_ramdisk(task) power_state_to_restore = manager_utils.power_on_node_if_needed(task) task.driver.network.remove_cleaning_network(task) if not (fast_track or cleaning_failure): manager_utils.restore_power_state_if_needed( task, power_state_to_restore)
def clean_up_ramdisk(self, task): """Cleans up the boot of ironic ramdisk. This method cleans up the environment that was setup for booting the deploy ramdisk. :param task: A task from TaskManager. :returns: None """ if manager_utils.is_fast_track(task): LOG.debug( 'Fast track operation for node %s, not ejecting ' 'any devices', task.node.uuid) return LOG.debug("Cleaning up deploy boot for " "%(node)s", {'node': task.node.uuid}) self._eject_all(task)
def deploy(self, task): """Perform a deployment to a node. Perform the necessary work to deploy an image onto the specified node. This method will be called after prepare(), which may have already performed any preparatory steps, such as pre-caching some data for the node. :param task: a TaskManager instance. :returns: status of the deploy. One of ironic.common.states. """ if manager_utils.is_fast_track(task): LOG.debug('Performing a fast track deployment for %(node)s.', {'node': task.node.uuid}) # Update the database for the API and the task tracking resumes # the state machine state going from DEPLOYWAIT -> DEPLOYING task.process_event('wait') self.continue_deploy(task) elif task.driver.storage.should_write_image(task): # Check if the driver has already performed a reboot in a previous # deploy step. if not task.node.driver_internal_info.get('deployment_reboot'): manager_utils.node_power_action(task, states.REBOOT) info = task.node.driver_internal_info info.pop('deployment_reboot', None) task.node.driver_internal_info = info task.node.save() return states.DEPLOYWAIT else: # TODO(TheJulia): At some point, we should de-dupe this code # as it is nearly identical to the iscsi deploy interface. # This is not being done now as it is expected to be # refactored in the near future. manager_utils.node_power_action(task, states.POWER_OFF) power_state_to_restore = ( manager_utils.power_on_node_if_needed(task)) task.driver.network.remove_provisioning_network(task) task.driver.network.configure_tenant_networks(task) manager_utils.restore_power_state_if_needed( task, power_state_to_restore) task.driver.boot.prepare_instance(task) manager_utils.node_power_action(task, states.POWER_ON) LOG.info('Deployment to node %s done', task.node.uuid) return None
def prepare(self, task): """Prepare the deployment environment for this node.""" node = task.node # TODO(pas-ha) investigate takeover scenario if node.provision_state == states.DEPLOYING: # adding network-driver dependent provisioning ports fast_track = manager_utils.is_fast_track(task) power_state_to_restore = None if not fast_track: manager_utils.node_power_action(task, states.POWER_OFF) power_state_to_restore = ( manager_utils.power_on_node_if_needed(task)) task.driver.network.add_provisioning_network(task) manager_utils.restore_power_state_if_needed( task, power_state_to_restore) if node.provision_state not in [states.ACTIVE, states.ADOPTING]: node.instance_info = deploy_utils.build_instance_info_for_deploy( task) node.save() boot_opt = deploy_utils.build_agent_options(node) task.driver.boot.prepare_ramdisk(task, boot_opt)
def start_deploy(task, manager, configdrive=None, event='deploy'): """Start deployment or rebuilding on a node. This function does not check the node suitability for deployment, it's left up to the caller. :param task: a TaskManager instance. :param manager: a ConductorManager to run tasks on. :param configdrive: a configdrive, if requested. :param event: event to process: deploy or rebuild. """ node = task.node # Record of any pre-existing agent_url should be removed # except when we are in fast track conditions. if not utils.is_fast_track(task): utils.remove_agent_url(node) if event == 'rebuild': # Note(gilliard) Clear these to force the driver to # check whether they have been changed in glance # NOTE(vdrok): If image_source is not from Glance we should # not clear kernel and ramdisk as they're input manually if glance_utils.is_glance_image( node.instance_info.get('image_source')): instance_info = node.instance_info instance_info.pop('kernel', None) instance_info.pop('ramdisk', None) node.instance_info = instance_info driver_internal_info = node.driver_internal_info # Infer the image type to make sure the deploy driver # validates only the necessary variables for different # image types. # NOTE(sirushtim): The iwdi variable can be None. It's up to # the deploy driver to validate this. iwdi = images.is_whole_disk_image(task.context, node.instance_info) driver_internal_info['is_whole_disk_image'] = iwdi node.driver_internal_info = driver_internal_info node.save() try: task.driver.power.validate(task) task.driver.deploy.validate(task) utils.validate_instance_info_traits(task.node) conductor_steps.validate_deploy_templates(task) except exception.InvalidParameterValue as e: raise exception.InstanceDeployFailure( _("Failed to validate deploy or power info for node " "%(node_uuid)s. Error: %(msg)s") % { 'node_uuid': node.uuid, 'msg': e }, code=e.code) try: task.process_event(event, callback=manager._spawn_worker, call_args=(do_node_deploy, task, manager.conductor.id, configdrive), err_handler=utils.provisioning_error_handler) except exception.InvalidState: raise exception.InvalidStateRequested(action=event, node=task.node.uuid, state=task.node.provision_state)
def prepare(self, task): """Prepare the deployment environment for this node. :param task: a TaskManager instance. :raises: NetworkError: if the previous cleaning ports cannot be removed or if new cleaning ports cannot be created. :raises: InvalidParameterValue when the wrong power state is specified or the wrong driver info is specified for power management. :raises: StorageError If the storage driver is unable to attach the configured volumes. :raises: other exceptions by the node's power driver if something wrong occurred during the power action. :raises: exception.ImageRefValidationFailed if image_source is not Glance href and is not HTTP(S) URL. :raises: exception.InvalidParameterValue if network validation fails. :raises: any boot interface's prepare_ramdisk exceptions. """ def _update_instance_info(): node.instance_info = ( deploy_utils.build_instance_info_for_deploy(task)) node.save() node = task.node deploy_utils.populate_storage_driver_internal_info(task) if node.provision_state == states.DEPLOYING: # Validate network interface to ensure that it supports boot # options configured on the node. try: task.driver.network.validate(task) except exception.InvalidParameterValue: # For 'neutron' network interface validation will fail # if node is using 'netboot' boot option while provisioning # a whole disk image. Updating 'boot_option' in node's # 'instance_info' to 'local for backward compatibility. # TODO(stendulker): Fail here once the default boot # option is local. # NOTE(TheJulia): Fixing the default boot mode only # masks the failure as the lack of a user definition # can be perceived as both an invalid configuration and # reliance upon the default configuration. The reality # being that in most scenarios, users do not want network # booting, so the changed default should be valid. with excutils.save_and_reraise_exception(reraise=False) as ctx: instance_info = node.instance_info capabilities = utils.parse_instance_info_capabilities(node) if 'boot_option' not in capabilities: capabilities['boot_option'] = 'local' instance_info['capabilities'] = capabilities node.instance_info = instance_info node.save() # Re-validate the network interface task.driver.network.validate(task) else: ctx.reraise = True # Determine if this is a fast track sequence fast_track_deploy = manager_utils.is_fast_track(task) if fast_track_deploy: # The agent has already recently checked in and we are # configured to take that as an indicator that we can # skip ahead. LOG.debug( 'The agent for node %(node)s has recently checked ' 'in, and the node power will remain unmodified.', {'node': task.node.uuid}) else: # Powering off node to setup networking for port and # ensure that the state is reset if it is inadvertently # on for any unknown reason. manager_utils.node_power_action(task, states.POWER_OFF) if task.driver.storage.should_write_image(task): # NOTE(vdrok): in case of rebuild, we have tenant network # already configured, unbind tenant ports if present if not fast_track_deploy: power_state_to_restore = ( manager_utils.power_on_node_if_needed(task)) task.driver.network.unconfigure_tenant_networks(task) task.driver.network.add_provisioning_network(task) if not fast_track_deploy: manager_utils.restore_power_state_if_needed( task, power_state_to_restore) else: # Fast track sequence in progress _update_instance_info() # Signal to storage driver to attach volumes task.driver.storage.attach_volumes(task) if (not task.driver.storage.should_write_image(task) or fast_track_deploy): # We have nothing else to do as this is handled in the # backend storage system, and we can return to the caller # as we do not need to boot the agent to deploy. # Alternatively, we could be in a fast track deployment # and again, we should have nothing to do here. return if node.provision_state in (states.ACTIVE, states.UNRESCUING): # Call is due to conductor takeover task.driver.boot.prepare_instance(task) elif node.provision_state != states.ADOPTING: if node.provision_state not in (states.RESCUING, states.RESCUEWAIT, states.RESCUE, states.RESCUEFAIL): _update_instance_info() if CONF.agent.manage_agent_boot: deploy_opts = deploy_utils.build_agent_options(node) task.driver.boot.prepare_ramdisk(task, deploy_opts)
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of deploy or rescue ramdisk over virtual media. This method prepares the boot of the deploy or rescue ramdisk after reading relevant information from the node's driver_info and instance_info. :param task: A task from TaskManager. :param ramdisk_params: the parameters to be passed to the ramdisk. :returns: None :raises: MissingParameterValue, if some information is missing in node's driver_info or instance_info. :raises: InvalidParameterValue, if some information provided is invalid. :raises: IronicException, if some power or set boot boot device operation failed on the node. """ node = task.node # NOTE(TheJulia): If this method is being called by something # aside from deployment, clean and rescue, such as conductor takeover, # we should treat this as a no-op and move on otherwise we would # modify the state of the node due to virtual media operations. if node.provision_state not in (states.DEPLOYING, states.CLEANING, states.RESCUING, states.INSPECTING): return d_info = _parse_driver_info(node) managers = redfish_utils.get_system(task.node).managers if manager_utils.is_fast_track(task): if _has_vmedia_device(managers, sushy.VIRTUAL_MEDIA_CD, inserted=True): LOG.debug( 'Fast track operation for node %s, not inserting ' 'any devices', node.uuid) return else: LOG.warning( 'Fast track is possible for node %s, but no ISO ' 'is currently inserted! Proceeding with ' 'normal operation.', node.uuid) # NOTE(TheJulia): Since we're deploying, cleaning, or rescuing, # with virtual media boot, we should generate a token! # However, we don't have a way to inject it with a pre-built ISO # if a removable disk is not used. can_config = d_info.pop('can_provide_config', True) if can_config: manager_utils.add_secret_token(node, pregenerated=True) node.save() ramdisk_params['ipa-agent-token'] = \ node.driver_internal_info['agent_secret_token'] manager_utils.node_power_action(task, states.POWER_OFF) deploy_nic_mac = deploy_utils.get_single_nic_with_vif_port_id(task) if deploy_nic_mac is not None: ramdisk_params['BOOTIF'] = deploy_nic_mac if CONF.debug and 'ipa-debug' not in ramdisk_params: ramdisk_params['ipa-debug'] = '1' # NOTE(TheJulia): This is a mandatory setting for virtual media # based deployment operations. ramdisk_params['boot_method'] = 'vmedia' config_via_removable = d_info.get('config_via_removable') if config_via_removable: removable = _has_vmedia_device( managers, # Prefer USB devices since floppies are outdated [sushy.VIRTUAL_MEDIA_USBSTICK, sushy.VIRTUAL_MEDIA_FLOPPY]) if removable: floppy_ref = image_utils.prepare_floppy_image( task, params=ramdisk_params) _eject_vmedia(task, managers, removable) _insert_vmedia(task, managers, floppy_ref, removable) LOG.info( 'Inserted virtual %(type)s device with configuration' ' for node %(node)s', { 'node': task.node.uuid, 'type': removable }) else: LOG.warning( 'Config via a removable device is requested, but ' 'virtual USB and floppy devices are not ' 'available on node %(node)s', {'node': task.node.uuid}) mode = deploy_utils.rescue_or_deploy_mode(node) iso_ref = image_utils.prepare_deploy_iso(task, ramdisk_params, mode, d_info) _eject_vmedia(task, managers, sushy.VIRTUAL_MEDIA_CD) _insert_vmedia(task, managers, iso_ref, sushy.VIRTUAL_MEDIA_CD) del managers boot_mode_utils.sync_boot_mode(task) self._set_boot_device(task, boot_devices.CDROM) LOG.debug("Node %(node)s is set to one time boot from " "%(device)s", { 'node': task.node.uuid, 'device': boot_devices.CDROM })