#!/usr/bin/env python #coding=utf8 ''' CloudControl CLI class ''' import os, os.path import sys import socket import ssl import threading import subprocess import ConfigParser import cccli from cccli import printer, command from cccli.clierror import * from cccli.command import Command from sjrpc.client import SimpleRpcClient from sjrpc.utils import RpcHandler, pure, threadless, ConnectionProxy import sjrpc.core.exceptions import re import readline class Cli(object): def __init__(self, settings, args): self._settings = settings if "alias" in settings: self.alias = Alias(settings["alias"]) self.alias.load() self._interactive = sys.stderr.isatty() and sys.stdin.isatty() self._prompt = "> " self._commands = args self.rpc = None def start(self): '''Start a CLI''' # Connecting self._connect() # authentifications self._auth() # run parsing args if len(self._commands) > 0: for c in self._commands: self._parse(c) elif self._interactive: self._interactive_parser() else: self._parser() def _connect(self): printer.debug("Connecting...") rpcc = SimpleRpcClient.from_addr(self._settings["server"], self._settings["port"], enable_ssl=True, on_disconnect=self._on_disconnect ) rpcc.start(daemonize=True) self.rpc = ConnectionProxy(rpcc) def _on_disconnect(self, rpc): printer.fatal("Disconnected from server!") def _auth(self): printer.debug("Authenticating...") if self.rpc.authentify(self._settings["login"], self._settings["pass"]): printer.debug("Authenticated.") else: printer.fatal("Autentification failed!") def _interactive_parser(self): '''Interactive shell parser''' # init readline while True: try: line = raw_input(self._prompt) self._parse_line(line) except EOFError: printer.out("") break except SystemExit: break except KeyboardInterrupt: printer.out("") try: pass #readline.write_history_file(self._settings["histfile"]) except IOError: pass printer.out("Tcho!") def _parser(self): '''Non interactive parser''' while True: line = raw_input(self._prompt) self._parse_line(line) def _parse_line(self, line): '''Parse a line (more than one command)''' for cmd in line.split(";"): if (cmd.strip() == "" or cmd[0] == "#"): continue elif (cmd[0] == "!"): p = subprocess.Popen(cmd[1:], close_fds=True, shell=True) p.wait() ret = p.returncode elif (cmd[0] == "?"): Command("help").call() else: self._parse_command(cmd) def _parse_command(self, cmd): try: # lex command argv = self._lex_argv(cmd) # alias subs if argv[0] in self.alias: argv[0] = self.alias[argv[0]] # execute command Command(argv, self).call() except BadArgument, e: if str(e): printer.error("Bad argument: %s."%str(e)) else: printer.error("Bad argument.") usage = Command.usage(argv[0]) if usage != "": printer.out("usage: %s."%usage) except BadCommand, e: if str(e): printer.error("command: %s."%str(e)) else: printer.error("No command: %s."%argv[0]) except sjrpc.core.exceptions.RpcError, e: if cccli.debug: raise printer.error("sjRPC: %s"%str(e)) except Exception, e: if cccli.debug: raise printer.error("%s: %s."%(argv[0], str(e))) def _lex_argv(self, string): '''Lex command argument''' return string.split(" ") class Alias(dict): ''' Alias wrapper''' def __init__(self, filename): self._filename = filename def load(self): '''load alias from file''' if os.access(self._filename, os.R_OK): fparser = ConfigParser.SafeConfigParser() fparser.read(self._filename) if fparser.has_section("alias"): self.clear() self.update(fparser.items("alias")) def save(self): '''save alias on file''' if os.access(self._filename, os.R_OK or os.W_OK): fparser = ConfigParser.SafeConfigParser() fparser.read(self._filename) fparser.remove_section("alias") fparser.add_section("alias") for n,v in self.items(): fparser.set("alias", n, v) fparser.write(open(self._filename, "w"))