Merge "Generate iPXE boot script when deploying with boot from volume"
This commit is contained in:
commit
4035eb7942
@ -452,16 +452,18 @@ class AgentDeploy(AgentDeployMixin, base.DeployInterface):
|
|||||||
if node.provision_state == states.ACTIVE:
|
if node.provision_state == states.ACTIVE:
|
||||||
# Call is due to conductor takeover
|
# Call is due to conductor takeover
|
||||||
task.driver.boot.prepare_instance(task)
|
task.driver.boot.prepare_instance(task)
|
||||||
elif not task.driver.storage.should_write_image(task):
|
|
||||||
# We have nothing else to do as this is handled in the
|
|
||||||
# backend storage system.
|
|
||||||
return
|
|
||||||
elif node.provision_state != states.ADOPTING:
|
elif node.provision_state != states.ADOPTING:
|
||||||
node.instance_info = deploy_utils.build_instance_info_for_deploy(
|
|
||||||
task)
|
if task.driver.storage.should_write_image(task):
|
||||||
node.save()
|
instance_info = deploy_utils.build_instance_info_for_deploy(
|
||||||
|
task)
|
||||||
|
node.instance_info = instance_info
|
||||||
|
node.save()
|
||||||
if CONF.agent.manage_agent_boot:
|
if CONF.agent.manage_agent_boot:
|
||||||
deploy_opts = deploy_utils.build_agent_options(node)
|
if task.driver.storage.should_write_image(task):
|
||||||
|
deploy_opts = deploy_utils.build_agent_options(node)
|
||||||
|
else:
|
||||||
|
deploy_opts = None
|
||||||
task.driver.boot.prepare_ramdisk(task, deploy_opts)
|
task.driver.boot.prepare_ramdisk(task, deploy_opts)
|
||||||
|
|
||||||
@METRICS.timer('AgentDeploy.clean_up')
|
@METRICS.timer('AgentDeploy.clean_up')
|
||||||
|
@ -472,6 +472,8 @@ class PXEBoot(base.BootInterface):
|
|||||||
if (not os.path.isfile(bootfile_path) or
|
if (not os.path.isfile(bootfile_path) or
|
||||||
not utils.file_has_content(bootfile_path, boot_script)):
|
not utils.file_has_content(bootfile_path, boot_script)):
|
||||||
utils.write_to_file(bootfile_path, boot_script)
|
utils.write_to_file(bootfile_path, boot_script)
|
||||||
|
if not task.driver.storage.should_write_image(task):
|
||||||
|
return
|
||||||
|
|
||||||
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
|
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
|
||||||
provider = dhcp_factory.DHCPFactory()
|
provider = dhcp_factory.DHCPFactory()
|
||||||
|
@ -426,6 +426,30 @@ class TestAgentDeploy(db_base.DbTestCase):
|
|||||||
self.assertFalse(pxe_prepare_ramdisk_mock.called)
|
self.assertFalse(pxe_prepare_ramdisk_mock.called)
|
||||||
self.assertFalse(add_provisioning_net_mock.called)
|
self.assertFalse(add_provisioning_net_mock.called)
|
||||||
|
|
||||||
|
@mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.'
|
||||||
|
'add_provisioning_network', autospec=True)
|
||||||
|
@mock.patch.object(pxe.PXEBoot, 'prepare_ramdisk')
|
||||||
|
@mock.patch.object(deploy_utils, 'build_agent_options')
|
||||||
|
@mock.patch.object(deploy_utils, 'build_instance_info_for_deploy')
|
||||||
|
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
|
||||||
|
autospec=True)
|
||||||
|
def test_prepare_boot_from_volume(self, mock_write,
|
||||||
|
build_instance_info_mock,
|
||||||
|
build_options_mock,
|
||||||
|
pxe_prepare_ramdisk_mock,
|
||||||
|
add_provisioning_net_mock):
|
||||||
|
mock_write.return_value = False
|
||||||
|
with task_manager.acquire(
|
||||||
|
self.context, self.node['uuid'], shared=False) as task:
|
||||||
|
task.node.provision_state = states.DEPLOYING
|
||||||
|
build_instance_info_mock.return_value = {'foo': 'bar'}
|
||||||
|
build_options_mock.return_value = {'a': 'b'}
|
||||||
|
|
||||||
|
self.driver.prepare(task)
|
||||||
|
build_instance_info_mock.assert_not_called()
|
||||||
|
build_options_mock.assert_not_called()
|
||||||
|
pxe_prepare_ramdisk_mock.assert_called_once_with(task, None)
|
||||||
|
|
||||||
@mock.patch('ironic.common.dhcp_factory.DHCPFactory._set_dhcp_provider')
|
@mock.patch('ironic.common.dhcp_factory.DHCPFactory._set_dhcp_provider')
|
||||||
@mock.patch('ironic.common.dhcp_factory.DHCPFactory.clean_dhcp')
|
@mock.patch('ironic.common.dhcp_factory.DHCPFactory.clean_dhcp')
|
||||||
@mock.patch.object(pxe.PXEBoot, 'clean_up_instance')
|
@mock.patch.object(pxe.PXEBoot, 'clean_up_instance')
|
||||||
|
@ -808,7 +808,10 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||||||
@mock.patch.object(pxe, '_cache_ramdisk_kernel', autospec=True)
|
@mock.patch.object(pxe, '_cache_ramdisk_kernel', autospec=True)
|
||||||
@mock.patch.object(pxe, '_build_pxe_config_options', autospec=True)
|
@mock.patch.object(pxe, '_build_pxe_config_options', autospec=True)
|
||||||
@mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True)
|
@mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True)
|
||||||
def _test_prepare_ramdisk(self, mock_pxe_config,
|
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
|
||||||
|
autospec=True)
|
||||||
|
def _test_prepare_ramdisk(self, mock_should_write_image,
|
||||||
|
mock_pxe_config,
|
||||||
mock_build_pxe, mock_cache_r_k,
|
mock_build_pxe, mock_cache_r_k,
|
||||||
mock_deploy_img_info,
|
mock_deploy_img_info,
|
||||||
mock_instance_img_info,
|
mock_instance_img_info,
|
||||||
@ -817,7 +820,9 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||||||
uefi=False,
|
uefi=False,
|
||||||
cleaning=False,
|
cleaning=False,
|
||||||
ipxe_use_swift=False,
|
ipxe_use_swift=False,
|
||||||
whole_disk_image=False):
|
whole_disk_image=False,
|
||||||
|
should_write_image=True):
|
||||||
|
mock_should_write_image.return_value = should_write_image
|
||||||
mock_build_pxe.return_value = {}
|
mock_build_pxe.return_value = {}
|
||||||
mock_deploy_img_info.return_value = {'deploy_kernel': 'a'}
|
mock_deploy_img_info.return_value = {'deploy_kernel': 'a'}
|
||||||
if whole_disk_image:
|
if whole_disk_image:
|
||||||
@ -833,38 +838,51 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||||||
self.node.driver_internal_info = driver_internal_info
|
self.node.driver_internal_info = driver_internal_info
|
||||||
self.node.save()
|
self.node.save()
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
|
if should_write_image:
|
||||||
|
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
|
||||||
task.driver.boot.prepare_ramdisk(task, {'foo': 'bar'})
|
task.driver.boot.prepare_ramdisk(task, {'foo': 'bar'})
|
||||||
mock_deploy_img_info.assert_called_once_with(task.node)
|
if should_write_image:
|
||||||
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
|
mock_deploy_img_info.assert_called_once_with(task.node)
|
||||||
set_boot_device_mock.assert_called_once_with(task,
|
provider_mock.update_dhcp.assert_called_once_with(task,
|
||||||
boot_devices.PXE,
|
dhcp_opts)
|
||||||
persistent=False)
|
set_boot_device_mock.assert_called_once_with(task,
|
||||||
if ipxe_use_swift:
|
boot_devices.PXE,
|
||||||
if whole_disk_image:
|
persistent=False)
|
||||||
self.assertFalse(mock_cache_r_k.called)
|
if ipxe_use_swift:
|
||||||
|
if whole_disk_image:
|
||||||
|
self.assertFalse(mock_cache_r_k.called)
|
||||||
|
else:
|
||||||
|
mock_cache_r_k.assert_called_once_with(
|
||||||
|
self.context, task.node,
|
||||||
|
{'kernel': 'b'})
|
||||||
|
mock_instance_img_info.assert_called_once_with(
|
||||||
|
task.node, self.context)
|
||||||
|
elif cleaning is False:
|
||||||
|
mock_cache_r_k.assert_called_once_with(
|
||||||
|
self.context, task.node,
|
||||||
|
{'deploy_kernel': 'a', 'kernel': 'b'})
|
||||||
|
mock_instance_img_info.assert_called_once_with(
|
||||||
|
task.node, self.context)
|
||||||
else:
|
else:
|
||||||
mock_cache_r_k.assert_called_once_with(
|
mock_cache_r_k.assert_called_once_with(
|
||||||
self.context, task.node,
|
self.context, task.node,
|
||||||
{'kernel': 'b'})
|
{'deploy_kernel': 'a'})
|
||||||
mock_instance_img_info.assert_called_once_with(task.node,
|
if uefi:
|
||||||
self.context)
|
mock_pxe_config.assert_called_once_with(
|
||||||
elif cleaning is False:
|
task, {'foo': 'bar'},
|
||||||
mock_cache_r_k.assert_called_once_with(
|
CONF.pxe.uefi_pxe_config_template)
|
||||||
self.context, task.node,
|
else:
|
||||||
{'deploy_kernel': 'a', 'kernel': 'b'})
|
mock_pxe_config.assert_called_once_with(
|
||||||
mock_instance_img_info.assert_called_once_with(task.node,
|
task, {'foo': 'bar'}, CONF.pxe.pxe_config_template)
|
||||||
self.context)
|
|
||||||
else:
|
else:
|
||||||
mock_cache_r_k.assert_called_once_with(
|
# When booting from volume we return early.
|
||||||
self.context, task.node,
|
# Check that nothing was called
|
||||||
{'deploy_kernel': 'a'})
|
self.assertFalse(mock_pxe_config.called)
|
||||||
if uefi:
|
self.assertFalse(mock_build_pxe.called)
|
||||||
mock_pxe_config.assert_called_once_with(
|
self.assertFalse(mock_cache_r_k.called)
|
||||||
task, {'foo': 'bar'}, CONF.pxe.uefi_pxe_config_template)
|
self.assertFalse(mock_deploy_img_info.called)
|
||||||
else:
|
self.assertFalse(mock_instance_img_info.called)
|
||||||
mock_pxe_config.assert_called_once_with(
|
self.assertFalse(dhcp_factory_mock.called)
|
||||||
task, {'foo': 'bar'}, CONF.pxe.pxe_config_template)
|
|
||||||
|
|
||||||
def test_prepare_ramdisk(self):
|
def test_prepare_ramdisk(self):
|
||||||
self.node.provision_state = states.DEPLOYING
|
self.node.provision_state = states.DEPLOYING
|
||||||
@ -926,6 +944,28 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||||||
CONF.pxe.ipxe_boot_script,
|
CONF.pxe.ipxe_boot_script,
|
||||||
{'ipxe_for_mac_uri': 'pxelinux.cfg/'})
|
{'ipxe_for_mac_uri': 'pxelinux.cfg/'})
|
||||||
|
|
||||||
|
@mock.patch.object(os.path, 'isfile', autospec=True)
|
||||||
|
@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_boot_from_volume(
|
||||||
|
self, render_mock, write_mock, cmp_mock, isfile_mock):
|
||||||
|
self.node.provision_state = states.DEPLOYING
|
||||||
|
self.node.save()
|
||||||
|
self.config(group='pxe', ipxe_enabled=True)
|
||||||
|
isfile_mock.return_value = False
|
||||||
|
render_mock.return_value = 'foo'
|
||||||
|
self._test_prepare_ramdisk(should_write_image=False)
|
||||||
|
self.assertFalse(cmp_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', autospec=True)
|
@mock.patch.object(os.path, 'isfile', autospec=True)
|
||||||
@mock.patch('ironic.common.utils.file_has_content', autospec=True)
|
@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.write_to_file', autospec=True)
|
||||||
|
Loading…
Reference in New Issue
Block a user