Merge pull request #733 from mwhudson/disable-multiple-boot-devices-on-bionic
do not offer resilient boot options pre-focal
This commit is contained in:
commit
905d34daaa
|
@ -26,10 +26,12 @@ from subiquitycore.async_helpers import (
|
||||||
schedule_task,
|
schedule_task,
|
||||||
SingleInstanceTask,
|
SingleInstanceTask,
|
||||||
)
|
)
|
||||||
|
from subiquitycore.lsb_release import lsb_release
|
||||||
from subiquitycore.utils import (
|
from subiquitycore.utils import (
|
||||||
run_command,
|
run_command,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
from subiquity.controller import SubiquityController
|
from subiquity.controller import SubiquityController
|
||||||
from subiquity.controllers.error import ErrorReportKind
|
from subiquity.controllers.error import ErrorReportKind
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
|
@ -80,6 +82,11 @@ class FilesystemController(SubiquityController):
|
||||||
self._probe_once, propagate_errors=False)
|
self._probe_once, propagate_errors=False)
|
||||||
self._probe_task = SingleInstanceTask(
|
self._probe_task = SingleInstanceTask(
|
||||||
self._probe, propagate_errors=False)
|
self._probe, propagate_errors=False)
|
||||||
|
if self.model.bootloader == Bootloader.PREP:
|
||||||
|
self.supports_resilient_boot = False
|
||||||
|
else:
|
||||||
|
release = lsb_release()['release']
|
||||||
|
self.supports_resilient_boot = release >= '20.04'
|
||||||
|
|
||||||
def load_autoinstall_data(self, data):
|
def load_autoinstall_data(self, data):
|
||||||
log.debug("load_autoinstall_data %s", data)
|
log.debug("load_autoinstall_data %s", data)
|
||||||
|
@ -679,7 +686,7 @@ class FilesystemController(SubiquityController):
|
||||||
|
|
||||||
def add_boot_disk(self, new_boot_disk):
|
def add_boot_disk(self, new_boot_disk):
|
||||||
bootloader = self.model.bootloader
|
bootloader = self.model.bootloader
|
||||||
if bootloader == Bootloader.PREP:
|
if not self.supports_resilient_boot:
|
||||||
for disk in self.model.all_disks():
|
for disk in self.model.all_disks():
|
||||||
if disk._is_boot_device():
|
if disk._is_boot_device():
|
||||||
self.remove_boot_disk(disk)
|
self.remove_boot_disk(disk)
|
||||||
|
|
|
@ -89,52 +89,6 @@ class TestFilesystemController(unittest.TestCase):
|
||||||
"add_boot_disk(disk) did not make _can_TOGGLE_BOOT false "
|
"add_boot_disk(disk) did not make _can_TOGGLE_BOOT false "
|
||||||
"with bootloader {}".format(bl))
|
"with bootloader {}".format(bl))
|
||||||
|
|
||||||
def test_make_boot_disk_BIOS(self):
|
|
||||||
controller = make_controller(Bootloader.BIOS)
|
|
||||||
disk1 = make_disk(controller.model, preserve=False)
|
|
||||||
|
|
||||||
controller.add_boot_disk(disk1)
|
|
||||||
self.assertEqual(len(disk1.partitions()), 1)
|
|
||||||
self.assertEqual(disk1.partitions()[0].flag, "bios_grub")
|
|
||||||
self.assertTrue(disk1.grub_device)
|
|
||||||
|
|
||||||
controller.remove_boot_disk(disk1)
|
|
||||||
self.assertEqual(len(disk1.partitions()), 0)
|
|
||||||
self.assertFalse(disk1.grub_device)
|
|
||||||
|
|
||||||
disk2 = make_disk(controller.model, preserve=False)
|
|
||||||
disk2p1 = controller.model.add_partition(
|
|
||||||
disk2, size=disk2.free_for_partitions)
|
|
||||||
size_before = disk2p1.size
|
|
||||||
controller.add_boot_disk(disk2)
|
|
||||||
self.assertEqual(len(disk2.partitions()), 2)
|
|
||||||
self.assertEqual(disk2.partitions()[1], disk2p1)
|
|
||||||
self.assertEqual(
|
|
||||||
disk2.partitions()[0].size + disk2p1.size, size_before)
|
|
||||||
self.assertEqual(disk2.partitions()[0].flag, "bios_grub")
|
|
||||||
self.assertTrue(disk2.grub_device)
|
|
||||||
|
|
||||||
controller.remove_boot_disk(disk2)
|
|
||||||
self.assertEqual(disk2.partitions(), [disk2p1])
|
|
||||||
self.assertEqual(disk2p1.size, size_before)
|
|
||||||
self.assertFalse(disk2.grub_device)
|
|
||||||
|
|
||||||
def test_make_boot_disk_BIOS_existing(self):
|
|
||||||
controller = make_controller(Bootloader.BIOS)
|
|
||||||
disk1 = make_disk(controller.model, preserve=True)
|
|
||||||
disk1p1 = controller.model.add_partition(
|
|
||||||
disk1, size=1 << 20, flag="bios_grub")
|
|
||||||
disk1p1.preserve = True
|
|
||||||
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
self.assertFalse(disk1.grub_device)
|
|
||||||
controller.add_boot_disk(disk1)
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
self.assertTrue(disk1.grub_device)
|
|
||||||
controller.remove_boot_disk(disk1)
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
self.assertFalse(disk1.grub_device)
|
|
||||||
|
|
||||||
def assertIsMountedAtBootEFI(self, device):
|
def assertIsMountedAtBootEFI(self, device):
|
||||||
efi_mnts = device._m._all(type="mount", path="/boot/efi")
|
efi_mnts = device._m._all(type="mount", path="/boot/efi")
|
||||||
self.assertEqual(len(efi_mnts), 1)
|
self.assertEqual(len(efi_mnts), 1)
|
||||||
|
@ -144,103 +98,137 @@ class TestFilesystemController(unittest.TestCase):
|
||||||
if device.fs():
|
if device.fs():
|
||||||
self.assertIs(device.fs().mount(), None)
|
self.assertIs(device.fs().mount(), None)
|
||||||
|
|
||||||
def test_make_boot_disk_UEFI(self):
|
def add_existing_boot_partition(self, controller, disk):
|
||||||
controller = make_controller(Bootloader.UEFI)
|
if controller.model.bootloader == Bootloader.BIOS:
|
||||||
|
part = controller.model.add_partition(
|
||||||
|
disk, size=1 << 20, flag="bios_grub")
|
||||||
|
elif controller.model.bootloader == Bootloader.UEFI:
|
||||||
|
part = controller.model.add_partition(
|
||||||
|
disk, size=512 << 20, flag="boot")
|
||||||
|
elif controller.model.bootloader == Bootloader.PREP:
|
||||||
|
part = controller.model.add_partition(
|
||||||
|
disk, size=8 << 20, flag="prep")
|
||||||
|
part.preserve = True
|
||||||
|
return part
|
||||||
|
|
||||||
|
def assertIsBootDisk(self, controller, disk):
|
||||||
|
if controller.model.bootloader == Bootloader.BIOS:
|
||||||
|
self.assertTrue(disk.grub_device)
|
||||||
|
self.assertEqual(disk.partitions()[0].flag, "bios_grub")
|
||||||
|
elif controller.model.bootloader == Bootloader.UEFI:
|
||||||
|
for part in disk.partitions():
|
||||||
|
if part.flag == "boot" and part.grub_device:
|
||||||
|
return
|
||||||
|
self.fail("{} is not a boot disk".format(disk))
|
||||||
|
elif controller.model.bootloader == Bootloader.PREP:
|
||||||
|
for part in disk.partitions():
|
||||||
|
if part.flag == "prep" and part.grub_device:
|
||||||
|
self.assertEqual(part.wipe, 'zero')
|
||||||
|
return
|
||||||
|
self.fail("{} is not a boot disk".format(disk))
|
||||||
|
|
||||||
|
def assertIsNotBootDisk(self, controller, disk):
|
||||||
|
if controller.model.bootloader == Bootloader.BIOS:
|
||||||
|
self.assertFalse(disk.grub_device)
|
||||||
|
elif controller.model.bootloader == Bootloader.UEFI:
|
||||||
|
for part in disk.partitions():
|
||||||
|
if part.flag == "boot" and part.grub_device:
|
||||||
|
self.fail("{} is a boot disk".format(disk))
|
||||||
|
elif controller.model.bootloader == Bootloader.PREP:
|
||||||
|
for part in disk.partitions():
|
||||||
|
if part.flag == "prep" and part.grub_device:
|
||||||
|
self.fail("{} is a boot disk".format(disk))
|
||||||
|
|
||||||
|
def test_boot_disk_resilient(self):
|
||||||
|
for bl in Bootloader:
|
||||||
|
if bl == Bootloader.NONE:
|
||||||
|
continue
|
||||||
|
controller = make_controller(bl)
|
||||||
|
controller.supports_resilient_boot = True
|
||||||
|
|
||||||
disk1 = make_disk(controller.model, preserve=False)
|
disk1 = make_disk(controller.model, preserve=False)
|
||||||
disk2 = make_disk(controller.model, preserve=False)
|
disk2 = make_disk(controller.model, preserve=False)
|
||||||
disk2p1 = controller.model.add_partition(
|
disk2p1 = controller.model.add_partition(
|
||||||
disk2, size=disk2.free_for_partitions)
|
disk2, size=disk2.free_for_partitions)
|
||||||
|
|
||||||
controller.add_boot_disk(disk1)
|
controller.add_boot_disk(disk1)
|
||||||
self.assertEqual(len(disk1.partitions()), 1)
|
self.assertIsBootDisk(controller, disk1)
|
||||||
disk1esp = disk1.partitions()[0]
|
if bl == Bootloader.UEFI:
|
||||||
self.assertEqual(disk1esp.flag, "boot")
|
self.assertIsMountedAtBootEFI(disk1.partitions()[0])
|
||||||
self.assertEqual(disk1esp.fs().fstype, "fat32")
|
|
||||||
self.assertTrue(disk1esp.grub_device)
|
|
||||||
self.assertIsMountedAtBootEFI(disk1esp)
|
|
||||||
|
|
||||||
size_before = disk2p1.size
|
size_before = disk2p1.size
|
||||||
controller.add_boot_disk(disk2)
|
controller.add_boot_disk(disk2)
|
||||||
self.assertEqual(len(disk2.partitions()), 2)
|
self.assertIsBootDisk(controller, disk1)
|
||||||
self.assertEqual(disk2.partitions()[1], disk2p1)
|
self.assertIsBootDisk(controller, disk2)
|
||||||
disk2esp = disk2.partitions()[0]
|
if bl == Bootloader.UEFI:
|
||||||
self.assertEqual(disk2esp.size + disk2p1.size, size_before)
|
self.assertIsMountedAtBootEFI(disk1.partitions()[0])
|
||||||
self.assertEqual(disk2esp.flag, "boot")
|
self.assertNotMounted(disk2.partitions()[0])
|
||||||
self.assertTrue(disk2esp.grub_device)
|
|
||||||
self.assertIsMountedAtBootEFI(disk1esp)
|
|
||||||
self.assertNotMounted(disk2esp)
|
|
||||||
|
|
||||||
controller.remove_boot_disk(disk1)
|
|
||||||
self.assertIsMountedAtBootEFI(disk2esp)
|
|
||||||
self.assertEqual(len(disk1.partitions()), 0)
|
|
||||||
|
|
||||||
controller.remove_boot_disk(disk2)
|
|
||||||
self.assertEqual(len(disk2.partitions()), 1)
|
|
||||||
self.assertEqual(disk2p1.size, size_before)
|
|
||||||
|
|
||||||
def test_make_boot_disk_UEFI_existing(self):
|
|
||||||
controller = make_controller(Bootloader.UEFI)
|
|
||||||
disk1 = make_disk(controller.model, preserve=True)
|
|
||||||
disk1p1 = controller.model.add_partition(
|
|
||||||
disk1, size=512 << 20, flag="boot")
|
|
||||||
disk1p1.preserve = True
|
|
||||||
disk2 = make_disk(controller.model, preserve=True)
|
|
||||||
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
efi_mnt = controller.model._mount_for_path("/boot/efi")
|
|
||||||
self.assertEqual(efi_mnt, None)
|
|
||||||
controller.add_boot_disk(disk1)
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
self.assertTrue(disk1p1.grub_device)
|
|
||||||
self.assertIsMountedAtBootEFI(disk1p1)
|
|
||||||
self.assertEqual(disk1p1.fs().fstype, "fat32")
|
|
||||||
|
|
||||||
controller.add_boot_disk(disk2)
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
self.assertTrue(disk1p1.grub_device)
|
|
||||||
self.assertIsMountedAtBootEFI(disk1p1)
|
|
||||||
|
|
||||||
def test_make_boot_disk_PREP(self):
|
|
||||||
controller = make_controller(Bootloader.PREP)
|
|
||||||
disk1 = make_disk(controller.model, preserve=False)
|
|
||||||
disk2 = make_disk(controller.model, preserve=False)
|
|
||||||
disk2p1 = controller.model.add_partition(
|
|
||||||
disk2, size=disk2.free_for_partitions)
|
|
||||||
|
|
||||||
controller.add_boot_disk(disk1)
|
|
||||||
self.assertEqual(len(disk1.partitions()), 1)
|
|
||||||
self.assertEqual(disk1.partitions()[0].flag, "prep")
|
|
||||||
self.assertEqual(disk1.partitions()[0].wipe, "zero")
|
|
||||||
self.assertTrue(disk1.partitions()[0].grub_device)
|
|
||||||
|
|
||||||
size_before = disk2p1.size
|
|
||||||
controller.add_boot_disk(disk2)
|
|
||||||
self.assertEqual(len(disk1.partitions()), 0)
|
|
||||||
self.assertEqual(len(disk2.partitions()), 2)
|
self.assertEqual(len(disk2.partitions()), 2)
|
||||||
self.assertEqual(disk2.partitions()[1], disk2p1)
|
self.assertEqual(disk2.partitions()[1], disk2p1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
disk2.partitions()[0].size + disk2p1.size, size_before)
|
disk2.partitions()[0].size + disk2p1.size, size_before)
|
||||||
self.assertEqual(disk2.partitions()[0].flag, "prep")
|
|
||||||
self.assertEqual(disk2.partitions()[0].wipe, "zero")
|
|
||||||
|
|
||||||
def test_make_boot_disk_PREP_existing(self):
|
|
||||||
controller = make_controller(Bootloader.PREP)
|
|
||||||
disk1 = make_disk(controller.model, preserve=True)
|
|
||||||
disk1p1 = controller.model.add_partition(
|
|
||||||
disk1, size=8 << 20, flag="prep")
|
|
||||||
disk1p1.preserve = True
|
|
||||||
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
self.assertFalse(disk1p1.grub_device)
|
|
||||||
controller.add_boot_disk(disk1)
|
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
|
||||||
self.assertTrue(disk1p1.grub_device)
|
|
||||||
self.assertEqual(disk1p1.wipe, 'zero')
|
|
||||||
|
|
||||||
controller.remove_boot_disk(disk1)
|
controller.remove_boot_disk(disk1)
|
||||||
self.assertEqual(disk1.partitions(), [disk1p1])
|
self.assertIsNotBootDisk(controller, disk1)
|
||||||
self.assertFalse(disk1p1.grub_device)
|
self.assertIsBootDisk(controller, disk2)
|
||||||
self.assertEqual(disk1p1.wipe, None)
|
if bl == Bootloader.UEFI:
|
||||||
|
self.assertIsMountedAtBootEFI(disk2.partitions()[0])
|
||||||
|
self.assertEqual(len(disk1.partitions()), 0)
|
||||||
|
|
||||||
|
controller.remove_boot_disk(disk2)
|
||||||
|
self.assertIsNotBootDisk(controller, disk2)
|
||||||
|
self.assertEqual(len(disk2.partitions()), 1)
|
||||||
|
self.assertEqual(disk2p1.size, size_before)
|
||||||
|
|
||||||
|
def test_boot_disk_no_resilient(self):
|
||||||
|
for bl in Bootloader:
|
||||||
|
if bl == Bootloader.NONE:
|
||||||
|
continue
|
||||||
|
controller = make_controller(bl)
|
||||||
|
controller.supports_resilient_boot = False
|
||||||
|
|
||||||
|
disk1 = make_disk(controller.model, preserve=False)
|
||||||
|
disk2 = make_disk(controller.model, preserve=False)
|
||||||
|
disk2p1 = controller.model.add_partition(
|
||||||
|
disk2, size=disk2.free_for_partitions)
|
||||||
|
|
||||||
|
controller.add_boot_disk(disk1)
|
||||||
|
self.assertIsBootDisk(controller, disk1)
|
||||||
|
if bl == Bootloader.UEFI:
|
||||||
|
self.assertIsMountedAtBootEFI(disk1.partitions()[0])
|
||||||
|
|
||||||
|
size_before = disk2p1.size
|
||||||
|
controller.add_boot_disk(disk2)
|
||||||
|
self.assertIsNotBootDisk(controller, disk1)
|
||||||
|
self.assertIsBootDisk(controller, disk2)
|
||||||
|
if bl == Bootloader.UEFI:
|
||||||
|
self.assertIsMountedAtBootEFI(disk2.partitions()[0])
|
||||||
|
self.assertEqual(len(disk2.partitions()), 2)
|
||||||
|
self.assertEqual(disk2.partitions()[1], disk2p1)
|
||||||
|
self.assertEqual(
|
||||||
|
disk2.partitions()[0].size + disk2p1.size, size_before)
|
||||||
|
|
||||||
|
def test_boot_disk_existing(self):
|
||||||
|
for bl in Bootloader:
|
||||||
|
if bl == Bootloader.NONE:
|
||||||
|
continue
|
||||||
|
controller = make_controller(bl)
|
||||||
|
|
||||||
|
disk1 = make_disk(controller.model, preserve=True)
|
||||||
|
part = self.add_existing_boot_partition(controller, disk1)
|
||||||
|
|
||||||
|
wipe_before = part.wipe
|
||||||
|
controller.add_boot_disk(disk1)
|
||||||
|
self.assertIsBootDisk(controller, disk1)
|
||||||
|
if bl == Bootloader.UEFI:
|
||||||
|
self.assertIsMountedAtBootEFI(part)
|
||||||
|
|
||||||
|
controller.remove_boot_disk(disk1)
|
||||||
|
self.assertIsNotBootDisk(controller, disk1)
|
||||||
|
self.assertEqual(len(disk1.partitions()), 1)
|
||||||
|
self.assertEqual(part.wipe, wipe_before)
|
||||||
|
if bl == Bootloader.UEFI:
|
||||||
|
self.assertNotMounted(part)
|
||||||
|
|
||||||
def test_mounting_partition_makes_boot_disk(self):
|
def test_mounting_partition_makes_boot_disk(self):
|
||||||
controller = make_controller(Bootloader.UEFI)
|
controller = make_controller(Bootloader.UEFI)
|
||||||
|
|
|
@ -61,7 +61,6 @@ from subiquitycore.ui.utils import (
|
||||||
from subiquitycore.view import BaseView
|
from subiquitycore.view import BaseView
|
||||||
|
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
Bootloader,
|
|
||||||
DeviceAction,
|
DeviceAction,
|
||||||
humanize_size,
|
humanize_size,
|
||||||
)
|
)
|
||||||
|
@ -330,7 +329,7 @@ class DeviceList(WidgetWrap):
|
||||||
if device._is_boot_device():
|
if device._is_boot_device():
|
||||||
return _("Stop Using As Boot Device")
|
return _("Stop Using As Boot Device")
|
||||||
else:
|
else:
|
||||||
if self.parent.model.bootloader != Bootloader.PREP:
|
if self.parent.controller.supports_resilient_boot:
|
||||||
for other in self.parent.model.all_disks():
|
for other in self.parent.model.all_disks():
|
||||||
if other._is_boot_device():
|
if other._is_boot_device():
|
||||||
return _("Add As Another Boot Device")
|
return _("Add As Another Boot Device")
|
||||||
|
|
Loading…
Reference in New Issue