Skip to content

Commit a235033

Browse files
committed
build: add support for inherit-labels
Allows users to specify if they want to inherit labels from base image or not. Signed-off-by: flouthoc <[email protected]>
1 parent ebbfb3a commit a235033

File tree

9 files changed

+109
-4
lines changed

9 files changed

+109
-4
lines changed

define/build.go

+3
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ type BuildOptions struct {
236236
// ID mapping options to use if we're setting up our own user namespace
237237
// when handling RUN instructions.
238238
IDMappingOptions *IDMappingOptions
239+
// InheritLabels controls whether or not built images will retain the labels
240+
// which were set in their base images
241+
InheritLabels types.OptionalBool
239242
// AddCapabilities is a list of capabilities to add to the default set when
240243
// handling RUN instructions.
241244
AddCapabilities []string

docs/buildah-build.1.md

+4
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,10 @@ Path to an alternative .containerignore (.dockerignore) file.
497497
Write the built image's ID to the file. When `--platform` is specified more
498498
than once, attempting to use this option will trigger an error.
499499

500+
**--inherit-labels** *bool-value*
501+
502+
Inherit the labels from the base image or base stages. (default true).
503+
500504
**--ipc** *how*
501505

502506
Sets the configuration for IPC namespaces when handling `RUN` instructions.

imagebuildah/executor.go

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type Executor struct {
8282
additionalTags []string
8383
log func(format string, args ...any) // can be nil
8484
in io.Reader
85+
inheritLabels types.OptionalBool
8586
out io.Writer
8687
err io.Writer
8788
signaturePolicyPath string
@@ -261,6 +262,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
261262
err: options.Err,
262263
reportWriter: writer,
263264
isolation: options.Isolation,
265+
inheritLabels: options.InheritLabels,
264266
namespaceOptions: options.NamespaceOptions,
265267
configureNetwork: options.ConfigureNetwork,
266268
cniPluginPath: options.CNIPluginPath,

imagebuildah/stage_executor.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,11 @@ func (s *StageExecutor) prepare(ctx context.Context, from string, initializeIBCo
10691069
RootFS: rootfs,
10701070
}
10711071
dImage.Config = &dImage.ContainerConfig
1072+
if s.executor.inheritLabels == types.OptionalBoolFalse {
1073+
// If user has selected `--inherit-labels=false` let's not
1074+
// inherit labels from base image.
1075+
dImage.Config.Labels = nil
1076+
}
10721077
err = ib.FromImage(&dImage, node)
10731078
if err != nil {
10741079
if err2 := builder.Delete(); err2 != nil {
@@ -1872,6 +1877,11 @@ func (s *StageExecutor) getCreatedBy(node *parser.Node, addedContentSummary stri
18721877
if node == nil {
18731878
return "/bin/sh", nil
18741879
}
1880+
inheritLabels := ""
1881+
// If --inherit-label was manually set to false then update history.
1882+
if s.executor.inheritLabels == types.OptionalBoolFalse {
1883+
inheritLabels = "|inheritLabels=false"
1884+
}
18751885
switch strings.ToUpper(node.Value) {
18761886
case "ARG":
18771887
for _, variable := range strings.Fields(node.Original) {
@@ -1880,7 +1890,7 @@ func (s *StageExecutor) getCreatedBy(node *parser.Node, addedContentSummary stri
18801890
}
18811891
}
18821892
buildArgs := s.getBuildArgsKey()
1883-
return "/bin/sh -c #(nop) ARG " + buildArgs, nil
1893+
return "/bin/sh -c #(nop) ARG " + buildArgs + inheritLabels, nil
18841894
case "RUN":
18851895
shArg := ""
18861896
buildArgs := s.getBuildArgsResolvedForRun()
@@ -1960,16 +1970,16 @@ func (s *StageExecutor) getCreatedBy(node *parser.Node, addedContentSummary stri
19601970
if buildArgs != "" {
19611971
result = result + "|" + strconv.Itoa(len(strings.Split(buildArgs, " "))) + " " + buildArgs + " "
19621972
}
1963-
result = result + "/bin/sh -c " + shArg + heredoc + appendCheckSum
1973+
result = result + "/bin/sh -c " + shArg + heredoc + appendCheckSum + inheritLabels
19641974
return result, nil
19651975
case "ADD", "COPY":
19661976
destination := node
19671977
for destination.Next != nil {
19681978
destination = destination.Next
19691979
}
1970-
return "/bin/sh -c #(nop) " + strings.ToUpper(node.Value) + " " + addedContentSummary + " in " + destination.Value + " ", nil
1980+
return "/bin/sh -c #(nop) " + strings.ToUpper(node.Value) + " " + addedContentSummary + " in " + destination.Value + " " + inheritLabels, nil
19711981
default:
1972-
return "/bin/sh -c #(nop) " + node.Original, nil
1982+
return "/bin/sh -c #(nop) " + node.Original + inheritLabels, nil
19731983
}
19741984
}
19751985

pkg/cli/build.go

+1
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
376376
IIDFile: iopts.Iidfile,
377377
IgnoreFile: iopts.IgnoreFile,
378378
In: stdin,
379+
InheritLabels: types.NewOptionalBool(iopts.InheritLabels),
379380
Isolation: isolation,
380381
Jobs: &iopts.Jobs,
381382
Labels: iopts.Label,

pkg/cli/common.go

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ type BudResults struct {
7272
Format string
7373
From string
7474
Iidfile string
75+
InheritLabels bool
7576
Label []string
7677
LayerLabel []string
7778
Logfile string
@@ -231,6 +232,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
231232
fs.StringVar(&flags.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry")
232233
fs.BoolVar(&flags.Compress, "compress", false, "this is a legacy option, which has no effect on the image")
233234
fs.BoolVar(&flags.CompatVolumes, "compat-volumes", false, "preserve the contents of VOLUMEs during RUN instructions")
235+
fs.BoolVar(&flags.InheritLabels, "inherit-labels", true, "inherit the labels from the base image or base stages.")
234236
fs.StringArrayVar(&flags.CPPFlags, "cpp-flag", []string{}, "set additional flag to pass to C preprocessor (cpp)")
235237
fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry")
236238
fs.StringVarP(&flags.CWOptions, "cw", "", "", "confidential workload `options`")

tests/bud.bats

+74
Original file line numberDiff line numberDiff line change
@@ -2670,6 +2670,80 @@ _EOF
26702670
expect_output "$want_output"
26712671
}
26722672

2673+
@test "bud and test inherit-labels" {
2674+
base=registry.fedoraproject.org/fedora-minimal
2675+
_prefetch $base
2676+
_prefetch alpine
2677+
run_buildah --version
2678+
local -a output_fields=($output)
2679+
buildah_version=${output_fields[2]}
2680+
run_buildah build $WITH_POLICY_JSON -t exp -f $BUDFILES/base-with-labels/Containerfile
2681+
2682+
run_buildah inspect --format '{{ index .Docker.Config.Labels "license"}}' exp
2683+
expect_output "MIT" "license must be MIT from fedora base image"
2684+
run_buildah inspect --format '{{ index .Docker.Config.Labels "name"}}' exp
2685+
expect_output "fedora-minimal" "name must be fedora from base image"
2686+
2687+
run_buildah build $WITH_POLICY_JSON --inherit-labels=false --label name=world -t exp -f $BUDFILES/base-with-labels/Containerfile
2688+
# no labels should be inherited from base image, only the buildah version label
2689+
# and `hello=world` which we just added using cli flag
2690+
want_output='map["io.buildah.version":"'$buildah_version'" "name":"world"]'
2691+
run_buildah inspect --format '{{printf "%q" .Docker.Config.Labels}}' exp
2692+
expect_output "$want_output"
2693+
2694+
# Try building another file with multiple layers
2695+
run_buildah build $WITH_POLICY_JSON --iidfile ${TEST_SCRATCH_DIR}/id1 --layers -t exp -f $BUDFILES/base-with-labels/Containerfile.layer
2696+
run_buildah inspect --format '{{ index .Docker.Config.Labels "license"}}' exp
2697+
expect_output "MIT" "license must be MIT from fedora base image"
2698+
run_buildah inspect --format '{{ index .Docker.Config.Labels "name"}}' exp
2699+
expect_output "world" "name must be world from Containerfile"
2700+
2701+
# Now build same file with --inherit-labels=false and verify if we are not using the cache again.
2702+
run_buildah build $WITH_POLICY_JSON --layers --inherit-labels=false --iidfile ${TEST_SCRATCH_DIR}/inherit_false_1 -t exp -f $BUDFILES/base-with-labels/Containerfile.layer
2703+
# Should not contain `Using cache` at all since
2704+
assert "$output" !~ "Using cache"
2705+
want_output='map["io.buildah.version":"'$buildah_version'" "name":"world"]'
2706+
run_buildah inspect --format '{{printf "%q" .Docker.Config.Labels}}' exp
2707+
expect_output "$want_output"
2708+
2709+
run_buildah build $WITH_POLICY_JSON --layers --inherit-labels=false --iidfile ${TEST_SCRATCH_DIR}/inherit_false_2 -t exp -f $BUDFILES/base-with-labels/Containerfile.layer
2710+
# Should contain `Using cache`
2711+
expect_output --substring " Using cache"
2712+
want_output='map["io.buildah.version":"'$buildah_version'" "name":"world"]'
2713+
run_buildah inspect --format '{{printf "%q" .Docker.Config.Labels}}' exp
2714+
expect_output "$want_output"
2715+
assert "$(cat ${TEST_SCRATCH_DIR}/inherit_false_1)" = "$(cat ${TEST_SCRATCH_DIR}/inherit_false_2)" "expected image ids to not change"
2716+
2717+
# Now build same file with --inherit-labels=true and verify if using the cache
2718+
run_buildah build $WITH_POLICY_JSON --iidfile ${TEST_SCRATCH_DIR}/id2 --layers --inherit-labels=true -t exp -f $BUDFILES/base-with-labels/Containerfile.layer
2719+
expect_output --substring " Using cache"
2720+
run_buildah inspect --format '{{ index .Docker.Config.Labels "license"}}' exp
2721+
expect_output "MIT" "license must be MIT from fedora base image"
2722+
run_buildah inspect --format '{{ index .Docker.Config.Labels "name"}}' exp
2723+
expect_output "world" "name must be world from Containerfile"
2724+
# Final image id should be exactly same as the one image which was built in the past.
2725+
assert "$(cat ${TEST_SCRATCH_DIR}/id1)" = "$(cat ${TEST_SCRATCH_DIR}/id2)" "expected image ids to not change"
2726+
2727+
# Now build same file with --inherit-labels=false and verify if target stage did not inherit any labels from base stage.
2728+
run_buildah build $WITH_POLICY_JSON --layers --inherit-labels=false -t exp -f $BUDFILES/base-with-labels/Containerfile.multi-stage
2729+
want_output='map["io.buildah.version":"'$buildah_version'"]'
2730+
run_buildah inspect --format '{{printf "%q" .Docker.Config.Labels}}' exp
2731+
expect_output "$want_output"
2732+
2733+
# Now build same file with --inherit-labels=true and verify if target stage inherits labels from the base stage.
2734+
run_buildah build $WITH_POLICY_JSON --iidfile ${TEST_SCRATCH_DIR}/id3 --layers --inherit-labels=true -t exp -f $BUDFILES/base-with-labels/Containerfile.multi-stage
2735+
want_output='map["io.buildah.version":"'$buildah_version'" "name":"world"]'
2736+
run_buildah inspect --format '{{printf "%q" .Docker.Config.Labels}}' exp
2737+
expect_output "$want_output"
2738+
2739+
# Rebuild again with layers should not build image again at all.
2740+
run_buildah build $WITH_POLICY_JSON --iidfile ${TEST_SCRATCH_DIR}/id4 --layers --inherit-labels=true -t exp -f $BUDFILES/base-with-labels/Containerfile.multi-stage
2741+
want_output='map["io.buildah.version":"'$buildah_version'" "name":"world"]'
2742+
run_buildah inspect --format '{{printf "%q" .Docker.Config.Labels}}' exp
2743+
expect_output "$want_output"
2744+
assert "$(cat ${TEST_SCRATCH_DIR}/id3)" = "$(cat ${TEST_SCRATCH_DIR}/id4)" "expected image ids to not change"
2745+
}
2746+
26732747
@test "build using intermediate images should not inherit label" {
26742748
_prefetch alpine
26752749

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM registry.fedoraproject.org/fedora-minimal
2+
LABEL name world
3+
RUN echo world
4+
RUN echo hello
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM alpine as one
2+
LABEL name world
3+
4+
FROM one
5+
RUN echo world

0 commit comments

Comments
 (0)