20
20
import stat
21
21
import tempfile
22
22
23
+ from ironic_lib import disk_utils
23
24
from ironic_lib import utils as ilib_utils
24
25
from oslo_concurrency import processutils
25
26
from oslo_config import cfg
@@ -261,7 +262,7 @@ def _get_efi_bootloaders(location):
261
262
262
263
263
264
def _run_efibootmgr (valid_efi_bootloaders , device , efi_partition ,
264
- mount_point ):
265
+ mount_point , label_suffix = None ):
265
266
"""Executes efibootmgr and removes duplicate entries.
266
267
267
268
:param valid_efi_bootloaders: the list of valid efi bootloaders
@@ -270,6 +271,9 @@ def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition,
270
271
:param mount_point: The mountpoint for the EFI partition so we can
271
272
read contents of files if necessary to perform
272
273
proper bootloader injection operations.
274
+ :param label_suffix: a string to be appended to the EFI label,
275
+ mainly used in the case of software to uniqify
276
+ the entries for the md components.
273
277
"""
274
278
275
279
# Before updating let's get information about the bootorder
@@ -292,9 +296,13 @@ def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition,
292
296
v_efi_bl_path = v_bl .replace (csv_filename , str (csv_contents [0 ]))
293
297
v_efi_bl_path = '\\ ' + v_efi_bl_path .replace ('/' , '\\ ' )
294
298
label = csv_contents [1 ]
299
+ if label_suffix :
300
+ label = label + " " + str (label_suffix )
295
301
else :
296
302
v_efi_bl_path = '\\ ' + v_bl .replace ('/' , '\\ ' )
297
303
label = 'ironic' + str (label_id )
304
+ if label_suffix :
305
+ label = label + " " + str (label_suffix )
298
306
299
307
# Iterate through standard out, and look for duplicates
300
308
for line in original_efi_output [0 ].split ('\n ' ):
@@ -307,9 +315,11 @@ def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition,
307
315
LOG .debug ("Found bootnum %s matching label" , boot_num )
308
316
utils .execute ('efibootmgr' , '-b' , boot_num , '-B' )
309
317
310
- LOG .debug ("Adding loader %(path)s on partition %(part)s of device "
311
- " %(dev)s" , {'path' : v_efi_bl_path , 'part' : efi_partition ,
312
- 'dev' : device })
318
+ LOG .info ("Adding loader %(path)s on partition %(part)s of device "
319
+ " %(dev)s with label %(label)s" ,
320
+ {'path' : v_efi_bl_path , 'part' : efi_partition ,
321
+ 'dev' : device , 'label' : label })
322
+
313
323
# Update the nvram using efibootmgr
314
324
# https://linux.die.net/man/8/efibootmgr
315
325
utils .execute ('efibootmgr' , '-v' , '-c' , '-d' , device ,
@@ -380,16 +390,60 @@ def _manage_uefi(device, efi_system_part_uuid=None):
380
390
efi_mounted = True
381
391
382
392
valid_efi_bootloaders = _get_efi_bootloaders (efi_partition_mount_point )
383
- if valid_efi_bootloaders :
384
- _run_efibootmgr (valid_efi_bootloaders , device , efi_partition ,
385
- efi_partition_mount_point )
386
- return True
387
- else :
393
+ if not valid_efi_bootloaders :
388
394
# NOTE(dtantsur): if we have an empty EFI partition, try to use
389
395
# grub-install to populate it.
390
396
LOG .warning ('Empty EFI partition detected.' )
391
397
return False
392
398
399
+ if not hardware .is_md_device (device ):
400
+ efi_devices = [device ]
401
+ efi_partition_numbers = [efi_partition ]
402
+ efi_label_suffix = ''
403
+ else :
404
+ # umount to allow for signature removal (to avoid confusion about
405
+ # which ESP to mount once the instance is deployed)
406
+ utils .execute ('umount' , efi_partition_mount_point , attempts = 3 ,
407
+ delay_on_retry = True )
408
+ efi_mounted = False
409
+
410
+ holders = hardware .get_holder_disks (device )
411
+ efi_md_device = prepare_boot_partitions_for_softraid (
412
+ device , holders , efi_device_part , target_boot_mode = 'uefi'
413
+ )
414
+ efi_devices = hardware .get_component_devices (efi_md_device )
415
+ efi_partition_numbers = []
416
+ _PARTITION_NUMBER = re .compile (r'(\d+)$' )
417
+ for dev in efi_devices :
418
+ match = _PARTITION_NUMBER .search (dev )
419
+ if match :
420
+ partition_number = match .group (1 )
421
+ efi_partition_numbers .append (partition_number )
422
+ else :
423
+ raise errors .DeviceNotFound (
424
+ "Could not extract the partition number "
425
+ "from %s!" % dev )
426
+ efi_label_suffix = "(RAID, part%s)"
427
+
428
+ # remount for _run_efibootmgr
429
+ utils .execute ('mount' , efi_device_part , efi_partition_mount_point )
430
+ efi_mounted = True
431
+
432
+ efi_dev_part = zip (efi_devices , efi_partition_numbers )
433
+ for i , (efi_dev , efi_part ) in enumerate (efi_dev_part ):
434
+ LOG .debug ("Calling efibootmgr with dev %s part %s" ,
435
+ efi_dev , efi_part )
436
+ if efi_label_suffix :
437
+ # NOTE (arne_wiebalck): uniqify the labels to prevent
438
+ # unintentional boot entry cleanup
439
+ _run_efibootmgr (valid_efi_bootloaders , efi_dev , efi_part ,
440
+ efi_partition_mount_point ,
441
+ efi_label_suffix % i )
442
+ else :
443
+ _run_efibootmgr (valid_efi_bootloaders , efi_dev , efi_part ,
444
+ efi_partition_mount_point )
445
+ return True
446
+
393
447
except processutils .ProcessExecutionError as e :
394
448
error_msg = ('Could not verify uefi on device %(dev)s'
395
449
'failed with %(err)s.' % {'dev' : device , 'err' : e })
@@ -422,8 +476,8 @@ def _manage_uefi(device, efi_system_part_uuid=None):
422
476
423
477
424
478
# TODO(rg): handle PreP boot parts relocation as well
425
- def _prepare_boot_partitions_for_softraid (device , holders , efi_part ,
426
- target_boot_mode ):
479
+ def prepare_boot_partitions_for_softraid (device , holders , efi_part ,
480
+ target_boot_mode ):
427
481
"""Prepare boot partitions when relevant.
428
482
429
483
Create either a RAIDed EFI partition or bios boot partitions for software
@@ -492,15 +546,17 @@ def _prepare_boot_partitions_for_softraid(device, holders, efi_part,
492
546
target_part , holder )
493
547
494
548
# RAID the ESPs, metadata=1.0 is mandatory to be able to boot
495
- md_device = '/dev/md/esp'
549
+ md_device = raid_utils . get_next_free_raid_device ()
496
550
LOG .debug ("Creating md device %(md_device)s for the ESPs "
497
551
"on %(efi_partitions)s" ,
498
552
{'md_device' : md_device , 'efi_partitions' : efi_partitions })
499
553
utils .execute ('mdadm' , '--create' , md_device , '--force' ,
500
554
'--run' , '--metadata=1.0' , '--level' , '1' ,
501
- '--raid-devices' , len (efi_partitions ),
555
+ '--name' , 'esp' , '-- raid-devices' , len (efi_partitions ),
502
556
* efi_partitions )
503
557
558
+ disk_utils .trigger_device_rescan (md_device )
559
+
504
560
if efi_part :
505
561
# Blockdev copy the source ESP and erase it
506
562
LOG .debug ("Relocating EFI %s to %s" , efi_part , md_device )
@@ -627,7 +683,7 @@ def _install_grub2(device, root_uuid, efi_system_part_uuid=None,
627
683
efi_partition = efi_part
628
684
if hardware .is_md_device (device ):
629
685
holders = hardware .get_holder_disks (device )
630
- efi_partition = _prepare_boot_partitions_for_softraid (
686
+ efi_partition = prepare_boot_partitions_for_softraid (
631
687
device , holders , efi_part , target_boot_mode
632
688
)
633
689
@@ -1004,9 +1060,7 @@ def _efi_boot_setup(device, efi_system_part_uuid=None, target_boot_mode=None):
1004
1060
{'target' : target_boot_mode ,
1005
1061
'current' : boot .current_boot_mode })
1006
1062
1007
- # FIXME(arne_wiebalck): make software RAID work with efibootmgr
1008
- if (boot .current_boot_mode == 'uefi'
1009
- and not hardware .is_md_device (device )):
1063
+ if boot .current_boot_mode == 'uefi' :
1010
1064
try :
1011
1065
utils .execute ('efibootmgr' , '--version' )
1012
1066
except FileNotFoundError :
0 commit comments