From a4e582eb6d4dbea1b1ffa3dd4c9596bff3db4f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Sch=C3=A4fer?= Date: Fri, 2 Mar 2018 16:31:14 +0100 Subject: [PATCH] Resize partition table after image resize The command 'kiwi image resize' allows to resize the size of a disk image. Depending on the partition table type it is also required to resize the partition table inside of the image to let the file size change become effective This Fixes #534 --- kiwi/partitioner/base.py | 8 ++++++++ kiwi/partitioner/dasd.py | 8 ++++++++ kiwi/partitioner/gpt.py | 13 +++++++++++++ kiwi/partitioner/msdos.py | 8 ++++++++ kiwi/storage/loop_device.py | 17 +++++++++++------ kiwi/tasks/image_resize.py | 16 ++++++++++++++++ test/unit/partitioner_base_test.py | 4 ++++ test/unit/partitioner_dasd_test.py | 3 +++ test/unit/partitioner_gpt_test.py | 7 +++++++ test/unit/partitioner_msdos_test.py | 3 +++ test/unit/tasks_image_resize_test.py | 23 +++++++++++++++++++++++ 11 files changed, 104 insertions(+), 6 deletions(-) diff --git a/kiwi/partitioner/base.py b/kiwi/partitioner/base.py index b04840f7..03d79a08 100644 --- a/kiwi/partitioner/base.py +++ b/kiwi/partitioner/base.py @@ -98,3 +98,11 @@ class PartitionerBase(object): Implementation in specialized partitioner class """ raise NotImplementedError + + def resize_table(self, entries=None): + """ + Resize partition table + + :param int entries: unused + """ + raise NotImplementedError diff --git a/kiwi/partitioner/dasd.py b/kiwi/partitioner/dasd.py index 91bf46a2..93c59b7a 100644 --- a/kiwi/partitioner/dasd.py +++ b/kiwi/partitioner/dasd.py @@ -76,3 +76,11 @@ class PartitionerDasd(PartitionerBase): # are not able to detect real errors with the fdasd operation at # that point. log.debug('potential fdasd errors were ignored') + + def resize_table(self, entries=None): + """ + Resize partition table + + Nothing to be done here for DASD devices + """ + pass diff --git a/kiwi/partitioner/gpt.py b/kiwi/partitioner/gpt.py index 4e59d74c..c30c437c 100644 --- a/kiwi/partitioner/gpt.py +++ b/kiwi/partitioner/gpt.py @@ -136,3 +136,16 @@ class PartitionerGpt(PartitionerBase): if efi_partition_number: # turn former EFI partition into standard linux partition self.set_flag(efi_partition_number, 't.linux') + + def resize_table(self, entries=128): + """ + Resize partition table + + :param int entries: default entries + """ + Command.run( + [ + 'sgdisk', '--resize-table', '{0}'.format(entries), + self.disk_device + ] + ) diff --git a/kiwi/partitioner/msdos.py b/kiwi/partitioner/msdos.py index 3636fe90..fbdf512a 100644 --- a/kiwi/partitioner/msdos.py +++ b/kiwi/partitioner/msdos.py @@ -120,3 +120,11 @@ class PartitionerMsDos(PartitionerBase): ) else: log.warning('Flag %s ignored on msdos', flag_name) + + def resize_table(self, entries=None): + """ + Resize partition table + + Nothing to be done here for msdos table + """ + pass diff --git a/kiwi/storage/loop_device.py b/kiwi/storage/loop_device.py index e776705a..84adbd36 100644 --- a/kiwi/storage/loop_device.py +++ b/kiwi/storage/loop_device.py @@ -72,14 +72,19 @@ class LoopDevice(DeviceProvider): """ return True - def create(self): + def create(self, overwrite=True): """ - Setup a loop device of the specified size and blocksize + Setup a loop device of the blocksize given in the constructor + The file to loop is created with the size specified in the + constructor unless an existing one should not be overwritten + + :param bool overwrite: overwrite existing file to loop """ - qemu_img_size = format(self.filesize_mbytes) + 'M' - Command.run( - ['qemu-img', 'create', self.filename, qemu_img_size] - ) + if overwrite: + qemu_img_size = format(self.filesize_mbytes) + 'M' + Command.run( + ['qemu-img', 'create', self.filename, qemu_img_size] + ) loop_options = [] if self.blocksize_bytes and self.blocksize_bytes != 512: loop_options.append('--logical-blocksize') diff --git a/kiwi/tasks/image_resize.py b/kiwi/tasks/image_resize.py index b5401991..27d6122e 100644 --- a/kiwi/tasks/image_resize.py +++ b/kiwi/tasks/image_resize.py @@ -46,6 +46,9 @@ options: import os # project +from kiwi.firmware import FirmWare +from kiwi.storage.loop_device import LoopDevice +from kiwi.partitioner import Partitioner from kiwi.tasks.base import CliTask from kiwi.help import Help from kiwi.logger import log @@ -107,10 +110,23 @@ class ImageResizeTask(CliTask): new_disk_size = StringToSize.to_bytes(self.command_args['--size']) + # resize raw disk log.info( 'Resizing raw disk to {0} bytes'.format(new_disk_size) ) resize_result = image_format.resize_raw_disk(new_disk_size) + + # resize raw disk partition table + firmware = FirmWare(self.xml_state) + loop_provider = LoopDevice(image_format.diskname) + loop_provider.create(overwrite=False) + partitioner = Partitioner( + firmware.get_partition_table_type(), loop_provider + ) + partitioner.resize_table() + del loop_provider + + # resize disk format from resized raw disk if disk_format and resize_result is True: log.info( 'Creating {0} disk format from resized raw disk'.format( diff --git a/test/unit/partitioner_base_test.py b/test/unit/partitioner_base_test.py index 4771d28a..2742a5c6 100644 --- a/test/unit/partitioner_base_test.py +++ b/test/unit/partitioner_base_test.py @@ -31,3 +31,7 @@ class TestPartitionerBase(object): @raises(NotImplementedError) def test_set_mbr(self): self.partitioner.set_mbr() + + @raises(NotImplementedError) + def test_resize_table(self): + self.partitioner.resize_table() diff --git a/test/unit/partitioner_dasd_test.py b/test/unit/partitioner_dasd_test.py index 01a8eb4d..50cbb035 100644 --- a/test/unit/partitioner_dasd_test.py +++ b/test/unit/partitioner_dasd_test.py @@ -65,3 +65,6 @@ class TestPartitionerDasd(object): self.file_mock.write.assert_called_once_with( 'n\np\n\n\nw\nq\n' ) + + def test_resize_table(self): + self.partitioner.resize_table() diff --git a/test/unit/partitioner_gpt_test.py b/test/unit/partitioner_gpt_test.py index 3260a7da..0c40320a 100644 --- a/test/unit/partitioner_gpt_test.py +++ b/test/unit/partitioner_gpt_test.py @@ -77,3 +77,10 @@ class TestPartitionerGpt(object): call(['sgdisk', '-m', '1:2:3:4', '/dev/loop0']), call(['sgdisk', '-t', '4:8300', '/dev/loop0']) ] + + @patch('kiwi.partitioner.gpt.Command.run') + def test_resize_table(self, mock_command): + self.partitioner.resize_table(42) + mock_command.assert_called_once_with( + ['sgdisk', '--resize-table', '42', '/dev/loop0'] + ) diff --git a/test/unit/partitioner_msdos_test.py b/test/unit/partitioner_msdos_test.py index c64e2ee3..d1857ee5 100644 --- a/test/unit/partitioner_msdos_test.py +++ b/test/unit/partitioner_msdos_test.py @@ -106,3 +106,6 @@ class TestPartitionerMsDos(object): def test_set_flag_ignored(self, mock_warn): self.partitioner.set_flag(1, 't.csm') assert mock_warn.called + + def test_resize_table(self): + self.partitioner.resize_table() diff --git a/test/unit/tasks_image_resize_test.py b/test/unit/tasks_image_resize_test.py index 2b0e0c59..2f5207f2 100644 --- a/test/unit/tasks_image_resize_test.py +++ b/test/unit/tasks_image_resize_test.py @@ -29,12 +29,27 @@ class TestImageResizeTask(object): return_value=mock.Mock() ) + self.firmware = mock.Mock() + self.firmware.get_partition_table_type = mock.Mock( + return_value='gpt' + ) + self.partitioner = mock.Mock() + self.loop_provider = mock.Mock() self.image_format = mock.Mock() self.image_format.has_raw_disk = mock.Mock() self.image_format.diskname = 'some-disk.raw' kiwi.tasks.image_resize.DiskFormat = mock.Mock( return_value=self.image_format ) + kiwi.tasks.image_resize.FirmWare = mock.Mock( + return_value=self.firmware + ) + kiwi.tasks.image_resize.LoopDevice = mock.Mock( + return_value=self.loop_provider + ) + kiwi.tasks.image_resize.Partitioner = mock.Mock( + return_value=self.partitioner + ) self.task = ImageResizeTask() @@ -74,6 +89,8 @@ class TestImageResizeTask(object): self.task.command_args['resize'] = True self.image_format.resize_raw_disk.return_value = True self.task.process() + self.loop_provider.create.assert_called_once_with(overwrite=False) + self.partitioner.resize_table.assert_called_once_with() self.image_format.resize_raw_disk.assert_called_once_with( 42 * 1024 * 1024 * 1024 ) @@ -85,6 +102,8 @@ class TestImageResizeTask(object): self.task.command_args['--size'] = '42m' self.image_format.resize_raw_disk.return_value = True self.task.process() + self.loop_provider.create.assert_called_once_with(overwrite=False) + self.partitioner.resize_table.assert_called_once_with() self.image_format.resize_raw_disk.assert_called_once_with( 42 * 1024 * 1024 ) @@ -96,6 +115,8 @@ class TestImageResizeTask(object): self.task.command_args['--size'] = '42' self.image_format.resize_raw_disk.return_value = True self.task.process() + self.loop_provider.create.assert_called_once_with(overwrite=False) + self.partitioner.resize_table.assert_called_once_with() self.image_format.resize_raw_disk.assert_called_once_with( 42 ) @@ -108,6 +129,8 @@ class TestImageResizeTask(object): self.task.command_args['--size'] = '42' self.image_format.resize_raw_disk.return_value = False self.task.process() + self.loop_provider.create.assert_called_once_with(overwrite=False) + self.partitioner.resize_table.assert_called_once_with() self.image_format.resize_raw_disk.assert_called_once_with( 42 )