From 9279e4532db055772b72b1eeb777e54083d480a3 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sat, 21 Nov 2020 21:38:39 +0100 Subject: [PATCH] Add ability to resize existing partition (#773) (#1348) * Add ability to resize existing partition * Add 'resize' flag to support backwards compatability, and allow partition reduction * Add changelog fragment for #773 * Update changelogs/fragments/773-resize-partition.yml Co-authored-by: Felix Fontein * Update plugins/modules/system/parted.py Co-authored-by: Felix Fontein * Update resize flag with PR review comments Co-authored-by: Andrew Klychkov * Update plugins/modules/system/parted.py Co-authored-by: Felix Fontein * Update default on resize flag in parted.py * Apply suggestions from code review Co-authored-by: Felix Fontein Co-authored-by: Andrew Klychkov (cherry picked from commit 8f99f9cb1c1569b77585ea3d15b9988e05161a4d) Co-authored-by: jake2184 --- changelogs/fragments/773-resize-partition.yml | 2 + plugins/modules/system/parted.py | 52 +++++++++++++++++++ .../plugins/modules/system/test_parted.py | 11 ++++ 3 files changed, 65 insertions(+) create mode 100644 changelogs/fragments/773-resize-partition.yml diff --git a/changelogs/fragments/773-resize-partition.yml b/changelogs/fragments/773-resize-partition.yml new file mode 100644 index 0000000000..6763b6ec45 --- /dev/null +++ b/changelogs/fragments/773-resize-partition.yml @@ -0,0 +1,2 @@ +minor_changes: + - parted - add ``resize`` option to resize existing partitions (https://github.com/ansible-collections/community.general/pull/773). diff --git a/plugins/modules/system/parted.py b/plugins/modules/system/parted.py index 4ec3c29c5e..3cc4ec0ebf 100644 --- a/plugins/modules/system/parted.py +++ b/plugins/modules/system/parted.py @@ -103,6 +103,13 @@ options: - Parameter optional, but see notes below about negative negative C(part_start) values. type: str version_added: '0.2.0' + resize: + description: + - Call C(resizepart) on existing partitions to match the size specified by I(part_end). + type: bool + default: false + version_added: '1.3.0' + notes: - When fetching information about a new disk and when the version of parted installed on the system is before version 3.1, the module queries the kernel @@ -207,6 +214,13 @@ EXAMPLES = r''' number: '{{ item.num }}' state: absent loop: '{{ sdb_info.partitions }}' + +- name: Extend an existing partition to fill all available space + community.general.parted: + decice: /dev/sdb + number: "{{ sdb_info.partitions | length }}" + part_end: "100%" + resize: true ''' @@ -392,6 +406,21 @@ def format_disk_size(size_bytes, unit): return round(output, precision), unit +def convert_to_bytes(size_str, unit): + size = float(size_str) + multiplier = 1.0 + if unit in units_si: + multiplier = 1000.0 ** units_si.index(unit) + elif unit in units_iec: + multiplier = 1024.0 ** (units_iec.index(unit) + 1) + elif unit in ['', 'compact', 'cyl', 'chs']: + # As per format_disk_size, default to compact, which defaults to megabytes + multiplier = 1000.0 ** units_si.index("MB") + + output = size * multiplier + return int(output) + + def get_unlabeled_device_info(device, unit): """ Fetches device information directly from the kernel and it is used when @@ -586,6 +615,9 @@ def main(): # rm/mkpart command state=dict(type='str', default='info', choices=['absent', 'info', 'present']), + + # resize part + resize=dict(type='bool', default=False), ), required_if=[ ['state', 'present', ['number']], @@ -608,6 +640,7 @@ def main(): state = module.params['state'] flags = module.params['flags'] fs_type = module.params['fs_type'] + resize = module.params['resize'] # Parted executable parted_exec = module.get_bin_path('parted', True) @@ -652,6 +685,25 @@ def main(): if unit and script: script = "unit %s %s" % (unit, script) + # If partition exists, try to resize + if resize and part_exists(current_parts, 'num', number): + # Ensure new end is different to current + partition = [p for p in current_parts if p['num'] == number][0] + current_part_end = convert_to_bytes(partition['end'], unit) + + size, parsed_unit = parse_unit(part_end, unit) + if parsed_unit == "%": + size = int((int(current_device['generic']['size']) * size) / 100) + parsed_unit = unit + + desired_part_end = convert_to_bytes(size, parsed_unit) + + if current_part_end != desired_part_end: + script += "resizepart %s %s " % ( + number, + part_end + ) + # Execute the script and update the data structure. # This will create the partition for the next steps if script: diff --git a/tests/unit/plugins/modules/system/test_parted.py b/tests/unit/plugins/modules/system/test_parted.py index 3db8fae231..5ed7514646 100644 --- a/tests/unit/plugins/modules/system/test_parted.py +++ b/tests/unit/plugins/modules/system/test_parted.py @@ -206,6 +206,17 @@ class TestParted(ModuleTestCase): with patch('ansible_collections.community.general.plugins.modules.system.parted.get_device_info', return_value=parted_dict1): self.execute_module(changed=True, script='rm 1') + def test_resize_partition(self): + set_module_args({ + 'device': '/dev/sdb', + 'number': 3, + 'state': 'present', + 'part_end': '100%', + 'resize': True + }) + with patch('ansible_collections.community.general.plugins.modules.system.parted.get_device_info', return_value=parted_dict1): + self.execute_module(changed=True, script='resizepart 3 100%') + def test_change_flag(self): # Flags are set in a second run of parted(). # Between the two runs, the partition dict is updated.