diff --git a/roles/global_defaults/defaults/main.yml b/roles/global_defaults/defaults/main.yml index 3ed33c2..8b942b9 100644 --- a/roles/global_defaults/defaults/main.yml +++ b/roles/global_defaults/defaults/main.yml @@ -112,6 +112,42 @@ system_defaults: chroot: tool: "arch-chroot" # arch-chroot|chroot|systemd-nspawn +# Per-hypervisor required fields — drives data-driven validation. +# All virtual types additionally require network bridge or interfaces. +hypervisor_required_fields: + proxmox: + hypervisor: [url, username, password, host, storage] + system: [id] + vmware: + hypervisor: [url, username, password, datacenter, cluster, storage] + system: [] + xen: + hypervisor: [] + system: [] + libvirt: + hypervisor: [] + system: [] + +# Hypervisor-to-disk device prefix mapping for virtual machines. +# Physical installs must set system.disks[].device explicitly. +hypervisor_disk_device_map: + libvirt: "/dev/vd" + xen: "/dev/xvd" + proxmox: "/dev/sd" + vmware: "/dev/sd" + +# Mountpoints managed by the partitioning role — forbidden for extra disks. +reserved_mounts: + - /boot + - /boot/efi + - /home + - /var + - /var/log + - /var/log/audit + +# Drive letter sequence for disk device naming (max 26 disks). +disk_letter_map: "abcdefghijklmnopqrstuvwxyz" + system_disk_defaults: size: 0 device: "" diff --git a/roles/global_defaults/tasks/_normalize_disks.yml b/roles/global_defaults/tasks/_normalize_disks.yml index 747d33b..6610d74 100644 --- a/roles/global_defaults/tasks/_normalize_disks.yml +++ b/roles/global_defaults/tasks/_normalize_disks.yml @@ -2,10 +2,10 @@ - name: Normalize system disks input vars: system_disks: "{{ system_cfg.disks | default([]) }}" - system_disk_letter_map: "abcdefghijklmnopqrstuvwxyz" + system_disk_letter_map: "{{ disk_letter_map }}" system_disk_device_prefix: >- {{ - {'libvirt': '/dev/vd', 'xen': '/dev/xvd', 'proxmox': '/dev/sd', 'vmware': '/dev/sd'}.get(hypervisor_type, '') + hypervisor_disk_device_map.get(hypervisor_type, '') if system_cfg.type == 'virtual' else '' }} diff --git a/roles/global_defaults/tasks/validation.yml b/roles/global_defaults/tasks/validation.yml index 6e19900..f211a5b 100644 --- a/roles/global_defaults/tasks/validation.yml +++ b/roles/global_defaults/tasks/validation.yml @@ -152,70 +152,43 @@ fail_msg: "rhel_iso is required when os=rhel." quiet: true -- name: Validate Proxmox hypervisor inputs +- name: Validate hypervisor-specific required fields when: - system_cfg.type == "virtual" - - hypervisor_type == "proxmox" + - hypervisor_type in hypervisor_required_fields + ansible.builtin.assert: + that: + - (hypervisor_cfg[item] | default('') | string | length) > 0 + fail_msg: "Missing required {{ hypervisor_type }} field: hypervisor.{{ item }}" + quiet: true + loop: "{{ hypervisor_required_fields[hypervisor_type].hypervisor | default([]) }}" + loop_control: + label: "hypervisor.{{ item }}" + no_log: true + +- name: Validate hypervisor-specific required system fields + when: + - system_cfg.type == "virtual" + - hypervisor_type in hypervisor_required_fields + ansible.builtin.assert: + that: + - (system_cfg[item] | default('') | string | length) > 0 + fail_msg: "Missing required {{ hypervisor_type }} field: system.{{ item }}" + quiet: true + loop: "{{ hypervisor_required_fields[hypervisor_type].system | default([]) }}" + loop_control: + label: "system.{{ item }}" + +- name: Validate virtual machine network requirement + when: system_cfg.type == "virtual" ansible.builtin.assert: that: - - hypervisor_cfg.url | string | length > 0 - - hypervisor_cfg.username | string | length > 0 - - hypervisor_cfg.password | string | length > 0 - - hypervisor_cfg.host | string | length > 0 - - hypervisor_cfg.storage | string | length > 0 - - system_cfg.id | string | length > 0 - >- (system_cfg.network.bridge | default('') | string | length > 0) or (system_cfg.network.interfaces | default([]) | length > 0) fail_msg: >- - Missing required Proxmox inputs. Define hypervisor.(url,username,password,host,storage), - system.id, and system.network.bridge (or system.network.interfaces[]). - quiet: true - no_log: true - -- name: Validate VMware hypervisor inputs - when: - - system_cfg.type == "virtual" - - hypervisor_type == "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.bridge | default('') | string | length > 0) - or (system_cfg.network.interfaces | default([]) | length > 0) - fail_msg: >- - Missing required VMware inputs. Define hypervisor.(url,username,password,datacenter,cluster,storage) - and system.network.bridge (or system.network.interfaces[]). - quiet: true - no_log: true - -- name: Validate Xen hypervisor inputs - when: - - system_cfg.type == "virtual" - - hypervisor_type == "xen" - ansible.builtin.assert: - that: - - >- - (system_cfg.network.bridge | default('') | string | length > 0) - or (system_cfg.network.interfaces | default([]) | length > 0) - fail_msg: "Missing required Xen inputs. Define system.network.bridge (or system.network.interfaces[])." - quiet: true - -- name: Validate libvirt hypervisor inputs - when: - - system_cfg.type == "virtual" - - hypervisor_type == "libvirt" - ansible.builtin.assert: - that: - - >- - (system_cfg.network.bridge | default('') | string | length > 0) - or (system_cfg.network.interfaces | default([]) | length > 0) - fail_msg: "Missing required libvirt inputs. Define system.network.bridge (or system.network.interfaces[])." + Missing required {{ hypervisor_type }} network configuration. + Define system.network.bridge (or system.network.interfaces[]). quiet: true - name: Validate virtual installer ISO requirement @@ -250,6 +223,8 @@ - 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 + # Btrfs minimum disk: swap_size + 5.5 GiB overhead (subvolumes + metadata). + # Swap sizing: memory < 16 GiB → max(memory_GiB, 2); memory >= 16 GiB → memory/2. - >- system_cfg.filesystem != "btrfs" or ( @@ -333,9 +308,9 @@ - name: Validate disk mount definitions when: system_cfg.disks is defined vars: - reserved_mounts: >- + all_reserved_mounts: >- {{ - ['/boot', '/boot/efi', '/home', '/var', '/var/log', '/var/log/audit'] + reserved_mounts + (['/var/cache/pacman/pkg'] if os == 'archlinux' else []) }} disk_mount: "{{ (item.mount.path | default('') | string) | trim }}" @@ -346,7 +321,7 @@ 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_mount not in all_reserved_mounts - disk_mount == "" or disk_fstype in ["btrfs", "ext4", "xfs"] - disk_mount == "" or system_cfg.type == "virtual" or (disk_device | length) > 0 - disk_mount == "" or system_cfg.type != "virtual" or (disk_size | float) > 0 diff --git a/roles/virtualization/tasks/libvirt.yml b/roles/virtualization/tasks/libvirt.yml index fd7da74..fb1d247 100644 --- a/roles/virtualization/tasks/libvirt.yml +++ b/roles/virtualization/tasks/libvirt.yml @@ -3,7 +3,7 @@ ansible.builtin.set_fact: virtualization_libvirt_disks: "{{ virtualization_libvirt_disks | default([]) + [virtualization_libvirt_disk_cfg] }}" vars: - device_letter_map: "abcdefghijklmnopqrstuvwxyz" + device_letter_map: "{{ disk_letter_map }}" device_letter: "{{ device_letter_map[ansible_loop.index0] }}" virtualization_libvirt_disk_cfg: >- {{ diff --git a/roles/virtualization/tasks/xen.yml b/roles/virtualization/tasks/xen.yml index 19cbb50..f459688 100644 --- a/roles/virtualization/tasks/xen.yml +++ b/roles/virtualization/tasks/xen.yml @@ -5,7 +5,7 @@ ansible.builtin.set_fact: virtualization_xen_disks: "{{ virtualization_xen_disks | default([]) + [virtualization_xen_disk_cfg] }}" vars: - device_letter_map: "abcdefghijklmnopqrstuvwxyz" + device_letter_map: "{{ disk_letter_map }}" device_letter: "{{ device_letter_map[ansible_loop.index0] }}" virtualization_xen_disk_cfg: >- {{