From 5aa9661db632b844d3524081414e48a56e379171 Mon Sep 17 00:00:00 2001 From: Christian Volk Date: Wed, 9 Feb 2022 10:17:34 +0100 Subject: [PATCH] feat(kanikoExecute): preparation for multi-arch builds (#3515) * feat(kanikoExecute): preparation for multi-arch builds * missing files --- cmd/golangBuild_generated.go | 2 +- cmd/kanikoExecute.go | 6 ++++++ cmd/kanikoExecute_generated.go | 11 ++++++++++ pkg/docker/multiarch.go | 10 +++++++++ pkg/docker/multiarch_test.go | 31 +++++++++++++++++++++++++++ resources/metadata/golangBuild.yaml | 1 + resources/metadata/kanikoExecute.yaml | 9 ++++++++ 7 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 pkg/docker/multiarch.go create mode 100644 pkg/docker/multiarch_test.go diff --git a/cmd/golangBuild_generated.go b/cmd/golangBuild_generated.go index ebb70bcbe..9379c2bd2 100644 --- a/cmd/golangBuild_generated.go +++ b/cmd/golangBuild_generated.go @@ -339,7 +339,7 @@ func golangBuildMetadata() config.StepData { { Name: "targetArchitectures", ResourceRef: []config.ResourceReference{}, - Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"}, Type: "[]string", Mandatory: true, Aliases: []config.Alias{}, diff --git a/cmd/kanikoExecute.go b/cmd/kanikoExecute.go index 5f0860740..0e9dede2a 100644 --- a/cmd/kanikoExecute.go +++ b/cmd/kanikoExecute.go @@ -42,6 +42,12 @@ func kanikoExecute(config kanikoExecuteOptions, telemetryData *telemetry.CustomD } func runKanikoExecute(config *kanikoExecuteOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *kanikoExecuteCommonPipelineEnvironment, execRunner command.ExecRunner, httpClient piperhttp.Sender, fileUtils piperutils.FileUtils) error { + binfmtSupported, _ := docker.IsBinfmtMiscSupportedByHost(fileUtils) + + if !binfmtSupported && len(config.TargetArchitectures) > 0 { + log.Entry().Warning("Be aware that the host doesn't support binfmt_misc and thus multi archtecture docker builds might not be possible") + } + // backward compatibility for parameter ContainerBuildOptions if len(config.ContainerBuildOptions) > 0 { config.BuildOptions = strings.Split(config.ContainerBuildOptions, " ") diff --git a/cmd/kanikoExecute_generated.go b/cmd/kanikoExecute_generated.go index 756776a24..9e4fc66c7 100644 --- a/cmd/kanikoExecute_generated.go +++ b/cmd/kanikoExecute_generated.go @@ -31,6 +31,7 @@ type kanikoExecuteOptions struct { CustomTLSCertificateLinks []string `json:"customTlsCertificateLinks,omitempty"` DockerConfigJSON string `json:"dockerConfigJSON,omitempty"` DockerfilePath string `json:"dockerfilePath,omitempty"` + TargetArchitectures []string `json:"targetArchitectures,omitempty"` } type kanikoExecuteCommonPipelineEnvironment struct { @@ -190,6 +191,7 @@ func addKanikoExecuteFlags(cmd *cobra.Command, stepConfig *kanikoExecuteOptions) cmd.Flags().StringSliceVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", []string{}, "List containing download links of custom TLS certificates. This is required to ensure trusted connections to registries with custom certificates.") cmd.Flags().StringVar(&stepConfig.DockerConfigJSON, "dockerConfigJSON", os.Getenv("PIPER_dockerConfigJSON"), "Path to the file `.docker/config.json` - this is typically provided by your CI/CD system. You can find more details about the Docker credentials in the [Docker documentation](https://docs.docker.com/engine/reference/commandline/login/).") cmd.Flags().StringVar(&stepConfig.DockerfilePath, "dockerfilePath", `Dockerfile`, "Defines the location of the Dockerfile relative to the Jenkins workspace.") + cmd.Flags().StringSliceVar(&stepConfig.TargetArchitectures, "targetArchitectures", []string{``}, "Defines the target architectures for which the build should run using OS and architecture separated by a comma. (EXPERIMENTAL)") } @@ -355,6 +357,15 @@ func kanikoExecuteMetadata() config.StepData { Aliases: []config.Alias{{Name: "dockerfile"}}, Default: `Dockerfile`, }, + { + Name: "targetArchitectures", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"}, + Type: "[]string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: []string{``}, + }, }, }, Containers: []config.Container{ diff --git a/pkg/docker/multiarch.go b/pkg/docker/multiarch.go new file mode 100644 index 000000000..78899f419 --- /dev/null +++ b/pkg/docker/multiarch.go @@ -0,0 +1,10 @@ +package docker + +import ( + "github.com/SAP/jenkins-library/pkg/piperutils" +) + +// IsBinfmtMiscSupportedByHost checks if the hosts kernel does support binfmt_misc +func IsBinfmtMiscSupportedByHost(utils piperutils.FileUtils) (bool, error) { + return utils.DirExists("/proc/sys/fs/binfmt_misc") +} diff --git a/pkg/docker/multiarch_test.go b/pkg/docker/multiarch_test.go new file mode 100644 index 000000000..dc5bc4638 --- /dev/null +++ b/pkg/docker/multiarch_test.go @@ -0,0 +1,31 @@ +package docker + +import ( + "testing" + + "github.com/SAP/jenkins-library/pkg/mock" + "github.com/stretchr/testify/assert" +) + +func TestIsBinfmtMiscSupportedByHost(t *testing.T) { + t.Run("returns true - binfmt_misc supported by host", func(t *testing.T) { + utils := mock.FilesMock{} + utils.AddDir("/proc/sys/fs/binfmt_misc") + + b, err := IsBinfmtMiscSupportedByHost(&utils) + + if assert.NoError(t, err) { + assert.True(t, b) + } + }) + + t.Run("returns false - binfmt_misc not supported by host", func(t *testing.T) { + utils := mock.FilesMock{} + + b, err := IsBinfmtMiscSupportedByHost(&utils) + + if assert.NoError(t, err) { + assert.False(t, b) + } + }) +} diff --git a/resources/metadata/golangBuild.yaml b/resources/metadata/golangBuild.yaml index 138e88d91..7ff62723a 100644 --- a/resources/metadata/golangBuild.yaml +++ b/resources/metadata/golangBuild.yaml @@ -159,6 +159,7 @@ spec: description: Defines the target architectures for which the build should run using OS and architecture separated by a comma. default: linux,amd64 scope: + - GENERAL - STEPS - STAGES - PARAMETERS diff --git a/resources/metadata/kanikoExecute.yaml b/resources/metadata/kanikoExecute.yaml index 5a45d7479..47204926d 100644 --- a/resources/metadata/kanikoExecute.yaml +++ b/resources/metadata/kanikoExecute.yaml @@ -158,6 +158,15 @@ spec: - STAGES - STEPS default: Dockerfile + - name: targetArchitectures + type: "[]string" + description: Defines the target architectures for which the build should run using OS and architecture separated by a comma. (EXPERIMENTAL) + default: [] + scope: + - GENERAL + - STEPS + - STAGES + - PARAMETERS outputs: resources: - name: commonPipelineEnvironment