Make bot.py behave like a daemon

This includes a number of changes to prevent printing to stdout and
enable using daemonContext so that we can run bot.py as a daemon.
This commit is contained in:
Matthew Treinish 2013-09-18 17:45:12 -04:00
parent b0b024e080
commit 545012839a
4 changed files with 35 additions and 21 deletions

30
bot.py
View File

@ -25,7 +25,6 @@ openstack-qa:
import ConfigParser import ConfigParser
import daemon import daemon
import lockfile
import irc.bot import irc.bot
import os import os
import sys import sys
@ -37,6 +36,14 @@ import logging
from elasticRecheck import Stream from elasticRecheck import Stream
from elasticRecheck import Classifier from elasticRecheck import Classifier
try:
import daemon.pidlockfile
pid_file_module = daemon.pidlockfile
except Exception:
# as of python-daemon 1.6 it doesn't bundle pidlockfile anymore
# instead it depends on lockfile-0.9.1
import daemon.pidfile
pid_file_module = daemon.pidfile
class RecheckWatchBot(irc.bot.SingleServerIRCBot): class RecheckWatchBot(irc.bot.SingleServerIRCBot):
@ -47,7 +54,7 @@ class RecheckWatchBot(irc.bot.SingleServerIRCBot):
self.channel_list = channels self.channel_list = channels
self.nickname = nickname self.nickname = nickname
self.password = password self.password = password
self.log = logging.getLogger('gerritbot') self.log = logging.getLogger('recheckwatchbot')
def on_nicknameinuse(self, c, e): def on_nicknameinuse(self, c, e):
self.log.info('Nick previously in use, recovering.') self.log.info('Nick previously in use, recovering.')
@ -73,13 +80,15 @@ class RecheckWatchBot(irc.bot.SingleServerIRCBot):
self.connection.privmsg(channel, msg) self.connection.privmsg(channel, msg)
time.sleep(0.5) time.sleep(0.5)
class RecheckWatch(threading.Thread): class RecheckWatch(threading.Thread):
def __init__(self, ircbot, channel_config, username): def __init__(self, ircbot, channel_config, username, queries):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.ircbot = ircbot self.ircbot = ircbot
self.channel_config = channel_config self.channel_config = channel_config
self.log = logging.getLogger('recheckwatchbot') self.log = logging.getLogger('recheckwatchbot')
self.username = username self.username = username
self.queries = queries
self.connected = False self.connected = False
def new_error(self, channel, data): def new_error(self, channel, data):
@ -108,7 +117,7 @@ class RecheckWatch(threading.Thread):
self.new_error(channel, data) self.new_error(channel, data)
def run(self): def run(self):
classifier = Classifier() classifier = Classifier(self.queries)
stream = Stream(self.username) stream = Stream(self.username)
while True: while True:
event = stream.get_failed_tempest() event = stream.get_failed_tempest()
@ -120,7 +129,6 @@ class RecheckWatch(threading.Thread):
else: else:
event['bug_number'] = bug_number event['bug_number'] = bug_number
self._read(event) self._read(event)
class ChannelConfig(object): class ChannelConfig(object):
@ -160,7 +168,9 @@ def _main():
config.get('ircbot', 'server'), config.get('ircbot', 'server'),
config.getint('ircbot', 'port'), config.getint('ircbot', 'port'),
config.get('ircbot', 'server_password')) config.get('ircbot', 'server_password'))
recheck = RecheckWatch(bot, channel_config, config.get('gerrit', 'user')) recheck = RecheckWatch(bot, channel_config,
config.get('gerrit', 'user'),
config.get('gerrit', 'query_file'))
recheck.start() recheck.start()
bot.start() bot.start()
@ -171,10 +181,10 @@ def main():
print "Usage: %s CONFIGFILE" % sys.argv[0] print "Usage: %s CONFIGFILE" % sys.argv[0]
sys.exit(1) sys.exit(1)
pid = lockfile.FileLock( pid = pid_file_module.TimeoutPIDLockFile(
"/var/run/recheckwatchbot/recheckwatchbot.pid", 10) "/tmp/recheckwatchbot.pid", 10)
# with daemon.DaemonContext(pidfile=pid): with daemon.DaemonContext(pidfile=pid):
_main() _main()
def setup_logging(config): def setup_logging(config):

View File

@ -3,7 +3,8 @@ nick=RecheckWatchBot
pass= pass=
server=irc.freenode.net server=irc.freenode.net
port=6667 port=6667
channel_config=recheckwatchbot.yaml channel_config=/home/mtreinish/elasticRecheck/recheckwatchbot.yaml
[gerrit] [gerrit]
user=jogo user=treinish
query_file=/home/mtreinish/elasticRecheck/queries.json

View File

@ -104,9 +104,10 @@ class Classifier():
queries = None queries = None
def __init__(self): def __init__(self, queries):
self.es = ElasticSearch(self.ES_URL) self.es = ElasticSearch(self.ES_URL)
self.queries = json.loads(open('queries.json').read()) self.queries = json.loads(open(queries).read())
self.log = logging.getLogger("recheckwatchbot")
def _apply_template(self, template, values): def _apply_template(self, template, values):
query = copy.deepcopy(template) query = copy.deepcopy(template)
@ -121,7 +122,7 @@ class Classifier():
def last_failures(self): def last_failures(self):
for x in self.queries: for x in self.queries:
print "Looking for bug: https://bugs.launchpad.net/bugs/%s" % x['bug'] self.log.debug("Looking for bug: https://bugs.launchpad.net/bugs/%s" % x['bug'])
query = self._apply_template(self.general_template, x['query']) query = self._apply_template(self.general_template, x['query'])
results = self.es.search(query, size='10') results = self.es.search(query, size='10')
self._parse_results(results) self._parse_results(results)
@ -131,10 +132,10 @@ class Classifier():
try: try:
change = x["_source"]['@fields']['build_change'] change = x["_source"]['@fields']['build_change']
patchset = x["_source"]['@fields']['build_patchset'] patchset = x["_source"]['@fields']['build_patchset']
print "build_name %s" % x["_source"]['@fields']['build_name'] self.log.debug("build_name %s" % x["_source"]['@fields']['build_name'])
print "https://review.openstack.org/#/c/%(change)s/%(patchset)s" % locals() self.log.debug("https://review.openstack.org/#/c/%(change)s/%(patchset)s" % locals())
except KeyError: except KeyError:
print "build_name %s" % x["_source"]['@fields']['build_name'] self.log.debug("build_name %s" % x["_source"]['@fields']['build_name'])
def classify(self, change_number, patch_number, comment): def classify(self, change_number, patch_number, comment):
"""Returns either None or a bug number""" """Returns either None or a bug number"""
@ -143,7 +144,7 @@ class Classifier():
#Wait till Elastic search is ready #Wait till Elastic search is ready
self._wait_till_ready(change_number, patch_number, comment) self._wait_till_ready(change_number, patch_number, comment)
for x in self.queries: for x in self.queries:
print "Looking for bug: https://bugs.launchpad.net/bugs/%s" % x['bug'] self.log.debug("Looking for bug: https://bugs.launchpad.net/bugs/%s" % x['bug'])
query = self._apply_template(self.targeted_template, (x['query'], query = self._apply_template(self.targeted_template, (x['query'],
change_number, patch_number)) change_number, patch_number))
results = self.es.search(query, size='10') results = self.es.search(query, size='10')
@ -201,7 +202,7 @@ class Classifier():
def main(): def main():
classifier = Classifier()
#classifier.test() #classifier.test()
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
if len(sys.argv) is 2: if len(sys.argv) is 2:
@ -210,6 +211,8 @@ def main():
config_path = 'elasticRecheck.conf' config_path = 'elasticRecheck.conf'
config.read(config_path) config.read(config_path)
user = config.get('gerrit', 'user', 'jogo') user = config.get('gerrit', 'user', 'jogo')
queries = config.get('gerrit', 'query_file', 'queries.json')
classifier = Classifier(queries)
stream = Stream(user) stream = Stream(user)
while True: while True:
event = stream.get_failed_tempest() event = stream.get_failed_tempest()

View File

@ -1,4 +1,4 @@
openstack-recheck-watch-test: openstack-qa:
events: events:
- positive - positive
- negative - negative