--- - name: Build normalized system configuration vars: system_raw: "{{ system_defaults | combine(system, recursive=True) }}" system_type: "{{ 'virtual' if (system_raw.type | string | lower) in ['vm', 'virtual'] else (system_raw.type | string | lower) }}" system_os_input: "{{ system_raw.os | default('') | string | lower }}" system_name: >- {{ system_raw.name | string | trim if (system_raw.name | default('') | string | trim | length) > 0 else inventory_hostname }} _mirror_defaults: debian: "https://deb.debian.org/debian/" ubuntu: "http://archive.ubuntu.com/ubuntu/" ubuntu-lts: "http://archive.ubuntu.com/ubuntu/" ansible.builtin.set_fact: system_cfg: # --- Identity & platform --- type: "{{ system_type }}" os: "{{ system_os_input if system_os_input | length > 0 else (physical_default_os if system_type == 'physical' else '') }}" version: "{{ system_raw.version | default('') | string }}" filesystem: "{{ system_raw.filesystem | default('') | string | lower }}" name: "{{ system_name }}" id: "{{ system_raw.id | default('') | string }}" # --- VM sizing (ignored for physical) --- cpus: "{{ [system_raw.cpus | default(0) | int, 0] | max }}" memory: "{{ [system_raw.memory | default(0) | int, 0] | max }}" balloon: "{{ [system_raw.balloon | default(0) | int, 0] | max }}" # --- Network --- # Flat fields (bridge, ip, etc.) and interfaces[] express the same primary NIC. # When only flat fields are set, a synthetic interfaces[] entry is built below. # When interfaces[] is set, the flat ip/prefix/gateway are backfilled from # interfaces[0] so consumers reading the flat fields (e.g. the post-reboot # reconnect block) still work. network: bridge: >- {{ (system_raw.network.bridge | default('') | string) if (system_raw.network.bridge | default('') | string | length) > 0 else (system_raw.network.interfaces[0].bridge | default('') | string if (system_raw.network.interfaces | default([]) | length) > 0 else '') }} vlan: "{{ system_raw.network.vlan | default('') | string }}" ip: >- {{ (system_raw.network.ip | default('') | string) if (system_raw.network.ip | default('') | string | length) > 0 else (system_raw.network.interfaces[0].ip | default('') | string if (system_raw.network.interfaces | default([]) | length) > 0 else '') }} prefix: >- {{ (system_raw.network.prefix | int | string) if (system_raw.network.prefix | default('') | string | length) > 0 else (system_raw.network.interfaces[0].prefix | default('') | string if (system_raw.network.interfaces | default([]) | length) > 0 else '') }} gateway: >- {{ (system_raw.network.gateway | default('') | string) if (system_raw.network.gateway | default('') | string | length) > 0 else (system_raw.network.interfaces[0].gateway | default('') | string if (system_raw.network.interfaces | default([]) | length) > 0 else '') }} dns: servers: "{{ system_raw.network.dns.servers | default([]) }}" search: "{{ system_raw.network.dns.search | default([]) }}" interfaces: >- {{ system_raw.network.interfaces if (system_raw.network.interfaces | default([]) | length > 0) else ( [{ 'name': '', 'bridge': system_raw.network.bridge | default('') | string, 'vlan': system_raw.network.vlan | default('') | string, 'ip': system_raw.network.ip | default('') | string, 'prefix': ( (system_raw.network.prefix | int | string) if (system_raw.network.prefix | default('') | string | length) > 0 else '' ), 'gateway': system_raw.network.gateway | default('') | string }] if (system_raw.network.bridge | default('') | string | length > 0) else [] ) }} # --- Locale & environment --- timezone: "{{ system_raw.timezone | string }}" locale: "{{ system_raw.locale | string }}" keymap: "{{ system_raw.keymap | string }}" mirror: >- {{ system_raw.mirror | string | trim if (system_raw.mirror | default('') | string | trim | length) > 0 else _mirror_defaults[system_raw.os | default('') | string | lower] | default('') }} path: >- {{ (system_raw.path | default('') | string) if (system_raw.path | default('') | string | length > 0) else (hypervisor_cfg.folder | default('') | string) }} packages: >- {{ ( system_raw.packages if system_raw.packages is iterable and system_raw.packages is not string else (system_raw.packages | string).split(',') ) | map('trim') | reject('equalto', '') | list }} # --- Storage & accounts --- disks: "{{ system_raw.disks | default([]) }}" users: "{{ system_raw.users | default({}) }}" root: password: "{{ system_raw.root.password | string }}" shell: "{{ system_raw.root.shell | default('/bin/bash') | string }}" # --- LUKS disk encryption --- luks: enabled: "{{ system_raw.luks.enabled | bool }}" passphrase: "{{ system_raw.luks.passphrase | string }}" mapper: "{{ system_raw.luks.mapper | string }}" auto: "{{ system_raw.luks.auto | bool }}" method: "{{ system_raw.luks.method | string | lower }}" tpm2: device: "{{ system_raw.luks.tpm2.device | string }}" pcrs: "{{ system_raw.luks.tpm2.pcrs | string }}" keysize: "{{ system_raw.luks.keysize | int }}" options: "{{ system_raw.luks.options | string }}" type: "{{ system_raw.luks.type | string }}" cipher: "{{ system_raw.luks.cipher | string }}" hash: "{{ system_raw.luks.hash | string }}" iter: "{{ system_raw.luks.iter | int }}" bits: "{{ system_raw.luks.bits | int }}" pbkdf: "{{ system_raw.luks.pbkdf | string }}" # --- Feature flags --- features: cis: enabled: "{{ system_raw.features.cis.enabled | bool }}" profile: "{{ system_raw.features.cis.profile | default('default') | string }}" rules: "{{ system_raw.features.cis.rules | default({}) }}" params: "{{ system_raw.features.cis.params | default({}) }}" selinux: enabled: "{{ system_raw.features.selinux.enabled | bool }}" firewall: enabled: "{{ system_raw.features.firewall.enabled | bool }}" backend: "{{ system_raw.features.firewall.backend | string | lower }}" toolkit: "{{ system_raw.features.firewall.toolkit | string | lower }}" ssh: enabled: "{{ system_raw.features.ssh.enabled | bool }}" zstd: enabled: "{{ system_raw.features.zstd.enabled | bool }}" swap: enabled: "{{ system_raw.features.swap.enabled | bool }}" banner: motd: "{{ system_raw.features.banner.motd | bool }}" sudo: "{{ system_raw.features.banner.sudo | bool }}" rhel_repo: source: "{{ system_raw.features.rhel_repo.source | default('iso') | string | lower }}" url: "{{ system_raw.features.rhel_repo.url | default('') | string }}" chroot: tool: "{{ system_raw.features.chroot.tool | string }}" initramfs: generator: "{{ system_raw.features.initramfs.generator | default('') | string | lower }}" desktop: enabled: "{{ system_raw.features.desktop.enabled | bool }}" environment: "{{ system_raw.features.desktop.environment | default('') | string | lower }}" display_manager: "{{ system_raw.features.desktop.display_manager | default('') | string | lower }}" autologin: "{{ system_raw.features.desktop.autologin | default(false) }}" session: "{{ system_raw.features.desktop.session | default('') | string }}" groups: "{{ system_raw.features.desktop.groups | default([]) }}" secure_boot: enabled: "{{ system_raw.features.secure_boot.enabled | bool }}" method: "{{ system_raw.features.secure_boot.method | default('') | string | lower }}" firmware: enabled: >- {{ (system_type == 'physical') if (system_raw.features.firmware.enabled | string | lower) == 'auto' else (system_raw.features.firmware.enabled | bool) }} microcode: >- {{ ( (system_type == 'physical') if (system_raw.features.firmware.enabled | string | lower) == 'auto' else (system_raw.features.firmware.enabled | bool) ) if (system_raw.features.firmware.microcode | string | lower) == 'auto' else (system_raw.features.firmware.microcode | bool) }} gpu: enabled: >- {{ (system_raw.features.desktop.enabled | bool) if (system_raw.features.gpu.enabled | string | lower) == 'auto' else (system_raw.features.gpu.enabled | bool) }} nvidia_driver: "{{ system_raw.features.gpu.nvidia_driver | default('auto') | string | lower }}" peripherals: enabled: >- {{ (system_raw.features.desktop.enabled | bool) if (system_raw.features.peripherals.enabled | string | lower) == 'auto' else (system_raw.features.peripherals.enabled | bool) }} # fingerprint/camera/audio/bluetooth stay tri-state ('auto'|'true'|'false') # because the 'auto' branch is resolved at install time using detection results. fingerprint: >- {{ 'auto' if (system_raw.features.peripherals.fingerprint | string | lower) == 'auto' else (system_raw.features.peripherals.fingerprint | bool | string | lower) }} camera: >- {{ 'auto' if (system_raw.features.peripherals.camera | string | lower) == 'auto' else (system_raw.features.peripherals.camera | bool | string | lower) }} audio: >- {{ 'auto' if (system_raw.features.peripherals.audio | string | lower) == 'auto' else (system_raw.features.peripherals.audio | bool | string | lower) }} bluetooth: >- {{ 'auto' if (system_raw.features.peripherals.bluetooth | string | lower) == 'auto' else (system_raw.features.peripherals.bluetooth | bool | string | lower) }} displaylink: "{{ system_raw.features.peripherals.displaylink | bool }}" hardware: profile: "{{ system_raw.features.hardware.profile | default({}) }}" cpu: "{{ system_raw.features.hardware.cpu | default('') | string }}" gpus: "{{ system_raw.features.hardware.gpus | default([]) | list }}" wireless: "{{ system_raw.features.hardware.wireless | default([]) | list }}" audio: "{{ system_raw.features.hardware.audio | default([]) | list }}" camera: "{{ system_raw.features.hardware.camera | default({}) }}" fingerprint: "{{ system_raw.features.hardware.fingerprint | default(false) | bool }}" bluetooth: "{{ system_raw.features.hardware.bluetooth | default(false) | bool }}" packages: "{{ system_raw.features.hardware.packages | default({}) }}" disable: "{{ system_raw.features.hardware.disable | default([]) | list }}" kernel_params: "{{ system_raw.features.hardware.kernel_params | default([]) | list }}" hostname: "{{ system_name }}" os: "{{ system_os_input if system_os_input | length > 0 else (physical_default_os if system_type == 'physical' else '') }}" os_version: "{{ system_raw.version | default('') | string }}" no_log: true