Skip to content

Commit

Permalink
Add ownerReference on managed Templates
Browse files Browse the repository at this point in the history
  • Loading branch information
eromanova committed Nov 8, 2024
1 parent 18a0b62 commit 955ccfc
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 256 deletions.
16 changes: 0 additions & 16 deletions api/v1alpha1/clustertemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@
package v1alpha1

import (
"context"
"fmt"

"github.com/Masterminds/semver/v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
Expand Down Expand Up @@ -110,20 +108,6 @@ func (t *ClusterTemplate) GetCommonStatus() *TemplateStatusCommon {
return &t.Status.TemplateStatusCommon
}

// IsOrphaned checks whether the Template is orphaned or not.
func (t *ClusterTemplate) IsOrphaned(ctx context.Context, cl client.Client) (bool, error) {
list := new(ClusterTemplateChainList)
if err := cl.List(ctx, list, client.InNamespace(t.Namespace), client.MatchingFields{SupportedTemplateKey: t.Name}); err != nil {
return false, fmt.Errorf("failed to list %s: %w", list.GroupVersionKind(), err)
}
for _, chain := range list.Items {
if chain.DeletionTimestamp == nil {
return false, nil
}
}
return true, nil
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortName=clustertmpl
Expand Down
7 changes: 0 additions & 7 deletions api/v1alpha1/providertemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
package v1alpha1

import (
"context"
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// ProviderTemplateKind denotes the providertemplate resource Kind.
Expand Down Expand Up @@ -70,11 +68,6 @@ func (t *ProviderTemplate) GetCommonStatus() *TemplateStatusCommon {
return &t.Status.TemplateStatusCommon
}

// IsOrphaned checks whether the Template is orphaned or not.
func (*ProviderTemplate) IsOrphaned(_ context.Context, _ client.Client) (bool, error) {
return false, nil
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortName=providertmpl,scope=Cluster
Expand Down
16 changes: 0 additions & 16 deletions api/v1alpha1/servicetemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@
package v1alpha1

import (
"context"
"fmt"

"github.com/Masterminds/semver/v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
Expand Down Expand Up @@ -87,20 +85,6 @@ func (t *ServiceTemplate) GetCommonStatus() *TemplateStatusCommon {
return &t.Status.TemplateStatusCommon
}

// IsOrphaned checks whether the Template is orphaned or not.
func (t *ServiceTemplate) IsOrphaned(ctx context.Context, cl client.Client) (bool, error) {
list := new(ServiceTemplateChainList)
if err := cl.List(ctx, list, client.InNamespace(t.Namespace), client.MatchingFields{SupportedTemplateKey: t.Name}); err != nil {
return false, fmt.Errorf("failed to list %s: %w", list.GroupVersionKind(), err)
}
for _, chain := range list.Items {
if chain.DeletionTimestamp == nil {
return false, nil
}
}
return true, nil
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortName=svctmpl
Expand Down
2 changes: 0 additions & 2 deletions api/v1alpha1/templatechain_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

package v1alpha1

const TemplateChainFinalizer = "hmc.mirantis.com/template-chain"

// TemplateChainSpec defines the observed state of TemplateChain
type TemplateChainSpec struct {
// SupportedTemplates is the list of supported Templates definitions and all available upgrade sequences for it.
Expand Down
3 changes: 2 additions & 1 deletion internal/controller/multiclusterservice_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,9 @@ var _ = Describe("MultiClusterService Controller", func() {
It("should successfully reconcile the resource", func() {
By("reconciling ServiceTemplate used by MultiClusterService")
templateReconciler := TemplateReconciler{
Client: k8sClient,
Client: mgrClient,
downloadHelmChartFunc: fakeDownloadHelmChartFunc,
templateKind: hmc.ServiceTemplateKind,
}
serviceTemplateReconciler := &ServiceTemplateReconciler{TemplateReconciler: templateReconciler}
_, err := serviceTemplateReconciler.Reconcile(ctx, reconcile.Request{NamespacedName: serviceTemplateRef})
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ var _ = BeforeSuite(func() {
})
Expect(err).NotTo(HaveOccurred())
mgrClient = mgr.GetClient()
Expect(mgr).NotTo(BeNil())
Expect(mgrClient).NotTo(BeNil())

err = hmcmirantiscomv1alpha1.SetupIndexers(ctx, mgr)
Expect(err).NotTo(HaveOccurred())
Expand Down
107 changes: 104 additions & 3 deletions internal/controller/template_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
Expand All @@ -51,10 +52,11 @@ const (
// TemplateReconciler reconciles a *Template object
type TemplateReconciler struct {
client.Client

downloadHelmChartFunc func(context.Context, *sourcev1.Artifact) (*chart.Chart, error)

SystemNamespace string
SystemNamespace string
templateKind string

DefaultRegistryConfig helm.DefaultRegistryConfig
}

Expand Down Expand Up @@ -85,6 +87,16 @@ func (r *ClusterTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, err
}

changed, err := r.setTemplateChainOwnership(ctx, clusterTemplate)
if err != nil {
l.Error(err, "Failed to set OwnerReferences")
return ctrl.Result{}, err
}
if changed {
l.Info("Updating OwnerReferences with associated ClusterTemplateChain")
return ctrl.Result{RequeueAfter: DefaultRequeueInterval}, r.Update(ctx, clusterTemplate)
}

result, err := r.ReconcileTemplate(ctx, clusterTemplate)
if err != nil {
l.Error(err, "failed to reconcile template")
Expand Down Expand Up @@ -118,6 +130,17 @@ func (r *ServiceTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Requ
l.Error(err, "Failed to get ServiceTemplate")
return ctrl.Result{}, err
}

changed, err := r.setTemplateChainOwnership(ctx, serviceTemplate)
if err != nil {
l.Error(err, "Failed to set OwnerReferences")
return ctrl.Result{}, err
}
if changed {
l.Info("Updating OwnerReferences with associated ServiceTemplateChain")
return ctrl.Result{RequeueAfter: DefaultRequeueInterval}, r.Update(ctx, serviceTemplate)
}

return r.ReconcileTemplate(ctx, serviceTemplate)
}

Expand Down Expand Up @@ -169,7 +192,6 @@ type templateCommon interface {
GetHelmSpec() *hmc.HelmSpec
GetCommonStatus() *hmc.TemplateStatusCommon
FillStatusWithProviders(map[string]string) error
IsOrphaned(context.Context, client.Client) (bool, error)
}

func (r *TemplateReconciler) ReconcileTemplate(ctx context.Context, template templateCommon) (ctrl.Result, error) {
Expand Down Expand Up @@ -273,6 +295,42 @@ func (r *TemplateReconciler) ReconcileTemplate(ctx context.Context, template tem
return ctrl.Result{}, r.updateStatus(ctx, template, "")
}

func (r *TemplateReconciler) setTemplateChainOwnership(ctx context.Context, template templateCommon) (changed bool, err error) {
if template.GetNamespace() == r.SystemNamespace {
return false, nil
}

opts := &client.ListOptions{
Namespace: template.GetNamespace(),
FieldSelector: fields.SelectorFromSet(fields.Set{hmc.SupportedTemplateKey: template.GetName()}),
}
switch r.templateKind {
case hmc.ClusterTemplateKind:
chainList := &hmc.ClusterTemplateChainList{}
if err = r.List(ctx, chainList, opts); err != nil {
return false, err
}
for _, chain := range chainList.Items {
if utils.AddOwnerReference(template, &chain) {
changed = true
}
}
case hmc.ServiceTemplateKind:
chainList := &hmc.ServiceTemplateChainList{}
if err = r.List(ctx, chainList, opts); err != nil {
return false, err
}
for _, chain := range chainList.Items {
if utils.AddOwnerReference(template, &chain) {
changed = true
}
}
default:
return false, fmt.Errorf("invalid Template kind %s. Supported kinds are %s and %s", r.templateKind, hmc.ClusterTemplateKind, hmc.ServiceTemplateKind)
}
return changed, nil
}

func templateManagedByHMC(template templateCommon) bool {
return template.GetLabels()[hmc.HMCManagedLabelKey] == hmc.HMCManagedLabelValue
}
Expand Down Expand Up @@ -427,20 +485,63 @@ func (r *ClusterTemplateReconciler) validateCompatibilityAttrs(ctx context.Conte

// SetupWithManager sets up the controller with the Manager.
func (r *ClusterTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error {
r.templateKind = hmc.ClusterTemplateKind
return ctrl.NewControllerManagedBy(mgr).
For(&hmc.ClusterTemplate{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Watches(&hmc.ClusterTemplateChain{},
handler.EnqueueRequestsFromMapFunc(func(_ context.Context, o client.Object) []ctrl.Request {
chain, ok := o.(*hmc.ClusterTemplateChain)
if !ok {
return nil
}
return r.getRequestsForSupportedTemplates(chain)
}),
builder.WithPredicates(predicate.Funcs{
UpdateFunc: func(event.UpdateEvent) bool { return false },
GenericFunc: func(event.GenericEvent) bool { return false },
}),
).
Complete(r)
}

// SetupWithManager sets up the controller with the Manager.
func (r *ServiceTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error {
r.templateKind = hmc.ServiceTemplateKind
return ctrl.NewControllerManagedBy(mgr).
For(&hmc.ServiceTemplate{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Watches(&hmc.ServiceTemplateChain{},
handler.EnqueueRequestsFromMapFunc(func(_ context.Context, o client.Object) []ctrl.Request {
chain, ok := o.(*hmc.ServiceTemplateChain)
if !ok {
return nil
}
return r.getRequestsForSupportedTemplates(chain)
}),
builder.WithPredicates(predicate.Funcs{
UpdateFunc: func(event.UpdateEvent) bool { return false },
GenericFunc: func(event.GenericEvent) bool { return false },
}),
).
Complete(r)
}

func (r *TemplateReconciler) getRequestsForSupportedTemplates(chain templateChain) []ctrl.Request {
if chain.GetNamespace() == r.SystemNamespace {
return []ctrl.Request{}
}
supportedTemplates := chain.GetSpec().SupportedTemplates
requests := make([]ctrl.Request, 0, len(supportedTemplates))
for _, template := range supportedTemplates {
requests = append(requests, ctrl.Request{
NamespacedName: types.NamespacedName{Name: template.Name},
})
}
return requests
}

// SetupWithManager sets up the controller with the Manager.
func (r *ProviderTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error {
r.templateKind = hmc.ProviderTemplateKind
return ctrl.NewControllerManagedBy(mgr).
For(&hmc.ProviderTemplate{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Watches(&hmc.Release{},
Expand Down
6 changes: 5 additions & 1 deletion internal/controller/template_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,19 @@ var _ = Describe("Template Controller", func() {
downloadHelmChartFunc: fakeDownloadHelmChartFunc,
}
By("Reconciling the ClusterTemplate resource")
templateReconciler.templateKind = hmcmirantiscomv1alpha1.ClusterTemplateKind
clusterTemplateReconciler := &ClusterTemplateReconciler{TemplateReconciler: templateReconciler}
_, err := clusterTemplateReconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
Expect(err).NotTo(HaveOccurred())

By("Reconciling the ServiceTemplate resource")
templateReconciler.templateKind = hmcmirantiscomv1alpha1.ServiceTemplateKind
serviceTemplateReconciler := &ServiceTemplateReconciler{TemplateReconciler: templateReconciler}
_, err = serviceTemplateReconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
Expect(err).NotTo(HaveOccurred())

By("Reconciling the ProviderTemplate resource")
templateReconciler.templateKind = hmcmirantiscomv1alpha1.ProviderTemplateKind
providerTemplateReconciler := &ProviderTemplateReconciler{TemplateReconciler: templateReconciler}
_, err = providerTemplateReconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
Expect(err).NotTo(HaveOccurred())
Expand Down Expand Up @@ -301,8 +304,9 @@ var _ = Describe("Template Controller", func() {

By("Reconciling the cluster template")
clusterTemplateReconciler := &ClusterTemplateReconciler{TemplateReconciler: TemplateReconciler{
Client: k8sClient,
Client: mgrClient,
downloadHelmChartFunc: fakeDownloadHelmChartFunc,
templateKind: hmcmirantiscomv1alpha1.ClusterTemplateKind,
}}
_, err := clusterTemplateReconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{
Name: clusterTemplateName,
Expand Down
Loading

0 comments on commit 955ccfc

Please sign in to comment.