This commit is contained in:
Barret Rennie 2021-06-24 20:01:39 -04:00
Родитель b60522cf15
Коммит 3d87e0d250
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4D71D86C09132D72
18 изменённых файлов: 662 добавлений и 2 удалений

Просмотреть файл

@ -114,3 +114,23 @@ cargo test -p integration-tests -- --nocapture --test-threads 1
```
to force unit tests to run sequentially.
## Deployment
Deployment is done with the `Deploy.ps1` script.
Example:
```ps1
# Deploy fxrecorder the host-specific configuration.
.\contrib\Deploy.ps1 `
-HostName fxrecorder01.corp.tor1.mozilla.com `
-UserName fxrecord `
-MachineType recorder
# Deploy fxrunner and the host-specific configuration.
.\contrib\Deploy.ps1 `
-HostName fxrunner01.corp.tor1.mozilla.com `
-UserName fxrunner `
-MachineType runner
```

105
contrib/Deploy.ps1 Normal file
Просмотреть файл

@ -0,0 +1,105 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Deploy to the given machine.
.Description
Deploy the appropriate binaries and management scripts to the given machine.
SSH is required to be enabled and set up correctly for PowerShell
sessions. See Scripts/Enable-SSH.ps1.
#>
param(
[Parameter(Mandatory = $true)]
[string]$HostName,
[Parameter(Mandatory = $true)]
[ValidateSet("runner", "recorder")]
[string]$MachineType,
[Parameter(Mandatory = $true)]
[string]$UserName
)
# Exit script on error.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues["*:ErrorAction"] = "Stop"
# Ensure we are executing from the repository root.
Set-Location (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Definition))
$session = New-PSSession -UserName $UserName $HostName
try {
# Compute paths for PowerShell directories on the remote host.
$remotePaths = Invoke-Command -Session $session -ScriptBlock {
$paths = @{}
$paths.PowerShell = Join-Path $home "Documents" "PowerShell"
$paths.Scripts = Join-Path $paths.PowerShell "Scripts"
$paths.Modules = Join-Path $paths.PowerShell "Modules"
New-Item -ItemType Directory -Path $paths.Scripts -Force > $null
$paths
}
Push-Location contrib\deployment
# Copy management scripts to the machine.
Write-Host Copying Profile.ps1...
Copy-Item -Force -Path Profile.ps1 -ToSession $session -Destination $remotePaths.PowerShell
Write-Host Copying PowerShell Modules...
Copy-Item -Recurse -Force -Path Modules -ToSession $session -Destination $remotePaths.Modules
Write-Host Copying PowerShell scripts...
if ($MachineType -eq "runner") {
Copy-Item -Force -Path Scripts\fxrunner\*.ps1 -ToSession $session -Destination $remotePaths.Scripts
}
else {
Copy-Item -Force -Path Scripts\fxrecorder\*.ps1 -ToSession $session -Destination $remotePaths.Scripts
}
Write-Host Copying configuration...
$configFile = "contrib\config\${HostName}\fxrecord.toml"
if (Test-File $configFile) {
if ($MachineType -eq "runner") {
Copy-Item -Force -Path $configFile -ToSession $session -Destination C:\fxrunner\
}
else {
Copy-Item -Force -Path $configFile -ToSession $session -Destination C:\fxrecorder\
}
}
else {
Write-Host No configuration found for host ${HostName}, skipping...
}
Pop-Location
# Build fxrecord and deploy the exectuable.
Write-Host Building fxrecord...
cargo build --release
Write-Host Copying binaries...
if ($MachineType -eq "runner") {
New-Item C:\fxrunner -ItemType Directory -Force > $null
Copy-Item -Force -Path target\release\fxrunner.exe -ToSession $session -Destination C:\fxrunner
}
else {
New-Item C:\fxrecorder -ItemType Directory -Force > $null
Copy-Item -Force -Path target\release\fxrecorder.exe -ToSession $session -Destination C:\fxrecorder
Copy-Item -Force -Path vendor -ToSession $session -Destination C:\fxrecorder
Copy-Item -Force -Path requirements.txt -ToSession $session -Destination C:\fxrecorder
}
}
finally {
Remove-PSSession $session
}

Просмотреть файл

@ -4,6 +4,10 @@ This folder contains configuration and management scripts.
## Contents
### config/
### deployment/
Configuration files for fxrecord deployments.
Management scripts and configuration for fxrecord deployments.
### Deploy.ps1
The deployment script.

Просмотреть файл

@ -0,0 +1,82 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
$scriptDir = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "Scripts"
$env:path += ";$scriptDir"
function Get-ShortCWD() {
$pathAsString = ([string] $executionContext.SessionState.Path.CurrentLocation)
if ($pathAsString.StartsWith($HOME)) {
if ($pathAsString.Length -eq $HOME.Length) {
return "~"
}
$components = @("~")
$restPath = $pathAsString.Substring($HOME.Length + 1)
}
else {
$components = @($pathASString.Substring(0, 2))
$restPath = $pathAsString.Substring(3) # Skip the prefix AND the trailing slash
}
$components += $restPath.split("\")
if ($components.Length -gt 2) {
foreach ($i in 1..($components.Length - 2)) {
$components[$i] = $components[$i][0]
}
}
$components -join "\"
}
function prompt() {
$lastCmdSuccess = $global:?
$statusCode = $global:LASTEXITCODE
if ($null -ne $env:VIRTUAL_ENV) {
$envName = Split-Path -Leaf $env:VIRTUAL_ENV
Write-Host -NoNewline "("
Write-Host -NoNewline -ForegroundColor red $envName
Write-Host -NoNewline ") "
}
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal] $identity
$adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator
if ($principal.IsInRole($adminRole)) {
$sigil = "#"
$prefixColour = "red"
}
else {
$sigil = "$"
$prefixColour = "green"
}
$hostname, $username = $identity.Name.split("\")
Write-Host -NoNewline -ForegroundColor $prefixColour $username
Write-Host -NoNewline "@"
Write-Host -NoNewline -ForegroundColor $prefixColour $hostname
Write-Host -NoNewline " "
Write-Host -NoNewline -ForegroundColor blue (Get-ShortCWD)
Write-Host -NoNewline " "
if (!$lastCmdSuccess) {
if ($null -eq $statusCode) {
$statusCode = "!"
}
Write-Host -NoNewline -ForegroundColor red "[$statusCode] "
}
Write-Host -NoNewline $sigil
" "
}
Set-PSReadLineOption -EditMode Emacs -BellStyle None
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete

Просмотреть файл

@ -0,0 +1,22 @@
# contrib/management
This folder contains management scripts for adminstering fxrecord deployments.
## Contents
### config\
Per-instance configuration files for fxrecord deployments.
### modules\
PowerShell modules for adminstering fxrecord deployments.
### scripts\
PowerShell scripts for administering fxrecord deployments.
### Profile.ps1
A PowerShell profile with basic utilities.

Просмотреть файл

@ -0,0 +1,86 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
function Get-UserSessions {
<#
.Synopsis
Return all active user sessions
.Outputs
An array of user session objects.
#>
# Sample output of quser:
# ```
# USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
# >fxrecorder rdp-tcp#7 5 Active . 2021-06-11 6:06 PM
# ```
$output = quser 2>&1 <# Query all user sessions #> `
if ($global:LASTEXITCODE -eq 1) {
return @()
}
return $output |
Select-Object -Skip 1 | <# Strip off the leading column names #> `
Foreach-Object { $_.substring(1) } | <# Strip off the leading character (> or space) #>`
ConvertFrom-String -PropertyNames @("UserName", "SessionName", "Id", "State", "IdleTime", "LoginTime")
}
function Read-TOML {
<#
.Synopsis
Read a TOML file into a table. Does not support nested objects.
.Outputs
A hashtable parsed from the the TOML file.
#>
param (
[Parameter(Mandatory = $true)]
[string]$FileName
)
$toml = @{}
$section = ""
switch -regex -file $FileName {
"^\[(.+)\]$" {
$section = $matches[1]
$toml[$section] = @{}
}
"\s*(.+?)\s*=\s*(.+)" {
$name, $value = $matches[1..2]
# Unquote string values
if (($value[0] -eq '"') -and ($value[-1] -eq '"')) {
$value = $value.Substring(1, $value.Length - 2)
}
$toml[$section][$name] = $value
}
}
$toml
}
function Test-AdminRole {
<#
.Synopsis
Check if the user is in an administrator role.
#>
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal] $identity
$adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator
if (!$principal.IsInRole($adminRole)) {
Write-Host -ForegroundColor Red "$($MyInvocation.ScriptName): Admin required"
exit 1
}
}
Export-ModuleMember Get-UserSessions
Export-ModuleMember Read-TOML
Export-ModuleMember Test-AdminRole

Просмотреть файл

@ -0,0 +1,13 @@
# Scripts/
Management scripts for fxrecord.
## Contents
### fxrecorder/
Management scripts to be installed on a FxRecorder machine by [`Deploy.ps1`][../Deploy.Ps1].
### fxrunner/
Management scripts to be installed on a FxRunner machine by [`Deploy.ps1`][../Deploy.Ps1].

Просмотреть файл

@ -0,0 +1,40 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Stop and disable fxrecorder.
.Description
Stop and disable the Taskcluster generic worker service so the host can
undergo maintenance.
Any active task users will be logged off and their processes terminated.
Home directories are not removed.
#>
Import-Module FxRecord-Management
Test-AdminRole
$WINLOGON_KEY = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"
Set-Service -Name "Generic Worker" -StartupType Disabled -Status Stopped
# Prevent auto-login on next restart.
Remove-Item -Force "C:\generic-worker\next-task-user.json" -ErrorAction Ignore
Remove-ItemProperty $WINLOGON_KEY -Name "DefaultUserName" -ErrorAction Ignore
Remove-ItemProperty $WINLOGON_KEY -Name "DefaultPassword" -ErrorAction Ignore
# Log off existing task users and kill any remaining processes
foreach ($session in (Get-UserSessions | Where-Object { $_.UserName -like "task_*" })) {
logoff $session.Id
}
# Kill any remaining task processes.
Get-Process -IncludeUserName | Where-Object { $_.Username -like "task_*" } | Stop-Process
# Delete any task users.
$taskUsers = Get-LocalUser | Where-Object { $_.Name -like "task_*" }
Remove-LocalUser $taskUsers

Просмотреть файл

@ -0,0 +1,13 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Start and enable the fxrecorder worker.
#>
Import-Module FxRecord-Management
Test-AdminRole
Set-Service -Name "Generic Worker" -StartupType Automatic -Status Running

Просмотреть файл

@ -0,0 +1,110 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Set up this machine to be an fxrecorder host.
.Description
This will install most dependencies. It currently does not install
ImageMagick or ffmpeg. See the installation documenation for details.
#>
Import-Module FxRecord-Management
Test-AdminRole
$TASKCLUSTER_VERSION = "v44.0.0"
$NSSM_VERSION = "2.24"
$PYTHON_VERSION = "3.9.5"
Set-ExecutionPolicy Unrestricted -Force -Scope Process
$webClient = [System.Net.WebClient]::new()
$webClient.DownloadFile("https://www.nssm.cc/release/nssm-${NSSM_VERSION}.zip", "C:\nssm.zip")
Expand-Archive -LiteralPath C:\nssm.zip -DestinationPath C:\
Rename-Item C:\nssm-2.24 c:\nssm
Remove-Item c:\nssm-2.24.zip
$nssm = "C:\nssm\win64\nssm.exe"
# Install generic-worker and its dependencies.
New-Item -ItemType Directory C:\generic-worker
$genericWorker = "C:\generic-worker\generic-worker.exe"
$livelog = "C:\generic-worker\livelog.exe"
$taskclusterProxy = "C:\generic-worker\taskcluster-proxy.exe"
$webClient.DownloadFile(
"https://github.com/taskcluster/taskcluster/releases/download/v${TASKCLUSTER_VERSION}/generic-worker-multiuser-windows-amd64",
$genericWorker)
$webClient.DownloadFile(
"https://github.com/taskcluster/taskcluster/releases/download/v${TASKCLUSTER_VERSION}/livelog-windows-amd64",
$livelog)
$webClient.DownloadFile(
"https://github.com/taskcluster/taskcluster/releases/download/v${TASKCLUSTER_VERSION}/taskcluster-proxy-windows-amd64",
$taskclusterProxy)
$SIGNING_KEY = C:\generic-worker\generic-worker-ed25519-signing-key.key
$CONFIG_FILE = C:\generic-worker\generic-worker-config.json
# Generate a keypair for signing artifacts.
& $genericWorker new-ed25519-keypair --file $SIGNING_KEY
$accessToken = Read-Host "Access Token"
$clientId = Read-Host "Client ID"
$workerId = Read-Host "Worker ID"
Set-Content -Path $CONFIG_FILE @"
{
"accessToken": "$accessToken",
"clientId": "$clientId",
"cleanUpTaskDirs": true,
"ed25519SigningKeyLocation": "$SIGNING_KEY",
"workerId": "$workerId",
"provisionerId": "performance-hardware",
"workerType": "gecko-t-fxrecorder",
"rootURL": "https://firefox-ci-tc.services.mozilla.com",
"shutdownMachineOnIdle": false,
"shutdownMachineOnError": false,
"livelogExecutable": "$($livelog.Replace("\", "\\"))",
"taskclusterProxyExecutable": "$($taskclusterProxy.Replace("\", "\\"))",
"wstAudience": "firefoxcitc",
"wstServerURL": "https://firefoxci-websocktunnel.services.mozilla.com/"
}
"@
# Install the generic worker service.
& $nssm install "Generic Worker" c:\generic-worker\generic-worker.exe
& $nssm set "Generic Worker" AppParameters run --config $CONFIG_FILE
& $nssm set "Generic Worker" DisplayName "Generic Worker"
& $nssm set "Generic Worker" Description "Taskcluster worker"
& $nssm set "Generic Worker" Start SERVICE_AUTO_START
& $nssm set "Generic Worker" Type SERVICE_WIN32_OWN_PROCESS
& $nssm set "Generic Worker" AppNoConsole 1
& $nssm set "Generic Worker" AppAffinity All
& $nssm set "Generic Worker" AppStopMethodSkip 0
& $nssm set "Generic Worker" AppExit Default Exit
& $nssm set "Generic Worker" AppRestartDelay 0
& $nssm set "Generic Worker" AppStdout C:\generic-worker\generic-worker-service.log
& $nssm set "Generic Worker" AppStderr c:\generic-worker\generic-worker-service.log
& $nssm set "Generic Worker" AppRotateFiles 1
& $nssm set "Generic Worker" AppRotateSeconds 3600
& $nssm set "Generic Worker" AppRotateBytes 0
# Download and install Python
$pyInstaller = "C:\python-installer.exe"
$pythonDir = "C:\python-${PYTHON_VERSION}"
$webClient.DownloadFile("https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-amd64.exe", $pyInstaller)
& $pyInstaller /quiet InstallAllUsers=1 PrependPath=1 Include_test=0 TargetDir=$pythonDir
Remove-Item $pyInstaller
# Install Python dependencies.
# C:\fxrecorder\requirements.txt is deployed by Deploy.ps1
$env:PATH += ";${pythonDir}"
python -m pip install -U pip wheel
python -m pip install --require-hashes -r C:\fxrecorder\requirements.txt

Просмотреть файл

@ -0,0 +1,22 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Take a screenshot of the configured fxrunner machine.
#>
param(
[string]$ConfigPath = "C:\fxrecorder\fxrecord.toml"
)
Import-Module FxRecord-Management
$config = Read-TOML $ConfigPath
ffmpeg `
-hide_banner `
-f dshow `
-i "video=$($config["fxrecorder.recording"]["device"])" `
-vframes 1 `
screenshot.jpg

Просмотреть файл

@ -0,0 +1,17 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Update FxRecorder after a deploy.
.Description
This will ensure the Python dependencies are kept up-to-date.
#>
Import-Module FxRecord-Management
Test-AdminRole
python -m pip install -U pip wheel
python -m pip install --require-hashes -r C:\fxrecorder\requirements.txt

Просмотреть файл

@ -0,0 +1,18 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Stop and disable fxrunner
.Description
Stop and disable the fxrunner scheduled task so the machine can undero maintenance.
undergo maintenance.
#>
Import-Module FxRecord-Management
Test-AdminRole
Disable-ScheduledTask -TaskPath \fxrecord\ -TaskName fxrunner
Stop-ScheduledTask -TaskPath \fxrecord\ -TaskName fxrunner

Просмотреть файл

@ -0,0 +1,19 @@
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Enable and start fxrunner.
.Description
Enable and start the fxrunner scheduled task so the machine can undero maintenance.
undergo maintenance.
#>
Import-Module FxRecord-Management
Test-AdminRole
Enable-ScheduledTask -TaskPath \fxrecord\ -TaskName fxrunner
Start-ScheduledTask -TaskPath \fxrecord\ -TaskName fxrunner

Просмотреть файл

@ -0,0 +1,81 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
<#
.Synopsis
Set up this machine to be an fxrunner host.
#>
Import-Module FxRecord-Management
Test-AdminRole
$WINLOGON_KEY = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"
$credentials = Get-Credential $env:USERNAME
Set-ItemProperty `
-Path $WINLOGON_KEY `
-Name "DefaultUserName" `
-Type String `
-Value $credentials.UserName
Set-ItemProperty `
-Path $WINLOGON_KEY `
-Name "DefaultPassword" `
-Type String `
-Value (ConvertFrom-SecureString -AsPlainText $credentials.Password)
Set-ItemProperty `
-Path $WINLOGON_KEY `
-Name "AutoAdminLogon" `
-Type Dword `
-Value 1
New-Item -ItemType Directory -Path C:\fxrunner
$action = New-ScheduledTaskAction `
-Execute "C:\fxrunner\fxrunner.exe" `
-WorkingDirectory "C:\fxrunner"
$trigger = New-ScheduledTaskTrigger `
-AtLogon `
-User $env:USERNAME
$principal = New-ScheduledTaskPrincipal $env:USERNAME
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimelimit (New-TimeSpan) <# Do not impose a time limit on execution (default 3d) #>
$task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Settings $settings
Register-ScheduledTask -TaskPath "\fxrecord\" -TaskName fxrunner -InputObject $task
# Enable legacy IO counters
diskperf -Y
# Disable services that impact performance or are not required.
# Disable "SysMain" (superfetch)
Set-Service -Name SysMain -StartupType Disabled -Status Stopped
# Disable "Synaptics Touchpad Enhanced Service"
# We ignore errors in case the reference hardware does not have this service.
Set-Service -Name SynTPEnhService -StartupDype Disabled -Status -Stopped -ErrorAction Ignore
# Disable "Connected User Experiences and Telemetry"
Set-Service -Name DiagTrack -StartupType Disabled -Status Stopped
# Disable "Touch Keyboard and Handwriting Panel Service"
Set-Service -Name TabletInputService -StartupType Disabled -Status Stopped
# Disable "Windows Search"
Set-Service -Name WSearch -StartupType Disabled -Status Stopped
# Disable "Print Spooler"
Set-Service -Name Spooler -StartupType Disabled -Status Stopped
# Disable "Microsoft Compatability Appraiser"
Disable-ScheduledTask `
-TaskPath "\Microsoft\Windows\Application Experience\" `
-TaskName "Microsoft Compatibility Appraiser"

8
requirements.txt Normal file
Просмотреть файл

@ -0,0 +1,8 @@
pyssim==0.4 \
--hash=sha256:52184c85e6ed0362a508617497c70251837ab38a62531793e3ea7eeaf7a2e150
Pillow==8.2.0 \
--hash=sha256:238c197fc275b475e87c1453b05b467d2d02c2915fdfdd4af126145ff2e4610c
scipy==1.7.0 \
--hash=sha256:aef6e922aea6f2e6bbb539b413c85210a9ee32757535b84204ebd22723e69704
numpy==1.21.0 \
--hash=sha256:2ba579dde0563f47021dcd652253103d6fd66165b18011dce1a0609215b2791e