#! /usr/bin/env python # -*- coding: UTF-8 -*- """The site URL server module """ # Copyright 2009-2010 eGovMon # This program is distributed under the terms of the GNU General # Public License. # # This file is part of the eGovernment Monitoring # (eGovMon) # # eGovMon 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. # # eGovMon 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 eGovMon; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, # MA 02110-1301 USA __owner__ = "Morten Goodwin" __maintainer__ = "Morten Goodwin" __version__ = 0.1 import sc import psycopg2 import Queue import random import getopt import time import sys import urlparse import urllib import memcache import SOAPpy import egovmondb from logit import * class Log: """Ensure auto-flush after each write""" def __init__(self, f): self.f = f def write(self, s): self.f.write(s) self.f.flush() def flush(self): self.f.flush() log=Log(open(sc.loglocation+'/siteurlserver.log','a')) PIDFILE="/var/run/siteurlserver.pid" class SiteURLServer: """Site URL server class """ def __init__(self): """initialise the class Keyword arguements: port -- [Optional] Port to host at. 8889 as default site -- [Optional] Timeout for a site. Retrieved from the System Configuration as defeult. maxtries -- [Optional] Number of strikes for a site. 3 as default. """ self.siteurlqueue = Queue.Queue() import sc self.sc = sc.SystemConfiguration() self.mc = memcache.Client([self.sc.memcache], debug=0) self.testrunid = None self.egovmondb = egovmondb.eGovMonDB() self.alivesites = {} def keepAlive(self,site,pid): self.alivesites[site] = (pid,time.time()) def getSilentSites(self): retsites = [] timeout = int(self.sc.sitetimeout) for site,value in self.alivesites.items(): pid,lasttime = value duration=time.time()-lasttime if duration>timeout: retsites.append((site,pid)) for site,pid in retsites: print 'Site:',site,'is silent' self.alivesites.pop(site) return [i[1] for i in retsites] def ping(self): return True def getSiteURL(self): if self.testrunid and len(self.siteurlqueue.queue)==0: self.startTestrun(self.testrunid, self.contenttype) logit('Automatically retrying') time.sleep(random.randint(30,60)) url,contenttype = self.siteurlqueue.get() logit('Giving out url:'+str(url),'siteurlserver') return url,self.testrunid,contenttype def startTestrun(self,testrunid,contenttype): mc = memcache.Client([sc.memcache],debug=0) mc.flush_all() self.testrunid = testrunid self.contenttype = contenttype self.siteurlqueue = Queue.Queue() for site in self.egovmondb.getUnfinishedSites(testrunid, contenttype): if not site in self.siteurlqueue.queue: logit('Scheduling site '+site+' to testrun '+str(testrunid),stdout=True) self.siteurlqueue.put((site,contenttype)) def daemonize(): # Disconnect from controlling TTY as a service try: pid = os.fork() if pid > 0: sys.exit(0) except OSError, e: print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror) sys.exit(1) # Do not prevent unmounting... os.chdir("/") os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent, print eventual PID before #print "Daemon PID %d" % pid open(PIDFILE,'w').write("%d"%pid) sys.exit(0) except OSError, e: print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror) sys.exit(1) # Redirect stdout/stderr to log file sys.stdout=sys.stderr=log # UID and GID Nobody os.setegid(99) os.seteuid(99) def main(port): import sc thissc = sc.SystemConfiguration() host = urlparse.urlparse(urllib.unquote(thissc.siteurlserver))[1] host,port = host.split(':') sus = SiteURLServer() server = SOAPpy.ThreadingSOAPServer((host, int(port))) server.registerFunction(sus.startTestrun) server.registerFunction(sus.getSiteURL) server.registerFunction(sus.ping) server.registerFunction(sus.keepAlive) server.registerFunction(sus.getSilentSites) try: server.serve_forever() except KeyboardInterrupt: import sys sys.exit("Siteurlserver was stopped.") sys.exit(0) if __name__== "__main__": port=8889 # Service port number daemonise=False (opts,args)=getopt.getopt(sys.argv[1:],"dp:fhi",["daemonise","port=","force-reload","help",'import']) for opt,arg in opts: if opt in ("-p","--port"): port=int(arg) if opt in ("-f","--force-reload"): forceReload=True if opt in ("-d","--daemonise"): daemonise=True if opt in ("-h","--help"): sys.exit(usage()) if opt in ('-i','--import'): if raw_input('This will the delete all content of the URL repository and instert the basic URLs. Are you sure you want to do that (y/n). No as default.').lower() in ('y','yes'): directory = sys.argv[sys.argv('-i') + 1] import os files = [directory+l for l in os.listdir(directory) if l.endswith('.csv')] if not files: print 'No csv-files found in directory:',directory,'.Please make sure this directory includes at least one csv-file.' else: ur=URLRep(deletemodel=True) for f in files: print 'Adding sites from file',f ur.addInitialURLs(f) if len(args)>0: sys.exit(usage()) if daemonise: daemonize() else: print "Starting Site URL server on localhost, port",port main(port)