Use upstream gerritbot.
Stop using the gerritbot script within the puppet tree. Use the upstream gerritbot implementation from pypi instead. Remove old gerritbot script, use pip to install upstream gerritbot, and update init script to find new location, of the gerritbot script. Change-Id: I62afe404b1c4d130901e54ca4e7857bb71b4cdd8 Reviewed-on: https://review.openstack.org/10676 Reviewed-by: James E. Blair <corvus@inaugust.com> Approved: Clark Boylan <clark.boylan@gmail.com> Reviewed-by: Clark Boylan <clark.boylan@gmail.com> Tested-by: Jenkins
This commit is contained in:
parent
6860917686
commit
97933d1cd2
@ -1,273 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# The configuration file should look like:
|
||||
"""
|
||||
[ircbot]
|
||||
nick=NICKNAME
|
||||
pass=PASSWORD
|
||||
server=irc.freenode.net
|
||||
port=6667
|
||||
channel_config=/path/to/yaml/config
|
||||
|
||||
[gerrit]
|
||||
user=gerrit2
|
||||
key=/path/to/id_rsa
|
||||
host=review.example.com
|
||||
port=29418
|
||||
"""
|
||||
|
||||
# The yaml channel config should look like:
|
||||
"""
|
||||
openstack-dev:
|
||||
events:
|
||||
- patchset-created
|
||||
- change-merged
|
||||
projects:
|
||||
- openstack/nova
|
||||
- openstack/swift
|
||||
branches:
|
||||
- master
|
||||
"""
|
||||
|
||||
import ircbot
|
||||
import time
|
||||
import subprocess
|
||||
import threading
|
||||
import select
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import ConfigParser
|
||||
import daemon, daemon.pidlockfile
|
||||
import traceback
|
||||
import yaml
|
||||
|
||||
class GerritBot(ircbot.SingleServerIRCBot):
|
||||
def __init__(self, channels, nickname, password, server, port=6667):
|
||||
ircbot.SingleServerIRCBot.__init__(self,
|
||||
[(server, port)],
|
||||
nickname, nickname)
|
||||
self.channel_list = channels
|
||||
self.nickname = nickname
|
||||
self.password = password
|
||||
|
||||
def on_nicknameinuse(self, c, e):
|
||||
c.nick(c.get_nickname() + "_")
|
||||
c.privmsg("nickserv", "identify %s " % self.password)
|
||||
c.privmsg("nickserv", "ghost %s %s" % (self.nickname, self.password))
|
||||
c.privmsg("nickserv", "release %s %s" % (self.nickname, self.password))
|
||||
time.sleep(1)
|
||||
c.nick(self.nickname)
|
||||
|
||||
def on_welcome(self, c, e):
|
||||
c.privmsg("nickserv", "identify %s "% self.password)
|
||||
for channel in self.channel_list:
|
||||
c.join(channel)
|
||||
|
||||
def send(self, channel, msg):
|
||||
self.connection.privmsg(channel, msg)
|
||||
time.sleep(0.5)
|
||||
|
||||
class Gerrit(threading.Thread):
|
||||
def __init__(self, ircbot, channel_config,
|
||||
username, keyfile, server, port=29418):
|
||||
threading.Thread.__init__(self)
|
||||
self.ircbot = ircbot
|
||||
self.channel_config = channel_config
|
||||
self.username = username
|
||||
self.keyfile = keyfile
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.proc = None
|
||||
self.poll = select.poll()
|
||||
|
||||
def _open(self):
|
||||
self.proc = subprocess.Popen(['/usr/bin/ssh', '-p', str(self.port),
|
||||
'-i', self.keyfile,
|
||||
'-l', self.username, self.server,
|
||||
'gerrit', 'stream-events'],
|
||||
bufsize=1,
|
||||
stdin=None,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=None,
|
||||
)
|
||||
self.poll.register(self.proc.stdout)
|
||||
|
||||
def _close(self):
|
||||
try:
|
||||
self.poll.unregister(self.proc.stdout)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
self.proc.kill()
|
||||
except:
|
||||
pass
|
||||
self.proc = None
|
||||
|
||||
def patchset_created(self, channel, data):
|
||||
msg = '%s proposed a change to %s: %s %s' % (
|
||||
data['patchSet']['uploader']['name'],
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
data['change']['url'])
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
def comment_added(self, channel, data):
|
||||
msg = 'A comment has been added to a proposed change to %s: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
data['change']['url'])
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
for approval in data.get('approvals', []):
|
||||
if (approval['type'] == 'VRIF' and approval['value'] == '-2' and
|
||||
channel in self.channel_config.events.get(
|
||||
'x-vrif-minus-2', set())):
|
||||
msg = 'Verification of a change to %s failed: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
data['change']['url'])
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
if (approval['type'] == 'VRIF' and approval['value'] == '2' and
|
||||
channel in self.channel_config.events.get(
|
||||
'x-vrif-plus-2', set())):
|
||||
msg = 'Verification of a change to %s succeeded: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
data['change']['url'])
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
if (approval['type'] == 'CRVW' and approval['value'] == '-2' and
|
||||
channel in self.channel_config.events.get(
|
||||
'x-crvw-minus-2', set())):
|
||||
msg = 'A change to %s has been rejected: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
data['change']['url'])
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
if (approval['type'] == 'CRVW' and approval['value'] == '2' and
|
||||
channel in self.channel_config.events.get(
|
||||
'x-crvw-plus-2', set())):
|
||||
msg = 'A change to %s has been approved: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
data['change']['url'])
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
def change_merged(self, channel, data):
|
||||
msg = 'A change was merged to %s: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
data['change']['url'])
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
def _read(self):
|
||||
l = self.proc.stdout.readline()
|
||||
data = json.loads(l)
|
||||
channel_set = (self.channel_config.projects.get(
|
||||
data['change']['project'], set()) &
|
||||
self.channel_config.events.get(
|
||||
data['type'], set()) &
|
||||
self.channel_config.branches.get(
|
||||
data['change']['branch'], set()))
|
||||
for channel in channel_set:
|
||||
if data['type'] == 'comment-added':
|
||||
self.comment_added(channel, data)
|
||||
elif data['type'] == 'patchset-created':
|
||||
self.patchset_created(channel, data)
|
||||
elif data['type'] == 'change-merged':
|
||||
self.change_merged(channel, data)
|
||||
|
||||
def _listen(self):
|
||||
while True:
|
||||
ret = self.poll.poll()
|
||||
for (fd, event) in ret:
|
||||
if fd == self.proc.stdout.fileno():
|
||||
if event == select.POLLIN:
|
||||
self._read()
|
||||
else:
|
||||
raise Exception("event on ssh connection")
|
||||
|
||||
def _run(self):
|
||||
try:
|
||||
if not self.proc:
|
||||
self._open()
|
||||
self._listen()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
self._close()
|
||||
time.sleep(5)
|
||||
|
||||
def run(self):
|
||||
time.sleep(5)
|
||||
while True:
|
||||
self._run()
|
||||
|
||||
class ChannelConfig(object):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
keys = data.keys()
|
||||
for key in keys:
|
||||
if key[0] != '#':
|
||||
data['#'+key] = data.pop(key)
|
||||
self.channels = data.keys()
|
||||
self.projects = {}
|
||||
self.events = {}
|
||||
self.branches = {}
|
||||
for channel, val in self.data.iteritems():
|
||||
for event in val['events']:
|
||||
event_set = self.events.get(event, set())
|
||||
event_set.add(channel)
|
||||
self.events[event] = event_set
|
||||
for project in val['projects']:
|
||||
project_set = self.projects.get(project, set())
|
||||
project_set.add(channel)
|
||||
self.projects[project] = project_set
|
||||
for branch in val['branches']:
|
||||
branch_set = self.branches.get(branch, set())
|
||||
branch_set.add(channel)
|
||||
self.branches[branch] = branch_set
|
||||
|
||||
def _main():
|
||||
config=ConfigParser.ConfigParser()
|
||||
config.read(sys.argv[1])
|
||||
|
||||
fp = config.get('ircbot', 'channel_config')
|
||||
if fp:
|
||||
fp = os.path.expanduser(fp)
|
||||
if not os.path.exists(fp):
|
||||
raise Exception("Unable to read layout config file at %s" % fp)
|
||||
else:
|
||||
raise Exception("Channel Config must be specified in config file.")
|
||||
|
||||
channel_config = ChannelConfig(yaml.load(open(fp)))
|
||||
|
||||
bot = GerritBot(channel_config.channels,
|
||||
config.get('ircbot', 'nick'),
|
||||
config.get('ircbot', 'pass'),
|
||||
config.get('ircbot', 'server'),
|
||||
config.getint('ircbot', 'port'))
|
||||
g = Gerrit(bot,
|
||||
channel_config,
|
||||
config.get('gerrit', 'user'),
|
||||
config.get('gerrit', 'key'),
|
||||
config.get('gerrit', 'host'),
|
||||
config.getint('gerrit', 'port'))
|
||||
g.start()
|
||||
bot.start()
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print "Usage: %s CONFIGFILE" % sys.argv[0]
|
||||
sys.exit(1)
|
||||
|
||||
pid = daemon.pidlockfile.TimeoutPIDLockFile(
|
||||
"/var/run/gerritbot/gerritbot.pid", 10)
|
||||
with daemon.DaemonContext(pidfile=pid):
|
||||
_main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -17,8 +17,8 @@
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DESC="GerritBot"
|
||||
NAME=gerritbot
|
||||
DAEMON=/usr/local/gerrit/$NAME
|
||||
DAEMON_ARGS="/home/gerrit2/gerritbot.config"
|
||||
DAEMON=/usr/local/bin/$NAME
|
||||
DAEMON_ARGS="/etc/gerritbot/gerritbot.config"
|
||||
PIDFILE=/var/run/$NAME/$NAME.pid
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
USER=gerrit2
|
||||
@ -36,17 +36,6 @@ USER=gerrit2
|
||||
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
pidof_gerritbot() {
|
||||
# if there is actually an gerritbot process whose pid is in PIDFILE,
|
||||
# print it and return 0.
|
||||
if [ -e "$PIDFILE" ]; then
|
||||
if ps -ef | grep gerrit[b]ot | grep python | awk '{print $2}' | grep -w $(cat $PIDFILE); then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#
|
||||
# Function that starts the daemon/service
|
||||
#
|
||||
@ -117,19 +106,8 @@ case "$1" in
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
PID=$(pidof_gerritbot) || true
|
||||
if [ -n "$PID" ]; then
|
||||
log_daemon_msg "$DESC is running (pid $PID)."
|
||||
exit 0
|
||||
else
|
||||
log_daemon_msg "$DESC is NOT running."
|
||||
if [ -e "$PIDFILE" ]; then
|
||||
exit 1
|
||||
else
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
#reload|force-reload)
|
||||
#
|
||||
# If do_reload() is not implemented then leave this commented out
|
||||
|
@ -1,57 +1,61 @@
|
||||
class gerritbot(
|
||||
$nick,
|
||||
$password,
|
||||
$server,
|
||||
$user,
|
||||
$vhost_name
|
||||
) {
|
||||
$nick,
|
||||
$password,
|
||||
$server,
|
||||
$user,
|
||||
$vhost_name
|
||||
) {
|
||||
|
||||
file { "/usr/local/gerrit/gerritbot":
|
||||
owner => 'root',
|
||||
group => 'root',
|
||||
mode => 555,
|
||||
ensure => 'present',
|
||||
source => 'puppet:///modules/gerritbot/gerritbot',
|
||||
require => File['/usr/local/gerrit'],
|
||||
}
|
||||
include pip
|
||||
|
||||
file { "/etc/init.d/gerritbot":
|
||||
owner => 'root',
|
||||
group => 'root',
|
||||
mode => 555,
|
||||
ensure => 'present',
|
||||
source => 'puppet:///modules/gerritbot/gerritbot.init',
|
||||
require => File['/usr/local/gerrit/gerritbot'],
|
||||
}
|
||||
package { 'gerritbot':
|
||||
ensure => latest, # we want the latest from pip
|
||||
provider => pip,
|
||||
require => Class[pip]
|
||||
}
|
||||
|
||||
file { "/home/gerrit2/gerritbot_channel_config.yaml":
|
||||
owner => 'root',
|
||||
group => 'gerrit2',
|
||||
mode => 440,
|
||||
ensure => 'present',
|
||||
source => 'puppet:///modules/gerritbot/gerritbot_channel_config.yaml',
|
||||
replace => true,
|
||||
require => User['gerrit2'],
|
||||
}
|
||||
file { '/etc/init.d/gerritbot':
|
||||
owner => 'root',
|
||||
group => 'root',
|
||||
mode => 555,
|
||||
ensure => 'present',
|
||||
source => 'puppet:///modules/gerritbot/gerritbot.init',
|
||||
require => Package['gerritbot'],
|
||||
}
|
||||
|
||||
service { 'gerritbot':
|
||||
name => 'gerritbot',
|
||||
ensure => running,
|
||||
enable => true,
|
||||
hasrestart => true,
|
||||
require => File['/etc/init.d/gerritbot'],
|
||||
subscribe => [File["/usr/local/gerrit/gerritbot"],
|
||||
File["/home/gerrit2/gerritbot_channel_config.yaml"]],
|
||||
}
|
||||
service { 'gerritbot':
|
||||
name => 'gerritbot',
|
||||
ensure => running,
|
||||
enable => true,
|
||||
hasrestart => true,
|
||||
require => File['/etc/init.d/gerritbot'],
|
||||
subscribe => [Package['gerritbot'],
|
||||
File['/etc/gerritbot/gerritbot.confg'],
|
||||
File['/etc/gerritbot/channel_config.yaml']],
|
||||
}
|
||||
|
||||
file { '/home/gerrit2/gerritbot.config':
|
||||
owner => 'root',
|
||||
group => 'gerrit2',
|
||||
mode => 440,
|
||||
ensure => 'present',
|
||||
content => template('gerritbot/gerritbot.config.erb'),
|
||||
replace => 'true',
|
||||
require => User['gerrit2']
|
||||
}
|
||||
file { '/etc/gerritbot':
|
||||
ensure => directory
|
||||
}
|
||||
|
||||
file { '/etc/gerritbot/channel_config.yaml':
|
||||
owner => 'root',
|
||||
group => 'gerrit2',
|
||||
mode => 440,
|
||||
ensure => 'present',
|
||||
source => 'puppet:///modules/gerritbot/gerritbot_channel_config.yaml',
|
||||
replace => true,
|
||||
require => User['gerrit2'],
|
||||
}
|
||||
|
||||
file { '/etc/gerritbot/gerritbot.config':
|
||||
owner => 'root',
|
||||
group => 'gerrit2',
|
||||
mode => 440,
|
||||
ensure => 'present',
|
||||
content => template('gerritbot/gerritbot.config.erb'),
|
||||
replace => 'true',
|
||||
require => User['gerrit2']
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ nick=<%= nick %>
|
||||
pass=<%= password %>
|
||||
server=<%= server %>
|
||||
port=6667
|
||||
channel_config=/home/gerrit2/gerritbot_channel_config.yaml
|
||||
channel_config=/etc/gerritbot/channel_config.yaml
|
||||
lockfile=/var/run/gerritbot/gerritbot.pid
|
||||
|
||||
[gerrit]
|
||||
|
Loading…
x
Reference in New Issue
Block a user