Loading README +92 −0 Original line number Diff line number Diff line ================== Tag Query Language ================== == by examples == # list accounts > list a # list hypervisor > list hv # list vm > list vm # list vm of hypervisor toto > list hv=toto&vm # list vm chiche of hypervisor toto > list hv=toto&vm=chiche #list vm with 2 cpu > list vm&cpu=2 #list vm with 2 cpu and mem > 10g > list vm&cpu=2&mem>10g #list hypervistor with 2cpu and vm with 2cpu > list hv&cpu=2&vm&cpu=2 #list hypervistor at least 2cpu and show tags pop and alloc > list hv&cpu>=2$pop$alloc == Basics == - TQL build a list of objects from left to right - Every tag can add or remove objects - Separators create link between tag - Operators apply only on one tag == separators of tags == & and between tags $ show a tag == operators on tags == = strict equality != not strict equlity : globing matching !:not globing matching ~ regex matching !~ not regex matching > superior strict >= superior < inferior <= inferior strict == number facility == 10k = 1000 10ki = 1024 1m = 1000 ^ 2 1mi = 1024 ^ 2 1g = 1000 ^ 3 1gi = 1024 ^ 3 == well known tags == a: account name hv: hypervisor name vm: virtual machine name id: a.hv.vm h: hostname role: (hypersivor/host/cli/vm) hvtype: hypervistor type (xen/kvm) libvirtver: Libvirt version status: online/offline vmstatus: Running/Paused/Stoped pop: Point of Presence cpu: cpu count mem: memory size usedmem: memory used freemem: memory free arch: (x86/x64) uname: uname of host uptime: uptime of hostname load: load average hvm: hardware virtualisation enabled alloc: host is allowed to be selected to a migration nvm: vm count on an hypervisor version: account version sto: total available storage freesto: free storage usedsto: used storage =========== New release =========== Loading @@ -5,3 +95,5 @@ Update version in debian/control Update version in debian/changelog Update version in setup.py Update version in cccli/__init__.py bin/cc-cli +10 −9 Original line number Diff line number Diff line Loading @@ -17,17 +17,15 @@ import warnings import getpass settings = {} alias = {} try: # parse rc file if "HOME" in os.environ and os.access("%s/.cc-cli.conf"%os.environ["HOME"], os.R_OK): fparser = ConfigParser.SafeConfigParser() fparser.read("%s/.cc-cli.conf"%os.environ["HOME"]) settings["alias"] = "%s/.cc-cli.conf"%os.environ["HOME"] if fparser.has_section("cli"): settings = dict(fparser.items("cli")) if fparser.has_section("alias"): alias = dict(fparser.items("alias")) settings.update(fparser.items("cli")) # parse env if "CC_SERVER" in os.environ: Loading @@ -36,6 +34,8 @@ try: settings["port"] = os.environ["CC_PORT"] if "CC_LOGIN" in os.environ: settings["login"] = os.environ["CC_LOGIN"] if "CC_PASS" in os.environ: settings["pass"] = os.environ["CC_PASS"] if "CC_DEBUG" in os.environ: settings["debug"] = "True" Loading Loading @@ -78,8 +78,8 @@ try: sys.exit(1) # remove pass to prevent stupid guy if "pass" in settings: del settings["pass"] #if "pass" in settings: # del settings["pass"] # debug stuff if "debug" in settings: Loading @@ -88,7 +88,6 @@ try: warnings.filterwarnings("ignore") printer.debug("Debugging on") printer.debug("Settings: %s"%settings) printer.debug("Alias: %s"%alias) # checking needs if settings["server"] == "": Loading @@ -103,15 +102,17 @@ try: settings["login"] = raw_input("Login: ") # asking for password if settings["pass"] == "": settings["pass"] = getpass.getpass("Password: ") # start cli cli = cli.Cli(settings, alias, args) cli = cli.Cli(settings, args) cli.start() except KeyboardInterrupt: exit(1) except Exception, e: if cccli.debug: printer.fatal(str(e), exitcode=-1) printer.warn("This is a not expected error, please report it!") raise printer.fatal(str(e)) cccli/__init__.py +0 −5 Original line number Diff line number Diff line Loading @@ -7,8 +7,3 @@ CloudControl CLI version = "1~dev" debug = False import printer import cli import clierror import command cccli/cli.py +71 −18 Original line number Diff line number Diff line Loading @@ -10,24 +10,30 @@ import sys import socket import ssl import threading import subprocess import ConfigParser import cccli from cccli import printer, command from cccli.clierror import * from cccli.command import Command from sjrpc.client import SimpleRpcClient from sjrpc.utils import RpcHandler, pure, threadless, ConnectionProxy import sjrpc.core.exceptions import re import readline class Cli(object): def __init__(self, settings, alias, args): def __init__(self, settings, args): self._settings = settings self._alias = alias if "alias" in settings: self.alias = Alias(settings["alias"]) self.alias.load() self._interactive = sys.stderr.isatty() and sys.stdin.isatty() self._prompt = "> " self._commands = args self._rpc = None self.rpc = None def start(self): '''Start a CLI''' Loading @@ -48,15 +54,18 @@ class Cli(object): printer.debug("Connecting...") rpcc = SimpleRpcClient.from_addr(self._settings["server"], self._settings["port"], enable_ssl=True enable_ssl=True, on_disconnect=self._on_disconnect ) # FIXME: wait sjrpc v5 with on_disconnect usable rpcc.start(daemonize=True) self._rpc = ConnectionProxy(rpcc) self.rpc = ConnectionProxy(rpcc) def _on_disconnect(self, rpc): printer.fatal("Disconnected from server!") def _auth(self): printer.debug("Authenticating...") if self._rpc.authentify(self._settings["login"], self._settings["pass"]): if self.rpc.authentify(self._settings["login"], self._settings["pass"]): printer.debug("Authenticated.") else: printer.fatal("Autentification failed!") Loading @@ -69,8 +78,6 @@ class Cli(object): try: line = raw_input(self._prompt) self._parse_line(line) except BadCommand, e: printer.error("No such command: %s"%e[0]) except EOFError: printer.out("") break Loading @@ -78,12 +85,6 @@ class Cli(object): break except KeyboardInterrupt: printer.out("") except Exception, e: printer.error(e) if cccli.debug: raise else: printer.error("This is a not expected error, please report it!") try: pass #readline.write_history_file(self._settings["histfile"]) Loading @@ -107,10 +108,62 @@ class Cli(object): p.wait() ret = p.returncode elif (cmd[0] == "?"): command.Command("help").call() Command("help").call() else: self._parse_command(cmd) def _parse_command(self, cmd): try: # lex command argv = self._lex_argv(cmd) command.Command(argv, self._rpc).call() # alias subs if argv[0] in self.alias: argv[0] = self.alias[argv[0]] # execute command Command(argv, self).call() except BadArgument, e: if str(e) != "": printer.error("Bad argument: %s."%str(e)) else: printer.error("Bad argument.") usage = Command.usage(argv[0]) if usage != "": printer.out("usage: %s."%usage) except BadCommand: printer.error("No command: %s."%argv[0]) except sjrpc.core.exceptions.RpcError, e: if cccli.debug: raise printer.error("sjRPC: %s"%str(e)) except Exception, e: if cccli.debug: raise printer.error("%s: %s."%(argv[0], str(e))) def _lex_argv(self, string): '''Lex command argument''' return string.split(" ") class Alias(dict): ''' Alias wrapper''' def __init__(self, filename): self._filename = filename def load(self): '''load alias from file''' if os.access(self._filename, os.R_OK): fparser = ConfigParser.SafeConfigParser() fparser.read(self._filename) if fparser.has_section("alias"): self.clear() self.update(fparser.items("alias")) def save(self): '''save alias on file''' if os.access(self._filename, os.R_OK or os.W_OK): fparser = ConfigParser.SafeConfigParser() fparser.read(self._filename) fparser.remove_section("alias") fparser.add_section("alias") for n,v in self.items(): fparser.set("alias", n, v) fparser.write(open(self._filename, "w")) cccli/clierror.py +3 −0 Original line number Diff line number Diff line Loading @@ -11,3 +11,6 @@ class cliError(Exception): class BadCommand(cliError): pass class BadArgument(cliError): pass Loading
README +92 −0 Original line number Diff line number Diff line ================== Tag Query Language ================== == by examples == # list accounts > list a # list hypervisor > list hv # list vm > list vm # list vm of hypervisor toto > list hv=toto&vm # list vm chiche of hypervisor toto > list hv=toto&vm=chiche #list vm with 2 cpu > list vm&cpu=2 #list vm with 2 cpu and mem > 10g > list vm&cpu=2&mem>10g #list hypervistor with 2cpu and vm with 2cpu > list hv&cpu=2&vm&cpu=2 #list hypervistor at least 2cpu and show tags pop and alloc > list hv&cpu>=2$pop$alloc == Basics == - TQL build a list of objects from left to right - Every tag can add or remove objects - Separators create link between tag - Operators apply only on one tag == separators of tags == & and between tags $ show a tag == operators on tags == = strict equality != not strict equlity : globing matching !:not globing matching ~ regex matching !~ not regex matching > superior strict >= superior < inferior <= inferior strict == number facility == 10k = 1000 10ki = 1024 1m = 1000 ^ 2 1mi = 1024 ^ 2 1g = 1000 ^ 3 1gi = 1024 ^ 3 == well known tags == a: account name hv: hypervisor name vm: virtual machine name id: a.hv.vm h: hostname role: (hypersivor/host/cli/vm) hvtype: hypervistor type (xen/kvm) libvirtver: Libvirt version status: online/offline vmstatus: Running/Paused/Stoped pop: Point of Presence cpu: cpu count mem: memory size usedmem: memory used freemem: memory free arch: (x86/x64) uname: uname of host uptime: uptime of hostname load: load average hvm: hardware virtualisation enabled alloc: host is allowed to be selected to a migration nvm: vm count on an hypervisor version: account version sto: total available storage freesto: free storage usedsto: used storage =========== New release =========== Loading @@ -5,3 +95,5 @@ Update version in debian/control Update version in debian/changelog Update version in setup.py Update version in cccli/__init__.py
bin/cc-cli +10 −9 Original line number Diff line number Diff line Loading @@ -17,17 +17,15 @@ import warnings import getpass settings = {} alias = {} try: # parse rc file if "HOME" in os.environ and os.access("%s/.cc-cli.conf"%os.environ["HOME"], os.R_OK): fparser = ConfigParser.SafeConfigParser() fparser.read("%s/.cc-cli.conf"%os.environ["HOME"]) settings["alias"] = "%s/.cc-cli.conf"%os.environ["HOME"] if fparser.has_section("cli"): settings = dict(fparser.items("cli")) if fparser.has_section("alias"): alias = dict(fparser.items("alias")) settings.update(fparser.items("cli")) # parse env if "CC_SERVER" in os.environ: Loading @@ -36,6 +34,8 @@ try: settings["port"] = os.environ["CC_PORT"] if "CC_LOGIN" in os.environ: settings["login"] = os.environ["CC_LOGIN"] if "CC_PASS" in os.environ: settings["pass"] = os.environ["CC_PASS"] if "CC_DEBUG" in os.environ: settings["debug"] = "True" Loading Loading @@ -78,8 +78,8 @@ try: sys.exit(1) # remove pass to prevent stupid guy if "pass" in settings: del settings["pass"] #if "pass" in settings: # del settings["pass"] # debug stuff if "debug" in settings: Loading @@ -88,7 +88,6 @@ try: warnings.filterwarnings("ignore") printer.debug("Debugging on") printer.debug("Settings: %s"%settings) printer.debug("Alias: %s"%alias) # checking needs if settings["server"] == "": Loading @@ -103,15 +102,17 @@ try: settings["login"] = raw_input("Login: ") # asking for password if settings["pass"] == "": settings["pass"] = getpass.getpass("Password: ") # start cli cli = cli.Cli(settings, alias, args) cli = cli.Cli(settings, args) cli.start() except KeyboardInterrupt: exit(1) except Exception, e: if cccli.debug: printer.fatal(str(e), exitcode=-1) printer.warn("This is a not expected error, please report it!") raise printer.fatal(str(e))
cccli/__init__.py +0 −5 Original line number Diff line number Diff line Loading @@ -7,8 +7,3 @@ CloudControl CLI version = "1~dev" debug = False import printer import cli import clierror import command
cccli/cli.py +71 −18 Original line number Diff line number Diff line Loading @@ -10,24 +10,30 @@ import sys import socket import ssl import threading import subprocess import ConfigParser import cccli from cccli import printer, command from cccli.clierror import * from cccli.command import Command from sjrpc.client import SimpleRpcClient from sjrpc.utils import RpcHandler, pure, threadless, ConnectionProxy import sjrpc.core.exceptions import re import readline class Cli(object): def __init__(self, settings, alias, args): def __init__(self, settings, args): self._settings = settings self._alias = alias if "alias" in settings: self.alias = Alias(settings["alias"]) self.alias.load() self._interactive = sys.stderr.isatty() and sys.stdin.isatty() self._prompt = "> " self._commands = args self._rpc = None self.rpc = None def start(self): '''Start a CLI''' Loading @@ -48,15 +54,18 @@ class Cli(object): printer.debug("Connecting...") rpcc = SimpleRpcClient.from_addr(self._settings["server"], self._settings["port"], enable_ssl=True enable_ssl=True, on_disconnect=self._on_disconnect ) # FIXME: wait sjrpc v5 with on_disconnect usable rpcc.start(daemonize=True) self._rpc = ConnectionProxy(rpcc) self.rpc = ConnectionProxy(rpcc) def _on_disconnect(self, rpc): printer.fatal("Disconnected from server!") def _auth(self): printer.debug("Authenticating...") if self._rpc.authentify(self._settings["login"], self._settings["pass"]): if self.rpc.authentify(self._settings["login"], self._settings["pass"]): printer.debug("Authenticated.") else: printer.fatal("Autentification failed!") Loading @@ -69,8 +78,6 @@ class Cli(object): try: line = raw_input(self._prompt) self._parse_line(line) except BadCommand, e: printer.error("No such command: %s"%e[0]) except EOFError: printer.out("") break Loading @@ -78,12 +85,6 @@ class Cli(object): break except KeyboardInterrupt: printer.out("") except Exception, e: printer.error(e) if cccli.debug: raise else: printer.error("This is a not expected error, please report it!") try: pass #readline.write_history_file(self._settings["histfile"]) Loading @@ -107,10 +108,62 @@ class Cli(object): p.wait() ret = p.returncode elif (cmd[0] == "?"): command.Command("help").call() Command("help").call() else: self._parse_command(cmd) def _parse_command(self, cmd): try: # lex command argv = self._lex_argv(cmd) command.Command(argv, self._rpc).call() # alias subs if argv[0] in self.alias: argv[0] = self.alias[argv[0]] # execute command Command(argv, self).call() except BadArgument, e: if str(e) != "": printer.error("Bad argument: %s."%str(e)) else: printer.error("Bad argument.") usage = Command.usage(argv[0]) if usage != "": printer.out("usage: %s."%usage) except BadCommand: printer.error("No command: %s."%argv[0]) except sjrpc.core.exceptions.RpcError, e: if cccli.debug: raise printer.error("sjRPC: %s"%str(e)) except Exception, e: if cccli.debug: raise printer.error("%s: %s."%(argv[0], str(e))) def _lex_argv(self, string): '''Lex command argument''' return string.split(" ") class Alias(dict): ''' Alias wrapper''' def __init__(self, filename): self._filename = filename def load(self): '''load alias from file''' if os.access(self._filename, os.R_OK): fparser = ConfigParser.SafeConfigParser() fparser.read(self._filename) if fparser.has_section("alias"): self.clear() self.update(fparser.items("alias")) def save(self): '''save alias on file''' if os.access(self._filename, os.R_OK or os.W_OK): fparser = ConfigParser.SafeConfigParser() fparser.read(self._filename) fparser.remove_section("alias") fparser.add_section("alias") for n,v in self.items(): fparser.set("alias", n, v) fparser.write(open(self._filename, "w"))
cccli/clierror.py +3 −0 Original line number Diff line number Diff line Loading @@ -11,3 +11,6 @@ class cliError(Exception): class BadCommand(cliError): pass class BadArgument(cliError): pass