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 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'''
227
228
229
230
231
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
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)'''
if len(argv) == 1:
argv.append(self.cli.settings["login"])
tl = self.cli.rpc.call("tags", a)
tags = " ".join([ "%s%s:%s%s"%(color["green"], t, color["reset"], v) for (t,v) in tl.items() ])
self.printer.out("%sa:%s%s%s %s"%(color["green"], color["yellow"], a, color["reset"], tags))
except RpcError as e:
raise cmdError("RPCError: %s"%str(e))
cmd_tags.usage = "tags [account]"
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>"
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
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
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"
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):