extras-buildsys/server UserInterface.py, NONE, 1.1 CONFIG.py, 1.7, 1.8 User.py, 1.1, 1.2 buildserver.py, 1.5, 1.6

Daniel Williams (dcbw) fedora-extras-commits at redhat.com
Tue Jun 14 13:37:44 UTC 2005


Author: dcbw

Update of /cvs/fedora/extras-buildsys/server
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv4079/server

Modified Files:
	CONFIG.py User.py buildserver.py 
Added Files:
	UserInterface.py 
Log Message:
2005-06-14  Dan Williams <dcbw at redhat.com>

    * server/CONFIG.py
        - New options "ssl_frontend" and "ssl_buildclients".  Only ssl_frontend is
            used at this time.  Setting it to True requires use of SSL to submit
            build jobs and get server status.  Setting it to False allows use of
            xmlrpclib connections over HTTP, no certificates involved.

    * server/User.py
        - Add guest member to User class

    * server/buildserver.py
        - Move UserInterface class to UserInterface.py
        - Re-enable the non-SSL XMLRPC server code
        - Switch XMLRPC servers between SSL/non-SSL depending on CONFIG's
            ssl_frontend value
        - VerifiableSSLXMLRPCServer -> AuthenticatedSSLXMLRPCServer

    * server/UserInterface.py
        - Generalize UserInterface into a base class
        - Implement UserInterfaceSSLAuth to handle SSL authenticated requests
        - Implement UserInterfaceNoAuth to handle non-SSL requests




--- NEW FILE UserInterface.py ---
# 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 <dcbw at redhat.com> and Red Hat, Inc.


import CONFIG
import sqlite
import smtplib
from email.MIMEText import MIMEText
import time
import sys
import os
from buildmaster import ensure_build_db_tables


def email_result(email, cvs_tag, resultstring, subject=None):
    """send 'resultstring' to email"""
    
    msg = MIMEText(resultstring)
    if not subject:
        subject = 'Build Result: %s' % cvs_tag
    msg['Subject'] = subject
    msg['From'] = CONFIG.get('email_from')
    email_to = '%s@%s' % (username, CONFIG.get('email_to_domain'))
    msg['To'] = email_to
    s = smtplib.SMTP()
    s.connect()
    s.sendmail(CONFIG.get('email_from'), [email_to], msg.as_string())
    s.close()



class UserInterface:
    """
    Base UserInterface class. NO AUTHENTICATION.  Subclass this to provide some.
    """

    def __init__(self, client_manager):
        self.bcm = client_manager
        self.dbcx = sqlite.connect("jobdb", encoding="utf-8", timeout=2)
        self.curs = self.dbcx.cursor()
        ensure_build_db_tables(self.dbcx)


    def __del__(self):
        self.dbcx.close()


    def _insert_job(self, email, package, cvs_tag, target, buildreq, time):
        # Insert request into the database
        self.curs.execute('INSERT INTO jobs (uid, username, package,' \
                ' cvs_tag, target, buildreq, time_submitted, status)' \
                ' VALUES (NULL, "%s", "%s", "%s", "%s", "%s", %d, "%s")' \
                % (email, package, cvs_tag, target, buildreq, time, 'waiting'))
        self.dbcx.commit()

        # Find the UID
        self.curs.execute('SELECT uid FROM jobs WHERE username="%s" AND' \
                ' package="%s" AND cvs_tag="%s" AND target="%s" AND' \
                ' buildreq="%s" AND time_submitted=%d AND status="waiting"' \
                % (email, package, cvs_tag, target, buildreq, time))
        self.dbcx.commit()
        item = self.curs.fetchone()
        return item['uid']


    def enqueue(self, email, package, cvs_tag, target, buildreq=None):
        """ Accept a job to build and stuff it into the job database """

        if CONFIG.get('use_srpm_not_cvs') == True:
            email_result(email, cvs_tag, "Error setting up build for %s on "\
                    "%s: this server builds SRPMs, not CVS checkouts." % (cvs_tag, target))
            return (-1, "This build server is set up for building SRPMS only.  Use the 'enqueue_srpm' command instead.")

        print "Request to enqueue '%s' tag '%s' for target '%s' (user '%s')" \
                % (package, cvs_tag, target, email)
        targets = CONFIG.get('targets')
        jobid = -1
        if not targets.has_key(target):
            print "Error setting up build for %s on %s: target does not exist."\
                    % (cvs_tag, target)
            email_result(email, cvs_tag, "Error setting up build for %s on "\
                    "%s: target does not exist." % (cvs_tag, target))
            return (-1, "This build server does not support the target %s." % target)
        else:
            jobid = self._insert_job(email, package, cvs_tag, target, buildreq, time.time())
        return (0, "Success: package has been queued.", jobid)


    def enqueue_srpm(self, email, package, srpm_file, target, buildreq=None):
        """ Accept a job to build from SRPM file and stuff it into the job database """

        if CONFIG.get('use_srpm_not_cvs') == False:
            email_result(email, srpm_file, "Error setting up build for %s on "\
                    "%s: this server builds CVS checkouts, not SRPMS." % (srpm_file, target))
            return (-1, "This build server is set up for building from CVS.  Use the 'enqueue' command instead.")

        # We limit the database field to 255 chars
        if len(srpm_file) > 255:
            email_result(email, srpm_file, "Error setting up build for %s on "\
                    "%s: try using a shorter path to the SRPM (< 255 chars)." % (srpm_file, target))
            return (-1, "Pathname to SRPM is limited to 255 characters.")

        print "Request to enqueue '%s' file '%s' for target '%s' (user '%s')" \
                % (package, srpm_file, target, email)
        targets = CONFIG.get('targets')
        jobid = -1
        if not targets.has_key(target):
            print "Error setting up build for %s on %s: target does not exist."\
                    % (srpm_file, target)
            email_result(email, srpm_file, "Error setting up build for %s on "\
                    "%s: target does not exist." % (srpm_file, target))
            return (-1, "This build server does not support the target %s." % target)
        else:
            jobid = self._insert_job(email, package, cvs_tag, target, buildreq, time.time())
        return (0, "Success: package has been queued.", jobid)


    def list_waiting_jobs(self):
        self.curs.execute('SELECT uid, username, package, cvs_tag, target' \
                ' FROM jobs WHERE status="waiting"')
        self.dbcx.commit()
        data = self.curs.fetchall()
        job_list = []
        for row in data:
            tempX = [ item for item in row]
            job_list.append(tempX)
        return job_list


    def list_building_jobs(self):
        self.curs.execute('SELECT uid, username, package, cvs_tag, target' \
                ' FROM jobs WHERE status="building"')
        self.dbcx.commit()
        data = self.curs.fetchall()
        job_list = []
        for row in data:
            tempX = [ item for item in row]
            job_list.append(tempX)
        return job_list


    def update_clients(self):
        reload(CONFIG)
        print "-----------------------------------------------------"
        print " Looking for Build Clients..."
        self.bcm.update_clients()
        print "-----------------------------------------------------\n"
        return (0, "Success.")



class UserInterfaceSSLAuth(UserInterface):
    """
    Allow/Deny operations based on user privileges
    """

    def enqueue(self, user, package, cvs_tag, target, buildreq=None):
        if not user.own_jobs:
            return (-1, "Insufficient privileges.")
        return UserInterface.enqueue(self, user.email, package, cvs_tag, target, buildreq)


    def enqueue_srpm(self, user, package, srpm_file, target, buildreq=None):
        if not user.own_jobs:
            return (-1, "Insufficient privileges.")
        return UserInterface.enqueue_srpm(self, user.email, package, cvs_tag, target, buildreq)


    def list_waiting_jobs(self, user):
        return UserInterface.list_waiting_jobs(self)


    def list_building_jobs(self, user):
        return UserInterface.list_building_jobs(self)


    def update_clients(self, user):
        if not user.server_admin:
            return (-1, "Insufficient privileges.")
        return UserInterface.update_clients(self)


class UserInterfaceNoAuth(UserInterface):
    """
    Allow all operations, NULL authentication
    """

    def enqueue(self, email, package, cvs_tag, target, buildreq=None):
        return UserInterface.enqueue(self, email, package, cvs_tag, target, buildreq)


    def enqueue_srpm(self, email, package, srpm_file, target, buildreq=None):
        return UserInterface.enqueue_srpm(self, email, package, cvs_tag, target, buildreq)


    def list_waiting_jobs(self):
        return UserInterface.list_waiting_jobs(self)


    def list_building_jobs(self):
        return UserInterface.list_building_jobs(self)


    def update_clients(self):
        return UserInterface.update_clients(self)



Index: CONFIG.py
===================================================================
RCS file: /cvs/fedora/extras-buildsys/server/CONFIG.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- CONFIG.py	14 Jun 2005 01:16:30 -0000	1.7
+++ CONFIG.py	14 Jun 2005 13:37:42 -0000	1.8
@@ -11,6 +11,15 @@
 config_opts['log_url'] = "http://foo.foo.org/logs/"
 config_opts['guest_allowed'] = True
 
+# SSL options
+#
+# ssl_frontend: True = package submitters need SSL to connect to the server
+config_opts['ssl_frontend'] = True
+# ssl_buildclients: True = all communication between server & build client
+# be over an SSL connecction
+config_opts['ssl_buildclients'] = True
+
+
 SERVER_BASE_DIR = "/work/fedora-cvs/extras-buildsys/server"
 
 # SSL Cert and key bits


Index: User.py
===================================================================
RCS file: /cvs/fedora/extras-buildsys/server/User.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- User.py	14 Jun 2005 01:16:30 -0000	1.1
+++ User.py	14 Jun 2005 13:37:42 -0000	1.2
@@ -20,10 +20,11 @@
 
 
 class User:
-    def __init__(self, email):
+    def __init__(self, email, guest):
         if not email:
             raise Exception
         self.email = email
+        self.guest = guest
         self.own_jobs = False
         self.kill_any_job = False
         self.modify_users = False
@@ -65,13 +66,13 @@
         self.dbcx.commit()
         item = self.curs.fetchone()
         if item:
-            user = User(email)
+            user = User(email, False)
             user.own_jobs = item['own_jobs']
             user.kill_any_job = item['kill_any_job']
             user.modify_users = item['modify_users']
             user.server_admin = item['server_admin']
         else:
             if CONFIG.get('guest_allowed'):
-                user = User('guest at guest')
+                user = User('guest at guest', True)
         return user
 


Index: buildserver.py
===================================================================
RCS file: /cvs/fedora/extras-buildsys/server/buildserver.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- buildserver.py	14 Jun 2005 01:16:30 -0000	1.5
+++ buildserver.py	14 Jun 2005 13:37:42 -0000	1.6
@@ -16,169 +16,23 @@
 # written by Seth Vidal
 
 
-import time
 import CONFIG
-import socket
 import sys
 import os
-import sqlite
-import smtplib
-from email.MIMEText import MIMEText
-import threading
 from buildmaster import BuildMaster
-from buildmaster import ensure_build_db_tables
 from client_manager import BuildClientManager
 import SimpleHTTPSServer
 import SimpleSSLXMLRPCServer
 import User
+from UserInterface import UserInterfaceSSLAuth, UserInterfaceNoAuth
+import SimpleXMLRPCServer
 
 
-def email_result(username, cvs_tag, resultstring, subject=None):
-    """send 'resultstring' to username"""
-    
-    msg = MIMEText(resultstring)
-    if not subject:
-        subject = 'Build Result: %s' % cvs_tag
-    msg['Subject'] = subject
-    msg['From'] = CONFIG.get('email_from')
-    email_to = '%s@%s' % (username, CONFIG.get('email_to_domain'))
-    msg['To'] = email_to
-    s = smtplib.SMTP()
-    s.connect()
-    s.sendmail(CONFIG.get('email_from'), [email_to], msg.as_string())
-    s.close()
-
-
-class UserInterface:
-    def __init__(self, client_manager):
-        self.bcm = client_manager
-        self.dbcx = sqlite.connect("jobdb", encoding="utf-8", timeout=2)
-        self.curs = self.dbcx.cursor()
-        ensure_build_db_tables(self.dbcx)
-
-    def __del__(self):
-        self.dbcx.close()
-
-    def _insert_job(self, username, package, cvs_tag, target, buildreq, time):
-        # Insert request into the database
-        self.curs.execute('INSERT INTO jobs (uid, username, package,' \
-                ' cvs_tag, target, buildreq, time_submitted, status)' \
-                ' VALUES (NULL, "%s", "%s", "%s", "%s", "%s", %d, "%s")' \
-                % (username, package, cvs_tag, target, buildreq, time, 'waiting'))
-        self.dbcx.commit()
-
-        # Find the UID
-        self.curs.execute('SELECT uid FROM jobs WHERE username="%s" AND' \
-                ' package="%s" AND cvs_tag="%s" AND target="%s" AND' \
-                ' buildreq="%s" AND time_submitted=%d AND status="waiting"' \
-                % (username, package, cvs_tag, target, buildreq, time))
-        self.dbcx.commit()
-        item = self.curs.fetchone()
-        return item['uid']
-
-    def enqueue(self, user, username, package, cvs_tag, target, buildreq=None):
-        """ Accept a job to build and stuff it into the job database """
-
-        if not user.own_jobs:
-            return (-1, "Insufficient privileges.")
-
-        if CONFIG.get('use_srpm_not_cvs') == True:
-            email_result(username, cvs_tag, "Error setting up build for %s on "\
-                    "%s: this server builds SRPMs, not CVS checkouts." % (cvs_tag, target))
-            return (-1, "This build server is set up for building SRPMS only.  Use the 'enqueue_srpm' command instead.")
-
-        print "Request to enqueue '%s' tag '%s' for target '%s' (user '%s')" \
-                % (package, cvs_tag, target, username)
-        targets = CONFIG.get('targets')
-        jobid = -1
-        if not targets.has_key(target):
-            print "Error setting up build for %s on %s: target does not exist."\
-                    % (cvs_tag, target)
-            email_result(username, cvs_tag, "Error setting up build for %s on "\
-                    "%s: target does not exist." % (cvs_tag, target))
-            return (-1, "This build server does not support the target %s." % target)
-        else:
-            jobid = self._insert_job(username, package, cvs_tag, target, buildreq, time.time())
-        return (0, "Success: package has been queued.", jobid)
-
-    def enqueue_srpm(self, user, username, package, srpm_file, target, buildreq=None):
-        """ Accept a job to build from SRPM file and stuff it into the job database """
-
-        if not user.own_jobs:
-            return (-1, "Insufficient privileges.")
-
-        if CONFIG.get('use_srpm_not_cvs') == False:
-            email_result(username, srpm_file, "Error setting up build for %s on "\
-                    "%s: this server builds CVS checkouts, not SRPMS." % (srpm_file, target))
-            return (-1, "This build server is set up for building from CVS.  Use the 'enqueue' command instead.")
-
-        # We limit the database field to 255 chars
-        if len(srpm_file) > 255:
-            email_result(username, srpm_file, "Error setting up build for %s on "\
-                    "%s: try using a shorter path to the SRPM (< 255 chars)." % (srpm_file, target))
-            return (-1, "Pathname to SRPM is limited to 255 characters.")
-
-        print "Request to enqueue '%s' file '%s' for target '%s' (user '%s')" \
-                % (package, srpm_file, target, username)
-        targets = CONFIG.get('targets')
-        jobid = -1
-        if not targets.has_key(target):
-            print "Error setting up build for %s on %s: target does not exist."\
-                    % (srpm_file, target)
-            email_result(username, srpm_file, "Error setting up build for %s on "\
-                    "%s: target does not exist." % (srpm_file, target))
-            return (-1, "This build server does not support the target %s." % target)
-        else:
-            jobid = self._insert_job(username, package, cvs_tag, target, buildreq, time.time())
-        return (0, "Success: package has been queued.", jobid)
-
-
-    def list_waiting_jobs(self, user):
-        self.curs.execute('SELECT uid, username, package, cvs_tag, target' \
-                ' FROM jobs WHERE status="waiting"')
-        self.dbcx.commit()
-        data = self.curs.fetchall()
-        job_list = []
-        for row in data:
-            tempX = [ item for item in row]
-            job_list.append(tempX)
-        return job_list
-
-
-    def list_building_jobs(self, user):
-        self.curs.execute('SELECT uid, username, package, cvs_tag, target' \
-                ' FROM jobs WHERE status="building"')
-        self.dbcx.commit()
-        data = self.curs.fetchall()
-        job_list = []
-        for row in data:
-            tempX = [ item for item in row]
-            job_list.append(tempX)
-        return job_list
-
-
-    def update_clients(self, user):
-        if not user.server_admin:
-            return (-1, "Insufficient privileges.")
-
-        reload(CONFIG)
-        print "-----------------------------------------------------"
-        print " Looking for Build Clients..."
-        self.bcm.update_clients()
-        print "-----------------------------------------------------\n"
-        return (0, "Success.")
-
-
-# Unused for SSL connections, but keep around just in case
-# we give users the option of not using SSL at some later date
-#
-#class MyXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
-#    def __init__(self, address):
-#        self.allow_reuse_address = 1
-#        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, address, logRequests=0)
+class AuthenticatedSSLXMLRPCServer(SimpleSSLXMLRPCServer.SimpleSSLXMLRPCServer):
+    """
+    SSL XMLRPC server that authenticates clients based on their certificate.
+    """
 
-
-class VerifiableSSLXMLRPCServer(SimpleSSLXMLRPCServer.SimpleSSLXMLRPCServer):
     def __init__(self, certs, address):
         SimpleSSLXMLRPCServer.SimpleSSLXMLRPCServer.__init__(self, certs, address, self.auth_cb)
         self.authenticator = User.Authenticator()
@@ -198,6 +52,18 @@
         return user
 
 
+class MyXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
+    """
+    Simple XMLRPC server that turns on address reuse.
+    """
+
+    def __init__(self, address):
+        self.allow_reuse_address = 1
+        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, address, logRequests=0)
+
+
+#################################################################
+
 if __name__ == '__main__':
     if len(sys.argv) < 2:
         print "Usage:\n"
@@ -226,8 +92,13 @@
     ui_certs['peer_ca_cert'] = CONFIG.get('ui_ca_cert')
 
     # Create the BuildMaster XMLRPC server
-    ui = UserInterface(bcm)
-    bm_server = VerifiableSSLXMLRPCServer(ui_certs, (hostname, 8887))
+    ui = None
+    if CONFIG.get('ssl_frontend') == True:
+        ui = UserInterfaceSSLAuth(bcm)
+        bm_server = AuthenticatedSSLXMLRPCServer(ui_certs, (hostname, 8887))
+    else:
+        ui = UserInterfaceNoAuth(bcm)
+        bm_server = MyXMLRPCServer((hostname, 8887))
     bm_server.register_instance(ui)
 
     # SRPM fileserver




More information about the fedora-extras-commits mailing list