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

'''
CloudControl CLI class
'''

import os, os.path
import sys
import socket
import ssl
import threading
Seblu's avatar
Seblu committed
import subprocess
import ConfigParser
Seblu's avatar
Seblu committed
import cccli
from cccli import printer, command
from cccli.clierror import *
Seblu's avatar
Seblu committed
from cccli.command import Command
from sjrpc.client import SimpleRpcClient
from sjrpc.utils import RpcHandler, pure, threadless, ConnectionProxy
Seblu's avatar
Seblu committed
import sjrpc.core.exceptions
Seblu's avatar
Seblu committed
import re
import readline
Seblu's avatar
Seblu committed
    def __init__(self, settings, args):
        self._settings = settings
Seblu's avatar
Seblu committed
        if "alias" in settings:
            self.alias = Alias(settings["alias"])
            self.alias.load()
Seblu's avatar
Seblu committed
        self._interactive = sys.stderr.isatty() and sys.stdin.isatty()
        self._prompt = "> "
        self._commands = args
Seblu's avatar
Seblu committed
        self.rpc = None
Seblu's avatar
Seblu committed
    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()
Seblu's avatar
Seblu committed
    def _connect(self):
        printer.debug("Connecting...")
        rpcc = SimpleRpcClient.from_addr(self._settings["server"],
                                        self._settings["port"],
Seblu's avatar
Seblu committed
                                        enable_ssl=True,
                                        on_disconnect=self._on_disconnect
Seblu's avatar
Seblu committed
                                        )
        rpcc.start(daemonize=True)
Seblu's avatar
Seblu committed
        self.rpc = ConnectionProxy(rpcc)

    def _on_disconnect(self, rpc):
        printer.fatal("Disconnected from server!")
Seblu's avatar
Seblu committed
    def _auth(self):
        printer.debug("Authenticating...")
Seblu's avatar
Seblu committed
        if self.rpc.authentify(self._settings["login"], self._settings["pass"]):
Seblu's avatar
Seblu committed
            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] == "?"):
Seblu's avatar
Seblu committed
                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:
Seblu's avatar
Seblu committed
            if str(e):
Seblu's avatar
Seblu committed
                printer.error("Bad argument: %s."%str(e))
Seblu's avatar
Seblu committed
            else:
Seblu's avatar
Seblu committed
                printer.error("Bad argument.")
            usage = Command.usage(argv[0])
            if usage != "":
                printer.out("usage: %s."%usage)
Seblu's avatar
Seblu committed
        except BadCommand, e:
            if str(e):
                printer.error("command: %s."%str(e))
            else:
                printer.error("No command: %s."%argv[0])
Seblu's avatar
Seblu committed
        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)))
Seblu's avatar
Seblu committed

    def _lex_argv(self, string):
Seblu's avatar
Seblu committed
        '''Lex command argument'''
Seblu's avatar
Seblu committed
        return string.split(" ")
Seblu's avatar
Seblu committed


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"))