00001
00002 '''
00003 This module is the log file parser client start file.
00004
00005 Reading University
00006 MSc in Network Centered Computing
00007 a.weise - a.weise@reading.ac.uk - December 2005
00008 '''
00009
00010 import client_classes, os, sys, time
00011 import getopt, smtplib, socket
00012 from utils_client import LoadConfig, check_ip, usage_exit, get_password
00013
00014 class MyClient:
00015 '''
00016 main class for the client application
00017 '''
00018 def __init__(self, config_data, verb, smtp_pa):
00019 '''
00020 Constructor
00021 '''
00022 self._verbose = verb
00023 config = config_data
00024 self._workingpath = os.getcwd()
00025
00026
00027 self._database_name = config.get("database.name")
00028 self._database_path = config.get("database.path")
00029 self._database_path = self._database_path.rstrip("/")
00030 if(config.get("database.path") == '' or config.get("database.path") == None):
00031
00032 self._database_path = self._workingpath
00033
00034 else:
00035 self._database_name = self._database_name.strip()
00036 if (-1 != self._database_path.find("/", 0, 1)):
00037
00038 print "/ an erster stelle"
00039
00040 else:
00041 self._database_path = self._workingpath+"/"+self._database_path
00042
00043 self._error_description_name = config.get("files.error_description")
00044 self._error_description_path = config.get("path.path_error_description")
00045 self._error_description_path = self._error_description_path.rstrip("/")
00046 if(config.get("path.path_error_description") == '' or config.get("path.path_error_description") == None):
00047 self._error_description_path = self._workingpath
00048 else:
00049 self._error_description_name = self._error_description_name.strip()
00050 if (-1 != self._error_description_path.find("/", 0, 1)):
00051
00052 pass
00053 else:
00054 self._error_description_path = self._workingpath+"/"+self._error_description_path
00055
00056 self._client_certificate = config.get("files.client_certificate")
00057 self._client_certificate_path = config.get("path.path_client_certificate")
00058 self._client_certificate_path = self._client_certificate_path.rstrip("/")
00059 if(config.get("path.path_client_certificate") == '' or config.get("path.path_client_certificate") == None):
00060 self._client_certificate_path = self._workingpath
00061 else:
00062 self._client_certificate = self._client_certificate.strip()
00063 if (-1 != self._client_certificate_path.find("/", 0, 1)):
00064
00065 pass
00066 else:
00067 self._client_certificate_path = self._workingpath+"/"+self._client_certificate_path
00068
00069 self._client_ca = config.get("files.client_ca")
00070 self._client_ca_path = config.get("path.path_client_ca")
00071 self._client_ca_path = self._client_ca_path.rstrip("/")
00072 if(config.get("path.path_client_ca") == '' or config.get("path.path_client_ca") == None):
00073 self._client_ca_path = self._workingpath
00074 else:
00075 self._client_ca = self._client_ca.strip()
00076 if (-1 != self._client_ca_path.find("/", 0, 1)):
00077
00078 pass
00079 else:
00080 self._client_ca_path = self._workingpath+"/"+self._client_ca_path
00081
00082
00083 if(0 == os.path.exists(self._client_certificate_path+"/"+self._client_certificate)):
00084 print "Could not locate client certifiate under %s !\nMaybe change configuration file and try again!\n\n" % self._client_certificate_path
00085 os._exit(-1)
00086
00087 if(0 == os.path.exists(self._client_ca_path+"/"+self._client_ca)):
00088 print "Could not locate client ca certificate under %s !\nMaybe change configuration file and try again!\n\n" % self._client_ca_path
00089 os._exit(-1)
00090
00091 if(0 == os.path.exists(self._error_description_path+"/"+self._error_description_name)):
00092 print "Could not locate error description file under %s !\nMaybe change configuration file and try again!\n\n" % self._error_description_path
00093 os._exit(-1)
00094
00095 self._project = config.get("project.name")
00096 self._interval = int(config.get("misc.minute"))
00097
00098
00099 servers = config.get("server.serverlist")
00100
00101 servers_split = servers.split(",")
00102
00103 self._serverlist = {}
00104 for i in range(len(servers_split)):
00105
00106 servers_split[i] = servers_split[i].strip()
00107 temp_list = servers_split[i].split(":")
00108
00109 if len(temp_list) != 2:
00110 print "The IP configuration \"%s\" seems not correct. \nPlease check the configuration file!\n\n" % temp_list[0]
00111 os._exit(-1)
00112 temp_list[0] = temp_list[0].strip()
00113 temp_list[1] = temp_list[1].strip()
00114
00115 if( -1 == check_ip(temp_list[0])):
00116 print "The IP \"%s\" seems not correct. \nPlease check the configuration file!\n\n" % temp_list[0]
00117 os._exit(-1)
00118 try:
00119 temp_list[1] = int(temp_list[1])
00120 except ValueError:
00121 print "The port \"%s\" is not valid.\nPlease check the configuration file!\n\n" % temp_list[1]
00122 os._exit(-1)
00123 if (temp_list[1] < 1024 or temp_list[1] > 50001):
00124 print "A server port is out of range. \nPlease check the configuration file and make sure the server port lies between 1025 (inclusive) and 50000 (inclusive)!\n\n"
00125 os._exit(-1)
00126 self._serverlist[temp_list[0]] = temp_list[1]
00127
00128 self._share = client_classes.Mutex()
00129
00130
00131 self._smtp_server = config.get("mail.smtp_server")
00132 self._smtp_pass = smtp_pa
00133 self._smtp_from = config.get("mail.from")
00134 self._smtp_user = config.get("mail.user")
00135
00136 if (None != self._smtp_pass):
00137
00138 try:
00139 if self._verbose == 1:
00140 print "Test SMTP connection to server \"%s\"...." % self._smtp_server
00141 server = smtplib.SMTP(self._smtp_server)
00142 print "server object: ", server
00143 if self._verbose == 1:
00144 server.set_debuglevel(1)
00145 server.login(self._smtp_user, self._smtp_pass)
00146 server.quit()
00147 if self._verbose == 1:
00148 print "SMTP connection successfully tested"
00149 except smtplib.SMTPAuthenticationError, e:
00150 print "Problem with SMTP server authentication -> \"%s\" !" % e
00151 print "\n"
00152 os._exit(-1)
00153 except socket.error, e:
00154 print "Problem with SMTP server -> \"%s\" !" % e
00155 print "\n"
00156 os._exit(-1)
00157
00158 self._mail_address = []
00159 z = 1
00160 while(1):
00161 temp = "mail_to.address_%d" % z
00162 testus = config.get(temp)
00163 if testus == None:
00164 break
00165 self._mail_address.append(testus)
00166 z += 1
00167
00168 keywordfiles = []
00169
00170 z = 1
00171 while(1):
00172 temp = "mail_to.path_ignore_error_%d" % z
00173 path = config.get(temp)
00174 if(path == '' or path == None):
00175 path = self._workingpath
00176 else:
00177 path = path.rstrip("/")
00178 if (-1 != path.find("/", 0, 1)):
00179
00180 pass
00181 else:
00182 path = self._workingpath+"/"+path
00183
00184 temp = "mail_to.file_ignore_error_%d" % z
00185 filus = config.get(temp)
00186 if filus == None:
00187 break
00188 filus = filus.strip()
00189
00190 keywordfilus = path+"/"+filus
00191
00192 if(0 == os.access(keywordfilus, 4)):
00193 print "Could not access keyword file under %s !\nMaybe change configuration file and try again!\n\n" % keywordfilus
00194 os._exit(-1)
00195
00196 keywordfiles.append(keywordfilus)
00197 z += 1
00198
00199 self._mail_ignore_error = range(len(keywordfiles))
00200 for i in range(len(keywordfiles)):
00201 self._mail_ignore_error[i] = self._get_keywords(keywordfiles[i])
00202
00203 def _get_keywords(self, filus):
00204 '''
00205 This function extracts keyword from a give file!
00206 '''
00207 keys = []
00208
00209 try:
00210 file_fd = file(filus, 'r')
00211 except IOError, e:
00212 print "Problem with keyword file -> ", e
00213 return -1
00214
00215 content = file_fd.readlines()
00216
00217 file_fd.close()
00218
00219 content = self._remove_item(content, "#")
00220 content = self._remove_item(content, "\n")
00221
00222 for i in range(len(content)):
00223 content[i] = content[i].strip()
00224 content[i] = content[i].rstrip(",")
00225 content[i] = content[i].split(",")
00226 for a in range(len(content[i])):
00227 keys.append(content[i][a])
00228
00229 for i in range(len(keys)):
00230 keys[i] = keys[i].strip()
00231 keys[i] = keys[i].split(":")
00232
00233 return keys
00234
00235 def _remove_item(self, listus, item):
00236 '''
00237 This function removes an item for a list as a rekursive function.
00238 '''
00239 while(1):
00240
00241 for i in range(len(listus)):
00242 if -1 != listus[i].find(item, 0, 1):
00243 del listus[i]
00244 self._remove_item(listus, item)
00245 break
00246 else:
00247 break
00248
00249 return listus
00250
00251 def initialise_database(self):
00252 '''
00253 This function is initalising the database, creates it, when it's not there! It creates finally the database access cursor for further work with the database.
00254 '''
00255 self._db = client_classes.MyDatabase(self._error_description_name, self._error_description_path, self._database_name, self._database_path, self._serverlist.items(), self._project, self._verbose)
00256
00257 def get_serverlist(self):
00258 '''
00259 This function returns the server list.
00260 '''
00261 return self._serverlist
00262
00263 def fetch_error_messages(self):
00264 '''
00265 This function starts the worker thread, who initalises the regular fetching of the error messages.
00266 '''
00267 self._workerthread = client_classes.WorkerThread(self._share, self._db, self._interval, self._serverlist.items(), self._client_certificate, self._client_certificate_path, self._client_ca, self._client_ca_path, self._verbose, self._mail_address, self._mail_ignore_error, self._smtp_server, self._smtp_pass, self._smtp_from, self._smtp_user)
00268 self._workerthread.setName("workerthreadDaemon")
00269 self._workerthread.start()
00270
00271 if self._verbose == 1:
00272 print "%s -> Manager thread started !" % ( time.ctime() )
00273
00274
00275
00276
00277 def daemonize(verbose, stdout = '/dev/null', stderr = None, stdin = '/dev/null', pidfile = None, startmsg = 'Client daemon started with pid %s'):
00278
00279 '''
00280 This function creates a daemon by forking the current process. The parameters stdin, stdout, and stderr are file names which substitute the standard err-, in-, out- output. This parameters are optional and point normally to /dev/null. Note that stderr is opened unbuffered, so if it shares a file with stdout then interleaved output may not appear in the order that you expect.
00281
00282 source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012
00283 modified by a.weise November 2005
00284 '''
00285
00286
00287 try:
00288 pid = os.fork()
00289 if (pid > 0):
00290 sys.exit(0)
00291
00292 except OSError, e:
00293 sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
00294 sys.exit(1)
00295
00296 os.umask(0)
00297 os.setsid()
00298
00299
00300 try:
00301 pid = os.fork()
00302 if (pid > 0):
00303 sys.exit(0)
00304
00305 except OSError, e:
00306
00307 sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
00308 sys.exit(1)
00309
00310
00311 if (not stderr):
00312 stderr = stdout
00313
00314
00315 if verbose == 1:
00316 si = file(stdin, 'r')
00317 so = file(stdout, 'w+')
00318 se = file(stderr, 'w+', 0)
00319 pid = str(os.getpid())
00320 sys.stderr.write("\n%s\n" % startmsg % pid)
00321 sys.stderr.flush()
00322 if pidfile:
00323 file(pidfile,'w+').write("%s\n" % pid)
00324
00325
00326 os.dup2(si.fileno(), sys.stdin.fileno())
00327 os.dup2(so.fileno(), sys.stdout.fileno())
00328 os.dup2(se.fileno(), sys.stderr.fileno())
00329
00330
00331
00332
00333
00334 def start():
00335
00336 '''
00337 Start the application.
00338 '''
00339 configfile = ""
00340 verbose = 0
00341 smtp_pass = None
00342 daemon = 0
00343
00344 try:
00345 opts, args = getopt.getopt(sys.argv[1:], 'c:vhpd', ['config=', 'verbose', 'help', 'smtp_password', '--daemon'])
00346 for opt, value in opts:
00347 if opt in ('-h','--help'):
00348 msg = "\n----------- Help ----------\n\n\n"\
00349 "-c or --config\t\t-> defines config file, if no config file given, default values are used\n"\
00350 "-p or --smtp_password\t-> activates mail notification sending\n"\
00351 "-v or --verbose\t\t-> activates printing of messages [debug option]\n"\
00352 "-d or --daemon\t\t-> daemonize the client\n"\
00353 "-h or --help\t\t-> print this help\n\n"
00354 usage_exit(sys.argv[0], msg)
00355 if opt in ('-c','--config'):
00356 value = value.replace("=", "")
00357 configfile = os.getcwd()+"/"+value
00358 if opt in ('-v','--verbose'):
00359 verbose = 1
00360 if opt in ('-p', '--smtp_password'):
00361 smtp_pass = get_password("Please enter SMTP password: ")
00362 if opt in ('-d', '--daemon'):
00363 daemon = 1
00364 except getopt.error, e:
00365 usage_exit(sys.argv[0], e)
00366
00367
00368 if (configfile != ""):
00369
00370 if(1 == os.path.exists(configfile)):
00371 config = LoadConfig(configfile)
00372 else:
00373
00374 print "Sorry, a given file does NOT exist !\nPlease try again!\n\n"
00375 os._exit(-1)
00376 else:
00377 msg = "\nNo config file spezified !\n"
00378 usage_exit(sys.argv[0], msg)
00379
00380 print "\n\n--------------------- SRB LOG FILE PARSER [ CLIENT ] ------------------ \n\n"
00381 print "Starting ..."
00382
00383
00384 worker = MyClient(config, verbose, smtp_pass)
00385 worker.initialise_database()
00386
00387 if daemon == 1:
00388 if verbose == 1:
00389 daemonize(verbose, stdout = 'daemonize.log')
00390 else:
00391 daemonize(verbose)
00392 else:
00393 pass
00394
00395 print "%s -> Start manager thread ..." % (time.ctime())
00396 worker.fetch_error_messages()
00397
00398 if __name__ == '__main__':
00399
00400 start()