ReferencePlatforms/Buildserver

From MozillaWiki
Jump to: navigation, search

Buildserver Ref Image

This document describes how to create a "Build server" ref image. More info is in bug#385911.

Copy Linux Buildbot ref image

  1. VM->Clone
  2. Next
  3. If possible, use a clean snapshot of a machine, otherwise choose "The current state" and click Next.
  4. 'Create a full clone', Next.
  5. Choose a name and location and click Next.
  6. Finish

Add a 10GB drive

  1. VM->Settings
  2. Click Add
  3. Select 'Hard Disk' and click Next
  4. "Create a new virtual disk" and click Next
  5. SCSI, click Next
  6. Disk Size: 10GB, click Next
  7. Choose location, Finish

Create a single partition on the new hard drive (/dev/sdb) and run the following commands:

mkdir /cvs
mkfs -t ext3 -j /dev/sdb1
echo "/dev/sdb1 /cvs ext3 defaults 0 0" >> /etc/fstab
mount -a

Install and setup CVSD

CVSD is a wrapper for pserver that allows it to run in a rootjail. Here are the installation instructions:

wget http://ch.tudelft.nl/~arthur/cvsd/cvsd-1.0.13.tar.gz
tar -zvxf cvsd-1.0.13.tar.gz
cd cvsd-1.0.13
./configure
make
make install

Setup CVSD:

mkdir /etc/cvsd
cp /usr/local/etc/cvsd/cvsd.conf /etc/cvsd
cp /usr/local/etc/init.d/cvsd /etc/init.d
chkconfig --add cvsd

Edit /etc/init.d/cvsd and make sure 'CVSD_CFG' is set to '/etc/cvsd/cvsd.conf'. Edit /etc/cvsd/cvsd.conf and change the following parameters:

RootJail /cvs
Listen * 2401 
Repos /cvsroot
CvsArgs -u

Run these commands:

cvsd-buildroot /cvs
adduser cvsd

Install CVS

CVS must be patched to work in this setup.

wget http://ftp.gnu.org/non-gnu/cvs/source/stable/1.11.22/cvs-1.11.22.tar.bz2
wget http://people.mozilla.com/~bhearsum/Build/Misc/cvs.noreadlocks.patch
tar -jvxf cvs-1.11.22.tar.bz2
cd cvs-1.11.22/src
patch -p0 < ../../cvs.noreadlocks.patch
cd ../
./configure --prefix=/cvs
make
make install

Rsync cvs-mirror.m.o

These instructions taken from How to Create a CVS Mirror:

Create a directory for the repository

mkdir /cvs/cvsroot

Add that directory to your cvsd.conf

echo "/cvsroot" >> /etc/cvsd/cvsd.conf

Create an 'rsync-excludes' file to ignore history, users

echo "CVSROOT/passwd" > /cvs/etc/rsync-excludes
echo "CVSROOT/writers" >> /cvs/etc/rsync-excludes
echo "CVSROOT/history" >> /cvs/etc/rsync-excludes
echo "CVSROOT/history*" >> /cvs/etc/rsync-excludes

Copy this script that will perform an rsync of the Mozilla CVS

/etc/init.d/cvsd stop
rsync -q -az --delete --exclude-from=/cvs/etc/rsync-excludes cvs-mirror.mozilla.org::mozilla /cvs/cvsroot
/etc/init.d/cvsd start

If you want to continually update your mirror you should create a cron job to do so. Otherwise you can run the above script at any time to do it manually.

Create a buildbot master

mkdir -p /buildbot/default
chown -R buildbot /buildbot
su - buildbot
cd /buildbot/default
buildbot create-master .
mv Makefile.sample Makefile
rm master.cfg.sample

master.cfg:

# -*- python -*-
# ex: set syntax=python:

# This is a sample buildmaster config file. It must be installed as
# 'master.cfg' in your buildmaster's base directory (although the filename
# can be changed with the --basedir option to 'mktap buildbot master').

# It has one job: define a dictionary named BuildmasterConfig. This
# dictionary has a variety of keys to control different aspects of the
# buildmaster. They are documented in docs/config.xhtml .


# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}


####### PROJECT IDENTITY
c['projectName'] = "VMware Team Buildbot"
c['slavePortnum'] = 9990

####### BUILDSLAVES

# the 'bots' list defines the set of allowable buildslaves. Each element is a
# tuple of bot-name and bot-password. These correspond to values given to the
# buildslave's mktap invocation.
c['bots'] = [("win32", "w1nbu1ld3r"),
             ("linux", "l1nuxbu1ld3r")]

####### STATUS PLUGINS

from buildbot.status import html

c['status'] = []
c['status'].append(html.Waterfall(http_port=8810, allowForce=True))


####### SOURCES

c['sources'] = []


####### SCHEDULERS

c['schedulers'] = []


####### BUILDERS

c['builders'] = []

import mozbuild
reload(mozbuild)
from mozbuild import *
from buildbot.process import factory
from buildbot.steps.shell import Configure,Compile

s = factory.s

## unix builder

trunk_unix_steps = [
    s(MozillaCheckoutClientMk, workdir=".",
      cvsroot=":pserver:anonymous@10.0.0.1:/cvsroot"),
    s(MozillaClientMkPull, workdir="mozilla"),
    s(Configure,
      workdir="mozilla",
      command=["./configure",
               "--enable-application=browser"]),
    s(Compile, workdir="mozilla"),
]

trunk_unix_builder = {
    'name': "Build Team Default Unix Builder",
    'slavenames': ['linux'],
    'builddir': "trunk-unix",
    'factory': factory.BuildFactory(trunk_unix_steps),
    'category': "default",
}
c['builders'].append(trunk_unix_builder)


## win32 builder

trunk_win32_steps = [
    s(MozillaCheckoutClientMk, workdir=".",
      env=MozillaEnvironments['vc8_express']),
    s(MozillaClientMkPull, workdir="mozilla",
      env=MozillaEnvironments['vc8_express']),
    s(Configure,
      workdir="mozilla",
      env=MozillaEnvironments['vc8_express'],
      command=["bash", "-f", "configure",
               "--enable-application=browser",
              ]),
    s(Compile, workdir="mozilla", env=MozillaEnvironments['vc8_express'])
]

trunk_win32_builder = {
    'name': "Build Team Default Win32 Builder",
    'slavenames': ['win32'],
    'builddir': "trunk-win32",
    'factory': factory.BuildFactory(trunk_win32_steps),
    'category': "default"
}
c['builders'].append(trunk_win32_builder)

## END OF DEFAULT MASTER.CFG

mozbuild.py:

# -*- Python -*-

from buildbot.process import step
from buildbot.process.step import ShellCommand

MozillaEnvironments = { }

# standard vc8 express build env; vc8 normal will be very similar, just different
# platform SDK location.  we can build both from one generic template.
MozillaEnvironments['vc8_express'] = {
    "MOZ_TOOLS": '/cygdrive/d/moztools',
    "VSINSTALLDIR": 'C:\\Program Files\\Microsoft Visual Studio 8',
    "VS80COMMTOOLS": 'C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\',
    "VCINSTALLDIR": 'C:\\Program Files\\Microsoft Visual Studio 8\\VC',
    "FrameworkDir": 'C:\\WINDOWS\\Microsoft.NET\\Framework',
    "FrameworkVersion": 'v2.0.50727',
    "FrameworkSDKDir": 'C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0',
    "DevEnvDir": "C:\\Program Files\\Microsoft Visual Studio 8\\VC\\Common7\\IDE",
    "MSVCDir": 'C:\\Program Files\\Microsoft Visual Studio 8\\VC',
    "PATH": 'C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE;' + \
            'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\bin;' + \
            'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\bin;' + \
            'C:\\Program Files\\Microsoft Visual Studio 8\\VC;' + \
            'C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools;' + \
            'C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\bin;' + \
            'd:\\moztools\\bin;' + \
            'd:\\cygwin\\bin;' + \
            'd:\\buildtools\\NSIS;' + \
            'd:\\buildtools\\7-zip;' + \
            'd:\\buildtools\\upx;' + \
	    'C:\\WINDOWS\system32;',
    "INCLUDE": 'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\INCLUDE;' + \
               'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\INCLUDE;' + \
               'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\include',
    "LIB": 'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\LIB;' + \
           'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\LIB;' + \
           'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\lib'
}

class MozillaCheckoutClientMk(ShellCommand):
    haltOnFailure = True
    cvsroot = ":pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot"
    
    def __init__(self, **kwargs):
        if 'cvsroot' in kwargs:
            self.cvsroot = kwargs['cvsroot']
        if 'command' not in kwargs:
            kwargs['command'] = ["cvs", "-d", self.cvsroot, "co", "mozilla/client.mk"]
        ShellCommand.__init__(self, **kwargs)

    def describe(self, done=False):
        return ["client.mk update"]

class MozillaClientMkPull(ShellCommand):
    haltOnFailure = True
    def __init__(self, **kwargs):
        if 'project' not in kwargs or kwargs['project'] is None:
            self.project = "browser"
        else:
            self.project = kwargs['project']
            del kwargs['project']
        if 'workdir' not in kwargs:
            kwargs['workdir'] = "mozilla"
        if 'command' not in kwargs:
            kwargs['command'] = ["make", "-f", "client.mk", "pull_all"]
        env = {}
        if 'env' in kwargs:
            env = kwargs['env'].copy()
        env['MOZ_CO_PROJECT'] = self.project
        kwargs['env'] = env
        ShellCommand.__init__(self, **kwargs)

    def describe(self, done=False):
        if not done:
            return ["pulling (" + self.project + ")"]
        return ["pull (" + self.project + ")"]

class MozillaPackage(ShellCommand):
    name = "package"
    warnOnFailure = True
    description = ["packaging"]
    descriptionDone = ["package"]
    command = ["make"]

Set-up Buildbot to start with the system

Create the file '/etc/default/buildbot' with the following contents:

# buildbots to manage
# add a new set of variables for each buildbot to start

# BB_NUMBER    -> index for the buildbot
# BB_NAME      -> short name that is printed when starting/stopping
# BB_USER      -> user to run the buildbot as
# BB_BASEDIR   -> the absolute path to the buildbot master or slave
# BB_OPTIONS   -> extra options to pass to buildbot
# BB_PREFIXCMD -> prefix command, ie. nice, linux32, etc.
#
# Each of the preceeding are arrays. Each Buildbot you wish to run should
# increase the index of each. For example, the first Buildbot should use
# [0] on each array. The next one uses [1], etc.

BB_NUMBER[0]=0
BB_NAME[0]="Default Buildbot"
BB_USER[0]="buildbot"
BB_BASEDIR[0]="/buildbot/default/"
BB_OPTIONS[0]=""
BB_PREFIXCMD[0]=""

Create the file '/etc/init.d/buildbot' with the following contents:

#! /bin/bash
# initscript for buildbot

### BEGIN INIT INFO
# Provides:          cvsd
# Required-Start:    $local_fs $network
# Required-Stop:     $local_fs
# Should-Start:      $remote_fs 
# Should-Stop:       $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      S 0 1 6
# Short-Description: Buildbot
# Description:       Buildbot
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin
DESC="BuildBot"

USER=buildbot

DAEMON=/tools/buildbot/bin/buildbot
DNAME=buildbot
PROCNAME=$NAME

[ -r /etc/default/buildbot ] && . /etc/default/buildbot

test -x ${DAEMON} || exit 0

. /lib/lsb/init-functions

check_config()
{
    errors=0
    for i in ${BB_NUMBER[@]}; do
	[ $i -ge 0 ] || continue
	if [ -z "${BB_NAME[$i]}" ]; then
	    echo >&2 "buildbot $i: no name"
	    errors=$(($errors+1))
	fi
	if [ -z "${BB_USER[$i]}" ]; then
	    echo >&2 "buildbot $i: no user"
	    errors=$(($errors+1))
	elif ! getent passwd ${BB_USER[$i]} >/dev/null; then
	    echo >&2 "buildbot $i: unknown user ${BB_USER[$i]}"
	    errors=$(($errors+1))
	fi
	if [ ! -d "${BB_BASEDIR[$i]}" ]; then
	    echo >&2 "buildbot $i: no base directory ${BB_BASEDIR[$i]}"
	    errors=$(($errors+1))
	fi
    done
    [ $errors -eq 0 ] || exit 1
}

check_config

start_buildbot() {
    NAME="$1"
    USER="$2"
    BASEDIR="$3"
    PREFIXCMD="$4"
    OPTIONS="$5"

    #START="--start --quiet --exec ${DAEMON} --name ${NAME} --pidfile ${BASEDIR}/twistd.pid"
    #[ -n "${USER}" ] && START="${START} --chuid ${USER}"
    #START="${START} -- start ${BASEDIR} ${OPTIONS}"
    #${PREFIXCMD} start-stop-daemon ${START} >/dev/null 2>&1
    ${PREFIXCMD} su -s /bin/bash -c "${DAEMON} start ${BASEDIR} ${OPTIONS}" - ${USER}
    return $?
}

stop_buildbot() {
    NAME="$1"
    USER="$2"
    BASEDIR="$3"
    PREFIXCMD="$4"

    ${PREFIXCMD} su -s /bin/bash -c "${DAEMON} stop ${BASEDIR}" - ${USER}
    return $?
}

reload_buildbot() {
    NAME="$1"
    USER="$2"
    BASEDIR="$3"
    PREFIXCMD="$4"

    ${PREFIXCMD} su -s /bin/bash -c "${DAEMON} sighup ${BASEDIR}" - ${USER}
    return $?
}

do_start () {
    errors=0
    for i in ${BB_NUMBER[@]}; do
	[ $i -ge 0 ] || continue
	echo "Starting buildbot ${BB_NAME[$i]}"
	if start_buildbot "${BB_NAME[$i]}" "${BB_USER[$i]}" "${BB_BASEDIR[$i]}" \
	    "${BB_PREFIXCMD[$i]}" "${BB_OPTIONS[$i]}"
	then
	    echo "started"
	else
	    echo "not started"
	    errors=$(($errors+1))
	fi
    done
    return $errors
}

do_stop () {
    errors=0
    for i in ${BB_NUMBER[@]}; do
	[ $i -ge 0 ] || continue
	echo "Stopping buildbot ${BB_NAME[$i]}"
	if stop_buildbot "${BB_NAME[$i]}" "${BB_USER[$i]}" "${BB_BASEDIR[$i]}" \
	    "${BB_PREFIXCMD[$i]}"
	then
	    echo "stopped"
	else
	    echo "not stopped"
	    errors=$(($errors+1))
	fi
    done
    return $errors
}

do_reload () {
    errors=0
    for i in ${BB_NUMBER[@]}; do
	[ $i -ge 0 ] || continue
	echo "Reload buildbot ${BB_NAME[$i]}"
	if reload_buildbot "${BB_NAME[$i]}" "${BB_USER[$i]}" "${BB_BASEDIR[$i]}" \
	    "${BB_PREFIXCMD[$i]}"
	then
	    echo "reloaded"
	else
	    echo "not reloaded"
	    errors=$(($errors+1))
	fi
    done
    return $errors
}

do_restart () {
    errors=0
    for i in ${BB_NUMBER[@]}; do
	[ $i -ge 0 ] || continue
	echo "Restarting buildbot ${BB_NAME[$i]}"
	stop_buildbot "${BB_NAME[$i]}" "${BB_USER[$i]}" "${BB_BASEDIR[$i]}" \
	    "${BB_PREFIXCMD[$i]}" || true
	if start_buildbot "${BB_NAME[$i]}" "${BB_USER[$i]}" "${BB_BASEDIR[$i]}" \
	    "${BB_PREFIXCMD[$i]}" "${BB_OPTIONS[$i]}"
	then
	    echo "restarted"
	else
	    echo "not restarted"
	    errors=$(($errors+1))
	fi
    done
    return $errors
}

case "$1" in
  start)
  	do_start
  	exit $?
	;;
  stop)
  	do_stop
  	exit $?
	;;
  reload)
  	do_reload
  	exit $?
	;;
  restart|force-reload)
  	do_restart
  	exit $?
	;;
  *)
	log_warning_msg "Usage: $0 {start|stop|restart|reload|force-reload}"
	exit 1
	;;
esac

exit 0

Run the following command to add buildbot to the init scripts:

chkconfig --add buildbot