From 934a3e1a9a2e0ced42e6225f32c50c57045e4733 Mon Sep 17 00:00:00 2001 From: Suraj Deshmukh Date: Tue, 26 Jul 2016 12:55:23 +0000 Subject: [PATCH] Support for environment variables substitution Now user can put environment variables in docker-compose file and it will be read by kompose from environment Fixes # 56 --- Godeps/Godeps.json | 88 +++++++++---------- cli/app/app.go | 22 +++++ .../docker/libcompose/config/merge.go | 40 ++++++--- .../docker/libcompose/docker/project.go | 2 +- .../docker/libcompose/docker/service.go | 2 +- .../docker/libcompose/lookup/file.go | 12 +-- .../docker/libcompose/project/interface.go | 1 + .../libcompose/project/options/types.go | 4 +- .../docker/libcompose/project/project.go | 16 +--- 9 files changed, 106 insertions(+), 81 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 579a7f6f..776ad2b5 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -3,7 +3,7 @@ "GoVersion": "go1.6", "GodepVersion": "v74", "Packages": [ - "./..." + "./cli/main/" ], "Deps": [ { @@ -44,77 +44,77 @@ }, { "ImportPath": "github.com/docker/distribution", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/context", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/digest", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/manifest", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/manifest/schema1", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/manifest/schema2", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/reference", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/registry/api/errcode", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/registry/api/v2", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/registry/client", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/registry/client/auth", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/registry/client/transport", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/registry/storage/cache", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/registry/storage/cache/memory", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { "ImportPath": "github.com/docker/distribution/uuid", - "Comment": "v2.5.0-rc.1-22-g4e17ab5", + "Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5", "Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc" }, { @@ -434,73 +434,73 @@ }, { "ImportPath": "github.com/docker/libcompose/config", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/docker", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/docker/builder", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/docker/client", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/docker/network", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/labels", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/logger", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/lookup", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/project", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/project/events", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/project/options", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/utils", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/version", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libcompose/yaml", - "Comment": "v0.2.0-186-ga12288b", - "Rev": "a12288bd636066e330b5d39197737cd04882d164" + "Comment": "v0.2.0-198-gced6fdd", + "Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602" }, { "ImportPath": "github.com/docker/libtrust", diff --git a/cli/app/app.go b/cli/app/app.go index b4934923..8410002c 100644 --- a/cli/app/app.go +++ b/cli/app/app.go @@ -20,6 +20,7 @@ import ( "fmt" "math/rand" "os" + "path/filepath" "strconv" "strings" @@ -27,7 +28,9 @@ import ( "github.com/urfave/cli" "github.com/docker/docker/api/client/bundlefile" + "github.com/docker/libcompose/config" "github.com/docker/libcompose/docker" + "github.com/docker/libcompose/lookup" "github.com/docker/libcompose/project" "encoding/json" @@ -742,6 +745,25 @@ func loadComposeFile(file string, c *cli.Context) KomposeObject { } context.ComposeFiles = []string{file} + if context.ResourceLookup == nil { + context.ResourceLookup = &lookup.FileResourceLookup{} + } + + if context.EnvironmentLookup == nil { + cwd, err := os.Getwd() + if err != nil { + return KomposeObject{} + } + context.EnvironmentLookup = &lookup.ComposableEnvLookup{ + Lookups: []config.EnvironmentLookup{ + &lookup.EnvfileLookup{ + Path: filepath.Join(cwd, ".env"), + }, + &lookup.OsEnvLookup{}, + }, + } + } + // load compose file into composeObject composeObject := project.NewProject(&context.Context, nil, nil) err := composeObject.Parse() diff --git a/vendor/github.com/docker/libcompose/config/merge.go b/vendor/github.com/docker/libcompose/config/merge.go index b5d4be57..504e0473 100644 --- a/vendor/github.com/docker/libcompose/config/merge.go +++ b/vendor/github.com/docker/libcompose/config/merge.go @@ -8,6 +8,8 @@ import ( yaml "github.com/cloudfoundry-incubator/candiedyaml" "github.com/docker/docker/pkg/urlutil" + "github.com/docker/libcompose/utils" + composeYaml "github.com/docker/libcompose/yaml" ) var ( @@ -86,7 +88,13 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe if _, ok := serviceData["env_file"]; !ok { return serviceData, nil } - envFiles := serviceData["env_file"].([]interface{}) + + var envFiles composeYaml.Stringorslice + + if err := utils.Convert(serviceData["env_file"], &envFiles); err != nil { + return nil, err + } + if len(envFiles) == 0 { return serviceData, nil } @@ -95,13 +103,16 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile) } - var vars []interface{} + var vars composeYaml.MaporEqualSlice + if _, ok := serviceData["environment"]; ok { - vars = serviceData["environment"].([]interface{}) + if err := utils.Convert(serviceData["environment"], &vars); err != nil { + return nil, err + } } for i := len(envFiles) - 1; i >= 0; i-- { - envFile := envFiles[i].(string) + envFile := envFiles[i] content, _, err := resourceLookup.Lookup(envFile, inFile) if err != nil { return nil, err @@ -114,18 +125,21 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe scanner := bufio.NewScanner(bytes.NewBuffer(content)) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) - key := strings.SplitAfter(line, "=")[0] - found := false - for _, v := range vars { - if strings.HasPrefix(v.(string), key) { - found = true - break + if len(line) > 0 && !strings.HasPrefix(line, "#") { + key := strings.SplitAfter(line, "=")[0] + + found := false + for _, v := range vars { + if strings.HasPrefix(v, key) { + found = true + break + } } - } - if !found { - vars = append(vars, line) + if !found { + vars = append(vars, line) + } } } diff --git a/vendor/github.com/docker/libcompose/docker/project.go b/vendor/github.com/docker/libcompose/docker/project.go index 5b5b9538..b356c436 100644 --- a/vendor/github.com/docker/libcompose/docker/project.go +++ b/vendor/github.com/docker/libcompose/docker/project.go @@ -23,7 +23,7 @@ const ComposeVersion = "1.5.0" // NewProject creates a Project with the specified context. func NewProject(context *Context, parseOptions *config.ParseOptions) (project.APIProject, error) { if context.ResourceLookup == nil { - context.ResourceLookup = &lookup.FileConfigLookup{} + context.ResourceLookup = &lookup.FileResourceLookup{} } if context.EnvironmentLookup == nil { diff --git a/vendor/github.com/docker/libcompose/docker/service.go b/vendor/github.com/docker/libcompose/docker/service.go index eea5fc03..d03b6b5c 100644 --- a/vendor/github.com/docker/libcompose/docker/service.go +++ b/vendor/github.com/docker/libcompose/docker/service.go @@ -556,7 +556,7 @@ func (s *Service) Kill(ctx context.Context, signal string) error { func (s *Service) Delete(ctx context.Context, options options.Delete) error { return s.collectContainersAndDo(ctx, func(c *Container) error { running, _ := c.IsRunning(ctx) - if !running { + if !running || options.RemoveRunning { return c.Remove(ctx, options.RemoveVolume) } return nil diff --git a/vendor/github.com/docker/libcompose/lookup/file.go b/vendor/github.com/docker/libcompose/lookup/file.go index 70b3d8d6..643592d7 100644 --- a/vendor/github.com/docker/libcompose/lookup/file.go +++ b/vendor/github.com/docker/libcompose/lookup/file.go @@ -20,7 +20,7 @@ func relativePath(file, relativeTo string) string { // stdin: return the current working directory if possible. if relativeTo == "-" { if cwd, err := os.Getwd(); err == nil { - return cwd + return filepath.Join(cwd, file) } } @@ -39,15 +39,15 @@ func relativePath(file, relativeTo string) string { return abs } -// FileConfigLookup is a "bare" structure that implements the project.ResourceLookup interface -type FileConfigLookup struct { +// FileResourceLookup is a "bare" structure that implements the project.ResourceLookup interface +type FileResourceLookup struct { } // Lookup returns the content and the actual filename of the file that is "built" using the // specified file and relativeTo string. file and relativeTo are supposed to be file path. // If file starts with a slash ('/'), it tries to load it, otherwise it will build a // filename using the folder part of relativeTo joined with file. -func (f *FileConfigLookup) Lookup(file, relativeTo string) ([]byte, string, error) { +func (f *FileResourceLookup) Lookup(file, relativeTo string) ([]byte, string, error) { file = relativePath(file, relativeTo) logrus.Debugf("Reading file %s", file) bytes, err := ioutil.ReadFile(file) @@ -56,11 +56,11 @@ func (f *FileConfigLookup) Lookup(file, relativeTo string) ([]byte, string, erro // ResolvePath returns the path to be used for the given path volume. This // function already takes care of relative paths. -func (f *FileConfigLookup) ResolvePath(path, inFile string) string { +func (f *FileResourceLookup) ResolvePath(path, relativeTo string) string { vs := strings.SplitN(path, ":", 2) if len(vs) != 2 || filepath.IsAbs(vs[0]) { return path } - vs[0] = relativePath(vs[0], inFile) + vs[0] = relativePath(vs[0], relativeTo) return strings.Join(vs, ":") } diff --git a/vendor/github.com/docker/libcompose/project/interface.go b/vendor/github.com/docker/libcompose/project/interface.go index 40113a86..6d21aee8 100644 --- a/vendor/github.com/docker/libcompose/project/interface.go +++ b/vendor/github.com/docker/libcompose/project/interface.go @@ -37,6 +37,7 @@ type APIProject interface { CreateService(name string) (Service, error) AddConfig(name string, config *config.ServiceConfig) error Load(bytes []byte) error + ListStoppedContainers(ctx context.Context, services ...string) ([]string, error) } // RuntimeProject defines runtime-specific methods for a libcompose implementation. diff --git a/vendor/github.com/docker/libcompose/project/options/types.go b/vendor/github.com/docker/libcompose/project/options/types.go index 8828a0dd..2c74f92c 100644 --- a/vendor/github.com/docker/libcompose/project/options/types.go +++ b/vendor/github.com/docker/libcompose/project/options/types.go @@ -9,8 +9,8 @@ type Build struct { // Delete holds options of compose rm. type Delete struct { - RemoveVolume bool - BeforeDeleteCallback func([]string) bool + RemoveVolume bool + RemoveRunning bool } // Down holds options of compose down. diff --git a/vendor/github.com/docker/libcompose/project/project.go b/vendor/github.com/docker/libcompose/project/project.go index d6e27a79..e13e5430 100644 --- a/vendor/github.com/docker/libcompose/project/project.go +++ b/vendor/github.com/docker/libcompose/project/project.go @@ -496,8 +496,8 @@ func (p *Project) Pull(ctx context.Context, services ...string) error { }), nil) } -// listStoppedContainers lists the stopped containers for the specified services. -func (p *Project) listStoppedContainers(ctx context.Context, services ...string) ([]string, error) { +// ListStoppedContainers lists the stopped containers for the specified services. +func (p *Project) ListStoppedContainers(ctx context.Context, services ...string) ([]string, error) { stoppedContainers := []string{} err := p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) { wrapper.Do(nil, events.NoEvent, events.NoEvent, func(service Service) error { @@ -531,18 +531,6 @@ func (p *Project) listStoppedContainers(ctx context.Context, services ...string) // Delete removes the specified services (like docker rm). func (p *Project) Delete(ctx context.Context, options options.Delete, services ...string) error { - stoppedContainers, err := p.listStoppedContainers(ctx, services...) - if err != nil { - return err - } - if len(stoppedContainers) == 0 { - p.Notify(events.ProjectDeleteDone, "", nil) - fmt.Println("No stopped containers") - return nil - } - if options.BeforeDeleteCallback != nil && !options.BeforeDeleteCallback(stoppedContainers) { - return nil - } return p.perform(events.ProjectDeleteStart, events.ProjectDeleteDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) { wrapper.Do(nil, events.ServiceDeleteStart, events.ServiceDelete, func(service Service) error { return service.Delete(ctx, options)