From c969585a1aa6f2c0c743d422eb2260ed3aeaa7c6 Mon Sep 17 00:00:00 2001 From: Cole Deck Date: Fri, 5 Jul 2024 17:25:57 -0500 Subject: [PATCH] Add 'proxmox-util.py' --- proxmox-util.py | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 proxmox-util.py diff --git a/proxmox-util.py b/proxmox-util.py new file mode 100644 index 0000000..1cae9da --- /dev/null +++ b/proxmox-util.py @@ -0,0 +1,152 @@ +import requests +import json +import time +import urllib3 + +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) +# Proxmox API details +hosts = ['https://10.0.0.5:8006'] +hostnames = ['pve'] +username = 'root@pam' +password = 'mypasswordhere' +vmids = [100, 101, 102, 103, 104, 105, 106, 107] #, 101, 102, 103, 104, 105, 106, 107] # Replace with your VMIDs + +# Function to get the authentication ticket and CSRF token +def get_auth_ticket(username, password, host): + url = f"{host}/api2/json/access/ticket" + data = { + 'username': username, + 'password': password + } + print(f"Connecting to {host}") + response = requests.post(url, data=data, verify=False) + #print(response.json()) + result = response.json() + return result['data']['ticket'], result['data']['CSRFPreventionToken'] + +# Function to get the latest snapshot for a VM +def get_latest_snapshot(vm_id, ticket, csrf_token, host, node): + if not check_server(vm_id, ticket, csrf_token, host, node): + return None + url = f"{host}/api2/json/nodes/{node}/qemu/{vm_id}/snapshot" + headers = { + 'Cookie': f"PVEAuthCookie={ticket}" + } + response = requests.get(url, headers=headers, verify=False) + snapshots = response.json()['data'] + if snapshots: + snapshots = [s for s in snapshots if 'snaptime' in s] + #print(response.json()['data']) + else: + return None + if snapshots: + latest_snapshot = max(snapshots, key=lambda x: x['snaptime']) + return latest_snapshot['name'] + return None + +# Function to restore a snapshot for a VM +def restore_snapshot(vm_id, snapshot_name, ticket, csrf_token, host, node): + url = f"{host}/api2/json/nodes/{node}/qemu/{vm_id}/snapshot/{snapshot_name}/rollback?start=1" + headers = { + 'Cookie': f"PVEAuthCookie={ticket}", + 'CSRFPreventionToken': csrf_token + } + urla = f"{host}/api2/json/cluster/ha/resources/vm:{vm_id}?state=ignored" + response = requests.put(urla, headers=headers, verify=False) + print(f"Disabled HA for VM {vm_id}") + time.sleep(1) # wait for HA to stop + response = requests.post(url, headers=headers, verify=False) + + if response.status_code == 200: + print(f"VM {vm_id}: Restoring snapshot '{snapshot_name}'") + #print(response.json()['data']) + return response.json()['data'] + else: + print(f"VM {vm_id}: Failed to restore snapshot '{snapshot_name}'") + return None + +# Function to check the status of a task +def check_task_status(node, task_id, ticket, host): + url = f"{host}/api2/json/nodes/{node}/tasks/{task_id}/status" + headers = { + 'Cookie': f"PVEAuthCookie={ticket}" + } + response = requests.get(url, headers=headers, verify=False) + #print(response.json()) + return response.json()['data']['status'] == 'stopped' + +# Function to wait for all tasks to complete +def wait_for_tasks_to_complete(tasks, ticket, host): + print("Waiting for rollbacks to complete...") + while tasks: + time.sleep(3) + for node, task_id in tasks.copy(): + #print("Checking task", task_id) + if check_task_status(node, task_id, ticket, host): + print(f"Task {task_id} on node {node} completed") + tasks.remove((node, task_id)) + print("All VMs rolled back.") + +def enable_ha(vm_id, ticket, csrf_token, host): + headers = { + 'Cookie': f"PVEAuthCookie={ticket}", + 'CSRFPreventionToken': csrf_token + } + urla = f"{host}/api2/json/cluster/ha/resources/vm:{vm_id}?state=started" + response = requests.put(urla, headers=headers, verify=False) + print(f"HA re-enabled for VMID {vm_id}") + +def vm_snapshot(station=0): + if station > 0: + # individual station restore + vm_id = 99 + station + for host in hosts: + tasks = [] + ticket, csrf_token = get_auth_ticket(username, password, host) + for node in hostnames: + latest_snapshot = get_latest_snapshot(vm_id, ticket, csrf_token, host, node) + if latest_snapshot: + task = restore_snapshot(vm_id, latest_snapshot, ticket, csrf_token, host, node) + if task: + tasks.append((node, task)) + + else: + + for host in hosts: + tasks = [] + ticket, csrf_token = get_auth_ticket(username, password, host) + for node in hostnames: + for vm_id in vmids: + latest_snapshot = get_latest_snapshot(vm_id, ticket, csrf_token, host, node) + if latest_snapshot: + task = restore_snapshot(vm_id, latest_snapshot, ticket, csrf_token, host, node) + if task: + tasks.append((node, task)) + + wait_for_tasks_to_complete(tasks, ticket, host) + for vm_id in vmids: + enable_ha(vm_id, ticket, csrf_token, host) + +def check_server(vm_id, ticket, csrf_token, host, node): + headers = { + 'Cookie': f"PVEAuthCookie={ticket}", + 'CSRFPreventionToken': csrf_token + } + url = f"{host}/api2/json/nodes/{node}/qemu" + response = requests.get(url, headers=headers, verify=False) + #print("Server check:", response.json()) + for entry in response.json()['data']: + if entry['vmid'] == vm_id: + return True + return False + +def check_online(vm_id, ticket, csrf_token, host, node): + # check if VM is booted by seeing if the guest agent is running + headers = { + 'Cookie': f"PVEAuthCookie={ticket}", + 'CSRFPreventionToken': csrf_token + } + url = f"{host}/api2/json/nodes/{node}/qemu/{vm_id}/agent/ping" + response = requests.post(url, headers=headers, verify=False) + #print(response.json()) + return response.json()['data'] is not None