Skip to content
Snippets Groups Projects
cli.py 5.15 KiB
Newer Older
#!/usr/bin/env python
#coding=utf8

'''
Seblu's avatar
Seblu committed
CloudControl CLI main module
'''

import os, os.path
import sys
Seblu's avatar
Seblu committed
import re
Seblu's avatar
Seblu committed
import subprocess
Seblu's avatar
Seblu committed
import shlex
import StringIO
Seblu's avatar
Seblu committed

import cccli
Seblu's avatar
Seblu committed
from cccli.command import Command, Alias
from cccli.printer import Printer, color
Seblu's avatar
Seblu committed
from cccli.exception import *
Seblu's avatar
Seblu committed

from sjrpc.client import SimpleRpcClient
from sjrpc.utils import RpcHandler, ConnectionProxy, pure
Seblu's avatar
Seblu committed
from sjrpc.core.exceptions import *
Seblu's avatar
Seblu committed
    def __init__(self, settings):
        self.settings = settings
Seblu's avatar
Seblu committed
        self.rpc = None
Seblu's avatar
Seblu committed
        self.alias = Alias()
Seblu's avatar
Seblu committed
    def start(self, line=""):
Seblu's avatar
Seblu committed
        '''Start a CLI'''
Seblu's avatar
Seblu committed
        # line stuff
Seblu's avatar
Seblu committed
        if line:
Seblu's avatar
Seblu committed
            sys.stdin = StringIO.StringIO(line)
        # set interactive mode
        self.interactive = sys.stderr.isatty() and sys.stdin.isatty()
Seblu's avatar
Seblu committed
        # start printer and load history
        self.printer = Printer(self.interactive,
                               self.settings.get("forceyes", False),
                               historyfile=self.settings.get("history", ""),
                               historysize=self.settings.get("hsize", None))
Seblu's avatar
Seblu committed
        # load alias
        self.alias.load(self.settings.get("alias", ""))
Seblu's avatar
Seblu committed
        # print debug
        self.printer.debug("Interactive: %s"%self.interactive)
Seblu's avatar
Seblu committed
        self.printer.debug("Alias: %s"%self.alias)
Seblu's avatar
Seblu committed
        self.printer.debug("Loaded history: %s"%len(self.printer.history))
Seblu's avatar
Seblu committed
        self._connect()
Seblu's avatar
Seblu committed
        self._auth()
Seblu's avatar
Seblu committed
        self._parse()
        # save history
Seblu's avatar
Seblu committed
        self.printer.history.save(self.settings.get("history", ""))
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
    def _connect(self):
        '''Connect to a cloud control server'''
Seblu's avatar
Seblu committed
        self.printer.debug("Connecting...")
Seblu's avatar
Seblu committed
        try:
            rpcc = SimpleRpcClient.from_addr(self.settings["server"],
                                             self.settings["port"],
                                             enable_ssl=True,
                                             default_handler=CliHandler(),
                                             on_disconnect="quit",
                                             timeout=self.settings["timeout"]
Seblu's avatar
Seblu committed
                                        )
Seblu's avatar
Seblu committed
            rpcc.start(daemonize=True)
            self.rpc = ConnectionProxy(rpcc)
        except Exception:
            raise cliError("Connection failure!")
        self.printer.debug("Connected.")
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
    def _auth(self):
Seblu's avatar
Seblu committed
        '''Handle server authentification'''
Seblu's avatar
Seblu committed
        self.printer.debug("Authenticating...")
        try:
            self.rpc.authentify(self.settings["login"], self.settings["pass"])
        except Exception:
            raise cliError("Autentification failed!")
        self.printer.debug("Authenticated.")
Seblu's avatar
Seblu committed
    def _parse(self):
        '''Parse a line'''
        if self.interactive:
            prompt = "\001%s\002%s>\001%s\002 "%(color["light"],self.settings["login"],color["reset"])
        else:
            prompt = ""
Seblu's avatar
Seblu committed
        while True:
            try:
Seblu's avatar
Seblu committed
                argv = shlex.split(self.printer.getline(prompt), comments=True)
Seblu's avatar
Seblu committed
            except ValueError as e:
                print type(e)
Seblu's avatar
Seblu committed
                self.printer.error("Lexer: %s"%str(e))
                continue
            except KeyboardInterrupt:
                self.printer.out("")
                continue
Seblu's avatar
Seblu committed
            except EOFError:
                break
            except SystemExit:
                break
            if len(argv) == 0:
                continue
            # alias subsitution
            if argv[0] in self.alias:
Seblu's avatar
Seblu committed
                oldargv = argv[1:]
                argv = shlex.split(self.alias[argv[0]])
                argv.extend(oldargv)
Seblu's avatar
Seblu committed
            self._exec_command(argv)
        if self.interactive:
            self.printer.out("tcho!")
Seblu's avatar
Seblu committed
    def _exec_command(self, argv):
        '''Execute command'''
        try:
            if (argv[0] == "!"):
                p = subprocess.Popen(argv[1:], close_fds=True, shell=True)
Seblu's avatar
Seblu committed
                p.wait()
                ret = p.returncode
Seblu's avatar
Seblu committed
            elif (argv[0] == "?"):
Seblu's avatar
Seblu committed
                Command(["help"], self).call()
Seblu's avatar
Seblu committed
            else:
Seblu's avatar
Seblu committed
                Command(argv, self).call()
Seblu's avatar
Seblu committed
        except cmdBadArgument as e:
Seblu's avatar
Seblu committed
            if str(e):
Seblu's avatar
Seblu committed
                self.printer.error("Bad argument: %s."%str(e))
Seblu's avatar
Seblu committed
            else:
Seblu's avatar
Seblu committed
                self.printer.error("Bad argument.")
Seblu's avatar
Seblu committed
            usage = Command.usage(argv[0])
            if usage != "":
Seblu's avatar
Seblu committed
                self.printer.out("usage: %s."%usage)
Seblu's avatar
Seblu committed
        except cmdBadName:
            self.printer.error("No command: %s."%argv[0])
        except cmdWarning as e:
            self.printer.warn("%s: %s"%(argv[0], str(e)))
        except cmdError as e:
            self.printer.error("%s: %s"%(argv[0], str(e)))
Seblu's avatar
Seblu committed
        except Exception as e:
            if cccli.debug:
                raise
            self.printer.error(str(e))
            self.printer.warn("This is a not expected error, please report it!")
class CliHandler(RpcHandler):
    '''Handle RPC incoming request'''

    @pure
    def get_tags(self, tags=()):
        if "version" in tags:
            return { "version": cccli.version }
        Printer().fatal("Disconnected from server!")