Commit c09af9a2 authored by Sébastien Luttringer's avatar Sébastien Luttringer
Browse files

Merge server related commands inside server module

parent 56c1914a
Loading
Loading
Loading
Loading
+0 −43
Original line number Diff line number Diff line
#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 <http://www.gnu.org/licenses/>.

'''
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",))

cloudcontrol/cli/commands/kill.py

deleted100644 → 0
+0 −43
Original line number Diff line number Diff line
#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 <http://www.gnu.org/licenses/>.

'''
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",))
+0 −43
Original line number Diff line number Diff line
#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 <http://www.gnu.org/licenses/>.

'''
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",))
+170 −2
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@
# along with CloudControl.  If not, see <http://www.gnu.org/licenses/>.

'''
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)
+0 −134
Original line number Diff line number Diff line
#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 <http://www.gnu.org/licenses/>.

"""
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)