extras-buildsys-temp/automation2/client archwelder.py, NONE, 1.1 archwelder_config.py, NONE, 1.1

Daniel Williams (dcbw) fedora-extras-commits at redhat.com
Wed May 11 19:48:59 UTC 2005


Author: dcbw

Update of /cvs/fedora/extras-buildsys-temp/automation2/client
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv488/automation2/client

Added Files:
	archwelder.py archwelder_config.py 
Log Message:
2005-05-11  Dan Williams  <dcbw at redhat.com>

	* First cut of reworked build system.  Please see the soon-to-be
	committed README file for more details on how it works.




--- NEW FILE archwelder.py ---
#!/usr/bin/python -t
# 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 Duke University
# written by Seth Vidal

# TODO: xml-rpc communication using 2-way ssl-cert-verified xmlrpc connection
# TODO: config from file not cli


import SimpleXMLRPCServer
import xmlrpclib
import socket
import os
import popen2
import sha
import time
import base64
import sys
import string
import time
from archwelder_config import CONFIG

DEBUG = False
def debugprint(stuff=''):
    if DEBUG:
        print stuff

def log(stuff=''):
    print stuff

def is_done_status(status):
    if status == 'done' or status == 'killed' or status == 'failed':
        return True
    return False

class ArchWelderMach:
    """puts things together for an arch - baseclass for handling builds for 
       other arches"""
    def __init__(self, uniqid, srpm, target, mydir):
        self._status = 'init'
        self.target = target
        self.mydir = mydir
        self._output = []
        self.srpm = srpm
        self.uniqid = uniqid

    def die(self, sig=15):
        try:
            os.kill(self.pobj.pid, sig)
        except Exception, e:
            print "Couldn't kill process %d: %s" % (self.pobj.pid, e)
        self._status = 'killed'
        return True

    def _unlock(self):
        print "%s: starting step 'unlocking'" % self.uniqid
        cmd = '%s %s -r %s unlock' % (self.arch_command,
                            CONFIG('mach_cmd'), self.buildroot)
        self.pobj = popen2.Popen4(cmd=cmd)
        self._status = 'unlocking'

    def _clean(self):
        print "%s: starting step 'cleaning'" % self.uniqid
        cmd = '%s %s -r %s clean' % (self.arch_command,
                            CONFIG('mach_cmd'), self.buildroot)
        self.pobj = popen2.Popen4(cmd=cmd)
        self._status = 'cleaning'
        
    
    def _prep(self):
        print "%s: starting step 'prepping'" % self.uniqid
        cmd = '%s /%s -r %s setup prep' % (self.arch_command,
                            CONFIG('mach_cmd'), self.buildroot)
        self.pobj = popen2.Popen4(cmd=cmd)
        self._status = 'prepping'
        
    def _build(self):
        print "%s: starting step 'building'" % self.uniqid
        os.chdir(self.mydir + '/' + self.buildarch)
        cmd = '%s %s -r %s -c rebuild %s' % (self.arch_command,
                            CONFIG('mach_cmd'), self.buildroot, self.srpm)
        self.pobj = popen2.Popen4(cmd=cmd)
        self._status = 'building'

    def start(self):
        # check for existence of srpm before going on
        self._unlock()

    def process(self):
        if not is_done_status(self._status):
            # If we're done with a step, advance to next one
            exit_status = self.pobj.poll()
            if exit_status == 0:
                if self._status == 'unlocking':
                    self._clean()
                elif self._status == 'cleaning':
                    self._prep()
                elif self._status == 'prepping':
                    self._build()
                elif self._status == 'building':
                    print "%s: Job done." % self.uniqid
                    self._status = 'done'
                else:
                    print "Bad status %s encountered!" % self._status
            elif exit_status > 0:
                print "%s: job failed!\n" % self.uniqid
                self._status = 'failed'
            else:
                # mach process still running
                pass

    def status(self):
        return self._status

    def logs(self):
        self._output.extend(self.pobj.fromchild.readlines())
        return self._output
        

class i386Arch(ArchWelderMach):
    def __init__(self, uniqid, srpm, target, mydir, buildarch='i386'):
        self.buildroot = '%s-%s-i386-%s' % (target, CONFIG('distro_name'),
                            CONFIG('repo_name'))
        self.buildarch = buildarch
        self.arch_command = '/usr/bin/setarch i686'
        ArchWelderMach.__init__(self, uniqid, srpm, target, mydir)

class x86_64Arch(ArchWelderMach):
    def __init__(self, uniqid, srpm, target, mydir, buildarch='x86_64'):
        self.buildroot = '%s-%s-x86_64-%s' % (target, CONFIG('distro_name'),
                            CONFIG('repo_name'))
        self.buildarch = buildarch
        self.arch_command = ''
        ArchWelderMach.__init__(self, uniqid, srpm, target, mydir)

class PPCArch(ArchWelderMach):
    def __init__(self, uniqid, srpm, target, mydir, buildarch='ppc'):
        self.buildroot = '%s-%s-ppc-%s' % (target, CONFIG('distro_name'),
                            CONFIG('repo_name'))
        self.buildarch = buildarch
        self.arch_command = ''
        ArchWelderMach.__init__(self, uniqid, srpm, target, mydir)

class PPC64Arch(ArchWelderMach):
    def __init__(self, uniqid, srpm, target, mydir, buildarch='ppc64'):
        self.buildroot = '%s-%s-ppc64-%s' % (target, CONFIG('distro_name'),
                            CONFIG('repo_name'))
        self.buildarch = buildarch
        self.arch_command = ''
        ArchWelderMach.__init__(self, uniqid, srpm, target, mydir)


# Keep this global scope, used in __main__
welder_dict = { 'i386':i386Arch,
                'i486':i386Arch,
                'i586':i386Arch,
                'i686':i386Arch,
                'athlon':i386Arch,
                'x86_64':x86_64Arch,
                'amd64':x86_64Arch,
                'ia32e':x86_64Arch,
                'ppc':PPCArch,
                'ppc32':PPCArch,
                'ppc64':PPC64Arch,
               }

def getArchWelder(uniqid, srpm, target, mydir, buildarch, localarches):
    """hand it an arch it hands you back the archwelder instance you need"""
    
    if not welder_dict.has_key(buildarch):
        # raise an exception here bitching about no place to build for that arch
        pass 

    if buildarch == 'noarch':
        if len(localarches) > 0:
            welder = welder_dict[localarches[0]]
    else:
        if buildarch in localarches:
            welder = welder_dict[buildarch]
    
    awp = welder(uniqid, srpm, target, mydir, buildarch)
    return awp

class XMLRPCArchWelderServer:
    def __init__(self, localarches):
        self.ids = {} # unique id => awclass instance
        self.localarches = localarches
        self.cur_job = 0

    def _process(self):
        # Give jobs some time to update their status and do their thing
        job = 0
        for (uniqid, awp) in self.ids.iteritems():
            awp.process()
            if not is_done_status(awp.status()):
                job = uniqid
        self.cur_job = job  # Update current job

    def start(self, srpm, target, stagedir, buildarch):
        if self.cur_job != 0:
            print "Tried to build '%s' when already buiding something" % srpm
            return 0

        cur_time = time.time()
        check = '%d %s %s %s' % (cur_time, srpm, target, buildarch)
        sum = sha.new()
        sum.update(check)
        uniqid = sum.hexdigest()
        awp = getArchWelder(uniqid, srpm, target, stagedir, buildarch, self.localarches)
        if awp != None:
            self.ids[uniqid] = awp
            awp.start()
            log("%s: started %s on %s arch %s at time %d" % (uniqid, srpm,
                        target, buildarch, cur_time))
        else:
            log("%s: Failed request for %s on %s UNSUPPORTED arch %s at time %d" %
                        (uniqid, srpm, target, buildarch, cur_time))
            uniqid = 0
        self.cur_job = uniqid
        return uniqid

    def status(self, uniqid=None):
        awp = self.ids[uniqid]
        if not awp:
            return ''
        return awp.status()
    
    def die(self, uniqid=None):
        awp = self.ids[uniqid]
        return awp.die()
    
    def logs(self, uniqid=None):
        awp = self.ids[uniqid]
        result = []
        for line in awp.logs():
            enc = base64.encodestring(line)
            result.append(enc)
        return result
    
    def listjobs(self):
        return self.ids.keys()

    def get_cur_job(self):
        """ Are we currently building something? """
        return self.cur_job

    def supported_arches(self):
        return self.localarches

class MyXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
    """ XMLRPC server subclass that turns on SO_REUSEADDR """

    def __init__(self, address):
        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, addr=address, logRequests=False)

    def server_bind(self):
        self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        self.socket.bind(self.server_address)

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print "Usage:\n"
        print "   %s <hostname> <archlist>\n" % sys.argv[0]
        print "   <hostname> - hostname or IP address of this machine"
        print "   <archlist> - space-separated list of arches this machine can build"

        # pretty-print the available archlist
        archlist = ""
        avail_arches = welder_dict.keys()
        avail_arches.sort()
        for a in avail_arches:
            archlist = archlist + a
            if a != avail_arches[len(avail_arches)-1]:
                archlist = archlist + ", "
        print "                Available arches: [ %s ]\n" % archlist
        sys.exit(1)

    hostname = sys.argv[1]
    localarches = sys.argv[2:]

    print "Binding to address '%s' with arches: [%s]" % (hostname, string.join(localarches))
    server = MyXMLRPCServer((hostname, 8888))
    aws = XMLRPCArchWelderServer(localarches)
    server.register_instance(aws)
    last_time = time.time()
    while True:
        server.handle_request()
        cur_time = time.time()
        if cur_time >= last_time + 10:
            # do some work every 10s or so
            aws._process()
            last_time = time.time()



--- NEW FILE archwelder_config.py ---
# Configuration file for archwelder.py

config_opts = {}
config_opts['mach_cmd'] = "/usr/bin/mach"
config_opts['distro_name'] = "fedora"
config_opts['repo_name'] = "extras"


def CONFIG (key):
    return config_opts[key]




More information about the fedora-extras-commits mailing list