334 lines
13 KiB
YAML
334 lines
13 KiB
YAML
---
|
|
- name: Ensure system input is a dictionary
|
|
ansible.builtin.set_fact:
|
|
system: "{{ system | default({}) }}"
|
|
changed_when: false
|
|
|
|
- name: Validate system input type
|
|
ansible.builtin.assert:
|
|
that:
|
|
- system is mapping
|
|
fail_msg: "system must be a dictionary"
|
|
quiet: true
|
|
|
|
- name: Reject deprecated top-level system selectors
|
|
ansible.builtin.assert:
|
|
that:
|
|
- os is not defined
|
|
- os_version is not defined
|
|
- hostname is not defined
|
|
fail_msg: >-
|
|
Top-level `os`, `os_version`, and `hostname` are not supported.
|
|
Define these values under `system` (`system.os`, `system.os_version`, `system.name`).
|
|
quiet: true
|
|
|
|
- name: Build normalized system configuration
|
|
vars:
|
|
system_raw: "{{ system_defaults | combine(system, recursive=True) }}"
|
|
system_type: "{{ system_raw.type | string | lower }}"
|
|
system_os_input: "{{ system_raw.os | default('') | string | lower }}"
|
|
system_name: >-
|
|
{{
|
|
system_raw.name | string
|
|
if (system_raw.name | default('') | string | length) > 0
|
|
else inventory_hostname
|
|
}}
|
|
|
|
system_dns_raw: "{{ system_raw.dns if system_raw.dns is mapping else {} }}"
|
|
system_dns_servers_input: "{{ system_dns_raw.servers | default([]) }}"
|
|
system_dns_search_input: "{{ system_dns_raw.search | default([]) }}"
|
|
|
|
system_user_raw: "{{ system_raw.user if system_raw.user is mapping else {} }}"
|
|
system_root_raw: "{{ system_raw.root if system_raw.root is mapping else {} }}"
|
|
system_luks_raw: "{{ system_raw.luks if system_raw.luks is mapping else {} }}"
|
|
system_features_raw: "{{ system_raw.features if system_raw.features is mapping else {} }}"
|
|
|
|
system_feature_cis_raw: >-
|
|
{{
|
|
system_features_raw.cis
|
|
if system_features_raw.cis is defined and system_features_raw.cis is mapping
|
|
else {}
|
|
}}
|
|
system_feature_selinux_raw: >-
|
|
{{
|
|
system_features_raw.selinux
|
|
if system_features_raw.selinux is defined and system_features_raw.selinux is mapping
|
|
else {}
|
|
}}
|
|
system_feature_firewall_raw: >-
|
|
{{
|
|
system_features_raw.firewall
|
|
if system_features_raw.firewall is defined and system_features_raw.firewall is mapping
|
|
else {}
|
|
}}
|
|
system_feature_ssh_raw: >-
|
|
{{
|
|
system_features_raw.ssh
|
|
if system_features_raw.ssh is defined and system_features_raw.ssh is mapping
|
|
else {}
|
|
}}
|
|
system_feature_zstd_raw: >-
|
|
{{
|
|
system_features_raw.zstd
|
|
if system_features_raw.zstd is defined and system_features_raw.zstd is mapping
|
|
else {}
|
|
}}
|
|
system_feature_swap_raw: >-
|
|
{{
|
|
system_features_raw.swap
|
|
if system_features_raw.swap is defined and system_features_raw.swap is mapping
|
|
else {}
|
|
}}
|
|
system_feature_banner_raw: >-
|
|
{{
|
|
system_features_raw.banner
|
|
if system_features_raw.banner is defined and system_features_raw.banner is mapping
|
|
else {}
|
|
}}
|
|
system_feature_chroot_raw: >-
|
|
{{
|
|
system_features_raw.chroot
|
|
if system_features_raw.chroot is defined and system_features_raw.chroot is mapping
|
|
else {}
|
|
}}
|
|
|
|
system_packages_input: "{{ system_raw.packages | default([]) }}"
|
|
ansible.builtin.set_fact:
|
|
system_cfg:
|
|
type: "{{ system_type }}"
|
|
os: "{{ system_os_input if system_os_input | length > 0 else ('archlinux' if system_type == 'physical' else '') }}"
|
|
os_version: "{{ system_raw.os_version | default('') | string }}"
|
|
name: "{{ system_name }}"
|
|
id: "{{ system_raw.id | default('') | string }}"
|
|
cpus: "{{ [system_raw.cpus | default(0) | int, 0] | max }}"
|
|
memory: "{{ [system_raw.memory | default(0) | int, 0] | max }}"
|
|
balloon: "{{ [system_raw.balloon | default(0) | int, 0] | max }}"
|
|
network: "{{ system_raw.network | default('') | string }}"
|
|
vlan: "{{ system_raw.vlan | default('') | string }}"
|
|
ip: "{{ system_raw.ip | default('') | string }}"
|
|
prefix: >-
|
|
{{
|
|
(system_raw.prefix | int)
|
|
if (system_raw.prefix | default('') | string | length) > 0
|
|
else ''
|
|
}}
|
|
gateway: "{{ system_raw.gateway | default('') | string }}"
|
|
dns:
|
|
servers: >-
|
|
{{
|
|
(
|
|
system_dns_servers_input
|
|
if system_dns_servers_input is iterable and system_dns_servers_input is not string
|
|
else (system_dns_servers_input | string).split(',')
|
|
)
|
|
| map('trim')
|
|
| reject('equalto', '')
|
|
| list
|
|
}}
|
|
search: >-
|
|
{{
|
|
(
|
|
system_dns_search_input
|
|
if system_dns_search_input is iterable and system_dns_search_input is not string
|
|
else (system_dns_search_input | string).split(',')
|
|
)
|
|
| map('trim')
|
|
| reject('equalto', '')
|
|
| list
|
|
}}
|
|
path: "{{ system_raw.path | default('') | string }}"
|
|
packages: >-
|
|
{{
|
|
(
|
|
system_packages_input
|
|
if system_packages_input is iterable and system_packages_input is not string
|
|
else (system_packages_input | string).split(',')
|
|
)
|
|
| map('trim')
|
|
| reject('equalto', '')
|
|
| list
|
|
}}
|
|
disks: "{{ system_raw.disks | default([]) }}"
|
|
user:
|
|
name: "{{ system_user_raw.name | default('') | string }}"
|
|
password: "{{ system_user_raw.password | default('') | string }}"
|
|
public_key: "{{ system_user_raw.public_key | default('') | string }}"
|
|
root:
|
|
password: "{{ system_root_raw.password | default('') | string }}"
|
|
luks:
|
|
enabled: "{{ system_luks_raw.enabled | default(system_defaults.luks.enabled) | bool }}"
|
|
passphrase: "{{ system_luks_raw.passphrase | default(system_defaults.luks.passphrase) | string }}"
|
|
mapper_name: "{{ system_luks_raw.mapper_name | default(system_defaults.luks.mapper_name) | string }}"
|
|
auto_decrypt: "{{ system_luks_raw.auto_decrypt | default(system_defaults.luks.auto_decrypt) | bool }}"
|
|
auto_decrypt_method: "{{ system_luks_raw.auto_decrypt_method | default(system_defaults.luks.auto_decrypt_method) | string | lower }}"
|
|
tpm2_device: "{{ system_luks_raw.tpm2_device | default(system_defaults.luks.tpm2_device) | string }}"
|
|
tpm2_pcrs: "{{ system_luks_raw.tpm2_pcrs | default(system_defaults.luks.tpm2_pcrs) | string }}"
|
|
keyfile_size: "{{ system_luks_raw.keyfile_size | default(system_defaults.luks.keyfile_size) | int }}"
|
|
options: "{{ system_luks_raw.options | default(system_defaults.luks.options) | string }}"
|
|
type: "{{ system_luks_raw.type | default(system_defaults.luks.type) | string }}"
|
|
cipher: "{{ system_luks_raw.cipher | default(system_defaults.luks.cipher) | string }}"
|
|
hash: "{{ system_luks_raw.hash | default(system_defaults.luks.hash) | string }}"
|
|
iter_time: "{{ system_luks_raw.iter_time | default(system_defaults.luks.iter_time) | int }}"
|
|
key_size: "{{ system_luks_raw.key_size | default(system_defaults.luks.key_size) | int }}"
|
|
pbkdf: "{{ system_luks_raw.pbkdf | default(system_defaults.luks.pbkdf) | string }}"
|
|
use_urandom: "{{ system_luks_raw.use_urandom | default(system_defaults.luks.use_urandom) | bool }}"
|
|
verify_passphrase: "{{ system_luks_raw.verify_passphrase | default(system_defaults.luks.verify_passphrase) | bool }}"
|
|
features:
|
|
cis:
|
|
enabled: "{{ system_feature_cis_raw.enabled | default(system_defaults.features.cis.enabled) | bool }}"
|
|
selinux:
|
|
enabled: "{{ system_feature_selinux_raw.enabled | default(system_defaults.features.selinux.enabled) | bool }}"
|
|
firewall:
|
|
enabled: "{{ system_feature_firewall_raw.enabled | default(system_defaults.features.firewall.enabled) | bool }}"
|
|
backend: "{{ system_feature_firewall_raw.backend | default(system_defaults.features.firewall.backend) | string | lower }}"
|
|
toolkit: "{{ system_feature_firewall_raw.toolkit | default(system_defaults.features.firewall.toolkit) | string | lower }}"
|
|
ssh:
|
|
enabled: "{{ system_feature_ssh_raw.enabled | default(system_defaults.features.ssh.enabled) | bool }}"
|
|
zstd:
|
|
enabled: "{{ system_feature_zstd_raw.enabled | default(system_defaults.features.zstd.enabled) | bool }}"
|
|
swap:
|
|
enabled: "{{ system_feature_swap_raw.enabled | default(system_defaults.features.swap.enabled) | bool }}"
|
|
banner:
|
|
motd: "{{ system_feature_banner_raw.motd | default(system_defaults.features.banner.motd) | bool }}"
|
|
sudo: "{{ system_feature_banner_raw.sudo | default(system_defaults.features.banner.sudo) | bool }}"
|
|
chroot:
|
|
tool: "{{ system_feature_chroot_raw.tool | default(system_defaults.features.chroot.tool) | string }}"
|
|
hostname: "{{ system_name }}"
|
|
os: "{{ system_os_input if system_os_input | length > 0 else ('archlinux' if system_type == 'physical' else '') }}"
|
|
os_version: "{{ system_raw.os_version | default('') | string }}"
|
|
changed_when: false
|
|
|
|
- name: Normalize system disks input
|
|
vars:
|
|
system_disks: "{{ system_cfg.disks | default([]) }}"
|
|
system_disk_defaults:
|
|
size: 0
|
|
device: ""
|
|
mount:
|
|
path: ""
|
|
fstype: ""
|
|
label: ""
|
|
opts: "defaults"
|
|
system_disk_letter_map: "abcdefghijklmnopqrstuvwxyz"
|
|
system_disk_device_prefix: >-
|
|
{{
|
|
'/dev/vd'
|
|
if system_cfg.type == 'virtual' and hypervisor_type == 'libvirt'
|
|
else (
|
|
'/dev/xvd'
|
|
if system_cfg.type == 'virtual' and hypervisor_type == 'xen'
|
|
else (
|
|
'/dev/sd'
|
|
if system_cfg.type == 'virtual' and hypervisor_type in ['proxmox', 'vmware']
|
|
else ''
|
|
)
|
|
)
|
|
}}
|
|
block:
|
|
- name: Validate system disks type
|
|
ansible.builtin.assert:
|
|
that:
|
|
- system_disks is sequence
|
|
fail_msg: "system.disks must be a list"
|
|
quiet: true
|
|
|
|
- name: Validate system disk items
|
|
ansible.builtin.assert:
|
|
that:
|
|
- item is mapping
|
|
fail_msg: "Each system disk entry must be a dictionary"
|
|
quiet: true
|
|
loop: "{{ system_disks }}"
|
|
loop_control:
|
|
label: "{{ item | to_json }}"
|
|
|
|
- name: Validate system disk mount schema
|
|
ansible.builtin.assert:
|
|
that:
|
|
- item.mount is not defined or item.mount is mapping
|
|
fail_msg: "system.disks[].mount must be a dictionary (e.g. mount: {path: /data})."
|
|
quiet: true
|
|
loop: "{{ system_disks }}"
|
|
loop_control:
|
|
label: "{{ item | to_json }}"
|
|
|
|
- name: Validate system disk count
|
|
ansible.builtin.assert:
|
|
that:
|
|
- (system_disks | length) <= 26
|
|
fail_msg: "system.disks supports at most 26 entries."
|
|
quiet: true
|
|
|
|
- name: Initialize normalized disk list
|
|
ansible.builtin.set_fact:
|
|
system_disks_cfg: []
|
|
changed_when: false
|
|
|
|
- name: Build normalized system disk configuration
|
|
vars:
|
|
disk_idx: "{{ ansible_loop.index0 }}"
|
|
disk_letter: "{{ system_disk_letter_map[disk_idx] }}"
|
|
disk_cfg_base: "{{ system_disk_defaults | combine(item, recursive=True) }}"
|
|
disk_mount: "{{ system_disk_defaults.mount | combine((disk_cfg_base.mount | default({})), recursive=True) }}"
|
|
disk_mount_path: "{{ (disk_mount.path | default('') | string) | trim }}"
|
|
disk_mount_fstype: >-
|
|
{{
|
|
disk_mount.fstype
|
|
if (disk_mount.fstype | default('') | string | length) > 0
|
|
else ('ext4' if disk_mount_path | length > 0 else '')
|
|
}}
|
|
disk_device: >-
|
|
{{
|
|
disk_cfg_base.device
|
|
if (disk_cfg_base.device | string | length) > 0
|
|
else (
|
|
(system_disk_device_prefix ~ disk_letter)
|
|
if system_cfg.type == 'virtual'
|
|
else ''
|
|
)
|
|
}}
|
|
disk_partition: >-
|
|
{{
|
|
disk_device ~ ('p1' if (disk_device | regex_search('\\d$')) else '1')
|
|
if disk_device | length > 0
|
|
else ''
|
|
}}
|
|
ansible.builtin.set_fact:
|
|
system_disks_cfg: >-
|
|
{{
|
|
system_disks_cfg + [
|
|
disk_cfg_base
|
|
| combine(
|
|
{
|
|
'device': disk_device,
|
|
'mount': {
|
|
'path': disk_mount_path,
|
|
'fstype': disk_mount_fstype,
|
|
'label': disk_mount.label | default('') | string,
|
|
'opts': disk_mount.opts | default('defaults') | string
|
|
},
|
|
'partition': disk_partition
|
|
},
|
|
recursive=True
|
|
)
|
|
]
|
|
}}
|
|
loop: "{{ system_disks }}"
|
|
loop_control:
|
|
loop_var: item
|
|
extended: true
|
|
label: "{{ item | to_json }}"
|
|
|
|
- name: Update system configuration with normalized disks
|
|
ansible.builtin.set_fact:
|
|
system_cfg: "{{ system_cfg | combine({'disks': system_disks_cfg}, recursive=True) }}"
|
|
changed_when: false
|
|
|
|
- name: Set install_drive from primary disk
|
|
when:
|
|
- system_disks_cfg | length > 0
|
|
- system_disks_cfg[0].device | string | length > 0
|
|
ansible.builtin.set_fact:
|
|
install_drive: "{{ system_disks_cfg[0].device }}"
|
|
changed_when: false
|