diff --git a/.golangci.yml b/.golangci.yml index 683e020..e0bc3d5 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -8,6 +8,10 @@ linters-settings: min-confidence: 0 goimports: local-prefixes: github.com/foomo/squadron + revive: + rules: + - name: indent-error-flow + disabled: true gocritic: enabled-tags: - diagnostic diff --git a/squadron.go b/squadron.go index bb45543..c236121 100644 --- a/squadron.go +++ b/squadron.go @@ -130,17 +130,32 @@ func (sq *Squadron) FilterConfig(units []string) error { } func (sq *Squadron) RenderConfig() error { - tv := TemplateVars{} + var tv TemplateVars + var vars map[string]interface{} + if err := yaml.Unmarshal([]byte(sq.config), &vars); err != nil { + return err + } + // execute again with loaded template vars + tv = TemplateVars{} + if value, ok := vars["global"]; ok { + replace(value) + tv.add("Global", value) + } + if value, ok := vars["squadron"]; ok { + replace(value) + tv.add("Squadron", value) + } // execute without errors to get existing values out, err := executeFileTemplate(sq.config, tv, false) if err != nil { return errors.Wrap(err, "failed to execute initial file template") } - var vars map[string]interface{} + if err := yaml.Unmarshal(out, &vars); err != nil { return err } // execute again with loaded template vars + tv = TemplateVars{} if value, ok := vars["global"]; ok { replace(value) tv.add("Global", value) diff --git a/template.go b/template.go index 74f7109..c301d4f 100644 --- a/template.go +++ b/template.go @@ -32,7 +32,7 @@ func (tv *TemplateVars) add(name string, value interface{}) { func executeFileTemplate(text string, templateVars interface{}, errorOnMissing bool) ([]byte, error) { templateFunctions := template.FuncMap{} templateFunctions["env"] = env - templateFunctions["op"] = onePassword + templateFunctions["op"] = onePassword(templateVars, errorOnMissing) templateFunctions["base64"] = base64 templateFunctions["default"] = defaultIndex templateFunctions["indent"] = indent @@ -123,33 +123,60 @@ func indent(spaces int, v string) string { return strings.ReplaceAll(v, "\n", "\n"+pad) } -func onePassword(account, uuid, field string) (string, error) { - // validate command - if _, err := exec.LookPath("op"); err != nil { - fmt.Println("Your templates includes a call to 1Password, please install it:") - fmt.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") +func render(name, text string, data interface{}, errorOnMissing bool) (string, error) { + var opts []string + if !errorOnMissing { + opts = append(opts, "missingkey=error") + } + out := bytes.NewBuffer([]byte{}) + if uuidTpl, err := template.New(name).Option(opts...).Parse(text); err != nil { + return "", err + } else if err := uuidTpl.Execute(out, data); err != nil { return "", err } + return out.String(), nil +} - // validate session - if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { - if err := onePasswordSignIn(account); err != nil { +func onePassword(templateVars interface{}, errorOnMissing bool) func(account, uuid, field string) (string, error) { + return func(account, uuid, field string) (string, error) { + if value, err := render("op", uuid, templateVars, errorOnMissing); err != nil { + return "", err + } else { + uuid = value + } + if value, err := render("op", field, templateVars, errorOnMissing); err != nil { + return "", err + } else { + field = value + } + + // validate command + if _, err := exec.LookPath("op"); err != nil { + fmt.Println("Your templates includes a call to 1Password, please install it:") + fmt.Println("https://support.1password.com/command-line-getting-started/#set-up-the-command-line-tool") return "", err } - } - res, err := onePasswordGet(uuid, field) - if err != nil && strings.Contains(res, "You are not currently signed in") { - // retry with login - if err := onePasswordSignIn(account); err != nil { - return "", err - } else if res, err = onePasswordGet(uuid, field); err != nil { + // validate session + if os.Getenv(fmt.Sprintf("OP_SESSION_%s", account)) == "" { + if err := onePasswordSignIn(account); err != nil { + return "", err + } + } + + res, err := onePasswordGet(uuid, field) + if err != nil && strings.Contains(res, "You are not currently signed in") { + // retry with login + if err := onePasswordSignIn(account); err != nil { + return "", err + } else if res, err = onePasswordGet(uuid, field); err != nil { + return "", err + } + } else if err != nil { return "", err } - } else if err != nil { - return "", err + return res, nil } - return res, nil } func onePasswordGet(uuid, field string) (string, error) { diff --git a/testdata/config-no-render/squadron.yaml b/testdata/config-no-render/squadron.yaml index d124b77..4ccd5f7 100644 --- a/testdata/config-no-render/squadron.yaml +++ b/testdata/config-no-render/squadron.yaml @@ -17,7 +17,7 @@ squadron: image: tag: <% .Squadron.frontend.builds.default.tag %> repository: <% .Squadron.frontend.builds.default.image %> - env: <% env "LC_CTYPE" %> + env: <% env "SHELL" %> global: <% .Global.host %> base64: <% base64 "1234567890" %> values: | diff --git a/testdata/config-no-render/squadron.yaml.snapshot b/testdata/config-no-render/squadron.yaml.snapshot index 979f7e3..0815df0 100644 --- a/testdata/config-no-render/squadron.yaml.snapshot +++ b/testdata/config-no-render/squadron.yaml.snapshot @@ -12,7 +12,7 @@ squadron: version: 0.1.0 values: base64: <% base64 "1234567890" %> - env: <% env "LC_CTYPE" %> + env: <% env "SHELL" %> global: <% .Global.host %> image: repository: <% .Squadron.frontend.builds.default.image %> diff --git a/testdata/config-override-null/squadron.yaml.snapshot b/testdata/config-override-null/squadron.yaml.snapshot index 0c40ea6..d188ad2 100644 --- a/testdata/config-override-null/squadron.yaml.snapshot +++ b/testdata/config-override-null/squadron.yaml.snapshot @@ -2,13 +2,13 @@ squadron: backend: chart: name: mychart - version: 0.1.0 repository: http://helm.mycompany.com/repository + version: 0.1.0 values: ingress: hosts: - - name: mycompany.com - path: / - port: 80 - frontend: ~ + - name: mycompany.com + path: / + port: 80 + frontend: null version: "1.0" diff --git a/testdata/config-override/squadron.yaml.snapshot b/testdata/config-override/squadron.yaml.snapshot index d3f4a61..76a9e94 100644 --- a/testdata/config-override/squadron.yaml.snapshot +++ b/testdata/config-override/squadron.yaml.snapshot @@ -1,4 +1,5 @@ squadron: + backend: null frontend: builds: service: diff --git a/testdata/config-template-frontend/squadron.yaml b/testdata/config-template-frontend/squadron.yaml index 7410388..dd77615 100644 --- a/testdata/config-template-frontend/squadron.yaml +++ b/testdata/config-template-frontend/squadron.yaml @@ -19,7 +19,7 @@ squadron: tag: <% .Squadron.frontend.builds.default.tag %> repository: <% .Squadron.frontend.builds.default.image %> env: - ENV: <% env "LC_CTYPE" %> + ENV: <% env "SHELL" %> GLOBAL: <% .Global.host %> BASE64: <% base64 "1234567890" %> frontend-admin: @@ -36,4 +36,4 @@ squadron: tag: <% .Squadron.frontend_admin.builds.default.tag %> repository: <% .Squadron.frontend_admin.builds.default.image %> env: - ENV: <% env "LC_CTYPE" %> + ENV: <% env "SHELL" %> diff --git a/testdata/config-template-frontend/squadron.yaml.snapshot b/testdata/config-template-frontend/squadron.yaml.snapshot index 8f86175..d9e7da1 100644 --- a/testdata/config-template-frontend/squadron.yaml.snapshot +++ b/testdata/config-template-frontend/squadron.yaml.snapshot @@ -14,7 +14,7 @@ squadron: values: env: BASE64: MTIzNDU2Nzg5MA== - ENV: UTF-8 + ENV: /bin/zsh GLOBAL: mycompany.com image: repository: docker.mycompany.com/mycomapny/frontend diff --git a/testdata/config-template/squadron.yaml b/testdata/config-template/squadron.yaml index 3893225..71997b3 100644 --- a/testdata/config-template/squadron.yaml +++ b/testdata/config-template/squadron.yaml @@ -18,9 +18,12 @@ squadron: tag: <% .Squadron.frontend.builds.default.tag %> repository: <% .Squadron.frontend.builds.default.image %> env: - ENV: <% env "LC_CTYPE" %> + ENV: <% env "SHELL" %> GLOBAL: <% .Global.host %> BASE64: <% base64 "1234567890" %> + # ONE_PASSWORD: <% op "ACCOUNT_NAME" "UUID" "FIELD" %> + # ONE_PASSWORD: <% op "ACCOUNT_NAME" "Secret name" "FIELD" %> + # ONE_PASSWORD: <% op "ACCOUNT_NAME" "Secret name wit global {{ .Global.host }}" "FIELD" %> values: | <% file "testdata/config-template/values.yaml" | indent 8 %> frontend-admin: diff --git a/testdata/config-template/squadron.yaml.snapshot b/testdata/config-template/squadron.yaml.snapshot index 2b1a482..1a79ef7 100644 --- a/testdata/config-template/squadron.yaml.snapshot +++ b/testdata/config-template/squadron.yaml.snapshot @@ -13,7 +13,7 @@ squadron: values: env: BASE64: MTIzNDU2Nzg5MA== - ENV: UTF-8 + ENV: /bin/zsh GLOBAL: mycompany.com image: repository: docker.mycompany.com/mycomapny/frontend @@ -23,7 +23,7 @@ squadron: bar: - foo - bar - env: UTF-8 + env: /bin/zsh global: mycompany.com base64: MTIzNDU2Nzg5MA== frontend-admin: diff --git a/testdata/config-template/values.yaml b/testdata/config-template/values.yaml index cb37ff4..4d851be 100644 --- a/testdata/config-template/values.yaml +++ b/testdata/config-template/values.yaml @@ -2,6 +2,6 @@ foo: bar bar: - foo - bar -env: <% env "LC_CTYPE" %> +env: <% env "SHELL" %> global: <% .Global.host %> base64: <% base64 "1234567890" %> \ No newline at end of file