Skip to content

Commit

Permalink
Support alternative depends_on configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
rycus86 committed Jun 15, 2018
1 parent c131cd8 commit 9cfaa76
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 1 deletion.
84 changes: 84 additions & 0 deletions pkg/template/depends_on.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package template

import (
"fmt"
"github.com/docker/cli/cli/compose/loader"
)

// Remove and return the Compose v2 compatible depends_on configurations.
// These won't parse for the v3 service type, so we'll just have to add them
// back after the conversion is done.
func extractDependsOnConfig(configuration map[string]interface{}) map[string]interface{} {
servicesWithDependsOn := map[string]interface{}{}

for name, config := range configuration {
if mConfig, ok := config.(map[string]interface{}); !ok {
panic(fmt.Sprintf("unexpected service definition type: %T", config))

} else if dependsOn, ok := mConfig["depends_on"]; ok {
validateDependsOn(dependsOn)

servicesWithDependsOn[name] = map[string]interface{}{
"depends_on": dependsOn,
}

delete(mConfig, "depends_on")
}
}

return servicesWithDependsOn
}

func validateDependsOn(v interface{}) {
switch v.(type) {
case []string:
// ok

case []interface{}:
for _, item := range v.([]interface{}) {
if _, ok := item.(string); !ok {
panic(fmt.Sprintf("invalid depends_on list item: %+v %T", item, item))
}
}

case map[string]interface{}:
for svc, config := range v.(map[string]interface{}) {
if mConfig, ok := config.(map[string]interface{}); !ok {
panic(fmt.Sprintf("invalid depends_on defined for %s (type %T)", svc, config))
} else if condition, ok := mConfig["condition"]; !ok {
panic(fmt.Sprintf("condition not found for %s dependency", svc))
} else if condition != "service_started" && condition != "service_healthy" {
panic(fmt.Sprintf("invalid condition defined for %s : %s", svc, condition))
}
}

default:
panic(fmt.Sprintf("unexpected depends_on config type: %T", v))
}
}

// Merge in the previously removed depends_on configurations to the rendered YAML string.
func insertDependsOnConfig(target string, source map[string]interface{}, service string) string {
var config interface{}

if svcConfig, ok := source[service]; !ok {
return target
} else if mConfig, ok := svcConfig.(map[string]interface{}); !ok {
panic(fmt.Sprintf("somehow lost the depends_on settings for %s", service))
} else {
config = mConfig["depends_on"]
}

if config == nil {
panic(fmt.Sprintf("somehow lost the depends_on settings for %s", service))
}

parsed, err := loader.ParseYAML([]byte(target))
if err != nil {
panic(fmt.Sprintf("failed to parse the output YAML for %s", service))
}

parsed["depends_on"] = config

return convertToYaml(parsed)
}
25 changes: 25 additions & 0 deletions pkg/template/testdata/stack-with-dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: '3.5'
services:

dep:
image: sample/inline
x-podlike:
templates:

- inline:
first:
image: sample/first

- inline:
second:
image: sample/second
depends_on:
first:
condition: service_healthy

- inline:
third:
image: sample/third
depends_on:
- first
- second
17 changes: 16 additions & 1 deletion pkg/template/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,19 @@ func executeTransformers(tc *transformConfiguration) (string, string) {

mergeServiceProperties(definition, tc.getServiceConfig(), mergedTransformerKeys)

// we need to remove depends_on here, the Compose v2 compatible format won't parse for the v3 service type
servicesWithDependsOn := extractDependsOnConfig(definition)

converted := convertToServices(definition, tc.Session.WorkingDir)
if len(converted) != 1 {
panic(fmt.Sprintf("somehow we ended up with %d definitions for the main component", len(converted)))
}

comp := convertToYaml(converted[0])

// add back the removed depends_on
comp = insertDependsOnConfig(comp, servicesWithDependsOn, converted[0].Name)

return converted[0].Name, comp
}

Expand All @@ -132,8 +139,16 @@ func executeTemplates(tc *transformConfiguration) map[string]string {
mergeRecursively(definition, tmpl.render(tc))
}

// we need to remove depends_on here, the Compose v2 compatible format won't parse for the v3 service type
servicesWithDependsOn := extractDependsOnConfig(definition)

for _, comp := range convertToServices(definition, tc.Session.WorkingDir) {
components[comp.Name] = convertToYaml(comp)
rendered := convertToYaml(comp)

// add back the removed depends_on
rendered = insertDependsOnConfig(rendered, servicesWithDependsOn, comp.Name)

components[comp.Name] = rendered
}

return components
Expand Down
33 changes: 33 additions & 0 deletions pkg/template/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,39 @@ func TestTransform_Copy(t *testing.T) {
})
}

func TestTransform_WithDependencies(t *testing.T) {
output := Transform("testdata/stack-with-dependencies.yml")
verifyTemplatedComponent(t, output, "dep", "first",
func(c *component.Component, s *types.ServiceConfig) bool {
return c.Image == "sample/first"
})
verifyTemplatedComponent(t, output, "dep", "second",
func(c *component.Component, s *types.ServiceConfig) bool {
return c.Image == "sample/second"
},
func(c *component.Component, s *types.ServiceConfig) bool {
if deps, err := c.GetDependencies(); err != nil {
return false
} else {
return len(deps) == 1 &&
deps[0].Name == "first" && deps[0].NeedsHealthyState == true
}
})
verifyTemplatedComponent(t, output, "dep", "third",
func(c *component.Component, s *types.ServiceConfig) bool {
return c.Image == "sample/third"
},
func(c *component.Component, s *types.ServiceConfig) bool {
if deps, err := c.GetDependencies(); err != nil {
return false
} else {
return len(deps) == 2 &&
deps[0].Name == "first" && deps[0].NeedsHealthyState == false &&
deps[1].Name == "second" && deps[1].NeedsHealthyState == false
}
})
}

func TestTransform_CustomController(t *testing.T) {
nonDefaultImage = true
defer func() {
Expand Down

0 comments on commit 9cfaa76

Please sign in to comment.