Snapshot review script
This commit is contained in:
parent
72a5ae31f0
commit
aed349520a
6 changed files with 132 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -59,3 +59,4 @@ target/
|
||||||
|
|
||||||
# Project-specific
|
# Project-specific
|
||||||
venv
|
venv
|
||||||
|
proxmox_scripts/settings.py
|
||||||
|
|
19
proxmox_scripts/auth.py
Normal file
19
proxmox_scripts/auth.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from proxmoxer import ProxmoxAPI
|
||||||
|
from . import settings
|
||||||
|
|
||||||
|
import typing as t
|
||||||
|
|
||||||
|
|
||||||
|
_api: t.Optional[ProxmoxAPI] = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_api() -> ProxmoxAPI:
|
||||||
|
global _api
|
||||||
|
if _api is None:
|
||||||
|
_api = ProxmoxAPI(
|
||||||
|
settings.PROXMOX_HOST,
|
||||||
|
user=settings.PROXMOX_USER,
|
||||||
|
password=settings.PROXMOX_PASS(),
|
||||||
|
verify_ssl=True,
|
||||||
|
)
|
||||||
|
return _api
|
5
proxmox_scripts/settings.example.py
Normal file
5
proxmox_scripts/settings.example.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import typing as t
|
||||||
|
|
||||||
|
PROXMOX_HOST: str = "hv1.example.com:8006" # FIXME
|
||||||
|
PROXMOX_USER: str = "username@pam" # FIXME
|
||||||
|
PROXMOX_PASS: t.Callable[[], str] = lambda: "changeme" # FIXME
|
53
proxmox_scripts/snapshots.py
Normal file
53
proxmox_scripts/snapshots.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
from . import auth
|
||||||
|
from . import util
|
||||||
|
import datetime
|
||||||
|
import typing as t
|
||||||
|
from proxmoxer.core import ProxmoxResource
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
|
||||||
|
def list_snapshots() -> list:
|
||||||
|
snapshots = []
|
||||||
|
|
||||||
|
for vmid, vm in util.qemu_vms().items():
|
||||||
|
for snapshot in vm['api'].snapshot().get():
|
||||||
|
if snapshot['name'] != 'current':
|
||||||
|
snapshot['node'] = vm['node']
|
||||||
|
snapshot['vmid'] = vmid
|
||||||
|
snapshot['vmname'] = vm['name']
|
||||||
|
snapshot['api'] = vm['api'].snapshot(snapshot['name'])
|
||||||
|
snapshots.append(snapshot)
|
||||||
|
return snapshots
|
||||||
|
|
||||||
|
def review_snapshots():
|
||||||
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument('--older-than', help='More than N days ago only', type=int,
|
||||||
|
default=0)
|
||||||
|
parser.add_argument('--delete', '-d', help='Offer to delete snapshots',
|
||||||
|
action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
filter_date = datetime.datetime.now() - datetime.timedelta(days=args.older_than)
|
||||||
|
|
||||||
|
for snap in list_snapshots():
|
||||||
|
snap_date = datetime.datetime.fromtimestamp(snap['snaptime'])
|
||||||
|
snap_age = datetime.datetime.now() - snap_date
|
||||||
|
if snap_date > filter_date:
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"{snap['node']} -- [{snap['vmid']}] {snap['vmname']} -- "
|
||||||
|
f"at {snap_date} ({snap_age.days}d ago)")
|
||||||
|
for attr, val in snap.items():
|
||||||
|
if attr in ('node', 'vmid', 'vmname', 'snap_date', 'snaptime', 'api'):
|
||||||
|
continue
|
||||||
|
print(f" {attr}: {val}")
|
||||||
|
|
||||||
|
if args.delete:
|
||||||
|
print(" Delete? [vmid to delete] ", end='')
|
||||||
|
res = input().strip()
|
||||||
|
if res == str(snap['vmid']):
|
||||||
|
snap['api'].delete()
|
||||||
|
print(" Deleted.")
|
||||||
|
|
||||||
|
print("")
|
20
proxmox_scripts/util.py
Normal file
20
proxmox_scripts/util.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from . import auth
|
||||||
|
|
||||||
|
|
||||||
|
def nodes() -> dict[str, dict]:
|
||||||
|
""" List of hypervisors """
|
||||||
|
nodes = auth.get_api().nodes.get()
|
||||||
|
return {node['node']: node for node in nodes}
|
||||||
|
|
||||||
|
|
||||||
|
def qemu_vms() -> dict:
|
||||||
|
""" Flat dict of QEMU VMs on all hypervisors """
|
||||||
|
out = {}
|
||||||
|
api = auth.get_api()
|
||||||
|
|
||||||
|
for node in nodes():
|
||||||
|
for vm in api.nodes(node).qemu.get():
|
||||||
|
vm['node'] = node
|
||||||
|
vm['api'] = api.nodes(node).qemu(vm['vmid'])
|
||||||
|
out[vm['vmid']] = vm
|
||||||
|
return out
|
34
setup.py
Normal file
34
setup.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
|
||||||
|
def parse_requirements():
|
||||||
|
reqs = []
|
||||||
|
with open("requirements.txt", "r") as handle:
|
||||||
|
for line in handle:
|
||||||
|
reqs.append(line)
|
||||||
|
return reqs
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="proxmox_scripts",
|
||||||
|
version="0.1.0",
|
||||||
|
description="Collection of misc scripts to manage proxmox",
|
||||||
|
author="tobast",
|
||||||
|
author_email="contact@tobast.fr",
|
||||||
|
license="LICENSE",
|
||||||
|
url="https://git.tobast.fr/tobast/proxmox_scripts/",
|
||||||
|
packages=find_packages(),
|
||||||
|
include_package_data=True,
|
||||||
|
long_description=open("README.md").read(),
|
||||||
|
install_requires=parse_requirements(),
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
|
(
|
||||||
|
"proxmox-snapshot-review = proxmox_scripts.snapshots:review_snapshots",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in a new issue