Skip to content

Commit

Permalink
chore: improve Windows tests debug and small code cleanup (#396)
Browse files Browse the repository at this point in the history
* increase timout from 30 to 60 minutes

* add 'building and testing on Windows' README section

* chore: improve Windows tests debug and small code cleanup
  • Loading branch information
lemeurherve authored Apr 29, 2024
1 parent 4ac1c46 commit d97675f
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 73 deletions.
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pipeline {
label agentSelector(env.IMAGE_TYPE)
}
options {
timeout(time: 30, unit: 'MINUTES')
timeout(time: 60, unit: 'MINUTES')
}
environment {
DOCKERHUB_ORGANISATION = "${infra.isTrusted() ? 'jenkins' : 'jenkins4eval'}"
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,23 @@ make bats
make: 'bats' is up to date.
```
### Building and testing on Windows
From a Powershell console, set first the `IMAGE_TYPE` environment variable defining the Windows flavor ("nanoserver"/"windowsservercore") and version you want to build.
For example:
```
New-Item -Path env:IMAGE_TYPE -Value "nanoserver-ltsc2019"
```
Then run `.\build.ps1` to launch the build of the images for each jexdk specified in the build-windows.yaml docker compose file.
Run `.\build.ps1 test` if you also want to run the tests harness suit.
Run `.\build.ps1 test -TestsDebug 'debug'` to also get commands & stderr of tests, displayed on top of them.
You can set it to 'verbose' to also get stdout of every test command.
Finally, instead of passing -TestsDebug parameter to build.ps1, you can also set the desired value to $env:TESTS_DEBUG.
## Changelog
See [GitHub Releases](https://github.com/jenkinsci/docker-ssh-agent/releases/latest).
Expand Down
85 changes: 49 additions & 36 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,29 @@ Param(
[String] $Target = 'build',
[String] $Build = '',
[String] $VersionTag = '1.0-1',
[switch] $DryRun = $false
[switch] $DryRun = $false,
# Output debug info for tests. Accepted values:
# - empty (no additional test output)
# - 'debug' (test cmd & stderr outputed)
# - 'verbose' (test cmd, stderr, stdout outputed)
[String] $TestsDebug = ''
)

$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue' # Disable Progress bar for faster downloads

$Repository = 'ssh-agent'
$Organisation = 'jenkins'
$ImageType = 'windows-ltsc2019'

$baseDockerCmd = 'docker-compose --file=build-windows.yaml'
$baseDockerBuildCmd = '{0} build --parallel --pull' -f $baseDockerCmd

if(![String]::IsNullOrWhiteSpace($env:TESTS_DEBUG)) {
$ImageType = $env:IMAGE_TYPE
}
$env:TESTS_DEBUG = $TestsDebug

if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_REPO)) {
$Repository = $env:DOCKERHUB_REPO
}
Expand All @@ -24,6 +39,20 @@ if(![String]::IsNullOrWhiteSpace($env:IMAGE_TYPE)) {
$ImageType = $env:IMAGE_TYPE
}

# Ensure constant env vars used in the docker compose file are defined
$env:DOCKERHUB_ORGANISATION = "$Organisation"
$env:DOCKERHUB_REPO = "$Repository"
$env:VERSION = "$VersionTag"

$items = $ImageType.Split('-')
$env:WINDOWS_FLAVOR = $items[0]
$env:WINDOWS_VERSION_TAG = $items[1]
$env:TOOLS_WINDOWS_VERSION = $items[1]
if ($items[1] -eq 'ltsc2019') {
# There are no eclipse-temurin:*-ltsc2019 or mcr.microsoft.com/powershell:*-ltsc2019 docker images unfortunately, only "1809" ones
$env:TOOLS_WINDOWS_VERSION = '1809'
}

# Check for required commands
Function Test-CommandExists {
# From https://devblogs.microsoft.com/scripting/use-a-powershell-function-to-see-if-a-command-exists/
Expand All @@ -46,25 +75,9 @@ Function Test-CommandExists {
}
}

# Ensure constant env vars used in the docker compose file are defined
$env:DOCKERHUB_ORGANISATION = "$Organisation"
$env:DOCKERHUB_REPO = "$Repository"
$env:VERSION = "$VersionTag"

$items = $ImageType.Split("-")
$env:WINDOWS_FLAVOR = $items[0]
$env:WINDOWS_VERSION_TAG = $items[1]
$env:TOOLS_WINDOWS_VERSION = $items[1]
if ($items[1] -eq 'ltsc2019') {
# There are no eclipse-temurin:*-ltsc2019 or mcr.microsoft.com/powershell:*-ltsc2019 docker images unfortunately, only "1809" ones
$env:TOOLS_WINDOWS_VERSION = '1809'
}

$ProgressPreference = 'SilentlyContinue' # Disable Progress bar for faster downloads

Test-CommandExists "docker"
Test-CommandExists "docker-compose"
Test-CommandExists "yq"
Test-CommandExists 'docker'
Test-CommandExists 'docker-compose'
Test-CommandExists 'yq'

function Test-Image {
param (
Expand Down Expand Up @@ -104,27 +117,27 @@ $baseDockerBuildCmd = '{0} build --parallel --pull' -f $baseDockerCmd
Write-Host "= PREPARE: List of $Organisation/$env:DOCKERHUB_REPO images and tags to be processed:"
Invoke-Expression "$baseDockerCmd config"

Write-Host "= BUILD: Building all images..."
Write-Host '= BUILD: Building all images...'
switch ($DryRun) {
$true { Write-Host "(dry-run) $baseDockerBuildCmd" }
$false { Invoke-Expression $baseDockerBuildCmd }
}
Write-Host "= BUILD: Finished building all images."
Write-Host '= BUILD: Finished building all images.'

if($lastExitCode -ne 0) {
exit $lastExitCode
}

if($target -eq "test") {
if($target -eq 'test') {
if ($DryRun) {
Write-Host "= TEST: (dry-run) test harness"
Write-Host '= TEST: (dry-run) test harness'
} else {
Write-Host "= TEST: Starting test harness"
Write-Host '= TEST: Starting test harness'

$mod = Get-InstalledModule -Name Pester -MinimumVersion 5.3.0 -MaximumVersion 5.3.3 -ErrorAction SilentlyContinue
if($null -eq $mod) {
Write-Host "= TEST: Pester 5.3.x not found: installing..."
$module = "c:\Program Files\WindowsPowerShell\Modules\Pester"
Write-Host '= TEST: Pester 5.3.x not found: installing...'
$module = 'C:\Program Files\WindowsPowerShell\Modules\Pester'
if(Test-Path $module) {
takeown /F $module /A /R
icacls $module /reset
Expand All @@ -135,7 +148,7 @@ if($target -eq "test") {
}

Import-Module Pester
Write-Host "= TEST: Setting up Pester environment..."
Write-Host '= TEST: Setting up Pester environment...'
$configuration = [PesterConfiguration]::Default
$configuration.Run.PassThru = $true
$configuration.Run.Path = '.\tests'
Expand All @@ -145,7 +158,7 @@ if($target -eq "test") {
$configuration.Output.Verbosity = 'Diagnostic'
$configuration.CodeCoverage.Enabled = $false

Write-Host "= TEST: Testing all ${agentType} images..."
Write-Host '= TEST: Testing all images...'
# Only fail the run afterwards in case of any test failures
$testFailed = $false
Invoke-Expression "$baseDockerCmd config" | yq '.services[].image' | ForEach-Object {
Expand All @@ -154,31 +167,31 @@ if($target -eq "test") {

# Fail if any test failures
if($testFailed -ne $false) {
Write-Error "= TEST: stage failed!"
Write-Error '= TEST: stage failed!'
exit 1
} else {
Write-Host "= TEST: stage passed!"
Write-Host '= TEST: stage passed!'
}
}
}

if($target -eq "publish") {
Write-Host "= PUBLISH: push all images and tags"
if($target -eq 'publish') {
Write-Host '= PUBLISH: push all images and tags'
switch($DryRun) {
$true { Write-Host "(dry-run) $baseDockerCmd push" }
$false { Invoke-Expression "$baseDockerCmd push" }
}

# Fail if any issues when publising the docker images
if($lastExitCode -ne 0) {
Write-Error "= PUBLISH: failed!"
Write-Error '= PUBLISH: failed!'
exit 1
}
}

if($lastExitCode -ne 0) {
Write-Error "Build failed!"
Write-Error 'Build failed!'
} else {
Write-Host "Build finished successfully"
Write-Host 'Build finished successfully'
}
exit $lastExitCode
48 changes: 27 additions & 21 deletions tests/sshAgent.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ Import-Module -DisableNameChecking -Force $PSScriptRoot/test_helpers.psm1

$global:IMAGE_NAME = Get-EnvOrDefault 'IMAGE_NAME' '' # Ex: jenkins4eval/ssh-agent:nanoserver-1809-jdk17

$imageItems = $global:IMAGE_NAME.Split(":")
$imageItems = $global:IMAGE_NAME.Split(':')
$global:IMAGE_TAG = $imageItems[1]

$items = $global:IMAGE_TAG.Split("-")
$items = $global:IMAGE_TAG.Split('-')
# Remove the 'jdk' prefix
$global:JAVAMAJORVERSION = $items[2].Remove(0,3)
$global:WINDOWSFLAVOR = $items[0]
Expand All @@ -19,12 +19,12 @@ if ($items[1] -eq 'ltsc2019') {
# TODO: make this name unique for concurency
$global:CONTAINERNAME = 'pester-jenkins-ssh-agent-{0}' -f $global:IMAGE_TAG

$global:CONTAINERSHELL = "powershell.exe"
$global:CONTAINERSHELL = 'powershell.exe'
if($global:WINDOWSFLAVOR -eq 'nanoserver') {
$global:CONTAINERSHELL = "pwsh.exe"
$global:CONTAINERSHELL = 'pwsh.exe'
}

$global:PUBLIC_SSH_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAvnRN27LdPPQq2OH3GiFFGWX/SH5TCPVePLR21ngMFV8nAthXgYrFkRi/t+Wafe3ByTu2XYUDlXHKGIPIoAKo4gz5dIjUFfoac1ZuCDIbEiqPEjkk4tkfc2qr/BnIZsOYQi4Mbu+Z40VZEsAQU7eBinnZaHE1qGMHjS1xfrRtp2rdeO1EBz92FJ8dfnkUnohTXo3qPVSFGIPbh7UKEoKcyCosRO1P41iWD1rVsH1SLLXYAh2t49L7IPiplg09Dep6H47LyQVbxU9eXY8yMtUrRuwEk9IUX/IqpxNhk5hngHPP3JjsP0hyyrYSPkZlbs3izd9kk3y09Wn/ElHidiEk0Q=="
$global:PUBLIC_SSH_KEY = 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAvnRN27LdPPQq2OH3GiFFGWX/SH5TCPVePLR21ngMFV8nAthXgYrFkRi/t+Wafe3ByTu2XYUDlXHKGIPIoAKo4gz5dIjUFfoac1ZuCDIbEiqPEjkk4tkfc2qr/BnIZsOYQi4Mbu+Z40VZEsAQU7eBinnZaHE1qGMHjS1xfrRtp2rdeO1EBz92FJ8dfnkUnohTXo3qPVSFGIPbh7UKEoKcyCosRO1P41iWD1rVsH1SLLXYAh2t49L7IPiplg09Dep6H47LyQVbxU9eXY8yMtUrRuwEk9IUX/IqpxNhk5hngHPP3JjsP0hyyrYSPkZlbs3izd9kk3y09Wn/ElHidiEk0Q=='
$global:PRIVATE_SSH_KEY = @"
-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQEAvnRN27LdPPQq2OH3GiFFGWX/SH5TCPVePLR21ngMFV8nAthX
Expand Down Expand Up @@ -68,12 +68,13 @@ Describe "[$global:IMAGE_NAME] image is present" {

Describe "[$global:IMAGE_NAME] image has setup-sshd.ps1 in the correct location" {
BeforeAll {
docker run --detach --tty --name "$global:CONTAINERNAME" --publish-all "$global:IMAGE_NAME" "$global:CONTAINERSHELL"
$exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name=`"$global:CONTAINERNAME`" --publish-all `"$global:IMAGE_NAME`" `"$global:CONTAINERSHELL`""
$exitCode | Should -Be 0
Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue
}

It 'has setup-sshd.ps1 in C:/ProgramData/Jenkins' {
$exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"if(Test-Path C:/ProgramData/Jenkins/setup-sshd.ps1) { exit 0 } else { exit 1}`"" $global:TESTS_DEBUG
$exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"if(Test-Path C:/ProgramData/Jenkins/setup-sshd.ps1) { exit 0 } else { exit 1}`""
$exitCode | Should -Be 0
}

Expand All @@ -84,38 +85,39 @@ Describe "[$global:IMAGE_NAME] image has setup-sshd.ps1 in the correct location"

Describe "[$global:IMAGE_NAME] checking image metadata" {
It 'has correct volumes' {
$exitCode, $stdout, $stderr = Run-Program 'docker' "inspect --format '{{.Config.Volumes}}' $global:IMAGE_NAME" $global:TESTS_DEBUG
$exitCode, $stdout, $stderr = Run-Program 'docker' "inspect --format '{{.Config.Volumes}}' $global:IMAGE_NAME"
$exitCode | Should -Be 0

$stdout | Should -Match 'C:/Users/jenkins/AppData/Local/Temp'
$stdout | Should -Match 'C:/Users/jenkins/Work'
}

It 'has the source GitHub URL in docker metadata' {
$exitCode, $stdout, $stderr = Run-Program 'docker' "inspect --format=`"{{index .Config.Labels \`"org.opencontainers.image.source\`"}}`" $global:IMAGE_NAME" $global:TESTS_DEBUG
$exitCode, $stdout, $stderr = Run-Program 'docker' "inspect --format=`"{{index .Config.Labels \`"org.opencontainers.image.source\`"}}`" $global:IMAGE_NAME"
$exitCode | Should -Be 0
$stdout.Trim() | Should -Match 'https://github.com/jenkinsci/docker-ssh-agent'
}
}

Describe "[$global:IMAGE_NAME] image has correct version of java and git-lfs installed and in the PATH" {
BeforeAll {
docker run --detach --tty --name="$global:CONTAINERNAME" --publish-all "$global:IMAGE_NAME" $global:CONTAINERSHELL
$exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name=`"$global:CONTAINERNAME`" --publish-all `"$global:IMAGE_NAME`" `"$global:PUBLIC_SSH_KEY`""
$exitCode | Should -Be 0
Is-ContainerRunning $global:CONTAINERNAME
}

It 'has java installed and in the path' {
$exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"if(`$null -eq (Get-Command java.exe -ErrorAction SilentlyContinue)) { exit -1 } else { exit 0 }`"" $global:TESTS_DEBUG
$exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"if(`$null -eq (Get-Command java.exe -ErrorAction SilentlyContinue)) { exit -1 } else { exit 0 }`""
$exitCode | Should -Be 0

$exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"`$version = java -version 2>&1 ; Write-Host `$version`"" $global:TESTS_DEBUG
$exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"`$version = java -version 2>&1 ; Write-Host `$version`""
$r = [regex] "^openjdk version `"(?<major>\d+)"
$m = $r.Match($stdout)
$m | Should -Not -Be $null
$m.Groups['major'].ToString() | Should -Be "$global:JAVAMAJORVERSION"
}

It 'has git-lfs (and thus git) installed' {
It 'has git-lfs (and thus git) installed and in the path' {
$exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"`& git lfs version`""
$exitCode | Should -Be 0
$stdout.Trim() | Should -Match "git-lfs/$global:GITLFSVERSION"
Expand All @@ -128,15 +130,16 @@ Describe "[$global:IMAGE_NAME] image has correct version of java and git-lfs ins

Describe "[$global:IMAGE_NAME] create agent container with pubkey as argument" {
BeforeAll {
docker run --detach --tty --name="$global:CONTAINERNAME" --publish-all "$global:IMAGE_NAME" "$global:PUBLIC_SSH_KEY"
$exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name=`"$global:CONTAINERNAME`" --publish-all `"$global:IMAGE_NAME`" `"$global:PUBLIC_SSH_KEY`""
$exitCode | Should -Be 0
Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue
Start-Sleep -Seconds 10
}

It 'runs commands via ssh' {
$exitCode, $stdout, $stderr = Run-ThruSSH $global:CONTAINERNAME "$global:PRIVATE_SSH_KEY" "$global:CONTAINERSHELL -NoLogo -C `"Write-Host 'f00'`""
$exitCode | Should -Be 0
$stdout | Should -Match "f00"
$stdout | Should -Match 'f00'
}

AfterAll {
Expand All @@ -146,15 +149,17 @@ Describe "[$global:IMAGE_NAME] create agent container with pubkey as argument" {

Describe "[$global:IMAGE_NAME] create agent container with pubkey as envvar" {
BeforeAll {
docker run --detach --tty --name="$global:CONTAINERNAME" --publish-all --env="JENKINS_AGENT_SSH_PUBKEY=$global:PUBLIC_SSH_KEY" "$global:IMAGE_NAME"
$exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name=`"$global:CONTAINERNAME`" --publish-all `"$global:IMAGE_NAME`" `"$global:PUBLIC_SSH_KEY`""
$exitCode | Should -Be 0
Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue
Start-Sleep -Seconds 10
}

It 'runs commands via ssh' {
$exitCode, $stdout, $stderr = Run-ThruSSH $global:CONTAINERNAME "$global:PRIVATE_SSH_KEY" "$global:CONTAINERSHELL -NoLogo -C `"Write-Host 'f00'`""
$exitCode | Should -Be 0
$stdout | Should -Match "f00"
$stdout | Should -Match 'f00'
Start-Sleep -Seconds 10
}

AfterAll {
Expand All @@ -167,15 +172,16 @@ $global:DOCKER_PLUGIN_DEFAULT_ARG="/usr/sbin/sshd -D -p 22"
Describe "[$global:IMAGE_NAME] create agent container like docker-plugin with '$global:DOCKER_PLUGIN_DEFAULT_ARG' as argument" {
BeforeAll {
[string]::IsNullOrWhiteSpace($global:DOCKER_PLUGIN_DEFAULT_ARG) | Should -BeFalse
docker run --detach --tty --name="$global:CONTAINERNAME" --publish-all --env="JENKINS_AGENT_SSH_PUBKEY=$global:PUBLIC_SSH_KEY" "$global:IMAGE_NAME" "$global:DOCKER_PLUGIN_DEFAULT_ARG"
$exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name=`"$global:CONTAINERNAME`" --publish-all --env=`"JENKINS_AGENT_SSH_PUBKEY=$global:PUBLIC_SSH_KEY`" `"$global:IMAGE_NAME`" `"$global:DOCKER_PLUGIN_DEFAULT_ARG`""
$exitCode | Should -Be 0
Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue
Start-Sleep -Seconds 10
}

It 'runs commands via ssh' {
$exitCode, $stdout, $stderr = Run-ThruSSH $global:CONTAINERNAME "$global:PRIVATE_SSH_KEY" "$global:CONTAINERSHELL -NoLogo -C `"Write-Host 'f00'`""
$exitCode | Should -Be 0
$stdout | Should -Match "f00"
$stdout | Should -Match 'f00'
}

AfterAll {
Expand All @@ -189,8 +195,8 @@ Describe "[$global:IMAGE_NAME] build args" {
}

It 'uses build args correctly' {
$TEST_USER="testuser"
$TEST_JAW="C:/hamster"
$TEST_USER = 'testuser'
$TEST_JAW = 'C:/hamster'
$CUSTOM_IMAGE_NAME = "custom-${IMAGE_NAME}"

$exitCode, $stdout, $stderr = Run-Program 'docker' "build --build-arg `"WINDOWS_VERSION_TAG=${global:WINDOWSVERSIONTAG}`" --build-arg `"TOOLS_WINDOWS_VERSION=${global:TOOLSWINDOWSVERSION}`" --build-arg `"JAVA_VERSION=${global:JAVAMAJORVERSION}`" --build-arg `"JAVA_HOME=C:\openjdk-${global:JAVAMAJORVERSION}`" --build-arg `"user=$TEST_USER`" --build-arg `"JENKINS_AGENT_WORK=$TEST_JAW`" --tag=$CUSTOM_IMAGE_NAME --file ./windows/${global:WINDOWSFLAVOR}/Dockerfile ."
Expand Down
Loading

0 comments on commit d97675f

Please sign in to comment.