Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion cmd/buildah/bud.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/containerd/containerd/platforms"
specs "github.com/opencontainers/image-spec/specs-go/v1"
)

type budResults struct {
Expand Down Expand Up @@ -90,6 +92,18 @@ func getDockerfiles(files []string) []string {
return dockerfiles
}

type argArray map[string]string

func (args argArray) setArch(p specs.Platform) {
args["TARGETPLATFORM"] = p.OS + "/" + p.Architecture
args["TARGETOS"] = p.OS
args["TARGETARCH"] = p.Architecture
args["TARGETVARIANT"] = p.Variant
if p.Variant != "" {
args["TARGETPLATFORM"] = args["TARGETPLATFORM"] + "/" + p.Variant
}
}

func budCmd(c *cobra.Command, inputArgs []string, iopts budResults) error {
output := ""
tags := []string{}
Expand All @@ -116,12 +130,36 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budResults) error {
}
logrus.Debugf("Pull Policy for pull [%v]", pullPolicy)

args := make(map[string]string)
args := make(argArray)

p := platforms.DefaultSpec()
if c.Flag("platform").Changed {
var err error
p, err = platforms.Parse(iopts.Platform)
if err != nil {
return errors.Wrapf(err, "error parsing --platform argument")
}
}
args.setArch(p)

if c.Flag("build-arg").Changed {
for _, arg := range iopts.BuildArg {
av := strings.SplitN(arg, "=", 2)
if len(av) > 1 {
args[av[0]] = av[1]
if av[0] == "TARGETPLATFORM" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is TARGETPLATFORM a constant defined somewhere?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rhatdan I'm thinking this PR is dependent on openshift/imagebuilder#142. @ grooverdan can you confirm? We may need to hold this PR until the imagebuilder gets merged/vendored.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defined in https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope.

Quite right, should wait for dependent PR openshift/imagebuilder#142. I even checked it works with the version there rather than the slightly different version in this PR.

I'll rebase/revendor/retest on the merge/amendment of openshift/imagebuilder#142.

var err error
var p specs.Platform
if av[1] != "" {
p, err = platforms.Parse(av[1])
} else {
p, err = platforms.Parse(iopts.Platform)
}
if err != nil {
return errors.Wrapf(err, "error parsing --platform argument")
}
args.setArch(p)
}
} else {
delete(args, av[0])
}
Expand Down
3 changes: 3 additions & 0 deletions commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
}

systemContext := getSystemContext(b.store, options.SystemContext, options.SignaturePolicyPath)
systemContext.ArchitectureChoice = b.Architecture()
systemContext.OSChoice = b.OS()
systemContext.VariantChoice = b.Variant()

blocked, err := isReferenceBlocked(dest, systemContext)
if err != nil {
Expand Down
34 changes: 28 additions & 6 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ func (b *Builder) initConfig(ctx context.Context, img types.Image) error {
b.ImageAnnotations = v1Manifest.Annotations
}
}
if b.Args["TARGETOS"] != "" {
b.SetOS(b.Args["TARGETOS"])
} else if b.OS() == "" {
b.SetOS(runtime.GOOS)
}
if b.Args["TARGETARCH"] != "" {
b.SetArchitecture(b.Args["TARGETARCH"])
} else if b.Architecture() == "" {
b.SetArchitecture(runtime.GOARCH)
}
if b.Args["TARGETVARIANT"] != "" {
b.SetVariant(b.Args["TARGETVARIANT"])
// TODO else set based on detection
}

b.fixupConfig()
return nil
Expand All @@ -102,12 +116,6 @@ func (b *Builder) fixupConfig() {
if b.OCIv1.Created == nil || b.OCIv1.Created.IsZero() {
b.OCIv1.Created = &now
}
if b.OS() == "" {
b.SetOS(runtime.GOOS)
}
if b.Architecture() == "" {
b.SetArchitecture(runtime.GOARCH)
}
if b.Format == Dockerv2ImageManifest && b.Hostname() == "" {
b.SetHostname(stringid.TruncateID(stringid.GenerateRandomID()))
}
Expand Down Expand Up @@ -178,6 +186,20 @@ func (b *Builder) SetArchitecture(arch string) {
b.Docker.Architecture = arch
}

// Variant returns the variant of the architecture on which the container, or
// a container build using an image build from this container, is intended to
// be run.
func (b *Builder) Variant() string {
return b.Docker.Variant
}

// SetVariant sets the variant of the architecture on which the container, or
// a container built using an image built from this container, is intended to
// be run.
func (b *Builder) SetVariant(variant string) {
b.Docker.Variant = variant
}

// Maintainer returns contact information for the person who built the image.
func (b *Builder) Maintainer() string {
return b.OCIv1.Author
Expand Down
2 changes: 2 additions & 0 deletions docker/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ type V1Image struct {
Config *Config `json:"config,omitempty"`
// Architecture is the hardware that the image is build and runs on
Architecture string `json:"architecture,omitempty"`
// Variant is the architecture variant
Variant string `json:"variant,omitempty"`
// OS is the operating system used to build and run the image
OS string `json:"os,omitempty"`
// Size is the total size of the image including all layers it is composed of
Expand Down
7 changes: 3 additions & 4 deletions docs/buildah-bud.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,10 @@ that the PID namespace in which `buildah` itself is being run should be reused,
or it can be the path to a PID namespace which is already in use by another
process.

**--platform**="Linux"
**--platform**="OS[/arch[/variant]]"

This option has no effect on the build. Other container engines use this option
to control the execution platform for the build (e.g., Windows, Linux) which is
not required for Buildah as it supports only Linux.
Defines the platform for the destination, OS (e.g., Windows, Linux), arch (e.g.
x86_64, ppc64le, arm64), and variant (e.g. v7, for arm64).

**--pull**

Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.12

require (
github.com/blang/semver v3.5.0+incompatible // indirect
github.com/containerd/containerd v1.3.0
github.com/containernetworking/cni v0.7.1
github.com/containers/image/v5 v5.0.0
github.com/containers/storage v1.13.5
Expand All @@ -30,7 +31,7 @@ require (
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.3.0
github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible
github.com/openshift/imagebuilder v1.1.1
github.com/openshift/imagebuilder v1.1.1-0.20191118051649-22563141c8d6
github.com/pkg/errors v0.8.1
github.com/seccomp/containers-golang v0.0.0-20180629143253-cdfdaa7543f4
github.com/seccomp/libseccomp-golang v0.9.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible h1:s5
github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
github.com/openshift/imagebuilder v1.1.0 h1:oT704SkwMEzmIMU/+Uv1Wmvt+p10q3v2WuYMeFI18c4=
github.com/openshift/imagebuilder v1.1.0/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/openshift/imagebuilder v1.1.1-0.20191118051649-22563141c8d6 h1:+hNDmNoPVtdnhHZDNjCA1hCGGrdvZ0ijMsN9zdIQ0QM=
github.com/openshift/imagebuilder v1.1.1-0.20191118051649-22563141c8d6/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/openshift/imagebuilder v1.1.1 h1:KAUR31p8UBJdfVO42azWgb+LeMAed2zaKQ19e0C0X2I=
github.com/openshift/imagebuilder v1.1.1/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw=
Expand Down
36 changes: 28 additions & 8 deletions imagebuildah/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,22 @@ import (
// instruction in the Dockerfile, since that's usually an indication of a user
// error, but for these values we make exceptions and ignore them.
var builtinAllowedBuildArgs = map[string]bool{
"HTTP_PROXY": true,
"http_proxy": true,
"HTTPS_PROXY": true,
"https_proxy": true,
"FTP_PROXY": true,
"ftp_proxy": true,
"NO_PROXY": true,
"no_proxy": true,
"HTTP_PROXY": true,
"http_proxy": true,
"HTTPS_PROXY": true,
"https_proxy": true,
"FTP_PROXY": true,
"ftp_proxy": true,
"NO_PROXY": true,
"no_proxy": true,
"TARGETPLATFORM": true,
"TARGETOS": true,
"TARGETARCH": true,
"TARGETVARIANT": true,
"BUILDPLATFORM": true,
"BUILDOS": true,
"BUILDARCH": true,
"BUILDVARIANT": true,
}

// Executor is a buildah-based implementation of the imagebuilder.Executor
Expand Down Expand Up @@ -401,6 +409,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
}
}()

var lastFromStage imagebuilder.Stage
// Build maps of every named base image and every referenced stage root
// filesystem. Individual stages can use them to determine whether or
// not they can skip certain steps near the end of their stages.
Expand All @@ -418,6 +427,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
// FROM instruction uses argument values,
// we might not record the right value here.
b.baseMap[base] = true
lastFromStage = stage
logrus.Debugf("base: %q", base)
}
}
Expand All @@ -439,6 +449,16 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
}
}

// TODO: crude - needs derive from image received(?)
// we're assuming subsequent stages on a multistage image is the target stage.
// Ideally a user should be explicit like FROM --platform =$TARGETPLATFORM
// and we should handle this.
if lastFromStage.Builder != nil {
b.systemContext.ArchitectureChoice = lastFromStage.Builder.Args["TARGETARCH"]
b.systemContext.OSChoice = lastFromStage.Builder.Args["TARGETOS"]
b.systemContext.VariantChoice = lastFromStage.Builder.Args["TARGETVARIANT"]
}

// Run through the build stages, one at a time.
for stageIndex, stage := range stages {
var lastErr error
Expand Down
1 change: 1 addition & 0 deletions imagebuildah/stage_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ func (s *StageExecutor) prepare(ctx context.Context, stage imagebuilder.Stage, f
Container: builder.Container,
Author: builder.Maintainer(),
Architecture: builder.Architecture(),
OS: builder.OS(),
RootFS: rootfs,
}
dImage.Config = &dImage.ContainerConfig
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.BoolVar(&flags.NoCache, "no-cache", false, "Do not use existing cached images for the container build. Build from the start with a new set of cached layers.")
fs.StringVar(&flags.Logfile, "logfile", "", "log to `file` instead of stdout/stderr")
fs.IntVar(&flags.Loglevel, "loglevel", 0, "adjust logging level (range from -2 to 3)")
fs.StringVar(&flags.Platform, "platform", "", "CLI compatibility: no action or effect")
fs.StringVar(&flags.Platform, "platform", "", "Sets target platform and TARGET{PLATFORM,OS,ARCH,VARIANT} build args for cross builds")
fs.BoolVar(&flags.Pull, "pull", true, "pull the image from the registry if newer or not present in store, if false, only pull the image if not present")
fs.BoolVar(&flags.PullAlways, "pull-always", false, "pull the image even if the named image is present in store")
fs.BoolVar(&flags.PullNever, "pull-never", false, "do not pull the image, use the image present in store if available")
Expand Down
114 changes: 114 additions & 0 deletions tests/bud.bats
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -1850,3 +1850,117 @@ load helpers
target=alpine-image
run_buildah 1 bud --authfile /tmp/nonexist --signature-policy ${TESTSDIR}/policy.json -t ${target} ${TESTSDIR}/bud/containerfile
}

@test "bud with --platform" {
target=test_platform
# --platform args are parsed through to TARGET{PLATFORM|OS|ARCH}
buildah --log-level=error bud --platform linux/ppc64le/fakevariant -t "${target}" --layers -f Dockerfile.platformargs ${TESTSDIR}/bud/build-arg

# metadata
run_buildah --log-level=error inspect --format "{{ .Docker.Architecture }}" "${target}"
expect_output "ppc64le"
run_buildah --log-level=error inspect --format "{{ .OCIv1.Architecture }}" "${target}"
expect_output "ppc64le"
run_buildah --log-level=error inspect --format "{{ .Docker.OS }}" "${target}"
expect_output "linux"
run_buildah --log-level=error inspect --format "{{ .OCIv1.OS }}" "${target}"
expect_output "linux"

# environment
# build platform takes default values from native platform
native_os=$(OS=$(uname -o); case $OS in GNU/Linux) echo linux ;; *) echo $OS ;; esac)
native_arch=$(ARCH=$(uname -m); case $ARCH in x86_64) echo amd64 ;; i?86) echo 386 ;; armv?l) echo arm ;; *) echo $ARCH ;; esac)
native_variant=$(ARCH=$(uname -m); case $ARCH in armv?l) echo /v${ARCH//[^0-9]/} ;; arm64) echo /v8 ;; esac)

run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 1 }}" "${target}"
expect_output "BUILDPLATFORM=${native_os}/${native_arch}${native_variant}"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 1 }}" "${target}"
expect_output "BUILDPLATFORM=${native_os}/${native_arch}${native_variant}"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 2 }}" "${target}"
expect_output "BUILDOS=${native_os}"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 2 }}" "${target}"
expect_output "BUILDOS=${native_os}"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 3 }}" "${target}"
expect_output "BUILDARCH=${native_arch}"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 3 }}" "${target}"
expect_output "BUILDARCH=${native_arch}"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 4 }}" "${target}"
expect_output "BUILDVARIANT=${native_variant:1}"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 4 }}" "${target}"
expect_output "BUILDVARIANT=${native_variant:1}"

run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 5 }}" "${target}"
expect_output "TARGETPLATFORM=linux/ppc64le/fakevariant"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 5 }}" "${target}"
expect_output "TARGETPLATFORM=linux/ppc64le/fakevariant"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 6 }}" "${target}"
expect_output "TARGETOS=linux"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 6 }}" "${target}"
expect_output "TARGETOS=linux"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 7 }}" "${target}"
expect_output "TARGETARCH=ppc64le"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 7 }}" "${target}"
expect_output "TARGETARCH=ppc64le"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 8 }}" "${target}"
expect_output "TARGETVARIANT=fakevariant"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 8 }}" "${target}"
expect_output "TARGETVARIANT=fakevariant"

buildah rmi "${target}"
}

@test "bud with --build-arg TARGETPLATFORM=..." {
target=test_platform_buildarg
buildah --log-level=error bud --build-arg TARGETPLATFORM=linux/arm64/v7 --layers -t "${target}" -f Dockerfile.platformargs ${TESTSDIR}/bud/build-arg
# currently doesn't expand BUILDPLATFORM -> BUILDOS ....
# if so we want to we'd change vendor/github.com/openshift/imagebuilder/dispatchers.go

run_buildah --log-level=error inspect --format "{{ .Docker.Architecture }}" "${target}"
expect_output "arm64"
run_buildah --log-level=error inspect --format "{{ .OCIv1.Architecture }}" "${target}"
expect_output "arm64"
run_buildah --log-level=error inspect --format "{{ .Docker.OS }}" "${target}"
expect_output "linux"
run_buildah --log-level=error inspect --format "{{ .OCIv1.OS }}" "${target}"
expect_output "linux"

run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 5 }}" "${target}"
expect_output "TARGETPLATFORM=linux/arm64/v7"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 5 }}" "${target}"
expect_output "TARGETPLATFORM=linux/arm64/v7"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 6 }}" "${target}"
expect_output "TARGETOS=linux"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 6 }}" "${target}"
expect_output "TARGETOS=linux"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 7 }}" "${target}"
expect_output "TARGETARCH=arm64"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 7 }}" "${target}"
expect_output "TARGETARCH=arm64"
run_buildah --log-level=error inspect --format "{{ index .Docker.Config.Env 8 }}" "${target}"
expect_output "TARGETVARIANT=v7"
run_buildah --log-level=error inspect --format "{{ index .OCIv1.Config.Env 8 }}" "${target}"
expect_output "TARGETVARIANT=v7"

buildah rmi "${target}"
}

@test "bud-multi-stage-platform" {
target=test_multi_stage_platform
buildah --log-level=error bud --platform linux/ppc64le -t "${target}" --layers -f Dockerfile.platform_multistage ${TESTSDIR}/bud/build-arg
# --platform args effects the final image and second stage downloaded (ubuntu)
run_buildah --log-level=error inspect --format "{{ .Docker.Architecture }}" "${target}"
expect_output "ppc64le"
run_buildah --log-level=error inspect --format "{{ .OCIv1.Architecture }}" "${target}"
expect_output "ppc64le"
run_buildah --log-level=error inspect --format "{{ .Docker.Architecture }}" docker.io/library/ubuntu:latest
expect_output "ppc64le"
run_buildah --log-level=error inspect --format "{{ .OCIv1.Architecture }}" docker.io/library/ubuntu:latest
expect_output "ppc64le"

run_buildah --log-level=error inspect --format "{{ .Docker.OS }}" "${target}"
expect_output "linux"
run_buildah --log-level=error inspect --format "{{ .OCIv1.OS }}" "${target}"
expect_output "linux"

buildah rmi "${target}" docker.io/library/ubuntu:latest
}
11 changes: 11 additions & 0 deletions tests/bud/build-arg/Dockerfile.platform_multistage
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM scratch
ARG BUILDPLATFORM
ARG BUILDOS
ARG BUILDARCH
ARG BUILDVARIANT
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT

FROM ubuntu
Loading