Merge pull request #1302 from dbungert/report-size-mins

filesystem: report estimated partition size minimums
This commit is contained in:
Dan Bungert 2022-05-31 17:00:18 -06:00 committed by GitHub
commit 3e0c91e34b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1357 additions and 23 deletions

File diff suppressed because it is too large Load Diff

View File

@ -187,7 +187,7 @@ parts:
- libnl-route-3-dev
source: https://github.com/canonical/probert.git
source-type: git
source-commit: 0e52863cb0a1637c6268a74f224f5cc2653beb9d
source-commit: 31778895be3002422e9e8758d42940f290dc70af
requirements: [requirements.txt]
stage:
- "*"

View File

@ -319,6 +319,7 @@ def _for_client_partition(partition, *, min_size=0):
offset=partition.offset,
resize=partition.resize,
path=partition._path(),
estimated_min_size=partition.estimated_min_size,
mount=partition.mount,
format=partition.format)

View File

@ -268,6 +268,7 @@ class Partition:
boot: Optional[bool] = None
os: Optional[OsProber] = None
offset: Optional[int] = None
estimated_min_size: Optional[int] = -1
resize: Optional[bool] = None
path: Optional[str] = None

View File

@ -702,6 +702,18 @@ class Partition(_Formattable):
from subiquity.common.filesystem import boot
return boot.is_bootloader_partition(self)
@property
def estimated_min_size(self):
fs_data = self._m._probe_data.get('filesystem', {}).get(self._path())
if fs_data is None:
return -1
val = fs_data.get('ESTIMATED_MIN_SIZE', -1)
if val == 0:
return self.device.alignment_data().part_align
if val == -1:
return -1
return align_up(val, self.device.alignment_data().part_align)
@property
def ok_for_raid(self):
if self.boot:

View File

@ -414,7 +414,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
fname = 'probe-data-restricted.json'
key = "ProbeDataRestricted"
else:
probe_types = {'defaults'}
probe_types = {'defaults', 'filesystem_sizing'}
if self.app.opts.use_os_prober:
probe_types |= {'os'}
fname = 'probe-data.json'

View File

@ -40,15 +40,18 @@ class TestSubiquityControllerFilesystem(TestCase):
run_coro(self.fsc._probe_once(context=None, restricted=True))
self.app.prober.get_storage.assert_called_with({'blockdev'})
def test_probe_defaults(self):
def test_probe_os_prober_false(self):
self.app.opts.use_os_prober = False
run_coro(self.fsc._probe_once(context=None, restricted=False))
self.app.prober.get_storage.assert_called_with({'defaults'})
actual = self.app.prober.get_storage.call_args.args[0]
self.assertTrue({'defaults'} <= actual)
self.assertNotIn('os', actual)
def test_probe_defaults_and_os(self):
def test_probe_os_prober_true(self):
self.app.opts.use_os_prober = True
run_coro(self.fsc._probe_once(context=None, restricted=False))
self.app.prober.get_storage.assert_called_with({'defaults', 'os'})
actual = self.app.prober.get_storage.call_args.args[0]
self.assertTrue({'defaults', 'os'} <= actual)
class TestGuided(TestCase):

View File

@ -135,6 +135,27 @@ class Server(Client):
class TestAPI(unittest.IsolatedAsyncioTestCase, SubiTestCase):
class _MachineConfig(os.PathLike):
def __init__(self, outer, path):
self.outer = outer
self.orig_path = path
self.path = None
def __fspath__(self):
return self.path or self.orig_path
@contextlib.contextmanager
def edit(self):
with open(self.orig_path, 'r') as fp:
data = json.load(fp)
yield data
self.path = self.outer.tmp_path('machine-config.json')
with open(self.path, 'w') as fp:
json.dump(data, fp)
def machineConfig(self, path):
return self._MachineConfig(self, path)
def assertDictSubset(self, expected, actual):
"""All keys in dictionary expected, and matching values, must match
keys and values in actual. Actual may contain additional keys and
@ -853,23 +874,14 @@ class TestPartitionTableEditing(TestAPI):
@timeout()
async def test_resize(self):
# load config, edit size, use that for server
with open('examples/ubuntu-and-free-space.json', 'r') as fp:
data = json.load(fp)
# expand sda3 to use the rest of the disk
def get_size(key):
return int(data['storage']['blockdev'][key]['attrs']['size'])
sda_size = get_size('/dev/sda')
sda1_size = get_size('/dev/sda1')
sda2_size = get_size('/dev/sda2')
sda3_size = sda_size - sda1_size - sda2_size - (2 << 20)
data['storage']['blockdev']['/dev/sda3']['attrs']['size'] = \
str(sda3_size)
cfg = self.tmp_path('machine-config.json')
with open(cfg, 'w') as fp:
json.dump(data, fp)
cfg = self.machineConfig('examples/ubuntu-and-free-space.json')
with cfg.edit() as data:
blockdev = data['storage']['blockdev']
sizes = {k: int(v['attrs']['size']) for k, v in blockdev.items()}
# expand sda3 to use the rest of the disk
sda3_size = (sizes['/dev/sda'] - sizes['/dev/sda1']
- sizes['/dev/sda2'] - (2 << 20))
blockdev['/dev/sda3']['attrs']['size'] = str(sda3_size)
extra = ['--storage-version', '2']
async with start_server(cfg, extra_args=extra) as inst:
@ -922,6 +934,25 @@ class TestPartitionTableEditing(TestAPI):
self.assertTrue(sda3['resize'])
self.assertTrue(sda3_format['preserve'])
@timeout()
async def test_est_min_size(self):
cfg = self.machineConfig('examples/win10-along-ubuntu.json')
with cfg.edit() as data:
fs = data['storage']['filesystem']
fs['/dev/sda1']['ESTIMATED_MIN_SIZE'] = 0
# data file has no sda2 in filesystem
fs['/dev/sda3']['ESTIMATED_MIN_SIZE'] = -1
fs['/dev/sda4']['ESTIMATED_MIN_SIZE'] = (1 << 20) + 1
extra = ['--storage-version', '2']
async with start_server(cfg, extra_args=extra) as inst:
resp = await inst.get('/storage/v2')
[sda] = resp['disks']
[p1, _, p3, p4, _] = sda['partitions']
self.assertEqual(1 << 20, p1['estimated_min_size'])
self.assertEqual(-1, p3['estimated_min_size'])
self.assertEqual(2 << 20, p4['estimated_min_size'])
class TestGap(TestAPI):
async def test_blank_disk_is_one_big_gap(self):