Merge remote-tracking branch 'origin/master'
Conflicts: .gitignore bin/linspector examples/linspector.json linspector/core/job.py linspector/frontends/lish.py linspector/services/tcpconnect.py
This commit is contained in:
commit
9de9af9921
8 changed files with 186 additions and 61 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -9,10 +9,11 @@ nbproject
|
|||
|
||||
distfiles
|
||||
docs
|
||||
documentation
|
||||
files
|
||||
local
|
||||
log
|
||||
plugins
|
||||
.metadata
|
||||
|
||||
examples/private.json
|
||||
examples/private.json
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ 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/>.
|
||||
"""
|
||||
|
||||
__version__ = "0.6/TCPCONNECT"
|
||||
__version__ = "0.1.7"
|
||||
__default_config__ = "./examples/minimal.json"
|
||||
|
||||
import argparse
|
||||
|
|
@ -35,7 +35,7 @@ from linspector.backends.https import HttpsBackend
|
|||
from linspector.frontends.lish import LishFrontend
|
||||
|
||||
|
||||
def parseArgs():
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Linspector is for monitoring the vital information of hosts, services and devices in a network.",
|
||||
epilog="linspector is not some program expecting computers to run! Visit http://linspector.org for more "
|
||||
|
|
@ -62,14 +62,14 @@ def parseArgs():
|
|||
return parser.parse_args()
|
||||
|
||||
|
||||
def setupLogging(logfile="./log/linspector.log", logLevel=logging.ERROR, logfileLevel=logging.DEBUG):
|
||||
def setup_logging(logfile="./log/linspector.log", logLevel=logging.ERROR, logfileLevel=logging.DEBUG):
|
||||
logfile = path.expanduser(logfile)
|
||||
if not path.exists(path.dirname(logfile)):
|
||||
os.makedirs(path.dirname(logfile))
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
#logging.basicConfig(level=logging.WARNING)
|
||||
log = logging.getLogger(__name__)
|
||||
#log.setLevel(logging.ERROR)
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
consoleHandler = logging.StreamHandler()
|
||||
consoleHandler.setLevel(logLevel)
|
||||
|
|
@ -90,14 +90,14 @@ def setupLogging(logfile="./log/linspector.log", logLevel=logging.ERROR, logfile
|
|||
return log
|
||||
|
||||
|
||||
def handleJob(jobInfo):
|
||||
def handle_job(jobInfo):
|
||||
jobInfo.handle_call()
|
||||
|
||||
|
||||
def main():
|
||||
args = parseArgs()
|
||||
args = parse_args()
|
||||
#TODO: catch all log messages (apscheduler etc.); make logging more generic to support libraries logging
|
||||
log = setupLogging(args.logfile, args.loglevel)
|
||||
log = setup_logging(args.logfile, args.loglevel)
|
||||
|
||||
log.info("parsed arguments")
|
||||
|
||||
|
|
@ -114,8 +114,8 @@ def main():
|
|||
for service in hostgroup.get_services():
|
||||
for host in hostgroup.get_hosts():
|
||||
for period in service.get_periods():
|
||||
job = Job(service, host, hostgroup.get_members(), hostgroup.get_processors(), core)
|
||||
schedulerJob = period.createJob(scheduler, job, handleJob)
|
||||
job = Job(service, host, hostgroup.get_members(), hostgroup.get_processors(), core, hostgroup)
|
||||
schedulerJob = period.createJob(scheduler, job, handle_job)
|
||||
if schedulerJob is not None:
|
||||
job.set_job(schedulerJob)
|
||||
job.set_logger(log)
|
||||
|
|
@ -131,9 +131,9 @@ def main():
|
|||
frontend = LishFrontend(jobs=jobs, scheduler=scheduler, linspectorConfig=linConf)
|
||||
|
||||
log.debug("shutting down scheduler")
|
||||
logging.shutdown()
|
||||
scheduler.shutdown(wait=True)
|
||||
logging.shutdown()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@
|
|||
}
|
||||
},
|
||||
"layouts":{
|
||||
"_comment": "https://github.com/linspector/linspector/wiki/Configuration-Layouts",
|
||||
"production":{
|
||||
"hostgroups":[ "group1" ],
|
||||
"enabled": true
|
||||
|
|
@ -184,13 +185,16 @@
|
|||
}
|
||||
},
|
||||
"core":{
|
||||
"_comment": "https://github.com/linspector/linspector/wiki/Configuration-Core",
|
||||
"instance_name": "Master Monitoring (monitor.example.org)",
|
||||
"max_logfile_size": 1024000,
|
||||
"max_logfile_count": 4,
|
||||
"max_worker_threads": 8,
|
||||
"threshold_handling": "reset",
|
||||
"members":[ "root" ],
|
||||
"backends": {
|
||||
"jsonrpc": {
|
||||
"_comment": "https://github.com/linspector/linspector/wiki/Configuration-Core-Backends-JsonRPC",
|
||||
"host": "127.0.0.1",
|
||||
"port": "2323",
|
||||
"username": "linspector",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,27 @@ import time
|
|||
import atexit
|
||||
from signal import SIGTERM
|
||||
|
||||
"""
|
||||
TODO: Think about, that daemonizing this software is not our goal but when we want to that, this needs a rewrite and
|
||||
should maybe move over to the daemon frontend. daemon.py will remain the the base for this and should stay in linspector/core .
|
||||
Since a daemon it normally not a frontend we should think about how to handle this. When daemonizing a real frontend
|
||||
like "Lish" will make no sense but a frontend like "https" or "xmpp" could be useful anyway...
|
||||
"""
|
||||
|
||||
|
||||
class LinspectorDaemon(Daemon):
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
a = 2
|
||||
#logger.writeLogToFile(_logfile, "Running!")
|
||||
print "running!"
|
||||
except Exception as err:
|
||||
#logger.writeLogToFile(_logfile, str(err))
|
||||
print "failed"
|
||||
sys.exit(1)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
class Daemon:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -32,21 +32,22 @@ def generateId():
|
|||
|
||||
|
||||
class Job:
|
||||
def __init__(self, service, host, members, processors, core):
|
||||
def __init__(self, service, host, members, processors, core, hostgroup):
|
||||
self.service = service
|
||||
self.host = host
|
||||
self.members = members
|
||||
self.processors = processors
|
||||
self.core = core
|
||||
self.hostgroup = hostgroup
|
||||
self.jobInfos = []
|
||||
self.jobThreshold = 0
|
||||
self._enabled = True
|
||||
|
||||
def __str__(self):
|
||||
return str(self.__dict__)
|
||||
|
||||
|
||||
def __hex__(self):
|
||||
return hex(crc32(str(self.service) + str(self.host) + str(self.members)))
|
||||
return hex(crc32(str(self.hostgroup) + str(self.host) + str(self.service) + str(self.members)))
|
||||
|
||||
def hex_string(self):
|
||||
ret = self.__hex__()
|
||||
|
|
@ -62,7 +63,9 @@ class Job:
|
|||
self.log = log
|
||||
|
||||
def pretty_string(self):
|
||||
return self.hex_string() + ": (" + str(self.host) + str(self.service) + str(self.job) + ")"
|
||||
ret = (self.hex_string() + ": (Hostgroup: " + str(self.hostgroup.get_name()) +
|
||||
" Host: " + str(self.host) + " Service: " + str(self.service) + " " + str(self.job) + ")")
|
||||
return ret
|
||||
|
||||
def set_job(self, job):
|
||||
self.job = job
|
||||
|
|
@ -70,7 +73,15 @@ class Job:
|
|||
def handle_threshold(self, jobInfo, serviceThreshold, executionSucessful):
|
||||
if executionSucessful:
|
||||
if self.jobThreshold > 0:
|
||||
self.jobThreshold -= 1
|
||||
#TODO: maybe set threshold_handling for each service optionally; will override core setting!
|
||||
if self.core["threshold_handling"] == "reset":
|
||||
# Reset counter to 0
|
||||
self.log.debug("Threshold Reset")
|
||||
self.jobThreshold = 0
|
||||
else:
|
||||
# Decrement the counter (default)
|
||||
self.log.debug("Threshold Decrement")
|
||||
self.jobThreshold -= 1
|
||||
else:
|
||||
self.jobThreshold += 1
|
||||
|
||||
|
|
@ -87,23 +98,32 @@ class Job:
|
|||
def handle_call(self):
|
||||
self.log.debug("handle call")
|
||||
self.log.debug(self.service)
|
||||
try:
|
||||
jobInfo = JobInfo(self.__hex__(), self.host, self.service)
|
||||
self.service._execute(jobInfo)
|
||||
jobInfo.set_execution_end()
|
||||
if self._enabled:
|
||||
try:
|
||||
jobInfo = JobInfo(self.hex_string(), self.host, self.service)
|
||||
self.service._execute(jobInfo)
|
||||
jobInfo.set_execution_end()
|
||||
|
||||
self.handle_threshold(jobInfo, self.service.get_threshold(), jobInfo.was_execution_successful())
|
||||
self.handle_threshold(jobInfo, self.service.get_threshold(), jobInfo.was_execution_successful())
|
||||
|
||||
self.log.debug("Code: " + str(jobInfo.get_errorcode()) + ", Message: " + str(jobInfo.get_message()))
|
||||
self.log.debug("Code: " + str(jobInfo.get_errorcode()) + ", Message: " + str(jobInfo.get_message()))
|
||||
|
||||
self.jobInfos.append(jobInfo)
|
||||
self.jobInfos.append(jobInfo)
|
||||
|
||||
except Exception, e:
|
||||
self.log.debug(e)
|
||||
except Exception, e:
|
||||
self.log.debug(e)
|
||||
else:
|
||||
self.log.debug("Job " + self.hex_string() + " disabled")
|
||||
|
||||
def enable(self):
|
||||
self._enabled = True
|
||||
|
||||
def disable(self):
|
||||
self._enabled = False
|
||||
|
||||
|
||||
class JobInfo(object):
|
||||
def __init__(self,jobHex, host, service):
|
||||
def __init__(self, jobHex, host, service):
|
||||
self.id = generateId()
|
||||
self.jobHex = jobHex
|
||||
self.host = host
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""
|
||||
Lish is the Linspector Interactive Shell...
|
||||
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.
|
||||
This will become a commandline interface to Linspector. Think of a
|
||||
network switch or router like those from Cisco.
|
||||
|
||||
Copyright (c) 2011-2013 "Johannes Findeisen and Rafael Timmerberg"
|
||||
|
||||
|
|
@ -21,13 +22,12 @@ 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/>.
|
||||
"""
|
||||
|
||||
|
||||
from linspector.frontends.frontend import Frontend
|
||||
import os
|
||||
from shlex import split as shsplit
|
||||
from cmd import Cmd
|
||||
|
||||
__version__ = "0.1"
|
||||
__version__ = "0.1.1"
|
||||
|
||||
|
||||
class LishFrontend(Frontend):
|
||||
|
|
@ -128,7 +128,6 @@ class HostgroupCommander(Exit, object):
|
|||
|
||||
|
||||
class LishCommander(Exit, ShellCommander, LogCommander):
|
||||
|
||||
def __init__(self, kwargs):
|
||||
|
||||
super(LishCommander, self).__init__()
|
||||
|
|
@ -167,31 +166,44 @@ class LishCommander(Exit, ShellCommander, LogCommander):
|
|||
except KeyboardInterrupt, key:
|
||||
pass
|
||||
|
||||
def complete_hostgroup(self, text, line, begidx, endidx):
|
||||
if begidx == 10:
|
||||
return [x for x in self._hostgroupArgs if x.startswith(text)] if len(text) > 0 else self._hostgroupArgs
|
||||
|
||||
def help_hostgroup(self):
|
||||
print "usage:\n\t" + \
|
||||
"hostgroup list\n\t\t\t" + \
|
||||
"prints a list of all hostgroups\n\t" + \
|
||||
"hostgroup select HOSTGROUPNAME\n\t\t\t" + \
|
||||
"select a hostgroup to make changes on it"
|
||||
|
||||
def do_python(self, text):
|
||||
exec text
|
||||
|
||||
def help_python(self):
|
||||
print "executes python using 'exec'."
|
||||
|
||||
def do_job(self, text):
|
||||
if text == "disable":
|
||||
pass
|
||||
elif text == "enable":
|
||||
pass
|
||||
else:
|
||||
print "invalid or missing parameter\n"
|
||||
self.help_job()
|
||||
|
||||
def help_job(self):
|
||||
print "Job helper functions:\n\t" + \
|
||||
"disable <ID>:\t\tdisable a job\n\t" + \
|
||||
"enable <ID>:\t\tenable a job\n\t"
|
||||
|
||||
def do_jobs(self, text):
|
||||
if text == "list":
|
||||
for job in self._jobs:
|
||||
print job.pretty_string()
|
||||
else:
|
||||
print "invalid or missing parameter\n"
|
||||
self.help_jobs()
|
||||
|
||||
def help_jobs(self):
|
||||
print "Job helper functions"
|
||||
|
||||
def help_python(self):
|
||||
print '''
|
||||
executes python using 'exec'.
|
||||
'''
|
||||
|
||||
def help_hostgroup(self):
|
||||
print '''
|
||||
usage:
|
||||
hostgroup list
|
||||
prints a list of all hostgroups
|
||||
hostgroup select HOSTGROUPNAME
|
||||
select a hostgroup to make changes on it
|
||||
'''
|
||||
|
||||
def complete_hostgroup(self, text, line, begidx, endidx):
|
||||
if begidx == 10:
|
||||
return [x for x in self._hostgroupArgs if x.startswith(text)] if len(text) > 0 else self._hostgroupArgs
|
||||
print "Joblist helper functions:\n\t" + "list:\t\t\tlists all jobs"
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
"""
|
||||
The tcpconnect service. This is to check if a service on a specific port is reachable.
|
||||
The tcpconnect service. This is to check if a TCP service on a specific
|
||||
port is reachable.
|
||||
|
||||
This should just return 0 on success and NOT 0 on error. Just to make internals generic to just report this code and
|
||||
not use a parser.
|
||||
This should just return 0 on success and NOT 0 on error.
|
||||
|
||||
Copyright (c) 2011-2013 "Johannes Findeisen and Rafael Timmerberg"
|
||||
|
||||
|
|
@ -44,21 +44,21 @@ class TcpconnectService(Service):
|
|||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
except socket.error, msg:
|
||||
jobInfo.set_errorcode(2)
|
||||
jobInfo.set_message("[tcpconnect: " + jobInfo.jobHex + "] Could not create socket to host: " + jobInfo.get_host() +
|
||||
" on port: " + str(self.port) + " (" + str(msg) + ")")
|
||||
jobInfo.set_message("[tcpconnect: " + jobInfo.jobHex + "] Could not create socket to host: " +
|
||||
jobInfo.get_host() + " on port: " + str(self.port) + " (" + str(msg) + ")")
|
||||
|
||||
try:
|
||||
sock.connect((jobInfo.get_host(), self.port))
|
||||
except socket.error, msg:
|
||||
jobInfo.set_errorcode(1)
|
||||
jobInfo.set_message("[tcpconnect] Could not establish connection to host: " + jobInfo.get_host() +
|
||||
" on port: " + str(self.port) + " (" + str(msg) + ")")
|
||||
jobInfo.set_message("[tcpconnect: " + jobInfo.jobHex + "] Could not establish connection to host: " +
|
||||
jobInfo.get_host() + " on port: " + str(self.port) + " (" + str(msg) + ")")
|
||||
|
||||
if jobInfo.get_errorcode() == -1:
|
||||
jobInfo.set_execution_successful(True)
|
||||
jobInfo.set_errorcode(0)
|
||||
jobInfo.set_message("[tcpconnect] Connection successful established to host: " + jobInfo.get_host() +
|
||||
" on port: " + str(self.port))
|
||||
jobInfo.set_message("[tcpconnect: " + jobInfo.jobHex + "] Connection successful established to host: " +
|
||||
jobInfo.get_host() + " on port: " + str(self.port))
|
||||
|
||||
sock.close()
|
||||
|
||||
|
|
|
|||
67
linspector/services/udpconnect.py
Normal file
67
linspector/services/udpconnect.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
"""
|
||||
The udpconnect service. This is to check if a UDP service on a specific
|
||||
port is reachable.
|
||||
|
||||
This should just return 0 on success and NOT 0 on error.
|
||||
|
||||
Copyright (c) 2011-2013 "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 <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import socket
|
||||
from linspector.services.service import Service
|
||||
|
||||
|
||||
class UdpconnectService(Service):
|
||||
def __init__(self, **kwargs):
|
||||
super(UdpconnectService, self).__init__(**kwargs)
|
||||
|
||||
args = self.get_arguments()
|
||||
if "port" in args:
|
||||
self.port = args["port"]
|
||||
else:
|
||||
raise Exception("There is no port set")
|
||||
|
||||
def needs_arguments(self):
|
||||
return True
|
||||
|
||||
def execute(self, jobInfo):
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
except socket.error, msg:
|
||||
jobInfo.set_errorcode(2)
|
||||
jobInfo.set_message("[udpconnect: " + jobInfo.jobHex + "] Could not create socket to host: " +
|
||||
jobInfo.get_host() + " on port: " + str(self.port) + " (" + str(msg) + ")")
|
||||
|
||||
try:
|
||||
sock.connect((jobInfo.get_host(), self.port))
|
||||
except socket.error, msg:
|
||||
jobInfo.set_errorcode(1)
|
||||
jobInfo.set_message("[udpconnect: " + jobInfo.jobHex + "] Could not establish connection to host: " +
|
||||
jobInfo.get_host() + " on port: " + str(self.port) + " (" + str(msg) + ")")
|
||||
|
||||
if jobInfo.get_errorcode() == -1:
|
||||
jobInfo.set_execution_successful(True)
|
||||
jobInfo.set_errorcode(0)
|
||||
jobInfo.set_message("[udpconnect: " + jobInfo.jobHex + "] Connection successful established to host: " +
|
||||
jobInfo.get_host() + " on port: " + str(self.port))
|
||||
|
||||
sock.close()
|
||||
|
||||
|
||||
def create(kwargs):
|
||||
return UdpconnectService(**kwargs)
|
||||
Loading…
Add table
Add a link
Reference in a new issue