Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 controllers/clustersummary_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ func (r *ClusterSummaryReconciler) reconcileDelete(
r.cleanMaps(clusterSummaryScope)

manager := getManager()
manager.stopStaleWatchForTemplateResourceRef(clusterSummaryScope.ClusterSummary, true)
manager.stopStaleWatchForTemplateResourceRef(ctx, clusterSummaryScope.ClusterSummary, true)

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

Expand Down Expand Up @@ -1342,7 +1342,7 @@ func (r *ClusterSummaryReconciler) startWatcherForTemplateResourceRefs(ctx conte
}
}

manager.stopStaleWatchForTemplateResourceRef(clusterSummary, false)
manager.stopStaleWatchForTemplateResourceRef(ctx, clusterSummary, false)
return nil
}

Expand Down
12 changes: 6 additions & 6 deletions controllers/clustersummary_watchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,12 @@ func (m *manager) startWatcherForTemplateResourceRef(ctx context.Context, gvk sc

var err error
// If namespace is not defined, default to cluster namespace
resource.Namespace, err = getTemplateResourceNamespace(clusterSummary, ref)
resource.Namespace, err = getTemplateResourceNamespace(ctx, clusterSummary, ref)
if err != nil {
return err
}

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

consumer := &corev1.ObjectReference{
APIVersion: configv1beta1.GroupVersion.Group,
Expand All @@ -273,12 +273,12 @@ func (m *manager) stopStaleWatchForTemplateResourceRef(clusterSummary *configv1b
for i := range clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs {
resource := &clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i].Resource
var err error
resource.Namespace, err = getTemplateResourceNamespace(clusterSummary,
resource.Namespace, err = getTemplateResourceNamespace(ctx, clusterSummary,
&clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i])
if err != nil {
continue
}
resource.Name, _ = getTemplateResourceName(clusterSummary,
resource.Name, _ = getTemplateResourceName(ctx, clusterSummary,
&clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i])

currentResources[*resource] = true
Expand Down
90 changes: 12 additions & 78 deletions controllers/templateresourcedef_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,100 +17,34 @@ limitations under the License.
package controllers

import (
"bytes"
"context"
"fmt"
"text/template"

apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

configv1beta1 "github.com/projectsveltos/addon-controller/api/v1beta1"
"github.com/projectsveltos/libsveltos/lib/funcmap"
"github.com/projectsveltos/libsveltos/lib/k8s_utils"
libsveltostemplate "github.com/projectsveltos/libsveltos/lib/template"
)

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

namespace := ref.Resource.Namespace
if namespace == "" {
// Use cluster namespace
return clusterSummary.Spec.ClusterNamespace, nil
}

// Accept namespaces that are templates
templateName := getTemplateName(clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName,
string(clusterSummary.Spec.ClusterType))
tmpl, err := template.New(templateName).Option("missingkey=error").Funcs(
funcmap.SveltosFuncMap(funcmap.HasTextTemplateAnnotation(clusterSummary.Annotations))).Parse(ref.Resource.Namespace)
if err != nil {
return "", err
}

var buffer bytes.Buffer

// Cluster namespace and name can be used to instantiate the name of the resource that
// needs to be fetched from the management cluster. Defined an unstructured with namespace and name set
u := &unstructured.Unstructured{}
u.SetNamespace(clusterSummary.Spec.ClusterNamespace)
u.SetName(clusterSummary.Spec.ClusterName)
u.SetKind(string(clusterSummary.Spec.ClusterType))

if err := tmpl.Execute(&buffer,
struct {
Cluster map[string]interface{}
// deprecated. This used to be original format which was different than rest of templating
ClusterNamespace, ClusterName string
}{
Cluster: u.UnstructuredContent(),
ClusterNamespace: clusterSummary.Spec.ClusterNamespace,
ClusterName: clusterSummary.Spec.ClusterName}); err != nil {
return "", fmt.Errorf("error executing template: %w", err)
}
return buffer.String(), nil
return libsveltostemplate.GetReferenceResourceNamespace(ctx, getManagementClusterClient(),
clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName, ref.Resource.Namespace,
clusterSummary.Spec.ClusterType)
}

// Resources referenced in the management cluster can have their name expressed in function
// of cluster information:
// clusterNamespace => .Cluster.metadata.namespace
// clusterName => .Cluster.metadata.name
// clusterType => .Cluster.kind
func getTemplateResourceName(clusterSummary *configv1beta1.ClusterSummary,
// of cluster field
func getTemplateResourceName(ctx context.Context, clusterSummary *configv1beta1.ClusterSummary,
ref *configv1beta1.TemplateResourceRef) (string, error) {

// Accept name that are templates
templateName := getTemplateName(clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName,
string(clusterSummary.Spec.ClusterType))
tmpl, err := template.New(templateName).Option("missingkey=error").Funcs(
funcmap.SveltosFuncMap(funcmap.HasTextTemplateAnnotation(clusterSummary.Annotations))).Parse(ref.Resource.Name)
if err != nil {
return "", err
}

var buffer bytes.Buffer

// Cluster namespace and name can be used to instantiate the name of the resource that
// needs to be fetched from the management cluster. Defined an unstructured with namespace and name set
u := &unstructured.Unstructured{}
u.SetNamespace(clusterSummary.Spec.ClusterNamespace)
u.SetName(clusterSummary.Spec.ClusterName)
u.SetKind(string(clusterSummary.Spec.ClusterType))

if err := tmpl.Execute(&buffer,
struct {
Cluster map[string]interface{}
// deprecated. This used to be original format which was different than rest of templating
ClusterNamespace, ClusterName string
}{
Cluster: u.UnstructuredContent(),
ClusterNamespace: clusterSummary.Spec.ClusterNamespace,
ClusterName: clusterSummary.Spec.ClusterName}); err != nil {
return "", fmt.Errorf("error executing template: %w", err)
}
return buffer.String(), nil
return libsveltostemplate.GetReferenceResourceName(ctx, getManagementClusterClient(),
clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName, ref.Resource.Name,
clusterSummary.Spec.ClusterType)
}

// collectTemplateResourceRefs collects clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs
Expand All @@ -128,11 +62,11 @@ func collectTemplateResourceRefs(ctx context.Context, clusterSummary *configv1be
for i := range clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs {
ref := clusterSummary.Spec.ClusterProfileSpec.TemplateResourceRefs[i]
var err error
ref.Resource.Namespace, err = getTemplateResourceNamespace(clusterSummary, &ref)
ref.Resource.Namespace, err = getTemplateResourceNamespace(ctx, clusterSummary, &ref)
if err != nil {
return nil, err
}
ref.Resource.Name, err = getTemplateResourceName(clusterSummary, &ref)
ref.Resource.Name, err = getTemplateResourceName(ctx, clusterSummary, &ref)
if err != nil {
return nil, err
}
Expand Down
93 changes: 86 additions & 7 deletions controllers/templateresourcedef_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ limitations under the License.
package controllers_test

import (
"context"
"fmt"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand All @@ -32,6 +35,8 @@ import (
var _ = Describe("TemplateResourceDef utils ", func() {
var cluster *clusterv1.Cluster
var namespace string
var labelKey, labelValue string
var annotationKey, annotationValue string

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

namespace = randomString()

ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}

Expect(testEnv.Create(context.TODO(), ns)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv.Client, ns)).To(Succeed())

labelKey = randomString()
labelValue = randomString()
annotationKey = randomString()
annotationValue = randomString()
cluster = &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: upstreamClusterNamePrefix + randomString(),
Namespace: namespace,
Labels: map[string]string{
randomString(): randomString(),
labelKey: labelValue,
},
Annotations: map[string]string{
annotationKey: annotationValue,
},
},
}

Expect(testEnv.Create(context.TODO(), cluster)).To(Succeed())
Expect(waitForObject(context.TODO(), testEnv.Client, cluster)).To(Succeed())
})

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

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

It("GetTemplateResourceName returns the correct name (uses cluster label)", func() {
name := fmt.Sprintf("{{ index .Cluster.metadata.labels %q }}-{{ index .Cluster.metadata.annotations %q }}",
labelKey, annotationKey)
ref := &configv1beta1.TemplateResourceRef{
Resource: corev1.ObjectReference{
Name: name,
},
Identifier: randomString(),
}

clusterSummary := &configv1beta1.ClusterSummary{
ObjectMeta: metav1.ObjectMeta{
Name: randomString(),
},
Spec: configv1beta1.ClusterSummarySpec{
ClusterNamespace: cluster.Namespace,
ClusterName: cluster.Name,
ClusterType: libsveltosv1beta1.ClusterTypeCapi,
},
}

value, err := controllers.GetTemplateResourceName(context.TODO(), clusterSummary, ref)
Expect(err).To(BeNil())
Expect(value).To(Equal(fmt.Sprintf("%s-%s", labelValue, annotationValue)))
})

It("GetTemplateResourceNamespace returns the correct namespace (uses Cluster)", func() {
ref := &configv1beta1.TemplateResourceRef{
Resource: corev1.ObjectReference{
Expand All @@ -94,7 +144,7 @@ var _ = Describe("TemplateResourceDef utils ", func() {
},
}

value, err := controllers.GetTemplateResourceName(clusterSummary, ref)
value, err := controllers.GetTemplateResourceName(context.TODO(), clusterSummary, ref)
Expect(err).To(BeNil())
Expect(value).To(Equal(cluster.Namespace + "-" + cluster.Name))
})
Expand All @@ -118,12 +168,12 @@ var _ = Describe("TemplateResourceDef utils ", func() {
},
}

value, err := controllers.GetTemplateResourceNamespace(clusterSummary, ref)
value, err := controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
Expect(err).To(BeNil())
Expect(value).To(Equal(cluster.Namespace))

ref.Resource.Namespace = randomString()
value, err = controllers.GetTemplateResourceNamespace(clusterSummary, ref)
value, err = controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
Expect(err).To(BeNil())
Expect(value).To(Equal(ref.Resource.Namespace))
})
Expand All @@ -148,14 +198,43 @@ var _ = Describe("TemplateResourceDef utils ", func() {
},
}

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

ref.Resource.Namespace = randomString()
value, err = controllers.GetTemplateResourceNamespace(clusterSummary, ref)
value, err = controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
Expect(err).To(BeNil())
Expect(value).To(Equal(ref.Resource.Namespace))
})

It("GetTemplateResourceNamespace returns the correct namespace (template version with labels)", func() {
ref := &configv1beta1.TemplateResourceRef{
Resource: corev1.ObjectReference{
Name: randomString(),
Namespace: fmt.Sprintf("{{ index .Cluster.metadata.labels %q }}", labelKey),
},
Identifier: randomString(),
}

clusterSummary := &configv1beta1.ClusterSummary{
ObjectMeta: metav1.ObjectMeta{
Name: randomString(),
},
Spec: configv1beta1.ClusterSummarySpec{
ClusterNamespace: cluster.Namespace,
ClusterName: cluster.Name,
ClusterType: libsveltosv1beta1.ClusterTypeCapi,
},
}

value, err := controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
Expect(err).To(BeNil())
Expect(value).To(Equal(labelValue))

ref.Resource.Namespace = randomString()
value, err = controllers.GetTemplateResourceNamespace(context.TODO(), clusterSummary, ref)
Expect(err).To(BeNil())
Expect(value).To(Equal(ref.Resource.Namespace))
})
})