-
Seblu authored
tvincent> passwd tvincent_station Error: <type 'exceptions.AttributeError'>: 'Cli' object has no attribute 'interactive' Warning: This is a not expected error, please report it!
Seblu authoredtvincent> passwd tvincent_station Error: <type 'exceptions.AttributeError'>: 'Cli' object has no attribute 'interactive' Warning: This is a not expected error, please report it!
command.py 21.16 KiB
#!/usr/bin/env python
#coding=utf8
'''
CloudControl CLI command module
'''
import os, os.path
import sys
import re
import pprint
import ConfigParser
import code
from optparse import OptionParser
import cccli
from cccli.exception import *
from cccli.printer import color
from sjrpc.client import SimpleRpcClient
from sjrpc.utils import ConnectionProxy
from sjrpc.core.exceptions import *
class Command(object):
def __init__(self, argv, cli):
# check argv
if len(argv) == 0:
raise cmdBadName()
# check valid command chars
if not re.match("^[a-zA-Z0-9]+", argv[0]):
raise cmdBadName()
cmdlist = [ x[4:] for x in dir(self) if x.startswith("cmd_") ]
matchlist = [ x for x in cmdlist if re.match("%s.+"%argv[0], x) ]
if argv[0] in cmdlist:
pass
elif len(matchlist) == 1:
argv[0] = matchlist[0]
else:
raise cmdBadName()
self._cmd = getattr(self, "cmd_%s"%argv[0])
self._argv = argv
self.cli = cli
self.printer = cli.printer
@classmethod
def list(cls):
'''Return a list of command name'''
return [ x[4:] for x in dir(cls) if x.startswith("cmd_") ]
@classmethod
def usage(cls, cmdname):
'''Return usage of a command'''
fname = "cmd_%s"%cmdname
if not hasattr(cls, fname):
raise cmdBadName(cmdname)
if hasattr(getattr(cls, fname), "usage"):
return getattr(getattr(cls, fname), "usage")
return ""
def call(self):
'''Run command'''
if re.match("^[a-zA-Z0-9]+$", self._argv[0]):
name = "cmd_%s"%self._argv[0]
if hasattr(self, name):
cmd = getattr(self, name)
return cmd(self._argv)
raise cmdBadName(self._argv[0])
def cmd_exit(self, argv):
'''Quit application with respect'''
raise SystemExit()
cmd_exit.usage = "exit"
def cmd_quit(self, argv):
'''Quit application with respect'''
raise SystemExit()
cmd_quit.usage = "quit"
def cmd_version(self, argv):
'''Print cli version'''
self.printer.out(cccli.version)
cmd_version.usage = "version"
def cmd_usage(self, argv):
'''Print usage of a command'''
if len(argv) != 2:
raise cmdBadArgument()
usage = Command.usage(argv[1])
if usage != "":
self.printer.out("usage: %s"%usage)
else:
self.printer.out("No usage.")
cmd_usage.usage = "usage <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
self.printer.out("%sCommands:%s"%(color["lwhite"], color["reset"]))
for c, d in zip(cmdlist, doclist):
line = "%s"%c
line = line.ljust(width,)
line += "- %s"%d
self.printer.out(line)
elif len(argv) == 2:
fname = "cmd_%s"%argv[1]
if hasattr(self, fname):
if hasattr(getattr(self, fname), "__doc__"):
self.printer.out("Description: %s"%getattr(getattr(self, fname), "__doc__"))
if hasattr(getattr(self, fname), "usage"):
self.printer.out("Usage: %s"%getattr(getattr(self, fname), "usage"))
if hasattr(getattr(self, fname), "details"):
Self.Printer.out("Details: %s"%getattr(getattr(self, fname), "details"))
else:
raise cmdBadArgument(argv[1])
else:
raise cmdBadArgument()
cmd_help.usage = "help [command]"
def cmd_alias(self, argv):
'''Show or create alias'''
if len(argv) == 1:
for n, v in self.cli.alias.items():
self.printer.out("%s=%s"%(n, v))
elif len(argv) == 2:
if argv[1] not in self.cli.alias:
raise cmdBadArgument(argv[1])
self.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(self.cli.settings.get("alias", ""))
else:
raise cmdBadArgument()
cmd_alias.usage = "alias [name] [value]"
def cmd_unalias(self, argv):
'''Remove an alias'''
if len(argv) != 2:
raise cmdBadArgument()
if argv[1] not in self.cli.alias:
raise cmdBadArgument("%s: No such alias"%argv[1])
del self.cli.alias[argv[1]]
self.cli.alias.save(self.cli.settings.get("alias", ""))
cmd_unalias.usage = "unalias [name]"
def cmd_remote(self, argv):
'''Show remote command list'''
try:
for cmds in self.cli.rpc.call("list_commands"):
self.printer.out("%s"%cmds["name"])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_remote.usage = "remote"
def cmd_history(self, argv):
'''Show commands history'''
if not self.printer.history:
raise cmdError("not available")
for l in self.printer.history:
self.printer.out(l)
cmd_history.usage = "history"
def cmd_list(self, argv):
'''List objects'''
try:
oparser = OptionParser(prog="list")
oparser.add_option("-c", action="store_true", dest="table",
help="column aligment display")
oparser.add_option("-l", action="store_true", dest="align",
help="line aligment display")
(options, args) = oparser.parse_args(argv[1:])
except SystemExit:
return
if len(args) == 0:
args.append("a")
try:
objs = self.cli.rpc.call("list", str.join("", args))
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
if len(objs) == 0:
return
if options.align:
self._list_align(objs)
elif options.table:
self._list_table(objs)
else:
self._list(objs)
cmd_list.usage = "list [-t] [-a] [--help] <tql>"
def _list(self, objs):
for o in objs:
id = o.pop("id")
tags = " ".join([ "%s%s:%s%s"%(color["green"], t, color["reset"], v) for (t,v) in o.items() ])
self.printer.out("%sid:%s%s%s %s"%(color["green"], color["yellow"], id, color["reset"], tags))
def _list_align(self, objs):
# get all tag list
tags = dict()
for o in objs:
for t,v in o.items():
tags[t] = max(len(str(v)), tags.get(t, len(str(t))))
for o in objs:
id = str(o.pop("id"))
line = "%sid:%s%s%s"%(color["green"], color["yellow"], id.ljust(tags["id"] + 2), color["reset"])
taglist = o.keys()
taglist.sort()
for tagname in taglist:
line += "%s%s:%s%s"%(color["green"], tagname, color["reset"],
str(o[tagname]).ljust(tags[tagname] + 1))
self.printer.out(line)
def _list_table(self, objs):
# get all tag list
tags = dict()
for o in objs:
for t,v in o.items():
tags[t] = max(len(str(v)), tags.get(t, len(str(t))))
# extract id info
idsize = tags.pop("id")
# print titles
self.printer.out(color["green"], nl="")
self.printer.out("id".ljust(idsize+1), nl=" ")
for t,v in tags.items():
self.printer.out(t.ljust(v), nl=" ")
self.printer.out(color["reset"])
# print obj
for obj in objs:
self.printer.out("%s%s%s"%(color["yellow"], obj.pop("id").ljust(idsize+1), color["reset"]) ,nl=" ")
for (t, v) in tags.items():
self.printer.out(str(obj.get(t, "")).ljust(v) ,nl=" ")
self.printer.out()
def _vm_action(self, argv, filters=None):
'''All command about vm are the same'''
try:
oparser = OptionParser(prog=argv[0])
oparser.add_option("--raw", action="store_true", dest="raw",
help="Don't append filter on request")
oparser.add_option("--direct", action="store_true", dest="direct",
help="Directly send tql to server (don't list before)")
oparser.add_option("--force", action="store_true", dest="force",
help="Don't ask confirmation (Dangerous)")
(options, args) = oparser.parse_args(argv[1:])
except SystemExit:
return
if len(args) == 0:
raise cmdBadArgument()
tql = str.join("", args)
# append securty options by command name
if filters is not None and not options.raw:
tql += filters
if options.direct:
try:
objs = self.cli.rpc.call(argv[0], tql)
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
else:
# get objects id
try:
objs = self.cli.rpc.call("list", tql)
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
# no result, goodbye
if len(objs) == 0:
raise cmdWarning("tql: '%s': No result."%tql)
self.printer.out("You will %s:"%argv[0])
for obj in objs:
self.printer.out("%sid:%s%s%s"%(color["green"],color["yellow"],obj["id"],color["reset"]))
self.printer.out("%sCount: %s%s"%(color["green"],color["reset"], len(objs)))
# be sure boby want do that
if not options.force:
self.printer.out("%sProceed?%s"%(color["lred"], color["reset"]))
if self.printer.ask("Answer (yes/NO): ") != "yes":
raise cmdWarning("Aborted")
if len(objs) > 5:
self.printer.out("%sYou request is on more than 5 objets!%s"%(color["yellow"], color["reset"]))
self.printer.out("%sAre you really sure?%s"%(color["lred"], color["reset"]))
if self.printer.ask("Answer (Sir, yes Sir!): ") != "Sir, yes Sir!":
raise cmdWarning("Bad Answer. Aborted")
# execute action for each object
for obj in objs:
self.printer.out("%s%s%s %s%s%s"%(color["lblue"],
argv[0],
color["reset"],
color["yellow"],
obj["id"],
color["reset"]))
try:
self.cli.rpc.call(argv[0], "id:%s"%obj["id"])
except RpcError as e:
self.printer.error("RPCError: %s"%str(e))
def cmd_start(self, argv):
'''Start vm'''
self._vm_action(argv, "&role=vm&status=stopped")
cmd_start.usage = "start [--raw] [--direct] [--force] [--help] <tql>"
def cmd_stop(self, argv):
'''Stop vm'''
self._vm_action(argv, "&role=vm&status=running")
cmd_stop.usage = "stop [--raw] [--direct] [--force] [--help] <tql>"
def cmd_pause(self, argv):
'''Pause vm'''
self._vm_action(argv, "&role=vm&status=running")
cmd_pause.usage = "pause [--raw] [--direct] [--force] [--help] <tql>"
def cmd_resume(self, argv):
'''Resume vm'''
self._vm_action(argv, "&role=vm&status=stalled")
cmd_resume.usage = "resume [--raw] [--direct] [--force] [--help] <tql>"
def cmd_destroy(self, argv):
'''Force vm to stop'''
self._vm_action(argv, "&role=vm&status!=stopped")
cmd_destroy.usage = "destroy [--raw] [--direct] [--force] [--help] <tql>"
def cmd_clear(self, argv):
'''Clear tty'''
self.printer.out("\033[H\033[2J", nl="")
cmd_clear.usage = "clear"
def cmd_uptime(self, argv):
'''Show connection uptime'''
if len(argv) == 1:
argv.append("a=%s"%self.cli.settings["login"])
tql = "".join(argv[1:]) + "$con"
try:
objs = self.cli.rpc.call("list", tql)
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
for o in objs:
if "a" in o and "con" in o:
self.printer.out("%s: %ss"%(o["a"], o["con"]))
cmd_uptime.usage = "uptime [tql]"
def cmd_tags(self, argv):
'''List static tags on an account (current by default)'''
# Parse argline
try:
oparser = OptionParser(prog=argv[0])
oparser.add_option("--raw", action="store_true", dest="raw",
help="Don't append filter on request")
(options, args) = oparser.parse_args(argv[1:])
except SystemExit:
return
# append current login if nothing asked
if len(args) == 0:
tql = "a=%s"%self.cli.settings["login"]
else:
tql = "".join(args)
# update tql if mode
if not options.raw:
tql += "&a"
# ask server
try:
objs = self.cli.rpc.call("tags", tql)
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
# display answer
for o in objs:
id = o.pop("id")
tags = " ".join([ "%s%s:%s%s"%(color["green"], t, color["reset"], v) for (t,v) in o.items() ])
self.printer.out("%sid:%s%s%s %s"%(color["green"], color["yellow"], id, color["reset"], tags))
cmd_tags.usage = "tags [--raw] [--help] [tql]"
def cmd_addtag(self, argv):
'''Add/Modify a static tag on an account'''
if len(argv) != 4:
raise cmdBadArgument()
try:
self.cli.rpc.call("addtag", argv[1], argv[2], argv[3])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_addtag.usage = "addtag <tql> <tag> <value>"
def cmd_deltag(self, argv):
'''Delete a static tag from an account'''
if len(argv) != 3:
raise cmdBadArgument()
try:
self.cli.rpc.call("deltag", argv[1], argv[2])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_deltag.usage = "deltag <tql> <tag>"
def cmd_rights(self, argv):
'''List account rights (current by default)'''
# Parse argline
try:
oparser = OptionParser(prog=argv[0])
oparser.add_option("--raw", action="store_true", dest="raw",
help="Don't append filter on request")
(options, args) = oparser.parse_args(argv[1:])
except SystemExit:
return
# append current login if nothing asked
if len(args) == 0:
tql = "a=%s"%self.cli.settings["login"]
else:
tql = "".join(args)
# update tql if mode
if not options.raw:
tql += "&a"
# ask server
try:
al = self.cli.rpc.call("rights", tql)
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
# display answer
for (a, rl) in al.items():
self.printer.out("%srights of %s%s"%(color["lblue"], a, color["reset"]))
for i,r in enumerate(rl):
tags = " ".join([ "%s%s:%s%s"%(color["green"], t, color["reset"], v) for (t,v) in r.items() ])
self.printer.out("[%s] %s"%(i,tags))
cmd_rights.usage = "rights [--raw] [--help] [tql]"
def cmd_addright(self, argv):
'''Add/edit a right'''
if len(argv) != 5:
raise cmdBadArgument()
try:
self.cli.rpc.call("addright", argv[1], argv[2], argv[3], argv[4])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_addright.usage = "addright <tql> <right tql> <method> <target>"
def cmd_delright(self, argv):
'''Delete a right'''
if len(argv) != 3:
raise cmdBadArgument()
try:
self.cli.rpc.call("delright", argv[1], int(argv[2]))
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_delright.usage = "delright <account> <index>"
def cmd_addaccount(self, argv):
'''Create an account'''
if len(argv) != 3:
raise cmdBadArgument()
try:
self.cli.rpc.call("addaccount", argv[1], argv[2])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_addaccount.usage = "addaccount <account name> <role>"
def cmd_delaccount(self, argv):
'''Delete an account'''
if len(argv) != 2:
raise cmdBadArgument()
try:
self.cli.rpc.call("delaccount", argv[1])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_delaccount.usage = "delaccount <tql>"
def cmd_passwd(self, argv):
'''Change account password'''
if len(argv) == 1:
argv.append("a=%s"%self.cli.settings["login"])
if len(argv) == 2:
a = self.printer.getpass("Password: ")
b = self.printer.getpass("Again: ")
if a != b:
raise cmdError("You don't type twice the same password. Aborted")
argv.append(a)
elif len(argv) == 3:
if self.cli.interactive:
s = "You cannot set password with clear argument in interactive mode.\n"
s += "*** Think to clean your history! ***"
raise cmdError(s)
else:
raise cmdBadArgument()
try:
self.cli.rpc.call("passwd", argv[1], argv[2])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_passwd.usage = "passwd [tql] [password]"
def cmd_expert(self, argv):
'''Switch in expert mode'''
h = list(self.printer.history)
self.printer.history.read(self.cli.settings.get("expert", ""))
try:
local = dict()
local["cli"] = self.cli
local["rpc"] = self.cli.rpc
local["proxy"] = ConnectionProxy(self.cli.rpc)
c = code.InteractiveConsole(local)
c.interact("Use Ctrl+D to go back in CLI. Type dir() to see variables.")
finally:
self.printer.history.write(self.cli.settings.get("expert", ""))
self.printer.history.load(h)
cmd_expert.usage = "expert"
def cmd_whoami(self, argv):
'''Show connection login'''
self.printer.out(self.cli.settings["login"])
cmd_whoami.usage = "whoami"
def cmd_close(self, argv):
'''Close accounts'''
if len(argv) != 2:
raise cmdBadArgument()
try:
self.cli.rpc.call("close", argv[1])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_close.usage = "close <tql>"
def cmd_declose(self, argv):
'''Open closed accounts'''
if len(argv) != 2:
raise cmdBadArgument()
try:
self.cli.rpc.call("declose", argv[1])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_declose.usage = "declose <tql>"
def cmd_kill(self, argv):
'''Kill a server connection'''
if len(argv) != 2:
raise cmdBadArgument()
try:
self.cli.rpc.call("kill", argv[1])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_kill.usage = "kill <tql>"
def cmd_exec(self, argv):
'''exec a remote command'''
if len(argv) != 3:
raise cmdBadArgument()
try:
self.cli.rpc.call("exec", argv[1], argv[2])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_exec.usage = "exec <tql> <command>"
def cmd_shutdown(self, argv):
'''shutdown a physical host'''
if len(argv) != 2:
raise cmdBadArgument()
try:
self.cli.rpc.call("shutdown", argv[1])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_shutdown.usage = "shutdown <tql>"
class Alias(dict):
''' Alias wrapper'''
def load(self, filename):
'''load alias from file'''
if os.access(filename, os.R_OK):
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
if fparser.has_section("alias"):
self.clear()
self.update(fparser.items("alias"))
def save(self, filename):
'''save alias on file'''
if os.access(filename, os.R_OK or os.W_OK):
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
fparser.remove_section("alias")
fparser.add_section("alias")
for n,v in self.items():
fparser.set("alias", n, v)
fparser.write(open(filename, "w"))