def clean_up_ramdisk(self, task): """Cleans up the boot of ironic ramdisk. This method cleans up the PXE environment that was setup for booting the deploy or rescue ramdisk. It unlinks the deploy/rescue kernel/ramdisk in the node's directory in tftproot and removes it's PXE config. :param task: a task from TaskManager. :param mode: Label indicating a deploy or rescue operation was carried out on the node. Supported values are 'deploy' and 'rescue'. Defaults to 'deploy', indicating deploy operation was carried out. :returns: None """ node = task.node mode = deploy_utils.rescue_or_deploy_mode(node) try: images_info = pxe_utils.get_image_info(node, mode=mode) except exception.MissingParameterValue as e: LOG.warning('Could not get %(mode)s image info ' 'to clean up images for node %(node)s: %(err)s', {'mode': mode, 'node': node.uuid, 'err': e}) else: pxe_utils.clean_up_pxe_env(task, images_info)
def build_pxe_config_options(task, pxe_info, service=False, ipxe_enabled=False): """Build the PXE config options for a node This method builds the PXE boot options for a node, given all the required parameters. The options should then be passed to pxe_utils.create_pxe_config to create the actual config files. :param task: A TaskManager object :param pxe_info: a dict of values to set on the configuration file :param service: if True, build "service mode" pxe config for netboot-ed user image and skip adding deployment image kernel and ramdisk info to PXE options. :param ipxe_enabled: Default false boolean to indicate if ipxe is in use by the caller. :returns: A dictionary of pxe options to be used in the pxe bootfile template. """ node = task.node mode = deploy_utils.rescue_or_deploy_mode(node) if service: pxe_options = {} elif (node.driver_internal_info.get('boot_from_volume') and ipxe_enabled): pxe_options = get_volume_pxe_options(task) else: pxe_options = build_deploy_pxe_options(task, pxe_info, mode=mode, ipxe_enabled=ipxe_enabled) # NOTE(pas-ha) we still must always add user image kernel and ramdisk # info as later during switching PXE config to service mode the # template will not be regenerated anew, but instead edited as-is. # This can be changed later if/when switching PXE config will also use # proper templating instead of editing existing files on disk. pxe_options.update(build_instance_pxe_options(task, pxe_info, ipxe_enabled=ipxe_enabled)) pxe_options.update(build_extra_pxe_options()) return pxe_options
def _parse_driver_info(node): """Gets the driver specific Node deployment info. This method validates whether the 'driver_info' property of the supplied node contains the required or optional information properly for this driver to deploy images to the node. :param node: a target node of the deployment :returns: the driver_info values of the node. :raises: MissingParameterValue, if any of the required parameters are missing. :raises: InvalidParameterValue, if any of the parameters have invalid value. """ d_info = node.driver_info mode = deploy_utils.rescue_or_deploy_mode(node) params_to_check = KERNEL_RAMDISK_LABELS[mode] deploy_info = {option: d_info.get(option) for option in params_to_check} if not any(deploy_info.values()): # NOTE(dtantsur): avoid situation when e.g. deploy_kernel comes # from driver_info but deploy_ramdisk comes from configuration, # since it's a sign of a potential operator's mistake. deploy_info = {k: getattr(CONF.conductor, k) for k in params_to_check} error_msg = _("Error validating Redfish virtual media. Some " "parameters were missing in node's driver_info") deploy_utils.check_for_missing_params(deploy_info, error_msg) deploy_info.update( {option: d_info.get(option, getattr(CONF.conductor, option, None)) for option in OPTIONAL_PROPERTIES}) deploy_info.update(redfish_utils.parse_driver_info(node)) return deploy_info
def _build_pxe_config_options(task, pxe_info, service=False): """Build the PXE config options for a node This method builds the PXE boot options for a node, given all the required parameters. The options should then be passed to pxe_utils.create_pxe_config to create the actual config files. :param task: A TaskManager object :param pxe_info: a dict of values to set on the configuration file :param service: if True, build "service mode" pxe config for netboot-ed user image and skip adding deployment image kernel and ramdisk info to PXE options. :returns: A dictionary of pxe options to be used in the pxe bootfile template. """ node = task.node mode = deploy_utils.rescue_or_deploy_mode(node) if service: pxe_options = {} elif (node.driver_internal_info.get('boot_from_volume') and CONF.pxe.ipxe_enabled): pxe_options = _get_volume_pxe_options(task) else: pxe_options = _build_deploy_pxe_options(task, pxe_info, mode=mode) # NOTE(pas-ha) we still must always add user image kernel and ramdisk # info as later during switching PXE config to service mode the # template will not be regenerated anew, but instead edited as-is. # This can be changed later if/when switching PXE config will also use # proper templating instead of editing existing files on disk. pxe_options.update(_build_instance_pxe_options(task, pxe_info)) pxe_options.update(_build_extra_pxe_options()) return pxe_options
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of deploy ramdisk using 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. :raises: IloOperationError, if some operation on iLO failed. """ 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 prepare_node_for_deploy(task) # Clear ilo_boot_iso if it's a glance image to force recreate # another one again (or use existing one in glance). # This is mainly for rebuild and rescue scenario. if service_utils.is_glance_image( node.instance_info.get('image_source')): instance_info = node.instance_info instance_info.pop('ilo_boot_iso', None) node.instance_info = instance_info node.save() # Eject all virtual media devices, as we are going to use them # during boot. ilo_common.eject_vmedia_devices(task) # NOTE(TheJulia): Since we're deploying, cleaning, or rescuing, # with virtual media boot, we should generate a token! manager_utils.add_secret_token(task.node, pregenerated=True) ramdisk_params['ipa-agent-token'] = \ task.node.driver_internal_info['agent_secret_token'] task.node.save() deploy_nic_mac = deploy_utils.get_single_nic_with_vif_port_id(task) ramdisk_params['BOOTIF'] = deploy_nic_mac if (node.driver_info.get('ilo_rescue_iso') and node.provision_state == states.RESCUING): iso = node.driver_info['ilo_rescue_iso'] elif node.driver_info.get('ilo_deploy_iso'): iso = node.driver_info['ilo_deploy_iso'] else: mode = deploy_utils.rescue_or_deploy_mode(node) d_info = parse_driver_info(node, mode) use_web_server = CONF.ilo.use_web_server_for_images container = CONF.ilo.swift_ilo_container iso = virtual_media_base.prepare_deploy_iso( task, ramdisk_params, mode, d_info, use_web_server=use_web_server, container=container) ilo_common.setup_vmedia(task, iso, ramdisk_params)
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of Ironic ramdisk using PXE. This method prepares the boot of the deploy or rescue kernel/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. pxe driver passes these parameters as kernel command-line arguments. :param mode: Label indicating a deploy or rescue operation being carried out on the node. Supported values are 'deploy' and 'rescue'. Defaults to 'deploy', indicating deploy operation is being carried out. :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 mode = deploy_utils.rescue_or_deploy_mode(node) if CONF.pxe.ipxe_enabled: # NOTE(mjturek): At this point, the ipxe boot script should # already exist as it is created at startup time. However, we # call the boot script create method here to assert its # existence and handle the unlikely case that it wasn't created # or was deleted. pxe_utils.create_ipxe_boot_script() dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) pxe_info = _get_image_info(node, mode=mode) # NODE: Try to validate and fetch instance images only # if we are in DEPLOYING state. if node.provision_state == states.DEPLOYING: pxe_info.update(_get_instance_image_info(node, task.context)) pxe_options = _build_pxe_config_options(task, pxe_info) pxe_options.update(ramdisk_params) pxe_config_template = deploy_utils.get_pxe_config_template(node) pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template) persistent = strutils.bool_from_string( node.driver_info.get('force_persistent_boot_device', False)) manager_utils.node_set_boot_device(task, boot_devices.PXE, persistent=persistent) if CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_use_swift: kernel_label = '%s_kernel' % mode ramdisk_label = '%s_ramdisk' % mode pxe_info.pop(kernel_label, None) pxe_info.pop(ramdisk_label, None) if pxe_info: _cache_ramdisk_kernel(task.context, node, pxe_info)
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 manager_utils.node_power_action(task, states.POWER_OFF) d_info = self._parse_driver_info(node) config_via_floppy = d_info.get('config_via_floppy') deploy_nic_mac = deploy_utils.get_single_nic_with_vif_port_id(task) ramdisk_params['BOOTIF'] = deploy_nic_mac if CONF.debug and 'ipa-debug' not in ramdisk_params: ramdisk_params['ipa-debug'] = '1' if config_via_floppy: if self._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(task, params=ramdisk_params) self._eject_vmedia(task, sushy.VIRTUAL_MEDIA_FLOPPY) self._insert_vmedia(task, floppy_ref, sushy.VIRTUAL_MEDIA_FLOPPY) LOG.debug( 'Inserted virtual floppy with configuration for ' 'node %(node)s', {'node': task.node.uuid}) else: LOG.warning( 'Config via floppy is requested, but ' 'Floppy drive is not available on node ' '%(node)s', {'node': task.node.uuid}) mode = deploy_utils.rescue_or_deploy_mode(node) iso_ref = self._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) 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 })
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of Ironic ramdisk using PXE. This method prepares the boot of the deploy or rescue kernel/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. pxe driver passes these parameters as kernel command-line arguments. :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 # Label indicating a deploy or rescue operation being carried out on # the node, 'deploy' or 'rescue'. Unless the node is in a rescue like # state, the mode is set to 'deploy', indicating deploy operation is # being carried out. mode = deploy_utils.rescue_or_deploy_mode(node) ipxe_enabled = CONF.pxe.ipxe_enabled if ipxe_enabled: # NOTE(mjturek): At this point, the ipxe boot script should # already exist as it is created at startup time. However, we # call the boot script create method here to assert its # existence and handle the unlikely case that it wasn't created # or was deleted. pxe_utils.create_ipxe_boot_script() dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=ipxe_enabled) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) pxe_info = pxe_utils.get_image_info(node, mode=mode) # NODE: Try to validate and fetch instance images only # if we are in DEPLOYING state. if node.provision_state == states.DEPLOYING: pxe_info.update(pxe_utils.get_instance_image_info(task)) boot_mode_utils.sync_boot_mode(task) pxe_options = pxe_utils.build_pxe_config_options( task, pxe_info, ipxe_enabled=ipxe_enabled, ramdisk_params=ramdisk_params) # TODO(dtantsur): backwards compability hack, remove in the V release if ramdisk_params.get("ipa-api-url"): pxe_options["ipa-api-url"] = ramdisk_params["ipa-api-url"] pxe_config_template = deploy_utils.get_pxe_config_template(node) pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template, ipxe_enabled=CONF.pxe.ipxe_enabled) persistent = self._persistent_ramdisk_boot(node) manager_utils.node_set_boot_device(task, boot_devices.PXE, persistent=persistent) if CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_use_swift: kernel_label = '%s_kernel' % mode ramdisk_label = '%s_ramdisk' % mode pxe_info.pop(kernel_label, None) pxe_info.pop(ramdisk_label, None) if pxe_info: pxe_utils.cache_ramdisk_kernel(task, pxe_info, ipxe_enabled=CONF.pxe.ipxe_enabled) LOG.debug( 'Ramdisk PXE boot for node %(node)s has been prepared ' 'with kernel params %(params)s', { 'node': node.uuid, 'params': pxe_options })
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 })
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of Ironic ramdisk using PXE. This method prepares the boot of the deploy or rescue kernel/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. pxe driver passes these parameters as kernel command-line arguments. :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 # Label indicating a deploy or rescue operation being carried out on # the node, 'deploy' or 'rescue'. Unless the node is in a rescue like # state, the mode is set to 'deploy', indicating deploy operation is # being carried out. mode = deploy_utils.rescue_or_deploy_mode(node) # NOTE(mjturek): At this point, the ipxe boot script should # already exist as it is created at startup time. However, we # call the boot script create method here to assert its # existence and handle the unlikely case that it wasn't created # or was deleted. pxe_utils.create_ipxe_boot_script() dhcp_opts = pxe_utils.dhcp_options_for_instance( task, ipxe_enabled=True) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) pxe_info = pxe_utils.get_image_info(node, mode=mode, ipxe_enabled=True) # NODE: Try to validate and fetch instance images only # if we are in DEPLOYING state. if node.provision_state == states.DEPLOYING: pxe_info.update( pxe_utils.get_instance_image_info(task, ipxe_enabled=True)) boot_mode_utils.sync_boot_mode(task) pxe_options = pxe_utils.build_pxe_config_options(task, pxe_info, ipxe_enabled=True) pxe_options.update(ramdisk_params) pxe_config_template = deploy_utils.get_pxe_config_template(node) pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template, ipxe_enabled=True) persistent = False value = node.driver_info.get('force_persistent_boot_device', 'Default') if value in {'Always', 'Default', 'Never'}: if value == 'Always': persistent = True else: persistent = strutils.bool_from_string(value, False) manager_utils.node_set_boot_device(task, boot_devices.PXE, persistent=persistent) if CONF.pxe.ipxe_use_swift: kernel_label = '%s_kernel' % mode ramdisk_label = '%s_ramdisk' % mode pxe_info.pop(kernel_label, None) pxe_info.pop(ramdisk_label, None) if pxe_info: pxe_utils.cache_ramdisk_kernel(task, pxe_info, ipxe_enabled=True)