summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/general/plugins/modules/parted.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/community/general/plugins/modules/parted.py
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/community/general/plugins/modules/parted.py')
-rw-r--r--ansible_collections/community/general/plugins/modules/parted.py810
1 files changed, 810 insertions, 0 deletions
diff --git a/ansible_collections/community/general/plugins/modules/parted.py b/ansible_collections/community/general/plugins/modules/parted.py
new file mode 100644
index 000000000..8e6038180
--- /dev/null
+++ b/ansible_collections/community/general/plugins/modules/parted.py
@@ -0,0 +1,810 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2016, Fabrizio Colonna <colofabrix@tin.it>
+# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+
+DOCUMENTATION = r'''
+---
+author:
+ - Fabrizio Colonna (@ColOfAbRiX)
+module: parted
+short_description: Configure block device partitions
+description:
+ - This module allows configuring block device partition using the C(parted)
+ command line tool. For a full description of the fields and the options
+ check the GNU parted manual.
+requirements:
+ - This module requires C(parted) version 1.8.3 and above.
+ - Option I(align) (except C(undefined)) requires C(parted) 2.1 or above.
+ - If the version of C(parted) is below 3.1, it requires a Linux version running
+ the C(sysfs) file system C(/sys/).
+ - Requires the C(resizepart) command when using the I(resize) parameter.
+extends_documentation_fragment:
+ - community.general.attributes
+attributes:
+ check_mode:
+ support: full
+ diff_mode:
+ support: none
+options:
+ device:
+ description:
+ - The block device (disk) where to operate.
+ - Regular files can also be partitioned, but it is recommended to create a
+ loopback device using C(losetup) to easily access its partitions.
+ type: str
+ required: true
+ align:
+ description:
+ - Set alignment for newly created partitions. Use C(undefined) for parted default aligment.
+ type: str
+ choices: [ cylinder, minimal, none, optimal, undefined ]
+ default: optimal
+ number:
+ description:
+ - The partition number being affected.
+ - Required when performing any action on the disk, except fetching information.
+ type: int
+ unit:
+ description:
+ - Selects the current default unit that Parted will use to display
+ locations and capacities on the disk and to interpret those given by the
+ user if they are not suffixed by an unit.
+ - When fetching information about a disk, it is recommended to always specify a unit.
+ type: str
+ choices: [ s, B, KB, KiB, MB, MiB, GB, GiB, TB, TiB, '%', cyl, chs, compact ]
+ default: KiB
+ label:
+ description:
+ - Disk label type or partition table to use.
+ - If I(device) already contains a different label, it will be changed to I(label)
+ and any previous partitions will be lost.
+ - A I(name) must be specified for a C(gpt) partition table.
+ type: str
+ choices: [ aix, amiga, bsd, dvh, gpt, loop, mac, msdos, pc98, sun ]
+ default: msdos
+ part_type:
+ description:
+ - May be specified only with I(label=msdos) or I(label=dvh).
+ - Neither I(part_type) nor I(name) may be used with I(label=sun).
+ type: str
+ choices: [ extended, logical, primary ]
+ default: primary
+ part_start:
+ description:
+ - Where the partition will start as offset from the beginning of the disk,
+ that is, the "distance" from the start of the disk. Negative numbers
+ specify distance from the end of the disk.
+ - The distance can be specified with all the units supported by parted
+ (except compat) and it is case sensitive, e.g. C(10GiB), C(15%).
+ - Using negative values may require setting of I(fs_type) (see notes).
+ type: str
+ default: 0%
+ part_end:
+ description:
+ - Where the partition will end as offset from the beginning of the disk,
+ that is, the "distance" from the start of the disk. Negative numbers
+ specify distance from the end of the disk.
+ - The distance can be specified with all the units supported by parted
+ (except compat) and it is case sensitive, e.g. C(10GiB), C(15%).
+ type: str
+ default: 100%
+ name:
+ description:
+ - Sets the name for the partition number (GPT, Mac, MIPS and PC98 only).
+ type: str
+ flags:
+ description: A list of the flags that has to be set on the partition.
+ type: list
+ elements: str
+ state:
+ description:
+ - Whether to create or delete a partition.
+ - If set to C(info) the module will only return the device information.
+ type: str
+ choices: [ absent, present, info ]
+ default: info
+ fs_type:
+ description:
+ - If specified and the partition does not exist, will set filesystem type to given partition.
+ - Parameter optional, but see notes below about negative I(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
+ through C(/sys/) to obtain disk information. In this case the units CHS and
+ CYL are not supported.
+ - Negative I(part_start) start values were rejected if I(fs_type) was not given.
+ This bug was fixed in parted 3.2.153. If you want to use negative I(part_start),
+ specify I(fs_type) as well or make sure your system contains newer parted.
+'''
+
+RETURN = r'''
+partition_info:
+ description: Current partition information
+ returned: success
+ type: complex
+ contains:
+ disk:
+ description: Generic device information.
+ type: dict
+ partitions:
+ description: List of device partitions.
+ type: list
+ script:
+ description: parted script executed by module
+ type: str
+ sample: {
+ "disk": {
+ "dev": "/dev/sdb",
+ "logical_block": 512,
+ "model": "VMware Virtual disk",
+ "physical_block": 512,
+ "size": 5.0,
+ "table": "msdos",
+ "unit": "gib"
+ },
+ "partitions": [{
+ "begin": 0.0,
+ "end": 1.0,
+ "flags": ["boot", "lvm"],
+ "fstype": "",
+ "name": "",
+ "num": 1,
+ "size": 1.0
+ }, {
+ "begin": 1.0,
+ "end": 5.0,
+ "flags": [],
+ "fstype": "",
+ "name": "",
+ "num": 2,
+ "size": 4.0
+ }],
+ "script": "unit KiB print "
+ }
+'''
+
+EXAMPLES = r'''
+- name: Create a new ext4 primary partition
+ community.general.parted:
+ device: /dev/sdb
+ number: 1
+ state: present
+ fs_type: ext4
+
+- name: Remove partition number 1
+ community.general.parted:
+ device: /dev/sdb
+ number: 1
+ state: absent
+
+- name: Create a new primary partition with a size of 1GiB
+ community.general.parted:
+ device: /dev/sdb
+ number: 1
+ state: present
+ part_end: 1GiB
+
+- name: Create a new primary partition for LVM
+ community.general.parted:
+ device: /dev/sdb
+ number: 2
+ flags: [ lvm ]
+ state: present
+ part_start: 1GiB
+
+- name: Create a new primary partition with a size of 1GiB at disk's end
+ community.general.parted:
+ device: /dev/sdb
+ number: 3
+ state: present
+ fs_type: ext3
+ part_start: -1GiB
+
+# Example on how to read info and reuse it in subsequent task
+- name: Read device information (always use unit when probing)
+ community.general.parted: device=/dev/sdb unit=MiB
+ register: sdb_info
+
+- name: Remove all partitions from disk
+ community.general.parted:
+ device: /dev/sdb
+ number: '{{ item.num }}'
+ state: absent
+ loop: '{{ sdb_info.partitions }}'
+
+- name: Extend an existing partition to fill all available space
+ community.general.parted:
+ device: /dev/sdb
+ number: "{{ sdb_info.partitions | length }}"
+ part_end: "100%"
+ resize: true
+ state: present
+'''
+
+
+from ansible.module_utils.basic import AnsibleModule
+import math
+import re
+import os
+
+
+# Reference prefixes (International System of Units and IEC)
+units_si = ['B', 'KB', 'MB', 'GB', 'TB']
+units_iec = ['KiB', 'MiB', 'GiB', 'TiB']
+parted_units = units_si + units_iec + ['s', '%', 'cyl', 'chs', 'compact']
+
+
+def parse_unit(size_str, unit=''):
+ """
+ Parses a string containing a size or boundary information
+ """
+ matches = re.search(r'^(-?[\d.]+) *([\w%]+)?$', size_str)
+ if matches is None:
+ # "<cylinder>,<head>,<sector>" format
+ matches = re.search(r'^(\d+),(\d+),(\d+)$', size_str)
+ if matches is None:
+ module.fail_json(
+ msg="Error interpreting parted size output: '%s'" % size_str
+ )
+
+ size = {
+ 'cylinder': int(matches.group(1)),
+ 'head': int(matches.group(2)),
+ 'sector': int(matches.group(3))
+ }
+ unit = 'chs'
+
+ else:
+ # Normal format: "<number>[<unit>]"
+ if matches.group(2) is not None:
+ unit = matches.group(2)
+
+ size = float(matches.group(1))
+
+ return size, unit
+
+
+def parse_partition_info(parted_output, unit):
+ """
+ Parses the output of parted and transforms the data into
+ a dictionary.
+
+ Parted Machine Parseable Output:
+ See: https://lists.alioth.debian.org/pipermail/parted-devel/2006-December/00
+ 0573.html
+ - All lines end with a semicolon (;)
+ - The first line indicates the units in which the output is expressed.
+ CHS, CYL and BYT stands for CHS, Cylinder and Bytes respectively.
+ - The second line is made of disk information in the following format:
+ "path":"size":"transport-type":"logical-sector-size":"physical-sector-siz
+ e":"partition-table-type":"model-name";
+ - If the first line was either CYL or CHS, the next line will contain
+ information on no. of cylinders, heads, sectors and cylinder size.
+ - Partition information begins from the next line. This is of the format:
+ (for BYT)
+ "number":"begin":"end":"size":"filesystem-type":"partition-name":"flags-s
+ et";
+ (for CHS/CYL)
+ "number":"begin":"end":"filesystem-type":"partition-name":"flags-set";
+ """
+ lines = [x for x in parted_output.split('\n') if x.strip() != '']
+
+ # Generic device info
+ generic_params = lines[1].rstrip(';').split(':')
+
+ # The unit is read once, because parted always returns the same unit
+ size, unit = parse_unit(generic_params[1], unit)
+
+ generic = {
+ 'dev': generic_params[0],
+ 'size': size,
+ 'unit': unit.lower(),
+ 'table': generic_params[5],
+ 'model': generic_params[6],
+ 'logical_block': int(generic_params[3]),
+ 'physical_block': int(generic_params[4])
+ }
+
+ # CYL and CHS have an additional line in the output
+ if unit in ['cyl', 'chs']:
+ chs_info = lines[2].rstrip(';').split(':')
+ cyl_size, cyl_unit = parse_unit(chs_info[3])
+ generic['chs_info'] = {
+ 'cylinders': int(chs_info[0]),
+ 'heads': int(chs_info[1]),
+ 'sectors': int(chs_info[2]),
+ 'cyl_size': cyl_size,
+ 'cyl_size_unit': cyl_unit.lower()
+ }
+ lines = lines[1:]
+
+ parts = []
+ for line in lines[2:]:
+ part_params = line.rstrip(';').split(':')
+
+ # CHS use a different format than BYT, but contrary to what stated by
+ # the author, CYL is the same as BYT. I've tested this undocumented
+ # behaviour down to parted version 1.8.3, which is the first version
+ # that supports the machine parseable output.
+ if unit != 'chs':
+ size = parse_unit(part_params[3])[0]
+ fstype = part_params[4]
+ name = part_params[5]
+ flags = part_params[6]
+
+ else:
+ size = ""
+ fstype = part_params[3]
+ name = part_params[4]
+ flags = part_params[5]
+
+ parts.append({
+ 'num': int(part_params[0]),
+ 'begin': parse_unit(part_params[1])[0],
+ 'end': parse_unit(part_params[2])[0],
+ 'size': size,
+ 'fstype': fstype,
+ 'name': name,
+ 'flags': [f.strip() for f in flags.split(', ') if f != ''],
+ 'unit': unit.lower(),
+ })
+
+ return {'generic': generic, 'partitions': parts}
+
+
+def format_disk_size(size_bytes, unit):
+ """
+ Formats a size in bytes into a different unit, like parted does. It doesn't
+ manage CYL and CHS formats, though.
+ This function has been adapted from https://github.com/Distrotech/parted/blo
+ b/279d9d869ff472c52b9ec2e180d568f0c99e30b0/libparted/unit.c
+ """
+ global units_si, units_iec # pylint: disable=global-variable-not-assigned
+
+ unit = unit.lower()
+
+ # Shortcut
+ if size_bytes == 0:
+ return 0.0, 'b'
+
+ # Cases where we default to 'compact'
+ if unit in ['', 'compact', 'cyl', 'chs']:
+ index = max(0, int(
+ (math.log10(size_bytes) - 1.0) / 3.0
+ ))
+ unit = 'b'
+ if index < len(units_si):
+ unit = units_si[index]
+
+ # Find the appropriate multiplier
+ 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)
+
+ output = size_bytes // multiplier * (1 + 1E-16)
+
+ # Corrections to round up as per IEEE754 standard
+ if output < 10:
+ w = output + 0.005
+ elif output < 100:
+ w = output + 0.05
+ else:
+ w = output + 0.5
+
+ if w < 10:
+ precision = 2
+ elif w < 100:
+ precision = 1
+ else:
+ precision = 0
+
+ # Round and return
+ 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
+ parted cannot work because of a missing label. It always returns a 'unknown'
+ label.
+ """
+ device_name = os.path.basename(device)
+ base = "/sys/block/%s" % device_name
+
+ vendor = read_record(base + "/device/vendor", "Unknown")
+ model = read_record(base + "/device/model", "model")
+ logic_block = int(read_record(base + "/queue/logical_block_size", 0))
+ phys_block = int(read_record(base + "/queue/physical_block_size", 0))
+ size_bytes = int(read_record(base + "/size", 0)) * logic_block
+
+ size, unit = format_disk_size(size_bytes, unit)
+
+ return {
+ 'generic': {
+ 'dev': device,
+ 'table': "unknown",
+ 'size': size,
+ 'unit': unit,
+ 'logical_block': logic_block,
+ 'physical_block': phys_block,
+ 'model': "%s %s" % (vendor, model),
+ },
+ 'partitions': []
+ }
+
+
+def get_device_info(device, unit):
+ """
+ Fetches information about a disk and its partitions and it returns a
+ dictionary.
+ """
+ global module, parted_exec # pylint: disable=global-variable-not-assigned
+
+ # If parted complains about missing labels, it means there are no partitions.
+ # In this case only, use a custom function to fetch information and emulate
+ # parted formats for the unit.
+ label_needed = check_parted_label(device)
+ if label_needed:
+ return get_unlabeled_device_info(device, unit)
+
+ command = "%s -s -m %s -- unit '%s' print" % (parted_exec, device, unit)
+ rc, out, err = module.run_command(command)
+ if rc != 0 and 'unrecognised disk label' not in err:
+ module.fail_json(msg=(
+ "Error while getting device information with parted "
+ "script: '%s'" % command),
+ rc=rc, out=out, err=err
+ )
+
+ return parse_partition_info(out, unit)
+
+
+def check_parted_label(device):
+ """
+ Determines if parted needs a label to complete its duties. Versions prior
+ to 3.1 don't return data when there is no label. For more information see:
+ http://upstream.rosalinux.ru/changelogs/libparted/3.1/changelog.html
+ """
+ global parted_exec # pylint: disable=global-variable-not-assigned
+
+ # Check the version
+ parted_major, parted_minor, dummy = parted_version()
+ if (parted_major == 3 and parted_minor >= 1) or parted_major > 3:
+ return False
+
+ # Older parted versions return a message in the stdout and RC > 0.
+ rc, out, err = module.run_command("%s -s -m %s print" % (parted_exec, device))
+ if rc != 0 and 'unrecognised disk label' in out.lower():
+ return True
+
+ return False
+
+
+def parse_parted_version(out):
+ """
+ Returns version tuple from the output of "parted --version" command
+ """
+ lines = [x for x in out.split('\n') if x.strip() != '']
+ if len(lines) == 0:
+ return None, None, None
+
+ # Sample parted versions (see as well test unit):
+ # parted (GNU parted) 3.3
+ # parted (GNU parted) 3.4.5
+ # parted (GNU parted) 3.3.14-dfc61
+ matches = re.search(r'^parted.+\s(\d+)\.(\d+)(?:\.(\d+))?', lines[0].strip())
+
+ if matches is None:
+ return None, None, None
+
+ # Convert version to numbers
+ major = int(matches.group(1))
+ minor = int(matches.group(2))
+ rev = 0
+ if matches.group(3) is not None:
+ rev = int(matches.group(3))
+
+ return major, minor, rev
+
+
+def parted_version():
+ """
+ Returns the major and minor version of parted installed on the system.
+ """
+ global module, parted_exec # pylint: disable=global-variable-not-assigned
+
+ rc, out, err = module.run_command("%s --version" % parted_exec)
+ if rc != 0:
+ module.fail_json(
+ msg="Failed to get parted version.", rc=rc, out=out, err=err
+ )
+
+ (major, minor, rev) = parse_parted_version(out)
+ if major is None:
+ module.fail_json(msg="Failed to get parted version.", rc=0, out=out)
+
+ return major, minor, rev
+
+
+def parted(script, device, align):
+ """
+ Runs a parted script.
+ """
+ global module, parted_exec # pylint: disable=global-variable-not-assigned
+
+ align_option = '-a %s' % align
+ if align == 'undefined':
+ align_option = ''
+
+ if script and not module.check_mode:
+ command = "%s -s -m %s %s -- %s" % (parted_exec, align_option, device, script)
+ rc, out, err = module.run_command(command)
+
+ if rc != 0:
+ module.fail_json(
+ msg="Error while running parted script: %s" % command.strip(),
+ rc=rc, out=out, err=err
+ )
+
+
+def read_record(file_path, default=None):
+ """
+ Reads the first line of a file and returns it.
+ """
+ try:
+ f = open(file_path, 'r')
+ try:
+ return f.readline().strip()
+ finally:
+ f.close()
+ except IOError:
+ return default
+
+
+def part_exists(partitions, attribute, number):
+ """
+ Looks if a partition that has a specific value for a specific attribute
+ actually exists.
+ """
+ return any(
+ part[attribute] and
+ part[attribute] == number for part in partitions
+ )
+
+
+def check_size_format(size_str):
+ """
+ Checks if the input string is an allowed size
+ """
+ size, unit = parse_unit(size_str)
+ return unit in parted_units
+
+
+def main():
+ global module, units_si, units_iec, parted_exec # pylint: disable=global-variable-not-assigned
+
+ changed = False
+ output_script = ""
+ script = ""
+ module = AnsibleModule(
+ argument_spec=dict(
+ device=dict(type='str', required=True),
+ align=dict(type='str', default='optimal', choices=['cylinder', 'minimal', 'none', 'optimal', 'undefined']),
+ number=dict(type='int'),
+
+ # unit <unit> command
+ unit=dict(type='str', default='KiB', choices=parted_units),
+
+ # mklabel <label-type> command
+ label=dict(type='str', default='msdos', choices=['aix', 'amiga', 'bsd', 'dvh', 'gpt', 'loop', 'mac', 'msdos', 'pc98', 'sun']),
+
+ # mkpart <part-type> [<fs-type>] <start> <end> command
+ part_type=dict(type='str', default='primary', choices=['extended', 'logical', 'primary']),
+ part_start=dict(type='str', default='0%'),
+ part_end=dict(type='str', default='100%'),
+ fs_type=dict(type='str'),
+
+ # name <partition> <name> command
+ name=dict(type='str'),
+
+ # set <partition> <flag> <state> command
+ flags=dict(type='list', elements='str'),
+
+ # 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']],
+ ['state', 'absent', ['number']],
+ ],
+ supports_check_mode=True,
+ )
+ module.run_command_environ_update = {'LANG': 'C', 'LC_ALL': 'C', 'LC_MESSAGES': 'C', 'LC_CTYPE': 'C'}
+
+ # Data extraction
+ device = module.params['device']
+ align = module.params['align']
+ number = module.params['number']
+ unit = module.params['unit']
+ label = module.params['label']
+ part_type = module.params['part_type']
+ part_start = module.params['part_start']
+ part_end = module.params['part_end']
+ name = module.params['name']
+ 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)
+
+ # Conditioning
+ if number is not None and number < 1:
+ module.fail_json(msg="The partition number must be greater then 0.")
+ if not check_size_format(part_start):
+ module.fail_json(
+ msg="The argument 'part_start' doesn't respect required format."
+ "The size unit is case sensitive.",
+ err=parse_unit(part_start)
+ )
+ if not check_size_format(part_end):
+ module.fail_json(
+ msg="The argument 'part_end' doesn't respect required format."
+ "The size unit is case sensitive.",
+ err=parse_unit(part_end)
+ )
+
+ # Read the current disk information
+ current_device = get_device_info(device, unit)
+ current_parts = current_device['partitions']
+
+ if state == 'present':
+
+ # Assign label if required
+ mklabel_needed = current_device['generic'].get('table', None) != label
+ if mklabel_needed:
+ script += "mklabel %s " % label
+
+ # Create partition if required
+ if part_type and (mklabel_needed or not part_exists(current_parts, 'num', number)):
+ script += "mkpart %s %s%s %s " % (
+ part_type,
+ '%s ' % fs_type if fs_type is not None else '',
+ part_start,
+ part_end
+ )
+
+ # Set the unit of the run
+ 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:
+ output_script += script
+ parted(script, device, align)
+ changed = True
+ script = ""
+
+ if not module.check_mode:
+ current_parts = get_device_info(device, unit)['partitions']
+
+ if part_exists(current_parts, 'num', number) or module.check_mode:
+ if changed and module.check_mode:
+ partition = {'flags': []} # Empty structure for the check-mode
+ else:
+ partition = [p for p in current_parts if p['num'] == number][0]
+
+ # Assign name to the partition
+ if name is not None and partition.get('name', None) != name:
+ # Wrap double quotes in single quotes so the shell doesn't strip
+ # the double quotes as those need to be included in the arg
+ # passed to parted
+ script += 'name %s \'"%s"\' ' % (number, name)
+
+ # Manage flags
+ if flags:
+ # Parted infers boot with esp, if you assign esp, boot is set
+ # and if boot is unset, esp is also unset.
+ if 'esp' in flags and 'boot' not in flags:
+ flags.append('boot')
+
+ # Compute only the changes in flags status
+ flags_off = list(set(partition['flags']) - set(flags))
+ flags_on = list(set(flags) - set(partition['flags']))
+
+ for f in flags_on:
+ script += "set %s %s on " % (number, f)
+
+ for f in flags_off:
+ script += "set %s %s off " % (number, f)
+
+ # Set the unit of the run
+ if unit and script:
+ script = "unit %s %s" % (unit, script)
+
+ # Execute the script
+ if script:
+ output_script += script
+ changed = True
+ parted(script, device, align)
+
+ elif state == 'absent':
+ # Remove the partition
+ if part_exists(current_parts, 'num', number) or module.check_mode:
+ script = "rm %s " % number
+ output_script += script
+ changed = True
+ parted(script, device, align)
+
+ elif state == 'info':
+ output_script = "unit '%s' print " % unit
+
+ # Final status of the device
+ final_device_status = get_device_info(device, unit)
+ module.exit_json(
+ changed=changed,
+ disk=final_device_status['generic'],
+ partitions=final_device_status['partitions'],
+ script=output_script.strip()
+ )
+
+
+if __name__ == '__main__':
+ main()