#!/usr/bin/python # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Copyright 2005 Dan Williams and Red Hat, Inc. import sys import os import socket import signal import time from plague import AuthedXMLRPCServer from plague import HTTPServer from plague import daemonize from plague import DebugUtils import SimpleXMLRPCServer from optparse import OptionParser import threading sys.path.append('/usr/share/plague/server') import User import BuildMaster import BuilderManager import DBManager import Config from UserInterface import UserInterfaceSSLAuth from UserInterface import UserInterfaceNoAuth class AuthenticatedSSLXMLRPCServer(AuthedXMLRPCServer.AuthedSSLXMLRPCServer): """ SSL XMLRPC server that authenticates clients based on their certificate. """ def __init__(self, address, certs, db_manager, cfg): AuthedXMLRPCServer.AuthedSSLXMLRPCServer.__init__(self, address, self.auth_cb, certs) self.authenticator = User.Authenticator(db_manager, cfg) def auth_cb(self, request, client_address): peer_cert = request.get_peer_certificate() email = peer_cert.get_subject().emailAddress try: user = self.authenticator.new_authed_user(email, client_address) except Exception: user = None return user ################################################################# bm_server = None def exit_handler(signum, frame): global bm_server print "Received SIGTERM, quitting..." bm_server.stop() def main(): global bm_server usage = "Usage: %s [-p ] [-l ] [-d] [-c ]" % sys.argv[0] parser = OptionParser(usage=usage) parser.add_option("-p", "--pidfile", default=None, help='file to write the PID to') parser.add_option("-l", "--logfile", default=None, help="location of file to write log output to") parser.add_option("-d", "--daemon", default=False, action="store_true", help="daemonize (i.e., detach from the terminal)") parser.add_option("-c", "--configfile", default="/etc/plague/server/plague-server.cfg", help='server configuration file, default: /etc/plague/server/plague-server.cfg') (opts, args) = parser.parse_args() if not opts.configfile: print "Must specify a config file." sys.exit(1) if opts.daemon: ret=daemonize.createDaemon() if ret: print "Daemonizing failed!" os._exit(2) if opts.pidfile: open(opts.pidfile, 'w').write('%d\n' % os.getpid()) if opts.logfile: # 1 == line buffer the log file log=open(opts.logfile, 'a', 1) sys.stdout=log sys.stderr=log # Load in our config, filling in with defaults if it doesn't exist cfg = Config.ServerConfig(opts.configfile) cfg.load_target_configs() if len(cfg.targets()) == 0: print "You need at least one target to do anything useful." os._exit(3) hostname = cfg.get_str("General", "hostname") # Start the debugging server use_tbs = False try: use_tbs = cfg.get_bool("General", "traceback_server") if use_tbs: tbs_address = "/tmp/plague-server-debug-%s" % hostname tbs = DebugUtils.ThreadTracebackServer(tbs_address) tbs.start() except Config.BaseConfig.ConfigError: pass dbm = DBManager.DBManager(cfg) # Create the BuildMaster thread try: builder_manager = BuilderManager.BuilderManager(cfg) except Exception, exc: print "Couldn't create BuilderManager: %s" % exc os._exit(4) bm = BuildMaster.BuildMaster(builder_manager, dbm, cfg) bm.start() # Create the BuildMaster XMLRPC server port = cfg.get_int("UI", "port") ui = None try: if cfg.get_bool("UI", "use_ssl") == True: ui_certs = {} ui_certs['key_and_cert'] = cfg.get_str("SSL", "server_key_and_cert") ui_certs['ca_cert'] = cfg.get_str("SSL", "ca_cert") ui_certs['peer_ca_cert'] = cfg.get_str("UI", "client_ca_cert") ui = UserInterfaceSSLAuth(builder_manager, bm, dbm, cfg) bm_server = AuthenticatedSSLXMLRPCServer((hostname, port), ui_certs, dbm, cfg) else: ui = UserInterfaceNoAuth(builder_manager, bm, dbm, cfg) bm_server = AuthedXMLRPCServer.AuthedXMLRPCServer((hostname, port)) except socket.error, exc: if exc[0] == 98: # Address already in use print "Error: couldn't bind to address '%s:%s'. Is the server already running?" % (hostname, port) os._exit(4) bm_server.register_instance(ui) # Create dummy thread just to register main thread's name dummy = threading.Thread() dummy.setName("MainThread") DebugUtils.registerThreadName(dummy) del dummy # Set up our termination handler signal.signal(signal.SIGTERM, exit_handler) print "Build Server accepting requests on %s:%d.\n" % (hostname, port) # Serve requests until we're told to stop try: bm_server.serve_forever() except KeyboardInterrupt: bm_server.server_close() # Make sure the BuildMaster thread shuts down print "Shutting down..." bm.stop() if use_tbs: tbs.stop() builder_manager.stop() if opts.pidfile: os.unlink(opts.pidfile) try: time.sleep(2) except KeyboardInterrupt: pass print "Done." os._exit(0) if __name__ == '__main__': main()