replace free_for_paritions with largest_gap_size

This commit is contained in:
Michael Hudson-Doyle 2021-12-13 20:27:19 +13:00
parent 5429e97854
commit 83cfdbdfea
9 changed files with 48 additions and 46 deletions

View File

@ -88,3 +88,10 @@ def largest_gap(device):
largest = pg largest = pg
largest_size = pg.size largest_size = pg.size
return largest return largest
def largest_gap_size(device):
largest = largest_gap(device)
if largest is not None:
return largest.size
return 0

View File

@ -292,7 +292,7 @@ def _for_client_disk(disk, *, min_size=0):
preserve=disk.preserve, preserve=disk.preserve,
usage_labels=usage_labels(disk), usage_labels=usage_labels(disk),
partitions=[for_client(p) for p in disk._partitions], partitions=[for_client(p) for p in disk._partitions],
free_for_partitions=disk.free_for_partitions, free_for_partitions=gaps.largest_gap_size(disk),
boot_device=boot.is_boot_device(disk), boot_device=boot.is_boot_device(disk),
ok_for_guided=disk.size >= min_size, ok_for_guided=disk.size >= min_size,
model=getattr(disk, 'model', None), model=getattr(disk, 'model', None),

View File

@ -15,7 +15,7 @@
import logging import logging
from subiquity.common.filesystem import boot from subiquity.common.filesystem import boot, gaps
from subiquity.common.types import Bootloader from subiquity.common.types import Bootloader
from subiquity.models.filesystem import ( from subiquity.models.filesystem import (
align_up, align_up,
@ -199,12 +199,12 @@ class FilesystemManipulator:
def partition_disk_handler(self, disk, partition, spec): def partition_disk_handler(self, disk, partition, spec):
log.debug('partition_disk_handler: %s %s %s', disk, partition, spec) log.debug('partition_disk_handler: %s %s %s', disk, partition, spec)
log.debug('disk.freespace: {}'.format(disk.free_for_partitions)) log.debug('disk.freespace: {}'.format(gaps.largest_gap_size(disk)))
if partition is not None: if partition is not None:
if 'size' in spec: if 'size' in spec:
partition.size = align_up(spec['size']) partition.size = align_up(spec['size'])
if disk.free_for_partitions < 0: if gaps.largest_gap_size(disk) < 0:
raise Exception("partition size too large") raise Exception("partition size too large")
self.delete_filesystem(partition.fs()) self.delete_filesystem(partition.fs())
self.create_filesystem(partition, spec) self.create_filesystem(partition, spec)
@ -225,11 +225,11 @@ class FilesystemManipulator:
# adjust downward the partition size (if necessary) to accommodate # adjust downward the partition size (if necessary) to accommodate
# bios/grub partition # bios/grub partition
if spec['size'] > disk.free_for_partitions: if spec['size'] > gaps.largest_gap_size(disk):
log.debug( log.debug(
"Adjusting request down: %s - %s = %s", "Adjusting request down: %s - %s = %s",
spec['size'], part.size, disk.free_for_partitions) spec['size'], part.size, gaps.largest_gap_size(disk))
spec['size'] = disk.free_for_partitions spec['size'] = gaps.largest_gap_size(disk)
self.create_partition(disk, spec) self.create_partition(disk, spec)
@ -237,14 +237,14 @@ class FilesystemManipulator:
def logical_volume_handler(self, vg, lv, spec): def logical_volume_handler(self, vg, lv, spec):
log.debug('logical_volume_handler: %s %s %s', vg, lv, spec) log.debug('logical_volume_handler: %s %s %s', vg, lv, spec)
log.debug('vg.freespace: {}'.format(vg.free_for_partitions)) log.debug('vg.freespace: {}'.format(gaps.largest_gap_size(vg)))
if lv is not None: if lv is not None:
if 'name' in spec: if 'name' in spec:
lv.name = spec['name'] lv.name = spec['name']
if 'size' in spec: if 'size' in spec:
lv.size = align_up(spec['size']) lv.size = align_up(spec['size'])
if vg.free_for_partitions < 0: if gaps.largest_gap_size(vg) < 0:
raise Exception("lv size too large") raise Exception("lv size too large")
self.delete_filesystem(lv.fs()) self.delete_filesystem(lv.fs())
self.create_filesystem(lv, spec) self.create_filesystem(lv, spec)
@ -322,7 +322,7 @@ class FilesystemManipulator:
self.model.add_filesystem( self.model.add_filesystem(
p, p.original_fstype(), preserve=True) p, p.original_fstype(), preserve=True)
else: else:
full = boot_disk.free_for_partitions == 0 full = gaps.largest_gap_size(boot_disk) == 0
tot_size = 0 tot_size = 0
for p in partitions: for p in partitions:
tot_size += p.size tot_size += p.size
@ -371,9 +371,9 @@ class FilesystemManipulator:
elif bootloader == Bootloader.BIOS: elif bootloader == Bootloader.BIOS:
part_size = BIOS_GRUB_SIZE_BYTES part_size = BIOS_GRUB_SIZE_BYTES
log.debug("bootloader %s", bootloader) log.debug("bootloader %s", bootloader)
if part_size > new_boot_disk.free_for_partitions: if part_size > gaps.largest_gap_size(new_boot_disk):
largest_part = max( largest_part = max(
new_boot_disk.partitions(), key=lambda p: p.size) new_boot_disk.partitions(), key=lambda p: p.size)
largest_part.size -= ( largest_part.size -= (
part_size - new_boot_disk.free_for_partitions) part_size - gaps.largest_gap_size(new_boot_disk))
self._create_boot_partition(new_boot_disk) self._create_boot_partition(new_boot_disk)

View File

@ -142,7 +142,8 @@ class TestActions(unittest.TestCase):
self.assertActionPossible(dos_disk, DeviceAction.TOGGLE_BOOT) self.assertActionPossible(dos_disk, DeviceAction.TOGGLE_BOOT)
# Even if they have existing partitions # Even if they have existing partitions
make_partition( make_partition(
model, dos_disk, size=dos_disk.free_for_partitions, preserve=True) model, dos_disk, size=gaps.largest_gap_size(dos_disk),
preserve=True)
self.assertActionPossible(dos_disk, DeviceAction.TOGGLE_BOOT) self.assertActionPossible(dos_disk, DeviceAction.TOGGLE_BOOT)
# (we never create dos partition tables so no need to test # (we never create dos partition tables so no need to test
# preserve=False case). # preserve=False case).
@ -151,7 +152,7 @@ class TestActions(unittest.TestCase):
gpt_disk = make_disk(model, ptable='gpt', preserve=False) gpt_disk = make_disk(model, ptable='gpt', preserve=False)
self.assertActionPossible(gpt_disk, DeviceAction.TOGGLE_BOOT) self.assertActionPossible(gpt_disk, DeviceAction.TOGGLE_BOOT)
# Even if they are filled with partitions (we resize partitions to fit) # Even if they are filled with partitions (we resize partitions to fit)
make_partition(model, gpt_disk, size=dos_disk.free_for_partitions) make_partition(model, gpt_disk, size=gaps.largest_gap_size(dos_disk))
self.assertActionPossible(gpt_disk, DeviceAction.TOGGLE_BOOT) self.assertActionPossible(gpt_disk, DeviceAction.TOGGLE_BOOT)
# GPT disks with existing partition tables but no partitions can be the # GPT disks with existing partition tables but no partitions can be the
@ -187,7 +188,8 @@ class TestActions(unittest.TestCase):
new_disk = make_disk(model, preserve=False) new_disk = make_disk(model, preserve=False)
self.assertActionPossible(new_disk, DeviceAction.TOGGLE_BOOT) self.assertActionPossible(new_disk, DeviceAction.TOGGLE_BOOT)
# Even if they are filled with partitions (we resize partitions to fit) # Even if they are filled with partitions (we resize partitions to fit)
make_partition(model, new_disk, size=new_disk.free_for_partitions) make_partition(
model, new_disk, size=gaps.largest_gap_size(new_disk))
self.assertActionPossible(new_disk, DeviceAction.TOGGLE_BOOT) self.assertActionPossible(new_disk, DeviceAction.TOGGLE_BOOT)
# A disk with an existing but empty partitions can also be the # A disk with an existing but empty partitions can also be the
@ -363,7 +365,7 @@ class TestActions(unittest.TestCase):
def test_vg_action_EDIT(self): def test_vg_action_EDIT(self):
model, vg = make_model_and_vg() model, vg = make_model_and_vg()
self.assertActionPossible(vg, DeviceAction.EDIT) self.assertActionPossible(vg, DeviceAction.EDIT)
model.add_logical_volume(vg, 'lv1', size=vg.free_for_partitions//2) model.add_logical_volume(vg, 'lv1', size=gaps.largest_gap_size(vg))
self.assertActionNotPossible(vg, DeviceAction.EDIT) self.assertActionNotPossible(vg, DeviceAction.EDIT)
vg2 = make_vg(model) vg2 = make_vg(model)
@ -391,7 +393,7 @@ class TestActions(unittest.TestCase):
self.assertActionPossible(vg, DeviceAction.DELETE) self.assertActionPossible(vg, DeviceAction.DELETE)
self.assertActionPossible(vg, DeviceAction.DELETE) self.assertActionPossible(vg, DeviceAction.DELETE)
lv = model.add_logical_volume( lv = model.add_logical_volume(
vg, 'lv0', size=vg.free_for_partitions//2) vg, 'lv0', size=gaps.largest_gap_size(vg)//2)
self.assertActionPossible(vg, DeviceAction.DELETE) self.assertActionPossible(vg, DeviceAction.DELETE)
fs = model.add_filesystem(lv, 'ext4') fs = model.add_filesystem(lv, 'ext4')
self.assertActionPossible(vg, DeviceAction.DELETE) self.assertActionPossible(vg, DeviceAction.DELETE)

View File

@ -18,6 +18,7 @@ import unittest
from subiquity.common.filesystem.actions import ( from subiquity.common.filesystem.actions import (
DeviceAction, DeviceAction,
) )
from subiquity.common.filesystem import gaps
from subiquity.common.filesystem.manipulator import ( from subiquity.common.filesystem.manipulator import (
FilesystemManipulator, FilesystemManipulator,
) )
@ -130,7 +131,7 @@ class TestFilesystemManipulator(unittest.TestCase):
disk1 = make_disk(manipulator.model, preserve=False) disk1 = make_disk(manipulator.model, preserve=False)
disk2 = make_disk(manipulator.model, preserve=False) disk2 = make_disk(manipulator.model, preserve=False)
disk2p1 = manipulator.model.add_partition( disk2p1 = manipulator.model.add_partition(
disk2, size=disk2.free_for_partitions) disk2, size=gaps.largest_gap_size(disk2))
manipulator.add_boot_disk(disk1) manipulator.add_boot_disk(disk1)
self.assertIsBootDisk(manipulator, disk1) self.assertIsBootDisk(manipulator, disk1)
@ -171,7 +172,7 @@ class TestFilesystemManipulator(unittest.TestCase):
disk1 = make_disk(manipulator.model, preserve=False) disk1 = make_disk(manipulator.model, preserve=False)
disk2 = make_disk(manipulator.model, preserve=False) disk2 = make_disk(manipulator.model, preserve=False)
disk2p1 = manipulator.model.add_partition( disk2p1 = manipulator.model.add_partition(
disk2, size=disk2.free_for_partitions) disk2, size=gaps.largest_gap_size(disk2))
manipulator.add_boot_disk(disk1) manipulator.add_boot_disk(disk1)
self.assertIsBootDisk(manipulator, disk1) self.assertIsBootDisk(manipulator, disk1)
@ -218,7 +219,7 @@ class TestFilesystemManipulator(unittest.TestCase):
disk1, size=512 << 20, flag="boot") disk1, size=512 << 20, flag="boot")
disk1p1.preserve = True disk1p1.preserve = True
disk1p2 = manipulator.model.add_partition( disk1p2 = manipulator.model.add_partition(
disk1, size=disk1.free_for_partitions) disk1, size=gaps.largest_gap_size(disk1))
disk1p2.preserve = True disk1p2.preserve = True
manipulator.partition_disk_handler( manipulator.partition_disk_handler(
disk1, disk1p2, {'fstype': 'ext4', 'mount': '/'}) disk1, disk1p2, {'fstype': 'ext4', 'mount': '/'})

View File

@ -524,10 +524,6 @@ class _Device(_Formattable, ABC):
def available_for_partitions(self): def available_for_partitions(self):
return align_down(self.size, 1 << 20) - GPT_OVERHEAD return align_down(self.size, 1 << 20) - GPT_OVERHEAD
@property
def free_for_partitions(self):
return self.available_for_partitions - self.used
def available(self): def available(self):
# A _Device is available if: # A _Device is available if:
# 1) it is not part of a device like a RAID or LVM or zpool or ... # 1) it is not part of a device like a RAID or LVM or zpool or ...
@ -540,9 +536,11 @@ class _Device(_Formattable, ABC):
return False return False
if self._fs is not None: if self._fs is not None:
return self._fs._available() return self._fs._available()
if self.free_for_partitions > 0: from subiquity.common.filesystem.gaps import (
if not self._has_preexisting_partition(): largest_gap_size,
return True )
if largest_gap_size(self) > 0:
return True
return any(p.available() for p in self._partitions) return any(p.available() for p in self._partitions)
def has_unavailable_partition(self): def has_unavailable_partition(self):
@ -803,11 +801,6 @@ class LVM_VolGroup(_Device):
def available_for_partitions(self): def available_for_partitions(self):
return self.size return self.size
@property
def free_for_partitions(self):
return align_down(
self.available_for_partitions - self.used, LVM_CHUNK_SIZE)
ok_for_raid = False ok_for_raid = False
ok_for_lvm_vg = False ok_for_lvm_vg = False
@ -1083,10 +1076,10 @@ class FilesystemModel(object):
raise Exception( raise Exception(
"{} has negative size but is not final partition " "{} has negative size but is not final partition "
"of {}".format(p, parent)) "of {}".format(p, parent))
p.size = 0 from subiquity.common.filesystem.gaps import (
p.size = parent.free_for_partitions largest_gap_size,
if p.type == 'lvm_partition': )
p.size = align_down(p.size, LVM_CHUNK_SIZE) p.size = largest_gap_size(parent)
elif isinstance(p.size, str): elif isinstance(p.size, str):
if p.size.endswith("%"): if p.size.endswith("%"):
percentage = int(p.size[:-1]) percentage = int(p.size[:-1])
@ -1346,8 +1339,6 @@ class FilesystemModel(object):
def add_partition(self, device, size, flag="", wipe=None, def add_partition(self, device, size, flag="", wipe=None,
grub_device=None): grub_device=None):
from subiquity.common.filesystem import boot from subiquity.common.filesystem import boot
if size > device.free_for_partitions:
raise Exception("%s > %s", size, device.free_for_partitions)
real_size = align_up(size) real_size = align_up(size)
log.debug("add_partition: rounded size from %s to %s", size, real_size) log.debug("add_partition: rounded size from %s to %s", size, real_size)
if device._fs is not None: if device._fs is not None:

View File

@ -28,6 +28,7 @@ from subiquity.models.filesystem import (
align_down, align_down,
LVM_CHUNK_SIZE, LVM_CHUNK_SIZE,
) )
from subiquity.common.filesystem import gaps
class TestHumanizeSize(unittest.TestCase): class TestHumanizeSize(unittest.TestCase):
@ -164,7 +165,7 @@ def make_partition(model, device=None, *, preserve=False, size=None, **kw):
if device is None: if device is None:
device = make_disk(model) device = make_disk(model)
if size is None: if size is None:
size = device.free_for_partitions//2 size = gaps.largest_gap_size(device)//2
partition = Partition( partition = Partition(
m=model, device=device, size=size, preserve=preserve, **kw) m=model, device=device, size=size, preserve=preserve, **kw)
if preserve: if preserve:
@ -203,7 +204,7 @@ def make_model_and_vg(bootloader=None):
def make_lv(model): def make_lv(model):
vg = make_vg(model) vg = make_vg(model)
name = 'lv%s' % len(model._actions) name = 'lv%s' % len(model._actions)
return model.add_logical_volume(vg, name, vg.free_for_partitions//2) return model.add_logical_volume(vg, name, gaps.largest_gap_size(vg))
def make_model_and_lv(bootloader=None): def make_model_and_lv(bootloader=None):

View File

@ -40,7 +40,7 @@ from subiquity.common.errorreport import ErrorReportKind
from subiquity.common.filesystem.actions import ( from subiquity.common.filesystem.actions import (
DeviceAction, DeviceAction,
) )
from subiquity.common.filesystem import boot, labels from subiquity.common.filesystem import boot, gaps, labels
from subiquity.common.filesystem.manipulator import FilesystemManipulator from subiquity.common.filesystem.manipulator import FilesystemManipulator
from subiquity.common.types import ( from subiquity.common.types import (
Bootloader, Bootloader,
@ -126,7 +126,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
def guided_direct(self, disk): def guided_direct(self, disk):
self.reformat(disk) self.reformat(disk)
result = { result = {
"size": disk.free_for_partitions, "size": gaps.largest_gap_size(disk),
"fstype": "ext4", "fstype": "ext4",
"mount": "/", "mount": "/",
} }
@ -144,7 +144,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
)) ))
part = self.create_partition( part = self.create_partition(
device=disk, spec=dict( device=disk, spec=dict(
size=disk.free_for_partitions, size=gaps.largest_gap_size(disk),
fstype=None, fstype=None,
)) ))
vg_name = 'ubuntu-vg' vg_name = 'ubuntu-vg'
@ -348,7 +348,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
disk = self.model._one(id=data.disk_id) disk = self.model._one(id=data.disk_id)
size = data.partition.size size = data.partition.size
if size is None or size < 0: if size is None or size < 0:
size = disk.free_for_partitions size = gaps.largest_gap_size(disk)
spec = { spec = {
'size': size, 'size': size,
'fstype': data.partition.format, 'fstype': data.partition.format,

View File

@ -37,7 +37,7 @@ from subiquitycore.ui.container import Pile
from subiquitycore.ui.stretchy import Stretchy from subiquitycore.ui.stretchy import Stretchy
from subiquitycore.ui.utils import rewrap from subiquitycore.ui.utils import rewrap
from subiquity.common.filesystem import boot, labels from subiquity.common.filesystem import boot, gaps, labels
from subiquity.models.filesystem import ( from subiquity.models.filesystem import (
align_up, align_up,
Disk, Disk,
@ -375,7 +375,7 @@ class PartitionStretchy(Stretchy):
self.model = parent.model self.model = parent.model
self.controller = parent.controller self.controller = parent.controller
self.parent = parent self.parent = parent
max_size = disk.free_for_partitions max_size = gaps.largest_gap_size(disk)
initial = {} initial = {}
label = _("Create") label = _("Create")