Skip to content
This repository has been archived by the owner on Jun 29, 2022. It is now read-only.

Commit

Permalink
pkg/components/util: use Helm post-renderer instead of Manifests field
Browse files Browse the repository at this point in the history
As Manifests filed in Chart object is a custom field, added to our fork
of Helm. Now Helm offers post-renderer feature, which allows to further
customize the manfiests after Helm's templating engine and before the
installation of the manifests.

This allows us to use post-renderer feature and drop one of maintained
custom patches, which means less maintenance for us.

Signed-off-by: Mateusz Gozdek <mateusz@kinvolk.io>
  • Loading branch information
invidian committed Aug 10, 2020
1 parent 817ac0e commit a182195
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 12 deletions.
6 changes: 1 addition & 5 deletions pkg/components/util/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,7 @@ func chartFromManifests(metadata components.Metadata, manifests map[string]strin
Name: p,
}

// Apply rendered manifests to Manifests slice, which does not run through the rendering engine
// again when the chart is being installed. This is required, as some charts use complex escaping
// syntax, which breaks if the templates are evaluated twice. This, for example, breaks
// the prometheus-operator chart.
ch.Manifests = append(ch.Manifests, f)
ch.Templates = append(ch.Templates, f)
}

// If we collected any CRDs, put them in the special file in the dedicated crds/ directory.
Expand Down
18 changes: 11 additions & 7 deletions pkg/components/util/helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ metadata:
t.Fatalf("Chart should be created, got: %v", err)
}

if len(chart.Manifests) != 1 { //nolint:gomnd
if len(chart.Templates) != 1 {
t.Fatalf("Manifest file with the namespace should still be added, as it may contain other objects")
}

if len(chart.Manifests[0].Data) != 0 {
if len(chart.Templates[0].Data) != 0 {
t.Fatalf("Namespace object should be removed from chart")
}
}
Expand Down Expand Up @@ -140,7 +140,11 @@ metadata:
t.Fatalf("Chart should be created, got: %v", err)
}

if len(chart.Manifests[0].Data) == 0 {
if len(chart.Templates) != 1 {
t.Fatalf("templates should include exactly one object")
}

if len(chart.Templates[0].Data) == 0 {
t.Fatalf("Other objects should be retained in the file containing Namespace object")
}
}
Expand All @@ -165,7 +169,7 @@ metadata:
t.Fatalf("Chart should be created, got: %v", err)
}

if len(chart.Manifests[0].Data) == 0 {
if len(chart.Templates[0].Data) == 0 {
t.Fatalf("Only Namespace object with matching namespace name should be filtered")
}
}
Expand All @@ -188,15 +192,15 @@ metadata:
t.Fatalf("Chart should be created, got: %v", err)
}

if len(chart.Manifests) != 1 { //nolint:gomnd
if len(chart.Templates) != 1 {
t.Fatalf("Manifest file with the CRDs should still be added, as it may contain other objects")
}

if len(chart.Manifests[0].Data) != 0 {
if len(chart.Templates[0].Data) != 0 {
t.Fatalf("CRD object should be removed from the manifests file")
}

if len(chart.Files) != 1 { //nolint:gomnd
if len(chart.Files) != 1 {
t.Fatalf("CRD object should be added to Files field")
}

Expand Down
37 changes: 37 additions & 0 deletions pkg/components/util/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package util

import (
"bytes"
"context"
"fmt"

Expand Down Expand Up @@ -104,10 +105,45 @@ type helmAction struct {
wait bool
}

// postRender is a Lokomotive post-renderer for Helm, which allows bypassing Helm templating engine
// by copying manifests from Templates field and then including them into the chart.
//
// As we render original charts twice (once when we render manifests ourselves to be able to print them
// to the user and then again via Helm, when it installs/upgrades/uninstalls the release.
//
// This is required as some charts use complex escaping syntax, which breaks if the templates
// are evaluated twice. This, for example, breaks the prometheus-operator chart.
type postRender struct {
manifests bytes.Buffer
}

// Run implements postrender.PostRenderer interface by ignoring given templates from Helm and returning
// manifests defined at creation time.
func (pr postRender) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) {
return &pr.manifests, nil
}

// chartTemplatesToPostRender creates PostRenderer from given chart templates and resets
// chart's Templates field so it does not run twice trough rendering engine.
func chartTemplatesToPostRender(c *chart.Chart) postRender {
var buf bytes.Buffer

for _, template := range c.Templates {
fmt.Fprintf(&buf, "\n---\n# %s\n%s", template.Name, template.Data)
}

c.Templates = nil

return postRender{
manifests: buf,
}
}

func install(helmAction *helmAction, namespace string) error {
install := action.NewInstall(helmAction.actionConfig)
install.ReleaseName = helmAction.releaseName
install.Namespace = namespace
install.PostRenderer = chartTemplatesToPostRender(helmAction.chart)

// Currently, we install components one-by-one, in the order how they are
// defined in the configuration and we do not support any dependencies between
Expand All @@ -133,6 +169,7 @@ func upgrade(helmAction *helmAction) error {
upgrade := action.NewUpgrade(helmAction.actionConfig)
upgrade.Wait = helmAction.wait
upgrade.RecreateResources = true
upgrade.PostRenderer = chartTemplatesToPostRender(helmAction.chart)

if _, err := upgrade.Run(helmAction.releaseName, helmAction.chart, map[string]interface{}{}); err != nil {
return fmt.Errorf("upgrading release failed: %w", err)
Expand Down

0 comments on commit a182195

Please sign in to comment.