feat: accept proxmox API-token auth alongside password

This commit is contained in:
2026-05-31 12:40:31 +02:00
parent ceb2237bbb
commit 7f12a0f3d8
5 changed files with 41 additions and 27 deletions

View File

@@ -1,5 +1,4 @@
--- ---
# OS family lists - single source of truth for platform detection and validation
os_family_rhel: os_family_rhel:
- almalinux - almalinux
- fedora - fedora
@@ -10,8 +9,7 @@ os_family_debian:
- ubuntu - ubuntu
- ubuntu-lts - ubuntu-lts
# OS -> family mapping - aligns with the main project's ansible_os_family pattern. # OS -> family, so roles do platform_config lookups instead of is_rhel when-chains.
# Enables platform_config dict lookups per role instead of inline when: is_rhel chains.
os_family_map: os_family_map:
almalinux: RedHat almalinux: RedHat
archlinux: Archlinux archlinux: Archlinux
@@ -40,6 +38,8 @@ hypervisor_defaults:
url: "" url: ""
username: "" username: ""
password: "" password: ""
token_id: ""
token_secret: ""
node: "" node: ""
storage: "" storage: ""
datacenter: "" datacenter: ""
@@ -78,9 +78,8 @@ system_defaults:
timezone: "Europe/Vienna" timezone: "Europe/Vienna"
locale: "en_US.UTF-8" locale: "en_US.UTF-8"
keymap: "us" keymap: "us"
# Uniform content source, family-resolved. source: dvd|mirror|satellite|none # source: dvd|mirror|satellite|none ('' -> family default: EL=dvd, else mirror).
# ('' -> family default: EL=dvd, debian/ubuntu/arch=mirror). satellite values # satellite values come from inventory/vault only, never committed code.
# come from inventory/vault only, never committed code.
content: content:
source: "" source: ""
url: "" url: ""
@@ -119,9 +118,7 @@ system_defaults:
bits: 512 bits: 512
pbkdf: "argon2id" pbkdf: "argon2id"
features: features:
# Bake cloud-init for the deterministic clone-deploy golden path; off by # On only for the clone-deploy golden path; off keeps ansible-direct + smaller image.
# default (ansible-direct everywhere, smaller image). Package name is
# uniform across families.
cloud_init: false cloud_init: false
cis: cis:
enabled: false enabled: false
@@ -172,10 +169,8 @@ system_defaults:
displaylink: false displaylink: false
hardware: hardware:
profile: {} # full override: non-empty SKIPS detection (golden image) profile: {} # full override: non-empty SKIPS detection (golden image)
# Declarative hardware group: a per-device profile that MERGES over # The keys below MERGE over detection: lists union, booleans OR, packages
# auto-detect (auto-detect = base; these supplement/override it). Vendor # and kernel_params append, disable[] force-off applied last.
# lists union with detection, booleans OR with detection, packages append,
# disable[] force-off (applied last), kernel_params append to the cmdline.
cpu: "" # pin a CPU vendor (intel|amd); empty = use detection cpu: "" # pin a CPU vendor (intel|amd); empty = use detection
gpus: [] # extra GPU vendor codes to force gpus: [] # extra GPU vendor codes to force
wireless: [] # extra wireless vendor codes to force wireless: [] # extra wireless vendor codes to force
@@ -187,11 +182,10 @@ system_defaults:
disable: [] # feature/vendor names to force-off (audio|bluetooth|camera|fingerprint|displaylink|<vendor>) disable: [] # feature/vendor names to force-off (audio|bluetooth|camera|fingerprint|displaylink|<vendor>)
kernel_params: [] # extra kernel cmdline params (quirks), e.g. ["i915.enable_psr=0"] kernel_params: [] # extra kernel cmdline params (quirks), e.g. ["i915.enable_psr=0"]
# Per-hypervisor required fields - drives data-driven validation. # Drives data-driven validation. Virtual types also require a network bridge or interfaces.
# All virtual types additionally require network bridge or interfaces.
hypervisor_required_fields: hypervisor_required_fields:
proxmox: proxmox:
hypervisor: [url, username, password, node, storage] hypervisor: [url, username, node, storage]
system: [id] system: [id]
vmware: vmware:
hypervisor: [url, username, password, datacenter, storage] hypervisor: [url, username, password, datacenter, storage]
@@ -203,14 +197,13 @@ hypervisor_required_fields:
hypervisor: [] hypervisor: []
system: [] system: []
# Family default content mirror URLs, used when content.url is empty. # Used when content.url is empty.
content_mirror_defaults: content_mirror_defaults:
debian: "https://deb.debian.org/debian/" debian: "https://deb.debian.org/debian/"
ubuntu: "http://archive.ubuntu.com/ubuntu/" ubuntu: "http://archive.ubuntu.com/ubuntu/"
ubuntu-lts: "http://archive.ubuntu.com/ubuntu/" ubuntu-lts: "http://archive.ubuntu.com/ubuntu/"
# Hypervisor-to-disk device prefix mapping for virtual machines. # Virtual-only; physical installs must set system.disks[].device explicitly.
# Physical installs must set system.disks[].device explicitly.
hypervisor_disk_device_map: hypervisor_disk_device_map:
libvirt: "/dev/vd" libvirt: "/dev/vd"
xen: "/dev/xvd" xen: "/dev/xvd"

View File

@@ -1,8 +1,6 @@
--- ---
# Centralized normalization - all input dicts (system, hypervisor, disks) # Normalizes all input dicts into system_cfg/hypervisor_cfg/etc. here, so downstream
# are normalized here into system_cfg, hypervisor_cfg, etc. # roles consume the computed facts directly with no per-role _normalize (except CIS).
# Downstream roles consume these computed facts directly and do NOT need
# per-role _normalize.yml (except CIS, which has its own input dict).
- name: Global defaults loaded - name: Global defaults loaded
ansible.builtin.debug: ansible.builtin.debug:
msg: Global defaults loaded. msg: Global defaults loaded.
@@ -27,11 +25,15 @@
_proxmox_auth: _proxmox_auth:
api_host: "{{ hypervisor_cfg.url }}" api_host: "{{ hypervisor_cfg.url }}"
api_user: "{{ hypervisor_cfg.username }}" api_user: "{{ hypervisor_cfg.username }}"
api_password: "{{ hypervisor_cfg.password }}" api_password: "{{ hypervisor_cfg.password | default(omit, true) }}"
api_token_id: "{{ hypervisor_cfg.token_id | default(omit, true) }}"
api_token_secret: "{{ hypervisor_cfg.token_secret | default(omit, true) }}"
_proxmox_auth_node: _proxmox_auth_node:
api_host: "{{ hypervisor_cfg.url }}" api_host: "{{ hypervisor_cfg.url }}"
api_user: "{{ hypervisor_cfg.username }}" api_user: "{{ hypervisor_cfg.username }}"
api_password: "{{ hypervisor_cfg.password }}" api_password: "{{ hypervisor_cfg.password | default(omit, true) }}"
api_token_id: "{{ hypervisor_cfg.token_id | default(omit, true) }}"
api_token_secret: "{{ hypervisor_cfg.token_secret | default(omit, true) }}"
node: "{{ hypervisor_cfg.node }}" node: "{{ hypervisor_cfg.node }}"
no_log: true no_log: true

View File

@@ -166,6 +166,21 @@
label: "hypervisor.{{ item }}" label: "hypervisor.{{ item }}"
no_log: true no_log: true
- name: Validate Proxmox authentication (password or API token)
when:
- system_cfg.type == "virtual"
- hypervisor_type == "proxmox"
ansible.builtin.assert:
that:
- >-
(hypervisor_cfg.password | default('') | string | length > 0)
or (hypervisor_cfg.token_id | default('') | string | length > 0
and hypervisor_cfg.token_secret | default('') | string | length > 0)
fail_msg: >-
Proxmox requires either hypervisor.password or
hypervisor.token_id + hypervisor.token_secret (API token).
quiet: true
- name: Validate VMware placement (cluster or node required, mutually exclusive) - name: Validate VMware placement (cluster or node required, mutually exclusive)
when: when:
- system_cfg.type == "virtual" - system_cfg.type == "virtual"

View File

@@ -41,7 +41,9 @@
community.proxmox.proxmox_vm_info: community.proxmox.proxmox_vm_info:
api_host: "{{ hypervisor_cfg.url }}" api_host: "{{ hypervisor_cfg.url }}"
api_user: "{{ hypervisor_cfg.username }}" api_user: "{{ hypervisor_cfg.username }}"
api_password: "{{ hypervisor_cfg.password }}" api_password: "{{ hypervisor_cfg.password | default(omit, true) }}"
api_token_id: "{{ hypervisor_cfg.token_id | default(omit, true) }}"
api_token_secret: "{{ hypervisor_cfg.token_secret | default(omit, true) }}"
block: block:
- name: Query Proxmox for existing VM - name: Query Proxmox for existing VM
community.proxmox.proxmox_vm_info: community.proxmox.proxmox_vm_info:

View File

@@ -20,7 +20,9 @@
community.proxmox.proxmox_kvm: community.proxmox.proxmox_kvm:
api_host: "{{ hypervisor_cfg.url }}" api_host: "{{ hypervisor_cfg.url }}"
api_user: "{{ hypervisor_cfg.username }}" api_user: "{{ hypervisor_cfg.username }}"
api_password: "{{ hypervisor_cfg.password }}" api_password: "{{ hypervisor_cfg.password | default(omit, true) }}"
api_token_id: "{{ hypervisor_cfg.token_id | default(omit, true) }}"
api_token_secret: "{{ hypervisor_cfg.token_secret | default(omit, true) }}"
node: "{{ hypervisor_cfg.node }}" node: "{{ hypervisor_cfg.node }}"
vmid: "{{ system_cfg.id | default(omit, true) }}" vmid: "{{ system_cfg.id | default(omit, true) }}"
name: "{{ hostname }}" name: "{{ hostname }}"