From 011885eed0033caa6a85c2ad12626c750117e4b7 Mon Sep 17 00:00:00 2001 From: Vezpi Date: Wed, 19 Aug 2026 12:49:29 +0000 Subject: [PATCH 1/4] add: cloudinit_template playbook --- ansible/proxmox/cloudinit_template.yml | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 ansible/proxmox/cloudinit_template.yml diff --git a/ansible/proxmox/cloudinit_template.yml b/ansible/proxmox/cloudinit_template.yml new file mode 100644 index 0000000..2cd4fcf --- /dev/null +++ b/ansible/proxmox/cloudinit_template.yml @@ -0,0 +1,72 @@ +--- +- name: Create or update a cloud-init Ubuntu template + hosts: zenith.mgmt.vezpi.com + become: true + gather_facts: false + vars: + template_vmid: 900 + template_os: ubuntu + os_release: noble + + template_name: "{{template_os}}-{{ os_release }}-cloud" + + image_filename: "{{ os_release }}-server-cloudimg-amd64.img" + image_url: "https://cloud-images.ubuntu.com/{{ os_release }}/current/{{ image_filename }}" + image_dest: "/var/lib/vz/template/iso/{{ image_filename }}" + + iso_storage: local + vm_storage: ceph-workload + + template_memory: 2048 + template_cores: 1 + + tasks: + - name: Download the current Ubuntu cloud image + ansible.builtin.get_url: + url: "{{ image_url }}" + dest: "{{ image_dest }}" + force: false + mode: "0644" + register: image_download + + - name: Check whether the template VMID already exists + ansible.builtin.command: qm status {{ template_vmid }} + register: template_status + changed_when: false + failed_when: false + + - name: Rebuild the template + when: image_download.changed or template_status.rc != 0 + block: + - name: Destroy existing template if present + ansible.builtin.command: qm destroy {{ template_vmid }} --purge + when: template_status.rc == 0 + + - name: Create the base VM shell + ansible.builtin.command: > + qm create {{ template_vmid }} + --memory {{ template_memory }} + --core {{ template_cores }} + --net0 virtio,bridge=vmbr0 + --scsihw virtio-scsi-pci + --bios ovmf + --machine q35 + --efidisk0 {{ vm_storage }}:0,pre-enrolled-keys=0 + --name {{ template_name }} + changed_when: true + + - name: Import the cloud image as the primary disk + ansible.builtin.command: qm set {{ template_vmid }} --scsi0 {{ vm_storage }}:0,import-from={{ image_dest }} + + - name: Attach a cloud-init drive + ansible.builtin.command: qm set {{ template_vmid }} --scsi1 {{ vm_storage }}:cloudinit + + - name: Set boot order to the primary disk + ansible.builtin.command: qm set {{ template_vmid }} --boot order=scsi0 + + - name: Add serial console for cloud-init consoles + ansible.builtin.command: qm set {{ template_vmid }} --serial0 socket --vga serial0 + + - name: Convert the VM to a template + ansible.builtin.command: qm template {{ template_vmid }} + -- 2.54.0 From 189d031b13ed14f10ceecb5a07256862b37374a2 Mon Sep 17 00:00:00 2001 From: Vezpi Date: Thu, 20 Aug 2026 19:29:24 +0000 Subject: [PATCH 2/4] feat: the template can be create on other hosts --- ansible/proxmox/cloudinit_template.yml | 57 ++++++++++++++++++++------ 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/ansible/proxmox/cloudinit_template.yml b/ansible/proxmox/cloudinit_template.yml index 2cd4fcf..343755f 100644 --- a/ansible/proxmox/cloudinit_template.yml +++ b/ansible/proxmox/cloudinit_template.yml @@ -1,8 +1,7 @@ --- - name: Create or update a cloud-init Ubuntu template - hosts: zenith.mgmt.vezpi.com + hosts: nodes become: true - gather_facts: false vars: template_vmid: 900 template_os: ubuntu @@ -21,6 +20,41 @@ template_cores: 1 tasks: + - name: Check whether the template VMID already exists + ansible.builtin.command: qm status {{ template_vmid }} + register: template_status + changed_when: false + failed_when: false + + - name: Check if the cloud image file exists + ansible.builtin.stat: + path: "{{ image_dest }}" + register: image_exists + changed_when: false + failed_when: false + + - name: Set candidate information + ansible.builtin.set_fact: + has_image_file: "{{ image_exists.stat.exists }}" + root_free_space: "{{ (ansible_mounts | selectattr('mount', 'equalto', '/') | first).size_available }}" + + - name: Select target host + ansible.builtin.set_fact: + target_host: >- + {{ (ansible_play_hosts + | map('extract', hostvars) + | selectattr('has_target_file', 'equalto', true) + | sort(attribute='root_free_space', reverse=true) + | map(attribute='inventory_hostname') + | first) + | default(ansible_play_hosts + | map('extract', hostvars) + | sort(attribute='root_free_space', reverse=true) + | map(attribute='inventory_hostname') + | first, + true) }} + run_once: true + - name: Download the current Ubuntu cloud image ansible.builtin.get_url: url: "{{ image_url }}" @@ -28,19 +62,18 @@ force: false mode: "0644" register: image_download - - - name: Check whether the template VMID already exists - ansible.builtin.command: qm status {{ template_vmid }} - register: template_status - changed_when: false - failed_when: false + when: inventory_hostname == target_host + + - name: Destroy existing template if present + ansible.builtin.command: qm destroy {{ template_vmid }} --purge + when: template_status.rc == 0 - name: Rebuild the template - when: image_download.changed or template_status.rc != 0 + when: + - inventory_hostname == target_host + - image_download.changed or + template_status.rc != 0 block: - - name: Destroy existing template if present - ansible.builtin.command: qm destroy {{ template_vmid }} --purge - when: template_status.rc == 0 - name: Create the base VM shell ansible.builtin.command: > -- 2.54.0 From d1e416ea92aeb2e8470058231f7fd836c6d7e88c Mon Sep 17 00:00:00 2001 From: Vezpi Date: Thu, 20 Aug 2026 19:39:08 +0000 Subject: [PATCH 3/4] fix: remove template only when image changed --- ansible/proxmox/cloudinit_template.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ansible/proxmox/cloudinit_template.yml b/ansible/proxmox/cloudinit_template.yml index 343755f..1c98426 100644 --- a/ansible/proxmox/cloudinit_template.yml +++ b/ansible/proxmox/cloudinit_template.yml @@ -36,7 +36,7 @@ - name: Set candidate information ansible.builtin.set_fact: has_image_file: "{{ image_exists.stat.exists }}" - root_free_space: "{{ (ansible_mounts | selectattr('mount', 'equalto', '/') | first).size_available }}" + root_free_space: "{{ (ansible_facts['mounts'] | selectattr('mount', 'equalto', '/') | first).size_available }}" - name: Select target host ansible.builtin.set_fact: @@ -66,7 +66,9 @@ - name: Destroy existing template if present ansible.builtin.command: qm destroy {{ template_vmid }} --purge - when: template_status.rc == 0 + when: + - template_status.rc == 0 + - image_download.changed - name: Rebuild the template when: -- 2.54.0 From 48253e405589052c27c53060f3213a021761a88c Mon Sep 17 00:00:00 2001 From: Vezpi Date: Thu, 20 Aug 2026 19:43:06 +0000 Subject: [PATCH 4/4] fix: use correct var name --- ansible/proxmox/cloudinit_template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/proxmox/cloudinit_template.yml b/ansible/proxmox/cloudinit_template.yml index 1c98426..4d53f7c 100644 --- a/ansible/proxmox/cloudinit_template.yml +++ b/ansible/proxmox/cloudinit_template.yml @@ -43,7 +43,7 @@ target_host: >- {{ (ansible_play_hosts | map('extract', hostvars) - | selectattr('has_target_file', 'equalto', true) + | selectattr('has_image_file', 'equalto', true) | sort(attribute='root_free_space', reverse=true) | map(attribute='inventory_hostname') | first) -- 2.54.0