Skip to content

Commit 6b8876e

Browse files
committed
add new template function 'component' to kustomize controller
templates can use it to access the component which is triggering the current reconcile/generate; this function is in alpha state for now and might change in the future;
1 parent 698395f commit 6b8876e

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

pkg/component/context.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
type reconcilerNameContextKey struct{}
1616
type clientContextKey struct{}
17+
type componentContextKey struct{}
1718
type componentDigestContextKey struct{}
1819

1920
func newContext(ctx context.Context) *reconcileContext {
@@ -32,6 +33,10 @@ func (c *reconcileContext) WithClient(client cluster.Client) *reconcileContext {
3233
return &reconcileContext{Context: context.WithValue(c, clientContextKey{}, client)}
3334
}
3435

36+
func (c *reconcileContext) WithComponent(component Component) *reconcileContext {
37+
return &reconcileContext{Context: context.WithValue(c, componentContextKey{}, component)}
38+
}
39+
3540
func (c *reconcileContext) WithComponentDigest(componentDigest string) *reconcileContext {
3641
return &reconcileContext{Context: context.WithValue(c, componentDigestContextKey{}, componentDigest)}
3742
}
@@ -50,6 +55,13 @@ func ClientFromContext(ctx context.Context) (cluster.Client, error) {
5055
return nil, fmt.Errorf("client not found in context")
5156
}
5257

58+
func ComponentFromContext(ctx context.Context) (Component, error) {
59+
if component, ok := ctx.Value(componentContextKey{}).(Component); ok {
60+
return component, nil
61+
}
62+
return nil, fmt.Errorf("component not found in context")
63+
}
64+
5365
func ComponentDigestFromContext(ctx context.Context) (string, error) {
5466
if componentDigest, ok := ctx.Value(componentDigestContextKey{}).(string); ok {
5567
return componentDigest, nil

pkg/component/target.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,10 @@ func (t *reconcileTarget[T]) Reconcile(ctx context.Context, component T) (bool,
108108
componentDigest := calculateComponentDigest(component)
109109

110110
// render manifests
111-
// TODO: sometimes the generator needs more information about the rendered component (such as the component's name or namespace);
112-
// as of now, components have to help themselves through implementing post-read hooks; to simplify this for components,
113-
// we could expose the component (full object or maybe just its metadata) via the generate context;
114-
// another option would be to have a special NamespacedName reuse type, where the namespace part would be auto-defaulted
115-
// by the framework (similar to the auto-loading of configmap/secret references)
116111
generateCtx := newContext(ctx).
117112
WithReconcilerName(t.reconcilerName).
118113
WithClient(t.client).
114+
WithComponent(component).
119115
WithComponentDigest(componentDigest)
120116
objects, err := t.resourceGenerator.Generate(generateCtx, namespace, name, component.GetSpec())
121117
if err != nil {

pkg/manifests/kustomize/generator.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"io/fs"
1313
"os"
1414
"path/filepath"
15+
"reflect"
1516
"strings"
1617
"text/template"
1718

@@ -106,7 +107,7 @@ func NewKustomizeGenerator(fsys fs.FS, kustomizationPath string, templateSuffix
106107
Funcs(templatex.FuncMapForTemplate(t)).
107108
Funcs(templatex.FuncMapForLocalClient(client)).
108109
Funcs(templatex.FuncMapForClient(nil)).
109-
Funcs(funcMapForGenerateContext(nil, "", ""))
110+
Funcs(funcMapForGenerateContext(nil, nil, "", ""))
110111
} else {
111112
t = t.New(name)
112113
}
@@ -159,6 +160,10 @@ func (g *KustomizeGenerator) Generate(ctx context.Context, namespace string, nam
159160
if err != nil {
160161
return nil, err
161162
}
163+
component, err := component.ComponentFromContext(ctx)
164+
if err != nil {
165+
return nil, err
166+
}
162167

163168
data := parameters.ToUnstructured()
164169
fsys := kustfsys.MakeFsInMemory()
@@ -178,7 +183,7 @@ func (g *KustomizeGenerator) Generate(ctx context.Context, namespace string, nam
178183
}
179184
t0.Option("missingkey=zero").
180185
Funcs(templatex.FuncMapForClient(client)).
181-
Funcs(funcMapForGenerateContext(client, namespace, name))
186+
Funcs(funcMapForGenerateContext(client, component, namespace, name))
182187
}
183188
var buf bytes.Buffer
184189
if err := t0.ExecuteTemplate(&buf, t.Name(), data); err != nil {
@@ -234,14 +239,28 @@ func (g *KustomizeGenerator) Generate(ctx context.Context, namespace string, nam
234239
return objects, nil
235240
}
236241

237-
func funcMapForGenerateContext(client cluster.Client, namespace string, name string) template.FuncMap {
242+
func funcMapForGenerateContext(client cluster.Client, component component.Component, namespace string, name string) template.FuncMap {
238243
// TODO: add accessors for Kubernetes version etc.
239244
return template.FuncMap{
245+
// TODO: maybe it would it be better to convert component to unstructured;
246+
// then calling methods would no longer be possible, and attributes would be in lowercase
247+
"component": makeFuncData(component),
240248
"namespace": func() string { return namespace },
241249
"name": func() string { return name },
242250
}
243251
}
244252

253+
func makeFuncData(data any) any {
254+
if data == nil {
255+
return func() any { return nil }
256+
}
257+
ival := reflect.ValueOf(data)
258+
ityp := ival.Type()
259+
ftyp := reflect.FuncOf(nil, []reflect.Type{ityp}, false)
260+
fval := reflect.MakeFunc(ftyp, func(args []reflect.Value) []reflect.Value { return []reflect.Value{ival} })
261+
return fval.Interface()
262+
}
263+
245264
func generateKustomization(fsys kustfsys.FileSystem) ([]byte, error) {
246265
var resources []string
247266

0 commit comments

Comments
 (0)