Skip to content

Instantly share code, notes, and snippets.

@peter-b
Created February 21, 2017 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save peter-b/5448b8121c020e34a886a91f9d80bf20 to your computer and use it in GitHub Desktop.
Save peter-b/5448b8121c020e34a886a91f9d80bf20 to your computer and use it in GitHub Desktop.
PowerShell script for installing a buildbot worker on Windows
# PowerShell script for installing BuildBot 0.8.12 on Windows Server 2016
# Datacenter Edition
# For full explanation of everything in this script, see:
# http://blog.peter-b.co.uk/2017/02/deploying-buildbot-workers-on-windows.html
# Copyright (C) 2017 LiveCode Ltd.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Preparatory work
##################
$VerbosePreference = 'Continue'
$ErrorActionPreference = 'Stop'
# Helper function for converting failure exit status
# into errors
function CheckLastExitCode {
param ([int[]]$SuccessCodes = @(0))
if ($SuccessCodes -notcontains $LASTEXITCODE) {
throw "Command failed (exit code $LASTEXITCODE)"
}
}
# Helper function for fetching required installation
# resources
function Fetch-BuildbotResource {
param([string]$Path,
[string]$OutFile)
# FIXME fill this in with application-specific implementation
}
# Activate Windows
cscript.exe C:\Windows\System32\slmgr.vbs /ato
$k_buildbot_root = 'C:\buildbot'
# FIXME set your buildbot master server's address here
$k_buildbot_master = 'buildbot.example.org'
New-Item -Path $k_buildbot_root -ItemType Container -Force | Out-Null
# Install dependencies
######################
$env:ChocolateyInstall = 'C:\ProgramData\chocolatey'
# Install Chocolatey, if not already present
if (!(Test-Path -LiteralPath $env:ChocolateyInstall -PathType Container)) {
Invoke-WebRequest 'https://chocolatey.org/install.ps1' -UseBasicParsing | Invoke-Expression
}
Write-Verbose 'Installing Python and stunnel'
choco install --yes stunnel python2
CheckLastExitCode
Write-Verbose 'Installing Python modules'
$t_pip = 'C:\Python27\Scripts\pip.exe'
& $t_pip install pypiwin32 buildbot-slave==0.8.12
CheckLastExitCode
Write-Verbose 'Registering pywin32 DLLs'
$t_python = C:\Python27\python.exe
& $t_python C:\Python27\Scripts\pywin32_postinstall.py -install
# SSL tunnel service
####################
Write-Verbose 'Installing buildbot-stunnel service'
$t_stunnel = 'C:\Program Files (x86)\stunnel\bin\stunnel.exe'
$t_stunnel_conf = Join-Path $k_buildbot_root 'stunnel.conf'
$t_stunnel_crt = Join-Path $k_buildbot_root 'buildbot.crt'
# Fetch the client certificate that will be used to authenticate
# the buildbot master
Fetch-BuildbotResource `
-Path 'buildbot/stunnel/master.crt' -Outfile $t_stunnel_crt
# Create the stunnel configuration file
Set-Content -Path $t_stunnel_conf -Value @"
[buildbot]
client = yes
accept = 127.0.0.1:9989
cafile = $t_stunnel_crt
verify = 3
connect = $k_buildbot_master:9988
"@
# Register the stunnel service, if not already present
if (!(Get-Service buildbot-stunnel -ErrorAction Ignore)) {
New-Service -Name buildbot-stunnel `
-BinaryPathName "$t_stunnel -service $t_stunnel_conf" `
-DisplayName 'Buildbot Secure Tunnel' `
-StartupType Automatic
}
# Configure buildbot worker
###########################
Write-Verbose 'Initialising buildbot worker'
# Needed for password generation
Add-Type -AssemblyName System.Web
$t_buildbot_worker_script = 'C:\Python27\Scripts\buildslave'
$t_worker_dir = Join-Path $k_buildbot_root worker
$t_worker_name = "$env:COMPUTERNAME-$_"
$t_worker_password = `
[System.Web.Security.Membership]::GeneratePassword(12,0)
$t_worker_admin = 'Example Organisation'
$t_log = Join-Path $k_buildbot_root setup.log
Start-Process -Wait -NoNewWindow -FilePath $t_python `
-ArgumentList @($t_buildbot_worker_script, 'create-slave', `
$t_worker_dir, 127.0.0.1, $t_worker_name,
$t_worker_password) `
-RedirectStandardOutput $t_log
# Check log file contents
$t_expected = "buildslave configured in $t_worker_dir"
if ((Get-Content $t_log)[-1] -ne $t_expected) {
Get-Content $t_log | Write-Error
throw "Build worker setup failed (exit code $LASTEXITCODE)"
}
Set-Content -Path (Join-Path $t_worker_dir 'info\admin') `
-Value $t_worker_admin
Set-Content -Path (Join-Path $t_worker_dir 'info\host') `
-Value (Get-WmiObject -Class Win32_OperatingSystem).Caption
$t_config = Join-Path $t_worker_dir buildbot.tac
Get-Content $t_config | `
ForEach {$_ -replace '^keepalive\s*=\s*.*$', 'keepalive = 10'} | `
Set-Content "$t_config.new"
Remove-Item $t_config
Move-Item "$t_config.new" $t_config
# Configure buildbot service
############################
Write-Verbose 'Installing buildbot service'
$t_buildbot_service_script = 'C:\Python27\Scripts\buildbot_service.py'
$t_service_name = 'BuildBot'
$t_user_name = $t_service_name
$t_full_user_name = "$env:COMPUTERNAME\$t_service_name"
# Create a new user with a generated password
$t_user_password_clear = `
[System.Web.Security.Membership]::GeneratePassword(12,0)
$t_user_password = `
ConvertTo-SecureString $t_user_password_clear -AsPlainText -Force
$t_user = New-LocalUser -AccountNeverExpires `
-PasswordNeverExpires `
-UserMayNotChangePassword `
-Name $t_user_name `
-Password $t_user_password
# Install a buildbot service that runs as the unprivileged user
& $t_python $t_buildbot_service_script `
--username $t_full_user_name `
--password $t_user_password_clear `
--startup auto install
CheckLastExitCode
# Tell buildbot how to find the worker directory
$t_parameters_key = "HKLM:\SYSTEM\CurrentControlSet\Services\$t_service_name\Parameters"
New-Item -Path $t_parameters_key -Force
Set-ItemProperty -Path $t_parameters_key -Name "directories" `
-Value $t_worker_dir
# Give buildbot access to the worker directory
$t_acl = Get-Acl $t_worker_dir
$t_access_rule = New-Object `
System.Security.AccessControl.FileSystemAccessRule `
-ArgumentList @($t_full_user_name, 'FullControl', `
'ContainerInherit,ObjectInherit', 'None', 'Allow')
$t_acl.SetAccessRule($t_access_rule)
Set-Acl $t_worker_dir $t_acl
# Final steps
#############
#
# - You must grant the "Log on as a service" right to the "BuildBot" user.
# - You must start the "buildbot-stunnel" and "buildbot" services
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment