Parse efibootmgr type and details

This change improves the regex to match an exact entry name, and to also
match with the the entry type from a set of recognised types.
The boot entry details start from the recognised type onwards.

This can be used by a step which deletes all entries of type 'HW' and
UsbClass.

Related-Bug: #2041901
Change-Id: I5d879f724efc2919b541fd3fef0f931df67ff9c7
This commit is contained in:
Steve Baker 2023-11-06 15:29:13 +13:00
parent 768aa17442
commit 352df0bc54
2 changed files with 62 additions and 41 deletions

View File

@ -267,13 +267,16 @@ def _get_efi_bootloaders(location):
# NOTE(TheJulia): regex used to identify entries in the efibootmgr # NOTE(TheJulia): regex used to identify entries in the efibootmgr
# output on stdout. # output on stdout.
_ENTRY_LABEL = re.compile(r'Boot([0-9a-f-A-F]+)\*?\s(.*).*$') _ENTRY_LABEL = re.compile(
r'Boot([0-9a-f-A-F]+)\*?\s+(.*?)\s+'
r'((BBS|HD|FvFile|FvVol|PciRoot|VenMsg|VenHw|UsbClass)\(.*)$')
def get_boot_records(): def get_boot_records():
"""Executes efibootmgr and returns boot records. """Executes efibootmgr and returns boot records.
:return: an iterator yielding pairs (boot number, boot record). :return: An iterator yielding tuples
(boot number, boot record, root device type, device path).
""" """
# Invokes binary=True so we get a bytestream back. # Invokes binary=True so we get a bytestream back.
efi_output = utils.execute('efibootmgr', '-v', binary=True) efi_output = utils.execute('efibootmgr', '-v', binary=True)
@ -286,7 +289,7 @@ def get_boot_records():
for line in cmd_output.split('\n'): for line in cmd_output.split('\n'):
match = _ENTRY_LABEL.match(line) match = _ENTRY_LABEL.match(line)
if match is not None: if match is not None:
yield (match[1], match[2]) yield (match[1], match[2], match[4], match[3])
def add_boot_record(device, efi_partition, loader, label): def add_boot_record(device, efi_partition, loader, label):
@ -358,11 +361,11 @@ def _run_efibootmgr(valid_efi_bootloaders, device, efi_partition,
label = label + " " + str(label_suffix) label = label + " " + str(label_suffix)
# Iterate through standard out, and look for duplicates # Iterate through standard out, and look for duplicates
for boot_num, boot_rec in boot_records: for boot_num, boot_rec, boot_type, boot_details in boot_records:
# Look for the base label in the string if a line match # Look for the base label in the string if a line match
# occurs, so we can identify if we need to eliminate the # occurs, so we can identify if we need to eliminate the
# entry. # entry.
if label in boot_rec: if label == boot_rec:
LOG.debug("Found bootnum %s matching label", boot_num) LOG.debug("Found bootnum %s matching label", boot_num)
remove_boot_record(boot_num) remove_boot_record(boot_num)

View File

@ -211,9 +211,9 @@ class TestManageUefi(base.IronicAgentTest):
BootCurrent: 0001 BootCurrent: 0001
Timeout: 0 seconds Timeout: 0 seconds
BootOrder: 0001,0000,001B,001C,001D,001E,001F,0020,0021,0022,0012,0011,0023,0024,0002 BootOrder: 0001,0000,001B,001C,001D,001E,001F,0020,0021,0022,0012,0011,0023,0024,0002
Boot0000* Red Hat Enterprise Linux HD(1,GPT,34178504-2340-4fe0-8001-264372cf9b2d,0x800,0x64000)/File(\EFI\redhat\shimx64.efi) Boot0000* Red Hat Enterprise Linux HD(1,GPT,34178504-2340-4fe0-8001-264372cf9b2d,0x800,0x64000)/File(\\EFI\\redhat\\shimx64.efi)
Boot0001* Fedora HD(1,GPT,da6b4491-61f2-42b0-8ab1-7c4a87317c4e,0x800,0x64000)/File(\EFI\fedora\shimx64.efi) Boot0001* Fedora HD(1,GPT,da6b4491-61f2-42b0-8ab1-7c4a87317c4e,0x800,0x64000)/File(\\EFI\\fedora\\shimx64.efi)
Boot0002* Linux-Firmware-Updater HD(1,GPT,da6b4491-61f2-42b0-8ab1-7c4a87317c4e,0x800,0x64000)/File(\EFI\fedora\fwupdx64.efi) Boot0002* Linux-Firmware-Updater HD(1,GPT,da6b4491-61f2-42b0-8ab1-7c4a87317c4e,0x800,0x64000)/File(\\EFI\\fedora\\fwupdx64.efi)
Boot0003 ThinkShield secure wipe FvFile(3593a0d5-bd52-43a0-808e-cbff5ece2477) Boot0003 ThinkShield secure wipe FvFile(3593a0d5-bd52-43a0-808e-cbff5ece2477)
Boot0004 LENOVO CLOUD VenMsg(bc7838d2-0f82-4d60-8316-c068ee79d25b,ad38ccbbf7edf04d959cf42aa74d3650)/Uri(https://download.lenovo.com/pccbbs/cdeploy/efi/boot.efi) Boot0004 LENOVO CLOUD VenMsg(bc7838d2-0f82-4d60-8316-c068ee79d25b,ad38ccbbf7edf04d959cf42aa74d3650)/Uri(https://download.lenovo.com/pccbbs/cdeploy/efi/boot.efi)
Boot0005 IDER BOOT CDROM PciRoot(0x0)/Pci(0x14,0x0)/USB(11,1) Boot0005 IDER BOOT CDROM PciRoot(0x0)/Pci(0x14,0x0)/USB(11,1)
@ -229,53 +229,71 @@ Boot0009* Internal CD/DVD ROM Drive (UEFI) PciRoot(0x0)/Pci(0x11,0x0)/Sata(
mock_execute.return_value = (efibootmgr_resp, '') mock_execute.return_value = (efibootmgr_resp, '')
result = list(efi_utils.get_boot_records()) result = list(efi_utils.get_boot_records())
def assertEntry(expected, actual): self.assertEqual(
self.assertEqual(2, len(actual)) ('0000', 'Red Hat Enterprise Linux', 'HD',
self.assertEqual(expected[0], actual[0]) 'HD(1,GPT,34178504-2340-4fe0-8001-264372cf9b2d,0x800,0x64000)/'
self.assertIn(expected[1], actual[1]) 'File(\\EFI\\redhat\\shimx64.efi)'),
assertEntry(
('0000', 'Red Hat Enterprise Linux'),
result[0]) result[0])
assertEntry( self.assertEqual(
('0001', 'Fedora'), ('0001', 'Fedora', 'HD',
'HD(1,GPT,da6b4491-61f2-42b0-8ab1-7c4a87317c4e,0x800,0x64000)/'
'File(\\EFI\\fedora\\shimx64.efi)'),
result[1]) result[1])
assertEntry( self.assertEqual(
('0002', 'Linux-Firmware-Updater'), ('0002', 'Linux-Firmware-Updater', 'HD',
'HD(1,GPT,da6b4491-61f2-42b0-8ab1-7c4a87317c4e,0x800,0x64000)/'
'File(\\EFI\\fedora\\fwupdx64.efi)'),
result[2]) result[2])
assertEntry( self.assertEqual(
('0003', 'ThinkShield secure wipe'), ('0003', 'ThinkShield secure wipe', 'FvFile',
'FvFile(3593a0d5-bd52-43a0-808e-cbff5ece2477)'),
result[3]) result[3])
assertEntry( self.assertEqual(
('0004', 'LENOVO CLOUD'), ('0004', 'LENOVO CLOUD', 'VenMsg',
'VenMsg(bc7838d2-0f82-4d60-8316-c068ee79d25b,'
'ad38ccbbf7edf04d959cf42aa74d3650)/'
'Uri(https://download.lenovo.com/pccbbs/cdeploy/efi/boot.efi)'),
result[4]) result[4])
assertEntry( self.assertEqual(
('0005', 'IDER BOOT CDROM'), ('0005', 'IDER BOOT CDROM', 'PciRoot',
'PciRoot(0x0)/Pci(0x14,0x0)/USB(11,1)'),
result[5]) result[5])
assertEntry( self.assertEqual(
('0006', 'ATA HDD'), ('0006', 'ATA HDD', 'VenMsg',
'VenMsg(bc7838d2-0f82-4d60-8316-c068ee79d25b,'
'91af625956449f41a7b91f4f892ab0f6)'),
result[6]) result[6])
assertEntry( self.assertEqual(
('0007', 'Hard drive C:'), ('0007', 'Hard drive C:', 'VenHw',
mock.ANY),
result[7]) result[7])
assertEntry( self.assertEqual(
('AAA8', 'IBA GE Slot 0100 v1588'), ('AAA8', 'IBA GE Slot 0100 v1588', 'BBS',
mock.ANY),
result[8]) result[8])
assertEntry( self.assertEqual(
('0FF9', 'Virtual CD/DVD'), ('0FF9', 'Virtual CD/DVD', 'PciRoot',
'PciRoot(0x0)/Pci(0x14,0x0)/USB(13,0)/USB(3,0)/USB(1,0)'),
result[9]) result[9])
assertEntry( self.assertEqual(
('123A', 'Integrated NIC 1 Port 1 Partition 1'), ('123A', 'Integrated NIC 1 Port 1 Partition 1', 'VenHw',
'VenHw(33391845-5f86-4e78-8fce-c4cff59f9bbb)'),
result[10]) result[10])
assertEntry( self.assertEqual(
('000B', ('000B',
'UEFI: PXE IPv4 Realtek PCIe 2.5GBE Family Controller'), 'UEFI: PXE IPv4 Realtek PCIe 2.5GBE Family Controller',
'PciRoot',
'PciRoot(0x0)/Pci(0x1c,0x0)/Pci(0x0,0x0)/MAC([REDACTED],0)/'
'IPv4(0.0.0.00.0.0.0,0,0)..BO'),
result[11]) result[11])
assertEntry( self.assertEqual(
('0008', 'Generic USB Boot'), ('0008', 'Generic USB Boot', 'UsbClass',
'UsbClass(ffff,ffff,255,255)'),
result[12]) result[12])
assertEntry( self.assertEqual(
('0009', 'Internal CD/DVD ROM Drive (UEFI'), ('0009', 'Internal CD/DVD ROM Drive (UEFI)', 'PciRoot',
'PciRoot(0x0)/Pci(0x11,0x0)/Sata(1,65535,0)/'
'CDROM(1,0x265,0x2000)'),
result[13]) result[13])
@mock.patch.object(os.path, 'exists', lambda *_: False) @mock.patch.object(os.path, 'exists', lambda *_: False)