curtin-dev team mailing list archive
-
curtin-dev team
-
Mailing list archive
-
Message #02248
Re: [Merge] ~dbungert/curtin:resize into curtin:master
Closer to something I'm happy with.
See diff comments.
The commit history is awful, please ignore, will fix.
My plan at this point is a bit more integration tests, and to resolve the doc comment.
Diff comments:
> diff --git a/curtin/commands/block_meta_v2.py b/curtin/commands/block_meta_v2.py
> index 051649b..9870e58 100644
> --- a/curtin/commands/block_meta_v2.py
> +++ b/curtin/commands/block_meta_v2.py
> @@ -214,6 +226,67 @@ def _wipe_for_action(action):
> return 'superblock'
>
>
> +def verify_format(devpath, storage_config, part_action):
> + actions = [v for v in storage_config.values()
> + if 'volume' in v and v['volume'] == part_action['id']]
> + if not actions:
> + return
> + fstype = _get_volume_fstype(devpath)
> + target_fstype = actions[0]['fstype']
> + msg = (
> + 'Verifying %s format, expecting %s, found %s' % (
> + devpath, fstype, target_fstype))
> + LOG.debug(msg)
> + if fstype != target_fstype:
> + raise RuntimeError(msg)
> +
> +
> +def partition_verify_sfdisk_v2(part_action, label, sfdisk_part_info,
> + storage_config):
> + devpath = os.path.realpath(sfdisk_part_info['node'])
> + verify_format(devpath, storage_config, part_action)
> + if not part_action.get('resize', False):
> + verify_size(devpath, int(util.human2bytes(part_action['size'])),
> + sfdisk_part_info)
> + expected_flag = part_action.get('flag')
> + if expected_flag:
> + verify_ptable_flag(devpath, expected_flag, label, sfdisk_part_info)
> +
> +
> +def prepare_resize(part_action, storage_config):
> + if not part_action.get('resize', False):
> + return None
> +
> + disk_id = part_action['device']
> + disk_action = storage_config[disk_id]
> + part_num = part_action['number']
> + disk_dev = disk_action['dev']
> + part_dev = f'{disk_dev}p{part_num}'
Done
> +
> + start_size = get_part_size_bytes(part_dev, part_action)
> + end_size = util.human2bytes(part_action['size'])
> +
> + if end_size == start_size:
> + LOG.debug('Skipping resize of %s - partition is already target size',
> + part_dev)
> + return None
> +
> + direction = 'up' if start_size < end_size else 'down'
> +
> + return ResizeOperation(start_size=start_size, end_size=end_size,
> + device=part_dev, direction=direction)
> +
> +
> +def process_resizes(resizes, direction):
> + for op in resizes:
> + if op is not None and direction == op.direction:
> + LOG.debug('Resizing %s %s from %s to %s',
> + op.device, op.direction, op.start_size, op.end_size)
> + util.subp(['e2fsck', '-p', '-f', op.device])
> + end_size_k = op.end_size // 1024
> + util.subp(['resize2fs', op.device, f'{end_size_k}k'])
> +
> +
> def disk_handler_v2(info, storage_config, handlers):
> disk_handler_v1(info, storage_config, handlers)
>
> diff --git a/doc/topics/storage.rst b/doc/topics/storage.rst
> index 5fae90f..ab89b16 100644
> --- a/doc/topics/storage.rst
> +++ b/doc/topics/storage.rst
> @@ -429,6 +429,16 @@ filesystem or be mounted anywhere on the system.
>
> If the preserve flag is set to true, curtin will verify that the partition
> exists and that the ``size`` and ``flag`` match the configuration provided.
> +See also the resize flag, which adjust this behavior.
> +
> +**resize**: *true, false*
> +
> +Only applicable to v2 storage configuration.
> +If the preserve flag is set to false, this value is not applicable.
> +If the preserve flag is set to true, curtin will adjust the size of the
> +partition to the new size. When adjusting smaller, the size of the contents
> +must permit that. When adjusting larger, there must already be a gap beyond
> +the partition in question.
I think so? Are you thinking of the case where maybe we delete a partition and expand into it? Otherwise I don't understand. If it's just that then I can clarify the wording.
>
> **name**: *<name>*
>
> diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py
> index 0c74cd6..dffb5aa 100644
> --- a/tests/integration/test_block_meta.py
> +++ b/tests/integration/test_block_meta.py
> @@ -415,3 +439,128 @@ class TestBlockMeta(IntegrationTestCase):
> )
> finally:
> server.stop()
> +
> + def _do_test_resize(self, start, end):
> + start <<= 20
> + end <<= 20
> + img = self.tmp_path('image.img')
> + config = StorageConfigBuilder(version=2)
> + config.add_image(path=img, size='200M', ptable='gpt')
> + p1 = config.add_part(size=start, offset=1 << 20, number=1)
> + config.add_format(part=p1)
> + self.run_bm(config.render())
> +
> + expected = 'preserve my data!'
> + with loop_dev(img) as dev:
> + self.assertEqual(
> + summarize_partitions(dev), [
> + PartData(number=1, offset=1 << 20, size=start),
> + ])
> + with self.mount(dev, p1) as mnt_point:
> + with open(f'{mnt_point}/data.txt', 'w') as fp:
> + fp.write(expected)
> + orig_fs_size = _get_filesystem_size(dev, p1)
> + self.assertEqual(start, orig_fs_size)
> +
> + config.set_preserve()
> + p1['resize'] = True
> + p1['size'] = end
> + # self.run_bm(config.render(), fake=True)
> + self.run_bm(config.render())
> +
> + with loop_dev(img) as dev:
> + self.assertEqual(
> + summarize_partitions(dev), [
> + PartData(number=1, offset=1 << 20, size=end),
> + ])
> + with self.mount(dev, p1) as mnt_point:
> + with open(f'{mnt_point}/data.txt', 'r') as fp:
> + self.assertEqual(expected, fp.read())
> + resized_fs_size = _get_filesystem_size(dev, p1)
> + self.assertEqual(end, resized_fs_size)
> +
> + def test_resize_up(self):
> + self._do_test_resize(40, 80)
> +
> + def test_resize_down(self):
> + self._do_test_resize(80, 40)
> +
> + def test_sizes(self):
> + for size in (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048):
> + size <<= 20
> + img = self.tmp_path('image.img')
> + config = StorageConfigBuilder(version=2)
> + config.add_image(path=img, size='2100M', ptable='gpt')
> + p1 = config.add_part(size=size, offset=1 << 20, number=1)
> + config.add_format(part=p1)
> + self.run_bm(config.render())
> +
> + with loop_dev(img) as dev:
> + actual = _get_filesystem_size(dev, p1)
> + self.assertEqual(size, actual)
> +
> + def test_resizes_up(self):
> + start = 1 << 20
> + for end in (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048):
> + end <<= 20
> + img = self.tmp_path('image.img')
> + config = StorageConfigBuilder(version=2)
> + config.add_image(path=img, size='2100M', ptable='gpt')
> + p1 = config.add_part(size=start, offset=1 << 20, number=1)
> + config.add_format(part=p1)
> + self.run_bm(config.render())
> +
> + with loop_dev(img) as dev:
> + self.assertEqual(
> + summarize_partitions(dev), [
> + PartData(number=1, offset=1 << 20, size=start),
> + ])
> + actual = _get_filesystem_size(dev, p1)
> + self.assertEqual(start, actual, 'initial size')
> +
> + config.set_preserve()
> + p1['resize'] = True
> + p1['size'] = end
> + self.run_bm(config.render())
> +
> + with loop_dev(img) as dev:
> + self.assertEqual(
> + summarize_partitions(dev), [
> + PartData(number=1, offset=1 << 20, size=end),
> + ])
> + actual = _get_filesystem_size(dev, p1)
> + self.assertEqual(end, actual, 'resized size')
> +
> + def test_resizes_down(self):
> + start = 2048 << 20
> + for end in (128, 256, 512, 1024):
> + # resize2fs doesn't want to resize smaller than 128 for a 2048
> + # start
> + end <<= 20
> + img = self.tmp_path('image.img')
> + config = StorageConfigBuilder(version=2)
> + config.add_image(path=img, size='2100M', ptable='gpt')
> + p1 = config.add_part(size=start, offset=1 << 20, number=1)
> + config.add_format(part=p1)
> + self.run_bm(config.render())
> +
> + with loop_dev(img) as dev:
> + self.assertEqual(
> + summarize_partitions(dev), [
> + PartData(number=1, offset=1 << 20, size=start),
> + ])
> + actual = _get_filesystem_size(dev, p1)
> + self.assertEqual(start, actual, 'initial size')
> +
> + config.set_preserve()
> + p1['resize'] = True
> + p1['size'] = end
> + self.run_bm(config.render())
> +
> + with loop_dev(img) as dev:
> + self.assertEqual(
> + summarize_partitions(dev), [
> + PartData(number=1, offset=1 << 20, size=end),
> + ])
> + actual = _get_filesystem_size(dev, p1)
> + self.assertEqual(end, actual, 'resized size')
Started this, will do a little more.
--
https://code.launchpad.net/~dbungert/curtin/+git/curtin/+merge/417829
Your team curtin developers is requested to review the proposed merge of ~dbungert/curtin:resize into curtin:master.
References