From c09af9a2bc0c6b14c6990346a9216d8ce1a3fef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Luttringer?= Date: Thu, 30 Jul 2015 18:19:56 +0200 Subject: [PATCH] Merge server related commands inside server module --- cloudcontrol/cli/commands/cancel.py | 43 ------- cloudcontrol/cli/commands/kill.py | 43 ------- cloudcontrol/cli/commands/purge.py | 43 ------- cloudcontrol/cli/commands/server.py | 172 +++++++++++++++++++++++++++- cloudcontrol/cli/commands/stats.py | 134 ---------------------- 5 files changed, 170 insertions(+), 265 deletions(-) delete mode 100644 cloudcontrol/cli/commands/cancel.py delete mode 100644 cloudcontrol/cli/commands/kill.py delete mode 100644 cloudcontrol/cli/commands/purge.py delete mode 100644 cloudcontrol/cli/commands/stats.py diff --git a/cloudcontrol/cli/commands/cancel.py b/cloudcontrol/cli/commands/cancel.py deleted file mode 100644 index c271ca3..0000000 --- a/cloudcontrol/cli/commands/cancel.py +++ /dev/null @@ -1,43 +0,0 @@ -#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 cancel command -''' - -from cloudcontrol.cli.exception import * -from sjrpc.core.exceptions import * -from cloudcontrol.cli.printer import Printer, color -from cloudcontrol.cli.command import TqlCommand - -class Command_cancel(TqlCommand): - '''Cancel a job''' - - def __init__(self, cli, argv0): - TqlCommand.__init__(self, cli, argv0) - self.tql_filter += "&r=job&state=running" - - def __call__(self, argv): - # arg parse - self.parse_args(argv) - if len(self.args) != 1: - raise cmdBadArgument() - # rpc call - self.rpccall("cancel", self.args[0]) - - def remote_functions(self): - return set(("cancel",)) diff --git a/cloudcontrol/cli/commands/kill.py b/cloudcontrol/cli/commands/kill.py deleted file mode 100644 index 307d0df..0000000 --- a/cloudcontrol/cli/commands/kill.py +++ /dev/null @@ -1,43 +0,0 @@ -#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 Connection related commands -''' - -from cloudcontrol.cli.exception import * -from sjrpc.core.exceptions import * -from cloudcontrol.cli.printer import Printer, color -from cloudcontrol.cli.command import TqlCommand - -class Command_kill(TqlCommand): - '''Kill a server connection''' - - def __init__(self, cli, argv0): - TqlCommand.__init__(self, cli, argv0) - self.tql_filter += "&con" - - def __call__(self, argv): - # args parse - self.parse_args(argv) - if len(self.args) != 1: - raise cmdBadArgument() - # rpccall - self.rpccall("kill", self.args[0]) - - def remote_functions(self): - return set(("kill",)) diff --git a/cloudcontrol/cli/commands/purge.py b/cloudcontrol/cli/commands/purge.py deleted file mode 100644 index d37fc8b..0000000 --- a/cloudcontrol/cli/commands/purge.py +++ /dev/null @@ -1,43 +0,0 @@ -#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 cancel command -''' - -from cloudcontrol.cli.exception import * -from sjrpc.core.exceptions import * -from cloudcontrol.cli.printer import Printer, color -from cloudcontrol.cli.command import TqlCommand - -class Command_purge(TqlCommand): - '''Purge a job (delete it)''' - - def __init__(self, cli, argv0): - TqlCommand.__init__(self, cli, argv0) - self.tql_filter += "&r=job&state=done" - - def __call__(self, argv): - # arg parse - self.parse_args(argv) - if len(self.args) != 1: - raise cmdBadArgument() - # rpc call - self.rpccall("purge", self.args[0]) - - def remote_functions(self): - return set(("purge",)) diff --git a/cloudcontrol/cli/commands/server.py b/cloudcontrol/cli/commands/server.py index 866d844..5104a1c 100644 --- a/cloudcontrol/cli/commands/server.py +++ b/cloudcontrol/cli/commands/server.py @@ -16,12 +16,15 @@ # along with CloudControl. If not, see . ''' -CloudControl server command +CloudControl server commands ''' + from cloudcontrol.cli.exception import * from sjrpc.core.exceptions import * from cloudcontrol.cli.printer import Printer, color -from cloudcontrol.cli.command import RemoteCommand +from cloudcontrol.cli.command import RemoteCommand, TqlCommand + +import collections class Command_server(RemoteCommand): '''Server manipulation command''' @@ -72,3 +75,168 @@ class Command_server(RemoteCommand): self.printer.out(self.cli.rpc.call("version")) except RpcError as e: raise cmdError("RPCError: %s"%str(e)) + + +class Command_kill(TqlCommand): + '''Kill a server connection''' + + def __init__(self, cli, argv0): + TqlCommand.__init__(self, cli, argv0) + self.tql_filter += "&con" + + def __call__(self, argv): + # args parse + self.parse_args(argv) + if len(self.args) != 1: + raise cmdBadArgument() + # rpccall + self.rpccall("kill", self.args[0]) + + def remote_functions(self): + return set(("kill",)) + + +class Command_cancel(TqlCommand): + '''Cancel a job''' + + def __init__(self, cli, argv0): + TqlCommand.__init__(self, cli, argv0) + self.tql_filter += "&r=job&state=running" + + def __call__(self, argv): + # arg parse + self.parse_args(argv) + if len(self.args) != 1: + raise cmdBadArgument() + # rpc call + self.rpccall("cancel", self.args[0]) + + def remote_functions(self): + return set(("cancel",)) + + +class Command_purge(TqlCommand): + '''Purge a job (delete it)''' + + def __init__(self, cli, argv0): + TqlCommand.__init__(self, cli, argv0) + self.tql_filter += "&r=job&state=done" + + def __call__(self, argv): + # arg parse + self.parse_args(argv) + if len(self.args) != 1: + raise cmdBadArgument() + # rpc call + self.rpccall("purge", self.args[0]) + + def remote_functions(self): + return set(("purge",)) + + +class Command_stats(RemoteCommand): + """Provide statistics""" + + 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 = collections.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) diff --git a/cloudcontrol/cli/commands/stats.py b/cloudcontrol/cli/commands/stats.py deleted file mode 100644 index dc620b9..0000000 --- a/cloudcontrol/cli/commands/stats.py +++ /dev/null @@ -1,134 +0,0 @@ -#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