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 authored and Kshatrix committed Nov 11, 2024
1 parent ab3f029 commit 55bf573
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 258 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 @@ -108,20 +106,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 @@ -68,11 +66,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
2 changes: 1 addition & 1 deletion internal/controller/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,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
1 change: 0 additions & 1 deletion internal/controller/template_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,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
157 changes: 18 additions & 139 deletions internal/controller/templatechain_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,14 @@ import (
"errors"
"fmt"

"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"

hmc "github.com/Mirantis/hmc/api/v1alpha1"
"github.com/Mirantis/hmc/internal/utils"
)

// TemplateChainReconciler reconciles a TemplateChain object
Expand Down Expand Up @@ -72,11 +66,7 @@ func (r *ClusterTemplateChainReconciler) Reconcile(ctx context.Context, req ctrl
return ctrl.Result{}, err
}

if !clusterTemplateChain.DeletionTimestamp.IsZero() {
l.Info("Deleting ClusterTemplateChain")
return r.Delete(ctx, clusterTemplateChain)
}
return r.Update(ctx, clusterTemplateChain)
return r.ReconcileTemplateChain(ctx, clusterTemplateChain)
}

func (r *ServiceTemplateChainReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
Expand All @@ -94,21 +84,13 @@ func (r *ServiceTemplateChainReconciler) Reconcile(ctx context.Context, req ctrl
return ctrl.Result{}, err
}

if !serviceTemplateChain.DeletionTimestamp.IsZero() {
l.Info("Deleting ServiceTemplateChain")
return r.Delete(ctx, serviceTemplateChain)
}
return r.Update(ctx, serviceTemplateChain)
return r.ReconcileTemplateChain(ctx, serviceTemplateChain)
}

func (r *TemplateChainReconciler) Update(ctx context.Context, templateChain templateChain) (ctrl.Result, error) {
func (r *TemplateChainReconciler) ReconcileTemplateChain(ctx context.Context, templateChain templateChain) (ctrl.Result, error) {
l := ctrl.LoggerFrom(ctx)

if controllerutil.AddFinalizer(templateChain, hmc.TemplateChainFinalizer) {
if err := r.Client.Update(ctx, templateChain); err != nil {
l.Error(err, "Failed to update TemplateChain finalizers")
return ctrl.Result{}, err
}
if templateChain.GetNamespace() == r.SystemNamespace {
return ctrl.Result{}, nil
}

Expand All @@ -117,10 +99,7 @@ func (r *TemplateChainReconciler) Update(ctx context.Context, templateChain temp
return ctrl.Result{}, fmt.Errorf("failed to get system templates: %w", err)
}

var (
errs error
keepTemplate = make(map[string]struct{}, len(templateChain.GetSpec().SupportedTemplates))
)
var errs error
for _, supportedTemplate := range templateChain.GetSpec().SupportedTemplates {
meta := metav1.ObjectMeta{
Name: supportedTemplate.Name,
Expand All @@ -129,7 +108,6 @@ func (r *TemplateChainReconciler) Update(ctx context.Context, templateChain temp
hmc.HMCManagedLabelKey: hmc.HMCManagedLabelValue,
},
}
keepTemplate[supportedTemplate.Name] = struct{}{}

source, found := systemTemplates[supportedTemplate.Name]
if !found {
Expand Down Expand Up @@ -159,33 +137,24 @@ func (r *TemplateChainReconciler) Update(ctx context.Context, templateChain temp
return ctrl.Result{}, fmt.Errorf("invalid TemplateChain kind. Supported kinds are %s and %s", hmc.ClusterTemplateChainKind, hmc.ServiceTemplateChainKind)
}

if err := r.Create(ctx, target); err == nil {
l.Info(r.templateKind+" was successfully created", "template namespace", templateChain.GetNamespace(), "template name", supportedTemplate.Name)
operation, err := ctrl.CreateOrUpdate(ctx, r.Client, target, func() error {
utils.AddOwnerReference(target, templateChain)
return nil
})
if err != nil {
errs = errors.Join(errs, err)
continue
}

if !apierrors.IsAlreadyExists(err) {
errs = errors.Join(errs, err)
if operation == controllerutil.OperationResultCreated {
l.Info(r.templateKind+" was successfully created", "template namespace", templateChain.GetNamespace(), "template name", supportedTemplate.Name)
}
if operation == controllerutil.OperationResultUpdated {
l.Info("Successfully updated OwnerReference on "+r.templateKind, "template namespace", templateChain.GetNamespace(), "template name", supportedTemplate.Name)
}
}
if errs != nil {
return ctrl.Result{}, errs
}

return ctrl.Result{}, r.removeOrphanedTemplates(ctx, templateChain)
}

func (r *TemplateChainReconciler) Delete(ctx context.Context, chain templateChain) (ctrl.Result, error) {
if err := r.removeOrphanedTemplates(ctx, chain); err != nil {
return ctrl.Result{}, err
}

// Removing finalizer in the end of cleanup
if controllerutil.RemoveFinalizer(chain, hmc.TemplateChainFinalizer) {
ctrl.LoggerFrom(ctx).Info("Removing TemplateChain finalizer")
return ctrl.Result{}, r.Client.Update(ctx, chain)
}
return ctrl.Result{}, nil
return ctrl.Result{}, errs
}

func (r *TemplateChainReconciler) getSystemTemplates(ctx context.Context) (systemTemplates map[string]templateCommon, _ error) {
Expand Down Expand Up @@ -229,39 +198,6 @@ func (r *TemplateChainReconciler) getTemplates(ctx context.Context, templateKind
return templates, nil
}

func (r TemplateChainReconciler) removeOrphanedTemplates(ctx context.Context, chain templateChain) error {
l := log.FromContext(ctx)

managedTemplates, err := r.getTemplates(ctx, r.templateKind, &client.ListOptions{
Namespace: chain.GetNamespace(),
LabelSelector: labels.SelectorFromSet(map[string]string{hmc.HMCManagedLabelKey: hmc.HMCManagedLabelValue}),
})
if err != nil {
return err
}

// Removing templates not managed by any chain
var errs error
for _, tmpl := range managedTemplates {
orphaned, err := tmpl.IsOrphaned(ctx, r.Client)
if err != nil {
errs = errors.Join(errs, err)
continue
}
if orphaned {
ll := l.WithValues("template kind", r.templateKind, "template namespace", tmpl.GetNamespace(), "template name", tmpl.GetName())
ll.Info("Deleting Template")

if err := r.Client.Delete(ctx, tmpl); client.IgnoreNotFound(err) != nil {
errs = errors.Join(errs, err)
continue
}
ll.Info("Template has been deleted")
}
}
return errs
}

func getTemplateNamesManagedByChain(chain templateChain) []string {
result := make([]string, 0, len(chain.GetSpec().SupportedTemplates))
for _, tmpl := range chain.GetSpec().SupportedTemplates {
Expand All @@ -270,35 +206,12 @@ func getTemplateNamesManagedByChain(chain templateChain) []string {
return result
}

var tmEvents = predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
// Only trigger if access rules were changed
oldObject, ok := e.ObjectOld.(*hmc.TemplateManagement)
if !ok {
return false
}
newObject, ok := e.ObjectNew.(*hmc.TemplateManagement)
if !ok {
return false
}
return !equality.Semantic.DeepEqual(oldObject.Spec.AccessRules, newObject.Spec.AccessRules)
},
DeleteFunc: func(event.DeleteEvent) bool { return false },
GenericFunc: func(event.GenericEvent) bool { return false },
}

// SetupWithManager sets up the controller with the Manager.
func (r *ClusterTemplateChainReconciler) SetupWithManager(mgr ctrl.Manager) error {
r.templateKind = hmc.ClusterTemplateKind

return ctrl.NewControllerManagedBy(mgr).
For(&hmc.ClusterTemplateChain{}).
Watches(&hmc.TemplateManagement{},
handler.EnqueueRequestsFromMapFunc(func(_ context.Context, o client.Object) []ctrl.Request {
return getTemplateChainRequests(o, r.SystemNamespace, hmc.ClusterTemplateKind)
}),
builder.WithPredicates(tmEvents),
).
Complete(r)
}

Expand All @@ -308,39 +221,5 @@ func (r *ServiceTemplateChainReconciler) SetupWithManager(mgr ctrl.Manager) erro

return ctrl.NewControllerManagedBy(mgr).
For(&hmc.ServiceTemplateChain{}).
Watches(&hmc.TemplateManagement{},
handler.EnqueueRequestsFromMapFunc(func(_ context.Context, o client.Object) []ctrl.Request {
return getTemplateChainRequests(o, r.SystemNamespace, hmc.ServiceTemplateKind)
}),
builder.WithPredicates(tmEvents),
).
Complete(r)
}

func getTemplateChainRequests(o client.Object, systemNamespace, kind string) (reqs []ctrl.Request) {
tm, ok := o.(*hmc.TemplateManagement)
if !ok {
return nil
}
f := func(chains []string) {
for _, c := range chains {
reqs = append(reqs, ctrl.Request{
NamespacedName: client.ObjectKey{
Namespace: systemNamespace,
Name: c,
},
})
}
}
if kind == hmc.ClusterTemplateChainKind {
for _, ar := range tm.Spec.AccessRules {
f(ar.ClusterTemplateChains)
}
}
if kind == hmc.ServiceTemplateChainKind {
for _, ar := range tm.Spec.AccessRules {
f(ar.ServiceTemplateChains)
}
}
return reqs
}
Loading

0 comments on commit 55bf573

Please sign in to comment.