From 0645261f33c7ba44320117adf77154e8e02e5a14 Mon Sep 17 00:00:00 2001 From: Julien Dehee Date: Sun, 20 Nov 2016 15:36:21 +0100 Subject: [PATCH] support file inclusion in env and service attributes --- .../common-attributes/test/includeFile.yml | 2 + examples/config.yml | 1 + examples/env/prod-dc1/attributes/test.yml | 6 +++ .../services/test-service/attributes/test.yml | 4 ++ work/env.go | 45 +++++++++++++++++ work/env_test.go | 39 +++++++++++++++ work/service.go | 49 +++++++++++++++++++ work/service_test.go | 27 ++++++++++ work/spec.go | 1 + 9 files changed, 174 insertions(+) create mode 100644 examples/common-attributes/test/includeFile.yml create mode 100644 examples/config.yml create mode 100644 examples/env/prod-dc1/attributes/test.yml create mode 100644 examples/env/prod-dc1/services/test-service/attributes/test.yml create mode 100644 work/env_test.go create mode 100644 work/service_test.go diff --git a/examples/common-attributes/test/includeFile.yml b/examples/common-attributes/test/includeFile.yml new file mode 100644 index 0000000..3614c07 --- /dev/null +++ b/examples/common-attributes/test/includeFile.yml @@ -0,0 +1,2 @@ +default: + includeGlobal: includeGlobalValue diff --git a/examples/config.yml b/examples/config.yml new file mode 100644 index 0000000..ede149d --- /dev/null +++ b/examples/config.yml @@ -0,0 +1 @@ +workPath: ../examples diff --git a/examples/env/prod-dc1/attributes/test.yml b/examples/env/prod-dc1/attributes/test.yml new file mode 100644 index 0000000..c07097f --- /dev/null +++ b/examples/env/prod-dc1/attributes/test.yml @@ -0,0 +1,6 @@ +include: + - test.includeFile + - env:prod-dc2:test.includeFile + +default: + attribute: attributeValue diff --git a/examples/env/prod-dc1/services/test-service/attributes/test.yml b/examples/env/prod-dc1/services/test-service/attributes/test.yml new file mode 100644 index 0000000..d15f8c6 --- /dev/null +++ b/examples/env/prod-dc1/services/test-service/attributes/test.yml @@ -0,0 +1,4 @@ +include: + - test.includeFile + - env:prod-dc2:test.includeFile + - env::test.includeFile diff --git a/work/env.go b/work/env.go index 118fe8c..c4603b5 100644 --- a/work/env.go +++ b/work/env.go @@ -153,10 +153,55 @@ func (e *Env) loadAttributes() { if err != nil { logs.WithEF(err, e.fields).WithField("path", e.path+PATH_ATTRIBUTES).Fatal("Cannot load attribute files") } + files, err = e.addIncludeFiles(files) + if err != nil { + logs.WithEF(err, e.fields).WithField("path", e.path+PATH_ATTRIBUTES).Fatal("Cannot load include files") + } + e.attributes = attributes.MergeAttributesFiles(files) logs.WithFields(e.fields).WithField("attributes", e.attributes).Debug("Attributes loaded") } +func (e *Env) addIncludeFiles(files []string) ([]string, error) { + type includeFiles struct { + Include []string + } + for _, file := range files { + var f includeFiles + yml, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + err = yaml.Unmarshal(yml, &f) + for _, inclusion := range f.Include { + sepCount := strings.Count(inclusion, ":") + if sepCount == 2 { + fields := strings.Split(inclusion, ":") + includeFile := strings.Replace(fields[2], ".", "/", -1) + ".yml" + if fields[1] == "" { + logs.WithField("include", inclusion).Fatal("Trying to include environment attributes from itself") + } else { // env:prod-dc1:some.include + includeFile = fmt.Sprintf("%v%v/%v%v/%v", + ggn.Home.Config.WorkPath, + PATH_ENV, + fields[1], + PATH_COMMON_ATTRIBUTES, + includeFile, + ) + files = append(files, includeFile) + } + } else { // some.global.include + includeFile := strings.Replace(inclusion, ".", "/", -1) + ".yml" + includeFile = fmt.Sprintf("%v%v/%v", ggn.Home.Config.WorkPath, PATH_COMMON_ATTRIBUTES, includeFile) + files = append(files, includeFile) + + } + } + } + return files, nil + +} + func (e Env) ListServices() []string { path := e.path + PATH_SERVICES files, err := ioutil.ReadDir(path) diff --git a/work/env_test.go b/work/env_test.go new file mode 100644 index 0000000..9e78e6f --- /dev/null +++ b/work/env_test.go @@ -0,0 +1,39 @@ +package work + +import ( + "testing" + + "github.com/blablacar/ggn/ggn" +) + +func itemInSlice(a string, s []string) bool { + for _, x := range s { + if a == x { + return true + } + } + return false +} + +func TestAddEnvIncludeFiles(t *testing.T) { + ggn.Home.Config.WorkPath = "../examples" + env := Env{} + files := []string{"../examples/env/prod-dc1/attributes/test.yml"} + files, err := env.addIncludeFiles(files) + if err != nil { + t.Logf("addIncludeFiles returned an error : %v", err) + t.Fail() + } + for _, includeFile := range []string{ + "../examples/common-attributes/test/includeFile.yml", + "../examples/env/prod-dc2/common-attributes/test/includeFile.yml", + } { + if !itemInSlice(includeFile, files) { + t.Logf("File not included : %v", includeFile) + for _, f := range files { + t.Log(f) + } + t.Fail() + } + } +} diff --git a/work/service.go b/work/service.go index 7259baa..6a8cd1e 100644 --- a/work/service.go +++ b/work/service.go @@ -250,11 +250,60 @@ func (s *Service) loadAttributes() { if err != nil { logs.WithEF(err, s.fields).WithField("path", s.path+PATH_ATTRIBUTES).Fatal("Cannot load Attributes files") } + files, err = s.addIncludeFiles(files) + if err != nil { + logs.WithEF(err, s.fields).WithField("path", s.path+PATH_ATTRIBUTES).Fatal("Cannot load include files") + } attr = attributes.MergeAttributesFilesForMap(attr, files) s.attributes = attr logs.WithFields(s.fields).WithField("attributes", s.attributes).Debug("Attributes loaded") } +func (s *Service) addIncludeFiles(files []string) ([]string, error) { + type includeFiles struct { + Include []string + } + for _, file := range files { + var f includeFiles + yml, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + err = yaml.Unmarshal(yml, &f) + for _, inclusion := range f.Include { + sepCount := strings.Count(inclusion, ":") + if sepCount == 2 { + fields := strings.Split(inclusion, ":") + includeFile := strings.Replace(fields[2], ".", "/", -1) + ".yml" + if fields[1] == "" { // env::some.include + includeFile = fmt.Sprintf("%v%v/%v", + s.env.path, + PATH_COMMON_ATTRIBUTES, + includeFile, + ) + files = append(files, includeFile) + } else { // env:prod-dc1:some.include + includeFile = fmt.Sprintf("%v%v/%v%v/%v", + ggn.Home.Config.WorkPath, + PATH_ENV, + fields[1], + PATH_COMMON_ATTRIBUTES, + includeFile, + ) + files = append(files, includeFile) + } + + } else { // some.global.include + includeFile := strings.Replace(inclusion, ".", "/", -1) + ".yml" + includeFile = fmt.Sprintf("%v%v/%v", ggn.Home.Config.WorkPath, PATH_COMMON_ATTRIBUTES, includeFile) + files = append(files, includeFile) + + } + } + } + return files, nil +} + func (s *Service) loadUnitTemplate(filename string) (*template.Templating, error) { path := s.path + filename source, err := ioutil.ReadFile(path) diff --git a/work/service_test.go b/work/service_test.go new file mode 100644 index 0000000..a170d17 --- /dev/null +++ b/work/service_test.go @@ -0,0 +1,27 @@ +package work + +import "testing" + +func TestAddServiceIncludeFiles(t *testing.T) { + service := Service{} + service.env.path = "../examples/env/prod-dc1" + files := []string{"../examples/env/prod-dc1/services/test-service/attributes/test.yml"} + files, err := service.addIncludeFiles(files) + if err != nil { + t.Logf("addIncludeFiles returned an error : %v", err) + t.Fail() + } + for _, includeFile := range []string{ + "../examples/common-attributes/test/includeFile.yml", + "../examples/env/prod-dc2/common-attributes/test/includeFile.yml", + "../examples/env/prod-dc1/common-attributes/test/includeFile.yml", + } { + if !itemInSlice(includeFile, files) { + t.Logf("File not included : %v", includeFile) + for _, f := range files { + t.Log(f) + } + t.Fail() + } + } +} diff --git a/work/spec.go b/work/spec.go index 1d6c98b..5dbfe69 100644 --- a/work/spec.go +++ b/work/spec.go @@ -6,6 +6,7 @@ import ( const PATH_ATTRIBUTES = "/attributes" const PATH_TEMPLATES = "/templates" +const PATH_COMMON_ATTRIBUTES = "/common-attributes" const ACTIVE_ACTIVE = "active" const SUB_RUNNING = "running"