summaryrefslogtreecommitdiff
path: root/ironic/drivers
diff options
context:
space:
mode:
authorShivanand Tendulker <stendulker@gmail.com>2017-08-30 03:50:32 -0400
committerShivanand Tendulker <stendulker@gmail.com>2018-04-18 02:49:37 -0400
commit4fa1075b95e2e5262f98395275590dcd3833ab74 (patch)
tree6e2a0ab81b8aa35a9c90f5cce02d10aded31ed8e /ironic/drivers
parent46ee76aa461cd012a2b39dcb16c414957c463b72 (diff)
downloadironic-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.py92
-rw-r--r--ironic/drivers/modules/network/neutron.py11
-rw-r--r--ironic/drivers/modules/pxe.py5
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)