extras-buildsys/utils package-builder, NONE, 1.1 package-builder.py, NONE, 1.1 user-manager.py, NONE, 1.1

Daniel Williams (dcbw) fedora-extras-commits at redhat.com
Tue Jun 14 01:16:33 UTC 2005


Author: dcbw

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

Added Files:
	package-builder package-builder.py user-manager.py 
Log Message:
2005-06-13  Dan Williams <dcbw at redhat.com>

    * client/buildclient.py
      common/FileDownloader.py
      common/HTTPSURLopener.py
      common/SSLCommon.py
      common/SSLXMLRPCServerProxy.py
      common/SimpleHTTPSServer.py
      common/SimpleSSLXMLRPCServer.py
      server/client_manager.py
        - Clean up cert handling by stuffing cert file paths into a dict

    * common/SSLCommon.py
        - QuietSSLServer: new class to quiet certain SSL errors we don't care about

    * common/SimpleSSLXMLRPCServer.py
        - Add an authorization framework.  The actual request gets authorized
            in SimpleSSLXMLRPCServer, but since we need to pass the authorization
            object back up to the Instance class, we need to override a bunch
            of functions in superclasses just to pass the object through.  Subclasses
            of SimpleSSLXMLRPCServer don't need to use authorization, they just don't
            set an auth callback.  If authorization is in use, the subclass is asked
            to authorize the connection, and passes back an arbitrary authorization
            object, which gets passed to each Handler method.

    * server/buildmaster.py
      server/buildserver.py
        - Change buildmaster_db -> jobdb

    * server/buildserver.py
        - XMLRPCBuildMaster -> UserInterface
        - Attach authorization to all public XMLRPC methods
        - VerifiableSSLXMLRPCServer: new class to handle request authorization
        - Add "guest" user support.  If the user's cert checks out but they are not
            in the user database, they have read-only permission to the server

    * server/User.py
        - New User object: encapsulates all permissions that a user might
            have.
        - New UserAuthentication object: looks up user authentication info in
            a user database and creates User objects

    * utils/user-manager.py
        - Local user administration tool

    * utils/package-builder.py
        - New CLI front-end to the build system that support XMLRPC over SSL

    * utils/certs/fedora-upload-ca.cert
        - Fedora CVS Upload CA certificate, required to validate users




--- NEW FILE package-builder ---
#!/bin/bash

export PYTHONPATH="$PYTHONPATH:../common"
python package-builder.py $@


--- NEW FILE package-builder.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 sys, os
import SSLXMLRPCServerProxy
import ConfigParser
import M2Crypto


config = ConfigParser.ConfigParser()
config.add_section('Certs')
config.set('Certs', 'user-cert', '~/.fedora.cert')
config.set('Certs', 'user-key', '')
config.set('Certs', 'user-ca-cert', '~/.fedora-upload-ca.cert')
config.set('Certs', 'server-ca-cert', '~/.fedora-server-ca.cert')

config.add_section('Server')
config.set('Server', 'address', 'https://127.0.0.1:8887')

config.read([os.path.expanduser('~/.package-builder.cfg')])

# Write out config file if it doesn't exist
if not os.path.exists(os.path.expanduser('~/.package-builder.cfg')):
    f = open(os.path.expanduser('~/.package-builder.cfg'), "w+")
    config.write(f)
    f.close()


def getSSLXMLRPCServerProxy():
    """
    Create an SSL XMLRPC Server Proxy object that uses certificates for verification
    """

    certs = {}
    certs['cert'] = os.path.expanduser(config.get('Certs', 'user-cert'))
    client_key = config.get('Certs', 'user-key')
    # If client-key is empty, key assumed to be in user-cert
    certs['key'] = None
    if len(client_key) > 0:
        certs['key'] = os.path.expanduser(client_key)
    certs['ca_cert'] = os.path.expanduser(config.get('Certs', 'user-ca-cert'))
    certs['peer_ca_cert'] = os.path.expanduser(config.get('Certs', 'server-ca-cert'))
    return SSLXMLRPCServerProxy.SSLXMLRPCServerProxy(certs, config.get('Server', 'address'))


def enqueue(server, args):
    pass


def list_waiting_jobs(server):
    try:
        print server.list_waiting_jobs()
    except M2Crypto.SSL.SSLError, e:
        print "Error connecting to build server: '%s'" % e


def update_clients(server):
    try:
        print server.update_clients()
    except M2Crypto.SSL.SSLError, e:
        print "Error connecting to build server: '%s'" % e


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print "Usage:\npackage-builder.py <command>\n\n"
        sys.exit(1)

    cmd = sys.argv[1]

    server = getSSLXMLRPCServerProxy()

    if cmd == 'enqueue':
        enqueue(server, sys.argv[2:])
    elif cmd == 'list_waiting_jobs':
        list_waiting_jobs(server)
    elif cmd == 'update_clients':
        update_clients(server)



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


import sys, os
import sqlite


def print_usage(prog):
    print "Usage:\n"
    print "   %s <dbfile> <command ...>\n\n" % prog
    print "      Commands:"
    print "         add <email> [own_jobs] [kill_any_job] [modify_users] [server_admin]"
    print "         del <email>"
    print "         mod <email> [+/-own_jobs] [+/-kill_any_job] [+/-modify_users] [+/-server_admin]"
    print "         find <search string>"


class UserManagerException:
    def __init__(self, message):
        self.message = message


class UserManager:
    def __init__(self, dbfile):
        self.dbcx = sqlite.connect(dbfile, encoding="utf-8", timeout=2)
        self.curs = self.dbcx.cursor()

        # Ensure the table exists in the database
        create = False
        try:
            self.curs.execute('SELECT * FROM users')
            self.dbcx.commit()
        except sqlite._sqlite.DatabaseError, e:
            create = True

        if create:
            self.curs.execute('CREATE TABLE users (email VARCHAR(50), ' \
                    'own_jobs BOOLEAN, kill_any_job BOOLEAN, ' \
                    'modify_users BOOLEAN, server_admin BOOLEAN)')
            self.dbcx.commit()

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

    def dispatch(self, prog, command, args):
        if command == 'add':
            um.add_user(args)
        elif command == 'del':
            um.del_user(args)
        elif command == 'mod':
            um.mod_user(args)
        elif command == 'find':
            um.find_user(args)
        else:
            print_usage(prog)

    def add_user(self, args):
        if len(args) < 1:
            raise UserManagerException("Invalid command, too few options.")

        email = args[0]
        self.curs.execute('SELECT * FROM users WHERE email="%s"' % email)
        self.dbcx.commit()
        item = self.curs.fetchone()
        if item:
            raise UserManagerException("User %s already exists." % email)

        own_jobs = 0
        kill_any_job = 0
        modify_users = 0
        server_admin = 0
        for arg in args[1:]:
            if arg == 'own_jobs':
                own_jobs = 1
            elif arg == 'kill_any_job':
                kill_any_job = 1
            elif arg == 'modify_users':
                modify_users = 1
            elif arg == 'server_admin':
                server_admin = 1
            else:
                raise UserManagerException("The user privilege '%s' is unknown." % arg)

        self.curs.execute('INSERT INTO users (email, own_jobs, kill_any_job,' \
                ' modify_users, server_admin) VALUES ("%s", %d, %d, %d, %d)' \
                % (email, own_jobs, kill_any_job, modify_users, server_admin))
        self.dbcx.commit()
        print "User %s added." % email

    def del_user(self, args):
        if len(args) < 1:
            raise UserManagerException("Invalid command, too few options.")

        email = args[0]
        self.curs.execute('SELECT * FROM users WHERE email="%s"' % email)
        self.dbcx.commit()
        item = self.curs.fetchone()
        if not item:
            raise UserManagerException("User %s doesn't exist." % email)

        sys.stdout.write("Really delete %s? (y/n): " % email)
        resp = sys.stdin.readline()
        resp = resp.lower().strip()
        if resp == 'y' or resp == 'yes':
            self.curs.execute('DELETE FROM users WHERE email="%s"' % email)
            self.dbcx.commit()
            print "User %s deleted." % email
        else:
            print "User %s not deleted." % email

    def _cap_to_num(self, cap):
        if cap == '-':
            return 0
        elif cap == '+':
            return 1
        else:
            raise UserManagerException("Invalid format '%s', privileges must begin with + or -." % option)

    def mod_user(self, args):
        if len(args) < 1:
            raise UserManagerException("Invalid command, too few options.")

        email = args[0]
        self.curs.execute('SELECT * FROM users WHERE email="%s"' % email)
        self.dbcx.commit()
        item = self.curs.fetchone()
        if not item:
            raise UserManagerException("User %s doesn't exist." % email)

        own_jobs = item['own_jobs']
        kill_any_job = item['kill_any_job']
        modify_users = item['modify_users']
        server_admin = item['server_admin']
        for opt in args[1:]:
            if opt[0] != '+' and opt[0] != '-':
                raise UserManagerException("Invalid format '%s', privileges must begin with + or -." % opt)
            priv = opt[1:]
            if priv == 'own_jobs':
                own_jobs = self._cap_to_num(opt[0])
            elif priv == 'kill_any_job':
                kill_any_job = self._cap_to_num(opt[0])
            elif priv == 'modify_users':
                modify_users = self._cap_to_num(opt[0])
            elif priv == 'server_admin':
                server_admin = self._cap_to_num(opt[0])
            else:
                raise UserManagerException("The privilege '%s' is unknown." % privilege)

        self.curs.execute('UPDATE users SET own_jobs=%d, kill_any_job=%d, modify_users=%d, server_admin=%d' \
                    ' WHERE email="%s"' % (own_jobs, kill_any_job, modify_users, server_admin, email))
        self.dbcx.commit()
        print "User privileges updated: own_jobs=%d, kill_any_job=%d, modify_users=%d, server_admin=%d" % (
                    own_jobs, kill_any_job, modify_users, server_admin)

    def find_user(self, args):
        if len(args) < 1:
            raise UserManagerException("Invalid command, too few options.")

        email = args[0]
        self.curs.execute('SELECT * FROM users WHERE email LIKE "%%%s%%"' % email)
        self.dbcx.commit()
        data = self.curs.fetchall()
        if not len(data):
            raise UserManagerException("No matching users found.")

        print "\nResults:"
        print "-" * 100
        for row in data:
            string = "%s" % row['email'] + " " * (40 - len(row['email']))
            string = string + "own_jobs:%d  " % row['own_jobs']
            string = string + "kill_any_job:%d  " % row['kill_any_job']
            string = string + "modify_users:%d  " % row['modify_users']
            string = string + "server_admin:%d  " % row['server_admin']
            print string
        print ""


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print_usage(sys.argv[0])
        sys.exit(1)

    dbfile = sys.argv[1]
    if not os.access(dbfile, os.R_OK):
        print "The user database '%s' does not exist or is not readable." % dbfile
        sys.exit(1)

    um = UserManager(dbfile)
    try:
        um.dispatch(sys.argv[0], sys.argv[2], sys.argv[3:])
    except UserManagerException, e:
        print e.message
        sys.exit(1)

    sys.exit(0)





More information about the fedora-extras-commits mailing list