Refactor integration test (#90)

Signed-off-by: Jian Qiu <jqiu@redhat.com>

Signed-off-by: Jian Qiu <jqiu@redhat.com>
This commit is contained in:
Jian Qiu
2022-11-25 13:45:28 +08:00
committed by GitHub
parent 252e7ee1a3
commit fafcfbfdbe
4 changed files with 964 additions and 922 deletions

View File

@@ -0,0 +1,441 @@
package integration
import (
"context"
"fmt"
"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
clusterapiv1 "open-cluster-management.io/api/cluster/v1"
clusterapiv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
clusterapiv1beta1 "open-cluster-management.io/api/cluster/v1beta1"
clusterapiv1beta2 "open-cluster-management.io/api/cluster/v1beta2"
"open-cluster-management.io/placement/test/integration/util"
"sort"
"time"
)
func assertPlacementDecisionCreated(placement *clusterapiv1beta1.Placement) {
ginkgo.By("Check if placementdecision is created")
gomega.Eventually(func() bool {
pdl, err := clusterClient.ClusterV1beta1().PlacementDecisions(placement.Namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: placementLabel + "=" + placement.Name,
})
if err != nil {
return false
}
if len(pdl.Items) == 0 {
return false
}
for _, pd := range pdl.Items {
if controlled := metav1.IsControlledBy(&pd.ObjectMeta, placement); !controlled {
return false
}
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func assertCreatingPlacementDecision(name, namespace string, clusterNames []string) {
ginkgo.By(fmt.Sprintf("Create placementdecision %s", name))
placementDecision := &clusterapiv1beta1.PlacementDecision{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: name,
Labels: map[string]string{
placementLabel: name,
},
},
}
placementDecision, err := clusterClient.ClusterV1beta1().PlacementDecisions(namespace).Create(context.Background(), placementDecision, metav1.CreateOptions{})
var clusterDecisions []clusterapiv1beta1.ClusterDecision
for _, clusterName := range clusterNames {
clusterDecisions = append(clusterDecisions, clusterapiv1beta1.ClusterDecision{
ClusterName: clusterName,
})
}
placementDecision.Status.Decisions = clusterDecisions
placementDecision, err = clusterClient.ClusterV1beta1().PlacementDecisions(namespace).UpdateStatus(context.Background(), placementDecision, metav1.UpdateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
func assertPlacementDeleted(placementName, namespace string) {
ginkgo.By("Check if placement is gone")
gomega.Eventually(func() bool {
_, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
if err == nil {
return false
}
return errors.IsNotFound(err)
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func assertNumberOfDecisions(placementName, namespace string, desiredNOD int) {
ginkgo.By("Check the number of decisions in placementdecisions")
desiredNOPD := desiredNOD / maxNumOfClusterDecisions
if desiredNOD%maxNumOfClusterDecisions != 0 {
desiredNOPD++
}
gomega.Eventually(func() bool {
pdl, err := clusterClient.ClusterV1beta1().PlacementDecisions(namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: placementLabel + "=" + placementName,
})
if err != nil {
return false
}
if len(pdl.Items) != desiredNOPD {
return false
}
actualNOD := 0
for _, pd := range pdl.Items {
actualNOD += len(pd.Status.Decisions)
}
return actualNOD == desiredNOD
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func assertClusterNamesOfDecisions(placementName, namespace string, desiredClusters []string) {
ginkgo.By(fmt.Sprintf("Check the cluster names of placementdecisions %s", placementName))
gomega.Eventually(func() bool {
pdl, err := clusterClient.ClusterV1beta1().PlacementDecisions(namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: placementLabel + "=" + placementName,
})
if err != nil {
return false
}
actualClusters := sets.NewString()
desiredClusters := sets.NewString(desiredClusters...)
for _, pd := range pdl.Items {
for _, d := range pd.Status.Decisions {
actualClusters.Insert(d.ClusterName)
}
}
if actualClusters.Equal(desiredClusters) {
return true
}
ginkgo.By(fmt.Sprintf("Expect %v, but got %v", desiredClusters.List(), actualClusters.List()))
return false
}, eventuallyTimeout*2, eventuallyInterval).Should(gomega.BeTrue())
}
func assertPlacementConditionSatisfied(placementName, namespace string, numOfSelectedClusters int, satisfied bool) {
ginkgo.By("Check the condition PlacementSatisfied of placement")
gomega.Eventually(func() bool {
placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
if err != nil {
return false
}
if satisfied && !util.HasCondition(
placement.Status.Conditions,
clusterapiv1beta1.PlacementConditionSatisfied,
"AllDecisionsScheduled",
metav1.ConditionTrue,
) {
return false
}
if !satisfied && !util.HasCondition(
placement.Status.Conditions,
clusterapiv1beta1.PlacementConditionSatisfied,
"NotAllDecisionsScheduled",
metav1.ConditionFalse,
) {
return false
}
return placement.Status.NumberOfSelectedClusters == int32(numOfSelectedClusters)
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func assertPlacementConditionMisconfigured(placementName, namespace string, misConfigured bool) {
ginkgo.By("Check the condition PlacementMisconfigured of placement")
gomega.Eventually(func() bool {
placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
if err != nil {
return false
}
if !misConfigured && !util.HasCondition(
placement.Status.Conditions,
clusterapiv1beta1.PlacementConditionMisconfigured,
"Succeedconfigured",
metav1.ConditionFalse,
) {
return false
}
if misConfigured && !util.HasCondition(
placement.Status.Conditions,
clusterapiv1beta1.PlacementConditionMisconfigured,
"Misconfigured",
metav1.ConditionTrue,
) {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func assertBindingClusterSet(clusterSetName, namespace string) {
ginkgo.By("Create clusterset/clustersetbinding")
clusterset := &clusterapiv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: clusterSetName,
},
}
_, err := clusterClient.ClusterV1beta2().ManagedClusterSets().Create(context.Background(), clusterset, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
csb := &clusterapiv1beta2.ManagedClusterSetBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: clusterSetName,
},
Spec: clusterapiv1beta2.ManagedClusterSetBindingSpec{
ClusterSet: clusterSetName,
},
}
_, err = clusterClient.ClusterV1beta2().ManagedClusterSetBindings(namespace).Create(context.Background(), csb, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
func assertCreatingClusterSet(clusterSetName string, labels ...string) {
ginkgo.By(fmt.Sprintf("Create clusterset %s", clusterSetName))
clusterset := &clusterapiv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: clusterSetName,
Labels: map[string]string{},
},
Spec: clusterapiv1beta2.ManagedClusterSetSpec{},
}
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]
}
}
_, err := clusterClient.ClusterV1beta2().ManagedClusterSets().Create(context.Background(), clusterset, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
func assertDeletingClusterSet(clusterSetName string) {
ginkgo.By(fmt.Sprintf("Delete clusterset %s", clusterSetName))
err := clusterClient.ClusterV1beta2().ManagedClusterSets().Delete(context.Background(), clusterSetName, metav1.DeleteOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
ginkgo.By("Check if clusterset is gone")
gomega.Eventually(func() bool {
_, err := clusterClient.ClusterV1beta2().ManagedClusterSets().Get(context.Background(), clusterSetName, metav1.GetOptions{})
if err == nil {
return false
}
return errors.IsNotFound(err)
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func assertCreatingClusterSetBinding(clusterSetName, namespace string) {
ginkgo.By(fmt.Sprintf("Create clustersetbinding %s", clusterSetName))
csb := &clusterapiv1beta2.ManagedClusterSetBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: clusterSetName,
},
Spec: clusterapiv1beta2.ManagedClusterSetBindingSpec{
ClusterSet: clusterSetName,
},
}
_, err := clusterClient.ClusterV1beta2().ManagedClusterSetBindings(namespace).Create(context.Background(), csb, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
func assertDeletingClusterSetBinding(clusterSetName, namespace string) {
ginkgo.By(fmt.Sprintf("Delete clustersetbinding %s", clusterSetName))
err := clusterClient.ClusterV1beta2().ManagedClusterSetBindings(namespace).Delete(context.Background(), clusterSetName, metav1.DeleteOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
ginkgo.By("Check if clustersetbinding is gone")
gomega.Eventually(func() bool {
_, err := clusterClient.ClusterV1beta2().ManagedClusterSetBindings(namespace).Get(context.Background(), clusterSetName, metav1.GetOptions{})
if err == nil {
return false
}
return errors.IsNotFound(err)
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
func assertCreatingClusters(clusterSetName string, num int, labels ...string) []string {
ginkgo.By(fmt.Sprintf("Create %d clusters", num))
var names []string
for i := 0; i < num; i++ {
cluster := &clusterapiv1.ManagedCluster{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "cluster-",
Labels: map[string]string{
clusterSetLabel: clusterSetName,
},
},
}
for i := 1; i < len(labels); i += 2 {
cluster.Labels[labels[i-1]] = labels[i]
}
cluster, err := clusterClient.ClusterV1().ManagedClusters().Create(context.Background(), cluster, metav1.CreateOptions{})
names = append(names, cluster.Name)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
sort.SliceStable(names, func(i, j int) bool {
return names[i] < names[j]
})
return names
}
func assertUpdatingClusterWithClusterResources(managedClusterName string, res []string) {
ginkgo.By(fmt.Sprintf("Updating ManagedClusters %s cluster resources", managedClusterName))
mc, err := clusterClient.ClusterV1().ManagedClusters().Get(context.Background(), managedClusterName, metav1.GetOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
allocatable := map[clusterapiv1.ResourceName]resource.Quantity{}
capacity := map[clusterapiv1.ResourceName]resource.Quantity{}
allocatable[clusterapiv1.ResourceCPU], err = resource.ParseQuantity(res[0])
gomega.Expect(err).ToNot(gomega.HaveOccurred())
allocatable[clusterapiv1.ResourceMemory], err = resource.ParseQuantity(res[2])
gomega.Expect(err).ToNot(gomega.HaveOccurred())
capacity[clusterapiv1.ResourceCPU], err = resource.ParseQuantity(res[1])
gomega.Expect(err).ToNot(gomega.HaveOccurred())
capacity[clusterapiv1.ResourceMemory], err = resource.ParseQuantity(res[3])
gomega.Expect(err).ToNot(gomega.HaveOccurred())
mc.Status = clusterapiv1.ManagedClusterStatus{
Allocatable: allocatable,
Capacity: capacity,
Conditions: []metav1.Condition{},
}
_, err = clusterClient.ClusterV1().ManagedClusters().UpdateStatus(context.Background(), mc, metav1.UpdateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
func assertUpdatingClusterWithClusterTaint(managedClusterName string, taint *clusterapiv1.Taint) {
ginkgo.By(fmt.Sprintf("Updating ManagedClusters %s taint", managedClusterName))
if taint == nil {
return
}
mc, err := clusterClient.ClusterV1().ManagedClusters().Get(context.Background(), managedClusterName, metav1.GetOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
mc.Spec.Taints = append(mc.Spec.Taints, *taint)
_, err = clusterClient.ClusterV1().ManagedClusters().Update(context.Background(), mc, metav1.UpdateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
func assertDeletingClusters(clusterNames ...string) {
for _, clusterName := range clusterNames {
ginkgo.By(fmt.Sprintf("Delete cluster %s", clusterName))
err := clusterClient.ClusterV1().ManagedClusters().Delete(context.Background(), clusterName, metav1.DeleteOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
ginkgo.By("Check if cluster is gone")
gomega.Eventually(func() bool {
_, err := clusterClient.ClusterV1().ManagedClusters().Get(context.Background(), clusterName, metav1.GetOptions{})
if err == nil {
return false
}
return errors.IsNotFound(err)
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
}
func assertCreatingPlacement(name, namespace string, noc *int32, prioritizerPolicy clusterapiv1beta1.PrioritizerPolicy, tolerations []clusterapiv1beta1.Toleration) *clusterapiv1beta1.Placement {
ginkgo.By("Create placement")
placement := &clusterapiv1beta1.Placement{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: name,
},
Spec: clusterapiv1beta1.PlacementSpec{
NumberOfClusters: noc,
PrioritizerPolicy: prioritizerPolicy,
Tolerations: tolerations,
},
}
placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Create(context.Background(), placement, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
return placement
}
func assertCreatingPlacementWithDecision(name, namespace string, noc *int32, nod int, prioritizerPolicy clusterapiv1beta1.PrioritizerPolicy, tolerations []clusterapiv1beta1.Toleration) {
placement := assertCreatingPlacement(name, namespace, noc, prioritizerPolicy, tolerations)
assertPlacementDecisionCreated(placement)
assertNumberOfDecisions(name, namespace, nod)
if noc != nil {
assertPlacementConditionSatisfied(name, namespace, nod, nod == int(*noc))
}
}
func assertUpdatingPlacement(name, namespace string, noc *int32, prioritizerPolicy clusterapiv1beta1.PrioritizerPolicy, tolerations []clusterapiv1beta1.Toleration) {
ginkgo.By("Updating placement")
placement, err := clusterClient.ClusterV1beta1().Placements(namespace).Get(context.Background(), name, metav1.GetOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
placement.Spec.NumberOfClusters = noc
placement.Spec.Tolerations = tolerations
placement.Spec.PrioritizerPolicy = prioritizerPolicy
placement, err = clusterClient.ClusterV1beta1().Placements(namespace).Update(context.Background(), placement, metav1.UpdateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
func assertCreatingAddOnPlacementScores(clusternamespace, crname, scorename string, score int32) {
ginkgo.By(fmt.Sprintf("Create namespace %s for addonplacementscores %s", clusternamespace, crname))
if _, err := kubeClient.CoreV1().Namespaces().Get(context.Background(), clusternamespace, metav1.GetOptions{}); err != nil {
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: clusternamespace,
},
}
_, err := kubeClient.CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
ginkgo.By(fmt.Sprintf("Create addonplacementscores %s in %s", crname, clusternamespace))
addOn, err := clusterClient.ClusterV1alpha1().AddOnPlacementScores(clusternamespace).Get(context.Background(), crname, metav1.GetOptions{})
if err != nil {
newAddOn := &clusterapiv1alpha1.AddOnPlacementScore{
ObjectMeta: metav1.ObjectMeta{
Namespace: clusternamespace,
Name: crname,
},
}
addOn, err = clusterClient.ClusterV1alpha1().AddOnPlacementScores(clusternamespace).Create(context.Background(), newAddOn, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
vu := metav1.NewTime(time.Now().Add(10 * time.Second))
addOn.Status = clusterapiv1alpha1.AddOnPlacementScoreStatus{
Scores: []clusterapiv1alpha1.AddOnPlacementScoreItem{
{
Name: scorename,
Value: score,
},
},
ValidUntil: &vu,
}
_, err = clusterClient.ClusterV1alpha1().AddOnPlacementScores(clusternamespace).UpdateStatus(context.Background(), addOn, metav1.UpdateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,316 @@
package integration
import (
"context"
"fmt"
"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
"github.com/openshift/library-go/pkg/controller/controllercmd"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
clusterapiv1beta1 "open-cluster-management.io/api/cluster/v1beta1"
controllers "open-cluster-management.io/placement/pkg/controllers"
"open-cluster-management.io/placement/pkg/controllers/scheduling"
"open-cluster-management.io/placement/test/integration/util"
"time"
)
var _ = ginkgo.Describe("Prioritizers", func() {
var cancel context.CancelFunc
var namespace string
var placementName string
var clusterName string
var clusterSet1Name string
var suffix string
ginkgo.BeforeEach(func() {
suffix = rand.String(5)
namespace = fmt.Sprintf("ns-%s", suffix)
placementName = fmt.Sprintf("placement-%s", suffix)
clusterName = fmt.Sprintf("cluster-%s", suffix)
clusterSet1Name = fmt.Sprintf("clusterset-%s", suffix)
// create testing namespace
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
_, err := kubeClient.CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
// start controller manager
var ctx context.Context
ctx, cancel = context.WithCancel(context.Background())
scheduling.ResyncInterval = time.Second * 5
go controllers.RunControllerManager(ctx, &controllercmd.ControllerContext{
KubeConfig: restConfig,
EventRecorder: util.NewIntegrationTestEventRecorder("integration"),
})
})
ginkgo.AfterEach(func() {
if cancel != nil {
cancel()
}
err := kubeClient.CoreV1().Namespaces().Delete(context.Background(), namespace, metav1.DeleteOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
})
ginkgo.Context("BuiltinPlugin", func() {
ginkgo.It("Should schedule successfully with default SchedulePolicy", func() {
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{}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name, namespace)
clusterNames := assertCreatingClusters(clusterSet1Name, 3)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacementWithDecision(placementName, namespace, noc(2), 2, prioritizerPolicy, []clusterapiv1beta1.Toleration{})
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[1]})
})
ginkgo.It("Should schedule successfully based on SchedulePolicy ResourceAllocatableCPU & ResourceAllocatableMemory", 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: "ResourceAllocatableCPU",
},
Weight: 1,
},
{
ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{
Type: clusterapiv1beta1.ScoreCoordinateTypeBuiltIn,
BuiltIn: "ResourceAllocatableMemory",
},
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name, namespace)
clusterNames := assertCreatingClusters(clusterSet1Name, 3)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacementWithDecision(placementName, namespace, noc(2), 2, prioritizerPolicy, []clusterapiv1beta1.Toleration{})
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[2]})
})
ginkgo.It("Should keep steady successfully even placementdecisions' balance and cluster situation changes", 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.PrioritizerPolicyModeAdditive,
Configurations: []clusterapiv1beta1.PrioritizerConfig{
{
ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{
Type: clusterapiv1beta1.ScoreCoordinateTypeBuiltIn,
BuiltIn: "Steady",
},
Weight: 3,
},
{
ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{
Type: clusterapiv1beta1.ScoreCoordinateTypeBuiltIn,
BuiltIn: "ResourceAllocatableCPU",
},
Weight: 1,
},
{
ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{
Type: clusterapiv1beta1.ScoreCoordinateTypeBuiltIn,
BuiltIn: "ResourceAllocatableMemory",
},
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name, namespace)
clusterNames := assertCreatingClusters(clusterSet1Name, 3)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacementWithDecision(placementName, namespace, noc(2), 2, prioritizerPolicy, []clusterapiv1beta1.Toleration{})
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[2]})
ginkgo.By("Adding fake placement decisions")
assertCreatingPlacementDecision(placementName+"-1", namespace, []string{clusterNames[1]})
ginkgo.By("Adding a new cluster with resources")
clusterNames = append(clusterNames, clusterName+"-4")
newClusterResources := []string{"10", "10", "100", "100"}
newClusters := assertCreatingClusters(clusterSet1Name, 1)
assertUpdatingClusterWithClusterResources(newClusters[0], newClusterResources)
//Checking the result of the placement
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[2]})
})
ginkgo.It("Should re-schedule successfully once a new cluster with resources added/deleted", 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: "ResourceAllocatableCPU",
},
Weight: 1,
},
{
ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{
Type: clusterapiv1beta1.ScoreCoordinateTypeBuiltIn,
BuiltIn: "ResourceAllocatableMemory",
},
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name, namespace)
clusterNames := assertCreatingClusters(clusterSet1Name, 3)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacementWithDecision(placementName, namespace, noc(2), 2, prioritizerPolicy, []clusterapiv1beta1.Toleration{})
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[2]})
ginkgo.By("Adding a new cluster with resources")
clusterNames = append(clusterNames, clusterName+"-4")
newClusterResources := []string{"10", "10", "100", "100"}
newClusters := assertCreatingClusters(clusterSet1Name, 1)
assertUpdatingClusterWithClusterResources(newClusters[0], newClusterResources)
//Checking the result of the placement
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[2], newClusters[0]})
ginkgo.By("Deleting the cluster")
assertDeletingClusters(newClusters[0])
//Checking the result of the placement
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[2]})
})
})
ginkgo.Context("AddonScore", func() {
ginkgo.It("Should schedule successfully based on AddOnPlacementScore", func() {
// cluster settings
// placement settings
prioritizerPolicy := clusterapiv1beta1.PrioritizerPolicy{
Mode: clusterapiv1beta1.PrioritizerPolicyModeExact,
Configurations: []clusterapiv1beta1.PrioritizerConfig{
{
ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{
Type: clusterapiv1beta1.ScoreCoordinateTypeAddOn,
AddOn: &clusterapiv1beta1.AddOnScore{
ResourceName: "demo",
ScoreName: "demo",
},
},
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name, namespace)
clusterNames := assertCreatingClusters(clusterSet1Name, 3)
assertCreatingAddOnPlacementScores(clusterNames[0], "demo", "demo", 80)
assertCreatingAddOnPlacementScores(clusterNames[1], "demo", "demo", 90)
assertCreatingAddOnPlacementScores(clusterNames[2], "demo", "demo", 100)
//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 reschedule every ResyncInterval and update desicion when AddOnPlacementScore changes", func() {
// placement settings
prioritizerPolicy := clusterapiv1beta1.PrioritizerPolicy{
Mode: clusterapiv1beta1.PrioritizerPolicyModeExact,
Configurations: []clusterapiv1beta1.PrioritizerConfig{
{
ScoreCoordinate: &clusterapiv1beta1.ScoreCoordinate{
Type: clusterapiv1beta1.ScoreCoordinateTypeAddOn,
AddOn: &clusterapiv1beta1.AddOnScore{
ResourceName: "demo",
ScoreName: "demo",
},
},
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name, namespace)
clusterNames := assertCreatingClusters(clusterSet1Name, 3)
//Creating the placement
assertCreatingPlacementWithDecision(placementName, namespace, noc(2), 2, prioritizerPolicy, []clusterapiv1beta1.Toleration{})
//Checking the result of the placement when no AddOnPlacementScores
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[1]})
//Creating the AddOnPlacementScores
assertCreatingAddOnPlacementScores(clusterNames[0], "demo", "demo", 80)
assertCreatingAddOnPlacementScores(clusterNames[1], "demo", "demo", 90)
assertCreatingAddOnPlacementScores(clusterNames[2], "demo", "demo", 100)
//Checking the result of the placement when AddOnPlacementScores added
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[1], clusterNames[2]})
//update the AddOnPlacementScores
assertCreatingAddOnPlacementScores(clusterNames[0], "demo", "demo", 100)
assertCreatingAddOnPlacementScores(clusterNames[1], "demo", "demo", 90)
assertCreatingAddOnPlacementScores(clusterNames[2], "demo", "demo", 100)
//Checking the result of the placement when AddOnPlacementScores updated
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[2]})
})
})
})

View File

@@ -0,0 +1,119 @@
package integration
import (
"context"
"fmt"
"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
"github.com/openshift/library-go/pkg/controller/controllercmd"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
clusterapiv1 "open-cluster-management.io/api/cluster/v1"
clusterapiv1beta1 "open-cluster-management.io/api/cluster/v1beta1"
controllers "open-cluster-management.io/placement/pkg/controllers"
"open-cluster-management.io/placement/pkg/controllers/scheduling"
"open-cluster-management.io/placement/test/integration/util"
"time"
)
var _ = ginkgo.Describe("TaintToleration", func() {
var cancel context.CancelFunc
var namespace string
var placementName string
var clusterSet1Name string
var suffix string
ginkgo.BeforeEach(func() {
suffix = rand.String(5)
namespace = fmt.Sprintf("ns-%s", suffix)
placementName = fmt.Sprintf("placement-%s", suffix)
clusterSet1Name = fmt.Sprintf("clusterset-%s", suffix)
// create testing namespace
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
_, err := kubeClient.CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
// start controller manager
var ctx context.Context
ctx, cancel = context.WithCancel(context.Background())
scheduling.ResyncInterval = time.Second * 5
go controllers.RunControllerManager(ctx, &controllercmd.ControllerContext{
KubeConfig: restConfig,
EventRecorder: util.NewIntegrationTestEventRecorder("integration"),
})
})
ginkgo.AfterEach(func() {
if cancel != nil {
cancel()
}
err := kubeClient.CoreV1().Namespaces().Delete(context.Background(), namespace, metav1.DeleteOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
})
ginkgo.Context("TaintToleration", func() {
ginkgo.It("Should schedule successfully with taint/toleration and requeue when expire TolerationSeconds", func() {
addedTime := metav1.Now()
addedTime_60 := addedTime.Add(-60 * time.Second)
tolerationSeconds_10 := int64(10)
tolerationSeconds_20 := int64(20)
// cluster settings
assertBindingClusterSet(clusterSet1Name, namespace)
clusterNames := assertCreatingClusters(clusterSet1Name, 4)
assertUpdatingClusterWithClusterTaint(clusterNames[0], &clusterapiv1.Taint{
Key: "key1",
Value: "value1",
Effect: clusterapiv1.TaintEffectNoSelect,
TimeAdded: addedTime,
})
assertUpdatingClusterWithClusterTaint(clusterNames[1], &clusterapiv1.Taint{
Key: "key2",
Value: "value2",
Effect: clusterapiv1.TaintEffectNoSelect,
TimeAdded: addedTime,
})
assertUpdatingClusterWithClusterTaint(clusterNames[2], &clusterapiv1.Taint{
Key: "key2",
Value: "value2",
Effect: clusterapiv1.TaintEffectNoSelect,
TimeAdded: metav1.NewTime(addedTime_60),
})
//Checking the result of the placement
assertCreatingPlacementWithDecision(placementName, namespace, noc(4), 3, clusterapiv1beta1.PrioritizerPolicy{}, []clusterapiv1beta1.Toleration{
{
Key: "key1",
Operator: clusterapiv1beta1.TolerationOpExists,
TolerationSeconds: &tolerationSeconds_10,
},
{
Key: "key2",
Operator: clusterapiv1beta1.TolerationOpExists,
TolerationSeconds: &tolerationSeconds_20,
},
})
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[0], clusterNames[1], clusterNames[3]})
//Check placement requeue, clusterNames[0] should be removed when TolerationSeconds expired.
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[1], clusterNames[3]})
//Check placement requeue, clusterNames[1] should be removed when TolerationSeconds expired.
assertClusterNamesOfDecisions(placementName, namespace, []string{clusterNames[3]})
//Check placement update, clusterNames[3] should be removed when new taint added.
assertUpdatingClusterWithClusterTaint(clusterNames[3], &clusterapiv1.Taint{
Key: "key3",
Value: "value3",
Effect: clusterapiv1.TaintEffectNoSelect,
TimeAdded: metav1.NewTime(addedTime_60),
})
assertClusterNamesOfDecisions(placementName, namespace, []string{})
})
})
})