iPXE template support for iSCSI
Added support for iPXE template output of a template containing iscsi based URL sanhook entries to enable boot as well as additional attachments. Authored-By: Julia Kreger <juliaashleykreger@gmail.com> Co-Authored-By: Joanna Taryma <joanna.taryma@intel.com> Co-Authored-By: Michael Turek <mjturek@linux.vnet.ibm.com> Change-Id: I75869262dbfd1caa779fa21e93cdb31f193cb829 Partial-Bug: #1559691
This commit is contained in:
parent
cbedc8268c
commit
6883674b3c
|
@ -267,11 +267,13 @@ def _replace_root_uuid(path, root_uuid):
|
|||
|
||||
|
||||
def _replace_boot_line(path, boot_mode, is_whole_disk_image,
|
||||
trusted_boot=False):
|
||||
trusted_boot=False, iscsi_boot=False):
|
||||
if is_whole_disk_image:
|
||||
boot_disk_type = 'boot_whole_disk'
|
||||
elif trusted_boot:
|
||||
boot_disk_type = 'trusted_boot'
|
||||
elif iscsi_boot:
|
||||
boot_disk_type = 'boot_iscsi'
|
||||
else:
|
||||
boot_disk_type = 'boot_partition'
|
||||
|
||||
|
@ -292,7 +294,8 @@ def _replace_disk_identifier(path, disk_identifier):
|
|||
|
||||
|
||||
def switch_pxe_config(path, root_uuid_or_disk_id, boot_mode,
|
||||
is_whole_disk_image, trusted_boot=False):
|
||||
is_whole_disk_image, trusted_boot=False,
|
||||
iscsi_boot=False):
|
||||
"""Switch a pxe config from deployment mode to service mode.
|
||||
|
||||
:param path: path to the pxe config file in tftpboot.
|
||||
|
@ -303,13 +306,15 @@ def switch_pxe_config(path, root_uuid_or_disk_id, boot_mode,
|
|||
:param trusted_boot: if boot with trusted_boot or not. The usage of
|
||||
is_whole_disk_image and trusted_boot are mutually exclusive. You can
|
||||
have one or neither, but not both.
|
||||
:param iscsi_boot: if boot is from an iSCSI volume or not.
|
||||
"""
|
||||
if not is_whole_disk_image:
|
||||
_replace_root_uuid(path, root_uuid_or_disk_id)
|
||||
else:
|
||||
_replace_disk_identifier(path, root_uuid_or_disk_id)
|
||||
|
||||
_replace_boot_line(path, boot_mode, is_whole_disk_image, trusted_boot)
|
||||
_replace_boot_line(path, boot_mode, is_whole_disk_image, trusted_boot,
|
||||
iscsi_boot)
|
||||
|
||||
|
||||
def get_dev(address, port, iqn, lun):
|
||||
|
@ -1297,3 +1302,18 @@ def tear_down_storage_configuration(task):
|
|||
driver_internal_info.pop('boot_from_volume_deploy', None)
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
|
||||
|
||||
def is_iscsi_boot(task):
|
||||
"""Return true if booting from an iscsi volume."""
|
||||
node = task.node
|
||||
volume = node.driver_internal_info.get('boot_from_volume')
|
||||
if volume:
|
||||
try:
|
||||
boot_volume = objects.VolumeTarget.get_by_uuid(
|
||||
task.context, volume)
|
||||
if boot_volume.volume_type == 'iscsi':
|
||||
return True
|
||||
except exception.VolumeTargetNotFound:
|
||||
return False
|
||||
return False
|
||||
|
|
|
@ -14,6 +14,26 @@ imgfree
|
|||
kernel {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ pxe_options.aki_path }} root={{ ROOT }} ro text {{ pxe_options.pxe_append_params|default("", true) }} initrd=ramdisk || goto boot_partition
|
||||
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ pxe_options.ari_path }} || goto boot_partition
|
||||
boot
|
||||
{%- if pxe_options.boot_from_volume %}
|
||||
|
||||
:boot_iscsi
|
||||
imgfree
|
||||
{% if pxe_options.username %}set username {{ pxe_options.username }}{% endif %}
|
||||
{% if pxe_options.password %}set password {{ pxe_options.password }}{% endif %}
|
||||
{% if pxe_options.iscsi_initiator_iqn %}set initiator-iqn {{ pxe_options.iscsi_initiator_iqn }}{% endif %}
|
||||
sanhook --drive 0x80 {{ pxe_options.iscsi_boot_url }} || goto fail_iscsi_retry
|
||||
{%- if pxe_options.iscsi_volumes %}{% for volume in pxe_options
|
||||
.iscsi_volumes %}
|
||||
{%- set drive_id = 80 + loop.index %}
|
||||
sanhook --drive 0x{{ drive_id }} {{ volume }} || goto fail_iscsi_retry
|
||||
{%- endfor %}{% endif %}
|
||||
sanboot --no-describe || goto fail_iscsi_retry
|
||||
|
||||
:fail_iscsi_retry
|
||||
echo Failed to attach iSCSI volume(s), retrying in 10 seconds.
|
||||
sleep 10
|
||||
goto boot_iscsi
|
||||
{%- endif %}
|
||||
|
||||
:boot_whole_disk
|
||||
sanboot --no-describe
|
||||
|
|
|
@ -37,7 +37,7 @@ from ironic.drivers import base
|
|||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules import image_cache
|
||||
from ironic.drivers import utils as driver_utils
|
||||
|
||||
from ironic import objects
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
METRICS = metrics_utils.get_metrics_logger(__name__)
|
||||
|
@ -212,6 +212,9 @@ def _build_pxe_config_options(task, pxe_info, service=False):
|
|||
"""
|
||||
if service:
|
||||
pxe_options = {}
|
||||
elif (task.node.driver_internal_info.get('boot_from_volume') and
|
||||
CONF.pxe.ipxe_enabled):
|
||||
pxe_options = _get_volume_pxe_options(task)
|
||||
else:
|
||||
pxe_options = _build_deploy_pxe_options(task, pxe_info)
|
||||
|
||||
|
@ -243,7 +246,65 @@ def _build_service_pxe_config(task, instance_image_info,
|
|||
deploy_utils.switch_pxe_config(
|
||||
pxe_config_path, root_uuid_or_disk_id,
|
||||
deploy_utils.get_boot_mode_for_deploy(node),
|
||||
iwdi, deploy_utils.is_trusted_boot_requested(node))
|
||||
iwdi, deploy_utils.is_trusted_boot_requested(node),
|
||||
deploy_utils.is_iscsi_boot(task))
|
||||
|
||||
|
||||
def _get_volume_pxe_options(task):
|
||||
"""Identify volume information for iPXE template generation."""
|
||||
def __return_item_or_first_if_list(item):
|
||||
if isinstance(item, list):
|
||||
return item[0]
|
||||
else:
|
||||
return item
|
||||
|
||||
def __get_property(properties, key):
|
||||
prop = __return_item_or_first_if_list(properties.get(key, ''))
|
||||
if prop is not '':
|
||||
return prop
|
||||
return __return_item_or_first_if_list(properties.get(key + 's', ''))
|
||||
|
||||
def __generate_iscsi_url(properties):
|
||||
"""Returns iscsi url."""
|
||||
portal = __get_property(properties, 'target_portal')
|
||||
iqn = __get_property(properties, 'target_iqn')
|
||||
lun = __get_property(properties, 'target_lun')
|
||||
|
||||
if ':' in portal:
|
||||
host, port = portal.split(':')
|
||||
else:
|
||||
host = portal
|
||||
port = ''
|
||||
return ("iscsi:%(host)s::%(port)s:%(lun)s:%(iqn)s" %
|
||||
{'host': host, 'port': port, 'lun': lun, 'iqn': iqn})
|
||||
|
||||
pxe_options = {}
|
||||
node = task.node
|
||||
boot_volume = node.driver_internal_info.get('boot_from_volume')
|
||||
volume = objects.VolumeTarget.get_by_uuid(task.context,
|
||||
boot_volume)
|
||||
properties = volume.properties
|
||||
if 'iscsi' in volume['volume_type']:
|
||||
if 'auth_username' in properties:
|
||||
pxe_options['username'] = properties['auth_username']
|
||||
if 'auth_password' in properties:
|
||||
pxe_options['password'] = properties['auth_password']
|
||||
pxe_options.update(
|
||||
{'iscsi_boot_url': __generate_iscsi_url(volume.properties),
|
||||
'iscsi_initiator_iqn': (__get_property(properties,
|
||||
'target_iqn') or None)})
|
||||
# NOTE(TheJulia): This may be the route to multi-path, define
|
||||
# volumes via sanhook in the ipxe template and let the OS sort it out.
|
||||
additional_targets = []
|
||||
for target in task.volume_targets:
|
||||
if target.boot_index != 0 and 'iscsi' in target.volume_type:
|
||||
additional_targets.append(
|
||||
__generate_iscsi_url(target.properties))
|
||||
pxe_options.update({'iscsi_volumes': additional_targets,
|
||||
'boot_from_volume': True})
|
||||
# TODO(TheJulia): FibreChannel boot, i.e. wwpn in volume_type
|
||||
# for FCoE, should go here.
|
||||
return pxe_options
|
||||
|
||||
|
||||
@METRICS.timer('validate_boot_option_for_trusted_boot')
|
||||
|
@ -312,6 +373,9 @@ def _clean_up_pxe_env(task, images_info):
|
|||
|
||||
class PXEBoot(base.BootInterface):
|
||||
|
||||
def __init__(self):
|
||||
self.capabilities = ['iscsi_volume_boot']
|
||||
|
||||
def get_properties(self):
|
||||
"""Return the properties of the interface.
|
||||
|
||||
|
|
|
@ -64,6 +64,16 @@ class TestPXEUtils(db_base.DbTestCase):
|
|||
'ipxe_timeout': 120
|
||||
})
|
||||
|
||||
self.ipxe_options_boot_from_volume = self.ipxe_options.copy()
|
||||
self.ipxe_options_boot_from_volume.update({
|
||||
'boot_from_volume': True,
|
||||
'iscsi_boot_url': 'iscsi:fake_host::3260:0:fake_iqn',
|
||||
'iscsi_initiator_iqn': 'fake_iqn',
|
||||
'iscsi_volumes': ['iscsi:fake_host::3260:1:fake_iqn'],
|
||||
'username': 'fake_username',
|
||||
'password': 'fake_password'
|
||||
})
|
||||
|
||||
self.node = object_utils.create_test_node(self.context)
|
||||
|
||||
def test_default_pxe_config(self):
|
||||
|
@ -133,6 +143,47 @@ class TestPXEUtils(db_base.DbTestCase):
|
|||
|
||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||
|
||||
def test_default_ipxe_boot_from_volume_config(self):
|
||||
self.config(
|
||||
pxe_config_template='ironic/drivers/modules/ipxe_config.template',
|
||||
group='pxe'
|
||||
)
|
||||
self.config(http_url='http://1.2.3.4:1234', group='deploy')
|
||||
rendered_template = utils.render_template(
|
||||
CONF.pxe.pxe_config_template,
|
||||
{'pxe_options': self.ipxe_options_boot_from_volume,
|
||||
'ROOT': '{{ ROOT }}',
|
||||
'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'})
|
||||
|
||||
templ_file = 'ironic/tests/unit/drivers/' \
|
||||
'ipxe_config_boot_from_volume.template'
|
||||
with open(templ_file) as f:
|
||||
expected_template = f.read().rstrip()
|
||||
|
||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||
|
||||
def test_default_ipxe_boot_from_volume_config_no_volumes(self):
|
||||
self.config(
|
||||
pxe_config_template='ironic/drivers/modules/ipxe_config.template',
|
||||
group='pxe'
|
||||
)
|
||||
self.config(http_url='http://1.2.3.4:1234', group='deploy')
|
||||
|
||||
pxe_options = self.ipxe_options_boot_from_volume
|
||||
pxe_options['iscsi_volumes'] = []
|
||||
|
||||
rendered_template = utils.render_template(
|
||||
CONF.pxe.pxe_config_template,
|
||||
{'pxe_options': pxe_options,
|
||||
'ROOT': '{{ ROOT }}',
|
||||
'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'})
|
||||
|
||||
templ_file = 'ironic/tests/unit/drivers/' \
|
||||
'ipxe_config_boot_from_volume_no_volumes.template'
|
||||
with open(templ_file) as f:
|
||||
expected_template = f.read().rstrip()
|
||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||
|
||||
# NOTE(TheJulia): Remove elilo support after the deprecation period,
|
||||
# in the Queens release.
|
||||
def test_default_elilo_config(self):
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#!ipxe
|
||||
|
||||
goto deploy
|
||||
|
||||
:deploy
|
||||
imgfree
|
||||
kernel http://1.2.3.4:1234/deploy_kernel selinux=0 troubleshoot=0 text test_param ip=${ip}:${next-server}:${gateway}:${netmask} BOOTIF=${mac} ipa-api-url=http://192.168.122.184:6385 initrd=deploy_ramdisk coreos.configdrive=0 || goto deploy
|
||||
|
||||
initrd http://1.2.3.4:1234/deploy_ramdisk || goto deploy
|
||||
boot
|
||||
|
||||
:boot_partition
|
||||
imgfree
|
||||
kernel http://1.2.3.4:1234/kernel root={{ ROOT }} ro text test_param initrd=ramdisk || goto boot_partition
|
||||
initrd http://1.2.3.4:1234/ramdisk || goto boot_partition
|
||||
boot
|
||||
|
||||
:boot_iscsi
|
||||
imgfree
|
||||
set username fake_username
|
||||
set password fake_password
|
||||
set initiator-iqn fake_iqn
|
||||
sanhook --drive 0x80 iscsi:fake_host::3260:0:fake_iqn || goto fail_iscsi_retry
|
||||
sanhook --drive 0x81 iscsi:fake_host::3260:1:fake_iqn || goto fail_iscsi_retry
|
||||
sanboot --no-describe || goto fail_iscsi_retry
|
||||
|
||||
:fail_iscsi_retry
|
||||
echo Failed to attach iSCSI volume(s), retrying in 10 seconds.
|
||||
sleep 10
|
||||
goto boot_iscsi
|
||||
|
||||
:boot_whole_disk
|
||||
sanboot --no-describe
|
|
@ -0,0 +1,32 @@
|
|||
#!ipxe
|
||||
|
||||
goto deploy
|
||||
|
||||
:deploy
|
||||
imgfree
|
||||
kernel http://1.2.3.4:1234/deploy_kernel selinux=0 troubleshoot=0 text test_param ip=${ip}:${next-server}:${gateway}:${netmask} BOOTIF=${mac} ipa-api-url=http://192.168.122.184:6385 initrd=deploy_ramdisk coreos.configdrive=0 || goto deploy
|
||||
|
||||
initrd http://1.2.3.4:1234/deploy_ramdisk || goto deploy
|
||||
boot
|
||||
|
||||
:boot_partition
|
||||
imgfree
|
||||
kernel http://1.2.3.4:1234/kernel root={{ ROOT }} ro text test_param initrd=ramdisk || goto boot_partition
|
||||
initrd http://1.2.3.4:1234/ramdisk || goto boot_partition
|
||||
boot
|
||||
|
||||
:boot_iscsi
|
||||
imgfree
|
||||
set username fake_username
|
||||
set password fake_password
|
||||
set initiator-iqn fake_iqn
|
||||
sanhook --drive 0x80 iscsi:fake_host::3260:0:fake_iqn || goto fail_iscsi_retry
|
||||
sanboot --no-describe || goto fail_iscsi_retry
|
||||
|
||||
:fail_iscsi_retry
|
||||
echo Failed to attach iSCSI volume(s), retrying in 10 seconds.
|
||||
sleep 10
|
||||
goto boot_iscsi
|
||||
|
||||
:boot_whole_disk
|
||||
sanboot --no-describe
|
|
@ -206,6 +206,29 @@ append mbr:0x12345678
|
|||
boot
|
||||
"""
|
||||
|
||||
_IPXECONF_BOOT_ISCSI_NO_CONFIG = """
|
||||
#!ipxe
|
||||
|
||||
dhcp
|
||||
|
||||
goto boot_iscsi
|
||||
|
||||
:deploy
|
||||
kernel deploy_kernel
|
||||
initrd deploy_ramdisk
|
||||
boot
|
||||
|
||||
:boot_partition
|
||||
kernel kernel
|
||||
append initrd=ramdisk root=UUID=0x12345678
|
||||
boot
|
||||
|
||||
:boot_whole_disk
|
||||
kernel chain.c32
|
||||
append mbr:{{ DISK_IDENTIFIER }}
|
||||
boot
|
||||
"""
|
||||
|
||||
_UEFI_PXECONF_DEPLOY = b"""
|
||||
default=deploy
|
||||
|
||||
|
@ -936,6 +959,18 @@ class SwitchPxeConfigTestCase(tests_base.TestCase):
|
|||
pxeconf = f.read()
|
||||
self.assertEqual(_IPXECONF_BOOT_WHOLE_DISK, pxeconf)
|
||||
|
||||
def test_switch_ipxe_iscsi_boot(self):
|
||||
boot_mode = 'iscsi'
|
||||
cfg.CONF.set_override('ipxe_enabled', True, 'pxe')
|
||||
fname = self._create_config(boot_mode=boot_mode, ipxe=True)
|
||||
utils.switch_pxe_config(fname,
|
||||
'0x12345678',
|
||||
boot_mode,
|
||||
False, False, True)
|
||||
with open(fname, 'r') as f:
|
||||
pxeconf = f.read()
|
||||
self.assertEqual(_IPXECONF_BOOT_ISCSI_NO_CONFIG, pxeconf)
|
||||
|
||||
|
||||
class GetPxeBootConfigTestCase(db_base.DbTestCase):
|
||||
|
||||
|
@ -2500,3 +2535,37 @@ class TestStorageInterfaceUtils(db_base.DbTestCase):
|
|||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=False) as task:
|
||||
self.assertEqual(0, len(task.volume_targets))
|
||||
|
||||
def test_is_iscsi_boot(self):
|
||||
vol_id = uuidutils.generate_uuid()
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=0, volume_id='1234', uuid=vol_id)
|
||||
self.node.driver_internal_info = {'boot_from_volume': vol_id}
|
||||
self.node.save()
|
||||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=False) as task:
|
||||
self.assertTrue(utils.is_iscsi_boot(task))
|
||||
|
||||
def test_is_iscsi_boot_exception(self):
|
||||
self.node.driver_internal_info = {
|
||||
'boot_from_volume': uuidutils.generate_uuid()}
|
||||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=False) as task:
|
||||
self.assertFalse(utils.is_iscsi_boot(task))
|
||||
|
||||
def test_is_iscsi_boot_false(self):
|
||||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=False) as task:
|
||||
self.assertFalse(utils.is_iscsi_boot(task))
|
||||
|
||||
def test_is_iscsi_boot_false_fc_target(self):
|
||||
vol_id = uuidutils.generate_uuid()
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='fibre_channel',
|
||||
boot_index=0, volume_id='3214', uuid=vol_id)
|
||||
self.node.driver_internal_info.update({'boot_from_volume': vol_id})
|
||||
self.node.save()
|
||||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=False) as task:
|
||||
self.assertFalse(utils.is_iscsi_boot(task))
|
||||
|
|
|
@ -285,7 +285,8 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
whle_dsk_img=False,
|
||||
ipxe_timeout=0,
|
||||
ipxe_use_swift=False,
|
||||
debug=False):
|
||||
debug=False,
|
||||
boot_from_volume=False):
|
||||
self.config(debug=debug)
|
||||
self.config(pxe_append_params='test_param', group='pxe')
|
||||
# NOTE: right '/' should be removed from url string
|
||||
|
@ -370,6 +371,17 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
'ipxe_timeout': ipxe_timeout_in_ms,
|
||||
}
|
||||
|
||||
if boot_from_volume:
|
||||
expected_options.update({
|
||||
'boot_from_volume': True,
|
||||
'iscsi_boot_url': 'iscsi:fake_host::3260:0:fake_iqn',
|
||||
'iscsi_initiator_iqn': 'fake_iqn',
|
||||
'iscsi_volumes': ['iscsi:fake_host::3260:1:fake_iqn'],
|
||||
'username': 'fake_username',
|
||||
'password': 'fake_password'})
|
||||
expected_options.pop('deployment_aki_path')
|
||||
expected_options.pop('deployment_ari_path')
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
options = pxe._build_pxe_config_options(task, image_info)
|
||||
|
@ -401,6 +413,121 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
|||
self._test_build_pxe_config_options_ipxe(whle_dsk_img=True,
|
||||
ipxe_timeout=120)
|
||||
|
||||
def test__build_pxe_config_options_ipxe_and_iscsi_boot(self):
|
||||
vol_id = uuidutils.generate_uuid()
|
||||
vol_id2 = uuidutils.generate_uuid()
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=0, volume_id='1234', uuid=vol_id,
|
||||
properties={'target_lun': 0,
|
||||
'target_portal': 'fake_host:3260',
|
||||
'target_iqn': 'fake_iqn',
|
||||
'auth_username': 'fake_username',
|
||||
'auth_password': 'fake_password'})
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=1, volume_id='1235', uuid=vol_id2,
|
||||
properties={'target_lun': 1,
|
||||
'target_portal': 'fake_host:3260',
|
||||
'target_iqn': 'fake_iqn'})
|
||||
self.node.driver_internal_info.update({'boot_from_volume': vol_id})
|
||||
self._test_build_pxe_config_options_ipxe(boot_from_volume=True)
|
||||
|
||||
def test__build_pxe_config_options_ipxe_and_iscsi_boot_from_lists(self):
|
||||
vol_id = uuidutils.generate_uuid()
|
||||
vol_id2 = uuidutils.generate_uuid()
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=0, volume_id='1234', uuid=vol_id,
|
||||
properties={'target_luns': [0, 2],
|
||||
'target_portals': ['fake_host:3260',
|
||||
'faker_host:3261'],
|
||||
'target_iqns': ['fake_iqn', 'faker_iqn'],
|
||||
'auth_username': 'fake_username',
|
||||
'auth_password': 'fake_password'})
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=1, volume_id='1235', uuid=vol_id2,
|
||||
properties={'target_lun': [1, 3],
|
||||
'target_portal': ['fake_host:3260', 'faker_host:3261'],
|
||||
'target_iqn': ['fake_iqn', 'faker_iqn']})
|
||||
self.node.driver_internal_info.update({'boot_from_volume': vol_id})
|
||||
self._test_build_pxe_config_options_ipxe(boot_from_volume=True)
|
||||
|
||||
def test__get_volume_pxe_options(self):
|
||||
vol_id = uuidutils.generate_uuid()
|
||||
vol_id2 = uuidutils.generate_uuid()
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=0, volume_id='1234', uuid=vol_id,
|
||||
properties={'target_lun': [0, 1, 3],
|
||||
'target_portal': 'fake_host:3260',
|
||||
'target_iqns': 'fake_iqn',
|
||||
'auth_username': 'fake_username',
|
||||
'auth_password': 'fake_password'})
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=1, volume_id='1235', uuid=vol_id2,
|
||||
properties={'target_lun': 1,
|
||||
'target_portal': 'fake_host:3260',
|
||||
'target_iqn': 'fake_iqn'})
|
||||
self.node.driver_internal_info.update({'boot_from_volume': vol_id})
|
||||
driver_internal_info = self.node.driver_internal_info
|
||||
driver_internal_info['boot_from_volume'] = vol_id
|
||||
self.node.driver_internal_info = driver_internal_info
|
||||
self.node.save()
|
||||
|
||||
expected = {'boot_from_volume': True,
|
||||
'username': 'fake_username', 'password': 'fake_password',
|
||||
'iscsi_boot_url': 'iscsi:fake_host::3260:0:fake_iqn',
|
||||
'iscsi_initiator_iqn': 'fake_iqn',
|
||||
'iscsi_volumes': ['iscsi:fake_host::3260:1:fake_iqn']}
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=True) as task:
|
||||
options = pxe._get_volume_pxe_options(task)
|
||||
self.assertEqual(expected, options)
|
||||
|
||||
def test__get_volume_pxe_options_unsupported_volume_type(self):
|
||||
vol_id = uuidutils.generate_uuid()
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='fake_type',
|
||||
boot_index=0, volume_id='1234', uuid=vol_id,
|
||||
properties={'foo': 'bar'})
|
||||
|
||||
driver_internal_info = self.node.driver_internal_info
|
||||
driver_internal_info['boot_from_volume'] = vol_id
|
||||
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._get_volume_pxe_options(task)
|
||||
self.assertEqual({}, options)
|
||||
|
||||
def test__get_volume_pxe_options_unsupported_additional_volume_type(self):
|
||||
vol_id = uuidutils.generate_uuid()
|
||||
vol_id2 = uuidutils.generate_uuid()
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='iscsi',
|
||||
boot_index=0, volume_id='1234', uuid=vol_id,
|
||||
properties={'target_lun': 0,
|
||||
'target_portal': 'fake_host:3260',
|
||||
'target_iqn': 'fake_iqn',
|
||||
'auth_username': 'fake_username',
|
||||
'auth_password': 'fake_password'})
|
||||
obj_utils.create_test_volume_target(
|
||||
self.context, node_id=self.node.id, volume_type='fake_type',
|
||||
boot_index=1, volume_id='1234', uuid=vol_id2,
|
||||
properties={'foo': 'bar'})
|
||||
|
||||
driver_internal_info = self.node.driver_internal_info
|
||||
driver_internal_info['boot_from_volume'] = vol_id
|
||||
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._get_volume_pxe_options(task)
|
||||
self.assertEqual([], options['iscsi_volumes'])
|
||||
|
||||
@mock.patch.object(deploy_utils, 'fetch_images', autospec=True)
|
||||
def test__cache_tftp_images_master_path(self, mock_fetch_image):
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
|
@ -876,7 +1003,7 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
|
||||
switch_pxe_config_mock.assert_called_once_with(
|
||||
pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50",
|
||||
'bios', False, False)
|
||||
'bios', False, False, False)
|
||||
set_boot_device_mock.assert_called_once_with(task,
|
||||
boot_devices.PXE)
|
||||
|
||||
|
@ -918,7 +1045,7 @@ class PXEBootTestCase(db_base.DbTestCase):
|
|||
task, mock.ANY, CONF.pxe.pxe_config_template)
|
||||
switch_pxe_config_mock.assert_called_once_with(
|
||||
pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50",
|
||||
'bios', False, False)
|
||||
'bios', False, False, False)
|
||||
self.assertFalse(set_boot_device_mock.called)
|
||||
|
||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||
|
|
Loading…
Reference in New Issue