From 47662de86bb5770a08df4eba9da8b8902fcdd686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Le=20Meur?= Date: Sat, 8 Jul 2023 20:37:44 +0200 Subject: [PATCH] hack/debug copy jenkins-agent.ps1 in context --- Jenkinsfile | 147 +++++------ build-windows.yaml | 8 - build.ps1 | 5 +- make.ps1 | 237 ------------------ tests/inboundAgent.Tests.ps1 | 14 +- tests/test_helpers.psm1 | 2 +- updatecli/updatecli.d/docker-agent.yaml | 204 +++++++++++++++ windows/nanoserver-1809/jenkins-agent.ps1 | 156 ++++++++++++ .../jenkins-agent.ps1 | 156 ++++++++++++ 9 files changed, 584 insertions(+), 345 deletions(-) delete mode 100644 make.ps1 create mode 100644 updatecli/updatecli.d/docker-agent.yaml create mode 100644 windows/nanoserver-1809/jenkins-agent.ps1 create mode 100644 windows/windowsservercore-ltsc2019/jenkins-agent.ps1 diff --git a/Jenkinsfile b/Jenkinsfile index 880ab5aa..92e0387b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -26,24 +26,6 @@ pipeline { not { buildingTag() } } steps { - // script { - // def parallelBuilds = [:] - // def images = ['jdk11-windowsservercore-ltsc2019', 'jdk11-nanoserver-1809', 'jdk17-windowsservercore-ltsc2019', 'jdk17-nanoserver-1809'] - // for (unboundImage in images) { - // def image = unboundImage // Bind variable before the closure - // // Prepare a map of the steps to run in parallel - // parallelBuilds[image] = { - // // Allocate a node for each image to avoid filling disk - // node('docker-windows') { - // checkout scm - // powershell '& ./make.ps1 -Build ' + image + ' test' - // junit(allowEmptyResults: true, keepLongStdio: true, testResults: 'target/**/junit-results.xml') - // } - // } - // } - // // Peform the parallel execution - // parallel parallelBuilds - // } powershell '& ./build.ps1 test' } post { @@ -59,23 +41,6 @@ pipeline { } steps { script { - // // This function is defined in the jenkins-infra/pipeline-library - // infra.withDockerCredentials { - // powershell '& ./make.ps1 -PushVersions -VersionTag $env:TAG_NAME publish' - // } - - // // Directly from docker-agent - // def tagItems = env.TAG_NAME.split('-') - // if(tagItems.length == 2) { - // def dockerAgentVersion = tagItems[0] - // def buildNumber = tagItems[1] - // // This function is defined in the jenkins-infra/pipeline-library - // infra.withDockerCredentials { - // powershell "& ./build.ps1 -PushVersions -DockerAgentVersion $dockerAgentVersion -BuildNumber $buildNumber -DisableEnvProps publish" - // } - // } - // debug - echo "=== env.TAG_NAME: ${env:TAG_NAME}" infra.withDockerCredentials { // TODO: check if this function has the same beahvior in build.ps1 vs make.ps1 powershell '& ./build.ps1 -PushVersions -VersionTag $env:TAG_NAME publish' @@ -85,62 +50,62 @@ pipeline { } } } - // stage('Linux') { - // agent { - // label "docker&&linux" - // } - // options { - // timeout(time: 30, unit: 'MINUTES') - // } - // environment { - // JENKINS_REPO = "${infra.isTrusted() ? 'jenkins' : 'jenkins4eval'}/inbound-agent" - // } - // stages { - // stage('Prepare Docker') { - // steps { - // sh ''' - // docker buildx create --use - // docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - // ''' - // } - // } - // 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 { - // 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' - // } - // post { - // always { - // junit(allowEmptyResults: true, keepLongStdio: true, testResults: 'target/*.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 { - // sh ''' - // export IMAGE_TAG="${TAG_NAME}" - // export ON_TAG=true - // docker buildx bake --push --file docker-bake.hcl linux - // ''' - // } - // } - // } - // } - // } - // } + stage('Linux') { + agent { + label "docker&&linux" + } + options { + timeout(time: 30, unit: 'MINUTES') + } + environment { + JENKINS_REPO = "${infra.isTrusted() ? 'jenkins' : 'jenkins4eval'}/inbound-agent" + } + stages { + stage('Prepare Docker') { + steps { + sh ''' + docker buildx create --use + docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + ''' + } + } + 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 { + 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' + } + post { + always { + junit(allowEmptyResults: true, keepLongStdio: true, testResults: 'target/*.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 { + sh ''' + export IMAGE_TAG="${TAG_NAME}" + export ON_TAG=true + docker buildx bake --push --file docker-bake.hcl linux + ''' + } + } + } + } + } + } } } } diff --git a/build-windows.yaml b/build-windows.yaml index af06a57f..2470e384 100644 --- a/build-windows.yaml +++ b/build-windows.yaml @@ -4,30 +4,22 @@ services: build: context: ./windows/nanoserver-1809/ args: - JAVA_HOME: "C:/openjdk-11" - JAVA_VERSION: "11.0.19_7" VERSION: ${DOCKER_AGENT_VERSION} jdk17-nanoserver-1809: image: jdk17-nanoserver-1809 build: context: ./windows/nanoserver-1809/ args: - JAVA_HOME: "C:/openjdk-17" - JAVA_VERSION: "17.0.7_7" VERSION: ${DOCKER_AGENT_VERSION} jdk11-windowsservercore-ltsc2019: image: jdk11-windowsservercore-ltsc2019 build: context: ./windows/windowsservercore-ltsc2019/ args: - JAVA_HOME: "C:/openjdk-11" - JAVA_VERSION: "11.0.19_7" VERSION: ${DOCKER_AGENT_VERSION} jdk17-windowsservercore-ltsc2019: image: jdk17-windowsservercore-ltsc2019 build: context: ./windows/windowsservercore-ltsc2019/ args: - JAVA_HOME: "C:/openjdk-17" - JAVA_VERSION: "17.0.7_7" VERSION: ${DOCKER_AGENT_VERSION} diff --git a/build.ps1 b/build.ps1 index 4a46c93f..86f8102a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -120,8 +120,11 @@ function Test-Image { $env:AGENT_IMAGE = $ImageName $env:IMAGE_FOLDER = Invoke-Expression "$baseDockerCmd config" 2>$null | yq -r ".services.${ImageName}.build.context" - $env:VERSION = "$DockerAgentVersion-$BuildNumber" + # TODO: review build number removal (?) + # $env:VERSION = "$DockerAgentVersion-$BuildNumber" + $env:VERSION = $DockerAgentVersion + Write-Host "= TEST: image folder ${env:IMAGE_FOLDER}, version ${env:VERSION}" if(Test-Path ".\target\$ImageName") { Remove-Item -Recurse -Force ".\target\$ImageName" diff --git a/make.ps1 b/make.ps1 deleted file mode 100644 index ca021c60..00000000 --- a/make.ps1 +++ /dev/null @@ -1,237 +0,0 @@ -[CmdletBinding()] -Param( - [Parameter(Position=1)] - [String] $Target = "build", - [String] $Build = '', - [String] $VersionTag = '3071.v7e9b_0dc08466-1', - [String] $DockerAgentVersion = '3131.vf2b_b_798b_ce99-2', - [switch] $PushVersions = $false -) - -$Repository = 'inbound-agent' -$Organization = 'jenkins' - -if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_REPO)) { - $Repository = $env:DOCKERHUB_REPO -} - -if(![String]::IsNullOrWhiteSpace($env:DOCKERHUB_ORGANISATION)) { - $Organization = $env:DOCKERHUB_ORGANISATION -} - -# this is the jdk version that will be used for the 'bare tag' images, e.g., jdk8-windowsservercore-1809 -> windowsserver-1809 -$defaultBuild = '11' -$builds = @{} - -# TODO: use docker-compose / tooling like with docker-agent -$images = 'jdk11-nanoserver-1809', 'jdk11-windowsservercore-ltsc2019', 'jdk17-nanoserver-1809', 'jdk17-windowsservercore-ltsc2019' -Foreach($image in $images) { - $items = $image.Split('-') - # Remove the 'jdk' prefix (3 first characters) - $jdkMajorVersion = $items[0].Remove(0,3) - $windowsFlavor = $items[1] - $windowsVersion = $items[2] - $baseImage = "${windowsFlavor}-${windowsVersion}" - $dir = "windows/${baseImage}" - - Write-Host "New windows image to build: jenkins/jenkins:${baseImage} with JDK ${jdkMajorVersion} in ${dir}" - - $tags = @( $image ) - if($jdkMajorVersion -eq $defaultBuild) { - $tags += $baseImage - } - - $builds[$image] = @{ - 'Folder' = $dir; - 'Tags' = $tags; - 'JdkMajorVersion' = $jdkMajorVersion; - } -} - -function Build-Image { - param ( - [String] $Build, - [String] $ImageName, - [String] $DockerAgentVersion, - [String] $JdkMajorVersion, - [String] $Folder - ) - - Write-Host "Building $Build with name $imageName" - docker build --build-arg "VERSION=${DockerAgentVersion}" --build-arg "JAVA_MAJOR_VERSION=${JdkMajorVersion}" --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}" -DockerAgentVersion $DockerAgentVersion -JdkMajorVersion $builds[$Build]['JdkMajorVersion'] -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}" -DockerAgentVersion $DockerAgentVersion -JdkMajorVersion $builds[$Build]['JdkMajorVersion'] -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}" -DockerAgentVersion $DockerAgentVersion -JdkMajorVersion $builds[$b]['JdkMajorVersion'] -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}" -DockerAgentVersion $DockerAgentVersion -JdkMajorVersion $builds[$b]['JdkMajorVersion'] -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!" -} - -if($Target -eq "test") { - # Only fail the run afterwards in case of any test failures - $testFailed = $false - - $mod = Get-InstalledModule -Name Pester -MinimumVersion 5.3.0 -MaximumVersion 5.3.3 -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 5.3.3 - } - - Import-Module Pester - $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 - - if(![System.String]::IsNullOrWhiteSpace($Build) -and $builds.ContainsKey($Build)) { - $folder = $builds[$Build]['Folder'] - $env:AGENT_IMAGE = $Build - $env:FOLDER = $folder - $env:JAVA_MAJOR_VERSION = $builds[$Build]['JdkMajorVersion'] - $env:VERSION = $DockerAgentVersion - - if(Test-Path ".\target\$folder") { - Remove-Item -Recurse -Force ".\target\$folder" - } - New-Item -Path ".\target\$folder" -Type Directory | Out-Null - $configuration.TestResult.OutputPath = ".\target\$folder\junit-results.xml" - $TestResults = Invoke-Pester -Configuration $configuration - if ($TestResults.FailedCount -gt 0) { - Write-Host "There were $($TestResults.FailedCount) failed tests in $Build" - $testFailed = $true - } else { - Write-Host "There were $($TestResults.PassedCount) passed tests out of $($TestResults.TotalCount) in $Build" - } - Remove-Item env:\AGENT_IMAGE - Remove-Item env:\FOLDER - Remove-Item env:\JAVA_MAJOR_VERSION - Remove-Item env:\VERSION - } else { - foreach($b in $builds.Keys) { - $folder = $builds[$b]['Folder'] - $env:AGENT_IMAGE = $b - $env:FOLDER = $folder - $env:JAVA_MAJOR_VERSION = $builds[$Build]['JdkMajorVersion'] - $env:VERSION = $DockerAgentVersion - if(Test-Path ".\target\$folder") { - Remove-Item -Recurse -Force ".\target\$folder" - } - New-Item -Path ".\target\$folder" -Type Directory | Out-Null - $configuration.TestResult.OutputPath = ".\target\$folder\junit-results.xml" - $TestResults = Invoke-Pester -Configuration $configuration - if ($TestResults.FailedCount -gt 0) { - Write-Host "There were $($TestResults.FailedCount) failed tests in $Build" - $testFailed = $true - } else { - Write-Host "There were $($TestResults.PassedCount) passed tests out of $($TestResults.TotalCount) in $Build" - } - Remove-Item env:\AGENT_IMAGE - Remove-Item env:\FOLDER - Remove-Item env:\JAVA_MAJOR_VERSION - Remove-Item env:\VERSION - } - } - - # Fail if any test failures - if($testFailed -ne $false) { - Write-Error "Test stage failed!" - exit 1 - } else { - Write-Host "Test stage passed!" - } -} - -$exitCodes = 0 -if($Target -eq "publish") { - if(![System.String]::IsNullOrWhiteSpace($Build) -and $builds.ContainsKey($Build)) { - foreach($tag in $Builds[$Build]['Tags']) { - Write-Host "Publishing $Build => tag=$tag" - $cmd = "docker push {0}/{1}:{2}" -f $Organization, $Repository, $tag - Invoke-Expression $cmd - $exitCodes += $lastExitCode - - if($PushVersions) { - $buildTag = "$VersionTag-$tag" - if($tag -eq 'latest') { - $buildTag = "$VersionTag" - } - Write-Host "Publishing $Build => tag=$buildTag" - $cmd = "docker push {0}/{1}:{2}" -f $Organization, $Repository, $buildTag - Invoke-Expression $cmd - $exitCodes += $lastExitCode - } - } - } else { - foreach($b in $builds.Keys) { - foreach($tag in $Builds[$b]['Tags']) { - Write-Host "Publishing $b => tag=$tag" - $cmd = "docker push {0}/{1}:{2}" -f $Organization, $Repository, $tag - Invoke-Expression $cmd - $exitCodes += $lastExitCode - - if($PushVersions) { - $buildTag = "$VersionTag-$tag" - if($tag -eq 'latest') { - $buildTag = "$VersionTag" - } - Write-Host "Publishing $Build => tag=$buildTag" - $cmd = "docker push {0}/{1}:{2}" -f $Organization, $Repository, $buildTag - Invoke-Expression $cmd - $exitCodes += $lastExitCode - } - } - } - } - - if($exitCodes -ne 0) { - Write-Error "Publish stage failed!" - } else { - Write-Host "Publish stage passed!" - } -} - -exit $exitCodes diff --git a/tests/inboundAgent.Tests.ps1 b/tests/inboundAgent.Tests.ps1 index 1c00e24b..839af7a5 100644 --- a/tests/inboundAgent.Tests.ps1 +++ b/tests/inboundAgent.Tests.ps1 @@ -1,19 +1,19 @@ Import-Module -DisableNameChecking -Force $PSScriptRoot/test_helpers.psm1 $global:AGENT_IMAGE = Get-EnvOrDefault 'AGENT_IMAGE' '' -$global:FOLDER = Get-EnvOrDefault 'FOLDER' '' -$global:JAVA_MAJOR_VERSION = Get-EnvOrDefault 'JAVA_MAJOR_VERSION' '' +$global:IMAGE_FOLDER = Get-EnvOrDefault 'IMAGE_FOLDER' '' $global:VERSION = Get-EnvOrDefault 'VERSION' '' # TODO: make this name unique for concurency $global:CONTAINERNAME = 'pester-jenkins-inbound-agent-{0}' -f $global:AGENT_IMAGE -$REAL_FOLDER=Resolve-Path -Path "$PSScriptRoot/../${global:FOLDER}" +# TODO: delete as not used? +# $REAL_IMAGE_FOLDER=Resolve-Path -Path "$PSScriptRoot/../${global:IMAGE_FOLDER}" $items = $global:AGENT_IMAGE.Split("-") # Remove the 'jdk' prefix (3 first characters) -$global:JDKMAJORVERSION = $items[0].Remove(0,3) +$global:JAVA_MAJOR_VERSION = $items[0].Remove(0,3) $global:WINDOWSFLAVOR = $items[1] $global:WINDOWSVERSION = $items[2] @@ -31,7 +31,7 @@ BuildNcatImage Describe "[$global:AGENT_IMAGE] build image" { It 'builds image' { - $exitCode, $stdout, $stderr = Run-Program 'docker' "build --build-arg VERSION=${global:VERSION} --build-arg JAVA_MAJOR_VERSION=${global:JAVA_MAJOR_VERSION} --tag=${global:AGENT_IMAGE} --file $global:FOLDER/Dockerfile ./" + $exitCode, $stdout, $stderr = Run-Program 'docker' "build --build-arg VERSION=${global:VERSION} --build-arg JAVA_MAJOR_VERSION=${global:JAVA_MAJOR_VERSION} --tag=${global:AGENT_IMAGE} --file $global:IMAGE_FOLDER/Dockerfile ./" $exitCode | Should -Be 0 } } @@ -122,7 +122,7 @@ Describe "[$global:AGENT_IMAGE] custom build args" { } It 'builds image with arguments' { - $exitCode, $stdout, $stderr = Run-Program 'docker' "build --build-arg VERSION=${ARG_TEST_VERSION} --build-arg JAVA_MAJOR_VERSION=${global:JAVA_MAJOR_VERSION} --tag=${customImageName} --file=${global:FOLDER}/Dockerfile ./" + $exitCode, $stdout, $stderr = Run-Program 'docker' "build --build-arg VERSION=${ARG_TEST_VERSION} --build-arg JAVA_MAJOR_VERSION=${global:JAVA_MAJOR_VERSION} --tag=${customImageName} --file=${global:IMAGE_FOLDER}/Dockerfile ./" $exitCode | Should -Be 0 $exitCode, $stdout, $stderr = Run-Program 'docker' "run --detach --tty --name $global:CONTAINERNAME $customImageName -Cmd $global:CONTAINERSHELL" @@ -165,7 +165,7 @@ Describe "[$global:AGENT_IMAGE] passing JVM options (slow test)" { Is-ContainerRunning $global:CONTAINERNAME | Should -BeTrue $exitCode, $stdout, $stderr = Run-Program 'docker' "logs $global:CONTAINERNAME" $exitCode | Should -Be 0 - $stdout | Should -Match "OpenJDK Runtime Environment Temurin-${global:JDKMAJORVERSION}" + $stdout | Should -Match "OpenJDK Runtime Environment Temurin-${global:JAVA_MAJOR_VERSION}" } AfterAll { diff --git a/tests/test_helpers.psm1 b/tests/test_helpers.psm1 index 69395da0..bbc82156 100644 --- a/tests/test_helpers.psm1 +++ b/tests/test_helpers.psm1 @@ -114,7 +114,7 @@ function Run-Program($cmd, $params, $quiet=$false, $debug=$false) { $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 "`n`nstdout:`n$stdout`n`nstderr:`n$stderr`n`n`cmd:`n$cmd`n`nparams:`n$params`n`n" } return $proc.ExitCode, $stdout, $stderr diff --git a/updatecli/updatecli.d/docker-agent.yaml b/updatecli/updatecli.d/docker-agent.yaml new file mode 100644 index 00000000..d40d8668 --- /dev/null +++ b/updatecli/updatecli.d/docker-agent.yaml @@ -0,0 +1,204 @@ +--- +name: Bump the parent image `jenkins/agent` version + +scms: + default: + kind: github + spec: + user: "{{ .github.user }}" + email: "{{ .github.email }}" + owner: "{{ .github.owner }}" + repository: "{{ .github.repository }}" + token: "{{ requiredEnv .github.token }}" + username: "{{ .github.username }}" + branch: "{{ .github.branch }}" + +sources: + lastVersion: + kind: githubrelease + name: Get the latest version of the parent image `jenkins/agent` + spec: + owner: jenkinsci + repository: docker-agent + token: "{{ requiredEnv .github.token }}" + username: "{{ .github.username }}" + versionfilter: + kind: latest + +conditions: + checkJdk11AlpineDockerImage: + kind: dockerimage + name: Check if the container image "jenkins/agent:-alpine-jdk11" for linux/amd64 is available + disablesourceinput: true + spec: + architecture: amd64 + image: jenkins/agent + tag: '{{source "lastVersion" }}-alpine-jdk11' + checkJdk17AlpineDockerImage: + kind: dockerimage + name: Check if the container image "jenkins/agent:-alpine-jdk17" for linux/amd64 is available + disablesourceinput: true + spec: + architecture: amd64 + image: jenkins/agent + tag: '{{source "lastVersion" }}-alpine-jdk17' + checkJdk11DebianDockerImages: + kind: dockerimage + name: Check if the container image "jenkins/agent:-jdk11" for linux/amd64 is available + disablesourceinput: true + spec: + architectures: + - amd64 + - arm64 + - arm/v7 + - s390x + - ppc64le + image: jenkins/agent + tag: '{{source "lastVersion" }}-jdk11' + checkJdk17DebianDockerImages: + kind: dockerimage + name: Check if the container image "jenkins/agent:-jdk17" for linux/amd64 is available + disablesourceinput: true + spec: + architectures: + - amd64 + - arm64 + - arm/v7 + image: jenkins/agent + tag: '{{source "lastVersion" }}-jdk17' + checkJdk11WindowsNanoserver1809DockerImage: + kind: dockerimage + name: Check if the container image "jenkins/agent:-jdk11-nanoserver-1809" for windows/amd64 is available + disablesourceinput: true + spec: + architecture: amd64 + image: jenkins/agent + tag: '{{source "lastVersion" }}-jdk11-nanoserver-1809' + checkJdk17WindowsNanoserver1809DockerImage: + kind: dockerimage + name: Check if the container image "jenkins/agent:-jdk17-nanoserver-1809" for windows/amd64 is available + disablesourceinput: true + spec: + architecture: amd64 + image: jenkins/agent + tag: '{{source "lastVersion" }}-jdk17-nanoserver-1809' + checkJdk11WindowsServer2019DockerImage: + kind: dockerimage + name: Check if the container image "jenkins/agent:-jdk11-windowsservercore-ltsc2019" for windows/amd64 is available + disablesourceinput: true + spec: + architecture: amd64 + image: jenkins/agent + tag: '{{source "lastVersion" }}-jdk11-windowsservercore-ltsc2019' + checkJdk17WindowsServer2019DockerImage: + kind: dockerimage + name: Check if the container image "jenkins/agent:-jdk17-windowsservercore-ltsc2019" for windows/amd64 is available + disablesourceinput: true + spec: + architecture: amd64 + image: jenkins/agent + tag: '{{source "lastVersion" }}-jdk17-windowsservercore-ltsc2019' + +targets: + setJdk11AlpineDockerImage: + name: Bump the parent image `jenkins/agent` version on JDK11 Alpine + kind: dockerfile + spec: + file: alpine/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setJdk11DebianDockerImage: + name: Bump the parent image `jenkins/agent` version on JDK11 Debian + kind: dockerfile + spec: + file: debian/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setJdk11WindowsNanoserver1809DockerImage: + name: Bump the parent image `jenkins/agent` version on JDK11 Windows Nanoserver 1809 + kind: dockerfile + spec: + file: windows/nanoserver-1809/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setJdk11WindowsServer2019DockerImage: + name: Bump the parent image `jenkins/agent` version on JDK11 Windows Server 2019 + kind: dockerfile + spec: + file: windows/windowsservercore-ltsc2019/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setJdk17AlpineDockerImage: + name: Bump the parent image `jenkins/agent` version on JDK17 Alpine + kind: dockerfile + spec: + file: alpine/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setJdk17DebianDockerImage: + name: Bump the parent image `jenkins/agent` version on JDK17 Debian + kind: dockerfile + spec: + file: debian/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setJdk17WindowsNanoserver1809DockerImage: + name: Bump the parent image `jenkins/agent` version on JDK17 Windows Nanoserver 1809 + kind: dockerfile + spec: + file: windows/nanoserver-1809/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setJdk17WindowsServer2019DockerImage: + name: Bump the parent image `jenkins/agent` version on JDK17 Windows Server 2019 + kind: dockerfile + spec: + file: windows/windowsservercore-ltsc2019/Dockerfile + instruction: + keyword: ARG + matcher: version + scmid: default + setDockerBakeDefaultParentImage: + name: Bump the parent image `jenkins/agent` version on the docker-bake.hcl file + kind: file + spec: + file: docker-bake.hcl + matchpattern: >- + variable(.*)"DOCKER_AGENT_VERSION"(.*){(.*)(\r\n|\r|\n)(.*)default(.*)=(.*) + replacepattern: >- + variable${1}"DOCKER_AGENT_VERSION"${2}{${3}${4}${5}default${6}= "{{ source "lastVersion" }}" + scmid: default + setWindowsMakePwshParentImage: + name: Bump the parent image `jenkins/agent` version on the windows make.ps1 file + kind: file + spec: + file: make.ps1 + matchpattern: >- + \$DockerAgentVersion(.*)=(.*), + replacepattern: >- + $$DockerAgentVersion${1}= '{{ source "lastVersion" }}', + scmid: default + +actions: + default: + kind: github/pullrequest + scmid: default + title: Bump the parent image `jenkins/agent` version to {{ source "lastVersion" }} + spec: + labels: + - dependencies + - jenkins/agent diff --git a/windows/nanoserver-1809/jenkins-agent.ps1 b/windows/nanoserver-1809/jenkins-agent.ps1 new file mode 100644 index 00000000..c37ccb37 --- /dev/null +++ b/windows/nanoserver-1809/jenkins-agent.ps1 @@ -0,0 +1,156 @@ +# The MIT License +# +# Copyright (c) 2019-2020, Alex Earl +# +# 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. + +[CmdletBinding()] +Param( + $Cmd = '', # this must be specified explicitly + $Url = $( if([System.String]::IsNullOrWhiteSpace($Cmd) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_URL) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_DIRECT_CONNECTION)) { throw ("Url is required") } else { '' } ), + [Parameter(Position=0)]$Secret = $( if([System.String]::IsNullOrWhiteSpace($Cmd) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_SECRET)) { throw ("Secret is required") } else { '' } ), + [Parameter(Position=1)]$Name = $( if([System.String]::IsNullOrWhiteSpace($Cmd) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_AGENT_NAME)) { throw ("Name is required") } else { '' } ), + $Tunnel = '', + $WorkDir = '', + [switch] $WebSocket = $false, + $DirectConnection = '', + $InstanceIdentity = '', + $Protocols = '', + $JenkinsJavaBin = '', + $JavaHome = $env:JAVA_HOME, + $JenkinsJavaOpts = '' +) + +# Usage jenkins-agent.ps1 [options] -Url http://jenkins -Secret [SECRET] -Name [AGENT_NAME] +# Optional environment variables : +# * JENKINS_JAVA_BIN : Java executable to use instead of the default in PATH or obtained from JAVA_HOME +# * JENKINS_JAVA_OPTS : Java Options to use for the remoting process, otherwise obtained from JAVA_OPTS +# * JENKINS_TUNNEL : HOST:PORT for a tunnel to route TCP traffic to jenkins host, when jenkins can't be directly accessed over network +# * JENKINS_URL : alternate jenkins URL +# * JENKINS_SECRET : agent secret, if not set as an argument +# * JENKINS_AGENT_NAME : agent name, if not set as an argument +# * JENKINS_AGENT_WORKDIR : agent work directory, if not set by optional parameter -workDir +# * JENKINS_WEB_SOCKET : true if the connection should be made via WebSocket rather than TCP +# * JENKINS_DIRECT_CONNECTION: Connect directly to this TCP agent port, skipping the HTTP(S) connection parameter download. +# Value: ":" +# * JENKINS_INSTANCE_IDENTITY: The base64 encoded InstanceIdentity byte array of the Jenkins master. When this is set, +# the agent skips connecting to an HTTP(S) port for connection info. +# * JENKINS_PROTOCOLS: Specify the remoting protocols to attempt when instanceIdentity is provided. + +if(![System.String]::IsNullOrWhiteSpace($Cmd)) { + Invoke-Expression "$Cmd" +} else { + + # this maps the variable name from the CmdletBinding to environment variables + $ParamMap = @{ + 'JenkinsJavaBin' = 'JENKINS_JAVA_BIN'; + 'JenkinsJavaOpts' = 'JENKINS_JAVA_OPTS'; + 'Tunnel' = 'JENKINS_TUNNEL'; + 'Url' = 'JENKINS_URL'; + 'Secret' = 'JENKINS_SECRET'; + 'Name' = 'JENKINS_AGENT_NAME'; + 'WorkDir' = 'JENKINS_AGENT_WORKDIR'; + 'WebSocket' = 'JENKINS_WEB_SOCKET'; + 'DirectConnection' = 'JENKINS_DIRECT_CONNECTION'; + 'InstanceIdentity' = 'JENKINS_INSTANCE_IDENTITY'; + 'Protocols' = 'JENKINS_PROTOCOLS'; + } + + # this does some trickery to update the variable from the CmdletBinding + # with the value of the + foreach($p in $ParamMap.Keys) { + $var = Get-Variable $p + $envVar = Get-ChildItem -Path "env:$($ParamMap[$p])" -ErrorAction 'SilentlyContinue' + + if(($null -ne $envVar) -and ((($envVar.Value -is [System.String]) -and (![System.String]::IsNullOrWhiteSpace($envVar.Value))) -or ($null -ne $envVar.Value))) { + if(($null -ne $var) -and ((($var.Value -is [System.String]) -and (![System.String]::IsNullOrWhiteSpace($var.Value))))) { + Write-Warning "${p} is defined twice; in command-line arguments (-${p}) and in the environment variable ${envVar.Name}" + } + if($var.Value -is [System.String]) { + $var.Value = $envVar.Value + } elseif($var.Value -is [System.Management.Automation.SwitchParameter]) { + $var.Value = [bool]$envVar.Value + } + } + if($var.Value -is [System.String]) { + $var.Value = $var.Value.Trim() + } + } + + $AgentArguments = @() + + if(![System.String]::IsNullOrWhiteSpace($JenkinsJavaOpts)) { + # this magic will basically process the $JenkinsJavaOpts like a command line + # and split into an array, the command line processing follows the PowerShell + # commnd line processing, which means for things like -Dsomething.something=something, + # you need to quote the string like this: "-Dsomething.something=something" or else it + # will get parsed incorrectly. + $AgentArguments += Invoke-Expression "echo $JenkinsJavaOpts" + } + + $AgentArguments += @("-cp", "C:/ProgramData/Jenkins/agent.jar", "hudson.remoting.jnlp.Main", "-headless") + + if(![System.String]::IsNullOrWhiteSpace($Tunnel)) { + $AgentArguments += @("-tunnel", "`"$Tunnel`"") + } + + if(![System.String]::IsNullOrWhiteSpace($WorkDir)) { + $AgentArguments += @("-workDir", "`"$WorkDir`"") + } else { + $AgentArguments += @("-workDir", "`"C:/Users/jenkins/Work`"") + } + + if($WebSocket) { + $AgentArguments += @("-webSocket") + } + + if(![System.String]::IsNullOrWhiteSpace($Url)) { + $AgentArguments += @("-url", "`"$Url`"") + } + + if(![System.String]::IsNullOrWhiteSpace($DirectConnection)) { + $AgentArguments += @('-direct', $DirectConnection) + } + + if(![System.String]::IsNullOrWhiteSpace($InstanceIdentity)) { + $AgentArguments += @('-instanceIdentity', $InstanceIdentity) + } + + if(![System.String]::IsNullOrWhiteSpace($Protocols)) { + $AgentArguments += @('-protocols', $Protocols) + } + + # these need to be the last things added since they are positional + # parameters to agent.jar + $AgentArguments += @($Secret, $Name) + + if(![System.String]::IsNullOrWhiteSpace($JenkinsJavaBin)) { + $JAVA_BIN = $JenkinsJavaBin + } else { + # if java home is defined, use it + $JAVA_BIN = "java.exe" + if (![System.String]::IsNullOrWhiteSpace($JavaHome)) { + $JAVA_BIN = "$JavaHome/bin/java.exe" + } + } + + #TODO: Handle the case when the command-line and Environment variable contain different values. + #It is fine it blows up for now since it should lead to an error anyway. + Start-Process -FilePath $JAVA_BIN -Wait -NoNewWindow -ArgumentList $AgentArguments +} diff --git a/windows/windowsservercore-ltsc2019/jenkins-agent.ps1 b/windows/windowsservercore-ltsc2019/jenkins-agent.ps1 new file mode 100644 index 00000000..c37ccb37 --- /dev/null +++ b/windows/windowsservercore-ltsc2019/jenkins-agent.ps1 @@ -0,0 +1,156 @@ +# The MIT License +# +# Copyright (c) 2019-2020, Alex Earl +# +# 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. + +[CmdletBinding()] +Param( + $Cmd = '', # this must be specified explicitly + $Url = $( if([System.String]::IsNullOrWhiteSpace($Cmd) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_URL) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_DIRECT_CONNECTION)) { throw ("Url is required") } else { '' } ), + [Parameter(Position=0)]$Secret = $( if([System.String]::IsNullOrWhiteSpace($Cmd) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_SECRET)) { throw ("Secret is required") } else { '' } ), + [Parameter(Position=1)]$Name = $( if([System.String]::IsNullOrWhiteSpace($Cmd) -and [System.String]::IsNullOrWhiteSpace($env:JENKINS_AGENT_NAME)) { throw ("Name is required") } else { '' } ), + $Tunnel = '', + $WorkDir = '', + [switch] $WebSocket = $false, + $DirectConnection = '', + $InstanceIdentity = '', + $Protocols = '', + $JenkinsJavaBin = '', + $JavaHome = $env:JAVA_HOME, + $JenkinsJavaOpts = '' +) + +# Usage jenkins-agent.ps1 [options] -Url http://jenkins -Secret [SECRET] -Name [AGENT_NAME] +# Optional environment variables : +# * JENKINS_JAVA_BIN : Java executable to use instead of the default in PATH or obtained from JAVA_HOME +# * JENKINS_JAVA_OPTS : Java Options to use for the remoting process, otherwise obtained from JAVA_OPTS +# * JENKINS_TUNNEL : HOST:PORT for a tunnel to route TCP traffic to jenkins host, when jenkins can't be directly accessed over network +# * JENKINS_URL : alternate jenkins URL +# * JENKINS_SECRET : agent secret, if not set as an argument +# * JENKINS_AGENT_NAME : agent name, if not set as an argument +# * JENKINS_AGENT_WORKDIR : agent work directory, if not set by optional parameter -workDir +# * JENKINS_WEB_SOCKET : true if the connection should be made via WebSocket rather than TCP +# * JENKINS_DIRECT_CONNECTION: Connect directly to this TCP agent port, skipping the HTTP(S) connection parameter download. +# Value: ":" +# * JENKINS_INSTANCE_IDENTITY: The base64 encoded InstanceIdentity byte array of the Jenkins master. When this is set, +# the agent skips connecting to an HTTP(S) port for connection info. +# * JENKINS_PROTOCOLS: Specify the remoting protocols to attempt when instanceIdentity is provided. + +if(![System.String]::IsNullOrWhiteSpace($Cmd)) { + Invoke-Expression "$Cmd" +} else { + + # this maps the variable name from the CmdletBinding to environment variables + $ParamMap = @{ + 'JenkinsJavaBin' = 'JENKINS_JAVA_BIN'; + 'JenkinsJavaOpts' = 'JENKINS_JAVA_OPTS'; + 'Tunnel' = 'JENKINS_TUNNEL'; + 'Url' = 'JENKINS_URL'; + 'Secret' = 'JENKINS_SECRET'; + 'Name' = 'JENKINS_AGENT_NAME'; + 'WorkDir' = 'JENKINS_AGENT_WORKDIR'; + 'WebSocket' = 'JENKINS_WEB_SOCKET'; + 'DirectConnection' = 'JENKINS_DIRECT_CONNECTION'; + 'InstanceIdentity' = 'JENKINS_INSTANCE_IDENTITY'; + 'Protocols' = 'JENKINS_PROTOCOLS'; + } + + # this does some trickery to update the variable from the CmdletBinding + # with the value of the + foreach($p in $ParamMap.Keys) { + $var = Get-Variable $p + $envVar = Get-ChildItem -Path "env:$($ParamMap[$p])" -ErrorAction 'SilentlyContinue' + + if(($null -ne $envVar) -and ((($envVar.Value -is [System.String]) -and (![System.String]::IsNullOrWhiteSpace($envVar.Value))) -or ($null -ne $envVar.Value))) { + if(($null -ne $var) -and ((($var.Value -is [System.String]) -and (![System.String]::IsNullOrWhiteSpace($var.Value))))) { + Write-Warning "${p} is defined twice; in command-line arguments (-${p}) and in the environment variable ${envVar.Name}" + } + if($var.Value -is [System.String]) { + $var.Value = $envVar.Value + } elseif($var.Value -is [System.Management.Automation.SwitchParameter]) { + $var.Value = [bool]$envVar.Value + } + } + if($var.Value -is [System.String]) { + $var.Value = $var.Value.Trim() + } + } + + $AgentArguments = @() + + if(![System.String]::IsNullOrWhiteSpace($JenkinsJavaOpts)) { + # this magic will basically process the $JenkinsJavaOpts like a command line + # and split into an array, the command line processing follows the PowerShell + # commnd line processing, which means for things like -Dsomething.something=something, + # you need to quote the string like this: "-Dsomething.something=something" or else it + # will get parsed incorrectly. + $AgentArguments += Invoke-Expression "echo $JenkinsJavaOpts" + } + + $AgentArguments += @("-cp", "C:/ProgramData/Jenkins/agent.jar", "hudson.remoting.jnlp.Main", "-headless") + + if(![System.String]::IsNullOrWhiteSpace($Tunnel)) { + $AgentArguments += @("-tunnel", "`"$Tunnel`"") + } + + if(![System.String]::IsNullOrWhiteSpace($WorkDir)) { + $AgentArguments += @("-workDir", "`"$WorkDir`"") + } else { + $AgentArguments += @("-workDir", "`"C:/Users/jenkins/Work`"") + } + + if($WebSocket) { + $AgentArguments += @("-webSocket") + } + + if(![System.String]::IsNullOrWhiteSpace($Url)) { + $AgentArguments += @("-url", "`"$Url`"") + } + + if(![System.String]::IsNullOrWhiteSpace($DirectConnection)) { + $AgentArguments += @('-direct', $DirectConnection) + } + + if(![System.String]::IsNullOrWhiteSpace($InstanceIdentity)) { + $AgentArguments += @('-instanceIdentity', $InstanceIdentity) + } + + if(![System.String]::IsNullOrWhiteSpace($Protocols)) { + $AgentArguments += @('-protocols', $Protocols) + } + + # these need to be the last things added since they are positional + # parameters to agent.jar + $AgentArguments += @($Secret, $Name) + + if(![System.String]::IsNullOrWhiteSpace($JenkinsJavaBin)) { + $JAVA_BIN = $JenkinsJavaBin + } else { + # if java home is defined, use it + $JAVA_BIN = "java.exe" + if (![System.String]::IsNullOrWhiteSpace($JavaHome)) { + $JAVA_BIN = "$JavaHome/bin/java.exe" + } + } + + #TODO: Handle the case when the command-line and Environment variable contain different values. + #It is fine it blows up for now since it should lead to an error anyway. + Start-Process -FilePath $JAVA_BIN -Wait -NoNewWindow -ArgumentList $AgentArguments +}