Skip to content

Commit 618f642

Browse files
authored
Add support of env vars on config_sources section (#312)
1 parent d5b3384 commit 618f642

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

internal/configprovider/parser.go

+34-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ package configprovider
1818
import (
1919
"context"
2020
"fmt"
21+
"strings"
2122

2223
"github.com/spf13/cast"
2324
"go.opentelemetry.io/collector/config"
25+
"go.opentelemetry.io/collector/config/experimental/configsource"
2426
)
2527

2628
const (
@@ -37,16 +39,46 @@ type (
3739

3840
// Load reads the configuration for ConfigSource objects from the given parser and returns a map
3941
// from the full name of config sources to the respective ConfigSettings.
40-
func Load(_ context.Context, v *config.Parser, factories Factories) (map[string]ConfigSettings, error) {
42+
func Load(ctx context.Context, v *config.Parser, factories Factories) (map[string]ConfigSettings, error) {
43+
processedParser, err := processParser(ctx, v)
44+
if err != nil {
45+
return nil, err
46+
}
4147

42-
cfgSrcSettings, err := loadSettings(cast.ToStringMap(v.Get(configSourcesKey)), factories)
48+
cfgSrcSettings, err := loadSettings(cast.ToStringMap(processedParser.Get(configSourcesKey)), factories)
4349
if err != nil {
4450
return nil, err
4551
}
4652

4753
return cfgSrcSettings, nil
4854
}
4955

56+
// processParser prepares a config.Parser to be used to load config source settings.
57+
func processParser(ctx context.Context, v *config.Parser) (*config.Parser, error) {
58+
// Use a manager to resolve environment variables with a syntax consistent with
59+
// the config source usage.
60+
manager := newManager(make(map[string]configsource.ConfigSource))
61+
defer func() {
62+
_ = manager.Close(ctx)
63+
}()
64+
65+
processedParser := config.NewParser()
66+
for _, key := range v.AllKeys() {
67+
if !strings.HasPrefix(key, configSourcesKey) {
68+
// In Load we only care about config sources, ignore everything else.
69+
continue
70+
}
71+
72+
value, err := manager.expandStringValues(ctx, v.Get(key))
73+
if err != nil {
74+
return nil, err
75+
}
76+
processedParser.Set(key, value)
77+
}
78+
79+
return processedParser, nil
80+
}
81+
5082
func loadSettings(css map[string]interface{}, factories Factories) (map[string]ConfigSettings, error) {
5183
// Prepare resulting map.
5284
cfgSrcToSettings := make(map[string]ConfigSettings)
@@ -55,8 +87,6 @@ func loadSettings(css map[string]interface{}, factories Factories) (map[string]C
5587
for key, value := range css {
5688
settingsParser := config.NewParserFromStringMap(cast.ToStringMap(value))
5789

58-
// TODO: expand env vars.
59-
6090
// Decode the key into type and fullName components.
6191
componentID, err := config.IDFromString(key)
6292
if err != nil {

internal/configprovider/parser_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package configprovider
1717

1818
import (
1919
"context"
20+
"os"
2021
"path"
2122
"testing"
2223

@@ -35,6 +36,7 @@ func TestConfigSourceParser(t *testing.T) {
3536
tests := []struct {
3637
factories Factories
3738
expected map[string]ConfigSettings
39+
envvars map[string]string
3840
wantErr error
3941
name string
4042
file string
@@ -61,6 +63,31 @@ func TestConfigSourceParser(t *testing.T) {
6163
},
6264
},
6365
},
66+
{
67+
name: "env_var_on_load",
68+
file: "env_var_on_load",
69+
factories: testFactories,
70+
envvars: map[string]string{
71+
"ENV_VAR_ENDPOINT": "env_var_endpoint",
72+
"ENV_VAR_TOKEN": "env_var_token",
73+
},
74+
expected: map[string]ConfigSettings{
75+
"tstcfgsrc": &mockCfgSrcSettings{
76+
Settings: Settings{
77+
TypeVal: "tstcfgsrc",
78+
NameVal: "tstcfgsrc",
79+
},
80+
Endpoint: "https://env_var_endpoint:8200",
81+
Token: "env_var_token",
82+
},
83+
},
84+
},
85+
{
86+
name: "cfgsrc_load_cannot_use_cfgsrc",
87+
file: "cfgsrc_load_use_cfgsrc",
88+
factories: testFactories,
89+
wantErr: &errUnknownConfigSource{},
90+
},
6491
{
6592
name: "bad_name",
6693
file: "bad_name",
@@ -94,6 +121,14 @@ func TestConfigSourceParser(t *testing.T) {
94121
v, err := config.NewParserFromFile(cfgFile)
95122
require.NoError(t, err)
96123

124+
for key, value := range tt.envvars {
125+
require.NoError(t, os.Setenv(key, value))
126+
keyToUnset := key
127+
defer func() {
128+
assert.NoError(t, os.Unsetenv(keyToUnset))
129+
}()
130+
}
131+
97132
cfgSrcSettings, err := Load(ctx, v, tt.factories)
98133
require.IsType(t, tt.wantErr, err)
99134
assert.Equal(t, tt.expected, cfgSrcSettings)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
config_sources:
2+
tstcfgsrc:
3+
tstcfgsrc/named:
4+
# It is not valid to use a dynamic config source when defining other one.
5+
endpoint: $tstcfgsrc:str_value
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
config_sources:
2+
tstcfgsrc:
3+
endpoint: https://${ENV_VAR_ENDPOINT}:8200
4+
token: $ENV_VAR_TOKEN
5+
ignored_by_parser:
6+
some_field: $ENV_VAR_TOKEN

0 commit comments

Comments
 (0)