Skip to content

Commit 16cd044

Browse files
committed
(feat): TemplateResourceRefs template instantion
TemplateResourceRefs namespace/name can be expressed as template. This was possible even before this PR. Before this PR though only cluster namespace/name/kind were used to instantiate the template. Now any cluster field can be used.
1 parent 903c078 commit 16cd044

4 files changed

Lines changed: 106 additions & 93 deletions

File tree

controllers/clustersummary_controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ func (r *ClusterSummaryReconciler) reconcileDelete(
310310
r.cleanMaps(clusterSummaryScope)
311311

312312
manager := getManager()
313-
manager.stopStaleWatchForTemplateResourceRef(clusterSummaryScope.ClusterSummary, true)
313+
manager.stopStaleWatchForTemplateResourceRef(ctx, clusterSummaryScope.ClusterSummary, true)
314314

315315
logger.V(logs.LogInfo).Info("Reconcile delete success")
316316

@@ -1342,7 +1342,7 @@ func (r *ClusterSummaryReconciler) startWatcherForTemplateResourceRefs(ctx conte
13421342
}
13431343
}
13441344

1345-
manager.stopStaleWatchForTemplateResourceRef(clusterSummary, false)
1345+
manager.stopStaleWatchForTemplateResourceRef(ctx, clusterSummary, false)
13461346
return nil
13471347
}
13481348

controllers/clustersummary_watchers.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,12 @@ func (m *manager) startWatcherForTemplateResourceRef(ctx context.Context, gvk sc
155155

156156
var err error
157157
// If namespace is not defined, default to cluster namespace
158-
resource.Namespace, err = getTemplateResourceNamespace(clusterSummary, ref)
158+
resource.Namespace, err = getTemplateResourceNamespace(ctx, clusterSummary, ref)
159159
if err != nil {
160160
return err
161161
}
162162

163-
resource.Name, err = getTemplateResourceName(clusterSummary, ref)
163+
resource.Name, err = getTemplateResourceName(ctx, clusterSummary, ref)
164164
if err != nil {
165165
return err
166166
}
@@ -257,8 +257,8 @@ func (m *manager) stopStaleWatchForMgmtResource(currentResources map[corev1.Obje
257257
// It then stops any watchers that were previously set up to deliver notifications about those specific
258258
// resources to ClusterSummary.
259259
// Resources that are still included in the currentResources map will continue to be watched.
260-
func (m *manager) stopStaleWatchForTemplateResourceRef(clusterSummary *configv1beta1.ClusterSummary,
261-
removeAll bool) {
260+
func (m *manager) stopStaleWatchForTemplateResourceRef(ctx context.Context,
261+
clusterSummary *configv1beta1.ClusterSummary, removeAll bool) {
262262

263263
consumer := &corev1.ObjectReference{
264264
APIVersion: configv1beta1.GroupVersion.Group,
@@ -273,12 +273,12 @@ func (m *manager) stopStaleWatchForTemplateResourceRef(clusterSummary *configv1b
273273
for i := range clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs {
274274
resource := &clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i].Resource
275275
var err error
276-
resource.Namespace, err = getTemplateResourceNamespace(clusterSummary,
276+
resource.Namespace, err = getTemplateResourceNamespace(ctx, clusterSummary,
277277
&clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i])
278278
if err != nil {
279279
continue
280280
}
281-
resource.Name, _ = getTemplateResourceName(clusterSummary,
281+
resource.Name, _ = getTemplateResourceName(ctx, clusterSummary,
282282
&clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i])
283283

284284
currentResources[*resource] = true

controllers/templateresourcedef_utils.go

Lines changed: 12 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -17,100 +17,34 @@ limitations under the License.
1717
package controllers
1818

1919
import (
20-
"bytes"
2120
"context"
22-
"fmt"
23-
"text/template"
2421

2522
apierrors "k8s.io/apimachinery/pkg/api/errors"
2623
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2724
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2825

2926
configv1beta1 "github.com/projectsveltos/addon-controller/api/v1beta1"
30-
"github.com/projectsveltos/libsveltos/lib/funcmap"
3127
"github.com/projectsveltos/libsveltos/lib/k8s_utils"
28+
libsveltostemplate "github.com/projectsveltos/libsveltos/lib/template"
3229
)
3330

3431
// The TemplateResource namespace can be specified or it will inherit the cluster namespace
35-
func getTemplateResourceNamespace(clusterSummary *configv1beta1.ClusterSummary,
32+
func getTemplateResourceNamespace(ctx context.Context, clusterSummary *configv1beta1.ClusterSummary,
3633
ref *configv1beta1.TemplateResourceRef) (string, error) {
3734

38-
namespace := ref.Resource.Namespace
39-
if namespace == "" {
40-
// Use cluster namespace
41-
return clusterSummary.Spec.ClusterNamespace, nil
42-
}
43-
44-
// Accept namespaces that are templates
45-
templateName := getTemplateName(clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName,
46-
string(clusterSummary.Spec.ClusterType))
47-
tmpl, err := template.New(templateName).Option("missingkey=error").Funcs(
48-
funcmap.SveltosFuncMap(funcmap.HasTextTemplateAnnotation(clusterSummary.Annotations))).Parse(ref.Resource.Namespace)
49-
if err != nil {
50-
return "", err
51-
}
52-
53-
var buffer bytes.Buffer
54-
55-
// Cluster namespace and name can be used to instantiate the name of the resource that
56-
// needs to be fetched from the management cluster. Defined an unstructured with namespace and name set
57-
u := &unstructured.Unstructured{}
58-
u.SetNamespace(clusterSummary.Spec.ClusterNamespace)
59-
u.SetName(clusterSummary.Spec.ClusterName)
60-
u.SetKind(string(clusterSummary.Spec.ClusterType))
61-
62-
if err := tmpl.Execute(&buffer,
63-
struct {
64-
Cluster map[string]interface{}
65-
// deprecated. This used to be original format which was different than rest of templating
66-
ClusterNamespace, ClusterName string
67-
}{
68-
Cluster: u.UnstructuredContent(),
69-
ClusterNamespace: clusterSummary.Spec.ClusterNamespace,
70-
ClusterName: clusterSummary.Spec.ClusterName}); err != nil {
71-
return "", fmt.Errorf("error executing template: %w", err)
72-
}
73-
return buffer.String(), nil
35+
return libsveltostemplate.GetReferenceResourceNamespace(ctx, getManagementClusterClient(),
36+
clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName, ref.Resource.Namespace,
37+
clusterSummary.Spec.ClusterType)
7438
}
7539

7640
// Resources referenced in the management cluster can have their name expressed in function
77-
// of cluster information:
78-
// clusterNamespace => .Cluster.metadata.namespace
79-
// clusterName => .Cluster.metadata.name
80-
// clusterType => .Cluster.kind
81-
func getTemplateResourceName(clusterSummary *configv1beta1.ClusterSummary,
41+
// of cluster field
42+
func getTemplateResourceName(ctx context.Context, clusterSummary *configv1beta1.ClusterSummary,
8243
ref *configv1beta1.TemplateResourceRef) (string, error) {
8344

84-
// Accept name that are templates
85-
templateName := getTemplateName(clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName,
86-
string(clusterSummary.Spec.ClusterType))
87-
tmpl, err := template.New(templateName).Option("missingkey=error").Funcs(
88-
funcmap.SveltosFuncMap(funcmap.HasTextTemplateAnnotation(clusterSummary.Annotations))).Parse(ref.Resource.Name)
89-
if err != nil {
90-
return "", err
91-
}
92-
93-
var buffer bytes.Buffer
94-
95-
// Cluster namespace and name can be used to instantiate the name of the resource that
96-
// needs to be fetched from the management cluster. Defined an unstructured with namespace and name set
97-
u := &unstructured.Unstructured{}
98-
u.SetNamespace(clusterSummary.Spec.ClusterNamespace)
99-
u.SetName(clusterSummary.Spec.ClusterName)
100-
u.SetKind(string(clusterSummary.Spec.ClusterType))
101-
102-
if err := tmpl.Execute(&buffer,
103-
struct {
104-
Cluster map[string]interface{}
105-
// deprecated. This used to be original format which was different than rest of templating
106-
ClusterNamespace, ClusterName string
107-
}{
108-
Cluster: u.UnstructuredContent(),
109-
ClusterNamespace: clusterSummary.Spec.ClusterNamespace,
110-
ClusterName: clusterSummary.Spec.ClusterName}); err != nil {
111-
return "", fmt.Errorf("error executing template: %w", err)
112-
}
113-
return buffer.String(), nil
45+
return libsveltostemplate.GetReferenceResourceName(ctx, getManagementClusterClient(),
46+
clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName, ref.Resource.Name,
47+
clusterSummary.Spec.ClusterType)
11448
}
11549

11650
// collectTemplateResourceRefs collects clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs
@@ -128,11 +62,11 @@ func collectTemplateResourceRefs(ctx context.Context, clusterSummary *configv1be
12862
for i := range clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs {
12963
ref := clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i]
13064
var err error
131-
ref.Resource.Namespace, err = getTemplateResourceNamespace(clusterSummary, &ref)
65+
ref.Resource.Namespace, err = getTemplateResourceNamespace(ctx, clusterSummary, &ref)
13266
if err != nil {
13367
return nil, err
13468
}
135-
ref.Resource.Name, err = getTemplateResourceName(clusterSummary, &ref)
69+
ref.Resource.Name, err = getTemplateResourceName(ctx, clusterSummary, &ref)
13670
if err != nil {
13771
return nil, err
13872
}

controllers/templateresourcedef_utils_test.go

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ limitations under the License.
1717
package controllers_test
1818

1919
import (
20+
"context"
21+
"fmt"
22+
2023
. "github.com/onsi/ginkgo/v2"
2124
. "github.com/onsi/gomega"
2225

@@ -32,6 +35,8 @@ import (
3235
var _ = Describe("TemplateResourceDef utils ", func() {
3336
var cluster *clusterv1.Cluster
3437
var namespace string
38+
var labelKey, labelValue string
39+
var annotationKey, annotationValue string
3540

3641
BeforeEach(func() {
3742
var err error
@@ -40,15 +45,34 @@ var _ = Describe("TemplateResourceDef utils ", func() {
4045

4146
namespace = randomString()
4247

48+
ns := &corev1.Namespace{
49+
ObjectMeta: metav1.ObjectMeta{
50+
Name: namespace,
51+
},
52+
}
53+
54+
Expect(testEnv.Create(context.TODO(), ns)).To(Succeed())
55+
Expect(waitForObject(context.TODO(), testEnv.Client, ns)).To(Succeed())
56+
57+
labelKey = randomString()
58+
labelValue = randomString()
59+
annotationKey = randomString()
60+
annotationValue = randomString()
4361
cluster = &clusterv1.Cluster{
4462
ObjectMeta: metav1.ObjectMeta{
4563
Name: upstreamClusterNamePrefix + randomString(),
4664
Namespace: namespace,
4765
Labels: map[string]string{
48-
randomString(): randomString(),
66+
labelKey: labelValue,
67+
},
68+
Annotations: map[string]string{
69+
annotationKey: annotationValue,
4970
},
5071
},
5172
}
73+
74+
Expect(testEnv.Create(context.TODO(), cluster)).To(Succeed())
75+
Expect(waitForObject(context.TODO(), testEnv.Client, cluster)).To(Succeed())
5276
})
5377

5478
It("GetTemplateResourceName returns the correct name (uses ClusterNamespace and ClusterName)", func() {
@@ -70,11 +94,37 @@ var _ = Describe("TemplateResourceDef utils ", func() {
7094
},
7195
}
7296

73-
value, err := controllers.GetTemplateResourceName(clusterSummary, ref)
97+
value, err := controllers.GetTemplateResourceName(context.TODO(), clusterSummary, ref)
7498
Expect(err).To(BeNil())
7599
Expect(value).To(Equal(cluster.Namespace + "-" + cluster.Name))
76100
})
77101

102+
It("GetTemplateResourceName returns the correct name (uses cluster label)", func() {
103+
name := fmt.Sprintf("{{ index .Cluster.metadata.labels %q }}-{{ index .Cluster.metadata.annotations %q }}",
104+
labelKey, annotationKey)
105+
ref := &configv1beta1.TemplateResourceRef{
106+
Resource: corev1.ObjectReference{
107+
Name: name,
108+
},
109+
Identifier: randomString(),
110+
}
111+
112+
clusterSummary := &configv1beta1.ClusterSummary{
113+
ObjectMeta: metav1.ObjectMeta{
114+
Name: randomString(),
115+
},
116+
Spec: configv1beta1.ClusterSummarySpec{
117+
ClusterNamespace: cluster.Namespace,
118+
ClusterName: cluster.Name,
119+
ClusterType: libsveltosv1beta1.ClusterTypeCapi,
120+
},
121+
}
122+
123+
value, err := controllers.GetTemplateResourceName(context.TODO(), clusterSummary, ref)
124+
Expect(err).To(BeNil())
125+
Expect(value).To(Equal(fmt.Sprintf("%s-%s", labelValue, annotationValue)))
126+
})
127+
78128
It("GetTemplateResourceNamespace returns the correct namespace (uses Cluster)", func() {
79129
ref := &configv1beta1.TemplateResourceRef{
80130
Resource: corev1.ObjectReference{
@@ -94,7 +144,7 @@ var _ = Describe("TemplateResourceDef utils ", func() {
94144
},
95145
}
96146

97-
value, err := controllers.GetTemplateResourceName(clusterSummary, ref)
147+
value, err := controllers.GetTemplateResourceName(context.TODO(), clusterSummary, ref)
98148
Expect(err).To(BeNil())
99149
Expect(value).To(Equal(cluster.Namespace + "-" + cluster.Name))
100150
})
@@ -118,12 +168,12 @@ var _ = Describe("TemplateResourceDef utils ", func() {
118168
},
119169
}
120170

121-
value, err := controllers.GetTemplateResourceNamespace(clusterSummary, ref)
171+
value, err := controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
122172
Expect(err).To(BeNil())
123173
Expect(value).To(Equal(cluster.Namespace))
124174

125175
ref.Resource.Namespace = randomString()
126-
value, err = controllers.GetTemplateResourceNamespace(clusterSummary, ref)
176+
value, err = controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
127177
Expect(err).To(BeNil())
128178
Expect(value).To(Equal(ref.Resource.Namespace))
129179
})
@@ -148,14 +198,43 @@ var _ = Describe("TemplateResourceDef utils ", func() {
148198
},
149199
}
150200

151-
value, err := controllers.GetTemplateResourceNamespace(clusterSummary, ref)
201+
value, err := controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
152202
Expect(err).To(BeNil())
153203
Expect(value).To(Equal(cluster.Namespace + "-foo"))
154204

155205
ref.Resource.Namespace = randomString()
156-
value, err = controllers.GetTemplateResourceNamespace(clusterSummary, ref)
206+
value, err = controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
157207
Expect(err).To(BeNil())
158208
Expect(value).To(Equal(ref.Resource.Namespace))
159209
})
160210

211+
It("GetTemplateResourceNamespace returns the correct namespace (template version with labels)", func() {
212+
ref := &configv1beta1.TemplateResourceRef{
213+
Resource: corev1.ObjectReference{
214+
Name: randomString(),
215+
Namespace: fmt.Sprintf("{{ index .Cluster.metadata.labels %q }}", labelKey),
216+
},
217+
Identifier: randomString(),
218+
}
219+
220+
clusterSummary := &configv1beta1.ClusterSummary{
221+
ObjectMeta: metav1.ObjectMeta{
222+
Name: randomString(),
223+
},
224+
Spec: configv1beta1.ClusterSummarySpec{
225+
ClusterNamespace: cluster.Namespace,
226+
ClusterName: cluster.Name,
227+
ClusterType: libsveltosv1beta1.ClusterTypeCapi,
228+
},
229+
}
230+
231+
value, err := controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
232+
Expect(err).To(BeNil())
233+
Expect(value).To(Equal(labelValue))
234+
235+
ref.Resource.Namespace = randomString()
236+
value, err = controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
237+
Expect(err).To(BeNil())
238+
Expect(value).To(Equal(ref.Resource.Namespace))
239+
})
161240
})

0 commit comments

Comments
 (0)