From 427ab39aa51a21e3e0443a2b02c19929c9e2f60b Mon Sep 17 00:00:00 2001 From: Edileuton Henrique de Oliveira <eho09@c3sl.ufpr.br> Date: Thu, 27 Feb 2014 10:17:23 -0300 Subject: [PATCH] Add net usage monitor to the Windows agent Signed-off-by: Edileuton Henrique de Oliveira <eho09@c3sl.ufpr.br> --- windows-collect/Makefile | 5 +- windows-collect/src/collect.py | 61 ++++++++--- windows-collect/src/netmon/compileNetmon.py | 5 + windows-collect/src/netmon/netmon.py | 109 ++++++++++++++++++++ windows-collect/src/proinfodataAgent.py | 46 +++++++-- windows-installer/src/installer.nsi | 16 +++ 6 files changed, 220 insertions(+), 22 deletions(-) create mode 100644 windows-collect/src/netmon/compileNetmon.py create mode 100644 windows-collect/src/netmon/netmon.py diff --git a/windows-collect/Makefile b/windows-collect/Makefile index a47b11a..abc2705 100644 --- a/windows-collect/Makefile +++ b/windows-collect/Makefile @@ -1,2 +1,5 @@ -all: src/compile.py src/proinfodataAgent.py src/collect.py +all: netmon.py src/compile.py src/proinfodataAgent.py src/collect.py @cd src/ && wine ~/.wine/drive_c/Python27/python compile.py py2exe + +netmon.py: + @cd src/netmon && wine ~/.wine/drive_c/Python27/python compileNetmon.py py2exe \ No newline at end of file diff --git a/windows-collect/src/collect.py b/windows-collect/src/collect.py index 5de4b19..33b2211 100644 --- a/windows-collect/src/collect.py +++ b/windows-collect/src/collect.py @@ -25,7 +25,12 @@ import ctypes import wmi import socket import struct +import glob from xml.etree.ElementTree import Element, SubElement, Comment, tostring +from datetime import timedelta, date, datetime + +PROINFODATAPATH = os.environ["ProgramFiles"] + "\\ProInfoData" +PREVIOUSPATH = PROINFODATAPATH + "\\data\\previous" # Return the value from key/subkey in windows registry def getRegistryValue(key, subkey, value): @@ -226,17 +231,47 @@ def netCollect(): tagUse = SubElement(mainTag, 'use') tagUseBandUsage = SubElement(tagUse, 'bandwidth-usage', {'type':'tree'}) - for i in range(1, 289): - tagNetUse = SubElement(tagUseBandUsage, 'netuse', {'id':str(i)}) - tagDate = SubElement(tagNetUse, 'date', {'value':'0001-01-01', 'type':'string'}) - tagTime = SubElement(tagNetUse, 'time', {'value':'0:0', 'type':'string'}) - - tagRx = SubElement(tagNetUse, 'rx') - tagPackets = SubElement(tagRx, 'packets', {'value':"0", 'type':'int'}) - tagBytes = SubElement(tagRx, 'bytes', {'value':"0", 'type':'int'}) - - tagTx = SubElement(tagNetUse, 'tx') - tagPackets = SubElement(tagTx, 'packets', {'value':"0", 'type':'int'}) - tagBytes = SubElement(tagTx, 'bytes', {'value':"0", 'type':'int'}) - + # Collect network usage + for t in glob.glob(PREVIOUSPATH + "\\*"): + traffic = file(t, "r") + trafficDate = traffic.readline().split("\n")[0] + dateTmp = datetime.strptime(trafficDate, '%Y-%m-%d') + intervalIdOld, rxPackageOld, rxBytesOld, txPackageOld, txBytesOld = traffic.readline().split("\n")[0].split(" ") + if dateTmp >= datetime.now() - timedelta(days=15): + for line in traffic: + + intervalId, rxPackageAux, rxBytesAux, txPackageAux, txBytesAux = line.split(" ") + txBytesAux = txBytesAux.split("\n")[0] + rxPackage = int(rxPackageAux) - int(rxPackageOld) + rxBytes = int(rxBytesAux) - int(rxBytesOld) + txPackage = int(txPackageAux) - int(txPackageOld) + txBytes = int(txBytesAux) - int(txBytesOld) + + if rxBytes >= 0 and txBytes >= 0: + # Since we want the mean time between the five minutes intervals, + # the minute counter starts at 2 and gets 5 minutes increments. + # Also the "seconds counter" is fixed at 30. So we always get + # something like HH:2:30 or HH:7:30 (mean times). + # + # Example: if interval = 10:15~10:20 => mean = 10:17:30 + intervalId = int(intervalId) + 1 + trafficTime = timedelta(minutes=intervalId * 5 - 3) + timedelta(seconds=30) + + tagNetUse = SubElement(tagUseBandUsage, 'netuse', {'id':str(intervalId)}) + tagDate = SubElement(tagNetUse, 'date', {'value':trafficDate, 'type':'string'}) + tagTime = SubElement(tagNetUse, 'time', {'value':str(trafficTime), 'type':'string'}) + + tagRx = SubElement(tagNetUse, 'rx') + tagPackets = SubElement(tagRx, 'packets', {'value':str(rxPackage), 'type':'int'}) + tagBytes = SubElement(tagRx, 'bytes', {'value':str(rxBytes), 'type':'int'}) + + tagTx = SubElement(tagNetUse, 'tx') + tagPackets = SubElement(tagTx, 'packets', {'value':str(txPackage), 'type':'int'}) + tagBytes = SubElement(tagTx, 'bytes', {'value':str(txBytes), 'type':'int'}) + + intervalIdOld, rxPackageOld, rxBytesOld, txPackageOld, txBytesOld = intervalId, rxPackageAux, rxBytesAux, txPackageAux, txBytesAux + traffic.close() + else: + traffic.close() + os.remove(t) return mainTag diff --git a/windows-collect/src/netmon/compileNetmon.py b/windows-collect/src/netmon/compileNetmon.py new file mode 100644 index 0000000..f556790 --- /dev/null +++ b/windows-collect/src/netmon/compileNetmon.py @@ -0,0 +1,5 @@ +#coding: utf-8 +from distutils.core import setup +import py2exe + +setup(console=['netmon.py'], options={"py2exe":{"dll_excludes":[ "mswsock.dll", "powrprof.dll" ]}}) diff --git a/windows-collect/src/netmon/netmon.py b/windows-collect/src/netmon/netmon.py new file mode 100644 index 0000000..66f1ca0 --- /dev/null +++ b/windows-collect/src/netmon/netmon.py @@ -0,0 +1,109 @@ +# Copyright (C) 2013 Centro de Computacao Cientifica e Software Livre +# Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR +# +# This file is part of datasid +# +# windows-coleta is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +#coding: utf-8 +import os +import sys +import shutil +import subprocess +import re +from datetime import date, timedelta, datetime + +PROINFODATAPATH = os.environ["ProgramFiles"] + "\\ProInfoData" +PREVIOUSPATH = PROINFODATAPATH + "\\data\\previous" +TRAFFICPATH = PROINFODATAPATH + "\\data\\traffic.txt" + +# Get the network traffic from the current day +def getTraffic(): + # Uses netstat command to get the net usage + res = subprocess.Popen(["netstat", "-e"], shell=True, stdout=subprocess.PIPE).communicate()[0] + bytesLine = res.splitlines()[4] + unicastPackagesLine = res.splitlines()[5] + packagesLine = res.splitlines()[6] + + # Get the amount of bytes received and transmited + rxBytes = re.split(" +", bytesLine)[-2] + txBytes = re.split(" +", bytesLine)[-1] + + # Get the amount of packages received and transmited + rxPackages = int(re.split(" +", unicastPackagesLine)[-2]) + int(re.split(" +", packagesLine)[-2]) + txPackages = int(re.split(" +", unicastPackagesLine)[-1]) + int(re.split(" +", packagesLine)[-1]) + + return rxBytes, str(rxPackages), txBytes, str(txPackages) + +# Get a number identifying the current five minutes interval +def getIntervalId( ): + # Get a number identifying the current five minutes interval + intervalId = int(datetime.now().strftime("%H")) * 12 + (int(datetime.now().strftime("%M")) / 5 + 0.5) - 1 + # INTERVALID equal to -1 means midnight 00:00, but midnight needs + # to be the last id possible, so force it to 287 + if intervalId == -1: + intervalId = 287 + + return int(intervalId) + +# Get the traffic file +def getTrafficFile(currentDate): + trafficDate = "" + + # If there is no TRAFFIC (probably its the first run), then just create a + # new one. + try: + trafficFile = file(TRAFFICPATH, "r+") + trafficDate = trafficFile.readline() + trafficFile.seek(0, os.SEEK_END) + except IOError: + trafficFile = file(TRAFFICPATH, "w+") + trafficFile.write(currentDate + "\n") + return trafficFile + + # Finally, create a new TRAFFIC (keeping the previous one as + # PREVIOUS_TRAFFIC) if the dates doesnt match. + if trafficDate.find(currentDate) == -1: + if not os.path.exists(PREVIOUSPATH): + os.makedirs(PREVIOUSPATH) + trafficFile.close() + shutil.copy2(TRAFFICPATH, PREVIOUSPATH + "\\traffic-" + currentDate + ".txt") + trafficFile = file(TRAFFICPATH, "w+") + trafficFile.write(currentDate + "\n") + + return trafficFile + +# ========================================== +# Main program +# ========================================== + +try: + rxBytes, rxPackages, txBytes, txPackages = getTraffic() + intervalId = getIntervalId() + + # If it midnight (INTERVALID = 287), then consider current date as + # yesterday (subtract one day from current date). Thats because the + # data collect belongs to an interval beginning yesterday 23:55 and + # only ending today, at midnight. + if intervalId == 287: + currentDate = date.today() - timedelta(days=1) + else: + currentDate = date.today() + trafficFile = getTrafficFile(currentDate.strftime("%Y-%m-%d")) + trafficFile.write(str(intervalId)+ " " + rxPackages + " " + rxBytes + " " + txPackages + " " + txBytes +"\n") + trafficFile.close() +except: + sys.exit(1) diff --git a/windows-collect/src/proinfodataAgent.py b/windows-collect/src/proinfodataAgent.py index c021b9a..663ed6e 100644 --- a/windows-collect/src/proinfodataAgent.py +++ b/windows-collect/src/proinfodataAgent.py @@ -35,6 +35,7 @@ import glob # ========================================== # TODO: Check compatibility with 64bit Windows (Program Files(x86) folder) PROINFODATAPATH = os.environ["ProgramFiles"] + "\\ProInfoData" +PREVIOUSPATH = PROINFODATAPATH + "\\data\\previous" URL = "http://200.17.202.187/tomcat/axis/Seed2.jws" # Log lifetime in days LOGLIFETIME = 30 @@ -153,8 +154,8 @@ def deleteOldLogs(): os.remove(infile) # Send the collect-data.xml -def sendData(): - args = " --inventory --url=" + URL + " --inep=" + inep +def sendData(option, xmlFile): + args = option + " --url=" + URL + " --inep=" + inep (phost, pport, puser, ppass) = getProxyInfo() if phost != "": @@ -170,8 +171,8 @@ def sendData(): return 0 # Create collect-data.xml file -def writeCollectData(collectData): - collectDataFile = file(PROINFODATAPATH + "\\data\\collect-data.xml", "w") +def writeCollectData(collectData, xmlName): + collectDataFile = file(PROINFODATAPATH + "\\data\\" + xmlName, "w") collectDataFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") collectDataFile.write(tostring(collectData)) collectDataFile.close() @@ -280,7 +281,7 @@ except: # Write the collect-data.xml file try: - writeCollectData(collectData) + writeCollectData(collectData, "collect-data.xml") except: log.write("ERROR(9): Failed to write collect-data.xml.") log.close() @@ -288,17 +289,46 @@ except: # Send data try: - sendData() + sendData(" --inventory", "collect-data.xml") except clientError, e: log.write("ERROR(10): Failed to send data. Client returned " + str(e.code) + ".") log.write("Client message: " + str(e.errorMsg)) log.close() sys.exit(10) -except: - log.write("ERROR(11): Failed to get the proxy information from Windows registry.") +except Exception, e: + log.write("ERROR(11): " + str(e)) log.close() sys.exit(11) +# Collect net usage +if os.path.isdir(PREVIOUSPATH): + try: + netCollectData = collect.netCollect() + except Exception, e: + log.write("ERROR(12): Failed to collect net usage: " + str(e)) + log.close() + sys.exit(12) + # Write the collect-data.xml file + try: + writeCollectData(netCollectData, "network-data.xml") + except: + log.write("ERROR(13): Failed to write net-collect-data.xml.") + log.close() + sys.exit(13) + + try: + sendData(" --net-usage ", "network-data.xml") + shutil.rmtree(PREVIOUSPATH) + except clientError, e: + log.write("ERROR(10): Failed to send net usage data. Client returned " + str(e.code) + ".") + log.write("Client message: " + str(e.errorMsg)) + log.close() + sys.exit(10) + except Exception, e: + log.write("ERROR(14): " + str(e)) + log.close() + sys.exit(14) + # If everything ran ok, exit with success status log.write("EXIT(0): Success.") log.close() diff --git a/windows-installer/src/installer.nsi b/windows-installer/src/installer.nsi index af42ba2..7cb32e9 100644 --- a/windows-installer/src/installer.nsi +++ b/windows-installer/src/installer.nsi @@ -33,6 +33,7 @@ Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" !define PRODUCT_UNINST_NAME "Desinstalar ${PRODUCT_NAME}" !define PRODUCT_TASK "$PROGRAMFILES\${PRODUCT_NAME}\bin\agent\proinfodataAgent.exe" +!define NETMON_TASK "$PROGRAMFILES\${PRODUCT_NAME}\bin\agent\netmon.exe" !define MUI_FINISHPAGE_NOAUTOCLOSE SetCompressor bzip2 @@ -125,6 +126,11 @@ Function .onInit DetailPrint "Killing all processes called '$0'" KillProc::KillProcesses + ;Kill datasidAgent.exe process + StrCpy $0 "netmon.exe" + DetailPrint "Killing all processes called '$0'" + KillProc::KillProcesses + ;Verify if INEP exists in Windows registry ClearErrors ReadRegStr $R2 HKLM "SOFTWARE\${PRODUCT_NAME}" "INEP" @@ -161,6 +167,11 @@ Section "SeçãoPrincipal" SEC01 /TR $\"\$\"${PRODUCT_TASK}$\"\$\" /RU System /F" Pop $R2 + ;Add net monitoring task in Windows task scheduler + nsExec::Exec "schtasks /Create /SC MINUTE /MO 5 /TN ProinfodataNetMon \ + /TR $\"\$\"${NETMON_TASK}$\"\$\" /RU System /F" + Pop $R2 + File "..\COPYING" CreateDirectory "$INSTDIR\conf" CreateDirectory "$INSTDIR\data" @@ -180,6 +191,7 @@ Section "SeçãoPrincipal" SEC01 File "..\..\windows-collect\src\dist\library.zip" ;File "..\..\windows-collect\src\dist\powrprof.dll" File "..\..\windows-collect\src\dist\proinfodataAgent.exe" + File "..\..\windows-collect\src\netmon\dist\netmon.exe" File "..\..\windows-collect\src\dist\pyexpat.pyd" File "..\..\windows-collect\src\dist\python27.dll" File "..\..\windows-collect\src\dist\pythoncom27.dll" @@ -278,5 +290,9 @@ Section Uninstall nsExec::Exec "schtasks /Delete /TN ProinfodataAgent /F" Pop $R2 + ;Delete scheduled task + nsExec::Exec "schtasks /Delete /TN ProinfodataNetMon /F" + Pop $R2 + SetAutoClose true SectionEnd -- GitLab