Skip to content

Commit 550d532

Browse files
joshwgetvdemeester
authored andcommitted
Interpolate under volumes and networks
Signed-off-by: Josh Curl <[email protected]> Signed-off-by: Vincent Demeester <[email protected]>
1 parent 01be924 commit 550d532

15 files changed

+109
-126
lines changed

config/interpolation.go

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,19 @@ func parseLine(line string, mapping func(string) string) (string, bool) {
102102
return buffer.String(), true
103103
}
104104

105-
func parseConfig(option, service string, data *interface{}, mapping func(string) string) error {
105+
func parseConfig(key string, data *interface{}, mapping func(string) string) error {
106106
switch typedData := (*data).(type) {
107107
case string:
108108
var success bool
109109

110110
*data, success = parseLine(typedData, mapping)
111111

112112
if !success {
113-
return fmt.Errorf("Invalid interpolation format for \"%s\" option in service \"%s\": \"%s\"", option, service, typedData)
113+
return fmt.Errorf("Invalid interpolation format for key \"%s\": \"%s\"", key, typedData)
114114
}
115115
case []interface{}:
116116
for k, v := range typedData {
117-
err := parseConfig(option, service, &v, mapping)
117+
err := parseConfig(key, &v, mapping)
118118

119119
if err != nil {
120120
return err
@@ -124,7 +124,7 @@ func parseConfig(option, service string, data *interface{}, mapping func(string)
124124
}
125125
case map[interface{}]interface{}:
126126
for k, v := range typedData {
127-
err := parseConfig(option, service, &v, mapping)
127+
err := parseConfig(key, &v, mapping)
128128

129129
if err != nil {
130130
return err
@@ -137,33 +137,21 @@ func parseConfig(option, service string, data *interface{}, mapping func(string)
137137
return nil
138138
}
139139

140-
// Interpolate replaces variables in the raw map representation of the project file
141-
func Interpolate(environmentLookup EnvironmentLookup, config *RawServiceMap) error {
142-
for k, v := range *config {
143-
for k2, v2 := range v {
144-
err := parseConfig(k2, k, &v2, func(s string) string {
145-
values := environmentLookup.Lookup(s, k, nil)
140+
// Interpolate replaces variables in a map entry
141+
func Interpolate(key string, data *interface{}, environmentLookup EnvironmentLookup) error {
142+
return parseConfig(key, data, func(s string) string {
143+
values := environmentLookup.Lookup(s, nil)
146144

147-
if len(values) == 0 {
148-
logrus.Warnf("The %s variable is not set. Substituting a blank string.", s)
149-
return ""
150-
}
151-
152-
// Use first result if many are given
153-
value := values[0]
154-
155-
// Environment variables come in key=value format
156-
// Return everything past first '='
157-
return strings.SplitN(value, "=", 2)[1]
158-
})
159-
160-
if err != nil {
161-
return err
162-
}
163-
164-
(*config)[k][k2] = v2
145+
if len(values) == 0 {
146+
logrus.Warnf("The %s variable is not set. Substituting a blank string.", s)
147+
return ""
165148
}
166-
}
167149

168-
return nil
150+
// Use first result if many are given
151+
value := values[0]
152+
153+
// Environment variables come in key=value format
154+
// Return everything past first '='
155+
return strings.SplitN(value, "=", 2)[1]
156+
})
169157
}

config/interpolation_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ type MockEnvironmentLookup struct {
8181
Variables map[string]string
8282
}
8383

84-
func (m MockEnvironmentLookup) Lookup(key, serviceName string, config *ServiceConfig) []string {
84+
func (m MockEnvironmentLookup) Lookup(key string, config *ServiceConfig) []string {
8585
return []string{fmt.Sprintf("%s=%s", key, m.Variables[key])}
8686
}
8787

@@ -99,7 +99,7 @@ func testInterpolatedConfig(t *testing.T, expectedConfig, interpolatedConfig str
9999
yaml.Unmarshal(expectedConfigBytes, &expectedData)
100100
yaml.Unmarshal(interpolatedConfigBytes, &interpolatedData)
101101

102-
_ = Interpolate(MockEnvironmentLookup{envVariables}, &interpolatedData)
102+
_ = InterpolateRawServiceMap(&interpolatedData, MockEnvironmentLookup{envVariables})
103103

104104
for k := range envVariables {
105105
os.Unsetenv(k)
@@ -113,8 +113,7 @@ func testInvalidInterpolatedConfig(t *testing.T, interpolatedConfig string) {
113113
interpolatedData := make(RawServiceMap)
114114
yaml.Unmarshal(interpolatedConfigBytes, &interpolatedData)
115115

116-
err := Interpolate(new(MockEnvironmentLookup), &interpolatedData)
117-
116+
err := InterpolateRawServiceMap(&interpolatedData, new(MockEnvironmentLookup))
118117
assert.NotNil(t, err)
119118
}
120119

config/merge.go

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,22 @@ func CreateConfig(bytes []byte) (*Config, error) {
2929
if err := yaml.Unmarshal(bytes, &config); err != nil {
3030
return nil, err
3131
}
32-
if config.Version == "2" {
33-
for key, value := range config.Networks {
34-
if value == nil {
35-
config.Networks[key] = &NetworkConfig{}
36-
}
37-
}
38-
for key, value := range config.Volumes {
39-
if value == nil {
40-
config.Volumes[key] = &VolumeConfig{}
41-
}
42-
}
43-
} else {
32+
33+
if config.Version != "2" {
4434
var baseRawServices RawServiceMap
4535
if err := yaml.Unmarshal(bytes, &baseRawServices); err != nil {
4636
return nil, err
4737
}
4838
config.Services = baseRawServices
4939
}
5040

41+
if config.Volumes == nil {
42+
config.Volumes = make(map[string]interface{})
43+
}
44+
if config.Networks == nil {
45+
config.Networks = make(map[string]interface{})
46+
}
47+
5148
return &config, nil
5249
}
5350

@@ -63,6 +60,34 @@ func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup
6360
}
6461
baseRawServices := config.Services
6562

63+
if options.Interpolate {
64+
if err := InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil {
65+
return "", nil, nil, nil, err
66+
}
67+
68+
for k, v := range config.Volumes {
69+
if err := Interpolate(k, &v, environmentLookup); err != nil {
70+
return "", nil, nil, nil, err
71+
}
72+
config.Volumes[k] = v
73+
}
74+
75+
for k, v := range config.Networks {
76+
if err := Interpolate(k, &v, environmentLookup); err != nil {
77+
return "", nil, nil, nil, err
78+
}
79+
config.Networks[k] = v
80+
}
81+
}
82+
83+
if options.Preprocess != nil {
84+
var err error
85+
baseRawServices, err = options.Preprocess(baseRawServices)
86+
if err != nil {
87+
return "", nil, nil, nil, err
88+
}
89+
}
90+
6691
var serviceConfigs map[string]*ServiceConfig
6792
if config.Version == "2" {
6893
var err error
@@ -91,7 +116,29 @@ func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup
91116
}
92117
}
93118

94-
return config.Version, serviceConfigs, config.Volumes, config.Networks, nil
119+
var volumes map[string]*VolumeConfig
120+
var networks map[string]*NetworkConfig
121+
if err := utils.Convert(config.Volumes, &volumes); err != nil {
122+
return "", nil, nil, nil, err
123+
}
124+
if err := utils.Convert(config.Networks, &networks); err != nil {
125+
return "", nil, nil, nil, err
126+
}
127+
128+
return config.Version, serviceConfigs, volumes, networks, nil
129+
}
130+
131+
// InterpolateRawServiceMap replaces varialbse in raw service map struct based on environment lookup
132+
func InterpolateRawServiceMap(baseRawServices *RawServiceMap, environmentLookup EnvironmentLookup) error {
133+
for k, v := range *baseRawServices {
134+
for k2, v2 := range v {
135+
if err := Interpolate(k2, &v2, environmentLookup); err != nil {
136+
return err
137+
}
138+
(*baseRawServices)[k][k2] = v2
139+
}
140+
}
141+
return nil
95142
}
96143

97144
func adjustValues(configs map[string]*ServiceConfig) {

config/merge_test.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -405,20 +405,3 @@ services:
405405
}
406406
}
407407
}
408-
409-
func TestNilNetworks(t *testing.T) {
410-
composeFile := []byte(`
411-
version: '2'
412-
networks:
413-
public:`)
414-
415-
config, err := CreateConfig(composeFile)
416-
if err != nil {
417-
t.Fatal(err)
418-
}
419-
for key, networkConfig := range config.Networks {
420-
if networkConfig == nil {
421-
t.Fatalf("networkConfig %s was nil, shouldn't be", key)
422-
}
423-
}
424-
}

config/merge_v1.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,6 @@ import (
1010

1111
// MergeServicesV1 merges a v1 compose file into an existing set of service configs
1212
func MergeServicesV1(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, datas RawServiceMap, options *ParseOptions) (map[string]*ServiceConfigV1, error) {
13-
if options.Interpolate {
14-
if err := Interpolate(environmentLookup, &datas); err != nil {
15-
return nil, err
16-
}
17-
}
18-
19-
if options.Preprocess != nil {
20-
var err error
21-
datas, err = options.Preprocess(datas)
22-
if err != nil {
23-
return nil, err
24-
}
25-
}
26-
2713
if options.Validate {
2814
if err := validate(datas); err != nil {
2915
return nil, err
@@ -117,8 +103,7 @@ func parseV1(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup,
117103
baseRawServices := config.Services
118104

119105
if options.Interpolate {
120-
err = Interpolate(environmentLookup, &baseRawServices)
121-
if err != nil {
106+
if err = InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil {
122107
return nil, err
123108
}
124109
}

config/merge_v2.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,6 @@ import (
1010

1111
// MergeServicesV2 merges a v2 compose file into an existing set of service configs
1212
func MergeServicesV2(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, datas RawServiceMap, options *ParseOptions) (map[string]*ServiceConfig, error) {
13-
if options.Interpolate {
14-
if err := Interpolate(environmentLookup, &datas); err != nil {
15-
return nil, err
16-
}
17-
}
18-
19-
if options.Preprocess != nil {
20-
var err error
21-
datas, err = options.Preprocess(datas)
22-
if err != nil {
23-
return nil, err
24-
}
25-
}
26-
2713
if options.Validate {
2814
if err := validateV2(datas); err != nil {
2915
return nil, err
@@ -108,8 +94,7 @@ func parseV2(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup,
10894
baseRawServices := config.Services
10995

11096
if options.Interpolate {
111-
err = Interpolate(environmentLookup, &baseRawServices)
112-
if err != nil {
97+
if err = InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil {
11398
return nil, err
11499
}
115100
}

config/types.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
// EnvironmentLookup defines methods to provides environment variable loading.
1010
type EnvironmentLookup interface {
11-
Lookup(key, serviceName string, config *ServiceConfig) []string
11+
Lookup(key string, config *ServiceConfig) []string
1212
}
1313

1414
// ResourceLookup defines methods to provides file loading.
@@ -172,10 +172,10 @@ type NetworkConfig struct {
172172

173173
// Config holds libcompose top level configuration
174174
type Config struct {
175-
Version string `yaml:"version,omitempty"`
176-
Services RawServiceMap `yaml:"services,omitempty"`
177-
Volumes map[string]*VolumeConfig `yaml:"volumes,omitempty"`
178-
Networks map[string]*NetworkConfig `yaml:"networks,omitempty"`
175+
Version string `yaml:"version,omitempty"`
176+
Services RawServiceMap `yaml:"services,omitempty"`
177+
Volumes map[string]interface{} `yaml:"volumes,omitempty"`
178+
Networks map[string]interface{} `yaml:"networks,omitempty"`
179179
}
180180

181181
// NewServiceConfigs initializes a new Configs struct

lookup/composable.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ type ComposableEnvLookup struct {
1313
// Lookup creates a string slice of string containing a "docker-friendly" environment string
1414
// in the form of 'key=value'. It loop through the lookups and returns the latest value if
1515
// more than one lookup return a result.
16-
func (l *ComposableEnvLookup) Lookup(key, serviceName string, config *config.ServiceConfig) []string {
16+
func (l *ComposableEnvLookup) Lookup(key string, config *config.ServiceConfig) []string {
1717
result := []string{}
1818
for _, lookup := range l.Lookups {
19-
env := lookup.Lookup(key, serviceName, config)
19+
env := lookup.Lookup(key, config)
2020
if len(env) == 1 {
2121
result = env
2222
}

lookup/composable_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ type simpleEnvLookup struct {
1010
value []string
1111
}
1212

13-
func (l *simpleEnvLookup) Lookup(key, serviceName string, config *config.ServiceConfig) []string {
13+
func (l *simpleEnvLookup) Lookup(key string, config *config.ServiceConfig) []string {
1414
return l.value
1515
}
1616

1717
func TestComposableLookupWithoutAnyLookup(t *testing.T) {
1818
envLookup := &ComposableEnvLookup{}
19-
actuals := envLookup.Lookup("any", "", nil)
19+
actuals := envLookup.Lookup("any", nil)
2020
if len(actuals) != 0 {
2121
t.Fatalf("expected an empty slice, got %v", actuals)
2222
}
@@ -35,13 +35,13 @@ func TestComposableLookupReturnsTheLastValue(t *testing.T) {
3535
envLookup2,
3636
},
3737
}
38-
validateLookup(t, "value=2", envLookup.Lookup("value", "", nil))
38+
validateLookup(t, "value=2", envLookup.Lookup("value", nil))
3939

4040
envLookup = &ComposableEnvLookup{
4141
[]config.EnvironmentLookup{
4242
envLookup2,
4343
envLookup1,
4444
},
4545
}
46-
validateLookup(t, "value=1", envLookup.Lookup("value", "", nil))
46+
validateLookup(t, "value=1", envLookup.Lookup("value", nil))
4747
}

lookup/envfile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type EnvfileLookup struct {
1616
// Lookup creates a string slice of string containing a "docker-friendly" environment string
1717
// in the form of 'key=value'. It gets environment values using a '.env' file in the specified
1818
// path.
19-
func (l *EnvfileLookup) Lookup(key, serviceName string, config *config.ServiceConfig) []string {
19+
func (l *EnvfileLookup) Lookup(key string, config *config.ServiceConfig) []string {
2020
envs, err := opts.ParseEnvFile(l.Path)
2121
if err != nil {
2222
return []string{}

0 commit comments

Comments
 (0)