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. """ 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.pxe.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path) pxe_info = _get_image_info(node, task.context) pxe_options = _build_pxe_config_options(node, pxe_info, task.context) 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) # 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) # NOTE(deva): prepare may be called from conductor._do_takeover # in which case, it may need to regenerate the PXE config file for an # already-active deployment. if node.provision_state == states.ACTIVE: # this should have been stashed when the deploy was done # but let's guard, just in case it's missing iwdi = node.driver_internal_info.get('is_whole_disk_image') try: root_uuid_or_disk_id = ( node.driver_internal_info['root_uuid_or_disk_id']) except KeyError: if not iwdi: LOG.warn( _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": node.uuid}) else: LOG.warn( _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": node.uuid}) else: pxe_config_path = pxe_utils.get_pxe_config_file_path(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))
def test_create_pxe_config_uefi_ipxe(self, ensure_tree_mock, render_mock, write_mock, link_mac_pxe_mock, chmod_mock): self.config(ipxe_enabled=True, group='pxe') ipxe_template = "ironic/drivers/modules/ipxe_config.template" with task_manager.acquire(self.context, self.node.uuid) as task: task.node.properties['capabilities'] = 'boot_mode:uefi' pxe_utils.create_pxe_config(task, self.ipxe_options, ipxe_template) ensure_calls = [ mock.call(os.path.join(CONF.deploy.http_root, self.node.uuid)), mock.call(os.path.join(CONF.deploy.http_root, 'pxelinux.cfg')), ] ensure_tree_mock.assert_has_calls(ensure_calls) chmod_mock.assert_not_called() render_mock.assert_called_with( ipxe_template, {'pxe_options': self.ipxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'}) link_mac_pxe_mock.assert_called_once_with(task) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
def _prepare_pxe_boot(task): """Prepare the files required for PXE booting the agent.""" pxe_info = _get_tftp_image_info(task.node) pxe_options = _build_pxe_config_options(task, pxe_info) pxe_utils.create_pxe_config(task, pxe_options, CONF.fuel.pxe_config_template) _cache_tftp_images(task.context, task.node, pxe_info)
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. """ # 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.pxe.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path) pxe_info = _get_image_info(task.node, task.context) pxe_options = _build_pxe_config_options(task.node, pxe_info, task.context) if driver_utils.get_node_capability(task.node, 'boot_mode') == '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) _cache_ramdisk_kernel(task.context, task.node, pxe_info)
def _prepare_instance_pxe_config(self, task, image_info, iscsi_boot=False, ramdisk_boot=False): """Prepares the config file for PXE boot :param task: a task from TaskManager. :param image_info: a dict of values of instance image metadata to set on the configuration file. :param iscsi_boot: if boot is from an iSCSI volume or not. :param ramdisk_boot: if the boot is to a ramdisk configuration. :returns: None """ node = task.node dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid) if not os.path.isfile(pxe_config_path): pxe_options = _build_pxe_config_options(task, image_info, service=ramdisk_boot) pxe_config_template = (deploy_utils.get_pxe_config_template(node)) pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template) deploy_utils.switch_pxe_config( pxe_config_path, None, boot_mode_utils.get_boot_mode_for_deploy(node), False, iscsi_boot=iscsi_boot, ramdisk_boot=ramdisk_boot)
def test_create_pxe_config_set_dir_permission(self, ensure_tree_mock, render_mock, write_mock, chmod_mock): self.config(dir_permission=0o755, group='pxe') with task_manager.acquire(self.context, self.node.uuid) as task: pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.pxe_config_template) render_mock.assert_called_with( CONF.pxe.pxe_config_template, { 'pxe_options': self.pxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}' }) node_dir = os.path.join(CONF.pxe.tftp_root, self.node.uuid) pxe_dir = os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg') ensure_calls = [ mock.call(node_dir), mock.call(pxe_dir), ] ensure_tree_mock.assert_has_calls(ensure_calls) chmod_calls = [mock.call(node_dir, 0o755), mock.call(pxe_dir, 0o755)] chmod_mock.assert_has_calls(chmod_calls) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
def test_create_pxe_config_uefi_grub(self, ensure_tree_mock, render_mock, write_mock, link_ip_configs_mock, chmod_mock): grub_tmplte = "ironic/drivers/modules/pxe_grub_config.template" with task_manager.acquire(self.context, self.node.uuid) as task: task.node.properties['capabilities'] = 'boot_mode:uefi' pxe_utils.create_pxe_config(task, self.pxe_options, grub_tmplte) ensure_calls = [ mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)), mock.call(os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg')), ] ensure_tree_mock.assert_has_calls(ensure_calls) chmod_mock.assert_not_called() render_mock.assert_called_with( grub_tmplte, { 'pxe_options': self.pxe_options, 'ROOT': '(( ROOT ))', 'DISK_IDENTIFIER': '(( DISK_IDENTIFIER ))' }) link_ip_configs_mock.assert_called_once_with(task, False) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
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. """ # 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.pxe.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path) pxe_info = _get_image_info(task.node, task.context) pxe_options = _build_pxe_config_options(task.node, pxe_info, task.context) if driver_utils.get_node_capability(task.node, 'boot_mode') == '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) _cache_ramdisk_kernel(task.context, task.node, pxe_info)
def test_create_pxe_config_uefi_grub(self, ensure_tree_mock, render_mock, write_mock, link_ip_configs_mock, chmod_mock): grub_tmplte = "ironic/drivers/modules/pxe_grub_config.template" with task_manager.acquire(self.context, self.node.uuid) as task: task.node.properties['capabilities'] = 'boot_mode:uefi' pxe_utils.create_pxe_config(task, self.pxe_options, grub_tmplte) ensure_calls = [ mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)), mock.call(os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg')), ] ensure_tree_mock.assert_has_calls(ensure_calls) chmod_mock.assert_not_called() render_mock.assert_called_with( grub_tmplte, {'pxe_options': self.pxe_options, 'ROOT': '(( ROOT ))', 'DISK_IDENTIFIER': '(( DISK_IDENTIFIER ))'}) link_ip_configs_mock.assert_called_once_with(task, False) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
def test_create_pxe_config_set_dir_permission(self, ensure_tree_mock, render_mock, write_mock, chmod_mock): self.config(dir_permission=0o755, group='pxe') with task_manager.acquire(self.context, self.node.uuid) as task: pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.pxe_config_template) render_mock.assert_called_with( CONF.pxe.pxe_config_template, {'pxe_options': self.pxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'} ) node_dir = os.path.join(CONF.pxe.tftp_root, self.node.uuid) pxe_dir = os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg') ensure_calls = [ mock.call(node_dir), mock.call(pxe_dir), ] ensure_tree_mock.assert_has_calls(ensure_calls) chmod_calls = [mock.call(node_dir, 0o755), mock.call(pxe_dir, 0o755)] chmod_mock.assert_has_calls(chmod_calls) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
def test_create_pxe_config_uefi_elilo(self, ensure_tree_mock, render_mock, write_mock, link_ip_configs_mock): self.config(uefi_pxe_config_template=('ironic/drivers/modules/' 'elilo_efi_pxe_config.template'), group='pxe') with task_manager.acquire(self.context, self.node.uuid) as task: task.node.properties['capabilities'] = 'boot_mode:uefi' pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.uefi_pxe_config_template) ensure_calls = [ mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)), mock.call(os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg')) ] ensure_tree_mock.assert_has_calls(ensure_calls) render_mock.assert_called_with( CONF.pxe.uefi_pxe_config_template, { 'pxe_options': self.pxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}' }) link_ip_configs_mock.assert_called_once_with(task, True) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
def test_create_pxe_config_uefi_ipxe(self, ensure_tree_mock, render_mock, write_mock, link_mac_pxe_mock, chmod_mock): self.config(ipxe_enabled=True, group='pxe') ipxe_template = "ironic/drivers/modules/ipxe_config.template" with task_manager.acquire(self.context, self.node.uuid) as task: task.node.properties['capabilities'] = 'boot_mode:uefi' pxe_utils.create_pxe_config(task, self.ipxe_options, ipxe_template) ensure_calls = [ mock.call(os.path.join(CONF.deploy.http_root, self.node.uuid)), mock.call(os.path.join(CONF.deploy.http_root, 'pxelinux.cfg')), ] ensure_tree_mock.assert_has_calls(ensure_calls) chmod_mock.assert_not_called() render_mock.assert_called_with( ipxe_template, { 'pxe_options': self.ipxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}' }) link_mac_pxe_mock.assert_called_once_with(task) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
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. """ 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.pxe.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) shutil.copyfile(CONF.pxe.ipxe_boot_script, bootfile_path) pxe_info = _get_image_info(node, task.context) pxe_options = _build_pxe_config_options(node, pxe_info, task.context) 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) # 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) # NOTE(deva): prepare may be called from conductor._do_takeover # in which case, it may need to regenerate the PXE config file for an # already-active deployment. if node.provision_state == states.ACTIVE: # this should have been stashed when the deploy was done # but let's guard, just in case it's missing iwdi = node.driver_internal_info.get('is_whole_disk_image') try: root_uuid_or_disk_id = node.driver_internal_info[ 'root_uuid_or_disk_id'] except KeyError: if not iwdi: LOG.warn(_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": node.uuid}) else: LOG.warn(_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": node.uuid}) else: pxe_config_path = pxe_utils.get_pxe_config_file_path( node.uuid) deploy_utils.switch_pxe_config( pxe_config_path, root_uuid_or_disk_id, deploy_utils.get_boot_mode_for_deploy(node), iwdi)
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: # 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_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) 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: 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 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 test_create_pxe_config(self, ensure_tree_mock, build_mock, write_mock): build_mock.return_value = self.pxe_options with task_manager.acquire(self.context, self.node.uuid) as task: pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.pxe_config_template) build_mock.assert_called_with(self.pxe_options, CONF.pxe.pxe_config_template) ensure_calls = [ mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)), mock.call(os.path.join(CONF.pxe.tftp_root, "pxelinux.cfg")), ] ensure_tree_mock.has_calls(ensure_calls) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, self.pxe_options)
def prepare(self, task): """Prepare the deployment environment for this node. :param task: a TaskManager instance. """ node = task.node pxe_info = _get_tftp_image_info(task.node) pxe_options = _build_pxe_config_options(task.node, pxe_info) pxe_utils.create_pxe_config(task, pxe_options, CONF.agent.agent_pxe_config_template) _cache_tftp_images(task.context, node, pxe_info) node.instance_info = build_instance_info_for_deploy(task) node.save()
def prepare(self, task): """Prepare the deployment environment for this node. :param task: a TaskManager instance. """ node = task.node pxe_info = _get_tftp_image_info(task.node) pxe_options = _build_pxe_config_options(pxe_info) pxe_utils.create_pxe_config(task, pxe_options, CONF.agent.agent_pxe_config_template) _cache_tftp_images(task.context, node, pxe_info) node.instance_info = build_instance_info_for_deploy(task) node.save(task.context)
def test_create_pxe_config(self, ensure_tree_mock, build_mock, write_mock): build_mock.return_value = self.pxe_options with task_manager.acquire(self.context, self.node.uuid) as task: pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.pxe_config_template) build_mock.assert_called_with(self.pxe_options, CONF.pxe.pxe_config_template) ensure_calls = [ mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)), mock.call(os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg')) ] ensure_tree_mock.assert_has_calls(ensure_calls) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, self.pxe_options)
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. """ # TODO(deva): optimize this if rerun on existing files pxe_info = _get_tftp_image_info(task.node, task.context) pxe_options = _build_pxe_config_options(task.node, pxe_info, task.context) pxe_utils.create_pxe_config(task, pxe_options, CONF.pxe.pxe_config_template) _cache_tftp_images(task.context, task.node, pxe_info)
def _prepare_pxe_boot(self, task): """Prepare the files required for PXE booting the agent.""" pxe_info = self._get_tftp_image_info(task.node) # Do live boot if squashfs is specified in either way. is_live_boot = (task.node.driver_info.get('deploy_squashfs') or CONF.bareon.deploy_squashfs) pxe_options = self._build_pxe_config_options(task, pxe_info, is_live_boot) template = (CONF.bareon.pxe_config_template_live if is_live_boot else CONF.bareon.pxe_config_template) pxe_utils.create_pxe_config(task, pxe_options, template) self._cache_tftp_images(task.context, task.node, pxe_info)
def _build_service_pxe_config(task, instance_image_info, root_uuid_or_disk_id): node = task.node pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid) # NOTE(pas-ha) if it is takeover of ACTIVE node, # first ensure that basic PXE configs and links # are in place before switching pxe config if (node.provision_state == states.ACTIVE and not os.path.isfile(pxe_config_path)): pxe_options = _build_pxe_config_options(task, instance_image_info, service=True) pxe_config_template = deploy_utils.get_pxe_config_template(node) pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template) iwdi = node.driver_internal_info.get('is_whole_disk_image') 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))
def _build_service_pxe_config(task, instance_image_info, root_uuid_or_disk_id): node = task.node pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid) # NOTE(pas-ha) if it is takeover of ACTIVE node, # first ensure that basic PXE configs and links # are in place before switching pxe config if (node.provision_state == states.ACTIVE and not os.path.isfile(pxe_config_path)): pxe_options = _build_pxe_config_options(task, instance_image_info, service=True) pxe_config_template = deploy_utils.get_pxe_config_template(node) pxe_utils.create_pxe_config(task, pxe_options, pxe_config_template) iwdi = node.driver_internal_info.get('is_whole_disk_image') 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), deploy_utils.is_iscsi_boot(task))
def test_create_pxe_config_existing_dirs(self, ensure_tree_mock, render_mock, write_mock, chmod_mock, isdir_mock): self.config(dir_permission=0o755, group='pxe') with task_manager.acquire(self.context, self.node.uuid) as task: isdir_mock.return_value = True pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.pxe_config_template) render_mock.assert_called_with( CONF.pxe.pxe_config_template, { 'pxe_options': self.pxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}' }) ensure_tree_mock.assert_has_calls([]) chmod_mock.assert_not_called() isdir_mock.assert_has_calls([]) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
def test_create_pxe_config(self, ensure_tree_mock, render_mock, write_mock): with task_manager.acquire(self.context, self.node.uuid) as task: pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.pxe_config_template) render_mock.assert_called_with( CONF.pxe.pxe_config_template, { 'pxe_options': self.pxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}' }) ensure_calls = [ mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)), mock.call(os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg')) ] ensure_tree_mock.assert_has_calls(ensure_calls) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
def test_create_pxe_config_uefi_elilo(self, ensure_tree_mock, build_mock, write_mock, link_ip_configs_mock): build_mock.return_value = self.pxe_options_uefi with task_manager.acquire(self.context, self.node.uuid) as task: task.node.properties['capabilities'] = 'boot_mode:uefi' pxe_utils.create_pxe_config(task, self.pxe_options_uefi, CONF.pxe.uefi_pxe_config_template) ensure_calls = [ mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)), mock.call(os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg')) ] ensure_tree_mock.assert_has_calls(ensure_calls) build_mock.assert_called_with(self.pxe_options_uefi, CONF.pxe.uefi_pxe_config_template, '{{ ROOT }}', '{{ DISK_IDENTIFIER }}') link_ip_configs_mock.assert_called_once_with(task, True) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, self.pxe_options_uefi)
def test_create_pxe_config_existing_dirs(self, ensure_tree_mock, render_mock, write_mock, chmod_mock, isdir_mock): self.config(dir_permission=0o755, group='pxe') with task_manager.acquire(self.context, self.node.uuid) as task: isdir_mock.return_value = True pxe_utils.create_pxe_config(task, self.pxe_options, CONF.pxe.pxe_config_template) render_mock.assert_called_with( CONF.pxe.pxe_config_template, {'pxe_options': self.pxe_options, 'ROOT': '{{ ROOT }}', 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'} ) ensure_tree_mock.assert_has_calls([]) chmod_mock.assert_not_called() isdir_mock.assert_has_calls([]) pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) write_mock.assert_called_with(pxe_cfg_file_path, render_mock.return_value)
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_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)
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 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)
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_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 deploy_utils.is_iscsi_boot(task): dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) # configure iPXE for iscsi boot pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid) if not os.path.isfile(pxe_config_path): pxe_options = _build_pxe_config_options(task, {}) pxe_config_template = ( deploy_utils.get_pxe_config_template(node)) pxe_utils.create_pxe_config( task, pxe_options, pxe_config_template) deploy_utils.switch_pxe_config( pxe_config_path, None, deploy_utils.get_boot_mode_for_deploy(node), False, iscsi_boot=True) boot_device = boot_devices.PXE elif boot_option != "local": if task.driver.storage.should_write_image(task): # 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 task.driver.storage.should_write_image(task): pass elif not iwdi: LOG.warning("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("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: manager_utils.node_set_boot_device(task, boot_device, persistent=True)
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 deploy_utils.is_iscsi_boot(task): dhcp_opts = pxe_utils.dhcp_options_for_instance(task) provider = dhcp_factory.DHCPFactory() provider.update_dhcp(task, dhcp_opts) # configure iPXE for iscsi boot pxe_config_path = pxe_utils.get_pxe_config_file_path( task.node.uuid) if not os.path.isfile(pxe_config_path): pxe_options = _build_pxe_config_options(task, {}) pxe_config_template = ( deploy_utils.get_pxe_config_template(node)) pxe_utils.create_pxe_config( task, pxe_options, pxe_config_template) deploy_utils.switch_pxe_config( pxe_config_path, None, deploy_utils.get_boot_mode_for_deploy(node), False, iscsi_boot=True) boot_device = boot_devices.PXE elif boot_option != "local": if task.driver.storage.should_write_image(task): # 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 task.driver.storage.should_write_image(task): pass elif not iwdi: LOG.warning("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("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. Booting the instance " "from disk.", {"node": task.node.uuid}) pxe_utils.clean_up_pxe_config(task) boot_device = boot_devices.DISK 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: manager_utils.node_set_boot_device(task, boot_device, persistent=True)