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

import sys, os
from buildbot.plugins import *

#######

NotDebug = True

masterHost = "buildbot.tux3.org"
masterWorkerPort = 9989

# git proxy for https://
https_proxy = None
#https_proxy = 'http://localhost:8080'

# git proxy for git://
#
# Save the following as git-proxy.sh, then copy to everywhere by
# buildbot FileDownload and add it to $PATH (or add git config --global).
#
# $ cat > git-proxy.sh
# nc -x localhost:8080 -X connect "$@"
# ^D
#
# os.environ['GIT_PROXY_COMMAND'] = 'git-proxy.sh'
# git_configs['core.gitProxy'] = 'git-proxy.sh'

# linux-tux3 git repo
tux3_repo = "https://github.com/OGAWAHirofumi/linux-tux3.git"
linux_configs = "tux3-linux-configs"
linux_configs_repo = "https://github.com/OGAWAHirofumi/%s.git" % (linux_configs)
tux3_branch_def = {
    'master' : 'user',
    'hirofumi' : 'hirofumi-user',
}

# Setup proxy if there
git_configs = None
if https_proxy:
    # For GitPoller and git command in master
    os.environ['HTTPS_PROXY'] = https_proxy
    # For remote Git
    git_configs = {}
    git_configs['http.proxy'] = https_proxy

# location for providing static contents via normal http server
www_base = "../www/"
http_base = "/"
secrets_dir = os.path.join(os.path.dirname(__file__), "secrets")

tux3_user_branches = list(tux3_branch_def.values())
tux3_kern_branches = list(tux3_branch_def.keys())
tux3_branches = tux3_user_branches + tux3_kern_branches

# Define workers
workers_def = {
    'i386': [
        # i386-worker0 using port 11111
        { 'name': "i386-worker0", 'pass': None, 'kvm_host': False, },
        { 'name': "i386-worker1", 'pass': None, 'kvm_host': True,
          'kvm_cpus': 2, 'kvm_mem': 2048, 'kvm_port': 11112, },
#        { 'name': "x86_64-worker1", 'pass': "", 'kvm_host': True,
#          'kvm_cpus': 2, 'kvm_mem': 2048, 'kvm_port': 11114, },
    ],
    'x86_64': [
        { 'name': "x86_64-worker0", 'pass': None, 'kvm_host': False, },
        { 'name': "x86_64-worker1", 'pass': None, 'kvm_host': True,
          'kvm_cpus': 2, 'kvm_mem': 2048, 'kvm_port': 11113, },
    ],
}

# Get password from "master/secrets/<workername>", then update "workers_def"
for arch in workers_def.keys():
    for w in workers_def[arch]:
        if w['pass'] is None:
            # get the password based on the name
            with open(os.path.join(secrets_dir, w['name'])) as f:
                w['pass'] = f.read().strip()

# Option for kernel serial console
serial_console_opt = {
    'i386': 'console=ttyS0,115200 console=tty0',
    'x86_64': 'console=ttyS0,115200 console=tty0',
}

basic_workers = {}
stress_workers = {}
for arch in workers_def.keys():
    basic_workers[arch] = [
        s['name'] for s in workers_def[arch] if not s['kvm_host']
    ]
    stress_workers[arch] = [
        s['name'] for s in workers_def[arch] if s['kvm_host']
    ]

# Builders and associated workers
def user_buildname(arch):
    return "userspace-%s" % arch
def kern_buildname(arch):
    return "kernel-%s" % arch
def stress_buildname(arch):
    return "stress-%s" % arch

user_builders = [ user_buildname(arch) for arch in basic_workers.keys() ]
kern_builders = [ kern_buildname(arch) for arch in basic_workers.keys() ]
stress_builders = [ stress_buildname(arch) for arch in stress_workers.keys() ]

# All builders for "force" schedule
all_builders = user_builders + kern_builders + stress_builders

####### CONFIGS

# This is a sample buildmaster config file. It must be installed as
# 'master.cfg' in your buildmaster's base directory.

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

c['buildbotNetUsageData'] = None

####### WORKERS

# The 'workers' list defines the set of recognized workers. Each element is
# a Worker object, specifying a unique worker name and password.  The same
# worker name and password must be configured on the worker.

c['workers'] = []

for arch in workers_def.keys():
    for w in workers_def[arch]:
        # Add worker
        c['workers'].append(worker.Worker(
            w['name'], w['pass'],
            max_builds=1,
        ))

# 'protocols' contains information about protocols which master will use for
# communicating with workers. You must define at least 'port' option that workers
# could connect to your master with this protocol.
# 'port' must match the value configured into the workers (with their
# --master option)
c['protocols'] = {'pb': {'port': masterWorkerPort}}

####### CHANGESOURCES

# the 'change_source' setting tells the buildmaster how it should find out
# about source code changes.  Here we point to the buildbot version of a python hello-world project.

c['change_source'] = []
c['change_source'].append(changes.GitPoller(
    repourl=tux3_repo, branches=tux3_branches,
    workdir="gitpoller-workdir-tux3",
    pollinterval=300,
    buildPushesWithNoCommits=True))

####### SCHEDULERS

# Configure the Schedulers, which decide how to react to incoming changes.  In this
# case, just kick off a 'runtests' build

c['schedulers'] = []

# Base schedulers
c['schedulers'].append(schedulers.AnyBranchScheduler(
    name="basic",
    change_filter=util.ChangeFilter(branch=tux3_user_branches),
    treeStableTimer=60,
    builderNames=user_builders,
))

c['schedulers'].append(schedulers.AnyBranchScheduler(
    name="kern",
    change_filter=util.ChangeFilter(branch=tux3_kern_branches),
    treeStableTimer=60,
    builderNames=kern_builders,
))

c['schedulers'].append(schedulers.ForceScheduler(
    name="force",
    builderNames=all_builders,
))

####### BUILDERS

# The 'builders' list defines the Builders, which tell Buildbot how to perform a build:
# what steps, and which workers can execute them.  Note that any particular build will
# only take place on one worker.

import re
import textwrap
from twisted.internet import defer

c['builders'] = []

# warning patterns
gccWarnPattern = "^(.*?):([0-9]+):([0-9]+:)? (.*)?([Ww]arning|[Ee]rror|[Nn]ote): (.*)$"

modpostPattern = "^(WARNING|ERROR|FATAL): .*$"
headerPattern  = "^(.*):([0-9]+): (.*)$"
kernPattern    = "(%s|%s|%s)" % (gccWarnPattern, modpostPattern, headerPattern)

assertPattern    = "^(WARNING|BUG): .*$"
userTestPattern = "(%s|%s)" % (gccWarnPattern, assertPattern)

# tux3 command name
tux3cmd_name = "tux3"

# Workers set
def find_worker(arch, workername):
    for w in workers_def[arch]:
        if workername == w['name']:
            return w

def getVmlinuz():
    return "vmlinuz"
def getVmlinuxXz():
    return "vmlinux.xz"

# Parse output of "make tests" and produce test summary
# Based on PerlModuleTest class
class Tux3UserTestObserver(util.LogLineObserver):
    testPassedPattern = re.compile(r"^\[.*:test.*\] OK$")
    testFailedPattern = re.compile(r"^\[.*:test.*\] FAILED$")

    def __init__(self):
        super().__init__()
        self.rc = util.SUCCESS
        self.passed = 0
        self.failed = 0

    def outLineReceived(self, line):
        if self.testPassedPattern.match(line):
            self.passed += 1
        if self.testFailedPattern.match(line):
            self.failed += 1
            self.rc = util.FAILURE

class Tux3UserTest(steps.Test):
    command = ["make", "tests"]
    warningPattern = userTestPattern

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.observer = Tux3UserTestObserver()
        self.addLogObserver('stdio', self.observer)

    def evaluateCommand(self, cmd):
        total = self.observer.passed + self.observer.failed
        if total:
            self.setTestResults(total=total,
                                passed=self.observer.passed,
                                failed=self.observer.failed)

        rc = self.observer.rc
        if rc == util.SUCCESS and self.warnCount:
            rc = util.WARNINGS
        return rc

# Run compile, basic tests, coverage
def user_steps(arch):
    # Upload place for gcov
    gcovURL = "gcov/%s/%s" % (arch, "%(prop:buildnumber)s-%(prop:branch)s")
    return [
        # Checkout tux3 (checkout at last to set proper got_revision)
        steps.Git(
            repourl=tux3_repo,
            branch="user",
            config=git_configs,
            mode="full",
            method="copy",
            description=[util.Interpolate('updating %(prop:branch)s')],
            descriptionDone=[util.Interpolate('update %(prop:branch)s')],
            name="git tux3",
        ),
        # Compile userspace commands with UBSAN
        steps.Compile(
            command="make UBSAN=1",
            workdir="build/fs/tux3/user",
            warningPattern=gccWarnPattern,
            description=['compiling UBSAN=1'],
            descriptionDone=['compile UBSAN=1'],
            name="compile UBSAN=1",
        ),
        # Test
        Tux3UserTest(
            command="make UBSAN=1 tests",
            workdir="build/fs/tux3/user",
            description=["testing UBSAN=1"],
            descriptionDone=["test UBSAN=1"],
            name="test UBSAN=1",
        ),
        # Cleanup for next compile
        steps.Compile(
            command="make distclean",
            workdir="build/fs/tux3/user",
            description=['compiling distclean'],
            descriptionDone=['compile distclean'],
            name="compile distclean",
        ),
        # Compile userspace commands with ASAN
        steps.Compile(
            command="make ASAN=1",
            workdir="build/fs/tux3/user",
            warningPattern=gccWarnPattern,
            description=['compiling ASAN=1'],
            descriptionDone=['compile ASAN=1'],
            name="compile ASAN=1",
        ),
        # Test
        Tux3UserTest(
            command="make ASAN=1 tests",
            workdir="build/fs/tux3/user",
            description=["testing ASAN=1"],
            descriptionDone=["test ASAN=1"],
            name="test ASAN=1",
        ),
        # Cleanup for next compile
        steps.Compile(
            command="make distclean",
            workdir="build/fs/tux3/user",
            description=['compiling distclean'],
            descriptionDone=['compile distclean'],
            name="compile distclean",
        ),
        # Compile userspace commands with sparse and coverage
        steps.Compile(
            command="make CHECK=1 GCOV=1",
            workdir="build/fs/tux3/user",
            warningPattern=gccWarnPattern,
        ),
        # Test
        Tux3UserTest(
            workdir="build/fs/tux3/user",
        ),
        # Collect coverage info
        steps.ShellCommand(
            command="make coverage",
            workdir="build/fs/tux3/user",
            haltOnFailure=True,
            description=['coverage'],
            descriptionDone=['coverage'],
            name="coverage report",
        ),
        # Upload coverage info
        steps.DirectoryUpload(
            workersrc="fs/tux3/user/gcov",
            masterdest=util.Interpolate(www_base + gcovURL),
            url=util.Interpolate(http_base + gcovURL),
        ),
        # Update coverage summary in master
        steps.MasterShellCommand(
            command="./scripts/lcov-summary.sh",
            description=['updating coverage'],
            descriptionDone=['update coverage'],
            name="update coverage",
        ),
        # Run post process (remove old outputs, fix permissions, etc.)
        steps.MasterShellCommand(
            command="./scripts/post.sh",
            description=['post process'],
            descriptionDone=['post process'],
            name="post process",
        ),
    ]

# Get user branch for kernel branch
@util.renderer
def CheckoutUserBranch(props):
    kern = props.getProperty('branch')
    user = tux3_branch_def[kern]

    # make git config from git_configs 
    opt = ""
    if git_configs:
        for key, val in git_configs.items():
            opt += " -c '%s=%s'" % (key, val)

    return "git %s fetch -p && git checkout -B %s origin/%s" % (opt, user, user)

# Run kernel compile
def kern_steps(arch):
    master_basedir = "binaries/%s/%s" % (arch, "%(prop:buildnumber)s")
    # Upload place for compiled binaries
    master_tux3_path = "%s/%s" % (master_basedir, tux3cmd_name)
    # Upload place for vmlinuz
    master_vmlinuz_path = "%s/%s" % (master_basedir, getVmlinuz())
    # Upload place for vmlinux.xz
    master_vmlinux_xz_path = "%s/%s" % (master_basedir, getVmlinuxXz())
    return [
        # Checkout tux3 (checkout at last to set proper got_revision)
        steps.Git(
            repourl=tux3_repo,
            branch="master",
            config=git_configs,
            mode="full",
            method="copy",
            description=[util.Interpolate('updating %(prop:branch)s')],
            descriptionDone=[util.Interpolate('update %(prop:branch)s')],
            name="git tux3",
        ),
        # Update linux-configs repo
        steps.MasterShellCommand(
            command=textwrap.dedent(r"""
DIR="%s"
if [ -d "$DIR" ]; then
    cd "$DIR"
    git pull -p
else
    git clone "%s"
fi
            """ % (linux_configs, linux_configs_repo)).strip(),
            description=['updating linux-configs'],
            descriptionDone=['update linux-configs'],
            name="update linux-configs",
        ),
        # Get kernel version of source from Makefile
        steps.SetPropertyFromCommand(
            property="kern_ver",
            command=textwrap.dedent(r"""
eval $(sed -n -e 's/\(.*\) = \(.*\)/\1=\2/p' -e '/^EXTRAVERSION/q' Makefile)
echo $VERSION.$PATCHLEVEL
            """).strip(),
            hideStepIf=NotDebug,
        ),
        # Download .config
        steps.FileDownload(
            mastersrc=util.Interpolate(linux_configs + '/%(prop:kern_ver)s/.config.kvm-debug-' + arch),
            workerdest=".config",
            mode=0o644,
        ),
        # Note: olddefconfig sets new symbols to default value
        steps.Compile(
            command="make olddefconfig",
            warningPattern=kernPattern,
            description=['compiling olddefconfig'],
            descriptionDone=['compile olddefconfig'],
            name="compile olddefconfig",
        ),
        # Compile kernel
        steps.Compile(
            command="make",
            warningPattern=kernPattern,
            description=['compiling kernel'],
            descriptionDone=['compile kernel'],
            name="compile kernel",
        ),
        # Compress vmlinux, then upload bzImage and vmlinux
        steps.FileUpload(
            workersrc="arch/%s/boot/bzImage" % arch,
            masterdest=util.Interpolate(www_base + master_vmlinuz_path),
            mode=0o644,
            url=util.Interpolate(http_base + master_vmlinuz_path),
        ),
        steps.ShellCommand(
            command="xz -v vmlinux",
            hideStepIf=NotDebug,
            description=["xz vmlinux"],
            descriptionDone=["xz vmlinux"],
            name="xz vmlinux"
        ),
        steps.FileUpload(
            workersrc="vmlinux.xz",
            masterdest=util.Interpolate(www_base + master_vmlinux_xz_path),
            mode=0o644,
            url=util.Interpolate(http_base + master_vmlinux_xz_path),
        ),
        # Compile tux3 module
        steps.Compile(
            command="make CONFIG_TUX3=m C=1 M=fs/tux3",
            warningPattern=kernPattern,
            description=['compiling module'],
            descriptionDone=['compile module'],
            name="compile module",
        ),
        # Clean kernel
        steps.Compile(
            command="make mrproper",
            description=['clean kernel'],
            descriptionDone=['clean kernel'],
            name="clean kernel",
        ),
        # Compile user tools
        steps.ShellCommand(
            command=CheckoutUserBranch,
            haltOnFailure=True,
            description=['update tux3/user'],
            descriptionDone=['update tux3/user'],
            name="git tux3/user",
        ),
        steps.Compile(
            command="make",
            workdir="build/fs/tux3/user",
            warningPattern=kernPattern,
            description=['compiling command'],
            descriptionDone=['compile command'],
            name="compile command",
        ),
        # Upload tux3 command
        steps.FileUpload(
            workersrc="fs/tux3/user/%s" % tux3cmd_name,
            masterdest=util.Interpolate(www_base + master_tux3_path),
            url=util.Interpolate(http_base + master_tux3_path),
        ),
        # Run post process (remove old outputs, fix permissions, etc.)
        steps.MasterShellCommand(
            command="./scripts/post.sh",
            description=['post process'],
            descriptionDone=['post process'],
            name="post process",
        ),
        # Start stress test
        steps.Trigger(schedulerNames=[stress_buildname(arch)],
                waitForFinish=False,
                updateSourceStamp=True,
                set_properties={
                    'master_basedir': util.Interpolate(master_basedir),
                },
                copy_properties={
                    'got_revision',
                },
        ),
    ]

class FileUploadWithUrls(steps.FileUpload):
    renderables = ["auxUrls"]

    def __init__(self, auxUrls=None, **kwargs):
        self.auxUrls = auxUrls

        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        if self.auxUrls is not None:
            for url in self.auxUrls:
                yield self.addURL(os.path.basename(url), url)

        res = yield super().run()
        return res

class KvmStart(steps.ShellCommand):
    name = "kvm"
    haltOnFailure = True

    def __init__(self, script_name, sshkey_name, disks,
                 kernel_name, kernel_arch, **kwargs):
        self.script_name = script_name
        self.sshkey_name = sshkey_name
        self.disks = disks
        self.kernel_name = kernel_name
        self.kernel_arch = kernel_arch

        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        disk_opts = ['-hda', '-hdb', '-hdc', '-hdd']
        arch = self.kernel_arch
        workername = self.build.getWorkerName()
        w = find_worker(arch, workername)

        command = [
            self.script_name, "run",
            str(w['kvm_port']), self.sshkey_name,
            "-smp", str(w['kvm_cpus']),
            "-m", str(w['kvm_mem']),
            "-kernel", self.kernel_name,
            "-append", "root=/dev/sda1 ro %s" % serial_console_opt[arch],
        ]

        for (opt, disk) in zip(disk_opts, self.disks):
            command.append(opt)
            command.append(disk)

        self.command = command

        res = yield super().run()
        return res

class KvmStop(steps.ShellCommand):
    name = "kvm"
    alwaysRun = True

    def __init__(self, script_name, vmcore_name="vmcore", checkstep=None,
                 **kwargs):
        self.script_name = script_name
        self.vmcore_name = vmcore_name
        self.checkstep = checkstep

        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        result = util.SUCCESS
        if self.checkstep is not None:
            # get current build steps data
            steps_data = yield self.master.data.get(
                ('builds', self.build.buildid, 'steps')
            )
            # find a target step, then get result
            for step in steps_data:
                if step['name'] == self.checkstep:
                    result = step['results']
                    break

        command = [ self.script_name, "quit", ]

        # If checkstep was util.FAILURE, get kernel crashdump
        if result == util.FAILURE:
            command.append("dump_serial")
            command.append(self.vmcore_name)
            self.setProperty('has_vmcore', 'Y', "KvmStop Step")
        else:
            command.append("serial")
            self.setProperty('has_vmcore', 'N', "KvmStop Step")

        self.command = command

        res = yield super().run()
        return res

# Run stress test steps
def stress_steps(arch):
    kvm_workdir = "../guest-images"
    tarball_name = "kvm-%s.tar.xz" % arch
    tarball_cksum = "%s.sum" % tarball_name
    tarball_cksum_new = "%s.new" % tarball_cksum
    disk_name = "kvm-%s.qcow2" % arch
    tux3_disk = "tux3-disk.img"
    sshkey_name = "id_rsa-%s" % arch
    tests_name = "tests-%s.tar.xz" % arch
    master_vmlinuz_path = "%s/%s" % ("%(prop:master_basedir)s", getVmlinuz())
    master_vmlinux_xz_path = "%s/%s" % ("%(prop:master_basedir)s", getVmlinuxXz())
    master_tux3_path = "%s/%s" % ("%(prop:master_basedir)s", tux3cmd_name)
    kvm_script = "bb-kvm.sh"
    vmcore_name = "vmcore"
    vmcore_xz_name = "%s.xz" % vmcore_name
    master_vmcore_xz_path = "%s/%s" % ("%(prop:master_basedir)s", vmcore_xz_name)
    return [
        # Download guest image cksum
        steps.FileDownload(
            mastersrc="guest-images/%s" % tarball_cksum,
            workerdest=tarball_cksum_new,
            workdir=kvm_workdir,
            mode=0o644,
            hideStepIf=NotDebug,
        ),
        # Check whether need to download guest image
        steps.SetPropertyFromCommand(
            property="need_image",
            command=textwrap.dedent("""\
if cmp -s %s %s; then
    echo N
else
    echo Y
fi
mv %s %s
            """ % (tarball_cksum, tarball_cksum_new, 
                   tarball_cksum_new, tarball_cksum)).strip(),
            workdir=kvm_workdir,
            hideStepIf=NotDebug,
        ),
        # Download guest image tarball if need
        steps.FileDownload(
            mastersrc="guest-images/%s" % tarball_name,
            workerdest=tarball_name,
            workdir=kvm_workdir,
            mode=0o644,
            doStepIf=lambda step: step.build.getProperty("need_image") == "Y",
        ),
        steps.ShellCommand(
            command="tar xvf %s" % tarball_name,
            workdir=kvm_workdir,
            haltOnFailure=True,
            doStepIf=lambda step: step.build.getProperty("need_image") == "Y",
            description=["uncompressing image"],
            descriptionDone=["uncompress image"],
            name="uncompress image"
        ),
        # Download script for kvm
        steps.FileDownload(
            mastersrc="guest-images/%s" % kvm_script,
            workerdest=kvm_script,
            workdir=".",
            mode=0o755,
        ),
        # Download tests tools, tux3 command, and kernel for guest
        steps.FileDownload(
            mastersrc="guest-images/%s" % tests_name,
            workerdest=tests_name,
            workdir=".",
            mode=0o644,
        ),
        steps.FileDownload(
            mastersrc=util.Interpolate(www_base + master_tux3_path),
            workerdest=tux3cmd_name,
            workdir=".",
            mode=0o755,
        ),
        steps.FileDownload(
            mastersrc=util.Interpolate(www_base + master_vmlinuz_path),
            workerdest=getVmlinuz(),
            workdir=".",
            mode=0o644,
        ),
        # Make 8GB disk for tux3
        steps.ShellCommand(
            command=["dd", "if=/dev/null", "of=%s" % tux3_disk,
                     "bs=1M", "count=0", "seek=8192"],
            workdir=".",
            description=['making %s' % tux3_disk],
            descriptionDone=['make %s' % tux3_disk],
            name="make %s" % tux3_disk,
        ),
        # Run guest
        KvmStart(
            script_name="./%s" % kvm_script,
            sshkey_name="%s/%s" % (kvm_workdir, sshkey_name),
            disks=["%s/%s" % (kvm_workdir, disk_name), tux3_disk],
            kernel_name=getVmlinuz(),
            kernel_arch=arch,
            workdir=".",
            description=['running kvm'],
            descriptionDone=['run kvm'],
            name="run kvm",
        ),
        # Copy tests tools and tux3 command to guest
        steps.ShellCommand(
            command=["./%s" % kvm_script, "scp",
                     tests_name, tux3cmd_name, "localhost:"],
            workdir=".",
            description=['scp tools'],
            descriptionDone=['scp tools'],
            name="scp tools",
        ),
        # Run tests
        steps.ShellCommand(
            command=["./%s" % kvm_script, "ssh",
                     "tar xvf %s && "
                     "(cd tests && ./test.sh ../%s /dev/sdb)"
                     % (tests_name, tux3cmd_name),
            ],
            workdir=".",
            description=['run stress'],
            descriptionDone=['run stress'],
            name="run stress",
        ),
        # Stop guest
        KvmStop(
            script_name="./%s" % kvm_script,
            vmcore_name=vmcore_name,
            checkstep="run stress",
            workdir=".",
            description=['stopping kvm'],
            descriptionDone=['stop kvm'],
            name="stop kvm",
        ),
        # Compress and upload vmcore if need, then remove
        steps.ShellCommand(
            command="xz -v %s" % vmcore_name,
            workdir=".",
            alwaysRun=True,
            hideStepIf=NotDebug,
            doStepIf=lambda step: step.build.getProperty("has_vmcore") == "Y",
            description=["xz %s" % vmcore_name],
            descriptionDone=["xz %s" % vmcore_name],
            name="xz %s" % vmcore_name,
        ),
        FileUploadWithUrls(
            workersrc=vmcore_xz_name,
            masterdest=util.Interpolate(www_base + master_vmcore_xz_path),
            workdir=".",
            mode=0o644,
            url=util.Interpolate(http_base + master_vmcore_xz_path),
            # Add url of vmlinux.xz for convenience
            auxUrls=[
                util.Interpolate(http_base + master_vmlinux_xz_path),
            ],
            alwaysRun=True,
            doStepIf=lambda step: step.build.getProperty("has_vmcore") == "Y",
        ),
        steps.RemoveDirectory(
            dir=vmcore_xz_name,
            alwaysRun=True,
            hideStepIf=NotDebug,
            doStepIf=lambda step: step.build.getProperty("has_vmcore") == "Y",
        ),
        # Run post process (remove old outputs, fix permissions, etc.)
        steps.MasterShellCommand(
            command="./scripts/post.sh",
            description=['post process'],
            descriptionDone=['post process'],
            name="post process",
        ),
    ]

for arch in workers_def.keys():
    # Builder for userspace-<arch>
    c['builders'].append(util.BuilderConfig(
        name=user_buildname(arch),
        workernames=basic_workers[arch],
        factory=util.BuildFactory(user_steps(arch)),
    ))

    # Scheduler for kernel-<arch>
    c['schedulers'].append(schedulers.Triggerable(
        name=kern_buildname(arch),
        builderNames=[ kern_buildname(arch) ],
    ))
    # Builder for kernel-<arch>
    c['builders'].append(util.BuilderConfig(
        name=kern_buildname(arch),
        workernames=basic_workers[arch],
        factory=util.BuildFactory(kern_steps(arch)),
    ))

    # Scheduler for stress-<arch>
    c['schedulers'].append(schedulers.Triggerable(
        name=stress_buildname(arch),
        builderNames=[ stress_buildname(arch) ],
    ))
    # Builder for stress-<arch>
    c['builders'].append(util.BuilderConfig(
        name=stress_buildname(arch),
        workernames=stress_workers[arch],
        factory=util.BuildFactory(stress_steps(arch)),
    ))

####### BUILDBOT SERVICES

# 'services' is a list of BuildbotService items like reporter targets. The
# status of each build will be pushed to these targets. buildbot/reporters/*.py
# has a variety to choose from, like IRC bots.

c['services'] = []

#c['services'].append(reporters.MailNotifier(
#    fromaddr="buildbot@localhost",
#    extraRecipients=['example@example.org'],
#    mode=['failing', 'warnings'],
#    sendToInterestedUsers=False,
#    addLogs=False,
#    relayhost="smtp.example.org",
#    smtpPort=587,
#    smtpUser="example@example.org",
#    smtpPassword="example-password",
#))
#
#c['services'].append(reporters.IRC(
#    host="irc.oftc.net",
#    nick="buildbot",
#    channels=[{'channel': '#tux3'}],
#    allowForce=False,
#    notify_events={
#        'exception': 1,
#        'successToFailure': 1,
#        'failureToSuccess': 1,
#    },
#))

####### PROJECT IDENTITY

# the 'title' string will appear at the top of this buildbot installation's
# home pages (linked to the 'titleURL').

c['title'] = "tux3"
c['titleURL'] = "https://tux3.org/"

# the 'buildbotURL' string should point to the location where the buildbot's
# internal web server is visible. This typically uses the port number set in
# the 'www' entry below, but with an externally-visible host name which the
# buildbot cannot figure out without some help.

c['buildbotURL'] = "https://%s/buildbot/" % masterHost

# minimalistic config to activate new web UI
c['www'] = dict(port=8010,
                plugins=dict(waterfall_view={}, console_view={}, grid_view={}))

# Get username/password from "master/secrets/master-users"
account = {}
with open(os.path.join(secrets_dir, "master-users")) as f:
    for line in f.readlines():
        # make dict for { user: pass, ... }
        entry = line.strip().split(':')
        account[entry[0]] = entry[1]

c['www']['auth'] = util.UserPasswordAuth(account)
c['www']['authz'] = util.Authz(
    allowRules = [
        util.AnyControlEndpointMatcher(role="admins"),
    ],
    roleMatchers = [
        util.RolesFromUsername(roles=['admins'], usernames=['tux3'])
    ]
)

####### DB URL

c['db'] = {
    # This specifies what database buildbot uses to store its state.
    # It's easy to start with sqlite, but it's recommended to switch to a dedicated
    # database, such as PostgreSQL or MySQL, for use in production environments.
    # http://docs.buildbot.net/current/manual/configuration/global.html#database-specification
    'db_url' : "sqlite:///state.sqlite",
}

0d8371c9ebc9cdc18e840156b934c9a8dc6c01b2
<mask token>


class Tux3UserTest(steps.Test):
    <mask token>
    <mask token>
    <mask token>
    <mask token>


<mask token>


class FileUploadWithUrls(steps.FileUpload):
    renderables = ['auxUrls']

    def __init__(self, auxUrls=None, **kwargs):
        self.auxUrls = auxUrls
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        if self.auxUrls is not None:
            for url in self.auxUrls:
                yield self.addURL(os.path.basename(url), url)
        res = yield super().run()
        return res


class KvmStart(steps.ShellCommand):
    name = 'kvm'
    haltOnFailure = True

    def __init__(self, script_name, sshkey_name, disks, kernel_name,
        kernel_arch, **kwargs):
        self.script_name = script_name
        self.sshkey_name = sshkey_name
        self.disks = disks
        self.kernel_name = kernel_name
        self.kernel_arch = kernel_arch
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        disk_opts = ['-hda', '-hdb', '-hdc', '-hdd']
        arch = self.kernel_arch
        workername = self.build.getWorkerName()
        w = find_worker(arch, workername)
        command = [self.script_name, 'run', str(w['kvm_port']), self.
            sshkey_name, '-smp', str(w['kvm_cpus']), '-m', str(w['kvm_mem']
            ), '-kernel', self.kernel_name, '-append', 
            'root=/dev/sda1 ro %s' % serial_console_opt[arch]]
        for opt, disk in zip(disk_opts, self.disks):
            command.append(opt)
            command.append(disk)
        self.command = command
        res = yield super().run()
        return res


class KvmStop(steps.ShellCommand):
    name = 'kvm'
    alwaysRun = True

    def __init__(self, script_name, vmcore_name='vmcore', checkstep=None,
        **kwargs):
        self.script_name = script_name
        self.vmcore_name = vmcore_name
        self.checkstep = checkstep
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        result = util.SUCCESS
        if self.checkstep is not None:
            steps_data = yield self.master.data.get(('builds', self.build.
                buildid, 'steps'))
            for step in steps_data:
                if step['name'] == self.checkstep:
                    result = step['results']
                    break
        command = [self.script_name, 'quit']
        if result == util.FAILURE:
            command.append('dump_serial')
            command.append(self.vmcore_name)
            self.setProperty('has_vmcore', 'Y', 'KvmStop Step')
        else:
            command.append('serial')
            self.setProperty('has_vmcore', 'N', 'KvmStop Step')
        self.command = command
        res = yield super().run()
        return res


<mask token>

<mask token>


def user_buildname(arch):
    return 'userspace-%s' % arch


<mask token>


def getVmlinuxXz():
    return 'vmlinux.xz'


class Tux3UserTestObserver(util.LogLineObserver):
    testPassedPattern = re.compile('^\\[.*:test.*\\] OK$')
    testFailedPattern = re.compile('^\\[.*:test.*\\] FAILED$')

    def __init__(self):
        super().__init__()
        self.rc = util.SUCCESS
        self.passed = 0
        self.failed = 0

    def outLineReceived(self, line):
        if self.testPassedPattern.match(line):
            self.passed += 1
        if self.testFailedPattern.match(line):
            self.failed += 1
            self.rc = util.FAILURE


class Tux3UserTest(steps.Test):
    command = ['make', 'tests']
    warningPattern = userTestPattern

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.observer = Tux3UserTestObserver()
        self.addLogObserver('stdio', self.observer)

    def evaluateCommand(self, cmd):
        total = self.observer.passed + self.observer.failed
        if total:
            self.setTestResults(total=total, passed=self.observer.passed,
                failed=self.observer.failed)
        rc = self.observer.rc
        if rc == util.SUCCESS and self.warnCount:
            rc = util.WARNINGS
        return rc


def user_steps(arch):
    gcovURL = 'gcov/%s/%s' % (arch, '%(prop:buildnumber)s-%(prop:branch)s')
    return [steps.Git(repourl=tux3_repo, branch='user', config=git_configs,
        mode='full', method='copy', description=[util.Interpolate(
        'updating %(prop:branch)s')], descriptionDone=[util.Interpolate(
        'update %(prop:branch)s')], name='git tux3'), steps.Compile(command
        ='make UBSAN=1', workdir='build/fs/tux3/user', warningPattern=
        gccWarnPattern, description=['compiling UBSAN=1'], descriptionDone=
        ['compile UBSAN=1'], name='compile UBSAN=1'), Tux3UserTest(command=
        'make UBSAN=1 tests', workdir='build/fs/tux3/user', description=[
        'testing UBSAN=1'], descriptionDone=['test UBSAN=1'], name=
        'test UBSAN=1'), steps.Compile(command='make distclean', workdir=
        'build/fs/tux3/user', description=['compiling distclean'],
        descriptionDone=['compile distclean'], name='compile distclean'),
        steps.Compile(command='make ASAN=1', workdir='build/fs/tux3/user',
        warningPattern=gccWarnPattern, description=['compiling ASAN=1'],
        descriptionDone=['compile ASAN=1'], name='compile ASAN=1'),
        Tux3UserTest(command='make ASAN=1 tests', workdir=
        'build/fs/tux3/user', description=['testing ASAN=1'],
        descriptionDone=['test ASAN=1'], name='test ASAN=1'), steps.Compile
        (command='make distclean', workdir='build/fs/tux3/user',
        description=['compiling distclean'], descriptionDone=[
        'compile distclean'], name='compile distclean'), steps.Compile(
        command='make CHECK=1 GCOV=1', workdir='build/fs/tux3/user',
        warningPattern=gccWarnPattern), Tux3UserTest(workdir=
        'build/fs/tux3/user'), steps.ShellCommand(command='make coverage',
        workdir='build/fs/tux3/user', haltOnFailure=True, description=[
        'coverage'], descriptionDone=['coverage'], name='coverage report'),
        steps.DirectoryUpload(workersrc='fs/tux3/user/gcov', masterdest=
        util.Interpolate(www_base + gcovURL), url=util.Interpolate(
        http_base + gcovURL)), steps.MasterShellCommand(command=
        './scripts/lcov-summary.sh', description=['updating coverage'],
        descriptionDone=['update coverage'], name='update coverage'), steps
        .MasterShellCommand(command='./scripts/post.sh', description=[
        'post process'], descriptionDone=['post process'], name='post process')
        ]


<mask token>


class FileUploadWithUrls(steps.FileUpload):
    renderables = ['auxUrls']

    def __init__(self, auxUrls=None, **kwargs):
        self.auxUrls = auxUrls
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        if self.auxUrls is not None:
            for url in self.auxUrls:
                yield self.addURL(os.path.basename(url), url)
        res = yield super().run()
        return res


class KvmStart(steps.ShellCommand):
    name = 'kvm'
    haltOnFailure = True

    def __init__(self, script_name, sshkey_name, disks, kernel_name,
        kernel_arch, **kwargs):
        self.script_name = script_name
        self.sshkey_name = sshkey_name
        self.disks = disks
        self.kernel_name = kernel_name
        self.kernel_arch = kernel_arch
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        disk_opts = ['-hda', '-hdb', '-hdc', '-hdd']
        arch = self.kernel_arch
        workername = self.build.getWorkerName()
        w = find_worker(arch, workername)
        command = [self.script_name, 'run', str(w['kvm_port']), self.
            sshkey_name, '-smp', str(w['kvm_cpus']), '-m', str(w['kvm_mem']
            ), '-kernel', self.kernel_name, '-append', 
            'root=/dev/sda1 ro %s' % serial_console_opt[arch]]
        for opt, disk in zip(disk_opts, self.disks):
            command.append(opt)
            command.append(disk)
        self.command = command
        res = yield super().run()
        return res


class KvmStop(steps.ShellCommand):
    name = 'kvm'
    alwaysRun = True

    def __init__(self, script_name, vmcore_name='vmcore', checkstep=None,
        **kwargs):
        self.script_name = script_name
        self.vmcore_name = vmcore_name
        self.checkstep = checkstep
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        result = util.SUCCESS
        if self.checkstep is not None:
            steps_data = yield self.master.data.get(('builds', self.build.
                buildid, 'steps'))
            for step in steps_data:
                if step['name'] == self.checkstep:
                    result = step['results']
                    break
        command = [self.script_name, 'quit']
        if result == util.FAILURE:
            command.append('dump_serial')
            command.append(self.vmcore_name)
            self.setProperty('has_vmcore', 'Y', 'KvmStop Step')
        else:
            command.append('serial')
            self.setProperty('has_vmcore', 'N', 'KvmStop Step')
        self.command = command
        res = yield super().run()
        return res


def stress_steps(arch):
    kvm_workdir = '../guest-images'
    tarball_name = 'kvm-%s.tar.xz' % arch
    tarball_cksum = '%s.sum' % tarball_name
    tarball_cksum_new = '%s.new' % tarball_cksum
    disk_name = 'kvm-%s.qcow2' % arch
    tux3_disk = 'tux3-disk.img'
    sshkey_name = 'id_rsa-%s' % arch
    tests_name = 'tests-%s.tar.xz' % arch
    master_vmlinuz_path = '%s/%s' % ('%(prop:master_basedir)s', getVmlinuz())
    master_vmlinux_xz_path = '%s/%s' % ('%(prop:master_basedir)s',
        getVmlinuxXz())
    master_tux3_path = '%s/%s' % ('%(prop:master_basedir)s', tux3cmd_name)
    kvm_script = 'bb-kvm.sh'
    vmcore_name = 'vmcore'
    vmcore_xz_name = '%s.xz' % vmcore_name
    master_vmcore_xz_path = '%s/%s' % ('%(prop:master_basedir)s',
        vmcore_xz_name)
    return [steps.FileDownload(mastersrc='guest-images/%s' % tarball_cksum,
        workerdest=tarball_cksum_new, workdir=kvm_workdir, mode=420,
        hideStepIf=NotDebug), steps.SetPropertyFromCommand(property=
        'need_image', command=textwrap.dedent(
        """if cmp -s %s %s; then
    echo N
else
    echo Y
fi
mv %s %s
            """
         % (tarball_cksum, tarball_cksum_new, tarball_cksum_new,
        tarball_cksum)).strip(), workdir=kvm_workdir, hideStepIf=NotDebug),
        steps.FileDownload(mastersrc='guest-images/%s' % tarball_name,
        workerdest=tarball_name, workdir=kvm_workdir, mode=420, doStepIf=lambda
        step: step.build.getProperty('need_image') == 'Y'), steps.
        ShellCommand(command='tar xvf %s' % tarball_name, workdir=
        kvm_workdir, haltOnFailure=True, doStepIf=lambda step: step.build.
        getProperty('need_image') == 'Y', description=[
        'uncompressing image'], descriptionDone=['uncompress image'], name=
        'uncompress image'), steps.FileDownload(mastersrc='guest-images/%s' %
        kvm_script, workerdest=kvm_script, workdir='.', mode=493), steps.
        FileDownload(mastersrc='guest-images/%s' % tests_name, workerdest=
        tests_name, workdir='.', mode=420), steps.FileDownload(mastersrc=
        util.Interpolate(www_base + master_tux3_path), workerdest=
        tux3cmd_name, workdir='.', mode=493), steps.FileDownload(mastersrc=
        util.Interpolate(www_base + master_vmlinuz_path), workerdest=
        getVmlinuz(), workdir='.', mode=420), steps.ShellCommand(command=[
        'dd', 'if=/dev/null', 'of=%s' % tux3_disk, 'bs=1M', 'count=0',
        'seek=8192'], workdir='.', description=['making %s' % tux3_disk],
        descriptionDone=['make %s' % tux3_disk], name='make %s' % tux3_disk
        ), KvmStart(script_name='./%s' % kvm_script, sshkey_name='%s/%s' %
        (kvm_workdir, sshkey_name), disks=['%s/%s' % (kvm_workdir,
        disk_name), tux3_disk], kernel_name=getVmlinuz(), kernel_arch=arch,
        workdir='.', description=['running kvm'], descriptionDone=[
        'run kvm'], name='run kvm'), steps.ShellCommand(command=['./%s' %
        kvm_script, 'scp', tests_name, tux3cmd_name, 'localhost:'], workdir
        ='.', description=['scp tools'], descriptionDone=['scp tools'],
        name='scp tools'), steps.ShellCommand(command=['./%s' % kvm_script,
        'ssh', 'tar xvf %s && (cd tests && ./test.sh ../%s /dev/sdb)' % (
        tests_name, tux3cmd_name)], workdir='.', description=['run stress'],
        descriptionDone=['run stress'], name='run stress'), KvmStop(
        script_name='./%s' % kvm_script, vmcore_name=vmcore_name, checkstep
        ='run stress', workdir='.', description=['stopping kvm'],
        descriptionDone=['stop kvm'], name='stop kvm'), steps.ShellCommand(
        command='xz -v %s' % vmcore_name, workdir='.', alwaysRun=True,
        hideStepIf=NotDebug, doStepIf=lambda step: step.build.getProperty(
        'has_vmcore') == 'Y', description=['xz %s' % vmcore_name],
        descriptionDone=['xz %s' % vmcore_name], name='xz %s' % vmcore_name
        ), FileUploadWithUrls(workersrc=vmcore_xz_name, masterdest=util.
        Interpolate(www_base + master_vmcore_xz_path), workdir='.', mode=
        420, url=util.Interpolate(http_base + master_vmcore_xz_path),
        auxUrls=[util.Interpolate(http_base + master_vmlinux_xz_path)],
        alwaysRun=True, doStepIf=lambda step: step.build.getProperty(
        'has_vmcore') == 'Y'), steps.RemoveDirectory(dir=vmcore_xz_name,
        alwaysRun=True, hideStepIf=NotDebug, doStepIf=lambda step: step.
        build.getProperty('has_vmcore') == 'Y'), steps.MasterShellCommand(
        command='./scripts/post.sh', description=['post process'],
        descriptionDone=['post process'], name='post process')]


<mask token>

<mask token>


def user_buildname(arch):
    return 'userspace-%s' % arch


<mask token>


def getVmlinuz():
    return 'vmlinuz'


def getVmlinuxXz():
    return 'vmlinux.xz'


class Tux3UserTestObserver(util.LogLineObserver):
    testPassedPattern = re.compile('^\\[.*:test.*\\] OK$')
    testFailedPattern = re.compile('^\\[.*:test.*\\] FAILED$')

    def __init__(self):
        super().__init__()
        self.rc = util.SUCCESS
        self.passed = 0
        self.failed = 0

    def outLineReceived(self, line):
        if self.testPassedPattern.match(line):
            self.passed += 1
        if self.testFailedPattern.match(line):
            self.failed += 1
            self.rc = util.FAILURE


class Tux3UserTest(steps.Test):
    command = ['make', 'tests']
    warningPattern = userTestPattern

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.observer = Tux3UserTestObserver()
        self.addLogObserver('stdio', self.observer)

    def evaluateCommand(self, cmd):
        total = self.observer.passed + self.observer.failed
        if total:
            self.setTestResults(total=total, passed=self.observer.passed,
                failed=self.observer.failed)
        rc = self.observer.rc
        if rc == util.SUCCESS and self.warnCount:
            rc = util.WARNINGS
        return rc


def user_steps(arch):
    gcovURL = 'gcov/%s/%s' % (arch, '%(prop:buildnumber)s-%(prop:branch)s')
    return [steps.Git(repourl=tux3_repo, branch='user', config=git_configs,
        mode='full', method='copy', description=[util.Interpolate(
        'updating %(prop:branch)s')], descriptionDone=[util.Interpolate(
        'update %(prop:branch)s')], name='git tux3'), steps.Compile(command
        ='make UBSAN=1', workdir='build/fs/tux3/user', warningPattern=
        gccWarnPattern, description=['compiling UBSAN=1'], descriptionDone=
        ['compile UBSAN=1'], name='compile UBSAN=1'), Tux3UserTest(command=
        'make UBSAN=1 tests', workdir='build/fs/tux3/user', description=[
        'testing UBSAN=1'], descriptionDone=['test UBSAN=1'], name=
        'test UBSAN=1'), steps.Compile(command='make distclean', workdir=
        'build/fs/tux3/user', description=['compiling distclean'],
        descriptionDone=['compile distclean'], name='compile distclean'),
        steps.Compile(command='make ASAN=1', workdir='build/fs/tux3/user',
        warningPattern=gccWarnPattern, description=['compiling ASAN=1'],
        descriptionDone=['compile ASAN=1'], name='compile ASAN=1'),
        Tux3UserTest(command='make ASAN=1 tests', workdir=
        'build/fs/tux3/user', description=['testing ASAN=1'],
        descriptionDone=['test ASAN=1'], name='test ASAN=1'), steps.Compile
        (command='make distclean', workdir='build/fs/tux3/user',
        description=['compiling distclean'], descriptionDone=[
        'compile distclean'], name='compile distclean'), steps.Compile(
        command='make CHECK=1 GCOV=1', workdir='build/fs/tux3/user',
        warningPattern=gccWarnPattern), Tux3UserTest(workdir=
        'build/fs/tux3/user'), steps.ShellCommand(command='make coverage',
        workdir='build/fs/tux3/user', haltOnFailure=True, description=[
        'coverage'], descriptionDone=['coverage'], name='coverage report'),
        steps.DirectoryUpload(workersrc='fs/tux3/user/gcov', masterdest=
        util.Interpolate(www_base + gcovURL), url=util.Interpolate(
        http_base + gcovURL)), steps.MasterShellCommand(command=
        './scripts/lcov-summary.sh', description=['updating coverage'],
        descriptionDone=['update coverage'], name='update coverage'), steps
        .MasterShellCommand(command='./scripts/post.sh', description=[
        'post process'], descriptionDone=['post process'], name='post process')
        ]


<mask token>


class FileUploadWithUrls(steps.FileUpload):
    renderables = ['auxUrls']

    def __init__(self, auxUrls=None, **kwargs):
        self.auxUrls = auxUrls
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        if self.auxUrls is not None:
            for url in self.auxUrls:
                yield self.addURL(os.path.basename(url), url)
        res = yield super().run()
        return res


class KvmStart(steps.ShellCommand):
    name = 'kvm'
    haltOnFailure = True

    def __init__(self, script_name, sshkey_name, disks, kernel_name,
        kernel_arch, **kwargs):
        self.script_name = script_name
        self.sshkey_name = sshkey_name
        self.disks = disks
        self.kernel_name = kernel_name
        self.kernel_arch = kernel_arch
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        disk_opts = ['-hda', '-hdb', '-hdc', '-hdd']
        arch = self.kernel_arch
        workername = self.build.getWorkerName()
        w = find_worker(arch, workername)
        command = [self.script_name, 'run', str(w['kvm_port']), self.
            sshkey_name, '-smp', str(w['kvm_cpus']), '-m', str(w['kvm_mem']
            ), '-kernel', self.kernel_name, '-append', 
            'root=/dev/sda1 ro %s' % serial_console_opt[arch]]
        for opt, disk in zip(disk_opts, self.disks):
            command.append(opt)
            command.append(disk)
        self.command = command
        res = yield super().run()
        return res


class KvmStop(steps.ShellCommand):
    name = 'kvm'
    alwaysRun = True

    def __init__(self, script_name, vmcore_name='vmcore', checkstep=None,
        **kwargs):
        self.script_name = script_name
        self.vmcore_name = vmcore_name
        self.checkstep = checkstep
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        result = util.SUCCESS
        if self.checkstep is not None:
            steps_data = yield self.master.data.get(('builds', self.build.
                buildid, 'steps'))
            for step in steps_data:
                if step['name'] == self.checkstep:
                    result = step['results']
                    break
        command = [self.script_name, 'quit']
        if result == util.FAILURE:
            command.append('dump_serial')
            command.append(self.vmcore_name)
            self.setProperty('has_vmcore', 'Y', 'KvmStop Step')
        else:
            command.append('serial')
            self.setProperty('has_vmcore', 'N', 'KvmStop Step')
        self.command = command
        res = yield super().run()
        return res


def stress_steps(arch):
    kvm_workdir = '../guest-images'
    tarball_name = 'kvm-%s.tar.xz' % arch
    tarball_cksum = '%s.sum' % tarball_name
    tarball_cksum_new = '%s.new' % tarball_cksum
    disk_name = 'kvm-%s.qcow2' % arch
    tux3_disk = 'tux3-disk.img'
    sshkey_name = 'id_rsa-%s' % arch
    tests_name = 'tests-%s.tar.xz' % arch
    master_vmlinuz_path = '%s/%s' % ('%(prop:master_basedir)s', getVmlinuz())
    master_vmlinux_xz_path = '%s/%s' % ('%(prop:master_basedir)s',
        getVmlinuxXz())
    master_tux3_path = '%s/%s' % ('%(prop:master_basedir)s', tux3cmd_name)
    kvm_script = 'bb-kvm.sh'
    vmcore_name = 'vmcore'
    vmcore_xz_name = '%s.xz' % vmcore_name
    master_vmcore_xz_path = '%s/%s' % ('%(prop:master_basedir)s',
        vmcore_xz_name)
    return [steps.FileDownload(mastersrc='guest-images/%s' % tarball_cksum,
        workerdest=tarball_cksum_new, workdir=kvm_workdir, mode=420,
        hideStepIf=NotDebug), steps.SetPropertyFromCommand(property=
        'need_image', command=textwrap.dedent(
        """if cmp -s %s %s; then
    echo N
else
    echo Y
fi
mv %s %s
            """
         % (tarball_cksum, tarball_cksum_new, tarball_cksum_new,
        tarball_cksum)).strip(), workdir=kvm_workdir, hideStepIf=NotDebug),
        steps.FileDownload(mastersrc='guest-images/%s' % tarball_name,
        workerdest=tarball_name, workdir=kvm_workdir, mode=420, doStepIf=lambda
        step: step.build.getProperty('need_image') == 'Y'), steps.
        ShellCommand(command='tar xvf %s' % tarball_name, workdir=
        kvm_workdir, haltOnFailure=True, doStepIf=lambda step: step.build.
        getProperty('need_image') == 'Y', description=[
        'uncompressing image'], descriptionDone=['uncompress image'], name=
        'uncompress image'), steps.FileDownload(mastersrc='guest-images/%s' %
        kvm_script, workerdest=kvm_script, workdir='.', mode=493), steps.
        FileDownload(mastersrc='guest-images/%s' % tests_name, workerdest=
        tests_name, workdir='.', mode=420), steps.FileDownload(mastersrc=
        util.Interpolate(www_base + master_tux3_path), workerdest=
        tux3cmd_name, workdir='.', mode=493), steps.FileDownload(mastersrc=
        util.Interpolate(www_base + master_vmlinuz_path), workerdest=
        getVmlinuz(), workdir='.', mode=420), steps.ShellCommand(command=[
        'dd', 'if=/dev/null', 'of=%s' % tux3_disk, 'bs=1M', 'count=0',
        'seek=8192'], workdir='.', description=['making %s' % tux3_disk],
        descriptionDone=['make %s' % tux3_disk], name='make %s' % tux3_disk
        ), KvmStart(script_name='./%s' % kvm_script, sshkey_name='%s/%s' %
        (kvm_workdir, sshkey_name), disks=['%s/%s' % (kvm_workdir,
        disk_name), tux3_disk], kernel_name=getVmlinuz(), kernel_arch=arch,
        workdir='.', description=['running kvm'], descriptionDone=[
        'run kvm'], name='run kvm'), steps.ShellCommand(command=['./%s' %
        kvm_script, 'scp', tests_name, tux3cmd_name, 'localhost:'], workdir
        ='.', description=['scp tools'], descriptionDone=['scp tools'],
        name='scp tools'), steps.ShellCommand(command=['./%s' % kvm_script,
        'ssh', 'tar xvf %s && (cd tests && ./test.sh ../%s /dev/sdb)' % (
        tests_name, tux3cmd_name)], workdir='.', description=['run stress'],
        descriptionDone=['run stress'], name='run stress'), KvmStop(
        script_name='./%s' % kvm_script, vmcore_name=vmcore_name, checkstep
        ='run stress', workdir='.', description=['stopping kvm'],
        descriptionDone=['stop kvm'], name='stop kvm'), steps.ShellCommand(
        command='xz -v %s' % vmcore_name, workdir='.', alwaysRun=True,
        hideStepIf=NotDebug, doStepIf=lambda step: step.build.getProperty(
        'has_vmcore') == 'Y', description=['xz %s' % vmcore_name],
        descriptionDone=['xz %s' % vmcore_name], name='xz %s' % vmcore_name
        ), FileUploadWithUrls(workersrc=vmcore_xz_name, masterdest=util.
        Interpolate(www_base + master_vmcore_xz_path), workdir='.', mode=
        420, url=util.Interpolate(http_base + master_vmcore_xz_path),
        auxUrls=[util.Interpolate(http_base + master_vmlinux_xz_path)],
        alwaysRun=True, doStepIf=lambda step: step.build.getProperty(
        'has_vmcore') == 'Y'), steps.RemoveDirectory(dir=vmcore_xz_name,
        alwaysRun=True, hideStepIf=NotDebug, doStepIf=lambda step: step.
        build.getProperty('has_vmcore') == 'Y'), steps.MasterShellCommand(
        command='./scripts/post.sh', description=['post process'],
        descriptionDone=['post process'], name='post process')]


<mask token>

import sys, os
from buildbot.plugins import *
NotDebug = True
masterHost = 'buildbot.tux3.org'
masterWorkerPort = 9989
https_proxy = None
tux3_repo = 'https://github.com/OGAWAHirofumi/linux-tux3.git'
linux_configs = 'tux3-linux-configs'
linux_configs_repo = 'https://github.com/OGAWAHirofumi/%s.git' % linux_configs
tux3_branch_def = {'master': 'user', 'hirofumi': 'hirofumi-user'}
git_configs = None
if https_proxy:
    os.environ['HTTPS_PROXY'] = https_proxy
    git_configs = {}
    git_configs['http.proxy'] = https_proxy
www_base = '../www/'
http_base = '/'
secrets_dir = os.path.join(os.path.dirname(__file__), 'secrets')
tux3_user_branches = list(tux3_branch_def.values())
tux3_kern_branches = list(tux3_branch_def.keys())
tux3_branches = tux3_user_branches + tux3_kern_branches
workers_def = {'i386': [{'name': 'i386-worker0', 'pass': None, 'kvm_host': 
    False}, {'name': 'i386-worker1', 'pass': None, 'kvm_host': True,
    'kvm_cpus': 2, 'kvm_mem': 2048, 'kvm_port': 11112}], 'x86_64': [{'name':
    'x86_64-worker0', 'pass': None, 'kvm_host': False}, {'name':
    'x86_64-worker1', 'pass': None, 'kvm_host': True, 'kvm_cpus': 2,
    'kvm_mem': 2048, 'kvm_port': 11113}]}
for arch in workers_def.keys():
    for w in workers_def[arch]:
        if w['pass'] is None:
            with open(os.path.join(secrets_dir, w['name'])) as f:
                w['pass'] = f.read().strip()
serial_console_opt = {'i386': 'console=ttyS0,115200 console=tty0', 'x86_64':
    'console=ttyS0,115200 console=tty0'}
basic_workers = {}
stress_workers = {}
for arch in workers_def.keys():
    basic_workers[arch] = [s['name'] for s in workers_def[arch] if not s[
        'kvm_host']]
    stress_workers[arch] = [s['name'] for s in workers_def[arch] if s[
        'kvm_host']]


def user_buildname(arch):
    return 'userspace-%s' % arch


def kern_buildname(arch):
    return 'kernel-%s' % arch


def stress_buildname(arch):
    return 'stress-%s' % arch


user_builders = [user_buildname(arch) for arch in basic_workers.keys()]
kern_builders = [kern_buildname(arch) for arch in basic_workers.keys()]
stress_builders = [stress_buildname(arch) for arch in stress_workers.keys()]
all_builders = user_builders + kern_builders + stress_builders
c = BuildmasterConfig = {}
c['buildbotNetUsageData'] = None
c['workers'] = []
for arch in workers_def.keys():
    for w in workers_def[arch]:
        c['workers'].append(worker.Worker(w['name'], w['pass'], max_builds=1))
c['protocols'] = {'pb': {'port': masterWorkerPort}}
c['change_source'] = []
c['change_source'].append(changes.GitPoller(repourl=tux3_repo, branches=
    tux3_branches, workdir='gitpoller-workdir-tux3', pollinterval=300,
    buildPushesWithNoCommits=True))
c['schedulers'] = []
c['schedulers'].append(schedulers.AnyBranchScheduler(name='basic',
    change_filter=util.ChangeFilter(branch=tux3_user_branches),
    treeStableTimer=60, builderNames=user_builders))
c['schedulers'].append(schedulers.AnyBranchScheduler(name='kern',
    change_filter=util.ChangeFilter(branch=tux3_kern_branches),
    treeStableTimer=60, builderNames=kern_builders))
c['schedulers'].append(schedulers.ForceScheduler(name='force', builderNames
    =all_builders))
import re
import textwrap
from twisted.internet import defer
c['builders'] = []
gccWarnPattern = (
    '^(.*?):([0-9]+):([0-9]+:)? (.*)?([Ww]arning|[Ee]rror|[Nn]ote): (.*)$')
modpostPattern = '^(WARNING|ERROR|FATAL): .*$'
headerPattern = '^(.*):([0-9]+): (.*)$'
kernPattern = '(%s|%s|%s)' % (gccWarnPattern, modpostPattern, headerPattern)
assertPattern = '^(WARNING|BUG): .*$'
userTestPattern = '(%s|%s)' % (gccWarnPattern, assertPattern)
tux3cmd_name = 'tux3'


def find_worker(arch, workername):
    for w in workers_def[arch]:
        if workername == w['name']:
            return w


def getVmlinuz():
    return 'vmlinuz'


def getVmlinuxXz():
    return 'vmlinux.xz'


class Tux3UserTestObserver(util.LogLineObserver):
    testPassedPattern = re.compile('^\\[.*:test.*\\] OK$')
    testFailedPattern = re.compile('^\\[.*:test.*\\] FAILED$')

    def __init__(self):
        super().__init__()
        self.rc = util.SUCCESS
        self.passed = 0
        self.failed = 0

    def outLineReceived(self, line):
        if self.testPassedPattern.match(line):
            self.passed += 1
        if self.testFailedPattern.match(line):
            self.failed += 1
            self.rc = util.FAILURE


class Tux3UserTest(steps.Test):
    command = ['make', 'tests']
    warningPattern = userTestPattern

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.observer = Tux3UserTestObserver()
        self.addLogObserver('stdio', self.observer)

    def evaluateCommand(self, cmd):
        total = self.observer.passed + self.observer.failed
        if total:
            self.setTestResults(total=total, passed=self.observer.passed,
                failed=self.observer.failed)
        rc = self.observer.rc
        if rc == util.SUCCESS and self.warnCount:
            rc = util.WARNINGS
        return rc


def user_steps(arch):
    gcovURL = 'gcov/%s/%s' % (arch, '%(prop:buildnumber)s-%(prop:branch)s')
    return [steps.Git(repourl=tux3_repo, branch='user', config=git_configs,
        mode='full', method='copy', description=[util.Interpolate(
        'updating %(prop:branch)s')], descriptionDone=[util.Interpolate(
        'update %(prop:branch)s')], name='git tux3'), steps.Compile(command
        ='make UBSAN=1', workdir='build/fs/tux3/user', warningPattern=
        gccWarnPattern, description=['compiling UBSAN=1'], descriptionDone=
        ['compile UBSAN=1'], name='compile UBSAN=1'), Tux3UserTest(command=
        'make UBSAN=1 tests', workdir='build/fs/tux3/user', description=[
        'testing UBSAN=1'], descriptionDone=['test UBSAN=1'], name=
        'test UBSAN=1'), steps.Compile(command='make distclean', workdir=
        'build/fs/tux3/user', description=['compiling distclean'],
        descriptionDone=['compile distclean'], name='compile distclean'),
        steps.Compile(command='make ASAN=1', workdir='build/fs/tux3/user',
        warningPattern=gccWarnPattern, description=['compiling ASAN=1'],
        descriptionDone=['compile ASAN=1'], name='compile ASAN=1'),
        Tux3UserTest(command='make ASAN=1 tests', workdir=
        'build/fs/tux3/user', description=['testing ASAN=1'],
        descriptionDone=['test ASAN=1'], name='test ASAN=1'), steps.Compile
        (command='make distclean', workdir='build/fs/tux3/user',
        description=['compiling distclean'], descriptionDone=[
        'compile distclean'], name='compile distclean'), steps.Compile(
        command='make CHECK=1 GCOV=1', workdir='build/fs/tux3/user',
        warningPattern=gccWarnPattern), Tux3UserTest(workdir=
        'build/fs/tux3/user'), steps.ShellCommand(command='make coverage',
        workdir='build/fs/tux3/user', haltOnFailure=True, description=[
        'coverage'], descriptionDone=['coverage'], name='coverage report'),
        steps.DirectoryUpload(workersrc='fs/tux3/user/gcov', masterdest=
        util.Interpolate(www_base + gcovURL), url=util.Interpolate(
        http_base + gcovURL)), steps.MasterShellCommand(command=
        './scripts/lcov-summary.sh', description=['updating coverage'],
        descriptionDone=['update coverage'], name='update coverage'), steps
        .MasterShellCommand(command='./scripts/post.sh', description=[
        'post process'], descriptionDone=['post process'], name='post process')
        ]


@util.renderer
def CheckoutUserBranch(props):
    kern = props.getProperty('branch')
    user = tux3_branch_def[kern]
    opt = ''
    if git_configs:
        for key, val in git_configs.items():
            opt += " -c '%s=%s'" % (key, val)
    return 'git %s fetch -p && git checkout -B %s origin/%s' % (opt, user, user
        )


def kern_steps(arch):
    master_basedir = 'binaries/%s/%s' % (arch, '%(prop:buildnumber)s')
    master_tux3_path = '%s/%s' % (master_basedir, tux3cmd_name)
    master_vmlinuz_path = '%s/%s' % (master_basedir, getVmlinuz())
    master_vmlinux_xz_path = '%s/%s' % (master_basedir, getVmlinuxXz())
    return [steps.Git(repourl=tux3_repo, branch='master', config=
        git_configs, mode='full', method='copy', description=[util.
        Interpolate('updating %(prop:branch)s')], descriptionDone=[util.
        Interpolate('update %(prop:branch)s')], name='git tux3'), steps.
        MasterShellCommand(command=textwrap.dedent(
        """
DIR="%s"
if [ -d "$DIR" ]; then
    cd "$DIR"
    git pull -p
else
    git clone "%s"
fi
            """
         % (linux_configs, linux_configs_repo)).strip(), description=[
        'updating linux-configs'], descriptionDone=['update linux-configs'],
        name='update linux-configs'), steps.SetPropertyFromCommand(property
        ='kern_ver', command=textwrap.dedent(
        """
eval $(sed -n -e 's/\\(.*\\) = \\(.*\\)/\\1=\\2/p' -e '/^EXTRAVERSION/q' Makefile)
echo $VERSION.$PATCHLEVEL
            """
        ).strip(), hideStepIf=NotDebug), steps.FileDownload(mastersrc=util.
        Interpolate(linux_configs + '/%(prop:kern_ver)s/.config.kvm-debug-' +
        arch), workerdest='.config', mode=420), steps.Compile(command=
        'make olddefconfig', warningPattern=kernPattern, description=[
        'compiling olddefconfig'], descriptionDone=['compile olddefconfig'],
        name='compile olddefconfig'), steps.Compile(command='make',
        warningPattern=kernPattern, description=['compiling kernel'],
        descriptionDone=['compile kernel'], name='compile kernel'), steps.
        FileUpload(workersrc='arch/%s/boot/bzImage' % arch, masterdest=util
        .Interpolate(www_base + master_vmlinuz_path), mode=420, url=util.
        Interpolate(http_base + master_vmlinuz_path)), steps.ShellCommand(
        command='xz -v vmlinux', hideStepIf=NotDebug, description=[
        'xz vmlinux'], descriptionDone=['xz vmlinux'], name='xz vmlinux'),
        steps.FileUpload(workersrc='vmlinux.xz', masterdest=util.
        Interpolate(www_base + master_vmlinux_xz_path), mode=420, url=util.
        Interpolate(http_base + master_vmlinux_xz_path)), steps.Compile(
        command='make CONFIG_TUX3=m C=1 M=fs/tux3', warningPattern=
        kernPattern, description=['compiling module'], descriptionDone=[
        'compile module'], name='compile module'), steps.Compile(command=
        'make mrproper', description=['clean kernel'], descriptionDone=[
        'clean kernel'], name='clean kernel'), steps.ShellCommand(command=
        CheckoutUserBranch, haltOnFailure=True, description=[
        'update tux3/user'], descriptionDone=['update tux3/user'], name=
        'git tux3/user'), steps.Compile(command='make', workdir=
        'build/fs/tux3/user', warningPattern=kernPattern, description=[
        'compiling command'], descriptionDone=['compile command'], name=
        'compile command'), steps.FileUpload(workersrc='fs/tux3/user/%s' %
        tux3cmd_name, masterdest=util.Interpolate(www_base +
        master_tux3_path), url=util.Interpolate(http_base +
        master_tux3_path)), steps.MasterShellCommand(command=
        './scripts/post.sh', description=['post process'], descriptionDone=
        ['post process'], name='post process'), steps.Trigger(
        schedulerNames=[stress_buildname(arch)], waitForFinish=False,
        updateSourceStamp=True, set_properties={'master_basedir': util.
        Interpolate(master_basedir)}, copy_properties={'got_revision'})]


class FileUploadWithUrls(steps.FileUpload):
    renderables = ['auxUrls']

    def __init__(self, auxUrls=None, **kwargs):
        self.auxUrls = auxUrls
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        if self.auxUrls is not None:
            for url in self.auxUrls:
                yield self.addURL(os.path.basename(url), url)
        res = yield super().run()
        return res


class KvmStart(steps.ShellCommand):
    name = 'kvm'
    haltOnFailure = True

    def __init__(self, script_name, sshkey_name, disks, kernel_name,
        kernel_arch, **kwargs):
        self.script_name = script_name
        self.sshkey_name = sshkey_name
        self.disks = disks
        self.kernel_name = kernel_name
        self.kernel_arch = kernel_arch
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        disk_opts = ['-hda', '-hdb', '-hdc', '-hdd']
        arch = self.kernel_arch
        workername = self.build.getWorkerName()
        w = find_worker(arch, workername)
        command = [self.script_name, 'run', str(w['kvm_port']), self.
            sshkey_name, '-smp', str(w['kvm_cpus']), '-m', str(w['kvm_mem']
            ), '-kernel', self.kernel_name, '-append', 
            'root=/dev/sda1 ro %s' % serial_console_opt[arch]]
        for opt, disk in zip(disk_opts, self.disks):
            command.append(opt)
            command.append(disk)
        self.command = command
        res = yield super().run()
        return res


class KvmStop(steps.ShellCommand):
    name = 'kvm'
    alwaysRun = True

    def __init__(self, script_name, vmcore_name='vmcore', checkstep=None,
        **kwargs):
        self.script_name = script_name
        self.vmcore_name = vmcore_name
        self.checkstep = checkstep
        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        result = util.SUCCESS
        if self.checkstep is not None:
            steps_data = yield self.master.data.get(('builds', self.build.
                buildid, 'steps'))
            for step in steps_data:
                if step['name'] == self.checkstep:
                    result = step['results']
                    break
        command = [self.script_name, 'quit']
        if result == util.FAILURE:
            command.append('dump_serial')
            command.append(self.vmcore_name)
            self.setProperty('has_vmcore', 'Y', 'KvmStop Step')
        else:
            command.append('serial')
            self.setProperty('has_vmcore', 'N', 'KvmStop Step')
        self.command = command
        res = yield super().run()
        return res


def stress_steps(arch):
    kvm_workdir = '../guest-images'
    tarball_name = 'kvm-%s.tar.xz' % arch
    tarball_cksum = '%s.sum' % tarball_name
    tarball_cksum_new = '%s.new' % tarball_cksum
    disk_name = 'kvm-%s.qcow2' % arch
    tux3_disk = 'tux3-disk.img'
    sshkey_name = 'id_rsa-%s' % arch
    tests_name = 'tests-%s.tar.xz' % arch
    master_vmlinuz_path = '%s/%s' % ('%(prop:master_basedir)s', getVmlinuz())
    master_vmlinux_xz_path = '%s/%s' % ('%(prop:master_basedir)s',
        getVmlinuxXz())
    master_tux3_path = '%s/%s' % ('%(prop:master_basedir)s', tux3cmd_name)
    kvm_script = 'bb-kvm.sh'
    vmcore_name = 'vmcore'
    vmcore_xz_name = '%s.xz' % vmcore_name
    master_vmcore_xz_path = '%s/%s' % ('%(prop:master_basedir)s',
        vmcore_xz_name)
    return [steps.FileDownload(mastersrc='guest-images/%s' % tarball_cksum,
        workerdest=tarball_cksum_new, workdir=kvm_workdir, mode=420,
        hideStepIf=NotDebug), steps.SetPropertyFromCommand(property=
        'need_image', command=textwrap.dedent(
        """if cmp -s %s %s; then
    echo N
else
    echo Y
fi
mv %s %s
            """
         % (tarball_cksum, tarball_cksum_new, tarball_cksum_new,
        tarball_cksum)).strip(), workdir=kvm_workdir, hideStepIf=NotDebug),
        steps.FileDownload(mastersrc='guest-images/%s' % tarball_name,
        workerdest=tarball_name, workdir=kvm_workdir, mode=420, doStepIf=lambda
        step: step.build.getProperty('need_image') == 'Y'), steps.
        ShellCommand(command='tar xvf %s' % tarball_name, workdir=
        kvm_workdir, haltOnFailure=True, doStepIf=lambda step: step.build.
        getProperty('need_image') == 'Y', description=[
        'uncompressing image'], descriptionDone=['uncompress image'], name=
        'uncompress image'), steps.FileDownload(mastersrc='guest-images/%s' %
        kvm_script, workerdest=kvm_script, workdir='.', mode=493), steps.
        FileDownload(mastersrc='guest-images/%s' % tests_name, workerdest=
        tests_name, workdir='.', mode=420), steps.FileDownload(mastersrc=
        util.Interpolate(www_base + master_tux3_path), workerdest=
        tux3cmd_name, workdir='.', mode=493), steps.FileDownload(mastersrc=
        util.Interpolate(www_base + master_vmlinuz_path), workerdest=
        getVmlinuz(), workdir='.', mode=420), steps.ShellCommand(command=[
        'dd', 'if=/dev/null', 'of=%s' % tux3_disk, 'bs=1M', 'count=0',
        'seek=8192'], workdir='.', description=['making %s' % tux3_disk],
        descriptionDone=['make %s' % tux3_disk], name='make %s' % tux3_disk
        ), KvmStart(script_name='./%s' % kvm_script, sshkey_name='%s/%s' %
        (kvm_workdir, sshkey_name), disks=['%s/%s' % (kvm_workdir,
        disk_name), tux3_disk], kernel_name=getVmlinuz(), kernel_arch=arch,
        workdir='.', description=['running kvm'], descriptionDone=[
        'run kvm'], name='run kvm'), steps.ShellCommand(command=['./%s' %
        kvm_script, 'scp', tests_name, tux3cmd_name, 'localhost:'], workdir
        ='.', description=['scp tools'], descriptionDone=['scp tools'],
        name='scp tools'), steps.ShellCommand(command=['./%s' % kvm_script,
        'ssh', 'tar xvf %s && (cd tests && ./test.sh ../%s /dev/sdb)' % (
        tests_name, tux3cmd_name)], workdir='.', description=['run stress'],
        descriptionDone=['run stress'], name='run stress'), KvmStop(
        script_name='./%s' % kvm_script, vmcore_name=vmcore_name, checkstep
        ='run stress', workdir='.', description=['stopping kvm'],
        descriptionDone=['stop kvm'], name='stop kvm'), steps.ShellCommand(
        command='xz -v %s' % vmcore_name, workdir='.', alwaysRun=True,
        hideStepIf=NotDebug, doStepIf=lambda step: step.build.getProperty(
        'has_vmcore') == 'Y', description=['xz %s' % vmcore_name],
        descriptionDone=['xz %s' % vmcore_name], name='xz %s' % vmcore_name
        ), FileUploadWithUrls(workersrc=vmcore_xz_name, masterdest=util.
        Interpolate(www_base + master_vmcore_xz_path), workdir='.', mode=
        420, url=util.Interpolate(http_base + master_vmcore_xz_path),
        auxUrls=[util.Interpolate(http_base + master_vmlinux_xz_path)],
        alwaysRun=True, doStepIf=lambda step: step.build.getProperty(
        'has_vmcore') == 'Y'), steps.RemoveDirectory(dir=vmcore_xz_name,
        alwaysRun=True, hideStepIf=NotDebug, doStepIf=lambda step: step.
        build.getProperty('has_vmcore') == 'Y'), steps.MasterShellCommand(
        command='./scripts/post.sh', description=['post process'],
        descriptionDone=['post process'], name='post process')]


for arch in workers_def.keys():
    c['builders'].append(util.BuilderConfig(name=user_buildname(arch),
        workernames=basic_workers[arch], factory=util.BuildFactory(
        user_steps(arch))))
    c['schedulers'].append(schedulers.Triggerable(name=kern_buildname(arch),
        builderNames=[kern_buildname(arch)]))
    c['builders'].append(util.BuilderConfig(name=kern_buildname(arch),
        workernames=basic_workers[arch], factory=util.BuildFactory(
        kern_steps(arch))))
    c['schedulers'].append(schedulers.Triggerable(name=stress_buildname(
        arch), builderNames=[stress_buildname(arch)]))
    c['builders'].append(util.BuilderConfig(name=stress_buildname(arch),
        workernames=stress_workers[arch], factory=util.BuildFactory(
        stress_steps(arch))))
c['services'] = []
c['title'] = 'tux3'
c['titleURL'] = 'https://tux3.org/'
c['buildbotURL'] = 'https://%s/buildbot/' % masterHost
c['www'] = dict(port=8010, plugins=dict(waterfall_view={}, console_view={},
    grid_view={}))
account = {}
with open(os.path.join(secrets_dir, 'master-users')) as f:
    for line in f.readlines():
        entry = line.strip().split(':')
        account[entry[0]] = entry[1]
c['www']['auth'] = util.UserPasswordAuth(account)
c['www']['authz'] = util.Authz(allowRules=[util.AnyControlEndpointMatcher(
    role='admins')], roleMatchers=[util.RolesFromUsername(roles=['admins'],
    usernames=['tux3'])])
c['db'] = {'db_url': 'sqlite:///state.sqlite'}

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

import sys, os
from buildbot.plugins import *

#######

NotDebug = True

masterHost = "buildbot.tux3.org"
masterWorkerPort = 9989

# git proxy for https://
https_proxy = None
#https_proxy = 'http://localhost:8080'

# git proxy for git://
#
# Save the following as git-proxy.sh, then copy to everywhere by
# buildbot FileDownload and add it to $PATH (or add git config --global).
#
# $ cat > git-proxy.sh
# nc -x localhost:8080 -X connect "$@"
# ^D
#
# os.environ['GIT_PROXY_COMMAND'] = 'git-proxy.sh'
# git_configs['core.gitProxy'] = 'git-proxy.sh'

# linux-tux3 git repo
tux3_repo = "https://github.com/OGAWAHirofumi/linux-tux3.git"
linux_configs = "tux3-linux-configs"
linux_configs_repo = "https://github.com/OGAWAHirofumi/%s.git" % (linux_configs)
tux3_branch_def = {
    'master' : 'user',
    'hirofumi' : 'hirofumi-user',
}

# Setup proxy if there
git_configs = None
if https_proxy:
    # For GitPoller and git command in master
    os.environ['HTTPS_PROXY'] = https_proxy
    # For remote Git
    git_configs = {}
    git_configs['http.proxy'] = https_proxy

# location for providing static contents via normal http server
www_base = "../www/"
http_base = "/"
secrets_dir = os.path.join(os.path.dirname(__file__), "secrets")

tux3_user_branches = list(tux3_branch_def.values())
tux3_kern_branches = list(tux3_branch_def.keys())
tux3_branches = tux3_user_branches + tux3_kern_branches

# Define workers
workers_def = {
    'i386': [
        # i386-worker0 using port 11111
        { 'name': "i386-worker0", 'pass': None, 'kvm_host': False, },
        { 'name': "i386-worker1", 'pass': None, 'kvm_host': True,
          'kvm_cpus': 2, 'kvm_mem': 2048, 'kvm_port': 11112, },
#        { 'name': "x86_64-worker1", 'pass': "", 'kvm_host': True,
#          'kvm_cpus': 2, 'kvm_mem': 2048, 'kvm_port': 11114, },
    ],
    'x86_64': [
        { 'name': "x86_64-worker0", 'pass': None, 'kvm_host': False, },
        { 'name': "x86_64-worker1", 'pass': None, 'kvm_host': True,
          'kvm_cpus': 2, 'kvm_mem': 2048, 'kvm_port': 11113, },
    ],
}

# Get password from "master/secrets/<workername>", then update "workers_def"
for arch in workers_def.keys():
    for w in workers_def[arch]:
        if w['pass'] is None:
            # get the password based on the name
            with open(os.path.join(secrets_dir, w['name'])) as f:
                w['pass'] = f.read().strip()

# Option for kernel serial console
serial_console_opt = {
    'i386': 'console=ttyS0,115200 console=tty0',
    'x86_64': 'console=ttyS0,115200 console=tty0',
}

basic_workers = {}
stress_workers = {}
for arch in workers_def.keys():
    basic_workers[arch] = [
        s['name'] for s in workers_def[arch] if not s['kvm_host']
    ]
    stress_workers[arch] = [
        s['name'] for s in workers_def[arch] if s['kvm_host']
    ]

# Builders and associated workers
def user_buildname(arch):
    return "userspace-%s" % arch
def kern_buildname(arch):
    return "kernel-%s" % arch
def stress_buildname(arch):
    return "stress-%s" % arch

user_builders = [ user_buildname(arch) for arch in basic_workers.keys() ]
kern_builders = [ kern_buildname(arch) for arch in basic_workers.keys() ]
stress_builders = [ stress_buildname(arch) for arch in stress_workers.keys() ]

# All builders for "force" schedule
all_builders = user_builders + kern_builders + stress_builders

####### CONFIGS

# This is a sample buildmaster config file. It must be installed as
# 'master.cfg' in your buildmaster's base directory.

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

c['buildbotNetUsageData'] = None

####### WORKERS

# The 'workers' list defines the set of recognized workers. Each element is
# a Worker object, specifying a unique worker name and password.  The same
# worker name and password must be configured on the worker.

c['workers'] = []

for arch in workers_def.keys():
    for w in workers_def[arch]:
        # Add worker
        c['workers'].append(worker.Worker(
            w['name'], w['pass'],
            max_builds=1,
        ))

# 'protocols' contains information about protocols which master will use for
# communicating with workers. You must define at least 'port' option that workers
# could connect to your master with this protocol.
# 'port' must match the value configured into the workers (with their
# --master option)
c['protocols'] = {'pb': {'port': masterWorkerPort}}

####### CHANGESOURCES

# the 'change_source' setting tells the buildmaster how it should find out
# about source code changes.  Here we point to the buildbot version of a python hello-world project.

c['change_source'] = []
c['change_source'].append(changes.GitPoller(
    repourl=tux3_repo, branches=tux3_branches,
    workdir="gitpoller-workdir-tux3",
    pollinterval=300,
    buildPushesWithNoCommits=True))

####### SCHEDULERS

# Configure the Schedulers, which decide how to react to incoming changes.  In this
# case, just kick off a 'runtests' build

c['schedulers'] = []

# Base schedulers
c['schedulers'].append(schedulers.AnyBranchScheduler(
    name="basic",
    change_filter=util.ChangeFilter(branch=tux3_user_branches),
    treeStableTimer=60,
    builderNames=user_builders,
))

c['schedulers'].append(schedulers.AnyBranchScheduler(
    name="kern",
    change_filter=util.ChangeFilter(branch=tux3_kern_branches),
    treeStableTimer=60,
    builderNames=kern_builders,
))

c['schedulers'].append(schedulers.ForceScheduler(
    name="force",
    builderNames=all_builders,
))

####### BUILDERS

# The 'builders' list defines the Builders, which tell Buildbot how to perform a build:
# what steps, and which workers can execute them.  Note that any particular build will
# only take place on one worker.

import re
import textwrap
from twisted.internet import defer

c['builders'] = []

# warning patterns
gccWarnPattern = "^(.*?):([0-9]+):([0-9]+:)? (.*)?([Ww]arning|[Ee]rror|[Nn]ote): (.*)$"

modpostPattern = "^(WARNING|ERROR|FATAL): .*$"
headerPattern  = "^(.*):([0-9]+): (.*)$"
kernPattern    = "(%s|%s|%s)" % (gccWarnPattern, modpostPattern, headerPattern)

assertPattern    = "^(WARNING|BUG): .*$"
userTestPattern = "(%s|%s)" % (gccWarnPattern, assertPattern)

# tux3 command name
tux3cmd_name = "tux3"

# Workers set
def find_worker(arch, workername):
    for w in workers_def[arch]:
        if workername == w['name']:
            return w

def getVmlinuz():
    return "vmlinuz"
def getVmlinuxXz():
    return "vmlinux.xz"

# Parse output of "make tests" and produce test summary
# Based on PerlModuleTest class
class Tux3UserTestObserver(util.LogLineObserver):
    testPassedPattern = re.compile(r"^\[.*:test.*\] OK$")
    testFailedPattern = re.compile(r"^\[.*:test.*\] FAILED$")

    def __init__(self):
        super().__init__()
        self.rc = util.SUCCESS
        self.passed = 0
        self.failed = 0

    def outLineReceived(self, line):
        if self.testPassedPattern.match(line):
            self.passed += 1
        if self.testFailedPattern.match(line):
            self.failed += 1
            self.rc = util.FAILURE

class Tux3UserTest(steps.Test):
    command = ["make", "tests"]
    warningPattern = userTestPattern

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.observer = Tux3UserTestObserver()
        self.addLogObserver('stdio', self.observer)

    def evaluateCommand(self, cmd):
        total = self.observer.passed + self.observer.failed
        if total:
            self.setTestResults(total=total,
                                passed=self.observer.passed,
                                failed=self.observer.failed)

        rc = self.observer.rc
        if rc == util.SUCCESS and self.warnCount:
            rc = util.WARNINGS
        return rc

# Run compile, basic tests, coverage
def user_steps(arch):
    # Upload place for gcov
    gcovURL = "gcov/%s/%s" % (arch, "%(prop:buildnumber)s-%(prop:branch)s")
    return [
        # Checkout tux3 (checkout at last to set proper got_revision)
        steps.Git(
            repourl=tux3_repo,
            branch="user",
            config=git_configs,
            mode="full",
            method="copy",
            description=[util.Interpolate('updating %(prop:branch)s')],
            descriptionDone=[util.Interpolate('update %(prop:branch)s')],
            name="git tux3",
        ),
        # Compile userspace commands with UBSAN
        steps.Compile(
            command="make UBSAN=1",
            workdir="build/fs/tux3/user",
            warningPattern=gccWarnPattern,
            description=['compiling UBSAN=1'],
            descriptionDone=['compile UBSAN=1'],
            name="compile UBSAN=1",
        ),
        # Test
        Tux3UserTest(
            command="make UBSAN=1 tests",
            workdir="build/fs/tux3/user",
            description=["testing UBSAN=1"],
            descriptionDone=["test UBSAN=1"],
            name="test UBSAN=1",
        ),
        # Cleanup for next compile
        steps.Compile(
            command="make distclean",
            workdir="build/fs/tux3/user",
            description=['compiling distclean'],
            descriptionDone=['compile distclean'],
            name="compile distclean",
        ),
        # Compile userspace commands with ASAN
        steps.Compile(
            command="make ASAN=1",
            workdir="build/fs/tux3/user",
            warningPattern=gccWarnPattern,
            description=['compiling ASAN=1'],
            descriptionDone=['compile ASAN=1'],
            name="compile ASAN=1",
        ),
        # Test
        Tux3UserTest(
            command="make ASAN=1 tests",
            workdir="build/fs/tux3/user",
            description=["testing ASAN=1"],
            descriptionDone=["test ASAN=1"],
            name="test ASAN=1",
        ),
        # Cleanup for next compile
        steps.Compile(
            command="make distclean",
            workdir="build/fs/tux3/user",
            description=['compiling distclean'],
            descriptionDone=['compile distclean'],
            name="compile distclean",
        ),
        # Compile userspace commands with sparse and coverage
        steps.Compile(
            command="make CHECK=1 GCOV=1",
            workdir="build/fs/tux3/user",
            warningPattern=gccWarnPattern,
        ),
        # Test
        Tux3UserTest(
            workdir="build/fs/tux3/user",
        ),
        # Collect coverage info
        steps.ShellCommand(
            command="make coverage",
            workdir="build/fs/tux3/user",
            haltOnFailure=True,
            description=['coverage'],
            descriptionDone=['coverage'],
            name="coverage report",
        ),
        # Upload coverage info
        steps.DirectoryUpload(
            workersrc="fs/tux3/user/gcov",
            masterdest=util.Interpolate(www_base + gcovURL),
            url=util.Interpolate(http_base + gcovURL),
        ),
        # Update coverage summary in master
        steps.MasterShellCommand(
            command="./scripts/lcov-summary.sh",
            description=['updating coverage'],
            descriptionDone=['update coverage'],
            name="update coverage",
        ),
        # Run post process (remove old outputs, fix permissions, etc.)
        steps.MasterShellCommand(
            command="./scripts/post.sh",
            description=['post process'],
            descriptionDone=['post process'],
            name="post process",
        ),
    ]

# Get user branch for kernel branch
@util.renderer
def CheckoutUserBranch(props):
    kern = props.getProperty('branch')
    user = tux3_branch_def[kern]

    # make git config from git_configs 
    opt = ""
    if git_configs:
        for key, val in git_configs.items():
            opt += " -c '%s=%s'" % (key, val)

    return "git %s fetch -p && git checkout -B %s origin/%s" % (opt, user, user)

# Run kernel compile
def kern_steps(arch):
    master_basedir = "binaries/%s/%s" % (arch, "%(prop:buildnumber)s")
    # Upload place for compiled binaries
    master_tux3_path = "%s/%s" % (master_basedir, tux3cmd_name)
    # Upload place for vmlinuz
    master_vmlinuz_path = "%s/%s" % (master_basedir, getVmlinuz())
    # Upload place for vmlinux.xz
    master_vmlinux_xz_path = "%s/%s" % (master_basedir, getVmlinuxXz())
    return [
        # Checkout tux3 (checkout at last to set proper got_revision)
        steps.Git(
            repourl=tux3_repo,
            branch="master",
            config=git_configs,
            mode="full",
            method="copy",
            description=[util.Interpolate('updating %(prop:branch)s')],
            descriptionDone=[util.Interpolate('update %(prop:branch)s')],
            name="git tux3",
        ),
        # Update linux-configs repo
        steps.MasterShellCommand(
            command=textwrap.dedent(r"""
DIR="%s"
if [ -d "$DIR" ]; then
    cd "$DIR"
    git pull -p
else
    git clone "%s"
fi
            """ % (linux_configs, linux_configs_repo)).strip(),
            description=['updating linux-configs'],
            descriptionDone=['update linux-configs'],
            name="update linux-configs",
        ),
        # Get kernel version of source from Makefile
        steps.SetPropertyFromCommand(
            property="kern_ver",
            command=textwrap.dedent(r"""
eval $(sed -n -e 's/\(.*\) = \(.*\)/\1=\2/p' -e '/^EXTRAVERSION/q' Makefile)
echo $VERSION.$PATCHLEVEL
            """).strip(),
            hideStepIf=NotDebug,
        ),
        # Download .config
        steps.FileDownload(
            mastersrc=util.Interpolate(linux_configs + '/%(prop:kern_ver)s/.config.kvm-debug-' + arch),
            workerdest=".config",
            mode=0o644,
        ),
        # Note: olddefconfig sets new symbols to default value
        steps.Compile(
            command="make olddefconfig",
            warningPattern=kernPattern,
            description=['compiling olddefconfig'],
            descriptionDone=['compile olddefconfig'],
            name="compile olddefconfig",
        ),
        # Compile kernel
        steps.Compile(
            command="make",
            warningPattern=kernPattern,
            description=['compiling kernel'],
            descriptionDone=['compile kernel'],
            name="compile kernel",
        ),
        # Compress vmlinux, then upload bzImage and vmlinux
        steps.FileUpload(
            workersrc="arch/%s/boot/bzImage" % arch,
            masterdest=util.Interpolate(www_base + master_vmlinuz_path),
            mode=0o644,
            url=util.Interpolate(http_base + master_vmlinuz_path),
        ),
        steps.ShellCommand(
            command="xz -v vmlinux",
            hideStepIf=NotDebug,
            description=["xz vmlinux"],
            descriptionDone=["xz vmlinux"],
            name="xz vmlinux"
        ),
        steps.FileUpload(
            workersrc="vmlinux.xz",
            masterdest=util.Interpolate(www_base + master_vmlinux_xz_path),
            mode=0o644,
            url=util.Interpolate(http_base + master_vmlinux_xz_path),
        ),
        # Compile tux3 module
        steps.Compile(
            command="make CONFIG_TUX3=m C=1 M=fs/tux3",
            warningPattern=kernPattern,
            description=['compiling module'],
            descriptionDone=['compile module'],
            name="compile module",
        ),
        # Clean kernel
        steps.Compile(
            command="make mrproper",
            description=['clean kernel'],
            descriptionDone=['clean kernel'],
            name="clean kernel",
        ),
        # Compile user tools
        steps.ShellCommand(
            command=CheckoutUserBranch,
            haltOnFailure=True,
            description=['update tux3/user'],
            descriptionDone=['update tux3/user'],
            name="git tux3/user",
        ),
        steps.Compile(
            command="make",
            workdir="build/fs/tux3/user",
            warningPattern=kernPattern,
            description=['compiling command'],
            descriptionDone=['compile command'],
            name="compile command",
        ),
        # Upload tux3 command
        steps.FileUpload(
            workersrc="fs/tux3/user/%s" % tux3cmd_name,
            masterdest=util.Interpolate(www_base + master_tux3_path),
            url=util.Interpolate(http_base + master_tux3_path),
        ),
        # Run post process (remove old outputs, fix permissions, etc.)
        steps.MasterShellCommand(
            command="./scripts/post.sh",
            description=['post process'],
            descriptionDone=['post process'],
            name="post process",
        ),
        # Start stress test
        steps.Trigger(schedulerNames=[stress_buildname(arch)],
                waitForFinish=False,
                updateSourceStamp=True,
                set_properties={
                    'master_basedir': util.Interpolate(master_basedir),
                },
                copy_properties={
                    'got_revision',
                },
        ),
    ]

class FileUploadWithUrls(steps.FileUpload):
    renderables = ["auxUrls"]

    def __init__(self, auxUrls=None, **kwargs):
        self.auxUrls = auxUrls

        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        if self.auxUrls is not None:
            for url in self.auxUrls:
                yield self.addURL(os.path.basename(url), url)

        res = yield super().run()
        return res

class KvmStart(steps.ShellCommand):
    name = "kvm"
    haltOnFailure = True

    def __init__(self, script_name, sshkey_name, disks,
                 kernel_name, kernel_arch, **kwargs):
        self.script_name = script_name
        self.sshkey_name = sshkey_name
        self.disks = disks
        self.kernel_name = kernel_name
        self.kernel_arch = kernel_arch

        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        disk_opts = ['-hda', '-hdb', '-hdc', '-hdd']
        arch = self.kernel_arch
        workername = self.build.getWorkerName()
        w = find_worker(arch, workername)

        command = [
            self.script_name, "run",
            str(w['kvm_port']), self.sshkey_name,
            "-smp", str(w['kvm_cpus']),
            "-m", str(w['kvm_mem']),
            "-kernel", self.kernel_name,
            "-append", "root=/dev/sda1 ro %s" % serial_console_opt[arch],
        ]

        for (opt, disk) in zip(disk_opts, self.disks):
            command.append(opt)
            command.append(disk)

        self.command = command

        res = yield super().run()
        return res

class KvmStop(steps.ShellCommand):
    name = "kvm"
    alwaysRun = True

    def __init__(self, script_name, vmcore_name="vmcore", checkstep=None,
                 **kwargs):
        self.script_name = script_name
        self.vmcore_name = vmcore_name
        self.checkstep = checkstep

        super().__init__(**kwargs)

    @defer.inlineCallbacks
    def run(self):
        result = util.SUCCESS
        if self.checkstep is not None:
            # get current build steps data
            steps_data = yield self.master.data.get(
                ('builds', self.build.buildid, 'steps')
            )
            # find a target step, then get result
            for step in steps_data:
                if step['name'] == self.checkstep:
                    result = step['results']
                    break

        command = [ self.script_name, "quit", ]

        # If checkstep was util.FAILURE, get kernel crashdump
        if result == util.FAILURE:
            command.append("dump_serial")
            command.append(self.vmcore_name)
            self.setProperty('has_vmcore', 'Y', "KvmStop Step")
        else:
            command.append("serial")
            self.setProperty('has_vmcore', 'N', "KvmStop Step")

        self.command = command

        res = yield super().run()
        return res

# Run stress test steps
def stress_steps(arch):
    kvm_workdir = "../guest-images"
    tarball_name = "kvm-%s.tar.xz" % arch
    tarball_cksum = "%s.sum" % tarball_name
    tarball_cksum_new = "%s.new" % tarball_cksum
    disk_name = "kvm-%s.qcow2" % arch
    tux3_disk = "tux3-disk.img"
    sshkey_name = "id_rsa-%s" % arch
    tests_name = "tests-%s.tar.xz" % arch
    master_vmlinuz_path = "%s/%s" % ("%(prop:master_basedir)s", getVmlinuz())
    master_vmlinux_xz_path = "%s/%s" % ("%(prop:master_basedir)s", getVmlinuxXz())
    master_tux3_path = "%s/%s" % ("%(prop:master_basedir)s", tux3cmd_name)
    kvm_script = "bb-kvm.sh"
    vmcore_name = "vmcore"
    vmcore_xz_name = "%s.xz" % vmcore_name
    master_vmcore_xz_path = "%s/%s" % ("%(prop:master_basedir)s", vmcore_xz_name)
    return [
        # Download guest image cksum
        steps.FileDownload(
            mastersrc="guest-images/%s" % tarball_cksum,
            workerdest=tarball_cksum_new,
            workdir=kvm_workdir,
            mode=0o644,
            hideStepIf=NotDebug,
        ),
        # Check whether need to download guest image
        steps.SetPropertyFromCommand(
            property="need_image",
            command=textwrap.dedent("""\
if cmp -s %s %s; then
    echo N
else
    echo Y
fi
mv %s %s
            """ % (tarball_cksum, tarball_cksum_new, 
                   tarball_cksum_new, tarball_cksum)).strip(),
            workdir=kvm_workdir,
            hideStepIf=NotDebug,
        ),
        # Download guest image tarball if need
        steps.FileDownload(
            mastersrc="guest-images/%s" % tarball_name,
            workerdest=tarball_name,
            workdir=kvm_workdir,
            mode=0o644,
            doStepIf=lambda step: step.build.getProperty("need_image") == "Y",
        ),
        steps.ShellCommand(
            command="tar xvf %s" % tarball_name,
            workdir=kvm_workdir,
            haltOnFailure=True,
            doStepIf=lambda step: step.build.getProperty("need_image") == "Y",
            description=["uncompressing image"],
            descriptionDone=["uncompress image"],
            name="uncompress image"
        ),
        # Download script for kvm
        steps.FileDownload(
            mastersrc="guest-images/%s" % kvm_script,
            workerdest=kvm_script,
            workdir=".",
            mode=0o755,
        ),
        # Download tests tools, tux3 command, and kernel for guest
        steps.FileDownload(
            mastersrc="guest-images/%s" % tests_name,
            workerdest=tests_name,
            workdir=".",
            mode=0o644,
        ),
        steps.FileDownload(
            mastersrc=util.Interpolate(www_base + master_tux3_path),
            workerdest=tux3cmd_name,
            workdir=".",
            mode=0o755,
        ),
        steps.FileDownload(
            mastersrc=util.Interpolate(www_base + master_vmlinuz_path),
            workerdest=getVmlinuz(),
            workdir=".",
            mode=0o644,
        ),
        # Make 8GB disk for tux3
        steps.ShellCommand(
            command=["dd", "if=/dev/null", "of=%s" % tux3_disk,
                     "bs=1M", "count=0", "seek=8192"],
            workdir=".",
            description=['making %s' % tux3_disk],
            descriptionDone=['make %s' % tux3_disk],
            name="make %s" % tux3_disk,
        ),
        # Run guest
        KvmStart(
            script_name="./%s" % kvm_script,
            sshkey_name="%s/%s" % (kvm_workdir, sshkey_name),
            disks=["%s/%s" % (kvm_workdir, disk_name), tux3_disk],
            kernel_name=getVmlinuz(),
            kernel_arch=arch,
            workdir=".",
            description=['running kvm'],
            descriptionDone=['run kvm'],
            name="run kvm",
        ),
        # Copy tests tools and tux3 command to guest
        steps.ShellCommand(
            command=["./%s" % kvm_script, "scp",
                     tests_name, tux3cmd_name, "localhost:"],
            workdir=".",
            description=['scp tools'],
            descriptionDone=['scp tools'],
            name="scp tools",
        ),
        # Run tests
        steps.ShellCommand(
            command=["./%s" % kvm_script, "ssh",
                     "tar xvf %s && "
                     "(cd tests && ./test.sh ../%s /dev/sdb)"
                     % (tests_name, tux3cmd_name),
            ],
            workdir=".",
            description=['run stress'],
            descriptionDone=['run stress'],
            name="run stress",
        ),
        # Stop guest
        KvmStop(
            script_name="./%s" % kvm_script,
            vmcore_name=vmcore_name,
            checkstep="run stress",
            workdir=".",
            description=['stopping kvm'],
            descriptionDone=['stop kvm'],
            name="stop kvm",
        ),
        # Compress and upload vmcore if need, then remove
        steps.ShellCommand(
            command="xz -v %s" % vmcore_name,
            workdir=".",
            alwaysRun=True,
            hideStepIf=NotDebug,
            doStepIf=lambda step: step.build.getProperty("has_vmcore") == "Y",
            description=["xz %s" % vmcore_name],
            descriptionDone=["xz %s" % vmcore_name],
            name="xz %s" % vmcore_name,
        ),
        FileUploadWithUrls(
            workersrc=vmcore_xz_name,
            masterdest=util.Interpolate(www_base + master_vmcore_xz_path),
            workdir=".",
            mode=0o644,
            url=util.Interpolate(http_base + master_vmcore_xz_path),
            # Add url of vmlinux.xz for convenience
            auxUrls=[
                util.Interpolate(http_base + master_vmlinux_xz_path),
            ],
            alwaysRun=True,
            doStepIf=lambda step: step.build.getProperty("has_vmcore") == "Y",
        ),
        steps.RemoveDirectory(
            dir=vmcore_xz_name,
            alwaysRun=True,
            hideStepIf=NotDebug,
            doStepIf=lambda step: step.build.getProperty("has_vmcore") == "Y",
        ),
        # Run post process (remove old outputs, fix permissions, etc.)
        steps.MasterShellCommand(
            command="./scripts/post.sh",
            description=['post process'],
            descriptionDone=['post process'],
            name="post process",
        ),
    ]

for arch in workers_def.keys():
    # Builder for userspace-<arch>
    c['builders'].append(util.BuilderConfig(
        name=user_buildname(arch),
        workernames=basic_workers[arch],
        factory=util.BuildFactory(user_steps(arch)),
    ))

    # Scheduler for kernel-<arch>
    c['schedulers'].append(schedulers.Triggerable(
        name=kern_buildname(arch),
        builderNames=[ kern_buildname(arch) ],
    ))
    # Builder for kernel-<arch>
    c['builders'].append(util.BuilderConfig(
        name=kern_buildname(arch),
        workernames=basic_workers[arch],
        factory=util.BuildFactory(kern_steps(arch)),
    ))

    # Scheduler for stress-<arch>
    c['schedulers'].append(schedulers.Triggerable(
        name=stress_buildname(arch),
        builderNames=[ stress_buildname(arch) ],
    ))
    # Builder for stress-<arch>
    c['builders'].append(util.BuilderConfig(
        name=stress_buildname(arch),
        workernames=stress_workers[arch],
        factory=util.BuildFactory(stress_steps(arch)),
    ))

####### BUILDBOT SERVICES

# 'services' is a list of BuildbotService items like reporter targets. The
# status of each build will be pushed to these targets. buildbot/reporters/*.py
# has a variety to choose from, like IRC bots.

c['services'] = []

#c['services'].append(reporters.MailNotifier(
#    fromaddr="buildbot@localhost",
#    extraRecipients=['example@example.org'],
#    mode=['failing', 'warnings'],
#    sendToInterestedUsers=False,
#    addLogs=False,
#    relayhost="smtp.example.org",
#    smtpPort=587,
#    smtpUser="example@example.org",
#    smtpPassword="example-password",
#))
#
#c['services'].append(reporters.IRC(
#    host="irc.oftc.net",
#    nick="buildbot",
#    channels=[{'channel': '#tux3'}],
#    allowForce=False,
#    notify_events={
#        'exception': 1,
#        'successToFailure': 1,
#        'failureToSuccess': 1,
#    },
#))

####### PROJECT IDENTITY

# the 'title' string will appear at the top of this buildbot installation's
# home pages (linked to the 'titleURL').

c['title'] = "tux3"
c['titleURL'] = "https://tux3.org/"

# the 'buildbotURL' string should point to the location where the buildbot's
# internal web server is visible. This typically uses the port number set in
# the 'www' entry below, but with an externally-visible host name which the
# buildbot cannot figure out without some help.

c['buildbotURL'] = "https://%s/buildbot/" % masterHost

# minimalistic config to activate new web UI
c['www'] = dict(port=8010,
                plugins=dict(waterfall_view={}, console_view={}, grid_view={}))

# Get username/password from "master/secrets/master-users"
account = {}
with open(os.path.join(secrets_dir, "master-users")) as f:
    for line in f.readlines():
        # make dict for { user: pass, ... }
        entry = line.strip().split(':')
        account[entry[0]] = entry[1]

c['www']['auth'] = util.UserPasswordAuth(account)
c['www']['authz'] = util.Authz(
    allowRules = [
        util.AnyControlEndpointMatcher(role="admins"),
    ],
    roleMatchers = [
        util.RolesFromUsername(roles=['admins'], usernames=['tux3'])
    ]
)

####### DB URL

c['db'] = {
    # This specifies what database buildbot uses to store its state.
    # It's easy to start with sqlite, but it's recommended to switch to a dedicated
    # database, such as PostgreSQL or MySQL, for use in production environments.
    # http://docs.buildbot.net/current/manual/configuration/global.html#database-specification
    'db_url' : "sqlite:///state.sqlite",
}
