Merge "Correctly rebuild the PXE file during takeover of ACTIVE nodes"
This commit is contained in:
commit
eb05d31227
@ -413,6 +413,26 @@ class PXEDeploy(base.DeployInterface):
|
||||
# the image kernel and ramdisk (Or even require it).
|
||||
_cache_ramdisk_kernel(task.context, task.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 task.node.provision_state == states.ACTIVE:
|
||||
try:
|
||||
# this should have been stashed when the deploy was done
|
||||
# but let's guard, just in case it's missing
|
||||
root_uuid = task.node.driver_internal_info['root_uuid']
|
||||
except KeyError:
|
||||
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": task.node.uuid})
|
||||
else:
|
||||
pxe_config_path = pxe_utils.get_pxe_config_file_path(
|
||||
task.node.uuid)
|
||||
deploy_utils.switch_pxe_config(
|
||||
pxe_config_path, root_uuid,
|
||||
driver_utils.get_node_capability(task.node, 'boot_mode'))
|
||||
|
||||
def clean_up(self, task):
|
||||
"""Clean up the deployment environment for the task's node.
|
||||
|
||||
@ -497,6 +517,15 @@ class VendorPassthru(base.VendorInterface):
|
||||
if not root_uuid:
|
||||
return
|
||||
|
||||
# save the node's root disk UUID so that another conductor could
|
||||
# rebuild the PXE config file. Due to a shortcoming in Nova objects,
|
||||
# we have to assign to node.driver_internal_info so the node knows it
|
||||
# has changed.
|
||||
driver_internal_info = node.driver_internal_info
|
||||
driver_internal_info['root_uuid'] = root_uuid
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
|
||||
try:
|
||||
if iscsi_deploy.get_boot_option(node) == "local":
|
||||
try_set_boot_device(task, boot_devices.DISK)
|
||||
|
@ -38,6 +38,7 @@ from ironic.conductor import utils as manager_utils
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules import iscsi_deploy
|
||||
from ironic.drivers.modules import pxe
|
||||
from ironic.drivers import utils as driver_utils
|
||||
from ironic.openstack.common import fileutils
|
||||
from ironic.tests.conductor import utils as mgr_utils
|
||||
from ironic.tests.db import base as db_base
|
||||
@ -504,6 +505,71 @@ class PXEDriverTestCase(db_base.DbTestCase):
|
||||
mock_cache_r_k.assert_called_once_with(self.context,
|
||||
task.node, None)
|
||||
|
||||
@mock.patch.object(pxe, '_get_image_info')
|
||||
@mock.patch.object(pxe, '_cache_ramdisk_kernel')
|
||||
@mock.patch.object(pxe, '_build_pxe_config_options')
|
||||
@mock.patch.object(pxe_utils, 'create_pxe_config')
|
||||
@mock.patch.object(pxe_utils, 'get_pxe_config_file_path')
|
||||
@mock.patch.object(deploy_utils, 'switch_pxe_config')
|
||||
def test_prepare_node_active_missing_root_uuid(self,
|
||||
mock_switch,
|
||||
mock_pxe_get_cfg,
|
||||
mock_pxe_config,
|
||||
mock_build_pxe,
|
||||
mock_cache_r_k,
|
||||
mock_img_info):
|
||||
mock_build_pxe.return_value = None
|
||||
mock_img_info.return_value = None
|
||||
self.node.provision_state = states.ACTIVE
|
||||
self.node.save()
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.driver.deploy.prepare(task)
|
||||
mock_img_info.assert_called_once_with(task.node,
|
||||
self.context)
|
||||
mock_pxe_config.assert_called_once_with(
|
||||
task, None, CONF.pxe.pxe_config_template)
|
||||
mock_cache_r_k.assert_called_once_with(self.context,
|
||||
task.node, None)
|
||||
self.assertFalse(mock_pxe_get_cfg.called)
|
||||
self.assertFalse(mock_switch.called)
|
||||
|
||||
@mock.patch.object(pxe, '_get_image_info')
|
||||
@mock.patch.object(pxe, '_cache_ramdisk_kernel')
|
||||
@mock.patch.object(pxe, '_build_pxe_config_options')
|
||||
@mock.patch.object(pxe_utils, 'create_pxe_config')
|
||||
@mock.patch.object(pxe_utils, 'get_pxe_config_file_path')
|
||||
@mock.patch.object(deploy_utils, 'switch_pxe_config')
|
||||
@mock.patch.object(driver_utils, 'get_node_capability')
|
||||
def test_prepare_node_active(self,
|
||||
mock_get_cap,
|
||||
mock_switch,
|
||||
mock_pxe_get_cfg,
|
||||
mock_pxe_config,
|
||||
mock_build_pxe,
|
||||
mock_cache_r_k,
|
||||
mock_img_info):
|
||||
mock_build_pxe.return_value = None
|
||||
mock_img_info.return_value = None
|
||||
mock_pxe_get_cfg.return_value = '/path'
|
||||
mock_get_cap.return_value = None
|
||||
|
||||
self.node.provision_state = states.ACTIVE
|
||||
self.node.driver_internal_info = {'root_uuid': 'abcd'}
|
||||
self.node.save()
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.driver.deploy.prepare(task)
|
||||
mock_img_info.assert_called_once_with(task.node,
|
||||
self.context)
|
||||
mock_pxe_config.assert_called_once_with(
|
||||
task, None, CONF.pxe.pxe_config_template)
|
||||
mock_cache_r_k.assert_called_once_with(self.context,
|
||||
task.node, None)
|
||||
|
||||
mock_pxe_get_cfg.assert_called_once_with(task.node.uuid)
|
||||
mock_switch.assert_called_once_with('/path', 'abcd', None)
|
||||
|
||||
@mock.patch.object(keystone, 'token_expires_soon')
|
||||
@mock.patch.object(deploy_utils, 'get_image_mb')
|
||||
@mock.patch.object(iscsi_deploy, '_get_image_file_path')
|
||||
@ -656,6 +722,7 @@ class PXEDriverTestCase(db_base.DbTestCase):
|
||||
self.assertEqual(states.ACTIVE, self.node.provision_state)
|
||||
self.assertEqual(states.NOSTATE, self.node.target_provision_state)
|
||||
self.assertEqual(states.POWER_ON, self.node.power_state)
|
||||
self.assertIn('root_uuid', self.node.driver_internal_info)
|
||||
self.assertIsNone(self.node.last_error)
|
||||
self.assertFalse(os.path.exists(token_path))
|
||||
mock_image_cache.assert_called_once_with()
|
||||
|
Loading…
x
Reference in New Issue
Block a user