Merge "Correctly rebuild the PXE file during takeover of ACTIVE nodes"

This commit is contained in:
Jenkins 2015-02-20 13:30:36 +00:00 committed by Gerrit Code Review
commit eb05d31227
2 changed files with 96 additions and 0 deletions

View File

@ -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)

View File

@ -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()