Ansible for Proxmox VE · Module 05
module_defaultsOne API call, one cluster-wide change. You address any node; pmxcfs distributes the result.
Every node serves the full API reference, for exactly the version you are running:
Use it when a module lacks an option. The page tells you whether the API has it at all — which decides between “file a feature request” and “use ansible.builtin.uri”.
POST /nodes/{node}/qemu in the API browser lists vmid, cores, memory, scsihw — the same names. That correspondence is what makes the browser the fastest way to find out what a guest option is actually called.
module_defaultsEvery community.proxmox module in this play inherits those four lines.
The node is a Debian machine and a Proxmox VE node.
The backup directory is local to each node. An NFS library is shared, and it is where images and templates live in a real environment:
/mnt/pve/nfs-sharedcontent decides what may live there; no images, so nothing gets allocated on it- community.proxmox.proxmox_group:
name: automation
comment: Service accounts
- community.proxmox.proxmox_user:
name: automation@pve
groups: [automation]
comment: Ansible service account
enable: true
- community.proxmox.proxmox_access_acl:
path: /
type: group
ugid: automation
roleid: PVEVMAdmin
propagate: 1Realms matter: @pam are Linux users on the node, @pve exist only in Proxmox VE.
automation_user.secretsprivsep: false gives the token the user’s permissions; true restricts it further with its own ACLNever print a secret with debug in a shared session. Write it somewhere safe, ideally straight into an encrypted file.
A token can be revoked on its own, is scoped by ACL, and never unlocks an SSH session. The root password can do none of those things.
- community.proxmox.proxmox_kvm:
node: "{{ pve_vm_node }}"
vmid: "{{ pve_vm_id }}"
name: "{{ pve_vm_name }}"
cores: 1
memory: 1024
ostype: l26
scsihw: virtio-scsi-single
scsi:
scsi0: "{{ pve_vm_storage }}:0,import-from={{ pve_cloud_image_path }}"
ide:
ide2: "{{ pve_vm_storage }}:cloudinit"
net:
net0: virtio,bridge=vmbr0
boot: "order=scsi0"
timeout: 300 # NFS import is slower than the 30 s default
state: present:0 means “size taken from the source image”import-from reads the qcow2 straight off the NFS libraryide2: …:cloudinit adds the cloud-init drivecan't find fileWaiting for the path does not help: nothing has asked the node to mount it yet.
The guest configures its user, its SSH key and its address on first boot. No installer, no answer file, no template maintenance.
cipassword alone will not get you in: the Debian cloud image ships with PasswordAuthentication no. Set sshkeys.
Import, boot and cloud-init together take well under a minute on this lab.
The template has to be on the storage first; proxmox_template downloads it. Never hard-code the file name; ask the node which ones exist:
Not everything has a module, and some things are simply faster to write directly. A second bridge, over SSH:
- name: Add a second bridge
hosts: pve
tasks:
- name: Define vmbr1 in /etc/network/interfaces
ansible.builtin.blockinfile:
path: /etc/network/interfaces
marker: "# {mark} ANSIBLE MANAGED - vmbr1"
block: |
auto vmbr1
iface vmbr1 inet manual
bridge-ports none
bridge-stp off
bridge-fd 0
notify: Reload network configurationifreload -a applies the change immediately. A mistake in the file for vmbr0 takes the node off the network, including your own SSH session. Always keep a console (VDI, IPMI) available, and never touch the management interface of all three nodes in one run.
/etc/network/interfaces.new, the same pending state the GUI showsifreload -aBoth routes end in the same file. Only one of them is idempotent and reviewable before it takes effect.
blockinfile over SSH |
proxmox_node_network |
|
|---|---|---|
| Idempotent | you build the guard | yes |
| Visible in the GUI as pending | no, it is already in the live file | yes |
| Works without the collection | yes | no |
| Risk of locking yourself out | high | lower, but real |
Use the module when it covers your case. Reach for the file when it does not, and then go carefully: one node at a time, --limit, console at hand.
wait: true makes the task finish when the backup finishes, not when the API has accepted the request.
Creating a scheduled backup job is not covered by a module today. proxmox_backup_schedule only adds guests to a job that already exists.
ansible.builtin.uri against the REST API works for anything. You lose idempotency, so you add the guard yourself, the same way you do with command.
Storage, a service account with a token, a VM, a backup. One playbook.
→ Exercise sheet: Operating the cluster
credativ · Ansible for Proxmox VE