Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Post render #192

Merged
merged 8 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func main() {
Log: logg,
Scheme: mgr.GetScheme(),
HelmFactoryFn: func(namespace string) (controllers.Helm, error) {
return chart.NewHelmClient(namespace)
return chart.NewHelmClient(namespace, mgr.GetClient())
},
Now: time.Now,
Group: group,
Expand All @@ -141,7 +141,7 @@ func main() {
Scheme: mgr.GetScheme(),
TemplateReader: storage,
HelmFactoryFn: func(namespace string) (controllers.Helm, error) {
return chart.NewHelmClient(namespace)
return chart.NewHelmClient(namespace, mgr.GetClient())
},
Recorder: eventBroadcaster.NewRecorder(clientgoscheme.Scheme, v1.EventSource{
Component: "ketch-controller",
Expand Down
1 change: 1 addition & 0 deletions config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ kind: Kustomization
images:
- name: controller
newName: gcr.io/kubernetes-312803/ketch
newTag: "20"
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ require (
sigs.k8s.io/yaml v1.2.0
)

require sigs.k8s.io/kustomize/api v0.10.0

require (
cloud.google.com/go v0.57.0 // indirect
github.com/Azure/azure-sdk-for-go v42.3.0+incompatible // indirect
Expand Down Expand Up @@ -176,10 +178,9 @@ require (
k8s.io/component-base v0.21.3 // indirect
k8s.io/klog v1.0.0 // indirect
k8s.io/klog/v2 v2.8.0 // indirect
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
k8s.io/legacy-cloud-providers v0.18.8 // indirect
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 // indirect
sigs.k8s.io/kustomize/api v0.8.5 // indirect
sigs.k8s.io/kustomize/kyaml v0.10.15 // indirect
sigs.k8s.io/kustomize/kyaml v0.12.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
Expand Down Expand Up @@ -1510,6 +1511,8 @@ k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKf
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg=
k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks=
k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8=
Expand Down Expand Up @@ -1539,10 +1542,14 @@ sigs.k8s.io/controller-runtime v0.9.5 h1:WThcFE6cqctTn2jCZprLICO6BaKZfhsT37uAapT
sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA=
sigs.k8s.io/kustomize/api v0.8.5 h1:bfCXGXDAbFbb/Jv5AhMj2BB8a5VAJuuQ5/KU69WtDjQ=
sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY=
sigs.k8s.io/kustomize/api v0.10.0 h1:HK5gVSlVV24AmZ2fTHUIchZ6osaYNegK1jAdx7lJ/mU=
sigs.k8s.io/kustomize/api v0.10.0/go.mod h1:syysqD8Oews9oghLfCitMCuCPxxu4MErSJ6uw8ge9jk=
sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0=
sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL91fx0uKmUlUhrBk=
sigs.k8s.io/kustomize/kyaml v0.10.15 h1:dSLgG78KyaxN4HylPXdK+7zB3k7sW6q3IcCmcfKA+aI=
sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg=
sigs.k8s.io/kustomize/kyaml v0.12.0 h1:k08l8SLwnKa/eXXB5GW2/OnEc/4gJF90VDFebsOwqw4=
sigs.k8s.io/kustomize/kyaml v0.12.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
Expand Down
21 changes: 15 additions & 6 deletions internal/chart/helm_client.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package chart

import (
"log"
"os"

"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/release"
"k8s.io/cli-runtime/pkg/genericclioptions"
"log"
"os"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// HelmClient performs helm install and uninstall operations for provided application helm charts.
type HelmClient struct {
cfg *action.Configuration
namespace string
c client.Client
}

// TemplateValuer is an interface that permits types that implement it (e.g. Application, Job)
Expand All @@ -26,12 +27,12 @@ type TemplateValuer interface {
}

// NewHelmClient returns a HelmClient instance.
func NewHelmClient(namespace string) (*HelmClient, error) {
func NewHelmClient(namespace string, c client.Client) (*HelmClient, error) {
cfg, err := getActionConfig(namespace)
if err != nil {
return nil, err
}
return &HelmClient{cfg: cfg, namespace: namespace}, nil
return &HelmClient{cfg: cfg, namespace: namespace, c: c}, nil
}

func getActionConfig(namespace string) (*action.Configuration, error) {
Expand All @@ -51,7 +52,7 @@ func getActionConfig(namespace string) (*action.Configuration, error) {
return actionConfig, nil
}

// Option to perform additional configuration of action.Install before running a chart installation.
// InstallOption to perform additional configuration of action.Install before running a chart installation.
type InstallOption func(install *action.Install)

// UpdateChart checks if the app chart is already installed and performs "helm install" or "helm update" operation.
Expand All @@ -76,6 +77,10 @@ func (c HelmClient) UpdateChart(tv TemplateValuer, config ChartConfig, opts ...I
clientInstall := action.NewInstall(c.cfg)
clientInstall.ReleaseName = appName
clientInstall.Namespace = c.namespace
clientInstall.PostRenderer = &postRender{
namespace: c.namespace,
cli: c.c,
}
for _, opt := range opts {
opt(clientInstall)
}
Expand All @@ -86,6 +91,10 @@ func (c HelmClient) UpdateChart(tv TemplateValuer, config ChartConfig, opts ...I
}
updateClient := action.NewUpgrade(c.cfg)
updateClient.Namespace = c.namespace
updateClient.PostRenderer = &postRender{
namespace: c.namespace,
cli: c.c,
}
return updateClient.Run(appName, chrt, vals)
}

Expand Down
78 changes: 78 additions & 0 deletions internal/chart/post_render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package chart

import (
"bytes"
"context"
"strings"

"helm.sh/helm/v3/pkg/postrender"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/kustomize/api/krusty"
kTypes "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"
)

var _ postrender.PostRenderer = &postRender{}

type postRender struct {
cli client.Client
namespace string
}

func (p *postRender) Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) {

var configMapList v1.ConfigMapList
opts := &client.ListOptions{Namespace: p.namespace}
if err := p.cli.List(context.Background(), &configMapList, opts); err != nil {
return nil, err
}

fs := filesys.MakeFsInMemory()
if err := fs.Mkdir(p.namespace); err != nil {
return nil, err
}

var postrenderFound bool
for _, cm := range configMapList.Items {
if !strings.HasSuffix(cm.Name, "-postrender") {
continue
}
postrenderFound = true

for k, v := range cm.Data {
fileName := p.namespace + "/" + k
if err := fs.WriteFile(fileName, []byte(v)); err != nil {
return nil, err
}
}
}

// return original manifests, otherwise begin postrender
if !postrenderFound {
return renderedManifests, nil
}

if err := fs.WriteFile(p.namespace+"/app.yaml", renderedManifests.Bytes()); err != nil {
return nil, err
}

kustomizer := krusty.MakeKustomizer(&krusty.Options{
PluginConfig: &kTypes.PluginConfig{
HelmConfig: kTypes.HelmConfig{
Enabled: true,
Command: "helm",
},
},
})

result, err := kustomizer.Run(fs, p.namespace)
if err != nil {
return nil, err
}
y, err := result.AsYaml()
if err != nil {
return nil, err
}
return bytes.NewBuffer(y), nil
}
73 changes: 73 additions & 0 deletions internal/chart/post_render_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package chart

import (
"bytes"
_ "embed"
"fmt"
"testing"

"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

//go:embed testdata/render_yamls/prerendered-manifests.yaml
var prerender []byte

//go:embed testdata/render_yamls/kustomization.yaml
var kustomizationYaml string

//go:embed testdata/render_yamls/nodeaffinity-patch.yaml
var nodeaffinityPatchYaml string

//go:embed testdata/render_yamls/nodeaffinity-postrender.yaml
var nodeaffinityPostrender string

func TestPostRenderRun(t *testing.T) {
tc := []struct {
name string
configmap corev1.ConfigMap
expected string
}{
{
name: "postrender not found",
configmap: corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "some-other-configmap",
Namespace: "fake",
},
},
expected: string(prerender),
},
{
name: "postrender found, patch nodeAffinity",
configmap: corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "nodeaffinity-postrender",
Namespace: "fake",
},
Data: map[string]string{
"kustomization.yaml": kustomizationYaml,
"patch.yaml": nodeaffinityPatchYaml,
},
},
expected: nodeaffinityPostrender,
},
}
for _, tt := range tc {
t.Run(tt.name, func(t *testing.T) {
client := fake.NewClientBuilder()
client.WithObjects(&tt.configmap)

pr := postRender{
namespace: "fake",
cli: client.Build(),
}
result, err := pr.Run(bytes.NewBuffer(prerender))
fmt.Println(result.String())
require.Nil(t, err)
require.Equal(t, tt.expected, result.String())
})
}
}
7 changes: 7 additions & 0 deletions internal/chart/testdata/render_yamls/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resources:
- app.yaml
patches:
- path: patch.yaml
target:
kind: Deployment
name: ".*"
16 changes: 16 additions & 0 deletions internal/chart/testdata/render_yamls/nodeaffinity-patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: doesnotmatter
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: asdf
operator: In
values:
- asdf
Loading