filesystem: guided_method can take a gap

This commit is contained in:
Dan Bungert 2022-06-30 15:18:27 -06:00
parent 7a9e920de1
commit 1f3d36510f
2 changed files with 54 additions and 23 deletions

View File

@ -63,6 +63,7 @@ from subiquity.common.types import (
StorageResponseV2,
)
from subiquity.models.filesystem import (
align_up,
align_down,
LVM_CHUNK_SIZE,
Raid,
@ -137,20 +138,33 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
"autoinstall config did not create needed bootloader "
"partition")
def setup_disk_for_guided(self, disk, mode):
def setup_disk_for_guided(self, target, mode):
if isinstance(target, gaps.Gap):
disk = target.device
gap = target
else:
disk = target
gap = None
if mode is None or mode == 'reformat_disk':
self.reformat(disk, wipe='superblock-recursive')
if DeviceAction.TOGGLE_BOOT in DeviceAction.supported(disk):
self.add_boot_disk(disk)
return gaps.largest_gap(disk)
self.add_boot_disk(target)
if gap is None:
return disk, gaps.largest_gap(disk)
else:
# find what's left of the gap after adding boot
gap = gaps.within(disk, gap)
if gap is None:
raise Exception(f'failed to locate gap after adding boot')
return disk, gap
def guided_direct(self, disk, mode=None):
gap = self.setup_disk_for_guided(disk, mode)
def guided_direct(self, target, mode=None):
disk, gap = self.setup_disk_for_guided(target, mode)
spec = dict(fstype="ext4", mount="/")
self.create_partition(device=disk, gap=gap, spec=spec)
def guided_lvm(self, disk, mode=None, lvm_options=None):
gap = self.setup_disk_for_guided(disk, mode)
def guided_lvm(self, target, mode=None, lvm_options=None):
disk, gap = self.setup_disk_for_guided(target, mode)
gap_boot, gap_rest = gap.split(sizes.get_bootfs_size(gap.size))
spec = dict(fstype="ext4", mount='/boot')
self.create_partition(device=disk, gap=gap_boot, spec=spec)
@ -195,15 +209,27 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
def guided(self, choice: GuidedChoiceV2):
self.model.guided_configuration = choice
disk = self.model._one(id=choice.target.disk_id)
if isinstance(choice.target, GuidedStorageTargetReformat):
mode = 'reformat_disk'
target = disk
elif isinstance(choice.target, GuidedStorageTargetUseGap):
mode = 'use_gap' # FIXME not the correct gap
mode = 'use_gap'
target = gaps.at_offset(disk, choice.target.gap.offset)
elif isinstance(choice.target, GuidedStorageTargetResize):
mode = 'resize' # FIXME not actually working
partition = self.get_partition(
disk, choice.target.partition_number)
part_align = disk.alignment_data().part_align
new_size = align_up(choice.target.new_size, part_align)
if new_size > partition.size:
raise Exception(f'Aligned requested size {new_size} too large')
gap_offset = partition.offset + new_size
partition.size = new_size
partition.resize = True
mode = 'use_gap'
target = gaps.at_offset(disk, gap_offset)
else:
raise Exception(f'Unknown guided target {choice.target}')
disk = self.model._one(id=choice.target.disk_id)
if choice.use_lvm:
lvm_options = None
@ -214,9 +240,9 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
'password': choice.password,
},
}
self.guided_lvm(disk, mode=mode, lvm_options=lvm_options)
self.guided_lvm(target, mode=mode, lvm_options=lvm_options)
else:
self.guided_direct(disk, mode=mode)
self.guided_direct(target, mode=mode)
async def _probe_response(self, wait, resp_cls):
if self._probe_task.task is None or not self._probe_task.task.done():
@ -381,7 +407,10 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
for disk in self.get_guided_disks(with_reformatting=False):
gap = gaps.largest_gap(disk)
if gap is not None and gap.size >= install_min:
use_gap = GuidedStorageTargetUseGap(disk_id=disk.id, gap=gap)
api_gap = labels.for_client(gap)
use_gap = GuidedStorageTargetUseGap(
disk_id=disk.id,
gap=api_gap)
scenarios.append((gap.size, use_gap))
for disk in self.get_guided_disks(check_boot=False):
@ -539,8 +568,8 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
if mode == 'reformat_disk':
match = layout.get("match", {'size': 'largest'})
disk = self.model.disk_for_match(self.model.all_disks(), match)
if not disk:
target = self.model.disk_for_match(self.model.all_disks(), match)
if not target:
raise Exception("autoinstall cannot configure storage "
"- no disk found large enough for install")
elif mode == 'use_gap':
@ -552,10 +581,10 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
"- no gap found large enough for install")
# This is not necessarily the exact gap to be used, as the gap size
# may change once add_boot_disk has sorted things out.
disk = gap.device
target = gap
log.info(f'autoinstall: running guided {name} install in mode {mode} '
f'using {disk}')
guided_method(disk=disk, mode=mode)
f'using {target}')
guided_method(target=target, mode=mode)
def validate_layout_mode(self, mode):
if mode not in ('reformat_disk', 'use_gap'):

View File

@ -21,6 +21,7 @@ from subiquity.server.controllers.filesystem import FilesystemController
from subiquitycore.tests.mocks import make_app
from subiquity.common.filesystem import gaps
from subiquity.common import types
from subiquity.common.types import (
Bootloader,
GuidedStorageTargetReformat,
@ -154,10 +155,11 @@ class TestGuidedV2(IsolatedAsyncioTestCase):
@parameterized.expand(bootloaders)
async def test_blank_disk(self, bootloader):
self._setup(bootloader)
d = make_disk(self.model)
d = make_disk(self.model, size=(30 << 30) + (2 << 20))
gap = types.Gap(offset=1 << 20, size=30 << 30)
expected = [
GuidedStorageTargetReformat(disk_id=d.id),
GuidedStorageTargetUseGap(disk_id=d.id, gap=gaps.largest_gap(d)),
GuidedStorageTargetUseGap(disk_id=d.id, gap=gap),
]
resp = await self.fsc.v2_guided_GET()
self.assertEqual(expected, resp.possible)
@ -165,14 +167,14 @@ class TestGuidedV2(IsolatedAsyncioTestCase):
@parameterized.expand(bootloaders)
async def test_used_half_disk(self, bootloader):
self._setup(bootloader)
d = make_disk(self.model)
p1 = make_partition(self.model, d)
d = make_disk(self.model, size=(30 << 30) + (2 << 20))
p1 = make_partition(self.model, d, preserve=True, size=15 << 30)
self.fs_probe[p1._path()] = {'ESTIMATED_MIN_SIZE': 1 << 20}
resp = await self.fsc.v2_guided_GET()
reformat = resp.possible[0]
self.assertEqual(GuidedStorageTargetReformat(disk_id=d.id), reformat)
if bootloader != Bootloader.BIOS:
gap = gaps.largest_gap(d)
gap = types.Gap(offset=(15 << 30) + (1 << 20), size=15 << 30)
self.assertEqual(
GuidedStorageTargetUseGap(disk_id=d.id, gap=gap),
resp.possible[1])