#!/usr/bin/env python #coding=utf8 ''' CloudControl CLI main module ''' import os, os.path import sys import re import subprocess import shlex import StringIO import cccli from cccli.command import Command, Alias from cccli.printer import Printer, color from cccli.exception import * from sjrpc.client import SimpleRpcClient from sjrpc.utils import RpcHandler, ConnectionProxy, pure from sjrpc.core.exceptions import * class Cli(object): def __init__(self, settings): self.settings = settings self.prompt = "" self.rpc = None self.printer = None self.alias = Alias() def start(self, line=""): '''Start a CLI''' # line stuff if line: sys.stdin = StringIO.StringIO(line) # set interactive mode self.interactive = sys.stderr.isatty() and sys.stdin.isatty() # start printer and load history self.printer = Printer(self.interactive) self.printer.history.load(self.settings.get("history", "")) self.printer.history.maxsize(self.settings.get("hsize", None)) # load alias self.alias.load(self.settings.get("alias", "")) # print debug self.printer.debug("Interactive: %s"%self.interactive) self.printer.debug("Alias: %s"%self.alias) self.printer.debug("Loaded history: %s"%len(self.printer.history)) # Connecting self._connect() # authentifications self._auth() # Parsing self._parse() # save history self.printer.history.save(self.settings.get("history", "")) def _connect(self): self.printer.debug("Connecting...") rpcc = SimpleRpcClient.from_addr(self.settings["server"], self.settings["port"], enable_ssl=True, default_handler=CliHandler(), on_disconnect="quit", timeout=self.settings["timeout"] ) rpcc.start(daemonize=True) self.rpc = ConnectionProxy(rpcc) def _auth(self): '''Handle server authentification''' self.printer.debug("Authenticating...") try: self.rpc.authentify(self.settings["login"], self.settings["pass"]) except Exception: raise cliError("Autentification failed!") self.printer.debug("Authenticated.") def _parse(self): '''Parse a line''' if self.interactive: prompt = "%s%s>%s "%(color["lwhite"],self.settings["login"],color["reset"]) else: prompt = "" while True: try: argv = shlex.split(self.printer.getline(prompt), comments=True) except ValueError as e: print type(e) self.printer.error("Lexer: %s"%str(e)) continue except KeyboardInterrupt: self.printer.out("") continue except EOFError: break except SystemExit: break if len(argv) == 0: continue # alias subsitution if argv[0] in self.alias: argv[0] = self.alias[argv[0]] self._exec_command(argv) if self.interactive: self.printer.out("tcho!") def _exec_command(self, argv): '''Execute command''' try: if (argv[0] == "!"): p = subprocess.Popen(argv[1:], close_fds=True, shell=True) p.wait() ret = p.returncode elif (argv[0] == "?"): Command(["help"], self).call() else: Command(argv, self).call() except BadArgument as e: if str(e): self.printer.error("Bad argument: %s."%str(e)) else: self.printer.error("Bad argument.") usage = Command.usage(argv[0]) if usage != "": self.printer.out("usage: %s."%usage) except BadCommand as e: if str(e): self.printer.error("command: %s."%str(e)) else: 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))) 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 } @pure def quit(self, rpc=None): Printer().fatal("Disconnected from server!")