Merge pull request #1346 from dbungert/fix-guided-resize-gap
guided resize: improve post-resize gap handling
This commit is contained in:
commit
aa59399d6c
File diff suppressed because it is too large
Load Diff
|
@ -241,3 +241,12 @@ def within(device, gap):
|
||||||
if pg.offset >= gap.offset and pg_end <= gap_end:
|
if pg.offset >= gap.offset and pg_end <= gap_end:
|
||||||
return pg
|
return pg
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def after(device, offset):
|
||||||
|
"""Find the first gap that is after this offset."""
|
||||||
|
for pg in parts_and_gaps(device):
|
||||||
|
if isinstance(pg, Gap):
|
||||||
|
if pg.offset > offset:
|
||||||
|
return pg
|
||||||
|
return None
|
||||||
|
|
|
@ -135,6 +135,35 @@ class TestWithin(unittest.TestCase):
|
||||||
self.assertEqual(g2, gaps.within(d, orig_g2))
|
self.assertEqual(g2, gaps.within(d, orig_g2))
|
||||||
|
|
||||||
|
|
||||||
|
class TestAfter(unittest.TestCase):
|
||||||
|
def test_basic(self):
|
||||||
|
d = make_disk()
|
||||||
|
[gap] = gaps.parts_and_gaps(d)
|
||||||
|
self.assertEqual(gap, gaps.after(d, 0))
|
||||||
|
|
||||||
|
def test_no_equals(self):
|
||||||
|
d = make_disk()
|
||||||
|
[gap] = gaps.parts_and_gaps(d)
|
||||||
|
self.assertIsNone(gaps.after(d, gap.offset))
|
||||||
|
|
||||||
|
def test_partition_resize_full_part(self):
|
||||||
|
m, d = make_model_and_disk()
|
||||||
|
[g1] = gaps.parts_and_gaps(d)
|
||||||
|
p1 = make_partition(m, d, size=g1.size)
|
||||||
|
p1.size //= 2
|
||||||
|
gap = gaps.after(d, p1.offset)
|
||||||
|
self.assertIsNotNone(gap)
|
||||||
|
|
||||||
|
def test_partition_resize_half_part(self):
|
||||||
|
m, d = make_model_and_disk()
|
||||||
|
make_partition(m, d)
|
||||||
|
[p1, g1] = gaps.parts_and_gaps(d)
|
||||||
|
p1.size //= 2
|
||||||
|
gap = gaps.after(d, p1.offset)
|
||||||
|
self.assertNotEqual(gap, g1)
|
||||||
|
self.assertTrue(gap.offset < g1.offset)
|
||||||
|
|
||||||
|
|
||||||
class TestDiskGaps(unittest.TestCase):
|
class TestDiskGaps(unittest.TestCase):
|
||||||
|
|
||||||
def test_no_partition_gpt(self):
|
def test_no_partition_gpt(self):
|
||||||
|
|
|
@ -223,11 +223,16 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
||||||
new_size = align_up(choice.target.new_size, part_align)
|
new_size = align_up(choice.target.new_size, part_align)
|
||||||
if new_size > partition.size:
|
if new_size > partition.size:
|
||||||
raise Exception(f'Aligned requested size {new_size} too large')
|
raise Exception(f'Aligned requested size {new_size} too large')
|
||||||
gap_offset = partition.offset + new_size
|
|
||||||
partition.size = new_size
|
partition.size = new_size
|
||||||
partition.resize = True
|
partition.resize = True
|
||||||
mode = 'use_gap'
|
mode = 'use_gap'
|
||||||
target = gaps.at_offset(disk, gap_offset)
|
# Calculating where that gap will be can be tricky due to alignment
|
||||||
|
# needs and the possibility that we may be splitting a logical
|
||||||
|
# partition, which needs an extra 1MiB spacer.
|
||||||
|
target = gaps.after(disk, partition.offset)
|
||||||
|
if target is None:
|
||||||
|
pgs = gaps.parts_and_gaps(disk)
|
||||||
|
raise Exception(f'gap not found after resize, pgs={pgs}')
|
||||||
else:
|
else:
|
||||||
raise Exception(f'Unknown guided target {choice.target}')
|
raise Exception(f'Unknown guided target {choice.target}')
|
||||||
|
|
||||||
|
|
|
@ -184,8 +184,6 @@ class TestGuidedV2(IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
use_gap = resp.possible.pop(0)
|
use_gap = resp.possible.pop(0)
|
||||||
self.assertEqual(self.disk.id, use_gap.disk_id)
|
self.assertEqual(self.disk.id, use_gap.disk_id)
|
||||||
if gap_offset != use_gap.gap.offset:
|
|
||||||
breakpoint()
|
|
||||||
self.assertEqual(gap_offset, use_gap.gap.offset)
|
self.assertEqual(gap_offset, use_gap.gap.offset)
|
||||||
|
|
||||||
resize = resp.possible.pop(0)
|
resize = resp.possible.pop(0)
|
||||||
|
|
|
@ -479,6 +479,20 @@ class TestGuided(TestAPI):
|
||||||
}
|
}
|
||||||
self.assertDictSubset(expected_p5, p5)
|
self.assertDictSubset(expected_p5, p5)
|
||||||
|
|
||||||
|
@timeout()
|
||||||
|
async def test_guided_v2_resize_logical(self):
|
||||||
|
cfg = 'examples/threebuntu-on-msdos.json'
|
||||||
|
extra = ['--storage-version', '2']
|
||||||
|
async with start_server(cfg, extra_args=extra) as inst:
|
||||||
|
resp = await inst.get('/storage/v2/guided')
|
||||||
|
[resize] = match(
|
||||||
|
resp['possible'], _type='GuidedStorageTargetResize',
|
||||||
|
partition_number=6)
|
||||||
|
data = {'target': resize}
|
||||||
|
resp = await inst.post('/storage/v2/guided', data)
|
||||||
|
self.assertEqual(resize, resp['configured']['target'])
|
||||||
|
# should not throw a Gap Not Found exception
|
||||||
|
|
||||||
|
|
||||||
class TestAdd(TestAPI):
|
class TestAdd(TestAPI):
|
||||||
@timeout()
|
@timeout()
|
||||||
|
|
Loading…
Reference in New Issue