Compare commits

...

1 Commits
main ... enh

2 changed files with 94 additions and 59 deletions

View File

@ -1,4 +1,5 @@
import logging
import time
from proxmoxer import ProxmoxAPI
@ -55,12 +56,17 @@ def delete_vm(
proxmox: ProxmoxAPI,
node: str,
vmid: int,
) -> None:
proxmox.nodes(node).qemu(vmid).delete(
node=node,
vmid=vmid,
) -> str:
upid: str = (
proxmox.nodes(node)
.qemu(vmid)
.delete(
node=node,
vmid=vmid,
)
)
logger.info("VM %s was deleted successfully!", vmid)
return upid
def clone_template(
@ -107,17 +113,27 @@ def get_vm_ip(
node: str,
vmid: int,
) -> str:
res: dict = (
proxmox.nodes(node).qemu(vmid).agent("network-get-interfaces").get()
) # pyright: ignore
done = False
vm_ip_address = None
for net in res["result"]:
if net["name"] == "eth0" or net["name"] == "ens19":
for ip in net["ip-addresses"]:
if ip["ip-address-type"] == "ipv4":
vm_ip_address = ip["ip-address"]
while not done:
try:
res: dict = (
proxmox.nodes(node).qemu(vmid).agent("network-get-interfaces").get()
) # pyright: ignore
for net in res["result"]:
if net["name"] == "eth0" or net["name"] == "ens19":
for ip in net["ip-addresses"]:
if ip["ip-address-type"] == "ipv4":
vm_ip_address = ip["ip-address"]
done = True
except KeyError:
time.sleep(1)
except Exception as e:
raise RuntimeError(
f"Could not get the ip address of VM {vmid} on node {node}"
) from e
if vm_ip_address is None:
raise ValueError(f"Could not get the ip address of VM {vmid} on node {node}")
raise RuntimeError(f"Could not get the ip address of VM {vmid} on node {node}")
return vm_ip_address

111
main.py Normal file → Executable file
View File

@ -1,15 +1,15 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import argparse
import logging
import os
import sys
from time import sleep
from typing import Callable
import time
import urllib3
import yaml
from dotenv import load_dotenv
from proxmoxer import ProxmoxAPI
from proxmoxer import ProxmoxAPI, ResourceException
from proxmoxer.tools import Tasks
from functions import clone_template, delete_vm, get_vm_ip
@ -28,15 +28,19 @@ PROXMOX_USER_FULL: str | None = os.environ.get("PROXMOX_USER_FULL")
PROXMOX_PASSWORD: str | None = os.environ.get("PROXMOX_PASSWORD")
def wait_status(
funcs: list[Callable[[], dict[str, str]]], status: str, sleep_time: float = 60
) -> None:
statuses = [False] * len(funcs)
while not all(statuses):
logger.debug(statuses)
sleep(sleep_time)
for i in range(len(funcs)):
statuses[i] = funcs[i]()["status"] == status
def tasks_wait_completion(proxmox: ProxmoxAPI, upids: list[str]) -> None:
for upid in upids:
Tasks.blocking_status(proxmox, upid)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument(
"branch",
help="used to pick the appropriate VM template to clone",
choices=["sisyphus", "c10f2", "p10"],
)
return parser.parse_args()
def main() -> None:
@ -45,6 +49,8 @@ def main() -> None:
assert PROXMOX_USER_FULL is not None
assert PROXMOX_PASSWORD is not None
args = parse_args()
proxmox = ProxmoxAPI(
PROXMOX_HOST,
user=PROXMOX_USER_FULL,
@ -57,10 +63,7 @@ def main() -> None:
# node = min(nodes, key=lambda node: node['disk'])['node']
node: str = "pve05"
assert len(sys.argv) >= 2
branch: str = sys.argv[1]
match branch:
match args.branch:
case "sisyphus":
template_id: int = 374
case "p10":
@ -92,15 +95,24 @@ def main() -> None:
if delete != "0":
logger.info("Stopping VMs %s...", vm_ids)
proxmox.nodes(node).qemu(vm_ids["master"]).status.stop.post()
proxmox.nodes(node).qemu(vm_ids["worker1"]).status.stop.post()
proxmox.nodes(node).qemu(vm_ids["worker2"]).status.stop.post()
sleep(15)
tasks_wait_completion(
proxmox,
[
proxmox.nodes(node).qemu(vm_ids["master"]).status.stop.post(),
proxmox.nodes(node).qemu(vm_ids["worker1"]).status.stop.post(),
proxmox.nodes(node).qemu(vm_ids["worker2"]).status.stop.post(),
],
)
logger.info("Deleting VMs %s...", vm_ids)
delete_vm(proxmox, node, vm_ids["master"])
delete_vm(proxmox, node, vm_ids["worker1"])
delete_vm(proxmox, node, vm_ids["worker2"])
sleep(15)
tasks_wait_completion(
proxmox,
[
delete_vm(proxmox, node, vm_ids["master"]),
delete_vm(proxmox, node, vm_ids["worker1"]),
delete_vm(proxmox, node, vm_ids["worker2"]),
],
)
vm_id_master, upid_master = clone_template(
proxmox,
@ -130,35 +142,42 @@ def main() -> None:
assert vm_id_worker2 == vm_ids["worker2"]
logger.info("Waiting for cloning to complete...")
wait_status(
tasks_wait_completion(
proxmox,
[
proxmox.nodes(node).tasks(upid_master).status.get,
proxmox.nodes(node).tasks(upid_worker1).status.get,
proxmox.nodes(node).tasks(upid_worker2).status.get,
], # pyright: ignore
"stopped",
sleep_time=40,
upid_master,
upid_worker1,
upid_worker2,
],
)
logger.info("Cloning completed!")
logger.info("Starting VMs...")
proxmox.nodes(node).qemu(vm_ids["master"]).status.start.post()
proxmox.nodes(node).qemu(vm_ids["worker1"]).status.start.post()
proxmox.nodes(node).qemu(vm_ids["worker2"]).status.start.post()
wait_status(
tasks_wait_completion(
proxmox,
[
proxmox.nodes(node).qemu(vm_ids["master"]).status.current.get,
proxmox.nodes(node).qemu(vm_ids["worker1"]).status.current.get,
proxmox.nodes(node).qemu(vm_ids["worker2"]).status.current.get,
], # pyright: ignore
"running",
sleep_time=10,
proxmox.nodes(node).qemu(vm_ids["master"]).status.start.post(),
proxmox.nodes(node).qemu(vm_ids["worker1"]).status.start.post(),
proxmox.nodes(node).qemu(vm_ids["worker2"]).status.start.post(),
],
)
sleep(40)
logger.info("VMs are running!")
logger.info("Waiting for QEMU guest agent to start")
done = False
while not done:
try:
_ = proxmox.nodes(node).qemu(vm_ids["master"]).agent.ping.post()
_ = proxmox.nodes(node).qemu(vm_ids["worker1"]).agent.ping.post()
_ = proxmox.nodes(node).qemu(vm_ids["worker2"]).agent.ping.post()
except ResourceException:
time.sleep(1)
except Exception as e:
raise RuntimeError("Failed to ping QEMU agent") from e
else:
done = True
logger.info("QEMU guest agent is running")
vm_ip_master: str = get_vm_ip(proxmox, node, vm_ids["master"])
vm_ip_worker1: str = get_vm_ip(proxmox, node, vm_ids["worker1"])
vm_ip_worker2: str = get_vm_ip(proxmox, node, vm_ids["worker2"])