def reboot_to_instance(self, task): node = task.node try: # anaconda deploy will install the bootloader and the node is ready # to boot from disk. deploy_utils.try_set_boot_device(task, boot_devices.DISK) except Exception as e: msg = (_("Failed to change the boot device to %(boot_dev)s " "when deploying node %(node)s. Error: %(error)s") % { 'boot_dev': boot_devices.DISK, 'node': node.uuid, 'error': e }) agent_base.log_and_raise_deployment_error(task, msg) try: self.clean_up(task) manager_utils.node_power_action(task, states.POWER_OFF) task.driver.network.remove_provisioning_network(task) task.driver.network.configure_tenant_networks(task) manager_utils.node_power_action(task, states.POWER_ON) node.provision_state = states.ACTIVE node.save() except Exception as e: msg = (_('Error rebooting node %(node)s after deploy. ' 'Error: %(error)s') % { 'node': node.uuid, 'error': e }) agent_base.log_and_raise_deployment_error(task, msg)
def prepare_instance(self, task): """Prepares the boot of instance. This method prepares the boot of the instance after reading relevant information from the node's instance_info. In case of netboot, it updates the dhcp entries and switches the PXE config. In case of localboot, it cleans up the PXE config. :param task: a task from TaskManager. :returns: None """ node = task.node boot_option = deploy_utils.get_boot_option(node) boot_device = None if boot_option != "local": # Make sure that the instance kernel/ramdisk is cached. # This is for the takeover scenario for active nodes. instance_image_info = _get_instance_image_info( task.node, task.context) _cache_ramdisk_kernel(task.context, task.node, instance_image_info) # If it's going to PXE boot we need to update the DHCP server dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) iwdi = task.node.driver_internal_info.get('is_whole_disk_image') try: root_uuid_or_disk_id = task.node.driver_internal_info[ 'root_uuid_or_disk_id'] except KeyError: if not iwdi: LOG.warning( _LW("The UUID for the root partition can't be " "found, unable to switch the pxe config from " "deployment mode to service (boot) mode for " "node %(node)s"), {"node": task.node.uuid}) else: LOG.warning( _LW("The disk id for the whole disk image can't " "be found, unable to switch the pxe config " "from deployment mode to service (boot) mode " "for node %(node)s"), {"node": task.node.uuid}) else: _build_service_pxe_config(task, instance_image_info, root_uuid_or_disk_id) boot_device = boot_devices.PXE else: # If it's going to boot from the local disk, we don't need # PXE config files. They still need to be generated as part # of the prepare() because the deployment does PXE boot the # deploy ramdisk pxe_utils.clean_up_pxe_config(task) boot_device = boot_devices.DISK # NOTE(pas-ha) do not re-set boot device on ACTIVE nodes # during takeover if boot_device and task.node.provision_state != states.ACTIVE: deploy_utils.try_set_boot_device(task, boot_device)
def deploy(self, task): """Start deployment of the task's node'. Fetches instance image, creates a temporary keystone token file, 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 VendorPassthru.pass_deploy_info(). :param task: a TaskManager instance containing the node to act on. :returns: deploy state DEPLOYWAIT. """ iscsi_deploy.cache_instance_image(task.context, task.node) iscsi_deploy.check_image_size(task) # TODO(yuriyz): more secure way needed for pass auth token # to deploy ramdisk _create_token_file(task) dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) deploy_utils.try_set_boot_device(task, boot_devices.PXE) manager_utils.node_power_action(task, states.REBOOT) return states.DEPLOYWAIT
def pxeauto(self, task, data): task.upgrade_lock() node = task.node LOG.info( 'Pxeauto info for node %(node)s with ' 'progress info %(data)s', { 'node': node.uuid, 'data': data }) # Parse progress info title = data['Title'] progress = float(data['InstallProgress']) * 100 LOG.info('data[\'InstallProgress\']: %s', data['InstallProgress']) LOG.info('progress: %f', progress) if progress == 60: task.process_event('resume') LOG.info('resume...') if progress == 100: deploy_utils.try_set_boot_device(task, boot_devices.DISK) manager_utils.node_power_action(task, states.REBOOT) ret = self.check_conn(node.instance_info.get('management_ip'), 22) if ret == 'success': task.process_event('done') LOG.info(_LI('Deployment to node %s done'), task.node.uuid)
def deploy(self, task): """Start deployment of the task's node'. Fetches instance image, creates a temporary keystone token file, 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 VendorPassthru.pass_deploy_info(). :param task: a TaskManager instance containing the node to act on. :returns: deploy state DEPLOYWAIT. """ iscsi_deploy.cache_instance_image(task.context, task.node) iscsi_deploy.check_image_size(task) # TODO(yuriyz): more secure way needed for pass auth token # to deploy ramdisk _create_token_file(task) dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) deploy_utils.try_set_boot_device(task, boot_devices.PXE) manager_utils.node_power_action(task, states.REBOOT) return states.DEPLOYWAIT
def pass_deploy_info(self, task, **kwargs): """Continues the deployment of baremetal node over iSCSI. This method continues the deployment of the baremetal node over iSCSI from where the deployment ramdisk has left off. :param task: a TaskManager instance containing the node to act on. :param kwargs: kwargs for performing iscsi deployment. :raises: InvalidState """ node = task.node task.process_event('resume') _destroy_token_file(node) is_whole_disk_image = node.driver_internal_info['is_whole_disk_image'] uuid_dict = iscsi_deploy.continue_deploy(task, **kwargs) root_uuid_or_disk_id = uuid_dict.get( 'root uuid', uuid_dict.get('disk identifier')) # save the node's root disk UUID so that another conductor could # rebuild the PXE config file. Due to a shortcoming in Nova objects, # we have to assign to node.driver_internal_info so the node knows it # has changed. driver_internal_info = node.driver_internal_info driver_internal_info['root_uuid_or_disk_id'] = root_uuid_or_disk_id node.driver_internal_info = driver_internal_info node.save() try: if iscsi_deploy.get_boot_option(node) == "local": deploy_utils.try_set_boot_device(task, boot_devices.DISK) # If it's going to boot from the local disk, get rid of # the PXE configuration files used for the deployment pxe_utils.clean_up_pxe_config(task) # Ask the ramdisk to install bootloader and # wait for the call-back through the vendor passthru # 'pass_bootloader_install_info', if it's not a # whole disk image. if not is_whole_disk_image: deploy_utils.notify_ramdisk_to_proceed(kwargs['address']) task.process_event('wait') return else: pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid) boot_mode = deploy_utils.get_boot_mode_for_deploy(node) deploy_utils.switch_pxe_config(pxe_config_path, root_uuid_or_disk_id, boot_mode, is_whole_disk_image) except Exception as e: LOG.error(_LE('Deploy failed for instance %(instance)s. ' 'Error: %(error)s'), {'instance': node.instance_uuid, 'error': e}) msg = _('Failed to continue iSCSI deployment.') deploy_utils.set_failed_state(task, msg) else: iscsi_deploy.finish_deploy(task, kwargs.get('address'))
def prepare(self, task): # No need to update dhcp with standalone mode self._create_auto_config(task) self._create_pxe_config(task) deploy_utils.try_set_boot_device(task, boot_devices.PXE)
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of Ironic ramdisk using PXE. This method prepares the boot of the deploy 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 if CONF.pxe.ipxe_enabled: # Copy the iPXE boot script to HTTP root directory bootfile_path = os.path.join( CONF.deploy.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) if (not os.path.isfile(bootfile_path) or not filecmp.cmp(CONF.pxe.ipxe_boot_script, bootfile_path)): shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path) dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) pxe_info = _get_deploy_image_info(node) # 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) if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi': pxe_config_template = CONF.pxe.uefi_pxe_config_template else: pxe_config_template = CONF.pxe.pxe_config_template pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template) deploy_utils.try_set_boot_device(task, boot_devices.PXE) if CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_use_swift: pxe_info.pop('deploy_kernel', None) pxe_info.pop('deploy_ramdisk', None) if pxe_info: _cache_ramdisk_kernel(task.context, node, pxe_info)
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of Ironic ramdisk using PXE. This method prepares the boot of the deploy 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 # TODO(deva): optimize this if rerun on existing files if CONF.pxe.ipxe_enabled: # Copy the iPXE boot script to HTTP root directory bootfile_path = os.path.join( CONF.deploy.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path) dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) pxe_info = _get_deploy_image_info(node) # 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) if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi': pxe_config_template = CONF.pxe.uefi_pxe_config_template else: pxe_config_template = _get_pxe_conf_option(task, 'pxe_config_template') pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template) deploy_utils.try_set_boot_device(task, boot_devices.PXE) # FIXME(lucasagomes): If it's local boot we should not cache # the image kernel and ramdisk (Or even require it). _cache_ramdisk_kernel(task.context, node, pxe_info)
def configure_local_boot(self, task, root_uuid=None, efi_system_part_uuid=None): """Helper method to configure local boot on the node. This method triggers bootloader installation on the node. On successful installation of bootloader, this method sets the node to boot from disk. :param task: a TaskManager object containing the node :param root_uuid: The UUID of the root partition. This is used for identifying the partition which contains the image deployed or None in case of whole disk images which we expect to already have a bootloader installed. :param efi_system_part_uuid: The UUID of the efi system partition. This is used only in uefi boot mode. :raises: InstanceDeployFailure if bootloader installation failed or on encountering error while setting the boot device on the node. """ node = task.node LOG.debug('Configuring local boot for node %s', node.uuid) if not node.driver_internal_info.get( 'is_whole_disk_image') and root_uuid: LOG.debug( 'Installing the bootloader for node %(node)s on ' 'partition %(part)s, EFI system partition %(efi)s', { 'node': node.uuid, 'part': root_uuid, 'efi': efi_system_part_uuid }) result = self._client.install_bootloader( node, root_uuid=root_uuid, efi_system_part_uuid=efi_system_part_uuid) if result['command_status'] == 'FAILED': msg = (_("Failed to install a bootloader when " "deploying node %(node)s. Error: %(error)s") % { 'node': node.uuid, 'error': result['command_error'] }) self._log_and_raise_deployment_error(task, msg) try: deploy_utils.try_set_boot_device(task, boot_devices.DISK) except Exception as e: msg = (_("Failed to change the boot device to %(boot_dev)s " "when deploying node %(node)s. Error: %(error)s") % { 'boot_dev': boot_devices.DISK, 'node': node.uuid, 'error': e }) self._log_and_raise_deployment_error(task, msg) LOG.info(_LI('Local boot successfully configured for node %s'), node.uuid)
def configure_local_boot(self, task, root_uuid=None, efi_system_part_uuid=None, prep_boot_part_uuid=None): """Helper method to configure local boot on the node. This method triggers bootloader installation on the node. On successful installation of bootloader, this method sets the node to boot from disk. :param task: a TaskManager object containing the node :param root_uuid: The UUID of the root partition. This is used for identifying the partition which contains the image deployed or None in case of whole disk images which we expect to already have a bootloader installed. :param efi_system_part_uuid: The UUID of the efi system partition. This is used only in uefi boot mode. :param prep_boot_part_uuid: The UUID of the PReP Boot partition. This is used only for booting ppc64* hardware. :raises: InstanceDeployFailure if bootloader installation failed or on encountering error while setting the boot device on the node. """ node = task.node LOG.debug('Configuring local boot for node %s', node.uuid) if not node.driver_internal_info.get( 'is_whole_disk_image') and root_uuid: LOG.debug('Installing the bootloader for node %(node)s on ' 'partition %(part)s, EFI system partition %(efi)s', {'node': node.uuid, 'part': root_uuid, 'efi': efi_system_part_uuid}) result = self._client.install_bootloader( node, root_uuid=root_uuid, efi_system_part_uuid=efi_system_part_uuid, prep_boot_part_uuid=prep_boot_part_uuid) if result['command_status'] == 'FAILED': msg = (_("Failed to install a bootloader when " "deploying node %(node)s. Error: %(error)s") % {'node': node.uuid, 'error': result['command_error']}) log_and_raise_deployment_error(task, msg) try: persistent = True if node.driver_info.get('force_persistent_boot_device', 'Default') == 'Never': persistent = False deploy_utils.try_set_boot_device(task, boot_devices.DISK, persistent=persistent) except Exception as e: msg = (_("Failed to change the boot device to %(boot_dev)s " "when deploying node %(node)s. Error: %(error)s") % {'boot_dev': boot_devices.DISK, 'node': node.uuid, 'error': e}) log_and_raise_deployment_error(task, msg, exc=e) LOG.info('Local boot successfully configured for node %s', node.uuid)
def pass_deploy_info(self, task, **kwargs): """Continues the deployment of baremetal node over iSCSI. This method continues the deployment of the baremetal node over iSCSI from where the deployment ramdisk has left off. :param task: a TaskManager instance containing the node to act on. :param kwargs: kwargs for performing iscsi deployment. :raises: InvalidState """ node = task.node LOG.warning(_LW("The node %s is using the bash deploy ramdisk for " "its deployment. This deploy ramdisk has been " "deprecated. Please use the ironic-python-agent " "(IPA) ramdisk instead."), node.uuid) task.process_event('resume') LOG.debug('Continuing the deployment on node %s', node.uuid) is_whole_disk_image = node.driver_internal_info['is_whole_disk_image'] uuid_dict_returned = continue_deploy(task, **kwargs) root_uuid_or_disk_id = uuid_dict_returned.get( 'root uuid', uuid_dict_returned.get('disk identifier')) # save the node's root disk UUID so that another conductor could # rebuild the PXE config file. Due to a shortcoming in Nova objects, # we have to assign to node.driver_internal_info so the node knows it # has changed. driver_internal_info = node.driver_internal_info driver_internal_info['root_uuid_or_disk_id'] = root_uuid_or_disk_id node.driver_internal_info = driver_internal_info node.save() try: if deploy_utils.get_boot_option(node) == "local": deploy_utils.try_set_boot_device(task, boot_devices.DISK) if not is_whole_disk_image: LOG.debug('Installing the bootloader on node %s', node.uuid) deploy_utils.notify_ramdisk_to_proceed(kwargs['address']) task.process_event('wait') return task.driver.boot.prepare_instance(task) except Exception as e: LOG.error(_LE('Deploy failed for instance %(instance)s. ' 'Error: %(error)s'), {'instance': node.instance_uuid, 'error': e}) msg = _('Failed to continue iSCSI deployment.') deploy_utils.set_failed_state(task, msg) else: finish_deploy(task, kwargs.get('address'))
def configure_local_boot(self, task, root_uuid=None, efi_system_part_uuid=None): """Helper method to configure local boot on the node. This method triggers bootloader installation on the node. On successful installation of bootloader, this method sets the node to boot from disk. :param task: a TaskManager object containing the node :param root_uuid: The UUID of the root partition. This is used for identifying the partition which contains the image deployed or None in case of whole disk images which we expect to already have a bootloader installed. :param efi_system_part_uuid: The UUID of the efi system partition. This is used only in uefi boot mode. :raises: InstanceDeployFailure if bootloader installation failed or on encountering error while setting the boot device on the node. """ node = task.node LOG.debug("Configuring local boot for node %s", node.uuid) if not node.driver_internal_info.get("is_whole_disk_image") and root_uuid: LOG.debug( "Installing the bootloader for node %(node)s on ", "partition %(part)s, EFI system partition %(efi)s", {"node": node.uuid, "part": root_uuid, "efi": efi_system_part_uuid}, ) result = self._client.install_bootloader( node, root_uuid=root_uuid, efi_system_part_uuid=efi_system_part_uuid ) if result["command_status"] == "FAILED": msg = _("Failed to install a bootloader when " "deploying node %(node)s. Error: %(error)s") % { "node": node.uuid, "error": result["command_error"], } self._log_and_raise_deployment_error(task, msg) try: deploy_utils.try_set_boot_device(task, boot_devices.DISK) except Exception as e: msg = _( "Failed to change the boot device to %(boot_dev)s " "when deploying node %(node)s. Error: %(error)s" ) % {"boot_dev": boot_devices.DISK, "node": node.uuid, "error": e} self._log_and_raise_deployment_error(task, msg) LOG.info(_LI("Local boot successfully configured for node %s"), node.uuid)
def configure_local_boot(self, task, root_uuid=None, efi_system_part_uuid=None): """Helper method to configure local boot on the node. This method triggers bootloader installation on the node. On successful installation of bootloader, this method sets the node to boot from disk. :param task: a TaskManager object containing the node :param root_uuid: The UUID of the root partition. This is used for identifying the partition which contains the image deployed or None in case of whole disk images which we expect to already have a bootloader installed. :param efi_system_part_uuid: The UUID of the efi system partition. This is used only in uefi boot mode. :raises: InstanceDeployFailure if bootloader installation failed or on encountering error while setting the boot device on the node. """ node = task.node if not node.driver_internal_info.get( 'is_whole_disk_image') and root_uuid: LOG.debug('Installing the bootloader on node %s', node.uuid) result = self._client.install_bootloader( node, root_uuid=root_uuid, efi_system_part_uuid=efi_system_part_uuid) if result['command_status'] == 'FAILED': msg = (_("Failed to install a bootloader when " "deploying node %(node)s. Error: %(error)s") % {'node': node.uuid, 'error': result['command_error']}) self._log_and_raise_deployment_error(task, msg) try: deploy_utils.try_set_boot_device(task, boot_devices.DISK) except Exception as e: msg = (_("Failed to change the boot device to %(boot_dev)s " "when deploying node %(node)s. Error: %(error)s") % {'boot_dev': boot_devices.DISK, 'node': node.uuid, 'error': e}) self._log_and_raise_deployment_error(task, msg) LOG.info(_LI('Bootloader successfully installed on node %s'), node.uuid)
def prepare_ramdisk(self, task, ramdisk_params): node = task.node # TODO(deva): optimize this if rerun on existing files if CONF.pxe.ipxe_enabled: # Copy the iPXE boot script to HTTP root directory bootfile_path = os.path.join( CONF.deploy.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path) prov_ip = self._plug_provisioning(task) task.ports = objects.Port.list_by_node_id(task.context, node.id) pxe_info = pxe._get_deploy_image_info(node) # 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._get_instance_image_info(node, task.context)) pxe_options = pxe._build_pxe_config_options(task, pxe_info) pxe_options.update(ramdisk_params) pxe_options['advertise_host'] = prov_ip if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi': pxe_config_template = CONF.pxe.uefi_pxe_config_template else: pxe_config_template = CONF.pxe.pxe_config_template pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template) deploy_utils.try_set_boot_device(task, boot_devices.PXE) # FIXME(lucasagomes): If it's local boot we should not cache # the image kernel and ramdisk (Or even require it). pxe._cache_ramdisk_kernel(task.context, node, pxe_info)
def prepare_instance(self, task): """Prepares the boot of instance. This method prepares the boot of the instance after reading relevant information from the node's instance_info. In case of netboot, it updates the dhcp entries and switches the PXE config. In case of localboot, it cleans up the PXE config. :param task: a task from TaskManager. :returns: None """ node = task.node boot_option = deploy_utils.get_boot_option(node) if boot_option != "local": # Make sure that the instance kernel/ramdisk is cached. # This is for the takeover scenario for active nodes. instance_image_info = _get_instance_image_info( task.node, task.context) _cache_ramdisk_kernel(task.context, task.node, instance_image_info) # If it's going to PXE boot we need to update the DHCP server dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) iwdi = task.node.driver_internal_info.get('is_whole_disk_image') try: root_uuid_or_disk_id = task.node.driver_internal_info[ 'root_uuid_or_disk_id' ] except KeyError: if not iwdi: LOG.warning( _LW("The UUID for the root partition can't be " "found, unable to switch the pxe config from " "deployment mode to service (boot) mode for " "node %(node)s"), {"node": task.node.uuid}) else: LOG.warning( _LW("The disk id for the whole disk image can't " "be found, unable to switch the pxe config " "from deployment mode to service (boot) mode " "for node %(node)s"), {"node": task.node.uuid}) else: pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid) deploy_utils.switch_pxe_config( pxe_config_path, root_uuid_or_disk_id, deploy_utils.get_boot_mode_for_deploy(node), iwdi, deploy_utils.is_trusted_boot_requested(node)) # In case boot mode changes from bios to uefi, boot device # order may get lost in some platforms. Better to re-apply # boot device. deploy_utils.try_set_boot_device(task, boot_devices.PXE) else: # If it's going to boot from the local disk, we don't need # PXE config files. They still need to be generated as part # of the prepare() because the deployment does PXE boot the # deploy ramdisk pxe_utils.clean_up_pxe_config(task) deploy_utils.try_set_boot_device(task, boot_devices.DISK)
def prepare_ramdisk(self, task, ramdisk_params): """Prepares the boot of Ironic ramdisk using PXE. This method prepares the boot of the deploy 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 if CONF.pxe.ipxe_enabled: # Render the iPXE boot script template and save it # to HTTP root directory boot_script = utils.render_template( CONF.pxe.ipxe_boot_script, {'ipxe_for_mac_uri': pxe_utils.PXE_CFG_DIR_NAME + '/'}) bootfile_path = os.path.join( CONF.deploy.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) # NOTE(pas-ha) to prevent unneeded writes, # only write to file if its content is different from required, # which should be rather rare if (not os.path.isfile(bootfile_path) or not utils.file_has_content(bootfile_path, boot_script)): utils.write_to_file(bootfile_path, boot_script) dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) pxe_info = _get_deploy_image_info(node) # 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) deploy_utils.try_set_boot_device(task, boot_devices.PXE) if CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_use_swift: pxe_info.pop('deploy_kernel', None) pxe_info.pop('deploy_ramdisk', None) if pxe_info: _cache_ramdisk_kernel(task.context, node, pxe_info)
def configure_local_boot(self, task, root_uuid=None, efi_system_part_uuid=None, prep_boot_part_uuid=None): """Helper method to configure local boot on the node. This method triggers bootloader installation on the node. On successful installation of bootloader, this method sets the node to boot from disk. :param task: a TaskManager object containing the node :param root_uuid: The UUID of the root partition. This is used for identifying the partition which contains the image deployed or None in case of whole disk images which we expect to already have a bootloader installed. :param efi_system_part_uuid: The UUID of the efi system partition. This is used only in uefi boot mode. :param prep_boot_part_uuid: The UUID of the PReP Boot partition. This is used only for booting ppc64* hardware. :raises: InstanceDeployFailure if bootloader installation failed or on encountering error while setting the boot device on the node. """ node = task.node LOG.debug('Configuring local boot for node %s', node.uuid) # If the target RAID configuration is set to 'software' for the # 'controller', we need to trigger the installation of grub on # the holder disks of the desired Software RAID. internal_info = node.driver_internal_info raid_config = node.target_raid_config logical_disks = raid_config.get('logical_disks', []) software_raid = False for logical_disk in logical_disks: if logical_disk.get('controller') == 'software': LOG.debug('Node %s has a Software RAID configuration', node.uuid) software_raid = True break # For software RAID try to get the UUID of the root fs from the # image's metadata (via Glance). Fall back to the driver internal # info in case it is not available (e.g. not set or there's no Glance). if software_raid: image_source = node.instance_info.get('image_source') try: context = task.context context.is_admin = True glance = image_service.GlanceImageService( context=context) image_info = glance.show(image_source) image_properties = image_info.get('properties') root_uuid = image_properties['rootfs_uuid'] LOG.debug('Got rootfs_uuid from Glance: %s ' '(node %s)', root_uuid, node.uuid) except Exception as e: LOG.warning('Could not get \'rootfs_uuid\' property for ' 'image %(image)s from Glance for node %(node)s. ' '%(cls)s: %(error)s.', {'image': image_source, 'node': node.uuid, 'cls': e.__class__.__name__, 'error': e}) root_uuid = internal_info.get('root_uuid_or_disk_id') LOG.debug('Got rootfs_uuid from driver internal info: ' '%s (node %s)', root_uuid, node.uuid) # For whole disk images it is not necessary that the root_uuid # be provided since the bootloaders on the disk will be used whole_disk_image = internal_info.get('is_whole_disk_image') if (software_raid or (root_uuid and not whole_disk_image) or (whole_disk_image and boot_mode_utils.get_boot_mode(node) == 'uefi')): LOG.debug('Installing the bootloader for node %(node)s on ' 'partition %(part)s, EFI system partition %(efi)s', {'node': node.uuid, 'part': root_uuid, 'efi': efi_system_part_uuid}) result = self._client.install_bootloader( node, root_uuid=root_uuid, efi_system_part_uuid=efi_system_part_uuid, prep_boot_part_uuid=prep_boot_part_uuid) if result['command_status'] == 'FAILED': if not whole_disk_image: msg = (_("Failed to install a bootloader when " "deploying node %(node)s. Error: %(error)s") % {'node': node.uuid, 'error': result['command_error']}) log_and_raise_deployment_error(task, msg) else: # Its possible the install will fail if the IPA image # has not been updated, log this and continue LOG.info('Could not install bootloader for whole disk ' 'image for node %(node)s, Error: %(error)s"', {'node': node.uuid, 'error': result['command_error']}) return try: persistent = True if node.driver_info.get('force_persistent_boot_device', 'Default') == 'Never': persistent = False deploy_utils.try_set_boot_device(task, boot_devices.DISK, persistent=persistent) except Exception as e: msg = (_("Failed to change the boot device to %(boot_dev)s " "when deploying node %(node)s. Error: %(error)s") % {'boot_dev': boot_devices.DISK, 'node': node.uuid, 'error': e}) log_and_raise_deployment_error(task, msg, exc=e) LOG.info('Local boot successfully configured for node %s', node.uuid)
def configure_local_boot(self, task, root_uuid=None, efi_system_part_uuid=None, prep_boot_part_uuid=None): """Helper method to configure local boot on the node. This method triggers bootloader installation on the node. On successful installation of bootloader, this method sets the node to boot from disk. :param task: a TaskManager object containing the node :param root_uuid: The UUID of the root partition. This is used for identifying the partition which contains the image deployed or None in case of whole disk images which we expect to already have a bootloader installed. :param efi_system_part_uuid: The UUID of the efi system partition. This is used only in uefi boot mode. :param prep_boot_part_uuid: The UUID of the PReP Boot partition. This is used only for booting ppc64* hardware. :raises: InstanceDeployFailure if bootloader installation failed or on encountering error while setting the boot device on the node. """ node = task.node LOG.debug('Configuring local boot for node %s', node.uuid) # If the target RAID configuration is set to 'software' for the # 'controller', we need to trigger the installation of grub on # the holder disks of the desired Software RAID. internal_info = node.driver_internal_info raid_config = node.target_raid_config logical_disks = raid_config.get('logical_disks', []) software_raid = False for logical_disk in logical_disks: if logical_disk['controller'] == 'software': LOG.debug('Node %s has a Software RAID configuration', node.uuid) software_raid = True root_uuid = internal_info.get('root_uuid_or_disk_id') break whole_disk_image = internal_info.get('is_whole_disk_image') if software_raid or (root_uuid and not whole_disk_image): LOG.debug('Installing the bootloader for node %(node)s on ' 'partition %(part)s, EFI system partition %(efi)s', {'node': node.uuid, 'part': root_uuid, 'efi': efi_system_part_uuid}) result = self._client.install_bootloader( node, root_uuid=root_uuid, efi_system_part_uuid=efi_system_part_uuid, prep_boot_part_uuid=prep_boot_part_uuid) if result['command_status'] == 'FAILED': msg = (_("Failed to install a bootloader when " "deploying node %(node)s. Error: %(error)s") % {'node': node.uuid, 'error': result['command_error']}) log_and_raise_deployment_error(task, msg) try: persistent = True if node.driver_info.get('force_persistent_boot_device', 'Default') == 'Never': persistent = False deploy_utils.try_set_boot_device(task, boot_devices.DISK, persistent=persistent) except Exception as e: msg = (_("Failed to change the boot device to %(boot_dev)s " "when deploying node %(node)s. Error: %(error)s") % {'boot_dev': boot_devices.DISK, 'node': node.uuid, 'error': e}) log_and_raise_deployment_error(task, msg, exc=e) LOG.info('Local boot successfully configured for node %s', node.uuid)
def pass_deploy_info(self, task, **kwargs): """Continues the deployment of baremetal node over iSCSI. This method continues the deployment of the baremetal node over iSCSI from where the deployment ramdisk has left off. :param task: a TaskManager instance containing the node to act on. :param kwargs: kwargs for performing iscsi deployment. :raises: InvalidState """ node = task.node task.process_event('resume') LOG.debug('Continuing the deployment on node %s', node.uuid) _destroy_token_file(node) is_whole_disk_image = node.driver_internal_info['is_whole_disk_image'] uuid_dict = iscsi_deploy.continue_deploy(task, **kwargs) root_uuid_or_disk_id = uuid_dict.get('root uuid', uuid_dict.get('disk identifier')) # save the node's root disk UUID so that another conductor could # rebuild the PXE config file. Due to a shortcoming in Nova objects, # we have to assign to node.driver_internal_info so the node knows it # has changed. driver_internal_info = node.driver_internal_info driver_internal_info['root_uuid_or_disk_id'] = root_uuid_or_disk_id node.driver_internal_info = driver_internal_info node.save() try: if iscsi_deploy.get_boot_option(node) == "local": deploy_utils.try_set_boot_device(task, boot_devices.DISK) # If it's going to boot from the local disk, get rid of # the PXE configuration files used for the deployment pxe_utils.clean_up_pxe_config(task) # Ask the ramdisk to install bootloader and # wait for the call-back through the vendor passthru # 'pass_bootloader_install_info', if it's not a # whole disk image. if not is_whole_disk_image: LOG.debug('Installing the bootloader on node %s', node.uuid) deploy_utils.notify_ramdisk_to_proceed(kwargs['address']) task.process_event('wait') return else: pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid) boot_mode = deploy_utils.get_boot_mode_for_deploy(node) deploy_utils.switch_pxe_config(pxe_config_path, root_uuid_or_disk_id, boot_mode, is_whole_disk_image) except Exception as e: LOG.error( _LE('Deploy failed for instance %(instance)s. ' 'Error: %(error)s'), { 'instance': node.instance_uuid, 'error': e }) msg = _('Failed to continue iSCSI deployment.') deploy_utils.set_failed_state(task, msg) else: iscsi_deploy.finish_deploy(task, kwargs.get('address'))