Compare commits
75 Commits
master
...
6240217318
| Author | SHA1 | Date | |
|---|---|---|---|
| 6240217318 | |||
| 1c00ec9370 | |||
| 371d5a0acd | |||
| 41ccf2a5b9 | |||
| 8f9cfe3b2f | |||
| 6a75237197 | |||
| b04aad12fb | |||
| 4fff9f8d80 | |||
| 7f12a0f3d8 | |||
| ceb2237bbb | |||
| 477c8379c4 | |||
| 579c499c02 | |||
| 89e366d0f0 | |||
| 6fe843355e | |||
| 441876fab9 | |||
| 00acd4d200 | |||
| d922efd2e4 | |||
| 939c5c741f | |||
| 2c35409519 | |||
| d2a19cfd5c | |||
| 44f5adc682 | |||
| 0185797af9 | |||
| e0ecf628cd | |||
| 37df881daa | |||
| 55b21eae5d | |||
| b1e938b7f0 | |||
| c843f5289b | |||
| 9757ed3785 | |||
| 876e90ce2b | |||
| 7c44cb1ff0 | |||
| 5d0630a386 | |||
| 3eaf918a53 | |||
| 382e82ff85 | |||
| db7dc53bd7 | |||
| 7d45f25a7e | |||
| 3880b8f41e | |||
| dc3c4a901f | |||
| 6bfaa0aa2b | |||
| 5dc0424acb | |||
| c12332a853 | |||
| 5ace4577a2 | |||
| c0ff01ef40 | |||
| 57417514e3 | |||
| 0928588c1f | |||
| 6d622f2db4 | |||
| b11d65a6f3 | |||
| 3623fc292c | |||
| dfca7ec94b | |||
| e8be84bf49 | |||
| 322cc0b1ce | |||
| 4b38754f8b | |||
| a6bc7ffe04 | |||
| c529e71ebc | |||
| cb46de2b6d | |||
| 9169117b25 | |||
| 6c94c519fb | |||
| efd96a42b8 | |||
| 68661c3cca | |||
| 1db20c7ac0 | |||
| 7b155b427b | |||
| ca8721e98f | |||
| cdb2559d8f | |||
| 443f6623df | |||
| 6cf418fe00 | |||
| 47ec5fe621 | |||
| 240f945cce | |||
| 663a04556f | |||
| 6febd1acf1 | |||
| 008187860c | |||
| cd1be6b5e1 | |||
| 15be6149fd | |||
| ca29ad200d | |||
| 8079099cee | |||
| 9e79185b07 | |||
| b88bf2860f |
@@ -183,7 +183,7 @@ Top-level variables outside `system`/`hypervisor`.
|
||||
|
||||
#### `system.content`
|
||||
|
||||
Uniform package content source, family-resolved. `source: ''` defaults to `dvd` on `rhel` and to `mirror` everywhere else, AlmaLinux, Rocky and Fedora included: they have public mirrors, RHEL does not. Satellite values come from inventory/vault only, never committed code.
|
||||
Uniform package content source, family-resolved. `source: ''` defaults to `dvd` on EL and `mirror` on Debian/Ubuntu/Arch. Satellite values come from inventory/vault only, never committed code.
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| -------------------------- | ------ | -------------- | ----------------------------------------------------------------- |
|
||||
@@ -538,8 +538,6 @@ When `hypervisor.type: vmware` uses the `vmware_tools` connection:
|
||||
|
||||
`system.disks[0]` is the OS disk (no `mount.path`). Additional entries define data disks.
|
||||
|
||||
On VMware, `device` is resolved on the target from the SCSI address instead: entry N is the disk at target N on the first SCSI controller (N+1 from index 7 on, since unit 7 is reserved). The kernel's `sdX` order is not stable between the install environment and the installed system, so a letter-derived path can point at another disk.
|
||||
|
||||
| Key | Type | Description |
|
||||
| ------------- | ------ | ------------------------------------------------------ |
|
||||
| `size` | number | Disk size in GB (required for virtual) |
|
||||
|
||||
@@ -9,7 +9,7 @@ bootstrap_hardware_packages:
|
||||
amd: [amd-ucode]
|
||||
firmware_base: []
|
||||
firmware:
|
||||
intel: [linux-firmware-intel] # iwlwifi (WiFi) + i915/xe (GPU) + ibt (BT) firmware live here
|
||||
intel: [linux-firmware-other] # iwlwifi + i915 firmware live here
|
||||
amd: [linux-firmware-amdgpu]
|
||||
nvidia: [linux-firmware-nvidia]
|
||||
atheros: [linux-firmware-atheros]
|
||||
|
||||
@@ -3,5 +3,3 @@
|
||||
cleanup_verify_boot: true
|
||||
cleanup_boot_timeout: 300
|
||||
cleanup_remove_on_failure: true
|
||||
cleanup_poweroff_retries: 24
|
||||
cleanup_poweroff_delay: 5
|
||||
|
||||
@@ -6,30 +6,7 @@
|
||||
module_defaults:
|
||||
community.proxmox.proxmox_disk: "{{ _proxmox_auth }}"
|
||||
community.proxmox.proxmox_kvm: "{{ _proxmox_auth_node }}"
|
||||
community.proxmox.proxmox_vm_info: "{{ _proxmox_auth_node }}"
|
||||
block:
|
||||
- name: Wait for the installer environment to power off
|
||||
community.proxmox.proxmox_vm_info:
|
||||
vmid: "{{ system_cfg.id }}"
|
||||
register: cleanup_proxmox_power
|
||||
until: >-
|
||||
((cleanup_proxmox_power.proxmox_vms | default([]) | first | default({})).status
|
||||
| default('')) == 'stopped'
|
||||
retries: "{{ cleanup_poweroff_retries }}"
|
||||
delay: "{{ cleanup_poweroff_delay }}"
|
||||
failed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Force the installer environment off when it did not shut down
|
||||
when: >-
|
||||
((cleanup_proxmox_power.proxmox_vms | default([]) | first | default({})).status
|
||||
| default('')) != 'stopped'
|
||||
community.proxmox.proxmox_kvm:
|
||||
vmid: "{{ system_cfg.id }}"
|
||||
state: stopped
|
||||
force: true
|
||||
no_log: true
|
||||
|
||||
- name: Cleanup Setup Disks
|
||||
community.proxmox.proxmox_disk:
|
||||
name: "{{ hostname }}"
|
||||
@@ -44,6 +21,13 @@
|
||||
failed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Ensure the installer environment is powered off
|
||||
community.proxmox.proxmox_kvm:
|
||||
vmid: "{{ system_cfg.id }}"
|
||||
state: stopped
|
||||
force: true
|
||||
no_log: true
|
||||
|
||||
- name: Boot the installed OS
|
||||
community.proxmox.proxmox_kvm:
|
||||
vmid: "{{ system_cfg.id }}"
|
||||
|
||||
@@ -5,26 +5,9 @@
|
||||
become: false
|
||||
module_defaults:
|
||||
community.vmware.vmware_guest: "{{ _vmware_auth }}"
|
||||
community.vmware.vmware_guest_info: "{{ _vmware_auth }}"
|
||||
vmware.vmware.vm_powerstate: "{{ _vmware_auth }}"
|
||||
no_log: true
|
||||
block:
|
||||
- name: Wait for the installer environment to power off
|
||||
community.vmware.vmware_guest_info:
|
||||
name: "{{ hostname }}"
|
||||
register: cleanup_vmware_power
|
||||
until: (cleanup_vmware_power.instance.hw_power_status | default('') | lower) == 'poweredoff'
|
||||
retries: "{{ cleanup_poweroff_retries }}"
|
||||
delay: "{{ cleanup_poweroff_delay }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Force the installer environment off when it did not shut down
|
||||
when: (cleanup_vmware_power.instance.hw_power_status | default('') | lower) != 'poweredoff'
|
||||
vmware.vmware.vm_powerstate:
|
||||
name: "{{ hostname }}"
|
||||
state: powered-off
|
||||
force: true
|
||||
|
||||
- name: Remove CD-ROM from VM in vCenter
|
||||
community.vmware.vmware_guest:
|
||||
name: "{{ hostname }}"
|
||||
@@ -58,7 +41,7 @@
|
||||
}}
|
||||
failed_when: false
|
||||
|
||||
- name: Boot the installed OS
|
||||
- name: Start VM in vCenter
|
||||
vmware.vmware.vm_powerstate:
|
||||
name: "{{ hostname }}"
|
||||
state: powered-on
|
||||
|
||||
@@ -18,24 +18,13 @@
|
||||
register: configuration_bootloader_result
|
||||
changed_when: configuration_bootloader_result.rc == 0
|
||||
|
||||
- name: Remove stale EFI boot entries for this OS
|
||||
# UEFI NVRAM entries survive a disk wipe (they live in firmware, not on disk).
|
||||
# A prior install leaves a dead entry, and a case-insensitive duplicate label
|
||||
# ("ArchLinux" vs "archlinux") would otherwise win the boot order - the firmware
|
||||
# then falls through to removable media. Delete every entry carrying our label,
|
||||
# then recreate exactly one clean entry.
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
set -o pipefail;
|
||||
efibootmgr | grep -iP '^Boot[0-9A-F]{4}\*?\s+{{ _efi_vendor }}\s*$'
|
||||
| grep -oP '^Boot\K[0-9A-F]{4}'
|
||||
| xargs -r -I{} efibootmgr -b {} -B
|
||||
executable: /bin/bash
|
||||
register: _efi_gc_result
|
||||
changed_when: _efi_gc_result.stdout | length > 0
|
||||
failed_when: false
|
||||
- name: Check existing EFI boot entries
|
||||
ansible.builtin.command: efibootmgr
|
||||
register: configuration_efi_entries
|
||||
changed_when: false
|
||||
|
||||
- name: Create EFI boot entry (efibootmgr -c prepends it to BootOrder)
|
||||
- name: Ensure EFI boot entry exists
|
||||
when: ('* ' + _efi_vendor) not in configuration_efi_entries.stdout
|
||||
ansible.builtin.command: >-
|
||||
efibootmgr -c
|
||||
-L '{{ _efi_vendor }}'
|
||||
@@ -45,16 +34,15 @@
|
||||
register: configuration_efi_entry_result
|
||||
changed_when: configuration_efi_entry_result.rc == 0
|
||||
|
||||
- name: Install removable EFI fallback loader
|
||||
# Firmware-agnostic fallback (\EFI\BOOT\BOOTX64.EFI): many consumer firmwares
|
||||
# ignore or reset custom NVRAM entries and boot only the removable path.
|
||||
when: _configuration_platform.grub_install
|
||||
ansible.builtin.command: >-
|
||||
{{ chroot_command }} /usr/bin/install -Dm644
|
||||
{{ partitioning_efi_mountpoint }}/EFI/{{ _efi_vendor }}/{{ _efi_loader }}
|
||||
{{ partitioning_efi_mountpoint }}/EFI/BOOT/BOOTX64.EFI
|
||||
register: _efi_fallback_result
|
||||
changed_when: _efi_fallback_result.rc == 0
|
||||
- name: Set installed OS as first EFI boot entry
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
set -o pipefail &&
|
||||
efibootmgr | grep -i '{{ _efi_vendor }}' | grep -oP 'Boot\K[0-9A-F]+' | head -1
|
||||
| xargs -I{} efibootmgr -o {}
|
||||
executable: /bin/bash
|
||||
register: _efi_bootorder_result
|
||||
changed_when: _efi_bootorder_result.rc == 0
|
||||
|
||||
- name: Ensure lvm2 for non btrfs filesystems
|
||||
when: os == "archlinux" and system_cfg.filesystem != "btrfs"
|
||||
|
||||
@@ -12,21 +12,6 @@
|
||||
and 'No such file or directory' not in (_firewall_enable.stderr | default(''))
|
||||
and 'does not exist' not in (_firewall_enable.stderr | default(''))
|
||||
|
||||
# Distro base sets ship the daemon preset-enabled (RHEL @core pulls firewalld in),
|
||||
# so opting out has to disable the unit, not merely skip enabling it.
|
||||
- name: Disable the firewall daemon in the install chroot
|
||||
when:
|
||||
- firewall_phase == 'install'
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- not system_cfg.features.firewall.enabled | bool
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl disable {{ system_cfg.features.firewall.backend }}"
|
||||
register: _firewall_disable
|
||||
changed_when: "'Removed' in (_firewall_disable.stderr | default(''))"
|
||||
failed_when: >-
|
||||
_firewall_disable.rc != 0
|
||||
and 'No such file or directory' not in (_firewall_disable.stderr | default(''))
|
||||
and 'does not exist' not in (_firewall_disable.stderr | default(''))
|
||||
|
||||
# ufw's CLI needs a running kernel and is a no-op in the chroot (leaves ENABLED=no),
|
||||
# so its activation and SSH rule are applied here, after reboot.
|
||||
- name: Allow SSH through ufw before enabling
|
||||
|
||||
@@ -43,14 +43,11 @@
|
||||
}}
|
||||
grub_root_flags: >-
|
||||
{{ ['rootflags=subvol=@'] if system_cfg.filesystem == 'btrfs' else [] }}
|
||||
grub_selinux_args: >-
|
||||
{{ [] if system_cfg.features.selinux.enabled | bool else ['selinux=0'] }}
|
||||
# String-concat (not list-concat like grub_kernel_cmdline_base below): ansible-lint's
|
||||
# jinja render trips on list+list when grub_lvm_args leads the expression here.
|
||||
grub_cmdline_linux_base: >-
|
||||
{{
|
||||
((grub_lvm_args | join(' ')) ~ ' ' ~ (grub_selinux_args | join(' ')) ~ ' '
|
||||
~ (_hardware_profile_kernel_params | default([]) | join(' '))) | trim
|
||||
((grub_lvm_args | join(' ')) ~ ' ' ~ (_hardware_profile_kernel_params | default([]) | join(' '))) | trim
|
||||
}}
|
||||
grub_kernel_cmdline_base: >-
|
||||
{{
|
||||
@@ -60,7 +57,6 @@
|
||||
+ ['ro']
|
||||
+ grub_lvm_args
|
||||
+ grub_root_flags
|
||||
+ grub_selinux_args
|
||||
+ (_hardware_profile_kernel_params | default([]))
|
||||
)
|
||||
| join(' ')
|
||||
|
||||
@@ -22,12 +22,10 @@
|
||||
mode: "0644"
|
||||
|
||||
# Fedora: setfiles segfaults during bootstrap chroot relabeling, so SELinux
|
||||
# is left permissive and expected to relabel on first boot. Opting out writes
|
||||
# disabled here and selinux=0 on the kernel cmdline (grub.yml), the only form
|
||||
# EL9 honours.
|
||||
- name: Set the SELinux mode
|
||||
# is left permissive and expected to relabel on first boot.
|
||||
- name: Disable SELinux
|
||||
when: os == "fedora" or not system_cfg.features.selinux.enabled | bool
|
||||
ansible.builtin.lineinfile:
|
||||
path: /mnt/etc/selinux/config
|
||||
regexp: ^SELINUX=
|
||||
line: "SELINUX={{ 'permissive' if system_cfg.features.selinux.enabled | bool else 'disabled' }}"
|
||||
line: SELINUX=permissive
|
||||
|
||||
@@ -78,8 +78,7 @@ system_defaults:
|
||||
timezone: "Europe/Vienna"
|
||||
locale: "en_US.UTF-8"
|
||||
keymap: "us"
|
||||
# source: dvd|mirror|satellite|none ('' -> family default: rhel=dvd, else mirror;
|
||||
# almalinux/rocky/fedora have public mirrors, rhel does not).
|
||||
# source: dvd|mirror|satellite|none ('' -> family default: EL=dvd, else mirror).
|
||||
# satellite values come from inventory/vault only, never committed code.
|
||||
content:
|
||||
source: ""
|
||||
|
||||
@@ -94,7 +94,6 @@
|
||||
|
||||
- name: Set install_drive from primary disk
|
||||
when:
|
||||
- install_drive is not defined
|
||||
- system_disks_cfg | length > 0
|
||||
- system_disks_cfg[0].device | string | length > 0
|
||||
ansible.builtin.set_fact:
|
||||
|
||||
@@ -79,7 +79,9 @@
|
||||
os_version: "{{ system_cfg.version | default('') | string }}"
|
||||
|
||||
- name: Normalize disk configuration (pre-computed system_cfg)
|
||||
when: system_cfg is defined
|
||||
when:
|
||||
- system_cfg is defined
|
||||
- install_drive is not defined
|
||||
ansible.builtin.include_tasks: _normalize_disks.yml
|
||||
|
||||
# Runs on every path before validation, so an empty firewall.backend / content.source
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
# The virtualization role attaches system.disks to SCSI controller 0 in list order, and
|
||||
# vSphere never gives a disk unit 7 (the controller's own address). The kernel's sdX order
|
||||
# is not that order and differs between the install environment and the installed OS, so
|
||||
# a disk derived as /dev/sd<letter of its index> can be the wrong one. Resolve by target.
|
||||
- name: List disks with their SCSI address
|
||||
ansible.builtin.command: lsblk -dnpo NAME,TYPE,HCTL
|
||||
register: partitioning_vmware_lsblk
|
||||
changed_when: false
|
||||
|
||||
- name: Map SCSI targets to devices
|
||||
vars:
|
||||
_scsi: >-
|
||||
{%- set out = [] -%}
|
||||
{%- for line in partitioning_vmware_lsblk.stdout_lines -%}
|
||||
{%- set p = line.split() -%}
|
||||
{%- if (p | length) == 3 and p[1] == 'disk' and p[2] is match('^\d+:0:\d+:0$') -%}
|
||||
{%- set _ = out.append({'name': p[0], 'host': p[2].split(':')[0], 'target': p[2].split(':')[2]}) -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{{ out }}
|
||||
ansible.builtin.set_fact:
|
||||
partitioning_vmware_hosts: "{{ _scsi | map(attribute='host') | unique | list }}"
|
||||
partitioning_vmware_targets: "{{ _scsi | items2dict(key_name='target', value_name='name') }}"
|
||||
partitioning_vmware_target_count: "{{ _scsi | length }}"
|
||||
|
||||
- name: Assert the system disks sit on one SCSI controller with unique targets
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- partitioning_vmware_hosts | length == 1
|
||||
- partitioning_vmware_targets | length == partitioning_vmware_target_count | int
|
||||
fail_msg: >-
|
||||
Expected every disk on one SCSI controller with unique targets, got
|
||||
{{ partitioning_vmware_lsblk.stdout_lines | select('search', ' disk ') | list }}.
|
||||
quiet: true
|
||||
|
||||
- name: Assert each system disk has a device at its SCSI target
|
||||
vars:
|
||||
_target: "{{ (idx if idx < 7 else idx + 1) | string }}"
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _target in partitioning_vmware_targets
|
||||
fail_msg: "system.disks[{{ idx }}] ({{ item.size }} GB) expects a disk at SCSI target {{ _target }}, none found."
|
||||
quiet: true
|
||||
loop: "{{ system_cfg.disks }}"
|
||||
loop_control:
|
||||
index_var: idx
|
||||
label: "{{ idx }}"
|
||||
|
||||
- name: Point system disks and install_drive at the resolved devices
|
||||
vars:
|
||||
_disks: >-
|
||||
{%- set out = [] -%}
|
||||
{%- for d in system_cfg.disks -%}
|
||||
{%- set dev = partitioning_vmware_targets[(loop.index0 if loop.index0 < 7 else loop.index0 + 1) | string] -%}
|
||||
{%- set _ = out.append(d | combine({'device': dev, 'partition': dev ~ '1'})) -%}
|
||||
{%- endfor -%}
|
||||
{{ out }}
|
||||
ansible.builtin.set_fact:
|
||||
system_cfg: "{{ system_cfg | combine({'disks': _disks}) }}"
|
||||
install_drive: "{{ _disks[0].device }}"
|
||||
@@ -1,10 +1,4 @@
|
||||
---
|
||||
- name: Resolve VMware disks by SCSI target
|
||||
when:
|
||||
- hypervisor_type == "vmware"
|
||||
- system_cfg.type == "virtual"
|
||||
ansible.builtin.include_tasks: _resolve_vmware_disks.yml
|
||||
|
||||
- name: Detect system sizing
|
||||
ansible.builtin.include_tasks: _detect_sizing.yml
|
||||
|
||||
|
||||
@@ -50,9 +50,6 @@
|
||||
esxi_hostname: "{{ hypervisor_cfg.node }}"
|
||||
register: system_check_esxi
|
||||
delegate_facts: true
|
||||
until: system_check_esxi.ansible_facts is defined
|
||||
retries: 3
|
||||
delay: 10
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
@@ -87,9 +84,6 @@
|
||||
community.vmware.vmware_datastore_info:
|
||||
cluster: "{{ hypervisor_cfg.cluster }}"
|
||||
register: system_check_cluster
|
||||
until: system_check_cluster.datastores is defined
|
||||
retries: 3
|
||||
delay: 10
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
@@ -138,10 +132,6 @@
|
||||
path: "{{ item.path }}"
|
||||
state: file
|
||||
register: system_check_media_files
|
||||
# A missing file fails with status 404; a dropped vCenter connection fails with status None.
|
||||
until: system_check_media_files is not failed or system_check_media_files.status is not none
|
||||
retries: 3
|
||||
delay: 10
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
loop: "{{ system_check_datastores_needed | rejectattr('source', 'equalto', 'hypervisor.storage') | list }}"
|
||||
|
||||
@@ -82,11 +82,6 @@
|
||||
name: "{{ hostname }}"
|
||||
folder: "{{ system_cfg.path if system_cfg.path | length > 0 else omit }}"
|
||||
register: system_check_vmware_check_result
|
||||
until: >-
|
||||
not system_check_vmware_check_result.failed
|
||||
or (system_check_vmware_check_result.msg is search('non-existing VM'))
|
||||
retries: 3
|
||||
delay: 10
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
# Raw system.content input -> expected normalized system_cfg.content. Covers family
|
||||
# source defaults (rhel=dvd, else mirror), url pass-through, satellite inputs, and the
|
||||
# source defaults (EL=dvd, else mirror), url pass-through, satellite inputs, and the
|
||||
# Arch reflector lock-out (dropped only when a custom mirror url is set).
|
||||
content_fixtures:
|
||||
- name: arch-mirror-url-drops-reflector
|
||||
|
||||
Reference in New Issue
Block a user