diff --git a/pkg/controllers/framework/interface.go b/pkg/controllers/framework/interface.go index 5e1f7e62f..dd45ad28a 100644 --- a/pkg/controllers/framework/interface.go +++ b/pkg/controllers/framework/interface.go @@ -81,7 +81,7 @@ func (s *Status) AsError() error { return errors.New(s.Message()) } -// FailedPlugin returns the failed plugin name. +// Plugin returns the plugin name. func (s *Status) Plugin() string { return s.plugin } diff --git a/pkg/controllers/scheduling/schedule.go b/pkg/controllers/scheduling/schedule.go index 668c3c302..6bc481123 100644 --- a/pkg/controllers/scheduling/schedule.go +++ b/pkg/controllers/scheduling/schedule.go @@ -239,7 +239,7 @@ func (s *pluginScheduler) Schedule( // The final score is a sum of each prioritizer score * weight. // A higher weight indicates that the prioritizer weights more in the cluster selection, - // while 0 weight indicate thats the prioritizer is disabled. + // while 0 weight indicate that the prioritizer is disabled. for name, val := range score { scoreSum[name] = scoreSum[name] + val*int64(weight) } diff --git a/pkg/controllers/scheduling/scheduling_controller.go b/pkg/controllers/scheduling/scheduling_controller.go index 6e5ef156e..f173ea087 100644 --- a/pkg/controllers/scheduling/scheduling_controller.go +++ b/pkg/controllers/scheduling/scheduling_controller.go @@ -65,7 +65,7 @@ type schedulingController struct { recorder kevents.EventRecorder } -// NewDecisionSchedulingController return an instance of schedulingController +// NewSchedulingController return an instance of schedulingController func NewSchedulingController( clusterClient clusterclient.Interface, clusterInformer clusterinformerv1.ManagedClusterInformer, diff --git a/pkg/plugins/balance/balance.go b/pkg/plugins/balance/balance.go index 63f4e9f28..bc6e689d4 100644 --- a/pkg/plugins/balance/balance.go +++ b/pkg/plugins/balance/balance.go @@ -15,7 +15,7 @@ const ( placementLabel = "cluster.open-cluster-management.io/placement" description = ` Balance prioritizer balance the number of decisions among the clusters. The cluster - with the highest number of decison is given the lowest score, while the empty cluster is given + with the highest number of decision is given the lowest score, while the empty cluster is given the highest score. ` ) diff --git a/pkg/plugins/interface.go b/pkg/plugins/interface.go index 85fb113e1..f70677b11 100644 --- a/pkg/plugins/interface.go +++ b/pkg/plugins/interface.go @@ -29,13 +29,13 @@ const ( // Plugin is the parent type for all the scheduling plugins. type Plugin interface { Name() string - // Set is to set the placement for the current scheduling. + // Description of the plugin Description() string // RequeueAfter returns the requeue time interval of the placement RequeueAfter(ctx context.Context, placement *clusterapiv1beta1.Placement) (PluginRequeueResult, *framework.Status) } -// Fitler defines a filter plugin that filter unsatisfied cluster. +// Filter defines a filter plugin that filter unsatisfied cluster. type Filter interface { Plugin @@ -44,7 +44,7 @@ type Filter interface { } // Prioritizer defines a prioritizer plugin that score each cluster. The score is normalized -// as a floating betwween 0 and 1. +// as a floating between 0 and 1. type Prioritizer interface { Plugin diff --git a/test/e2e/placement_test.go b/test/e2e/placement_test.go index 4038677b9..d85e091ef 100644 --- a/test/e2e/placement_test.go +++ b/test/e2e/placement_test.go @@ -215,12 +215,16 @@ var _ = ginkgo.Describe("Placement", func() { assertCreatingPlacement(placementName, noc(10), 5) ginkgo.By("Reduce NOC of the placement") - placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{}) - gomega.Expect(err).ToNot(gomega.HaveOccurred()) - noc := int32(6) - placement.Spec.NumberOfClusters = &noc - placement, err = clusterClient.ClusterV1beta1().Placements(namespace).Update(context.Background(), placement, metav1.UpdateOptions{}) - gomega.Expect(err).ToNot(gomega.HaveOccurred()) + gomega.Eventually(func() error { + placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{}) + if err != nil { + return err + } + noc := int32(6) + placement.Spec.NumberOfClusters = &noc + _, err = clusterClient.ClusterV1beta1().Placements(namespace).Update(context.Background(), placement, metav1.UpdateOptions{}) + return err + }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) assertNumberOfDecisions(placementName, 5) assertPlacementStatus(placementName, 5, false) @@ -255,21 +259,25 @@ var _ = ginkgo.Describe("Placement", func() { assertCreatingPlacement(placementName, nil, 1) ginkgo.By("Add cluster predicate") - placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{}) - gomega.Expect(err).ToNot(gomega.HaveOccurred()) - placement.Spec.Predicates = []clusterapiv1beta1.ClusterPredicate{ - { - RequiredClusterSelector: clusterapiv1beta1.ClusterSelector{ - LabelSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "a": "b", + gomega.Eventually(func() error { + placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{}) + if err != nil { + return err + } + placement.Spec.Predicates = []clusterapiv1beta1.ClusterPredicate{ + { + RequiredClusterSelector: clusterapiv1beta1.ClusterSelector{ + LabelSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "a": "b", + }, }, }, }, - }, - } - placement, err = clusterClient.ClusterV1beta1().Placements(namespace).Update(context.Background(), placement, metav1.UpdateOptions{}) - gomega.Expect(err).ToNot(gomega.HaveOccurred()) + } + _, err = clusterClient.ClusterV1beta1().Placements(namespace).Update(context.Background(), placement, metav1.UpdateOptions{}) + return err + }, eventuallyTimeout, eventuallyInterval).ShouldNot(gomega.HaveOccurred()) assertNumberOfDecisions(placementName, 0) assertPlacementStatus(placementName, 0, false) diff --git a/test/integration/assertion_test.go b/test/integration/assertion_test.go index 040aecede..bed34e0b6 100644 --- a/test/integration/assertion_test.go +++ b/test/integration/assertion_test.go @@ -209,16 +209,17 @@ func assertCreatingClusterSet(clusterSetName string, labels ...string) { Name: clusterSetName, Labels: map[string]string{}, }, - Spec: clusterapiv1beta2.ManagedClusterSetSpec{}, + Spec: clusterapiv1beta2.ManagedClusterSetSpec{ + ClusterSelector: clusterapiv1beta2.ManagedClusterSelector{ + SelectorType: clusterapiv1beta2.LabelSelector, + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{}, + }, + }, + }, } if len(labels) > 0 { - clusterset.Spec.ClusterSelector = clusterapiv1beta2.ManagedClusterSelector{ - SelectorType: clusterapiv1beta2.LabelSelector, - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{}, - }, - } for i := 1; i < len(labels); i += 2 { clusterset.Spec.ClusterSelector.LabelSelector.MatchLabels[labels[i-1]] = labels[i] } @@ -301,6 +302,20 @@ func assertCreatingClusters(clusterSetName string, num int, labels ...string) [] return names } +func assertCleanupClusters() []string { + ginkgo.By("Cleanup all managed clusters") + var clusterNames []string + clusters, err := clusterClient.ClusterV1().ManagedClusters().List(context.Background(), metav1.ListOptions{}) + gomega.Expect(err).ToNot(gomega.HaveOccurred()) + for _, cluster := range clusters.Items { + clusterNames = append(clusterNames, cluster.Name) + } + + assertDeletingClusters(clusterNames...) + + return clusterNames +} + func assertUpdatingClusterWithClusterResources(managedClusterName string, res []string) { ginkgo.By(fmt.Sprintf("Updating ManagedClusters %s cluster resources", managedClusterName)) diff --git a/test/integration/placement_test.go b/test/integration/placement_test.go index 4f7575208..486b154fb 100644 --- a/test/integration/placement_test.go +++ b/test/integration/placement_test.go @@ -66,6 +66,8 @@ var _ = ginkgo.Describe("Placement", func() { } err := kubeClient.CoreV1().Namespaces().Delete(context.Background(), namespace, metav1.DeleteOptions{}) gomega.Expect(err).ToNot(gomega.HaveOccurred()) + + assertCleanupClusters() }) ginkgo.Context("Scheduling", func() { @@ -74,6 +76,7 @@ var _ = ginkgo.Describe("Placement", func() { err = clusterClient.ClusterV1beta1().Placements(namespace).Delete(context.Background(), placementName, metav1.DeleteOptions{}) gomega.Expect(err).ToNot(gomega.HaveOccurred()) assertPlacementDeleted(placementName, namespace) + }) ginkgo.It("Should re-create placementdecisions successfully once placementdecisions are deleted", func() { @@ -336,6 +339,24 @@ var _ = ginkgo.Describe("Placement", func() { assertPlacementConditionSatisfied(placementName, namespace, 5, false) }) + ginkgo.It("Should schedule successfully with global clusterset(labelselector type clusterset without label selector)", func() { + assertCreatingClusterSet("global") + assertCreatingClusterSetBinding("global", namespace) + clusters1 := assertCreatingClusters(clusterName+"1", 1) + clusters2 := assertCreatingClusters(clusterName+"2", 1) + assertCreatingPlacementWithDecision(placementName, namespace, noc(2), 2, clusterapiv1beta1.PrioritizerPolicy{}, []clusterapiv1beta1.Toleration{}) + + assertNumberOfDecisions(placementName, namespace, 2) + assertPlacementConditionSatisfied(placementName, namespace, 2, true) + + ginkgo.By("Delete the cluster") + assertDeletingClusters(clusters1...) + assertNumberOfDecisions(placementName, namespace, 1) + + assertDeletingClusters(clusters2...) + assertNumberOfDecisions(placementName, namespace, 0) + }) + }) }) diff --git a/test/integration/prioritizer_test.go b/test/integration/prioritizer_test.go index 7eab923ed..0c43c5e5a 100644 --- a/test/integration/prioritizer_test.go +++ b/test/integration/prioritizer_test.go @@ -178,6 +178,48 @@ var _ = ginkgo.Describe("Prioritizers", func() { assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[2]}) }) + ginkgo.It("Should schedule successfully based on SchedulePolicy balance", func() { + // cluster settings + clusterResources := make([][]string, 3) + clusterResources[0] = []string{"10", "10", "50", "100"} + clusterResources[1] = []string{"7", "10", "90", "100"} + clusterResources[2] = []string{"9", "10", "80", "100"} + + // placement settings + prioritizerPolicy := clusterapiv1beta1.PrioritizerPolicy{ + Mode: clusterapiv1beta1.PrioritizerPolicyModeExact, + Configurations: []clusterapiv1beta1.PrioritizerConfig{ + { + ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{ + Type: clusterapiv1beta1.ScoreCoordinateTypeBuiltIn, + BuiltIn: "Balance", + }, + Weight: 2, + }, + { + ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{ + Type: clusterapiv1beta1.ScoreCoordinateTypeBuiltIn, + BuiltIn: "ResourceAllocatableCPU", + }, + Weight: 1, + }, + }, + } + //Creating the clusters with resources + assertBindingClusterSet(clusterSet1Name, namespace) + clusterNames := assertCreatingClusters(clusterSet1Name, 3) + for i, name := range clusterNames { + assertUpdatingClusterWithClusterResources(name, clusterResources[i]) + } + + ginkgo.By("Adding fake placement decisions") + assertCreatingPlacementDecision("fake-1", namespace, []string{clusterNames[0]}) + + //Checking the result of the placement + assertCreatingPlacementWithDecision(placementName, namespace, noc(2), 2, prioritizerPolicy, []clusterapiv1beta1.Toleration{}) + assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[1], clusterNames[2]}) + }) + ginkgo.It("Should re-schedule successfully once a new cluster with resources added/deleted", func() { // cluster settings clusterResources := make([][]string, 3)