Merge "Allow using TempURLs for deploy images"
This commit is contained in:
commit
f41c26d4f2
|
@ -212,6 +212,8 @@ IRONIC_HOSTPORT=${IRONIC_HOSTPORT:-$SERVICE_HOST:$IRONIC_SERVICE_PORT}
|
|||
|
||||
# Enable iPXE
|
||||
IRONIC_IPXE_ENABLED=$(trueorfalse True IRONIC_IPXE_ENABLED)
|
||||
# Options below are only applied when IRONIC_IPXE_ENABLED is True
|
||||
IRONIC_IPXE_USE_SWIFT=$(trueorfalse False IRONIC_IPXE_USE_SWIFT)
|
||||
IRONIC_HTTP_DIR=${IRONIC_HTTP_DIR:-$IRONIC_DATA_DIR/httpboot}
|
||||
IRONIC_HTTP_SERVER=${IRONIC_HTTP_SERVER:-$IRONIC_TFTPSERVER_IP}
|
||||
IRONIC_HTTP_PORT=${IRONIC_HTTP_PORT:-3928}
|
||||
|
@ -743,6 +745,9 @@ function configure_ironic_conductor {
|
|||
iniset $IRONIC_CONF_FILE pxe pxe_bootfile_name $pxebin
|
||||
iniset $IRONIC_CONF_FILE deploy http_root $IRONIC_HTTP_DIR
|
||||
iniset $IRONIC_CONF_FILE deploy http_url "http://$IRONIC_HTTP_SERVER:$IRONIC_HTTP_PORT"
|
||||
if [[ "$IRONIC_IPXE_USE_SWIFT" == "True" ]]; then
|
||||
iniset $IRONIC_CONF_FILE pxe ipxe_use_swift True
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
|
||||
|
|
|
@ -2758,6 +2758,13 @@
|
|||
# Allowed values: 4, 6
|
||||
#ip_version = 4
|
||||
|
||||
# Download deploy images directly from swift using temporary
|
||||
# URLs. If set to false (default), images are downloaded to
|
||||
# the ironic-conductor node and served over its local HTTP
|
||||
# server. Applicable only when 'ipxe_enabled' option is set to
|
||||
# true. (boolean value)
|
||||
#ipxe_use_swift = false
|
||||
|
||||
|
||||
[seamicro]
|
||||
|
||||
|
|
|
@ -96,6 +96,16 @@ opts = [
|
|||
choices=['4', '6'],
|
||||
help=_('The IP version that will be used for PXE booting. '
|
||||
'Defaults to 4. EXPERIMENTAL')),
|
||||
cfg.BoolOpt('ipxe_use_swift',
|
||||
default=False,
|
||||
help=_("Download deploy images directly from swift using "
|
||||
"temporary URLs. "
|
||||
"If set to false (default), images are downloaded "
|
||||
"to the ironic-conductor node and served over its "
|
||||
"local HTTP server. "
|
||||
"Applicable only when 'ipxe_enabled' option is "
|
||||
"set to true.")),
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ from ironic.common import exception
|
|||
from ironic.common.glance_service import service_utils
|
||||
from ironic.common.i18n import _, _LE, _LW
|
||||
from ironic.common import image_service as service
|
||||
from ironic.common import images
|
||||
from ironic.common import pxe_utils
|
||||
from ironic.common import states
|
||||
from ironic.conf import CONF
|
||||
|
@ -81,11 +82,15 @@ def _get_instance_image_info(node, ctx):
|
|||
:param ctx: context
|
||||
:returns: a dictionary whose keys are the names of the images (kernel,
|
||||
ramdisk) and values are the absolute paths of them. If it's a whole
|
||||
disk image, it returns an empty dictionary.
|
||||
disk image or node is configured for localboot,
|
||||
it returns an empty dictionary.
|
||||
"""
|
||||
image_info = {}
|
||||
if node.driver_internal_info.get('is_whole_disk_image'):
|
||||
return image_info
|
||||
# NOTE(pas-ha) do not report image kernel and ramdisk for
|
||||
# local boot or whole disk images so that they are not cached
|
||||
if (node.driver_internal_info.get('is_whole_disk_image') or
|
||||
deploy_utils.get_boot_option(node) == 'local'):
|
||||
return image_info
|
||||
|
||||
root_dir = pxe_utils.get_root_dir()
|
||||
i_info = node.instance_info
|
||||
|
@ -125,6 +130,48 @@ def _get_deploy_image_info(node):
|
|||
return pxe_utils.get_deploy_kr_info(node.uuid, d_info)
|
||||
|
||||
|
||||
def _get_pxe_kernel_ramdisk(pxe_info):
|
||||
pxe_opts = {}
|
||||
pxe_opts['deployment_aki_path'] = pxe_info['deploy_kernel'][1]
|
||||
pxe_opts['deployment_ari_path'] = pxe_info['deploy_ramdisk'][1]
|
||||
# It is possible that we don't have kernel/ramdisk or even
|
||||
# image_source to determine if it's a whole disk image or not.
|
||||
# For example, when transitioning to 'available' state for first
|
||||
# time from 'manage' state.
|
||||
if 'kernel' in pxe_info:
|
||||
pxe_opts['aki_path'] = pxe_info['kernel'][1]
|
||||
if 'ramdisk' in pxe_info:
|
||||
pxe_opts['ari_path'] = pxe_info['ramdisk'][1]
|
||||
return pxe_opts
|
||||
|
||||
|
||||
def _get_ipxe_kernel_ramdisk(task, pxe_info):
|
||||
pxe_opts = {}
|
||||
node = task.node
|
||||
|
||||
for label, option in (('deploy_kernel', 'deployment_aki_path'),
|
||||
('deploy_ramdisk', 'deployment_ari_path')):
|
||||
image_href = pxe_info[label][0]
|
||||
if (CONF.pxe.ipxe_use_swift and
|
||||
service_utils.is_glance_image(image_href)):
|
||||
pxe_opts[option] = images.get_temp_url_for_glance_image(
|
||||
task.context, image_href)
|
||||
else:
|
||||
pxe_opts[option] = '/'.join([CONF.deploy.http_url, node.uuid,
|
||||
label])
|
||||
# NOTE(pas-ha) do not use Swift TempURLs for kernel and ramdisk
|
||||
# of user image when boot_option is not local,
|
||||
# as this will break instance reboot later when temp urls have timed out.
|
||||
if 'kernel' in pxe_info:
|
||||
pxe_opts['aki_path'] = '/'.join(
|
||||
[CONF.deploy.http_url, node.uuid, 'kernel'])
|
||||
if 'ramdisk' in pxe_info:
|
||||
pxe_opts['ari_path'] = '/'.join(
|
||||
[CONF.deploy.http_url, node.uuid, 'ramdisk'])
|
||||
|
||||
return pxe_opts
|
||||
|
||||
|
||||
def _build_pxe_config_options(task, pxe_info):
|
||||
"""Build the PXE config options for a node
|
||||
|
||||
|
@ -139,47 +186,21 @@ def _build_pxe_config_options(task, pxe_info):
|
|||
:returns: A dictionary of pxe options to be used in the pxe bootfile
|
||||
template.
|
||||
"""
|
||||
node = task.node
|
||||
is_whole_disk_image = node.driver_internal_info.get('is_whole_disk_image')
|
||||
if CONF.pxe.ipxe_enabled:
|
||||
pxe_options = _get_ipxe_kernel_ramdisk(task, pxe_info)
|
||||
else:
|
||||
pxe_options = _get_pxe_kernel_ramdisk(pxe_info)
|
||||
|
||||
# These are dummy values to satisfy elilo.
|
||||
# image and initrd fields in elilo config cannot be blank.
|
||||
kernel = 'no_kernel'
|
||||
ramdisk = 'no_ramdisk'
|
||||
pxe_options.setdefault('aki_path', 'no_kernel')
|
||||
pxe_options.setdefault('ari_path', 'no_ramdisk')
|
||||
|
||||
if CONF.pxe.ipxe_enabled:
|
||||
deploy_kernel = '/'.join([CONF.deploy.http_url, node.uuid,
|
||||
'deploy_kernel'])
|
||||
deploy_ramdisk = '/'.join([CONF.deploy.http_url, node.uuid,
|
||||
'deploy_ramdisk'])
|
||||
if not is_whole_disk_image:
|
||||
kernel = '/'.join([CONF.deploy.http_url, node.uuid,
|
||||
'kernel'])
|
||||
ramdisk = '/'.join([CONF.deploy.http_url, node.uuid,
|
||||
'ramdisk'])
|
||||
else:
|
||||
deploy_kernel = pxe_info['deploy_kernel'][1]
|
||||
deploy_ramdisk = pxe_info['deploy_ramdisk'][1]
|
||||
if not is_whole_disk_image:
|
||||
# It is possible that we don't have kernel/ramdisk or even
|
||||
# image_source to determine if it's a whole disk image or not.
|
||||
# For example, when transitioning to 'available' state for first
|
||||
# time from 'manage' state. Retain dummy values if we don't have
|
||||
# kernel/ramdisk.
|
||||
if 'kernel' in pxe_info:
|
||||
kernel = pxe_info['kernel'][1]
|
||||
if 'ramdisk' in pxe_info:
|
||||
ramdisk = pxe_info['ramdisk'][1]
|
||||
|
||||
pxe_options = {
|
||||
'deployment_aki_path': deploy_kernel,
|
||||
'deployment_ari_path': deploy_ramdisk,
|
||||
pxe_options.update({
|
||||
'pxe_append_params': CONF.pxe.pxe_append_params,
|
||||
'tftp_server': CONF.pxe.tftp_server,
|
||||
'aki_path': kernel,
|
||||
'ari_path': ramdisk,
|
||||
'ipxe_timeout': CONF.pxe.ipxe_timeout * 1000
|
||||
}
|
||||
})
|
||||
|
||||
return pxe_options
|
||||
|
||||
|
@ -324,7 +345,8 @@ class PXEBoot(base.BootInterface):
|
|||
|
||||
_parse_driver_info(node)
|
||||
d_info = deploy_utils.get_image_instance_info(node)
|
||||
if node.driver_internal_info.get('is_whole_disk_image'):
|
||||
if (node.driver_internal_info.get('is_whole_disk_image') or
|
||||
deploy_utils.get_boot_option(node) == 'local'):
|
||||
props = []
|
||||
elif service_utils.is_glance_image(d_info['image_source']):
|
||||
props = ['kernel_id', 'ramdisk_id']
|
||||
|
@ -386,9 +408,11 @@ class PXEBoot(base.BootInterface):
|
|||
pxe_config_template)
|
||||
deploy_utils.try_set_boot_device(task, boot_devices.PXE)
|
||||
|
||||
# FIXME(lucasagomes): If it's local boot we should not cache
|
||||
# the image kernel and ramdisk (Or even require it).
|
||||
_cache_ramdisk_kernel(task.context, node, pxe_info)
|
||||
if CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_use_swift:
|
||||
pxe_info.pop('deploy_kernel', None)
|
||||
pxe_info.pop('deploy_ramdisk', None)
|
||||
if pxe_info:
|
||||
_cache_ramdisk_kernel(task.context, node, pxe_info)
|
||||
|
||||
@METRICS.timer('PXEBoot.clean_up_ramdisk')
|
||||
def clean_up_ramdisk(self, task):
|
||||
|
|
|
@ -19,6 +19,7 @@ import filecmp
|
|||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
from ironic_lib import utils as ironic_utils
|
||||
import mock
|
||||
|
@ -145,6 +146,14 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
self.node.save()
|
||||
self._test__get_instance_image_info()
|
||||
|
||||
@mock.patch('ironic.drivers.modules.deploy_utils.get_boot_option',
|
||||
return_value='local')
|
||||
def test__get_instance_image_info_localboot(self, boot_opt_mock):
|
||||
self.node.driver_internal_info['is_whole_disk_image'] = False
|
||||
self.node.save()
|
||||
image_info = pxe._get_instance_image_info(self.node, self.context)
|
||||
self.assertEqual({}, image_info)
|
||||
|
||||
@mock.patch.object(base_image_service.BaseImageService, '_show',
|
||||
autospec=True)
|
||||
def test__get_instance_image_info_whole_disk_image(self, show_mock):
|
||||
|
@ -154,11 +163,14 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
image_info = pxe._get_instance_image_info(self.node, self.context)
|
||||
self.assertEqual({}, image_info)
|
||||
|
||||
@mock.patch('ironic.common.image_service.GlanceImageService',
|
||||
autospec=True)
|
||||
@mock.patch.object(pxe_utils, '_build_pxe_config', autospec=True)
|
||||
def _test_build_pxe_config_options(self, build_pxe_mock,
|
||||
def _test_build_pxe_config_options(self, build_pxe_mock, glance_mock,
|
||||
whle_dsk_img=False,
|
||||
ipxe_enabled=False,
|
||||
ipxe_timeout=0):
|
||||
ipxe_timeout=0,
|
||||
ipxe_use_swift=False):
|
||||
self.config(pxe_append_params='test_param', group='pxe')
|
||||
# NOTE: right '/' should be removed from url string
|
||||
self.config(api_url='http://192.168.122.184:6385', group='conductor')
|
||||
|
@ -175,11 +187,18 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
http_url = 'http://192.1.2.3:1234'
|
||||
self.config(ipxe_enabled=True, group='pxe')
|
||||
self.config(http_url=http_url, group='deploy')
|
||||
|
||||
deploy_kernel = os.path.join(http_url, self.node.uuid,
|
||||
'deploy_kernel')
|
||||
deploy_ramdisk = os.path.join(http_url, self.node.uuid,
|
||||
'deploy_ramdisk')
|
||||
if ipxe_use_swift:
|
||||
self.config(ipxe_use_swift=True, group='pxe')
|
||||
glance = mock.Mock()
|
||||
glance_mock.return_value = glance
|
||||
glance.swift_temp_url.side_effect = [
|
||||
deploy_kernel, deploy_ramdisk] = [
|
||||
'swift_kernel', 'swift_ramdisk']
|
||||
else:
|
||||
deploy_kernel = os.path.join(http_url, self.node.uuid,
|
||||
'deploy_kernel')
|
||||
deploy_ramdisk = os.path.join(http_url, self.node.uuid,
|
||||
'deploy_ramdisk')
|
||||
kernel = os.path.join(http_url, self.node.uuid, 'kernel')
|
||||
ramdisk = os.path.join(http_url, self.node.uuid, 'ramdisk')
|
||||
root_dir = CONF.deploy.http_root
|
||||
|
@ -194,9 +213,44 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
'ramdisk')
|
||||
root_dir = CONF.pxe.tftp_root
|
||||
|
||||
if whle_dsk_img:
|
||||
ramdisk = 'no_ramdisk'
|
||||
kernel = 'no_kernel'
|
||||
if ipxe_use_swift:
|
||||
image_info = {
|
||||
'deploy_kernel': (str(uuid.uuid4()),
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_kernel')),
|
||||
'deploy_ramdisk': (str(uuid.uuid4()),
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_ramdisk'))
|
||||
}
|
||||
else:
|
||||
image_info = {
|
||||
'deploy_kernel': ('deploy_kernel',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_kernel')),
|
||||
'deploy_ramdisk': ('deploy_ramdisk',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_ramdisk'))
|
||||
}
|
||||
|
||||
if (whle_dsk_img or
|
||||
deploy_utils.get_boot_option(self.node) == 'local'):
|
||||
ramdisk = 'no_ramdisk'
|
||||
kernel = 'no_kernel'
|
||||
else:
|
||||
image_info.update({
|
||||
'kernel': ('kernel_id',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'kernel')),
|
||||
'ramdisk': ('ramdisk_id',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'ramdisk'))
|
||||
})
|
||||
|
||||
ipxe_timeout_in_ms = ipxe_timeout * 1000
|
||||
|
||||
|
@ -210,23 +264,6 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
'ipxe_timeout': ipxe_timeout_in_ms,
|
||||
}
|
||||
|
||||
image_info = {'deploy_kernel': ('deploy_kernel',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_kernel')),
|
||||
'deploy_ramdisk': ('deploy_ramdisk',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_ramdisk')),
|
||||
'kernel': ('kernel_id',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'kernel')),
|
||||
'ramdisk': ('ramdisk_id',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'ramdisk'))}
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
options = pxe._build_pxe_config_options(task, image_info)
|
||||
|
@ -236,10 +273,38 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
self._test_build_pxe_config_options(whle_dsk_img=True,
|
||||
ipxe_enabled=False)
|
||||
|
||||
def test__build_pxe_config_options_local_boot(self):
|
||||
del self.node.driver_internal_info['is_whole_disk_image']
|
||||
i_info = self.node.instance_info
|
||||
i_info.update({'capabilities': {'boot_option': 'local'}})
|
||||
self.node.instance_info = i_info
|
||||
self.node.save()
|
||||
self._test_build_pxe_config_options(whle_dsk_img=False,
|
||||
ipxe_enabled=False)
|
||||
|
||||
def test__build_pxe_config_options_ipxe(self):
|
||||
self._test_build_pxe_config_options(whle_dsk_img=True,
|
||||
ipxe_enabled=True)
|
||||
|
||||
def test__build_pxe_config_options_ipxe_local_boot(self):
|
||||
del self.node.driver_internal_info['is_whole_disk_image']
|
||||
i_info = self.node.instance_info
|
||||
i_info.update({'capabilities': {'boot_option': 'local'}})
|
||||
self.node.instance_info = i_info
|
||||
self.node.save()
|
||||
self._test_build_pxe_config_options(whle_dsk_img=False,
|
||||
ipxe_enabled=True)
|
||||
|
||||
def test__build_pxe_config_options_ipxe_swift_wdi(self):
|
||||
self._test_build_pxe_config_options(whle_dsk_img=True,
|
||||
ipxe_enabled=True,
|
||||
ipxe_use_swift=True)
|
||||
|
||||
def test__build_pxe_config_options_ipxe_swift_partition(self):
|
||||
self._test_build_pxe_config_options(whle_dsk_img=False,
|
||||
ipxe_enabled=True,
|
||||
ipxe_use_swift=True)
|
||||
|
||||
def test__build_pxe_config_options_without_is_whole_disk_image(self):
|
||||
del self.node.driver_internal_info['is_whole_disk_image']
|
||||
self.node.save()
|
||||
|
@ -251,62 +316,6 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
ipxe_enabled=True,
|
||||
ipxe_timeout=120)
|
||||
|
||||
@mock.patch.object(pxe_utils, '_build_pxe_config', autospec=True)
|
||||
def test__build_pxe_config_options_whole_disk_image(self,
|
||||
build_pxe_mock,
|
||||
ipxe_enabled=False):
|
||||
self.config(pxe_append_params='test_param', group='pxe')
|
||||
# NOTE: right '/' should be removed from url string
|
||||
self.config(api_url='http://192.168.122.184:6385', group='conductor')
|
||||
|
||||
tftp_server = CONF.pxe.tftp_server
|
||||
|
||||
if ipxe_enabled:
|
||||
http_url = 'http://192.1.2.3:1234'
|
||||
self.config(ipxe_enabled=True, group='pxe')
|
||||
self.config(http_url=http_url, group='deploy')
|
||||
|
||||
deploy_kernel = os.path.join(http_url, self.node.uuid,
|
||||
'deploy_kernel')
|
||||
deploy_ramdisk = os.path.join(http_url, self.node.uuid,
|
||||
'deploy_ramdisk')
|
||||
root_dir = CONF.deploy.http_root
|
||||
else:
|
||||
deploy_kernel = os.path.join(CONF.pxe.tftp_root, self.node.uuid,
|
||||
'deploy_kernel')
|
||||
deploy_ramdisk = os.path.join(CONF.pxe.tftp_root, self.node.uuid,
|
||||
'deploy_ramdisk')
|
||||
root_dir = CONF.pxe.tftp_root
|
||||
|
||||
expected_options = {
|
||||
'deployment_ari_path': deploy_ramdisk,
|
||||
'pxe_append_params': 'test_param',
|
||||
'deployment_aki_path': deploy_kernel,
|
||||
'tftp_server': tftp_server,
|
||||
'aki_path': 'no_kernel',
|
||||
'ari_path': 'no_ramdisk',
|
||||
'ipxe_timeout': 0,
|
||||
}
|
||||
|
||||
image_info = {'deploy_kernel': ('deploy_kernel',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_kernel')),
|
||||
'deploy_ramdisk': ('deploy_ramdisk',
|
||||
os.path.join(root_dir,
|
||||
self.node.uuid,
|
||||
'deploy_ramdisk')),
|
||||
}
|
||||
driver_internal_info = self.node.driver_internal_info
|
||||
driver_internal_info['is_whole_disk_image'] = True
|
||||
self.node.driver_internal_info = driver_internal_info
|
||||
self.node.save()
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
options = pxe._build_pxe_config_options(task, image_info)
|
||||
self.assertEqual(expected_options, options)
|
||||
|
||||
def test__build_pxe_config_options_no_kernel_no_ramdisk(self):
|
||||
del self.node.driver_internal_info['is_whole_disk_image']
|
||||
self.node.save()
|
||||
|
@ -655,20 +664,38 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||
mock_deploy_img_info,
|
||||
mock_instance_img_info,
|
||||
dhcp_factory_mock, uefi=False,
|
||||
cleaning=False):
|
||||
cleaning=False,
|
||||
ipxe_use_swift=False,
|
||||
whole_disk_image=False):
|
||||
mock_build_pxe.return_value = {}
|
||||
mock_deploy_img_info.return_value = {'deploy_kernel': 'a'}
|
||||
mock_instance_img_info.return_value = {'kernel': 'b'}
|
||||
if whole_disk_image:
|
||||
mock_instance_img_info.return_value = {}
|
||||
else:
|
||||
mock_instance_img_info.return_value = {'kernel': 'b'}
|
||||
mock_pxe_config.return_value = None
|
||||
mock_cache_r_k.return_value = None
|
||||
provider_mock = mock.MagicMock()
|
||||
dhcp_factory_mock.return_value = provider_mock
|
||||
driver_internal_info = self.node.driver_internal_info
|
||||
driver_internal_info['is_whole_disk_image'] = whole_disk_image
|
||||
self.node.driver_internal_info = driver_internal_info
|
||||
self.node.save()
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
|
||||
task.driver.boot.prepare_ramdisk(task, {'foo': 'bar'})
|
||||
mock_deploy_img_info.assert_called_once_with(task.node)
|
||||
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
|
||||
if cleaning is False:
|
||||
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'})
|
||||
|
@ -749,6 +776,34 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||
self._test_prepare_ramdisk()
|
||||
self.assertFalse(copyfile_mock.called)
|
||||
|
||||
@mock.patch.object(shutil, 'copyfile', autospec=True)
|
||||
def test_prepare_ramdisk_ipxe_swift(self, copyfile_mock):
|
||||
self.node.provision_state = states.DEPLOYING
|
||||
self.node.save()
|
||||
self.config(group='pxe', ipxe_enabled=True)
|
||||
self.config(group='pxe', ipxe_use_swift=True)
|
||||
self.config(group='deploy', http_url='http://myserver')
|
||||
self._test_prepare_ramdisk(ipxe_use_swift=True)
|
||||
copyfile_mock.assert_called_once_with(
|
||||
CONF.pxe.ipxe_boot_script,
|
||||
os.path.join(
|
||||
CONF.deploy.http_root,
|
||||
os.path.basename(CONF.pxe.ipxe_boot_script)))
|
||||
|
||||
@mock.patch.object(shutil, 'copyfile', autospec=True)
|
||||
def test_prepare_ramdisk_ipxe_swift_whole_disk_image(self, copyfile_mock):
|
||||
self.node.provision_state = states.DEPLOYING
|
||||
self.node.save()
|
||||
self.config(group='pxe', ipxe_enabled=True)
|
||||
self.config(group='pxe', ipxe_use_swift=True)
|
||||
self.config(group='deploy', http_url='http://myserver')
|
||||
self._test_prepare_ramdisk(ipxe_use_swift=True, whole_disk_image=True)
|
||||
copyfile_mock.assert_called_once_with(
|
||||
CONF.pxe.ipxe_boot_script,
|
||||
os.path.join(
|
||||
CONF.deploy.http_root,
|
||||
os.path.basename(CONF.pxe.ipxe_boot_script)))
|
||||
|
||||
def test_prepare_ramdisk_cleaning(self):
|
||||
self.node.provision_state = states.CLEANING
|
||||
self.node.save()
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
features:
|
||||
- By default, the ironic-conductor service caches the node's deploy
|
||||
ramdisk and kernel images locally and serves them via a separate
|
||||
HTTP server. A new ``[pxe]ipxe_use_swift`` configuration option
|
||||
(disabled by default) allows images to be accessed directly
|
||||
from object store via Swift temporary URLs.
|
||||
This is only applicable if iPXE is enabled (via ``[pxe]ipxe_enabled``
|
||||
configuration option) and image store is in Glance/Swift.
|
||||
For user images that are partition images requiring non-local boot,
|
||||
the default behavior with local caching and an HTTP server
|
||||
will still apply for user image kernel and ramdisk.
|
Loading…
Reference in New Issue