mirror of https://github.com/knative/func.git
src: update runner with shared env interpolation (#992)
This commit is contained in:
parent
14248311b1
commit
8185c0acce
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"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) {
|
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(fmt.Sprintf("%v/tcp", port))
|
||||||
httpPort := nat.Port("8080/tcp")
|
httpPort := nat.Port("8080/tcp")
|
||||||
return container.Config{
|
c = container.Config{
|
||||||
Image: f.Image,
|
Image: f.Image,
|
||||||
Env: envs,
|
|
||||||
Tty: false,
|
Tty: false,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStdin: false,
|
AttachStdin: false,
|
||||||
ExposedPorts: map[nat.Port]struct{}{httpPort: {}},
|
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) {
|
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
|
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
|
// copy stdin and stdout from the container of the given ID. Errors encountered
|
||||||
// during copy are communicated via a provided errs channel.
|
// 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) {
|
func copyStdio(ctx context.Context, c client.CommonAPIClient, id string, errs chan error) (conn net.Conn, err error) {
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ func TestFunction_NameDefault(t *testing.T) {
|
||||||
// environment variables by interpolating properly formatted references to
|
// environment variables by interpolating properly formatted references to
|
||||||
// local environment variables, returning a final simple map structure.
|
// local environment variables, returning a final simple map structure.
|
||||||
// Also ensures that nil value references are interpreted as meaning the
|
// 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.
|
// with an empty value.
|
||||||
// TODO: Perhaps referring to a nonexistent local env var should be treated
|
// 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?
|
// as a "leave as is" (do not set) rather than "required" resulting in error?
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue