refactor(vars): add system/hypervisor dict inputs

This commit is contained in:
2026-02-11 05:37:18 +01:00
parent c4c96dbfb5
commit fc05708466
62 changed files with 2422 additions and 871 deletions

View File

@@ -2,44 +2,59 @@
all: all:
vars: vars:
install_type: "virtual" install_type: "virtual"
hypervisor: "proxmox" hypervisor:
type: "proxmox"
url: "pve01.example.com"
username: "root@pam"
password: "CHANGE_ME"
node: "pve01"
storage: "local-lvm"
install_drive: "/dev/sda" install_drive: "/dev/sda"
boot_iso: "local:iso/archlinux-x86_64.iso" boot_iso: "local:iso/archlinux-x86_64.iso"
vm_nif: "vmbr0"
children: children:
proxmox: proxmox:
hosts: hosts:
app01.example.com: app01.example.com:
ansible_host: 10.0.0.10 ansible_host: 10.0.0.10
hostname: "app01.example.com"
os: "archlinux" os: "archlinux"
filesystem: "btrfs" filesystem: "btrfs"
vm_id: 100 system:
vm_cpus: 2 name: "app01.example.com"
vm_memory: 4096 id: 100
vm_size: 40 cpus: 2
vm_ip: 10.0.0.10 memory_mb: 4096
vm_nms: 24 network: "vmbr0"
vm_gw: 10.0.0.1 ip: 10.0.0.10
vm_dns: prefix: 24
- 1.1.1.1 gateway: 10.0.0.1
- 1.0.0.1 dns_servers:
- 1.1.1.1
- 1.0.0.1
disks:
- size: 40
- size: 80
mount: /data
fstype: xfs
extra_packages: extra_packages:
- jq - jq
- tmux - tmux
db01.example.com: db01.example.com:
ansible_host: 10.0.0.11 ansible_host: 10.0.0.11
hostname: "db01.example.com" os: "rhel"
os: "rhel9" os_version: "9"
filesystem: "xfs" filesystem: "xfs"
vm_id: 101 system:
vm_cpus: 4 name: "db01.example.com"
vm_memory: 8192 id: 101
vm_size: 80 cpus: 4
vm_ip: 10.0.0.11 memory_mb: 8192
vm_nms: 24 network: "vmbr0"
vm_gw: 10.0.0.1 ip: 10.0.0.11
vm_dns: "1.1.1.1,1.0.0.1" prefix: 24
gateway: 10.0.0.1
dns_servers: "1.1.1.1,1.0.0.1"
disks:
- size: 80
rhel_iso: "local:iso/rhel-9.4-x86_64-dvd.iso" rhel_iso: "local:iso/rhel-9.4-x86_64-dvd.iso"
luks_enabled: true luks_enabled: true
luks_passphrase: "CHANGE_ME" luks_passphrase: "CHANGE_ME"
@@ -47,4 +62,4 @@ all:
luks_keyfile_size: 128 luks_keyfile_size: 128
cis: true cis: true
selinux: false selinux: false
firewalld_enabled: false firewall_enabled: false

View File

@@ -2,7 +2,8 @@
all: all:
vars: vars:
install_type: "virtual" install_type: "virtual"
hypervisor: "libvirt" hypervisor:
type: "libvirt"
install_drive: "/dev/vda" install_drive: "/dev/vda"
boot_iso: "/var/lib/libvirt/images/archlinux-x86_64.iso" boot_iso: "/var/lib/libvirt/images/archlinux-x86_64.iso"
children: children:
@@ -10,47 +11,55 @@ all:
hosts: hosts:
web01.example.com: web01.example.com:
ansible_host: 192.168.122.10 ansible_host: 192.168.122.10
hostname: "web01.example.com" os: "debian"
os: "debian12" os_version: "12"
filesystem: "ext4" filesystem: "ext4"
vm_cpus: 2 system:
vm_memory: 2048 name: "web01.example.com"
vm_size: 30 cpus: 2
vm_ip: 192.168.122.10 memory_mb: 2048
vm_nms: 24 ip: 192.168.122.10
vm_gw: 192.168.122.1 prefix: 24
vm_dns: 1.1.1.1 gateway: 192.168.122.1
dns_servers: 1.1.1.1
disks:
- size: 30
extra_packages: extra_packages:
- nginx - nginx
- fail2ban - fail2ban
vault01.example.com: vault01.example.com:
ansible_host: 192.168.122.11 ansible_host: 192.168.122.11
hostname: "vault01.example.com"
os: "ubuntu-lts" os: "ubuntu-lts"
filesystem: "btrfs" filesystem: "btrfs"
vm_cpus: 2 system:
vm_memory: 4096 name: "vault01.example.com"
vm_size: 40 cpus: 2
vm_ip: 192.168.122.11 memory_mb: 4096
vm_nms: 24 ip: 192.168.122.11
vm_gw: 192.168.122.1 prefix: 24
vm_dns_search: "example.com" gateway: 192.168.122.1
dns_search: "example.com"
disks:
- size: 40
luks_enabled: true luks_enabled: true
luks_passphrase: "CHANGE_ME" luks_passphrase: "CHANGE_ME"
luks_auto_decrypt_method: "keyfile" luks_auto_decrypt_method: "keyfile"
firewalld_enabled: false firewall_enabled: false
rhel9.example.com: rhel9.example.com:
ansible_host: 192.168.122.12 ansible_host: 192.168.122.12
hostname: "rhel9.example.com" os: "rhel"
os: "rhel9" os_version: "9"
filesystem: "xfs" filesystem: "xfs"
vm_cpus: 4 system:
vm_memory: 8192 name: "rhel9.example.com"
vm_size: 80 cpus: 4
vm_ip: 192.168.122.12 memory_mb: 8192
vm_nms: 24 vlan: "100"
vm_gw: 192.168.122.1 ip: 192.168.122.12
vm_dns: "1.1.1.1,1.0.0.1" prefix: 24
vm_path: "/srv/libvirt/images" gateway: 192.168.122.1
dns_servers: "1.1.1.1,1.0.0.1"
path: "/srv/libvirt/images"
disks:
- size: 80
rhel_iso: "/var/lib/libvirt/images/rhel-9.4-x86_64-dvd.iso" rhel_iso: "/var/lib/libvirt/images/rhel-9.4-x86_64-dvd.iso"
vlan_name: "100"

View File

@@ -1,7 +1,7 @@
--- ---
- name: Create and configure VMs - name: Create and configure VMs
hosts: all hosts: all
strategy: free # noqa: run-once[play] strategy: free # noqa: run-once[play]
gather_facts: false gather_facts: false
become: true become: true
vars_prompt: vars_prompt:
@@ -29,6 +29,10 @@
ansible.builtin.import_role: ansible.builtin.import_role:
name: global_defaults name: global_defaults
- name: Perform safety checks
ansible.builtin.import_role:
name: system_check
roles: roles:
- role: virtualization - role: virtualization
when: install_type == "virtual" when: install_type == "virtual"
@@ -62,7 +66,7 @@
post_reboot_can_connect: >- post_reboot_can_connect: >-
{{ {{
(ansible_connection | default('ssh')) != 'ssh' (ansible_connection | default('ssh')) != 'ssh'
or (vm_ip is defined and (vm_ip | string | length) > 0) or ((system_cfg.ip | default('') | string | length) > 0)
or ( or (
install_type == 'physical' install_type == 'physical'
and (ansible_host | default('') | string | length) > 0 and (ansible_host | default('') | string | length) > 0

View File

@@ -1,20 +1,35 @@
--- ---
- name: Bootstrap AlmaLinux 9 - name: Bootstrap AlmaLinux
vars: vars:
bootstrap_alma_extra: >- bootstrap_almalinux_extra: >-
{{ {{
lookup('vars', bootstrap_var_key) lookup('vars', bootstrap_var_key)
| reject('equalto', '') | reject('equalto', '')
| join(' ') | join(' ')
}} }}
ansible.builtin.command: "{{ item }}" block:
loop: - name: Install AlmaLinux base system
- >- ansible.builtin.command: >-
dnf --releasever=9 --best --repo=alma-baseos --installroot=/mnt dnf --releasever={{ os_version }} --best --repo=baseos --repo=appstream
--setopt=install_weak_deps=False groupinstall -y base core --installroot=/mnt --setopt=install_weak_deps=False
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf groupinstall -y core
- >- register: bootstrap_almalinux_base_result
{{ chroot_command }} /mnt dnf --releasever=9 --setopt=install_weak_deps=False changed_when: bootstrap_almalinux_base_result.rc == 0
install -y {{ bootstrap_alma_extra }}
register: bootstrap_result - name: Ensure chroot has resolv.conf
changed_when: bootstrap_result.rc == 0 ansible.builtin.file:
src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf
state: link
- name: Install extra packages
ansible.builtin.command: >-
{{ chroot_command }} dnf --releasever={{ os_version }} --setopt=install_weak_deps=False
install -y {{ bootstrap_almalinux_extra }}
register: bootstrap_almalinux_extra_result
changed_when: bootstrap_almalinux_extra_result.rc == 0
- name: Reinstall kernel core
ansible.builtin.command: "{{ chroot_command }} dnf reinstall -y kernel-core"
register: bootstrap_almalinux_kernel_result
changed_when: bootstrap_almalinux_kernel_result.rc == 0

View File

@@ -0,0 +1,33 @@
---
- name: Bootstrap Alpine Linux
vars:
bootstrap_alpine_packages: >-
{{
lookup('vars', 'bootstrap_alpine') | reject('equalto', '') | join(' ')
}}
block:
- name: Ensure chroot has resolv.conf
ansible.builtin.file:
src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf
state: link
force: true
- name: Install Alpine Linux packages
ansible.builtin.command: >
apk --root /mnt --no-cache add alpine-base
register: bootstrap_alpine_bootstrap_result
changed_when: bootstrap_alpine_bootstrap_result.rc == 0
- name: Install extra packages
when: bootstrap_alpine_packages | length > 0
ansible.builtin.command: >
apk --root /mnt add {{ bootstrap_alpine_packages }}
register: bootstrap_alpine_extra_result
changed_when: bootstrap_alpine_extra_result.rc == 0
- name: Install bootloader
ansible.builtin.command: >
apk --root /mnt add grub grub-efi efibootmgr
register: bootstrap_alpine_bootloader_result
changed_when: bootstrap_alpine_bootloader_result.rc == 0

View File

@@ -3,13 +3,27 @@
vars: vars:
bootstrap_debian_release: >- bootstrap_debian_release: >-
{{ {{
'bullseye' if bootstrap_os_key == 'debian11' 'buster' if (os_version | string) == '10'
else 'bookworm' if bootstrap_os_key == 'debian12' else 'bullseye' if (os_version | string) == '11'
else 'bookworm' if (os_version | string) == '12'
else 'trixie' if (os_version | string) == '13'
else 'sid' if (os_version | string) == 'unstable'
else 'trixie' else 'trixie'
}} }}
bootstrap_debian_base_list: "{{ lookup('vars', bootstrap_var_key).base | default([]) }}" bootstrap_debian_version_packages: >-
bootstrap_debian_extra_list: "{{ lookup('vars', bootstrap_var_key).extra | default([]) }}" {{
bootstrap_debian_base: "{{ bootstrap_debian_base_list | reject('equalto', '') | join(',') }}" lookup('vars', bootstrap_var_key)
| reject('equalto', '')
| list
}}
bootstrap_debian_base_list: >-
{{
bootstrap_debian_base
| reject('equalto', '')
| list
}}
bootstrap_debian_extra_list: "{{ bootstrap_debian_version_packages | difference(bootstrap_debian_base_list) }}"
bootstrap_debian_base: "{{ bootstrap_debian_base_list | join(',') }}"
bootstrap_debian_extra: >- bootstrap_debian_extra: >-
{{ {{
( (
@@ -18,12 +32,20 @@
| reject('equalto', '') | reject('equalto', '')
| join(' ') | join(' ')
}} }}
ansible.builtin.command: "{{ item }}" block:
loop: - name: Install Debian base system
- >- ansible.builtin.command: >-
debootstrap --include={{ bootstrap_debian_base }} debootstrap --include={{ bootstrap_debian_base }}
{{ bootstrap_debian_release }} /mnt http://deb.debian.org/debian/ {{ bootstrap_debian_release }} /mnt http://deb.debian.org/debian/
- "{{ chroot_command }} /mnt apt install -y {{ bootstrap_debian_extra }}" register: bootstrap_debian_base_result
- "{{ chroot_command }} /mnt apt remove -y libcups2 libavahi-common3 libavahi-common-data" changed_when: bootstrap_debian_base_result.rc == 0
register: bootstrap_result
changed_when: bootstrap_result.rc == 0 - name: Install extra packages
ansible.builtin.command: "{{ chroot_command }} apt install -y {{ bootstrap_debian_extra }}"
register: bootstrap_debian_extra_result
changed_when: bootstrap_debian_extra_result.rc == 0
- name: Remove unnecessary packages
ansible.builtin.command: "{{ chroot_command }} apt remove -y libcups2 libavahi-common3 libavahi-common-data"
register: bootstrap_debian_remove_result
changed_when: bootstrap_debian_remove_result.rc == 0

View File

@@ -1,5 +1,5 @@
--- ---
- name: Bootstrap Fedora 43 - name: Bootstrap Fedora
vars: vars:
bootstrap_fedora_extra: >- bootstrap_fedora_extra: >-
{{ {{
@@ -7,16 +7,29 @@
| reject('equalto', '') | reject('equalto', '')
| join(' ') | join(' ')
}} }}
ansible.builtin.command: "{{ item }}" block:
loop: - name: Install Fedora base system
- >- ansible.builtin.command: >-
dnf --releasever=43 --best --repo=fedora --repo=fedora-updates dnf --releasever={{ os_version }} --best --repo=fedora --repo=fedora-updates
--installroot=/mnt --setopt=install_weak_deps=False --installroot=/mnt --setopt=install_weak_deps=False
groupinstall -y critical-path-base core groupinstall -y critical-path-base core
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf register: bootstrap_fedora_base_result
- >- changed_when: bootstrap_fedora_base_result.rc == 0
{{ chroot_command }} /mnt dnf --releasever=43 --setopt=install_weak_deps=False
- name: Ensure chroot has resolv.conf
ansible.builtin.file:
src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf
state: link
- name: Install extra packages
ansible.builtin.command: >-
{{ chroot_command }} dnf --releasever={{ os_version }} --setopt=install_weak_deps=False
install -y {{ bootstrap_fedora_extra }} install -y {{ bootstrap_fedora_extra }}
- "{{ chroot_command }} /mnt dnf reinstall -y kernel-core" register: bootstrap_fedora_extra_result
register: bootstrap_result changed_when: bootstrap_fedora_extra_result.rc == 0
changed_when: bootstrap_result.rc == 0
- name: Reinstall kernel core
ansible.builtin.command: "{{ chroot_command }} dnf reinstall -y kernel-core"
register: bootstrap_fedora_kernel_result
changed_when: bootstrap_fedora_kernel_result.rc == 0

View File

@@ -1,27 +1,35 @@
--- ---
- name: Run OS-specific bootstrap process - name: Run OS-specific bootstrap process
vars: vars:
bootstrap_os_key: "{{ os | lower }}" bootstrap_os_key: "{{ (os_resolved | default(os)) | lower }}"
bootstrap_var_key: "{{ 'bootstrap_' + (os | lower | replace('-', '_')) }}" bootstrap_var_key: "{{ 'bootstrap_' + ((os_resolved | default(os)) | lower | replace('-', '_')) }}"
block: block:
- name: Include AlmaLinux bootstrap tasks - name: Include AlmaLinux bootstrap tasks
when: bootstrap_os_key == 'almalinux' when: bootstrap_os_key in ['almalinux', 'almalinux8', 'almalinux9', 'almalinux10']
ansible.builtin.include_tasks: almalinux.yml ansible.builtin.include_tasks: almalinux.yml
- name: Include Alpine bootstrap tasks
when: bootstrap_os_key == 'alpine'
ansible.builtin.include_tasks: alpine.yml
- name: Include ArchLinux bootstrap tasks - name: Include ArchLinux bootstrap tasks
when: bootstrap_os_key == 'archlinux' when: bootstrap_os_key == 'archlinux'
ansible.builtin.include_tasks: archlinux.yml ansible.builtin.include_tasks: archlinux.yml
- name: Include Debian bootstrap tasks - name: Include Debian bootstrap tasks
when: bootstrap_os_key in ['debian11', 'debian12', 'debian13'] when: bootstrap_os_key in ['debian10', 'debian11', 'debian12', 'debian13', 'debianunstable']
ansible.builtin.include_tasks: debian.yml ansible.builtin.include_tasks: debian.yml
- name: Include Fedora bootstrap tasks - name: Include Fedora bootstrap tasks
when: bootstrap_os_key == 'fedora' when: bootstrap_os_key in ['fedora', 'fedora40', 'fedora41', 'fedora42', 'fedora43']
ansible.builtin.include_tasks: fedora.yml ansible.builtin.include_tasks: fedora.yml
- name: Include openSUSE bootstrap tasks
when: bootstrap_os_key == 'opensuse'
ansible.builtin.include_tasks: opensuse.yml
- name: Include Rocky bootstrap tasks - name: Include Rocky bootstrap tasks
when: bootstrap_os_key == 'rocky' when: bootstrap_os_key in ['rocky', 'rocky8', 'rocky9', 'rocky10']
ansible.builtin.include_tasks: rocky.yml ansible.builtin.include_tasks: rocky.yml
- name: Include RHEL bootstrap tasks - name: Include RHEL bootstrap tasks
@@ -31,3 +39,7 @@
- name: Include Ubuntu bootstrap tasks - name: Include Ubuntu bootstrap tasks
when: bootstrap_os_key in ['ubuntu', 'ubuntu-lts'] when: bootstrap_os_key in ['ubuntu', 'ubuntu-lts']
ansible.builtin.include_tasks: ubuntu.yml ansible.builtin.include_tasks: ubuntu.yml
- name: Include Void bootstrap tasks
when: bootstrap_os_key == 'void'
ansible.builtin.include_tasks: void.yml

View File

@@ -0,0 +1,33 @@
---
- name: Bootstrap openSUSE
vars:
bootstrap_opensuse_packages: >-
{{
lookup('vars', 'bootstrap_opensuse') | reject('equalto', '') | join(' ')
}}
block:
- name: Ensure chroot has resolv.conf
ansible.builtin.file:
src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf
state: link
force: true
- name: Install openSUSE base packages
ansible.builtin.command: >
zypper --root /mnt --non-interactive install -t pattern patterns-base-base
register: bootstrap_opensuse_base_result
changed_when: bootstrap_opensuse_base_result.rc == 0
- name: Install openSUSE extra packages
when: bootstrap_opensuse_packages | length > 0
ansible.builtin.command: >
zypper --root /mnt --non-interactive install {{ bootstrap_opensuse_packages }}
register: bootstrap_opensuse_extra_result
changed_when: bootstrap_opensuse_extra_result.rc == 0
- name: Install bootloader
ansible.builtin.command: >
zypper --root /mnt --non-interactive install grub2 grub2-efi efibootmgr
register: bootstrap_opensuse_bootloader_result
changed_when: bootstrap_opensuse_bootloader_result.rc == 0

View File

@@ -17,7 +17,6 @@
src: /run/NetworkManager/resolv.conf src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf dest: /mnt/etc/resolv.conf
state: link state: link
force: true
- name: Ensure chroot RHEL DVD directory exists - name: Ensure chroot RHEL DVD directory exists
ansible.builtin.file: ansible.builtin.file:
@@ -34,7 +33,7 @@
state: mounted state: mounted
- name: Rebuild RPM database inside chroot - name: Rebuild RPM database inside chroot
ansible.builtin.command: "{{ chroot_command }} /mnt rpm --rebuilddb" ansible.builtin.command: "{{ chroot_command }} rpm --rebuilddb"
register: bootstrap_rpm_rebuild_result register: bootstrap_rpm_rebuild_result
changed_when: bootstrap_rpm_rebuild_result.rc == 0 changed_when: bootstrap_rpm_rebuild_result.rc == 0
@@ -55,7 +54,7 @@
| join(' ') | join(' ')
}} }}
ansible.builtin.command: >- ansible.builtin.command: >-
{{ chroot_command }} /mnt dnf --releasever={{ bootstrap_rhel_release }} {{ chroot_command }} dnf --releasever={{ bootstrap_rhel_release }}
--setopt=install_weak_deps=False install -y {{ bootstrap_rhel_extra }} --setopt=install_weak_deps=False install -y {{ bootstrap_rhel_extra }}
register: bootstrap_result register: bootstrap_result
changed_when: bootstrap_result.rc == 0 changed_when: bootstrap_result.rc == 0

View File

@@ -1,5 +1,5 @@
--- ---
- name: Bootstrap RockyLinux 9 - name: Bootstrap Rocky Linux
vars: vars:
bootstrap_rocky_extra: >- bootstrap_rocky_extra: >-
{{ {{
@@ -7,15 +7,29 @@
| reject('equalto', '') | reject('equalto', '')
| join(' ') | join(' ')
}} }}
ansible.builtin.command: "{{ item }}" block:
loop: - name: Install Rocky Linux base system
- >- ansible.builtin.command: >-
dnf --releasever=9 --best --repo=rocky-baseos --installroot=/mnt dnf --releasever={{ os_version }} --best --repo=baseos --repo=appstream
--setopt=install_weak_deps=False --setopt=optional_metadata_types=filelists --installroot=/mnt --setopt=install_weak_deps=False
groupinstall -y base core groupinstall -y core
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf register: bootstrap_rocky_base_result
- >- changed_when: bootstrap_rocky_base_result.rc == 0
{{ chroot_command }} /mnt dnf --releasever=9 --setopt=install_weak_deps=False
- name: Ensure chroot has resolv.conf
ansible.builtin.file:
src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf
state: link
- name: Install extra packages
ansible.builtin.command: >-
{{ chroot_command }} dnf --releasever={{ os_version }} --setopt=install_weak_deps=False
install -y {{ bootstrap_rocky_extra }} install -y {{ bootstrap_rocky_extra }}
register: bootstrap_result register: bootstrap_rocky_extra_result
changed_when: bootstrap_result.rc == 0 changed_when: bootstrap_rocky_extra_result.rc == 0
- name: Reinstall kernel core
ansible.builtin.command: "{{ chroot_command }} dnf reinstall -y kernel-core"
register: bootstrap_rocky_kernel_result
changed_when: bootstrap_rocky_kernel_result.rc == 0

View File

@@ -3,25 +3,38 @@
vars: vars:
bootstrap_ubuntu_release: >- bootstrap_ubuntu_release: >-
{{ 'plucky' if bootstrap_os_key == 'ubuntu' else 'noble' }} {{ 'plucky' if bootstrap_os_key == 'ubuntu' else 'noble' }}
bootstrap_ubuntu_base_list: "{{ lookup('vars', bootstrap_var_key).base | default([]) }}"
bootstrap_ubuntu_extra_list: "{{ lookup('vars', bootstrap_var_key).extra | default([]) }}"
bootstrap_ubuntu_base: "{{ bootstrap_ubuntu_base_list | reject('equalto', '') | join(',') }}"
bootstrap_ubuntu_extra: >- bootstrap_ubuntu_extra: >-
{{ {{
( lookup('vars', bootstrap_var_key)
bootstrap_ubuntu_extra_list
)
| reject('equalto', '') | reject('equalto', '')
| join(' ') | join(' ')
}} }}
ansible.builtin.command: "{{ item }}" block:
loop: - name: Install Ubuntu base system
- >- ansible.builtin.command: >-
debootstrap --include={{ bootstrap_ubuntu_base }} debootstrap --include=linux-image-generic
{{ bootstrap_ubuntu_release }} /mnt http://archive.ubuntu.com/ubuntu/ {{ bootstrap_ubuntu_release }} /mnt
- ln -sf /run/NetworkManager/resolv.conf /mnt/etc/resolv.conf http://archive.ubuntu.com/ubuntu/
- "{{ chroot_command }} /mnt sed -i '1s|$| universe|' /etc/apt/sources.list" register: bootstrap_ubuntu_base_result
- "{{ chroot_command }} /mnt apt update" changed_when: bootstrap_ubuntu_base_result.rc == 0
- "{{ chroot_command }} /mnt apt install -y {{ bootstrap_ubuntu_extra }}"
register: bootstrap_result - name: Ensure chroot has resolv.conf
changed_when: bootstrap_result.rc == 0 ansible.builtin.file:
src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf
state: link
- name: Enable universe repository
ansible.builtin.command: "{{ chroot_command }} sed -i '1s|$| universe|' /etc/apt/sources.list"
register: bootstrap_ubuntu_repo_result
changed_when: bootstrap_ubuntu_repo_result.rc == 0
- name: Update package lists
ansible.builtin.command: "{{ chroot_command }} apt update"
register: bootstrap_ubuntu_update_result
changed_when: bootstrap_ubuntu_update_result.rc == 0
- name: Install extra packages
ansible.builtin.command: "{{ chroot_command }} apt install -y {{ bootstrap_ubuntu_extra }}"
register: bootstrap_ubuntu_extra_result
changed_when: bootstrap_ubuntu_extra_result.rc == 0

View File

@@ -0,0 +1,33 @@
---
- name: Bootstrap Void Linux
vars:
bootstrap_void_packages: >-
{{
lookup('vars', 'bootstrap_void') | reject('equalto', '') | join(' ')
}}
block:
- name: Ensure chroot has resolv.conf
ansible.builtin.file:
src: /run/NetworkManager/resolv.conf
dest: /mnt/etc/resolv.conf
state: link
force: true
- name: Install Void Linux base packages
ansible.builtin.command: >
xbps-install -Sy -r /mnt -R https://repo-default.voidlinux.org/current void-repo-nonfree base-system
register: bootstrap_void_base_result
changed_when: bootstrap_void_base_result.rc == 0
- name: Install extra packages
when: bootstrap_void_packages | length > 0
ansible.builtin.command: >
xbps-install -Su -r /mnt {{ bootstrap_void_packages }}
register: bootstrap_void_extra_result
changed_when: bootstrap_void_extra_result.rc == 0
- name: Install bootloader
ansible.builtin.command: >
xbps-install -Sy -r /mnt grub-x86_64-efi efibootmgr
register: bootstrap_void_bootloader_result
changed_when: bootstrap_void_bootloader_result.rc == 0

View File

@@ -1,21 +1,20 @@
--- ---
bootstrap_almalinux: bootstrap_rhel_base:
- bind-utils - bind-utils
- dbus-daemon
- dhcp-client - dhcp-client
- efibootmgr - efibootmgr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}" - "{{ 'firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}"
- "{{ 'ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}"
- "{{ 'iptables' if firewall_toolkit == 'iptables' else '' }}"
- "{{ 'nftables' if firewall_toolkit == 'nftables' else '' }}"
- glibc-langpack-de - glibc-langpack-de
- glibc-langpack-en - glibc-langpack-en
- grub2
- grub2-efi
- lrzsz - lrzsz
- lvm2 - lvm2
- nc
- nfs-utils
- nfsv4-client-utils
- mtr - mtr
- ppp - ncurses-term
- nfs-utils
- policycoreutils-python-utils
- shim - shim
- tmux - tmux
- "{{ 'cryptsetup' if luks_enabled else '' }}" - "{{ 'cryptsetup' if luks_enabled else '' }}"
@@ -23,10 +22,162 @@ bootstrap_almalinux:
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}" - "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}" - "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim - vim
- wget
- zram-generator - zram-generator
- zstd - zstd
bootstrap_rhel_versioned:
- grub2
- "{{ 'grub2-efi-x64' if os_version_major | default('') == '8' else 'grub2-efi' }}"
- "{{ 'grub2-tools-extra' if os_version_major | default('') in ['8', '9'] else '' }}"
- "{{ 'python39' if os_version_major | default('') == '8' else 'python' }}"
- "{{ 'kernel' if os_version_major | default('') == '10' else '' }}"
bootstrap_rhel_common: "{{ bootstrap_rhel_base + bootstrap_rhel_versioned }}"
bootstrap_rhel8: "{{ bootstrap_rhel_common }}"
bootstrap_rhel9: "{{ bootstrap_rhel_common }}"
bootstrap_rhel10: "{{ bootstrap_rhel_common }}"
bootstrap_almalinux:
"{{ bootstrap_rhel_base + ['grub2', 'grub2-efi', 'dbus-daemon', 'lrzsz', 'nfsv4-client-utils', 'nc', 'ppp'] }}"
bootstrap_rocky:
"{{ bootstrap_rhel_base + ['grub2', 'grub2-efi', 'nfsv4-client-utils', 'nc', 'ppp', 'telnet', 'util-linux-core', 'wget'] }}"
bootstrap_almalinux8: "{{ bootstrap_almalinux }}"
bootstrap_almalinux9: "{{ bootstrap_almalinux }}"
bootstrap_almalinux10: "{{ bootstrap_almalinux }}"
bootstrap_rocky8: "{{ bootstrap_rocky }}"
bootstrap_rocky9: "{{ bootstrap_rocky }}"
bootstrap_rocky10: "{{ bootstrap_rocky }}"
bootstrap_fedora:
- bat
- bind-utils
- btrfs-progs
- cronie
- dhcp-client
- duf
- efibootmgr
- entr
- "{{ 'firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}"
- "{{ 'ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}"
- "{{ 'iptables' if firewall_toolkit == 'iptables' else '' }}"
- "{{ 'nftables' if firewall_toolkit == 'nftables' else '' }}"
- fish
- fzf
- glibc-langpack-de
- glibc-langpack-en
- grub2
- grub2-efi
- htop
- iperf3
- logrotate
- lrzsz
- lvm2
- nc
- nfs-utils
- nfsv4-client-utils
- polkit
- ppp
- ripgrep
- shim
- tmux
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim-default-editor
- wget
- zoxide
- zram-generator
- zstd
bootstrap_fedora40: "{{ bootstrap_fedora }}"
bootstrap_fedora41: "{{ bootstrap_fedora }}"
bootstrap_fedora42: "{{ bootstrap_fedora }}"
bootstrap_fedora43: "{{ bootstrap_fedora }}"
bootstrap_debian_base:
- btrfs-progs
- cron
- gnupg
- grub-efi
- grub-efi-amd64-signed
- grub2-common
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
- locales
- logrotate
- lvm2
- "{{ 'iptables' if firewall_toolkit == 'iptables' else '' }}"
- "{{ 'nftables' if firewall_toolkit == 'nftables' else '' }}"
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
- python3
- xfsprogs
bootstrap_debian_extra:
- apparmor-utils
- bat
- chrony
- curl
- duf
- entr
- "{{ 'firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}"
- "{{ 'ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}"
- fish
- fzf
- htop
- jq
- libpam-pwquality
- lrzsz
- mtr
- ncdu
- net-tools
- network-manager
- python-is-python3
- ripgrep
- rsync
- screen
- software-properties-common
- sudo
- syslog-ng
- systemd-zram-generator
- tcpd
- tldr
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim
- wget
- zstd
bootstrap_debian_versioned:
- "{{ 'linux-image-amd64' if (os_version | string) in ['10', '11', '13', 'unstable'] else '' }}"
- "{{ 'fastfetch' if (os_version | string) in ['12', '13', 'unstable'] else '' }}"
- "{{ 'neofetch' if (os_version | string) == '12' else '' }}"
bootstrap_debian_common: "{{ bootstrap_debian_base + bootstrap_debian_extra + bootstrap_debian_versioned }}"
bootstrap_debian10: "{{ bootstrap_debian_common }}"
bootstrap_debian11: "{{ bootstrap_debian_common }}"
bootstrap_debian12: "{{ bootstrap_debian_common }}"
bootstrap_debian13: "{{ bootstrap_debian_common }}"
bootstrap_debianunstable: "{{ bootstrap_debian_common }}"
bootstrap_ubuntu:
"{{
bootstrap_debian_base + bootstrap_debian_extra +
['bash-completion', 'dnsutils', 'eza', 'fdupes', 'fio', 'ncurses-term', 'traceroute', 'util-linux-extra', 'yq', 'zoxide']
}}"
bootstrap_ubuntu_lts:
"{{
bootstrap_debian_base + bootstrap_debian_extra +
['bash-completion', 'dnsutils', 'eza', 'fdupes', 'fio', 'ncurses-term', 'traceroute', 'util-linux-extra', 'yq', 'zoxide']
}}"
bootstrap_archlinux: bootstrap_archlinux:
- base - base
- btrfs-progs - btrfs-progs
@@ -34,7 +185,10 @@ bootstrap_archlinux:
- dhcpcd - dhcpcd
- efibootmgr - efibootmgr
- fastfetch - fastfetch
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}" - "{{ 'firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}"
- "{{ 'ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}"
- "{{ 'iptables' if firewall_toolkit == 'iptables' else '' }}"
- "{{ 'iptables-nft' if firewall_toolkit == 'nftables' else '' }}"
- fish - fish
- fzf - fzf
- grub - grub
@@ -65,436 +219,39 @@ bootstrap_archlinux:
- wireguard-tools - wireguard-tools
- zram-generator - zram-generator
bootstrap_debian11: bootstrap_alpine:
base: - alpine-base
- apparmor-utils
- btrfs-progs
- chrony
- cron
- gnupg
- grub-efi
- grub-efi-amd64-signed
- grub2-common
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
- linux-image-amd64
- locales
- logrotate
- lvm2
- net-tools
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
- python3
- sudo
- xfsprogs
extra:
- bat
- curl
- entr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- fish
- fzf
- htop
- jq
- libpam-pwquality
- lrzsz
- mtr
- ncdu
- neofetch
- network-manager
- python-is-python3
- ripgrep
- rsync
- screen
- software-properties-common
- syslog-ng
- tcpd
- tldr
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim
- wget
- zstd
bootstrap_debian12:
base:
- btrfs-progs
- cron
- gnupg
- grub-efi
- grub-efi-amd64-signed
- grub2-common
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
- linux-image-amd64
- locales
- logrotate
- lvm2
- xfsprogs
extra:
- apparmor-utils
- bat
- chrony
- curl
- duf
- entr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- fish
- fzf
- htop
- jq
- libpam-pwquality
- logrotate
- lrzsz
- mtr
- ncdu
- neofetch
- net-tools
- network-manager
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
- python-is-python3
- python3
- ripgrep
- rsync
- screen
- software-properties-common
- sudo
- syslog-ng
- systemd-zram-generator
- tcpd
- tldr
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim
- wget
- zstd
bootstrap_debian13:
base:
- btrfs-progs
- cron
- gnupg
- grub-efi
- grub-efi-amd64-signed
- grub2-common
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
- linux-image-amd64
- locales
- logrotate
- lvm2
- xfsprogs
extra:
- apparmor-utils
- bat
- chrony
- curl
- duf
- entr
- fastfetch
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- fish
- fzf
- htop
- jq
- libpam-pwquality
- logrotate
- lrzsz
- mtr
- ncdu
- net-tools
- network-manager
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
- python-is-python3
- python3
- ripgrep
- rsync
- screen
- sudo
- syslog-ng
- systemd-zram-generator
- tcpd
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim
- wget
- zstd
bootstrap_fedora:
- bat
- bind-utils
- btrfs-progs
- cronie
- dhcp-client
- duf
- efibootmgr
- entr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- fish
- fzf
- glibc-langpack-de
- glibc-langpack-en
- grub2
- grub2-efi
- htop
- iperf3
- logrotate
- lrzsz
- lvm2
- nc
- nfs-utils
- nfsv4-client-utils
- polkit
- ppp
- ripgrep
- shim
- tmux
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim-default-editor
- wget
- zoxide
- zram-generator
- zstd
bootstrap_rhel8:
- bind-utils
- dhcp-client
- efibootmgr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- glibc-langpack-de
- glibc-langpack-en
- grub2
- grub2-efi-x64
- grub2-tools-extra
- lrzsz
- lvm2
- mtr
- ncurses-term
- nfs-utils
- policycoreutils-python-utils
- python39
- shim
- tmux
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim - vim
- zstd - "{{ 'openssh' if ssh_enabled | bool else '' }}"
bootstrap_rhel9:
- bind-utils
- dhcp-client
- efibootmgr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- glibc-langpack-de
- glibc-langpack-en
- grub2
- grub2-efi
- grub2-tools-extra
- lrzsz
- lvm2
- mtr
- ncurses-term
- nfs-utils
- policycoreutils-python-utils
- python
- shim
- tmux
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}" - "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}" - "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim - "{{ 'firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}"
- zram-generator - "{{ 'ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}"
- zstd - "{{ 'iptables' if firewall_toolkit == 'iptables' else '' }}"
- "{{ 'nftables' if firewall_toolkit == 'nftables' else '' }}"
bootstrap_rhel10:
- bind-utils
- efibootmgr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- glibc-langpack-de
- glibc-langpack-en
- grub2
- grub2-efi
- kernel
- lrzsz
- lvm2
- mtr
- ncurses-term
- nfs-utils
- policycoreutils-python-utils
- python
- shim
- tmux
- "{{ 'cryptsetup' if luks_enabled else '' }}" - "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'tpm2-tools' if luks_enabled else '' }}" - "{{ 'tpm2-tools' if luks_enabled else '' }}"
bootstrap_opensuse:
- vim
- "{{ 'openssh' if ssh_enabled | bool else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}" - "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}" - "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- vim - "{{ 'firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}"
- zram-generator - "{{ 'ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}"
- zstd - "{{ 'iptables' if firewall_toolkit == 'iptables' else '' }}"
- "{{ 'nftables' if firewall_toolkit == 'nftables' else '' }}"
bootstrap_rocky:
- bind-utils
- dbus-daemon
- dhcp-client
- efibootmgr
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- glibc-langpack-de
- glibc-langpack-en
- grub2
- grub2-efi
- lrzsz
- lvm2
- mtr
- nc
- nfs-utils
- nfsv4-client-utils
- ppp
- shim
- telnet
- tmux
- "{{ 'cryptsetup' if luks_enabled else '' }}" - "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'tpm2-tools' if luks_enabled else '' }}" - "{{ 'tpm2-tools' if luks_enabled else '' }}"
bootstrap_void:
- vim
- "{{ 'openssh' if ssh_enabled | bool else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}" - "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}" - "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- util-linux-core - "{{ 'firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}"
- vim - "{{ 'ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}"
- wget - "{{ 'iptables' if firewall_toolkit == 'iptables' else '' }}"
- zram-generator - "{{ 'nftables' if firewall_toolkit == 'nftables' else '' }}"
- zstd - "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
bootstrap_ubuntu:
base:
- btrfs-progs
- cron
- gnupg
- grub-efi
- grub-efi-amd64-signed
- grub2-common
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
- linux-image-generic
- locales
- lvm2
- xfsprogs
extra:
- apparmor-utils
- bash-completion
- bat
- chrony
- curl
- dnsutils
- duf
- entr
- eza
- fdupes
- fio
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- fish
- htop
- jq
- libpam-pwquality
- logrotate
- lrzsz
- mtr
- ncdu
- ncurses-term
- net-tools
- network-manager
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
- python-is-python3
- python3
- ripgrep
- rsync
- screen
- software-properties-common
- sudo
- syslog-ng
- systemd-zram-generator
- tcpd
- tldr
- tmux
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- traceroute
- util-linux-extra
- vim
- wget
- yq
- zoxide
- zstd
bootstrap_ubuntu_lts:
base:
- btrfs-progs
- cron
- gnupg
- grub-efi
- grub-efi-amd64-signed
- grub2-common
- "{{ 'cryptsetup' if luks_enabled else '' }}"
- "{{ 'cryptsetup-initramfs' if luks_enabled else '' }}"
- linux-image-generic
- locales
- lvm2
- xfsprogs
extra:
- apparmor-utils
- bash-completion
- bat
- chrony
- curl
- dnsutils
- duf
- entr
- eza
- fdupes
- fio
- "{{ 'firewalld' if firewalld_enabled | bool else '' }}"
- fish
- htop
- jq
- libpam-pwquality
- logrotate
- lrzsz
- mtr
- ncdu
- ncurses-term
- net-tools
- network-manager
- "{{ 'openssh-server' if ssh_enabled | bool else '' }}"
- python-is-python3
- python3
- ripgrep
- rsync
- screen
- software-properties-common
- sudo
- syslog-ng
- systemd-zram-generator
- tcpd
- tldr
- tmux
- "{{ 'tpm2-tools' if luks_enabled else '' }}"
- "{{ 'qemu-guest-agent' if hypervisor | lower in ['libvirt', 'proxmox'] else '' }}"
- "{{ 'open-vm-tools' if hypervisor | lower == 'vmware' else '' }}"
- traceroute
- util-linux-extra
- vim
- wget
- yq
- zoxide
- zstd

View File

@@ -10,12 +10,12 @@ cis_permission_targets: >-
{ "path": "/mnt/etc/cron.d", "mode": "0700" }, { "path": "/mnt/etc/cron.d", "mode": "0700" },
{ "path": "/mnt/etc/crontab", "mode": "0600" }, { "path": "/mnt/etc/crontab", "mode": "0600" },
{ "path": "/mnt/etc/logrotate.conf", "mode": "0644" }, { "path": "/mnt/etc/logrotate.conf", "mode": "0644" },
{ "path": "/mnt/usr/sbin/pppd", "mode": "0754" } if os not in ["rhel8", "rhel9", "rhel10"] else None, { "path": "/mnt/usr/sbin/pppd", "mode": "0754" } if os != "rhel" else None,
{ {
"path": "/mnt/usr/bin/" "path": "/mnt/usr/bin/"
+ ("fusermount3" if os in ["archlinux", "debian12", "fedora", "rhel9", "rhel10", "rocky"] else "fusermount"), + ("fusermount3" if os in ["archlinux", "fedora", "rocky"] or os == "rhel" or (os == "debian" and (os_version | string) == "12") else "fusermount"),
"mode": "755" "mode": "755"
}, },
{ "path": "/mnt/usr/bin/" + ("write.ul" if os == "debian11" else "write"), "mode": "755" } { "path": "/mnt/usr/bin/" + ("write.ul" if os == "debian" and (os_version | string) == "11" else "write"), "mode": "755" }
] | reject("none") ] | reject("none")
}} }}

View File

@@ -1,12 +1,12 @@
--- ---
- name: Configure System Cryptography Policy - name: Configure System Cryptography Policy
when: os in ["almalinux", "rhel9", "rhel10", "rocky"] when: os == "rhel" or os in ["almalinux", "rocky"]
ansible.builtin.command: "{{ chroot_command }} /mnt /usr/bin/update-crypto-policies --set DEFAULT:NO-SHA1" ansible.builtin.command: "{{ chroot_command }} /usr/bin/update-crypto-policies --set DEFAULT:NO-SHA1"
register: cis_crypto_policy_result register: cis_crypto_policy_result
changed_when: "'Setting system-wide crypto-policies to' in cis_crypto_policy_result.stdout" changed_when: "'Setting system-wide crypto-policies to' in cis_crypto_policy_result.stdout"
- name: Mask Systemd Services - name: Mask Systemd Services
ansible.builtin.command: > ansible.builtin.command: >
{{ chroot_command }} /mnt systemctl mask nftables bluetooth rpcbind {{ chroot_command }} systemctl mask {{ 'nftables' if firewall_toolkit == 'iptables' else 'iptables' }} bluetooth rpcbind
register: cis_mask_services_result register: cis_mask_services_result
changed_when: cis_mask_services_result.rc == 0 changed_when: cis_mask_services_result.rc == 0

View File

@@ -4,21 +4,21 @@
path: "{{ item.path }}" path: "{{ item.path }}"
line: "{{ item.content }}" line: "{{ item.content }}"
loop: loop:
- {path: /mnt/etc/security/limits.conf, content: "* hard core 0"} - { path: /mnt/etc/security/limits.conf, content: "* hard core 0" }
- {path: /mnt/etc/security/pwquality.conf, content: minlen = 14} - { path: /mnt/etc/security/pwquality.conf, content: minlen = 14 }
- {path: /mnt/etc/security/pwquality.conf, content: dcredit = -1} - { path: /mnt/etc/security/pwquality.conf, content: dcredit = -1 }
- {path: /mnt/etc/security/pwquality.conf, content: ucredit = -1} - { path: /mnt/etc/security/pwquality.conf, content: ucredit = -1 }
- {path: /mnt/etc/security/pwquality.conf, content: ocredit = -1} - { path: /mnt/etc/security/pwquality.conf, content: ocredit = -1 }
- {path: /mnt/etc/security/pwquality.conf, content: lcredit = -1} - { path: /mnt/etc/security/pwquality.conf, content: lcredit = -1 }
- {path: '/mnt/etc/{{ "bashrc" if is_rhel else "bash.bashrc" }}', content: umask 077} - { path: '/mnt/etc/{{ "bashrc" if is_rhel else "bash.bashrc" }}', content: umask 077 }
- {path: '/mnt/etc/{{ "bashrc" if is_rhel else "bash.bashrc" }}', content: export TMOUT=3000} - { path: '/mnt/etc/{{ "bashrc" if is_rhel else "bash.bashrc" }}', content: export TMOUT=3000 }
- {path: '/mnt/{{ "usr/lib/systemd/journald.conf" if os == "fedora" else "etc/systemd/journald.conf" }}', content: Storage=persistent} - { path: '/mnt/{{ "usr/lib/systemd/journald.conf" if os == "fedora" else "etc/systemd/journald.conf" }}', content: Storage=persistent }
- {path: /mnt/etc/sudoers, content: Defaults logfile="/var/log/sudo.log"} - { path: /mnt/etc/sudoers, content: Defaults logfile="/var/log/sudo.log" }
- {path: /mnt/etc/pam.d/su, content: auth required pam_wheel.so} - { path: /mnt/etc/pam.d/su, content: auth required pam_wheel.so }
- path: >- - path: >-
/mnt/etc/{{ /mnt/etc/{{
"pam.d/common-auth" "pam.d/common-auth"
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] if is_debian | bool
else "authselect/system-auth" else "authselect/system-auth"
if os == "fedora" if os == "fedora"
else "pam.d/system-auth" else "pam.d/system-auth"
@@ -28,7 +28,7 @@
- path: >- - path: >-
/mnt/etc/{{ /mnt/etc/{{
"pam.d/common-account" "pam.d/common-account"
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] if is_debian | bool
else "authselect/system-auth" else "authselect/system-auth"
if os == "fedora" if os == "fedora"
else "pam.d/system-auth" else "pam.d/system-auth"
@@ -37,10 +37,10 @@
- path: >- - path: >-
/mnt/etc/pam.d/{{ /mnt/etc/pam.d/{{
"common-password" "common-password"
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] if is_debian | bool
else "passwd" else "passwd"
}} }}
content: >- content: >-
password [success=1 default=ignore] pam_unix.so obscure sha512 remember=5 password [success=1 default=ignore] pam_unix.so obscure sha512 remember=5
- {path: /mnt/etc/hosts.deny, content: "ALL: ALL"} - { path: /mnt/etc/hosts.deny, content: "ALL: ALL" }
- {path: /mnt/etc/hosts.allow, content: "sshd: ALL"} - { path: /mnt/etc/hosts.allow, content: "sshd: ALL" }

View File

@@ -5,30 +5,30 @@
regexp: ^\s*#?{{ item.option }}\s+.*$ regexp: ^\s*#?{{ item.option }}\s+.*$
line: "{{ item.option }} {{ item.value }}" line: "{{ item.option }} {{ item.value }}"
loop: loop:
- {option: LogLevel, value: VERBOSE} - { option: LogLevel, value: VERBOSE }
- {option: LoginGraceTime, value: "60"} - { option: LoginGraceTime, value: "60" }
- {option: PermitRootLogin, value: "no"} - { option: PermitRootLogin, value: "no" }
- {option: StrictModes, value: "yes"} - { option: StrictModes, value: "yes" }
- {option: MaxAuthTries, value: "4"} - { option: MaxAuthTries, value: "4" }
- {option: MaxSessions, value: "10"} - { option: MaxSessions, value: "10" }
- {option: MaxStartups, value: "10:30:60"} - { option: MaxStartups, value: "10:30:60" }
- {option: PubkeyAuthentication, value: "yes"} - { option: PubkeyAuthentication, value: "yes" }
- {option: HostbasedAuthentication, value: "no"} - { option: HostbasedAuthentication, value: "no" }
- {option: IgnoreRhosts, value: "yes"} - { option: IgnoreRhosts, value: "yes" }
- {option: PasswordAuthentication, value: "no"} - { option: PasswordAuthentication, value: "no" }
- {option: PermitEmptyPasswords, value: "no"} - { option: PermitEmptyPasswords, value: "no" }
- {option: KerberosAuthentication, value: "no"} - { option: KerberosAuthentication, value: "no" }
- {option: GSSAPIAuthentication, value: "no"} - { option: GSSAPIAuthentication, value: "no" }
- {option: AllowAgentForwarding, value: "no"} - { option: AllowAgentForwarding, value: "no" }
- {option: AllowTcpForwarding, value: "no"} - { option: AllowTcpForwarding, value: "no" }
- {option: ChallengeResponseAuthentication, value: "no"} - { option: ChallengeResponseAuthentication, value: "no" }
- {option: GatewayPorts, value: "no"} - { option: GatewayPorts, value: "no" }
- {option: X11Forwarding, value: "no"} - { option: X11Forwarding, value: "no" }
- {option: PermitUserEnvironment, value: "no"} - { option: PermitUserEnvironment, value: "no" }
- {option: ClientAliveInterval, value: "300"} - { option: ClientAliveInterval, value: "300" }
- {option: ClientAliveCountMax, value: "1"} - { option: ClientAliveCountMax, value: "1" }
- {option: PermitTunnel, value: "no"} - { option: PermitTunnel, value: "no" }
- {option: Banner, value: /etc/issue.net} - { option: Banner, value: /etc/issue.net }
- name: Append CIS specific configurations to sshd_config - name: Append CIS specific configurations to sshd_config
ansible.builtin.blockinfile: ansible.builtin.blockinfile:

View File

@@ -1,5 +1,9 @@
--- ---
cleanup_libvirt_image_dir: >- cleanup_libvirt_image_dir: >-
{{ vm_path if vm_path is defined and vm_path | length > 0 else '/var/lib/libvirt/images' }} {{
system_cfg.path
if system_cfg is defined and (system_cfg.path | string | length) > 0
else '/var/lib/libvirt/images'
}}
cleanup_libvirt_cloudinit_path: >- cleanup_libvirt_cloudinit_path: >-
{{ [cleanup_libvirt_image_dir, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }} {{ [cleanup_libvirt_image_dir, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }}

View File

@@ -102,3 +102,5 @@
delegate_to: "{{ inventory_hostname }}" delegate_to: "{{ inventory_hostname }}"
ansible.builtin.wait_for_connection: ansible.builtin.wait_for_connection:
timeout: 300 timeout: 300
failed_when: false
changed_when: false

View File

@@ -10,7 +10,7 @@
api_user: "{{ hypervisor_username }}" api_user: "{{ hypervisor_username }}"
api_password: "{{ hypervisor_password }}" api_password: "{{ hypervisor_password }}"
name: "{{ hostname }}" name: "{{ hostname }}"
vmid: "{{ vm_id }}" vmid: "{{ system_cfg.id }}"
disk: "{{ item }}" disk: "{{ item }}"
state: absent state: absent
loop: loop:
@@ -23,5 +23,5 @@
api_user: "{{ hypervisor_username }}" api_user: "{{ hypervisor_username }}"
api_password: "{{ hypervisor_password }}" api_password: "{{ hypervisor_password }}"
node: "{{ hypervisor_node }}" node: "{{ hypervisor_node }}"
vmid: "{{ vm_id }}" vmid: "{{ system_cfg.id }}"
state: restarted state: restarted

View File

@@ -13,3 +13,196 @@
- name: Cleanup libvirt resources - name: Cleanup libvirt resources
ansible.builtin.include_tasks: libvirt.yml ansible.builtin.include_tasks: libvirt.yml
- name: Cleanup Xen resources
ansible.builtin.include_tasks: xen.yml
- name: Determine post-reboot connectivity
ansible.builtin.set_fact:
cleanup_post_reboot_can_connect: >-
{{
(
post_reboot_can_connect
if post_reboot_can_connect is defined
else (
(ansible_connection | default('ssh')) != 'ssh'
or ((system_cfg.ip | default('') | string | length) > 0)
or (
install_type == 'physical'
and (ansible_host | default('') | string | length) > 0
)
)
) | bool
}}
changed_when: false
- name: Check VM accessibility after reboot
when:
- install_type == "virtual"
- cleanup_post_reboot_can_connect | bool
block:
- name: Attempt to connect to VM
delegate_to: "{{ inventory_hostname }}"
ansible.builtin.wait_for_connection:
timeout: 300
register: cleanup_vm_connection_check
failed_when: false
changed_when: false
- name: VM failed to boot - initiate cleanup
when:
- cleanup_vm_connection_check is defined
- cleanup_vm_connection_check.failed | bool
block:
- name: VM boot failure detected - removing VM
ansible.builtin.debug:
msg: |
VM {{ hostname }} failed to boot after provisioning.
This VM was created in the current playbook run and will be removed
to prevent orphaned resources.
- name: Remove VM for libvirt
when:
- hypervisor == "libvirt"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
community.libvirt.virt:
name: "{{ hostname }}"
state: destroyed
- name: Undefine VM for libvirt
when:
- hypervisor == "libvirt"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
community.libvirt.virt:
name: "{{ hostname }}"
command: undefine
- name: Remove VM disk for libvirt
when:
- hypervisor == "libvirt"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ virtualization_libvirt_disks | default([]) }}"
loop_control:
label: "{{ item.path }}"
- name: Remove cloud-init disk for libvirt
when:
- hypervisor == "libvirt"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
ansible.builtin.file:
path: "{{ virtualization_libvirt_cloudinit_path }}"
state: absent
- name: Remove VM for proxmox
when:
- hypervisor == "proxmox"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
community.proxmox.proxmox_kvm:
api_host: "{{ hypervisor_url }}"
api_user: "{{ hypervisor_username }}"
api_password: "{{ hypervisor_password }}"
node: "{{ hypervisor_node }}"
name: "{{ hostname }}"
vmid: "{{ system_cfg.id }}"
state: stopped
- name: Delete VM for proxmox
when:
- hypervisor == "proxmox"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
community.proxmox.proxmox_kvm:
api_host: "{{ hypervisor_url }}"
api_user: "{{ hypervisor_username }}"
api_password: "{{ hypervisor_password }}"
node: "{{ hypervisor_node }}"
name: "{{ hostname }}"
vmid: "{{ system_cfg.id }}"
state: absent
unprivileged: false
- name: Remove VM for VMware
when:
- hypervisor == "vmware"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
community.vmware.vmware_guest:
hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}"
validate_certs: "{{ hypervisor_validate_certs }}"
name: "{{ hostname }}"
folder: "{{ system_cfg.path | default('/') }}"
state: poweredoff
- name: Delete VM for VMware
when:
- hypervisor == "vmware"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
community.vmware.vmware_guest:
hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}"
validate_certs: "{{ hypervisor_validate_certs }}"
name: "{{ hostname }}"
folder: "{{ system_cfg.path | default('/') }}"
state: absent
- name: Destroy Xen VM if running
when:
- hypervisor == "xen"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
ansible.builtin.command:
argv:
- xl
- destroy
- "{{ hostname }}"
register: cleanup_xen_destroy
failed_when: false
changed_when: cleanup_xen_destroy.rc == 0
- name: Remove Xen VM disk
when:
- hypervisor == "xen"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
ansible.builtin.file:
path: "{{ item.path }}"
state: absent
loop: "{{ virtualization_xen_disks | default([]) }}"
loop_control:
label: "{{ item.path }}"
- name: Remove Xen VM config file
when:
- hypervisor == "xen"
- virtualization_vm_created_in_run | default(false) | bool
delegate_to: localhost
become: false
ansible.builtin.file:
path: "/tmp/xen-{{ hostname }}.cfg"
state: absent
- name: VM cleanup completed
ansible.builtin.debug:
msg: VM {{ hostname }} has been successfully removed due to boot failure.

View File

@@ -10,7 +10,7 @@
hostname: "{{ hypervisor_url }}" hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}" username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}" password: "{{ hypervisor_password }}"
validate_certs: false validate_certs: "{{ hypervisor_validate_certs }}"
datacenter: "{{ hypervisor_datacenter }}" datacenter: "{{ hypervisor_datacenter }}"
name: "{{ hostname }}" name: "{{ hostname }}"
cdrom: cdrom:
@@ -34,7 +34,7 @@
hostname: "{{ hypervisor_url }}" hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}" username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}" password: "{{ hypervisor_password }}"
validate_certs: false validate_certs: "{{ hypervisor_validate_certs }}"
datacenter: "{{ hypervisor_datacenter }}" datacenter: "{{ hypervisor_datacenter }}"
name: "{{ hostname }}" name: "{{ hostname }}"
state: powered-on state: powered-on

View File

@@ -0,0 +1,58 @@
---
- name: Cleanup Xen installer media
when: hypervisor == "xen"
delegate_to: localhost
become: false
block:
- name: Ensure Xen disk definitions exist
when: virtualization_xen_disks is not defined
ansible.builtin.set_fact:
cleanup_xen_disks: "{{ cleanup_xen_disks | default([]) + [cleanup_xen_disk_cfg] }}"
vars:
device_letter_map: "abcdefghijklmnopqrstuvwxyz"
device_letter: "{{ device_letter_map[ansible_loop.index0] }}"
cleanup_xen_disk_cfg: >-
{{
{
'path': (
virtualization_xen_disk_path ~ '/' ~ hostname ~ '.qcow2'
if ansible_loop.index0 == 0
else virtualization_xen_disk_path ~ '/' ~ hostname ~ '-disk' ~ ansible_loop.index0 ~ '.qcow2'
),
'target': 'xvd' ~ device_letter,
'size': (item.size | float)
}
}}
loop: "{{ system_cfg.disks }}"
loop_control:
label: "{{ item | to_json }}"
extended: true
changed_when: false
- name: Render Xen VM configuration without installer media
vars:
xen_installer_media_enabled: false
virtualization_xen_disks: "{{ virtualization_xen_disks | default(cleanup_xen_disks | default([])) }}"
ansible.builtin.template:
src: xen.cfg.j2
dest: /tmp/xen-{{ hostname }}.cfg
mode: "0644"
- name: Destroy Xen VM if running
ansible.builtin.command:
argv:
- xl
- destroy
- "{{ hostname }}"
register: cleanup_xen_destroy
failed_when: false
changed_when: cleanup_xen_destroy.rc == 0
- name: Start Xen VM without installer media
ansible.builtin.command:
argv:
- xl
- create
- /tmp/xen-{{ hostname }}.cfg
register: cleanup_xen_start_result
changed_when: cleanup_xen_start_result.rc == 0

View File

@@ -0,0 +1,5 @@
---
configuration_motd_enabled: "{{ motd_enabled | bool }}"
configuration_sudo_banner_enabled: "{{ sudo_banner_enabled | bool }}"
configuration_firewall_enabled: "{{ firewall_enabled | bool }}"
configuration_luks_enabled: "{{ luks_enabled | bool }}"

View File

@@ -0,0 +1,56 @@
---
- name: Configure MOTD
when: configuration_motd_enabled | bool
block:
- name: Create MOTD file
ansible.builtin.copy:
content: |
***************************************************************************
* AUTHORIZED ACCESS ONLY. ALL ACTIVITIES ARE MONITORED AND LOGGED. *
* *
***************************************************************************
dest: /mnt/etc/motd
mode: "0644"
owner: root
group: root
- name: Remove other MOTD files
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /mnt/etc/motd.d/99-motd
- /mnt/etc/motd.d/cockpit
- /mnt/etc/motd.d/insights-client
failed_when: false
- name: Configure sudo banner
when: configuration_sudo_banner_enabled | bool
block:
- name: Create sudoers banner directory
ansible.builtin.file:
path: /mnt/etc/sudoers.d
state: directory
mode: "0755"
owner: root
group: root
- name: Create sudo banner file
ansible.builtin.copy:
content: |
I am Groot, and I know what I'm doing.
dest: /mnt/etc/sudoers.d/banner
mode: "0644"
owner: root
group: root
- name: Enable sudo banner in sudoers
ansible.builtin.lineinfile:
path: /mnt/etc/sudoers
line: "Defaults lecture=@/etc/sudoers.d/banner"
state: present
create: true
mode: "0440"
owner: root
group: root
validate: "visudo -cf - %s"

View File

@@ -8,7 +8,7 @@
configuration_bootloader_id: >- configuration_bootloader_id: >-
{{ "ubuntu" if os | lower in ["ubuntu", "ubuntu-lts"] else os }} {{ "ubuntu" if os | lower in ["ubuntu", "ubuntu-lts"] else os }}
configuration_efi_vendor: >- configuration_efi_vendor: >-
{{ "redhat" if os | lower in ["rhel8", "rhel9", "rhel10"] else os | lower }} {{ "redhat" if os | lower == "rhel" else os | lower }}
configuration_efibootmgr_cmd: >- configuration_efibootmgr_cmd: >-
/usr/sbin/efibootmgr -c -L '{{ os }}' -d "{{ install_drive }}" -p 1 /usr/sbin/efibootmgr -c -L '{{ os }}' -d "{{ install_drive }}" -p 1
-l '\efi\EFI\{{ configuration_efi_vendor }}\shimx64.efi' -l '\efi\EFI\{{ configuration_efi_vendor }}\shimx64.efi'
@@ -18,7 +18,7 @@
--bootloader-id={{ configuration_bootloader_id }} --bootloader-id={{ configuration_bootloader_id }}
configuration_bootloader_cmd: >- configuration_bootloader_cmd: >-
{{ configuration_efibootmgr_cmd if configuration_use_efibootmgr else configuration_grub_cmd }} {{ configuration_efibootmgr_cmd if configuration_use_efibootmgr else configuration_grub_cmd }}
ansible.builtin.command: "{{ chroot_command }} /mnt {{ configuration_bootloader_cmd }}" ansible.builtin.command: "{{ chroot_command }} {{ configuration_bootloader_cmd }}"
register: configuration_bootloader_result register: configuration_bootloader_result
changed_when: configuration_bootloader_result.rc == 0 changed_when: configuration_bootloader_result.rc == 0
@@ -27,10 +27,11 @@
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/mkinitcpio.conf path: /mnt/etc/mkinitcpio.conf
regexp: "^(HOOKS=.*block)(?!.*lvm2)(.*)" regexp: "^(HOOKS=.*block)(?!.*lvm2)(.*)"
line: '\1 lvm2\2' line: "\\1 lvm2\\2"
backrefs: true backrefs: true
- name: Regenerate initramfs - name: Regenerate initramfs
when: os | lower not in ["alpine", "void"]
vars: vars:
configuration_initramfs_cmd: >- configuration_initramfs_cmd: >-
{{ {{
@@ -43,14 +44,14 @@
else '/usr/bin/dracut --regenerate-all --force' else '/usr/bin/dracut --regenerate-all --force'
) )
}} }}
ansible.builtin.command: "{{ chroot_command }} /mnt {{ configuration_initramfs_cmd }}" ansible.builtin.command: "{{ chroot_command }} {{ configuration_initramfs_cmd }}"
register: configuration_initramfs_result register: configuration_initramfs_result
changed_when: configuration_initramfs_result.rc == 0 changed_when: configuration_initramfs_result.rc == 0
- name: Generate grub config - name: Generate grub config
vars: vars:
configuration_efi_vendor: >- configuration_efi_vendor: >-
{{ "redhat" if os | lower in ["rhel8", "rhel9", "rhel10"] else os | lower }} {{ "redhat" if os | lower == "rhel" else os | lower }}
configuration_grub_cfg_cmd: >- configuration_grub_cfg_cmd: >-
{{ {{
'/usr/sbin/grub2-mkconfig -o ' '/usr/sbin/grub2-mkconfig -o '
@@ -59,6 +60,6 @@
if is_rhel | bool if is_rhel | bool
else '/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg' else '/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg'
}} }}
ansible.builtin.command: "{{ chroot_command }} /mnt {{ configuration_grub_cfg_cmd }}" ansible.builtin.command: "{{ chroot_command }} {{ configuration_grub_cfg_cmd }}"
register: configuration_grub_result register: configuration_grub_result
changed_when: configuration_grub_result.rc == 0 changed_when: configuration_grub_result.rc == 0

View File

@@ -141,8 +141,8 @@
- configuration_luks_keyfile_in_use - configuration_luks_keyfile_in_use
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/cryptsetup-initramfs/conf-hook path: /mnt/etc/cryptsetup-initramfs/conf-hook
regexp: '^KEYFILE_PATTERN=' regexp: "^KEYFILE_PATTERN="
line: 'KEYFILE_PATTERN=/etc/cryptsetup-keys.d/*.key' line: "KEYFILE_PATTERN=/etc/cryptsetup-keys.d/*.key"
create: true create: true
mode: "0644" mode: "0644"
@@ -150,7 +150,7 @@
when: os | lower == 'archlinux' when: os | lower == 'archlinux'
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/mkinitcpio.conf path: /mnt/etc/mkinitcpio.conf
regexp: '^HOOKS=' regexp: "^HOOKS="
line: >- line: >-
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole
block sd-encrypt lvm2 filesystems fsck) block sd-encrypt lvm2 filesystems fsck)
@@ -194,7 +194,7 @@
when: os | lower == 'archlinux' when: os | lower == 'archlinux'
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/mkinitcpio.conf path: /mnt/etc/mkinitcpio.conf
regexp: '^FILES=' regexp: "^FILES="
line: >- line: >-
FILES=({{ FILES=({{
configuration_mkinitcpio_files_list_new | join(' ') configuration_mkinitcpio_files_list_new | join(' ')
@@ -271,7 +271,7 @@
- configuration_kernel_bls_entries.files | length > 0 - configuration_kernel_bls_entries.files | length > 0
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: "{{ item.path }}" path: "{{ item.path }}"
regexp: '^options ' regexp: "^options "
line: "options {{ configuration_kernel_cmdline_new }}" line: "options {{ configuration_kernel_cmdline_new }}"
loop: "{{ configuration_kernel_bls_entries.files }}" loop: "{{ configuration_kernel_bls_entries.files }}"
loop_control: loop_control:
@@ -351,5 +351,5 @@
when: not is_rhel | bool when: not is_rhel | bool
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/default/grub path: /mnt/etc/default/grub
regexp: '^GRUB_CMDLINE_LINUX_DEFAULT=' regexp: "^GRUB_CMDLINE_LINUX_DEFAULT="
line: 'GRUB_CMDLINE_LINUX_DEFAULT="{{ configuration_grub_cmdline_default_new }}"' line: 'GRUB_CMDLINE_LINUX_DEFAULT="{{ configuration_grub_cmdline_default_new }}"'

View File

@@ -36,7 +36,7 @@
+ [configuration_luks_device] + [configuration_luks_device]
}} }}
configuration_luks_enroll_chroot_cmd: >- configuration_luks_enroll_chroot_cmd: >-
{{ chroot_command }} /mnt {{ configuration_luks_enroll_args | join(' ') }} {{ chroot_command }} {{ configuration_luks_enroll_args | join(' ') }}
ansible.builtin.command: "{{ configuration_luks_enroll_chroot_cmd }}" ansible.builtin.command: "{{ configuration_luks_enroll_chroot_cmd }}"
register: configuration_luks_tpm2_enroll_chroot register: configuration_luks_tpm2_enroll_chroot
changed_when: configuration_luks_tpm2_enroll_chroot.rc == 0 changed_when: configuration_luks_tpm2_enroll_chroot.rc == 0

View File

@@ -27,7 +27,8 @@
- name: Create zram config - name: Create zram config
when: when:
- os | lower not in ['debian11', 'rhel8'] - (os != "debian" or (os_version | string) != "11") and os != "rhel"
- os | lower not in ["alpine", "void"]
- swap_enabled | bool - swap_enabled | bool
ansible.builtin.copy: ansible.builtin.copy:
dest: /mnt/etc/systemd/zram-generator.conf dest: /mnt/etc/systemd/zram-generator.conf
@@ -62,7 +63,7 @@
- /mnt/etc/issue.net - /mnt/etc/issue.net
- name: Remove motd files - name: Remove motd files
when: os | lower in ["rhel8", "rhel9", "rhel10"] when: os == "rhel"
ansible.builtin.file: ansible.builtin.file:
path: "{{ item }}" path: "{{ item }}"
state: absent state: absent

View File

@@ -17,14 +17,14 @@
mode: "0644" mode: "0644"
- name: Remove deprecated attr2 and disable large extent - name: Remove deprecated attr2 and disable large extent
when: os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] and filesystem == "xfs" when: os in ["almalinux", "rocky", "rhel"] and filesystem == "xfs"
ansible.builtin.replace: ansible.builtin.replace:
path: /mnt/etc/fstab path: /mnt/etc/fstab
regexp: "(xfs.*?)(attr2)" regexp: "(xfs.*?)(attr2)"
replace: '\1allocsize=64m' replace: "\\1allocsize=64m"
- name: Replace ISO UUID entry with /dev/sr0 in fstab - name: Replace ISO UUID entry with /dev/sr0 in fstab
when: os in ["rhel8", "rhel9", "rhel10"] when: os == "rhel"
vars: vars:
configuration_fstab_dvd_line: >- configuration_fstab_dvd_line: >-
{{ {{
@@ -34,12 +34,12 @@
}} }}
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/fstab path: /mnt/etc/fstab
regexp: '^.*\/dvd.*$' regexp: "^.*\\/dvd.*$"
line: "{{ configuration_fstab_dvd_line }}" line: "{{ configuration_fstab_dvd_line }}"
state: present state: present
- name: Write image from RHEL ISO to the target machine - name: Write image from RHEL ISO to the target machine
when: os in ["rhel8", "rhel9", "rhel10"] and hypervisor == 'vmware' when: os == "rhel" and hypervisor == 'vmware'
ansible.builtin.command: ansible.builtin.command:
argv: argv:
- dd - dd
@@ -57,9 +57,9 @@
line: "{{ fstab_entry.line }}" line: "{{ fstab_entry.line }}"
insertafter: EOF insertafter: EOF
loop: loop:
- {regexp: '^# TempFS$', line: '# TempFS'} - { regexp: "^# TempFS$", line: "# TempFS" }
- {regexp: '^tmpfs\\s+/tmp\\s+', line: 'tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec 0 0'} - { regexp: "^tmpfs\\\\s+/tmp\\\\s+", line: "tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec 0 0" }
- {regexp: '^tmpfs\\s+/var/tmp\\s+', line: 'tmpfs /var/tmp tmpfs defaults,nosuid,nodev,noexec 0 0'} - { regexp: "^tmpfs\\\\s+/var/tmp\\\\s+", line: "tmpfs /var/tmp tmpfs defaults,nosuid,nodev,noexec 0 0" }
- {regexp: '^tmpfs\\s+/dev/shm\\s+', line: 'tmpfs /dev/shm tmpfs defaults,nosuid,nodev,noexec 0 0'} - { regexp: "^tmpfs\\\\s+/dev/shm\\\\s+", line: "tmpfs /dev/shm tmpfs defaults,nosuid,nodev,noexec 0 0" }
loop_control: loop_control:
loop_var: fstab_entry loop_var: fstab_entry

View File

@@ -106,7 +106,7 @@
when: configuration_grub_bls_entries.files | length > 0 when: configuration_grub_bls_entries.files | length > 0
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: "{{ item.path }}" path: "{{ item.path }}"
regexp: '^options ' regexp: "^options "
line: "options {{ configuration_kernel_cmdline_base }}" line: "options {{ configuration_kernel_cmdline_base }}"
loop: "{{ configuration_grub_bls_entries.files }}" loop: "{{ configuration_grub_bls_entries.files }}"
loop_control: loop_control:
@@ -116,5 +116,5 @@
when: partitioning_grub_enable_cryptodisk | bool when: partitioning_grub_enable_cryptodisk | bool
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/default/grub path: /mnt/etc/default/grub
regexp: '^GRUB_ENABLE_CRYPTODISK=' regexp: "^GRUB_ENABLE_CRYPTODISK="
line: GRUB_ENABLE_CRYPTODISK=y line: GRUB_ENABLE_CRYPTODISK=y

View File

@@ -1,5 +1,6 @@
--- ---
- name: Reload systemd in installer environment - name: Reload systemd in installer environment
when: ansible_service_mgr == 'systemd'
ansible.builtin.systemd: ansible.builtin.systemd:
daemon_reload: true daemon_reload: true
@@ -19,14 +20,15 @@
regexp: "{{ item.regex }}" regexp: "{{ item.regex }}"
line: "{{ item.line }}" line: "{{ item.line }}"
loop: loop:
- {regex: en_US\.UTF-8 UTF-8, line: en_US.UTF-8 UTF-8} - { regex: en_US\.UTF-8 UTF-8, line: en_US.UTF-8 UTF-8 }
- name: Generate locales - name: Generate locales
when: not is_rhel | bool when: not is_rhel | bool
ansible.builtin.command: "{{ chroot_command }} /mnt /usr/sbin/locale-gen" ansible.builtin.command: "{{ chroot_command }} /usr/sbin/locale-gen"
register: configuration_locale_result register: configuration_locale_result
changed_when: configuration_locale_result.rc == 0 changed_when: configuration_locale_result.rc == 0
- name: Set hostname - name: Set hostname
vars: vars:
configuration_hostname_fqdn: >- configuration_hostname_fqdn: >-
@@ -34,8 +36,8 @@
hostname hostname
if '.' in hostname if '.' in hostname
else ( else (
hostname + '.' + vm_dns_search hostname + '.' + system_cfg.dns_search
if vm_dns_search is defined and vm_dns_search | length if system_cfg.dns_search is defined and system_cfg.dns_search | length
else hostname else hostname
) )
}} }}
@@ -51,16 +53,22 @@
hostname hostname
if '.' in hostname if '.' in hostname
else ( else (
hostname + '.' + vm_dns_search hostname + '.' + system_cfg.dns_search
if vm_dns_search is defined and vm_dns_search | length if system_cfg.dns_search is defined and system_cfg.dns_search | length
else hostname else hostname
) )
}} }}
configuration_hostname_short: "{{ hostname.split('.')[0] }}" configuration_hostname_short: "{{ hostname.split('.')[0] }}"
configuration_hostname_entries: >- configuration_hostname_entries: >-
{{ [configuration_hostname_fqdn, configuration_hostname_short] | unique | join(' ') }} {{ [configuration_hostname_fqdn, configuration_hostname_short] | unique | join(' ') }}
configuration_hosts_ip: >-
{{
system_cfg.ip
if system_cfg.ip is defined and (system_cfg.ip | string | length) > 0
else inventory_hostname
}}
configuration_hosts_line: >- configuration_hosts_line: >-
{{ (vm_ip if vm_ip is defined and vm_ip | length > 0 else inventory_hostname) }} {{ configuration_hostname_entries }} {{ configuration_hosts_ip }} {{ configuration_hostname_entries }}
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /mnt/etc/hosts path: /mnt/etc/hosts
line: "{{ configuration_hosts_line }}" line: "{{ configuration_hosts_line }}"

View File

@@ -2,6 +2,7 @@
- name: Include configuration tasks - name: Include configuration tasks
ansible.builtin.include_tasks: "{{ configuration_task }}" ansible.builtin.include_tasks: "{{ configuration_task }}"
loop: loop:
- banner.yml
- fstab.yml - fstab.yml
- locales.yml - locales.yml
- services.yml - services.yml

View File

@@ -82,15 +82,100 @@
- configuration_net_mac | length > 0 - configuration_net_mac | length > 0
fail_msg: Failed to detect the MAC address for network interface {{ configuration_net_inf }}. fail_msg: Failed to detect the MAC address for network interface {{ configuration_net_inf }}.
- name: Copy NetworkManager keyfile - name: Configure NetworkManager profile
ansible.builtin.template: when: os | lower not in ["alpine", "void"]
src: network.j2 block:
dest: /mnt/etc/NetworkManager/system-connections/LAN.nmconnection - name: Copy NetworkManager keyfile
mode: "0600" ansible.builtin.template:
src: network.j2
dest: /mnt/etc/NetworkManager/system-connections/LAN.nmconnection
mode: "0600"
- name: Fix Ubuntu unmanaged devices - name: Fix Ubuntu unmanaged devices
when: os | lower in ["ubuntu", "ubuntu-lts"] when: os | lower in ["ubuntu", "ubuntu-lts"]
ansible.builtin.file: ansible.builtin.file:
path: /mnt/etc/NetworkManager/conf.d/10-globally-managed-devices.conf path: /mnt/etc/NetworkManager/conf.d/10-globally-managed-devices.conf
state: touch state: touch
mode: "0644" mode: "0644"
- name: Configure Alpine networking
when: os | lower == "alpine"
vars:
configuration_dns_value: "{{ system_cfg.dns_servers if system_cfg.dns_servers is defined else '' }}"
configuration_dns_list_raw: >-
{{
configuration_dns_value
if configuration_dns_value is iterable and configuration_dns_value is not string
else configuration_dns_value.split(',')
}}
configuration_dns_list: >-
{{ configuration_dns_list_raw | map('trim') | reject('equalto', '') | list }}
configuration_alpine_static: >-
{{
system_cfg.ip is defined
and system_cfg.ip | string | length > 0
and system_cfg.prefix is defined
and (system_cfg.prefix | string | length) > 0
}}
block:
- name: Write Alpine network interfaces
ansible.builtin.copy:
dest: /mnt/etc/network/interfaces
mode: "0644"
content: |
auto lo
iface lo inet loopback
auto {{ configuration_net_inf }}
iface {{ configuration_net_inf }} inet {{ 'static' if configuration_alpine_static | bool else 'dhcp' }}
{% if configuration_alpine_static | bool %}
address {{ system_cfg.ip }}/{{ system_cfg.prefix }}
{% if system_cfg.gateway is defined and system_cfg.gateway | string | length %}
gateway {{ system_cfg.gateway }}
{% endif %}
{% endif %}
- name: Set Alpine DNS resolvers
when: configuration_dns_list | length > 0
ansible.builtin.copy:
dest: /mnt/etc/resolv.conf
mode: "0644"
content: |
{% for resolver in configuration_dns_list %}
nameserver {{ resolver }}
{% endfor %}
- name: Configure Void networking
when: os | lower == "void"
vars:
configuration_dns_value: "{{ system_cfg.dns_servers if system_cfg.dns_servers is defined else '' }}"
configuration_dns_list_raw: >-
{{
configuration_dns_value
if configuration_dns_value is iterable and configuration_dns_value is not string
else configuration_dns_value.split(',')
}}
configuration_dns_list: >-
{{ configuration_dns_list_raw | map('trim') | reject('equalto', '') | list }}
configuration_void_static: >-
{{
system_cfg.ip is defined
and system_cfg.ip | string | length > 0
and system_cfg.prefix is defined
and (system_cfg.prefix | string | length) > 0
}}
block:
- name: Write dhcpcd configuration for static networking
when: configuration_void_static | bool
ansible.builtin.copy:
dest: /mnt/etc/dhcpcd.conf
mode: "0644"
content: |
interface {{ configuration_net_inf }}
static ip_address={{ system_cfg.ip }}/{{ system_cfg.prefix }}
{% if system_cfg.gateway is defined and system_cfg.gateway | string | length %}
static routers={{ system_cfg.gateway }}
{% endif %}
{% if configuration_dns_list | length > 0 %}
static domain_name_servers={{ configuration_dns_list | join(' ') }}
{% endif %}

View File

@@ -3,9 +3,9 @@
when: is_rhel | bool when: is_rhel | bool
block: block:
- name: Fix SELinux by pre-labeling the filesystem before first boot - name: Fix SELinux by pre-labeling the filesystem before first boot
when: os | lower in ['almalinux', 'rhel8', 'rhel9', 'rhel10', 'rocky'] and selinux | bool when: os in ['almalinux', 'rocky', 'rhel'] and selinux | bool
ansible.builtin.command: > ansible.builtin.command: >
{{ chroot_command }} /mnt /sbin/setfiles -v -F {{ chroot_command }} /sbin/setfiles -v -F
-e /dev -e /proc -e /sys -e /run -e /dev -e /proc -e /sys -e /run
/etc/selinux/targeted/contexts/files/file_contexts / /etc/selinux/targeted/contexts/files/file_contexts /
register: configuration_setfiles_result register: configuration_setfiles_result

View File

@@ -1,11 +1,12 @@
--- ---
- name: Enable Systemd Services - name: Enable Systemd Services
when: os | lower not in ['alpine', 'void']
ansible.builtin.command: > ansible.builtin.command: >
{{ chroot_command }} /mnt systemctl enable NetworkManager {{ chroot_command }} systemctl enable NetworkManager
{{ ' firewalld' if firewalld_enabled | bool else '' }} {{ ' firewalld' if firewall_backend == 'firewalld' and firewall_enabled | bool else '' }}
{{ ' ufw' if firewall_backend == 'ufw' and firewall_enabled | bool else '' }}
{{ {{
(' ssh' if os | lower in ['ubuntu', 'ubuntu-lts'] else (' ssh' if is_debian | bool else ' sshd')
(' sshd' if os | lower not in ['debian11', 'debian12', 'debian13'] else ''))
if ssh_enabled | bool else '' if ssh_enabled | bool else ''
}} }}
{{ {{
@@ -14,3 +15,65 @@
}} }}
register: configuration_enable_services_result register: configuration_enable_services_result
changed_when: configuration_enable_services_result.rc == 0 changed_when: configuration_enable_services_result.rc == 0
- name: Enable OpenRC services
when: os | lower == 'alpine'
vars:
configuration_openrc_services: >-
{{
['networking']
+ (['sshd'] if ssh_enabled | bool else [])
+ ([firewall_backend] if firewall_enabled | bool else [])
}}
block:
- name: Ensure OpenRC runlevel directory exists
ansible.builtin.file:
path: /mnt/etc/runlevels/default
state: directory
mode: "0755"
- name: Check OpenRC init scripts
ansible.builtin.stat:
path: "/mnt/etc/init.d/{{ item }}"
loop: "{{ configuration_openrc_services }}"
register: configuration_openrc_service_stats
changed_when: false
- name: Enable OpenRC services
ansible.builtin.file:
src: "/mnt/etc/init.d/{{ item.item }}"
dest: "/mnt/etc/runlevels/default/{{ item.item }}"
state: link
loop: "{{ configuration_openrc_service_stats.results }}"
when: item.stat.exists
- name: Enable runit services
when: os | lower == 'void'
vars:
configuration_runit_services: >-
{{
['dhcpcd']
+ (['sshd'] if ssh_enabled | bool else [])
+ ([firewall_backend] if firewall_enabled | bool else [])
}}
block:
- name: Ensure runit service directory exists
ansible.builtin.file:
path: /mnt/var/service
state: directory
mode: "0755"
- name: Check runit service definitions
ansible.builtin.stat:
path: "/mnt/etc/sv/{{ item }}"
loop: "{{ configuration_runit_services }}"
register: configuration_runit_service_stats
changed_when: false
- name: Enable runit services
ansible.builtin.file:
src: "/mnt/etc/sv/{{ item.item }}"
dest: "/mnt/var/service/{{ item.item }}"
state: link
loop: "{{ configuration_runit_service_stats.results }}"
when: item.stat.exists

View File

@@ -4,11 +4,11 @@
configuration_user_group: >- configuration_user_group: >-
{{ "sudo" if is_debian | bool else "wheel" }} {{ "sudo" if is_debian | bool else "wheel" }}
configuration_useradd_cmd: >- configuration_useradd_cmd: >-
{{ chroot_command }} /mnt /usr/sbin/useradd --create-home --user-group {{ chroot_command }} /usr/sbin/useradd --create-home --user-group
--groups {{ configuration_user_group }} {{ user_name }} --groups {{ configuration_user_group }} {{ user_name }}
--password {{ user_password | password_hash('sha512') }} --shell /bin/bash --password {{ user_password | password_hash('sha512') }} --shell /bin/bash
configuration_root_cmd: >- configuration_root_cmd: >-
{{ chroot_command }} /mnt /usr/sbin/usermod --password {{ chroot_command }} /usr/sbin/usermod --password
'{{ root_password | password_hash('sha512') }}' root --shell /bin/bash '{{ root_password | password_hash('sha512') }}' root --shell /bin/bash
ansible.builtin.command: "{{ item }}" ansible.builtin.command: "{{ item }}"
loop: loop:

View File

@@ -4,14 +4,14 @@ uuid={{ configuration_net_uuid }}
type=ethernet type=ethernet
[ipv4] [ipv4]
{% set dns_value = vm_dns if vm_dns is defined else '' %} {% set dns_value = system_cfg.dns_servers if system_cfg.dns_servers is defined else '' %}
{% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %} {% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %}
{% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %} {% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %}
{% set search_value = vm_dns_search if vm_dns_search is defined else '' %} {% set search_value = system_cfg.dns_search if system_cfg.dns_search is defined else '' %}
{% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %} {% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %}
{% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %} {% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %}
{% if vm_ip is defined and vm_ip | length %} {% if system_cfg.ip is defined and system_cfg.ip | string | length %}
address1={{ vm_ip }}/{{ vm_nms }}{{ (',' ~ vm_gw) if (vm_gw is defined and vm_gw | length) else '' }} address1={{ system_cfg.ip }}/{{ system_cfg.prefix }}{{ (',' ~ system_cfg.gateway) if (system_cfg.gateway is defined and system_cfg.gateway | string | length) else '' }}
method=manual method=manual
{% else %} {% else %}
method=auto method=auto

View File

@@ -10,15 +10,73 @@
- name: Gather facts - name: Gather facts
ansible.builtin.setup: ansible.builtin.setup:
- name: Check if host is booted from the Arch install media - name: Check for live environment markers
ansible.builtin.stat: ansible.builtin.stat:
path: /run/archiso path: "{{ item }}"
register: environment_archiso_stat loop:
- /run/archiso
- /run/live
- /run/initramfs
- /run/initramfs/live
register: environment_live_marker_stat
changed_when: false
- name: Determine root filesystem type
ansible.builtin.set_fact:
environment_root_fstype: >-
{{
ansible_mounts
| selectattr('mount', 'equalto', '/')
| map(attribute='fstype')
| list
| first
| default('')
| lower
}}
environment_archiso_present: >-
{{
(
environment_live_marker_stat.results
| selectattr('item', 'equalto', '/run/archiso')
| selectattr('stat.exists')
| list
| length
) > 0
}}
changed_when: false
- name: Identify live environment indicators
ansible.builtin.set_fact:
environment_is_live_environment: >-
{{
(
environment_live_marker_stat.results
| selectattr('stat.exists')
| list
| length
) > 0
or environment_root_fstype in ['overlay', 'overlayfs', 'squashfs', 'aufs']
or (ansible_hostname | default('') | lower is search('live'))
}}
changed_when: false
- name: Abort if target is not a live environment
ansible.builtin.assert:
that:
- environment_is_live_environment | bool
fail_msg: |
PRODUCTION SYSTEM DETECTED - ABORTING
The target system does not appear to be a live installer environment.
This playbook must run from a live ISO to avoid wiping production data.
Boot from a live installer (Arch, Debian, Ubuntu, etc.) and retry.
quiet: true
- name: Abort if the host is not booted from the Arch install media - name: Abort if the host is not booted from the Arch install media
when: when:
- not (custom_iso | bool) - not (custom_iso | bool)
- not environment_archiso_stat.stat.exists - not environment_archiso_present | bool
ansible.builtin.fail: ansible.builtin.fail:
msg: This host is not booted from the Arch install media! msg: This host is not booted from the Arch install media!
@@ -40,9 +98,9 @@
- name: Set IP-Address - name: Set IP-Address
when: when:
- hypervisor == "vmware" - hypervisor == "vmware"
- vm_ip is defined and vm_ip | length > 0 - system_cfg.ip is defined and system_cfg.ip | string | length > 0
ansible.builtin.command: >- ansible.builtin.command: >-
ip addr replace {{ vm_ip }}/{{ vm_nms }} ip addr replace {{ system_cfg.ip }}/{{ system_cfg.prefix }}
dev {{ environment_interface_name }} dev {{ environment_interface_name }}
register: environment_ip_result register: environment_ip_result
changed_when: environment_ip_result.rc == 0 changed_when: environment_ip_result.rc == 0
@@ -50,9 +108,9 @@
- name: Set Default Gateway - name: Set Default Gateway
when: when:
- hypervisor == "vmware" - hypervisor == "vmware"
- vm_gw is defined and vm_gw | length > 0 - system_cfg.gateway is defined and system_cfg.gateway | string | length > 0
- vm_ip is defined and vm_ip | length > 0 - system_cfg.ip is defined and system_cfg.ip | string | length > 0
ansible.builtin.command: "ip route replace default via {{ vm_gw }}" ansible.builtin.command: "ip route replace default via {{ system_cfg.gateway }}"
register: environment_gateway_result register: environment_gateway_result
changed_when: environment_gateway_result.rc == 0 changed_when: environment_gateway_result.rc == 0
@@ -105,23 +163,23 @@
- name: Setup Pacman - name: Setup Pacman
when: when:
- not (custom_iso | bool) - not (custom_iso | bool)
- "'os' not in item or os in item.os" - item.os is not defined or (os_resolved | default(os)) in item.os
community.general.pacman: community.general.pacman:
update_cache: true update_cache: true
force: true force: true
name: "{{ item.name }}" name: "{{ item.name }}"
state: latest state: latest
loop: loop:
- {name: glibc} - { name: glibc }
- {name: dnf, os: [almalinux, fedora, rhel8, rhel9, rhel10, rocky]} - { name: dnf, os: [almalinux8, almalinux9, almalinux10, fedora40, fedora41, fedora42, fedora43, rhel8, rhel9, rhel10, rocky8, rocky9, rocky10] }
- {name: debootstrap, os: [debian11, debian12, debian13, ubuntu, ubuntu-lts]} - { name: debootstrap, os: [debian10, debian11, debian12, debian13, debianunstable, ubuntu, ubuntu-lts] }
- {name: debian-archive-keyring, os: [debian11, debian12, debian13]} - { name: debian-archive-keyring, os: [debian10, debian11, debian12, debian13, debianunstable] }
- {name: ubuntu-keyring, os: [ubuntu, ubuntu-lts]} - { name: ubuntu-keyring, os: [ubuntu, ubuntu-lts] }
retries: 4 retries: 4
delay: 15 delay: 15
- name: Prepare /iso mount and repository for RHEL-based systems - name: Prepare /iso mount and repository for RHEL-based systems
when: os | lower in ["rhel8", "rhel9", "rhel10"] when: os == "rhel"
block: block:
- name: Create /iso directory - name: Create /iso directory
ansible.builtin.file: ansible.builtin.file:
@@ -129,9 +187,19 @@
state: directory state: directory
mode: "0755" mode: "0755"
- name: Select RHEL ISO device
ansible.builtin.set_fact:
environment_rhel_iso_device: >-
{{
'/dev/sr2'
if hypervisor == 'libvirt'
else '/dev/sr1'
}}
changed_when: false
- name: Mount RHEL ISO - name: Mount RHEL ISO
ansible.posix.mount: ansible.posix.mount:
src: "{{ '/dev/sr1' if hypervisor == 'vmware' else '/dev/sr2' }}" src: "{{ environment_rhel_iso_device }}"
path: /usr/local/install/redhat/dvd path: /usr/local/install/redhat/dvd
fstype: iso9660 fstype: iso9660
opts: "ro,loop" opts: "ro,loop"
@@ -140,6 +208,16 @@
- name: Configure RHEL Repos for installation - name: Configure RHEL Repos for installation
when: is_rhel | bool when: is_rhel | bool
block: block:
- name: Select repository template
ansible.builtin.set_fact:
environment_repo_template: >-
{{
(os_resolved | default(os)) | lower
if os == 'rhel'
else os | lower
}}
changed_when: false
- name: Create directories for repository files and RPM GPG keys - name: Create directories for repository files and RPM GPG keys
ansible.builtin.file: ansible.builtin.file:
path: /etc/yum.repos.d path: /etc/yum.repos.d
@@ -148,8 +226,8 @@
- name: Create RHEL repository file - name: Create RHEL repository file
ansible.builtin.template: ansible.builtin.template:
src: "{{ os | lower }}.repo.j2" src: "{{ environment_repo_template }}.repo.j2"
dest: /etc/yum.repos.d/{{ os | lower }}.repo dest: /etc/yum.repos.d/{{ environment_repo_template }}.repo
mode: "0644" mode: "0644"
- name: Check for third-party preparation tasks - name: Check for third-party preparation tasks

View File

@@ -1,18 +1,49 @@
--- ---
hypervisor: "none" hypervisor: "none"
hypervisor_defaults:
type: "none"
url: ""
username: ""
password: ""
node: ""
storage: ""
datacenter: ""
cluster: ""
validate_certs: false
custom_iso: false custom_iso: false
cis: false cis: false
selinux: true selinux: true
vmware_ssh: false vmware_ssh: false
firewalld_enabled: true firewall_enabled: true
firewall_backend: "firewalld"
firewall_toolkit: "nftables"
ssh_enabled: true ssh_enabled: true
zstd_enabled: true zstd_enabled: true
swap_enabled: true swap_enabled: true
chroot_command: "arch-chroot" chroot_tool: "arch-chroot"
os_version: ""
motd_enabled: true
sudo_banner_enabled: true
thirdparty_preparation_tasks_path: "dropins/preparation.yml" thirdparty_preparation_tasks_path: "dropins/preparation.yml"
cis_enabled: "{{ cis | bool }}" cis_enabled: "{{ cis | bool }}"
system_defaults:
name: ""
id: ""
cpus: 0
memory_mb: 0
balloon_mb: 0
network: ""
vlan: ""
ip: ""
prefix: ""
gateway: ""
dns_servers: []
dns_search: []
path: ""
disks: []
luks_enabled: false luks_enabled: false
luks_mapper_name: "SYSTEM_DECRYPTED" luks_mapper_name: "SYSTEM_DECRYPTED"
luks_auto_decrypt: true luks_auto_decrypt: true

View File

@@ -0,0 +1,42 @@
---
- name: Validate hypervisor dict input
when: hypervisor is mapping
ansible.builtin.assert:
that:
- hypervisor.type is defined
- hypervisor.type | string | length > 0
fail_msg: "hypervisor.type is required when hypervisor is a dictionary"
quiet: true
- name: Normalize hypervisor configuration
vars:
hypervisor_input: "{{ hypervisor if hypervisor is mapping else {} }}"
hypervisor_type_legacy: "{{ (hypervisor | default('none')) if hypervisor is string else '' }}"
hypervisor_legacy_cfg:
type: "{{ hypervisor_type_legacy }}"
url: "{{ hypervisor_url | default('') }}"
username: "{{ hypervisor_username | default('') }}"
password: "{{ hypervisor_password | default('') }}"
node: "{{ hypervisor_node | default('') }}"
storage: "{{ hypervisor_storage | default('') }}"
datacenter: "{{ hypervisor_datacenter | default('') }}"
cluster: "{{ hypervisor_cluster | default('') }}"
validate_certs: "{{ hypervisor_validate_certs | default(false) | bool }}"
hypervisor_cfg_effective: >-
{{
hypervisor_defaults
| combine(hypervisor_legacy_cfg, recursive=True)
| combine(hypervisor_input, recursive=True)
}}
ansible.builtin.set_fact:
hypervisor_cfg: "{{ hypervisor_cfg_effective }}"
hypervisor: "{{ hypervisor_cfg_effective.type | string | lower }}"
hypervisor_url: "{{ hypervisor_cfg_effective.url }}"
hypervisor_username: "{{ hypervisor_cfg_effective.username }}"
hypervisor_password: "{{ hypervisor_cfg_effective.password }}"
hypervisor_node: "{{ hypervisor_cfg_effective.node }}"
hypervisor_storage: "{{ hypervisor_cfg_effective.storage }}"
hypervisor_datacenter: "{{ hypervisor_cfg_effective.datacenter }}"
hypervisor_cluster: "{{ hypervisor_cfg_effective.cluster }}"
hypervisor_validate_certs: "{{ hypervisor_cfg_effective.validate_certs | bool }}"
changed_when: false

View File

@@ -4,96 +4,59 @@
msg: Global defaults loaded. msg: Global defaults loaded.
changed_when: false changed_when: false
- name: Normalize hypervisor inputs
ansible.builtin.include_tasks: hypervisor.yml
- name: Normalize system inputs
ansible.builtin.include_tasks: system.yml
- name: Validate variables - name: Validate variables
ansible.builtin.assert: ansible.builtin.include_tasks: validation.yml
that:
- install_type is defined and install_type in ["virtual", "physical"]
- hypervisor in ["libvirt", "proxmox", "vmware", "none"]
- >-
install_type is defined and (
install_type == "physical"
or hypervisor in ["libvirt", "proxmox", "vmware"]
)
- filesystem is defined and filesystem in ["btrfs", "ext4", "xfs"]
- install_drive is defined and install_drive | length > 0
- hostname is defined and hostname | length > 0
- >-
os is defined and os in [
"archlinux", "almalinux", "debian11", "debian12", "debian13", "fedora",
"rhel8", "rhel9", "rhel10", "rocky", "ubuntu", "ubuntu-lts"
]
- >-
os is defined and (
os not in ["rhel8", "rhel9", "rhel10"]
or (rhel_iso is defined and rhel_iso | length > 0)
)
- >-
install_type is defined and (
install_type == "physical"
or (boot_iso is defined and boot_iso | length > 0)
)
- >-
install_type is defined and (
install_type == "physical"
or (vm_cpus is defined and (vm_cpus | int) > 0)
)
- >-
install_type is defined and (
install_type == "physical"
or (vm_size is defined and (vm_size | float) > 0)
)
- >-
install_type is defined and (
install_type == "physical"
or (vm_memory is defined and (vm_memory | float) > 0)
)
- >-
install_type is defined and filesystem is defined and (
install_type == "physical"
or (
vm_size is defined
and (vm_size | int) >= 20
)
)
- >-
install_type is defined and (
install_type == "physical"
or (
vm_size is defined
and vm_memory is defined
and filesystem is defined
and (
filesystem != "btrfs"
or (
(vm_size | float)
>= (
(vm_memory | float / 1024 >= 16.0)
| ternary(
(vm_memory | float / 2048),
[vm_memory | float / 1024, 4.0] | max
)
+ 5.5
)
)
)
)
)
- >-
vm_ip is not defined
or vm_ip | length == 0
or (vm_nms is defined and (vm_nms | int) > 0)
fail_msg: Invalid input specified, please try again.
- name: Set OS family flags - name: Set OS family flags
ansible.builtin.set_fact: ansible.builtin.set_fact:
is_rhel: "{{ os | lower in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] }}" is_rhel: "{{ os | lower in ['almalinux', 'fedora', 'rhel', 'rocky'] }}"
is_debian: "{{ os | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts'] }}" is_debian: "{{ os | lower in ['debian', 'ubuntu', 'ubuntu-lts'] }}"
changed_when: false
- name: Normalize OS version for keying
when:
- os_version is defined
- (os_version | string | length) > 0
ansible.builtin.set_fact:
os_version_major: "{{ (os_version | string).split('.')[0] }}"
changed_when: false
- name: Resolve final OS key with version
when:
- os_version is defined
- (os_version | string | length) > 0
ansible.builtin.set_fact:
os_resolved: >-
{{
'debian' + os_version | string if os == 'debian'
else 'fedora' + os_version | string if os == 'fedora'
else 'rocky' + os_version_major if os == 'rocky'
else 'almalinux' + os_version_major if os == 'almalinux'
else 'rhel' + os_version_major if os == 'rhel'
else os
}}
changed_when: false
- name: Set chroot command wrapper
ansible.builtin.set_fact:
chroot_command: >-
{{
'systemd-nspawn -D /mnt'
if chroot_tool == 'systemd-nspawn'
else chroot_tool ~ ' /mnt'
}}
changed_when: false changed_when: false
- name: Set Python interpreter for RHEL-based installers - name: Set Python interpreter for RHEL-based installers
when: when:
- ansible_python_interpreter is not defined - ansible_python_interpreter is not defined
- os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] - is_rhel | bool
ansible.builtin.set_fact: ansible.builtin.set_fact:
ansible_python_interpreter: /usr/bin/python3 ansible_python_interpreter: /usr/bin/python3
changed_when: false changed_when: false
@@ -107,8 +70,10 @@
ansible_password: "{{ user_password }}" ansible_password: "{{ user_password }}"
ansible_become_password: "{{ user_password }}" ansible_become_password: "{{ user_password }}"
ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" ansible_ssh_extra_args: "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
changed_when: false
- name: Set connection for VMware - name: Set connection for VMware
when: hypervisor == "vmware" when: hypervisor == "vmware"
ansible.builtin.set_fact: ansible.builtin.set_fact:
ansible_connection: vmware_tools ansible_connection: vmware_tools
changed_when: false

View File

@@ -0,0 +1,291 @@
---
- 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: Normalize base system fields
vars:
system_name_effective: >-
{{
system.name
if system.name is defined and (system.name | string | length) > 0
else (
hostname
if hostname is defined and (hostname | string | length) > 0
else inventory_hostname
)
}}
system_id_effective: >-
{{
system.id
if system.id is defined and (system.id | string | length) > 0
else (vm_id | default(''))
}}
system_cpus_effective: >-
{{
system.cpus
if system.cpus is defined and (system.cpus | int) > 0
else (vm_cpus | default(0))
}}
system_memory_mb_effective: >-
{{
system.memory_mb
if system.memory_mb is defined and (system.memory_mb | int) > 0
else (vm_memory | default(0))
}}
system_balloon_mb_effective: >-
{{
system.balloon_mb
if system.balloon_mb is defined and (system.balloon_mb | int) > 0
else (vm_ballo | default(''))
}}
system_network_effective: >-
{{
system.network
if system.network is defined and (system.network | string | length) > 0
else (vm_nif | default(''))
}}
system_vlan_effective: >-
{{
system.vlan
if system.vlan is defined and (system.vlan | string | length) > 0
else (vlan_name | default(''))
}}
system_ip_effective: >-
{{
system.ip
if system.ip is defined and (system.ip | string | length) > 0
else (vm_ip | default(''))
}}
system_prefix_effective: >-
{{
system.prefix
if system.prefix is defined and (system.prefix | int) > 0
else (vm_nms | default(''))
}}
system_gateway_effective: >-
{{
system.gateway
if system.gateway is defined and (system.gateway | string | length) > 0
else (vm_gw | default(''))
}}
system_dns_servers_effective: >-
{{
system.dns_servers
if system.dns_servers is defined
else (vm_dns | default([]))
}}
system_dns_search_effective: >-
{{
system.dns_search
if system.dns_search is defined
else (vm_dns_search | default([]))
}}
system_path_effective: >-
{{
system.path
if system.path is defined and (system.path | string | length) > 0
else (
system.hypervisor_path
if system.hypervisor_path is defined and (system.hypervisor_path | string | length) > 0
else (vm_path | default(''))
)
}}
ansible.builtin.set_fact:
hostname: "{{ system_name_effective }}"
system_cfg: >-
{{
system_defaults
| combine(system, recursive=True)
| combine(
{
'name': system_name_effective,
'id': system_id_effective,
'cpus': system_cpus_effective,
'memory_mb': system_memory_mb_effective,
'balloon_mb': system_balloon_mb_effective,
'network': system_network_effective,
'vlan': system_vlan_effective,
'ip': system_ip_effective,
'prefix': system_prefix_effective,
'gateway': system_gateway_effective,
'dns_servers': system_dns_servers_effective,
'dns_search': system_dns_search_effective,
'path': system_path_effective
},
recursive=True
)
}}
changed_when: false
- name: Normalize system disks input
vars:
system_disk_defaults:
size: 0
device: ""
mount: ""
fstype: ""
label: ""
opts: "defaults"
system_disks_raw: >-
{{
system_cfg.disks
if system_cfg.disks is defined
else []
}}
system_disks_legacy: >-
{{
[ {'size': vm_size} ]
if (system_disks_raw | length) == 0 and (vm_size is defined and (vm_size | float) > 0)
else []
}}
system_disks_effective: >-
{{
system_disks_raw
if (system_disks_raw | length) > 0
else system_disks_legacy
}}
system_disk_device_prefix: >-
{{
'/dev/vd'
if (install_type | default('')) == 'virtual' and (hypervisor | default('')) == 'libvirt'
else (
'/dev/xvd'
if (install_type | default('')) == 'virtual' and (hypervisor | default('')) == 'xen'
else (
'/dev/sd'
if (install_type | default('')) == 'virtual'
and (hypervisor | default('')) in ['proxmox', 'vmware']
else ''
)
)
}}
system_disk_letter_map: "abcdefghijklmnopqrstuvwxyz"
block:
- name: Validate system disks type
ansible.builtin.assert:
that:
- system_disks_effective 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_effective }}"
loop_control:
label: "{{ item | to_json }}"
- name: Validate system disk count
ansible.builtin.assert:
that:
- (system_disks_effective | length) <= 26
fail_msg: "system.disks supports at most 26 entries."
quiet: true
- name: Build normalized system disk configuration
ansible.builtin.set_fact:
system_disks_cfg: "{{ system_disks_cfg | default([]) + [system_disk_cfg] }}"
vars:
disk_idx: "{{ ansible_loop.index0 }}"
disk_letter: "{{ system_disk_letter_map[disk_idx] }}"
disk_device_default: >-
{{
(
install_drive
if disk_idx == 0 and install_drive is defined and (install_drive | string | length) > 0
else (system_disk_device_prefix ~ disk_letter)
)
if (install_type | default('')) == 'virtual'
else (
install_drive
if disk_idx == 0 and install_drive is defined and (install_drive | string | length) > 0
else ''
)
}}
system_disk_cfg_base: "{{ system_disk_defaults | combine(item, recursive=True) }}"
system_disk_cfg_tmp: >-
{{
system_disk_cfg_base
| combine(
{
'device': (
system_disk_cfg_base.device
if system_disk_cfg_base.device | string | length > 0
else disk_device_default
),
'fstype': (
system_disk_cfg_base.fstype
if system_disk_cfg_base.fstype | string | length > 0
else (
'ext4'
if system_disk_cfg_base.mount | string | length > 0
else ''
)
)
},
recursive=True
)
}}
system_disk_partition_device: >-
{{
system_disk_cfg_tmp.device
~ ('p1' if (system_disk_cfg_tmp.device | regex_search('\\d$')) else '1')
}}
system_disk_cfg: >-
{{
system_disk_cfg_tmp
| combine(
{
'partition': system_disk_partition_device
},
recursive=True
)
}}
loop: "{{ system_disks_effective }}"
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 | default([])}, recursive=True) }}"
changed_when: false
- name: Set install_drive from system disk definition (if needed)
when:
- (install_drive is not defined) or (install_drive | string | length) == 0
- 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
- name: Set legacy vm_* aliases (compat)
ansible.builtin.set_fact:
vm_id: "{{ system_cfg.id }}"
vm_cpus: "{{ system_cfg.cpus }}"
vm_memory: "{{ system_cfg.memory_mb }}"
vm_ballo: "{{ system_cfg.balloon_mb }}"
vm_nif: "{{ system_cfg.network }}"
vlan_name: "{{ system_cfg.vlan }}"
vm_ip: "{{ system_cfg.ip }}"
vm_nms: "{{ system_cfg.prefix }}"
vm_gw: "{{ system_cfg.gateway }}"
vm_dns: "{{ system_cfg.dns_servers }}"
vm_dns_search: "{{ system_cfg.dns_search }}"
vm_path: "{{ system_cfg.path }}"
vm_size: "{{ (system_cfg.disks | default([]) | first | default({})).size | default(0) }}"
changed_when: false

View File

@@ -0,0 +1,234 @@
---
- name: Validate core variables
ansible.builtin.assert:
that:
- install_type is defined
- install_type in ["virtual", "physical"]
- hypervisor is defined
- hypervisor in ["libvirt", "proxmox", "vmware", "xen", "none"]
- filesystem is defined
- filesystem in ["btrfs", "ext4", "xfs"]
- install_drive is defined
- install_drive | string | length > 0
- hostname is defined
- hostname | string | length > 0
fail_msg: Invalid core variables were specified, please check your inventory/vars.
quiet: true
- name: Validate install_type/hypervisor relationship
ansible.builtin.assert:
that:
- install_type == "physical" or hypervisor in ["libvirt", "proxmox", "vmware", "xen"]
fail_msg: "hypervisor must be one of: libvirt, proxmox, vmware, xen when install_type=virtual."
quiet: true
- name: Validate OS and version inputs
ansible.builtin.assert:
that:
- os is defined
- os in ["almalinux", "alpine", "archlinux", "debian", "fedora", "opensuse", "rhel", "rocky", "ubuntu", "ubuntu-lts", "void"]
- >-
os not in ["debian", "fedora", "rocky", "almalinux", "rhel"]
or (os_version is defined and (os_version | string | length) > 0)
- >-
os_version is not defined or (os_version | string | length) == 0
or (
os == "debian" and (os_version | string) in ["10", "11", "12", "13", "unstable"]
) or (
os == "fedora" and (os_version | string) in ["40", "41", "42", "43"]
) or (
os in ["rocky", "almalinux"]
and (os_version | string) is match("^(8|9|10)(\\.\\d+)?$")
) or (
os == "rhel"
and (os_version | string) is match("^(8|9|10)(\\.\\d+)?$")
) or (
os in ["alpine", "archlinux", "opensuse", "ubuntu", "ubuntu-lts", "void"]
)
fail_msg: "Invalid os/os_version specified. Please check README.md for supported values."
quiet: true
- name: Validate RHEL ISO requirement
ansible.builtin.assert:
that:
- os != "rhel" or (rhel_iso is defined and (rhel_iso | string | length) > 0)
fail_msg: "rhel_iso is required when os=rhel."
quiet: true
- name: Validate Proxmox hypervisor inputs
when:
- install_type == "virtual"
- hypervisor == "proxmox"
ansible.builtin.assert:
that:
- hypervisor_cfg.url | string | length > 0
- hypervisor_cfg.username | string | length > 0
- hypervisor_cfg.password | string | length > 0
- hypervisor_cfg.node | string | length > 0
- hypervisor_cfg.storage | string | length > 0
- system_cfg.id | string | length > 0
- system_cfg.network | string | length > 0
fail_msg: "Missing required Proxmox inputs. Define hypervisor.(url,username,password,node,storage) and system.(id,network)."
quiet: true
- name: Validate VMware hypervisor inputs
when:
- install_type == "virtual"
- hypervisor == "vmware"
ansible.builtin.assert:
that:
- hypervisor_cfg.url | string | length > 0
- hypervisor_cfg.username | string | length > 0
- hypervisor_cfg.password | string | length > 0
- hypervisor_cfg.datacenter | string | length > 0
- hypervisor_cfg.cluster | string | length > 0
- hypervisor_cfg.storage | string | length > 0
- system_cfg.network | string | length > 0
fail_msg: "Missing required VMware inputs. Define hypervisor.(url,username,password,datacenter,cluster,storage) and system.network."
quiet: true
- name: Validate Xen hypervisor inputs
when:
- install_type == "virtual"
- hypervisor == "xen"
ansible.builtin.assert:
that:
- system_cfg.network | string | length > 0
fail_msg: "Missing required Xen inputs. Define system.network."
quiet: true
- name: Validate virtual installer ISO requirement
ansible.builtin.assert:
that:
- install_type == "physical" or (boot_iso is defined and (boot_iso | string | length) > 0)
fail_msg: "boot_iso is required when install_type=virtual."
quiet: true
- name: Validate firewall and feature flags
ansible.builtin.assert:
that:
- firewall_backend is defined
- firewall_backend in ["firewalld", "ufw"]
- firewall_toolkit is defined
- firewall_toolkit in ["iptables", "nftables"]
- firewall_enabled is defined
- motd_enabled is defined
- sudo_banner_enabled is defined
- luks_enabled is defined
- chroot_tool is defined
- chroot_tool in ["arch-chroot", "chroot", "systemd-nspawn"]
fail_msg: Invalid feature flags were specified, please check your inventory/vars.
quiet: true
- name: Validate system configuration exists
ansible.builtin.assert:
that:
- system_cfg is defined
- system_cfg is mapping
fail_msg: "system configuration is missing. Define system: {...} or legacy vm_* variables."
quiet: true
- name: Validate virtual system sizing
when: install_type == "virtual"
ansible.builtin.assert:
that:
- system_cfg.cpus is defined and (system_cfg.cpus | int) > 0
- system_cfg.memory_mb is defined and (system_cfg.memory_mb | int) > 0
- system_cfg.disks is defined and (system_cfg.disks | length) > 0
- (system_cfg.disks[0].size | float) > 0
- (system_cfg.disks[0].size | float) >= 20
- >-
filesystem != "btrfs"
or (
(system_cfg.disks[0].size | float)
>= (
(
(system_cfg.memory_mb | float / 1024 >= 16.0)
| ternary(
(system_cfg.memory_mb | float / 2048),
[system_cfg.memory_mb | float / 1024, 4.0] | max
)
)
+ 5.5
)
)
fail_msg: "Invalid system sizing. Check system.cpus, system.memory_mb, and system.disks[0].size."
quiet: true
- name: Validate all virtual disks have a positive size
when: install_type == "virtual"
ansible.builtin.assert:
that:
- item.size is defined
- (item.size | float) > 0
fail_msg: "Each system disk must have a positive size when install_type=virtual: {{ item | to_json }}"
quiet: true
loop: "{{ system_cfg.disks | default([]) }}"
loop_control:
label: "{{ item | to_json }}"
- name: Validate primary disk mount is not used
when:
- system_cfg.disks is defined
- system_cfg.disks | length > 0
ansible.builtin.assert:
that:
- (system_cfg.disks[0].mount | default('') | string | trim) == ''
fail_msg: "system.disks[0].mount must be empty; use system.disks[1:] for additional mounts."
quiet: true
- name: Validate disk mountpoint inputs
vars:
system_disk_mounts: >-
{{
(system_cfg.disks | default([]))
| map(attribute='mount')
| map('string')
| map('trim')
| reject('equalto', '')
| list
}}
ansible.builtin.assert:
that:
- system_disk_mounts | length == (system_disk_mounts | unique | list | length)
fail_msg: "Duplicate disk mountpoints found in system.disks."
quiet: true
- name: Validate disk mount definitions
when: system_cfg.disks is defined
vars:
reserved_mounts:
- /boot
- /boot/efi
- /home
- /swap
- /var
- /var/cache/pacman/pkg
- /var/log
- /var/log/audit
disk_mount: "{{ (item.mount | default('') | string) | trim }}"
disk_fstype: "{{ (item.fstype | default('') | string) | trim }}"
disk_device: "{{ (item.device | default('') | string) | trim }}"
disk_size: "{{ item.size | default(0) }}"
ansible.builtin.assert:
that:
- disk_mount == "" or disk_mount.startswith("/")
- disk_mount == "" or disk_mount != "/"
- disk_mount == "" or disk_mount not in reserved_mounts
- disk_mount == "" or disk_fstype in ["btrfs", "ext4", "xfs"]
- disk_mount == "" or install_type == "virtual" or (disk_device | length) > 0
- disk_mount == "" or install_type != "virtual" or (disk_size | float) > 0
fail_msg: "Invalid system disk entry: {{ item | to_json }}"
quiet: true
loop: "{{ system_cfg.disks }}"
loop_control:
label: "{{ item | to_json }}"
- name: Validate static IP requirements
when: system_cfg.ip is defined and (system_cfg.ip | string | length) > 0
ansible.builtin.assert:
that:
- system_cfg.prefix is defined
- (system_cfg.prefix | int) > 0
fail_msg: "system.prefix is required when system.ip is set."
quiet: true

View File

@@ -51,7 +51,7 @@ partitioning_efi_mountpoint: >-
if (partitioning_separate_boot | bool) if (partitioning_separate_boot | bool)
else ( else (
'/boot/efi' '/boot/efi'
if is_rhel or (os | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts']) if is_rhel or (os in ['ubuntu', 'ubuntu-lts'] or (os == 'debian' and (os_version | string) in ['11', '12', '13']))
else '/boot' else '/boot'
) )
}} }}

View File

@@ -47,20 +47,20 @@
args: args:
creates: /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }} creates: /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
loop: loop:
- {subvol: root} - { subvol: root }
- {subvol: swap} - { subvol: swap }
- {subvol: home} - { subvol: home }
- {subvol: var} - { subvol: var }
- {subvol: pkg} - { subvol: pkg }
- {subvol: var_log} - { subvol: var_log }
- {subvol: var_log_audit} - { subvol: var_log_audit }
register: partitioning_btrfs_subvol_result register: partitioning_btrfs_subvol_result
- name: Set quotas for subvolumes - name: Set quotas for subvolumes
when: cis_enabled when: cis_enabled
ansible.builtin.command: btrfs qgroup limit {{ item.quota }} /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }} ansible.builtin.command: btrfs qgroup limit {{ item.quota }} /mnt/{{ '@' if item.subvol == 'root' else '@' + item.subvol }}
loop: loop:
- {subvol: home, quota: 2G} - { subvol: home, quota: 2G }
register: partitioning_btrfs_qgroup_result register: partitioning_btrfs_qgroup_result
changed_when: false changed_when: false

View File

@@ -6,20 +6,22 @@
fstype: ext4 fstype: ext4
force: true force: true
loop: loop:
- {lv: root} - { lv: root }
- {lv: home} - { lv: home }
- {lv: var} - { lv: var }
- {lv: var_log} - { lv: var_log }
- {lv: var_log_audit} - { lv: var_log_audit }
- name: Remove Unsupported features for older Systems - name: Remove Unsupported features for older Systems
when: (os | lower in ['almalinux', 'debian11', 'rhel8', 'rhel9', 'rocky']) and (cis_enabled or item.lv not in ['home', 'var', 'var_log', 'var_log_audit']) when: >
(os in ['almalinux', 'rocky', 'rhel'] or (os == 'debian' and (os_version | string) == '11'))
and (cis_enabled or item.lv not in ['home', 'var', 'var_log', 'var_log_audit'])
ansible.builtin.command: tune2fs -O "^orphan_file,^metadata_csum_seed" "/dev/sys/{{ item.lv }}" ansible.builtin.command: tune2fs -O "^orphan_file,^metadata_csum_seed" "/dev/sys/{{ item.lv }}"
loop: loop:
- {lv: root} - { lv: root }
- {lv: home} - { lv: home }
- {lv: var} - { lv: var }
- {lv: var_log} - { lv: var_log }
- {lv: var_log_audit} - { lv: var_log_audit }
register: partitioning_ext4_tune_result register: partitioning_ext4_tune_result
changed_when: partitioning_ext4_tune_result.rc == 0 changed_when: partitioning_ext4_tune_result.rc == 0

View File

@@ -0,0 +1,85 @@
---
- name: Determine additional disks to auto-mount
ansible.builtin.set_fact:
partitioning_extra_disks: >-
{{
(system_cfg.disks | default([]))[1:]
| selectattr('mount')
| list
}}
changed_when: false
- name: Validate additional disks do not target install_drive
when: partitioning_extra_disks | length > 0
ansible.builtin.assert:
that:
- item.device is defined
- item.device | string | length > 0
- item.device != install_drive
- item.partition is defined
- item.partition | string | length > 0
- item.fstype is defined
- item.fstype in ['btrfs', 'ext4', 'xfs']
- item.mount is defined
- item.mount | string | length > 0
- item.mount.startswith('/')
- item.mount != '/'
fail_msg: "Invalid additional disk definition: {{ item | to_json }}"
quiet: true
loop: "{{ partitioning_extra_disks }}"
loop_control:
label: "{{ item | to_json }}"
- name: Partition additional disks
when: partitioning_extra_disks | length > 0
community.general.parted:
device: "{{ item.device }}"
label: gpt
number: 1
part_start: "1MiB"
part_end: "100%"
name: "{{ (item.label | default('') | string | length > 0) | ternary(item.label, 'data') }}"
state: present
loop: "{{ partitioning_extra_disks }}"
loop_control:
label: "{{ item.device }}"
- name: Settle partition tables for additional disks
when: partitioning_extra_disks | length > 0
ansible.builtin.command: udevadm settle
changed_when: false
- name: Create filesystems on additional disks
when: partitioning_extra_disks | length > 0
community.general.filesystem:
dev: "{{ item.partition }}"
fstype: "{{ item.fstype }}"
opts: "{{ ('-L ' ~ item.label) if (item.label | default('') | string | length) > 0 else omit }}"
force: true
loop: "{{ partitioning_extra_disks }}"
loop_control:
label: "{{ item.partition }}"
- name: Ensure mount directories exist for additional disks
when: partitioning_extra_disks | length > 0
ansible.builtin.file:
path: "/mnt{{ item.mount }}"
state: directory
owner: root
group: root
mode: "0755"
loop: "{{ partitioning_extra_disks }}"
loop_control:
label: "{{ item.mount }}"
- name: Mount additional disks for fstab generation
when: partitioning_extra_disks | length > 0
ansible.posix.mount:
path: "/mnt{{ item.mount }}"
src: "{{ item.partition }}"
fstype: "{{ item.fstype }}"
opts: "{{ item.opts | default('defaults') }}"
state: mounted
loop: "{{ partitioning_extra_disks }}"
loop_control:
label: "{{ item.mount }}"

View File

@@ -403,9 +403,9 @@
size: "{{ partitioning_lvm_swap_gb | string + 'G' }}" size: "{{ partitioning_lvm_swap_gb | string + 'G' }}"
- lv: home - lv: home
size: "{{ partitioning_lvm_home_gb | string + 'G' }}" size: "{{ partitioning_lvm_home_gb | string + 'G' }}"
- {lv: var, size: "2G"} - { lv: var, size: "2G" }
- {lv: var_log, size: "2G"} - { lv: var_log, size: "2G" }
- {lv: var_log_audit, size: "1.5G"} - { lv: var_log_audit, size: "1.5G" }
- name: Create filesystems - name: Create filesystems
block: block:
@@ -427,7 +427,7 @@
when: when:
- partitioning_separate_boot | bool - partitioning_separate_boot | bool
- partitioning_boot_fs_fstype == 'ext4' - partitioning_boot_fs_fstype == 'ext4'
- os | lower in ['almalinux', 'debian11', 'rhel8', 'rhel9', 'rocky'] - os in ['almalinux', 'rocky', 'rhel'] or (os == 'debian' and (os_version | string) == '11')
ansible.builtin.command: >- ansible.builtin.command: >-
tune2fs -O "^orphan_file,^metadata_csum_seed" tune2fs -O "^orphan_file,^metadata_csum_seed"
"{{ install_drive }}{{ partitioning_boot_fs_partition_suffix }}" "{{ install_drive }}{{ partitioning_boot_fs_partition_suffix }}"
@@ -548,14 +548,14 @@
- name: Mount filesystems and subvolumes - name: Mount filesystems and subvolumes
when: when:
- >- - >-
cis_enabled or ( cis_enabled or (
not cis_enabled and ( not cis_enabled and (
(filesystem == 'btrfs' and item.path in ['/home', '/var/log', '/var/cache/pacman/pkg']) (filesystem == 'btrfs' and item.path in ['/home', '/var/log', '/var/cache/pacman/pkg'])
or (item.path not in ['/home', '/var', '/var/log', '/var/log/audit', '/var/cache/pacman/pkg']) or (item.path not in ['/home', '/var', '/var/log', '/var/log/audit', '/var/cache/pacman/pkg'])
)
) )
)
- >- - >-
not (item.path in ['/swap', '/var/cache/pacman/pkg'] and filesystem != 'btrfs') not (item.path in ['/swap', '/var/cache/pacman/pkg'] and filesystem != 'btrfs')
- swap_enabled | bool or item.path != '/swap' - swap_enabled | bool or item.path != '/swap'
ansible.posix.mount: ansible.posix.mount:
path: /mnt{{ item.path }} path: /mnt{{ item.path }}
@@ -663,3 +663,6 @@
ansible.builtin.command: "{{ partitioning_swap_cmd }}" ansible.builtin.command: "{{ partitioning_swap_cmd }}"
register: partitioning_swap_activate_result register: partitioning_swap_activate_result
changed_when: partitioning_swap_activate_result.rc == 0 changed_when: partitioning_swap_activate_result.rc == 0
- name: Mount additional disks
ansible.builtin.include_tasks: extra_disks.yml

View File

@@ -6,8 +6,8 @@
fstype: xfs fstype: xfs
force: true force: true
loop: loop:
- {lv: root} - { lv: root }
- {lv: home} - { lv: home }
- {lv: var} - { lv: var }
- {lv: var_log} - { lv: var_log }
- {lv: var_log_audit} - { lv: var_log_audit }

View File

@@ -0,0 +1,188 @@
---
- name: Gather minimal facts for safety checks
ansible.builtin.setup:
gather_subset:
- "!all"
- "min"
- "mounts"
changed_when: false
- name: Production system protection check
block:
- name: Check for OS release information
ansible.builtin.stat:
path: /etc/os-release
register: system_check_os_release_exists
- name: Check for live environment markers
ansible.builtin.stat:
path: "{{ item }}"
loop:
- /run/archiso
- /run/live
- /run/initramfs
- /run/initramfs/live
register: system_check_live_markers
changed_when: false
- name: Determine root filesystem type
ansible.builtin.set_fact:
system_check_root_fstype: >-
{{
ansible_mounts
| selectattr('mount', 'equalto', '/')
| map(attribute='fstype')
| list
| first
| default('')
| lower
}}
changed_when: false
- name: Identify live environment indicators
ansible.builtin.set_fact:
system_check_is_live_environment: >-
{{
(not system_check_os_release_exists.stat.exists)
or (
system_check_live_markers.results
| selectattr('stat.exists')
| list
| length
> 0
)
or system_check_root_fstype in ['overlay', 'overlayfs', 'squashfs', 'aufs']
or (ansible_hostname | default('') | lower is search('live'))
}}
changed_when: false
- name: Assert target is not a production system
ansible.builtin.assert:
that:
- system_check_is_live_environment | bool
fail_msg: |
PRODUCTION SYSTEM DETECTED - ABORTING
The target system appears to be a production environment with an already
installed operating system. This playbook is designed to run ONLY on
live installer environments (e.g., ArchLinux ISO, Debian netinst).
DO NOT proceed on production systems. This could result in data loss.
To use this playbook:
1. Boot from a live installer ISO (ArchLinux, Debian, Ubuntu, etc.)
2. Run playbook against live environment
3. Target an empty disk for installation
If you are certain you want to proceed, you must verify you are running
from a live environment, not an installed system.
quiet: true
- name: VM existence protection check
when: install_type == "virtual"
block:
- name: Check if VM already exists on libvirt
when: hypervisor == "libvirt"
delegate_to: localhost
become: false
community.libvirt.virt:
command: list_vms
register: system_check_libvirt_existing_vms
changed_when: false
failed_when: false
- name: Abort if VM already exists on libvirt
when: hypervisor == "libvirt"
ansible.builtin.assert:
that:
- hostname not in system_check_libvirt_existing_vms.domains | default([])
fail_msg: |
VM {{ hostname }} already exists on libvirt hypervisor.
To avoid data loss, the playbook will not overwrite or delete existing VMs.
Please choose a different hostname or remove the existing VM manually before proceeding.
quiet: true
- name: Check if VM already exists on Proxmox
when: hypervisor == "proxmox"
delegate_to: localhost
become: false
community.proxmox.proxmox_vm_info:
api_host: "{{ hypervisor_url }}"
api_user: "{{ hypervisor_username }}"
api_password: "{{ hypervisor_password }}"
node: "{{ hypervisor_node }}"
vmid: "{{ system_cfg.id }}"
name: "{{ hostname }}"
type: qemu
register: system_check_proxmox_check_result
changed_when: false
- name: Abort if VM already exists on Proxmox
when: hypervisor == "proxmox"
ansible.builtin.assert:
that:
- system_check_proxmox_check_result.proxmox_vms | default([]) | length == 0
fail_msg: |
VM {{ hostname }} (ID: {{ system_cfg.id }}) already exists on Proxmox hypervisor.
To avoid data loss, the playbook will not overwrite or delete existing VMs.
Please choose a different hostname or VM ID, or remove the existing VM manually before proceeding.
quiet: true
- name: Check if VM already exists in vCenter
when: hypervisor == "vmware"
delegate_to: localhost
community.vmware.vmware_guest_info:
hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}"
validate_certs: "{{ hypervisor_validate_certs }}"
datacenter: "{{ hypervisor_datacenter }}"
name: "{{ hostname }}"
folder: "{{ system_cfg.path if system_cfg.path | length > 0 else omit }}"
register: system_check_vmware_check_result
failed_when: false
changed_when: false
- name: Fail if vCenter lookup failed unexpectedly
when: hypervisor == "vmware"
ansible.builtin.assert:
that:
- not system_check_vmware_check_result.failed
or (system_check_vmware_check_result.msg is search('non-existing VM'))
fail_msg: |
Unable to verify VM existence in vCenter.
{{ system_check_vmware_check_result.msg | default('Unknown error') }}
quiet: true
- name: Abort if VM already exists in vCenter
when: hypervisor == "vmware"
ansible.builtin.assert:
that:
- system_check_vmware_check_result.instance is not defined
fail_msg: |
VM {{ hostname }} already exists in vCenter.
To avoid data loss, the playbook will not overwrite or delete existing VMs.
Please choose a different hostname or remove the existing VM manually before proceeding.
quiet: true
- name: Check if VM already exists on Xen
when: hypervisor == "xen"
delegate_to: localhost
ansible.builtin.command:
argv:
- xl
- list
register: system_check_xen_existing_vms
changed_when: false
failed_when: false
- name: Abort if VM already exists on Xen
when: hypervisor == "xen"
ansible.builtin.assert:
that:
- hostname not in system_check_xen_existing_vms.stdout | default('')
fail_msg: |
VM {{ hostname }} already exists on Xen hypervisor.
To avoid data loss, the playbook will not overwrite or delete existing VMs.
Please choose a different hostname or remove the existing VM manually before proceeding.
quiet: true

View File

@@ -1,12 +1,15 @@
--- ---
virtualization_libvirt_image_dir: >- virtualization_libvirt_image_dir: >-
{{ vm_path if vm_path is defined and vm_path | length > 0 else '/var/lib/libvirt/images' }} {{
system_cfg.path
if system_cfg is defined and (system_cfg.path | string | length) > 0
else '/var/lib/libvirt/images'
}}
virtualization_libvirt_disk_path: >- virtualization_libvirt_disk_path: >-
{{ [virtualization_libvirt_image_dir, hostname ~ '.qcow2'] | ansible.builtin.path_join }} {{ [virtualization_libvirt_image_dir, hostname ~ '.qcow2'] | ansible.builtin.path_join }}
virtualization_libvirt_cloudinit_path: >- virtualization_libvirt_cloudinit_path: >-
{{ [virtualization_libvirt_image_dir, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }} {{ [virtualization_libvirt_image_dir, hostname ~ '-cloudinit.iso'] | ansible.builtin.path_join }}
virtualization_mac_address: >- virtualization_xen_disk_path: /var/lib/xen/images
{{ '52:54:00' | community.general.random_mac(seed=hostname) }}
virtualization_tpm2_enabled: >- virtualization_tpm2_enabled: >-
{{ {{

View File

@@ -1,5 +1,31 @@
--- ---
- name: Create VM disk - name: Build disk definitions
ansible.builtin.set_fact:
virtualization_libvirt_disks: "{{ virtualization_libvirt_disks | default([]) + [virtualization_libvirt_disk_cfg] }}"
vars:
device_letter_map: "abcdefghijklmnopqrstuvwxyz"
device_letter: "{{ device_letter_map[ansible_loop.index0] }}"
virtualization_libvirt_disk_cfg: >-
{{
{
'path': (
virtualization_libvirt_disk_path
if ansible_loop.index0 == 0
else ([virtualization_libvirt_image_dir, hostname ~ '-disk' ~ ansible_loop.index0 ~ '.qcow2'] | ansible.builtin.path_join)
),
'target': 'vd' ~ device_letter,
'bus': 'virtio',
'format': 'qcow2',
'size': (item.size | float)
}
}}
loop: "{{ system_cfg.disks }}"
loop_control:
label: "{{ item | to_json }}"
extended: true
changed_when: false
- name: Create VM disks
delegate_to: localhost delegate_to: localhost
ansible.builtin.command: ansible.builtin.command:
argv: argv:
@@ -7,19 +33,22 @@
- create - create
- -f - -f
- qcow2 - qcow2
- "{{ virtualization_libvirt_disk_path }}" - "{{ item.path }}"
- "{{ vm_size }}G" - "{{ item.size }}G"
creates: "{{ virtualization_libvirt_disk_path }}" creates: "{{ item.path }}"
loop: "{{ virtualization_libvirt_disks }}"
loop_control:
label: "{{ item.path }}"
- name: Render cloud config templates - name: Render cloud config templates
delegate_to: localhost delegate_to: localhost
ansible.builtin.template: ansible.builtin.template:
src: "{{ item.src }}" src: "{{ item.src }}"
dest: /tmp/{{ item.dest_prefix }}-{{ hostname }}.yml dest: /tmp/{{ item.dest_prefix }}-{{ hostname }}.yml
mode: '0644' mode: "0644"
loop: loop:
- {src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data} - { src: cloud-user-data.yml.j2, dest_prefix: cloud-user-data }
- {src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config} - { src: cloud-network-config.yml.j2, dest_prefix: cloud-network-config }
- name: Create cloud-init disk - name: Create cloud-init disk
delegate_to: localhost delegate_to: localhost
@@ -43,3 +72,9 @@
community.libvirt.virt: community.libvirt.virt:
name: "{{ hostname }}" name: "{{ hostname }}"
state: running state: running
register: virtualization_libvirt_start_result
- name: Set VM created fact
ansible.builtin.set_fact:
virtualization_vm_created_in_run: true
when: virtualization_libvirt_start_result is defined and virtualization_libvirt_start_result.changed | bool

View File

@@ -2,7 +2,7 @@
- name: Deploy VM on Proxmox - name: Deploy VM on Proxmox
delegate_to: localhost delegate_to: localhost
vars: vars:
virtualization_dns_value: "{{ vm_dns if vm_dns is defined else '' }}" virtualization_dns_value: "{{ system_cfg.dns_servers if system_cfg.dns_servers is defined else '' }}"
virtualization_dns_list_raw: >- virtualization_dns_list_raw: >-
{{ {{
virtualization_dns_value virtualization_dns_value
@@ -11,7 +11,7 @@
}} }}
virtualization_dns_list: >- virtualization_dns_list: >-
{{ virtualization_dns_list_raw | map('trim') | reject('equalto', '') | list }} {{ virtualization_dns_list_raw | map('trim') | reject('equalto', '') | list }}
virtualization_search_value: "{{ vm_dns_search if vm_dns_search is defined else '' }}" virtualization_search_value: "{{ system_cfg.dns_search if system_cfg.dns_search is defined else '' }}"
virtualization_search_list_raw: >- virtualization_search_list_raw: >-
{{ {{
virtualization_search_value virtualization_search_value
@@ -20,6 +20,12 @@
}} }}
virtualization_search_list: >- virtualization_search_list: >-
{{ virtualization_search_list_raw | map('trim') | reject('equalto', '') | list }} {{ virtualization_search_list_raw | map('trim') | reject('equalto', '') | list }}
virtualization_proxmox_scsi: >-
{%- set out = {} -%}
{%- for disk in system_cfg.disks -%}
{%- set _ = out.update({ 'scsi' ~ loop.index0: hypervisor_storage ~ ':' ~ (disk.size | int) }) -%}
{%- endfor -%}
{{ out }}
community.proxmox.proxmox_kvm: community.proxmox.proxmox_kvm:
api_host: "{{ hypervisor_url }}" api_host: "{{ hypervisor_url }}"
api_user: "{{ hypervisor_username }}" api_user: "{{ hypervisor_username }}"
@@ -28,12 +34,12 @@
cipassword: "{{ user_password }}" cipassword: "{{ user_password }}"
ciupgrade: false ciupgrade: false
node: "{{ hypervisor_node }}" node: "{{ hypervisor_node }}"
vmid: "{{ vm_id }}" vmid: "{{ system_cfg.id }}"
name: "{{ hostname }}" name: "{{ hostname }}"
cpu: host cpu: host
cores: "{{ vm_cpus }}" cores: "{{ system_cfg.cpus }}"
memory: "{{ vm_memory }}" memory: "{{ system_cfg.memory_mb }}"
balloon: "{{ vm_ballo if vm_ballo is defined and vm_ballo | int > 0 else omit }}" balloon: "{{ system_cfg.balloon_mb if system_cfg.balloon_mb is defined and system_cfg.balloon_mb | int > 0 else omit }}"
numa_enabled: true numa_enabled: true
hotplug: network,disk hotplug: network,disk
update: "{{ virtualization_tpm2_enabled | bool }}" update: "{{ virtualization_tpm2_enabled | bool }}"
@@ -42,8 +48,7 @@
machine: "{{ 'q35' if virtualization_tpm2_enabled | bool else omit }}" machine: "{{ 'q35' if virtualization_tpm2_enabled | bool else omit }}"
boot: ac boot: ac
scsihw: virtio-scsi-single scsihw: virtio-scsi-single
scsi: scsi: "{{ virtualization_proxmox_scsi }}"
scsi0: "{{ hypervisor_storage }}:{{ vm_size }}"
efidisk0: efidisk0:
efitype: 4m efitype: 4m
format: raw format: raw
@@ -60,13 +65,14 @@
ide1: "{{ rhel_iso + ',media=cdrom' if rhel_iso is defined and rhel_iso | length > 0 else omit }}" ide1: "{{ rhel_iso + ',media=cdrom' if rhel_iso is defined and rhel_iso | length > 0 else omit }}"
ide2: "{{ hypervisor_storage }}:cloudinit" ide2: "{{ hypervisor_storage }}:cloudinit"
net: net:
net0: virtio,bridge={{ vm_nif }}{% if vlan_name is defined and vlan_name | length > 0 %},tag={{ vlan_name }}{% endif %} net0: >-
virtio,bridge={{ system_cfg.network }}{% if system_cfg.vlan is defined and system_cfg.vlan | string | length > 0 %},tag={{ system_cfg.vlan }}{% endif %}
ipconfig: ipconfig:
ipconfig0: >- ipconfig0: >-
{{ {{
'ip=' ~ vm_ip ~ '/' ~ vm_nms 'ip=' ~ system_cfg.ip ~ '/' ~ system_cfg.prefix
~ (',gw=' ~ vm_gw if vm_gw is defined and vm_gw | length else '') ~ (',gw=' ~ system_cfg.gateway if system_cfg.gateway is defined and system_cfg.gateway | length else '')
if vm_ip is defined and vm_ip | length if system_cfg.ip is defined and system_cfg.ip | string | length
else 'ip=dhcp' else 'ip=dhcp'
}} }}
nameservers: "{{ virtualization_dns_list if virtualization_dns_list | length else omit }}" nameservers: "{{ virtualization_dns_list if virtualization_dns_list | length else omit }}"
@@ -82,5 +88,11 @@
api_password: "{{ hypervisor_password }}" api_password: "{{ hypervisor_password }}"
node: "{{ hypervisor_node }}" node: "{{ hypervisor_node }}"
name: "{{ hostname }}" name: "{{ hostname }}"
vmid: "{{ vm_id }}" vmid: "{{ system_cfg.id }}"
state: started state: started
register: virtualization_proxmox_start_result
- name: Set VM created fact
ansible.builtin.set_fact:
virtualization_vm_created_in_run: true
when: virtualization_proxmox_start_result is defined and virtualization_proxmox_start_result.changed | bool

View File

@@ -1,26 +1,36 @@
--- ---
- name: Build vCenter disk list
ansible.builtin.set_fact:
virtualization_vmware_disks: "{{ virtualization_vmware_disks | default([]) + [virtualization_vmware_disk_cfg] }}"
vars:
virtualization_vmware_disk_cfg:
size_gb: "{{ item.size | int }}"
type: thin
datastore: "{{ hypervisor_storage }}"
loop: "{{ system_cfg.disks }}"
loop_control:
label: "{{ item | to_json }}"
changed_when: false
- name: Create VM in vCenter - name: Create VM in vCenter
delegate_to: localhost delegate_to: localhost
community.vmware.vmware_guest: community.vmware.vmware_guest:
hostname: "{{ hypervisor_url }}" hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}" username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}" password: "{{ hypervisor_password }}"
validate_certs: false validate_certs: "{{ hypervisor_validate_certs }}"
datacenter: "{{ hypervisor_datacenter }}" datacenter: "{{ hypervisor_datacenter }}"
cluster: "{{ hypervisor_cluster }}" cluster: "{{ hypervisor_cluster }}"
folder: "{{ vm_path if vm_path is defined and vm_path | length > 0 else omit }}" folder: "{{ system_cfg.path if system_cfg.path | string | length > 0 else omit }}"
name: "{{ hostname }}" name: "{{ hostname }}"
guest_id: otherLinux64Guest guest_id: otherLinux64Guest
annotation: | annotation: |
{{ note if note is defined else '' }} {{ note if note is defined else '' }}
state: "{{ 'poweredoff' if virtualization_tpm2_enabled | bool else 'poweredon' }}" state: "{{ 'poweredoff' if virtualization_tpm2_enabled | bool else 'poweredon' }}"
disk: disk: "{{ virtualization_vmware_disks }}"
- size_gb: "{{ vm_size }}"
type: thin
datastore: "{{ hypervisor_storage }}"
hardware: hardware:
memory_mb: "{{ vm_memory }}" memory_mb: "{{ system_cfg.memory_mb }}"
num_cpus: "{{ vm_cpus }}" num_cpus: "{{ system_cfg.cpus }}"
boot_firmware: efi boot_firmware: efi
secure_boot: false secure_boot: false
cdrom: >- cdrom: >-
@@ -44,9 +54,18 @@
} ] if rhel_iso is defined and rhel_iso | length > 0 else [] ) } ] if rhel_iso is defined and rhel_iso | length > 0 else [] )
}} }}
networks: networks:
- name: "{{ vm_nif }}" - name: "{{ system_cfg.network }}"
type: dhcp type: dhcp
vlan: "{{ vlan_name if vlan_name is defined and vlan_name | length > 0 else omit }}" vlan: "{{ system_cfg.vlan if system_cfg.vlan is defined and system_cfg.vlan | string | length > 0 else omit }}"
register: virtualization_vmware_create_result
- name: Set VM created fact when VM was powered on during creation
ansible.builtin.set_fact:
virtualization_vm_created_in_run: true
when:
- virtualization_vmware_create_result is defined
- not virtualization_tpm2_enabled | bool
- virtualization_vmware_create_result.changed | bool
- name: Ensure vTPM2 is enabled when required - name: Ensure vTPM2 is enabled when required
when: virtualization_tpm2_enabled | bool when: virtualization_tpm2_enabled | bool
@@ -55,9 +74,9 @@
hostname: "{{ hypervisor_url }}" hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}" username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}" password: "{{ hypervisor_password }}"
validate_certs: false validate_certs: "{{ hypervisor_validate_certs }}"
datacenter: "{{ hypervisor_datacenter }}" datacenter: "{{ hypervisor_datacenter }}"
folder: "{{ vm_path if vm_path is defined and vm_path | length > 0 else omit }}" folder: "{{ system_cfg.path if system_cfg.path | string | length > 0 else omit }}"
name: "{{ hostname }}" name: "{{ hostname }}"
state: present state: present
@@ -68,7 +87,16 @@
hostname: "{{ hypervisor_url }}" hostname: "{{ hypervisor_url }}"
username: "{{ hypervisor_username }}" username: "{{ hypervisor_username }}"
password: "{{ hypervisor_password }}" password: "{{ hypervisor_password }}"
validate_certs: false validate_certs: "{{ hypervisor_validate_certs }}"
datacenter: "{{ hypervisor_datacenter }}" datacenter: "{{ hypervisor_datacenter }}"
name: "{{ hostname }}" name: "{{ hostname }}"
state: powered-on state: powered-on
register: virtualization_vmware_start_result
- name: Set VM created fact when VM was started separately (TPM2 case)
ansible.builtin.set_fact:
virtualization_vm_created_in_run: true
when:
- virtualization_tpm2_enabled | bool
- virtualization_vmware_start_result is defined
- virtualization_vmware_start_result.changed | bool

View File

@@ -0,0 +1,77 @@
---
- name: Deploy VM on Xen
block:
- name: Build disk definitions
ansible.builtin.set_fact:
virtualization_xen_disks: "{{ virtualization_xen_disks | default([]) + [virtualization_xen_disk_cfg] }}"
vars:
device_letter_map: "abcdefghijklmnopqrstuvwxyz"
device_letter: "{{ device_letter_map[ansible_loop.index0] }}"
virtualization_xen_disk_cfg: >-
{{
{
'path': (
virtualization_xen_disk_path ~ '/' ~ hostname ~ '.qcow2'
if ansible_loop.index0 == 0
else virtualization_xen_disk_path ~ '/' ~ hostname ~ '-disk' ~ ansible_loop.index0 ~ '.qcow2'
),
'target': 'xvd' ~ device_letter,
'size': (item.size | float)
}
}}
loop: "{{ system_cfg.disks }}"
loop_control:
label: "{{ item | to_json }}"
extended: true
changed_when: false
- name: Create VM disks for Xen
delegate_to: localhost
ansible.builtin.command:
argv:
- qemu-img
- create
- -f
- qcow2
- "{{ item.path }}"
- "{{ item.size }}G"
creates: "{{ item.path }}"
loop: "{{ virtualization_xen_disks }}"
loop_control:
label: "{{ item.path }}"
- name: Render Xen VM configuration
delegate_to: localhost
vars:
xen_installer_media_enabled: true
ansible.builtin.template:
src: xen.cfg.j2
dest: /tmp/xen-{{ hostname }}.cfg
mode: "0644"
- name: Create Xen VM
delegate_to: localhost
ansible.builtin.command:
argv:
- xl
- create
- /tmp/xen-{{ hostname }}.cfg
register: virtualization_xen_create_result
changed_when: virtualization_xen_create_result.rc == 0
- name: Ensure VM is running
delegate_to: localhost
ansible.builtin.command:
argv:
- xl
- list
register: virtualization_xen_list_result
changed_when: false
failed_when: false
- name: Set VM created fact
ansible.builtin.set_fact:
virtualization_vm_created_in_run: true
when:
- virtualization_xen_list_result is defined
- hostname in virtualization_xen_list_result.stdout

View File

@@ -4,27 +4,27 @@ network:
id0: id0:
match: match:
macaddress: "{{ virtualization_mac_address }}" macaddress: "{{ virtualization_mac_address }}"
{% set has_static = vm_ip is defined and vm_ip | length %} {% set has_static = system_cfg.ip is defined and system_cfg.ip | string | length %}
{% set dns_value = vm_dns if vm_dns is defined else '' %} {% set dns_value = system_cfg.dns_servers if system_cfg.dns_servers is defined else '' %}
{% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %} {% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %}
{% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %} {% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %}
{% set search_value = vm_dns_search if vm_dns_search is defined else '' %} {% set search_value = system_cfg.dns_search if system_cfg.dns_search is defined else '' %}
{% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %} {% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %}
{% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %} {% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %}
{% if has_static %} {% if has_static %}
addresses: addresses:
- "{{ vm_ip }}/{{ vm_nms }}" - "{{ system_cfg.ip }}/{{ system_cfg.prefix }}"
{% if vm_gw is defined and vm_gw | length %} {% if system_cfg.gateway is defined and system_cfg.gateway | string | length %}
gateway4: "{{ vm_gw }}" gateway4: "{{ system_cfg.gateway }}"
{% endif %} {% endif %}
{% else %} {% else %}
dhcp4: true dhcp4: true
{% if (vm_dns is defined and vm_dns | length) or (vm_dns_search is defined and vm_dns_search | length) %} {% if (system_cfg.dns_servers is defined and system_cfg.dns_servers | length) or (system_cfg.dns_search is defined and system_cfg.dns_search | length) %}
dhcp4-overrides: dhcp4-overrides:
{% if vm_dns is defined and vm_dns | length %} {% if system_cfg.dns_servers is defined and system_cfg.dns_servers | length %}
use-dns: false use-dns: false
{% endif %} {% endif %}
{% if vm_dns_search is defined and vm_dns_search | length %} {% if system_cfg.dns_search is defined and system_cfg.dns_search | length %}
use-domains: false use-domains: false
{% endif %} {% endif %}
{% endif %} {% endif %}

View File

@@ -1,8 +1,8 @@
<domain type='kvm'> <domain type='kvm'>
<name>{{ hostname }}</name> <name>{{ hostname }}</name>
<memory>{{ vm_memory | int * 1024 }}</memory> <memory>{{ system_cfg.memory_mb | int * 1024 }}</memory>
{% if vm_ballo is defined and vm_ballo | int > 0 %}<currentMemory>{{ vm_ballo | int * 1024 }}</currentMemory>{% endif %} {% if system_cfg.balloon_mb is defined and system_cfg.balloon_mb | int > 0 %}<currentMemory>{{ system_cfg.balloon_mb | int * 1024 }}</currentMemory>{% endif %}
<vcpu placement='static'>{{ vm_cpus }}</vcpu> <vcpu placement='static'>{{ system_cfg.cpus }}</vcpu>
<os> <os>
<type arch='x86_64' machine="pc-q35-8.0">hvm</type> <type arch='x86_64' machine="pc-q35-8.0">hvm</type>
<bootmenu enable='no'/> <bootmenu enable='no'/>
@@ -22,11 +22,13 @@
<on_reboot>restart</on_reboot> <on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash> <on_crash>destroy</on_crash>
<devices> <devices>
{% for disk in virtualization_libvirt_disks | default([]) %}
<disk type='file' device='disk'> <disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/> <driver name='qemu' type='{{ disk.format }}'/>
<source file='{{ virtualization_libvirt_disk_path }}'/> <source file='{{ disk.path }}'/>
<target dev='vda' bus='virtio'/> <target dev='{{ disk.target }}' bus='{{ disk.bus }}'/>
</disk> </disk>
{% endfor %}
<disk type="file" device="cdrom"> <disk type="file" device="cdrom">
<driver name="qemu" type="raw"/> <driver name="qemu" type="raw"/>
<source file="{{ boot_iso }}"/> <source file="{{ boot_iso }}"/>

17
templates/xen.cfg.j2 Normal file
View File

@@ -0,0 +1,17 @@
builder = "hvm"
name = "{{ hostname }}"
memory = "{{ system_cfg.memory_mb }}"
vcpus = "{{ system_cfg.cpus }}"
disk = [
{%- for disk in virtualization_xen_disks | default([]) -%}
'file:{{ disk.path }},{{ disk.target }},w'{% if not loop.last or xen_installer_media_enabled | bool %}, {% endif %}
{%- endfor -%}
{%- if xen_installer_media_enabled | bool -%}
'{{ boot_iso }},,hdc,cdrom'{% if rhel_iso is defined and rhel_iso | length > 0 %}, '{{ rhel_iso }},,hdd,cdrom'{% endif %}
{%- endif -%}
]
vif = [ 'bridge={{ system_cfg.network }},model=e1000' ]
boot = "{{ 'dc' if xen_installer_media_enabled | bool else 'c' }}"
on_crash = "preserve"
on_poweroff = "destroy"
serial = "pty"

View File

@@ -1,5 +1,6 @@
--- ---
hypervisor: "none" hypervisor:
type: "none"
install_type: "physical" install_type: "physical"
install_drive: "/dev/sda" install_drive: "/dev/sda"
@@ -8,7 +9,7 @@ filesystem: "btrfs"
cis: false cis: false
selinux: true selinux: true
firewalld_enabled: true firewall_enabled: true
luks_enabled: true luks_enabled: true
luks_passphrase: "1234" luks_passphrase: "1234"

View File

@@ -1,24 +1,32 @@
--- ---
# Set vm_ip for static addressing. Remove vm_ip to use DHCP. # Set system.ip for static addressing. Remove system.ip to use DHCP.
vm_ip: "{{ inventory_hostname }}" system:
ip: "{{ inventory_hostname }}"
install_type: "virtual" install_type: "virtual"
install_drive: "/dev/sda" # Use /dev/vda for virtio/libvirt. install_drive: "/dev/sda" # Use /dev/vda for virtio/libvirt.
custom_iso: false # Set true to skip ArchISO-specific validation and pacman setup. custom_iso: false # Set true to skip ArchISO-specific validation and pacman setup.
cis: false # Set true to enable CIS hardening. cis: false # Set true to enable CIS hardening.
selinux: true # Toggle SELinux where supported. selinux: true # Toggle SELinux where supported.
firewalld_enabled: true # Toggle firewalld package and service. firewall_enabled: true # Toggle firewall package and service.
hypervisor_url: "pve01.example.com" hypervisor:
hypervisor_username: "root@pam" type: "proxmox" # libvirt|proxmox|vmware|xen|none
hypervisor_password: "CHANGE_ME" url: "pve01.example.com"
hypervisor_node: "pve01" username: "root@pam"
hypervisor_storage: "local-lvm" password: "CHANGE_ME"
hypervisor_datacenter: "dc01" node: "pve01"
hypervisor_cluster: "cluster01" storage: "local-lvm"
datacenter: "dc01"
cluster: "cluster01"
validate_certs: false
# Legacy (still supported): hypervisor_url, hypervisor_username, hypervisor_password, hypervisor_node, hypervisor_storage,
# hypervisor_datacenter, hypervisor_cluster, hypervisor_validate_certs.
# VMware (only needed when hypervisor: vmware) # VMware (only needed when hypervisor: vmware)
# vm_path: "/Folder" # Optional folder path segment in vCenter. # system:
# path: "/Folder" # Optional folder path segment in vCenter.
vmware_ssh: true vmware_ssh: true
# LUKS disk encryption (optional) # LUKS disk encryption (optional)