13c663e906
This change revealed more about how the system needs to work, so there are some supporting changes: * helm.upgrade and helm.help are now vars rather than raw functions. This allows unit tests to target the "which step should we run" logic directly by comparing function pointers, rather than having to configure/prepare a fully-valid Plan and then infer the logic’s correctness based on the Plan’s state. * configuration that's specific to kubeconfig initialization is now part of the InitKube struct rather than run.Config, since other steps shouldn’t need access to those settings (particularly the secrets). * Step.Execute now receives a run.Config so it can log debug output.
94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
package run
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"text/template"
|
|
)
|
|
|
|
// InitKube is a step in a helm Plan that initializes the kubernetes config file.
|
|
type InitKube struct {
|
|
SkipTLSVerify bool
|
|
Certificate string
|
|
APIServer string
|
|
ServiceAccount string
|
|
Token string
|
|
TemplateFile string
|
|
|
|
template *template.Template
|
|
configFile io.WriteCloser
|
|
values kubeValues
|
|
}
|
|
|
|
type kubeValues struct {
|
|
SkipTLSVerify bool
|
|
Certificate string
|
|
APIServer string
|
|
Namespace string
|
|
ServiceAccount string
|
|
Token string
|
|
}
|
|
|
|
// Execute generates a kubernetes config file from drone-helm3's template.
|
|
func (i *InitKube) Execute(cfg Config) error {
|
|
if cfg.Debug {
|
|
fmt.Fprintf(cfg.Stderr, "writing kubeconfig file to %s\n", cfg.KubeConfig)
|
|
}
|
|
defer i.configFile.Close()
|
|
return i.template.Execute(i.configFile, i.values)
|
|
}
|
|
|
|
// Prepare ensures all required configuration is present and that the config file is writable.
|
|
func (i *InitKube) Prepare(cfg Config) error {
|
|
var err error
|
|
|
|
if i.APIServer == "" {
|
|
return errors.New("an API Server is needed to deploy")
|
|
}
|
|
if i.Token == "" {
|
|
return errors.New("token is needed to deploy")
|
|
}
|
|
if i.Certificate == "" && !i.SkipTLSVerify {
|
|
return errors.New("certificate is needed to deploy")
|
|
}
|
|
|
|
if i.ServiceAccount == "" {
|
|
i.ServiceAccount = "helm"
|
|
}
|
|
|
|
if cfg.Debug {
|
|
fmt.Fprintf(cfg.Stderr, "loading kubeconfig template from %s\n", i.TemplateFile)
|
|
}
|
|
i.template, err = template.ParseFiles(i.TemplateFile)
|
|
if err != nil {
|
|
return fmt.Errorf("could not load kubeconfig template: %w", err)
|
|
}
|
|
|
|
i.values = kubeValues{
|
|
SkipTLSVerify: i.SkipTLSVerify,
|
|
Certificate: i.Certificate,
|
|
APIServer: i.APIServer,
|
|
ServiceAccount: i.ServiceAccount,
|
|
Token: i.Token,
|
|
Namespace: cfg.Namespace,
|
|
}
|
|
|
|
if cfg.Debug {
|
|
if _, err := os.Stat(cfg.KubeConfig); err != nil {
|
|
// non-nil err here isn't an actual error state; the kubeconfig just doesn't exist
|
|
fmt.Fprint(cfg.Stderr, "creating ")
|
|
} else {
|
|
fmt.Fprint(cfg.Stderr, "truncating ")
|
|
}
|
|
fmt.Fprintf(cfg.Stderr, "kubeconfig file at %s\n", cfg.KubeConfig)
|
|
}
|
|
|
|
i.configFile, err = os.Create(cfg.KubeConfig)
|
|
if err != nil {
|
|
return fmt.Errorf("could not open kubeconfig file for writing: %w", err)
|
|
}
|
|
return nil
|
|
}
|