Skip to content

Commit 308b6d9

Browse files
author
Ma Shimiao
authored
Merge pull request #276 from wrouesnel/env-file
Add docker-style --env-file flag support.
2 parents bd4a85d + 2f76e20 commit 308b6d9

3 files changed

Lines changed: 115 additions & 2 deletions

File tree

cmd/oci-runtime-tool/generate.go

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package main
22

33
import (
4+
"bufio"
5+
"bytes"
46
"fmt"
57
"os"
68
"runtime"
79
"strconv"
810
"strings"
11+
"unicode"
12+
"unicode/utf8"
913

1014
rspec "github.com/opencontainers/runtime-spec/specs-go"
1115
"github.com/opencontainers/runtime-tools/generate"
@@ -25,6 +29,7 @@ var generateFlags = []cli.Flag{
2529
cli.StringFlag{Name: "cwd", Value: "/", Usage: "current working directory for the process"},
2630
cli.BoolFlag{Name: "disable-oom-kill", Usage: "disable OOM Killer"},
2731
cli.StringSliceFlag{Name: "env", Usage: "add environment variable e.g. key=value"},
32+
cli.StringSliceFlag{Name: "env-file", Usage: "read in a file of environment variables"},
2833
cli.IntFlag{Name: "gid", Usage: "gid for the process"},
2934
cli.StringSliceFlag{Name: "gidmappings", Usage: "add GIDMappings e.g HostID:ContainerID:Size"},
3035
cli.StringSliceFlag{Name: "groups", Usage: "supplementary groups for the process"},
@@ -196,8 +201,12 @@ func setupSpec(g *generate.Generator, context *cli.Context) error {
196201
g.SetProcessArgs(context.StringSlice("args"))
197202
}
198203

199-
if context.IsSet("env") {
200-
envs := context.StringSlice("env")
204+
{
205+
envs, err := readKVStrings(context.StringSlice("env-file"), context.StringSlice("env"))
206+
if err != nil {
207+
return err
208+
}
209+
201210
for _, env := range envs {
202211
g.AddProcessEnv(env)
203212
}
@@ -711,3 +720,94 @@ func seccompSet(context *cli.Context, seccompFlag string, g *generate.Generator)
711720
}
712721
return nil
713722
}
723+
724+
// readKVStrings reads a file of line terminated key=value pairs, and overrides any keys
725+
// present in the file with additional pairs specified in the override parameter
726+
//
727+
// This function is copied from github.com/docker/docker/runconfig/opts/parse.go
728+
func readKVStrings(files []string, override []string) ([]string, error) {
729+
envVariables := []string{}
730+
for _, ef := range files {
731+
parsedVars, err := parseEnvFile(ef)
732+
if err != nil {
733+
return nil, err
734+
}
735+
envVariables = append(envVariables, parsedVars...)
736+
}
737+
// parse the '-e' and '--env' after, to allow override
738+
envVariables = append(envVariables, override...)
739+
740+
return envVariables, nil
741+
}
742+
743+
// parseEnvFile reads a file with environment variables enumerated by lines
744+
//
745+
// ``Environment variable names used by the utilities in the Shell and
746+
// Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase
747+
// letters, digits, and the '_' (underscore) from the characters defined in
748+
// Portable Character Set and do not begin with a digit. *But*, other
749+
// characters may be permitted by an implementation; applications shall
750+
// tolerate the presence of such names.''
751+
// -- http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
752+
//
753+
// As of #16585, it's up to application inside docker to validate or not
754+
// environment variables, that's why we just strip leading whitespace and
755+
// nothing more.
756+
//
757+
// This function is copied from github.com/docker/docker/runconfig/opts/envfile.go
758+
func parseEnvFile(filename string) ([]string, error) {
759+
fh, err := os.Open(filename)
760+
if err != nil {
761+
return []string{}, err
762+
}
763+
defer fh.Close()
764+
765+
lines := []string{}
766+
scanner := bufio.NewScanner(fh)
767+
currentLine := 0
768+
utf8bom := []byte{0xEF, 0xBB, 0xBF}
769+
for scanner.Scan() {
770+
scannedBytes := scanner.Bytes()
771+
if !utf8.Valid(scannedBytes) {
772+
return []string{}, fmt.Errorf("env file %s contains invalid utf8 bytes at line %d: %v", filename, currentLine+1, scannedBytes)
773+
}
774+
// We trim UTF8 BOM
775+
if currentLine == 0 {
776+
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
777+
}
778+
// trim the line from all leading whitespace first
779+
line := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace)
780+
currentLine++
781+
// line is not empty, and not starting with '#'
782+
if len(line) > 0 && !strings.HasPrefix(line, "#") {
783+
data := strings.SplitN(line, "=", 2)
784+
785+
// trim the front of a variable, but nothing else
786+
variable := strings.TrimLeft(data[0], whiteSpaces)
787+
if strings.ContainsAny(variable, whiteSpaces) {
788+
return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' has white spaces", variable)}
789+
}
790+
791+
if len(data) > 1 {
792+
793+
// pass the value through, no trimming
794+
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
795+
} else {
796+
// if only a pass-through variable is given, clean it up.
797+
lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line)))
798+
}
799+
}
800+
}
801+
return lines, scanner.Err()
802+
}
803+
804+
var whiteSpaces = " \t"
805+
806+
// ErrBadEnvVariable typed error for bad environment variable
807+
type ErrBadEnvVariable struct {
808+
msg string
809+
}
810+
811+
func (e ErrBadEnvVariable) Error() string {
812+
return fmt.Sprintf("poorly formatted environment: %s", e.msg)
813+
}

completions/bash/oci-runtime-tool

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ _oci-runtime-tool_generate() {
279279
--cwd
280280
--disable-oom-kill
281281
--env
282+
--env-file
282283
--gid
283284
--gidmappings
284285
--groups
@@ -406,6 +407,11 @@ _oci-runtime-tool_generate() {
406407
__oci-runtime-tool_nospace
407408
return
408409
;;
410+
--env-file)
411+
_filedir
412+
__oci-runtime-tool_nospace
413+
return
414+
;;
409415
$(__oci-runtime-tool_to_extglob "$options_with_args") )
410416
return
411417
;;

man/oci-runtime-tool-generate.1.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ read the configuration from `config.json`.
6565
This option allows you to specify arbitrary environment variables
6666
that are available for the process that will be launched inside of
6767
the container.
68+
69+
**--env-file**=[]
70+
Set environment variables from a file.
71+
This option sets environment variables in the container from the
72+
contents of a file formatted with key=value pairs, one per line.
73+
When specified multiple times, files are loaded in order with duplicate
74+
keys overwriting previous ones.
6875

6976
**--gid**=GID
7077
Gid for the process inside of container

0 commit comments

Comments
 (0)