Redacting KubeToken may not be sufficient, since it's possible that someone would put secrets in Values or StringValues. Unilaterally redacting those seems unhelpful, though, since they may be the very thing the user is trying to debug. I've settled on redacting the obvious field without trying to promise that all sensitive data will be hidden.
150 lines
3.1 KiB
Go
150 lines
3.1 KiB
Go
package helm
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/pelotech/drone-helm3/internal/run"
|
|
"os"
|
|
)
|
|
|
|
const (
|
|
kubeConfigTemplate = "/root/.kube/config.tpl"
|
|
kubeConfigFile = "/root/.kube/config"
|
|
)
|
|
|
|
// A Step is one step in the plan.
|
|
type Step interface {
|
|
Prepare(run.Config) error
|
|
Execute(run.Config) error
|
|
}
|
|
|
|
// A Plan is a series of steps to perform.
|
|
type Plan struct {
|
|
steps []Step
|
|
cfg Config
|
|
runCfg run.Config
|
|
}
|
|
|
|
// NewPlan makes a plan for running a helm operation.
|
|
func NewPlan(cfg Config) (*Plan, error) {
|
|
p := Plan{
|
|
cfg: cfg,
|
|
runCfg: run.Config{
|
|
Debug: cfg.Debug,
|
|
Values: cfg.Values,
|
|
StringValues: cfg.StringValues,
|
|
ValuesFiles: cfg.ValuesFiles,
|
|
Namespace: cfg.Namespace,
|
|
Stdout: cfg.Stdout,
|
|
Stderr: cfg.Stderr,
|
|
},
|
|
}
|
|
|
|
p.steps = (*determineSteps(cfg))(cfg)
|
|
|
|
for i, step := range p.steps {
|
|
if cfg.Debug {
|
|
fmt.Fprintf(os.Stderr, "calling %T.Prepare (step %d)\n", step, i)
|
|
}
|
|
|
|
if err := step.Prepare(p.runCfg); err != nil {
|
|
err = fmt.Errorf("while preparing %T step: %w", step, err)
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return &p, nil
|
|
}
|
|
|
|
// determineSteps is primarily for the tests' convenience: it allows testing the "which stuff should
|
|
// we do" logic without building a config that meets all the steps' requirements.
|
|
func determineSteps(cfg Config) *func(Config) []Step {
|
|
switch cfg.Command {
|
|
case "upgrade":
|
|
return &upgrade
|
|
case "uninstall", "delete":
|
|
return &uninstall
|
|
case "lint":
|
|
return &lint
|
|
case "help":
|
|
return &help
|
|
default:
|
|
switch cfg.DroneEvent {
|
|
case "push", "tag", "deployment", "pull_request", "promote", "rollback":
|
|
return &upgrade
|
|
case "delete":
|
|
return &uninstall
|
|
default:
|
|
panic("not implemented")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Execute runs each step in the plan, aborting and reporting on error
|
|
func (p *Plan) Execute() error {
|
|
for i, step := range p.steps {
|
|
if p.cfg.Debug {
|
|
fmt.Fprintf(p.cfg.Stderr, "calling %T.Execute (step %d)\n", step, i)
|
|
}
|
|
|
|
if err := step.Execute(p.runCfg); err != nil {
|
|
return fmt.Errorf("in execution step %d: %w", i, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
var upgrade = func(cfg Config) []Step {
|
|
steps := initKube(cfg)
|
|
|
|
steps = append(steps, &run.Upgrade{
|
|
Chart: cfg.Chart,
|
|
Release: cfg.Release,
|
|
ChartVersion: cfg.ChartVersion,
|
|
DryRun: cfg.DryRun,
|
|
Wait: cfg.Wait,
|
|
ReuseValues: cfg.ReuseValues,
|
|
Timeout: cfg.Timeout,
|
|
Force: cfg.Force,
|
|
})
|
|
|
|
return steps
|
|
}
|
|
|
|
var uninstall = func(cfg Config) []Step {
|
|
steps := initKube(cfg)
|
|
steps = append(steps, &run.Uninstall{
|
|
Release: cfg.Release,
|
|
DryRun: cfg.DryRun,
|
|
})
|
|
|
|
return steps
|
|
}
|
|
|
|
var lint = func(cfg Config) []Step {
|
|
lint := &run.Lint{
|
|
Chart: cfg.Chart,
|
|
}
|
|
|
|
return []Step{lint}
|
|
}
|
|
|
|
var help = func(cfg Config) []Step {
|
|
help := &run.Help{}
|
|
return []Step{help}
|
|
}
|
|
|
|
func initKube(cfg Config) []Step {
|
|
return []Step{
|
|
&run.InitKube{
|
|
SkipTLSVerify: cfg.SkipTLSVerify,
|
|
Certificate: cfg.Certificate,
|
|
APIServer: cfg.APIServer,
|
|
ServiceAccount: cfg.ServiceAccount,
|
|
Token: cfg.KubeToken,
|
|
TemplateFile: kubeConfigTemplate,
|
|
ConfigFile: kubeConfigFile,
|
|
},
|
|
}
|
|
}
|