10 from threading import *
12 # RT database access constants file
13 RT_DB_CONSTANTS_PATH='/etc/planetlab/rt_db'
16 logger = logging.getLogger("monitor")
18 # seconds between ticket update
21 def stripQuotes( str ):
25 if str[len(str)-1] in quotes:
30 def readConstantsFile( file_path ):
32 read a file consisting of lines of
36 and return a dictionary of the values.
38 blank lines, and lines starting with # (comments) are skipped
44 input_file= file(file_path,"r")
48 for line in input_file:
51 line= string.strip(line)
55 parts= string.split(line,"=",)
59 contents[parts[0]]= stripQuotes(parts[1])
67 # read plc database passwords and connect
68 rt_db_constants= readConstantsFile(RT_DB_CONSTANTS_PATH)
69 if rt_db_constants is None:
70 print "Unable to read database access constants from %s" % \
75 rt_db = MySQLdb.connect(host=rt_db_constants['RT_DB_HOST'],
76 user=rt_db_constants['RT_DB_USER'],
77 passwd=rt_db_constants['RT_DB_PASSWORD'],
78 db=rt_db_constants['RT_DB_NAME'])
80 print "Failed to connect to RT database"
88 def rt_tickets(hostname):
90 sql = """SELECT distinct Tk.id, Tk.Status, Tk.Subject
92 JOIN Transactions AS Tr ON Tk.id=Tr.ObjectId
93 JOIN Attachments AS At ON Tr.id=At.TransactionID
94 WHERE (At.Content LIKE '%%%s%%' OR
95 At.Subject LIKE '%%%s%%') AND
96 (Tk.Status = 'new' OR Tk.Status = 'open') AND
98 ORDER BY Tk.Status, Tk.LastUpdated DESC""" \
102 # create a 'cursor' (required by MySQLdb)
105 except Exception, err:
106 print "Could not execute RT query %s" %err
109 # fetch all rows (list of lists)
112 # map list of lists (raw) to list of dicts (tickets)
113 # when int gets pulls from SQL into python ints are converted to LONG to
114 # prevent overflow .. convert back
115 tickets = map(lambda x: {"ticket_id":int(x[0]),
125 Finds tickets associated with hostnames.
126 The idea is if you give it an array of host names,
127 presumeably from comon's list of bad nodes, it starts
128 a few threads to query RT. RT takes a while to return.
130 This is turning into a reinvention of DB design, which I dont believe in.
131 In an effort to keep things minimal, here's the basic algo:
133 Give list of hostnames to RT()
134 Finds tickets associate with new hostnames (not in dict(tickets)).
135 Remove nodes that have come backup. Don't care of ticket is closed after first query.
136 Another thread refresh tickets of nodes already in dict and remove nodes that have come up.
139 def __init__(self, tickets, bucket, target = None):
140 # Time of last update of ticket DB
142 # Queue() is MP/MC self locking
144 #DB of tickets. Name -> ticket
145 self.tickets = tickets
146 Thread.__init__(self,target = self.getTickets)
148 # Takes node from alldownq, gets tickets.
149 # Thread that actually gets the tickets.
150 def getTickets(self):
152 host = self.bucket.get(block = True)
153 if host == "None": break
154 #if self.tickets.has_key(host) == False:
155 logger.debug("Popping from q - %s" %host)
156 tmp = rt_tickets(host)
158 logger.debug("Found tickets for %s" %host)
159 self.tickets[host] = tmp
161 # Removes hosts that are no longer down.
162 def remTickets(self):
163 logger.debug("Removing stale entries from DB.")
164 prevdown = self.tickets.keys()
167 #BEGIN HACK. This should be outside of this file. passed to class.
168 cmn = comon.Comon(None, None)
170 for bucket in cmn.comonbkts.keys():
171 for host in getattr(cmn,bucket):
172 if host not in currdown: currdown.append(host)
175 # Actually do the comparison
176 for host in prevdown:
177 if host not in currdown:
178 del self.tickets[host]
179 logger.info("%s no longer down" % host)
182 def updateTickets(self):
183 logger.info("Refreshing DB.")
184 for host in self.tickets.keys():
185 # Put back in Q to refresh
186 self.bucket.put(host)
188 def cleanTickets(self):
195 logger.setLevel(logging.DEBUG)
196 ch = logging.StreamHandler()
197 ch.setLevel(logging.DEBUG)
198 formatter = logging.Formatter('%(message)s')
199 ch.setFormatter(formatter)
200 logger.addHandler(ch)
202 bucket = Queue.Queue()
204 a = RT(tickets, bucket)
205 b = RT(tickets, bucket)
206 c = RT(tickets, bucket)
207 d = RT(tickets, bucket)
208 e = RT(tickets, bucket)
213 tmp = ('planetlab-2.vuse.vanderbilt.edu', 'planetlab-11.cs.princeton.edu', 'planet03.csc.ncsu.edu', 'planetlab1.pop-rj.rnp.br', 'planet1.halifax.canet4.nodes.planet-lab.org', 'planet1.cavite.nodes.planet-lab.org', 'ds-pl3.technion.ac.il', 'planetlab2.cs.purdue.edu', 'planetlab3.millennium.berkeley.edu', 'planetlab1.unl.edu', 'planetlab1.cs.colorado.edu', 'planetlab02.cs.washington.edu', 'orbpl2.rutgers.edu', 'planetlab2.informatik.uni-erlangen.de', 'pl2.ernet.in', 'neu2.6planetlab.edu.cn', 'planetlab-2.cs.uni-paderborn.de', 'planetlab1.elet.polimi.it', 'planetlab2.iiitb.ac.in', 'server1.planetlab.iit-tech.net', 'planetlab2.iitb.ac.in', 'planetlab1.ece.ucdavis.edu', 'planetlab02.dis.unina.it', 'planetlab-1.dis.uniroma1.it', 'planetlab1.iitb.ac.in', 'pku1.6planetlab.edu.cn', 'planetlab1.warsaw.rd.tp.pl', 'planetlab2.cs.unc.edu', 'csu2.6planetlab.edu.cn', 'pl1.ernet.in', 'planetlab2.georgetown.edu', 'planetlab1.cs.uchicago.edu')
216 #et = Thread(target=e.pushHosts)
224 #cmn = comon.Comon(cdb, bucket)
226 #for bucket in cmn.comonbkts.keys():
227 # for host in getattr(cmn,bucket):
230 at = Thread(target=a.cleanTickets)
236 if __name__ == '__main__':