buildah build: add a --env

Add a `--env` option to `buildah build` that functions similarly to the
`buildah config --env` option, to complement `buildah build`'s
`--unsetenv` option.

Document that `buildah config`'s `--env` function fetches the current
value for a variable when the name is supplied, but no `=` or value
follows it.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
Nalin Dahyabhai 2022-05-02 18:24:59 -04:00
parent 0828507728
commit 4be3b7dec9
10 changed files with 72 additions and 6 deletions

View File

@ -394,6 +394,7 @@ func buildCmd(c *cobra.Command, inputArgs []string, iopts buildOptions) error {
Timestamp: timestamp,
Platforms: platforms,
UnsetEnvs: iopts.UnsetEnvs,
Envs: iopts.Envs,
}
if iopts.Quiet {
options.ReportWriter = ioutil.Discard

View File

@ -226,7 +226,6 @@ func updateConfig(builder *buildah.Builder, c *cobra.Command, iopts configResult
}
env[1] = os.Expand(env[1], getenv)
builder.SetEnv(env[0], env[1])
case env[0] == "-":
builder.ClearEnv()
case strings.HasSuffix(env[0], "-"):

View File

@ -102,6 +102,7 @@ type CommitOptions struct {
// indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
OciEncryptLayers *[]int
// UnsetEnvs is a list of environments to not add to final image.
// Deprecated: use UnsetEnv() before committing instead.
UnsetEnvs []string
}

View File

@ -260,4 +260,6 @@ type BuildOptions struct {
AllPlatforms bool
// UnsetEnvs is a list of environments to not add to final image.
UnsetEnvs []string
// Envs is a list of environment variables to set in the final image.
Envs []string
}

View File

@ -241,6 +241,14 @@ Set custom DNS options
Set custom DNS search domains
**--env** *env[=value]*
Add a value (e.g. env=*value*) to the built image. Can be used multiple times.
If neither `=` nor a `*value*` are specified, but *env* is set in the current
environment, the value from the current environment will be added to the image.
To remove an environment variable from the built image, use the `--unsetenv`
option.
**--file**, **-f** *Containerfile*
Specifies a Containerfile which contains instructions for building the image,
@ -829,6 +837,12 @@ buildah build -f Containerfile.in -t imageName .
buildah build --network mynet .
buildah build --env LANG=en_US.UTF-8 -t imageName .
buildah build --env EDITOR -t imageName .
buildah build --unsetenv LANG -t imageName .
### Building an multi-architecture image using the --manifest option (requires emulation software)
buildah build --arch arm --manifest myimage /tmp/mysrc

View File

@ -77,10 +77,12 @@ ignore the `cmd` value of the container image. However if you use the array
form, then the cmd will be appended onto the end of the entrypoint cmd and be
executed together.
**--env**, **-e** *env=value*
**--env**, **-e** *env[=value]*
Add a value (e.g. env=*value*) to the environment for containers based on any
images which will be built using the specified container. Can be used multiple times.
If *env* is named but neither `=` nor a `value` is specified, then the value
will be taken from the current process environment.
If *env* has a trailing `-`, then the *env* is removed from the config.
If the *env* is set to "-" then all environment variables are removed from the config.
@ -229,6 +231,8 @@ buildah config --volume /usr/myvol- containerID
buildah config --port 1234 --port 8080 containerID
buildah config --env 1234=5678 containerID
buildah config --env 1234- containerID
## SEE ALSO

View File

@ -134,6 +134,7 @@ type Executor struct {
processLabel string // Shares processLabel of first stage container with containers of other stages in same build
mountLabel string // Shares mountLabel of first stage container with containers of other stages in same build
buildOutput string // Specifies instructions for any custom build output
envs []string
}
type imageTypeAndHistoryAndDiffIDs struct {
@ -276,8 +277,9 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
secrets: secrets,
sshsources: sshsources,
logPrefix: logPrefix,
unsetEnvs: options.UnsetEnvs,
unsetEnvs: append([]string{}, options.UnsetEnvs...),
buildOutput: options.BuildOutput,
envs: append([]string{}, options.Envs...),
}
if exec.err == nil {
exec.err = os.Stderr

View File

@ -1494,6 +1494,28 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
spec := strings.SplitN(envSpec, "=", 2)
s.builder.SetEnv(spec[0], spec[1])
}
for _, envSpec := range s.executor.envs {
env := strings.SplitN(envSpec, "=", 2)
if len(env) > 1 {
getenv := func(name string) string {
for _, envvar := range s.builder.Env() {
val := strings.SplitN(envvar, "=", 2)
if len(val) == 2 && val[0] == name {
return val[1]
}
}
logrus.Errorf("error expanding variable %q: no value set in image", name)
return name
}
env[1] = os.Expand(env[1], getenv)
s.builder.SetEnv(env[0], env[1])
} else {
s.builder.SetEnv(env[0], os.Getenv(env[0]))
}
}
for _, envSpec := range s.executor.unsetEnvs {
s.builder.UnsetEnv(envSpec)
}
s.builder.SetCmd(config.Cmd)
s.builder.ClearVolumes()
for v := range config.Volumes {
@ -1566,7 +1588,6 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
RetryDelay: s.executor.retryPullPushDelay,
HistoryTimestamp: s.executor.timestamp,
Manifest: s.executor.manifest,
UnsetEnvs: s.executor.unsetEnvs,
}
// generate build output
if s.executor.buildOutput != "" {

View File

@ -92,6 +92,7 @@ type BudResults struct {
LogRusage bool
RusageLogFile string
UnsetEnvs []string
Envs []string
}
// FromAndBugResults represents the results for common flags
@ -194,6 +195,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.StringArrayVar(&flags.Envs, "env", []string{}, "set environment variable for the image")
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")
@ -262,6 +264,7 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions {
flagCompletion["cache-from"] = commonComp.AutocompleteNone
flagCompletion["cert-dir"] = commonComp.AutocompleteDefault
flagCompletion["creds"] = commonComp.AutocompleteNone
flagCompletion["env"] = commonComp.AutocompleteNone
flagCompletion["file"] = commonComp.AutocompleteDefault
flagCompletion["from"] = commonComp.AutocompleteDefault
flagCompletion["format"] = commonComp.AutocompleteNone

View File

@ -582,6 +582,25 @@ _EOF
expect_output "[container=buildah date=tomorrow]" "No Path should be defined"
}
@test "bud with --env" {
target=scratch-image
run_buildah build --quiet=false --iidfile ${TEST_SCRATCH_DIR}/output.iid --env PATH $WITH_POLICY_JSON -t ${target} $BUDFILES/from-scratch
iid=$(cat ${TEST_SCRATCH_DIR}/output.iid)
run_buildah inspect --format '{{.Docker.Config.Env}}' $iid
expect_output "[PATH=$PATH]"
run_buildah build --quiet=false --iidfile ${TEST_SCRATCH_DIR}/output.iid --env PATH=foo $WITH_POLICY_JSON -t ${target} $BUDFILES/from-scratch
iid=$(cat ${TEST_SCRATCH_DIR}/output.iid)
run_buildah inspect --format '{{.Docker.Config.Env}}' $iid
expect_output "[PATH=foo]"
# --unsetenv takes precedence over --env, since we don't know the relative order of the two
run_buildah build --quiet=false --iidfile ${TEST_SCRATCH_DIR}/output.iid --unsetenv PATH --env PATH=foo --env PATH= $WITH_POLICY_JSON -t ${target} $BUDFILES/from-scratch
iid=$(cat ${TEST_SCRATCH_DIR}/output.iid)
run_buildah inspect --format '{{.Docker.Config.Env}}' $iid
expect_output "[]"
}
@test "build with custom build output and output rootfs to directory" {
_prefetch alpine
mytmpdir=${TEST_SCRATCH_DIR}/my-dir
@ -659,7 +678,7 @@ _EOF
expect_output "" "no base name for untagged base image"
}
@test "bud with --tag " {
@test "bud with --tag" {
target=scratch-image
run_buildah build --quiet=false --tag test1 $WITH_POLICY_JSON -t ${target} $BUDFILES/from-scratch
expect_output --substring "Successfully tagged localhost/test1:latest"
@ -669,7 +688,7 @@ _EOF
expect_output --substring "Successfully tagged localhost/test2:latest"
}
@test "bud with bad --tag " {
@test "bud with bad --tag" {
target=scratch-image
run_buildah 125 build --quiet=false --tag TEST1 $WITH_POLICY_JSON -t ${target} $BUDFILES/from-scratch
expect_output --substring "tag TEST1: invalid reference format: repository name must be lowercase"