Newer
Older
#!/usr/bin/env python
#coding=utf8
'''
CloudControl CLI command module
'''
from cccli.exception import *
from cccli.printer import color
from sjrpc.client import SimpleRpcClient
# check valid command chars
if not re.match("^[a-zA-Z0-9]+", argv[0]):
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:
@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):
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)
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'''
cmd_version.usage = "version"
def cmd_usage(self, argv):
'''Print usage of a command'''
if len(argv) != 2:
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
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__"))
self.printer.out("Usage: %s"%getattr(getattr(self, fname), "usage"))
Self.Printer.out("Details: %s"%getattr(getattr(self, fname), "details"))
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():
elif len(argv) == 2:
if argv[1] not in self.cli.alias:
self.printer.out("%s=%s"%(argv[1], self.cli.alias[argv[1]]))
elif len(argv) == 3:
self.cli.alias[argv[1]] = argv[2]
cmd_alias.usage = "alias [name] [value]"
def cmd_unalias(self, argv):
'''Remove an alias'''
if len(argv) != 2:
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))
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:
objs = self.cli.rpc.call("list", str.join("", args))
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
if options.align:
self._list_align(objs)
elif options.table:
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)
# 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=" ")
# 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'''
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
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))
self._vm_action(argv, "&role=vm&status=stopped")
cmd_start.usage = "start [--raw] [--direct] [--force] [--help] <tql>"
self._vm_action(argv, "&role=vm&status=running")
cmd_stop.usage = "stop [--raw] [--direct] [--force] [--help] <tql>"
self._vm_action(argv, "&role=vm&status=running")
cmd_pause.usage = "pause [--raw] [--direct] [--force] [--help] <tql>"
self._vm_action(argv, "&role=vm&status=stalled")
cmd_resume.usage = "resume [--raw] [--direct] [--force] [--help] <tql>"
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"
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)'''
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# 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))
self.cli.rpc.call("addtag", argv[1], argv[2], argv[3])
self.cli.rpc.call("deltag", argv[1], argv[2])
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'''
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))
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])
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.")
self.printer.history.write(self.cli.settings.get("expert", ""))
self.printer.history.load(h)
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))
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))
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.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):