In an effort to modernize my workflows I’ve finally started to add roles to my growing collection of Ansible playbooks. The first iteration was to remove some simple copy past I’ve done to make rolling back upgrades simple and nearly perfectly reliable. The previous workflow would be identifying risky updates, shutting down the VM, run a ZFS snapshot, start it up, then run the upgrade. Rolling back was simply reverting the snapshot and starting the VM- easy and almost impossible to screw up. The core issue was that my collection of services has grown to 20+ which means manual processes just didn’t scale.

The role certainly isn’t the cleanest but it gets the job done. Here’s the content of the role:

---
- name: Check if VM exists
  community.general.proxmox_kvm:
    api_user: "{{ api_user }}"
    api_password: "{{ api_password }}"
    api_host: "{{ api_host }}"
    node: "{{ node }}"
    vmid: "{{ vmid }}"
  delegate_to: 127.0.0.1
- name: Shutdown VM
  community.general.proxmox_kvm:
    api_user: "{{ api_user }}"
    api_password: "{{ api_password }}"
    api_host: "{{ api_host }}"
    node: "{{ node }}"
    vmid: "{{ vmid }}"
    state: stopped
  delegate_to: 127.0.0.1
- name: Delete old snapshot
  community.general.proxmox_snap:
    api_user: "{{ api_user }}"
    api_password: "{{ api_password }}"
    api_host: "{{ api_host }}"
    vmid: "{{ vmid }}"
    state: absent
    snapname: pre-updates
  delegate_to: 127.0.0.1
- name: Create new snapshot
  community.general.proxmox_snap:
    api_user: "{{ api_user }}"
    api_password: "{{ api_password }}"
    api_host: "{{ api_host }}"
    vmid: "{{ vmid }}"
    state: present
    snapname: pre-updates
  delegate_to: 127.0.0.1
- name: Pause for 5 seconds
  ansible.builtin.pause:
    seconds: 5
  delegate_to: 127.0.0.1
- name: start VM
  community.general.proxmox_kvm:
    api_user: "{{ api_user }}"
    api_password: "{{ api_password }}"
    api_host: "{{ api_host }}"
    node: "{{ node }}"
    vmid: "{{ vmid }}"
    state: started
  delegate_to: 127.0.0.1
- name: Pause for 10 seconds
  ansible.builtin.pause:
    seconds: 20
---

The delegate_to tags are used as the role is used on playbooks executed on application hosts. This allows me to only have credentials wherever I’m executing it from and deal with the proxmoxer dependency locally.