summaryrefslogtreecommitdiffstats
path: root/roles/kube_nfs_volumes/library/partitionpool.py
diff options
context:
space:
mode:
Diffstat (limited to 'roles/kube_nfs_volumes/library/partitionpool.py')
-rw-r--r--roles/kube_nfs_volumes/library/partitionpool.py247
1 files changed, 0 insertions, 247 deletions
diff --git a/roles/kube_nfs_volumes/library/partitionpool.py b/roles/kube_nfs_volumes/library/partitionpool.py
deleted file mode 100644
index 1857433c7..000000000
--- a/roles/kube_nfs_volumes/library/partitionpool.py
+++ /dev/null
@@ -1,247 +0,0 @@
-#!/usr/bin/python
-"""
-Ansible module for partitioning.
-"""
-
-from __future__ import print_function
-
-# There is no pyparted on our Jenkins worker
-# pylint: disable=import-error
-import parted
-
-DOCUMENTATION = """
----
-module: partitionpool
-short_description; Partition a disk into parititions.
-description:
- - Creates partitions on given disk based on partition sizes and their weights.
- Unless 'force' option is set to True, it ignores already partitioned disks.
-
- When the disk is empty or 'force' is set to True, it always creates a new
- GPT partition table on the disk. Then it creates number of partitions, based
- on their weights.
-
- This module should be used when a system admin wants to split existing disk(s)
- into pools of partitions of specific sizes. It is not intended as generic disk
- partitioning module!
-
- Independent on 'force' parameter value and actual disk state, the task
- always fills 'partition_pool' fact with all partitions on given disks,
- together with their sizes (in bytes). E.g.:
- partition_sizes = [
- { name: sda1, Size: 1048576000 },
- { name: sda2, Size: 1048576000 },
- { name: sdb1, Size: 1048576000 },
- ...
- ]
-
-options:
- disk:
- description:
- - Disk to partition.
- size:
- description:
- - Sizes of partitions to create and their weights. Has form of:
- <size1>[:<weigth1>][,<size2>[:<weight2>][,...]]
- - Any <size> can end with 'm' or 'M' for megabyte, 'g/G' for gigabyte
- and 't/T' for terabyte. Megabyte is used when no unit is specified.
- - If <weight> is missing, 1.0 is used.
- - From each specified partition <sizeX>, number of these partitions are
- created so they occupy spaces represented by <weightX>, proportionally to
- other weights.
-
- - Example 1: size=100G says, that the whole disk is split in number of 100 GiB
- partitions. On 1 TiB disk, 10 partitions will be created.
-
- - Example 2: size=100G:1,10G:1 says that ratio of space occupied by 100 GiB
- partitions and 10 GiB partitions is 1:1. Therefore, on 1 TiB disk, 500 GiB
- will be split into five 100 GiB partition and 500 GiB will be split into fifty
- 10GiB partitions.
- - size=100G:1,10G:1 = 5x 100 GiB and 50x 10 GiB partitions (on 1 TiB disk).
-
- - Example 3: size=200G:1,100G:2 says that the ratio of space occupied by 200 GiB
- partitions and 100GiB partition is 1:2. Therefore, on 1 TiB disk, 1/3
- (300 GiB) should be occupied by 200 GiB partitions. Only one fits there,
- so only one is created (we always round nr. of partitions *down*). The rest
- (800 GiB) is split into eight 100 GiB partitions, even though it's more
- than 2/3 of total space - free space is always allocated as much as possible.
- - size=200G:1,100G:2 = 1x 200 GiB and 8x 100 GiB partitions (on 1 TiB disk).
-
- - Example: size=200G:1,100G:1,50G:1 says that the ratio of space occupied by
- 200 GiB, 100 GiB and 50 GiB partitions is 1:1:1. Therefore 1/3 of 1 TiB disk
- is dedicated to 200 GiB partitions. Only one fits there and only one is
- created. The rest (800 GiB) is distributed according to remaining weights:
- 100 GiB vs 50 GiB is 1:1, we create four 100 GiB partitions (400 GiB in total)
- and eight 50 GiB partitions (again, 400 GiB).
- - size=200G:1,100G:1,50G:1 = 1x 200 GiB, 4x 100 GiB and 8x 50 GiB partitions
- (on 1 TiB disk).
-
- force:
- description:
- - If True, it will always overwite partition table on the disk and create new one.
- - If False (default), it won't change existing partition tables.
-
-"""
-
-
-# It's not class, it's more a simple struct with almost no functionality.
-# pylint: disable=too-few-public-methods
-class PartitionSpec(object):
- """ Simple class to represent required partitions."""
- def __init__(self, size, weight):
- """ Initialize the partition specifications."""
- # Size of the partitions
- self.size = size
- # Relative weight of this request
- self.weight = weight
- # Number of partitions to create, will be calculated later
- self.count = -1
-
- def set_count(self, count):
- """ Set count of parititions of this specification. """
- self.count = count
-
-
-def assign_space(total_size, specs):
- """
- Satisfy all the PartitionSpecs according to their weight.
- In other words, calculate spec.count of all the specs.
- """
- total_weight = 0.0
- for spec in specs:
- total_weight += float(spec.weight)
-
- for spec in specs:
- num_blocks = int((float(spec.weight) / total_weight) * (total_size / float(spec.size)))
- spec.set_count(num_blocks)
- total_size -= num_blocks * spec.size
- total_weight -= spec.weight
-
-
-def partition(diskname, specs, force=False, check_mode=False):
- """
- Create requested partitions.
- Returns nr. of created partitions or 0 when the disk was already partitioned.
- """
- count = 0
-
- dev = parted.getDevice(diskname)
- try:
- disk = parted.newDisk(dev)
- except parted.DiskException:
- # unrecognizable format, treat as empty disk
- disk = None
-
- if disk and len(disk.partitions) > 0 and not force:
- print("skipping", diskname)
- return 0
-
- # create new partition table, wiping all existing data
- disk = parted.freshDisk(dev, 'gpt')
- # calculate nr. of partitions of each size
- assign_space(dev.getSize(), specs)
- last_megabyte = 1
- for spec in specs:
- for _ in range(spec.count):
- # create the partition
- start = parted.sizeToSectors(last_megabyte, "MiB", dev.sectorSize)
- length = parted.sizeToSectors(spec.size, "MiB", dev.sectorSize)
- geo = parted.Geometry(device=dev, start=start, length=length)
- filesystem = parted.FileSystem(type='ext4', geometry=geo)
- part = parted.Partition(
- disk=disk,
- type=parted.PARTITION_NORMAL,
- fs=filesystem,
- geometry=geo)
- disk.addPartition(partition=part, constraint=dev.optimalAlignedConstraint)
- last_megabyte += spec.size
- count += 1
- try:
- if not check_mode:
- disk.commit()
- except parted.IOException:
- # partitions have been written, but we have been unable to inform the
- # kernel of the change, probably because they are in use.
- # Ignore it and hope for the best...
- pass
- return count
-
-
-def parse_spec(text):
- """ Parse string with partition specification. """
- tokens = text.split(",")
- specs = []
- for token in tokens:
- if ":" not in token:
- token += ":1"
-
- (sizespec, weight) = token.split(':')
- weight = float(weight) # throws exception with reasonable error string
-
- units = {"m": 1, "g": 1 << 10, "t": 1 << 20, "p": 1 << 30}
- unit = units.get(sizespec[-1].lower(), None)
- if not unit:
- # there is no unit specifier, it must be just the number
- size = float(sizespec)
- unit = 1
- else:
- size = float(sizespec[:-1])
- spec = PartitionSpec(int(size * unit), weight)
- specs.append(spec)
- return specs
-
-
-def get_partitions(diskpath):
- """ Return array of partition names for given disk """
- dev = parted.getDevice(diskpath)
- disk = parted.newDisk(dev)
- partitions = []
- for part in disk.partitions:
- (_, _, pname) = part.path.rsplit("/")
- partitions.append({"name": pname, "size": part.getLength() * dev.sectorSize})
-
- return partitions
-
-
-def main():
- """ Ansible module main method. """
- module = AnsibleModule( # noqa: F405
- argument_spec=dict(
- disks=dict(required=True, type='str'),
- force=dict(required=False, default="no", type='bool'),
- sizes=dict(required=True, type='str')
- ),
- supports_check_mode=True,
- )
-
- disks = module.params['disks']
- force = module.params['force']
- if force is None:
- force = False
- sizes = module.params['sizes']
-
- try:
- specs = parse_spec(sizes)
- except ValueError as ex:
- err = "Error parsing sizes=" + sizes + ": " + str(ex)
- module.fail_json(msg=err)
-
- partitions = []
- changed_count = 0
- for disk in disks.split(","):
- try:
- changed_count += partition(disk, specs, force, module.check_mode)
- except Exception as ex:
- err = "Error creating partitions on " + disk + ": " + str(ex)
- raise
- # module.fail_json(msg=err)
- partitions += get_partitions(disk)
-
- module.exit_json(changed=(changed_count > 0), ansible_facts={"partition_pool": partitions})
-
-
-# ignore pylint errors related to the module_utils import
-# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, wrong-import-order, wrong-import-position
-# import module snippets
-from ansible.module_utils.basic import * # noqa: E402,F403
-main()