Skip to content
Snippets Groups Projects
command.py 12.18 KiB
#!/usr/bin/env python
#coding=utf8

'''
CloudControl CLI command module
'''

import os, os.path
import sys
import re
import pprint
import ConfigParser
from optparse import OptionParser

import cccli
from cccli.exception import *
from cccli.printer import color

from sjrpc.client import SimpleRpcClient
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 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"
    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'''
        self.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 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]"
    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
                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]"
    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():
                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]"
    cmd_alias.desc = "Show or create aliases"

    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]"
    cmd_unalias.desc = "Remove an aliases"

    def cmd_rcmd(self, argv):
        '''Show remote commands'''
        for cmds in self.cli.rpc.list_commands():
            self.printer.out("%s"%cmds["name"])
    cmd_rcmd.usage = "rcmd"
    cmd_rcmd.desc = "Print remote command list"

    def cmd_history(self, argv):
        '''Show history of commands'''
        if not self.printer.history:
            raise cmdError("not available")
        for l in self.printer.history:
            self.printer.out(l)
    cmd_history.usage = "history"
    cmd_history.desc = "Show commands history"

    def cmd_list(self, argv):
        '''List objects'''
        try:
            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.list(str.join("", args))
        except RpcError as e:
            raise cmdError("RPCError: %s"%str(e))
        if len(objs) == 0:
            return
        if options.table:
            self._list_table(objs)
        else:
            self._list(objs)
    cmd_list.usage = "list [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"%(color["green"], color["yellow"], id, tags))

    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 _startstopsdestroypauseresume(self, argv):
        # arg stuff
        if len(argv) == 1:
            raise cmdBadArgument()
        tql = str.join("", argv[1:])
        # print tql list result
        try:
            objs = self.cli.rpc.list(tql)
        except RpcError as e:
            raise cmdError("RPCError: %s"%str(e))
        if len(objs) == 0:
            raise cmdWarning("No selected object")
        self.printer.out("You request give the following result:")
        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)))
        if self.printer.ask("Are you sure to %s%s%s these %s id? (yes/NO) "%(color["lred"],
                                                                             argv[0],
                                                                             color["reset"],
                                                                             len(objs)), "yes") != "yes":
            raise cmdWarning("Aborted")
        if len(objs) > 5:
            if self.printer.ask("You request is on more than 5 objets. Are you really sure to %s its? (Yes, I am) "%argv[0], "Yes, I am") != "Yes, I am":
                raise cmdWarning("Aborted")
        try:
            self.cli.rpc[argv[0]](tql)
        except RpcError as e:
            raise cmdError("RPCError: %s"%str(e))

    def cmd_start(self, argv):
        '''Start objects'''
        self._startstopsdestroypauseresume(argv)
    cmd_start.usage = "start [tql]"

    def cmd_stop(self, argv):
        '''Stop objects'''
        self._startstopsdestroypauseresume(argv)
    cmd_stop.usage = "stop [tql]"

    def cmd_pause(self, argv):
        '''Pause objects'''
        self._startstopsdestroypauseresume(argv)
    cmd_pause.usage = "pause [tql]"

    def cmd_resume(self, argv):
        '''Resume objects'''
        self._startstopsdestroypauseresume(argv)
    cmd_resume.usage = "resume [tql]"

    def cmd_destroy(self, argv):
        '''Force objects to stop'''
        self._startstopsdestroypauseresume(argv)
    cmd_destroy.usage = "destroy [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.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_addtag(self, argv):
        '''Add/Modify a tag on an account'''
        if len(argv) != 4:
            raise cmdBadArgument()
        try:
            self.cli.rpc.settag(argv[1], argv[2], argv[3])
        except RpcError as e:
            raise cmdError("RPCError: %s"%str(e))
    cmd_addtag.usage = "addtag <account> <tag> <value>"

    def cmd_deltag(self, argv):
        '''Delete a tag from an user'''
        if len(argv) != 3:
            raise cmdBadArgument()
        try:
            self.cli.rpc.deltag(argv[1], argv[2])
        except RpcError as e:
            raise cmdError("RPCError: %s"%str(e))
    cmd_deltag.usage = "deltag <account> <tag>"

    def cmd_addaccount(self, argv):
        '''Create an account'''
        if len(argv) != 2:
            raise cmdBadArgument()
        try:
            self.cli.rpc.addaccount(argv[1])
        except RpcError as e:
            raise cmdError("RPCError: %s"%str(e))
    cmd_addaccount.usage = "addaccount <name>"

    def cmd_delaccount(self, argv):
        '''Delete an account'''
        if len(argv) != 2:
            raise cmdBadArgument()
        try:
            self.cli.rpc.delaccount(argv[1])
        except RpcError as e:
            raise cmdError("RPCError: %s"%str(e))
    cmd_delaccount.usage = "delaccount <name>"


class Alias(dict):
    ''' Alias wrapper'''
    def load(self, filename):
        '''load alias from file'''
        if os.access(filename, os.R_OK):
            fparser = ConfigParser.SafeConfigParser()
            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.SafeConfigParser()
            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"))