refactor: proxmox_upgrade use inline community.proxmox for API calls.

This commit is contained in:
Semaphore
2026-03-14 15:23:47 -07:00
parent 464fba619f
commit 9bb8e97c82
9 changed files with 274 additions and 384 deletions

View File

@@ -1,81 +1,43 @@
---
# =============================================================================
# proxmox_upgrade — restore.yml
# Optionally migrate guests back to their original node after upgrade
# Optionally migrate guests back to original node after upgrade
# Only runs if migration_restore: true
# =============================================================================
- name: "Restore | Skip — migration_restore=false"
ansible.builtin.debug:
msg: "migration_restore=false — leaving guests on their current nodes"
msg: "migration_restore=false — guests remain on {{ migration_target }}"
when: not migration_restore | bool
delegate_to: localhost
- name: "Restore | Migrate guests back to {{ current_node }}"
when: migration_restore | bool
block:
- name: "Restore | Migrate all guests back to {{ current_node }}"
ansible.builtin.shell: |
python3 << 'PYEOF'
import urllib.request, json, ssl, time
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
api_base = "https://{{ api_host }}:{{ api_port }}/api2/json"
headers = {"Authorization": "PVEAPIToken={{ api_token_id }}={{ api_token_secret }}"}
node = "{{ current_node }}"
source = "{{ migration_targets | first }}"
plan = {{ migration_plan | to_json }}
fallback = "{{ live_migrate_fallback }}"
def api_req(path, method="GET", body=None):
url = f"{api_base}{path}"
data = json.dumps(body).encode() if body else None
hdrs = {**headers}
if data:
hdrs["Content-Type"] = "application/json"
req = urllib.request.Request(url, data=data, headers=hdrs, method=method)
with urllib.request.urlopen(req, context=ctx) as r:
return json.loads(r.read())["data"]
task_ids = []
for guest in plan:
if guest["needs_fallback"] and fallback == "skip":
print(f"SKIP restore: {guest['type'].upper()} {guest['vmid']} ({guest['name']}) — was skipped during drain")
continue
gtype = guest["type"]
online = 0 if (guest["needs_fallback"] and fallback == "shutdown") else 1
print(f"Restoring {gtype.upper()} {guest['vmid']} ({guest['name']}) → {node} (online={online})...")
task_id = api_req(f"/nodes/{source}/{gtype}/{guest['vmid']}/migrate", "POST",
{"target": node, "online": online})
task_ids.append({"vmid": guest["vmid"], "name": guest["name"], "task": task_id, "type": gtype})
failed = []
for t in task_ids:
for _ in range(60):
status = api_req(f"/nodes/{source}/tasks/{t['task']}/status")
if status["status"] == "stopped":
if status.get("exitstatus") != "OK":
failed.append(f"{t['name']} ({t['vmid']}): {status.get('exitstatus')}")
else:
print(f"OK: {t['name']} ({t['vmid']}) restored to {node}")
break
time.sleep(10)
else:
failed.append(f"{t['name']} ({t['vmid']}): timed out")
if failed:
print("FAILED restores: " + ", ".join(failed))
exit(1)
print(f"All guests restored to {node}")
PYEOF
register: restore_result
- name: "Restore | KVM | Migrate back to {{ current_node }}"
community.proxmox.proxmox_kvm:
api_host: "{{ api_host }}"
api_token_id: "{{ api_token_id }}"
api_token_secret: "{{ api_token_secret }}"
api_port: "{{ api_port }}"
node: "{{ migration_target }}"
vmid: "{{ item.vmid }}"
migrate: true
target_node: "{{ current_node }}"
online: "{{ true if item.status == 'running' else false }}"
timeout: "{{ vm_shutdown_timeout }}"
loop: "{{ kvm_guests | default([]) }}"
delegate_to: localhost
- name: "Restore | LXC | Migrate back to {{ current_node }}"
ansible.builtin.command: >
pct migrate {{ item.vmid }} {{ current_node }}
{{ '--restart' if item.status == 'running' else '' }}
--timeout {{ lxc_migrate_timeout }}
loop: "{{ lxc_guests | default([]) }}"
when: live_migrate_fallback != 'skip'
changed_when: true
delegate_to: "{{ migration_target }}"
- name: "Restore | Log result"
- name: "Restore | Complete"
ansible.builtin.debug:
msg: "{{ restore_result.stdout_lines }}"
delegate_to: localhost
msg: "All guests restored to {{ current_node }}"