Fix authentication issues along with add multi extra volumes

This commit will fix authentication in boot from volume (BFV) feature,
which use the volumes from Cinder for Baremetal via Ironic.

Each volume will need pair of account for authentication when perform
sanhook into SAN device via iPXE. And sandboot from drive 0x80 (default)
also need pair accounts same with the iscsi sanhook on drive 0x80 with
multi volumes has supported.

NOTE:
- We could add more than two volumes into iSCSI Boot Firmware Table(iBFT)
- Due to Linux does not support an iBFT that has more than two volumes,
  thus BFV only support for add one etra volume. If over two volume in iBFT
  then machine will raise "iBFT error: Control header is invalid!".
- Our code-base already for more than two volumes in iBFT, If Linux kernel
  bugs[1] is fixing this issue then we can use BFV with more than two volumes.

Tested successfully on Fujitsu Baremetal Server TX2540 M1.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/acpi/actbl1.h#n1567

Co-authored-By: Hoang Trung Hieu <hieuht@vn.fujitsu.com>
Co-authored-By: Dao Cong Tien <tiendc@vn.fujitsu.com>

Change-Id: I98f658cced8491872d39adbd8e0a1a643dd24868
Story: #2001824
Task: #12573
This commit is contained in:
Nguyen Van Trung 2018-05-23 15:26:24 +07:00
parent 44f4768a69
commit d27b27679f
8 changed files with 79 additions and 26 deletions

View File

@ -497,7 +497,7 @@ def render_template(template, params, is_file=True):
loader = jinja2.DictLoader({tmpl_name: template})
env = jinja2.Environment(loader=loader)
tmpl = env.get_template(tmpl_name)
return tmpl.render(params)
return tmpl.render(params, enumerate=enumerate)
def warn_about_deprecated_extra_vif_port_id():

View File

@ -22,11 +22,14 @@ imgfree
{% 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
{%- if pxe_options.iscsi_volumes %}{% for i, volume in enumerate(pxe_options.iscsi_volumes) %}
set username {{ volume.username }}
set password {{ volume.password }}
{%- set drive_id = 129 + i %}
sanhook --drive {{ '0x%x' % drive_id }} {{ volume.url }} || goto fail_iscsi_retry
{%- endfor %}{% endif %}
{% if pxe_options.iscsi_volumes %}set username {{ pxe_options.username }}{% endif %}
{% if pxe_options.iscsi_volumes %}set password {{ pxe_options.password }}{% endif %}
sanboot --no-describe || goto fail_iscsi_retry
:fail_iscsi_retry
@ -36,4 +39,4 @@ goto boot_iscsi
{%- endif %}
:boot_whole_disk
sanboot --no-describe
sanboot --no-describe

View File

@ -334,12 +334,17 @@ def _get_volume_pxe_options(task):
'iscsi_initiator_iqn': iscsi_initiator_iqn})
# 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 = []
extra_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,
iscsi_url = __generate_iscsi_url(target.properties)
username = target.properties['auth_username']
password = target.properties['auth_password']
extra_targets.append({'url': iscsi_url,
'username': username,
'password': password})
pxe_options.update({'iscsi_volumes': extra_targets,
'boot_from_volume': True})
# TODO(TheJulia): FibreChannel boot, i.e. wwpn in volume_type
# for FCoE, should go here.

View File

@ -63,16 +63,35 @@ 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({
self.ipxe_options_boot_from_volume_no_extra_volume = \
self.ipxe_options.copy()
self.ipxe_options_boot_from_volume_no_extra_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'],
'iscsi_volumes': [],
'username': 'fake_username',
'password': 'fake_password'
'password': 'fake_password',
})
self.ipxe_options_boot_from_volume.pop('initrd_filename', None)
self.ipxe_options_boot_from_volume_extra_volume = \
self.ipxe_options.copy()
self.ipxe_options_boot_from_volume_extra_volume.update({
'boot_from_volume': True,
'iscsi_boot_url': 'iscsi:fake_host::3260:0:fake_iqn',
'iscsi_initiator_iqn': 'fake_iqn',
'iscsi_volumes': [{'url': 'iscsi:fake_host::3260:1:fake_iqn',
'username': 'fake_username_1',
'password': 'fake_password_1',
}],
'username': 'fake_username',
'password': 'fake_password',
})
self.ipxe_options_boot_from_volume_no_extra_volume.pop(
'initrd_filename', None)
self.ipxe_options_boot_from_volume_extra_volume.pop(
'initrd_filename', None)
self.node = object_utils.create_test_node(self.context)
@ -151,25 +170,25 @@ class TestPXEUtils(db_base.DbTestCase):
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,
{'pxe_options': self.ipxe_options_boot_from_volume_extra_volume,
'ROOT': '{{ ROOT }}',
'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'})
templ_file = 'ironic/tests/unit/drivers/' \
'ipxe_config_boot_from_volume.template'
'ipxe_config_boot_from_volume_extra_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):
def test_default_ipxe_boot_from_volume_config_no_extra_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 = self.ipxe_options_boot_from_volume_no_extra_volume
pxe_options['iscsi_volumes'] = []
rendered_template = utils.render_template(
@ -179,7 +198,7 @@ class TestPXEUtils(db_base.DbTestCase):
'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'})
templ_file = 'ironic/tests/unit/drivers/' \
'ipxe_config_boot_from_volume_no_volumes.template'
'ipxe_config_boot_from_volume_no_extra_volumes.template'
with open(templ_file) as f:
expected_template = f.read().rstrip()
self.assertEqual(six.text_type(expected_template), rendered_template)

View File

@ -21,7 +21,11 @@ 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
set username fake_username_1
set password fake_password_1
sanhook --drive 0x81 iscsi:fake_host::3260:1:fake_iqn || goto fail_iscsi_retry
set username fake_username
set password fake_password
sanboot --no-describe || goto fail_iscsi_retry
:fail_iscsi_retry

View File

@ -21,6 +21,8 @@ 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

View File

@ -428,9 +428,13 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
'boot_from_volume': True,
'iscsi_boot_url': 'iscsi:fake_host::3260:0:fake_iqn',
'iscsi_initiator_iqn': 'fake_iqn_initiator',
'iscsi_volumes': ['iscsi:fake_host::3260:1:fake_iqn'],
'iscsi_volumes': [{'url': 'iscsi:fake_host::3260:1:fake_iqn',
'username': 'fake_username_1',
'password': 'fake_password_1'
}],
'username': 'fake_username',
'password': 'fake_password'})
'password': 'fake_password'
})
expected_options.pop('deployment_aki_path')
expected_options.pop('deployment_ari_path')
expected_options.pop('initrd_filename')
@ -488,7 +492,9 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
boot_index=1, volume_id='1235', uuid=vol_id2,
properties={'target_lun': 1,
'target_portal': 'fake_host:3260',
'target_iqn': 'fake_iqn'})
'target_iqn': 'fake_iqn',
'auth_username': 'fake_username_1',
'auth_password': 'fake_password_1'})
self.node.driver_internal_info.update({'boot_from_volume': vol_id})
self._test_build_pxe_config_options_ipxe(boot_from_volume=True)
@ -515,7 +521,9 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
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']})
'target_iqn': ['fake_iqn', 'faker_iqn'],
'auth_username': 'fake_username_1',
'auth_password': 'fake_password_1'})
self.node.driver_internal_info.update({'boot_from_volume': vol_id})
self._test_build_pxe_config_options_ipxe(boot_from_volume=True)
@ -541,7 +549,9 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
boot_index=1, volume_id='1235', uuid=vol_id2,
properties={'target_lun': 1,
'target_portal': 'fake_host:3260',
'target_iqn': 'fake_iqn'})
'target_iqn': 'fake_iqn',
'auth_username': 'fake_username_1',
'auth_password': 'fake_password_1'})
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
@ -552,7 +562,12 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
'username': 'fake_username', 'password': 'fake_password',
'iscsi_boot_url': 'iscsi:fake_host::3260:0:fake_iqn',
'iscsi_initiator_iqn': 'fake_iqn_initiator',
'iscsi_volumes': ['iscsi:fake_host::3260:1:fake_iqn']}
'iscsi_volumes': [{
'url': 'iscsi:fake_host::3260:1:fake_iqn',
'username': 'fake_username_1',
'password': 'fake_password_1'
}]
}
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
options = pxe._get_volume_pxe_options(task)

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Fix an issue with iPXE is used for authentication during boot from volume
with multi attached volumes.