mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-19 04:06:35 +00:00
🐛 fix flaky e2e cleanup and addon conversion test (#1573)
* 🐛 fix flaky e2e cleanup and addon conversion test Pre-delete ManagedClusterAddOns and wait for ManifestWorks before ManagedCluster deletion in CleanKlusterletRelatedResources. Merge CMA status update and v1beta1 conversion verify into one Eventually loop to avoid race with cmaInstallProgressionController. Fixes #1402 Signed-off-by: bot69dude <nrithvik19@gmail.com> * Wait for ManagedClusterAddOn deletion in cleanup helper DeleteAllManagedClusterAddOnsInCluster now waits until all addons are removed before proceeding, so ManifestWork drain is not racing with still-active addon controllers. Addresses CodeRabbit review on #1573 Signed-off-by: bot69dude <nrithvik19@gmail.com> * Address review: use single MCA API version and drop nested RetryOnConflict Eventually already retries; listing both converted API versions is redundant. Signed-off-by: bot69dude <nrithvik19@gmail.com> --------- Signed-off-by: bot69dude <nrithvik19@gmail.com>
This commit is contained in:
@@ -464,9 +464,9 @@ var _ = ginkgo.Describe("Create v1alpha1 ClusterManagementAddOn", ginkgo.Label("
|
||||
_, err := hub.CreateClusterManagementAddOnV1Alpha1(addonName, addon)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
ginkgo.By("Update v1alpha1 ClusterManagementAddOn status using v1alpha1 client")
|
||||
ginkgo.By("Update v1alpha1 ClusterManagementAddOn status and verify v1beta1 conversion")
|
||||
gomega.Eventually(func() error {
|
||||
addon, err = hub.GetClusterManagementAddOnV1Alpha1(addonName)
|
||||
addon, err := hub.GetClusterManagementAddOnV1Alpha1(addonName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -485,28 +485,28 @@ var _ = ginkgo.Describe("Create v1alpha1 ClusterManagementAddOn", ginkgo.Label("
|
||||
}
|
||||
_, err = hub.AddonClient.AddonV1alpha1().ClusterManagementAddOns().UpdateStatus(
|
||||
context.Background(), addon, metav1.UpdateOptions{})
|
||||
return err
|
||||
}).Should(gomega.Succeed())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ginkgo.By("Get v1alpha1 ClusterManagementAddOn using v1beta1 client and verify conversion")
|
||||
gomega.Eventually(func() error {
|
||||
v1beta1Addon, err := hub.GetClusterManagementAddOnV1Beta1(addonName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Verify spec.supportedConfigs → spec.defaultConfigs conversion
|
||||
if len(v1beta1Addon.Spec.DefaultConfigs) != 1 {
|
||||
return fmt.Errorf("expected 1 default config but got %v", len(v1beta1Addon.Spec.DefaultConfigs))
|
||||
return fmt.Errorf("expected 1 default config but got %d", len(v1beta1Addon.Spec.DefaultConfigs))
|
||||
}
|
||||
if v1beta1Addon.Spec.DefaultConfigs[0].Name != "test-config" {
|
||||
return fmt.Errorf("expected test-config but got %v", v1beta1Addon.Spec.DefaultConfigs[0].Name)
|
||||
return fmt.Errorf("expected test-config but got %s", v1beta1Addon.Spec.DefaultConfigs[0].Name)
|
||||
}
|
||||
// Verify status.DefaultConfigReferences conversion
|
||||
if len(v1beta1Addon.Status.DefaultConfigReferences) != 1 {
|
||||
return fmt.Errorf("expected 1 default config but got %v", len(v1beta1Addon.Status.DefaultConfigReferences))
|
||||
return fmt.Errorf("expected 1 default config reference but got %d", len(v1beta1Addon.Status.DefaultConfigReferences))
|
||||
}
|
||||
if v1beta1Addon.Status.DefaultConfigReferences[0].DesiredConfig == nil {
|
||||
return fmt.Errorf("expected desired config in status")
|
||||
}
|
||||
if v1beta1Addon.Status.DefaultConfigReferences[0].DesiredConfig.Name != "test-config" {
|
||||
return fmt.Errorf("expected status-config but got %v", v1beta1Addon.Status.DefaultConfigReferences[0].DesiredConfig.Name)
|
||||
return fmt.Errorf("expected test-config in status but got %s", v1beta1Addon.Status.DefaultConfigReferences[0].DesiredConfig.Name)
|
||||
}
|
||||
return nil
|
||||
}).Should(gomega.Succeed())
|
||||
|
||||
@@ -288,12 +288,16 @@ func (spoke *Spoke) RemoveRegistrationFeature(klusterletName string, feature str
|
||||
return err
|
||||
}
|
||||
|
||||
// CleanKlusterletRelatedResources needs both hub side and spoke side operations
|
||||
// CleanKlusterletRelatedResources needs both hub side and spoke side operations.
|
||||
func CleanKlusterletRelatedResources(
|
||||
hub *Hub, spoke *Spoke,
|
||||
klusterletName, managedClusterName string) {
|
||||
Expect(klusterletName).NotTo(Equal(""))
|
||||
|
||||
// Remove addons and manifest works first; leftover ManifestWorks (e.g. pre-delete hooks) block ManagedCluster deletion.
|
||||
hub.DeleteAllManagedClusterAddOnsInCluster(managedClusterName)
|
||||
hub.WaitUntilNoManifestWorks(managedClusterName)
|
||||
|
||||
// clean the managed clusters at first.
|
||||
err := hub.ClusterClient.ClusterV1().ManagedClusters().Delete(context.TODO(), managedClusterName, metav1.DeleteOptions{})
|
||||
if apierrors.IsNotFound(err) {
|
||||
|
||||
@@ -5,11 +5,14 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
coordv1 "k8s.io/api/coordination/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
|
||||
addonv1beta1 "open-cluster-management.io/api/addon/v1beta1"
|
||||
@@ -175,3 +178,31 @@ func (hub *Hub) UpdateManagedClusterAddOnV1Alpha1(addon *addonv1alpha1.ManagedCl
|
||||
return hub.AddonClient.AddonV1alpha1().ManagedClusterAddOns(addon.Namespace).Update(
|
||||
context.TODO(), addon, metav1.UpdateOptions{})
|
||||
}
|
||||
|
||||
// DeleteAllManagedClusterAddOnsInCluster deletes every ManagedClusterAddOn in the cluster namespace.
|
||||
// A single API version is enough because both versions share the same storage.
|
||||
func (hub *Hub) DeleteAllManagedClusterAddOnsInCluster(clusterName string) {
|
||||
addons, err := hub.AddonClient.AddonV1beta1().ManagedClusterAddOns(clusterName).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
klog.Errorf("failed to list managed cluster addons in %s: %v", clusterName, err)
|
||||
} else {
|
||||
for _, addon := range addons.Items {
|
||||
err := hub.AddonClient.AddonV1beta1().ManagedClusterAddOns(clusterName).Delete(
|
||||
context.TODO(), addon.Name, metav1.DeleteOptions{})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
klog.Errorf("failed to delete managed cluster addon %s/%s: %v", clusterName, addon.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Eventually(func() error {
|
||||
addons, err := hub.AddonClient.AddonV1beta1().ManagedClusterAddOns(clusterName).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
if len(addons.Items) > 0 {
|
||||
return fmt.Errorf("managed cluster addons still exist in %s", clusterName)
|
||||
}
|
||||
return nil
|
||||
}).Should(Succeed())
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package framework
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -24,3 +25,20 @@ func (hub *Hub) CleanManifestWorks(clusterName, workName string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitUntilNoManifestWorks waits until all ManifestWorks are removed from the managed cluster namespace.
|
||||
func (hub *Hub) WaitUntilNoManifestWorks(clusterName string) {
|
||||
Eventually(func() error {
|
||||
works, err := hub.WorkClient.WorkV1().ManifestWorks(clusterName).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if len(works.Items) != 0 {
|
||||
return fmt.Errorf("expected no manifest works, but got %d", len(works.Items))
|
||||
}
|
||||
return nil
|
||||
}).Should(Succeed())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user