- basics of init-script working

- basic shell script which enables virtualenv environment and calls traceroute.py at intervals
- added stubs to only call webhook based on a specified latency
- still need to store offline data in redis - coming soon
This commit is contained in:
Brian Martin 2015-07-27 22:40:40 -04:00
commit ffd8158c25
4 changed files with 152 additions and 7 deletions

View file

@ -7,6 +7,7 @@ Multi-source traceroute with geolocation information. Demo: [IP Address Lookup](
1. Install dependencies listed in requirements.txt file. Pip is recommended. You could also use virtualenv to keep things isolated.
2. Save traceroute.py into a directory with its path stored in your PYTHONPATH environment variable. (if using virtualenv, copy it here)
3. Install Redis-Server ( may change )
## Usage

64
init-script/traceroute Normal file
View file

@ -0,0 +1,64 @@
#!/bin/bash
# traceroute.py daemon
# chkconfig: 345 20 80
# description: traceroute.py daemon
# processname: traceroute.py
DAEMON_PATH="/var/lib/python/traceroute"
DAEMON=traceroute.sh
DAEMONOPTS=""
NAME=traceroute.py
DESC="Traceroute Python Tool"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
case "$1" in
start)
printf "%-50s" "Starting $NAME..."
cd $DAEMON_PATH
PID=`$DAEMON $DAEMONOPTS > /dev/null 2>&1 & echo $!`
#echo "Saving PID" $PID " to " $PIDFILE
if [ -z $PID ]; then
printf "%s\n" "Fail"
else
echo $PID > $PIDFILE
printf "%s\n" "Ok"
fi
;;
status)
printf "%-50s" "Checking $NAME..."
if [ -f $PIDFILE ]; then
PID=`cat $PIDFILE`
if [ -z "`ps axf | grep ${PID} | grep -v grep`" ]; then
printf "%s\n" "Process dead but pidfile exists"
else
echo "Running"
fi
else
printf "%s\n" "Service not running"
fi
;;
stop)
printf "%-50s" "Stopping $NAME"
PID=`cat $PIDFILE`
cd $DAEMON_PATH
if [ -f $PIDFILE ]; then
kill -HUP $PID
printf "%s\n" "Ok"
rm -f $PIDFILE
else
printf "%s\n" "pidfile not found"
fi
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {status|start|stop|restart}"
exit 1
esac

19
init-script/traceroute.sh Executable file
View file

@ -0,0 +1,19 @@
#!/bin/bash
EXEC_DIR=/var/lib/python/traceroute
VIRTUALENV_DIR=/var/lib/python/traceroute/env
# Repeat every 5 seconds
INTERVAL=5 #
source $VIRTUALENV_DIR/bin/activate
cd $EXEC_DIR
# TODO add some logging later
while true;
do
python ./traceroute.py --ip_address=8.8.8.8 -c LO --webhook=http://localhost:8081/test;
sleep $INTERVAL;
done

View file

@ -27,7 +27,7 @@ class Traceroute(object):
Multi-source traceroute instance.
"""
def __init__(self, ip_address, source=None, country="US", tmp_dir="/tmp",
no_geo=False, timeout=120, debug=False):
no_geo=False, timeout=120, debug=False, max_latency=5):
super(Traceroute, self).__init__()
self.ip_address = ip_address
self.source = source
@ -37,6 +37,9 @@ class Traceroute(object):
self.source = sources[country]
self.tmp_dir = tmp_dir
self.LATENCY_THRESHOLD = float(max_latency)
self.no_geo = no_geo
self.timeout = timeout
self.debug = debug
@ -44,6 +47,9 @@ class Traceroute(object):
self.hops = {}
self.country = country
# flag to determine if webhook alert is warranted
self.latency_exceeded = False
# Localhost Specific operations happen here
if self.country == 'LO':
self.local_mode = True
@ -59,6 +65,11 @@ class Traceroute(object):
self.__run_traceroute()
self.probe_end = time.time() * 1000
def pingLatencyThresholdExceeded(self):
"""public method to query state of Traceroute calls"""
return self.latency_exceeded
def __run_traceroute(self):
"""
Instead of running the actual traceroute command, we will fetch
@ -134,6 +145,7 @@ class Traceroute(object):
hop_element_pattern = '([\d\w.-]+)\s+\((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\)\s+(\d+\.\d+ ms)'
hp = re.compile(hop_element_pattern)
alertTriggered = False
for entry in traceroute.split('\n'):
entry = entry.strip()
result = re.match(hop_pattern,entry)
@ -146,9 +158,17 @@ class Traceroute(object):
hop_hosts = re.findall(host_pattern, hop['hosts'])
self.hops[hop_num] = []
for host in hop_hosts:
m = hp.search(host)
(hostname, ip, ping_time) = m.groups()
# Check ping time to see if it exceeds threshold. Once one is found, don't need any more info from other hops
if alertTriggered is False:
if self._exceeds_hop_latency(ping_time):
self.latency_exceeded = True
alertTriggered = True
if self.no_geo:
self.hops[hop_num].append(
{
@ -207,6 +227,15 @@ class Traceroute(object):
if 'latitude' in tmp_location and 'longitude' in tmp_location:
location = tmp_location
return location
def _exceeds_hop_latency(self,ping_time):
"""return true if hop time exceeds specified latency threshold"""
# remote ' ms' from ping time
ping_as_float = float(ping_time.replace(" ms",""))
return ping_as_float >= self.LATENCY_THRESHOLD
def execute_cmd(self, cmd):
"""
@ -360,6 +389,18 @@ def post_result(webhook_url, report, timeout=120):
"""
return requests.post(webhook_url, data=json.dumps(report), timeout=timeout)
def webhook_available(webhook_url):
"""
Function to check if a webhook host is responding.
Not 100% sure this will work...
"""
try:
data = urllib.urlopen(webhook_url)
return True
except Exception,e:
return False
def main():
cmdparser = optparse.OptionParser("%prog --ip_address=IP_ADDRESS")
@ -393,6 +434,11 @@ def main():
cmdparser.add_option(
"-w", "--webhook", type="string", default="",
help="Specify URL to POST report payload rather than stdout")
cmdparser.add_option(
"--max_latency", type="int", default="5",
help="Maximum latency whereby the system will trigger the webhook ( if requested ). ")
options, _ = cmdparser.parse_args()
json_file = open(options.json_file, "r").read()
@ -406,17 +452,32 @@ def main():
tmp_dir=options.tmp_dir,
no_geo=options.no_geo,
timeout=options.timeout,
debug=options.debug)
debug=options.debug, max_latency = options.max_latency)
# pull complete report -> Hop data plus meta info about the network
report = traceroute.get_report()
if options.webhook != "":
try:
result = post_result(options.webhook, report, options.timeout)
print "Webhook POST Result: {}".format(result)
except Exception,e:
print "Provided webhook {0} is invalid. Message was: {1}".format(options.webhook, e)
# check if remote host is available
if webhook_available(options.webhook):
# if available, check if there are any outstanding reports that should be sent
# if traceroute::backlog == true => Purge results
if traceroute.pingLatencyThresholdExceeded():
try:
result = post_result(options.webhook, report, options.timeout)
print "Webhook POST Result: {}".format(result)
except Exception,e:
print "Provided webhook {0} is invalid. Message was: {1}".format(options.webhook, e)
else:
print "Webhook unavailable, caching"
pass
# Dump Result into Redis
# Set redis flag traceroute::backlog => true
else:
print(json.dumps(report, indent=4))
return 0