feat(vmware): add VMware hypervisor support (node field, connection vars, validation)
This commit is contained in:
@@ -91,7 +91,7 @@ all:
|
|||||||
username: root@pam
|
username: root@pam
|
||||||
password: !vault |
|
password: !vault |
|
||||||
$ANSIBLE_VAULT...
|
$ANSIBLE_VAULT...
|
||||||
host: pve01
|
node: pve01
|
||||||
storage: local-lvm
|
storage: local-lvm
|
||||||
|
|
||||||
children:
|
children:
|
||||||
@@ -268,7 +268,7 @@ The first user's credentials are prompted interactively via `vars_prompt` unless
|
|||||||
| `url` | string | -- | API host (Proxmox/VMware) |
|
| `url` | string | -- | API host (Proxmox/VMware) |
|
||||||
| `username` | string | -- | API username |
|
| `username` | string | -- | API username |
|
||||||
| `password` | string | -- | API password |
|
| `password` | string | -- | API password |
|
||||||
| `host` | string | -- | Proxmox node name |
|
| `node` | string | -- | Target compute node (Proxmox node / VMware ESXi host; mutually exclusive with `cluster` on VMware) |
|
||||||
| `storage` | string | -- | Storage identifier (Proxmox/VMware) |
|
| `storage` | string | -- | Storage identifier (Proxmox/VMware) |
|
||||||
| `datacenter` | string | -- | VMware datacenter |
|
| `datacenter` | string | -- | VMware datacenter |
|
||||||
| `cluster` | string | -- | VMware cluster |
|
| `cluster` | string | -- | VMware cluster |
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ all:
|
|||||||
url: "pve01.example.com"
|
url: "pve01.example.com"
|
||||||
username: "root@pam"
|
username: "root@pam"
|
||||||
password: "CHANGE_ME"
|
password: "CHANGE_ME"
|
||||||
host: "pve01"
|
node: "pve01"
|
||||||
storage: "local-lvm"
|
storage: "local-lvm"
|
||||||
boot_iso: "local:iso/archlinux-x86_64.iso"
|
boot_iso: "local:iso/archlinux-x86_64.iso"
|
||||||
children:
|
children:
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ hypervisor_defaults:
|
|||||||
url: ""
|
url: ""
|
||||||
username: ""
|
username: ""
|
||||||
password: ""
|
password: ""
|
||||||
host: ""
|
node: ""
|
||||||
storage: ""
|
storage: ""
|
||||||
datacenter: ""
|
datacenter: ""
|
||||||
cluster: ""
|
cluster: ""
|
||||||
@@ -136,10 +136,10 @@ system_defaults:
|
|||||||
# All virtual types additionally require 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, host, storage]
|
hypervisor: [url, username, password, node, storage]
|
||||||
system: [id]
|
system: [id]
|
||||||
vmware:
|
vmware:
|
||||||
hypervisor: [url, username, password, datacenter, cluster, storage]
|
hypervisor: [url, username, password, datacenter, storage]
|
||||||
system: []
|
system: []
|
||||||
xen:
|
xen:
|
||||||
hypervisor: []
|
hypervisor: []
|
||||||
|
|||||||
@@ -77,7 +77,12 @@
|
|||||||
if (system_raw.mirror | default('') | string | trim | length) > 0
|
if (system_raw.mirror | default('') | string | trim | length) > 0
|
||||||
else _mirror_defaults[system_raw.os | default('') | string | lower] | default('')
|
else _mirror_defaults[system_raw.os | default('') | string | lower] | default('')
|
||||||
}}
|
}}
|
||||||
path: "{{ system_raw.path | default('') | string }}"
|
path: >-
|
||||||
|
{{
|
||||||
|
(system_raw.path | default('') | string)
|
||||||
|
if (system_raw.path | default('') | string | length > 0)
|
||||||
|
else (hypervisor_cfg.folder | default('') | string)
|
||||||
|
}}
|
||||||
packages: >-
|
packages: >-
|
||||||
{{
|
{{
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -32,12 +32,19 @@
|
|||||||
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 }}"
|
||||||
node: "{{ hypervisor_cfg.host }}"
|
node: "{{ hypervisor_cfg.node }}"
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
- name: Normalize system inputs
|
- name: Normalize system inputs
|
||||||
ansible.builtin.include_tasks: system.yml
|
ansible.builtin.include_tasks: system.yml
|
||||||
|
|
||||||
|
- name: Inherit folder from hypervisor when system path is empty
|
||||||
|
when:
|
||||||
|
- system_cfg.path | default('') | string | length == 0
|
||||||
|
- hypervisor_cfg.folder | default('') | string | length > 0
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
system_cfg: "{{ system_cfg | combine({'path': hypervisor_cfg.folder | string}, recursive=True) }}"
|
||||||
|
|
||||||
- name: Validate variables
|
- name: Validate variables
|
||||||
ansible.builtin.include_tasks: validation.yml
|
ansible.builtin.include_tasks: validation.yml
|
||||||
|
|
||||||
@@ -85,3 +92,12 @@
|
|||||||
when: hypervisor_type == "vmware"
|
when: hypervisor_type == "vmware"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
ansible_connection: vmware_tools
|
ansible_connection: vmware_tools
|
||||||
|
ansible_vmware_host: "{{ hypervisor_cfg.url }}"
|
||||||
|
ansible_vmware_port: 443
|
||||||
|
ansible_vmware_user: "{{ hypervisor_cfg.username }}"
|
||||||
|
ansible_vmware_password: "{{ hypervisor_cfg.password }}"
|
||||||
|
ansible_vmware_guest_path: "/{{ hypervisor_cfg.datacenter }}/vm{{ system_cfg.path }}/{{ hostname }}"
|
||||||
|
ansible_vmware_validate_certs: "{{ hypervisor_cfg.certs | bool }}"
|
||||||
|
ansible_vmware_tools_user: root
|
||||||
|
ansible_vmware_tools_password: "{{ system_cfg.root.password }}"
|
||||||
|
no_log: true
|
||||||
|
|||||||
@@ -166,6 +166,23 @@
|
|||||||
label: "hypervisor.{{ item }}"
|
label: "hypervisor.{{ item }}"
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
||||||
|
- name: Validate VMware placement (cluster or node required, mutually exclusive)
|
||||||
|
when:
|
||||||
|
- system_cfg.type == "virtual"
|
||||||
|
- hypervisor_type == "vmware"
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- >-
|
||||||
|
(hypervisor_cfg.cluster | default('') | string | length > 0)
|
||||||
|
or (hypervisor_cfg.node | default('') | string | length > 0)
|
||||||
|
- >-
|
||||||
|
(hypervisor_cfg.cluster | default('') | string | length == 0)
|
||||||
|
or (hypervisor_cfg.node | default('') | string | length == 0)
|
||||||
|
fail_msg: >-
|
||||||
|
VMware requires either hypervisor.cluster or hypervisor.node (mutually exclusive).
|
||||||
|
cluster targets a vSphere cluster; node targets a specific ESXi host.
|
||||||
|
quiet: true
|
||||||
|
|
||||||
- name: Validate hypervisor-specific required system fields
|
- name: Validate hypervisor-specific required system fields
|
||||||
when:
|
when:
|
||||||
- system_cfg.type == "virtual"
|
- system_cfg.type == "virtual"
|
||||||
@@ -293,8 +310,8 @@
|
|||||||
system_disk_mounts: >-
|
system_disk_mounts: >-
|
||||||
{{
|
{{
|
||||||
(system_cfg.disks | default([]))
|
(system_cfg.disks | default([]))
|
||||||
| map(attribute='mount')
|
| map(attribute='mount', default={})
|
||||||
| map(attribute='path')
|
| map(attribute='path', default='')
|
||||||
| map('string')
|
| map('string')
|
||||||
| map('trim')
|
| map('trim')
|
||||||
| reject('equalto', '')
|
| reject('equalto', '')
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
block:
|
block:
|
||||||
- name: Query Proxmox for existing VM
|
- name: Query Proxmox for existing VM
|
||||||
community.proxmox.proxmox_vm_info:
|
community.proxmox.proxmox_vm_info:
|
||||||
node: "{{ hypervisor_cfg.host }}"
|
node: "{{ hypervisor_cfg.node }}"
|
||||||
vmid: "{{ system_cfg.id }}"
|
vmid: "{{ system_cfg.id }}"
|
||||||
name: "{{ hostname }}"
|
name: "{{ hostname }}"
|
||||||
type: qemu
|
type: qemu
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
- name: Check VM existence in vCenter
|
- name: Check VM existence in vCenter
|
||||||
when: hypervisor_type == "vmware"
|
when: hypervisor_type == "vmware"
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
module_defaults:
|
module_defaults:
|
||||||
community.vmware.vmware_guest_info:
|
community.vmware.vmware_guest_info:
|
||||||
hostname: "{{ hypervisor_cfg.url }}"
|
hostname: "{{ hypervisor_cfg.url }}"
|
||||||
@@ -106,6 +107,7 @@
|
|||||||
- name: Check if VM already exists on Xen
|
- name: Check if VM already exists on Xen
|
||||||
when: hypervisor_type == "xen"
|
when: hypervisor_type == "xen"
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
argv:
|
argv:
|
||||||
- xl
|
- xl
|
||||||
|
|||||||
@@ -32,7 +32,8 @@
|
|||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{{ ns.out }}
|
{{ ns.out }}
|
||||||
community.vmware.vmware_guest:
|
community.vmware.vmware_guest:
|
||||||
cluster: "{{ hypervisor_cfg.cluster }}"
|
cluster: "{{ hypervisor_cfg.cluster if (hypervisor_cfg.node | default('') | length == 0) else omit }}"
|
||||||
|
esxi_hostname: "{{ hypervisor_cfg.node if (hypervisor_cfg.node | default('') | length > 0) else omit }}"
|
||||||
folder: "{{ system_cfg.path if system_cfg.path | string | length > 0 else omit }}"
|
folder: "{{ system_cfg.path if system_cfg.path | string | length > 0 else omit }}"
|
||||||
name: "{{ hostname }}"
|
name: "{{ hostname }}"
|
||||||
# Generic guest ID — VMware auto-detects OS post-install
|
# Generic guest ID — VMware auto-detects OS post-install
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ hypervisor:
|
|||||||
url: "pve01.example.com"
|
url: "pve01.example.com"
|
||||||
username: "root@pam"
|
username: "root@pam"
|
||||||
password: "CHANGE_ME"
|
password: "CHANGE_ME"
|
||||||
host: "pve01"
|
node: "pve01"
|
||||||
storage: "local-lvm"
|
storage: "local-lvm"
|
||||||
datacenter: "dc01"
|
datacenter: "dc01"
|
||||||
cluster: "cluster01"
|
cluster: "cluster01"
|
||||||
|
|||||||
Reference in New Issue
Block a user