From 276fc0ff1bf1e2137d490f8018ebae78ece4fa66 Mon Sep 17 00:00:00 2001 From: Timofey Kirillov Date: Tue, 17 May 2022 18:27:59 +0300 Subject: [PATCH] feat(cross-platform-builds): basic support of --platform=OS/ARCH[/VARIANT] parameter for buildah builder Signed-off-by: Timofey Kirillov --- cmd/werf/common/common.go | 2 +- cmd/werf/common/container_backend.go | 5 ++- pkg/buildah/common.go | 4 +- pkg/buildah/native_linux.go | 47 +++++++++++++++++++++++- pkg/container_backend/buildah_backend.go | 10 ++--- 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/cmd/werf/common/common.go b/cmd/werf/common/common.go index 6fcfeadc9c..20ffd81264 100644 --- a/cmd/werf/common/common.go +++ b/cmd/werf/common/common.go @@ -1434,7 +1434,7 @@ func SetupPlatform(cmdData *CmdData, cmd *cobra.Command) { } } - cmd.Flags().StringVarP(cmdData.Platform, "platform", "", defaultValue, "Enable platform emulation when building images with werf. The only supported option for now is linux/amd64.") + cmd.Flags().StringVarP(cmdData.Platform, "platform", "", defaultValue, "Enable platform emulation when building images with werf, format: OS/ARCH[/VARIANT].") } func GetContext() context.Context { diff --git a/cmd/werf/common/container_backend.go b/cmd/werf/common/container_backend.go index 2413ef4e5c..02ed52cac4 100644 --- a/cmd/werf/common/container_backend.go +++ b/cmd/werf/common/container_backend.go @@ -117,12 +117,15 @@ func InitProcessContainerBackend(ctx context.Context, cmdData *CmdData) (contain Isolation: buildahIsolation, StorageDriver: storageDriver, }, + NativeModeOpts: buildah.NativeModeOpts{ + Platform: *cmdData.Platform, + }, }) if err != nil { return nil, ctx, fmt.Errorf("unable to get buildah client: %w", err) } - return wrapContainerBackend(container_backend.NewBuildahBackend(b, filepath.Join(werf.GetServiceDir(), "tmp", "buildah"))), ctx, nil + return wrapContainerBackend(container_backend.NewBuildahBackend(b, container_backend.BuildahBackendOptions{TmpDir: filepath.Join(werf.GetServiceDir(), "tmp", "buildah")})), ctx, nil } newCtx, err := InitProcessDocker(ctx, cmdData) diff --git a/pkg/buildah/common.go b/pkg/buildah/common.go index 41f111633e..01cdc85bac 100644 --- a/pkg/buildah/common.go +++ b/pkg/buildah/common.go @@ -123,7 +123,9 @@ type CommonBuildahOpts struct { Insecure bool } -type NativeModeOpts struct{} +type NativeModeOpts struct { + Platform string +} type DockerWithFuseModeOpts struct{} diff --git a/pkg/buildah/native_linux.go b/pkg/buildah/native_linux.go index 4faa2cd0ed..0eeccc49cd 100644 --- a/pkg/buildah/native_linux.go +++ b/pkg/buildah/native_linux.go @@ -17,6 +17,7 @@ import ( "github.com/containers/buildah/define" "github.com/containers/buildah/docker" "github.com/containers/buildah/imagebuildah" + "github.com/containers/buildah/pkg/parse" "github.com/containers/common/libimage" "github.com/containers/image/v5/manifest" imgstor "github.com/containers/image/v5/storage" @@ -62,6 +63,8 @@ type NativeBuildah struct { Runtime libimage.Runtime DefaultSystemContext imgtypes.SystemContext DefaultCommonBuildOptions define.CommonBuildOptions + + platforms []struct{ OS, Arch, Variant string } } func NewNativeBuildah(commonOpts CommonBuildahOpts, opts NativeModeOpts) (*NativeBuildah, error) { @@ -95,6 +98,21 @@ func NewNativeBuildah(commonOpts CommonBuildahOpts, opts NativeModeOpts) (*Nativ DockerDaemonInsecureSkipTLSVerify: b.Insecure, } + if opts.Platform != "" { + os, arch, variant, err := parse.Platform(opts.Platform) + if err != nil { + return nil, fmt.Errorf("unable to parse platform %q: %w", opts.Platform, err) + } + + b.DefaultSystemContext.OSChoice = os + b.DefaultSystemContext.ArchitectureChoice = arch + b.DefaultSystemContext.VariantChoice = variant + + b.platforms = []struct{ OS, Arch, Variant string }{ + {os, arch, variant}, + } + } + b.DefaultCommonBuildOptions = define.CommonBuildOptions{ ShmSize: DefaultShmSize, } @@ -177,6 +195,7 @@ func (b *NativeBuildah) BuildFromDockerfile(ctx context.Context, dockerfile []by Target: opts.Target, MaxPullPushRetries: MaxPullPushRetries, PullPushRetryDelay: PullPushRetryDelay, + Platforms: b.platforms, } errLog := &bytes.Buffer{} @@ -287,10 +306,36 @@ func (b *NativeBuildah) Pull(ctx context.Context, ref string, opts PullOpts) err PullPolicy: define.PullIfNewer, } - if _, err := buildah.Pull(ctx, ref, pullOpts); err != nil { + imageID, err := buildah.Pull(ctx, ref, pullOpts) + if err != nil { return fmt.Errorf("error pulling image %q: %w", ref, err) } + imageInspect, err := b.Inspect(ctx, imageID) + if err != nil { + return fmt.Errorf("unable to inspect pulled image %q: %w", imageID, err) + } + + platformMismatch := false + if b.DefaultSystemContext.OSChoice != "" && b.DefaultSystemContext.OSChoice != imageInspect.OCIv1.OS { + platformMismatch = true + } + if b.DefaultSystemContext.ArchitectureChoice != "" && b.DefaultSystemContext.ArchitectureChoice != imageInspect.OCIv1.Architecture { + platformMismatch = true + } + if b.DefaultSystemContext.VariantChoice != "" && b.DefaultSystemContext.VariantChoice != imageInspect.OCIv1.Variant { + platformMismatch = true + } + + if platformMismatch { + imagePlatform := fmt.Sprintf("%s/%s/%s", imageInspect.OCIv1.OS, imageInspect.OCIv1.Architecture, imageInspect.OCIv1.Variant) + expectedPlatform := fmt.Sprintf("%s/%s", b.DefaultSystemContext.OSChoice, b.DefaultSystemContext.ArchitectureChoice) + if b.DefaultSystemContext.VariantChoice != "" { + expectedPlatform = fmt.Sprintf("%s/%s", expectedPlatform, b.DefaultSystemContext.VariantChoice) + } + return fmt.Errorf("image platform mismatch: image uses %s, expecting %s platform", imagePlatform, expectedPlatform) + } + return nil } diff --git a/pkg/container_backend/buildah_backend.go b/pkg/container_backend/buildah_backend.go index ef689aa7a5..7ec0fd2426 100644 --- a/pkg/container_backend/buildah_backend.go +++ b/pkg/container_backend/buildah_backend.go @@ -25,16 +25,16 @@ import ( ) type BuildahBackend struct { - TmpDir string buildah buildah.Buildah + BuildahBackendOptions } -type BuildahImage struct { - Image LegacyImageInterface +type BuildahBackendOptions struct { + TmpDir string } -func NewBuildahBackend(buildah buildah.Buildah, tmpDir string) *BuildahBackend { - return &BuildahBackend{buildah: buildah, TmpDir: tmpDir} +func NewBuildahBackend(buildah buildah.Buildah, opts BuildahBackendOptions) *BuildahBackend { + return &BuildahBackend{buildah: buildah, BuildahBackendOptions: opts} } func (runtime *BuildahBackend) HasStapelBuildSupport() bool {