diff --git a/container/docker/factory.go b/container/docker/factory.go index 8e6a6d93..c231a71f 100644 --- a/container/docker/factory.go +++ b/container/docker/factory.go @@ -60,7 +60,7 @@ const rootDirRetryPeriod time.Duration = 1000 * time.Millisecond // --cgroup-parent have another prefix than 'docker' var dockerCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`) -var dockerEnvWhitelist = flag.String("docker_env_metadata_whitelist", "", "a comma-separated list of environment variable keys that needs to be collected for docker containers") +var dockerEnvWhitelist = flag.String("docker_env_metadata_whitelist", "", "a comma-separated list of environment variable keys matched with specified prefix that needs to be collected for docker containers") var ( // Basepath to all container specific information that libcontainer stores. diff --git a/container/docker/handler.go b/container/docker/handler.go index ff1cbffa..ca891bcd 100644 --- a/container/docker/handler.go +++ b/container/docker/handler.go @@ -51,7 +51,6 @@ const ( ) type dockerContainerHandler struct { - // machineInfoFactory provides info.MachineInfo machineInfoFactory info.MachineInfoFactory @@ -253,11 +252,16 @@ func newDockerContainerHandler( // split env vars to get metadata map. for _, exposedEnv := range metadataEnvs { + if exposedEnv == "" { + // if no dockerEnvWhitelist provided, len(metadataEnvs) == 1, metadataEnvs[0] == "" + continue + } + for _, envVar := range ctnr.Config.Env { if envVar != "" { splits := strings.SplitN(envVar, "=", 2) - if len(splits) == 2 && splits[0] == exposedEnv { - handler.envs[strings.ToLower(exposedEnv)] = splits[1] + if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) { + handler.envs[strings.ToLower(splits[0])] = splits[1] } } } diff --git a/container/docker/handler_test.go b/container/docker/handler_test.go index 60382e34..f7d1881c 100644 --- a/container/docker/handler_test.go +++ b/container/docker/handler_test.go @@ -19,8 +19,10 @@ import ( "io/ioutil" "os" "path" + "strings" "testing" + "github.com/docker/docker/api/types/container" "github.com/stretchr/testify/assert" ) @@ -48,3 +50,97 @@ func TestStorageDirDetectionWithNewVersions(t *testing.T) { as.Equal(rwLayer, randomizedID) } + +func rawMetadataEnvMatch(dockerEnvWhiteList string, cntConfig container.Config) map[string]string { + metadataEnvs := strings.Split(dockerEnvWhiteList, ",") + handlerEnvs := make(map[string]string) + + // split env vars to get metadata map. + for _, exposedEnv := range metadataEnvs { + for _, envVar := range cntConfig.Env { + if envVar != "" { + splits := strings.SplitN(envVar, "=", 2) + if len(splits) == 2 && splits[0] == exposedEnv { + handlerEnvs[strings.ToLower(exposedEnv)] = splits[1] + } + } + } + } + + return handlerEnvs +} + +func newMetadataEnvMatch(dockerEnvWhiteList string, cntConfig container.Config) map[string]string { + metadataEnvs := strings.Split(dockerEnvWhiteList, ",") + handlerEnvs := make(map[string]string) + + // split env vars to get metadata map. + for _, exposedEnv := range metadataEnvs { + if exposedEnv == "" { + // if no dockerEnvWhitelist provided, len(metadataEnvs) == 1, metadataEnvs[0] == "" + continue + } + + for _, envVar := range cntConfig.Env { + if envVar != "" { + splits := strings.SplitN(envVar, "=", 2) + if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) { + handlerEnvs[strings.ToLower(splits[0])] = splits[1] + } + } + } + } + + return handlerEnvs +} + +func TestDockerEnvWhitelist(t *testing.T) { + as := assert.New(t) + + envTotalMatch := "TEST_REGION,TEST_ZONE" + envMatchWithPrefix := "TEST_" + envMatchWithPrefixEmpty := "" + + rawCntConfig := container.Config{Env: []string{"TEST_REGION=FRA", "TEST_ZONE=A", "HELLO=WORLD"}} + newCntConfig := container.Config{Env: []string{"TEST_REGION=FRA", "TEST_ZONE=A", "TEST_POOL=TOOLING", "HELLO=WORLD"}} + + rawExpected := map[string]string{ + "test_region": "FRA", + "test_zone": "A", + } + newExpected := map[string]string{ + "test_region": "FRA", + "test_zone": "A", + "test_pool": "TOOLING", + } + emptyExpected := map[string]string{} + + rawEnvsTotalMatch := rawMetadataEnvMatch(envTotalMatch, rawCntConfig) + newEnvsTotalMatch := newMetadataEnvMatch(envTotalMatch, rawCntConfig) + + // make sure total match does not change + as.Equal(rawEnvsTotalMatch, newEnvsTotalMatch) + as.Equal(rawEnvsTotalMatch, rawExpected) + + rawEnvsTotalMatch2 := rawMetadataEnvMatch(envTotalMatch, newCntConfig) + newEnvsTotalMatch2 := newMetadataEnvMatch(envTotalMatch, newCntConfig) + + // make sure total match does not change with more envs exposed + as.Equal(rawEnvsTotalMatch2, newEnvsTotalMatch2) + as.Equal(rawEnvsTotalMatch2, rawExpected) + + newEnvsMatchWithPrefix := newMetadataEnvMatch(envMatchWithPrefix, rawCntConfig) + newEnvsMatchWithPrefix2 := newMetadataEnvMatch(envMatchWithPrefix, newCntConfig) + + // make sure new method can return envs with prefix specified + as.Equal(newEnvsMatchWithPrefix, rawExpected) + as.Equal(newEnvsMatchWithPrefix2, newExpected) + + newEnvsMatchWithEmptyPrefix := newMetadataEnvMatch(envMatchWithPrefixEmpty, newCntConfig) + rawEnvsMatchWithEmptyWhitelist := rawMetadataEnvMatch(envMatchWithPrefixEmpty, newCntConfig) + + // make sure empty whitelist returns nothing + as.Equal(newEnvsMatchWithEmptyPrefix, emptyExpected) + as.Equal(rawEnvsMatchWithEmptyWhitelist, emptyExpected) + +}