Skip to content

Commit

Permalink
Support Helm storage backends in Helm runner
Browse files Browse the repository at this point in the history
  • Loading branch information
pkosiec committed Mar 24, 2022
1 parent f686d82 commit 97661ed
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 62 deletions.
4 changes: 4 additions & 0 deletions cmd/helm-runner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ To check if the PostgreSQL Helm release was created, run:
helm list
```

To see the output TypeInstances, open `/tmp/helm-release.yaml` and `/tmp/additional.yaml` files.

### Upgrade

Follow the instructions from the [Installation](#installation) section first.
Expand All @@ -58,6 +60,8 @@ Observe the incremented value in "Revision" column. Verify `upgraded: "true"` an
kubectl get svc postgresql-server -o jsonpath='{.metadata.annotations}'
```

To see the output TypeInstances, open `/tmp/helm-release.yaml` and `/tmp/additional.yaml` files.

## Configuration

The following environment variables can be set:
Expand Down
18 changes: 11 additions & 7 deletions cmd/helm-runner/example-input/install-args.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ values:
postgresqlDatabase: postgres
postgresqlPassword: s3cr3t
output:
goTemplate: |
host: '{{ template "postgresql.primary.fullname" . }}'
port: '{{ template "postgresql.port" . }}'
defaultDBName: '{{ template "postgresql.database" . }}'
superuser:
username: '{{ template "postgresql.username" . }}'
password: '{{ template "postgresql.password" . }}'
helmRelease:
useHelmReleaseStorage: true
additional:
useHelmTemplateStorage: true
goTemplate: |
host: '{{ template "postgresql.primary.fullname" . }}'
port: '{{ template "postgresql.port" . }}'
defaultDBName: '{{ template "postgresql.database" . }}'
superuser:
username: '{{ template "postgresql.username" . }}'
password: '{{ template "postgresql.password" . }}'
20 changes: 12 additions & 8 deletions cmd/helm-runner/example-input/upgrade-args.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ chart:
values:
postgresqlPassword: foo
commonAnnotations:
upgraded: "true"
upgraded: "true"
output:
goTemplate: |
host: '{{ template "postgresql.primary.fullname" . }}'
port: '{{ template "postgresql.port" . }}'
defaultDBName: '{{ template "postgresql.database" . }}'
superuser:
username: '{{ template "postgresql.username" . }}'
password: '{{ template "postgresql.password" . }}'
helmRelease:
useHelmReleaseStorage: true
additional:
useHelmTemplateStorage: true
goTemplate: |
host: '{{ template "postgresql.primary.fullname" . }}'
port: '{{ template "postgresql.port" . }}'
defaultDBName: '{{ template "postgresql.database" . }}'
superuser:
username: '{{ template "postgresql.username" . }}'
password: '{{ template "postgresql.password" . }}'
26 changes: 18 additions & 8 deletions internal/installation/capact_register.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
actionNameFormat = "%s-config"
helmReleaseTypeRefPath = "cap.type.helm.chart.release"
capactTypeRefPath = "cap.type.capactio.capact.config"
helmDriver = "secrets"
)

var capactAdditionalOutput = heredoc.Doc(`
Expand All @@ -43,6 +44,7 @@ type CapactRegister struct {
localHubCli *local.Client
cfg TypeInstancesConfig
helmOutputter *helm.Outputter
helmDriver string
}

// NewCapactRegister returns a new CapactRegister instance.
Expand Down Expand Up @@ -70,6 +72,7 @@ func NewCapactRegister() (*CapactRegister, error) {
logger: logger,
localHubCli: client,
cfg: cfg,
helmDriver: helmDriver,
helmOutputter: helm.NewOutputter(logger, helm.NewRenderer()),
}, nil
}
Expand Down Expand Up @@ -155,7 +158,7 @@ func (i *CapactRegister) newHelmListAction() (*action.List, error) {
i.logger.Debug(fmt.Sprintf(format, v...), zap.String("source", "Helm"))
}

err := actionConfig.Init(helmCfg, "", "secrets", debugLog)
err := actionConfig.Init(helmCfg, "", i.helmDriver, debugLog)
if err != nil {
return nil, err
}
Expand All @@ -171,13 +174,17 @@ func (i *CapactRegister) newHelmListAction() (*action.List, error) {
return actList, nil
}

// TODO: Support registering TypeInstances using Helm storage (release + template) backends
func (i *CapactRegister) produceHelmReleaseTypeInstance(helmRelease *release.Release) (*gqllocalapi.CreateTypeInstanceInput, error) {
releaseOut, err := i.helmOutputter.ProduceHelmRelease(i.cfg.HelmRepositoryPath, helmRelease)
args := helm.ReleaseOutputArgs{
UseHelmReleaseStorage: false,
}
releaseOut, err := i.helmOutputter.ProduceHelmRelease(args, i.cfg.HelmRepositoryPath, i.helmDriver, helmRelease)
if err != nil {
return nil, errors.Wrap(err, "while producing Helm release definition")
}

var unmarshalled interface{}
var unmarshalled helm.OutputFile
err = yaml.Unmarshal(releaseOut, &unmarshalled)
if err != nil {
return nil, errors.Wrap(err, "while unmarshaling bytes")
Expand All @@ -189,7 +196,7 @@ func (i *CapactRegister) produceHelmReleaseTypeInstance(helmRelease *release.Rel
Path: helmReleaseTypeRefPath,
Revision: "0.1.0",
},
Value: unmarshalled,
Value: unmarshalled.Value,
}, nil
}

Expand All @@ -200,14 +207,17 @@ func (i *CapactRegister) produceConfigTypeInstance(ownerName string, helmRelease
}

args := helm.OutputArgs{
GoTemplate: string(tpl),
Additional: helm.AdditionalOutputArgs{
GoTemplate: string(tpl),
UseHelmTemplateStorage: false,
},
}
data, err := i.helmOutputter.ProduceAdditional(args, helmRelease.Chart, helmRelease)
data, err := i.helmOutputter.ProduceAdditional(args, helmRelease.Chart, i.helmDriver, helmRelease)
if err != nil {
return nil, errors.Wrap(err, "while producing additional info")
}

var unmarshalled interface{}
var unmarshalled helm.OutputFile
err = yaml.Unmarshal(data, &unmarshalled)
if err != nil {
return nil, errors.Wrap(err, "while unmarshaling bytes")
Expand All @@ -218,6 +228,6 @@ func (i *CapactRegister) produceConfigTypeInstance(ownerName string, helmRelease
Path: capactTypeRefPath,
Revision: "0.1.0",
},
Value: unmarshalled,
Value: unmarshalled.Value,
}, nil
}
4 changes: 2 additions & 2 deletions pkg/runner/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ func (r *helmRunner) Do(ctx context.Context, in runner.StartInput) (*runner.Wait
var helmCmd helmCommand
switch r.cfg.Command {
case InstallCommandType:
helmCmd = newInstaller(r.log, r.cfg.RepositoryCachePath, actionCfgProducer, outputter)
helmCmd = newInstaller(r.log, r.cfg, actionCfgProducer, outputter)
case UpgradeCommandType:
helmCmd = newUpgrader(r.log, r.cfg.RepositoryCachePath, r.cfg.HelmReleasePath, actionCfgProducer, outputter)
helmCmd = newUpgrader(r.log, r.cfg, actionCfgProducer, outputter)
default:
return nil, errors.New("Unsupported command")
}
Expand Down
10 changes: 6 additions & 4 deletions pkg/runner/helm/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ type installer struct {
log *zap.Logger
out outputter
repositoryCachePath string
helmDriver string
}

func newInstaller(log *zap.Logger, repositoryCachePath string, actionCfgProducer actionConfigProducer, outputter outputter) *installer {
func newInstaller(log *zap.Logger, cfg Config, actionCfgProducer actionConfigProducer, outputter outputter) *installer {
return &installer{
log: log,
actionCfgProducer: actionCfgProducer,
repositoryCachePath: repositoryCachePath,
repositoryCachePath: cfg.RepositoryCachePath,
helmDriver: cfg.HelmDriver,
out: outputter,
}
}
Expand Down Expand Up @@ -68,12 +70,12 @@ func (i *installer) Do(_ context.Context, in Input) (Output, Status, error) {
return Output{}, Status{}, errors.Wrap(err, "Helm release is nil")
}

releaseOut, err := i.out.ProduceHelmRelease(in.Args.Chart.Repo, helmRelease)
releaseOut, err := i.out.ProduceHelmRelease(in.Args.Output.HelmRelease, in.Args.Chart.Repo, i.helmDriver, helmRelease)
if err != nil {
return Output{}, Status{}, errors.Wrap(err, "while saving default output")
}

additionalOut, err := i.out.ProduceAdditional(in.Args.Output, chartData, helmRelease)
additionalOut, err := i.out.ProduceAdditional(in.Args.Output, chartData, i.helmDriver, helmRelease)
if err != nil {
return Output{}, Status{}, errors.Wrap(err, "while rendering and saving additional output")
}
Expand Down
124 changes: 110 additions & 14 deletions pkg/runner/helm/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package helm
import (
"strings"

"capact.io/capact/internal/ptr"

"github.com/pkg/errors"
"go.uber.org/zap"
"helm.sh/helm/v3/pkg/chart"
Expand All @@ -16,6 +18,44 @@ type ChartRenderer interface {
Do(chartData *chart.Chart, release *release.Release, additionalOutputTemplate []byte) ([]byte, error)
}

// TODO: Use types from https://github.com/capactio/capact/pull/685/files

// OutputFile defines the shape of the output file.
type OutputFile struct {
Value interface{} `json:"value"`
Backend *OutputFileBackend `json:"backend"`
}

// OutputFileBackend defines shape of the Backend property in output file.
type OutputFileBackend struct {
Context interface{} `json:"context"`
}

// OutputFileHelmReleaseContext contains context data form Helm Release storage.
type OutputFileHelmReleaseContext struct {
Release
// ChartLocation specifies Helm Chart location.
ChartLocation string `json:"chartLocation"`
}

// OutputFileAdditionalContext holds context used by Helm template storage backend.
type OutputFileAdditionalContext struct {
// GoTemplate specifies Go template which is used to render returned value.
GoTemplate string `json:"goTemplate"`
// HelmRelease specifies Helm release details against which the render logic should be executed.
HelmRelease Release `json:"release"`
}

// Release holds details about Helm release.
type Release struct {
// Name specifies Helm release name for a given request.
Name string `json:"name"`
// Namespace specifies in which Kubernetes Namespace Helm release is located.
Namespace string `json:"namespace"`
// Driver specifies drivers used for storing the Helm release.
Driver *string `json:"driver,omitempty"`
}

// Outputter handles producing the runner output artifacts.
type Outputter struct {
log *zap.Logger
Expand All @@ -28,18 +68,33 @@ func NewOutputter(log *zap.Logger, renderer ChartRenderer) *Outputter {
}

// ProduceHelmRelease creates an output artifacts with the Helm release data.
func (o *Outputter) ProduceHelmRelease(repository string, helmRelease *release.Release) ([]byte, error) {
releaseData := ChartRelease{
Name: helmRelease.Name,
Namespace: helmRelease.Namespace,
Chart: Chart{
Name: helmRelease.Chart.Metadata.Name,
Version: helmRelease.Chart.Metadata.Version,
Repo: repository,
},
func (o *Outputter) ProduceHelmRelease(args ReleaseOutputArgs, repository, driver string, helmRelease *release.Release) ([]byte, error) {
outputData := OutputFile{}

if !args.UseHelmReleaseStorage {
outputData.Value = ChartRelease{
Name: helmRelease.Name,
Namespace: helmRelease.Namespace,
Chart: Chart{
Name: helmRelease.Chart.Metadata.Name,
Version: helmRelease.Chart.Metadata.Version,
Repo: repository,
},
}
} else {
outputData.Backend = &OutputFileBackend{
Context: OutputFileHelmReleaseContext{
Release: Release{
Name: helmRelease.Name,
Namespace: helmRelease.Namespace,
Driver: ptr.String(driver),
},
ChartLocation: repository,
},
}
}

bytes, err := yaml.Marshal(&releaseData)
bytes, err := yaml.Marshal(&outputData)
if err != nil {
return nil, errors.Wrap(err, "while marshaling yaml")
}
Expand All @@ -49,15 +104,56 @@ func (o *Outputter) ProduceHelmRelease(repository string, helmRelease *release.R

// ProduceAdditional creates an output artifacts from the output template provided in the args.
// TODO: consider to get rid of the chrt arg and use rel.Chart instead.
func (o *Outputter) ProduceAdditional(args OutputArgs, chrt *chart.Chart, rel *release.Release) ([]byte, error) {
if strings.TrimSpace(args.GoTemplate) == "" {
func (o *Outputter) ProduceAdditional(args OutputArgs, chrt *chart.Chart, driver string, rel *release.Release) ([]byte, error) {
goTemplate := args.Additional.GoTemplate
if strings.TrimSpace(goTemplate) == "" {
// Fallback to legacy field
goTemplate = args.LegacyGoTemplate
}

if strings.TrimSpace(goTemplate) == "" {
// still nothing - exit
o.log.Debug("No additional output to render and save. skipping...")
return nil, nil
}

bytes, err := o.renderer.Do(chrt, rel, []byte(args.GoTemplate))
outputData := OutputFile{}
if !args.Additional.UseHelmTemplateStorage {
bytes, err := o.renderer.Do(chrt, rel, []byte(goTemplate))
if err != nil {
return nil, errors.Wrap(err, "while rendering additional output")
}

var unmarshalled interface{}
err = yaml.Unmarshal(bytes, &unmarshalled)
if err != nil {
return nil, errors.Wrap(err, "while unmarshalling additional output bytes")
}

outputData.Value = unmarshalled

bytes, err = yaml.Marshal(&outputData)
if err != nil {
return nil, errors.Wrap(err, "while marshaling yaml")
}

return bytes, nil
}

outputData.Backend = &OutputFileBackend{
Context: OutputFileAdditionalContext{
HelmRelease: Release{
Name: rel.Name,
Namespace: rel.Namespace,
Driver: ptr.String(driver),
},
GoTemplate: goTemplate,
},
}

bytes, err := yaml.Marshal(&outputData)
if err != nil {
return nil, errors.Wrap(err, "while rendering additional output")
return nil, errors.Wrap(err, "while marshaling yaml")
}

return bytes, nil
Expand Down
Loading

0 comments on commit 97661ed

Please sign in to comment.