diff --git a/cmd/werf/ci_env/ci_env.go b/cmd/werf/ci_env/ci_env.go index 358957fc9d..8a8f8445fd 100644 --- a/cmd/werf/ci_env/ci_env.go +++ b/cmd/werf/ci_env/ci_env.go @@ -18,7 +18,6 @@ import ( "github.com/werf/logboek" "github.com/werf/logboek/pkg/level" "github.com/werf/werf/cmd/werf/common" - "github.com/werf/werf/pkg/container_backend/thirdparty/platformutil" "github.com/werf/werf/pkg/docker" "github.com/werf/werf/pkg/docker_registry" "github.com/werf/werf/pkg/git_repo" @@ -118,17 +117,15 @@ func runCIEnv(cmd *cobra.Command, args []string) error { return err } - var platform string - if len(commonCmdData.GetPlatform()) > 0 { - platforms, err := platformutil.NormalizeUserParams(commonCmdData.GetPlatform()) - if err != nil { - return fmt.Errorf("unable to normalize platforms params %v: %w", commonCmdData.GetPlatform(), err) - } - platform = platforms[0] - } // FIXME(multiarch): do not initialize platform in backend here // FIXME(multiarch): why docker initialization here? what if buildah backend enabled? - if err := docker.Init(ctx, dockerConfig, *commonCmdData.LogVerbose, *commonCmdData.LogDebug, platform); err != nil { + opts := docker.InitOptions{ + DockerConfigDir: dockerConfig, + ClaimPlatforms: commonCmdData.GetPlatform(), + Verbose: *commonCmdData.LogVerbose, + Debug: *commonCmdData.LogDebug, + } + if err := docker.Init(ctx, opts); err != nil { return fmt.Errorf("docker init failed in dir %q: %w", dockerConfig, err) } diff --git a/cmd/werf/common/container_backend.go b/cmd/werf/common/container_backend.go index 8a46238b9b..0ae2dfd320 100644 --- a/cmd/werf/common/container_backend.go +++ b/cmd/werf/common/container_backend.go @@ -10,7 +10,6 @@ import ( "github.com/werf/werf/pkg/buildah" "github.com/werf/werf/pkg/buildah/thirdparty" "github.com/werf/werf/pkg/container_backend" - "github.com/werf/werf/pkg/container_backend/thirdparty/platformutil" "github.com/werf/werf/pkg/docker" "github.com/werf/werf/pkg/util" "github.com/werf/werf/pkg/werf" @@ -100,16 +99,6 @@ func InitProcessContainerBackend(ctx context.Context, cmdData *CmdData) (contain insecure := *cmdData.InsecureRegistry || *cmdData.SkipTlsVerifyRegistry - // FIXME(multiarch): rework container backend platform initialization, specify platform only when running build operation - var platform string - if len(cmdData.GetPlatform()) > 0 { - platforms, err := platformutil.NormalizeUserParams(cmdData.GetPlatform()) - if err != nil { - return nil, ctx, fmt.Errorf("unable to normalize platforms params %v: %w", cmdData.GetPlatform(), err) - } - platform = platforms[0] - } - b, err := buildah.NewBuildah(*buildahMode, buildah.BuildahOpts{ CommonBuildahOpts: buildah.CommonBuildahOpts{ TmpDir: filepath.Join(werf.GetServiceDir(), "tmp", "buildah"), @@ -117,7 +106,7 @@ func InitProcessContainerBackend(ctx context.Context, cmdData *CmdData) (contain Isolation: buildahIsolation, StorageDriver: storageDriver, }, - NativeModeOpts: buildah.NativeModeOpts{Platform: platform}, + NativeModeOpts: buildah.NativeModeOpts{}, }) if err != nil { return nil, ctx, fmt.Errorf("unable to get buildah client: %w", err) @@ -136,13 +125,14 @@ func InitProcessContainerBackend(ctx context.Context, cmdData *CmdData) (contain } func InitProcessDocker(ctx context.Context, cmdData *CmdData) (context.Context, error) { - // FIXME(multiarch): rework container backend platform initialization, specify platform only when running build operation - var platform string - if len(cmdData.GetPlatform()) > 0 { - platform = cmdData.GetPlatform()[0] + opts := docker.InitOptions{ + DockerConfigDir: *cmdData.DockerConfig, + ClaimPlatforms: cmdData.GetPlatform(), + Verbose: *cmdData.LogVerbose, + Debug: *cmdData.LogDebug, } - if err := docker.Init(ctx, *cmdData.DockerConfig, *cmdData.LogVerbose, *cmdData.LogDebug, platform); err != nil { + if err := docker.Init(ctx, opts); err != nil { return ctx, fmt.Errorf("unable to init docker for buildah container backend: %w", err) } diff --git a/cmd/werf/kube_run/kube_run.go b/cmd/werf/kube_run/kube_run.go index d086bfc1d5..a8b4c6ee29 100644 --- a/cmd/werf/kube_run/kube_run.go +++ b/cmd/werf/kube_run/kube_run.go @@ -416,13 +416,21 @@ func run(ctx context.Context, pod, secret, namespace string, werfConfig *config. } } + targetPlatforms, err := c.GetTargetPlatforms() + if err != nil { + return fmt.Errorf("invalid target platforms: %w", err) + } + if len(targetPlatforms) == 0 { + targetPlatforms = []string{containerBackend.GetDefaultPlatform()} + } + // FIXME(multiarch): specify multiarch manifest here - if err := c.FetchLastImageStage(ctx, "", imageName); err != nil { + if err := c.FetchLastImageStage(ctx, targetPlatforms[0], imageName); err != nil { return err } // FIXME(multiarch): specify multiarch manifest here - image = c.GetImageNameForLastImageStage("", imageName) + image = c.GetImageNameForLastImageStage(targetPlatforms[0], imageName) return nil }); err != nil { return err diff --git a/cmd/werf/run/run.go b/cmd/werf/run/run.go index 3e8e15c116..b6e673a382 100644 --- a/cmd/werf/run/run.go +++ b/cmd/werf/run/run.go @@ -402,11 +402,19 @@ func run(ctx context.Context, containerBackend container_backend.ContainerBacken } } - if err := c.FetchLastImageStage(ctx, "", imageName); err != nil { + targetPlatforms, err := c.GetTargetPlatforms() + if err != nil { + return fmt.Errorf("invalid target platforms: %w", err) + } + if len(targetPlatforms) == 0 { + targetPlatforms = []string{containerBackend.GetDefaultPlatform()} + } + + if err := c.FetchLastImageStage(ctx, targetPlatforms[0], imageName); err != nil { return err } - dockerImageName = c.GetImageNameForLastImageStage("", imageName) + dockerImageName = c.GetImageNameForLastImageStage(targetPlatforms[0], imageName) return nil }); err != nil { return err diff --git a/pkg/build/build_phase.go b/pkg/build/build_phase.go index 5c136fde41..4e07978ada 100644 --- a/pkg/build/build_phase.go +++ b/pkg/build/build_phase.go @@ -531,7 +531,7 @@ func (phase *BuildPhase) findAndFetchStageFromSecondaryStagesStorage(ctx context err := logboek.Context(ctx).Default().LogProcess("Copy suitable stage from secondary %s", secondaryStagesStorage.String()).DoError(func() error { // Copy suitable stage from a secondary stages storage to the primary stages storage // while primary stages storage lock for this digest is held - if copiedStageDesc, err := storageManager.CopySuitableByDigestStage(ctx, secondaryStageDesc, secondaryStagesStorage, storageManager.GetStagesStorage(), phase.Conveyor.ContainerBackend); err != nil { + if copiedStageDesc, err := storageManager.CopySuitableByDigestStage(ctx, secondaryStageDesc, secondaryStagesStorage, storageManager.GetStagesStorage(), phase.Conveyor.ContainerBackend, img.TargetPlatform); err != nil { return fmt.Errorf("unable to copy suitable stage %s from %s to %s: %w", secondaryStageDesc.StageID.String(), secondaryStagesStorage.String(), storageManager.GetStagesStorage().String(), err) } else { i := phase.Conveyor.GetOrCreateStageImage(copiedStageDesc.Info.Name, phase.StagesIterator.GetPrevImage(img, stg), stg, img) @@ -783,7 +783,9 @@ func (phase *BuildPhase) atomicBuildStageImage(ctx context.Context, img *image.I } if err := logboek.Context(ctx).Streams().DoErrorWithTag(fmt.Sprintf("%s/%s", img.LogName(), stg.Name()), img.LogTagStyle(), func() error { - return stageImage.Builder.Build(ctx, phase.ImageBuildOptions) + opts := phase.ImageBuildOptions + opts.TargetPlatform = img.TargetPlatform + return stageImage.Builder.Build(ctx, opts) }); err != nil { return fmt.Errorf("failed to build image for stage %s with digest %s: %w", stg.Name(), stg.GetDigest(), err) } diff --git a/pkg/build/conveyor.go b/pkg/build/conveyor.go index 71e9f7e9aa..4ea6242f62 100644 --- a/pkg/build/conveyor.go +++ b/pkg/build/conveyor.go @@ -223,10 +223,12 @@ func (c *Conveyor) GetImportServer(ctx context.Context, targetPlatform, imageNam if stageName != "" { importServerName += "/" + stageName } - // FIXME(multiarch): in this place we should get our current platform from the container backend in the case when targetPlatform is empty - if targetPlatform != "" && targetPlatform != "linux/amd64" { - importServerName += "[" + targetPlatform + "]" + + if targetPlatform == "" { + panic("assertion: targetPlatform cannot be empty") } + importServerName += fmt.Sprintf("[%s]", targetPlatform) + if srv, hasKey := c.importServers[importServerName]; hasKey { return srv, nil } @@ -249,9 +251,9 @@ func (c *Conveyor) GetImportServer(ctx context.Context, targetPlatform, imageNam DoError(func() error { var tmpDir string if stageName == "" { - tmpDir = filepath.Join(c.tmpDir, "import-server", imageName) + tmpDir = filepath.Join(c.tmpDir, "import-server", imageName, targetPlatform) } else { - tmpDir = filepath.Join(c.tmpDir, "import-server", fmt.Sprintf("%s-%s", imageName, stageName)) + tmpDir = filepath.Join(c.tmpDir, "import-server", fmt.Sprintf("%s-%s", imageName, stageName), targetPlatform) } if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil { @@ -682,7 +684,7 @@ func (c *Conveyor) GetOrCreateStageImage(name string, prevStageImage *stage.Stag return stageImage } - i := container_backend.NewLegacyStageImage(extractLegacyStageImage(prevStageImage), name, c.ContainerBackend) + i := container_backend.NewLegacyStageImage(extractLegacyStageImage(prevStageImage), name, c.ContainerBackend, img.TargetPlatform) var baseImage string if stg != nil { @@ -701,6 +703,10 @@ func (c *Conveyor) GetOrCreateStageImage(name string, prevStageImage *stage.Stag } func (c *Conveyor) GetImage(targetPlatform, name string) *image.Image { + if targetPlatform == "" { + panic("assertion: targetPlatform should not be empty") + } + for _, img := range c.imagesTree.GetImages() { if img.GetName() == name && img.TargetPlatform == targetPlatform { return img diff --git a/pkg/build/image/dockerfile.go b/pkg/build/image/dockerfile.go index 210354389e..a3713a2600 100644 --- a/pkg/build/image/dockerfile.go +++ b/pkg/build/image/dockerfile.go @@ -22,7 +22,7 @@ import ( "github.com/werf/werf/pkg/util" ) -func MapDockerfileConfigToImagesSets(ctx context.Context, dockerfileImageConfig *config.ImageFromDockerfile, opts CommonImageOptions) (ImagesSets, error) { +func MapDockerfileConfigToImagesSets(ctx context.Context, dockerfileImageConfig *config.ImageFromDockerfile, targetPlatform string, opts CommonImageOptions) (ImagesSets, error) { if dockerfileImageConfig.Staged { relDockerfilePath := filepath.Join(dockerfileImageConfig.Context, dockerfileImageConfig.Dockerfile) dockerfileData, err := opts.GiterminismManager.FileReader().ReadDockerfile(ctx, relDockerfilePath) @@ -44,10 +44,10 @@ func MapDockerfileConfigToImagesSets(ctx context.Context, dockerfileImageConfig return nil, fmt.Errorf("unable to parse dockerfile %s: %w", relDockerfilePath, err) } - return mapDockerfileToImagesSets(ctx, d, dockerfileImageConfig, opts) + return mapDockerfileToImagesSets(ctx, d, dockerfileImageConfig, targetPlatform, opts) } - img, err := mapLegacyDockerfileToImage(ctx, dockerfileImageConfig, opts) + img, err := mapLegacyDockerfileToImage(ctx, dockerfileImageConfig, targetPlatform, opts) if err != nil { return nil, err } @@ -59,7 +59,7 @@ func MapDockerfileConfigToImagesSets(ctx context.Context, dockerfileImageConfig return ret, nil } -func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile, dockerfileImageConfig *config.ImageFromDockerfile, opts CommonImageOptions) (ImagesSets, error) { +func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile, dockerfileImageConfig *config.ImageFromDockerfile, targetPlatform string, opts CommonImageOptions) (ImagesSets, error) { var ret ImagesSets targetStage, err := cfg.GetTargetStage() @@ -106,7 +106,7 @@ func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile, var img *Image var err error if baseStg := cfg.FindStage(stg.BaseName); baseStg != nil { - img, err = NewImage(ctx, item.WerfImageName, StageAsBaseImage, ImageOptions{ + img, err = NewImage(ctx, targetPlatform, item.WerfImageName, StageAsBaseImage, ImageOptions{ IsDockerfileImage: true, IsDockerfileTargetStage: item.IsTargetStage, DockerfileImageConfig: dockerfileImageConfig, @@ -120,7 +120,7 @@ func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile, appendQueue(baseStg.GetWerfImageName(), baseStg, item.Level+1) } else { - img, err = NewImage(ctx, item.WerfImageName, ImageFromRegistryAsBaseImage, ImageOptions{ + img, err = NewImage(ctx, targetPlatform, item.WerfImageName, ImageFromRegistryAsBaseImage, ImageOptions{ IsDockerfileImage: true, IsDockerfileTargetStage: item.IsTargetStage, DockerfileImageConfig: dockerfileImageConfig, @@ -198,8 +198,8 @@ func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile, return ret, nil } -func mapLegacyDockerfileToImage(ctx context.Context, dockerfileImageConfig *config.ImageFromDockerfile, opts CommonImageOptions) (*Image, error) { - img, err := NewImage(ctx, dockerfileImageConfig.Name, NoBaseImage, ImageOptions{ +func mapLegacyDockerfileToImage(ctx context.Context, dockerfileImageConfig *config.ImageFromDockerfile, targetPlatform string, opts CommonImageOptions) (*Image, error) { + img, err := NewImage(ctx, targetPlatform, dockerfileImageConfig.Name, NoBaseImage, ImageOptions{ CommonImageOptions: opts, IsDockerfileImage: true, IsDockerfileTargetStage: true, @@ -258,7 +258,7 @@ func mapLegacyDockerfileToImage(ctx context.Context, dockerfileImageConfig *conf ) baseStageOptions := &stage.BaseStageOptions{ - TargetPlatform: opts.TargetPlatform, + TargetPlatform: targetPlatform, ImageName: dockerfileImageConfig.Name, ProjectName: opts.ProjectName, } diff --git a/pkg/build/image/image.go b/pkg/build/image/image.go index 83597e5aa6..5c24c106c8 100644 --- a/pkg/build/image/image.go +++ b/pkg/build/image/image.go @@ -38,7 +38,8 @@ type CommonImageOptions struct { ProjectName string ContainerWerfDir string TmpDir string - TargetPlatform string + + ForceTargetPlatformLogging bool } type ImageOptions struct { @@ -52,13 +53,17 @@ type ImageOptions struct { DockerfileExpanderFactory dockerfile.ExpanderFactory } -func NewImage(ctx context.Context, name string, baseImageType BaseImageType, opts ImageOptions) (*Image, error) { +func NewImage(ctx context.Context, targetPlatform, name string, baseImageType BaseImageType, opts ImageOptions) (*Image, error) { switch baseImageType { case NoBaseImage, ImageFromRegistryAsBaseImage, StageAsBaseImage: default: panic(fmt.Sprintf("unknown opts.BaseImageType %q", baseImageType)) } + if targetPlatform == "" { + panic("assertion: targetPlatform cannot be empty") + } + i := &Image{ Name: name, CommonImageOptions: opts.CommonImageOptions, @@ -66,7 +71,7 @@ func NewImage(ctx context.Context, name string, baseImageType BaseImageType, opt IsDockerfileImage: opts.IsDockerfileImage, IsDockerfileTargetStage: opts.IsDockerfileTargetStage, DockerfileImageConfig: opts.DockerfileImageConfig, - TargetPlatform: opts.TargetPlatform, + TargetPlatform: targetPlatform, baseImageType: baseImageType, baseImageReference: opts.BaseImageReference, @@ -113,7 +118,11 @@ func (i *Image) LogName() string { } func (i *Image) LogDetailedName() string { - return logging.ImageLogProcessName(i.Name, i.IsArtifact, i.TargetPlatform) + var targetPlatformForLog string + if i.ForceTargetPlatformLogging || i.TargetPlatform != i.ContainerBackend.GetRuntimePlatform() { + targetPlatformForLog = i.TargetPlatform + } + return logging.ImageLogProcessName(i.Name, i.IsArtifact, targetPlatformForLog) } func (i *Image) LogProcessStyle() color.Style { diff --git a/pkg/build/image/image_tree.go b/pkg/build/image/image_tree.go index 6c849e7846..37d56169f3 100644 --- a/pkg/build/image/image_tree.go +++ b/pkg/build/image/image_tree.go @@ -52,9 +52,12 @@ func (tree *ImagesTree) Calculate(ctx context.Context) error { return fmt.Errorf("invalid target platforms: %w", err) } if len(targetPlatforms) == 0 { - targetPlatforms = []string{""} + targetPlatforms = []string{tree.ContainerBackend.GetDefaultPlatform()} } + commonImageOpts := tree.CommonImageOptions + commonImageOpts.ForceTargetPlatformLogging = (len(targetPlatforms) > 1) + builder := NewImagesSetsBuilder() for _, iteration := range imageConfigSets { @@ -80,18 +83,15 @@ func (tree *ImagesTree) Calculate(ctx context.Context) error { var err error var newImagesSets ImagesSets - commonOpts := tree.CommonImageOptions - commonOpts.TargetPlatform = targetPlatform - switch imageConfig := imageConfigI.(type) { case config.StapelImageInterface: - newImagesSets, err = MapStapelConfigToImagesSets(ctx, tree.werfConfig.Meta, imageConfig, commonOpts) + newImagesSets, err = MapStapelConfigToImagesSets(ctx, tree.werfConfig.Meta, imageConfig, targetPlatform, commonImageOpts) if err != nil { return fmt.Errorf("unable to map stapel config to images sets: %w", err) } case *config.ImageFromDockerfile: - newImagesSets, err = MapDockerfileConfigToImagesSets(ctx, imageConfig, commonOpts) + newImagesSets, err = MapDockerfileConfigToImagesSets(ctx, imageConfig, targetPlatform, commonImageOpts) if err != nil { return fmt.Errorf("unable to map dockerfile to images sets: %w", err) } diff --git a/pkg/build/image/stapel.go b/pkg/build/image/stapel.go index f88c505450..f276e27a21 100644 --- a/pkg/build/image/stapel.go +++ b/pkg/build/image/stapel.go @@ -12,8 +12,8 @@ import ( "github.com/werf/werf/pkg/git_repo" ) -func MapStapelConfigToImagesSets(ctx context.Context, metaConfig *config.Meta, stapelImageConfig config.StapelImageInterface, opts CommonImageOptions) (ImagesSets, error) { - img, err := mapStapelConfigToImage(ctx, metaConfig, stapelImageConfig, opts) +func MapStapelConfigToImagesSets(ctx context.Context, metaConfig *config.Meta, stapelImageConfig config.StapelImageInterface, targetPlatform string, opts CommonImageOptions) (ImagesSets, error) { + img, err := mapStapelConfigToImage(ctx, metaConfig, stapelImageConfig, targetPlatform, opts) if err != nil { return nil, err } @@ -25,7 +25,7 @@ func MapStapelConfigToImagesSets(ctx context.Context, metaConfig *config.Meta, s return ret, nil } -func mapStapelConfigToImage(ctx context.Context, metaConfig *config.Meta, stapelImageConfig config.StapelImageInterface, opts CommonImageOptions) (*Image, error) { +func mapStapelConfigToImage(ctx context.Context, metaConfig *config.Meta, stapelImageConfig config.StapelImageInterface, targetPlatform string, opts CommonImageOptions) (*Image, error) { imageBaseConfig := stapelImageConfig.ImageBaseConfig() imageName := imageBaseConfig.Name imageArtifact := stapelImageConfig.IsArtifact() @@ -46,7 +46,7 @@ func mapStapelConfigToImage(ctx context.Context, metaConfig *config.Meta, stapel imageOpts.BaseImageName = fromImageName } - image, err := NewImage(ctx, imageName, baseImageType, imageOpts) + image, err := NewImage(ctx, targetPlatform, imageName, baseImageType, imageOpts) if err != nil { return nil, fmt.Errorf("unable to create image %q: %w", imageName, err) } diff --git a/pkg/build/stage/dependencies.go b/pkg/build/stage/dependencies.go index 76899d5b7b..873dbcef75 100644 --- a/pkg/build/stage/dependencies.go +++ b/pkg/build/stage/dependencies.go @@ -324,7 +324,7 @@ func (s *DependenciesStage) generateImportChecksum(ctx context.Context, c Convey ExcludePaths: importElm.ExcludePaths, Owner: importElm.Owner, Group: importElm.Group, - }) + }, container_backend.CalculateDependencyImportChecksum{TargetPlatform: s.targetPlatform}) }) if err != nil { diff --git a/pkg/buildah/common.go b/pkg/buildah/common.go index 555923e4c3..d761db6ba2 100644 --- a/pkg/buildah/common.go +++ b/pkg/buildah/common.go @@ -36,11 +36,8 @@ const ( ) type CommonOpts struct { - LogWriter io.Writer -} - -type BuildFromCommandsOpts struct { - CommonOpts + TargetPlatform string + LogWriter io.Writer } type BuildFromDockerfileOpts struct { @@ -126,16 +123,19 @@ type AddOpts struct { } type ( - FromCommandOpts CommonOpts - PushOpts CommonOpts - PullOpts CommonOpts - TagOpts CommonOpts - MountOpts CommonOpts - UmountOpts CommonOpts - RmOpts CommonOpts + FromCommandOpts CommonOpts + BuildFromCommandsOpts CommonOpts + PushOpts CommonOpts + PullOpts CommonOpts + TagOpts CommonOpts + MountOpts CommonOpts + UmountOpts CommonOpts + RmOpts CommonOpts ) type Buildah interface { + GetDefaultPlatform() string + GetRuntimePlatform() string Tag(ctx context.Context, ref, newRef string, opts TagOpts) error Push(ctx context.Context, ref string, opts PushOpts) error BuildFromDockerfile(ctx context.Context, dockerfile string, opts BuildFromDockerfileOpts) (string, error) @@ -169,7 +169,7 @@ type CommonBuildahOpts struct { } type NativeModeOpts struct { - Platform string + DefaultPlatform string } type BuildahOpts struct { diff --git a/pkg/buildah/native_linux.go b/pkg/buildah/native_linux.go index cb112f5e69..ed2864ca41 100644 --- a/pkg/buildah/native_linux.go +++ b/pkg/buildah/native_linux.go @@ -17,6 +17,7 @@ import ( "syscall" "time" + "github.com/containerd/containerd/platforms" "github.com/containers/buildah" "github.com/containers/buildah/define" "github.com/containers/buildah/docker" @@ -39,7 +40,6 @@ import ( "gopkg.in/errgo.v2/fmt/errors" "github.com/werf/werf/pkg/buildah/thirdparty" - "github.com/werf/werf/pkg/util" ) const ( @@ -72,12 +72,13 @@ type NativeBuildah struct { RegistriesConfigDirPath string Insecure bool - Store storage.Store - Runtime libimage.Runtime - DefaultSystemContext imgtypes.SystemContext - DefaultCommonBuildOptions define.CommonBuildOptions + Store storage.Store - platforms []struct{ OS, Arch, Variant string } + defaultCommonBuildOptions define.CommonBuildOptions + defaultSystemContext imgtypes.SystemContext + defaultPlatform string + defaultPlatformOverrideSpecs []struct{ OS, Arch, Variant string } + runtimePlatform string } func NewNativeBuildah(commonOpts CommonBuildahOpts, opts NativeModeOpts) (*NativeBuildah, error) { @@ -127,7 +128,7 @@ func NewNativeBuildah(commonOpts CommonBuildahOpts, opts NativeModeOpts) (*Nativ return nil, fmt.Errorf("unable to get storage: %w", err) } - b.DefaultSystemContext = imgtypes.SystemContext{ + b.defaultSystemContext = imgtypes.SystemContext{ SignaturePolicyPath: b.SignaturePolicyPath, SystemRegistriesConfPath: b.RegistriesConfigPath, SystemRegistriesConfDirPath: b.RegistriesConfigDirPath, @@ -136,19 +137,25 @@ func NewNativeBuildah(commonOpts CommonBuildahOpts, opts NativeModeOpts) (*Nativ DockerDaemonInsecureSkipTLSVerify: b.Insecure, } - if opts.Platform != "" { - os, arch, variant, err := parse.Platform(opts.Platform) + b.runtimePlatform = platforms.Format(platforms.DefaultSpec()) + + if opts.DefaultPlatform != "" { + b.defaultPlatform = opts.DefaultPlatform + + os, arch, variant, err := parse.Platform(opts.DefaultPlatform) if err != nil { - return nil, fmt.Errorf("unable to parse platform %q: %w", opts.Platform, err) + return nil, fmt.Errorf("unable to parse platform %q: %w", opts.DefaultPlatform, err) } - b.DefaultSystemContext.OSChoice = os - b.DefaultSystemContext.ArchitectureChoice = arch - b.DefaultSystemContext.VariantChoice = variant + b.defaultSystemContext.OSChoice = os + b.defaultSystemContext.ArchitectureChoice = arch + b.defaultSystemContext.VariantChoice = variant - b.platforms = []struct{ OS, Arch, Variant string }{ + b.defaultPlatformOverrideSpecs = []struct{ OS, Arch, Variant string }{ {os, arch, variant}, } + } else { + b.defaultPlatform = b.runtimePlatform } var ulimit []string @@ -162,26 +169,51 @@ func NewNativeBuildah(commonOpts CommonBuildahOpts, opts NativeModeOpts) (*Nativ ulimit = rlimitsToBuildahUlimits(rlimits) } - b.DefaultCommonBuildOptions = define.CommonBuildOptions{ + b.defaultCommonBuildOptions = define.CommonBuildOptions{ ShmSize: DefaultShmSize, Ulimit: ulimit, } imgstor.Transport.SetStore(b.Store) - runtime, err := libimage.RuntimeFromStore(b.Store, &libimage.RuntimeOptions{ - SystemContext: &b.DefaultSystemContext, - }) - if err != nil { - return nil, fmt.Errorf("error getting runtime from store: %w", err) - } - b.Runtime = *runtime return b, nil } +func (b *NativeBuildah) getSystemContext(targetPlatform string) (*imgtypes.SystemContext, error) { + systemContext := new(imgtypes.SystemContext) + *systemContext = b.defaultSystemContext + + if targetPlatform != "" { + os, arch, variant, err := parse.Platform(targetPlatform) + if err != nil { + return nil, fmt.Errorf("unable to parse platform %q: %w", targetPlatform, err) + } + + systemContext.OSChoice = os + systemContext.ArchitectureChoice = arch + systemContext.VariantChoice = variant + } + + return systemContext, nil +} + +func (b *NativeBuildah) getRuntime(systemContext *imgtypes.SystemContext) (*libimage.Runtime, error) { + return libimage.RuntimeFromStore(b.Store, &libimage.RuntimeOptions{ + SystemContext: systemContext, + }) +} + +func (b *NativeBuildah) GetRuntimePlatform() string { + return b.runtimePlatform +} + +func (b *NativeBuildah) GetDefaultPlatform() string { + return b.defaultPlatform +} + // Inspect returns nil, nil if image not found. func (b *NativeBuildah) Inspect(ctx context.Context, ref string) (*thirdparty.BuilderInfo, error) { - builder, err := b.getBuilderFromImage(ctx, ref) + builder, err := b.getBuilderFromImage(ctx, ref, CommonOpts{}) if err != nil { return nil, fmt.Errorf("error doing inspect: %w", err) } @@ -195,7 +227,7 @@ func (b *NativeBuildah) Inspect(ctx context.Context, ref string) (*thirdparty.Bu } func (b *NativeBuildah) Tag(_ context.Context, ref, newRef string, opts TagOpts) error { - image, err := b.getImage(ref) + image, err := b.getImage(ref, CommonOpts(opts)) if err != nil { return err } @@ -208,12 +240,18 @@ func (b *NativeBuildah) Tag(_ context.Context, ref, newRef string, opts TagOpts) } func (b *NativeBuildah) Push(ctx context.Context, ref string, opts PushOpts) error { + // NOTICE: targetPlatform specified for push causes buildah to fail for some unknown reason + sysCtx, err := b.getSystemContext("") + if err != nil { + return err + } + pushOpts := buildah.PushOptions{ Compression: define.Gzip, SignaturePolicyPath: b.SignaturePolicyPath, ReportWriter: opts.LogWriter, Store: b.Store, - SystemContext: &b.DefaultSystemContext, + SystemContext: sysCtx, ManifestType: manifest.DockerV2Schema2MediaType, MaxRetries: MaxPullPushRetries, RetryDelay: PullPushRetryDelay, @@ -232,25 +270,56 @@ func (b *NativeBuildah) Push(ctx context.Context, ref string, opts PushOpts) err } func (b *NativeBuildah) BuildFromDockerfile(ctx context.Context, dockerfile string, opts BuildFromDockerfileOpts) (string, error) { + var targetPlatform string + var targetPlatforms []struct{ OS, Arch, Variant string } + if opts.TargetPlatform != "" { + os, arch, variant, err := parse.Platform(opts.TargetPlatform) + if err != nil { + return "", fmt.Errorf("unable to parse target platform %q: %w", opts.TargetPlatform, err) + } + + targetPlatform = opts.TargetPlatform + targetPlatforms = []struct{ OS, Arch, Variant string }{ + {os, arch, variant}, + } + } else { + targetPlatform = b.defaultPlatform + targetPlatforms = b.defaultPlatformOverrideSpecs + } + + // FIXME(multiarch): Fix warning in the build log: + // FIXME(multiarch): [Warning] one or more build args were not consumed: [TARGETARCH TARGETOS TARGETPLATFORM] + + sysCtx, err := b.getSystemContext(targetPlatform) + if err != nil { + return "", err + } + buildOpts := define.BuildOptions{ Isolation: define.Isolation(b.Isolation), Args: opts.BuildArgs, SignaturePolicyPath: b.SignaturePolicyPath, ReportWriter: opts.LogWriter, OutputFormat: buildah.Dockerv2ImageManifest, - SystemContext: &b.DefaultSystemContext, + SystemContext: sysCtx, ConfigureNetwork: define.NetworkEnabled, - CommonBuildOpts: &b.DefaultCommonBuildOptions, + CommonBuildOpts: &b.defaultCommonBuildOptions, Target: opts.Target, + Platforms: targetPlatforms, MaxPullPushRetries: MaxPullPushRetries, PullPushRetryDelay: PullPushRetryDelay, - Platforms: b.platforms, Layers: true, RemoveIntermediateCtrs: true, ForceRmIntermediateCtrs: false, NoCache: false, } + if targetPlatform != b.GetRuntimePlatform() { + // Prevent local cache collisions in multiplatform build mode: + // allow local cache only for the current runtime platform. + buildOpts.NoCache = true + } + errLog := &bytes.Buffer{} if opts.LogWriter != nil { buildOpts.Out = opts.LogWriter @@ -300,6 +369,11 @@ func (b *NativeBuildah) RunCommand(ctx context.Context, container string, comman stdout, stderr, stderrBuf := generateStdoutStderr(opts.LogWriter) command = prependShellToCommand(opts.PrependShell, opts.Shell, command, builder) + sysCtx, err := b.getSystemContext(opts.TargetPlatform) + if err != nil { + return err + } + runOpts := buildah.RunOptions{ Env: opts.Envs, ContextDir: contextDir, @@ -310,7 +384,7 @@ func (b *NativeBuildah) RunCommand(ctx context.Context, container string, comman NamespaceOptions: nsOpts, ConfigureNetwork: netPolicy, Isolation: define.Isolation(b.Isolation), - SystemContext: &b.DefaultSystemContext, + SystemContext: sysCtx, WorkingDir: opts.WorkingDir, User: opts.User, Entrypoint: []string{}, @@ -331,15 +405,20 @@ func (b *NativeBuildah) RunCommand(ctx context.Context, container string, comman } func (b *NativeBuildah) FromCommand(ctx context.Context, container, image string, opts FromCommandOpts) (string, error) { + sysCtx, err := b.getSystemContext(opts.TargetPlatform) + if err != nil { + return "", err + } + builder, err := buildah.NewBuilder(ctx, b.Store, buildah.BuilderOptions{ FromImage: image, Container: container, SignaturePolicyPath: b.SignaturePolicyPath, ReportWriter: opts.LogWriter, - SystemContext: &b.DefaultSystemContext, + SystemContext: sysCtx, Isolation: define.Isolation(b.Isolation), ConfigureNetwork: define.NetworkEnabled, - CommonBuildOpts: &b.DefaultCommonBuildOptions, + CommonBuildOpts: &b.defaultCommonBuildOptions, Format: buildah.Dockerv2ImageManifest, MaxPullRetries: MaxPullPushRetries, PullRetryDelay: PullPushRetryDelay, @@ -353,11 +432,16 @@ func (b *NativeBuildah) FromCommand(ctx context.Context, container, image string } func (b *NativeBuildah) Pull(ctx context.Context, ref string, opts PullOpts) error { + sysCtx, err := b.getSystemContext(opts.TargetPlatform) + if err != nil { + return err + } + pullOpts := buildah.PullOptions{ SignaturePolicyPath: b.SignaturePolicyPath, ReportWriter: opts.LogWriter, Store: b.Store, - SystemContext: &b.DefaultSystemContext, + SystemContext: sysCtx, MaxRetries: MaxPullPushRetries, RetryDelay: PullPushRetryDelay, PullPolicy: define.PullIfNewer, @@ -374,21 +458,21 @@ func (b *NativeBuildah) Pull(ctx context.Context, ref string, opts PullOpts) 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 { + if sysCtx.OSChoice != "" && sysCtx.OSChoice != imageInspect.OCIv1.OS { platformMismatch = true } - if b.DefaultSystemContext.VariantChoice != "" && b.DefaultSystemContext.VariantChoice != imageInspect.OCIv1.Variant { + if sysCtx.ArchitectureChoice != "" && sysCtx.ArchitectureChoice != imageInspect.OCIv1.Architecture { 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) + imagePlatform := fmt.Sprintf("%s/%s", imageInspect.OCIv1.OS, imageInspect.OCIv1.Architecture) + if imageInspect.OCIv1.Variant != "" { + imagePlatform = fmt.Sprintf("%s/%s", imagePlatform, imageInspect.OCIv1.Variant) + } + expectedPlatform := fmt.Sprintf("%s/%s", sysCtx.OSChoice, sysCtx.ArchitectureChoice) + if sysCtx.VariantChoice != "" { + expectedPlatform = fmt.Sprintf("%s/%s", expectedPlatform, sysCtx.VariantChoice) } return fmt.Errorf("image platform mismatch: image uses %s, expecting %s platform", imagePlatform, expectedPlatform) } @@ -406,7 +490,17 @@ func (b *NativeBuildah) Rm(ctx context.Context, ref string, opts RmOpts) error { } func (b *NativeBuildah) Rmi(ctx context.Context, ref string, opts RmiOpts) error { - _, rmiErrors := b.Runtime.RemoveImages(ctx, []string{ref}, &libimage.RemoveImagesOptions{ + sysCtx, err := b.getSystemContext(opts.TargetPlatform) + if err != nil { + return err + } + + runtime, err := b.getRuntime(sysCtx) + if err != nil { + return err + } + + _, rmiErrors := runtime.RemoveImages(ctx, []string{ref}, &libimage.RemoveImagesOptions{ Force: opts.Force, // Filters: []string{"readonly=false", "intermediate=false", "dangling=true"}, }) @@ -431,11 +525,16 @@ func (b *NativeBuildah) Commit(ctx context.Context, container string, opts Commi builder.SetLabel("werf.io/base-image-id", fmt.Sprintf("sha256:%s", builder.FromImageID)) + sysCtx, err := b.getSystemContext(opts.TargetPlatform) + if err != nil { + return "", err + } + imgID, _, _, err := builder.Commit(ctx, imageRef, buildah.CommitOptions{ PreferredManifestType: buildah.Dockerv2ImageManifest, SignaturePolicyPath: b.SignaturePolicyPath, ReportWriter: opts.LogWriter, - SystemContext: &b.DefaultSystemContext, + SystemContext: sysCtx, MaxRetries: MaxPullPushRetries, RetryDelay: PullPushRetryDelay, }) @@ -600,8 +699,18 @@ func (b *NativeBuildah) Add(ctx context.Context, container string, src []string, return nil } -func (b *NativeBuildah) getImage(ref string) (*libimage.Image, error) { - image, _, err := b.Runtime.LookupImage(ref, &libimage.LookupImageOptions{ +func (b *NativeBuildah) getImage(ref string, opts CommonOpts) (*libimage.Image, error) { + sysCtx, err := b.getSystemContext(opts.TargetPlatform) + if err != nil { + return nil, err + } + + runtime, err := b.getRuntime(sysCtx) + if err != nil { + return nil, err + } + + image, _, err := runtime.LookupImage(ref, &libimage.LookupImageOptions{ ManifestList: true, }) if err != nil { @@ -612,11 +721,16 @@ func (b *NativeBuildah) getImage(ref string) (*libimage.Image, error) { } // getBuilderFromImage returns nil, nil if image not found. -func (b *NativeBuildah) getBuilderFromImage(ctx context.Context, imgName string) (builder *buildah.Builder, err error) { +func (b *NativeBuildah) getBuilderFromImage(ctx context.Context, imgName string, opts CommonOpts) (builder *buildah.Builder, err error) { + sysCtx, err := b.getSystemContext(opts.TargetPlatform) + if err != nil { + return nil, err + } + builder, err = buildah.ImportBuilderFromImage(ctx, b.Store, buildah.ImportFromImageOptions{ Image: imgName, SignaturePolicyPath: b.SignaturePolicyPath, - SystemContext: &b.DefaultSystemContext, + SystemContext: sysCtx, }) switch { case err != nil && strings.HasSuffix(err.Error(), storage.ErrImageUnknown.Error()): @@ -678,31 +792,6 @@ func (b *NativeBuildah) NewSessionTmpDir() (string, error) { return sessionTmpDir, nil } -func (b *NativeBuildah) prepareBuildFromDockerfile(dockerfile []byte, contextTar io.Reader) (string, string, string, error) { - sessionTmpDir, err := b.NewSessionTmpDir() - if err != nil { - return "", "", "", err - } - - dockerfileTmpPath := filepath.Join(sessionTmpDir, "Dockerfile") - if err := ioutil.WriteFile(dockerfileTmpPath, dockerfile, os.ModePerm); err != nil { - return "", "", "", fmt.Errorf("error writing %q: %w", dockerfileTmpPath, err) - } - - contextTmpDir := filepath.Join(sessionTmpDir, "context") - if err := os.MkdirAll(contextTmpDir, os.ModePerm); err != nil { - return "", "", "", fmt.Errorf("unable to create dir %q: %w", contextTmpDir, err) - } - - if contextTar != nil { - if err := util.ExtractTar(contextTar, contextTmpDir, util.ExtractTarOptions{}); err != nil { - return "", "", "", fmt.Errorf("unable to extract context tar to tmp context dir: %w", err) - } - } - - return sessionTmpDir, contextTmpDir, dockerfileTmpPath, nil -} - func NewNativeStoreOptions(rootlessUID int, driver StorageDriver) (*thirdparty.StoreOptions, error) { var ( runRoot string diff --git a/pkg/config/raw_meta_build.go b/pkg/config/raw_meta_build.go index 03366c4415..e8c1e2114c 100644 --- a/pkg/config/raw_meta_build.go +++ b/pkg/config/raw_meta_build.go @@ -1,7 +1,7 @@ package config type rawMetaBuild struct { - Platforms []string `yaml:"platforms,omitempty"` + Platform []string `yaml:"platform,omitempty"` rawMeta *rawMeta @@ -30,6 +30,6 @@ func (c *rawMetaBuild) UnmarshalYAML(unmarshal func(interface{}) error) error { func (c *rawMetaBuild) toMetaBuild() MetaBuild { metaBuild := MetaBuild{} - metaBuild.Platform = c.Platforms + metaBuild.Platform = c.Platform return metaBuild } diff --git a/pkg/container_backend/build_stapel_stage_options.go b/pkg/container_backend/build_stapel_stage_options.go index 58686d5eda..03419333eb 100644 --- a/pkg/container_backend/build_stapel_stage_options.go +++ b/pkg/container_backend/build_stapel_stage_options.go @@ -29,6 +29,8 @@ type BuildStapelStageOptionsInterface interface { } type BuildStapelStageOptions struct { + TargetPlatform string + Labels []string Volumes []string Expose []string diff --git a/pkg/container_backend/buildah_backend.go b/pkg/container_backend/buildah_backend.go index 0477db6ca2..0db313bbe3 100644 --- a/pkg/container_backend/buildah_backend.go +++ b/pkg/container_backend/buildah_backend.go @@ -42,26 +42,27 @@ func NewBuildahBackend(buildah buildah.Buildah, opts BuildahBackendOptions) *Bui return &BuildahBackend{buildah: buildah, BuildahBackendOptions: opts} } -func (runtime *BuildahBackend) HasStapelBuildSupport() bool { +func (backend *BuildahBackend) HasStapelBuildSupport() bool { return true } -func (runtime *BuildahBackend) IsTargetPlatformSupportedForStapel(targetPlatform string) bool { - return true +func (backend *BuildahBackend) GetDefaultPlatform() string { + return backend.buildah.GetDefaultPlatform() } -func (runtime *BuildahBackend) IsTargetPlatformSupportedForStagedDockerfile(targetPlatform string) bool { - return true +func (backend *BuildahBackend) GetRuntimePlatform() string { + return backend.buildah.GetRuntimePlatform() } -func (runtime *BuildahBackend) IsTargetPlatformSupportedForDockerfile(targetPlatform string) bool { - return true -} - -func (runtime *BuildahBackend) getBuildahCommonOpts(ctx context.Context, suppressLog bool) (opts buildah.CommonOpts) { +func (backend *BuildahBackend) getBuildahCommonOpts(ctx context.Context, suppressLog bool, logWriterOverride io.Writer, targetPlatform string) (opts buildah.CommonOpts) { if !suppressLog { - opts.LogWriter = logboek.Context(ctx).OutStream() + if logWriterOverride != nil { + opts.LogWriter = logWriterOverride + } else { + opts.LogWriter = logboek.Context(ctx).OutStream() + } } + opts.TargetPlatform = targetPlatform return } @@ -72,7 +73,7 @@ type containerDesc struct { RootMount string } -func (runtime *BuildahBackend) createContainers(ctx context.Context, images []string) ([]*containerDesc, error) { +func (backend *BuildahBackend) createContainers(ctx context.Context, images []string, opts CommonOpts) ([]*containerDesc, error) { var res []*containerDesc for _, img := range images { @@ -82,7 +83,7 @@ func (runtime *BuildahBackend) createContainers(ctx context.Context, images []st panic("cannot start container for an empty image param") } - _, err := runtime.buildah.FromCommand(ctx, containerID, img, buildah.FromCommandOpts(runtime.getBuildahCommonOpts(ctx, true))) + _, err := backend.buildah.FromCommand(ctx, containerID, img, buildah.FromCommandOpts(backend.getBuildahCommonOpts(ctx, true, nil, opts.TargetPlatform))) if err != nil { return nil, fmt.Errorf("unable to create container using base image %q: %w", img, err) } @@ -94,9 +95,9 @@ func (runtime *BuildahBackend) createContainers(ctx context.Context, images []st return res, nil } -func (runtime *BuildahBackend) removeContainers(ctx context.Context, containers []*containerDesc) error { +func (backend *BuildahBackend) removeContainers(ctx context.Context, containers []*containerDesc, opts CommonOpts) error { for _, cont := range containers { - if err := runtime.buildah.Rm(ctx, cont.Name, buildah.RmOpts(runtime.getBuildahCommonOpts(ctx, true))); err != nil { + if err := backend.buildah.Rm(ctx, cont.Name, buildah.RmOpts(backend.getBuildahCommonOpts(ctx, true, nil, opts.TargetPlatform))); err != nil { return fmt.Errorf("unable to remove container %q: %w", cont.Name, err) } } @@ -104,9 +105,9 @@ func (runtime *BuildahBackend) removeContainers(ctx context.Context, containers return nil } -func (runtime *BuildahBackend) mountContainers(ctx context.Context, containers []*containerDesc) error { +func (backend *BuildahBackend) mountContainers(ctx context.Context, containers []*containerDesc, opts CommonOpts) error { for _, cont := range containers { - containerRoot, err := runtime.buildah.Mount(ctx, cont.Name, buildah.MountOpts(runtime.getBuildahCommonOpts(ctx, true))) + containerRoot, err := backend.buildah.Mount(ctx, cont.Name, buildah.MountOpts(backend.getBuildahCommonOpts(ctx, true, nil, opts.TargetPlatform))) if err != nil { return fmt.Errorf("unable to mount container %q root dir: %w", cont.Name, err) } @@ -116,9 +117,9 @@ func (runtime *BuildahBackend) mountContainers(ctx context.Context, containers [ return nil } -func (runtime *BuildahBackend) unmountContainers(ctx context.Context, containers []*containerDesc) error { +func (backend *BuildahBackend) unmountContainers(ctx context.Context, containers []*containerDesc, opts CommonOpts) error { for _, cont := range containers { - if err := runtime.buildah.Umount(ctx, cont.Name, buildah.UmountOpts(runtime.getBuildahCommonOpts(ctx, true))); err != nil { + if err := backend.buildah.Umount(ctx, cont.Name, buildah.UmountOpts(backend.getBuildahCommonOpts(ctx, true, nil, opts.TargetPlatform))); err != nil { return fmt.Errorf("container %q: %w", cont.Name, err) } } @@ -153,8 +154,8 @@ fi `, strings.Join(scriptCommands, "\n"))) } -func (runtime *BuildahBackend) applyCommands(ctx context.Context, container *containerDesc, buildVolumes, commands []string) error { - hostScriptPath := filepath.Join(runtime.TmpDir, fmt.Sprintf("script-%s.sh", uuid.New().String())) +func (backend *BuildahBackend) applyCommands(ctx context.Context, container *containerDesc, buildVolumes, commands []string, opts CommonOpts) error { + hostScriptPath := filepath.Join(backend.TmpDir, fmt.Sprintf("script-%s.sh", uuid.New().String())) if err := os.WriteFile(hostScriptPath, makeScript(commands), os.FileMode(0o555)); err != nil { return fmt.Errorf("unable to write script file %q: %w", hostScriptPath, err) } @@ -177,8 +178,8 @@ func (runtime *BuildahBackend) applyCommands(ctx context.Context, container *con mounts = append(mounts, m...) } - if err := runtime.buildah.RunCommand(ctx, container.Name, []string{"sh", destScriptPath}, buildah.RunCommandOpts{ - CommonOpts: runtime.getBuildahCommonOpts(ctx, false), + if err := backend.buildah.RunCommand(ctx, container.Name, []string{"sh", destScriptPath}, buildah.RunCommandOpts{ + CommonOpts: backend.getBuildahCommonOpts(ctx, false, nil, opts.TargetPlatform), User: "0:0", WorkingDir: "/", GlobalMounts: mounts, @@ -189,28 +190,28 @@ func (runtime *BuildahBackend) applyCommands(ctx context.Context, container *con return nil } -func (runtime *BuildahBackend) CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec) (string, error) { +func (backend *BuildahBackend) CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec, opts CalculateDependencyImportChecksum) (string, error) { // TODO(2.0): Take into account empty dirs var container *containerDesc - if c, err := runtime.createContainers(ctx, []string{dependencyImport.ImageName}); err != nil { + if c, err := backend.createContainers(ctx, []string{dependencyImport.ImageName}, CommonOpts(opts)); err != nil { return "", err } else { container = c[0] } defer func() { - if err := runtime.removeContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.removeContainers(ctx, []*containerDesc{container}, CommonOpts(opts)); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to remove temporal dependency container %q: %s\n", container.Name, err) } }() logboek.Context(ctx).Debug().LogF("Mounting dependency container %s\n", container.Name) - if err := runtime.mountContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.mountContainers(ctx, []*containerDesc{container}, CommonOpts(opts)); err != nil { return "", fmt.Errorf("unable to mount build container %s: %w", container.Name, err) } defer func() { logboek.Context(ctx).Debug().LogF("Unmounting build container %s\n", container.Name) - if err := runtime.unmountContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.unmountContainers(ctx, []*containerDesc{container}, CommonOpts(opts)); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to unmount containers: %s\n", err) } }() @@ -274,7 +275,7 @@ func (runtime *BuildahBackend) CalculateDependencyImportChecksum(ctx context.Con return fmt.Sprintf("%x", hash.Sum(nil)), nil } -func (runtime *BuildahBackend) applyDataArchives(ctx context.Context, container *containerDesc, dataArchives []DataArchiveSpec) error { +func (backend *BuildahBackend) applyDataArchives(ctx context.Context, container *containerDesc, dataArchives []DataArchiveSpec) error { for _, archive := range dataArchives { destPath := filepath.Join(container.RootMount, archive.To) @@ -321,7 +322,7 @@ func (runtime *BuildahBackend) applyDataArchives(ctx context.Context, container return nil } -func (runtime *BuildahBackend) applyRemoveData(ctx context.Context, container *containerDesc, removeData []RemoveDataSpec) error { +func (backend *BuildahBackend) applyRemoveData(ctx context.Context, container *containerDesc, removeData []RemoveDataSpec) error { for _, spec := range removeData { switch spec.Type { case RemoveExactPath: @@ -353,7 +354,7 @@ func (runtime *BuildahBackend) applyRemoveData(ctx context.Context, container *c return nil } -func (runtime *BuildahBackend) applyDependenciesImports(ctx context.Context, container *containerDesc, depImports []DependencyImportSpec) error { +func (backend *BuildahBackend) applyDependenciesImports(ctx context.Context, container *containerDesc, depImports []DependencyImportSpec, opts CommonOpts) error { var depImages []string for _, imp := range depImports { if util.IsStringsContainValue(depImages, imp.ImageName) { @@ -364,24 +365,24 @@ func (runtime *BuildahBackend) applyDependenciesImports(ctx context.Context, con } logboek.Context(ctx).Debug().LogF("Creating containers for depContainers images %v\n", depImages) - createdDepContainers, err := runtime.createContainers(ctx, depImages) + createdDepContainers, err := backend.createContainers(ctx, depImages, opts) if err != nil { return fmt.Errorf("unable to create depContainers containers: %w", err) } defer func() { - if err := runtime.removeContainers(ctx, createdDepContainers); err != nil { + if err := backend.removeContainers(ctx, createdDepContainers, opts); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to remove temporal depContainers containers: %s\n", err) } }() // NOTE: maybe it is more optimal not to mount all dependencies at once, but mount one-by-one logboek.Context(ctx).Debug().LogF("Mounting depContainers containers %v\n", createdDepContainers) - if err := runtime.mountContainers(ctx, createdDepContainers); err != nil { + if err := backend.mountContainers(ctx, createdDepContainers, opts); err != nil { return fmt.Errorf("unable to mount containers: %w", err) } defer func() { logboek.Context(ctx).Debug().LogF("Unmounting depContainers containers %v\n", createdDepContainers) - if err := runtime.unmountContainers(ctx, createdDepContainers); err != nil { + if err := backend.unmountContainers(ctx, createdDepContainers, opts); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to unmount containers: %s\n", err) } }() @@ -438,28 +439,28 @@ func (runtime *BuildahBackend) applyDependenciesImports(ctx context.Context, con return nil } -func (runtime *BuildahBackend) BuildDockerfileStage(ctx context.Context, baseImage string, opts BuildDockerfileStageOptions, instructions ...InstructionInterface) (string, error) { +func (backend *BuildahBackend) BuildDockerfileStage(ctx context.Context, baseImage string, opts BuildDockerfileStageOptions, instructions ...InstructionInterface) (string, error) { var container *containerDesc - if c, err := runtime.createContainers(ctx, []string{baseImage}); err != nil { + if c, err := backend.createContainers(ctx, []string{baseImage}, opts.CommonOpts); err != nil { return "", err } else { container = c[0] } defer func() { - if err := runtime.removeContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.removeContainers(ctx, []*containerDesc{container}, opts.CommonOpts); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to remove temporary build container: %s\n", err) } }() // TODO: cleanup orphan build containers in werf-host-cleanup procedure logboek.Context(ctx).Debug().LogF("Mounting build container %s\n", container.Name) - if err := runtime.mountContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.mountContainers(ctx, []*containerDesc{container}, opts.CommonOpts); err != nil { return "", fmt.Errorf("unable to mount build container %s: %w", container.Name, err) } defer func() { logboek.Context(ctx).Debug().LogF("Unmounting build container %s\n", container.Name) - if err := runtime.unmountContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.unmountContainers(ctx, []*containerDesc{container}, opts.CommonOpts); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to unmount containers: %s\n", err) } }() @@ -467,14 +468,14 @@ func (runtime *BuildahBackend) BuildDockerfileStage(ctx context.Context, baseIma logboek.Context(ctx).Debug().LogF("Executing commands for build container %s: %#v\n", container.Name, instructions) for _, instruction := range instructions { - if err := instruction.Apply(ctx, container.Name, runtime.buildah, runtime.getBuildahCommonOpts(ctx, false), opts.BuildContextArchive); err != nil { + if err := instruction.Apply(ctx, container.Name, backend.buildah, backend.getBuildahCommonOpts(ctx, false, nil, opts.TargetPlatform), opts.BuildContextArchive); err != nil { return "", fmt.Errorf("unable to apply instruction %s: %w", instruction.Name(), err) } } logboek.Context(ctx).Debug().LogF("Committing build container %s\n", container.Name) - imageID, err := runtime.buildah.Commit(ctx, container.Name, buildah.CommitOpts{ - CommonOpts: runtime.getBuildahCommonOpts(ctx, true), + imageID, err := backend.buildah.Commit(ctx, container.Name, buildah.CommitOpts{ + CommonOpts: backend.getBuildahCommonOpts(ctx, true, nil, opts.TargetPlatform), }) if err != nil { return "", fmt.Errorf("error committing container %s: %w", container.Name, err) @@ -483,15 +484,17 @@ func (runtime *BuildahBackend) BuildDockerfileStage(ctx context.Context, baseIma return imageID, nil } -func (runtime *BuildahBackend) BuildStapelStage(ctx context.Context, baseImage string, opts BuildStapelStageOptions) (string, error) { +func (backend *BuildahBackend) BuildStapelStage(ctx context.Context, baseImage string, opts BuildStapelStageOptions) (string, error) { + commonOpts := CommonOpts{TargetPlatform: opts.TargetPlatform} + var container *containerDesc - if c, err := runtime.createContainers(ctx, []string{baseImage}); err != nil { + if c, err := backend.createContainers(ctx, []string{baseImage}, commonOpts); err != nil { return "", err } else { container = c[0] } defer func() { - if err := runtime.removeContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.removeContainers(ctx, []*containerDesc{container}, commonOpts); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to remove temporal build container: %s\n", err) } }() @@ -499,34 +502,34 @@ func (runtime *BuildahBackend) BuildStapelStage(ctx context.Context, baseImage s if len(opts.DependencyImportSpecs)+len(opts.DataArchiveSpecs)+len(opts.RemoveDataSpecs) > 0 { logboek.Context(ctx).Debug().LogF("Mounting build container %s\n", container.Name) - if err := runtime.mountContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.mountContainers(ctx, []*containerDesc{container}, commonOpts); err != nil { return "", fmt.Errorf("unable to mount build container %s: %w", container.Name, err) } defer func() { logboek.Context(ctx).Debug().LogF("Unmounting build container %s\n", container.Name) - if err := runtime.unmountContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.unmountContainers(ctx, []*containerDesc{container}, commonOpts); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to unmount containers: %s\n", err) } }() } if len(opts.DependencyImportSpecs) > 0 { - if err := runtime.applyDependenciesImports(ctx, container, opts.DependencyImportSpecs); err != nil { + if err := backend.applyDependenciesImports(ctx, container, opts.DependencyImportSpecs, commonOpts); err != nil { return "", err } } if len(opts.DataArchiveSpecs) > 0 { - if err := runtime.applyDataArchives(ctx, container, opts.DataArchiveSpecs); err != nil { + if err := backend.applyDataArchives(ctx, container, opts.DataArchiveSpecs); err != nil { return "", err } } if len(opts.RemoveDataSpecs) > 0 { - if err := runtime.applyRemoveData(ctx, container, opts.RemoveDataSpecs); err != nil { + if err := backend.applyRemoveData(ctx, container, opts.RemoveDataSpecs); err != nil { return "", err } } if len(opts.Commands) > 0 { - if err := runtime.applyCommands(ctx, container, opts.BuildVolumes, opts.Commands); err != nil { + if err := backend.applyCommands(ctx, container, opts.BuildVolumes, opts.Commands, commonOpts); err != nil { return "", err } } @@ -537,8 +540,8 @@ func (runtime *BuildahBackend) BuildStapelStage(ctx context.Context, baseImage s } logboek.Context(ctx).Debug().LogF("Setting config for build container %q\n", container.Name) - if err := runtime.buildah.Config(ctx, container.Name, buildah.ConfigOpts{ - CommonOpts: runtime.getBuildahCommonOpts(ctx, true), + if err := backend.buildah.Config(ctx, container.Name, buildah.ConfigOpts{ + CommonOpts: backend.getBuildahCommonOpts(ctx, true, nil, opts.TargetPlatform), Labels: opts.Labels, Volumes: opts.Volumes, Expose: opts.Expose, @@ -555,7 +558,7 @@ func (runtime *BuildahBackend) BuildStapelStage(ctx context.Context, baseImage s // TODO(stapel-to-buildah): Save container name as builtID. There is no need to commit an image here, // because buildah allows to commit and push directly container, which would happen later. logboek.Context(ctx).Debug().LogF("committing container %q\n", container.Name) - imgID, err := runtime.buildah.Commit(ctx, container.Name, buildah.CommitOpts{CommonOpts: runtime.getBuildahCommonOpts(ctx, true)}) + imgID, err := backend.buildah.Commit(ctx, container.Name, buildah.CommitOpts{CommonOpts: backend.getBuildahCommonOpts(ctx, true, nil, opts.TargetPlatform)}) if err != nil { return "", fmt.Errorf("unable to commit container %q: %w", container.Name, err) } @@ -564,8 +567,8 @@ func (runtime *BuildahBackend) BuildStapelStage(ctx context.Context, baseImage s } // GetImageInfo returns nil, nil if image not found. -func (runtime *BuildahBackend) GetImageInfo(ctx context.Context, ref string, opts GetImageInfoOpts) (*image.Info, error) { - inspect, err := runtime.buildah.Inspect(ctx, ref) +func (backend *BuildahBackend) GetImageInfo(ctx context.Context, ref string, opts GetImageInfoOpts) (*image.Info, error) { + inspect, err := backend.buildah.Inspect(ctx, ref) if err != nil { return nil, fmt.Errorf("error getting buildah inspect of %q: %w", ref, err) } @@ -597,54 +600,55 @@ func (runtime *BuildahBackend) GetImageInfo(ctx context.Context, ref string, opt }, nil } -func (runtime *BuildahBackend) Rmi(ctx context.Context, ref string, opts RmiOpts) error { +func (backend *BuildahBackend) Rmi(ctx context.Context, ref string, opts RmiOpts) error { var logWriter io.Writer if logboek.Context(ctx).Info().IsAccepted() { logWriter = logboek.Context(ctx).OutStream() } - return runtime.buildah.Rmi(ctx, ref, buildah.RmiOpts{ - Force: true, - CommonOpts: buildah.CommonOpts{ - LogWriter: logWriter, - }, + return backend.buildah.Rmi(ctx, ref, buildah.RmiOpts{ + Force: true, + CommonOpts: backend.getBuildahCommonOpts(ctx, false, logWriter, opts.TargetPlatform), }) } -func (runtime *BuildahBackend) Pull(ctx context.Context, ref string, opts PullOpts) error { +func (backend *BuildahBackend) Pull(ctx context.Context, ref string, opts PullOpts) error { var logWriter io.Writer if logboek.Context(ctx).Info().IsAccepted() { logWriter = logboek.Context(ctx).OutStream() } - return runtime.buildah.Pull(ctx, ref, buildah.PullOpts{ - LogWriter: logWriter, - }) + return backend.buildah.Pull( + ctx, ref, + buildah.PullOpts(backend.getBuildahCommonOpts(ctx, false, logWriter, opts.TargetPlatform)), + ) } -func (runtime *BuildahBackend) Tag(ctx context.Context, ref, newRef string, opts TagOpts) error { +func (backend *BuildahBackend) Tag(ctx context.Context, ref, newRef string, opts TagOpts) error { var logWriter io.Writer if logboek.Context(ctx).Info().IsAccepted() { logWriter = logboek.Context(ctx).OutStream() } - return runtime.buildah.Tag(ctx, ref, newRef, buildah.TagOpts{ - LogWriter: logWriter, - }) + return backend.buildah.Tag( + ctx, ref, newRef, + buildah.TagOpts(backend.getBuildahCommonOpts(ctx, false, logWriter, opts.TargetPlatform)), + ) } -func (runtime *BuildahBackend) Push(ctx context.Context, ref string, opts PushOpts) error { +func (backend *BuildahBackend) Push(ctx context.Context, ref string, opts PushOpts) error { var logWriter io.Writer if logboek.Context(ctx).Info().IsAccepted() { logWriter = logboek.Context(ctx).OutStream() } - return runtime.buildah.Push(ctx, ref, buildah.PushOpts{ - LogWriter: logWriter, - }) + return backend.buildah.Push( + ctx, ref, + buildah.PushOpts(backend.getBuildahCommonOpts(ctx, false, logWriter, opts.TargetPlatform)), + ) } -func (runtime *BuildahBackend) BuildDockerfile(ctx context.Context, dockerfileContent []byte, opts BuildDockerfileOpts) (string, error) { +func (backend *BuildahBackend) BuildDockerfile(ctx context.Context, dockerfileContent []byte, opts BuildDockerfileOpts) (string, error) { buildArgs := make(map[string]string) for _, argStr := range opts.BuildArgs { argParts := strings.SplitN(argStr, "=", 2) @@ -659,7 +663,7 @@ func (runtime *BuildahBackend) BuildDockerfile(ctx context.Context, dockerfileCo return "", fmt.Errorf("unable to extract build context: %w", err) } - dockerfile, err := ioutil.TempFile(runtime.TmpDir, "*.Dockerfile") + dockerfile, err := ioutil.TempFile(backend.TmpDir, "*.Dockerfile") if err != nil { return "", fmt.Errorf("error creating temporary dockerfile: %w", err) } @@ -673,22 +677,20 @@ func (runtime *BuildahBackend) BuildDockerfile(ctx context.Context, dockerfileCo } }() - return runtime.buildah.BuildFromDockerfile(ctx, dockerfile.Name(), buildah.BuildFromDockerfileOpts{ - CommonOpts: buildah.CommonOpts{ - LogWriter: logboek.Context(ctx).OutStream(), - }, + return backend.buildah.BuildFromDockerfile(ctx, dockerfile.Name(), buildah.BuildFromDockerfileOpts{ + CommonOpts: backend.getBuildahCommonOpts(ctx, false, nil, opts.TargetPlatform), ContextDir: buildContextTmpDir, BuildArgs: buildArgs, Target: opts.Target, }) } -func (runtime *BuildahBackend) ShouldCleanupDockerfileImage() bool { +func (backend *BuildahBackend) ShouldCleanupDockerfileImage() bool { return false } -func (runtime *BuildahBackend) RefreshImageObject(ctx context.Context, img LegacyImageInterface) error { - if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { +func (backend *BuildahBackend) RefreshImageObject(ctx context.Context, img LegacyImageInterface) error { + if info, err := backend.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return err } else { img.SetInfo(info) @@ -696,12 +698,12 @@ func (runtime *BuildahBackend) RefreshImageObject(ctx context.Context, img Legac return nil } -func (runtime *BuildahBackend) PullImageFromRegistry(ctx context.Context, img LegacyImageInterface) error { - if err := runtime.Pull(ctx, img.Name(), PullOpts{}); err != nil { +func (backend *BuildahBackend) PullImageFromRegistry(ctx context.Context, img LegacyImageInterface) error { + if err := backend.Pull(ctx, img.Name(), PullOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to pull image %s: %w", img.Name(), err) } - if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { + if info, err := backend.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to get inspect of image %s: %w", img.Name(), err) } else { img.SetInfo(info) @@ -710,9 +712,9 @@ func (runtime *BuildahBackend) PullImageFromRegistry(ctx context.Context, img Le return nil } -func (runtime *BuildahBackend) RenameImage(ctx context.Context, img LegacyImageInterface, newImageName string, removeOldName bool) error { +func (backend *BuildahBackend) RenameImage(ctx context.Context, img LegacyImageInterface, newImageName string, removeOldName bool) error { if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Tagging image %s by name %s", img.Name(), newImageName)).DoError(func() error { - if err := runtime.Tag(ctx, img.Name(), newImageName, TagOpts{}); err != nil { + if err := backend.Tag(ctx, img.Name(), newImageName, TagOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to tag image %s by name %s: %w", img.Name(), newImageName, err) } return nil @@ -722,7 +724,7 @@ func (runtime *BuildahBackend) RenameImage(ctx context.Context, img LegacyImageI if removeOldName { if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Removing old image tag %s", img.Name())).DoError(func() error { - if err := runtime.Rmi(ctx, img.Name(), RmiOpts{}); err != nil { + if err := backend.Rmi(ctx, img.Name(), RmiOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to remove image %q: %w", img.Name(), err) } return nil @@ -733,7 +735,7 @@ func (runtime *BuildahBackend) RenameImage(ctx context.Context, img LegacyImageI img.SetName(newImageName) - if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { + if info, err := backend.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return err } else { img.SetInfo(info) @@ -749,9 +751,9 @@ func (runtime *BuildahBackend) RenameImage(ctx context.Context, img LegacyImageI return nil } -func (runtime *BuildahBackend) RemoveImage(ctx context.Context, img LegacyImageInterface) error { +func (backend *BuildahBackend) RemoveImage(ctx context.Context, img LegacyImageInterface) error { if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Removing image tag %s", img.Name())).DoError(func() error { - if err := runtime.Rmi(ctx, img.Name(), RmiOpts{}); err != nil { + if err := backend.Rmi(ctx, img.Name(), RmiOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to remove image %q: %w", img.Name(), err) } return nil @@ -762,19 +764,19 @@ func (runtime *BuildahBackend) RemoveImage(ctx context.Context, img LegacyImageI return nil } -func (runtime *BuildahBackend) String() string { +func (backend *BuildahBackend) String() string { return "buildah-runtime" } -func (runtime *BuildahBackend) RemoveHostDirs(ctx context.Context, mountDir string, dirs []string) error { +func (backend *BuildahBackend) RemoveHostDirs(ctx context.Context, mountDir string, dirs []string) error { var container *containerDesc - if c, err := runtime.createContainers(ctx, []string{"alpine"}); err != nil { + if c, err := backend.createContainers(ctx, []string{"alpine"}, CommonOpts{}); err != nil { return fmt.Errorf("unable to create container based on alpine: %w", err) } else { container = c[0] } defer func() { - if err := runtime.removeContainers(ctx, []*containerDesc{container}); err != nil { + if err := backend.removeContainers(ctx, []*containerDesc{container}, CommonOpts{}); err != nil { logboek.Context(ctx).Error().LogF("ERROR: unable to remove temporal container %q: %s\n", container.Name, err) } }() @@ -783,7 +785,7 @@ func (runtime *BuildahBackend) RemoveHostDirs(ctx context.Context, mountDir stri containerDirs = append(containerDirs, util.ToLinuxContainerPath(dir)) } - return runtime.buildah.RunCommand(ctx, container.Name, append([]string{"rm", "-rf"}, containerDirs...), buildah.RunCommandOpts{ + return backend.buildah.RunCommand(ctx, container.Name, append([]string{"rm", "-rf"}, containerDirs...), buildah.RunCommandOpts{ User: "0:0", WorkingDir: "/", GlobalMounts: []*specs.Mount{ diff --git a/pkg/container_backend/docker_server_backend.go b/pkg/container_backend/docker_server_backend.go index c377474fe7..0f24969e18 100644 --- a/pkg/container_backend/docker_server_backend.go +++ b/pkg/container_backend/docker_server_backend.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "os" - go_runtime "runtime" "strings" "github.com/docker/docker/api/types" @@ -23,41 +22,23 @@ func NewDockerServerBackend() *DockerServerBackend { return &DockerServerBackend{} } -func (runtime *DockerServerBackend) HasStapelBuildSupport() bool { - return false +func (runtime *DockerServerBackend) GetDefaultPlatform() string { + return docker.GetDefaultPlatform() } -func (runtime *DockerServerBackend) IsTargetPlatformSupportedForStapel(targetPlatform string) bool { - if targetPlatform == "" { - // werf uses current host platform in such case, - // non amd64 platform is not supported for stapel-builder+docker-server backend - // because of usage of werf's service image (stapel image is built only for amd64). - - if go_runtime.GOARCH != "amd64" { - return false - } - } else if targetPlatform != "linux/amd64" { - // user specified unsupported target platform - return false - } - - return true +func (runtime *DockerServerBackend) GetRuntimePlatform() string { + return docker.GetRuntimePlatform() } -func (runtime *DockerServerBackend) IsTargetPlatformSupportedForStagedDockerfile(targetPlatform string) bool { - // no staged dockerfile support at all +func (runtime *DockerServerBackend) HasStapelBuildSupport() bool { return false } -func (runtime *DockerServerBackend) IsTargetPlatformSupportedForDockerfile(targetPlatform string) bool { - return true -} - func (runtime *DockerServerBackend) BuildStapelStage(ctx context.Context, baseImage string, opts BuildStapelStageOptions) (string, error) { panic("BuildStapelStage does not implemented for DockerServerBackend. Please report the bug if you've received this message.") } -func (runtime *DockerServerBackend) CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec) (string, error) { +func (runtime *DockerServerBackend) CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec, opts CalculateDependencyImportChecksum) (string, error) { panic("CalculateDependencyImportChecksum does not implemented for DockerServerBackend. Please report the bug if you've received this message.") } @@ -70,8 +51,11 @@ func (runtime *DockerServerBackend) BuildDockerfile(ctx context.Context, _ []byt } var cliArgs []string - cliArgs = append(cliArgs, "--file", opts.DockerfileCtxRelPath) + + if opts.TargetPlatform != "" { + cliArgs = append(cliArgs, "--platform", opts.TargetPlatform) + } if opts.Target != "" { cliArgs = append(cliArgs, "--target", opts.Target) } @@ -144,7 +128,7 @@ func (runtime *DockerServerBackend) GetImageInspect(ctx context.Context, ref str } func (runtime *DockerServerBackend) RefreshImageObject(ctx context.Context, img LegacyImageInterface) error { - if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return err } else { img.SetInfo(info) @@ -152,6 +136,7 @@ func (runtime *DockerServerBackend) RefreshImageObject(ctx context.Context, img return nil } +// FIXME(multiarch): targetPlatform support needed? func (runtime *DockerServerBackend) RenameImage(ctx context.Context, img LegacyImageInterface, newImageName string, removeOldName bool) error { if err := logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Tagging image %s by name %s", img.Name(), newImageName)).DoError(func() error { if err := docker.CliTag(ctx, img.Name(), newImageName); err != nil { @@ -175,7 +160,7 @@ func (runtime *DockerServerBackend) RenameImage(ctx context.Context, img LegacyI img.SetName(newImageName) - if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return err } else { img.SetInfo(info) @@ -193,7 +178,7 @@ func (runtime *DockerServerBackend) RenameImage(ctx context.Context, img LegacyI func (runtime *DockerServerBackend) RemoveImage(ctx context.Context, img LegacyImageInterface) error { return logboek.Context(ctx).Info().LogProcess(fmt.Sprintf("Removing image tag %s", img.Name())).DoError(func() error { - return runtime.Rmi(ctx, img.Name(), RmiOpts{}) + return runtime.Rmi(ctx, img.Name(), RmiOpts{TargetPlatform: img.GetTargetPlatform()}) }) } @@ -202,7 +187,7 @@ func (runtime *DockerServerBackend) PullImageFromRegistry(ctx context.Context, i return fmt.Errorf("unable to pull image %s: %w", img.Name(), err) } - if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{}); err != nil { + if info, err := runtime.GetImageInfo(ctx, img.Name(), GetImageInfoOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to get inspect of image %s: %w", img.Name(), err) } else { img.SetInfo(info) @@ -220,7 +205,13 @@ func (runtime *DockerServerBackend) Push(ctx context.Context, ref string, opts P } func (runtime *DockerServerBackend) Pull(ctx context.Context, ref string, opts PullOpts) error { - if err := docker.CliPull(ctx, ref); err != nil { + var args []string + if opts.TargetPlatform != "" { + args = append(args, "--platform", opts.TargetPlatform) + } + args = append(args, ref) + + if err := docker.CliPull(ctx, args...); err != nil { return fmt.Errorf("unable to pull image %s: %w", ref, err) } return nil diff --git a/pkg/container_backend/interface.go b/pkg/container_backend/interface.go index 7d2b842990..c27b9527ed 100644 --- a/pkg/container_backend/interface.go +++ b/pkg/container_backend/interface.go @@ -6,31 +6,23 @@ import ( "github.com/werf/werf/pkg/image" ) -type CommonOpts struct{} - -type TagOpts struct { - CommonOpts -} - -type PushOpts struct { - CommonOpts -} - -type PullOpts struct { - CommonOpts +type CommonOpts struct { + TargetPlatform string } -type RmiOpts struct { - CommonOpts -} - -type GetImageInfoOpts struct { - CommonOpts -} +type ( + TagOpts CommonOpts + PushOpts CommonOpts + PullOpts CommonOpts + RmiOpts CommonOpts + GetImageInfoOpts CommonOpts + CalculateDependencyImportChecksum CommonOpts +) type BuildDockerfileOpts struct { CommonOpts + TargetPlatform string BuildContextArchive BuildContextArchiver DockerfileCtxRelPath string // TODO: remove this and instead write the []byte dockerfile to /Dockerfile in the ContextTar inDockerServerBackend.BuildDockerfile(). Target string @@ -48,6 +40,12 @@ type BuildDockerfileStageOptions struct { BuildContextArchive BuildContextArchiver } +type BuildOptions struct { + TargetPlatform string + IntrospectBeforeError bool + IntrospectAfterError bool +} + type ContainerBackend interface { Tag(ctx context.Context, ref, newRef string, opts TagOpts) error Push(ctx context.Context, ref string, opts PushOpts) error @@ -58,12 +56,11 @@ type ContainerBackend interface { BuildDockerfile(ctx context.Context, dockerfile []byte, opts BuildDockerfileOpts) (string, error) BuildDockerfileStage(ctx context.Context, baseImage string, opts BuildDockerfileStageOptions, instructions ...InstructionInterface) (string, error) BuildStapelStage(ctx context.Context, baseImage string, opts BuildStapelStageOptions) (string, error) - CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec) (string, error) + CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec, opts CalculateDependencyImportChecksum) (string, error) HasStapelBuildSupport() bool - IsTargetPlatformSupportedForStapel(targetPlatform string) bool - IsTargetPlatformSupportedForStagedDockerfile(targetPlatform string) bool - IsTargetPlatformSupportedForDockerfile(targetPlatform string) bool + GetDefaultPlatform() string + GetRuntimePlatform() string String() string diff --git a/pkg/container_backend/legacy_interface.go b/pkg/container_backend/legacy_interface.go index c7a9ab3cd7..41f00410a7 100644 --- a/pkg/container_backend/legacy_interface.go +++ b/pkg/container_backend/legacy_interface.go @@ -6,15 +6,12 @@ import ( "github.com/werf/werf/pkg/image" ) -type BuildOptions struct { - IntrospectBeforeError bool - IntrospectAfterError bool -} - type LegacyImageInterface interface { Name() string SetName(name string) + GetTargetPlatform() string + Pull(ctx context.Context) error Push(ctx context.Context) error diff --git a/pkg/container_backend/legacy_stage_image.go b/pkg/container_backend/legacy_stage_image.go index 1b662477da..376d710797 100644 --- a/pkg/container_backend/legacy_stage_image.go +++ b/pkg/container_backend/legacy_stage_image.go @@ -20,18 +20,24 @@ type LegacyStageImage struct { buildImage *legacyBaseImage builtID string commitChangeOptions LegacyCommitChangeOptions + targetPlatform string } -func NewLegacyStageImage(fromImage *LegacyStageImage, name string, containerBackend ContainerBackend) *LegacyStageImage { +func NewLegacyStageImage(fromImage *LegacyStageImage, name string, containerBackend ContainerBackend, targetPlatform string) *LegacyStageImage { stage := &LegacyStageImage{} stage.legacyBaseImage = newLegacyBaseImage(name, containerBackend) stage.fromImage = fromImage stage.container = newLegacyStageImageContainer(stage) + stage.targetPlatform = targetPlatform return stage } +func (i *LegacyStageImage) GetTargetPlatform() string { + return i.targetPlatform +} + func (i *LegacyStageImage) GetCopy() LegacyImageInterface { - ni := NewLegacyStageImage(i.fromImage, i.name, i.ContainerBackend) + ni := NewLegacyStageImage(i.fromImage, i.name, i.ContainerBackend, i.targetPlatform) if desc := i.GetStageDescription(); desc != nil { ni.SetStageDescription(desc.GetCopy()) } else if info := i.GetInfo(); info != nil { @@ -61,6 +67,22 @@ func (i *LegacyStageImage) GetID() string { } func (i *LegacyStageImage) Build(ctx context.Context, options BuildOptions) error { + // FIXME(multiarch): docker server default platform should be defined using server-info, not current machine platform + if i.GetTargetPlatform() == i.ContainerBackend.GetDefaultPlatform() && i.ContainerBackend.GetDefaultPlatform() != "linux/amd64" { + logboek.Context(ctx).Error().LogF("Detected your default build platform as %s.\n", i.ContainerBackend.GetDefaultPlatform()) + logboek.Context(ctx).Error().LogF("Building of stapel-type images using Docker-Server backend for platforms other than linux/amd64 is not supported.\n") + logboek.Context(ctx).Error().LogF("Please either:\n * confirm emulation of linux/amd64 by exlicitly setting --platform=linux/amd64 param;\n * or use Dockerfile-type image instead.\n") + logboek.Context(ctx).Error().LogLn() + return fmt.Errorf("building of stapel image using Docker-Server backend is unsupported on your current platform %q", i.ContainerBackend.GetDefaultPlatform()) + } + + if i.GetTargetPlatform() != "" && i.GetTargetPlatform() != "linux/amd64" { + logboek.Context(ctx).Error().LogF("Building of stapel-type images using Docker-Server backend for platforms other than linux/amd64 is not supported.\n") + logboek.Context(ctx).Error().LogF("Please either:\n * use Buildah backend to build stapel-type images for arbitrary platforms;\n * or use Dockerfile-type images with any backend.\n") + logboek.Context(ctx).Error().LogLn() + return fmt.Errorf("building of stapel image using Docker-Server backend is unsupported for specified platform %q", i.GetTargetPlatform()) + } + containerLockName := ContainerLockName(i.container.Name()) if _, lock, err := werf.AcquireHostLock(ctx, containerLockName, lockgate.AcquireOptions{}); err != nil { return fmt.Errorf("failed to lock %s: %w", containerLockName, err) @@ -213,7 +235,13 @@ func (i *LegacyStageImage) Tag(ctx context.Context, name string) error { func (i *LegacyStageImage) Pull(ctx context.Context) error { _ = i.ContainerBackend.(*DockerServerBackend) - if err := docker.CliPullWithRetries(ctx, i.name); err != nil { + var args []string + if i.targetPlatform != "" { + args = append(args, "--platform", i.targetPlatform) + } + args = append(args, i.name) + + if err := docker.CliPullWithRetries(ctx, args...); err != nil { return err } diff --git a/pkg/container_backend/legacy_stage_image_container.go b/pkg/container_backend/legacy_stage_image_container.go index 9dd72144a8..954b9066bd 100644 --- a/pkg/container_backend/legacy_stage_image_container.go +++ b/pkg/container_backend/legacy_stage_image_container.go @@ -71,6 +71,10 @@ func (c *LegacyStageImageContainer) prepareRunArgs(ctx context.Context) ([]strin var args []string args = append(args, fmt.Sprintf("--name=%s", c.name)) + if c.image.GetTargetPlatform() != "" { + args = append(args, fmt.Sprintf("--platform=%s", c.image.GetTargetPlatform())) + } + runOptions, err := c.prepareRunOptions(ctx) if err != nil { return nil, err diff --git a/pkg/container_backend/perf_check_container_backend.go b/pkg/container_backend/perf_check_container_backend.go index c5f6dff4e6..6ca5c94589 100644 --- a/pkg/container_backend/perf_check_container_backend.go +++ b/pkg/container_backend/perf_check_container_backend.go @@ -19,16 +19,12 @@ func (runtime *PerfCheckContainerBackend) HasStapelBuildSupport() bool { return runtime.ContainerBackend.HasStapelBuildSupport() } -func (runtime *PerfCheckContainerBackend) IsTargetPlatformSupportedForStapel(targetPlatform string) bool { - return runtime.ContainerBackend.IsTargetPlatformSupportedForStapel(targetPlatform) +func (runtime *PerfCheckContainerBackend) GetDefaultPlatform() string { + return runtime.ContainerBackend.GetDefaultPlatform() } -func (runtime *PerfCheckContainerBackend) IsTargetPlatformSupportedForStagedDockerfile(targetPlatform string) bool { - return runtime.ContainerBackend.IsTargetPlatformSupportedForStagedDockerfile(targetPlatform) -} - -func (runtime *PerfCheckContainerBackend) IsTargetPlatformSupportedForDockerfile(targetPlatform string) bool { - return runtime.ContainerBackend.IsTargetPlatformSupportedForDockerfile(targetPlatform) +func (runtime *PerfCheckContainerBackend) GetRuntimePlatform() string { + return runtime.ContainerBackend.GetRuntimePlatform() } func (runtime *PerfCheckContainerBackend) ShouldCleanupDockerfileImage() bool { @@ -99,10 +95,10 @@ func (runtime *PerfCheckContainerBackend) BuildStapelStage(ctx context.Context, return } -func (runtime *PerfCheckContainerBackend) CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec) (resID string, resErr error) { +func (runtime *PerfCheckContainerBackend) CalculateDependencyImportChecksum(ctx context.Context, dependencyImport DependencyImportSpec, opts CalculateDependencyImportChecksum) (resID string, resErr error) { logboek.Context(ctx).Default().LogProcess("ContainerBackend.BuildDockerfile"). Do(func() { - resID, resErr = runtime.ContainerBackend.CalculateDependencyImportChecksum(ctx, dependencyImport) + resID, resErr = runtime.ContainerBackend.CalculateDependencyImportChecksum(ctx, dependencyImport, opts) }) return } diff --git a/pkg/container_backend/stage_builder/dockerfile_builder.go b/pkg/container_backend/stage_builder/dockerfile_builder.go index 547fdda654..5d0048e6a1 100644 --- a/pkg/container_backend/stage_builder/dockerfile_builder.go +++ b/pkg/container_backend/stage_builder/dockerfile_builder.go @@ -9,7 +9,7 @@ import ( ) type DockerfileBuilderInterface interface { - Build(ctx context.Context) error + Build(ctx context.Context, opts container_backend.BuildOptions) error Cleanup(ctx context.Context) error SetDockerfile(dockerfile []byte) SetDockerfileCtxRelPath(dockerfileCtxRelPath string) @@ -35,22 +35,23 @@ func NewDockerfileBuilder(containerBackend container_backend.ContainerBackend, i return &DockerfileBuilder{ContainerBackend: containerBackend, Image: image} } -func (b *DockerfileBuilder) Build(ctx context.Context) error { +func (b *DockerfileBuilder) Build(ctx context.Context, opts container_backend.BuildOptions) error { // filePathToStdin != "" ?? if container_backend.Debug() { fmt.Printf("[DOCKER BUILD] context archive path: %s\n", b.BuildContextArchive.Path()) } - opts := b.BuildDockerfileOptions - opts.BuildContextArchive = b.BuildContextArchive + finalOpts := b.BuildDockerfileOptions + finalOpts.BuildContextArchive = b.BuildContextArchive + finalOpts.TargetPlatform = opts.TargetPlatform if container_backend.Debug() { fmt.Printf("BuildContextArchive=%q\n", b.BuildContextArchive) fmt.Printf("BiuldDockerfileOptions: %#v\n", opts) } - builtID, err := b.ContainerBackend.BuildDockerfile(ctx, b.Dockerfile, opts) + builtID, err := b.ContainerBackend.BuildDockerfile(ctx, b.Dockerfile, finalOpts) if err != nil { return fmt.Errorf("error building dockerfile with %s: %w", b.ContainerBackend.String(), err) } diff --git a/pkg/container_backend/stage_builder/dockerfile_stage_builder.go b/pkg/container_backend/stage_builder/dockerfile_stage_builder.go index ccd08f1f5f..a86f5b80a2 100644 --- a/pkg/container_backend/stage_builder/dockerfile_stage_builder.go +++ b/pkg/container_backend/stage_builder/dockerfile_stage_builder.go @@ -60,7 +60,10 @@ func (b *DockerfileStageBuilder) SetBuildContextArchive(buildContextArchive cont func (b *DockerfileStageBuilder) Build(ctx context.Context, opts container_backend.BuildOptions) error { instructions := append(append(b.preInstructions, b.instructions...), b.postInstructions...) - backendOpts := container_backend.BuildDockerfileStageOptions{BuildContextArchive: b.buildContextArchive} + backendOpts := container_backend.BuildDockerfileStageOptions{ + CommonOpts: container_backend.CommonOpts{TargetPlatform: opts.TargetPlatform}, + BuildContextArchive: b.buildContextArchive, + } if builtID, err := b.containerBackend.BuildDockerfileStage(ctx, b.baseImage, backendOpts, instructions...); err != nil { return fmt.Errorf("error building dockerfile stage: %w", err) diff --git a/pkg/container_backend/stage_builder/stage_builder.go b/pkg/container_backend/stage_builder/stage_builder.go index 1724ce7385..43dd4af874 100644 --- a/pkg/container_backend/stage_builder/stage_builder.go +++ b/pkg/container_backend/stage_builder/stage_builder.go @@ -81,7 +81,7 @@ func (stageBuilder *StageBuilder) DockerfileStageBuilder() DockerfileStageBuilde func (stageBuilder *StageBuilder) Build(ctx context.Context, opts container_backend.BuildOptions) error { switch { case stageBuilder.dockerfileBuilder != nil: - return stageBuilder.dockerfileBuilder.Build(ctx) + return stageBuilder.dockerfileBuilder.Build(ctx, opts) case stageBuilder.dockerfileStageBuilder != nil: return stageBuilder.dockerfileStageBuilder.Build(ctx, opts) case stageBuilder.stapelStageBuilder != nil: diff --git a/pkg/container_backend/stage_builder/stapel_stage_builder.go b/pkg/container_backend/stage_builder/stapel_stage_builder.go index cb7180c6a5..662eb64231 100644 --- a/pkg/container_backend/stage_builder/stapel_stage_builder.go +++ b/pkg/container_backend/stage_builder/stapel_stage_builder.go @@ -29,9 +29,11 @@ func NewStapelStageBuilder(containerBackend container_backend.ContainerBackend, } func (builder *StapelStageBuilder) Build(ctx context.Context, opts container_backend.BuildOptions) error { + finalOpts := builder.BuildStapelStageOptions + finalOpts.TargetPlatform = opts.TargetPlatform // TODO: support introspect options - builtID, err := builder.ContainerBackend.BuildStapelStage(ctx, builder.BaseImage, builder.BuildStapelStageOptions) + builtID, err := builder.ContainerBackend.BuildStapelStage(ctx, builder.BaseImage, finalOpts) if err != nil { return fmt.Errorf("error building stapel stage with %s: %w", builder.ContainerBackend.String(), err) } diff --git a/pkg/container_backend/thirdparty/platformutil/parse.go b/pkg/container_backend/thirdparty/platformutil/parse.go index 8f5a7f6cbd..f473d41f1c 100644 --- a/pkg/container_backend/thirdparty/platformutil/parse.go +++ b/pkg/container_backend/thirdparty/platformutil/parse.go @@ -24,7 +24,7 @@ func Parse(platformsStr []string) ([]specs.Platform, error) { out = append(out, p...) continue } - p, err := parse(s) + p, err := ParsePlatform(s) if err != nil { return nil, err } @@ -33,7 +33,7 @@ func Parse(platformsStr []string) ([]specs.Platform, error) { return out, nil } -func parse(in string) (specs.Platform, error) { +func ParsePlatform(in string) (specs.Platform, error) { if strings.EqualFold(in, "local") { return platforms.DefaultSpec(), nil } diff --git a/pkg/docker/main.go b/pkg/docker/main.go index 2c3ed62096..44112e835c 100644 --- a/pkg/docker/main.go +++ b/pkg/docker/main.go @@ -6,8 +6,8 @@ import ( "io" "os" "path/filepath" - "runtime" + "github.com/containerd/containerd/platforms" "github.com/docker/cli/cli/command" cliconfig "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/flags" @@ -24,6 +24,8 @@ var ( liveCliOutputEnabled bool isDebug bool defaultCLi command.Cli + defaultPlatform string + runtimePlatform string DockerConfigDir string ) @@ -36,43 +38,66 @@ func IsEnabled() bool { return defaultCLi != nil } -// TODO(multiarch): do not configure platform globally, instead specify platform on each build call -func Init(ctx context.Context, dockerConfigDir string, verbose, debug bool, platform string) error { - if (platform == "" && runtime.GOARCH != "amd64") || (platform != "" && platform != "linux/amd64") { - logboek.Context(ctx).Error().LogF("werf currently does not support building of images for any other platform besides linux/amd64.\n") - logboek.Context(ctx).Error().LogF("Please set --platform option (or WERF_PLATFORM, or DOCKER_DEFAULT_PLATFORM environment variable) to linux/amd64 to enable platform emulation when building images with werf.\n") - logboek.Context(ctx).Error().LogLn() - return fmt.Errorf("unsupported platform") - } - if platform != "" { - os.Setenv("DOCKER_DEFAULT_PLATFORM", platform) - os.Setenv("DOCKER_BUILDKIT", "1") - } - - DockerConfigDir = dockerConfigDir +type InitOptions struct { + DockerConfigDir string + DefaultPlatform string + ClaimPlatforms []string + Verbose bool + Debug bool +} - if dockerConfigDir == "" { - DockerConfigDir = filepath.Join(os.Getenv("HOME"), ".docker") +func Init(ctx context.Context, opts InitOptions) error { + if opts.DockerConfigDir != "" { + DockerConfigDir = opts.DockerConfigDir + cliconfig.SetDir(opts.DockerConfigDir) } else { - cliconfig.SetDir(dockerConfigDir) + DockerConfigDir = filepath.Join(os.Getenv("HOME"), ".docker") } - err := os.Setenv("DOCKER_CONFIG", dockerConfigDir) + err := os.Setenv("DOCKER_CONFIG", DockerConfigDir) if err != nil { - return fmt.Errorf("cannot set DOCKER_CONFIG to %s: %w", dockerConfigDir, err) + return fmt.Errorf("cannot set DOCKER_CONFIG to %s: %w", DockerConfigDir, err) } isDebug = os.Getenv("WERF_DEBUG_DOCKER") == "1" - liveCliOutputEnabled = verbose || debug + liveCliOutputEnabled = opts.Verbose || opts.Debug defaultCLi, err = newDockerCli(defaultCliOptions(ctx)) if err != nil { return err } + spec := platforms.DefaultSpec() + spec.OS = defaultCLi.ServerInfo().OSType + runtimePlatform = platforms.Format(spec) + claimPlatforms := opts.ClaimPlatforms + + if opts.DefaultPlatform != "" { + defaultPlatform = opts.DefaultPlatform + os.Setenv("DOCKER_DEFAULT_PLATFORM", opts.DefaultPlatform) + claimPlatforms = append(claimPlatforms, opts.DefaultPlatform) + } else { + defaultPlatform = runtimePlatform + } + + for _, claimPlatform := range claimPlatforms { + if claimPlatform != runtimePlatform { + os.Setenv("DOCKER_BUILDKIT", "1") + break + } + } + return nil } +func GetDefaultPlatform() string { + return defaultPlatform +} + +func GetRuntimePlatform() string { + return runtimePlatform +} + func ServerVersion(ctx context.Context) (*types.Version, error) { version, err := cli(ctx).Client().ServerVersion(ctx) if err != nil { diff --git a/pkg/storage/manager/storage_manager.go b/pkg/storage/manager/storage_manager.go index f0b6a87230..f32473fa3c 100644 --- a/pkg/storage/manager/storage_manager.go +++ b/pkg/storage/manager/storage_manager.go @@ -78,7 +78,7 @@ type StorageManagerInterface interface { FetchStage(ctx context.Context, containerBackend container_backend.ContainerBackend, stg stage.Interface) error SelectSuitableStage(ctx context.Context, c stage.Conveyor, stg stage.Interface, stages []*image.StageDescription) (*image.StageDescription, error) - CopySuitableByDigestStage(ctx context.Context, stageDesc *image.StageDescription, sourceStagesStorage, destinationStagesStorage storage.StagesStorage, containerBackend container_backend.ContainerBackend) (*image.StageDescription, error) + CopySuitableByDigestStage(ctx context.Context, stageDesc *image.StageDescription, sourceStagesStorage, destinationStagesStorage storage.StagesStorage, containerBackend container_backend.ContainerBackend, targetPlatform string) (*image.StageDescription, error) CopyStageIntoCacheStorages(ctx context.Context, stg stage.Interface, containerBackend container_backend.ContainerBackend) error CopyStageIntoFinalStorage(ctx context.Context, stg stage.Interface, containerBackend container_backend.ContainerBackend, opts CopyStageIntoFinalStorageOptions) error @@ -468,7 +468,7 @@ func (m *StorageManager) FetchStage(ctx context.Context, containerBackend contai fetchStageFromCache := func(stagesStorage storage.StagesStorage) (container_backend.LegacyImageInterface, error) { stageID := stg.GetStageImage().Image.GetStageDescription().StageID imageName := stagesStorage.ConstructStageImageName(m.ProjectName, stageID.Digest, stageID.UniqueID) - stageImage := container_backend.NewLegacyStageImage(nil, imageName, containerBackend) + stageImage := container_backend.NewLegacyStageImage(nil, imageName, containerBackend, stg.GetStageImage().Image.GetTargetPlatform()) shouldFetch, err := stagesStorage.ShouldFetchImage(ctx, stageImage) if err != nil { @@ -800,8 +800,8 @@ func (m *StorageManager) getStagesByDigestFromStagesStorage(ctx context.Context, return stages, nil } -func (m *StorageManager) CopySuitableByDigestStage(ctx context.Context, stageDesc *image.StageDescription, sourceStagesStorage, destinationStagesStorage storage.StagesStorage, containerBackend container_backend.ContainerBackend) (*image.StageDescription, error) { - img := container_backend.NewLegacyStageImage(nil, stageDesc.Info.Name, containerBackend) +func (m *StorageManager) CopySuitableByDigestStage(ctx context.Context, stageDesc *image.StageDescription, sourceStagesStorage, destinationStagesStorage storage.StagesStorage, containerBackend container_backend.ContainerBackend, targetPlatform string) (*image.StageDescription, error) { + img := container_backend.NewLegacyStageImage(nil, stageDesc.Info.Name, containerBackend, targetPlatform) logboek.Context(ctx).Info().LogF("Fetching %s\n", img.Name()) if err := sourceStagesStorage.FetchImage(ctx, img); err != nil { diff --git a/pkg/storage/repo_stages_storage.go b/pkg/storage/repo_stages_storage.go index b3554a3c5f..d8fdcd8ac7 100644 --- a/pkg/storage/repo_stages_storage.go +++ b/pkg/storage/repo_stages_storage.go @@ -483,12 +483,12 @@ func (storage *RepoStagesStorage) FetchImage(ctx context.Context, img container_ // FIXME(stapel-to-buildah): possible optimization would be to push buildah container directly into registry wihtout committing a local image func (storage *RepoStagesStorage) StoreImage(ctx context.Context, img container_backend.LegacyImageInterface) error { if img.GetBuiltID() != "" { - if err := storage.ContainerBackend.Tag(ctx, img.GetBuiltID(), img.Name(), container_backend.TagOpts{}); err != nil { + if err := storage.ContainerBackend.Tag(ctx, img.GetBuiltID(), img.Name(), container_backend.TagOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to tag built image %q by %q: %w", img.GetBuiltID(), img.Name(), err) } } - if err := storage.ContainerBackend.Push(ctx, img.Name(), container_backend.PushOpts{}); err != nil { + if err := storage.ContainerBackend.Push(ctx, img.Name(), container_backend.PushOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return fmt.Errorf("unable to push image %q: %w", img.Name(), err) } @@ -496,7 +496,7 @@ func (storage *RepoStagesStorage) StoreImage(ctx context.Context, img container_ } func (storage *RepoStagesStorage) ShouldFetchImage(ctx context.Context, img container_backend.LegacyImageInterface) (bool, error) { - if info, err := storage.ContainerBackend.GetImageInfo(ctx, img.Name(), container_backend.GetImageInfoOpts{}); err != nil { + if info, err := storage.ContainerBackend.GetImageInfo(ctx, img.Name(), container_backend.GetImageInfoOpts{TargetPlatform: img.GetTargetPlatform()}); err != nil { return false, fmt.Errorf("unable to get inspect for image %s: %w", img.Name(), err) } else if info != nil { img.SetInfo(info) diff --git a/test/pkg/utils/docker/container_command.go b/test/pkg/utils/docker/container_command.go index c27d3cb92f..7baa855eb3 100644 --- a/test/pkg/utils/docker/container_command.go +++ b/test/pkg/utils/docker/container_command.go @@ -23,7 +23,12 @@ func init() { } } - if err := docker.Init(context.Background(), "", true, true, platform); err != nil { + opts := docker.InitOptions{ + Verbose: true, + Debug: true, + DefaultPlatform: platform, + } + if err := docker.Init(context.Background(), opts); err != nil { _, _ = fmt.Fprintf(os.Stderr, "init werf docker failed: %s\n", err) os.Exit(1) }