""" Lish is the Linspector Interactive Shell. This will become a commandline interface to Linspector. Think of a network switch or router like those from Cisco. Copyright (c) 2011-2013 by Johannes Findeisen and Rafael Timmerberg This file is part of Linspector (http://linspector.org). Linspector is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . """ import os import socket from cmd import Cmd from logging import getLogger from shlex import split as shsplit from linspector.frontends.frontend import Frontend __version__ = "0.2.3-alpha" PURPLE = "\033[95m" BLUE = "\033[94m" YELLOW = "\033[93m" GREEN = "\033[92m" RED = "\033[91m" END = "\033[0m" logger = getLogger(__name__) class LishFrontend(Frontend): def __init__(self, linpsectorInterface): super(LishFrontend, self) commander = LishCommander(linpsectorInterface) run = True while run: try: commander.cmdloop(GREEN + "Lish - Linspector interactive shell (" + __version__ + ")" + END) except KeyboardInterrupt, ki: run = False except Exception, err: print(err) if commander.can_exit(): run = False class CommandBase(Cmd, object): def __init__(self): super(CommandBase, self).__init__() self._needs_update = False def get_completion(self, args, text): if len(text) == 0: return args else: return [x for x in args if x.startswith(text)] class Exit(CommandBase, object): def __init__(self): super(Exit, self).__init__() self.set_can_exit(False) def set_can_exit(self, canExit=True): self._canExit = canExit def can_exit(self): return self._canExit def do_exit(self, text): self.set_can_exit() return self.can_exit() def help_exit(self): print(''' Exits Linspector ''') class BaseCommand(object): def set_command(self, cmd): self.command = cmd def can_execute(self): if self.command.children is not None: return False else: return True def execute(self, text): text = shsplit(text) if len(text) == 0 and self.can_execute(): self.do_action() else: pass def do_action(self): pass def get_list(): return [] class Command(Cmd, object): def __init__(self, alias, interface, shortHelp=None, extendedHelp=None, completion=get_list, func=None, children=None): super(Command, self).__init__() self.interface = interface self.alias = alias self.shortHelp = shortHelp self.completion = completion self.extendedHelp = extendedHelp self.func = func self.children = children def get_short_help(self): if self.shortHelp is not None: return str(self.shortHelp) else: return "undocumented. see help %s for further information." % str(self.alias) def get_children(self): if self.children is None: self.children = [] return self.children def find_child_by_alias(self, alias): pass def get_extended_help(self): return self.extendedHelp def print_help(self): help = self.get_extended_help() if help is not None: print help elif len(self.get_children()) > 0: print "%s usage:\n" % str(self.alias) for child in self.get_children(): print child.alias + "\t\t" + child.short_help() + "\n" else: print "invalid or unsupported syntax" print "\n" def default(self, line): if len(line) == 0: if self.func is not None: return self.func(self.interface) else: self.print_help() else: line = shsplit(line) if len(line) > 0 and line[0] in [child.alias for child in self.get_children()]: pass def completenames(self, text, *ignored): ret = super(Command, self).completenames(text, *ignored) if len(self.get_children()) > 0: func = lambda alias: True if len(text) > 0: func = lambda alias: alias.startswith(text) ret.extend([cmd.alias for cmd in self.children if func(cmd.alias)]) return ret def completedefault(self, text, *ignored): pass def do_help(self, arg): if arg: pass else: pass class CommandTree(object): def __init__(self, name): self.name = name class LishCommander(Exit): def __init__(self, linspectorInterface): super(LishCommander, self).__init__() self.prompt = BLUE + ": " + END self.interface = linspectorInterface def do_python(self, text): exec text def help_python(self): print(''' Executes Python code using 'exec' ''') def print_color(self, color, text): print(color + str(text) + END) def print_dict(self, dict): for key, val in dict.items(): tab = ":\t" if len(str(key)) < 7: tab += "\t" print(GREEN + str(key) + END + tab + YELLOW + str(val) + END) def print_jobs_infos(self, job): self.print_dict(self.interface.get_job_info_dict(job)) def do_job(self, text): text = shsplit(text) job_hex = text[0] job = self.interface.find_job_by_hex_string(job_hex) if job is None: self.print_color(RED, "First parameter must be a job ID. Get a List of all IDs by typing 'jobs list'") self.help_job() return if len(text) == 1: self.print_jobs_infos(job) return cmd = text[1] if cmd in ["enable", "disable"]: job.set_enabled("n" in cmd) else: self.print_color(RED, "Invalid or missing parameter") self.help_job() def complete_job(self, text, line, begidx, endidx): if begidx == 4: return self.get_completion(self.interface.get_job_hex_strings(), text) elif begidx == 13: return self.get_completion(["enable", "disable"], text) def help_job(self): print(''' Usage: Prints extended information about this job enable Enables a job disable Disables a job ''') def do_jobs(self, text): if text == "list": for job in self.interface.jobs: job_dict = self.interface.get_job_info_dict(job) print GREEN + job_dict["Job"] + END + ":\t" + \ PURPLE + "Hostgroup" + END + ": " + job_dict["Hostgroup"] + \ PURPLE + " Host" + END + ": " + job_dict["Host"] + \ PURPLE + " Service" + END + ": " + job_dict["Service"] + \ PURPLE + " Next run" + END + ": " + job_dict["Next run"] + \ PURPLE + " Runs" + END + ": " + job_dict["Runs"] + \ PURPLE + " Fails" + END + ": " + job_dict["Fails"] + \ PURPLE + " Enabled" + END + ": " + job_dict["Enabled"] elif text == "count": print GREEN + "Job Count" + END + ":\t" + str(self.interface.get_job_count()) else: self.print_color(RED, "Invalid or missing parameter") self.help_jobs() def help_jobs(self): print(''' Usage: count Show count of all jobs list Lists all jobs ''') def do_host(self, text): pass def help_host(self): print(''' Usage: Prints extended information about enable Enables all jobs for disable Disables all jobs for list Lists all jobs for ''') def do_hostgroup(self, text): pass def help_hostgroup(self): print(''' Usage: Prints extended information about enable Enables all jobs for disable Disables all jobs for list Lists all jobs for ''') def do_hostgrouphost(self, text): pass def help_hostgrouphost(self): print(''' Usage: Prints extended information about in enable Enables all jobs for in disable Disables all jobs for in list Lists all jobs for in ''') def do_shell(self, text): os.system(text) def help_shell(self): print("Execute any shell command. Can also be achieved by a '!' prefix") def complete_shell(self, text, line, begidx, endidx): try: PATH = os.environ['PATH'].split(os.pathsep) bins = [] for p in PATH: bins.extend(os.listdir(p)) return self.get_completion(bins, text, False) except: pass def do_log(self, text): if text == "less": try: # TODO: do the less on the logfile set by args and not a static path with open(os.path.dirname(os.path.abspath(__file__)) + "/../../log/linspector.log"): os.system("less " + os.path.dirname(os.path.abspath(__file__)) + "/../../log/linspector.log") except IOError: self.print_color(RED, "Logfile not found.") self.help_log() elif text == "more": try: # TODO: do the more on the logfile set by args and not a static path with open(os.path.dirname(os.path.abspath(__file__)) + "/../../log/linspector.log"): os.system("more " + os.path.dirname(os.path.abspath(__file__)) + "/../../log/linspector.log") except IOError: self.print_color(RED, "Logfile not found.") self.help_log() elif text == "tail": try: # TODO: do the tail on the logfile set by args and not a static path with open(os.path.dirname(os.path.abspath(__file__)) + "/../../log/linspector.log"): os.system("tail -F " + os.path.dirname(os.path.abspath(__file__)) + "/../../log/linspector.log") except IOError: self.print_color(RED, "Logfile not found.") self.help_log() def help_log(self): print(''' Usage: less less on the linspector logfile (press "q" to exit) more more on the linspector logfile (press "q" to exit) tail tail (-F) on the linspector logfile (Ctrl+C to exit) ''') def do_status(self, text): # TODO: print instance name from core config print GREEN + "Hostname" + END + ":\t" + socket.gethostname() # TODO: print instance uptime print GREEN + "Job Count" + END + ":\t" + str(self.interface.get_job_count()) thread_info = self.interface.get_thread_count() print GREEN + "Threads" + END + ":\t" + str(thread_info["Num Threads"]) + "/" + str(thread_info["Max Threads"]) print GREEN + "Lish Version" + END + ":\t" + __version__ # TODO: print Linspector version #print GREEN + "Core Version" + END + ":\t" + __linspector_version__ def help_status(self): print(''' Show status information about the Linspector instance ''') def do_about(self, text): self.print_color(GREEN, "Linspector Monitoring\n") self.print_color(YELLOW, "Developers:") self.print_color(BLUE, " - Johannes Findeisen ") self.print_color(BLUE, " - Rafael Timmerberg \n") self.print_color(PURPLE, "(c) 2011 - 2013") self.print_color(PURPLE, "Web: http://linspector.org") self.print_color(PURPLE, "License: GNU Affero General Public License Version 3.0") def help_about(self): print(''' Show information about Linspector ''') def do_license(self, text): os.system("less " + os.path.dirname(os.path.abspath(__file__)) + "/../../LICENSE") def help_license(self): print(''' Show license information ''') def do_man(self, text): try: with open(os.path.dirname(os.path.abspath(__file__)) + "/../../man/" + text + ".md"): #TODO: maybe convert markdown to plain text before displaying it and write own pager in pure Python os.system("less " + os.path.dirname(os.path.abspath(__file__)) + "/../../man/" + text + ".md") except IOError: self.print_color(RED, "Manual page \"" + text + "\" not found.") self.help_man() def help_man(self): print(''' Usage: Show manual page ''')