From d718b51e11758d5c226502f9867dd4d53b66d090 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Thu, 4 Nov 2021 13:29:08 -0400 Subject: [PATCH] config: support the variant field Add the variant field, along with methods for setting and querying it, and expose them in the `buildah config` and `buildah inspect` commands. When setting an initial architecture for a container based on an image which doesn't contain an architecture, or from "scratch", normalize the architecture name we've been given, and set both it and the variant field at the same time. Provide normalized architecture+variant values in `buildah info`. Signed-off-by: Nalin Dahyabhai --- cmd/buildah/config.go | 5 +++++ config.go | 20 ++++++++++++++++++++ contrib/completions/bash/buildah | 3 ++- docker/types.go | 2 ++ docs/buildah-config.1.md | 7 +++++++ info.go | 8 ++++++-- tests/config.bats | 2 ++ tests/inspect.bats | 11 +++++++++++ 8 files changed, 55 insertions(+), 3 deletions(-) diff --git a/cmd/buildah/config.go b/cmd/buildah/config.go index 4c5a7424391..cafaee3a525 100644 --- a/cmd/buildah/config.go +++ b/cmd/buildah/config.go @@ -43,6 +43,7 @@ type configResults struct { shell string stopSignal string user string + variant string volume []string workingDir string } @@ -91,6 +92,7 @@ func init() { flags.StringVar(&opts.shell, "shell", "", "add `shell` to run in containers") flags.StringVar(&opts.stopSignal, "stop-signal", "", "set `stop signal` for containers based on image") flags.StringVarP(&opts.user, "user", "u", "", "set default `user` to run inside containers based on image") + flags.StringVar(&opts.variant, "variant", "", "set architecture `variant` of the target image") flags.StringSliceVarP(&opts.volume, "volume", "v", []string{}, "add default `volume` path to be created for containers based on image (default [])") flags.StringVar(&opts.workingDir, "workingdir", "", "set working `directory` for containers based on image") @@ -169,6 +171,9 @@ func updateConfig(builder *buildah.Builder, c *cobra.Command, iopts configResult if c.Flag("arch").Changed { builder.SetArchitecture(iopts.arch) } + if c.Flag("variant").Changed { + builder.SetVariant(iopts.variant) + } if c.Flag("os").Changed { builder.SetOS(iopts.os) } diff --git a/config.go b/config.go index c50aa43503c..effaa81e4d0 100644 --- a/config.go +++ b/config.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/containerd/containerd/platforms" "github.com/containers/buildah/define" "github.com/containers/buildah/docker" "github.com/containers/image/v5/manifest" @@ -133,6 +134,10 @@ func (b *Builder) fixupConfig(sys *types.SystemContext) { } else { b.SetArchitecture(runtime.GOARCH) } + // in case the arch string we started with was shorthand for a known arch+variant pair, normalize it + ps := platforms.Normalize(ociv1.Platform{OS: b.OS(), Architecture: b.Architecture(), Variant: b.Variant()}) + b.SetArchitecture(ps.Architecture) + b.SetVariant(ps.Variant) } if b.Format == define.Dockerv2ImageManifest && b.Hostname() == "" { b.SetHostname(stringid.TruncateID(stringid.GenerateRandomID())) @@ -212,6 +217,21 @@ func (b *Builder) SetArchitecture(arch string) { b.Docker.Architecture = arch } +// Variant returns a name of the architecture variant on which the container, +// or a container built using an image built from this container, is intended +// to be run. +func (b *Builder) Variant() string { + return b.OCIv1.Variant +} + +// SetVariant sets the name of the architecture variant 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 + b.OCIv1.Variant = variant +} + // Maintainer returns contact information for the person who built the image. func (b *Builder) Maintainer() string { return b.OCIv1.Author diff --git a/contrib/completions/bash/buildah b/contrib/completions/bash/buildah index 0421cd7aa62..9fd65f88a73 100644 --- a/contrib/completions/bash/buildah +++ b/contrib/completions/bash/buildah @@ -301,6 +301,7 @@ return 1 --stop-signal --user -u + --variant --volume -v --workingdir @@ -435,7 +436,6 @@ return 1 --os --pid --platform - --platforms --runtime --runtime-flag --security-opt @@ -451,6 +451,7 @@ return 1 --userns-uid-map-user --userns-gid-map-group --uts + --variant --volume -v " diff --git a/docker/types.go b/docker/types.go index 561287ac276..b0ed2e4c021 100644 --- a/docker/types.go +++ b/docker/types.go @@ -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 a variant of the CPU that the image is built and runs on + 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 diff --git a/docs/buildah-config.1.md b/docs/buildah-config.1.md index 48d9429852c..7441ddb0244 100644 --- a/docs/buildah-config.1.md +++ b/docs/buildah-config.1.md @@ -186,6 +186,13 @@ or UID, optionally followed by a group name or GID, separated by a colon (':'). If names are used, the container should include entries for those names in its */etc/passwd* and */etc/group* files. +**--variant** *variant* + +Set the target architecture *variant* for any images which will be built using +the specified container. By default, if the container was based on an image, +that image's target architecture and variant information is kept, otherwise the +host's architecture and variant are recorded. + **--volume**, **-v** *volume* Add a location in the directory tree which should be marked as a *volume* in any images which will be built using the specified container. Can be used multiple times. If *volume* has a trailing `-`, and is already set, then the *volume* is removed from the config. diff --git a/info.go b/info.go index f0bf92ddf33..12b69c9ba60 100644 --- a/info.go +++ b/info.go @@ -11,10 +11,12 @@ import ( "strings" "time" + "github.com/containerd/containerd/platforms" "github.com/containers/buildah/util" "github.com/containers/storage" "github.com/containers/storage/pkg/system" "github.com/containers/storage/pkg/unshare" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -43,8 +45,10 @@ func Info(store storage.Store) ([]InfoData, error) { func hostInfo() map[string]interface{} { info := map[string]interface{}{} - info["os"] = runtime.GOOS - info["arch"] = runtime.GOARCH + ps := platforms.Normalize(v1.Platform{OS: runtime.GOOS, Architecture: runtime.GOARCH}) + info["os"] = ps.OS + info["arch"] = ps.Architecture + info["variant"] = ps.Variant info["cpus"] = runtime.NumCPU() info["rootless"] = unshare.IsRootless() diff --git a/tests/config.bats b/tests/config.bats index 1027503910c..127a8c8f34d 100644 --- a/tests/config.bats +++ b/tests/config.bats @@ -198,6 +198,7 @@ function check_matrix() { --created-by COINCIDENCE \ --arch amd64 \ --os linux \ + --variant abc \ --user likes:things \ --port 12345 \ --env VARIABLE=VALUE1,VALUE2 \ @@ -228,6 +229,7 @@ function check_matrix() { check_matrix 'Author' 'TESTAUTHOR' check_matrix 'Architecture' 'amd64' check_matrix 'OS' 'linux' + check_matrix 'Variant' 'abc' run_buildah inspect --format '{{.ImageCreatedBy}}' $cid expect_output "COINCIDENCE" diff --git a/tests/inspect.bats b/tests/inspect.bats index 2022cf2b8e5..861327dfec3 100644 --- a/tests/inspect.bats +++ b/tests/inspect.bats @@ -113,3 +113,14 @@ load helpers run_buildah inspect --format "{{.Docker}}" alpine expect_output --substring '\{' } + +@test "inspect-format-docker-variant" { + # github.com/containerd/containerd/platforms.Normalize() converts Arch:"armhf" to Arch:"arm"+Variant:"v7", + # so check that platform normalization happens at least for that one + run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json --arch=armhf scratch + cid=$output + run_buildah inspect --format "{{.Docker.Architecture}}" $cid + [[ "$output" == "arm" ]] + run_buildah inspect --format "{{.Docker.Variant}}" $cid + [[ "$output" == "v7" ]] +}