diff options
author | Shivanand Tendulker <stendulker@gmail.com> | 2017-08-30 03:50:32 -0400 |
---|---|---|
committer | Shivanand Tendulker <stendulker@gmail.com> | 2018-04-18 02:49:37 -0400 |
commit | 4fa1075b95e2e5262f98395275590dcd3833ab74 (patch) | |
tree | 6e2a0ab81b8aa35a9c90f5cce02d10aded31ed8e /ironic/drivers | |
parent | 46ee76aa461cd012a2b39dcb16c414957c463b72 (diff) | |
download | ironic-4fa1075b95e2e5262f98395275590dcd3833ab74.tar.gz |
Fix ``agent`` deploy interface to call ``boot.prepare_instance``
``agent`` deploy interface do not call ``boot.prepare_instance``
if image being provisioned is whole disk image. This commit fixes
that issue.
It also updates ``validate`` method of neutron network interface
module to validate if it can support boot options requested for
instance image.
Change-Id: Ibd49d65f4512f2fa417794b66f4007d82f02e2ac
Story: 1713916
Task: 9259
Story: 1750958
Task: 9288
Diffstat (limited to 'ironic/drivers')
-rw-r--r-- | ironic/drivers/modules/agent.py | 92 | ||||
-rw-r--r-- | ironic/drivers/modules/network/neutron.py | 11 | ||||
-rw-r--r-- | ironic/drivers/modules/pxe.py | 5 |
3 files changed, 88 insertions, 20 deletions
diff --git a/ironic/drivers/modules/agent.py b/ironic/drivers/modules/agent.py index 0a47ab3a9..f78c744d7 100644 --- a/ironic/drivers/modules/agent.py +++ b/ironic/drivers/modules/agent.py @@ -15,6 +15,7 @@ from ironic_lib import metrics_utils from ironic_lib import utils as il_utils from oslo_log import log +from oslo_utils import excutils from oslo_utils import units import six.moves.urllib_parse as urlparse @@ -272,35 +273,63 @@ class AgentDeployMixin(agent_base_vendor.AgentDeployMixin): LOG.error(msg) deploy_utils.set_failed_state(task, msg) return + + # If `boot_option` is set to `netboot`, PXEBoot.prepare_instance() + # would need root_uuid of the whole disk image to add it into the + # pxe config to perform chain boot. + # IPA would have returned us the 'root_uuid_or_disk_id' if image + # being provisioned is a whole disk image. IPA would also provide us + # 'efi_system_partition_uuid' if the image being provisioned is a + # partition image. + # In case of local boot using partition image, we need both + # 'root_uuid_or_disk_id' and 'efi_system_partition_uuid' to configure + # bootloader for local boot. + driver_internal_info = task.node.driver_internal_info + root_uuid = self._get_uuid_from_result(task, 'root_uuid') + if root_uuid: + driver_internal_info['root_uuid_or_disk_id'] = root_uuid + task.node.driver_internal_info = driver_internal_info + task.node.save() + elif iwdi and CONF.agent.manage_agent_boot: + # IPA version less than 3.1.0 will not return root_uuid for + # whole disk image. Also IPA version introduced a requirement + # for hexdump utility that may not be always available. Need to + # fall back to older behavior for the same. + LOG.warning("With the deploy ramdisk based on Ironic Python Agent " + "version 3.1.0 and beyond, the drivers using " + "`direct` deploy interface performs `netboot` or " + "`local` boot for whole disk image based on value " + "of boot option setting. When you upgrade Ironic " + "Python Agent in your deploy ramdisk, ensure that " + "boot option is set appropriately for the node %s. " + "The boot option can be set using configuration " + "`[deploy]/default_boot_option` or as a `boot_option` " + "capability in node's `properties['capabilities']`. " + "Also please note that this functionality requires " + "`hexdump` command in the ramdisk.", node.uuid) + + efi_sys_uuid = None if not iwdi: - root_uuid = self._get_uuid_from_result(task, 'root_uuid') if deploy_utils.get_boot_mode_for_deploy(node) == 'uefi': efi_sys_uuid = ( self._get_uuid_from_result(task, 'efi_system_partition_uuid')) - else: - efi_sys_uuid = None - driver_internal_info = task.node.driver_internal_info - driver_internal_info['root_uuid_or_disk_id'] = root_uuid - task.node.driver_internal_info = driver_internal_info - task.node.save() - self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid) LOG.info('Image successfully written to node %s', node.uuid) - LOG.debug('Rebooting node %s to instance', node.uuid) - if iwdi: + + if CONF.agent.manage_agent_boot: + # It is necessary to invoke prepare_instance() of the node's + # boot interface, so that the any necessary configurations like + # setting of the boot mode (e.g. UEFI secure boot) which cannot + # be done on node during deploy stage can be performed. + LOG.debug('Executing driver specific tasks before booting up the ' + 'instance for node %s', node.uuid) + self.prepare_instance_to_boot(task, root_uuid, efi_sys_uuid) + else: manager_utils.node_set_boot_device(task, 'disk', persistent=True) + LOG.debug('Rebooting node %s to instance', node.uuid) self.reboot_and_finish_deploy(task) - # NOTE(TheJulia): If we deployed a whole disk image, we - # should expect a whole disk image and clean-up the tftp files - # on-disk incase the node is disregarding the boot preference. - # TODO(rameshg87): Not all in-tree drivers using reboot_to_instance - # have a boot interface. So include a check for now. Remove this - # check once all in-tree drivers have a boot interface. - if task.driver.boot and iwdi: - task.driver.boot.clean_up_ramdisk(task) - class AgentDeploy(AgentDeployMixin, base.DeployInterface): """Interface for deploy-related actions.""" @@ -440,11 +469,36 @@ class AgentDeploy(AgentDeployMixin, base.DeployInterface): wrong occurred during the power action. :raises: exception.ImageRefValidationFailed if image_source is not Glance href and is not HTTP(S) URL. + :raises: exception.InvalidParameterValue if network validation fails. :raises: any boot interface's prepare_ramdisk exceptions. """ node = task.node deploy_utils.populate_storage_driver_internal_info(task) if node.provision_state == states.DEPLOYING: + # Validate network interface to ensure that it supports boot + # options configured on the node. + try: + task.driver.network.validate(task) + except exception.InvalidParameterValue: + # For 'neutron' network interface validation will fail + # if node is using 'netboot' boot option while provisioning + # a whole disk image. Updating 'boot_option' in node's + # 'instance_info' to 'local for backward compatibility. + # TODO(stendulker): Fail here once the default boot + # option is local. + with excutils.save_and_reraise_exception(reraise=False) as ctx: + instance_info = node.instance_info + capabilities = instance_info.get('capabilities', {}) + if 'boot_option' not in capabilities: + capabilities['boot_option'] = 'local' + instance_info['capabilities'] = capabilities + node.instance_info = instance_info + node.save() + # Re-validate the network interface + task.driver.network.validate(task) + else: + ctx.reraise = True + # Adding the node to provisioning network so that the dhcp # options get added for the provisioning port. manager_utils.node_power_action(task, states.POWER_OFF) diff --git a/ironic/drivers/modules/network/neutron.py b/ironic/drivers/modules/network/neutron.py index 7bef57ce0..5bba613db 100644 --- a/ironic/drivers/modules/network/neutron.py +++ b/ironic/drivers/modules/network/neutron.py @@ -20,7 +20,9 @@ from oslo_log import log from ironic.common import exception from ironic.common.i18n import _ from ironic.common import neutron +from ironic.common import states from ironic.drivers import base +from ironic.drivers.modules import deploy_utils from ironic.drivers.modules.network import common LOG = log.getLogger(__name__) @@ -59,6 +61,15 @@ class NeutronNetwork(common.NeutronVIFPortIDMixin, """ self.get_cleaning_network_uuid(task) self.get_provisioning_network_uuid(task) + node = task.node + if (node.provision_state == states.DEPLOYING and + node.driver_internal_info.get('is_whole_disk_image') and + deploy_utils.get_boot_option(node) == 'netboot'): + error_msg = (_('The node %s cannot perform "local" boot for ' + 'whole disk image when node is using "neutron" ' + 'network and is configured with "netboot" boot ' + 'option.') % node.uuid) + raise exception.InvalidParameterValue(error_msg) def add_provisioning_network(self, task): """Add the provisioning network to a node. diff --git a/ironic/drivers/modules/pxe.py b/ironic/drivers/modules/pxe.py index 8ce679a4f..e43cdf5d1 100644 --- a/ironic/drivers/modules/pxe.py +++ b/ironic/drivers/modules/pxe.py @@ -639,7 +639,10 @@ class PXEBoot(base.BootInterface): 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}) + "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) |