Skip to content

Commit

Permalink
chore: use docker bake to generate docker compose file
Browse files Browse the repository at this point in the history
  • Loading branch information
lemeurherve committed Jun 23, 2024
1 parent 2bc7774 commit 4cc014e
Show file tree
Hide file tree
Showing 14 changed files with 254 additions and 176 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
bats-core/
bats/
target/
build-windows-current.yaml
build-windows_*.yaml
3 changes: 2 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pipeline {
}
steps {
script {
if(isUnix()) {
if (isUnix()) {
sh './build.sh'
sh './build.sh test'
// If the tests are passing for Linux AMD64, then we can build all the CPU architectures
Expand All @@ -66,6 +66,7 @@ pipeline {
}
post {
always {
archiveArtifacts artifacts: 'build-windows_*.yaml', allowEmptyArchive: true
junit(allowEmptyResults: true, keepLongStdio: true, testResults: 'target/**/junit-results*.xml')
}
}
Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ check_cli = type "$(1)" >/dev/null 2>&1 || { echo "Error: command '$(1)' require
## Check if a given image exists in the current manifest docker-bake.hcl
check_image = make --silent list | grep -w '$(1)' >/dev/null 2>&1 || { echo "Error: the image '$(1)' does not exist in manifest for the platform 'linux/$(ARCH)'. Please check the output of 'make list'. Exiting." ; exit 1 ; }
## Base "docker buildx base" command to be reused everywhere
bake_base_cli := docker buildx bake -f docker-bake.hcl --load
bake_base_cli := docker buildx bake --file docker-bake.hcl
bake_cli := $(bake_base_cli) --load

Expand All @@ -39,12 +38,12 @@ docker-init: check-reqs
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

build: check-reqs
@set -x; $(bake_cli) --set '*.platform=linux/$(ARCH)' $(shell make --silent list)
@set -x; $(bake_cli) $(shell make --silent list) --set '*.platform=linux/$(ARCH)'

build-%:
@$(call check_image,$*)
@echo "== building $*"
@set -x; $(bake_cli) --set '*.platform=linux/$(ARCH)' '$*'
@set -x; $(bake_cli) '$*' --set '*.platform=linux/$(ARCH)'

every-build: check-reqs
@set -x; $(bake_base_cli) linux
Expand Down
45 changes: 0 additions & 45 deletions build-windows.yaml

This file was deleted.

176 changes: 105 additions & 71 deletions build.ps1
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
[CmdletBinding()]
Param(
[Parameter(Position=1)]
[Parameter(Position = 1)]
# Default build.ps1 target
[String] $Target = 'build',
# Remoting version to include
[String] $RemotingVersion = '3256.v88a_f6e922152',
# Type of agent ("agent" or "inbound-agent")
[String] $AgentType = '',
# Windows flavor and windows version to build
[String] $ImageType = 'nanoserver-ltsc2019',
# Image build number
[String] $BuildNumber = '1',
[switch] $DisableEnvProps = $false,
# Generate a docker compose file even if it already exists
[switch] $OverwriteDockerComposeFile = $false,
# Print the build and publish command instead of executing them if set
[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)
# Output debug info for tests: '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

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

$originalDockerComposeFile = 'build-windows.yaml'
$finalDockerComposeFile = 'build-windows-current.yaml'
$baseDockerCmd = 'docker-compose --file={0}' -f $finalDockerComposeFile
$baseDockerBuildCmd = '{0} build --parallel --pull' -f $baseDockerCmd
if (![String]::IsNullOrWhiteSpace($env:AGENT_TYPE)) {
$AgentType = $env:AGENT_TYPE
}

$AgentTypes = @('agent', 'inbound-agent')
if ($AgentType -ne '' -and $AgentType -in $AgentTypes) {
$AgentTypes = @($AgentType)
}
$ImageType = 'windowsservercore-ltsc2019'
$Organisation = 'jenkins4eval'
$Repository = @{
'agent' = 'agent'
'inbound-agent' = 'inbound-agent'
}

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

if (!$DisableEnvProps) {
Get-Content env.props | ForEach-Object {
Expand All @@ -48,18 +47,6 @@ if (!$DisableEnvProps) {
}
}

if (![String]::IsNullOrWhiteSpace($env:DOCKERHUB_ORGANISATION)) {
$Organisation = $env:DOCKERHUB_ORGANISATION
}

if (![String]::IsNullOrWhiteSpace($env:DOCKERHUB_REPO_AGENT)) {
$Repository['agent'] = $env:DOCKERHUB_REPO_AGENT
}

if (![String]::IsNullOrWhiteSpace($env:DOCKERHUB_REPO_INBOUND_AGENT)) {
$Repository['inbound-agent'] = $env:DOCKERHUB_REPO_INBOUND_AGENT
}

if (![String]::IsNullOrWhiteSpace($env:REMOTING_VERSION)) {
$RemotingVersion = $env:REMOTING_VERSION
}
Expand All @@ -72,6 +59,16 @@ if (![String]::IsNullOrWhiteSpace($env:IMAGE_TYPE)) {
$ImageType = $env:IMAGE_TYPE
}

$Organisation = 'jenkins4eval'
if (![String]::IsNullOrWhiteSpace($env:DOCKERHUB_ORGANISATION)) {
$Organisation = $env:DOCKERHUB_ORGANISATION
}

# Ensure constant env vars used in docker-bake.hcl are defined
$env:REGISTRY_ORG = "$Organisation"
$env:REMOTING_VERSION = "$RemotingVersion"
$env:BUILD_NUMBER = $BuildNumber

# 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 @@ -82,8 +79,14 @@ Function Test-CommandExists {
$oldPreference = $ErrorActionPreference
$ErrorActionPreference = 'stop'
try {
if (Get-Command $command){
# Special case to test "docker buildx"
if ($command.Contains(' ')) {
Invoke-Expression $command | Out-Null
Write-Debug "$command exists"
} else {
if(Get-Command $command){
Write-Debug "$command exists"
}
}
}
Catch {
Expand All @@ -94,36 +97,15 @@ Function Test-CommandExists {
}
}

# Ensure constant env vars used in the docker compose file are defined
$env:DOCKERHUB_ORGANISATION = "$Organisation"
$env:REMOTING_VERSION = "$RemotingVersion"
$env:BUILD_NUMBER = $BuildNumber

$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 mcr.microsoft.com/powershell:*-ltsc2019 docker images unfortunately, only "1809" ones
$env:TOOLS_WINDOWS_VERSION = '1809'
# Workaround for 2019 only until https://github.com/microsoft/Windows-Containers/issues/493 is solved
$env:WINDOWS_VERSION_DIGEST = '@sha256:6fdf140282a2f809dae9b13fe441635867f0a27c33a438771673b8da8f3348a4'
}

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

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

function Test-Image {
param (
$AgentTypeAndImageName
[String] $AgentTypeAndImageName
)

# Ex: agent|docker.io/jenkins/agent:jdk21-windowsservercore-ltsc2019|21.0.3_9
$items = $AgentTypeAndImageName.Split('|')
$agentType = $items[0]
$imageName = $items[1]
$imageName = $items[1] -replace 'docker.io/', ''
$javaVersion = $items[2]
$imageNameItems = $imageName.Split(':')
$imageTag = $imageNameItems[1]
Expand Down Expand Up @@ -157,19 +139,71 @@ function Test-Image {
return $failed
}

function Initialize-DockerComposeFile {
param (
[String] $AgentType,
[String] $ImageType,
[String] $DockerComposeFile
)

$baseDockerBakeCmd = 'docker buildx bake --progress=plain --file=docker-bake.hcl'

$items = $ImageType.Split('-')
$windowsFlavor = $items[0]
$windowsVersion = $items[1]

# Override the list of Windows versions taken defined in docker-bake.hcl by the version from image type
$env:WINDOWS_VERSION_OVERRIDE = $windowsVersion

# Override the list of agent types defined in docker-bake.hcl by the specified agent type
$env:WINDOWS_AGENT_TYPE_OVERRIDE = $AgentType

# Retrieve the targets from docker buildx bake --print output
# Remove the 'output' section (unsupported by docker compose)
# For each target name as service key, return a map consisting of:
# - 'image' set to the first tag value
# - 'build' set to the content of the bake target
$yqMainQuery = '''.target[]' + `
' | del(.output)' + `
' | {(. | key): {\"image\": .tags[0], \"build\": .}}'''
# Encapsulate under a top level 'services' map
$yqServicesQuery = '''{\"services\": .}'''

# - Use docker buildx bake to output image definitions from the "<windowsFlavor>" bake target
# - Convert with yq to the format expected by docker compose
# - Store the result in the docker compose file
$generateDockerComposeFileCmd = ' {0} {1} --print' -f $baseDockerBakeCmd, $windowsFlavor + `
' | yq --prettyPrint {0} | yq {1}' -f $yqMainQuery, $yqServicesQuery + `
' | Out-File -FilePath {0}' -f $DockerComposeFile

Write-Host "= PREPARE: Docker compose file generation command`n$generateDockerComposeFileCmd"

Invoke-Expression $generateDockerComposeFileCmd

# Remove override
Remove-Item env:\WINDOWS_VERSION_OVERRIDE
Remove-Item env:\WINDOWS_AGENT_TYPE_OVERRIDE
}

Test-CommandExists 'docker'
Test-CommandExists 'docker-compose'
Test-CommandExists 'docker buildx'
Test-CommandExists 'yq'

foreach($agentType in $AgentTypes) {
# Ensure remaining env vars used in the docker compose file are defined
$env:AGENT_TYPE = $agentType
$env:DOCKERHUB_REPO = $Repository[$agentType]

# Temporary docker compose file (git ignored)
Copy-Item -Path $originalDockerComposeFile -Destination $finalDockerComposeFile
# If it's an "agent" type, add the corresponding target
if ($agentType -eq 'agent') {
yq '.services.[].build.target = \"agent\"' $originalDockerComposeFile | Out-File -FilePath $finalDockerComposeFile
$dockerComposeFile = 'build-windows_{0}_{1}.yaml' -f $AgentType, $ImageType
$baseDockerCmd = 'docker-compose --file={0}' -f $dockerComposeFile
$baseDockerBuildCmd = '{0} build --parallel --pull' -f $baseDockerCmd

# Generate the docker compose file if it doesn't exists or if the parameter OverwriteDockerComposeFile is set
if ((Test-Path $dockerComposeFile) -and -not $OverwriteDockerComposeFile) {
Write-Host "= PREPARE: The docker compose file '$dockerComposeFile' containing the image definitions already exists."
} else {
Write-Host "= PREPARE: Initialize the docker compose file '$dockerComposeFile' containing the image definitions."
Initialize-DockerComposeFile -AgentType $AgentType -ImageType $ImageType -DockerComposeFile $dockerComposeFile
}

Write-Host "= PREPARE: List of $Organisation/$env:DOCKERHUB_REPO images and tags to be processed:"
Write-Host '= PREPARE: List of images and tags to be processed:'
Invoke-Expression "$baseDockerCmd config"

Write-Host '= BUILD: Building all images...'
Expand Down Expand Up @@ -216,9 +250,9 @@ foreach($agentType in $AgentTypes) {
Write-Host "= TEST: Testing all ${agentType} images..."
# Only fail the run afterwards in case of any test failures
$testFailed = $false
$jdks = Invoke-Expression "$baseDockerCmd config" | yq -r --output-format json '.services' | ConvertFrom-Json
foreach ($jdk in $jdks.PSObject.Properties) {
$testFailed = $testFailed -or (Test-Image ('{0}|{1}|{2}' -f $agentType, $jdk.Value.image, $jdk.Value.build.args.JAVA_VERSION))
$imageDefinitions = Invoke-Expression "$baseDockerCmd config" | yq --unwrapScalar --output-format json '.services' | ConvertFrom-Json
foreach ($imageDefinition in $imageDefinitions.PSObject.Properties) {
$testFailed = $testFailed -or (Test-Image ('{0}|{1}|{2}' -f $agentType, $imageDefinition.Value.image, $imageDefinition.Value.build.args.JAVA_VERSION))
}

# Fail if any test failures
Expand Down
Loading

0 comments on commit 4cc014e

Please sign in to comment.