diff --git a/buildbot/master/files/buildbot-master-autostart.conf b/buildbot/master/files/buildbot-master-autostart.conf new file mode 100644 index 00000000..f46c3ee9 --- /dev/null +++ b/buildbot/master/files/buildbot-master-autostart.conf @@ -0,0 +1,19 @@ +# Because the buildbot-master service is an instance job, +# we must provide a reason to start an instance of it. +# This Upstart task will automatically start one instance at bootup. +# Additionally, if no instances are alive during a Salt deploy, +# then this task will start a fresh instance. +# Upstart will not create new instances otherwise; +# additional instances can be created on-demand. +# Each instance will automatically stop itself at shutdown via its `stop on`. + +start on (local-filesystems and net-device-up IFACE!=lo) + +task + +script + # Avoid restarting Buildbot if it's already running + if ! initctl list | grep "buildbot-master (" >/dev/null; then + start buildbot-master reason="$(date --utc --iso-8601=seconds)-autostart" + fi +end script diff --git a/buildbot/master/files/buildbot-master.conf b/buildbot/master/files/buildbot-master.conf index 414407c8..81bf5199 100644 --- a/buildbot/master/files/buildbot-master.conf +++ b/buildbot/master/files/buildbot-master.conf @@ -1,10 +1,21 @@ -exec /usr/local/bin/buildbot start --nodaemon {{ common.servo_home }}/buildbot/master +# Use multiple instances to model multiple process: +# - (1) currently running Buildbot master +# - (n) queued restarts +# Each 'restart' process will wait for the existing master to finish pending +# builds, then take over as its own long-lived process. +# Runnign them via Upstart provides process supervision and monitoring, +# obviating the need to run restarts in tmux or screen (or disown them). +# +# Note that we don't actually use the $reason variable, +# except to provide distinct instance IDs for Upstart. +instance $reason + +exec /usr/local/bin/buildbot restart --clean --nodaemon $HOME/buildbot/master setuid servo setgid servo -start on (local-filesystems and net-device-up IFACE!=lo) stop on runlevel [016] env HOME={{ common.servo_home }} - +env PYTHONDONTWRITEBYTECODE=1 diff --git a/buildbot/master/files/stop-buildbot.py b/buildbot/master/files/stop-buildbot.py new file mode 100644 index 00000000..2feb5669 --- /dev/null +++ b/buildbot/master/files/stop-buildbot.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +""" +Utility which stops a Buildbot daemon gracefully +and blocks until the daemon is stopped. +This is built-in to Buildbot but not exposed by default. +""" + +from __future__ import absolute_import, print_function + +import os +import sys + +from buildbot.scripts import base, stop + + +USAGE = "usage: {} [ -h | --help | ]" + + +def main(argv): + usage = USAGE.format(argv[0]) + + if len(argv) != 2: + print(usage, file=sys.stderr) + return 1 + + if argv[1] == "-h" or argv[1] == "--help": + print(usage) + return 0 + + config = { + 'quiet': False, + 'clean': True, + 'basedir': os.path.abspath(argv[1]), + } + return stop.stop(config, wait=True) + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/buildbot/master/init.sls b/buildbot/master/init.sls index 97a6b6e4..70f0927a 100644 --- a/buildbot/master/init.sls +++ b/buildbot/master/init.sls @@ -1,26 +1,8 @@ {% from 'common/map.jinja' import common %} -buildbot-master: - pip.installed: - - pkgs: - - buildbot == 0.8.12 - - service_identity == 14.0.0 - - txgithub == 15.0.0 - - boto == 2.38.0 - - pyyaml == 3.11 - - require: - - pkg: pip - service.running: - - enable: True - # Buildbot must be restarted manually! See 'Buildbot administration' on the - # wiki and https://github.com/servo/saltfs/issues/304. - - require: - - pip: buildbot-master - - file: {{ common.servo_home }}/buildbot/master - - file: /etc/init/buildbot-master.conf - -{{ common.servo_home }}/buildbot/master: +buildbot-config: file.recurse: + - name: {{ common.servo_home }}/buildbot/master - source: salt://{{ tpldir }}/files/config - user: servo - group: servo @@ -30,8 +12,10 @@ buildbot-master: - context: common: {{ common }} buildbot_credentials: {{ pillar['buildbot']['credentials'] }} + - require: + - user: servo -ownership-{{ common.servo_home }}/buildbot/master: +buildbot-config-ownership: file.directory: - name: {{ common.servo_home }}/buildbot/master - user: servo @@ -39,9 +23,45 @@ ownership-{{ common.servo_home }}/buildbot/master: - recurse: - user - group + - require: + - user: servo + - file: buildbot-config -/etc/init/buildbot-master.conf: +/usr/local/bin/stop-buildbot.py: + file.managed: + - source: salt://{{ tpldir }}/files/stop-buildbot.py + - user: root + - group: root + - mode: 755 + +buildbot-master: + pip.installed: + - pkgs: + - buildbot == 0.8.12 + - service_identity == 14.0.0 + - txgithub == 15.0.0 + - boto == 2.38.0 + - pyyaml == 3.11 + - require: + - pkg: pip + cmd.run: # Need to create/upgrade DB file on new Buildbot version + # Explicit call to `/usr/bin/python` is to work around Travis mega-PATH, + # the stop-buildbot.py script has a proper shebang + - name: | + /usr/bin/python /usr/local/bin/stop-buildbot.py \ + '{{ common.servo_home }}/buildbot/master' \ + && buildbot upgrade-master '{{ common.servo_home }}/buildbot/master' + - runas: servo + - env: + - PYTHONDONTWRITEBYTECODE: "1" + - require: + - user: servo + - file: buildbot-config-ownership + - file: /usr/local/bin/stop-buildbot.py + - onchanges: + - pip: buildbot-master file.managed: + - name: /etc/init/buildbot-master.conf - source: salt://{{ tpldir }}/files/buildbot-master.conf - user: root - group: root @@ -50,6 +70,37 @@ ownership-{{ common.servo_home }}/buildbot/master: - context: common: {{ common }} +# Automatically queue a clean restart of Buildbot if anything changes +queue-buildbot-master-restart: + cmd.run: + - name: 'initctl start buildbot-master reason="$(date --utc --iso-8601=seconds)-salt-restart"' + - runas: root + - onchanges: + - pip: buildbot-master + - file: buildbot-config + - file: buildbot-config-ownership + - file: buildbot-master + +# Start a fresh Buildbot instance if one isn't running (including at bootup) +buildbot-master-autostart: + file.managed: + - name: /etc/init/buildbot-master-autostart.conf + - source: salt://{{ tpldir }}/files/buildbot-master-autostart.conf + - user: root + - group: root + - mode: 644 + - template: jinja + service.running: + - enable: True + - require: + - pip: buildbot-master + - file: buildbot-config-ownership + - cmd: buildbot-master + - file: buildbot-master + - cmd: queue-buildbot-master-restart + - file: buildbot-master-autostart + + /usr/local/bin/github_buildbot.py: file.managed: - source: salt://{{ tpldir }}/files/github_buildbot.py @@ -57,8 +108,9 @@ ownership-{{ common.servo_home }}/buildbot/master: - group: root - mode: 755 -/etc/init/buildbot-github-listener.conf: +buildbot-github-listener: file.managed: + - name: /etc/init/buildbot-github-listener.conf - source: salt://{{ tpldir }}/files/buildbot-github-listener.conf - user: root - group: root @@ -66,13 +118,12 @@ ownership-{{ common.servo_home }}/buildbot/master: - template: jinja - context: common: {{ common }} - -buildbot-github-listener: service.running: - enable: True - watch: - file: /usr/local/bin/github_buildbot.py - - file: /etc/init/buildbot-github-listener.conf + - file: buildbot-github-listener + remove-old-build-logs: cron.present: