From 7724292a4d7a03d189f406663ae80b1f656fcbaa Mon Sep 17 00:00:00 2001 From: TomSweeneyRedHat Date: Tue, 24 Nov 2020 20:04:52 -0500 Subject: [PATCH] Allow FROM to be overriden with from option These changes will allow the "FROM" statement in a Containerfile to be overridden with a new `--from` option. If I have this Dockerfile.fedora ``` FROM fedora ``` This command will instead build an alpine image: ``` STEP 1: FROM alpine Completed short name "alpine" with unqualified-search registries (origin: /etc/containers/registries.conf) Getting image source signatures Copying blob 188c0c94c7c5 done Copying config d6e46aa247 done Writing manifest to image destination Storing signatures STEP 2: COMMIT tom --> d6e46aa2470 d6e46aa2470df1d32034c6707c8041158b652f38d2a9ae3d7ad7e7532d22ebe0 ``` Addresses: #2404 Signed-off-by: TomSweeneyRedHat --- cmd/buildah/bud.go | 1 + docs/buildah-bud.md | 30 +++++++++++++++++++++++++ imagebuildah/build.go | 3 +++ imagebuildah/executor.go | 9 ++++++++ pkg/cli/common.go | 3 +++ tests/bud.bats | 11 ++++++++- tests/bud/build-with-from/Containerfile | 4 ++++ 7 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/bud/build-with-from/Containerfile diff --git a/cmd/buildah/bud.go b/cmd/buildah/bud.go index fb65061998f..474ab9da0b2 100644 --- a/cmd/buildah/bud.go +++ b/cmd/buildah/bud.go @@ -318,6 +318,7 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error { DropCapabilities: iopts.CapDrop, Err: stderr, ForceRmIntermediateCtrs: iopts.ForceRm, + From: iopts.From, IDMappingOptions: idmappingOptions, IIDFile: iopts.Iidfile, Isolation: isolation, diff --git a/docs/buildah-bud.md b/docs/buildah-bud.md index f6b5a02fadd..93ce148ea50 100644 --- a/docs/buildah-bud.md +++ b/docs/buildah-bud.md @@ -61,6 +61,9 @@ instructions read from the Containerfiles in the same way that environment variables are, but which will not be added to environment variable list in the resulting image's configuration. +Please refer to the [BUILD TIME VARIABLES](#build-time-variables) section for the +list of variables that can be overridden within the Containerfile at run time. + **--cache-from** Images to utilise as potential cache sources. Buildah does not currently support caching so this is a NOOP. @@ -264,6 +267,11 @@ Recognized formats include *oci* (OCI image-spec v1.0, the default) and Note: You can also override the default format by setting the BUILDAH\_FORMAT environment variable. `export BUILDAH_FORMAT=docker` +**--from** + +Overrides the first `FROM` instruction within the Containerfile. If there are multiple +FROM instructions in a Containerfile, only the first is changed. + **-h**, **--help** Print usage statement @@ -666,6 +674,23 @@ will convert /foo into a `shared` mount point. The propagation properties of th mount can be changed directly. For instance if `/` is the source mount for `/foo`, then use `mount --make-shared /` to convert `/` into a `shared` mount. +## BUILD TIME VARIABLES + +The ENV instruction in a Containerfile can be used to define variable values. When the image +is built, the values will persist in the container image. At times it is more convenient to +change the values in the Containerfile via a command-line option rather than changing the +values within the Containerfile itself. + +The following variables can be used in conjunction with the `--build-arg` option to override the +corresponding values set in the Containerfile using the `ENV` instruction. + + * HTTP_PROXY + * HTTPS_PROXY + * FTP_PROXY + * NO_PROXY + +Please refer to the [Using Build Time Variables](#using-build-time-variables) section of the Examples. + ## EXAMPLE ### Build an image using local Containerfiles @@ -727,6 +752,11 @@ buildah bud --dns-search=example.com --dns=223.5.5.5 --dns-option=use-vc . Note: supported compression formats are 'xz', 'bzip2', 'gzip' and 'identity' (no compression). +### Using Build Time Variables +#### Replace the value set for the HTTP_PROXY environment variable within the Containerfile. + +buildah bud --build-arg=HTTP_PROXY="http://127.0.0.1:8321" + ## ENVIRONMENT **BUILD\_REGISTRY\_SOURCES** diff --git a/imagebuildah/build.go b/imagebuildah/build.go index 1ec21e7860b..a7b0f6eaa18 100644 --- a/imagebuildah/build.go +++ b/imagebuildah/build.go @@ -187,6 +187,9 @@ type BuildOptions struct { LogRusage bool // Excludes is a list of excludes to be used instead of the .dockerignore file. Excludes []string + // From is the image name to use to replace the value specified in the first + // FROM instruction in the Containerfile + From string } // BuildDockerfiles parses a set of one or more Dockerfiles (which may be diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index 3c41ec1d2d5..a72e24eea9f 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -114,6 +114,7 @@ type Executor struct { logRusage bool imageInfoLock sync.Mutex imageInfoCache map[string]imageTypeAndHistoryAndDiffIDs + fromOverride string } type imageTypeAndHistoryAndDiffIDs struct { @@ -229,6 +230,7 @@ func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Nod jobs: jobs, logRusage: options.LogRusage, imageInfoCache: make(map[string]imageTypeAndHistoryAndDiffIDs), + fromOverride: options.From, } if exec.err == nil { exec.err = os.Stderr @@ -245,6 +247,7 @@ func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Nod fmt.Fprintf(exec.out, prefix+format+suffix, args...) } } + for arg := range options.Args { if _, isBuiltIn := builtinAllowedBuildArgs[arg]; !isBuiltIn { exec.unusedArgs[arg] = struct{}{} @@ -522,6 +525,12 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image switch strings.ToUpper(child.Value) { // first token - instruction case "FROM": if child.Next != nil { // second token on this line + // If we have a fromOverride, replace the value of + // image name for the first FROM in the Containerfile. + if b.fromOverride != "" { + child.Next.Value = b.fromOverride + b.fromOverride = "" + } base := child.Next.Value if base != "scratch" { // TODO: this didn't undergo variable and arg diff --git a/pkg/cli/common.go b/pkg/cli/common.go index 1e2db58c4e5..33a030a2f3b 100644 --- a/pkg/cli/common.go +++ b/pkg/cli/common.go @@ -63,6 +63,7 @@ type BudResults struct { IgnoreFile string File []string Format string + From string Iidfile string Label []string Logfile string @@ -187,6 +188,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet { fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry") fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", true, "don't compress layers by default") fs.BoolVar(&flags.DisableContentTrust, "disable-content-trust", false, "This is a Docker specific option and is a NOOP") + fs.StringVar(&flags.From, "from", "", "image name used to replace the value in the first FROM instruction in the Containerfile") fs.StringVar(&flags.IgnoreFile, "ignorefile", "", "path to an alternate .dockerignore file") fs.StringSliceVarP(&flags.File, "file", "f", []string{}, "`pathname or URL` of a Dockerfile") fs.StringVar(&flags.Format, "format", DefaultFormat(), "`format` of the built image's manifest and metadata. Use BUILDAH_FORMAT environment variable to override.") @@ -233,6 +235,7 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions { flagCompletion["cert-dir"] = commonComp.AutocompleteDefault flagCompletion["creds"] = commonComp.AutocompleteNone flagCompletion["file"] = commonComp.AutocompleteDefault + flagCompletion["from"] = commonComp.AutocompleteDefault flagCompletion["format"] = commonComp.AutocompleteNone flagCompletion["ignorefile"] = commonComp.AutocompleteDefault flagCompletion["iidfile"] = commonComp.AutocompleteDefault diff --git a/tests/bud.bats b/tests/bud.bats index 4adecfd94e5..ee635b22190 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -2430,5 +2430,14 @@ EOF expect_output --substring "FROM alpine" run_buildah 125 bud --network=bogus --signature-policy ${TESTSDIR}/policy.json -t ${target} ${TESTSDIR}/bud/containerfile - expect_output "error checking for network namespace: stat bogus: no such file or directory" + +} + +@test "bud-replace-from-in-containerfile" { + _prefetch alpine + # override the first FROM (fedora) image in the Containerfile + # with alpine, leave the second (busybox) alone. + run_buildah bud --signature-policy ${TESTSDIR}/policy.json --from=alpine ${TESTSDIR}/bud/build-with-from + expect_output --substring "STEP 1: FROM alpine AS builder" + expect_output --substring "STEP 2: FROM busybox" } diff --git a/tests/bud/build-with-from/Containerfile b/tests/bud/build-with-from/Containerfile new file mode 100644 index 00000000000..d25cad9771c --- /dev/null +++ b/tests/bud/build-with-from/Containerfile @@ -0,0 +1,4 @@ +FROM fedora as builder +FROM busybox +COPY --from=builder /bin/df /tmp/df_tester +