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.