Skip to content

Commit 8d9fa25

Browse files
committed
v2 parsing
Signed-off-by: Josh Curl <[email protected]>
1 parent 345306e commit 8d9fa25

21 files changed

+1474
-333
lines changed

Diff for: config/convert.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package config
2+
3+
import "github.com/docker/libcompose/utils"
4+
5+
// ConvertV1toV2 converts a v1 service config to a v2 service config
6+
func ConvertV1toV2(v1Services map[string]*ServiceConfigV1, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup) (map[string]*ServiceConfig, error) {
7+
v2Services := make(map[string]*ServiceConfig)
8+
9+
builds := make(map[string]Build)
10+
logs := make(map[string]Log)
11+
12+
for name, service := range v1Services {
13+
builds[name] = Build{
14+
Context: service.Build,
15+
Dockerfile: service.Dockerfile,
16+
}
17+
18+
v1Services[name].Build = ""
19+
v1Services[name].Dockerfile = ""
20+
21+
logs[name] = Log{
22+
Driver: service.LogDriver,
23+
Options: service.LogOpt,
24+
}
25+
26+
v1Services[name].LogDriver = ""
27+
v1Services[name].LogOpt = nil
28+
}
29+
30+
if err := utils.Convert(v1Services, &v2Services); err != nil {
31+
return nil, err
32+
}
33+
34+
for name := range v2Services {
35+
v2Services[name].Build = builds[name]
36+
}
37+
38+
return v2Services, nil
39+
}

Diff for: config/marshal_config_test.go

+12-10
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ func newTestConfig() TestConfig {
1616
return TestConfig{
1717
SystemContainers: map[string]*ServiceConfig{
1818
"udev": {
19-
Image: "udev",
20-
Restart: "always",
21-
Net: "host",
22-
Privileged: true,
23-
DNS: []string{"8.8.8.8", "8.8.4.4"},
19+
Image: "udev",
20+
Restart: "always",
21+
NetworkMode: "host",
22+
Privileged: true,
23+
DNS: []string{"8.8.8.8", "8.8.4.4"},
2424
Environment: yamlTypes.MaporEqualSlice([]string{
2525
"DAEMON=true",
2626
}),
@@ -38,10 +38,10 @@ func newTestConfig() TestConfig {
3838
},
3939
},
4040
"system-volumes": {
41-
Image: "state",
42-
Net: "none",
43-
ReadOnly: true,
44-
Privileged: true,
41+
Image: "state",
42+
NetworkMode: "none",
43+
ReadOnly: true,
44+
Privileged: true,
4545
Labels: yamlTypes.SliceorMap{
4646
"io.rancher.os.createonly": "true",
4747
"io.rancher.os.scope": "system",
@@ -55,7 +55,9 @@ func newTestConfig() TestConfig {
5555
"/var/run:/var/run",
5656
"/var/log:/var/log",
5757
},
58-
LogDriver: "json-file",
58+
Logging: Log{
59+
Driver: "json-file",
60+
},
5961
},
6062
},
6163
}

Diff for: config/merge.go

+39-212
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@ import (
44
"bufio"
55
"bytes"
66
"fmt"
7-
"path"
87
"strings"
98

10-
"github.com/Sirupsen/logrus"
119
yaml "github.com/cloudfoundry-incubator/candiedyaml"
1210
"github.com/docker/docker/pkg/urlutil"
13-
"github.com/docker/libcompose/utils"
1411
)
1512

1613
var (
@@ -20,56 +17,44 @@ var (
2017
}
2118
)
2219

23-
// MergeServices merges a compose file into an existing set of service configs
24-
func MergeServices(existingServices *Configs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte) (map[string]*ServiceConfig, error) {
25-
configs := make(map[string]*ServiceConfig)
26-
27-
datas := make(RawServiceMap)
28-
if err := yaml.Unmarshal(bytes, &datas); err != nil {
29-
return nil, err
30-
}
31-
32-
if err := Interpolate(environmentLookup, &datas); err != nil {
33-
return nil, err
20+
// Merge merges a compose file into an existing set of service configs
21+
func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte) (map[string]*ServiceConfig, map[string]*VolumeConfig, map[string]*NetworkConfig, error) {
22+
var config Config
23+
if err := yaml.Unmarshal(bytes, &config); err != nil {
24+
return nil, nil, nil, err
3425
}
3526

36-
if err := validate(datas); err != nil {
37-
return nil, err
38-
}
39-
40-
for name, data := range datas {
41-
data, err := parse(resourceLookup, environmentLookup, file, data, datas)
27+
var serviceConfigs map[string]*ServiceConfig
28+
var volumeConfigs map[string]*VolumeConfig
29+
var networkConfigs map[string]*NetworkConfig
30+
if config.Version == "2" {
31+
var err error
32+
serviceConfigs, err = MergeServicesV2(existingServices, environmentLookup, resourceLookup, file, bytes)
4233
if err != nil {
43-
logrus.Errorf("Failed to parse service %s: %v", name, err)
44-
return nil, err
34+
return nil, nil, nil, err
4535
}
46-
47-
if serviceConfig, ok := existingServices.Get(name); ok {
48-
var rawExistingService RawService
49-
if err := utils.Convert(serviceConfig, &rawExistingService); err != nil {
50-
return nil, err
51-
}
52-
53-
data = mergeConfig(rawExistingService, data)
36+
volumeConfigs, err = ParseVolumes(environmentLookup, resourceLookup, file, bytes)
37+
if err != nil {
38+
return nil, nil, nil, err
5439
}
55-
56-
datas[name] = data
57-
}
58-
59-
for name, data := range datas {
60-
err := validateServiceConstraints(data, name)
40+
networkConfigs, err = ParseNetworks(environmentLookup, resourceLookup, file, bytes)
6141
if err != nil {
62-
return nil, err
42+
return nil, nil, nil, err
43+
}
44+
} else {
45+
serviceConfigsV1, err := MergeServicesV1(existingServices, environmentLookup, resourceLookup, file, bytes)
46+
if err != nil {
47+
return nil, nil, nil, err
48+
}
49+
serviceConfigs, err = ConvertV1toV2(serviceConfigsV1, environmentLookup, resourceLookup)
50+
if err != nil {
51+
return nil, nil, nil, err
6352
}
6453
}
6554

66-
if err := utils.Convert(datas, &configs); err != nil {
67-
return nil, err
68-
}
69-
70-
adjustValues(configs)
55+
adjustValues(serviceConfigs)
7156

72-
return configs, nil
57+
return serviceConfigs, volumeConfigs, networkConfigs, nil
7358
}
7459

7560
func adjustValues(configs map[string]*ServiceConfig) {
@@ -82,24 +67,25 @@ func adjustValues(configs map[string]*ServiceConfig) {
8267
}
8368

8469
func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawService) (RawService, error) {
85-
var config ServiceConfig
86-
87-
if err := utils.Convert(serviceData, &config); err != nil {
88-
return nil, err
70+
if _, ok := serviceData["env_file"]; !ok {
71+
return serviceData, nil
8972
}
90-
91-
if len(config.EnvFile) == 0 {
73+
envFiles := serviceData["env_file"].([]interface{})
74+
if len(envFiles) == 0 {
9275
return serviceData, nil
9376
}
9477

9578
if resourceLookup == nil {
9679
return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile)
9780
}
9881

99-
vars := config.Environment
82+
var vars []interface{}
83+
if _, ok := serviceData["environment"]; ok {
84+
vars = serviceData["environment"].([]interface{})
85+
}
10086

101-
for i := len(config.EnvFile) - 1; i >= 0; i-- {
102-
envFile := config.EnvFile[i]
87+
for i := len(envFiles) - 1; i >= 0; i-- {
88+
envFile := envFiles[i].(string)
10389
content, _, err := resourceLookup.Lookup(envFile, inFile)
10490
if err != nil {
10591
return nil, err
@@ -116,7 +102,7 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe
116102

117103
found := false
118104
for _, v := range vars {
119-
if strings.HasPrefix(v, key) {
105+
if strings.HasPrefix(v.(string), key) {
120106
found = true
121107
break
122108
}
@@ -139,124 +125,6 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe
139125
return serviceData, nil
140126
}
141127

142-
func resolveBuild(inFile string, serviceData RawService) (RawService, error) {
143-
144-
build := asString(serviceData["build"])
145-
if build == "" {
146-
return serviceData, nil
147-
}
148-
149-
if IsValidRemote(build) {
150-
return serviceData, nil
151-
}
152-
153-
current := path.Dir(inFile)
154-
155-
if build == "." {
156-
build = current
157-
} else {
158-
current = path.Join(current, build)
159-
}
160-
161-
serviceData["build"] = current
162-
163-
return serviceData, nil
164-
}
165-
166-
func parse(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, inFile string, serviceData RawService, datas RawServiceMap) (RawService, error) {
167-
serviceData, err := readEnvFile(resourceLookup, inFile, serviceData)
168-
if err != nil {
169-
return nil, err
170-
}
171-
172-
serviceData, err = resolveBuild(inFile, serviceData)
173-
if err != nil {
174-
return nil, err
175-
}
176-
177-
value, ok := serviceData["extends"]
178-
if !ok {
179-
return serviceData, nil
180-
}
181-
182-
mapValue, ok := value.(map[interface{}]interface{})
183-
if !ok {
184-
return serviceData, nil
185-
}
186-
187-
if resourceLookup == nil {
188-
return nil, fmt.Errorf("Can not use extends in file %s no mechanism provided to files", inFile)
189-
}
190-
191-
file := asString(mapValue["file"])
192-
service := asString(mapValue["service"])
193-
194-
if service == "" {
195-
return serviceData, nil
196-
}
197-
198-
var baseService RawService
199-
200-
if file == "" {
201-
if serviceData, ok := datas[service]; ok {
202-
baseService, err = parse(resourceLookup, environmentLookup, inFile, serviceData, datas)
203-
} else {
204-
return nil, fmt.Errorf("Failed to find service %s to extend", service)
205-
}
206-
} else {
207-
bytes, resolved, err := resourceLookup.Lookup(file, inFile)
208-
if err != nil {
209-
logrus.Errorf("Failed to lookup file %s: %v", file, err)
210-
return nil, err
211-
}
212-
213-
var baseRawServices RawServiceMap
214-
if err := yaml.Unmarshal(bytes, &baseRawServices); err != nil {
215-
return nil, err
216-
}
217-
218-
err = Interpolate(environmentLookup, &baseRawServices)
219-
if err != nil {
220-
return nil, err
221-
}
222-
223-
if err := validate(baseRawServices); err != nil {
224-
return nil, err
225-
}
226-
227-
baseService, ok = baseRawServices[service]
228-
if !ok {
229-
return nil, fmt.Errorf("Failed to find service %s in file %s", service, file)
230-
}
231-
232-
baseService, err = parse(resourceLookup, environmentLookup, resolved, baseService, baseRawServices)
233-
}
234-
235-
if err != nil {
236-
return nil, err
237-
}
238-
239-
baseService = clone(baseService)
240-
241-
logrus.Debugf("Merging %#v, %#v", baseService, serviceData)
242-
243-
for _, k := range noMerge {
244-
if _, ok := baseService[k]; ok {
245-
source := file
246-
if source == "" {
247-
source = inFile
248-
}
249-
return nil, fmt.Errorf("Cannot extend service '%s' in %s: services with '%s' cannot be extended", service, source, k)
250-
}
251-
}
252-
253-
baseService = mergeConfig(baseService, serviceData)
254-
255-
logrus.Debugf("Merged result %#v", baseService)
256-
257-
return baseService, nil
258-
}
259-
260128
func mergeConfig(baseService, serviceData RawService) RawService {
261129
for k, v := range serviceData {
262130
// Image and build are mutually exclusive in merge
@@ -276,47 +144,6 @@ func mergeConfig(baseService, serviceData RawService) RawService {
276144
return baseService
277145
}
278146

279-
func merge(existing, value interface{}) interface{} {
280-
// append strings
281-
if left, lok := existing.([]interface{}); lok {
282-
if right, rok := value.([]interface{}); rok {
283-
return append(left, right...)
284-
}
285-
}
286-
287-
//merge maps
288-
if left, lok := existing.(map[interface{}]interface{}); lok {
289-
if right, rok := value.(map[interface{}]interface{}); rok {
290-
newLeft := make(map[interface{}]interface{})
291-
for k, v := range left {
292-
newLeft[k] = v
293-
}
294-
for k, v := range right {
295-
newLeft[k] = v
296-
}
297-
return newLeft
298-
}
299-
}
300-
301-
return value
302-
}
303-
304-
func clone(in RawService) RawService {
305-
result := RawService{}
306-
for k, v := range in {
307-
result[k] = v
308-
}
309-
310-
return result
311-
}
312-
313-
func asString(obj interface{}) string {
314-
if v, ok := obj.(string); ok {
315-
return v
316-
}
317-
return ""
318-
}
319-
320147
// IsValidRemote checks if the specified string is a valid remote (for builds)
321148
func IsValidRemote(remote string) bool {
322149
return urlutil.IsGitURL(remote) || urlutil.IsURL(remote)

0 commit comments

Comments
 (0)