Skip to content

Commit

Permalink
Merge pull request #176 from Mirantis/cleanup
Browse files Browse the repository at this point in the history
Remove associated helm releases when Management deletion is requested
  • Loading branch information
Kshatrix authored Aug 12, 2024
2 parents d0b33ef + 3f02f37 commit 2129cea
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 16 deletions.
3 changes: 2 additions & 1 deletion api/v1alpha1/deployment_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import (
const (
DeploymentFinalizer = "hmc.mirantis.com/deployment"

HMCManagedLabelKey = "hmc.mirantis.com/managed"
HMCManagedLabelKey = "hmc.mirantis.com/managed"
HMCManagedLabelValue = "true"
)

const (
Expand Down
4 changes: 4 additions & 0 deletions api/v1alpha1/management_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func (in *Component) HelmValues() (values map[string]interface{}, err error) {
return values, err
}

func (in *Component) HelmReleaseName() string {
return in.Template
}

func (m *ManagementSpec) SetProvidersDefaults() {
m.Providers = []Component{
{
Expand Down
82 changes: 71 additions & 11 deletions internal/controller/management_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import (
"errors"
"fmt"

fluxv2 "github.com/fluxcd/helm-controller/api/v2"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
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/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/rest"
Expand All @@ -35,6 +37,7 @@ import (
hmc "github.com/Mirantis/hmc/api/v1alpha1"
"github.com/Mirantis/hmc/internal/certmanager"
"github.com/Mirantis/hmc/internal/helm"
"github.com/Mirantis/hmc/internal/utils"
)

// ManagementReconciler reconciles a Management object
Expand Down Expand Up @@ -83,13 +86,6 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *hmc.Manag
return ctrl.Result{}, r.Client.Update(ctx, management)
}

ownerRef := &metav1.OwnerReference{
APIVersion: hmc.GroupVersion.String(),
Kind: hmc.ManagementKind,
Name: management.Name,
UID: management.UID,
}

var errs error
detectedProviders := hmc.Providers{}
detectedComponents := make(map[string]hmc.ComponentStatus)
Expand Down Expand Up @@ -120,8 +116,8 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *hmc.Manag
continue
}

_, _, err = helm.ReconcileHelmRelease(ctx, r.Client, component.Template, management.Namespace, component.Config,
ownerRef, template.Status.ChartRef, defaultReconcileInterval, component.dependsOn)
_, _, err = helm.ReconcileHelmRelease(ctx, r.Client, component.HelmReleaseName(), management.Namespace, component.Config,
nil, template.Status.ChartRef, defaultReconcileInterval, component.dependsOn)
if err != nil {
errMsg := fmt.Sprintf("error reconciling HelmRelease %s/%s: %s", management.Namespace, component.Template, err)
updateComponentsStatus(detectedComponents, &detectedProviders, component.Template, template.Status, errMsg)
Expand All @@ -144,10 +140,74 @@ func (r *ManagementReconciler) Update(ctx context.Context, management *hmc.Manag
return ctrl.Result{}, nil
}

func (r *ManagementReconciler) Delete(_ context.Context, _ *hmc.Management) (ctrl.Result, error) {
func (r *ManagementReconciler) Delete(ctx context.Context, management *hmc.Management) (ctrl.Result, error) {
l := log.FromContext(ctx)
listOpts := &client.ListOptions{
LabelSelector: labels.SelectorFromSet(map[string]string{hmc.HMCManagedLabelKey: hmc.HMCManagedLabelValue}),
}
if err := r.removeHelmReleases(ctx, management.Spec.Core.HMC.HelmReleaseName(), listOpts); err != nil {
return ctrl.Result{}, err
}
if err := r.removeHelmCharts(ctx, listOpts); err != nil {
return ctrl.Result{}, err
}
if err := r.removeHelmRepositories(ctx, listOpts); err != nil {
return ctrl.Result{}, err
}

// Removing finalizer in the end of cleanup
l.Info("Removing Management finalizer")
if controllerutil.RemoveFinalizer(management, hmc.ManagementFinalizer) {
return ctrl.Result{}, r.Client.Update(ctx, management)
}
return ctrl.Result{}, nil
}

func (r *ManagementReconciler) removeHelmReleases(ctx context.Context, hmcReleaseName string, opts *client.ListOptions) error {
l := log.FromContext(ctx)
l.Info("Suspending HMC Helm Release reconciles")
hmcRelease := &fluxv2.HelmRelease{}
err := r.Client.Get(ctx, types.NamespacedName{Namespace: hmc.ManagementNamespace, Name: hmcReleaseName}, hmcRelease)
if err != nil && !apierrors.IsNotFound(err) {
return err
}
if err == nil && !hmcRelease.Spec.Suspend {
hmcRelease.Spec.Suspend = true
if err := r.Client.Update(ctx, hmcRelease); err != nil {
return err
}
}
l.Info("Ensuring all HelmReleases owned by HMC are removed")
gvk := fluxv2.GroupVersion.WithKind(fluxv2.HelmReleaseKind)
if err := utils.EnsureDeleteAllOf(ctx, r.Client, gvk, opts); err != nil {
l.Error(err, "Not all HelmReleases owned by HMC are removed")
return err
}
return nil
}

func (r *ManagementReconciler) removeHelmCharts(ctx context.Context, opts *client.ListOptions) error {
l := log.FromContext(ctx)
l.Info("Ensuring all HelmCharts owned by HMC are removed")
gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmChartKind)
if err := utils.EnsureDeleteAllOf(ctx, r.Client, gvk, opts); err != nil {
l.Error(err, "Not all HelmCharts owned by HMC are removed")
return err
}
return nil
}

func (r *ManagementReconciler) removeHelmRepositories(ctx context.Context, opts *client.ListOptions) error {
l := log.FromContext(ctx)
l.Info("Ensuring all HelmRepositories owned by HMC are removed")
gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)
if err := utils.EnsureDeleteAllOf(ctx, r.Client, gvk, opts); err != nil {
l.Error(err, "Not all HelmRepositories owned by HMC are removed")
return err
}
return nil
}

type component struct {
hmc.Component
// helm release dependencies
Expand Down
6 changes: 5 additions & 1 deletion internal/controller/release_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ func (p *Poller) reconcileDefaultHelmRepo(ctx context.Context) error {
},
}
operation, err := ctrl.CreateOrUpdate(ctx, p.Client, helmRepo, func() error {
if helmRepo.Labels == nil {
helmRepo.Labels = make(map[string]string)
}
helmRepo.Labels[hmc.HMCManagedLabelKey] = hmc.HMCManagedLabelValue
helmRepo.Spec = sourcev1.HelmRepositorySpec{
Type: defaultRepoType,
URL: p.DefaultOCIRegistry,
Expand Down Expand Up @@ -207,7 +211,7 @@ func (p *Poller) reconcileHMCTemplates(ctx context.Context) error {
if helmChart.Labels == nil {
helmChart.Labels = make(map[string]string)
}
helmChart.Labels[hmc.HMCManagedLabelKey] = "true"
helmChart.Labels[hmc.HMCManagedLabelKey] = hmc.HMCManagedLabelValue
helmChart.Spec = sourcev1.HelmChartSpec{
Chart: p.HMCTemplatesChartName,
Version: build.Version,
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/template_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func (r *TemplateReconciler) reconcileHelmChart(ctx context.Context, template *h
if helmChart.Labels == nil {
helmChart.Labels = make(map[string]string)
}
helmChart.Labels[hmc.HMCManagedLabelKey] = "true"
helmChart.Labels[hmc.HMCManagedLabelKey] = hmc.HMCManagedLabelValue
helmChart.OwnerReferences = []metav1.OwnerReference{
{
APIVersion: hmc.GroupVersion.String(),
Expand Down
5 changes: 3 additions & 2 deletions internal/helm/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ import (
"context"
"time"

hmc "github.com/Mirantis/hmc/api/v1alpha1"
hcv2 "github.com/fluxcd/helm-controller/api/v2"
"github.com/fluxcd/pkg/apis/meta"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

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

func ReconcileHelmRelease(
Expand All @@ -50,7 +51,7 @@ func ReconcileHelmRelease(
if helmRelease.Labels == nil {
helmRelease.Labels = make(map[string]string)
}
helmRelease.Labels[hmc.HMCManagedLabelKey] = "true"
helmRelease.Labels[hmc.HMCManagedLabelKey] = hmc.HMCManagedLabelValue
if ownerReference != nil {
helmRelease.OwnerReferences = []metav1.OwnerReference{*ownerReference}
}
Expand Down
45 changes: 45 additions & 0 deletions internal/utils/kube.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2024
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package utils

import (
"context"
"errors"
"fmt"

apierrors "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func EnsureDeleteAllOf(ctx context.Context, cl client.Client, gvk schema.GroupVersionKind, opts *client.ListOptions) error {
itemsList := &v1.PartialObjectMetadataList{}
itemsList.SetGroupVersionKind(gvk)
if err := cl.List(ctx, itemsList, opts); err != nil {
return err
}
var errs error
for _, item := range itemsList.Items {
if item.DeletionTimestamp.IsZero() {
if err := cl.Delete(ctx, &item); err != nil && !apierrors.IsNotFound(err) {
errs = errors.Join(err)
continue
}
}
errs = errors.Join(fmt.Errorf("waiting for %s %s/%s removal", gvk.Kind, item.Namespace, item.Name))
}
return errs
}

0 comments on commit 2129cea

Please sign in to comment.