From 4ffd69c577a7acb17a3a79a79c4fbe8994f23c8f Mon Sep 17 00:00:00 2001 From: Yang Le Date: Thu, 20 May 2021 10:02:43 +0800 Subject: [PATCH] add missing rbac rule & e2e test for placement Signed-off-by: Yang Le --- ...cluster-manager-placement-clusterrole.yaml | 3 + .../clustermanager/bindata/bindata.go | 3 + test/e2e/placement_test.go | 162 ++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 test/e2e/placement_test.go diff --git a/manifests/cluster-manager/cluster-manager-placement-clusterrole.yaml b/manifests/cluster-manager/cluster-manager-placement-clusterrole.yaml index 71aecddc3..48bef68e0 100644 --- a/manifests/cluster-manager/cluster-manager-placement-clusterrole.yaml +++ b/manifests/cluster-manager/cluster-manager-placement-clusterrole.yaml @@ -22,3 +22,6 @@ rules: - apiGroups: ["cluster.open-cluster-management.io"] resources: ["placements/status", "placementdecisions/status"] verbs: ["update", "patch"] +- apiGroups: ["cluster.open-cluster-management.io"] + resources: ["placements/finalizers"] + verbs: ["update"] diff --git a/pkg/operators/clustermanager/bindata/bindata.go b/pkg/operators/clustermanager/bindata/bindata.go index 2e471b360..0eaa68950 100644 --- a/pkg/operators/clustermanager/bindata/bindata.go +++ b/pkg/operators/clustermanager/bindata/bindata.go @@ -1672,6 +1672,9 @@ rules: - apiGroups: ["cluster.open-cluster-management.io"] resources: ["placements/status", "placementdecisions/status"] verbs: ["update", "patch"] +- apiGroups: ["cluster.open-cluster-management.io"] + resources: ["placements/finalizers"] + verbs: ["update"] `) func manifestsClusterManagerClusterManagerPlacementClusterroleYamlBytes() ([]byte, error) { diff --git a/test/e2e/placement_test.go b/test/e2e/placement_test.go new file mode 100644 index 000000000..4cc0737dd --- /dev/null +++ b/test/e2e/placement_test.go @@ -0,0 +1,162 @@ +package e2e + +import ( + "context" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/rand" + + clusterapiv1 "github.com/open-cluster-management/api/cluster/v1" + clusterapiv1alpha1 "github.com/open-cluster-management/api/cluster/v1alpha1" +) + +const ( + clusterSetLabel = "cluster.open-cluster-management.io/clusterset" + placementLabel = "cluster.open-cluster-management.io/placement" +) + +var _ = Describe("Placement", func() { + var suffix string + var clusterNamePrefix string + var placementNamespace string + var placementName string + var clusterSetName string + + BeforeEach(func() { + suffix = rand.String(6) + clusterNamePrefix = fmt.Sprintf("cluster-%s", suffix) + clusterSetName = fmt.Sprintf("clusterset-%s", suffix) + placementNamespace = fmt.Sprintf("ns-%s", suffix) + placementName = fmt.Sprintf("ns-%s", suffix) + + By("Create placement namespace") + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: placementNamespace, + }, + } + _, err := t.KubeClient.CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{}) + Expect(err).ToNot(HaveOccurred()) + }) + + AfterEach(func() { + // delete namespace + err := t.KubeClient.CoreV1().Namespaces().Delete(context.Background(), placementNamespace, metav1.DeleteOptions{}) + Expect(err).ToNot(HaveOccurred()) + + // delete clusters created + clusterList, err := t.ClusterClient.ClusterV1().ManagedClusters().List(context.Background(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", clusterSetLabel, clusterSetName), + }) + Expect(err).ToNot(HaveOccurred()) + for _, cluster := range clusterList.Items { + err = t.ClusterClient.ClusterV1().ManagedClusters().Delete(context.Background(), cluster.Name, metav1.DeleteOptions{}) + Expect(err).ToNot(HaveOccurred()) + } + + // delete clusterset created + err = t.ClusterClient.ClusterV1alpha1().ManagedClusterSets().Delete(context.Background(), clusterSetName, metav1.DeleteOptions{}) + Expect(err).ToNot(HaveOccurred()) + }) + + It("Should schedule placement successfully", func() { + By("Create clusterset/clustersetbinding") + clusterset := &clusterapiv1alpha1.ManagedClusterSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: clusterSetName, + }, + } + _, err := t.ClusterClient.ClusterV1alpha1().ManagedClusterSets().Create(context.Background(), clusterset, metav1.CreateOptions{}) + Expect(err).ToNot(HaveOccurred()) + + csb := &clusterapiv1alpha1.ManagedClusterSetBinding{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: placementNamespace, + Name: clusterSetName, + }, + Spec: clusterapiv1alpha1.ManagedClusterSetBindingSpec{ + ClusterSet: clusterSetName, + }, + } + _, err = t.ClusterClient.ClusterV1alpha1().ManagedClusterSetBindings(placementNamespace).Create(context.Background(), csb, metav1.CreateOptions{}) + Expect(err).ToNot(HaveOccurred()) + + numOfClusters := 5 + By(fmt.Sprintf("Create %d clusters", numOfClusters)) + for i := 0; i < numOfClusters; i++ { + cluster := &clusterapiv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: clusterNamePrefix, + Labels: map[string]string{ + clusterSetLabel: clusterSetName, + }, + }, + } + _, err = t.ClusterClient.ClusterV1().ManagedClusters().Create(context.Background(), cluster, metav1.CreateOptions{}) + Expect(err).ToNot(HaveOccurred()) + } + + By("Create a placement") + placement := &clusterapiv1alpha1.Placement{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: placementNamespace, + Name: placementName, + }, + } + + placement, err = t.ClusterClient.ClusterV1alpha1().Placements(placementNamespace).Create(context.TODO(), placement, metav1.CreateOptions{}) + Expect(err).ToNot(HaveOccurred()) + + By("Check if placementdecisions are created with desired number of decisions") + Eventually(func() bool { + placementDecisions, err := t.ClusterClient.ClusterV1alpha1().PlacementDecisions(placementNamespace).List(context.TODO(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", placementLabel, placementName), + }) + if err != nil { + return false + } + + nod := 0 + for _, placementDecision := range placementDecisions.Items { + nod += len(placementDecision.Status.Decisions) + } + + return nod == numOfClusters + }, t.EventuallyTimeout*5, t.EventuallyInterval*5).Should(BeTrue()) + + By("Check if placement status is updated") + Eventually(func() bool { + placement, err := t.ClusterClient.ClusterV1alpha1().Placements(placementNamespace).Get(context.TODO(), placementName, metav1.GetOptions{}) + if err != nil { + return false + } + + if int(placement.Status.NumberOfSelectedClusters) != numOfClusters { + return false + } + + return meta.IsStatusConditionTrue(placement.Status.Conditions, clusterapiv1alpha1.PlacementConditionSatisfied) + }, t.EventuallyTimeout*5, t.EventuallyInterval*5).Should(BeTrue()) + + By("Delete placement") + err = t.ClusterClient.ClusterV1alpha1().Placements(placementNamespace).Delete(context.TODO(), placementName, metav1.DeleteOptions{}) + Expect(err).ToNot(HaveOccurred()) + + By("Check if placementdecisions are deleted as well") + Eventually(func() bool { + placementDecisions, err := t.ClusterClient.ClusterV1alpha1().PlacementDecisions(placementNamespace).List(context.TODO(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", placementLabel, placementName), + }) + if err != nil { + return false + } + + return len(placementDecisions.Items) == 0 + }, t.EventuallyTimeout*5, t.EventuallyInterval*5).Should(BeTrue()) + }) +})