diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b21cfe25..da1d0028 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,12 +11,12 @@ updates: interval: weekly open-pull-requests-limit: 10 - package-ecosystem: docker - directory: "/windows/nanoserver-ltsc2019" + directory: "/windows/nanoserver" schedule: interval: weekly open-pull-requests-limit: 10 - package-ecosystem: docker - directory: "/windows/windowsservercore-ltsc2019" + directory: "/windows/windowsservercore" schedule: interval: weekly open-pull-requests-limit: 10 diff --git a/Jenkinsfile b/Jenkinsfile index 683a269c..b93f0522 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,85 +1,98 @@ +def agentSelector(String imageType) { + // Image type running on a Linux agent + if (imageType == 'linux') { + return 'linux' + } + // Image types running on a Windows Server Core 2022 agent + if (imageType.contains('2022')) { + return 'windows-2022' + } + // Remaining image types running on a Windows Server Core 2019 agent: (nanoserver|windowservercore)-(1809|2019) + return 'windows-2019' +} + pipeline { agent none options { buildDiscarder(logRotator(daysToKeepStr: '10')) - timestamps() } stages { - stage('Build Docker Image') { - parallel { - stage('Windows') { - agent { - label "docker-windows" + stage('docker-ssh-agent') { + matrix { + axes { + axis { + name 'IMAGE_TYPE' + values 'linux', 'nanoserver-1809', 'windowsservercore-ltsc2019' } - options { - timeout(time: 60, unit: 'MINUTES') - } - environment { - DOCKERHUB_ORGANISATION = "${infra.isTrusted() ? 'jenkins' : 'jenkins4eval'}" - } - steps { - powershell '& ./make.ps1 test' - script { - def branchName = "${env.BRANCH_NAME}" - if (branchName ==~ 'master') { - // we can't use dockerhub builds for windows - // so we publish here - infra.withDockerCredentials { - powershell '& ./make.ps1 publish' + } + stages { + stage('Main') { + agent { + label agentSelector(env.IMAGE_TYPE) + } + options { + timeout(time: 30, unit: 'MINUTES') + } + environment { + DOCKERHUB_ORGANISATION = "${infra.isTrusted() ? 'jenkins' : 'jenkins4eval'}" + } + stages { + stage('Prepare Docker') { + when { + environment name: 'IMAGE_TYPE', value: 'linux' } - } - - def tagName = "${env.TAG_NAME}" - if(tagName =~ /\d(\.\d)+(-\d+)?/) { - // we need to build and publish the tagged version - infra.withDockerCredentials { - powershell "& ./make.ps1 -PushVersions -VersionTag $tagName publish" + steps { + sh ''' + docker buildx create --use + docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + ''' } } - } - } - } - stage('Linux') { - agent { - label "docker&&linux" - } - options { - timeout(time: 30, unit: 'MINUTES') - } - steps { - script { - infra.withDockerCredentials { - def branchName = "${env.BRANCH_NAME}" - if (infra.isTrusted()) { - if (branchName ==~ 'master') { - sh ''' - docker buildx create --use - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker buildx bake --push --file docker-bake.hcl linux - ''' - } else if (env.TAG_NAME != null) { - sh """ - export ON_TAG=true - export VERSION=$TAG_NAME - docker buildx create --use - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker buildx bake --push --file docker-bake.hcl linux - """ + stage('Build and Test') { + // This stage is the "CI" and should be run on all code changes triggered by a code change + when { + not { buildingTag() } + } + steps { + script { + if(isUnix()) { + sh 'make build' + sh 'make test' + // If the tests are passing for Linux AMD64, then we can build all the CPU architectures + sh 'docker buildx bake --file docker-bake.hcl linux' + } else { + powershell '& ./build.ps1 test' + } } - } else { - sh 'make build' - try { - sh 'make test' - } finally { - junit('target/*.xml') + } + post { + always { + junit(allowEmptyResults: true, keepLongStdio: true, testResults: 'target/**/junit-results.xml') + } + } + } + stage('Deploy to DockerHub') { + // This stage is the "CD" and should only be run when a tag triggered the build + when { + buildingTag() + } + steps { + script { + // This function is defined in the jenkins-infra/pipeline-library + infra.withDockerCredentials { + if (isUnix()) { + sh """ + export ON_TAG=true + export VERSION=$TAG_NAME + docker buildx bake --push --file docker-bake.hcl linux + """ + } else { + powershell "& ./build.ps1 -PushVersions -VersionTag ${env.TAG_NAME} publish" + } + } } - sh ''' - docker buildx create --use - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker buildx bake --file docker-bake.hcl linux - ''' } } } diff --git a/build-windows.yaml b/build-windows.yaml new file mode 100644 index 00000000..cf9775d4 --- /dev/null +++ b/build-windows.yaml @@ -0,0 +1,15 @@ +services: + jdk11: + image: ${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${WINDOWS_FLAVOR}-${WINDOWS_VERSION_TAG}-jdk11 + build: + context: ./ + dockerfile: ./windows/${WINDOWS_FLAVOR}/Dockerfile + args: + JAVA_HOME: "C:/openjdk-11" + JAVA_VERSION: 11.0.20_8 + WINDOWS_VERSION_TAG: ${WINDOWS_VERSION_TAG} + TOOLS_WINDOWS_VERSION: ${TOOLS_WINDOWS_VERSION} + tags: + - "${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${VERSION}-${WINDOWS_FLAVOR}-${WINDOWS_VERSION_TAG}-jdk11" + - "${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${VERSION}-${WINDOWS_FLAVOR}-${WINDOWS_VERSION_TAG}" + - "${DOCKERHUB_ORGANISATION}/${DOCKERHUB_REPO}:${WINDOWS_FLAVOR}-${WINDOWS_VERSION_TAG}" diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 00000000..57d7ae05 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,184 @@ +[CmdletBinding()] +Param( + [Parameter(Position=1)] + [String] $Target = 'build', + [String] $Build = '', + [String] $VersionTag = '1.0-1', + [switch] $DryRun = $false +) + +$ErrorActionPreference = 'Stop' +$Repository = 'ssh-agent' +$Organisation = 'jenkins' +$ImageType = 'windows-ltsc2019' + +if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_REPO)) { + $Repository = $env:DOCKERHUB_REPO +} + +if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_ORGANISATION)) { + $Organisation = $env:DOCKERHUB_ORGANISATION +} + +if(![String]::IsNullOrWhiteSpace($env:IMAGE_TYPE)) { + $ImageType = $env:IMAGE_TYPE +} + +# Check for required commands +Function Test-CommandExists { + # From https://devblogs.microsoft.com/scripting/use-a-powershell-function-to-see-if-a-command-exists/ + Param ( + [String] $command + ) + + $oldPreference = $ErrorActionPreference + $ErrorActionPreference = 'stop' + try { + if(Get-Command $command){ + Write-Debug "$command exists" + } + } + Catch { + "$command does not exist" + } + Finally { + $ErrorActionPreference=$oldPreference + } +} + +# 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" + +function Test-Image { + param ( + $ImageName + ) + + $imageNameItems = $imageName.Split(":") + $imageTag = $imageNameItems[1] + + Write-Host "= TEST: Testing ${ImageName} image" + + $env:IMAGE_NAME = $ImageName + + $targetPath = '.\target\{0}' -f $imageTag + if(Test-Path $targetPath) { + Remove-Item -Recurse -Force $targetPath + } + New-Item -Path $targetPath -Type Directory | Out-Null + # $configuration.Run.Path = 'tests\sshAgent.Tests.ps1' + $configuration.TestResult.OutputPath = '{0}\junit-results.xml' -f $targetPath + $TestResults = Invoke-Pester -Configuration $configuration + $failed = $false + if ($TestResults.FailedCount -gt 0) { + Write-Host "There were $($TestResults.FailedCount) failed tests out of $($TestResults.TotalCount) in ${ImageName}" + $failed = $true + } else { + Write-Host "There were $($TestResults.PassedCount) passed tests in ${ImageName}" + } + Remove-Item env:\IMAGE_NAME + + return $failed +} + +$baseDockerCmd = 'docker-compose --file=build-windows.yaml' +$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..." + switch ($DryRun) { + $true { Write-Host "(dry-run) $baseDockerBuildCmd" } + $false { Invoke-Expression $baseDockerBuildCmd } + } + Write-Host "= BUILD: Finished building all images." + +if($lastExitCode -ne 0) { + exit $lastExitCode +} + +if($target -eq "test") { + if ($DryRun) { + Write-Host "= TEST: (dry-run) test harness" + } else { + 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" + if(Test-Path $module) { + takeown /F $module /A /R + icacls $module /reset + icacls $module /grant Administrators:'F' /inheritance:d /T + Remove-Item -Path $module -Recurse -Force -Confirm:$false + } + Install-Module -Force -Name Pester -MaximumVersion 5.3.3 + } + + Import-Module Pester + Write-Host "= TEST: Setting up Pester environment..." + $configuration = [PesterConfiguration]::Default + $configuration.Run.PassThru = $true + $configuration.Run.Path = '.\tests' + $configuration.Run.Exit = $true + $configuration.TestResult.Enabled = $true + $configuration.TestResult.OutputFormat = 'JUnitXml' + $configuration.Output.Verbosity = 'Diagnostic' + $configuration.CodeCoverage.Enabled = $false + + Write-Host "= TEST: Testing all ${agentType} images..." + # Only fail the run afterwards in case of any test failures + $testFailed = $false + Invoke-Expression "$baseDockerCmd config" | yq '.services[].image' | ForEach-Object { + $testFailed = $testFailed -or (Test-Image $_) + } + + # Fail if any test failures + if($testFailed -ne $false) { + Write-Error "= TEST: stage failed!" + exit 1 + } else { + Write-Host "= TEST: stage passed!" + } + } +} + +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!" + exit 1 + } +} + +if($lastExitCode -ne 0) { + Write-Error "Build failed!" +} else { + Write-Host "Build finished successfully" +} +exit $lastExitCode diff --git a/make.ps1 b/make.ps1 deleted file mode 100644 index 2c505ff9..00000000 --- a/make.ps1 +++ /dev/null @@ -1,173 +0,0 @@ -[CmdletBinding()] -Param( - [Parameter(Position=1)] - [String] $Target = "build", - [String] $Build = '', - [String] $VersionTag = '1.0-1', - [switch] $PushVersions = $false -) - -$Repository = 'ssh-agent' -$Organization = 'jenkins' -$Java11Version = '11.0.19_7' - -if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_REPO)) { - $Repository = $env:DOCKERHUB_REPO -} - -if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_ORGANISATION)) { - $Organization = $env:DOCKERHUB_ORGANISATION -} - -$builds = @{ - 'jdk11-windowsservercore-ltsc2019' = @{ - 'Folder' = 'windows\windowsservercore-ltsc2019'; - 'Tags' = @( "windowsservercore-1809", "windowsservercore-1809-jdk11", "windowsservercore-ltsc2019", "windowsservercore-ltsc2019-jdk11" ); - 'JavaVersion' = $Java11Version; - 'JavaHome' = 'C:\openjdk-11'; - }; - 'jdk11-nanoserver-1809' = @{ - 'Folder' = 'windows\nanoserver-ltsc2019'; - 'Tags' = @( "nanoserver-1809", "nanoserver-ltsc2019", "nanoserver-1809-jdk11", "nanoserver-ltsc2019", "nanoserver-ltsc2019-jdk11" ); - 'JavaVersion' = $Java11Version; - 'JavaHome' = 'C:\openjdk-11'; - }; -} - -function Build-Image { - param ( - [String] $Build, - [String] $ImageName, - [String] $JavaVersion, - [String] $JavaHome, - [String] $Folder - ) - - Write-Host "Building $Build with name $imageName" - docker build --build-arg "JAVA_VERSION=${JavaVersion}" --build-arg "JAVA_HOME=${JavaHome}" --tag="${ImageName}" --file="${Folder}/Dockerfile" ./ -} - -$exitCodes = 0 -if(![System.String]::IsNullOrWhiteSpace($Build) -and $builds.ContainsKey($Build)) { - foreach($tag in $builds[$Build]['Tags']) { - Build-Image -Build $Build -ImageName "${Organization}/${Repository}:${tag}" -JavaVersion $builds[$Build]['JavaVersion'] -JavaHome $builds[$Build]['JavaHome'] -Folder $builds[$Build]['Folder'] - $exitCodes += $lastExitCode - - if($PushVersions) { - $buildTag = "$VersionTag-$tag" - if($tag -eq 'latest') { - $buildTag = "$VersionTag" - } - Build-Image -Build $Build -ImageName "${Organization}/${Repository}:${buildTag}" -JavaVersion $builds[$Build]['JavaVersion'] -JavaHome $builds[$Build]['JavaHome'] -Folder $builds[$Build]['Folder'] - $exitCodes += $lastExitCode - } - } -} else { - foreach($b in $builds.Keys) { - foreach($tag in $builds[$b]['Tags']) { - Build-Image -Build $Build -ImageName "${Organization}/${Repository}:${tag}" -JavaVersion $builds[$b]['JavaVersion'] -JavaHome $builds[$b]['JavaHome'] -Folder $builds[$b]['Folder'] - $exitCodes += $lastExitCode - - if($PushVersions) { - $buildTag = "$VersionTag-$tag" - if($tag -eq 'latest') { - $buildTag = "$VersionTag" - } - Build-Image -Build $Build -ImageName "${Organization}/${Repository}:${buildTag}" -JavaVersion $builds[$b]['JavaVersion'] -JavaHome $builds[$b]['JavaHome'] -Folder $builds[$b]['Folder'] - $exitCodes += $lastExitCode - } - } - } -} - -if($exitCodes -ne 0) { - Write-Host "Image build stage failed!" - exit 1 -} else { - Write-Host "Image build stage passed!" -} - -function Test-Image { - param ( - [String] $ImageName, - [String] $ImageFolder - ) - - Write-Host "Testing $ImageName..." - $env:AGENT_IMAGE = $ImageName - $env:IMAGE_FOLDER = $ImageFolder - Invoke-Pester -Path tests -EnableExit - Remove-Item env:\AGENT_IMAGE - Remove-Item env:\IMAGE_FOLDER -} - -if($Target -eq "test") { - $mod = Get-InstalledModule -Name Pester -MinimumVersion 4.9.0 -MaximumVersion 4.99.99 -ErrorAction SilentlyContinue - if($null -eq $mod) { - $module = "c:\Program Files\WindowsPowerShell\Modules\Pester" - if(Test-Path $module) { - takeown /F $module /A /R - icacls $module /reset - icacls $module /grant Administrators:'F' /inheritance:d /T - Remove-Item -Path $module -Recurse -Force -Confirm:$false - } - Install-Module -Force -Name Pester -MaximumVersion 4.99.99 - } - - if(![System.String]::IsNullOrWhiteSpace($Build) -and $builds.ContainsKey($Build)) { - Test-Image $Build $builds[$Build]['Folder'] - } else { - foreach($b in $builds.Keys) { - Test-Image $b $builds[$b]['Folder'] - } - } -} - -function Publish-Image { - param ( - [String] $Build, - [String] $ImageName - ) - Write-Host "= PUBLISH: Tagging $Build => full name = $ImageName" - docker tag "$Build" "$ImageName" - - Write-Host "= PUBLISH: Publishing $ImageName..." - docker push "$ImageName" -} - -if($Target -eq "publish") { - if(![System.String]::IsNullOrWhiteSpace($Build) -and $builds.ContainsKey($Build)) { - foreach($tag in $Builds[$Build]['Tags']) { - Publish-Image "$Build" "${Organization}/${Repository}:${tag}" - - if($PushVersions) { - $buildTag = "$VersionTag-$tag" - if($tag -eq 'latest') { - $buildTag = "$VersionTag" - } - Publish-Image "$Build" "${Organization}/${Repository}:${buildTag}" - } - } - } else { - foreach($b in $builds.Keys) { - foreach($tag in $Builds[$b]['Tags']) { - Publish-Image "$b" "${Organization}/${Repository}:${tag}" - - if($PushVersions) { - $buildTag = "$VersionTag-$tag" - if($tag -eq 'latest') { - $buildTag = "$VersionTag" - } - Publish-Image "$b" "${Organization}/${Repository}:${tag}" - } - } - } - } -} - -if($lastExitCode -ne 0) { - Write-Error "Build failed!" -} else { - Write-Host "Build finished successfully" -} -exit $lastExitCode diff --git a/tests/sshAgent.Tests.ps1 b/tests/sshAgent.Tests.ps1 index e5963d43..49bd7b1e 100644 --- a/tests/sshAgent.Tests.ps1 +++ b/tests/sshAgent.Tests.ps1 @@ -1,25 +1,31 @@ Import-Module -DisableNameChecking -Force $PSScriptRoot/test_helpers.psm1 -$global:AGENT_IMAGE = Get-EnvOrDefault 'AGENT_IMAGE' '' -$global:IMAGE_FOLDER = Get-EnvOrDefault 'IMAGE_FOLDER' '' - -$items = $global:AGENT_IMAGE.Split("-") - -# Remove the 'jdk' prefix (3 first characters) -$global:JDKMAJORVERSION = $items[0].Remove(0,3) -$global:WINDOWSFLAVOR = $items[1] -$global:WINDOWSVERSION = $items[2] +$global:IMAGE_NAME = Get-EnvOrDefault 'IMAGE_NAME' '' # Ex: jenkins4eval/ssh-agent:nanoserver-1809-jdk17 + +$imageItems = $global:IMAGE_NAME.Split(":") +$global:IMAGE_TAG = $imageItems[1] + +$items = $global:IMAGE_TAG.Split("-") +# Remove the 'jdk' prefix +$global:JAVAMAJORVERSION = $items[2].Remove(0,3) +$global:WINDOWSFLAVOR = $items[0] +$global:WINDOWSVERSIONTAG = $items[1] +$global:TOOLSWINDOWSVERSION = $items[1] +# There are no eclipse-temurin:*-ltsc2019 or mcr.microsoft.com/powershell:*-ltsc2019 docker images unfortunately, only "1809" ones +if ($items[1] -eq 'ltsc2019') { + $global:TOOLSWINDOWSVERSION = '1809' +} # TODO: make this name unique for concurency -$global:CONTAINERNAME = 'pester-jenkins-ssh-agent-{0}' -f $global:AGENT_IMAGE +$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" } -$PUBLIC_SSH_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAvnRN27LdPPQq2OH3GiFFGWX/SH5TCPVePLR21ngMFV8nAthXgYrFkRi/t+Wafe3ByTu2XYUDlXHKGIPIoAKo4gz5dIjUFfoac1ZuCDIbEiqPEjkk4tkfc2qr/BnIZsOYQi4Mbu+Z40VZEsAQU7eBinnZaHE1qGMHjS1xfrRtp2rdeO1EBz92FJ8dfnkUnohTXo3qPVSFGIPbh7UKEoKcyCosRO1P41iWD1rVsH1SLLXYAh2t49L7IPiplg09Dep6H47LyQVbxU9eXY8yMtUrRuwEk9IUX/IqpxNhk5hngHPP3JjsP0hyyrYSPkZlbs3izd9kk3y09Wn/ElHidiEk0Q==" -$PRIVATE_SSH_KEY=@" +$global:PUBLIC_SSH_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAvnRN27LdPPQq2OH3GiFFGWX/SH5TCPVePLR21ngMFV8nAthXgYrFkRi/t+Wafe3ByTu2XYUDlXHKGIPIoAKo4gz5dIjUFfoac1ZuCDIbEiqPEjkk4tkfc2qr/BnIZsOYQi4Mbu+Z40VZEsAQU7eBinnZaHE1qGMHjS1xfrRtp2rdeO1EBz92FJ8dfnkUnohTXo3qPVSFGIPbh7UKEoKcyCosRO1P41iWD1rVsH1SLLXYAh2t49L7IPiplg09Dep6H47LyQVbxU9eXY8yMtUrRuwEk9IUX/IqpxNhk5hngHPP3JjsP0hyyrYSPkZlbs3izd9kk3y09Wn/ElHidiEk0Q==" +$global:PRIVATE_SSH_KEY = @" -----BEGIN RSA PRIVATE KEY----- MIIEoQIBAAKCAQEAvnRN27LdPPQq2OH3GiFFGWX/SH5TCPVePLR21ngMFV8nAthX gYrFkRi/t+Wafe3ByTu2XYUDlXHKGIPIoAKo4gz5dIjUFfoac1ZuCDIbEiqPEjkk @@ -51,21 +57,21 @@ TUwLP4n7pK4J2sCIs6fRD5kEYms4BnddXeRuI2fGZHGH70Ci/Q== Cleanup($global:CONTAINERNAME) -Describe "[$global:AGENT_IMAGE] image is present" { +Describe "[$global:IMAGE_NAME] image is present" { It 'builds image' { - $exitCode, $stdout, $stderr = Run-Program 'docker' "inspect $global:AGENT_IMAGE" + $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}`" --tag=${global:IMAGE_TAG} --file ./windows/${global:WINDOWSFLAVOR}/Dockerfile ." $exitCode | Should -Be 0 } } -Describe "[$global:AGENT_IMAGE] image has setup-sshd.ps1 in the correct location" { +Describe "[$global:IMAGE_NAME] image has setup-sshd.ps1 in the correct location" { BeforeAll { - docker run --detach --tty --name="$global:CONTAINERNAME" --publish "$global:AGENT_IMAGE" $global:CONTAINERSHELL + docker run --detach --tty --name "$global:CONTAINERNAME" --publish-all "$global:IMAGE_NAME" "$global:CONTAINERSHELL" 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}`"" + $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 | Should -Be 0 } @@ -74,9 +80,9 @@ Describe "[$global:AGENT_IMAGE] image has setup-sshd.ps1 in the correct location } } -Describe "[$global:AGENT_IMAGE] checking image metadata" { +Describe "[$global:IMAGE_NAME] checking image metadata" { It 'has correct volumes' { - $exitCode, $stdout, $stderr = Run-Program 'docker' "inspect -f '{{.Config.Volumes}}' $global:AGENT_IMAGE" + $exitCode, $stdout, $stderr = Run-Program 'docker' "inspect --format '{{.Config.Volumes}}' $global:IMAGE_NAME" $global:TESTS_DEBUG $exitCode | Should -Be 0 $stdout | Should -Match 'C:/Users/jenkins/AppData/Local/Temp' @@ -84,27 +90,33 @@ Describe "[$global:AGENT_IMAGE] checking image metadata" { } 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:AGENT_IMAGE" + $exitCode, $stdout, $stderr = Run-Program 'docker' "inspect --format=`"{{index .Config.Labels \`"org.opencontainers.image.source\`"}}`" $global:IMAGE_NAME" $global:TESTS_DEBUG $exitCode | Should -Be 0 $stdout.Trim() | Should -Match 'https://github.com/jenkinsci/docker-ssh-agent' } } -Describe "[$global:AGENT_IMAGE] image has correct version of java installed and in the PATH" { +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 "$global:AGENT_IMAGE" $global:CONTAINERSHELL + docker run --detach --tty --name="$global:CONTAINERNAME" --publish-all "$global:IMAGE_NAME" $global:CONTAINERSHELL 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 }`"" + $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 | Should -Be 0 - $exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"`$version = java -version 2>&1 ; Write-Host `$version`"" + $exitCode, $stdout, $stderr = Run-Program 'docker' "exec $global:CONTAINERNAME $global:CONTAINERSHELL -C `"`$version = java -version 2>&1 ; Write-Host `$version`"" $global:TESTS_DEBUG $r = [regex] "^openjdk version `"(?\d+)" $m = $r.Match($stdout) $m | Should -Not -Be $null - $m.Groups['major'].ToString() | Should -Be "$global:JDKMAJORVERSION" + $m.Groups['major'].ToString() | Should -Be "$global:JAVAMAJORVERSION" + } + + It 'has git-lfs (and thus git) installed' { + $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}" } AfterAll { @@ -112,14 +124,14 @@ Describe "[$global:AGENT_IMAGE] image has correct version of java installed and } } -Describe "[$global:AGENT_IMAGE] create agent container with pubkey as argument" { +Describe "[$global:IMAGE_NAME] create agent container with pubkey as argument" -Skip:($global:WINDOWSFLAVOR -eq 'windowsservercore') { BeforeAll { - docker run --detach --tty --name="$global:CONTAINERNAME" --publish "$global:AGENT_IMAGE" "$global:PUBLIC_SSH_KEY" + docker run --detach --tty --name="$global:CONTAINERNAME" --publish-all "$global:IMAGE_NAME" "$global:PUBLIC_SSH_KEY" Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue } It 'runs commands via ssh' { - $exitCode, $stdout, $stderr = Run-ThruSSH $global:CONTAINERNAME "$PRIVATE_SSH_KEY" "$global:CONTAINERSHELL -NoLogo -C `"Write-Host 'f00'`"" + $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" } @@ -129,14 +141,14 @@ Describe "[$global:AGENT_IMAGE] create agent container with pubkey as argument" } } -Describe "[$global:AGENT_IMAGE] create agent container with pubkey as envvar" { +Describe "[$global:IMAGE_NAME] create agent container with pubkey as envvar" -Skip:($global:WINDOWSFLAVOR -eq 'windowsservercore') { BeforeAll { - docker run --detach --tty --name="$global:CONTAINERNAME" --publish --env="JENKINS_AGENT_SSH_PUBKEY=$PUBLIC_SSH_KEY" "$global:AGENT_IMAGE" + docker run --detach --tty --name="$global:CONTAINERNAME" --publish-all --env="JENKINS_AGENT_SSH_PUBKEY=$global:PUBLIC_SSH_KEY" "$global:IMAGE_NAME" Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue } It 'runs commands via ssh' { - $exitCode, $stdout, $stderr = Run-ThruSSH $global:CONTAINERNAME "$PRIVATE_SSH_KEY" "$global:CONTAINERSHELL -NoLogo -C `"Write-Host 'f00'`"" + $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" } @@ -146,16 +158,17 @@ Describe "[$global:AGENT_IMAGE] create agent container with pubkey as envvar" { } } -$DOCKER_PLUGIN_DEFAULT_ARG="/usr/sbin/sshd -D -p 22" -Describe "[$global:AGENT_IMAGE] create agent container like docker-plugin with '$DOCKER_PLUGIN_DEFAULT_ARG' as argument" { + +$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" -Skip:($global:WINDOWSFLAVOR -eq 'windowsservercore') { BeforeAll { - [string]::IsNullOrWhiteSpace($DOCKER_PLUGIN_DEFAULT_ARG) | Should -BeFalse - docker run --detach --tty --name="$global:CONTAINERNAME" --publish --env="JENKINS_AGENT_SSH_PUBKEY=$PUBLIC_SSH_KEY" "$global:AGENT_IMAGE" "$DOCKER_PLUGIN_DEFAULT_ARG" + [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" Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue } It 'runs commands via ssh' { - $exitCode, $stdout, $stderr = Run-ThruSSH $global:CONTAINERNAME "$PRIVATE_SSH_KEY" "$global:CONTAINERSHELL -NoLogo -C `"Write-Host 'f00'`"" + $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" } @@ -165,7 +178,7 @@ Describe "[$global:AGENT_IMAGE] create agent container like docker-plugin with ' } } -Describe "[$global:AGENT_IMAGE] build args" { +Describe "[$global:IMAGE_NAME] build args" { BeforeAll { Push-Location -StackName 'agent' -Path "$PSScriptRoot/.." } @@ -173,12 +186,12 @@ Describe "[$global:AGENT_IMAGE] build args" { It 'uses build args correctly' { $TEST_USER="testuser" $TEST_JAW="C:/hamster" - $CUSTOM_IMAGE_NAME = "custom-${AGENT_IMAGE}" + $CUSTOM_IMAGE_NAME = "custom-${IMAGE_NAME}" - $exitCode, $stdout, $stderr = Run-Program 'docker' "build --build-arg `"user=$TEST_USER`" --build-arg `"JENKINS_AGENT_WORK=$TEST_JAW`" --tag=$CUSTOM_IMAGE_NAME --file=$global:IMAGE_FOLDER/Dockerfile ./" + $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 ." $exitCode | Should -Be 0 - $exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name=$global:CONTAINERNAME --publish $CUSTOM_IMAGE_NAME $global:CONTAINERSHELL" + $exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name=$global:CONTAINERNAME --publish-all $CUSTOM_IMAGE_NAME $global:CONTAINERSHELL" $exitCode | Should -Be 0 Is-ContainerRunning "$global:CONTAINERNAME" | Should -BeTrue diff --git a/tests/test_helpers.psm1 b/tests/test_helpers.psm1 index 5621d768..ee49ed6a 100644 --- a/tests/test_helpers.psm1 +++ b/tests/test_helpers.psm1 @@ -72,8 +72,14 @@ function Retry-Command { } function Cleanup($name='') { - docker kill "$name" 2>&1 | Out-Null - docker rm -fv "$name" 2>&1 | Out-Null + if([System.String]::IsNullOrWhiteSpace($name)) { + $name = Get-EnvOrDefault 'IMAGE_NAME' '' + } + + if(![System.String]::IsNullOrWhiteSpace($name)) { + docker kill "$name" 2>&1 | Out-Null + docker rm -fv "$name" 2>&1 | Out-Null + } } function CleanupNetwork($name) { @@ -83,7 +89,7 @@ function CleanupNetwork($name) { function Is-ContainerRunning($container) { Start-Sleep -Seconds 5 return Retry-Command -RetryCount 10 -Delay 2 -ScriptBlock { - $exitCode, $stdout, $stderr = Run-Program 'docker.exe' "inspect -f `"{{.State.Running}}`" $container" + $exitCode, $stdout, $stderr = Run-Program 'docker.exe' "inspect --format `"{{.State.Running}}`" $container" if(($exitCode -ne 0) -or (-not $stdout.Contains('true')) ) { throw('Exit code incorrect, or invalid value for running state') } @@ -92,7 +98,9 @@ function Is-ContainerRunning($container) { } function Run-Program($cmd, $params, $quiet=$true) { - #Write-Host "cmd = $cmd, params = $params" + if(-not $quiet) { + Write-Host "cmd & params: $cmd $params" + } $psi = New-Object System.Diagnostics.ProcessStartInfo $psi.CreateNoWindow = $true $psi.UseShellExecute = $false @@ -108,7 +116,10 @@ function Run-Program($cmd, $params, $quiet=$true) { $stderr = $proc.StandardError.ReadToEnd() $proc.WaitForExit() if(($proc.ExitCode -ne 0) -and (-not $quiet)) { - Write-Host "`n`nstdout:`n$stdout`n`nstderr:`n$stderr`n`n" + Write-Host "[err] stdout:`n$stdout" + Write-Host "[err] stderr:`n$stderr" + Write-Host "[err] cmd:`n$cmd" + Write-Host "[err] params:`n$param" } return $proc.ExitCode, $stdout, $stderr @@ -130,9 +141,9 @@ function Run-ThruSSH($container, $privateKeyVal, $cmd) { $TMP_PRIV_KEY_FILE = New-TemporaryFile Set-Content -Path $TMP_PRIV_KEY_FILE -Value "$privateKeyVal" - $exitCode, $stdout, $stderr = Run-Program (Join-Path $PSScriptRoot 'ssh.exe') "-i `"${TMP_PRIV_KEY_FILE}`" -o LogLevel=quiet -o UserKnownHostsFile=NUL -o StrictHostKeyChecking=no -l jenkins localhost -p $SSH_PORT $cmd" + $exitCode, $stdout, $stderr = Run-Program (Join-Path $PSScriptRoot 'ssh.exe') "-v -i `"${TMP_PRIV_KEY_FILE}`" -o LogLevel=quiet -o UserKnownHostsFile=NUL -o StrictHostKeyChecking=no -l jenkins localhost -p $SSH_PORT $cmd" Remove-Item -Force $TMP_PRIV_KEY_FILE return $exitCode, $stdout, $stderr } -} \ No newline at end of file +} diff --git a/updatecli/updatecli.d/git-lfs-windows.yml b/updatecli/updatecli.d/git-lfs-windows.yml index fd7be659..0cd52a7e 100644 --- a/updatecli/updatecli.d/git-lfs-windows.yml +++ b/updatecli/updatecli.d/git-lfs-windows.yml @@ -25,20 +25,20 @@ sources: kind: semver targets: - setGitLfsVersionWindowsNanoserver2019: - name: Update the `git-lfs` Windows version for Windows Nanoserver 2019 + setGitLfsVersionWindowsNanoserver: + name: Update the `git-lfs` Windows version for Windows Nanoserver kind: dockerfile spec: - file: windows/nanoserver-ltsc2019/Dockerfile + file: windows/nanoserver/Dockerfile instruction: keyword: ARG matcher: GIT_LFS_VERSION scmid: default - setGitLfsVersionWindowsServer2019: - name: Update the `git-lfs` Windows version for Windows Core Server 2019 + setGitLfsVersionWindowsServer: + name: Update the `git-lfs` Windows version for Windows Core Server kind: dockerfile spec: - file: windows/windowsservercore-ltsc2019/Dockerfile + file: windows/windowsservercore/Dockerfile instruction: keyword: ARG matcher: GIT_LFS_VERSION diff --git a/updatecli/updatecli.d/git-windows.yml b/updatecli/updatecli.d/git-windows.yml index d3b4ce2d..fb5564ef 100644 --- a/updatecli/updatecli.d/git-windows.yml +++ b/updatecli/updatecli.d/git-windows.yml @@ -30,56 +30,56 @@ sources: - trimprefix: "v" targets: - ############# JDK11 Nanoserver 18.09 - setGitVersionJDK11WindowsNanoserver1809: - name: Update the Git Windows version for JDK11 Windows Nanoserver 1809 + # Nanoserver + setGitVersionWindowsNanoserver: + name: Update the Git Windows version for Windows Nanoserver transformers: - findsubmatch: pattern: '(.*).windows\.(\d*)$' captureindex: 1 kind: dockerfile spec: - file: windows/nanoserver-ltsc2019/Dockerfile + file: windows/nanoserver/Dockerfile instruction: keyword: ARG matcher: GIT_VERSION scmid: default - setGitPackagePatchJDK11WindowsNanoserver1809: - name: Update the Git Package Windows patch for JDK11 Windows Nanoserver 1809 + setGitPackagePatchWindowsNanoserver: + name: Update the Git Package Windows patch for Windows Nanoserver transformers: - findsubmatch: pattern: '(.*).windows\.(\d*)$' captureindex: 2 kind: dockerfile spec: - file: windows/nanoserver-ltsc2019/Dockerfile + file: windows/nanoserver/Dockerfile instruction: keyword: ARG matcher: GIT_PATCH_VERSION scmid: default - ############# JDK11 Windows Server Core LTSC2019 - setGitVersionJDK11WindowsServer2019: - name: Update the Git Windows version for JDK11 Windows Server Core LTSC2019 + # Windows Server Core + setGitVersionWindowsServer: + name: Update the Git Windows version for Windows Server Core transformers: - findsubmatch: pattern: '(.*).windows\.(\d*)$' captureindex: 1 kind: dockerfile spec: - file: windows/windowsservercore-ltsc2019/Dockerfile + file: windows/windowsservercore/Dockerfile instruction: keyword: ARG matcher: GIT_VERSION scmid: default - setGitPackagePatchJDK11WindowsServer2019: - name: Update the Git Package Windows patch for Windows Server Core LTSC2019 + setGitPackagePatchWindowsServer: + name: Update the Git Package Windows patch for Windows Server Core transformers: - findsubmatch: pattern: '(.*).windows\.(\d*)$' captureindex: 2 kind: dockerfile spec: - file: windows/windowsservercore-ltsc2019/Dockerfile + file: windows/windowsservercore/Dockerfile instruction: keyword: ARG matcher: GIT_PATCH_VERSION diff --git a/updatecli/updatecli.d/jdk11.yaml b/updatecli/updatecli.d/jdk11.yaml index b3c56202..0ea1c945 100644 --- a/updatecli/updatecli.d/jdk11.yaml +++ b/updatecli/updatecli.d/jdk11.yaml @@ -64,26 +64,6 @@ conditions: image: eclipse-temurin targets: - setJDK11VersionNanoServer: - name: "Bump JDK11 default ARG version on Windows NanoServer Dockerfile" - kind: dockerfile - sourceid: jdk11LastVersion - spec: - file: windows/nanoserver-ltsc2019/Dockerfile - instruction: - keyword: ARG - matcher: JAVA_VERSION - scmid: default - setJDK11VersionServerCore: - name: "Bump JDK11 default ARG version on Windows Server Core Dockerfile" - kind: dockerfile - sourceid: jdk11LastVersion - spec: - file: windows/windowsservercore-ltsc2019/Dockerfile - instruction: - keyword: ARG - matcher: JAVA_VERSION - scmid: default setJDK11VersionDockerBake: name: "Bump JDK11 version for Linux images in the docker-bake.hcl file" kind: hcl @@ -92,6 +72,14 @@ targets: file: docker-bake.hcl path: variable.JAVA11_VERSION.default scmid: default + setJDK11VersionDockerCompose: + name: "Bump JDK11 version for Windows images in the build-windows.yaml file" + kind: yaml + sourceid: jdk11LastVersion + spec: + file: build-windows.yaml + key: $.services.jdk11.build.args.JAVA_VERSION + scmid: default actions: default: kind: github/pullrequest diff --git a/windows/nanoserver-ltsc2019/Dockerfile b/windows/nanoserver/Dockerfile similarity index 92% rename from windows/nanoserver-ltsc2019/Dockerfile rename to windows/nanoserver/Dockerfile index 513ce344..8e097d5f 100644 --- a/windows/nanoserver-ltsc2019/Dockerfile +++ b/windows/nanoserver/Dockerfile @@ -21,24 +21,34 @@ # 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. -ARG JAVA_VERSION=11.0.22_7 -FROM eclipse-temurin:"${JAVA_VERSION}"-jdk-windowsservercore-1809 AS jdk-core -FROM mcr.microsoft.com/powershell:nanoserver-1809 -SHELL ["pwsh.exe", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] -USER ContainerAdministrator +ARG JAVA_VERSION +ARG WINDOWS_VERSION_TAG +ARG TOOLS_WINDOWS_VERSION +FROM eclipse-temurin:"${JAVA_VERSION}"-jdk-windowsservercore-"${TOOLS_WINDOWS_VERSION}" AS jdk-core + +FROM mcr.microsoft.com/powershell:nanoserver-"${TOOLS_WINDOWS_VERSION}" AS pwsh-source + +FROM mcr.microsoft.com/windows/nanoserver:"${WINDOWS_VERSION_TAG}" + +ARG JAVA_HOME +ENV PSHOME="C:\Program Files\PowerShell" +ENV PATH="C:\Windows\system32;C:\Windows;${PSHOME};" # The nanoserver image is nice and small, but we need a couple of things to get SSH working COPY --from=jdk-core /windows/system32/netapi32.dll /windows/system32/netapi32.dll COPY --from=jdk-core /windows/system32/whoami.exe /windows/system32/whoami.exe - -ARG JAVA_HOME="C:\openjdk-11" COPY --from=jdk-core $JAVA_HOME $JAVA_HOME +COPY --from=pwsh-source $PSHOME $PSHOME + +SHELL ["pwsh.exe", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] +USER ContainerAdministrator # Backward compatibility with version <= 5.x: create a symlink to the "new" JAVA_HOME RUN $javaMajorVersion = $env:JAVA_HOME.Substring($env:JAVA_HOME.Length - 2); ` New-Item -Path "C:\jdk-${javaMajorVersion}" -ItemType SymbolicLink -Value "${env:JAVA_HOME}" +# Install git ARG GIT_VERSION=2.44.0 ARG GIT_PATCH_VERSION=1 RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` @@ -50,6 +60,12 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl Expand-Archive mingit.zip -DestinationPath c:\mingit ; ` Remove-Item mingit.zip -Force +# Add java & git to PATH +ENV ProgramFiles="C:\Program Files" +ENV WindowsPATH="C:\Windows\system32;C:\Windows" +ENV PATH="${WindowsPATH};${ProgramFiles}\PowerShell;${JAVA_HOME}\bin;C:\mingit\cmd" + +# Install git-lfs ARG GIT_LFS_VERSION=v3.1.4 RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` $url = $('https://github.com/git-lfs/git-lfs/releases/download/{0}/git-lfs-windows-amd64-{0}.zip' -f $env:GIT_LFS_VERSION) ; ` @@ -59,18 +75,13 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl Remove-Item GitLfs.zip -Force ; ` & C:\mingit\cmd\git.exe lfs install -ENV ProgramFiles="C:\Program Files" -ENV WindowsPATH="C:\Windows\system32;C:\Windows" -ENV PATH="${WindowsPATH};${ProgramFiles}\PowerShell;${JAVA_HOME}\bin;C:\mingit\cmd" - -ARG OPENSSH_VERSION=V8.6.0.0p1-Beta - ARG user=jenkins ARG JENKINS_AGENT_WORK="C:/Users/${user}/Work" ENV JENKINS_AGENT_USER ${user} ENV JENKINS_AGENT_WORK ${JENKINS_AGENT_WORK} -# setup SSH server +# Setup SSH server +ARG OPENSSH_VERSION=V8.6.0.0p1-Beta RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` $url = 'https://github.com/PowerShell/Win32-OpenSSH/releases/download/{0}/OpenSSH-Win64.zip' -f $env:OPENSSH_VERSION ; ` Write-Host "Retrieving $url..." ; ` @@ -101,7 +112,7 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl COPY CreateProfile.psm1 C:/ -# create user and user directory +# Create user and user directory RUN Import-Module -Force C:/CreateProfile.psm1 ; ` New-UserWithProfile -UserName $env:JENKINS_AGENT_USER -Description 'Jenkins Agent User' ; ` Remove-Item -Force C:/CreateProfile.psm1 @@ -113,8 +124,6 @@ COPY setup-sshd.ps1 C:/ProgramData/Jenkins/setup-sshd.ps1 EXPOSE 22 -ENTRYPOINT ["pwsh.exe", "-NoExit", "-Command", "& C:/ProgramData/Jenkins/setup-sshd.ps1"] - LABEL ` org.opencontainers.image.vendor="Jenkins project" ` org.opencontainers.image.title="Official Jenkins SSH Agent Docker image" ` @@ -122,3 +131,5 @@ LABEL ` org.opencontainers.image.url="https://www.jenkins.io/" ` org.opencontainers.image.source="https://github.com/jenkinsci/docker-ssh-agent" ` org.opencontainers.image.licenses="MIT" + +ENTRYPOINT ["pwsh.exe", "-NoExit", "-Command", "& C:/ProgramData/Jenkins/setup-sshd.ps1"] diff --git a/windows/windowsservercore-ltsc2019/Dockerfile b/windows/windowsservercore/Dockerfile similarity index 92% rename from windows/windowsservercore-ltsc2019/Dockerfile rename to windows/windowsservercore/Dockerfile index a99806bd..0d3c2051 100644 --- a/windows/windowsservercore-ltsc2019/Dockerfile +++ b/windows/windowsservercore/Dockerfile @@ -22,12 +22,19 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -ARG JAVA_VERSION=11.0.22_7 -FROM eclipse-temurin:"${JAVA_VERSION}"-jdk-windowsservercore-1809 +ARG JAVA_VERSION +ARG WINDOWS_VERSION_TAG +ARG TOOLS_WINDOWS_VERSION +FROM eclipse-temurin:"${JAVA_VERSION}"-jdk-windowsservercore-"${TOOLS_WINDOWS_VERSION}" AS jdk-core -SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] +FROM mcr.microsoft.com/windows/servercore:"${WINDOWS_VERSION_TAG}" -ARG OPENSSH_VERSION=V8.6.0.0p1-Beta +ARG JAVA_HOME +ENV JAVA_HOME=${JAVA_HOME} + +COPY --from=jdk-core $JAVA_HOME $JAVA_HOME + +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] ARG user=jenkins ARG JENKINS_AGENT_WORK="C:/Users/${user}/Work" @@ -36,7 +43,7 @@ ENV JENKINS_AGENT_WORK ${JENKINS_AGENT_WORK} USER ContainerAdministrator -# install git +# Install git ARG GIT_VERSION=2.44.0 ARG GIT_PATCH_VERSION=1 RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` @@ -48,6 +55,7 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl Expand-Archive mingit.zip -DestinationPath c:\mingit ; ` Remove-Item mingit.zip -Force +# Install git-lfs ARG GIT_LFS_VERSION=v3.1.4 RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` $url = $('https://github.com/git-lfs/git-lfs/releases/download/{0}/git-lfs-windows-amd64-{0}.zip' -f $env:GIT_LFS_VERSION) ; ` @@ -57,10 +65,11 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl Remove-Item GitLfs.zip -Force ; ` & C:\mingit\cmd\git.exe lfs install ; ` $CurrentPath = (Get-Itemproperty -path 'hklm:\system\currentcontrolset\control\session manager\environment' -Name Path).Path ; ` - $NewPath = $CurrentPath + ';C:\mingit\cmd' ; ` + $NewPath = $CurrentPath + ';{0}\bin;C:\mingit\cmd' -f $env:JAVA_HOME ; ` Set-ItemProperty -path 'hklm:\system\currentcontrolset\control\session manager\environment' -Name Path -Value $NewPath -# setup SSH server +# Setup SSH server +ARG OPENSSH_VERSION=V8.6.0.0p1-Beta RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` $url = 'https://github.com/PowerShell/Win32-OpenSSH/releases/download/{0}/OpenSSH-Win64.zip' -f $env:OPENSSH_VERSION ; ` Write-Host "Retrieving $url..." ; ` @@ -68,7 +77,7 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl Expand-Archive c:/openssh.zip 'C:/Program Files' ; ` Remove-Item C:/openssh.zip ; ` $env:PATH = '{0};{1}' -f $env:PATH,'C:\Program Files\OpenSSH-Win64' ; ` - & 'C:/Program Files/OpenSSH-Win64/Install-SSHd.ps1' ; ` + & 'C:/Program Files/OpenSSH-Win64/install-sshd.ps1' ; ` if(!(Test-Path 'C:\ProgramData\ssh')) { New-Item -Type Directory -Path 'C:\ProgramData\ssh' | Out-Null } ; ` Copy-Item 'C:\Program Files\OpenSSH-Win64\sshd_config_default' 'C:\ProgramData\ssh\sshd_config' ; ` $content = Get-Content -Path "C:\ProgramData\ssh\sshd_config" ; ` @@ -91,7 +100,7 @@ RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tl COPY CreateProfile.psm1 C:/ -# create user and user directory +# Create user and user directory RUN Import-Module -Force C:/CreateProfile.psm1 ; ` New-UserWithProfile -UserName $env:JENKINS_AGENT_USER -Description 'Jenkins Agent User' ; ` Remove-Item -Force C:/CreateProfile.psm1 @@ -103,8 +112,6 @@ COPY setup-sshd.ps1 C:/ProgramData/Jenkins/setup-sshd.ps1 EXPOSE 22 -ENTRYPOINT ["powershell.exe", "-NoExit", "-Command", "& C:/ProgramData/Jenkins/setup-sshd.ps1"] - LABEL ` org.opencontainers.image.vendor="Jenkins project" ` org.opencontainers.image.title="Official Jenkins SSH Agent Docker image" ` @@ -112,3 +119,5 @@ LABEL ` org.opencontainers.image.url="https://www.jenkins.io/" ` org.opencontainers.image.source="https://github.com/jenkinsci/docker-ssh-agent" ` org.opencontainers.image.licenses="MIT" + +ENTRYPOINT ["powershell.exe", "-NoExit", "-Command", "& C:/ProgramData/Jenkins/setup-sshd.ps1"]