parent
c88d6c431c
commit
ffa39af554
11
README.md
11
README.md
|
|
@ -31,6 +31,8 @@ releases:
|
|||
namespace: vault # target namespace
|
||||
chart: roboll/vault-secret-manager # the chart being installed to create this release, referenced by `repository/chart` syntax
|
||||
values: [ vault.yaml ] # value files (--values)
|
||||
secrets:
|
||||
- vault_secret.yaml # will attempt to decrypt it using helm-secrets plugin
|
||||
set: # values (--set)
|
||||
- name: address
|
||||
value: https://vault.example.com
|
||||
|
|
@ -83,10 +85,17 @@ GLOBAL OPTIONS:
|
|||
The `helmfile diff` sub-command executes the [helm-diff](https://github.com/databus23/helm-diff) plugin across all of
|
||||
the charts/releases defined in the manifest.
|
||||
|
||||
Under the covers Helmfile is simply using the `helm diff` plugin, so that needs to be installed prior. For Helm 2.3+
|
||||
To supply the diff functionality Helmfile needs the `helm diff` plugin installed. For Helm 2.3+
|
||||
you should be able to simply execute `helm plugin install https://github.com/databus23/helm-diff`. For more details
|
||||
please look at their [documentation](https://github.com/databus23/helm-diff#helm-diff-plugin).
|
||||
|
||||
### secrets
|
||||
|
||||
The `secrets` parameter in a `helmfile.yaml` causes the [helm-secrets](https://github.com/futuresimple/helm-secrets) plugin to be executed to decrypt the file.
|
||||
|
||||
To supply the secret functionality Helmfile needs the `helm secrets` plugin installed. For Helm 2.3+
|
||||
you should be able to simply execute `helm plugin install https://github.com/futuresimple/helm-secrets
|
||||
`.
|
||||
|
||||
## Paths Overview
|
||||
Using manifest files in conjunction with command line argument can be a bit confusing.
|
||||
|
|
|
|||
|
|
@ -59,6 +59,14 @@ func (helm *execer) SyncRelease(name, chart string, flags ...string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (helm *execer) DecryptSecret(name string) (string, error) {
|
||||
out, err := helm.exec(append([]string{"secrets", "dec", name})...)
|
||||
if helm.writer != nil {
|
||||
helm.writer.Write(out)
|
||||
}
|
||||
return name + ".dec", err
|
||||
}
|
||||
|
||||
func (helm *execer) DiffRelease(name, chart string, flags ...string) error {
|
||||
out, err := helm.exec(append([]string{"diff", name, chart}, flags...)...)
|
||||
if helm.writer != nil {
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ type Interface interface {
|
|||
SyncRelease(name, chart string, flags ...string) error
|
||||
DiffRelease(name, chart string, flags ...string) error
|
||||
DeleteRelease(name string) error
|
||||
|
||||
DecryptSecret(name string) (string, error)
|
||||
}
|
||||
|
|
|
|||
75
main.go
75
main.go
|
|
@ -5,7 +5,9 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/roboll/helmfile/helmexec"
|
||||
"github.com/roboll/helmfile/state"
|
||||
|
|
@ -67,13 +69,8 @@ func main() {
|
|||
helm.SetExtraArgs(strings.Split(args, " ")...)
|
||||
}
|
||||
|
||||
if errs := state.SyncRepos(helm); errs != nil && len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
fmt.Printf("err: %s\n", err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
errs := state.SyncRepos(helm)
|
||||
return clean(state, errs)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -109,13 +106,8 @@ func main() {
|
|||
values := c.StringSlice("values")
|
||||
workers := c.Int("concurrency")
|
||||
|
||||
if errs := state.SyncReleases(helm, values, workers); errs != nil && len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
fmt.Printf("err: %s\n", err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
errs := state.SyncReleases(helm, values, workers)
|
||||
return clean(state, errs)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -158,13 +150,8 @@ func main() {
|
|||
|
||||
values := c.StringSlice("values")
|
||||
|
||||
if errs := state.DiffReleases(helm, values); errs != nil && len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
fmt.Printf("err: %s\n", err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
errs := state.DiffReleases(helm, values)
|
||||
return clean(state, errs)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -197,13 +184,8 @@ func main() {
|
|||
values := c.StringSlice("values")
|
||||
workers := c.Int("concurrency")
|
||||
|
||||
if errs := state.SyncReleases(helm, values, workers); errs != nil && len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
fmt.Printf("err: %s\n", err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
errs := state.SyncReleases(helm, values, workers)
|
||||
return clean(state, errs)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -215,13 +197,8 @@ func main() {
|
|||
return err
|
||||
}
|
||||
|
||||
if errs := state.DeleteReleases(helm); errs != nil && len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
fmt.Printf("err: %s\n", err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
errs := state.DeleteReleases(helm)
|
||||
return clean(state, errs)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -267,5 +244,33 @@ func before(c *cli.Context) (*state.HelmState, helmexec.Interface, error) {
|
|||
writer = os.Stdout
|
||||
}
|
||||
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
sig := <-sigs
|
||||
|
||||
errs := []error{fmt.Errorf("Recived [%s] to shutdown ", sig)}
|
||||
clean(st, errs)
|
||||
}()
|
||||
|
||||
return st, helmexec.NewHelmExec(writer, kubeContext), nil
|
||||
}
|
||||
|
||||
func clean(state *state.HelmState, errs []error) error {
|
||||
if errs == nil {
|
||||
errs = []error{}
|
||||
}
|
||||
|
||||
cleanErrs := state.Clean()
|
||||
if cleanErrs != nil {
|
||||
errs = append(errs, cleanErrs...)
|
||||
}
|
||||
|
||||
if errs != nil && len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
fmt.Printf("err: %s\n", err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,14 @@ type ReleaseSpec struct {
|
|||
Name string `yaml:"name"`
|
||||
Namespace string `yaml:"namespace"`
|
||||
Values []string `yaml:"values"`
|
||||
Secrets []string `yaml:"secrets"`
|
||||
SetValues []SetValue `yaml:"set"`
|
||||
|
||||
// The 'env' section is not really necessary any longer, as 'set' would now provide the same functionality
|
||||
EnvValues []SetValue `yaml:"env"`
|
||||
|
||||
// generatedValues are values that need cleaned up on exit
|
||||
generatedValues []string
|
||||
}
|
||||
|
||||
type SetValue struct {
|
||||
|
|
@ -157,7 +161,7 @@ func (state *HelmState) SyncReleases(helm helmexec.Interface, additonalValues []
|
|||
go func() {
|
||||
for release := range jobQueue {
|
||||
releaseWithDefaults := state.applyDefaultsTo(release)
|
||||
flags, flagsErr := flagsForRelease(state.BaseChartPath, &releaseWithDefaults)
|
||||
flags, flagsErr := flagsForRelease(helm, state.BaseChartPath, &releaseWithDefaults)
|
||||
if flagsErr != nil {
|
||||
errQueue <- flagsErr
|
||||
doneQueue <- true
|
||||
|
|
@ -214,15 +218,17 @@ func (state *HelmState) DiffReleases(helm helmexec.Interface, additonalValues []
|
|||
var wg sync.WaitGroup
|
||||
errs := []error{}
|
||||
|
||||
for _, release := range state.Releases {
|
||||
for i := 0; i < len(state.Releases); i++ {
|
||||
release := &state.Releases[i]
|
||||
wg.Add(1)
|
||||
go func(wg *sync.WaitGroup, release ReleaseSpec) {
|
||||
go func(wg *sync.WaitGroup, release *ReleaseSpec) {
|
||||
// Plugin command doesn't support explicit namespace
|
||||
release.Namespace = ""
|
||||
flags, flagsErr := flagsForRelease(state.BaseChartPath, &release)
|
||||
flags, flagsErr := flagsForRelease(helm, state.BaseChartPath, release)
|
||||
if flagsErr != nil {
|
||||
errs = append(errs, flagsErr)
|
||||
}
|
||||
|
||||
for _, value := range additonalValues {
|
||||
valfile, err := filepath.Abs(value)
|
||||
if err != nil {
|
||||
|
|
@ -269,6 +275,26 @@ func (state *HelmState) DeleteReleases(helm helmexec.Interface) []error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Clean will remove any generated secrets
|
||||
func (state *HelmState) Clean() []error {
|
||||
errs := []error{}
|
||||
|
||||
for _, release := range state.Releases {
|
||||
for _, value := range release.generatedValues {
|
||||
err := os.Remove(value)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) != 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// normalizeChart allows for the distinction between a file path reference and repository references.
|
||||
// - Any single (or double character) followed by a `/` will be considered a local file reference and
|
||||
// be constructed relative to the `base path`.
|
||||
|
|
@ -281,7 +307,7 @@ func normalizeChart(basePath, chart string) string {
|
|||
return filepath.Join(basePath, chart)
|
||||
}
|
||||
|
||||
func flagsForRelease(basePath string, release *ReleaseSpec) ([]string, error) {
|
||||
func flagsForRelease(helm helmexec.Interface, basePath string, release *ReleaseSpec) ([]string, error) {
|
||||
flags := []string{}
|
||||
if release.Version != "" {
|
||||
flags = append(flags, "--version", release.Version)
|
||||
|
|
@ -300,6 +326,21 @@ func flagsForRelease(basePath string, release *ReleaseSpec) ([]string, error) {
|
|||
}
|
||||
flags = append(flags, "--values", valfileRendered)
|
||||
}
|
||||
for _, value := range release.Secrets {
|
||||
valfile := filepath.Join(basePath, value)
|
||||
path, err := renderTemplateString(valfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
valfileRendered, err := helm.DecryptSecret(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
release.generatedValues = append(release.generatedValues, valfileRendered)
|
||||
flags = append(flags, "--values", valfileRendered)
|
||||
}
|
||||
if len(release.SetValues) > 0 {
|
||||
val := []string{}
|
||||
for _, set := range release.SetValues {
|
||||
|
|
|
|||
Loading…
Reference in New Issue