Skip to content
Snippets Groups Projects
Commit b9cf7271 authored by Seblu's avatar Seblu
Browse files

Live free or die hard

parent 0d82cea3
No related branches found
No related tags found
No related merge requests found
==================
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
===========
......@@ -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
......@@ -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:
......@@ -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"
......@@ -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:
......@@ -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"] == "":
......@@ -103,15 +102,17 @@ try:
settings["login"] = raw_input("Login: ")
# asking for password
settings["pass"] = getpass.getpass("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))
......@@ -7,8 +7,3 @@ CloudControl CLI
version = "1~dev"
debug = False
import printer
import cli
import clierror
import command
......@@ -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'''
......@@ -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!")
......@@ -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
......@@ -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"])
......@@ -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)
# 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:
argv = self._lex_argv(cmd)
command.Command(argv, self._rpc).call()
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"))
......@@ -11,3 +11,6 @@ class cliError(Exception):
class BadCommand(cliError):
pass
class BadArgument(cliError):
pass
import os, os.path
import sys
import re
from sjrpc.client import SimpleRpcClient
import cccli
import pprint
from cccli import printer
from cccli.clierror import *
class Command(object):
def __init__(self, argv, rpc):
def __init__(self, argv, cli):
if len(argv) < 1:
raise Exception("Empty command")
raise BadCommand()
self._argv = argv
self._rpc = rpc
self.cli = cli
@classmethod
def usage(cls, cmdname):
'''Return usage of a command'''
fname = "cmd_%s"%cmdname
if not hasattr(cls, fname):
raise BadArgument(cmdname)
if hasattr(getattr(cls, fname), "usage"):
return getattr(getattr(cls, fname), "usage")
return ""
def call(self):
'''Run command'''
......@@ -20,35 +34,116 @@ class Command(object):
return cmd(self._argv)
raise BadCommand(self._argv[0])
def usage(self, cmdname, printf=None):
'''Return usage of a command'''
fname = "cmd_%s"%cmdname
if hasattr(self, fname):
if hasattr(getattr(self, fname), "usage"):
s = getattr(getattr(self, fname), "usage")
if printf != None:
printf(s)
return s
else:
return "No usage"
else:
raise myError("No such command: %s"%cmdname)
def cmd_exit(self, argv):
'''Quit application with respect'''
raise SystemExit()
cmd_exit.usage = "exit"
cmd_exit.desc = "Quit application with respect"
def cmd_quit(self, argv):
'''Quit application with respect'''
raise SystemExit()
cmd_quit.usage = "quit"
cmd_quit.desc = "Quit application with respect"
def cmd_version(self, argv):
'''Print cli version'''
printer.out(cccli.version)
cmd_version.usage = "version"
cmd_version.desc = "Print cli version"
def cmd_usage(self, argv):
'''Print usage of a command'''
if len(argv) != 2:
raise BadArgument()
usage = Command.usage(argv[1])
if usage != "":
printer.out("usage: %s"%usage)
else:
printer.out("No usage.")
cmd_usage.usage = "usage [command]"
cmd_usage.desc = "Print usage of a command"
def cmd_help(self, argv):
'''Print help'''
if len(argv) == 1:
# build command list
cmdlist = list()
doclist = list()
for x in dir(self):
m = re.match("^cmd_([a-zA-Z0-9]+)$", x)
if m:
cmdlist.append(m.group(1))
if hasattr(getattr(self, x), "__doc__"):
doclist.append(getattr(getattr(self, x), "__doc__"))
# printing commands list
width = max(map(len, cmdlist)) + 3
printer.out("%sCommands:%s"%(printer.color["lwhite"], printer.color["reset"]))
for c, d in zip(cmdlist, doclist):
line = "%s"%c
line = line.ljust(width,)
line += "- %s"%d
printer.out(line)
elif len(argv) == 2:
fname = "cmd_%s"%argv[1]
if hasattr(self, fname):
if hasattr(getattr(self, fname), "__doc__"):
printer.out("Description: %s"%getattr(getattr(self, fname), "__doc__"))
if hasattr(getattr(self, fname), "usage"):
printer.out("Usage: %s"%getattr(getattr(self, fname), "usage"))
if hasattr(getattr(self, fname), "details"):
Printer.out("Details: %s"%getattr(getattr(self, fname), "details"))
else:
raise BadArgument(argv[1])
else:
raise BadArgument()
cmd_help.usage = "help [command]"
cmd_help.desc = "Print help about a command"
def cmd_alias(self, argv):
'''Show or create alias'''
if len(argv) == 1:
for n, v in self.cli.alias.items():
printer.out("%s=%s"%(n, v))
elif len(argv) == 2:
if argv[1] not in self.cli.alias:
raise BadArgument(argv[1])
printer.out("%s=%s"%(argv[1], self.cli.alias[argv[1]]))
elif len(argv) == 3:
self.cli.alias[argv[1]] = argv[2]
self.cli.alias.save()
else:
raise BadArgument()
cmd_alias.usage = "alias [name] [value]"
cmd_alias.desc = "Show or create aliases"
def cmd_unalias(self, argv):
'''Remove an alias'''
if len(argv) != 2:
raise BadArgument()
if argv[1] not in self.cli.alias:
raise BadArgument("%s: No such alias"%argv[1])
del self.cli.alias[argv[1]]
self.cli.alias.save()
cmd_alias.usage = "unalias [name]"
cmd_alias.desc = "Remove an aliases"
def cmd_rcmd(self, argv):
'''Show remote commands'''
for cmds in self.cli.rpc.list_commands():
printer.out("%s"%cmds["name"])
cmd_rcmd.usage = "rcmd"
cmd_rcmd.desc = "Print remote command list"
def cmd_list(self, argv):
'''List something'''
if len(argv) == 1:
argv.append("hv")
items = self._rpc.list(str.join("", argv[1:]))
argv.append("")
items = self.cli.rpc.list(str.join("", argv[1:]))
for item in items:
for key, val in item.items():
printer.out("%s: %s "%(key, val))
printer.out("*"*80)
pprint.pprint(item)
#for key, val in item.items():
# printer.out("%s: %s "%(key, val))
cmd_list.usage = "list [tags]"
cmd_list.desc = "Print information about tags"
def cmd_export(self, argv):
'''List server exported methods'''
for cmds in self._rpc.list_commands():
printer.out("%s"%cmds["name"])
......@@ -56,11 +56,11 @@ def fatal(message, exitcode=42, fd=sys.stderr, nl=os.linesep):
color["reset"])
, fd, nl)
if exitcode >= 0:
exit(exitcode)
os._exit(exitcode)
###############################################################################
def error(message, fd=sys.stderr, nl=os.linesep):
out("%sError%s: %s.%s"%(color["lred"],
out("%sError%s: %s%s"%(color["lred"],
color["red"],
message,
color["reset"])
......@@ -68,7 +68,7 @@ def error(message, fd=sys.stderr, nl=os.linesep):
###############################################################################
def warn(message, fd=sys.stderr, nl=os.linesep):
out("%sWarning%s: %s.%s"%(color["lyellow"],
out("%sWarning%s: %s%s"%(color["lyellow"],
color["yellow"],
message,
color["reset"])
......
......@@ -9,7 +9,7 @@ Standards-Version: 3.8.0
Package: cc-cli
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}, python (<< 3), python-sjrpc (>= 4)
Depends: ${misc:Depends}, ${python:Depends}, python (<< 3), python-sjrpc (>= 5)
XB-Python-Version: ${python:Versions}
Description: CloudControl CLI
This package provides the Command Line Interface to CloudControl.
from setuptools import setup
import cccli
import os
ldesc = open(os.path.join(os.path.dirname(__file__), 'README')).read()
setup(
name='cc-cli',
version='1',
version=cccli.version,
description='CloudControl CLI',
long_description=ldesc,
author='Sebastien Luttringer',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment