start to return disallowed guided options

This commit is contained in:
Michael Hudson-Doyle 2023-06-12 14:24:02 +12:00
parent 702badf815
commit ab6e643d50
2 changed files with 95 additions and 19 deletions

View File

@ -134,6 +134,21 @@ class CapabilityInfo:
allowed: List[GuidedCapability] = attr.Factory(list)
disallowed: List[GuidedDisallowedCapability] = attr.Factory(list)
def combine(self, other: "CapabilityInfo"):
for allowed_cap in other.allowed:
if allowed_cap not in self.allowed:
self.allowed.append(allowed_cap)
seen_disallowed = set()
new_disallowed = []
for disallowed_cap in self.disallowed + other.disallowed:
if disallowed_cap.capability in self.allowed:
continue
if disallowed_cap.capability in seen_disallowed:
continue
new_disallowed.append(disallowed_cap)
seen_disallowed.add(disallowed_cap.capability)
self.disallowed = new_disallowed
@attr.s(auto_attribs=True)
class VariationInfo:
@ -149,6 +164,27 @@ class VariationInfo:
def is_valid(self) -> bool:
return bool(self.capability_info.allowed)
def capability_info_for_disk(
self,
part_align,
size: Optional[int],
) -> CapabilityInfo:
if self.label is None:
install_min = sizes.calculate_suggested_install_min(
self.min_size, part_align)
else:
install_min = self.min_size
r = CapabilityInfo()
r.disallowed = list(self.capability_info.disallowed)
if size < install_min:
for capability in self.capability_info.allowed:
r.disallowed.append(GuidedDisallowedCapability(
capability=capability,
reason=GuidedDisallowedCapabilityReason.TOO_SMALL))
else:
r.allowed = list(self.capability_info.allowed)
return r
@classmethod
def classic(cls, name: str, min_size: int):
return cls(
@ -893,24 +929,41 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
self.get_available_capabilities()
for disk in self.potential_boot_disks(with_reformatting=True):
if disk.size >= install_min:
reformat = GuidedStorageTargetReformat(
disk_id=disk.id,
allowed=core_boot_capabilities + classic_capabilities)
scenarios.append((disk.size, reformat))
capability_info = CapabilityInfo()
for variation in self._variation_info.values():
capability_info.combine(
variation.capability_info_for_disk(
disk.alignment_data().part_align, disk.size))
reformat = GuidedStorageTargetReformat(
disk_id=disk.id,
allowed=capability_info.allowed,
disallowed=capability_info.disallowed)
scenarios.append((disk.size, reformat))
for disk in self.potential_boot_disks(with_reformatting=False):
if len(disk.partitions()) < 1:
# On an empty disk, don't bother to offer it with UseGap, as
# it's basically the same as the Reformat case.
parts = [p for p in disk.partitions() if p.flag != 'bios_grub']
if len(parts) < 1:
# On an (essentially) empty disk, don't bother to offer it
# with UseGap, as it's basically the same as the Reformat
# case.
continue
gap = gaps.largest_gap(disk)
if gap is not None and gap.size >= install_min:
api_gap = labels.for_client(gap)
use_gap = GuidedStorageTargetUseGap(
disk_id=disk.id, gap=api_gap,
allowed=classic_capabilities)
scenarios.append((gap.size, use_gap))
if gap is None:
# Do we return a reason here?
continue
capability_info = CapabilityInfo()
for variation in self._variation_info.values():
if variation.is_core_boot_classic():
continue
capability_info.combine(
variation.capability_info_for_disk(
disk.alignment_data().part_align, gap.size))
api_gap = labels.for_client(gap)
use_gap = GuidedStorageTargetUseGap(
disk_id=disk.id, gap=api_gap,
allowed=capability_info.allowed,
disallowed=capability_info.disallowed)
scenarios.append((gap.size, use_gap))
for disk in self.potential_boot_disks(check_boot=False):
part_align = disk.alignment_data().part_align
@ -919,10 +972,12 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
partition.estimated_min_size, partition.size,
install_min, part_align=part_align)
if vals is None:
# Return a reason here
continue
if not boot.can_be_boot_device(
disk, resize_partition=partition,
with_reformatting=False):
# Return a reason here
continue
resize = GuidedStorageTargetResize.from_recommendations(
partition, vals, allowed=classic_capabilities)
@ -932,7 +987,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
return GuidedStorageResponseV2(
status=ProbeStatus.DONE,
configured=self.model.guided_configuration,
targets=[s[1] for s in scenarios if s[1].allowed])
targets=[s[1] for s in scenarios])
async def v2_guided_POST(self, data: GuidedChoiceV2) \
-> GuidedStorageResponseV2:

View File

@ -34,6 +34,7 @@ from subiquity.common.types import (
Gap,
GapUsable,
GuidedCapability,
GuidedDisallowedCapabilityReason,
GuidedChoiceV2,
GuidedStorageTargetReformat,
GuidedStorageTargetResize,
@ -525,7 +526,26 @@ class TestGuidedV2(IsolatedAsyncioTestCase):
async def test_small_blank_disk(self, bootloader, ptable):
await self._setup(bootloader, ptable, size=1 << 30)
resp = await self.fsc.v2_guided_GET()
self.assertEqual(0, len(resp.targets))
self.assertEqual(1, len(resp.targets))
self.assertEqual(0, len(resp.targets[0].allowed))
self.assertEqual(
{
disabled_cap.capability
for disabled_cap in resp.targets[0].disallowed
},
{
GuidedCapability.DIRECT,
GuidedCapability.LVM,
GuidedCapability.LVM_LUKS,
})
self.assertEqual(
{
disabled_cap.reason
for disabled_cap in resp.targets[0].disallowed
},
{
GuidedDisallowedCapabilityReason.TOO_SMALL,
})
@parameterized.expand(bootloaders_and_ptables)
async def test_used_half_disk(self, bootloader, ptable):
@ -580,13 +600,14 @@ class TestGuidedV2(IsolatedAsyncioTestCase):
self.fs_probe[p._path()] = {'ESTIMATED_MIN_SIZE': 40 << 30}
self.fsc.calculate_suggested_install_min.return_value = 10 << 30
resp = await self.fsc.v2_guided_GET()
reformat = resp.targets.pop(0)
possible = [t for t in resp.targets if t.allowed]
reformat = possible.pop(0)
self.assertEqual(
GuidedStorageTargetReformat(
disk_id=self.disk.id, allowed=default_capabilities),
reformat)
resize = resp.targets.pop(0)
resize = possible.pop(0)
expected = GuidedStorageTargetResize(
disk_id=self.disk.id,
partition_number=p.number,
@ -596,7 +617,7 @@ class TestGuidedV2(IsolatedAsyncioTestCase):
maximum=230 << 30,
allowed=default_capabilities)
self.assertEqual(expected, resize)
self.assertEqual(0, len(resp.targets))
self.assertEqual(0, len(possible))
@parameterized.expand(bootloaders_and_ptables)
async def test_half_disk_reformat(self, bootloader, ptable):