- Joined
- Jan 24, 2006
- Location
- South Dakota
logwatch email parser
This is a very dirty dirty hack job on the GUI. I built a CLI version of this which was much cleaner programatically
At any rate it works for what I need it to do
Main program
selection_screen.glade
report.glade
Like I said, its ugly ugly and I may go back and clean it up some time in the future.
This is a very dirty dirty hack job on the GUI. I built a CLI version of this which was much cleaner programatically
At any rate it works for what I need it to do
Main program
Code:
#!/usr/bin/python
#This program provides a graphical front end for some basic parsing of logwatch emails exported from
#Outlook/email clients
import pygtk
import gtk
import gobject
import gtk.glade
#When pulling files in from glade you need to refer to the objects as follows
# local_object_name = self.builder.get_object("name_in_glade")
server = []
class startUI:
sort_order = gtk.SORT_ASCENDING
########################This makes sure that the buttons work and call their proper functions
def connect_signals(self):
#Have the buttons start 'listening' for user interaction
self.button_exit = self.builder.get_object("button_exit")
self.button_report = self.builder.get_object("button_report")
self.select_file = self.builder.get_object("select_file")
self.button_report.connect("clicked", self.report_button_click)
self.button_exit.connect("clicked", self.exit_program)
self.select_file.connect("file-set", self.generate_server_list)
##########################
##########################This generates The list of servers to report on
def generate_server_list(self, widget, callback_data=None):
#I am making these global so that I can call them outside of this function
global samba_msg
global httpd_msg
global clam_msg
global pam_msg
global SSHD_msg
global iptables_msg
global disk_space_msg
#These are the tuples which will hold the messages from logwatch
samba_msg = []
httpd_msg = []
clam_msg = []
pam_msg = []
SSHD_msg = []
iptables_msg = []
disk_space_msg = []
server = []
samba_flag = 0
httpd_flag = 0
clam_flag = 0
pam_flag = 0
SSHD_flag = 0
iptables_flag = 0
disk_space_flag = 0
#In order to make sure that the elements from servers match up properly with the report elements
#We need to input our own message if one of the services is missing
#These True/False variables help to track whether each service is present for a given host
samba_is_present = False
httpd_is_present = False
clam_is_present = False
pam_is_present = False
SSHD_is_present = False
iptables_is_present = False
disk_space_is_present = False
#This section is to exclude duplicate lines of common problematic entries
spacer = False
popup = False
search_inventory = False
compare_rate = False
choose_model = False
#To get the name of the file that is selected by the user, use .get_filename()
filename = self.select_file.get_filename()
for line in open(filename).readlines():
if "Logwatch for" in line:
server_name = line.split()[2]
#Check the list of servers, if the current server is in the list, skip it
#Else add it to the list for later summerization
if line in server:
pass
else:
server.append(server_name)
#Find the end of the report and clearly mark it
elif "# Logwatch End #" in line:
#If a service is not present, make sure to make it as False and then add an entry
#Declaring the service missing
if samba_is_present == False:
append_me = (server_name, "\___ No Samba", "")
samba_msg.append(append_me)
if httpd_is_present == False:
append_me = (server_name, "\___ No httpd", "")
httpd_msg.append(append_me)
if clam_is_present == False:
append_me = (server_name, "\___ No clam", "")
clam_msg.append(append_me)
if pam_is_present == False:
append_me = (server_name, "\___ No pam", "")
pam_msg.append(append_me)
if SSHD_is_present == False:
append_me = (server_name, "\___ No SSHD", "")
SSHD_msg.append(append_me)
if iptables_is_present == False:
append_me = (server_name, "\___ No iptables", "")
iptables_msg.append(append_me)
#At the end of each loop we want to assume that all of the services are missing
#on the next host so set all of the services to false
samba_is_present = False
httpd_is_present = False
clam_is_present = False
pam_is_present = False
SSHD_is_present = False
iptables_is_present = False
#Dont print the logwatch@server line
elif "logwatch@" in line:
pass
#Look for the samba messages and store them in an array
if "-- samba" in line and not samba_flag:
#clear the samba variable. This variable is used to collect all the lines
#Relating to the samba report so that we can later add a single variable to the array
samba_line = ''
samba_is_present = True
samba_flag = 1
continue
if samba_flag and not "-- samba" in line:
#Add each line between samba Begin and samba End to the samba_line variable
samba_line += line.rstrip()
if "-- samba" in line and samba_flag:
samba_flag = 0
samba_line = (server_name, "Samaba", samba_line)
samba_msg.append(samba_line)
continue
if "-- httpd" in line and not httpd_flag:
#clear the httpd variable. This variable is used to collect all the lines
#Relating to the httpd report so that we can later add a single variable to the array
httpd_line = ""
httpd_is_present = True
httpd_flag = 1
continue
if httpd_flag and not "-- httpd" in line:
#Add each line between httpd Begin and httpd End to the httpd_line variable
#Below are the series of key words which make reading the httpd reports useless
#Therefore we want to reduce the duplicates to a single line so the reports are much shorter
if "spacer.gif" in line and spacer == False:
spacer = True
httpd_line += line.rstrip() + " "
elif "spacer.gif" in line and spacer == True:
pass
elif "popup_close" in line and popup == False:
popup = True
httpd_line += line.rstrip() + " "
elif "popup_close" in line and popup == True:
pass
elif "getsearchnewinventory_as" in line and search_inventory == False:
search_inventory = True
httpd_line += line.rstrip() + " "
elif "getsearchnewinventory_as" in line and search_inventory == True:
pass
elif "compareRate" in line and compare_rate == False:
compare_rate = True
httpd_line += line.rstrip() + " "
elif "compareRate" in line and compare_rate == True:
pass
elif "choose_model" in line and choose_model == False:
choose_model = True
httpd_line += line.rstrip() + " "
elif "choose_model" in line and choose_model == True:
pass
else:
httpd_line += line.rstrip() + "\n "
if "-- httpd" in line and httpd_flag:
httpd_flag = 0
httpd_line = (server_name, "httpd", httpd_line)
httpd_msg.append(httpd_line)
continue
if "-- clam" in line and not clam_flag:
#clear the clam variable. This variable is used to collect all the lines
#Relating to the clam report so that we can later add a single variable to the array
clam_line = ""
clam_is_present = True
clam_flag = 1
continue
if clam_flag and not "-- clam" in line:
#Add each line between clam Begin and clam End to the clam_line variable
clam_line += line + " "
if "-- clam" in line and clam_flag:
clam_flag = 0
clam_line = (server_name, "clam", clam_line)
clam_msg.append(clam_line)
continue
if "-- pam" in line and not pam_flag:
#clear the pam variable. This variable is used to collect all the lines
#Relating to the pam report so that we can later add a single variable to the array
pam_line = ""
pam_is_present = True
pam_flag = 1
continue
if pam_flag and not "-- pam" in line:
#Add each line between pam Begin and pam End to the pam_line variable
pam_line += line
if "-- pam" in line and pam_flag:
pam_flag = 0
pam_line = (server_name, "pam", pam_line)
pam_msg.append(pam_line)
continue
if "-- SSHD" in line and not SSHD_flag:
#clear the SSHD variable. This variable is used to collect all the lines
#Relating to the SSHD report so that we can later add a single variable to the array
SSHD_line = ""
SSHD_is_present = True
SSHD_flag = 1
continue
if SSHD_flag and not "-- SSHD" in line:
#Add each line between SSHD Begin and SSHD End to the SSHD_line variable
if "time" in line:
try:
hostname = line.split(":")[0]
line = line.replace(hostname,str(socket.gethostbyaddr(hostname)[0]))
except:
pass
SSHD_line += line + " "
if "-- SSHD" in line and SSHD_flag:
SSHD_flag = 0
SSHD_line = (server_name, "ssh", SSHD_line)
SSHD_msg.append(SSHD_line)
continue
if "-- iptables" in line and not iptables_flag:
#clear the iptables variable. This variable is used to collect all the lines
#Relating to the iptables report so that we can later add a single variable to the array
iptables_line = ""
iptables_is_present = True
iptables_flag = 1
continue
if iptables_flag and not "-- iptables" in line:
#Add each line between iptables Begin and iptables End to the iptables_line variable
if "packet" in line:
hostname = line.split("-")[0].split()[1]
if "." in hostname:
try:
#this section is intended to do a dns lookup
#It slows down the whole process so it is disabled by default
#line = line.replace(hostname,str(socket.gethostbyaddr(hostname)[0]))
#I dont really care about firewall alerts generated from within my domain
if "autodata" in line:
line = ""
except:
#print line
pass
iptables_line += line + " "
if "-- iptables" in line and iptables_flag:
iptables_flag = 0
iptables_line = (server_name, "iptables", iptables_line)
iptables_msg.append(iptables_line)
continue
if "-- Disk Space" in line and not disk_space_flag:
#clear the disk_space variable. This variable is used to collect all the lines
#Relating to the disk_space report so that we can later add a single variable to the array
disk_space_line = ""
disk_space_is_present = True
disk_space_flag = 1
continue
if disk_space_flag and not "-- Disk Space" in line:
#Add each line between disk_space Begin and disk_space End to the disk_space_line variable
disk_space_line += line + " "
if "-- Disk Space" in line and disk_space_flag:
disk_space_flag = 0
disk_space_line = (server_name, "Disk Space", disk_space_line)
disk_space_msg.append(disk_space_line)
continue
#we create then store and append our elements
liststore1 = self.builder.get_object("liststore1")
#Go through the server list and append them to the liststore
x = 0
while x < len(server):
liststore1.append([server[x]])
x +=1
self.treeview = self.builder.get_object("treeview1")
self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
cell = self.builder.get_object("cell")
col = self.builder.get_object("col1")
col.set_attributes(cell,text=0)
#I am cheating and hard coding the choices from logwatch
#These will appear about the same time as the email text file is selected by the user
liststore2 = self.builder.get_object("liststore2")
report_list = ["Samba", "httpd", "clam", "pam", "SSHD", "iptables", "Disk Space"]
y = 0
while y < len(report_list):
liststore2.append([report_list[y]])
y += 1
self.treeview2 = self.builder.get_object("treeview2")
self.treeview2.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
cell2 = self.builder.get_object("cell2")
col2 = self.builder.get_object("col2")
col2.set_attributes(cell2, text=0)
##################
def get_user_selections(self, widget, callback_data=None):
#This is the output screen
self.gladefile2 = "report.glade"
self.builder2 = gtk.Builder()
self.builder2.add_from_file(self.gladefile2)
self.window3 = self.builder2.get_object("window3")
liststore3 = self.builder2.get_object("liststore3")
report_selection = self.treeview2.get_selection()
host_selection = self.treeview.get_selection()
#get_selected returns <treeview memory address>, value so we assign both but discard the address
host_model, host_rows = host_selection.get_selected_rows()
host_list = []
#Loop through the rows and extract the values for the host_list
for row in host_rows:
iter = host_model.get_iter(row)
#In this particular case, I need to store the index of the host
#in a tupple so that I can later match the host with the correct report
append_msg = host_model.get_value(iter, 0), row
host_list.append(append_msg)
report_list = []
report_model, report_rows = report_selection.get_selected_rows()
for row in report_rows:
iter = report_model.get_iter(row)
report_list.append(report_model.get_value(iter, 0))
for host in host_list:
#I am extracting the host index away so that I can match it with the correct report
host_index = str(host[1]).strip("(").strip(")").strip(",")
#Since I was designing the GUI on the fly, I mixed up the order of the columns
#So I simply rearranged the order which the elements are appended to the liststore
for report in report_list:
if "Samba" in report:
liststore3.append([samba_msg[int(host_index)][1], samba_msg[int(host_index)][0], samba_msg[int(host_index)][2]])
elif "Disk Space" in report:
liststore3.append([disk_space_msg[int(host_index)][1], disk_space_msg[int(host_index)][0],disk_space_msg[int(host_index)][2]])
elif "pam" in report:
liststore3.append([pam_msg[int(host_index)][1], pam_msg[int(host_index)][0], pam_msg[int(host_index)][2]])
elif "clam" in report:
liststore3.append([clam_msg[int(host_index)][1], clam_msg[int(host_index)][0], clam_msg[int(host_index)][2]])
elif "iptables" in report:
liststore3.append([iptables_msg[int(host_index)][1], iptables_msg[int(host_index)][0], iptables_msg[int(host_index)][0]])
elif "SSHD" in report:
liststore3.append([SSHD_msg[int(host_index)][1], SSHD_msg[int(host_index)][0], SSHD_msg[int(host_index)][2]])
elif "httpd" in report:
liststore3.append([httpd_msg[int(host_index)][1], httpd_msg[int(host_index)][0], httpd_msg[int(host_index)][2]])
self.treeview3 = self.builder2.get_object("treeview3")
self.treeview3.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
cell3 = self.builder2.get_object("cell3")
col3 = self.builder2.get_object("col3")
col3.set_resizable(True)
col3.set_reorderable(True)
col3.set_attributes(cell3, text=0)
cell4 = self.builder2.get_object("cell4")
col4 = self.builder2.get_object("col4")
col4.set_resizable(True)
col4.set_reorderable(True)
col4.set_attributes(cell4, text=1)
cell5 = self.builder2.get_object("cell5")
col5 = self.builder2.get_object("col5")
col5.set_resizable(True)
col5.set_reorderable(True)
col5.set_attributes(cell5, text=2)
self.window3.show()
####################Quit the program
def exit_program(self, widget, callback_data=None):
gtk.main_quit()
#####################
#####################This will handle generating the reports
def report_button_click(self, widget, callback_data=None):
#I am purposely suppressing errors generated by this function because of poor programming/inability to resolve the error
try:
self.treeview.connect('cursor-changed', self.get_user_selections(self.treeview))
self.treeview2.connect('cursor-changed', self.get_user_selections(self.treeview2))
except Exception, e:
pass
####################This is the main initialization which loads the initial gui
def __init__(self):
#This is the initial window
self.gladefile = "selection_screen.glade"
self.builder = gtk.Builder()
self.builder.add_from_file(self.gladefile)
self.connect_signals()
#We have to pull the items from the glade file and associate them
#with a variable. In this case self.button_XYZ
self.select_file = self.builder.get_object("select_file")
self.window = self.builder.get_object("window1")
self.window.show()
###################
if __name__ == "__main__":
main = startUI()
gtk.main()
selection_screen.glade
Code:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name col1 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkListStore" id="liststore2">
<columns>
<!-- column-name col2 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="window_position">center-always</property>
<property name="default_width">500</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="select_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please select the email to parse</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="select_file">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="report_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please select which host(s) you want the report for:</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore1</property>
<property name="reorderable">True</property>
<property name="search_column">0</property>
<property name="enable_tree_lines">True</property>
<child>
<object class="GtkTreeViewColumn" id="col1">
<property name="resizable">True</property>
<property name="title" translatable="yes">Servers:</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_indicator">True</property>
<child>
<object class="GtkCellRendererText" id="cell"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Please select the reports you want to run:</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkTreeView" id="treeview2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore2</property>
<child>
<object class="GtkTreeViewColumn" id="col2">
<property name="title" translatable="yes">Reports:</property>
<child>
<object class="GtkCellRendererText" id="cell2"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button_report">
<property name="label" translatable="yes">Generate Report</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_exit">
<property name="label" translatable="yes">Exit</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
report.glade
Code:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkListStore" id="liststore3">
<columns>
<!-- column-name col3 -->
<column type="gchararray"/>
<!-- column-name col4 -->
<column type="gchararray"/>
<!-- column-name col5 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="window3">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<property name="default_width">600</property>
<property name="default_height">200</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkTreeView" id="treeview3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore3</property>
<child>
<object class="GtkTreeViewColumn" id="col4">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="title" translatable="yes">host_name</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_indicator">True</property>
<property name="sort_column_id">1</property>
<child>
<object class="GtkCellRendererText" id="cell4"/>
<attributes>
<attribute name="height">8</attribute>
<attribute name="alignment">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col3">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Reports</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_indicator">True</property>
<property name="sort_column_id">0</property>
<child>
<object class="GtkCellRendererText" id="cell3"/>
<attributes>
<attribute name="yalign">1</attribute>
<attribute name="strikethrough">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="col5">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Message</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_indicator">True</property>
<property name="sort_column_id">0</property>
<child>
<object class="GtkCellRendererText" id="cell5"/>
<attributes>
<attribute name="wrap-width">4</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
Like I said, its ugly ugly and I may go back and clean it up some time in the future.
Last edited: