diff --git a/cmd/app.go b/cmd/app.go index 381c41d..41615c4 100644 --- a/cmd/app.go +++ b/cmd/app.go @@ -673,7 +673,7 @@ var appDeployCmd = addCommand(appCmd, &cobra.Command{ } } - ctx.Log.Debugf("Created transient release to define deploy: \n%s\n", MustYaml(r)) + ctx.Log.Debugf("Created transient release to define deploy: \n%s\n", r.Name) err = r.Deploy(ctx) diff --git a/cmd/release.go b/cmd/release.go index 5890385..938bba1 100644 --- a/cmd/release.go +++ b/cmd/release.go @@ -7,6 +7,7 @@ import ( "github.com/naveego/bosun/pkg" "github.com/naveego/bosun/pkg/bosun" "github.com/naveego/bosun/pkg/git" + "github.com/naveego/bosun/pkg/util" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -405,7 +406,7 @@ func validateRelease(b *bosun.Bosun, ctx bosun.BosunContext, release *bosun.Rele hasErrors := false apps := release.AppReleases.GetAppsSortedByName() - p := NewProgressBar(len(apps)) + p := util.NewProgressBar(len(apps)) for _, app := range apps { if app.Excluded { @@ -528,7 +529,7 @@ func processAppReleases(b *bosun.Bosun, ctx bosun.BosunContext, appReleases []*b included = append(included, ar) } } - p := NewProgressBar(len(included)) + p := util.NewProgressBar(len(included)) for _, appRelease := range included { p.Add(1, appRelease.Name) diff --git a/pkg/bosun/app_actions.go b/pkg/bosun/app_actions.go index da94eb7..74fd965 100644 --- a/pkg/bosun/app_actions.go +++ b/pkg/bosun/app_actions.go @@ -2,6 +2,7 @@ package bosun import ( "crypto/tls" + "fmt" "github.com/naveego/bosun/pkg" "github.com/pkg/errors" "gopkg.in/yaml.v2" @@ -105,16 +106,18 @@ func (a *AppAction) Execute(ctx BosunContext) error { if attempts == 0 { return err } - - ctx.Log.WithField("wait", interval).Info("Waiting before trying again.") - select { - case <-ctx.Ctx().Done(): - return nil - case <-time.After(interval): + seconds := int(interval.Seconds()) + fmt.Printf("\rWaiting: %d", seconds) + for ; seconds >= 0; seconds = seconds - 1 { + select { + case <-ctx.Ctx().Done(): + return nil + case <-time.After(time.Second): + fmt.Printf("\rWaiting: %d", seconds - 1) + } } + fmt.Printf("\r") } - - return nil } func (a *AppAction) execute(ctx BosunContext) error { @@ -215,7 +218,15 @@ func (a *AppAction) executeTest(ctx BosunContext) error { if err != nil { return err } - resp.Body.Close() + body, _ := ioutil.ReadAll(resp.Body) + err = resp.Body.Close() + if err != nil { + return err + } + if resp.StatusCode >= 400 { + return errors.Errorf("got non-success code %d - %s: %s", resp.StatusCode, resp.Status, string(body)) + } + return nil } diff --git a/pkg/bosun/app_release.go b/pkg/bosun/app_release.go index c53a796..1b54a1b 100644 --- a/pkg/bosun/app_release.go +++ b/pkg/bosun/app_release.go @@ -60,18 +60,17 @@ type AppRelease struct { ActualState AppState DesiredState AppState helmRelease *HelmRelease - labels map[string]string + labels map[string]string } - func (a *AppRelease) Labels() map[string]string { if a.labels == nil { a.labels = map[string]string{ - string(FilterKeyName): a.Name, - string(FilterKeyPath):a.AppRepo.FromPath, - string(FilterKeyBranch):a.Branch, - string(FilterKeyCommit):a.Commit, - string(FilterKeyVersion):a.Version, + string(FilterKeyName): a.Name, + string(FilterKeyPath): a.AppRepo.FromPath, + string(FilterKeyBranch): a.Branch, + string(FilterKeyCommit): a.Commit, + string(FilterKeyVersion): a.Version, } for k, v := range a.AppRepo.AppLabels { a.labels[k] = v @@ -80,7 +79,6 @@ func (a *AppRelease) Labels() map[string]string { return a.labels } - func NewAppRelease(ctx BosunContext, config *AppReleaseConfig) (*AppRelease, error) { release := &AppRelease{ AppReleaseConfig: config, @@ -337,21 +335,28 @@ type ReleaseValues struct { } func (r *ReleaseValues) PersistValues() (string, error) { - if r.FilePath != "" { - return r.FilePath, nil - } + if r.FilePath == "" { - tmp, err := ioutil.TempFile(os.TempDir(), "bosun-release-*.yaml") - if err != nil { - return "", err - } - defer tmp.Close() - err = r.Values.Encode(tmp) - if err != nil { - return "", err + // b, err := r.Values.YAML() + // if err != nil { + // return "", err + // } + // r.FilePath = server.GetDefaultServer().AddValueFile(uuid.New().String(), []byte(b)) + + tmp, err := ioutil.TempFile(os.TempDir(), "bosun-release-*.yaml") + if err != nil { + return "", err + } + defer tmp.Close() + err = r.Values.Encode(tmp) + if err != nil { + return "", err + } + r.FilePath = tmp.Name() + return r.FilePath, nil } - r.FilePath = tmp.Name() return r.FilePath, nil + } func (r *ReleaseValues) Cleanup() { @@ -386,8 +391,6 @@ func (a *AppRelease) GetReleaseValues(ctx BosunContext) (*ReleaseValues, error) appValues = append(appValues, *ctx.Env.AppValues) } - - for _, v := range appValues { r.Values.Merge(v.Static) @@ -433,6 +436,9 @@ func (a *AppRelease) Reconcile(ctx BosunContext) error { return errors.Errorf("create values map for app %q: %s", a.Name, err) } + valuesYaml, _ := values.Values.YAML() + log.Debugf("Created release values for app:\n%s", valuesYaml) + _, err = values.PersistValues() if err != nil { return errors.Errorf("persist values for app %q: %s", a.Name, err) diff --git a/pkg/bosun/server/server.go b/pkg/bosun/server/server.go new file mode 100644 index 0000000..76a6735 --- /dev/null +++ b/pkg/bosun/server/server.go @@ -0,0 +1,82 @@ +package server + +import ( + "fmt" + "github.com/naveego/bosun/pkg" + "net" + "net/http" + "strings" + "sync" +) + +type Server struct { + url string + server *http.Server + valueFiles map[string][]byte +} + +var defaultServer *Server +var defaultServerInit = new(sync.Once) + +func GetDefaultServer() *Server { + defaultServerInit.Do(func(){ + defaultServer = newServer() + }) + + return defaultServer +} + +func newServer() *Server { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + panic(err) + } + + httpServer := &http.Server{ } + + pkg.Log.Infof("Value file server started at %s", listener.Addr().String()) + + go func(){ + err = httpServer.Serve(listener) + if err != nil { + panic(err) + } + }() + + s := &Server{ + server: httpServer, + valueFiles: map[string][]byte{}, + url:fmt.Sprintf("http://%s", listener.Addr().String()), + } + mux := http.NewServeMux() + mux.Handle("values/", http.HandlerFunc(s.HandleValueFileRequest)) + + return s +} + +// Adds a value file and returns the URL to it. +func (s *Server) AddValueFile(name string, b []byte) string { + s.valueFiles[name] = b + return fmt.Sprintf("%s/%s", s.url, name) +} + +func (s *Server) HandleValueFileRequest(resp http.ResponseWriter, req *http.Request) { + + segs := strings.Split(req.URL.Path, "/") + if len(segs) != 2 { + _, _ = fmt.Fprintf(resp, "Invalid value path (should be values/filename, was %q).", req.URL.Path) + resp.WriteHeader(400) + return + } + + valueFileName := segs[1] + + if valueFileBytes, ok := s.valueFiles[valueFileName]; ok { + resp.Write(valueFileBytes) + resp.WriteHeader(200) + return + } + + _, _ = fmt.Fprintf(resp, "Value file %q not registered.", valueFileName) + resp.WriteHeader(404) +} \ No newline at end of file diff --git a/pkg/templates.go b/pkg/templates.go index 829fc1b..627947d 100644 --- a/pkg/templates.go +++ b/pkg/templates.go @@ -167,17 +167,27 @@ func (t *TemplateBuilder) WithTemplate(c string) *TemplateBuilder { func (t *TemplateBuilder) WithKubeFunctions() *TemplateBuilder { t.t = t.t.Funcs(template.FuncMap{ - "kube_server": func(cluster string) (string, error) { - if cluster == "" { - return "", errors.New("cluster parameter was not set") + "kube_server": func(context string) (string, error) { + if context == "" { + return "", errors.New("context parameter was not set") + } + + cluster, err := getClusterForContext(context) + if err != nil { + return "", err } o, err := NewCommand(fmt.Sprintf(`kubectl config view --raw -o jsonpath={.clusters[?(@.name=="%s")].cluster.server}`, cluster)).RunOut() return o, err }, - "kube_ca_cert": func(cluster string) (string, error) { - if cluster == "" { - return "", errors.New("cluster parameter was not set") + "kube_ca_cert": func(context string) (string, error) { + if context == "" { + return "", errors.New("context parameter was not set") + } + + cluster, err := getClusterForContext(context) + if err != nil { + return "", err } data, err := NewCommand(fmt.Sprintf(`kubectl config view --raw -o jsonpath={.clusters[?(@.name=="%s")].cluster.certificate-authority-data}`, cluster)).RunOut() @@ -205,17 +215,17 @@ func (t *TemplateBuilder) WithKubeFunctions() *TemplateBuilder { return string(cert), nil }, - "kube_service_token": func(cluster string, serviceAccount string) (string, error) { - if cluster == "" { - return "", errors.New("cluster parameter was not set") + "kube_service_token": func(context string, serviceAccount string) (string, error) { + if context == "" { + return "", errors.New("context parameter was not set") } - o, err := NewCommand("kubectl", "--context", cluster, "get", "serviceaccounts", serviceAccount, "-o", "jsonpath={.secrets[0].name}").RunOut() + o, err := NewCommand("kubectl", "--context", context, "get", "serviceaccounts", serviceAccount, "-o", "jsonpath={.secrets[0].name}").RunOut() if err != nil { - return "", errors.Errorf("getting service account data for account %q in cluster %q: %s", serviceAccount, cluster, err) + return "", errors.Errorf("getting service account data for account %q in context %q: %s", serviceAccount, context, err) } - o, err = NewCommand(fmt.Sprintf(`kubectl --context=%s get secrets %s -o jsonpath={.data.token}'`, cluster, o)).RunOut() + o, err = NewCommand(fmt.Sprintf(`kubectl --context=%s get secrets %s -o jsonpath={.data.token}'`, context, o)).RunOut() if err != nil { return "", err } @@ -238,6 +248,11 @@ func (t *TemplateBuilder) WithKubeFunctions() *TemplateBuilder { } +func getClusterForContext(context string) (string, error) { + data, err := NewCommand(fmt.Sprintf(`kubectl config view --raw -o jsonpath={.contexts[?(@.name=="%s")].context.cluster}`, context)).RunOut() + return data, err +} + func (t *TemplateBuilder) WithDisabledVaultTemplateFunctions() *TemplateBuilder { t.t = t.t.Funcs(template.FuncMap{ diff --git a/cmd/progress.go b/pkg/util/progress.go similarity index 94% rename from cmd/progress.go rename to pkg/util/progress.go index 84670af..79d5d53 100644 --- a/cmd/progress.go +++ b/pkg/util/progress.go @@ -1,4 +1,4 @@ -package cmd +package util import ( "fmt" @@ -79,6 +79,14 @@ func (p *ProgressBar) SetWriter(w io.Writer) { p.w = w } +// Clear attempts to erase the progress bar. +func (p *ProgressBar) Clear() error { + if f, ok := p.w.(*os.File); ok { + return f.Sync() + } + return nil +} + // Add with increase the current count on the progress bar func (p *ProgressBar) Add(num int, label string) error { p.Lock()