Skip to content

Commit

Permalink
feat: Add summary command
Browse files Browse the repository at this point in the history
  • Loading branch information
lperdereau committed Oct 29, 2024
1 parent 2c2de3e commit 8a11685
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 8 deletions.
53 changes: 49 additions & 4 deletions src/pvecontrol/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,47 @@ def action_clusterstatus(proxmox, args):
_print_tableoutput([status])
_print_tableoutput(nodes)

def action_summary(proxmox, args):
status = "healthy" if proxmox.is_healthy() else "not healthy"

templates = sum([len(node.templates()) for node in proxmox.nodes])
vms = sum([len(node.vms) for node in proxmox.nodes])
metrics = proxmox.metrics()

metrics_cpu_output = "{:.2f}/{}({:.1f}%)".format(
metrics['cpu']['usage'],
metrics['cpu']['total'],
metrics['cpu']['percent']
)

metrics_memory_output = "{}/{}({:.1f}%)".format(
naturalsize(metrics['memory']['usage'], binary=True),
naturalsize(metrics['memory']['total'], binary=True),
metrics['memory']['percent']
)

metrics_disk_output = "{}/{}({:.1f}%)".format(
naturalsize(metrics['disk']['usage'], binary=True),
naturalsize(metrics['disk']['total'], binary=True),
metrics['disk']['percent']
)

output = f"""
Status: {status}
VMs: {vms - templates}
Templates: {templates}
Metrics:
CPU: {metrics_cpu_output}
Memory: {metrics_memory_output}
Disk: {metrics_disk_output}
Nodes:
Offline: {len([node for node in proxmox.nodes if node.status == NodeStatus.offline])}
Online: {len([node for node in proxmox.nodes if node.status == NodeStatus.online])}
Unknown: {len([node for node in proxmox.nodes if node.status == NodeStatus.unknown])}
"""

print(output)

def action_nodelist(proxmox, args):
"""List proxmox nodes in the cluster using proxmoxer api"""
nodes = [ _filter_keys(n.__dict__, ['node', 'status', 'allocatedcpu', 'maxcpu', 'mem', 'allocatedmem', 'maxmem']) for n in proxmox.nodes ]
Expand Down Expand Up @@ -126,7 +167,7 @@ def action_nodeevacuate(proxmox, args):
logging.debug("VM %i is not running, skipping"%(vm.vmid))
continue
# check ressources
for target in targets:
for target in targets:
logging.debug("Test target: %s, allocatedmem: %i, allocatedcpu: %i"%(target.node, target.allocatedmem, target.allocatedcpu))
if (vm.maxmem + target.allocatedmem) > (target.maxmem - validconfig.node.memoryminimum):
logging.debug("Discard target: %s, will overcommit ram"%(target.node))
Expand All @@ -140,7 +181,7 @@ def action_nodeevacuate(proxmox, args):
break
else:
print("No target found for VM %s"%vm.vmid)


logging.debug(plan)
# validate input
Expand Down Expand Up @@ -304,7 +345,11 @@ def _parser():
# clusterstatus parser
parser_clusterstatus = subparsers.add_parser('clusterstatus', help='Show cluster status')
parser_clusterstatus.set_defaults(func=action_clusterstatus)


# summary parser
parser_clusterstatus = subparsers.add_parser('summary', help='Show cluster summary')
parser_clusterstatus.set_defaults(func=action_summary)

# nodelist parser
parser_nodelist = subparsers.add_parser('nodelist', help='List nodes in the cluster')
parser_nodelist.set_defaults(func=action_nodelist)
Expand Down Expand Up @@ -360,7 +405,7 @@ def main():

# configure logging
logging.basicConfig(encoding='utf-8', level=logging.DEBUG if args.debug else logging.INFO)
logging.debug("Arguments: %s"%args)
logging.debug("Arguments: %s"%args)
logging.info("Proxmox cluster: %s" % args.cluster)

# Load configuration file
Expand Down
49 changes: 49 additions & 0 deletions src/pvecontrol/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,52 @@ def find_task(self, upid):
if task.upid == upid:
return task
return False

def is_healthy(self):
return bool([item for item in self.status if item.get('type') == 'cluster'][0]['quorate'])

def get_resources_nodes(self):
return [resource for resource in self.resources if resource["type"] == "node"]

def cpu_metrics(self):
nodes = self.get_resources_nodes()
total_cpu = sum([node['maxcpu'] for node in nodes])
total_cpu_usage = sum([node['cpu'] for node in nodes])
cpu_percent = total_cpu_usage / total_cpu

return {
"total": total_cpu,
"usage": total_cpu_usage,
"percent": cpu_percent,
}

def memory_metrics(self):
nodes = self.get_resources_nodes()
total_memory = sum([node['maxmem'] for node in nodes])
total_memory_usage = sum([node['mem'] for node in nodes])
memory_percent = total_memory_usage / total_memory

return {
"total": total_memory,
"usage": total_memory_usage,
"percent": memory_percent,
}

def disk_metrics(self):
nodes = self.get_resources_nodes()
total_disk = sum([node['maxdisk'] for node in nodes])
total_disk_usage = sum([node['disk'] for node in nodes])
disk_percent = total_disk_usage / total_disk

return {
"total": total_disk,
"usage": total_disk_usage,
"percent": disk_percent,
}

def metrics(self):
return {
"cpu": self.cpu_metrics(),
"memory": self.memory_metrics(),
"disk": self.disk_metrics()
}
5 changes: 4 additions & 1 deletion src/pvecontrol/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class NodeStatus(Enum):
class PVENode:
"""A proxmox VE Node"""
_api = None

def __init__(self, api, node, status, input = {}):
self.node = node
self.status = NodeStatus[status]
Expand Down Expand Up @@ -83,3 +83,6 @@ def _init_allocatedcpu(self):
# if vm.vmid == item:
# return True
# return False

def templates(self):
return [vm for vm in self.vms if vm.template]
10 changes: 7 additions & 3 deletions src/pvecontrol/vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ def __init__(self, api, node, vmid, status, input = {}):
self.maxmem = 0
self.uptime = 0
self.tags = ""
self.template = 0

for k in input:
if k == "name":
self.name = input["name"]
Expand All @@ -37,12 +39,14 @@ def __init__(self, api, node, vmid, status, input = {}):
self.uptime = input["uptime"]
elif k == "tags":
self.tags = input["tags"]

elif k == "template":
self.template = input["template"]

self.config = self._api.nodes(self.node).qemu(vmid).config.get()

def __str__(self):
return("vmid: {}, status: {}, name: {}, lock: {}, cpus: {}, maxdisk: {}, maxmem: {}, uptime: {}, tags: {}"
.format(self.vmid, self.status, self.name, self.lock, self.cpus, self.maxdisk, self.maxmem, self.uptime, self.tags))
return("vmid: {}, status: {}, name: {}, lock: {}, cpus: {}, maxdisk: {}, maxmem: {}, uptime: {}, tags: {}, template: {}"
.format(self.vmid, self.status, self.name, self.lock, self.cpus, self.maxdisk, self.maxmem, self.uptime, self.tags, self.template))

def migrate(self, target, online = False):
options = {}
Expand Down

0 comments on commit 8a11685

Please sign in to comment.