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"
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'''
cmd_version.usage = "version"
cmd_version.desc = "Print cli version"
def cmd_usage(self, argv):
'''Print usage of a command'''
if len(argv) != 2:
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
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]"
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():
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]"
cmd_alias.desc = "Show or create aliases"
def cmd_unalias(self, argv):
'''Remove an alias'''
if len(argv) != 2:
cmd_unalias.usage = "unalias [name]"
cmd_unalias.desc = "Remove an aliases"
def cmd_rcmd(self, argv):
'''Show remote commands'''
for cmds in self.cli.rpc.call("list_commands"):
cmd_rcmd.usage = "rcmd"
cmd_rcmd.desc = "Print remote command list"
def cmd_history(self, argv):
'''Show history of commands'''
cmd_history.usage = "history"
cmd_history.desc = "Show commands history"
oparser = OptionParser(prog="list")
oparser.add_option("-t", action="store_true", dest="table")
(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 options.table:
self._list_table(objs)
else:
self._list(objs)
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))
# 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'''
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
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
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"
def cmd_stop(self, argv):
'''Stop objects'''
self._vm_action(argv, "&role=vm&status=running")
cmd_stop.usage = "stop [--raw] [--direct] [--force] [--help] tql"
def cmd_pause(self, argv):
'''Pause objects'''
self._vm_action(argv, "&role=vm&status=running")
cmd_pause.usage = "pause [--raw] [--direct] [--force] [--help] tql"
def cmd_resume(self, argv):
'''Resume objects'''
self._vm_action(argv, "&role=vm&status=stalled")
cmd_resume.usage = "resume [--raw] [--direct] [--force] [--help] tql"
def cmd_destroy(self, argv):
'''Force objects 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(self.cli.settings["login"])
tql = "a~(%s)$con"%"|".join(argv[1:])
try:
objs = self.cli.rpc.call("list",tql)
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
for o in objs:
self.printer.out("%s: %ss"%(o["a"],o["con"]))
cmd_uptime.usage = "uptime [login]"
def cmd_tags(self, argv):
'''List static tags on an account (current by default)'''
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# 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] [account tql]"
self.cli.rpc.call("addtag", argv[1], argv[2], argv[3])
self.cli.rpc.call("deltag", argv[1], argv[2])
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_deltag.usage = "deltag <account> <tag>"
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
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 <account> <right tql> <method> <allow>"
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))
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:
if not self.cli.interactive:
raise cmdError("You must give a password argument in non interactive mode!")
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))
cmd_close.usage = "close <account 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 <account 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):