diff --git a/docker/runner.go b/docker/runner.go index e686c0f0b..51f7be855 100644 --- a/docker/runner.go +++ b/docker/runner.go @@ -5,8 +5,6 @@ import ( "fmt" "net" "os" - "regexp" - "strings" "time" "github.com/docker/docker/api/types" @@ -183,21 +181,32 @@ func newContainer(ctx context.Context, c client.CommonAPIClient, f fn.Function, } func newContainerConfig(f fn.Function, _ string, verbose bool) (c container.Config, err error) { - envs, err := newEnvironmentVariables(f, verbose) - if err != nil { - return - } // httpPort := nat.Port(fmt.Sprintf("%v/tcp", port)) httpPort := nat.Port("8080/tcp") - return container.Config{ + c = container.Config{ Image: f.Image, - Env: envs, Tty: false, AttachStderr: true, AttachStdout: true, AttachStdin: false, ExposedPorts: map[nat.Port]struct{}{httpPort: {}}, - }, nil + } + + // Environment Variables + // Interpolate references to local environment variables and convert to a + // simple string slice for use with container.Config + envs, err := fn.Interpolate(f.Envs) + if err != nil { + return + } + for k, v := range envs { + c.Env = append(c.Env, k+"="+v) + } + if verbose { + c.Env = append(c.Env, "VERBOSE=true") + } + + return } func newHostConfig(port string) (c container.HostConfig, err error) { @@ -214,58 +223,6 @@ func newHostConfig(port string) (c container.HostConfig, err error) { return container.HostConfig{PortBindings: ports}, nil } -func newEnvironmentVariables(f fn.Function, verbose bool) ([]string, error) { - // TODO: this has code-smell. It may not be ideal to have fn.Function - // represent Envs as pointers, as this causes the clearly odd situation of - // needing to check if an env defined in f is just nil pointers: an invalid - // data structure. - envs := []string{} - for _, env := range f.Envs { - if env.Name != nil && env.Value != nil { - value, set, err := processEnvValue(*env.Value) - if err != nil { - return envs, err - } - if set { - envs = append(envs, *env.Name+"="+value) - } - } - } - if verbose { - envs = append(envs, "VERBOSE=true") - } - return envs, nil -} - -// run command supports only ENV values in form: -// FOO=bar or FOO={{ env:LOCAL_VALUE }} -var evRegex = regexp.MustCompile(`^{{\s*(\w+)\s*:(\w+)\s*}}$`) - -const ( - ctxIdx = 1 - valIdx = 2 -) - -// processEnvValue returns only value for ENV variable, that is defined in form FOO=bar or FOO={{ env:LOCAL_VALUE }} -// if the value is correct, it is returned and the second return parameter is set to `true` -// otherwise it is set to `false` -// if the specified value is correct, but the required local variable is not set, error is returned as well -func processEnvValue(val string) (string, bool, error) { - if strings.HasPrefix(val, "{{") { - match := evRegex.FindStringSubmatch(val) - if len(match) > valIdx && match[ctxIdx] == "env" { - if v, ok := os.LookupEnv(match[valIdx]); ok { - return v, true, nil - } else { - return "", false, fmt.Errorf("required local environment variable %q is not set", match[valIdx]) - } - } else { - return "", false, nil - } - } - return val, true, nil -} - // copy stdin and stdout from the container of the given ID. Errors encountered // during copy are communicated via a provided errs channel. func copyStdio(ctx context.Context, c client.CommonAPIClient, id string, errs chan error) (conn net.Conn, err error) { diff --git a/function_test.go b/function_test.go index d0f5e3603..032301322 100644 --- a/function_test.go +++ b/function_test.go @@ -86,7 +86,7 @@ func TestFunction_NameDefault(t *testing.T) { // environment variables by interpolating properly formatted references to // local environment variables, returning a final simple map structure. // Also ensures that nil value references are interpreted as meaning the -// environment is to be disincluded from the resultant map, rathern than included +// environment is to be disincluded from the resultant map, rather than included // with an empty value. // TODO: Perhaps referring to a nonexistent local env var should be treated // as a "leave as is" (do not set) rather than "required" resulting in error?