testing: refactor Vagrant and Puppet configs
authorGregory Szorc <gps@mozilla.com>
Sat, 05 Jul 2014 17:42:02 -0700
changeset 358996 febf360d99a1bf85b70667f25a59dc224dd7d695
parent 358995 562e1b49c80ea6537cef05886674e3cb2de71c79
child 358997 af9bf3825398d13f16d898715d8a679c02f606e3
push id16998
push userrwood@mozilla.com
push dateMon, 02 May 2016 19:42:03 +0000
testing: refactor Vagrant and Puppet configs Puppet files have been moved into testing/puppet so they can be shared across multiple Vagrant configs. We now have a Vagrant config for a unified server that runs Bugzilla and ReviewBoard.
.hgignore
test-requirements.txt
testing/bmoserver/Puppetfile
testing/bmoserver/Vagrantfile
testing/bmoserver/files/apache24.patch
testing/bmoserver/files/apache_extra.conf
testing/bmoserver/files/apache_perlswitches.conf
testing/bmoserver/files/checksetup_answers.txt
testing/bmoserver/files/elasticsearch.patch
testing/bmoserver/files/fastimport.py
testing/bmoserver/files/fkpatch.patch
testing/bmoserver/files/nodefaultproduct.patch
testing/bmoserver/fileserver.conf
testing/bmoserver/manifests/bugzilla.pp
testing/bmoserver/vagrant-bootstrap.sh
testing/puppet/Puppetfile
testing/puppet/files/apache24.patch
testing/puppet/files/apache_extra.conf
testing/puppet/files/apache_perlswitches.conf
testing/puppet/files/checksetup_answers.txt
testing/puppet/files/elasticsearch.patch
testing/puppet/files/fastimport.py
testing/puppet/files/fkpatch.patch
testing/puppet/files/nodefaultproduct.patch
testing/puppet/files/rbserverconfigure.py
testing/puppet/files/reviewboard.vhost.conf
testing/puppet/manifests/bmoserver.pp
testing/puppet/manifests/bugzilla.pp
testing/puppet/manifests/reviewboard.pp
testing/puppet/manifests/unifiedserver.pp
testing/puppet/vagrant-bootstrap.sh
testing/unifiedserver/Vagrantfile
--- a/.hgignore
+++ b/.hgignore
@@ -1,10 +1,11 @@
 coverage/
 pylib/rbbz/rbbz.egg-info/
 pylib/rbmozui/rbmozui.egg-info/
 testing/bmoserver/.vagrant
-testing/bmoserver/files/Mozilla-Bugzilla-Public*
+testing/puppet/files/Mozilla-Bugzilla-Public*
+testing/unifiedserver/.vagrant
 venv/
 \.pyc$
 \.pyo$
 \.swp$
 ~$
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,15 +1,16 @@
 --find-links http://downloads.reviewboard.org/releases/Djblets/0.8/
 --find-links http://downloads.reviewboard.org/releases/django-evolution/0.7/
 Django==1.6.5
 Markdown==2.4.1
+MySQL-python==1.2.5
 Pillow==2.4.0
 Pygments==1.6
-RBTools==0.6.1
+--allow-external RBTools==0.6.1
 Whoosh==2.6.0
 coverage==3.7.1
 django-evolution==0.7.2
 django-haystack==2.1.0
 django-pipeline==1.3.24
 docutils==0.11
 ecdsa==0.11
 feedparser==5.1.3
deleted file mode 100644
--- a/testing/bmoserver/Puppetfile
+++ /dev/null
@@ -1,5 +0,0 @@
-forge "https://forgeapi.puppetlabs.com"
-
-mod "puppetlabs/apache", "1.0.1"
-mod "puppetlabs/mysql", "2.2.3"
-mod "puppetlabs/vcsrepo", "1.0.2"
--- a/testing/bmoserver/Vagrantfile
+++ b/testing/bmoserver/Vagrantfile
@@ -1,12 +1,15 @@
-Vagrant.configure("2") do |config|
-  config.vm.box = "ubuntu-1404-amd64"
+Vagrant.configure('2') do |config|
+  config.vm.box = 'ubuntu-1404-amd64'
 
-  config.vm.network "forwarded_port", guest: 80, host: 12000
-
-  config.vm.provider "virtualbox" do |v|
+  config.vm.provider 'virtualbox' do |v|
     v.memory = 4096
     v.cpus = 4
   end
 
-  config.vm.provision :shell, path: "vagrant-bootstrap.sh"
+  config.vm.network 'forwarded_port', guest: 80, host: 12000
+  config.vm.synced_folder '../../', '/version-control-tools'
+
+  config.vm.provision :shell, path: '../puppet/vagrant-bootstrap.sh'
+  config.vm.provision :shell,
+    inline: 'puppet apply --verbose --modulepath=/var/puppet-modules/modules /version-control-tools/testing/puppet/manifests/bmoserver.pp'
 end
deleted file mode 100644
--- a/testing/bmoserver/fileserver.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-[files]
-path /vagrant/files
-allow *
-
deleted file mode 100644
--- a/testing/bmoserver/manifests/bugzilla.pp
+++ /dev/null
@@ -1,280 +0,0 @@
-$packages = [
-  'build-essential',
-  'g++',
-  'graphviz',
-  'libdaemon-generic-perl',
-  'libgd-dev',
-  'libssl-dev',
-  # Installing PerlMagick from CPAN gives a compiler error.
-  'perlmagick',
-  'pkg-config',
-  'unzip',
-]
-
-package { $packages:
-  ensure       => installed,
-  responsefile => 'puppet:///files/debconf-responses',
-}
-
-user { 'bugzilla':
-  gid      => 'bugzilla',
-  groups   => ['bugzilla'],
-  uid      => 1002,
-  shell    => '/bin/bash',
-  password => 'bugzilla',
-}
-
-group { 'bugzilla':
-  gid => 500,
-}
-
-file { '/home/bugzilla':
-  ensure  => directory,
-  owner   => 'bugzilla',
-  group   => 'bugzilla',
-  require => User['bugzilla'],
-}
-
-vcsrepo { 'bugzilla':
-  path     => '/home/bugzilla/bugzilla',
-  source   => 'https://git.mozilla.org/webtools/bmo/bugzilla.git',
-  provider => git,
-  owner    => bugzilla,
-  group    => bugzilla,
-  ensure   => latest,
-  revision => 'production',
-  require  => File['/home/bugzilla'],
-}
-
-file { '/home/bugzilla/bugzilla':
-  mode    => 0755,
-  owner   => bugzilla,
-  group   => bugzilla,
-  require => Vcsrepo["bugzilla"],
-}
-
-# Changing this will cause the log file to be deleted. Due to
-# Exec['fix_innodb']. You have been warned.
-$innodb_log_file_megabytes = 512
-$innodb_log_file_bytes = $innodb_log_file_megabytes * 1024 * 1024
-
-class { '::mysql::server':
-  # BMO uses 5.6. Ubuntu 14.04 ships with 5.5 by default.
-  package_name   => 'mysql-server-5.6',
-  purge_conf_dir => true,
-  root_password  => 'root',
-  override_options         => {
-    'mysql'                => {
-      'max_allowed_packet' => '1G',
-    },
-    'mysqld'                    => {
-      'default_storage_engine'  => 'InnoDB',
-      'key_buffer_size'         => '32M',
-      'max_allowed_packet'      => '1G',
-      'innodb'                  => 'FORCE',
-      'character-set-server'    => 'utf8mb4',
-      'collation-server'        => 'utf8mb4_general_ci',
-
-      'tmp_table_size'         => '32M',
-      'max_heap_table_size'    => '32M',
-      'query_cache_type'       => '0',
-      'query_cache_size'       => '0',
-      'max_connections'        => '500',
-      'thread_cache_size'      => '50',
-      'table_definition_cache' => '1024',
-      'table_open_cache'       => '2048',
-
-      'innodb_flush_method'            => 'O_DIRECT',
-      # 0 is optimized for SSDs.
-      'innodb_flush_neighbors'         => '0',
-      'innodb_log_files_in_group'      => '2',
-      'innodb_log_file_size'           => "${innodb_log_file_megabytes}M",
-      # This is a bit large to optimize for bulk inserts.
-      'innodb_log_buffer_size'         => '64M',
-      'innodb_flush_log_at_trx_commit' => '2',
-      'innodb_file_per_table'          => '1',
-      # Decrease this if you don't run the VM with 4 GB of memory.
-      'innodb_buffer_pool_size'       => '2G',
-      'innodb_write_io_threads'       => '8',
-      'innodb_read_io_threads'        => '8',
-      'innodb_change_buffer_max_size' => '75',
-
-      'log_error' => '/var/lib/mysql/mysql-error.log',
-    },
-  },
-
-  databases => {
-    'bugs'  => {
-      ensure  => 'present',
-      charset => 'utf8',
-    },
-  },
-
-  users => {
-    'bugs@localhost' => {
-      ensure => 'present',
-      # bugs
-      password_hash => '*F6143BCA58806D14CD1C97998C6792405D8AE8AE',
-    },
-  },
-
-  grants => {
-    'bugs@localhost/*.*' => {
-      ensure     => 'present',
-      options    => ['GRANT'],
-      privileges => 'ALL',
-      table      => '*.*',
-      user       => 'bugs@localhost',
-    },
-  },
-}
-
-# We adjust the default innodb log file sizes. This causes MySQL to
-# throw a fit about mismatched size because the log files created during
-# package install and subsequent initial run are a different size from
-# the config. We forcefully remove the log file after log file size
-# change.
-exec { 'fix_innodb':
-  command   => "/sbin/stop mysql; /bin/rm /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile1",
-  onlyif    => "/usr/bin/test -e /var/lib/mysql/ib_logfile0 -a \$(/usr/bin/du -b /var/lib/mysql/ib_logfile0 | /usr/bin/awk '{ print \$1 }') -ne ${innodb_log_file_bytes}}",
-}
-
-Class['mysql::server::config'] ~> Exec['fix_innodb'] ~> Class['mysql::server::service']
-
-# Bugzilla dump file to load. This is optional.
-# Dumps can be obtained from https://people.mozilla.org/~mhoye/bugzilla/.
-$bmo_dump_file = 'Mozilla-Bugzilla-Public-*.sql.gz'
-
-exec { 'load_bmo':
-  onlyif  => [
-    "/usr/bin/test -f /vagrant/files/${bmo_dump_file}",
-    "/usr/bin/test ! -f /home/bugzilla/bmo_loaded",
-  ],
-  user    => 'bugzilla',
-  command => "/bin/zcat /vagrant/files/${bmo_dump_file} | /vagrant/files/fastimport.py | /usr/bin/mysql -ubugs -pbugs bugs && /usr/bin/touch /home/bugzilla/bmo_loaded",
-  timeout => 14400,
-}
-
-Class['mysql::server'] ~> Exec['load_bmo']
-
-exec { 'reset_git':
-  require => Vcsrepo['bugzilla'],
-  command => '/usr/bin/git reset --hard HEAD && /usr/bin/git clean -f',
-  user    => 'bugzilla',
-  cwd     => '/home/bugzilla/bugzilla',
-}
-
-# ElasticSearch isn't available on CPAN. Hack around failure installing
-# it.
-exec { 'patch_es':
-  require => Exec['reset_git'],
-  before  => Exec['bzmodules'],
-  command => '/usr/bin/patch -p1 < /vagrant/files/elasticsearch.patch',
-  user    => 'bugzilla',
-  cwd     => '/home/bugzilla/bugzilla',
-}
-
-exec { 'bzmodules':
-  require => [Exec['patch_es'], Package[$packages], Class[::mysql::server]],
-  command => '/home/bugzilla/bugzilla/install-module.pl --all',
-  user    => 'bugzilla',
-  cwd     => '/home/bugzilla/bugzilla',
-  timeout => 1800,
-}
-
-# Linux::Pid is a dependency for Apache::SizeLimit. For whatever reason
-# it isn't detected by CPAN.
-# XMLRPC::Transport::HTTP is needed by xmlrpc.cgi. For whatever reason
-# the dependency isn't installed.
-exec { 'pm_extra':
-  require => Vcsrepo['bugzilla'],
-  command => '/home/bugzilla/bugzilla/install-module.pl Linux::Pid XMLRPC::Transport::HTTP',
-  user    => 'bugzilla',
-  cwd     => '/home/bugzilla/bugzilla',
-}
-
-# Bug 769829. Foreign key issue with component watch schema updating.
-exec { 'patch_db':
-  before  => Exec['bzchecksetup'],
-  require => Exec['reset_git'],
-  command => '/usr/bin/patch -p1 < /vagrant/files/fkpatch.patch',
-  user    => 'bugzilla',
-  cwd     => '/home/bugzilla/bugzilla',
-}
-
-# Bug 1034678. Error creating default product.
-# This is only relevant is we don't do a BMO load. But it's harmless of
-# we do.
-exec { 'patch_defaultproduct':
-  before   => Exec['bzchecksetup'],
-  require  => Exec['reset_git'],
-  command  => '/usr/bin/patch -p1 < /vagrant/files/nodefaultproduct.patch',
-  user     => 'bugzilla',
-  cwd      => '/home/bugzilla/bugzilla',
-}
-
-# The .htaccess isn't compatible with Apache 2.4. We fix that.
-exec { 'patch_htaccess':
-  require => Exec['reset_git'],
-  before  => Service['httpd'],
-  command => '/usr/bin/patch -p1 < /vagrant/files/apache24.patch',
-  user    => 'bugzilla',
-  cwd     => '/home/bugzilla/bugzilla',
-}
-
-# checksetup.pl appears to not always refresh data/params if the
-# answers have been updated. Force it by removing output.
-file { '/home/bugzilla/bugzilla/data':
-  ensure  => absent,
-  recurse => true,
-  force   => true,
-}
-
-exec { 'bzchecksetup':
-  require  => [Exec['bzmodules'], Exec['load_bmo'], File['/home/bugzilla/bugzilla/data']],
-  command => '/home/bugzilla/bugzilla/checksetup.pl /vagrant/files/checksetup_answers.txt',
-  user     => 'bugzilla',
-  cwd      => '/home/bugzilla/bugzilla',
-}
-
-# Restore pristine repo state (undo local patch hacks).
-exec { 'unpatch_bugzilla':
-  require => Exec['bzchecksetup'],
-  command => '/usr/bin/git checkout -- Bugzilla/DB.pm Bugzilla/Install/Requirements.pm checksetup.pl',
-  user    => 'bugzilla',
-  cwd     => '/home/bugzilla/bugzilla',
-}
-
-file { '/etc/apache2/conf.d/50perlswitches.conf':
-  source => '/vagrant/files/apache_perlswitches.conf',
-  owner  => 'root',
-  group  => 'root',
-  notify => Service['httpd'],
-}
-
-class { 'apache':
-  default_vhost => false,
-  group         => 'bugzilla',
-  manage_group  => false,
-  mpm_module    => 'prefork',
-}
-
-class { 'apache::mod::perl': }
-class { 'apache::mod::rewrite': }
-
-apache::vhost { 'bugzilla':
-  port        => '80',
-  docroot     => '/home/bugzilla/bugzilla',
-  directories => [
-    {
-      path           => '/home/bugzilla/bugzilla',
-      addhandlers    => [{ handler => 'cgi-script', extensions => ['.cgi'] }],
-      directoryindex => 'index.cgi',
-      allow_override => ['All'],
-      options        => ['Indexes', 'FollowSymLinks', 'ExecCGI'],
-    },
-  ],
-  additional_includes => '/vagrant/files/apache_extra.conf',
-  require             => Exec['pm_extra'],
-}
-
deleted file mode 100644
--- a/testing/bmoserver/vagrant-bootstrap.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# This script provisions a Vagrant VM for development mode.
-
-set -e
-
-MODULES_DIR='/var/puppet-modules'
-
-if [ ! -f /root/provision.initial ]; then
-  apt-get update
-  # We don't need chef since we use puppet.
-  apt-get -y remove chef
-  apt-get -y autoremove
-  touch /root/provision.initial
-  apt-get -y dist-upgrade
-  apt-get -q -y install git ruby-dev
-fi
-
-if [ ! -d $MODULES_DIR ]; then
-  mkdir -p $MODULES_DIR
-fi
-
-cp /vagrant/Puppetfile $MODULES_DIR/Puppetfile
-
-if [ `gem query --local | grep librarian-puppet | wc -l` -eq 0 ]; then
-  gem install librarian-puppet
-  cd $MODULES_DIR && librarian-puppet install --clean
-else
-  cd $MODULES_DIR && librarian-puppet update
-fi
-
-puppet apply --verbose \
-  --modulepath=$MODULES_DIR/modules/ \
-  --fileserverconfig=/vagrant/puppet/fileserver.vagrant.conf \
-  /vagrant/manifests/bugzilla.pp
new file mode 100644
--- /dev/null
+++ b/testing/puppet/Puppetfile
@@ -0,0 +1,6 @@
+forge "https://forgeapi.puppetlabs.com"
+
+mod "puppetlabs/apache", "1.0.1"
+mod "puppetlabs/mysql", "2.2.3"
+mod "puppetlabs/vcsrepo", "1.0.2"
+mod "stankevich/python", "1.7.5"
rename from testing/bmoserver/files/apache24.patch
rename to testing/puppet/files/apache24.patch
rename from testing/bmoserver/files/apache_extra.conf
rename to testing/puppet/files/apache_extra.conf
rename from testing/bmoserver/files/apache_perlswitches.conf
rename to testing/puppet/files/apache_perlswitches.conf
rename from testing/bmoserver/files/checksetup_answers.txt
rename to testing/puppet/files/checksetup_answers.txt
rename from testing/bmoserver/files/elasticsearch.patch
rename to testing/puppet/files/elasticsearch.patch
rename from testing/bmoserver/files/fastimport.py
rename to testing/puppet/files/fastimport.py
rename from testing/bmoserver/files/fkpatch.patch
rename to testing/puppet/files/fkpatch.patch
rename from testing/bmoserver/files/nodefaultproduct.patch
rename to testing/puppet/files/nodefaultproduct.patch
new file mode 100644
--- /dev/null
+++ b/testing/puppet/files/rbserverconfigure.py
@@ -0,0 +1,56 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import subprocess
+import sys
+
+path = sys.argv[1]
+path = os.path.abspath(path)
+
+sys.path.insert(0, path)
+
+manage = [sys.executable, '-m', 'reviewboard.manage']
+
+args = ['/home/reviewboard/venv/bin/rb-site']
+
+if os.path.exists(path):
+    args.append('upgrade')
+else:
+    args.append('install')
+
+args.extend([
+    path,
+    '--noinput',
+    '--domain-name=localhost',
+    '--site-root=/',
+    '--db-type=mysql',
+    '--db-name=reviewboard',
+    '--db-user=reviewboard',
+    '--db-pass=reviewboard',
+    '--cache-type=file',
+    '--cache-info=/home/reviewboard/cache',
+    '--web-server-type=apache',
+    '--python-loader=wsgi',
+])
+
+if not os.path.exists(path):
+    args.extend([
+        '--admin-user=testadmin',
+        '--admin-password=password',
+        '--admin-email=testadmin@example.com',
+    ])
+
+subprocess.check_call(args)
+
+conf_dir = os.path.join(path, 'conf')
+os.chdir(conf_dir)
+
+subprocess.check_call(manage + ['enable-extension',
+    'rbbz.extension.BugzillaExtension'],
+    cwd=conf_dir)
+
+subprocess.check_call(manage + ['enable-extension',
+    'rbmozui.extension.RBMozUI'],
+    cwd=conf_dir)
new file mode 100644
--- /dev/null
+++ b/testing/puppet/files/reviewboard.vhost.conf
@@ -0,0 +1,2 @@
+WSGIDaemonProcess reviewboard user=reviewboard group=reviewboard processes=2 home=/home/reviewboard/site/conf python-path=/home/reviewboard/venv/lib/python2.7/site-packages
+WSGIProcessGroup reviewboard
new file mode 100644
--- /dev/null
+++ b/testing/puppet/manifests/bmoserver.pp
@@ -0,0 +1,2 @@
+import 'bugzilla.pp'
+class { 'bugzilla': }
new file mode 100644
--- /dev/null
+++ b/testing/puppet/manifests/bugzilla.pp
@@ -0,0 +1,272 @@
+class bugzilla {
+  $files = '/version-control-tools/testing/puppet/files'
+
+  $packages = [
+    'build-essential',
+    'g++',
+    'graphviz',
+    'libdaemon-generic-perl',
+    'libgd-dev',
+    'libssl-dev',
+    # Installing PerlMagick from CPAN gives a compiler error.
+    'perlmagick',
+    'pkg-config',
+    'unzip',
+  ]
+
+  package { $packages:
+    ensure       => installed,
+  }
+
+  user { 'bugzilla':
+    gid      => 'bugzilla',
+    groups   => ['bugzilla'],
+    uid      => 1002,
+    shell    => '/bin/bash',
+    password => 'bugzilla',
+  }
+
+  group { 'bugzilla':
+    gid => 500,
+  }
+
+  file { '/home/bugzilla':
+    ensure  => directory,
+    owner   => 'bugzilla',
+    group   => 'bugzilla',
+    require => User['bugzilla'],
+  }
+
+  vcsrepo { 'bugzilla':
+    path     => '/home/bugzilla/bugzilla',
+    source   => 'https://git.mozilla.org/webtools/bmo/bugzilla.git',
+    provider => git,
+    owner    => bugzilla,
+    group    => bugzilla,
+    ensure   => latest,
+    revision => 'production',
+    require  => File['/home/bugzilla'],
+  }
+
+  file { '/home/bugzilla/bugzilla':
+    mode    => 0755,
+    owner   => bugzilla,
+    group   => bugzilla,
+    require => Vcsrepo["bugzilla"],
+  }
+
+# Changing this will cause the log file to be deleted. Due to
+# Exec['fix_innodb']. You have been warned.
+  $innodb_log_file_megabytes = 512
+  $innodb_log_file_bytes = $innodb_log_file_megabytes * 1024 * 1024
+
+  class { '::mysql::server':
+    # BMO uses 5.6. Ubuntu 14.04 ships with 5.5 by default.
+    package_name   => 'mysql-server-5.6',
+    purge_conf_dir => true,
+    root_password  => 'root',
+    override_options         => {
+      'mysql'                => {
+        'max_allowed_packet' => '1G',
+      },
+      'mysqld'                    => {
+        'default_storage_engine'  => 'InnoDB',
+        'key_buffer_size'         => '32M',
+        'max_allowed_packet'      => '1G',
+        'innodb'                  => 'FORCE',
+        'character-set-server'    => 'utf8mb4',
+        'collation-server'        => 'utf8mb4_general_ci',
+
+        'tmp_table_size'         => '32M',
+        'max_heap_table_size'    => '32M',
+        'query_cache_type'       => '0',
+        'query_cache_size'       => '0',
+        'max_connections'        => '500',
+        'thread_cache_size'      => '50',
+        'table_definition_cache' => '1024',
+        'table_open_cache'       => '2048',
+
+        'innodb_flush_method'            => 'O_DIRECT',
+        # 0 is optimized for SSDs.
+        'innodb_flush_neighbors'         => '0',
+        'innodb_log_files_in_group'      => '2',
+        'innodb_log_file_size'           => "${innodb_log_file_megabytes}M",
+        # This is a bit large to optimize for bulk inserts.
+        'innodb_log_buffer_size'         => '64M',
+        'innodb_flush_log_at_trx_commit' => '2',
+        'innodb_file_per_table'          => '1',
+        # Decrease this if you don't run the VM with 4 GB of memory.
+        'innodb_buffer_pool_size'       => '2G',
+        'innodb_write_io_threads'       => '8',
+        'innodb_read_io_threads'        => '8',
+        'innodb_change_buffer_max_size' => '75',
+
+        'log_error' => '/var/lib/mysql/mysql-error.log',
+      },
+    },
+  }
+
+  mysql_database { 'bugs':
+    ensure  => 'present',
+    charset => 'utf8',
+  } -> mysql_user { 'bugs@localhost':
+    ensure => 'present',
+    # bugs
+    password_hash => '*F6143BCA58806D14CD1C97998C6792405D8AE8AE',
+  } -> mysql_grant { 'bugs@localhost/*.*':
+    ensure     => 'present',
+    options    => ['GRANT'],
+    privileges => 'ALL',
+    table      => '*.*',
+    user       => 'bugs@localhost',
+  }
+
+  # We adjust the default innodb log file sizes. This causes MySQL to
+  # throw a fit about mismatched size because the log files created during
+  # package install and subsequent initial run are a different size from
+  # the config. We forcefully remove the log file after log file size
+  # change.
+  exec { 'fix_innodb':
+    command   => "/sbin/stop mysql; /bin/rm /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile1",
+    onlyif    => "/usr/bin/test -e /var/lib/mysql/ib_logfile0 -a \$(/usr/bin/du -b /var/lib/mysql/ib_logfile0 | /usr/bin/awk '{ print \$1 }') -ne ${innodb_log_file_bytes}}",
+  }
+
+  Class['mysql::server::config'] ~> Exec['fix_innodb'] ~> Class['mysql::server::service']
+
+  # Bugzilla dump file to load. This is optional.
+  # Dumps can be obtained from https://people.mozilla.org/~mhoye/bugzilla/.
+  $bmo_dump_file = 'Mozilla-Bugzilla-Public-*.sql.gz'
+
+  exec { 'load_bmo':
+    onlyif  => [
+      "/usr/bin/test -f $files/${bmo_dump_file}",
+      "/usr/bin/test ! -f /home/bugzilla/bmo_loaded",
+    ],
+    user    => 'bugzilla',
+    command => "/bin/zcat $files/${bmo_dump_file} | $files/fastimport.py | /usr/bin/mysql -ubugs -pbugs bugs && /usr/bin/touch /home/bugzilla/bmo_loaded",
+    timeout => 14400,
+  }
+
+  Class['mysql::server'] ~> Exec['load_bmo']
+
+  exec { 'reset_git':
+    require => Vcsrepo['bugzilla'],
+    command => '/usr/bin/git reset --hard HEAD && /usr/bin/git clean -f',
+    user    => 'bugzilla',
+    cwd     => '/home/bugzilla/bugzilla',
+  }
+
+  # ElasticSearch isn't available on CPAN. Hack around failure installing
+  # it.
+  exec { 'patch_es':
+    require => Exec['reset_git'],
+    before  => Exec['bzmodules'],
+    command => "/usr/bin/patch -p1 < $files/elasticsearch.patch",
+    user    => 'bugzilla',
+    cwd     => '/home/bugzilla/bugzilla',
+  }
+
+  exec { 'bzmodules':
+    require => [Exec['patch_es'], Package[$packages], Class[::mysql::server]],
+    command => '/home/bugzilla/bugzilla/install-module.pl --all',
+    user    => 'bugzilla',
+    cwd     => '/home/bugzilla/bugzilla',
+    timeout => 1800,
+  }
+
+  # Linux::Pid is a dependency for Apache::SizeLimit. For whatever reason
+  # it isn't detected by CPAN.
+  # XMLRPC::Transport::HTTP is needed by xmlrpc.cgi. For whatever reason
+  # the dependency isn't installed.
+  exec { 'pm_extra':
+    require => Vcsrepo['bugzilla'],
+    command => '/home/bugzilla/bugzilla/install-module.pl Linux::Pid XMLRPC::Transport::HTTP',
+    user    => 'bugzilla',
+    cwd     => '/home/bugzilla/bugzilla',
+  }
+
+  # Bug 769829. Foreign key issue with component watch schema updating.
+  exec { 'patch_db':
+    before  => Exec['bzchecksetup'],
+    require => Exec['reset_git'],
+    command => "/usr/bin/patch -p1 < $files/fkpatch.patch",
+    user    => 'bugzilla',
+    cwd     => '/home/bugzilla/bugzilla',
+  }
+
+  # Bug 1034678. Error creating default product.
+  # This is only relevant is we don't do a BMO load. But it's harmless of
+  # we do.
+  exec { 'patch_defaultproduct':
+    before   => Exec['bzchecksetup'],
+    require  => Exec['reset_git'],
+    command  => "/usr/bin/patch -p1 < $files/nodefaultproduct.patch",
+    user     => 'bugzilla',
+    cwd      => '/home/bugzilla/bugzilla',
+  }
+
+  # The .htaccess isn't compatible with Apache 2.4. We fix that.
+  exec { 'patch_htaccess':
+    require => Exec['reset_git'],
+    before  => Service['httpd'],
+    command => "/usr/bin/patch -p1 < $files/apache24.patch",
+    user    => 'bugzilla',
+    cwd     => '/home/bugzilla/bugzilla',
+  }
+
+  # checksetup.pl appears to not always refresh data/params if the
+  # answers have been updated. Force it by removing output.
+  file { '/home/bugzilla/bugzilla/data':
+    ensure  => absent,
+    recurse => true,
+    force   => true,
+  }
+
+  exec { 'bzchecksetup':
+    require  => [Exec['bzmodules'], Exec['load_bmo'], File['/home/bugzilla/bugzilla/data']],
+    command  => "/home/bugzilla/bugzilla/checksetup.pl $files/checksetup_answers.txt",
+    user     => 'bugzilla',
+    cwd      => '/home/bugzilla/bugzilla',
+  }
+
+  # Restore pristine repo state (undo local patch hacks).
+  exec { 'unpatch_bugzilla':
+    require => Exec['bzchecksetup'],
+    command => '/usr/bin/git checkout -- Bugzilla/DB.pm Bugzilla/Install/Requirements.pm checksetup.pl',
+    user    => 'bugzilla',
+    cwd     => '/home/bugzilla/bugzilla',
+  }
+
+  file { '/etc/apache2/conf.d/50perlswitches.conf':
+    source => "$files/apache_perlswitches.conf",
+    owner  => 'root',
+    group  => 'root',
+    notify => Service['httpd'],
+  }
+
+  class { 'apache':
+    default_vhost => false,
+    group         => 'bugzilla',
+    manage_group  => false,
+    mpm_module    => 'prefork',
+  }
+
+  class { 'apache::mod::perl': }
+  class { 'apache::mod::rewrite': }
+
+  apache::vhost { 'bugzilla':
+    port        => '80',
+    docroot     => '/home/bugzilla/bugzilla',
+    directories => [
+      {
+        path           => '/home/bugzilla/bugzilla',
+        addhandlers    => [{ handler => 'cgi-script', extensions => ['.cgi'] }],
+        directoryindex => 'index.cgi',
+        allow_override => ['All'],
+        options        => ['Indexes', 'FollowSymLinks', 'ExecCGI'],
+      },
+    ],
+    additional_includes => "$files/apache_extra.conf",
+    require             => Exec['pm_extra'],
+  }
+}
new file mode 100644
--- /dev/null
+++ b/testing/puppet/manifests/reviewboard.pp
@@ -0,0 +1,139 @@
+class reviewboard {
+  include apache
+  include mysql::server
+
+  $files = '/version-control-tools/testing/puppet/files'
+
+  user { 'reviewboard':
+    gid      => 'reviewboard',
+    groups   => ['reviewboard'],
+    uid      => 1003,
+    shell    => '/bin/bash',
+    password => 'reviewboard',
+  }
+
+  group { 'reviewboard':
+    gid => 501,
+  }
+
+  file { '/home/reviewboard':
+    ensure  => directory,
+    owner   => 'reviewboard',
+    group   => 'reviewboard',
+    require => User['reviewboard'],
+  }
+
+  class { 'python':
+    dev        => true,
+    pip        => true,
+    virtualenv => true,
+  }
+
+  package { 'libmysqlclient-dev':
+    ensure => present,
+  }
+
+  python::virtualenv { '/home/reviewboard/venv':
+    require      => Package['libmysqlclient-dev'],
+    ensure       => present,
+    version      => 'system',
+    requirements => '/version-control-tools/test-requirements.txt',
+    owner        => 'reviewboard',
+    group        => 'reviewboard',
+    cwd          => '/home/reviewboard',
+  }
+
+  exec { 'install_reviewboard':
+    require => Python::Virtualenv['/home/reviewboard/venv'],
+    command => '/home/reviewboard/venv/bin/easy_install ReviewBoard==2.0.2',
+    user    => 'reviewboard',
+    cwd     => '/home/reviewboard',
+  }
+
+  file { '/home/reviewboard/venv/lib/python2.7/site-packages/rbmozui.pth':
+    require => Python::Virtualenv['/home/reviewboard/venv'],
+    content => '/version-control-tools/pylib/rbmozui',
+    owner   => 'reviewboard',
+    group   => 'reviewboard',
+  } -> Exec['rbsetup']
+
+  file { '/home/reviewboard/venv/lib/python2.7/site-packages/rbbz.pth':
+    require => Python::Virtualenv['/home/reviewboard/venv'],
+    content => '/version-control-tools/pylib/rbbz',
+    owner   => 'reviewboard',
+    group   => 'reviewboard',
+  } -> Exec['rbsetup']
+
+  mysql_database { 'reviewboard':
+    ensure  => 'present',
+    charset => 'utf8',
+  } -> mysql_user { 'reviewboard@localhost':
+    ensure        => 'present',
+    # reviewboard
+    password_hash => '*E9DFA5B14F817324A5F00B8A70FC6908174719ED',
+  } -> mysql_grant { 'reviewboard@localhost/reviewboard.*':
+    ensure     => 'present',
+    options    => ['GRANT'],
+    privileges => ['ALL'],
+    table      => 'reviewboard.*',
+    user       => 'reviewboard@localhost',
+  } -> exec { 'rbsetup':
+    command     => "/home/reviewboard/venv/bin/python $files/rbserverconfigure.py /home/reviewboard/site",
+    user        => 'reviewboard',
+  } ~> Service['httpd']
+
+  class { '::apache::mod::wsgi': }
+
+  ::apache::vhost { 'reviewboard':
+    require       => Exec['rbsetup'],
+    port          => 8001,
+    docroot       => '/home/reviewboard/site/htdocs',
+    docroot_owner => 'reviewboard',
+    docroot_group => 'reviewboard',
+
+    directories => [
+      {
+        path           => '/home/reviewboard/site/htdocs',
+        options        => ['-Indexes', '+FollowSymLinks'],
+        allow_override => ['All'],
+      },
+      {
+        path     => '/media/uploaded',
+        provider => 'location',
+        options  => ['None'],
+        handler  => 'None',
+      },
+    ],
+
+    aliases => [
+      {
+        alias => '/media',
+        path  => '/home/reviewboard/site/htdocs/media',
+      },
+      {
+        alias => '/static',
+        path  => '/home/reviewboard/site/htdocs/static',
+      },
+      {
+        alias => '/errordocs',
+        path  => '/home/reviewboard/site/htdocs/errordocs',
+      },
+      {
+        alias => '/favicon.ico',
+        path  => '/home/reviewboard/site/htdocs/static/rb/images/favicon.png',
+      },
+    ],
+
+    error_documents  => [
+      { 'error_code' => '500', 'document' => '/errordocs/500.html' },
+    ],
+
+    wsgi_script_aliases => {
+      '/' => '/home/reviewboard/site/htdocs/reviewboard.wsgi/',
+    },
+
+    additional_includes => [
+      "$files/reviewboard.vhost.conf",
+    ],
+  }
+}
new file mode 100644
--- /dev/null
+++ b/testing/puppet/manifests/unifiedserver.pp
@@ -0,0 +1,5 @@
+import 'bugzilla.pp'
+import 'reviewboard.pp'
+
+class { 'bugzilla': }
+class { 'reviewboard': }
new file mode 100644
--- /dev/null
+++ b/testing/puppet/vagrant-bootstrap.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# This script provisions a Vagrant VM for development mode.
+
+set -e
+
+MODULES_DIR='/var/puppet-modules'
+
+if [ ! -f /root/provision.initial ]; then
+  apt-get update
+  # We don't need chef since we use puppet.
+  apt-get -y remove chef
+  apt-get -y autoremove
+  touch /root/provision.initial
+  apt-get -y dist-upgrade
+  apt-get -q -y install git ruby-dev
+fi
+
+if [ ! -d $MODULES_DIR ]; then
+  mkdir -p $MODULES_DIR
+fi
+
+cp /version-control-tools/testing/puppet/Puppetfile $MODULES_DIR/Puppetfile
+
+if [ `gem query --local | grep librarian-puppet | wc -l` -eq 0 ]; then
+  gem install librarian-puppet
+  cd $MODULES_DIR && librarian-puppet install
+else
+  cd $MODULES_DIR && librarian-puppet update
+fi
new file mode 100644
--- /dev/null
+++ b/testing/unifiedserver/Vagrantfile
@@ -0,0 +1,16 @@
+Vagrant.configure('2') do |config|
+  config.vm.box = 'ubuntu-1404-amd64'
+
+  config.vm.provider 'virtualbox' do |v|
+    v.memory = 4096
+    v.cpus = 4
+  end
+
+  config.vm.network 'forwarded_port', guest: 80, host: 12000
+  config.vm.network 'forwarded_port', guest: 8001, host: 12001
+  config.vm.synced_folder '../../', '/version-control-tools'
+
+  config.vm.provision :shell, path: '../puppet/vagrant-bootstrap.sh'
+  config.vm.provision :shell,
+    inline: 'puppet apply --verbose --modulepath=/var/puppet-modules/modules /version-control-tools/testing/puppet/manifests/unifiedserver.pp'
+end