From 949e4f0e2e1121f2bc7d23823b46252afc86792c Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Wed, 22 Jul 2015 11:50:55 +0200 Subject: [PATCH] Added stats command (usage statistics) --- cloudcontrol/cli/commands/stats.py | 134 +++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 cloudcontrol/cli/commands/stats.py diff --git a/cloudcontrol/cli/commands/stats.py b/cloudcontrol/cli/commands/stats.py new file mode 100644 index 0000000..dc620b9 --- /dev/null +++ b/cloudcontrol/cli/commands/stats.py @@ -0,0 +1,134 @@ +#coding=utf8 + +# This file is part of CloudControl. +# +# CloudControl is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# CloudControl is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with CloudControl. If not, see . + +""" +CloudControl server command +""" + +from collections import defaultdict + +from cloudcontrol.cli.exception import cmdBadArgument +from cloudcontrol.cli.printer import color +from cloudcontrol.cli.command import RemoteCommand + + +class Command_stats(RemoteCommand): + """VM allocation command""" + + def __init__(self, cli, argv0): + RemoteCommand.__init__(self, cli, argv0) + self.set_usage("%prog [options] (hv [tql] | hvpop pop1 [pop2] [...])") + + def __call__(self, argv): + self.parse_args(argv) + if len(self.args) == 0: + raise cmdBadArgument() + + if hasattr(self, "stats_" + self.args[0]): + func = getattr(self, "stats_" + self.args[0]) + func(*self.args[1:]) + else: + raise cmdBadArgument() + + def remote_functions(self): + return set(("list",)) + + def stats_hvpop(self, *args): + if not args: + args = ["all"] + + for pop in args: + self.printer.out(color["light"] + pop + ": " + color["reset"]) + self.printer.out(color["light"] + "=" * (len(pop) + 1) + color["reset"]) + if pop == "all": + self.stats_hv() + else: + self.stats_hv("pop=%s" % pop) + + def stats_hv(self, tql="id", *args): + tql = "(%s)&r=hv&con$alloc$cpu$cpualloc$mem$memalloc$sto*$nvm$vmstarted$vmstopped$hmodel" % tql + response = self.rpc.call("list", tql) + + count_hv = 0 + count_hv_allocatable = 0 + count_vm = 0 + count_vm_started = 0 + count_vm_stopped = 0 + count_cpu_allocated = 0 + count_cpu_total = 0 + count_memory_allocated = 0 + count_memory_total = 0 + count_disk_allocated = 0 + count_disk_total = 0 + count_by_model = defaultdict(lambda: 0) + + # Sum each metric iterating over matching HVs: + for hv in response["objects"]: + try: + count_hv += 1 + count_hv_allocatable += 1 if hv.get("alloc") == "yes" else 0 + count_vm += int(hv.get("nvm", 0)) + count_vm_started += int(hv.get("vmstarted", 0)) + count_vm_stopped += int(hv.get("vmstopped", 0)) + count_cpu_allocated += int(hv.get("cpualloc", 0)) + count_cpu_total += int(hv.get("cpu", 0)) + count_memory_allocated += int(hv.get("memalloc", 0)) + count_memory_total += int(hv.get("mem", 0)) + count_disk_allocated += sum(int(hv.get("sto%s_used" % x, 0)) for x in hv.get("sto", "").split()) + count_disk_total += sum(int(hv.get("sto%s_size" % x, 0)) for x in hv.get("sto", "").split()) + count_by_model[hv.get("hmodel", "Unknown")] += 1 + except ValueError: + pass # Ignore errors casting tags as int (most likely a tag timeout error "#ERR") + + # Compute ratios: + try: + ratio_cpu = float(count_cpu_allocated) / count_cpu_total * 100 + except ZeroDivisionError: + ratio_cpu = 0 + try: + ratio_memory = float(count_memory_allocated) / count_memory_total * 100 + except ZeroDivisionError: + ratio_memory = 0 + try: + ratio_disk = float(count_disk_allocated) / count_disk_total * 100 + except ZeroDivisionError: + ratio_disk = 0 + + # Print stats: + self._print_stats("Number of hypervisors", "%s (%s are allocatable)", + count_hv, count_hv_allocatable) + self._print_stats("Number of VM", "%s (%s are started, %s are stopped)", + count_vm, count_vm_started, count_vm_stopped) + self._print_stats("CPU (threads)", "%s allocated, %s total (%0.1f%% allocated)", + count_cpu_allocated, count_cpu_total, ratio_cpu) + self._print_stats("Memory", "%sB allocated, %sB total (%0.1f%% allocated)", + self.cli.tagdisplay.type_bit(unicode(count_memory_allocated)), + self.cli.tagdisplay.type_bit(unicode(count_memory_total)), + ratio_memory) + self._print_stats("Storage", "%sB allocated, %sB total (%0.1f%% allocated)", + self.cli.tagdisplay.type_bit(unicode(count_disk_allocated)), + self.cli.tagdisplay.type_bit(unicode(count_disk_total)), + ratio_disk) + self._print_stats("Hardware", ["%s: %s" % (k, v) for k, v in count_by_model.iteritems()]) + self.printer.out("") # Empty line + + def _print_stats(self, key, value, *args): + if isinstance(value, list): + padding = len(key) + 2 + value = ("\n" + " " * padding).join(value) + + self.printer.out(color["light"] + key + ":" + color["reset"] + " " + value % args) -- GitLab