[Oval-commits] r382 - trunk/oval-infrastructure/src

Pavel Vinogradov blaze-guest at alioth.debian.org
Tue Sep 23 17:41:39 UTC 2008


Author: blaze-guest
Date: 2008-09-23 17:41:39 +0000 (Tue, 23 Sep 2008)
New Revision: 382

Added:
   trunk/oval-infrastructure/src/dba.py
   trunk/oval-infrastructure/src/manager.py
   trunk/oval-infrastructure/src/oval-server.db
   trunk/oval-infrastructure/src/reporter.py
Log:
Merge oval-monitor

Copied: trunk/oval-infrastructure/src/dba.py (from rev 379, trunk/oval-monitor/dba.py)
===================================================================
--- trunk/oval-infrastructure/src/dba.py	                        (rev 0)
+++ trunk/oval-infrastructure/src/dba.py	2008-09-23 17:41:39 UTC (rev 382)
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+# 
+# Written by Pavel Vinogradov <Pavel.Vinogradov at nixdev.net>
+# Licensed under the GNU General Public License version 2.
+
+from pysqlite2 import dbapi2 as db
+from datetime import datetime
+
+class dbaNotInitialized(Exception):
+	pass
+
+class AgentAlreadyExistException(Exception):
+	pass
+
+class AgentDoesNotExistException(Exception):
+	pass
+
+class dbaNotAccesible (Exception):
+	pass
+
+class dba:
+	"""
+		You need initialize static field dbPath before create instances of dba class"""
+		
+	__dbStruct = """		
+		drop table if exists agents;
+		create table agents(
+				agentID INTEGER primary key AUTOINCREMENT,
+				agentName varchar(255),
+				agentStatus smallint DEFAULT 0,
+				agentTimestamp datetime DEFAULT CURRENT_TIMESTAMP
+		);
+		
+		drop table if exists vulnerabilities;
+		create table vulnerabilities(
+				vulnID INTEGER primary key AUTOINCREMENT,
+				vulnDSA INTEGER,
+				vulnLocation carchar(255),
+				vulnTimestamp datetime
+		);
+
+		drop table if exists affected;
+		create table affected(
+				id INTEGER primary key AUTOINCREMENT,
+				agentID INTEGER,
+				vulnDSA INTEGER,
+				vulnTimestamp datetime,
+				status smallint
+		);"""
+	
+	dbPath = None
+	
+	def __init__ (self):
+		if dba.dbPath == None:
+			raise dbaNotInitialized
+				
+		try:
+			self.__conn = db.connect(self.dbPath)
+			self.__conn.isolation_level = None
+			self.cursor = self.__conn.cursor()
+			#Chech if tables exists
+			self.cursor.execute ("""SELECT name FROM sqlite_master 
+				WHERE type=\'table\'
+				ORDER BY name;""")
+			if not self.cursor.fetchall():
+				raise dbaNotInitialized ()
+		except dbaNotInitialized:
+			self.__initDB()
+		except db.OperationalError:
+			raise dbaNotAccesible
+
+		
+	def getCursor(self):
+		if self.__conn:
+			if self.cursor:
+				return self.cursor
+			else:
+				self.cursor = self.__conn.cursor()
+	
+	def __initDB(self):
+		self.cursor.executescript(self.__dbStruct)
+
+	def updateAffected(self, agentID, vulnID, status):
+		self.cursor.execute ('SELECT id FROM affected WHERE agentID = %d AND vulnDSA = %d' % 
+							(agentID, vulnID))
+		timestamp = datetime.now().strftime('%Y-%m-%d %H:%M')	
+		try:
+			id = self.cursor.fetchall()[0][0]
+			self.cursor.execute ('UPDATE  affected set  status = %d, vulnTimestamp = \'%s\' WHERE id = %d' % (status, timestamp, id))
+		except IndexError:
+			self.cursor.execute ('INSERT INTO affected VALUES (NULL, %d, %d, \'%s\', %d)' %
+				(agentID, vulnID, timestamp, status))
+			
+	def updateDSA(self, dsa, location, timestamp):
+		self.cursor.execute ('SELECT vulnID FROM vulnerabilities WHERE vulnDSA = %d' % dsa)
+		if self.cursor.fetchall():
+			self.cursor.execute ('UPDATE  vulnerabilities set  vulnLocation = \'%s\', vulnTimestamp = \'%s\' WHERE vulnDSA = %d' % (location, timestamp, dsa))
+		else:
+			self.__insertDSA(dsa, location, timestamp)
+				
+	def __insertDSA(self, dsa, location, timestamp):
+		self.cursor.execute ('INSERT  INTO vulnerabilities (vulnDSA, vulnLocation, vulnTimestamp) VALUES (%d, \'%s\', \'%s\')' % (dsa, location, timestamp))
+		
+	def addAgent(self, agentName):
+		self.cursor.execute ('SELECT agentID FROM agents WHERE agentName = \'%s\'' % agentName)
+		if self.cursor.fetchall():
+			raise AgentAlreadyExistException
+		else:
+			self.cursor.execute ('INSERT INTO agents (agentID, agentName, agentTimestamp) VALUES (NULL, \'%s\', \'%s\')' %
+								(agentName, datetime.now().strftime('%Y-%m-%d %H:%M')))
+	
+	def getAgentInfo(self, agentName):
+		self.cursor.execute ('SELECT agentID FROM agents WHERE agentName = \'%s\'' % agentName)
+		try:
+			agentID = self.cursor.fetchall()[0][0]
+			return agentID
+		except IndexError:
+			return 0
+	
+	def getAgentsList(self):
+		self.cursor.execute ('SELECT agentID, agentName FROM agents')
+		return self.cursor.fetchall()
+		
+	def makeDefList (self, agentID):
+		self.cursor.execute (
+				"""SELECT vulnLocation FROM vulnerabilities 
+					LEFT JOIN affected 
+					ON vulnerabilities.vulnDSA = affected.vulnDSA 
+					WHERE affected.agentID = %d AND vulnerabilities.vulnTimestamp > affected.vulnTimestamp OR affected.vulnTimestamp IS NULL OR affected.status = 1;
+			""" % agentID)
+		return self.cursor.fetchall()
+		
+if __name__ == "__main__":
+	dba.dbPath ='/home/blaze/tmp/oval/server/oval-server.db' 
+	sql = dba()
+	print sql.makeDefList(1)


Property changes on: trunk/oval-infrastructure/src/dba.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: trunk/oval-infrastructure/src/manager.py (from rev 379, trunk/oval-monitor/manager.py)
===================================================================
--- trunk/oval-infrastructure/src/manager.py	                        (rev 0)
+++ trunk/oval-infrastructure/src/manager.py	2008-09-23 17:41:39 UTC (rev 382)
@@ -0,0 +1,303 @@
+import wx
+import wx.grid
+import os
+import sys
+import traceback
+from reporter import Report
+
+ID_ABOUT=wx.NewId()
+ID_REFRESH=wx.NewId()
+ID_PREFERENCES=wx.NewId()
+ID_BUTTON1=wx.NewId()
+ID_EXIT=wx.NewId()
+
+class AgentsGridTable(wx.grid.PyGridTableBase):
+    
+    cols = ["ID", "IP", "Affected", "Not Affected", "Not Tested"]
+    
+    def __init__(self, reporter):
+        wx.grid.PyGridTableBase.__init__(self)
+        self.reporter = reporter
+        self.data = self.reporter.reportGeneral()
+
+    def Update(self):
+        self.data = self.reporter.reportGeneral()        
+        
+    def GetNumberRows(self):
+        """Return the number of rows in the grid"""
+        return len(self.data)
+
+    def GetNumberCols(self):
+        """Return the number of columns in the grid"""
+        return len(AgentsGridTable.cols)
+
+    def IsEmptyCell(self, row, col):
+        """Return True if the cell is empty"""
+        return False
+
+    def GetTypeName(self, row, col):
+        """Return the name of the data type of the value in the cell"""
+        return None
+
+    def GetValue(self, row, col):
+        """Return the value of a cell"""
+        return self.data[row][col]
+
+    def SetValue(self, row, col, value):
+        """Set the value of a cell"""
+        pass
+    
+    def GetColLabelValue(self, col):
+        return self.cols[col]
+
+class MonitorConfig():
+    
+    def __init__(self):
+        self._readConf()        
+        
+    def _readConf(self):
+        self.cfg = wx.Config('monitor')
+        if self.cfg.Exists('AutoRefresh'):
+            self.refrAuto = self.cfg.ReadBool('AutoRefresh');            
+        else:
+            self.refrAuto = True
+        
+        if self.cfg.Exists('RefreshRate'):
+            self.refrRate = self.cfg.ReadInt('RefreshRate');            
+        else:
+            self.refrRate = 10
+            
+        if self.cfg.Exists('DbPath'):
+            self.dbPath = self.cfg.Read('DbPath');            
+        else:
+            self.dbPath = "./oval-server.db"
+    
+    def updateConf(self, auto, rate, path):
+        self.refrAuto = auto
+        self.refrRate = rate
+        self.dbPath = path
+        self.writeConf()
+        
+    def writeConf(self):
+        self.cfg.WriteBool("AutoRefresh", self.refrAuto)
+        self.cfg.WriteInt("RefreshRate", self.refrRate)
+        self.cfg.Write("DbPath", self.dbPath)
+        
+class MonitorPrefBox(wx.Dialog):
+    def __init__(self, parent, id, title):        
+        wx.Dialog.__init__(self, parent, id, title, size=(360, 190))
+        
+        self.conf = MonitorConfig()
+        wx.StaticBox(self, -1, 'Settings', (5, 5), size=(340, 120))
+        
+        self.cb = wx.CheckBox(self, -1 ,'Auto-refresh', (15, 30))
+        self.cb.SetValue(self.conf.refrAuto)
+        
+        wx.EVT_CHECKBOX(self, self.cb.GetId(), self.OnToggleRateSpin)
+
+        wx.StaticText(self, -1, 'Refresh rate', (30, 55))
+        self.sp = wx.SpinCtrl(self, -1, str(self.conf.refrRate), (105, 55), (50, -1), min=1, max=120)
+        
+        wx.StaticText(self, -1, 'Path to db', (15, 95))
+        self.tc = wx.TextCtrl(self, -1, self.conf.dbPath, size=(230, 25), pos=(100, 85))
+        
+        wx.Button(self, 1, 'Ok', (150, 130), (60, -1))
+
+        self.Bind(wx.EVT_BUTTON, self.OnClose, id=1)
+
+        self.Centre()
+        self.ShowModal()
+        self.Destroy()
+    
+        
+    def OnToggleRateSpin(self, event):
+        if self.sp.IsEnabled():
+            self.sp.Disable()
+        else:
+            self.sp.Enable()
+        
+    def OnClose(self, event):
+        self.conf.updateConf(self.cb.GetValue(), self.sp.GetValue(), self.tc.GetValue())   
+        self.Close()
+
+class AgentPopupMenu(wx.Menu):
+    def __init__(self, parent):
+        wx.Menu.__init__(self)
+
+        self.parent = parent
+
+        query = wx.MenuItem(self, wx.NewId(), 'Query')
+        self.AppendItem(query)
+        self.Bind(wx.EVT_MENU, self.OnQuery, id=query.GetId())
+
+        detail = wx.MenuItem(self, wx.NewId(), 'Detail')
+        self.AppendItem(detail)
+        self.Bind(wx.EVT_MENU, self.OnDetail, id=detail.GetId())
+
+
+    def OnQuery(self, event):
+        pass
+
+    def OnDetail(self, event):
+        pass
+
+class MainWindow(wx.Frame):
+    def __init__(self,parent,id,title):
+        
+        wx.Frame.__init__(self, parent, wx.ID_ANY, title, pos=(150, 150), size=(350, 200))
+        
+        self.conf = MonitorConfig()
+        self.grid = self.__initGrid() 
+        self.log = wx.TextCtrl(self, 1, size=(10, 10), style=wx.TE_AUTO_SCROLL | wx.TE_READONLY | wx.TE_AUTO_URL | wx.TE_MULTILINE)
+        
+        # A Statusbar in the bottom of the window
+        self.CreateStatusBar()         
+        # Adding the MenuBar to the Frame content.
+        self.SetMenuBar(self.__createMenu())  
+        
+        wx.EVT_MENU(self, ID_ABOUT, self.OnAbout)
+        wx.EVT_MENU(self, ID_REFRESH, self.OnRefresh)
+        wx.EVT_MENU(self, ID_EXIT, self.OnExit)
+        wx.EVT_MENU(self, ID_PREFERENCES, self.OnPref)
+        
+#        self.sizerButtons = wx.BoxSizer(wx.HORIZONTAL)
+#        self.tabs=[]
+#        statusButton = wx.Button(self, wx.NewId(), "Current status")
+#        statisticButton = wx.Button(self, wx.NewId(), "Statistic")
+#        wx.EVT_BUTTON(self, statusButton.GetId(), self.OnStatus)
+#        wx.EVT_BUTTON(self, statisticButton.GetId(), self.OnStatistic)
+        
+#        self.tabs.append(statusButton)
+#        self.tabs.append(statisticButton)
+#        for i in range(len(self.tabs)):            
+#            self.sizerButtons.Add(self.tabs[i],1,wx.EXPAND)
+            
+        self.sizerGrid = wx.BoxSizer(wx.HORIZONTAL)
+        self.sizerGrid.Add(self.grid, 1, wx.EXPAND)
+        
+        # Use some sizers to see layout options
+        self.sizer=wx.BoxSizer(wx.VERTICAL)
+#        self.sizer.Add(self.sizerButtons,0,wx.EXPAND)
+        self.sizer.Add(self.sizerGrid,1,wx.EXPAND)
+        self.sizer.Add(self.log,2,wx.EXPAND)
+                
+        #Layout sizers
+        self.SetSizer(self.sizer)
+        self.SetAutoLayout(1)
+        self.sizer.Fit(self)
+        self.Show(1)
+        
+    def __createMenu(self):
+        # Setting up the filemenu.
+        menuFile=wx.Menu()        
+        menuFile.AppendSeparator()
+        menuFile.Append(ID_EXIT,"E&xit"," Terminate the program")
+        
+        # Setting up the actions menu
+        menuActions=wx.Menu()
+        menuActions.Append(ID_REFRESH, "&Refresh"," Refresh Agents info ")
+        
+        # Setting up the settingsmenu.
+        menuSettings=wx.Menu()
+        menuSettings.Append(ID_PREFERENCES, "&Preferences"," OVAL monitor preferences ")
+
+        # Setting up the aboutmenu.
+        menuAbout=wx.Menu()
+        menuAbout.Append(ID_ABOUT, "&About"," Information about this program")
+        
+        # Creating the menubar.
+        menuBar = wx.MenuBar()
+        menuBar.Append(menuFile,"&File") # Adding the "filemenu" to the MenuBar
+        menuBar.Append(menuActions, "Actions")
+        menuBar.Append(menuSettings,"&Settings") # Adding the "settingsmenu" to the MenuBar
+        menuBar.Append(menuAbout,"&Help") # Adding the "aboutmenu" to the MenuBar        
+        
+        return menuBar
+    
+    def __initGrid(self):
+        newGrid = wx.grid.Grid(self)        
+        table = AgentsGridTable(Report (self.conf.dbPath))
+        newGrid.SetTable(table, True)
+        self.table = table
+        wx.grid.EVT_GRID_CELL_LEFT_DCLICK(self, self.OnStatus)
+        wx.grid.EVT_GRID_CELL_RIGHT_CLICK(self, self.OnAgentContext)
+
+        return newGrid
+    
+    def __updateGrid(self):
+        self.log.AppendText("Updating agent grid\n")
+        self.table.Update()
+        self.grid.Refresh()
+        
+    def __appendLog(self, message):
+        self.log.AppendText(message)
+        
+    def OnAbout(self,e):
+        description = """Oval Monitor is an advanced GUI tool for monitoring status of Oval agents.
+Features include agents list, full network status, detailed agent status, manual agent control
+and much more."""
+
+        licence = """File Hunter 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.
+
+File Hunter 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 File Hunter; if not, write to 
+the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA"""
+
+        info = wx.AboutDialogInfo()
+                
+        #info.SetIcon(wx.Icon('icons/hunter.png', wx.BITMAP_TYPE_PNG))
+        info.SetName('Oval Monitor')
+        info.SetVersion('0.1.0')
+        info.SetDescription(description)
+        info.SetCopyright('(C) 2008 Pavel Vinogradov')
+        info.SetWebSite('http://www.nixdev.net')
+        info.SetLicence(licence)
+        info.AddDeveloper('Pavel Vinogradov')        
+        info.AddDeveloper('Javier Fernandez-Sanguino')
+        wx.AboutBox(info)
+
+    def OnRefresh(self, e):
+        self.__updateGrid()
+        
+    def OnPref(self, e):
+        MonitorPrefBox(self, wx.NewId(), 'Monitor preference')        
+    
+    def OnExit(self,e):
+        self.Close(True)  # Close the frame.
+
+#    def addRow(self):
+#        msg = wx.grid.GridTableMessage(self.table, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1)        
+#        self.grid.ProcessTableMessage(msg)
+#        self.grid.ForceRefresh()
+#
+#    def delRow(self):
+#        msg = wx.grid.GridTableMessage(self.table, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, self.grid.GetNumberRows(), 1)        
+#        self.grid.ProcessTableMessage(msg)
+#        self.grid.ForceRefresh()
+
+    def OnAgentContext(self, event):
+        self.PopupMenu(AgentPopupMenu(self), event.GetPosition())
+        self.__appendLog(str(event))
+
+    def OnStatus(self, event):
+        self.grid.Show()
+#        result = " Click on object with Id %d\n" %event.GetId()
+#        #self.delRow()
+#        self.__appendLog(result)
+#        self.__appendLog(Report (self.conf.dbPath).reportStdAgent(event.Row+1))
+        self.__updateGrid()
+        
+    def OnStatistic(self, event):
+        self.grid.Hide()
+#        result = " Click on object with Id %d\n" %event.GetId()
+#        #self.addRow()
+#        self.__appendLog(result)
+        
+if __name__ == "__main__":
+    app = wx.PySimpleApp()
+    frame = MainWindow(None, -1, "OVAL status monitor")
+    app.MainLoop()
\ No newline at end of file


Property changes on: trunk/oval-infrastructure/src/manager.py
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: trunk/oval-infrastructure/src/oval-server.db (from rev 379, trunk/oval-monitor/oval-server.db)
===================================================================
(Binary files differ)


Property changes on: trunk/oval-infrastructure/src/oval-server.db
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mergeinfo
   + 

Copied: trunk/oval-infrastructure/src/reporter.py (from rev 379, trunk/oval-monitor/reporter.py)
===================================================================
--- trunk/oval-infrastructure/src/reporter.py	                        (rev 0)
+++ trunk/oval-infrastructure/src/reporter.py	2008-09-23 17:41:39 UTC (rev 382)
@@ -0,0 +1,191 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#                                                                                                   # Written by Pavel Vinogradov
+# Licensed under the GNU General Public License version 2.
+
+from dba import dba, dbaNotAccesible
+import os, sys, time, getopt
+import traceback, exceptions
+sys.path = ['/usr/share/oval-server'] + sys.path
+
+assert sys.version_info >= (2,4), 'Requires Python 2.4 or better'
+
+class Report:
+
+    def __init__(self, dbfile):
+        dba.dbPath = dbfile
+        self.db = dba ()
+
+    def __getAgentAffectedVuln (self, agentID):
+        """ Return list of affected DSA for certain agent
+
+        Return list of DSA numbers which affected host for certain agent.
+
+        @type agentID: C(integer)
+        @param agentID: Identificator of inspected agent
+        @rtype: C(list)
+        @return: list of DSA numbers
+        """
+
+        cursor = self.db.getCursor()
+
+        cursor.execute ('SELECT vulnDSA from affected WHERE agentID = %d and status = 1' % agentID)
+        result = cursor.fetchall()
+        return result
+
+    def __getAgentNotAffectedVuln  (self, agentID):
+        """ Return list of not affected DSA for certain agent
+
+        Return list of DSA numbers which not affected host for certain agent.
+
+        @type agentID: C(integer)
+        @param agentID: Identificator of inspected agent
+        @rtype: C(list)
+        @return: list of DSA numbers
+        """
+
+        cursor = self.db.getCursor()
+
+        cursor.execute ('SELECT vulnDSA from affected WHERE agentID = %d and status = 0' % agentID)
+        result = cursor.fetchall()
+        return result
+
+    def __getAgentNotTestedVuln  (self, agentID):
+        """ Return list of not tested DSA for certain agent
+
+        Return list of DSA numbers which not tested again host for certain agent.
+
+        @type agentID: C(integer)
+        @param agentID: Identificator of inspected agent
+        @rtype: C(list)
+        @return: list of DSA numbers
+        """
+
+        cursor = self.db.getCursor()
+        
+        cursor.execute ("""SELECT vulnDSA FROM vulnerabilities 
+            WHERE vulnDSA NOT IN (
+                SELECT vulnDSA FROM affected where agentID = %d);
+                """ % agentID)
+        result = cursor.fetchall()
+        return result
+
+    def reportGeneral (self):
+        """Generate full report about status of all agents.
+
+        Generate report, which include list of all registered agents with:
+        ID, IP, number of affected, not affected and not tested DSA.
+        """
+        result = []
+        
+        cursor = self.db.getCursor()
+
+        cursor.execute ("SELECT * FROM agents;")
+        agents = cursor.fetchall()
+        
+        for agent in agents:
+            #ID, IP, AFF, NotAFF, NotTested
+            result.append([agent[0], agent[1], len(self.__getAgentAffectedVuln(agent[0])), len(self.__getAgentNotAffectedVuln (agent[0])), len(self.__getAgentNotTestedVuln (agent[0]))])
+    
+        return result
+
+    def reportAgent (self, agentID):
+        """Generate report for certain agent.
+
+        Generate report, which include list of affected and not tested DSA.
+        Also contain number of not affected DSA.
+
+        @type agentID: C(integer)
+        @param agentID: Identificator of inspected agent
+        """
+
+        cursor = self.db.getCursor()
+
+        cursor.execute ('SELECT vulnDSA, status from affected WHERE agentID = %d' % agentID)
+        dsas = cursor.fetchall()
+        count = 0
+
+        print 'Agent %d:' % agentID
+        for dsa in dsas:
+            if dsa[1] == 1:
+                print '\tAffected to DSA ID %s' % dsa[0]
+            else:
+                count += 1
+        print '\tNot affected to %d DSA' % count
+
+        print '--------------------------'
+        cursor.execute ("""SELECT vulnerabilities.vulnDSA FROM vulnerabilities 
+            OUTER JOIN affected
+            ON vulnerabilities.vulnDSA = affected.vulnDSA
+            WHERE affected.agentID = %d AND vulnerabilities.vulnTimestamp > affected.vulnTimestamp OR affected.vulnTimestamp IS NULL;""" % agentID)
+
+        dsas = cursor.fetchall()
+        count = 0
+        for dsa in dsas:
+            print 'Not tested again DSA ID %s' %dsa[0]
+            count += 1    
+            
+    def reportDSA (self, dsaID):
+        """Generate report for certain DSA.
+
+        Generate report, which include list of affected and not tested agents 
+        again certain DSA.
+
+        @type agentID: C(integer)
+        @param agentID: Identificator of inspected DSA
+        """
+        
+        cursor = self.db.getCursor()
+        cursor.execute ('SELECT affected.agentID, agents.agentName from affected JOIN agents on affected.agentID = agents.agentID WHERE vulnDSA = %d and status = 1' % dsaID)
+        agents = cursor.fetchall ()
+        print 'Agents affected to DSA %d:' % dsaID
+        for agent in agents:
+            print '\t%d \t %s' % (agent[0], agent[1])
+
+        print '------------------------------'
+        cursor.execute ("""
+            SELECT agentID, agentName from agents 
+                WHERE agentID NOT IN (
+                    SELECT agentID FROM affected WHERE vulnDSA = %d);""" % dsaID)
+        agents = cursor.fetchall ()
+        print 'Agents not tested to DSA %d:' % dsaID
+        for agent in agents:
+            print '\t%d \t %s' % (agent[0], agent[1])    
+        
+    def reportStdAgent (self, agentID):
+        """Generate report for certain agent.
+
+        Generate report, which include list of affected and not tested DSA.
+        Also contain number of not affected DSA.
+
+        @type agentID: C(integer)
+        @param agentID: Identificator of inspected agent
+        """
+        result = ""
+        cursor = self.db.getCursor()
+
+        cursor.execute ('SELECT vulnDSA, status from affected WHERE agentID = %d' % agentID)
+        dsas = cursor.fetchall()
+        count = 0
+
+        result += 'Agent %d:\n' % agentID
+        for dsa in dsas:
+            if dsa[1] == 1:
+                result += '\tAffected to DSA ID %s\n' % dsa[0]
+            else:
+                count += 1
+        result += '\tNot affected to %d DSA\n' % count
+
+        result += '--------------------------\n'
+        cursor.execute ("""SELECT vulnerabilities.vulnDSA FROM vulnerabilities 
+            OUTER JOIN affected
+            ON vulnerabilities.vulnDSA = affected.vulnDSA
+            WHERE affected.agentID = %d AND vulnerabilities.vulnTimestamp > affected.vulnTimestamp OR affected.vulnTimestamp IS NULL;""" % agentID)
+
+        dsas = cursor.fetchall()
+        count = 0
+        for dsa in dsas:
+            result += 'Not tested again DSA ID %s\n' %dsa[0]
+            count += 1    
+            
+        return result
\ No newline at end of file




More information about the Oval-commits mailing list