Skip to content
3 changes: 3 additions & 0 deletions tests/data/grub-linux-no-kernel.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
menuentry 'Linux - Safe Mode' {
initrd /boot/initrd.img-1
}
7 changes: 0 additions & 7 deletions tests/data/grub-linux.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,3 @@ menuentry 'Linux - Safe Mode' {
linux /boot/vmlinuz-1 ro
initrd /boot/initrd.img-1
}
menuentry 'XCP-ng (Trusted Boot)' {
search --label --set root root-vgdorj
multiboot2 /boot/tboot.gz logging=serial,memory
module2 /boot/xen.gz dom0_mem=7584M,max:7584M watchdog crashkernel=256M,below=4G
module2 /boot/vmlinuz-6.1-xen root=LABEL=root-vgdorj ro console=hvc0 console=tty0
module2 /boot/initrd-6.1-xen.img
}
10 changes: 10 additions & 0 deletions tests/data/grub-no-hypervisor.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
serial --unit=0 --speed=115200
terminal_input serial console
terminal_output serial console
set default=0
set timeout=5
menuentry 'XCP-ng' {
search --label --set root root-vgdorj
xen_module /boot/vmlinuz-4.19-xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=hvc0 console=tty0 quiet vga=785 splash plymouth.ignore-serial-consoles
xen_module /boot/initrd-4.19-xen.img
}
10 changes: 10 additions & 0 deletions tests/data/grub-no-multiboot.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
serial --unit=0 --speed=115200
terminal_input serial console
terminal_output serial console
set default=0
set timeout=5
menuentry 'XCP-ng' {
search --label --set root root-vgdorj
module2 /boot/vmlinuz-4.19-xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=hvc0 console=tty0 quiet vga=785 splash plymouth.ignore-serial-consoles
module2 /boot/initrd-4.19-xen.img
}
35 changes: 35 additions & 0 deletions tests/data/grub-xen-boot.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
serial --unit=0 --speed=115200
terminal_input serial console
terminal_output serial console
set default=0
set timeout=5
menuentry 'XCP-ng' {
search --label --set root root-vgdorj
xen_hypervisor /boot/xen.gz dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G console=vga vga=mode-0x0311
xen_module /boot/vmlinuz-4.19-xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=hvc0 console=tty0 quiet vga=785 splash plymouth.ignore-serial-consoles
xen_module /boot/initrd-4.19-xen.img
}
menuentry 'XCP-ng (Serial)' {
search --label --set root root-vgdorj
xen_hypervisor /boot/xen.gz com1=115200,8n1 console=com1,vga dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G
xen_module /boot/vmlinuz-4.19-xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=tty0 console=hvc0
xen_module /boot/initrd-4.19-xen.img
}
menuentry 'XCP-ng in Safe Mode' {
search --label --set root root-vgdorj
xen_hypervisor /boot/xen.gz nosmp noreboot noirqbalance no-mce no-bootscrub no-numa no-hap no-mmcfg max_cstate=0 nmi=ignore allow_unsafe dom0_mem=7584M,max:7584M com1=115200,8n1 console=com1,vga
xen_module /boot/vmlinuz-4.19-xen earlyprintk=xen root=LABEL=root-vgdorj ro nolvm hpet=disable console=tty0 console=hvc0
xen_module /boot/initrd-4.19-xen.img
}
menuentry 'XCP-ng (Xen 4.13.1 / Linux 4.19.0+1)' {
search --label --set root root-vgdorj
xen_hypervisor /boot/xen-fallback.gz dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G
xen_module /boot/vmlinuz-fallback root=LABEL=root-vgdorj ro nolvm hpet=disable console=hvc0 console=tty0
xen_module /boot/initrd-fallback.img
}
menuentry 'XCP-ng (Serial, Xen 4.13.1 / Linux 4.19.0+1)' {
search --label --set root root-vgdorj
xen_hypervisor /boot/xen-fallback.gz com1=115200,8n1 console=com1,vga dom0_mem=7584M,max:7584M watchdog ucode=scan dom0_max_vcpus=1-16 crashkernel=256M,below=4G
xen_module /boot/vmlinuz-fallback root=LABEL=root-vgdorj ro nolvm hpet=disable console=tty0 console=hvc0
xen_module /boot/initrd-fallback.img
}
179 changes: 130 additions & 49 deletions tests/test_bootloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,137 @@
import subprocess
from tempfile import NamedTemporaryFile, mkdtemp

from xcp.bootloader import Bootloader
from xcp.bootloader import Bootloader, Grub2Format, MenuEntry
from xcp.compat import open_with_codec_handling


def test_writeGrubWithTempFile(tmpdir):
"""Test xcp.bootloader.{writeGrub,writeExtLinux}.open_with_codec_handling with tmpdir fixture"""
bootloader = Bootloader.readGrub2("tests/data/grub.cfg")
filename = str(tmpdir.mkdir("grub").join("menu.lst"))
bootloader.writeGrub(filename)
Bootloader.readGrub(filename)
bootloader.writeExtLinux(filename)
Bootloader.readExtLinux(filename)


def test_GrubLegacyExtLinuxWithTempFile(tmpdir):
"""Note: GRUB-Legacy and EXTLINUX code can likely be removed (pending approval)"""
bootloader = Bootloader.readGrub2("tests/data/grub-linux.cfg")
filename = str(tmpdir.mkdir("grub").join("menu.lst"))
bootloader.writeExtLinux(filename)
Bootloader.readExtLinux(filename)
bootloader.menu.pop("xe-tboot")
bootloader.menu_order.remove("xe-tboot")
bootloader.writeGrub(filename)
Bootloader.readGrub(filename)


class TestBootloader(unittest.TestCase):
def test_grub2(self):
bl = Bootloader.readGrub2("tests/data/grub.cfg")
def _test_cfg(self, cfg):
bl = Bootloader.readGrub2(cfg)
with NamedTemporaryFile("w") as temp:
bl.writeGrub2(temp.name)
# get a diff
proc = subprocess.Popen(["diff", "tests/data/grub.cfg", temp.name],
proc = subprocess.Popen(["diff", cfg, temp.name],
stdout = subprocess.PIPE,
universal_newlines=True)
assert proc.stdout
for line in proc.stdout:
# pylint: disable-next=deprecated-method
self.assertRegexpMatches(line, r"^(5a6,13$|>)")

proc.stdout.close()
proc.wait()
self.assertEqual(proc.stdout.read(), '''5a6,13

Check warning on line 21 in tests/test_bootloader.py

View workflow job for this annotation

GitHub Actions / test (3.11, ubuntu-22.04)

"read" is not a known attribute of "None" (reportOptionalMemberAccess)
> if [ -s $prefix/grubenv ]; then
> load_env
> fi
>
> if [ -n "$override_entry" ]; then
> set default=$override_entry
> fi
>
''')
proc.stdout.close()

Check warning on line 31 in tests/test_bootloader.py

View workflow job for this annotation

GitHub Actions / test (3.11, ubuntu-22.04)

"close" is not a known attribute of "None" (reportOptionalMemberAccess)
proc.wait()
self.assertEqual(proc.returncode, 1)

def test_grub2(self):
'''Test read/write roundtrip of GRUB2 multiboot config'''
self._test_cfg("tests/data/grub.cfg")

def test_grub2_xen_boot(self):
'''Test read/write roundtrip of GRUB2 xen_boot config'''
self._test_cfg("tests/data/grub-xen-boot.cfg")

def test_no_multiboot(self):
# A module2 line without a multiboot2 line is an error
with self.assertRaises(RuntimeError):
Bootloader.readGrub2("tests/data/grub-no-multiboot.cfg")

def test_no_hypervisor(self):
# A xen_module line without a xen_hypervisor line is an error
with self.assertRaises(RuntimeError):
Bootloader.readGrub2("tests/data/grub-no-hypervisor.cfg")


class TestMenuEntry(unittest.TestCase):
def setUp(self):
self.tmpdir = mkdtemp(prefix="testbl")
self.fn = os.path.join(self.tmpdir, 'grub.cfg')
self.bl = Bootloader('grub2', self.fn)

def tearDown(self):
shutil.rmtree(self.tmpdir)

def test_new_multiboot(self):
# No format specified, default to multiboot2
e = MenuEntry(hypervisor='xen.efi', hypervisor_args='xarg1 xarg2',
kernel='vmlinuz', kernel_args='karg1 karg2',
initrd='initrd.img', title='xe')
self.bl.append('xe', e)

e = MenuEntry(hypervisor='xen.efi', hypervisor_args='xarg1 xarg2',
kernel='vmlinuz', kernel_args='karg1 karg2',
initrd='initrd.img', title='xe-serial')
e.entry_format = Grub2Format.MULTIBOOT2

Check warning on line 73 in tests/test_bootloader.py

View workflow job for this annotation

GitHub Actions / test (3.11, ubuntu-22.04)

Cannot assign to attribute "entry_format" for class "MenuEntry"
self.bl.append('xe-serial', e)

self.bl.commit()

with open_with_codec_handling(self.fn, 'r') as f:
content = f.read()

self.assertEqual(content, '''menuentry 'xe' {
multiboot2 xen.efi xarg1 xarg2
module2 vmlinuz karg1 karg2
module2 initrd.img
}
menuentry 'xe-serial' {
multiboot2 xen.efi xarg1 xarg2
module2 vmlinuz karg1 karg2
module2 initrd.img
}
''')

def test_new_xen_boot(self):
e = MenuEntry(hypervisor='xen.efi', hypervisor_args='xarg1 xarg2',
kernel='vmlinuz', kernel_args='karg1 karg2',
initrd='initrd.img', title='xe')
e.entry_format = Grub2Format.XEN_BOOT

Check warning on line 97 in tests/test_bootloader.py

View workflow job for this annotation

GitHub Actions / test (3.11, ubuntu-22.04)

Cannot assign to attribute "entry_format" for class "MenuEntry"
self.bl.append('xe', e)
self.bl.commit()

with open_with_codec_handling(self.fn, 'r') as f:
content = f.read()

self.assertEqual(content, '''menuentry 'xe' {
xen_hypervisor xen.efi xarg1 xarg2
xen_module vmlinuz karg1 karg2
xen_module initrd.img
}
''')

def test_new_linux(self):
e = MenuEntry(hypervisor='', hypervisor_args='',
kernel='vmlinuz', kernel_args='karg1 karg2',
initrd='initrd.img', title='linux')
self.bl.append('linux', e)
self.bl.commit()

e = MenuEntry(hypervisor='', hypervisor_args='',
kernel='vmlinuz2', kernel_args='karg3 karg4',
initrd='initrd2.img', title='linux2')
e.entry_format = Grub2Format.LINUX

Check warning on line 121 in tests/test_bootloader.py

View workflow job for this annotation

GitHub Actions / test (3.11, ubuntu-22.04)

Cannot assign to attribute "entry_format" for class "MenuEntry"
self.bl.append('linux2', e)
self.bl.commit()

with open_with_codec_handling(self.fn, 'r') as f:
content = f.read()

self.assertEqual(content, '''menuentry 'linux' {
linux vmlinuz karg1 karg2
initrd initrd.img
}
menuentry 'linux2' {
linux vmlinuz2 karg3 karg4
initrd initrd2.img
}
''')


class TestLinuxBootloader(unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -80,7 +169,6 @@
"",
],
[],
[],
]
assert str(bl.default).startswith("safe")
assert bl.location == "mbr"
Expand All @@ -90,34 +178,27 @@
assert bl.menu["safe"].kernel == "/boot/vmlinuz-2"
assert bl.menu["safe"].kernel_args == "ro"
assert bl.menu["safe"].initrd == "/boot/initrd.img-2"
assert bl.menu["xe-tboot"].title == "XCP-ng (Trusted Boot)"
assert bl.menu["xe-tboot"].hypervisor == "/boot/xen.gz"
assert bl.menu["xe-tboot"].tboot == "/boot/tboot.gz"
assert bl.menu["xe-tboot"].getTbootArgs() == ["logging=serial,memory"]

def test_no_kernel(self):
# An initrd line without a kernel line is an error
with self.assertRaises(RuntimeError):
Bootloader.readGrub2("tests/data/grub-linux-no-kernel.cfg")


class TestBootloaderAdHoc(unittest.TestCase):
def setUp(self):
self.bl = Bootloader.readGrub2("tests/data/grub.cfg")
check_config(self.bl)

def test_grub(self):
def test_grub2(self):
with NamedTemporaryFile("w", delete=False) as temp:
self.bl.writeGrub(temp)
bl2 = Bootloader.readGrub(temp.name)
self.bl.writeGrub2(temp)
bl2 = Bootloader.readGrub2(temp.name)
# Check config from tests/data/grub.cfg:
os.unlink(temp.name)
assert bl2.serial == {"port": 0, "baud": 115200}
check_config(bl2)

def test_extlinux(self):
with NamedTemporaryFile("w", delete=False) as temp:
self.bl.writeExtLinux(temp)
bl2 = Bootloader.readExtLinux(temp.name)
os.unlink(temp.name)
# readExtLinux tries to read flow-control (there is none in tests/data/grub.cfg):
assert bl2.serial == {"port": 0, "baud": 115200, "flow": None}
check_config(bl2)


def check_config(bl):
# Check config from tests/data/grub.cfg:
Expand Down
Loading
Loading