here a more complete python program that reads the syslog file and the AP-dict i.e.:
1. init parameters :userid, setup dirs .
2. create threads for each AP that will read the syslogfiles on each AP
3. check if every this is running and restart if needed, e.g. if you restart an AP the listener has to be restarted too.
4. get the "dict" with the more static data once every xx seconds.
5. two methods for logfile and dict that print the data. These you should modify to do something with it.
I indicated which part should go where in a plugin.
Three programs are attached.
1. the main python program, (unfiread.py) ===> replace userid, password and IP numbers of your APs
2. expect program to get the syslog (exec.exp)
3. expect program to get the dict (getDict.exp)
change these lines in unifiread.py to your environment
- Code: Select all
unifiUserID = "xxx" ## unifi AP userid
unifiPassWd = "xxx" ## unifi AP password
ipNumbersOfAPs = ["192.168.1.x","192.168.1.x","192.168.1.x"] ## one ip # for each ap, add/delete if you have more.less AP than 3
APsEnabled = [0,1,2] ## which of the above are enabled
these files must go to ~ /documents/unifi
then open terminal,
cd ~/documents/unifi
python unifiread.py
and you should see the output on your screen.
Karl
================================
readunifi.py:
- Code: Select all
###
# read unifi Ap data
# Karl Wachs may 30
# use as you see fit.
###
import subprocess
import fcntl
import os
import sys
import pwd
import time
import Queue
import signal
import threading
import copy
import json
### setup CTRL reaction
def Exit_gracefully(signal, frame):
global stopCTRLC
print "CTRL-C pressed"
stopCTRLC = True
### start the expect command to get the logfile
def startConnect(ipNumber):
global unifiUserID, unifiPassWd, listLogFileCommand
for ii in range(20):
cmd="/usr/bin/expect "+unifiPath+"exec.exp "+unifiUserID+" "+unifiPassWd+" "+ipNumber+" "+listLogFileCommand
pOpen = subprocess.Popen(cmd,stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
##pid = pOpen.pid
##print " pid= ", pid
msg = unicode(pOpen.stderr)
if msg.find("[Err ") > -1: # try this again
print " error connecting ", msg
time.sleep(20)
continue
# set the O_NONBLOCK flag of pOpen.stdout file descriptor:
flags = fcntl.fcntl(pOpen.stdout, fcntl.F_GETFL) # get current p.stdout flags
fcntl.fcntl(pOpen.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
return pOpen,""
### kill expect pids if running
def killIfRunning(ipNumber):
ret = subprocess.Popen("ps -ef | grep "+ipNumber+ " | grep /usr/bin/expect | grep -v grep" ,stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True).communicate()[0]
if len(ret) < 5:
return
lines = ret.split("\n")
for line in lines:
if len(line) < 5:
continue
items = line.split()
if len(items) < 5:
continue
pid = items[1]
try:
ipid = int(pid)
ret = subprocess.Popen("/bin/kill -9 "+pid,stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True).communicate()
print u"killing ip#, pid# ", ipNumber, pid
continue
except:
pass
### test if AP are up, first ping then check if expect is running
def testAPandPing(ipNumber,pOpen):
print "testing if "+ ipNumber +" pid "+ str(pOpen.pid)+" is running "
if testPing(ipNumber) !=0: return False
ret = subprocess.Popen("ps -ef | grep "+str(pOpen.pid)+ " | grep /usr/bin/expect | grep -v grep" ,stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True).communicate()[0]
if len(ret) < 5: False
lines= ret.split("\n")
for line in lines:
if len(line) < 5:
continue
##print line
items = line.split()
if len(items) < 5:
continue
if items[1] != str(pOpen.pid):
continue
if line.find("expect") > -1:
#print "expect found ", line
return True
return False
### do the ping test
def testPing( ipNumber):
try:
ret = os.system("/sbin/ping -c 4 -W 1 -o " + ipNumber +">/dev/null ") # send max 4 packets, wait 0.5 secs between each and if one gets back stop
if int(ret) ==0:
return 0
print u" ping return-code not 0: " + unicode(ret)
time.sleep(2)
ret = os.system("/sbin/ping -c 4 -W 1 -o " + ipNumber +">/dev/null ")
if int(ret) ==0:
return 0
print u" ping return-code not 0: " + unicode(ret)
return 1
except Exception, e:
print u"in Line '%s' has error='%s'" % (sys.exc_traceback.tb_lineno, e)
return 1
### here we do the work, setup the logfiles listening and read the logfiles and check if everything is running, if not restart
def getMessages(ipNumber):
global stop, connectPids, stopCTRLC, unifiUserID, unifiPassWd, ipNumbersOfAPs, listLogFileCommand, unifiPath,restartIfNoMessageSeconds, verifyUpEverySeconds, stop, stopCTRLC, logQueue, loopCounterRestart, APsEnabled
loopCounter=0
## print "launching " + ipNumber
pOpen, msg = startConnect(ipNumber)
if msg !="":
print " fatal error, connect for ip#: " + ipNumber
return
lastTest = time.time()
lastForcedRestart = time.time()
#### for ever, until stop is set
while True:
time.sleep(0.1)
tt= time.time()
## time to verify if every is still running?
if (tt - lastTest) > verifyUpEverySeconds:
lastTest = time.time()
if not testAPandPing(ipNumber, pOpen):
killIfRunning(ipNumber)
pOpen, msg = startConnect(ipNumber)
## force restart after xx seconds no matter what?
if (tt - lastForcedRestart) > restartIfNoMessageSeconds:
print "AP# " + ipNumber + " forcing restart of msg after " + str(int(time.time() - lastForcedRestart)) + " sec without message"
lastForcedRestart = time.time()
lastTest = time.time()
killIfRunning(ipNumber)
pOpen, msg = startConnect(ipNumber)
## should we stop?, is our IP number listed?
if ipNumber in stop:
print " stop in getMessage stop=True"
#pOpen.close()
return
while stop.count(ipNumber) > 0:
stopremove(ipNumber)
## here we actually read the stuff
try:
r= os.read(pOpen.stdout.fileno(), 20000)
except Exception, e:
if unicode(e).find("[Errno 35]") ==-1: # "Errno 35" is the normal response if no data, if other error: exit
print "error", e
#pOpen.close()
stop.append(ipNumber)
continue
## did we get anything?
if r !="":
## any error messages from OSX?
if (
r.find("closed by remote host") >-1 or
r.find("Killed by signal") >-1 ):
print " returning " +ipNumber + " " +unicode(r)
killIfRunning(ipNumber)
pOpen, msg = startConnect(ipNumber)
continue
lastForcedRestart = time.time()
## fill the queue and send to the method that uses it
logQueue.put((ipNumber,r))
doSomethingWithLog() ##################### here we call method to do something with the data
## loop counter, test if we should restart litening
loopCounter +=1
if loopCounter > loopCounterRestart:
lastForcedRestart = 0
loopCounter = 0
print "AP# " +ipNumber+" forcing restart of msg after "+ str(ccc) +" loops"
### get the dict from the APs
def getapDict(ipNumber):
global unifiUserID, unifiPassWd, listDictCommand, unifiPath
ret= subprocess.Popen("/usr/bin/expect "+unifiPath+"getDict.exp "+unifiUserID+" "+unifiPassWd+" "+ipNumber+" "+listDictCommand,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
firstTag = "# mca-dump \r\n"
lastTag = "}\r\nBZ."
apDict = {}
y = ret[0].split(firstTag)
if len(y) !=2:
errorMsg = "bad data, first tag not found"
else:
z = y[1].split(lastTag)
if len(z) !=2:
errorMsg = "bad data, last tag not found"
else:
try:
apDict=json.loads(z[0]+"}")
except:
print " error encoding json for " +z[0][0:100]
return apDict
####### for the logfile this you should replace if you want to do something with it
def doSomethingWithLog():
global logQueue
while not logQueue.empty():
item = logQueue.get()
print "\n> from: " + unicode(item[0])
lines= item[1].split("\r\n")
for line in lines:
if len(line) < 2: continue
if line.find("spawn ssh") > -1: ## this is command output, can be ignored
print "---- "+line
elif line.find("'s password:") > -1: ## this is command output, can be ignored
print "---- "+line
elif line.find("BusyBox v") > -1: ## this is command output, can be ignored
print "---- "+line
elif line.find("Enter 'help' for a list of built-in commands.") > -1: ## this is command output, can be ignored
print "---- "+line
elif line.find("BZ.")==0: ## this is command output, can be ignored
print "---- "+line
elif line.find(listLogFileCommand) > -1: ## this is command output, can be ignored
print line
##### this is the real daata
else:
print ">>>> "+ line
logQueue.task_done()
### for the dict, replace with something useful
def doSomethingWithDict(apDict):
print ">>>> Dict" + unicode(apDict)[0:100]+"...."
return
### init parameters, .. this should go to def startup(self):
def initMain():
global stop, connectPids, stopCTRLC, unifiUserID, unifiPassWd, ipNumbersOfAPs, listLogFileCommand, listDictCommand, unifiPath,restartIfNoMessageSeconds, verifyUpEverySeconds,readDictEverySeconds, stop, stopCTRLC, logQueue, loopCounterRestart, APsEnabled
######################################################################################################################
######################## set parameters #########################################################################
######################################################################################################################
unifiUserID = "xxx" ## unifi AP userid
unifiPassWd = "xxx" ## unifi AP password
ipNumbersOfAPs = ["192.168.1.x","192.168.1.x","192.168.1.x"] ## one ip # for each ap
APsEnabled = [0,1,2] ## which of the above are enabled
listLogFileCommand = "'/usr/bin/tail -f /var/log/messages'" ## this is the command send to AP to get the logfile
listDictCommand = "mca-dump" ## this is the command to get the dict from each AP
restartIfNoMessageSeconds = 500 ## #of seconds without any msg do a restart expect listen
verifyUpEverySeconds = 20 ## do a ping and check if expect is still running every xx seconds
loopCounterRestart = 1000000 ## force getmsg restart after n loops , just a safety net
readDictEverySeconds = 120 ##
######################################################################################################################
######################## set parameters end #####################################################################
######################################################################################################################
MACuserName = pwd.getpwuid( os.getuid() )[ 0 ]
MAChome = os.path.expanduser("~")
unifiPath = MAChome+"/documents/unifi/"
print unifiPath
ret = subprocess.Popen("mkdir "+unifiPath+" > /dev/null 2>&1 &",shell=True)
stop = []
stopCTRLC = False
logQueue= Queue.Queue()
signal.signal(signal.SIGINT, Exit_gracefully)
for ll in range(len(ipNumbersOfAPs)):
killIfRunning(ipNumbersOfAPs[ll])
### main routine that starts things, this should go to def runConcurrentThread(self):
def _main():
global stop, connectPids, stopCTRLC, readDictEverySeconds, unifiUserID, unifiPassWd, ipNumbersOfAPs, listLogFileCommand, unifiPath,restartIfNoMessageSeconds, verifyUpEverySeconds, stop, stopCTRLC, logQueue, loopCounterRestart, APsEnabled
initMain()
apDict={}
########### set up threads ########
try:
tr=[]
for ll in range(len(APsEnabled)):
ipn = ipNumbersOfAPs[APsEnabled[ll]]
tr.append(threading.Thread(name='getMessages', target=getMessages,args=(ipn,)))
tr[ll].start()
time.sleep(3)
lastTimeDictRead =0
ddd=0
except Exception, e:
print u"in Line '%s' has error='%s'" % (sys.exc_traceback.tb_lineno, e)
stop = copy.copy(ipNumbersOfAPs)
return
########### loop for get dict and to stop if requested #####
try:
while True:
if time.time() - lastTimeDictRead > readDictEverySeconds:
lastTimeDictRead = time.time()
for ll in range(len(APsEnabled)):
## print " getting dict for #", ll
apDict[str(ll)] = getapDict(ipNumbersOfAPs[APsEnabled[ll]])
doSomethingWithDict(apDict) ## <--------- here we should do something with the dict
if stopCTRLC:
stop = copy.copy(ipNumbersOfAPs)
print " in loop stop= ", stop
ddd +=1
if ddd> 300000 or stop == ipNumbersOfAPs: # safety to just stop after 30k seconds
print "stop in main " + str(ddd)
stop= copy.copy(ipNumbersOfAPs)
time.sleep(1)
for ll in range(len(APsEnabled)):
tr[ll].join()
return
time.sleep(1)
except Exception, e:
print u"in Line '%s' has error='%s'" % (sys.exc_traceback.tb_lineno, e)
stop = copy.copy(ipNumbersOfAPs)
time.sleep(2)
_main()
exit()
exec.exp:
- Code: Select all
set userID [lindex $argv 0 ]
set password [lindex $argv 1 ]
set ipNumber [lindex $argv 2 ]
set cmd [lindex $argv 3]
set timeout 15
spawn ssh $userID@$ipNumber
expect {
"assword:" {
exp_send -- "$password\r"
}
}
expect "BZ." {
send $cmd\r\n
interact
}
getDict.exp:
- Code: Select all
set userID [lindex $argv 0 ]
set password [lindex $argv 1 ]
set ipNumber [lindex $argv 2 ]
set cmd [lindex $argv 3]
set timeout 15
spawn -noecho ssh $userID@$ipNumber
expect {
"assword:" {
exp_send -- "$password\r"
}
}
expect "BZ." {
expect "#"
sleep 0.1
send "$cmd \r"
}
expect "BZ." {}
set timeout 0.1
expect eof