From 4f607a9c10e1bfbcab6381b639a61a4432fe7ee8 Mon Sep 17 00:00:00 2001 From: Milos Pejanovic Date: Wed, 24 Jun 2020 12:55:13 +0200 Subject: [PATCH 1/3] add support for group templating --- cmd/actions/build.go | 6 +- cmd/actions/install.go | 6 +- cmd/actions/root.go | 51 +++++--- cmd/actions/uninstall.go | 9 +- configurd.go | 122 +++++++++++++++--- .../namespaces/local/hello-group.yml | 6 +- go.mod | 2 + helm.go | 9 +- 8 files changed, 151 insertions(+), 60 deletions(-) diff --git a/cmd/actions/build.go b/cmd/actions/build.go index 03b07a6..8c18054 100644 --- a/cmd/actions/build.go +++ b/cmd/actions/build.go @@ -19,16 +19,14 @@ var buildCmd = &cobra.Command{ Short: "Build a service with a given tag", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - out, err := build(args[0], flagTag, flagDir, flagPush, flagVerbose) + out, err := build(args[0], flagPush) if err != nil { log.WithError(err).WithField("output", out).Fatal("Build failed") } }, } -func build(service, tag, dir string, push, verbose bool) (string, error) { - logger := newLogger(verbose) - cnf := mustNewConfigurd(logger, tag, dir) +func build(service string, push bool) (string, error) { svc, err := cnf.Service(service) if err != nil { return "", fmt.Errorf("could not find service: %w", err) diff --git a/cmd/actions/install.go b/cmd/actions/install.go index 0e4a58c..5b51fd3 100644 --- a/cmd/actions/install.go +++ b/cmd/actions/install.go @@ -34,9 +34,6 @@ var ( ) func install(group, namespace, tag, workDir, outputDir, service string, buildService, verbose bool) (string, error) { - log := newLogger(verbose) - cnf := mustNewConfigurd(log, tag, workDir) - ns, err := cnf.Namespace(namespace) if err != nil { return "", err @@ -61,7 +58,7 @@ func install(group, namespace, tag, workDir, outputDir, service string, buildSer if buildService { log.Printf("Building services") for _, si := range sis { - output, err := build(si.Name, tag, workDir, true, verbose) + output, err := build(si.Name, true) if err != nil { return output, err } @@ -72,6 +69,7 @@ func install(group, namespace, tag, workDir, outputDir, service string, buildSer BasePath: workDir, OutputDir: outputDir, Tag: tag, + TemplateVars: templateVars, Verbose: verbose, }) } diff --git a/cmd/actions/root.go b/cmd/actions/root.go index d5e018e..ad5faef 100644 --- a/cmd/actions/root.go +++ b/cmd/actions/root.go @@ -13,50 +13,61 @@ var ( log = logrus.New() rootCmd = &cobra.Command{ Use: "configurd", - PersistentPreRun: func(cmd *cobra.Command, args []string) { + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if cmd.Name() == "help" || cmd.Name() == "init" { + return nil + } + // flagDir wdir, err := os.Getwd() if err != nil { - log.Fatal(err) + return err } if flagDir != "" { flagDir = path.Join(wdir, flagDir) } else { flagDir = wdir } - if cmd.Name() == "help" || cmd.Name() == "init" { - return + // templateVars + templateVars, err = configurd.NewTemplateVars(flagDir, flagTemplateSlice, flagTemplateFile) + if err != nil { + return err } + // cnf + cnf, err = newConfigurd(newLogger(flagVerbose), flagTag, flagDir, templateVars) + if err != nil { + return err + } + return nil }, } - flagTag string - flagDir string - flagVerbose bool - flagNamespace string + cnf configurd.Configurd + templateVars configurd.TemplateVars + flagTag string + flagDir string + flagVerbose bool + flagNamespace string + flagTemplateSlice []string + flagTemplateFile string ) -func newConfigurd(log *logrus.Entry, tag, basePath string) (configurd.Configurd, error) { +func newConfigurd(log *logrus.Entry, tag, basePath string, tv configurd.TemplateVars) (configurd.Configurd, error) { config := configurd.Config{ - Tag: tag, - BasePath: basePath, - Log: log, + Tag: tag, + BasePath: basePath, + Log: log, + TemplateVars: tv, } return configurd.New(config) } -func mustNewConfigurd(log *logrus.Entry, tag, basePath string) configurd.Configurd { - cnf, err := newConfigurd(log, tag, basePath) - if err != nil { - log.Fatal(err) - } - return cnf -} - func init() { rootCmd.PersistentFlags().StringVarP(&flagTag, "tag", "t", "latest", "Specifies the image tag") rootCmd.PersistentFlags().StringVarP(&flagDir, "dir", "d", "", "Specifies working directory") rootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "Specifies should command output be displayed") + rootCmd.PersistentFlags().StringSliceVar(&flagTemplateSlice, "template-vars", nil, "Specifies template vars x=y") + rootCmd.PersistentFlags().StringVar(&flagTemplateFile, "template-file", "", "Specifies the template file with vars") rootCmd.AddCommand(buildCmd, installCmd, uninstallCmd, initCmd, versionCmd) } diff --git a/cmd/actions/uninstall.go b/cmd/actions/uninstall.go index 6b45afa..67bfc63 100644 --- a/cmd/actions/uninstall.go +++ b/cmd/actions/uninstall.go @@ -15,7 +15,7 @@ var ( Long: "uninstalls a group with given namespace and tag version", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - _, err := uninstall(args[0], flagNamespace, flagTag, flagDir, flagVerbose) + _, err := uninstall(args[0], flagNamespace) if err != nil { log.WithError(err).Fatalf("Uninstallation failed") } @@ -23,10 +23,7 @@ var ( } ) -func uninstall(group, namespace, tag, dir string, verbose bool) (string, error) { - log := newLogger(verbose) - cnf := mustNewConfigurd(log, tag, dir) - +func uninstall(group, namespace string) (string, error) { ns, err := cnf.Namespace(namespace) if err != nil { return "", err @@ -40,5 +37,5 @@ func uninstall(group, namespace, tag, dir string, verbose bool) (string, error) return "", err } - return cnf.Uninstall(sis, namespace, verbose) + return cnf.Uninstall(sis, namespace) } diff --git a/configurd.go b/configurd.go index 930d168..4b0f3e5 100644 --- a/configurd.go +++ b/configurd.go @@ -2,15 +2,20 @@ package configurd import ( "bufio" + "bytes" + "encoding/json" "errors" "fmt" "io" + "io/ioutil" "os" "os/exec" "path" "path/filepath" "strings" + "text/template" + "github.com/foomo/config-bob/builder" "github.com/foomo/configurd/exampledata" "github.com/sirupsen/logrus" @@ -43,9 +48,10 @@ type Namespace struct { } type Config struct { - Tag string - BasePath string - Log *logrus.Entry + Tag string + BasePath string + Log *logrus.Entry + TemplateVars TemplateVars } type Configurd struct { @@ -105,7 +111,7 @@ func New(config Config) (Configurd, error) { return Configurd{}, err } - c.Namespaces, err = loadNamespaces(log, c.Service, config.BasePath) + c.Namespaces, err = loadNamespaces(log, c.Service, config.BasePath, c.config.TemplateVars) if err != nil { return Configurd{}, err @@ -114,7 +120,7 @@ func New(config Config) (Configurd, error) { return c, nil } -func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string) ([]Namespace, error) { +func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string, tv TemplateVars) ([]Namespace, error) { var nss []Namespace namespaceDir := path.Join(basePath, defaultNamespaceDir) err := filepath.Walk(namespaceDir, func(path string, info os.FileInfo, err error) error { @@ -123,7 +129,7 @@ func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string) ([]Nam } if info.IsDir() && path != namespaceDir { log.Infof("Loading namespace: %v, from: %q", info.Name(), relativePath(path, basePath)) - gs, err := loadGroups(log, sl, basePath, info.Name()) + gs, err := loadGroups(log, sl, basePath, info.Name(), tv) if err != nil { return err } @@ -138,7 +144,7 @@ func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string) ([]Nam return nss, err } -func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string) ([]Group, error) { +func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string, tv TemplateVars) ([]Group, error) { var gs []Group groupPath := path.Join(basePath, defaultNamespaceDir, namespace) err := filepath.Walk(groupPath, func(path string, info os.FileInfo, err error) error { @@ -148,7 +154,7 @@ func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string) if !info.IsDir() && (strings.HasSuffix(path, defaultConfigFileExt)) { name := strings.TrimSuffix(info.Name(), defaultConfigFileExt) log.Infof("Loading group: %v, from: %q", name, relativePath(path, basePath)) - g, err := loadGroup(log, sl, path, namespace, name) + g, err := loadGroup(log, sl, path, namespace, name, tv) if err != nil { return err } @@ -159,18 +165,12 @@ func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string) return gs, err } -func loadGroup(log *logrus.Entry, sl serviceLoader, path, namespace, group string) (Group, error) { - file, err := os.Open(path) - if err != nil { - return Group{}, err - } - defer file.Close() - +func loadGroup(log *logrus.Entry, sl serviceLoader, path, namespace, group string, tv TemplateVars) (Group, error) { var wrapper struct { Group Group `yaml:"group"` } - if err := yaml.NewDecoder(file).Decode(&wrapper); err != nil { - return Group{}, fmt.Errorf("could not decode group: %w", err) + if err := loadYamlTemplate(path, &wrapper, tv); err != nil { + return Group{}, err } for name := range wrapper.Group.Services { @@ -336,3 +336,91 @@ func errResourceNotFound(name, resource string, available []string) error { } return fmt.Errorf("%s '%s' not found. Available: %s", resource, name, strings.Join(available, ", ")) } + +func stringInSlice(str string, slice []string) bool { + for _, s := range slice { + if s == str { + return true + } + } + return false +} + +func isYaml(file string) bool { + return stringInSlice(filepath.Ext(file), []string{"yml, yaml"}) +} + +func isJson(file string) bool { + return filepath.Ext(file) == "json" +} + +type TemplateVars map[string]interface{} + +func (tv TemplateVars) supportedFileExt() []string { + return []string{"yml", "yaml", "json"} +} + +func NewTemplateVars(workDir string, sourceSlice []string, sourceFile string) (TemplateVars, error) { + tv := TemplateVars{} + if err := tv.parseFile(workDir, sourceFile); err != nil { + return nil, err + } + if err := tv.parseSlice(sourceSlice); err != nil { + return nil, err + } + tv["cwd"] = workDir + return tv, nil +} + +func (tv TemplateVars) parseSlice(source []string) error { + for _, item := range source { + pieces := strings.Split(item, "=") + if len(pieces) != 2 || pieces[0] == "" { + return fmt.Errorf("Invalid format for template var %q, use x=y", item) + } + tv[pieces[0]] = pieces[1] + } + return nil +} +func (tv TemplateVars) parseFile(workDir, source string) error { + if source == "" { + return nil + } + if !filepath.IsAbs(source) { + source = path.Join(workDir, source) + } + if !isYaml(source) && !isJson(source) { + return fmt.Errorf("Unable to parse %q, supported: %v", source, strings.Join(tv.supportedFileExt(), ", ")) + } + file, err := ioutil.ReadFile(source) + if err != nil { + return fmt.Errorf("Error while opening template file: %s", err) + } + if isYaml(source) { + if err := yaml.Unmarshal(file, &tv); err != nil { + return fmt.Errorf("Error while unmarshalling template file: %s", err) + } + } + if isJson(source) { + if err := json.Unmarshal(file, &tv); err != nil { + return fmt.Errorf("Error while unmarshalling template file: %s", err) + } + return nil + } + return nil +} + +func loadYamlTemplate(file string, data interface{}, templateVars interface{}) error { + tmp, err := template.ParseFiles(file) + if err != nil { + return err + } + out := bytes.NewBuffer([]byte{}) + if err := tmp.Option("missingkey=error").Funcs(builder.TemplateFuncs).Execute(out, templateVars); err != nil { + return err + } + if err := yaml.Unmarshal(out.Bytes(), &data); err != nil { + return err + } + return nil +} diff --git a/example/configurd/namespaces/local/hello-group.yml b/example/configurd/namespaces/local/hello-group.yml index 8583fb6..4514496 100644 --- a/example/configurd/namespaces/local/hello-group.yml +++ b/example/configurd/namespaces/local/hello-group.yml @@ -9,11 +9,11 @@ group: port: 80 ingress: hosts: - - name: localhost + - name: {{ .host }} path: /services/hello volumes: - name: config - host: ./application + host: {{ .cwd }}/application mount: /config/ hi-service: overrides: @@ -24,6 +24,6 @@ group: port: 80 ingress: hosts: - - name: localhost + - name: {{ .host }} path: /services/hi jobs: diff --git a/go.mod b/go.mod index 8683b7e..7bcbe55 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/foomo/configurd go 1.14 require ( + github.com/foomo/config-bob v0.0.0-20180509121310-96db3832d519 + github.com/foomo/htpasswd v0.0.0-20200116085101-e3a90e78da9c // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/otiai10/copy v1.0.2 github.com/sirupsen/logrus v1.4.2 diff --git a/helm.go b/helm.go index 715ad7a..812a4b1 100644 --- a/helm.go +++ b/helm.go @@ -21,7 +21,7 @@ type Volume struct { type ServiceItem struct { Name string - Overrides map[string]interface{} + Overrides interface{} namespace string group string chart string @@ -91,10 +91,6 @@ func generate(log *logrus.Entry, si ServiceItem, basePath, outputDir string) err return fmt.Errorf("could not copy template files: %w", err) } - if _, ok := si.Overrides["volumes"]; ok { - si.Overrides["volumes"] = fixVolumeRelativePath(basePath, si.Overrides["volumes"]) - } - log.Printf("Generating yaml file: %q", path.Join(outputDir, si.Name, defaultOverridesFile)) err = generateYaml(log, path.Join(outputPath, defaultOverridesFile), si.Overrides) if err != nil { @@ -142,6 +138,7 @@ type InstallConfiguration struct { BasePath string OutputDir string Tag string + TemplateVars map[string]interface{} Verbose bool } @@ -184,7 +181,7 @@ func (c Configurd) Install(cnf InstallConfiguration) (string, error) { return strings.Join(output, "\n"), nil } -func (c Configurd) Uninstall(sis []ServiceItem, namespace string, verbose bool) (string, error) { +func (c Configurd) Uninstall(sis []ServiceItem, namespace string) (string, error) { logger := c.config.Log var outputs []string From c36c88efbcd4b53bca163516fc95340764c4100f Mon Sep 17 00:00:00 2001 From: Milos Pejanovic Date: Wed, 24 Jun 2020 14:58:25 +0200 Subject: [PATCH 2/3] move template parsing where actually needed --- configurd.go | 27 +++++++++++++++------------ helm.go | 27 +++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/configurd.go b/configurd.go index 4b0f3e5..dfcf84f 100644 --- a/configurd.go +++ b/configurd.go @@ -111,7 +111,7 @@ func New(config Config) (Configurd, error) { return Configurd{}, err } - c.Namespaces, err = loadNamespaces(log, c.Service, config.BasePath, c.config.TemplateVars) + c.Namespaces, err = loadNamespaces(log, c.Service, config.BasePath) if err != nil { return Configurd{}, err @@ -120,7 +120,7 @@ func New(config Config) (Configurd, error) { return c, nil } -func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string, tv TemplateVars) ([]Namespace, error) { +func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string) ([]Namespace, error) { var nss []Namespace namespaceDir := path.Join(basePath, defaultNamespaceDir) err := filepath.Walk(namespaceDir, func(path string, info os.FileInfo, err error) error { @@ -129,7 +129,7 @@ func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string, tv Tem } if info.IsDir() && path != namespaceDir { log.Infof("Loading namespace: %v, from: %q", info.Name(), relativePath(path, basePath)) - gs, err := loadGroups(log, sl, basePath, info.Name(), tv) + gs, err := loadGroups(log, sl, basePath, info.Name()) if err != nil { return err } @@ -144,7 +144,7 @@ func loadNamespaces(log *logrus.Entry, sl serviceLoader, basePath string, tv Tem return nss, err } -func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string, tv TemplateVars) ([]Group, error) { +func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string) ([]Group, error) { var gs []Group groupPath := path.Join(basePath, defaultNamespaceDir, namespace) err := filepath.Walk(groupPath, func(path string, info os.FileInfo, err error) error { @@ -154,7 +154,7 @@ func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string, if !info.IsDir() && (strings.HasSuffix(path, defaultConfigFileExt)) { name := strings.TrimSuffix(info.Name(), defaultConfigFileExt) log.Infof("Loading group: %v, from: %q", name, relativePath(path, basePath)) - g, err := loadGroup(log, sl, path, namespace, name, tv) + g, err := loadGroup(log, sl, path, namespace, name) if err != nil { return err } @@ -165,19 +165,19 @@ func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string, return gs, err } -func loadGroup(log *logrus.Entry, sl serviceLoader, path, namespace, group string, tv TemplateVars) (Group, error) { +func loadGroup(log *logrus.Entry, sl serviceLoader, path, namespace, group string) (Group, error) { + var g Group var wrapper struct { Group Group `yaml:"group"` } - if err := loadYamlTemplate(path, &wrapper, tv); err != nil { - return Group{}, err + if err := loadYamlTemplate(path, &wrapper, nil, false); err != nil { + return wrapper.Group, err } - for name := range wrapper.Group.Services { log.Infof("Loading group item: %v", name) svc, err := sl(name) if err != nil { - return Group{}, err + return g, err } wrapper.Group.Services[name] = loadServiceItem(wrapper.Group.Services[name], svc.Name, namespace, group, svc.Chart) } @@ -410,13 +410,16 @@ func (tv TemplateVars) parseFile(workDir, source string) error { return nil } -func loadYamlTemplate(file string, data interface{}, templateVars interface{}) error { +func loadYamlTemplate(file string, data interface{}, templateVars interface{}, errOnMissing bool) error { tmp, err := template.ParseFiles(file) if err != nil { return err } out := bytes.NewBuffer([]byte{}) - if err := tmp.Option("missingkey=error").Funcs(builder.TemplateFuncs).Execute(out, templateVars); err != nil { + if errOnMissing { + tmp = tmp.Option("missingkey=error") + } + if err := tmp.Funcs(builder.TemplateFuncs).Execute(out, templateVars); err != nil { return err } if err := yaml.Unmarshal(out.Bytes(), &data); err != nil { diff --git a/helm.go b/helm.go index 812a4b1..47c74cf 100644 --- a/helm.go +++ b/helm.go @@ -21,12 +21,26 @@ type Volume struct { type ServiceItem struct { Name string - Overrides interface{} + overrides interface{} namespace string group string chart string } +func (si ServiceItem) getOverrides(basePath string, tv TemplateVars) (interface{}, error) { + if si.overrides == nil { + path := path.Join(basePath, defaultNamespaceDir, si.namespace, si.group, defaultConfigFileExt) + var wrapper struct { + Group Group `yaml:"group"` + } + if err := loadYamlTemplate(path, &wrapper, tv, true); err != nil { + return nil, err + } + si.overrides = wrapper.Group.Services[si.Name].overrides + } + return si.overrides, nil +} + type JobItem struct { Name string Overrides interface{} @@ -61,7 +75,7 @@ func fixVolumeRelativePath(basePath string, volumes interface{}) []Volume { return vs } -func generate(log *logrus.Entry, si ServiceItem, basePath, outputDir string) error { +func generate(log *logrus.Entry, si ServiceItem, basePath, outputDir string, tv TemplateVars) error { outputPath := path.Join(basePath, defaultOutputDir, outputDir, si.Name) log.Infof("Creating dir: %q", path.Join(outputDir, si.Name)) if err := os.MkdirAll(outputPath, 0744); err != nil { @@ -91,8 +105,13 @@ func generate(log *logrus.Entry, si ServiceItem, basePath, outputDir string) err return fmt.Errorf("could not copy template files: %w", err) } + overrides, err := si.getOverrides(basePath, tv) + if err != nil { + return err + } + log.Printf("Generating yaml file: %q", path.Join(outputDir, si.Name, defaultOverridesFile)) - err = generateYaml(log, path.Join(outputPath, defaultOverridesFile), si.Overrides) + err = generateYaml(log, path.Join(outputPath, defaultOverridesFile), overrides) if err != nil { return fmt.Errorf("could not generate %v: %w", defaultOverridesFile, err) } @@ -159,7 +178,7 @@ func (c Configurd) Install(cnf InstallConfiguration) (string, error) { return "", fmt.Errorf("could not create a workdir directory: %w", err) } for _, si := range cnf.ServiceItems { - err := generate(logger, si, cnf.BasePath, cnf.OutputDir) + err := generate(logger, si, cnf.BasePath, cnf.OutputDir, cnf.TemplateVars) if err != nil { return "", err } From 5a794e155b72ba84fb800c71de26bf6bb40c7ad0 Mon Sep 17 00:00:00 2001 From: Milos Pejanovic Date: Thu, 25 Jun 2020 11:44:26 +0200 Subject: [PATCH 3/3] fix template implementation, do a small refactor --- cmd/actions/install.go | 7 ++--- cmd/actions/root.go | 5 ++- configurd.go | 31 +++++++++---------- .../namespaces/local/hello-group.yml | 3 +- helm.go | 25 ++++++++------- 5 files changed, 34 insertions(+), 37 deletions(-) diff --git a/cmd/actions/install.go b/cmd/actions/install.go index 5b51fd3..b66f89e 100644 --- a/cmd/actions/install.go +++ b/cmd/actions/install.go @@ -25,7 +25,7 @@ var ( Long: "installs a group of services with given namespace and tag version", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - _, err := install(args[0], flagNamespace, flagTag, flagDir, flagOutputDir, flagService, flagBuild, flagVerbose) + _, err := install(args[0], flagNamespace, flagTag, flagDir, flagOutputDir, flagService, flagBuild, templateVars) if err != nil { log.WithError(err).Fatalf("Installation failed") } @@ -33,7 +33,7 @@ var ( } ) -func install(group, namespace, tag, workDir, outputDir, service string, buildService, verbose bool) (string, error) { +func install(group, namespace, tag, workDir, outputDir, service string, buildService bool, tv configurd.TemplateVars) (string, error) { ns, err := cnf.Namespace(namespace) if err != nil { return "", err @@ -69,7 +69,6 @@ func install(group, namespace, tag, workDir, outputDir, service string, buildSer BasePath: workDir, OutputDir: outputDir, Tag: tag, - TemplateVars: templateVars, - Verbose: verbose, + TemplateVars: tv, }) } diff --git a/cmd/actions/root.go b/cmd/actions/root.go index ad5faef..852edcf 100644 --- a/cmd/actions/root.go +++ b/cmd/actions/root.go @@ -33,7 +33,7 @@ var ( return err } // cnf - cnf, err = newConfigurd(newLogger(flagVerbose), flagTag, flagDir, templateVars) + cnf, err = newConfigurd(newLogger(flagVerbose), flagTag, flagDir) if err != nil { return err } @@ -51,12 +51,11 @@ var ( flagTemplateFile string ) -func newConfigurd(log *logrus.Entry, tag, basePath string, tv configurd.TemplateVars) (configurd.Configurd, error) { +func newConfigurd(log *logrus.Entry, tag, basePath string) (configurd.Configurd, error) { config := configurd.Config{ Tag: tag, BasePath: basePath, Log: log, - TemplateVars: tv, } return configurd.New(config) diff --git a/configurd.go b/configurd.go index dfcf84f..09a9a7e 100644 --- a/configurd.go +++ b/configurd.go @@ -48,10 +48,9 @@ type Namespace struct { } type Config struct { - Tag string - BasePath string - Log *logrus.Entry - TemplateVars TemplateVars + Tag string + BasePath string + Log *logrus.Entry } type Configurd struct { @@ -166,18 +165,21 @@ func loadGroups(log *logrus.Entry, sl serviceLoader, basePath, namespace string) } func loadGroup(log *logrus.Entry, sl serviceLoader, path, namespace, group string) (Group, error) { - var g Group var wrapper struct { Group Group `yaml:"group"` } - if err := loadYamlTemplate(path, &wrapper, nil, false); err != nil { + bs, err := parseTemplate(path, nil, false) + if err != nil { + return wrapper.Group, err + } + if err := yaml.Unmarshal(bs, &wrapper); err != nil { return wrapper.Group, err } for name := range wrapper.Group.Services { log.Infof("Loading group item: %v", name) svc, err := sl(name) if err != nil { - return g, err + return Group{}, err } wrapper.Group.Services[name] = loadServiceItem(wrapper.Group.Services[name], svc.Name, namespace, group, svc.Chart) } @@ -347,11 +349,11 @@ func stringInSlice(str string, slice []string) bool { } func isYaml(file string) bool { - return stringInSlice(filepath.Ext(file), []string{"yml, yaml"}) + return stringInSlice(filepath.Ext(file), []string{".yml, .yaml"}) } func isJson(file string) bool { - return filepath.Ext(file) == "json" + return filepath.Ext(file) == ".json" } type TemplateVars map[string]interface{} @@ -410,20 +412,17 @@ func (tv TemplateVars) parseFile(workDir, source string) error { return nil } -func loadYamlTemplate(file string, data interface{}, templateVars interface{}, errOnMissing bool) error { +func parseTemplate(file string, templateVars interface{}, errOnMissing bool) ([]byte, error) { tmp, err := template.ParseFiles(file) if err != nil { - return err + return nil, err } out := bytes.NewBuffer([]byte{}) if errOnMissing { tmp = tmp.Option("missingkey=error") } if err := tmp.Funcs(builder.TemplateFuncs).Execute(out, templateVars); err != nil { - return err + return nil, err } - if err := yaml.Unmarshal(out.Bytes(), &data); err != nil { - return err - } - return nil + return out.Bytes(), nil } diff --git a/example/configurd/namespaces/local/hello-group.yml b/example/configurd/namespaces/local/hello-group.yml index 4514496..4a59e25 100644 --- a/example/configurd/namespaces/local/hello-group.yml +++ b/example/configurd/namespaces/local/hello-group.yml @@ -25,5 +25,4 @@ group: ingress: hosts: - name: {{ .host }} - path: /services/hi -jobs: + path: /services/hi \ No newline at end of file diff --git a/helm.go b/helm.go index 47c74cf..bb570fd 100644 --- a/helm.go +++ b/helm.go @@ -21,24 +21,25 @@ type Volume struct { type ServiceItem struct { Name string - overrides interface{} + Overrides interface{} namespace string group string chart string } func (si ServiceItem) getOverrides(basePath string, tv TemplateVars) (interface{}, error) { - if si.overrides == nil { - path := path.Join(basePath, defaultNamespaceDir, si.namespace, si.group, defaultConfigFileExt) - var wrapper struct { - Group Group `yaml:"group"` - } - if err := loadYamlTemplate(path, &wrapper, tv, true); err != nil { - return nil, err - } - si.overrides = wrapper.Group.Services[si.Name].overrides + path := path.Join(basePath, defaultNamespaceDir, si.namespace, fmt.Sprintf("%v%v", si.group, defaultConfigFileExt)) + var wrapper struct { + Group Group `yaml:"group"` } - return si.overrides, nil + bs, err := parseTemplate(path, tv, true) + if err != nil { + return nil, err + } + if err := yaml.Unmarshal(bs, &wrapper); err != nil { + return nil, err + } + return wrapper.Group.Services[si.Name].Overrides, nil } type JobItem struct { @@ -157,7 +158,7 @@ type InstallConfiguration struct { BasePath string OutputDir string Tag string - TemplateVars map[string]interface{} + TemplateVars TemplateVars Verbose bool }