Use entrypoints for zuul-server.
If we put the code for zuul-server into the zuul module, then autodoc
will pick it up for documentation.
Change-Id: Idf2db82f706243c6e69984170b4783f1eece2237
Reviewed-on: https://review.openstack.org/16850
Reviewed-by: Clark Boylan <clark.boylan@gmail.com>
Reviewed-by: James E. Blair <corvus@inaugust.com>
Approved: James E. Blair <corvus@inaugust.com>
Tested-by: Jenkins
diff --git a/zuul/cmd/server.py b/zuul/cmd/server.py
new file mode 100755
index 0000000..4f77610
--- /dev/null
+++ b/zuul/cmd/server.py
@@ -0,0 +1,142 @@
+# 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 argparse
+import ConfigParser
+import daemon
+
+try:
+ import daemon.pidlockfile as pid_file_module
+ pid_file_module # workaround for pyflakes issue #13
+except:
+ # as of python-daemon 1.6 it doesn't bundle pidlockfile anymore
+ # instead it depends on lockfile-0.9.1 which uses pidfile.
+ import daemon.pidfile as pid_file_module
+
+import logging.config
+import os
+import signal
+
+# No zuul imports here because they pull in paramiko which must not be
+# imported until after the daemonization.
+# https://github.com/paramiko/paramiko/issues/59
+
+
+class Server(object):
+ def __init__(self):
+ self.args = None
+ self.config = None
+
+ def parse_arguments(self):
+ parser = argparse.ArgumentParser(description='Project gating system.')
+ parser.add_argument('-c', dest='config',
+ help='specify the config file')
+ parser.add_argument('-d', dest='nodaemon', action='store_true',
+ help='do not run as a daemon')
+ self.args = parser.parse_args()
+
+ def read_config(self):
+ self.config = ConfigParser.ConfigParser()
+ if self.args.config:
+ locations = [self.args.config]
+ else:
+ locations = ['/etc/zuul/zuul.conf',
+ '~/zuul.conf']
+ for fp in locations:
+ if os.path.exists(os.path.expanduser(fp)):
+ self.config.read(os.path.expanduser(fp))
+ return
+ raise Exception("Unable to locate config file in %s" % locations)
+
+ def setup_logging(self):
+ if self.config.has_option('zuul', 'log_config'):
+ fp = os.path.expanduser(self.config.get('zuul', 'log_config'))
+ if not os.path.exists(fp):
+ raise Exception("Unable to read logging config file at %s" %
+ fp)
+ logging.config.fileConfig(fp)
+ else:
+ logging.basicConfig(level=logging.DEBUG)
+
+ def reconfigure_handler(self, signum, frame):
+ signal.signal(signal.SIGHUP, signal.SIG_IGN)
+ self.read_config()
+ self.setup_logging()
+ self.sched.reconfigure(self.config)
+ signal.signal(signal.SIGHUP, self.reconfigure_handler)
+
+ def exit_handler(self, signum, frame):
+ signal.signal(signal.SIGUSR1, signal.SIG_IGN)
+ self.sched.exit()
+
+ def main(self):
+ # See comment at top of file about zuul imports
+ import zuul.scheduler
+ import zuul.launcher.jenkins
+ import zuul.trigger.gerrit
+
+ self.sched = zuul.scheduler.Scheduler()
+
+ jenkins = zuul.launcher.jenkins.Jenkins(self.config, self.sched)
+ gerrit = zuul.trigger.gerrit.Gerrit(self.config, self.sched)
+
+ self.sched.setLauncher(jenkins)
+ self.sched.setTrigger(gerrit)
+
+ self.sched.start()
+ self.sched.reconfigure(self.config)
+ self.sched.resume()
+ signal.signal(signal.SIGHUP, self.reconfigure_handler)
+ signal.signal(signal.SIGUSR1, self.exit_handler)
+ while True:
+ try:
+ signal.pause()
+ except KeyboardInterrupt:
+ print "Ctrl + C: asking scheduler to exit nicely...\n"
+ self.exit_handler(signal.SIGINT, None)
+
+
+def main():
+ server = Server()
+ server.parse_arguments()
+ server.read_config()
+
+ if server.config.has_option('zuul', 'state_dir'):
+ state_dir = os.path.expanduser(server.config.get('zuul', 'state_dir'))
+ else:
+ state_dir = '/var/lib/zuul'
+ test_fn = os.path.join(state_dir, 'test')
+ try:
+ f = open(test_fn, 'w')
+ f.close()
+ os.unlink(test_fn)
+ except:
+ print
+ print "Unable to write to state directory: %s" % state_dir
+ print
+ raise
+
+ if server.config.has_option('zuul', 'pidfile'):
+ pid_fn = os.path.expanduser(server.config.get('zuul', 'pidfile'))
+ else:
+ pid_fn = '/var/run/zuul/zuul.pid'
+ pid = pid_file_module.TimeoutPIDLockFile(pid_fn, 10)
+
+ if server.args.nodaemon:
+ server.setup_logging()
+ server.main()
+ else:
+ with daemon.DaemonContext(pidfile=pid):
+ server.setup_logging()
+ server.main()