Start removing ipxe support from the pxe interface

This patch starts removing codes related to ipxe support from the pxe interface,
and extract common logic to the PXEBaseMixin.

Story: 2007003
Task: 37779

Change-Id: Ia621f38d9b6c4570ba6a62ddb8c72244ff3fe33b
This commit is contained in:
Kaifeng Wang 2019-11-29 16:24:44 +08:00
parent d86b0f61d7
commit 6ba983b615
6 changed files with 248 additions and 591 deletions

View File

@ -17,19 +17,13 @@ iPXE Boot Interface
from ironic_lib import metrics_utils
from oslo_log import log as logging
from oslo_utils import strutils
from ironic.common import boot_devices
from ironic.common import dhcp_factory
from ironic.common import exception
from ironic.common.glance_service import service_utils
from ironic.common.i18n import _
from ironic.common import pxe_utils
from ironic.common import states
from ironic.conductor import utils as manager_utils
from ironic.conf import CONF
from ironic.drivers import base
from ironic.drivers.modules import boot_mode_utils
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules import pxe
from ironic.drivers.modules import pxe_base
@ -128,203 +122,3 @@ class iPXEBoot(pxe_base.PXEBaseMixin, base.BootInterface):
# Fall back to non-managed in-band inspection
raise exception.UnsupportedDriverExtension(
driver=task.node.driver, extension='inspection')
@METRICS.timer('iPXEBoot.prepare_ramdisk')
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, 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=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)
LOG.debug('Ramdisk iPXE boot for node %(node)s has been prepared '
'with kernel params %(params)s',
{'node': node.uuid, 'params': pxe_options})
@METRICS.timer('iPXEBoot.prepare_instance')
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
"""
boot_mode_utils.sync_boot_mode(task)
node = task.node
boot_option = deploy_utils.get_boot_option(node)
boot_device = None
instance_image_info = {}
if boot_option == "ramdisk":
instance_image_info = pxe_utils.get_instance_image_info(
task, ipxe_enabled=True)
pxe_utils.cache_ramdisk_kernel(task, instance_image_info,
ipxe_enabled=True)
if deploy_utils.is_iscsi_boot(task) or boot_option == "ramdisk":
pxe_utils.prepare_instance_pxe_config(
task, instance_image_info,
iscsi_boot=deploy_utils.is_iscsi_boot(task),
ramdisk_boot=(boot_option == "ramdisk"),
ipxe_enabled=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 = pxe_utils.get_instance_image_info(
task, ipxe_enabled=True)
pxe_utils.cache_ramdisk_kernel(task, instance_image_info,
ipxe_enabled=True)
# If it's going to PXE boot we need to update the DHCP server
dhcp_opts = pxe_utils.dhcp_options_for_instance(task,
ipxe_enabled=True)
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, ipxe_enabled=True)
boot_device = boot_devices.DISK
else:
pxe_utils.build_service_pxe_config(task, instance_image_info,
root_uuid_or_disk_id,
ipxe_enabled=True)
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, ipxe_enabled=True)
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:
persistent = True
if node.driver_info.get('force_persistent_boot_device',
'Default') == 'Never':
persistent = False
manager_utils.node_set_boot_device(task, boot_device,
persistent=persistent)
@METRICS.timer('iPXEBoot.clean_up_instance')
def clean_up_instance(self, task):
"""Cleans up the boot of instance.
This method cleans up the environment that was setup for booting
the instance. It unlinks the instance kernel/ramdisk in node's
directory in tftproot and removes the PXE config.
:param task: a task from TaskManager.
:returns: None
"""
node = task.node
try:
images_info = pxe_utils.get_instance_image_info(task,
ipxe_enabled=True)
except exception.MissingParameterValue as e:
LOG.warning('Could not get instance image info '
'to clean up images for node %(node)s: %(err)s',
{'node': node.uuid, 'err': e})
else:
pxe_utils.clean_up_pxe_env(task, images_info, ipxe_enabled=True)

View File

@ -18,8 +18,6 @@ PXE Boot Interface
from ironic_lib import metrics_utils
from oslo_log import log as logging
from ironic.common import boot_devices
from ironic.common import dhcp_factory
from ironic.common import exception
from ironic.common.glance_service import service_utils
from ironic.common.i18n import _
@ -27,10 +25,8 @@ from ironic.common import pxe_utils
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.conf import CONF
from ironic.drivers import base
from ironic.drivers.modules import agent
from ironic.drivers.modules import boot_mode_utils
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules import pxe_base
from ironic.drivers import utils as driver_utils
@ -54,12 +50,6 @@ class PXEBoot(pxe_base.PXEBaseMixin, base.BootInterface):
# interface.
capabilities = ['iscsi_volume_boot', 'ramdisk_boot', 'pxe_boot']
def __init__(self):
# TODO(TheJulia): Once the pxe/ipxe interfaces split is complete,
# this can be removed.
if CONF.pxe.ipxe_enabled:
pxe_utils.create_ipxe_boot_script()
def _validate_common(self, task):
node = task.node
@ -68,15 +58,6 @@ class PXEBoot(pxe_base.PXEBaseMixin, base.BootInterface):
_("Node %s does not have any port associated with it.")
% node.uuid)
# TODO(TheJulia): Once ipxe support is remove from the pxe
# interface, this can be removed.
if CONF.pxe.ipxe_enabled:
if (not CONF.deploy.http_url
or not CONF.deploy.http_root):
raise exception.MissingParameterValue(_(
"iPXE boot is enabled but no HTTP URL or HTTP "
"root was specified."))
# Check the trusted_boot capabilities value.
deploy_utils.validate_capabilities(node)
if deploy_utils.is_trusted_boot_requested(node):
@ -132,200 +113,6 @@ class PXEBoot(pxe_base.PXEBaseMixin, base.BootInterface):
raise exception.UnsupportedDriverExtension(
driver=task.node.driver, extension='inspection')
@METRICS.timer('PXEBoot.prepare_ramdisk')
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})
@METRICS.timer('PXEBoot.prepare_instance')
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
"""
ipxe_enabled = CONF.pxe.ipxe_enabled
boot_mode_utils.sync_boot_mode(task)
node = task.node
boot_option = deploy_utils.get_boot_option(node)
boot_device = None
instance_image_info = {}
if boot_option == "ramdisk":
instance_image_info = pxe_utils.get_instance_image_info(task)
pxe_utils.cache_ramdisk_kernel(task, instance_image_info,
ipxe_enabled=CONF.pxe.ipxe_enabled)
if deploy_utils.is_iscsi_boot(task) or boot_option == "ramdisk":
pxe_utils.prepare_instance_pxe_config(
task, instance_image_info,
iscsi_boot=deploy_utils.is_iscsi_boot(task),
ramdisk_boot=(boot_option == "ramdisk"),
ipxe_enabled=CONF.pxe.ipxe_enabled)
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 = pxe_utils.get_instance_image_info(task)
pxe_utils.cache_ramdisk_kernel(
task, instance_image_info,
ipxe_enabled=CONF.pxe.ipxe_enabled)
# If it's going to PXE boot we need to update the DHCP server
dhcp_opts = pxe_utils.dhcp_options_for_instance(
task, ipxe_enabled)
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, ipxe_enabled=CONF.pxe.ipxe_enabled)
boot_device = boot_devices.DISK
else:
pxe_utils.build_service_pxe_config(task, instance_image_info,
root_uuid_or_disk_id,
ipxe_enabled=ipxe_enabled)
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, ipxe_enabled=CONF.pxe.ipxe_enabled)
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:
persistent = True
if node.driver_info.get('force_persistent_boot_device',
'Default') == 'Never':
persistent = False
manager_utils.node_set_boot_device(task, boot_device,
persistent=persistent)
@METRICS.timer('PXEBoot.clean_up_instance')
def clean_up_instance(self, task):
"""Cleans up the boot of instance.
This method cleans up the environment that was setup for booting
the instance. It unlinks the instance kernel/ramdisk in node's
directory in tftproot and removes the PXE config.
:param task: a task from TaskManager.
:returns: None
"""
node = task.node
try:
images_info = pxe_utils.get_instance_image_info(task)
except exception.MissingParameterValue as e:
LOG.warning('Could not get instance image info '
'to clean up images for node %(node)s: %(err)s',
{'node': node.uuid, 'err': e})
else:
pxe_utils.clean_up_pxe_env(task, images_info)
class PXERamdiskDeploy(agent.AgentDeploy):

View File

@ -20,12 +20,14 @@ from oslo_log import log as logging
from oslo_utils import strutils
from ironic.common import boot_devices
from ironic.common import dhcp_factory
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import pxe_utils
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules import boot_mode_utils
from ironic.drivers.modules import deploy_utils
@ -105,6 +107,205 @@ class PXEBaseMixin(object):
pxe_utils.clean_up_pxe_env(
task, images_info, ipxe_enabled=self.ipxe_enabled)
@METRICS.timer('PXEBaseMixin.clean_up_instance')
def clean_up_instance(self, task):
"""Cleans up the boot of instance.
This method cleans up the environment that was setup for booting
the instance. It unlinks the instance kernel/ramdisk in node's
directory in tftproot and removes the PXE config.
:param task: a task from TaskManager.
:returns: None
"""
node = task.node
try:
images_info = pxe_utils.get_instance_image_info(
task, ipxe_enabled=self.ipxe_enabled)
except exception.MissingParameterValue as e:
LOG.warning('Could not get instance image info '
'to clean up images for node %(node)s: %(err)s',
{'node': node.uuid, 'err': e})
else:
pxe_utils.clean_up_pxe_env(task, images_info,
ipxe_enabled=self.ipxe_enabled)
@METRICS.timer('PXEBaseMixin.prepare_ramdisk')
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)
if self.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=self.ipxe_enabled)
provider = dhcp_factory.DHCPFactory()
provider.update_dhcp(task, dhcp_opts)
pxe_info = pxe_utils.get_image_info(node, mode=mode,
ipxe_enabled=self.ipxe_enabled)
# 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=self.ipxe_enabled))
boot_mode_utils.sync_boot_mode(task)
pxe_options = pxe_utils.build_pxe_config_options(
task, pxe_info, ipxe_enabled=self.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=self.ipxe_enabled)
persistent = self._persistent_ramdisk_boot(node)
manager_utils.node_set_boot_device(task, boot_devices.PXE,
persistent=persistent)
if self.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=self.ipxe_enabled)
LOG.debug('Ramdisk (i)PXE boot for node %(node)s has been prepared '
'with kernel params %(params)s',
{'node': node.uuid, 'params': pxe_options})
@METRICS.timer('PXEBaseMixin.prepare_instance')
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
"""
boot_mode_utils.sync_boot_mode(task)
node = task.node
boot_option = deploy_utils.get_boot_option(node)
boot_device = None
instance_image_info = {}
if boot_option == "ramdisk":
instance_image_info = pxe_utils.get_instance_image_info(
task, ipxe_enabled=self.ipxe_enabled)
pxe_utils.cache_ramdisk_kernel(task, instance_image_info,
ipxe_enabled=self.ipxe_enabled)
if deploy_utils.is_iscsi_boot(task) or boot_option == "ramdisk":
pxe_utils.prepare_instance_pxe_config(
task, instance_image_info,
iscsi_boot=deploy_utils.is_iscsi_boot(task),
ramdisk_boot=(boot_option == "ramdisk"),
ipxe_enabled=self.ipxe_enabled)
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 = pxe_utils.get_instance_image_info(
task, ipxe_enabled=self.ipxe_enabled)
pxe_utils.cache_ramdisk_kernel(task, instance_image_info,
ipxe_enabled=self.ipxe_enabled)
# If it's going to PXE boot we need to update the DHCP server
dhcp_opts = pxe_utils.dhcp_options_for_instance(
task, ipxe_enabled=self.ipxe_enabled)
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, ipxe_enabled=self.ipxe_enabled)
boot_device = boot_devices.DISK
else:
pxe_utils.build_service_pxe_config(
task, instance_image_info, root_uuid_or_disk_id,
ipxe_enabled=self.ipxe_enabled)
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, ipxe_enabled=self.ipxe_enabled)
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:
persistent = True
if node.driver_info.get('force_persistent_boot_device',
'Default') == 'Never':
persistent = False
manager_utils.node_set_boot_device(task, boot_device,
persistent=persistent)
@METRICS.timer('PXEBaseMixin.validate_rescue')
def validate_rescue(self, task):
"""Validate that the node has required properties for rescue.

View File

@ -36,6 +36,7 @@ from ironic.drivers import base as drivers_base
from ironic.drivers.modules import agent_base
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules import ipxe
from ironic.drivers.modules import pxe_base
from ironic.drivers.modules.storage import noop as noop_storage
from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.db import utils as db_utils
@ -730,7 +731,7 @@ class iPXEBootTestCase(db_base.DbTestCase):
# NOTE(TheJulia): The log mock below is attached to the iPXE interface
# which directly logs the warning that is being checked for.
@mock.patch.object(ipxe.LOG, 'warning', autospec=True)
@mock.patch.object(pxe_base.LOG, 'warning', autospec=True)
@mock.patch.object(pxe_utils, 'clean_up_pxe_config', autospec=True)
@mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
@mock.patch.object(dhcp_factory, 'DHCPFactory')

View File

@ -1275,7 +1275,8 @@ class CleanUpFullFlowTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.driver.deploy.clean_up(task)
mock_get_instance_image_info.assert_called_with(task)
mock_get_instance_image_info.assert_called_with(task,
ipxe_enabled=False)
mock_get_deploy_image_info.assert_called_with(
task.node, mode='deploy', ipxe_enabled=False)
set_dhcp_provider_mock.assert_called_once_with()

View File

@ -31,7 +31,6 @@ from ironic.common import exception
from ironic.common.glance_service import image_service
from ironic.common import pxe_utils
from ironic.common import states
from ironic.common import utils as common_utils
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers import base as drivers_base
@ -40,6 +39,7 @@ from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules import fake
from ironic.drivers.modules import ipxe
from ironic.drivers.modules import pxe
from ironic.drivers.modules import pxe_base
from ironic.drivers.modules.storage import noop as noop_storage
from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.db import utils as db_utils
@ -268,7 +268,9 @@ class PXEBootTestCase(db_base.DbTestCase):
dhcp_opts = pxe_utils.dhcp_options_for_instance(
task, ipxe_enabled=CONF.pxe.ipxe_enabled)
task.driver.boot.prepare_ramdisk(task, {'foo': 'bar'})
mock_deploy_img_info.assert_called_once_with(task.node, mode=mode)
mock_deploy_img_info.assert_called_once_with(task.node,
mode=mode,
ipxe_enabled=False)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
if self.node.provision_state == states.DEPLOYING:
get_boot_mode_mock.assert_called_once_with(task)
@ -282,33 +284,35 @@ class PXEBootTestCase(db_base.DbTestCase):
mock_cache_r_k.assert_called_once_with(
task,
{'kernel': 'b'},
ipxe_enabled=CONF.pxe.ipxe_enabled)
mock_instance_img_info.assert_called_once_with(task)
ipxe_enabled=False)
mock_instance_img_info.assert_called_once_with(
task, ipxe_enabled=False)
elif not cleaning and mode == 'deploy':
mock_cache_r_k.assert_called_once_with(
task,
{'deploy_kernel': 'a', 'deploy_ramdisk': 'r',
'kernel': 'b'},
ipxe_enabled=CONF.pxe.ipxe_enabled)
mock_instance_img_info.assert_called_once_with(task)
ipxe_enabled=False)
mock_instance_img_info.assert_called_once_with(
task, ipxe_enabled=False)
elif mode == 'deploy':
mock_cache_r_k.assert_called_once_with(
task,
{'deploy_kernel': 'a', 'deploy_ramdisk': 'r'},
ipxe_enabled=CONF.pxe.ipxe_enabled)
ipxe_enabled=False)
elif mode == 'rescue':
mock_cache_r_k.assert_called_once_with(
task,
{'rescue_kernel': 'a', 'rescue_ramdisk': 'r'},
ipxe_enabled=CONF.pxe.ipxe_enabled)
ipxe_enabled=False)
if uefi:
mock_pxe_config.assert_called_once_with(
task, {}, CONF.pxe.uefi_pxe_config_template,
ipxe_enabled=CONF.pxe.ipxe_enabled)
ipxe_enabled=False)
else:
mock_pxe_config.assert_called_once_with(
task, {}, CONF.pxe.pxe_config_template,
ipxe_enabled=CONF.pxe.ipxe_enabled)
ipxe_enabled=False)
def test_prepare_ramdisk(self):
self.node.provision_state = states.DEPLOYING
@ -403,93 +407,6 @@ class PXEBootTestCase(db_base.DbTestCase):
self.node.save()
self._test_prepare_ramdisk(uefi=True)
@mock.patch.object(os.path, 'isfile', lambda path: True)
@mock.patch.object(common_utils, 'file_has_content', lambda *args: False)
@mock.patch('ironic.common.utils.write_to_file', autospec=True)
@mock.patch('ironic.common.utils.render_template', autospec=True)
def test_prepare_ramdisk_ipxe_with_copy_file_different(
self, render_mock, write_mock):
self.node.provision_state = states.DEPLOYING
self.node.save()
self.config(group='pxe', ipxe_enabled=True)
self.config(group='deploy', http_url='http://myserver')
render_mock.return_value = 'foo'
self._test_prepare_ramdisk()
write_mock.assert_called_once_with(
os.path.join(
CONF.deploy.http_root,
os.path.basename(CONF.pxe.ipxe_boot_script)),
'foo')
render_mock.assert_called_once_with(
CONF.pxe.ipxe_boot_script,
{'ipxe_for_mac_uri': 'pxelinux.cfg/'})
@mock.patch.object(os.path, 'isfile', lambda path: False)
@mock.patch('ironic.common.utils.file_has_content', autospec=True)
@mock.patch('ironic.common.utils.write_to_file', autospec=True)
@mock.patch('ironic.common.utils.render_template', autospec=True)
def test_prepare_ramdisk_ipxe_with_copy_no_file(
self, render_mock, write_mock, file_has_content_mock):
self.node.provision_state = states.DEPLOYING
self.node.save()
self.config(group='pxe', ipxe_enabled=True)
self.config(group='deploy', http_url='http://myserver')
render_mock.return_value = 'foo'
self._test_prepare_ramdisk()
self.assertFalse(file_has_content_mock.called)
write_mock.assert_called_once_with(
os.path.join(
CONF.deploy.http_root,
os.path.basename(CONF.pxe.ipxe_boot_script)),
'foo')
render_mock.assert_called_once_with(
CONF.pxe.ipxe_boot_script,
{'ipxe_for_mac_uri': 'pxelinux.cfg/'})
@mock.patch.object(os.path, 'isfile', lambda path: True)
@mock.patch.object(common_utils, 'file_has_content', lambda *args: True)
@mock.patch('ironic.common.utils.write_to_file', autospec=True)
@mock.patch('ironic.common.utils.render_template', autospec=True)
def test_prepare_ramdisk_ipxe_without_copy(
self, render_mock, write_mock):
self.node.provision_state = states.DEPLOYING
self.node.save()
self.config(group='pxe', ipxe_enabled=True)
self.config(group='deploy', http_url='http://myserver')
self._test_prepare_ramdisk()
self.assertFalse(write_mock.called)
@mock.patch.object(common_utils, 'render_template', lambda *args: 'foo')
@mock.patch('ironic.common.utils.write_to_file', autospec=True)
def test_prepare_ramdisk_ipxe_swift(self, write_mock):
self.node.provision_state = states.DEPLOYING
self.node.save()
self.config(group='pxe', ipxe_enabled=True)
self.config(group='pxe', ipxe_use_swift=True)
self.config(group='deploy', http_url='http://myserver')
self._test_prepare_ramdisk(ipxe_use_swift=True)
write_mock.assert_called_once_with(
os.path.join(
CONF.deploy.http_root,
os.path.basename(CONF.pxe.ipxe_boot_script)),
'foo')
@mock.patch.object(common_utils, 'render_template', lambda *args: 'foo')
@mock.patch('ironic.common.utils.write_to_file', autospec=True)
def test_prepare_ramdisk_ipxe_swift_whole_disk_image(
self, write_mock):
self.node.provision_state = states.DEPLOYING
self.node.save()
self.config(group='pxe', ipxe_enabled=True)
self.config(group='pxe', ipxe_use_swift=True)
self.config(group='deploy', http_url='http://myserver')
self._test_prepare_ramdisk(ipxe_use_swift=True, whole_disk_image=True)
write_mock.assert_called_once_with(
os.path.join(
CONF.deploy.http_root,
os.path.basename(CONF.pxe.ipxe_boot_script)),
'foo')
def test_prepare_ramdisk_cleaning(self):
self.node.provision_state = states.CLEANING
self.node.save()
@ -635,7 +552,7 @@ class PXEBootTestCase(db_base.DbTestCase):
get_image_info_mock.return_value = image_info
with task_manager.acquire(self.context, self.node.uuid) as task:
dhcp_opts = pxe_utils.dhcp_options_for_instance(
task, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, ipxe_enabled=False)
pxe_config_path = pxe_utils.get_pxe_config_file_path(
task.node.uuid)
task.node.properties['capabilities'] = 'boot_mode:bios'
@ -646,9 +563,9 @@ class PXEBootTestCase(db_base.DbTestCase):
task.driver.boot.prepare_instance(task)
get_image_info_mock.assert_called_once_with(
task)
task, ipxe_enabled=False)
cache_mock.assert_called_once_with(
task, image_info, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, image_info, ipxe_enabled=False)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
switch_pxe_config_mock.assert_called_once_with(
pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50",
@ -688,9 +605,9 @@ class PXEBootTestCase(db_base.DbTestCase):
task.driver.boot.prepare_instance(task)
get_image_info_mock.assert_called_once_with(
task)
task, ipxe_enabled=False)
cache_mock.assert_called_once_with(
task, image_info, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, image_info, ipxe_enabled=False)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
create_pxe_config_mock.assert_called_once_with(
task, mock.ANY, CONF.pxe.pxe_config_template,
@ -716,20 +633,21 @@ class PXEBootTestCase(db_base.DbTestCase):
get_image_info_mock.return_value = image_info
with task_manager.acquire(self.context, self.node.uuid) as task:
dhcp_opts = pxe_utils.dhcp_options_for_instance(
task, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, ipxe_enabled=False)
task.node.properties['capabilities'] = 'boot_mode:bios'
task.node.driver_internal_info['is_whole_disk_image'] = False
task.driver.boot.prepare_instance(task)
get_image_info_mock.assert_called_once_with(task)
get_image_info_mock.assert_called_once_with(task,
ipxe_enabled=False)
cache_mock.assert_called_once_with(
task, image_info, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, image_info, ipxe_enabled=False)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
self.assertFalse(switch_pxe_config_mock.called)
self.assertFalse(set_boot_device_mock.called)
@mock.patch.object(pxe.LOG, 'warning', autospec=True)
@mock.patch.object(pxe_base.LOG, 'warning', autospec=True)
@mock.patch.object(pxe_utils, 'clean_up_pxe_config', autospec=True)
@mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
@mock.patch.object(dhcp_factory, 'DHCPFactory')
@ -744,70 +662,21 @@ class PXEBootTestCase(db_base.DbTestCase):
get_image_info_mock.return_value = {}
with task_manager.acquire(self.context, self.node.uuid) as task:
dhcp_opts = pxe_utils.dhcp_options_for_instance(
task, CONF.pxe.ipxe_enabled)
task, ipxe_enabled=False)
task.node.properties['capabilities'] = 'boot_mode:bios'
task.node.driver_internal_info['is_whole_disk_image'] = True
task.driver.boot.prepare_instance(task)
get_image_info_mock.assert_called_once_with(task)
get_image_info_mock.assert_called_once_with(task,
ipxe_enabled=False)
cache_mock.assert_called_once_with(
task, {}, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, {}, ipxe_enabled=False)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
self.assertTrue(log_mock.called)
clean_up_pxe_mock.assert_called_once_with(
task, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, ipxe_enabled=False)
set_boot_device_mock.assert_called_once_with(
task, boot_devices.DISK, persistent=True)
@mock.patch('os.path.isfile', lambda filename: False)
@mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True)
@mock.patch.object(deploy_utils, 'is_iscsi_boot', lambda task: True)
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
lambda task: False)
@mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
@mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True)
@mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True)
@mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True)
@mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True)
def test_prepare_instance_netboot_iscsi(
self, get_image_info_mock, cache_mock,
dhcp_factory_mock, switch_pxe_config_mock,
set_boot_device_mock, create_pxe_config_mock):
http_url = 'http://192.1.2.3:1234'
self.config(ipxe_enabled=True, group='pxe')
self.config(http_url=http_url, group='deploy')
provider_mock = mock.MagicMock()
dhcp_factory_mock.return_value = provider_mock
vol_id = uuidutils.generate_uuid()
obj_utils.create_test_volume_target(
self.context, node_id=self.node.id, volume_type='iscsi',
boot_index=0, volume_id='1234', uuid=vol_id,
properties={'target_lun': 0,
'target_portal': 'fake_host:3260',
'target_iqn': 'fake_iqn',
'auth_username': 'fake_username',
'auth_password': 'fake_password'})
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_internal_info = {
'boot_from_volume': vol_id}
dhcp_opts = pxe_utils.dhcp_options_for_instance(task,
ipxe_enabled=True)
pxe_config_path = pxe_utils.get_pxe_config_file_path(
task.node.uuid, ipxe_enabled=True)
task.node.properties['capabilities'] = 'boot_mode:bios'
task.driver.boot.prepare_instance(task)
self.assertFalse(get_image_info_mock.called)
self.assertFalse(cache_mock.called)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
create_pxe_config_mock.assert_called_once_with(
task, mock.ANY, CONF.pxe.pxe_config_template,
ipxe_enabled=True)
switch_pxe_config_mock.assert_called_once_with(
pxe_config_path, None, boot_modes.LEGACY_BIOS, False,
ipxe_enabled=True, ramdisk_boot=False, iscsi_boot=True)
set_boot_device_mock.assert_called_once_with(task,
boot_devices.PXE,
persistent=True)
@mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
@mock.patch.object(pxe_utils, 'clean_up_pxe_config', autospec=True)
def test_prepare_instance_localboot(self, clean_up_pxe_config_mock,
@ -869,7 +738,8 @@ class PXEBootTestCase(db_base.DbTestCase):
task.node.uuid)
task.driver.boot.prepare_instance(task)
get_image_info_mock.assert_called_once_with(task)
get_image_info_mock.assert_called_once_with(task,
ipxe_enabled=False)
cache_mock.assert_called_once_with(
task, image_info, CONF.pxe.ipxe_enabled)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
@ -904,8 +774,10 @@ class PXEBootTestCase(db_base.DbTestCase):
'ramdisk': ['', '/path/to/ramdisk']}
get_image_info_mock.return_value = image_info
task.driver.boot.clean_up_instance(task)
clean_up_pxe_env_mock.assert_called_once_with(task, image_info)
get_image_info_mock.assert_called_once_with(task)
clean_up_pxe_env_mock.assert_called_once_with(task, image_info,
ipxe_enabled=False)
get_image_info_mock.assert_called_once_with(task,
ipxe_enabled=False)
class PXERamdiskDeployTestCase(db_base.DbTestCase):
@ -957,7 +829,7 @@ class PXERamdiskDeployTestCase(db_base.DbTestCase):
get_image_info_mock.return_value = image_info
with task_manager.acquire(self.context, self.node.uuid) as task:
dhcp_opts = pxe_utils.dhcp_options_for_instance(
task, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, ipxe_enabled=False)
pxe_config_path = pxe_utils.get_pxe_config_file_path(
task.node.uuid)
task.node.properties['capabilities'] = 'boot_option:netboot'
@ -965,9 +837,10 @@ class PXERamdiskDeployTestCase(db_base.DbTestCase):
task.driver.deploy.prepare(task)
task.driver.deploy.deploy(task)
get_image_info_mock.assert_called_once_with(task)
get_image_info_mock.assert_called_once_with(task,
ipxe_enabled=False)
cache_mock.assert_called_once_with(
task, image_info, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, image_info, ipxe_enabled=False)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
switch_pxe_config_mock.assert_called_once_with(
pxe_config_path, None,
@ -993,9 +866,9 @@ class PXERamdiskDeployTestCase(db_base.DbTestCase):
self.node.save()
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertIsNone(task.driver.deploy.deploy(task))
mock_image_info.assert_called_once_with(task)
mock_image_info.assert_called_once_with(task, ipxe_enabled=False)
mock_cache.assert_called_once_with(
task, image_info, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, image_info, ipxe_enabled=False)
self.assertFalse(mock_warning.called)
i_info['configdrive'] = 'meow'
self.node.instance_info = i_info
@ -1110,9 +983,9 @@ class PXERamdiskDeployTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.uuid) as task:
power_on_node_if_needed_mock.return_value = states.POWER_OFF
self.assertIsNone(task.driver.deploy.deploy(task))
mock_image_info.assert_called_once_with(task)
mock_image_info.assert_called_once_with(task, ipxe_enabled=False)
mock_cache.assert_called_once_with(
task, image_info, ipxe_enabled=CONF.pxe.ipxe_enabled)
task, image_info, ipxe_enabled=False)
self.assertFalse(mock_warning.called)
power_on_node_if_needed_mock.assert_called_once_with(task)
restore_power_state_mock.assert_called_once_with(