2013-08-14 20:36:35 +02:00
|
|
|
"""
|
2013-10-11 00:05:40 +02:00
|
|
|
Lish is the Linspector Interactive Shell.
|
2013-08-13 23:10:06 +02:00
|
|
|
|
2013-10-11 00:05:40 +02:00
|
|
|
This will become a commandline interface to Linspector. Think of a
|
|
|
|
|
network switch or router like those from Cisco.
|
2013-10-08 00:08:47 +02:00
|
|
|
|
2013-10-25 04:22:09 +02:00
|
|
|
Copyright (c) 2011-2013 by Johannes Findeisen and Rafael Timmerberg
|
2013-10-08 00:08:47 +02:00
|
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
2013-08-14 20:36:35 +02:00
|
|
|
"""
|
2013-08-18 03:08:09 +02:00
|
|
|
|
|
|
|
|
import os
|
2013-10-19 21:28:26 +02:00
|
|
|
import socket
|
2013-10-27 02:28:20 +01:00
|
|
|
|
2013-08-17 03:38:48 +02:00
|
|
|
from cmd import Cmd
|
2013-10-27 02:28:20 +01:00
|
|
|
from logging import getLogger
|
2013-10-19 21:28:26 +02:00
|
|
|
from shlex import split as shsplit
|
|
|
|
|
|
|
|
|
|
from linspector.frontends.frontend import Frontend
|
2013-08-17 03:38:48 +02:00
|
|
|
|
2013-10-28 04:00:54 +01:00
|
|
|
__version__ = "0.2.3-alpha"
|
2013-10-19 21:16:24 +02:00
|
|
|
|
|
|
|
|
PURPLE = "\033[95m"
|
|
|
|
|
BLUE = "\033[94m"
|
|
|
|
|
YELLOW = "\033[93m"
|
2013-10-19 23:22:07 +02:00
|
|
|
GREEN = "\033[92m"
|
2013-10-19 21:16:24 +02:00
|
|
|
RED = "\033[91m"
|
|
|
|
|
END = "\033[0m"
|
2013-08-14 20:36:35 +02:00
|
|
|
|
2013-10-27 02:28:20 +01:00
|
|
|
logger = getLogger(__name__)
|
|
|
|
|
|
2013-08-18 03:08:09 +02:00
|
|
|
|
2013-08-14 20:36:35 +02:00
|
|
|
class LishFrontend(Frontend):
|
2013-10-17 23:36:57 +02:00
|
|
|
def __init__(self, linpsectorInterface):
|
|
|
|
|
super(LishFrontend, self)
|
|
|
|
|
commander = LishCommander(linpsectorInterface)
|
2013-10-20 17:13:53 +02:00
|
|
|
|
2013-08-17 03:38:48 +02:00
|
|
|
run = True
|
|
|
|
|
while run:
|
2013-08-15 02:24:05 +02:00
|
|
|
try:
|
2013-10-19 21:41:58 +02:00
|
|
|
commander.cmdloop(GREEN + "Lish - Linspector interactive shell (" + __version__ + ")" + END)
|
2013-08-17 03:38:48 +02:00
|
|
|
except KeyboardInterrupt, ki:
|
|
|
|
|
run = False
|
|
|
|
|
except Exception, err:
|
|
|
|
|
print(err)
|
|
|
|
|
|
|
|
|
|
if commander.can_exit():
|
|
|
|
|
run = False
|
|
|
|
|
|
|
|
|
|
|
2013-08-20 00:49:04 +02:00
|
|
|
class CommandBase(Cmd, object):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
super(CommandBase, self).__init__()
|
|
|
|
|
self._needs_update = False
|
|
|
|
|
|
2013-10-17 23:36:57 +02:00
|
|
|
def get_completion(self, args, text):
|
|
|
|
|
if len(text) == 0:
|
2013-08-20 00:49:04 +02:00
|
|
|
return args
|
|
|
|
|
else:
|
|
|
|
|
return [x for x in args if x.startswith(text)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Exit(CommandBase, object):
|
2013-08-17 03:38:48 +02:00
|
|
|
def __init__(self):
|
|
|
|
|
super(Exit, self).__init__()
|
2013-08-20 00:49:04 +02:00
|
|
|
self.set_can_exit(False)
|
|
|
|
|
|
|
|
|
|
def set_can_exit(self, canExit=True):
|
|
|
|
|
self._canExit = canExit
|
2013-08-17 03:38:48 +02:00
|
|
|
|
|
|
|
|
def can_exit(self):
|
|
|
|
|
return self._canExit
|
|
|
|
|
|
|
|
|
|
def do_exit(self, text):
|
2013-08-20 00:51:02 +02:00
|
|
|
self.set_can_exit()
|
2013-08-17 03:38:48 +02:00
|
|
|
return self.can_exit()
|
|
|
|
|
|
|
|
|
|
def help_exit(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Exits Linspector
|
|
|
|
|
''')
|
2013-08-17 03:38:48 +02:00
|
|
|
|
|
|
|
|
|
2013-10-20 03:18:57 +02:00
|
|
|
class Command(object):
|
|
|
|
|
def __init__(self, name, command, helpText, children=None):
|
|
|
|
|
self.name = name
|
|
|
|
|
self.command = command
|
|
|
|
|
self.helpText = helpText
|
|
|
|
|
self.children = children
|
|
|
|
|
self.completion = []
|
|
|
|
|
if isinstance(children, list):
|
|
|
|
|
for child in children:
|
|
|
|
|
self.completion.append((child.get_name()))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CommandTree(object):
|
|
|
|
|
def __init__(self, name):
|
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
|
|
|
2013-10-20 17:10:49 +02:00
|
|
|
class LishCommander(Exit):
|
2013-10-17 23:36:57 +02:00
|
|
|
def __init__(self, linspectorInterface):
|
2013-08-17 03:38:48 +02:00
|
|
|
super(LishCommander, self).__init__()
|
|
|
|
|
|
2013-10-19 21:41:58 +02:00
|
|
|
self.prompt = BLUE + "<Lish@" + socket.gethostname() + ">: " + END
|
2013-10-17 23:36:57 +02:00
|
|
|
self.interface = linspectorInterface
|
|
|
|
|
|
2013-08-20 03:06:08 +02:00
|
|
|
def do_python(self, text):
|
|
|
|
|
exec text
|
|
|
|
|
|
2013-10-11 00:05:40 +02:00
|
|
|
def help_python(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Executes Python code using 'exec'
|
|
|
|
|
''')
|
2013-10-11 00:05:40 +02:00
|
|
|
|
2013-10-20 01:20:27 +02:00
|
|
|
def print_color(self, color, text):
|
2013-10-28 03:07:45 +01:00
|
|
|
print(color + str(text) + END)
|
2013-10-20 01:20:27 +02:00
|
|
|
|
|
|
|
|
def print_dict(self, dict):
|
|
|
|
|
for key, val in dict.items():
|
|
|
|
|
tab = ":\t"
|
|
|
|
|
if len(str(key)) < 7:
|
|
|
|
|
tab += "\t"
|
|
|
|
|
|
2013-10-28 03:07:45 +01:00
|
|
|
print(GREEN + str(key) + END + tab + YELLOW + str(val) + END)
|
2013-10-20 01:20:27 +02:00
|
|
|
|
2013-10-17 23:36:57 +02:00
|
|
|
def print_jobs_infos(self, job):
|
2013-10-20 01:20:27 +02:00
|
|
|
self.print_dict(self.interface.get_job_info_dict(job))
|
2013-10-17 23:36:57 +02:00
|
|
|
|
2013-10-11 00:05:40 +02:00
|
|
|
def do_job(self, text):
|
2013-10-17 23:36:57 +02:00
|
|
|
text = shsplit(text)
|
|
|
|
|
job_hex = text[0]
|
|
|
|
|
job = self.interface.find_job_by_hex_string(job_hex)
|
|
|
|
|
|
|
|
|
|
if job is None:
|
2013-10-20 15:40:14 +02:00
|
|
|
self.print_color(RED, "First parameter must be a job ID. Get a List of all IDs by typing 'jobs list'")
|
2013-10-17 23:36:57 +02:00
|
|
|
self.help_job()
|
2013-10-20 01:20:27 +02:00
|
|
|
return
|
2013-10-17 23:36:57 +02:00
|
|
|
|
|
|
|
|
if len(text) == 1:
|
|
|
|
|
self.print_jobs_infos(job)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
cmd = text[1]
|
|
|
|
|
if cmd in ["enable", "disable"]:
|
2013-10-19 00:55:24 +02:00
|
|
|
job.set_enabled("n" in cmd)
|
2013-10-11 00:05:40 +02:00
|
|
|
else:
|
2013-10-20 15:40:14 +02:00
|
|
|
self.print_color(RED, "Invalid or missing parameter")
|
2013-10-11 00:05:40 +02:00
|
|
|
self.help_job()
|
|
|
|
|
|
2013-10-17 23:36:57 +02:00
|
|
|
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)
|
|
|
|
|
|
2013-10-11 00:05:40 +02:00
|
|
|
def help_job(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Usage:
|
2013-10-28 04:43:27 +01:00
|
|
|
<ID> Prints extended information about this job
|
|
|
|
|
<ID> enable Enables a job
|
|
|
|
|
<ID> disable Disables a job
|
2013-10-28 04:30:10 +01:00
|
|
|
''')
|
2013-10-11 00:05:40 +02:00
|
|
|
|
2013-10-04 18:01:22 +02:00
|
|
|
def do_jobs(self, text):
|
|
|
|
|
if text == "list":
|
2013-10-17 23:36:57 +02:00
|
|
|
for job in self.interface.jobs:
|
2013-10-21 02:53:58 +02:00
|
|
|
job_dict = self.interface.get_job_info_dict(job)
|
2013-10-21 03:18:25 +02:00
|
|
|
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"] + \
|
2013-10-25 04:22:09 +02:00
|
|
|
PURPLE + " Runs" + END + ": " + job_dict["Runs"] + \
|
|
|
|
|
PURPLE + " Fails" + END + ": " + job_dict["Fails"] + \
|
2013-10-21 03:18:25 +02:00
|
|
|
PURPLE + " Enabled" + END + ": " + job_dict["Enabled"]
|
2013-10-21 15:48:39 +02:00
|
|
|
elif text == "count":
|
|
|
|
|
print GREEN + "Job Count" + END + ":\t" + str(self.interface.get_job_count())
|
2013-10-11 00:05:40 +02:00
|
|
|
else:
|
2013-10-20 15:40:14 +02:00
|
|
|
self.print_color(RED, "Invalid or missing parameter")
|
2013-10-11 00:05:40 +02:00
|
|
|
self.help_jobs()
|
2013-10-04 18:01:22 +02:00
|
|
|
|
|
|
|
|
def help_jobs(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Usage:
|
2013-10-28 04:43:27 +01:00
|
|
|
count Show count of all jobs
|
|
|
|
|
list Lists all jobs
|
2013-10-28 04:30:10 +01:00
|
|
|
''')
|
2013-10-28 03:07:45 +01:00
|
|
|
|
|
|
|
|
def do_host(self, text):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def help_host(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Usage:
|
2013-10-28 04:43:27 +01:00
|
|
|
<HOST> Prints extended information about <HOST>
|
|
|
|
|
<HOST> enable Enables all jobs for <HOST>
|
|
|
|
|
<HOST> disable Disables all jobs for <HOST>
|
|
|
|
|
<HOST> list Lists all jobs for <HOST>
|
2013-10-28 04:30:10 +01:00
|
|
|
''')
|
2013-10-28 03:07:45 +01:00
|
|
|
|
|
|
|
|
def do_hostgroup(self, text):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def help_hostgroup(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Usage:
|
2013-10-28 04:43:27 +01:00
|
|
|
<HOSTGROUP> Prints extended information about <HOSTGROUP>
|
|
|
|
|
<HOSTGROUP> enable Enables all jobs for <HOSTGROUP>
|
|
|
|
|
<HOSTGROUP> disable Disables all jobs for <HOSTGROUP>
|
|
|
|
|
<HOSTGROUP> list Lists all jobs for <HOSTGROUP>
|
2013-10-28 04:30:10 +01:00
|
|
|
''')
|
2013-10-28 03:07:45 +01:00
|
|
|
|
|
|
|
|
def do_hostgrouphost(self, text):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def help_hostgrouphost(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Usage:
|
2013-10-28 04:43:27 +01:00
|
|
|
<HOSTGROUP> <HOST> Prints extended information about <HOST> in <HOSTGROUP>
|
|
|
|
|
<HOSTGROUP> <HOST> enable Enables all jobs for <HOST> in <HOSTGROUP>
|
|
|
|
|
<HOSTGROUP> <HOST> disable Disables all jobs for <HOST> in <HOSTGROUP>
|
|
|
|
|
<HOSTGROUP> <HOST> list Lists all jobs for <HOST> in <HOSTGROUP>
|
2013-10-28 04:30:10 +01:00
|
|
|
''')
|
2013-10-20 04:08:58 +02:00
|
|
|
|
2013-10-20 17:09:41 +02:00
|
|
|
def do_shell(self, text):
|
|
|
|
|
os.system(text)
|
|
|
|
|
|
|
|
|
|
def help_shell(self):
|
2013-10-28 03:07:45 +01:00
|
|
|
print("Execute any shell command. Can also be achieved by a '!' prefix")
|
2013-10-20 17:09:41 +02:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2013-10-20 17:10:49 +02:00
|
|
|
def do_log(self, text):
|
2013-10-28 03:54:19 +01:00
|
|
|
if 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()
|
2013-10-29 02:31:17 +01:00
|
|
|
elif text == "less":
|
|
|
|
|
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("less " + os.path.dirname(os.path.abspath(__file__)) + "/../../log/linspector.log")
|
|
|
|
|
except IOError:
|
|
|
|
|
self.print_color(RED, "Logfile not found.")
|
|
|
|
|
self.help_log()
|
2013-10-20 17:10:49 +02:00
|
|
|
|
|
|
|
|
def help_log(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Usage:
|
2013-10-29 02:31:17 +01:00
|
|
|
less less on the linspector logfile (press "q" to exit)
|
|
|
|
|
tail tail on the linspector logfile (Ctrl+C to exit)
|
2013-10-28 04:30:10 +01:00
|
|
|
''')
|
2013-10-28 03:07:45 +01:00
|
|
|
|
|
|
|
|
def do_status(self, text):
|
2013-10-28 03:38:16 +01:00
|
|
|
# TODO: print instance name from core config
|
2013-10-28 03:24:25 +01:00
|
|
|
print GREEN + "Hostname" + END + ":\t" + socket.gethostname()
|
2013-10-28 03:38:16 +01:00
|
|
|
# TODO: print instance uptime
|
2013-10-28 03:24:25 +01:00
|
|
|
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"])
|
2013-10-28 04:15:25 +01:00
|
|
|
print GREEN + "Lish Version" + END + ":\t" + __version__
|
|
|
|
|
# TODO: print Linspector version
|
|
|
|
|
#print GREEN + "Core Version" + END + ":\t" + __linspector_version__
|
2013-10-28 03:07:45 +01:00
|
|
|
|
|
|
|
|
def help_status(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Show status information about the Linspector instance
|
|
|
|
|
''')
|
2013-10-20 17:10:49 +02:00
|
|
|
|
2013-10-20 04:08:58 +02:00
|
|
|
def do_about(self, text):
|
|
|
|
|
self.print_color(GREEN, "Linspector Monitoring\n")
|
2013-10-20 06:05:56 +02:00
|
|
|
self.print_color(YELLOW, "Developers:")
|
2013-10-20 04:08:58 +02:00
|
|
|
self.print_color(BLUE, " - Johannes Findeisen <hanez@linspector.org>")
|
|
|
|
|
self.print_color(BLUE, " - Rafael Timmerberg <ruff@linspector.org>\n")
|
|
|
|
|
self.print_color(PURPLE, "(c) 2011 - 2013")
|
|
|
|
|
self.print_color(PURPLE, "Web: http://linspector.org")
|
2013-10-20 06:05:56 +02:00
|
|
|
self.print_color(PURPLE, "License: GNU Affero General Public License Version 3.0")
|
2013-10-20 04:08:58 +02:00
|
|
|
|
|
|
|
|
def help_about(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Show information about Linspector
|
|
|
|
|
''')
|
2013-10-20 14:47:51 +02:00
|
|
|
|
|
|
|
|
def do_license(self, text):
|
|
|
|
|
os.system("less " + os.path.dirname(os.path.abspath(__file__)) + "/../../LICENSE")
|
|
|
|
|
|
|
|
|
|
def help_license(self):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Show license information
|
|
|
|
|
''')
|
2013-10-20 15:10:14 +02:00
|
|
|
|
|
|
|
|
def do_man(self, text):
|
|
|
|
|
try:
|
|
|
|
|
with open(os.path.dirname(os.path.abspath(__file__)) + "/../../man/" + text + ".md"):
|
2013-10-20 15:40:14 +02:00
|
|
|
#TODO: maybe convert markdown to plain text before displaying it and write own pager in pure Python
|
2013-10-20 15:10:14 +02:00
|
|
|
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):
|
2013-10-28 04:30:10 +01:00
|
|
|
print('''
|
|
|
|
|
Usage:
|
2013-10-28 04:43:27 +01:00
|
|
|
<PAGE> Show manual page <PAGE>
|
2013-10-28 04:30:10 +01:00
|
|
|
''')
|