summaryrefslogtreecommitdiff
path: root/zuul/lib/gerrit.py
diff options
context:
space:
mode:
Diffstat (limited to 'zuul/lib/gerrit.py')
-rw-r--r--zuul/lib/gerrit.py171
1 files changed, 171 insertions, 0 deletions
diff --git a/zuul/lib/gerrit.py b/zuul/lib/gerrit.py
new file mode 100644
index 000000000..9c72d4436
--- /dev/null
+++ b/zuul/lib/gerrit.py
@@ -0,0 +1,171 @@
+# Copyright 2012 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import threading
+import select
+import json
+import time
+import subprocess
+import Queue
+import paramiko
+import logging
+import pprint
+
+# TODO: switch this to paramiko?
+
+class GerritWatcher(threading.Thread):
+ log = logging.getLogger("gerrit.GerritWatcher")
+
+ def __init__(self, gerrit, username, server, port=29418, keyfile=None):
+ threading.Thread.__init__(self)
+ self.username = username
+ self.keyfile = keyfile
+ self.server = server
+ self.port = port
+ self.proc = None
+ self.poll = select.poll()
+ self.gerrit = gerrit
+
+ def _open(self):
+ self.log.debug("Opening ssh connection to %s" % self.server)
+ cmd = ['/usr/bin/ssh', '-p', str(self.port)]
+ if self.keyfile:
+ cmd += ['-i', self.keyfile]
+ cmd += ['-l', self.username, self.server,
+ 'gerrit', 'stream-events']
+ self.proc = subprocess.Popen(cmd,
+ bufsize=1,
+ stdin=None,
+ stdout=subprocess.PIPE,
+ stderr=None,
+ )
+ self.poll.register(self.proc.stdout)
+
+ def _close(self):
+ self.log.debug("Closing ssh connection")
+ try:
+ self.poll.unregister(self.proc.stdout)
+ except:
+ pass
+ try:
+ self.proc.kill()
+ except:
+ pass
+ self.proc = None
+
+ def _read(self):
+ l = self.proc.stdout.readline()
+ data = json.loads(l)
+ self.log.debug("Received data from Gerrit event stream: \n%s" % pprint.pformat(data))
+ self.gerrit.addEvent(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:
+ self.log.exception("Exception on ssh event stream:")
+ self._close()
+ time.sleep(5)
+
+ def run(self):
+ while True:
+ self._run()
+
+class Gerrit(object):
+ log = logging.getLogger("gerrit.Gerrit")
+
+ def __init__(self, hostname, username, keyfile=None):
+ self.username = username
+ self.hostname = hostname
+ self.keyfile = keyfile
+ self.watcher_thread = None
+ self.event_queue = None
+
+ def startWatching(self):
+ self.event_queue = Queue.Queue()
+ self.watcher_thread = GerritWatcher(
+ self,
+ self.username,
+ self.hostname,
+ keyfile=self.keyfile)
+ self.watcher_thread.start()
+
+ def addEvent(self, data):
+ return self.event_queue.put(data)
+
+ def getEvent(self):
+ return self.event_queue.get()
+
+ def review(self, project, change, message, action={}):
+ cmd = 'gerrit review --project %s --message "%s"' % (
+ project, message)
+ for k,v in action.items():
+ if v == True:
+ cmd += ' --%s' % k
+ else:
+ cmd += ' --%s %s' % (k, v)
+ cmd += ' %s' % change
+ out, err = self._ssh(cmd)
+ return err
+
+ def query(self, change):
+ cmd = 'gerrit query --format json %s"' % (
+ change)
+ out, err = self._ssh(cmd)
+ if not out:
+ return False
+ lines = out.split('\n')
+ if not lines:
+ return False
+ data = json.loads(lines[0])
+ if not data:
+ return False
+ self.log.debug("Received data from Gerrit query: \n%s" % (
+ pprint.pformat(data)))
+ return data
+
+ def _ssh(self, command):
+ client = paramiko.SSHClient()
+ client.load_system_host_keys()
+ client.set_missing_host_key_policy(paramiko.WarningPolicy())
+ client.connect(self.hostname,
+ username=self.username,
+ port=29418)
+
+ self.log.debug("SSH command:\n%s" % command)
+ stdin, stdout, stderr = client.exec_command(command)
+
+ out = stdout.read()
+ self.log.debug("SSH received stdout:\n%s" % out)
+
+ ret = stdout.channel.recv_exit_status()
+ self.log.debug("SSH exit status: %s" % ret)
+
+ err = stderr.read()
+ self.log.debug("SSH received stderr:\n%s" % err)
+ if ret:
+ raise Exception("Gerrit error executing %s" % command)
+ return (out, err)