Skip to content

Commit bf530aa

Browse files
authored
Merge pull request #178 from Jont828/helm-uninstall-spec
✨ Add spec to uninstall Helm chart from Cluster
2 parents 21eb535 + ef21024 commit bf530aa

File tree

2 files changed

+133
-1
lines changed

2 files changed

+133
-1
lines changed

test/e2e/helm_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ var _ = Describe("Workload cluster creation", func() {
118118
})
119119

120120
Context("Creating workload cluster [REQUIRED]", func() {
121-
It("With default template to install and upgrade nginx Helm chart", func() {
121+
It("With default template to install, upgrade, and uninstall nginx Helm chart", func() {
122122
clusterName = fmt.Sprintf("%s-%s", specName, util.RandomString(6))
123123
clusterctl.ApplyClusterTemplateAndWait(ctx, createApplyClusterTemplateInput(
124124
specName,
@@ -203,6 +203,18 @@ var _ = Describe("Workload cluster creation", func() {
203203
}
204204
})
205205
})
206+
207+
// Uninstall Helm chart by removing the label selector from the Cluster.
208+
By("Uninstalling Helm chart from cluster", func() {
209+
HelmUninstallSpec(ctx, func() HelmUninstallInput {
210+
return HelmUninstallInput{
211+
BootstrapClusterProxy: bootstrapClusterProxy,
212+
Namespace: namespace,
213+
ClusterName: clusterName,
214+
HelmChartProxy: hcp,
215+
}
216+
})
217+
})
206218
})
207219
})
208220
})

test/e2e/helm_uninstall.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//go:build e2e
2+
// +build e2e
3+
4+
/*
5+
Copyright 2024 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package e2e
21+
22+
import (
23+
"context"
24+
25+
. "github.com/onsi/ginkgo/v2"
26+
. "github.com/onsi/gomega"
27+
"github.com/pkg/errors"
28+
helmAction "helm.sh/helm/v3/pkg/action"
29+
helmDriver "helm.sh/helm/v3/pkg/storage/driver"
30+
corev1 "k8s.io/api/core/v1"
31+
apierrors "k8s.io/apimachinery/pkg/api/errors"
32+
apitypes "k8s.io/apimachinery/pkg/types"
33+
addonsv1alpha1 "sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1"
34+
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
35+
36+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
37+
"sigs.k8s.io/cluster-api/test/framework"
38+
)
39+
40+
// HelmUninstallInput specifies the input for uninstalling a Helm chart on a workload cluster and verifying that it was successful.
41+
type HelmUninstallInput struct {
42+
BootstrapClusterProxy framework.ClusterProxy
43+
Namespace *corev1.Namespace
44+
ClusterName string
45+
HelmChartProxy *addonsv1alpha1.HelmChartProxy
46+
}
47+
48+
// HelmUninstallSpec implements a test to uninstall a Helm chart from a given Cluster by removing the label selector from the Cluster.
49+
func HelmUninstallSpec(ctx context.Context, inputGetter func() HelmUninstallInput) {
50+
var (
51+
specName = "helm-uninstall"
52+
input HelmUninstallInput
53+
mgmtClient ctrlclient.Client
54+
)
55+
56+
input = inputGetter()
57+
Expect(input.BootstrapClusterProxy).NotTo(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName)
58+
Expect(input.Namespace).NotTo(BeNil(), "Invalid argument. input.Namespace can't be nil when calling %s spec", specName)
59+
60+
By("creating a Kubernetes client to the management cluster")
61+
mgmtClient = input.BootstrapClusterProxy.GetClient()
62+
Expect(mgmtClient).NotTo(BeNil())
63+
64+
// Get Cluster from management Cluster
65+
workloadCluster := &clusterv1.Cluster{}
66+
key := apitypes.NamespacedName{
67+
Namespace: input.Namespace.Name,
68+
Name: input.ClusterName,
69+
}
70+
Expect(mgmtClient.Get(ctx, key, workloadCluster)).To(Succeed())
71+
72+
// Patch cluster labels if not nil, ignore match expressions for now.
73+
// Ignore the case where the label selector matches all, since there isn't a way to unmatch a single cluster without unmatching all of them.
74+
selector := input.HelmChartProxy.Spec.ClusterSelector
75+
if workloadCluster.Labels != nil {
76+
hrp, err := getHelmReleaseProxy(ctx, mgmtClient, input.ClusterName, *input.HelmChartProxy)
77+
Expect(err).NotTo(HaveOccurred())
78+
79+
for k := range selector.MatchLabels {
80+
delete(workloadCluster.Labels, k)
81+
}
82+
83+
Expect(mgmtClient.Update(ctx, workloadCluster)).To(Succeed())
84+
85+
// Verify that the HelmReleaseProxy is deleted as well as the Helm release.
86+
// We want to fetch the Helm release first, then, so we can check the release name field.
87+
Eventually(func() error {
88+
key := apitypes.NamespacedName{
89+
Namespace: hrp.Namespace,
90+
Name: hrp.Name,
91+
}
92+
if err := mgmtClient.Get(ctx, key, &addonsv1alpha1.HelmReleaseProxy{}); apierrors.IsNotFound(err) {
93+
return nil
94+
}
95+
96+
return errors.Errorf("HelmReleaseProxy %s still exists", key.Name)
97+
}, e2eConfig.GetIntervals(specName, "wait-delete-helmreleaseproxy")...).Should(Succeed())
98+
99+
// Get workload Cluster proxy
100+
By("creating a clusterctl proxy to the workload cluster")
101+
workloadClusterProxy := bootstrapClusterProxy.GetWorkloadCluster(ctx, input.Namespace.Name, input.ClusterName)
102+
Expect(workloadClusterProxy).NotTo(BeNil())
103+
actionConfig := getHelmActionConfigForTests(ctx, workloadClusterProxy, hrp.Spec.ReleaseNamespace)
104+
105+
// Wait for Helm release to be deleted
106+
releaseName := hrp.Spec.ReleaseName
107+
Eventually(func() error {
108+
getClient := helmAction.NewGet(actionConfig)
109+
if r, err := getClient.Run(releaseName); err != nil {
110+
if err == helmDriver.ErrReleaseNotFound {
111+
return nil
112+
}
113+
return err
114+
} else {
115+
return errors.Errorf("Helm release %s still exists", r.Name)
116+
}
117+
}, e2eConfig.GetIntervals(specName, "wait-helm-release")...).Should(Succeed())
118+
}
119+
120+
}

0 commit comments

Comments
 (0)