diff options
Diffstat (limited to 'roles')
| -rw-r--r-- | roles/partition/README.md | 38 | ||||
| -rw-r--r-- | roles/partition/defaults/main.yml | 3 | ||||
| -rw-r--r-- | roles/partition/meta/argument_specs.yml | 120 | ||||
| -rw-r--r-- | roles/partition/meta/main.yml | 19 | ||||
| -rw-r--r-- | roles/partition/tasks/main.yml | 99 |
5 files changed, 279 insertions, 0 deletions
diff --git a/roles/partition/README.md b/roles/partition/README.md new file mode 100644 index 0000000..e9fae12 --- /dev/null +++ b/roles/partition/README.md @@ -0,0 +1,38 @@ +# Ansible Role: partition + +This role partitions the desired host with defined partition map + +## Role Variables + +- `partition_disk` the `dev/disk` to be partitioned (required) +- `partition_wipe` whether or not to wipe the disk before partitioning (default: false) +- `partition_root` partition map (defined below) +- `partition_boot` partition map (defined below) +- `partition_swap` partition map (defined below) +- `partition_extras` list of partition map (defined below) default: [] + +### Partition map + +This is the `dict` defining the partition properties: + +- `num` partition number (required) +- `name` partition name (required) +- `label` partition label (default `gpt`) check `argument_specs` for available labels +- `flags` partition flags (default `[]`) check `argument_specs` for available flags +- `part_start` address to start partition (required, ex: `11G`, `0%`) +- `part_end` address to end partition (required, ex: `250G`, `100%`) +- `fstype` partition file system type (required) check `argument_specs` for available file systems +- `fstype_opts` list of options to be passed to `mkfs` (default: `""`) +- `dev` device mounted path (required, ex: `/dev/nvme0n1p4`, `/dev/sdb4`) +- `mount_path` mount path directory of the partition (required, ex: `/mnt`) +- `fstab_opts` options to add to `fstab` mount (default `"defaults"`) + +## Internals + +- force erase/wipe partition when configured with `partition_wipe: true` +- ensure swap is unmounted (to avoid failures on multiple consequent runs) +- ensure partitions are unmounted (respecting mount tree), ex. `/mnt/dir/sub` is unmounted before `/mnt/dir` +- partition the partition list provided +- create (force) file system on partitions +- create swap partition (using `mkswap` and `swapon` as ansible parted doesn't support that) +- mount partitions (respecting mount tree), ex. `/mnt` is mounted before `/mnt/dir` before `/mnt/dir/sub` diff --git a/roles/partition/defaults/main.yml b/roles/partition/defaults/main.yml new file mode 100644 index 0000000..3a512fe --- /dev/null +++ b/roles/partition/defaults/main.yml @@ -0,0 +1,3 @@ +--- +partition_wipe: false +partition_extras: [] diff --git a/roles/partition/meta/argument_specs.yml b/roles/partition/meta/argument_specs.yml new file mode 100644 index 0000000..9645798 --- /dev/null +++ b/roles/partition/meta/argument_specs.yml @@ -0,0 +1,120 @@ +--- +argument_specs: + main: + options: + partition_disk: + type: "str" + required: true + description: "The device to partition. (ex: /dev/nvme0n1)" + partition_wipe: + type: "bool" + default: "false" + description: "Force wiping of the partition_disk" + partition_boot: + type: "dict" + description: "The boot partition definition" + required: true + options: &partition_options + num: + type: "int" + description: "Partition number" + required: true + name: + type: "str" + description: "Partition name" + required: true + label: + type: "str" + description: "Partition label" + default: "gpt" + choices: + - "aix" + - "amiga" + - "bsd" + - "dvh" + - "gpt" + - "loop" + - "mac" + - "msdos" + - "pc98" + - "sun" + flags: + type: "list" + description: "Partition flags" + default: [] + elements: "str" + choices: + - "atvrecv" + - "bios_grup" + - "boot" + - "DIAG" + - "esp" + - "hidden" + - "hp-service" + - "irst" + - "lba" + - "legacy_boot" + - "LVM" + - "msftdata" + - "msftres" + - "PALO" + - "PREP" + - "raid" + - "root" + - "swap" + part_start: + type: "str" + description: "Partition start (ex: 10GiB, 15%)" + required: true + part_end: + type: "str" + description: "Partition end (ex: 11GiB, 100%)" + required: true + fstype: + type: "str" + description: "Partition filesystem type" + required: true + choices: + - "bcachefs" + - "btrfs" + - "ext2" + - "ext3" + - "ext4" + - "ext4dev" + - "f2fs" + - "lvm" + - "ocfs2" + - "reiserfs" + - "xfs" + - "vfat" + - "swap" + - "ufs" + fstype_opts: + type: "str" + description: "List of options to be passed to mkfs command" + default: "" + dev: + type: "str" + description: "Partition device path (ex: /dev/nvme0n1p3) ignore for partitions not used in playbook" + mount_path: + type: "str" + description: "Partition mount path (ex: /mnt/home), ignore for partitions not used in playbook" + fstab_opts: + type: "str" + description: "Options used for mounting (fstab options)" + default: "defaults" + partition_swap: + type: "dict" + description: "The swap partition definition" + options: *partition_options + partition_root: + description: "The root partition definition" + required: true + options: *partition_options + partition_extras: + type: "list" + description: "The list of extra partitions" + required: false + default: [] + elements: "dict" + options: *partition_options diff --git a/roles/partition/meta/main.yml b/roles/partition/meta/main.yml new file mode 100644 index 0000000..3872e6c --- /dev/null +++ b/roles/partition/meta/main.yml @@ -0,0 +1,19 @@ +--- +dependencies: [] +galaxy_info: + role_name: partition + author: a14m + description: "Create and manage device partitions" + company: "kartoffeln.work GmbH." + license: "license MIT" + min_ansible_version: "2.18" + platforms: + - name: ArchLinux + versions: + - all + - name: Ubuntu + versions: + - noble + - name: Debian + versions: + - bookworm diff --git a/roles/partition/tasks/main.yml b/roles/partition/tasks/main.yml new file mode 100644 index 0000000..faa6bd0 --- /dev/null +++ b/roles/partition/tasks/main.yml @@ -0,0 +1,99 @@ +--- +- name: "Ensure partition_swap is defined" + ansible.builtin.set_fact: + partition_swap: "{{ partition_swap | default({'name': 'default-swap'}) }}" + +- name: "Set partition_list" + ansible.builtin.set_fact: + partition_list: >- + {{ + ([partition_boot, partition_swap, partition_root] + partition_extras) + | rejectattr('num', 'undefined') + | sort(attribute="num") + }} + +- name: "Show partition_list" + ansible.builtin.debug: + msg: "{{ partition_list }}" + +- name: "Erase device: {{ partition_disk }}" + ansible.builtin.command: + cmd: "wipefs -af {{ partition_disk }}" + when: partition_wipe + changed_when: true + +- name: "Run swapoff {{ partition_swap.dev }}" + # Ensure unmounting swap partition as it's mounted using swapon + ansible.builtin.command: + cmd: "swapoff {{ partition_swap.dev }}" + changed_when: true + failed_when: false + when: partition_swap.dev is defined + +- name: "Ensure partitions are not mounted" + ansible.posix.mount: + path: "{{ item.mount_path | default('') }}" + state: "unmounted" + # Ensure the /mnt/path is unmounted before /mnt (respect mount tree) + # This ensures not getting error device is busy when unmounting + # Ignore partitions without mount_path + with_items: "{{ + partition_list + | rejectattr('mount_path', 'undefined') + | sort(attribute='mount_path') + | reverse + }}" + +- name: "Partition device: {{ partition_disk }}" + community.general.parted: + device: "{{ partition_disk }}" + number: "{{ item.num }}" + name: "{{ item.name }}" + label: "{{ item.label | default('gpt') }}" + flags: "{{ item.flags | default([]) }}" + part_start: "{{ item.part_start }}" + part_end: "{{ item.part_end }}" + state: "present" + with_items: "{{ partition_list }}" + +- name: "Create filesystem on device: {{ partition_disk }}" + community.general.filesystem: + dev: "{{ item.dev }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.fstype_opts | default(omit) }}" + # For swap partiton and root partitions, always force recreation of the filesystem + # For any other partition, only create the filesystem if partition_wipe is true + # This is done to ensure that new install a distro won't affect other already installed systems. + force: "{{ (item.name in [partition_swap.name, partition_root.name]) | ternary(true, partition_wipe) }}" + with_items: "{{ partition_list }}" + +- name: "Run mkswap" + ansible.builtin.command: + cmd: "mkswap {{ partition_swap.dev }}" + changed_when: true + when: partition_swap.dev is defined + +- name: "Run swapon {{ partition_swap.dev }}" + ansible.builtin.command: + cmd: "swapon {{ partition_swap.dev }}" + changed_when: true + when: partition_swap.dev is defined + +- name: "Mount partitions" + ansible.posix.mount: + src: "{{ item.dev }}" + path: "{{ item.mount_path }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.fstab_opts | default('defaults') }}" + state: "mounted" + # Ignore mounting partitions without mount_path + when: not (item.mount_path is undefined) + # Ignore mounting swap partition as it's mounted using swapon + # Ignore partitions without mount_path + # Ensure the /mnt is mounted before /mnt/path (respect mount tree) + with_items: "{{ + partition_list + | difference([partition_swap]) + | rejectattr('mount_path', 'undefined') + | sort(attribute='mount_path') + }}" |
