Modify the incorrect format of sentence in the README.md

Signed-off-by: wangglbj <wangglbj@cn.ibm.com>
This commit is contained in:
OpenShift Merge Robot
2021-09-10 04:58:47 -04:00
committed by wangglbj
7 changed files with 959 additions and 28 deletions

View File

@@ -115,7 +115,7 @@ spec:
EOF
```
Check the 'PlacementDecision' created for this placement. It contains all selected clusters in status.
Check the `PlacementDecision` created for this placement. It contains all selected clusters in status.
```txt
kubectl get placementdecisions

View File

@@ -14,6 +14,7 @@ import (
"open-cluster-management.io/placement/pkg/plugins"
"open-cluster-management.io/placement/pkg/plugins/balance"
"open-cluster-management.io/placement/pkg/plugins/predicate"
"open-cluster-management.io/placement/pkg/plugins/resource"
"open-cluster-management.io/placement/pkg/plugins/steady"
)
@@ -120,6 +121,10 @@ func NewPluginScheduler(handle plugins.Handle) *pluginScheduler {
prioritizers: []plugins.Prioritizer{
balance.New(handle),
steady.New(handle),
resource.NewResourcePrioritizerBuilder(handle).WithPrioritizerName("ResourceAllocatableCPU").Build(),
resource.NewResourcePrioritizerBuilder(handle).WithPrioritizerName("ResourceAllocatableMemory").Build(),
resource.NewResourcePrioritizerBuilder(handle).WithPrioritizerName("ResourceRatioCPU").Build(),
resource.NewResourcePrioritizerBuilder(handle).WithPrioritizerName("ResourceRatioMemory").Build(),
},
prioritizerWeights: defaultPrioritizerConfig,
}

View File

@@ -59,6 +59,26 @@ func TestSchedule(t *testing.T) {
Weight: 1,
Scores: PrioritizerScore{"cluster1": 0},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterSetLabel, clusterSetName).Build(),
@@ -96,6 +116,26 @@ func TestSchedule(t *testing.T) {
Weight: 1,
Scores: PrioritizerScore{"cluster1": 0},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
expectedUnScheduled: 2,
},
@@ -140,6 +180,26 @@ func TestSchedule(t *testing.T) {
Weight: 1,
Scores: PrioritizerScore{"cluster1": 100, "cluster2": 100, "cluster3": 0},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
expectedUnScheduled: 0,
},
@@ -171,6 +231,26 @@ func TestSchedule(t *testing.T) {
Weight: 1,
Scores: PrioritizerScore{"cluster1": 0},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterSetLabel, clusterSetName).Build(),
@@ -179,69 +259,115 @@ func TestSchedule(t *testing.T) {
},
{
name: "placement with additive Prioritizer Policy",
placement: testinghelpers.NewPlacement(placementNamespace, placementName).WithPrioritizerPolicy("Additive").WithPrioritizerConfig("Steady", 3).Build(),
placement: testinghelpers.NewPlacement(placementNamespace, placementName).WithNOC(2).WithPrioritizerPolicy("Additive").WithPrioritizerConfig("Balance", 3).WithPrioritizerConfig("ResourceRatioCPU", 1).Build(),
initObjs: []runtime.Object{
testinghelpers.NewClusterSet(clusterSetName),
testinghelpers.NewClusterSetBinding(placementNamespace, clusterSetName),
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceCPU, "10", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
},
decisions: []runtime.Object{},
expectedDecisions: []clusterapiv1alpha1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster2"},
},
expectedFilterResult: []FilterResult{
{
Name: "Predicate",
FilteredClusters: []string{"cluster1"},
FilteredClusters: []string{"cluster1", "cluster2", "cluster3"},
},
},
expectedScoreResult: []PrioritizerResult{
{
Name: "Balance",
Weight: 1,
Scores: PrioritizerScore{"cluster1": 100},
Weight: 3,
Scores: PrioritizerScore{"cluster1": 100, "cluster2": 100, "cluster3": 100},
},
{
Name: "Steady",
Weight: 3,
Scores: PrioritizerScore{"cluster1": 0},
Weight: 1,
Scores: PrioritizerScore{"cluster1": 0, "cluster2": 0, "cluster3": 0},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 1,
Scores: PrioritizerScore{"cluster1": 100, "cluster2": 0, "cluster3": -100},
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterSetLabel, clusterSetName).Build(),
},
expectedUnScheduled: 0,
},
{
name: "placement with exact Prioritizer Policy",
placement: testinghelpers.NewPlacement(placementNamespace, placementName).WithPrioritizerPolicy("Exact").WithPrioritizerConfig("Steady", 3).Build(),
placement: testinghelpers.NewPlacement(placementNamespace, placementName).WithNOC(2).WithPrioritizerPolicy("Exact").WithPrioritizerConfig("Balance", 3).WithPrioritizerConfig("ResourceRatioCPU", 1).Build(),
initObjs: []runtime.Object{
testinghelpers.NewClusterSet(clusterSetName),
testinghelpers.NewClusterSetBinding(placementNamespace, clusterSetName),
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceCPU, "10", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
},
decisions: []runtime.Object{},
expectedDecisions: []clusterapiv1alpha1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster2"},
},
expectedFilterResult: []FilterResult{
{
Name: "Predicate",
FilteredClusters: []string{"cluster1"},
FilteredClusters: []string{"cluster1", "cluster2", "cluster3"},
},
},
expectedScoreResult: []PrioritizerResult{
{
Name: "Balance",
Weight: 3,
Scores: PrioritizerScore{"cluster1": 100, "cluster2": 100, "cluster3": 100},
},
{
Name: "Steady",
Weight: 0,
Scores: nil,
},
{
Name: "Steady",
Weight: 3,
Scores: PrioritizerScore{"cluster1": 0},
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 1,
Scores: PrioritizerScore{"cluster1": 100, "cluster2": 0, "cluster3": -100},
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterSetLabel, clusterSetName).Build(),
},
expectedUnScheduled: 0,
},
@@ -285,6 +411,26 @@ func TestSchedule(t *testing.T) {
Weight: 1,
Scores: PrioritizerScore{"cluster1": 100, "cluster2": 0},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
expectedUnScheduled: 2,
},
@@ -326,6 +472,26 @@ func TestSchedule(t *testing.T) {
Weight: 1,
Scores: PrioritizerScore{"cluster1": 0, "cluster2": 0, "cluster3": 0},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
expectedUnScheduled: 0,
},
@@ -377,6 +543,26 @@ func TestSchedule(t *testing.T) {
Weight: 1,
Scores: PrioritizerScore{"cluster1": 0, "cluster2": 0, "cluster3": 100},
},
{
Name: "ResourceAllocatableCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceAllocatableMemory",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioCPU",
Weight: 0,
Scores: nil,
},
{
Name: "ResourceRatioMemory",
Weight: 0,
Scores: nil,
},
},
expectedUnScheduled: 0,
},

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -95,6 +96,14 @@ func (b *placementBuilder) WithSatisfiedCondition(numbOfScheduledDecisions, numb
return b
}
func (b *placementBuilder) WithPrioritizerConfigs(name string, weight int32) *placementBuilder {
if b.placement.Spec.PrioritizerPolicy.Configurations == nil {
b.placement.Spec.PrioritizerPolicy.Configurations = []clusterapiv1alpha1.PrioritizerConfig{}
}
b.placement.Spec.PrioritizerPolicy.Configurations = append(b.placement.Spec.PrioritizerPolicy.Configurations, clusterapiv1alpha1.PrioritizerConfig{Name: name, Weight: weight})
return b
}
func (b *placementBuilder) Build() *clusterapiv1alpha1.Placement {
return b.placement
}
@@ -209,6 +218,19 @@ func (b *managedClusterBuilder) WithClaim(name, value string) *managedClusterBui
return b
}
func (b *managedClusterBuilder) WithResource(resourceName clusterapiv1.ResourceName, allocatable, capacity string) *managedClusterBuilder {
if b.cluster.Status.Allocatable == nil {
b.cluster.Status.Allocatable = make(map[clusterapiv1.ResourceName]resource.Quantity)
}
if b.cluster.Status.Capacity == nil {
b.cluster.Status.Capacity = make(map[clusterapiv1.ResourceName]resource.Quantity)
}
b.cluster.Status.Allocatable[resourceName], _ = resource.ParseQuantity(allocatable)
b.cluster.Status.Capacity[resourceName], _ = resource.ParseQuantity(capacity)
return b
}
func (b *managedClusterBuilder) Build() *clusterapiv1.ManagedCluster {
return b.cluster
}

View File

@@ -0,0 +1,181 @@
package resource
import (
"context"
"fmt"
"regexp"
"sort"
clusterapiv1 "open-cluster-management.io/api/cluster/v1"
clusterapiv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
"open-cluster-management.io/placement/pkg/plugins"
)
const (
placementLabel = clusterapiv1alpha1.PlacementLabel
description = `
ResourceRatio[ResourceType] and ResourceAllocatable[ResourceType] prioritizer makes the scheduling
decisions based on the resource allocatable to capacity ratio or allocatable of managed clusters.
The [ResourceType] could be CPU or Memory.
The clusters that has the most allocatable to capacity ratio or allocatable are given the highest score,
while the least is given the lowest score.
`
)
var _ plugins.Prioritizer = &ResourcePrioritizer{}
var resourceMap = map[string]clusterapiv1.ResourceName{
"CPU": clusterapiv1.ResourceCPU,
"Memory": clusterapiv1.ResourceMemory,
}
type ResourcePrioritizer struct {
handle plugins.Handle
prioritizerName string
algorithm string
resource clusterapiv1.ResourceName
}
type ResourcePrioritizerBuilder struct {
resourcePrioritizer *ResourcePrioritizer
}
func NewResourcePrioritizerBuilder(handle plugins.Handle) *ResourcePrioritizerBuilder {
return &ResourcePrioritizerBuilder{
resourcePrioritizer: &ResourcePrioritizer{
handle: handle,
},
}
}
func (r *ResourcePrioritizerBuilder) WithPrioritizerName(name string) *ResourcePrioritizerBuilder {
r.resourcePrioritizer.prioritizerName = name
return r
}
func (r *ResourcePrioritizerBuilder) Build() *ResourcePrioritizer {
algorithm, resource := parsePrioritizerName(r.resourcePrioritizer.prioritizerName)
r.resourcePrioritizer.algorithm = algorithm
r.resourcePrioritizer.resource = resource
return r.resourcePrioritizer
}
// parese prioritizerName to algorithm and resource.
// For example, prioritizerName ResourceAllocatableCPU will return Allocatable, CPU.
func parsePrioritizerName(prioritizerName string) (algorithm string, resource clusterapiv1.ResourceName) {
s := regexp.MustCompile("[A-Z]+[a-z]*").FindAllString(prioritizerName, -1)
if len(s) == 3 {
return s[1], resourceMap[s[2]]
}
return "", ""
}
func (r *ResourcePrioritizer) Name() string {
return r.prioritizerName
}
func (r *ResourcePrioritizer) Description() string {
return description
}
func (r *ResourcePrioritizer) Score(ctx context.Context, placement *clusterapiv1alpha1.Placement, clusters []*clusterapiv1.ManagedCluster) (map[string]int64, error) {
switch r.algorithm {
case "Ratio":
return mostResourceRatioScores(r.resource, clusters)
case "Allocatable":
return mostResourceAllocatableScores(r.resource, clusters)
}
return nil, nil
}
// Calculate clusters scores based on the resource allocatable to capacity ratio.
// The clusters that has the most allocatable to capacity ratio are given the highest score, while the least is given the lowest score.
// The score range is from -100 to 100.
func mostResourceRatioScores(resourceName clusterapiv1.ResourceName, clusters []*clusterapiv1.ManagedCluster) (map[string]int64, error) {
scores := map[string]int64{}
for _, cluster := range clusters {
// get cluster resourceName's allocatable and capacity
allocatable, capacity, err := getClusterResource(cluster, resourceName)
if err != nil {
continue
}
// score = (resource_x_allocatable / resource_x_capacity - 0.5) * 2 * 100
if capacity != 0 {
ratio := float64(allocatable) / float64(capacity)
scores[cluster.Name] = int64((ratio - 0.5) * 2.0 * 100.0)
}
}
return scores, nil
}
// Calculate clusters scores based on the resource allocatable.
// The clusters that has the most allocatable are given the highest score, while the least is given the lowest score.
// The score range is from -100 to 100.
func mostResourceAllocatableScores(resourceName clusterapiv1.ResourceName, clusters []*clusterapiv1.ManagedCluster) (map[string]int64, error) {
scores := map[string]int64{}
// get resourceName's min and max allocatable among all the clusters
minAllocatable, maxAllocatable, err := getClustersMinMaxAllocatableResource(clusters, resourceName)
if err != nil {
return scores, nil
}
for _, cluster := range clusters {
// get one cluster resourceName's allocatable
allocatable, _, err := getClusterResource(cluster, resourceName)
if err != nil {
continue
}
// score = ((resource_x_allocatable - min(resource_x_allocatable)) / (max(resource_x_allocatable) - min(resource_x_allocatable)) - 0.5) * 2 * 100
if (maxAllocatable - minAllocatable) != 0 {
ratio := float64(allocatable-minAllocatable) / float64(maxAllocatable-minAllocatable)
scores[cluster.Name] = int64((ratio - 0.5) * 2.0 * 100.0)
} else {
scores[cluster.Name] = 100.0
}
}
return scores, nil
}
// Go through one cluster resources and return the allocatable and capacity of the resourceName.
func getClusterResource(cluster *clusterapiv1.ManagedCluster, resourceName clusterapiv1.ResourceName) (allocatable, capacity float64, err error) {
if v, exist := cluster.Status.Allocatable[resourceName]; exist {
allocatable = v.AsApproximateFloat64()
} else {
return allocatable, capacity, fmt.Errorf("no allocatable %s found in cluster %s", resourceName, cluster.ObjectMeta.Name)
}
if v, exist := cluster.Status.Capacity[resourceName]; exist {
capacity = v.AsApproximateFloat64()
} else {
return allocatable, capacity, fmt.Errorf("no capacity %s found in cluster %s", resourceName, cluster.ObjectMeta.Name)
}
return allocatable, capacity, nil
}
// Go through all the cluster resources and return the min and max allocatable value of the resourceName.
func getClustersMinMaxAllocatableResource(clusters []*clusterapiv1.ManagedCluster, resourceName clusterapiv1.ResourceName) (minAllocatable, maxAllocatable float64, err error) {
allocatable := sort.Float64Slice{}
// get allocatable resources
for _, cluster := range clusters {
if alloc, _, err := getClusterResource(cluster, resourceName); err == nil {
allocatable = append(allocatable, alloc)
}
}
// return err if no allocatable resource
if len(allocatable) == 0 {
return 0, 0, fmt.Errorf("no allocatable %s found in clusters", resourceName)
}
// sort to get min and max
sort.Float64s(allocatable)
return allocatable[0], allocatable[len(allocatable)-1], nil
}

View File

@@ -0,0 +1,237 @@
package resource
import (
"context"
"testing"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/runtime"
clusterapiv1 "open-cluster-management.io/api/cluster/v1"
clusterapiv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
testinghelpers "open-cluster-management.io/placement/pkg/helpers/testing"
)
func TestScoreClusterWithResource(t *testing.T) {
cases := []struct {
name string
resource clusterapiv1.ResourceName
algorithm string
placement *clusterapiv1alpha1.Placement
clusters []*clusterapiv1.ManagedCluster
existingDecisions []runtime.Object
expectedScores map[string]int64
}{
{
name: "scores of ResourceRatioMemory",
resource: clusterapiv1.ResourceMemory,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceMemory, "20", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceMemory, "100", "100").Build(),
},
existingDecisions: []runtime.Object{},
expectedScores: map[string]int64{"cluster1": -60, "cluster2": 0, "cluster3": 100},
},
{
name: "scores of ResourceRatioMemory with same resource value",
resource: clusterapiv1.ResourceMemory,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
},
expectedScores: map[string]int64{"cluster1": 0, "cluster2": 0, "cluster3": 0},
},
{
name: "scores of ResourceRatioMemory with zero resource value",
resource: clusterapiv1.ResourceMemory,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
},
expectedScores: map[string]int64{"cluster1": -100, "cluster2": -100, "cluster3": -100},
},
{
name: "scores of ResourceRatioMemory with no cluster resource",
resource: clusterapiv1.ResourceMemory,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").Build(),
testinghelpers.NewManagedCluster("cluster2").Build(),
testinghelpers.NewManagedCluster("cluster3").Build(),
},
expectedScores: map[string]int64{},
},
{
name: "scores of ResourceRatioCPU",
resource: clusterapiv1.ResourceCPU,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceCPU, "10", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceCPU, "2", "10").Build(),
},
expectedScores: map[string]int64{"cluster1": 100, "cluster2": 0, "cluster3": -60},
},
{
name: "scores of ResourceRatioCPU with same resource value",
resource: clusterapiv1.ResourceCPU,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
},
expectedScores: map[string]int64{"cluster1": 0, "cluster2": 0, "cluster3": 0},
},
{
name: "scores of ResourceRatioCPU with zero resource value",
resource: clusterapiv1.ResourceCPU,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
},
expectedScores: map[string]int64{"cluster1": -100, "cluster2": -100, "cluster3": -100},
},
{
name: "scores of ResourceRatioCPU with no cluster resource",
resource: clusterapiv1.ResourceCPU,
algorithm: "Ratio",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").Build(),
testinghelpers.NewManagedCluster("cluster2").Build(),
testinghelpers.NewManagedCluster("cluster3").Build(),
},
expectedScores: map[string]int64{},
},
{
name: "scores of ResourceAllocatableMemory",
resource: clusterapiv1.ResourceMemory,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceMemory, "20", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceMemory, "60", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceMemory, "100", "100").Build(),
},
expectedScores: map[string]int64{"cluster1": -100, "cluster2": 0, "cluster3": 100},
},
{
name: "scores of ResourceAllocatableMemory with same resource value",
resource: clusterapiv1.ResourceMemory,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
},
expectedScores: map[string]int64{"cluster1": 100, "cluster2": 100, "cluster3": 100},
},
{
name: "scores of ResourceAllocatableMemory with zero resource value",
resource: clusterapiv1.ResourceMemory,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
},
expectedScores: map[string]int64{"cluster1": 100, "cluster2": 100, "cluster3": 100},
},
{
name: "scores of ResourceAllocatableMemory with no cluster resource",
resource: clusterapiv1.ResourceMemory,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").Build(),
testinghelpers.NewManagedCluster("cluster2").Build(),
testinghelpers.NewManagedCluster("cluster3").Build(),
},
expectedScores: map[string]int64{},
},
{
name: "scores of ResourceAllocatableCPU",
resource: clusterapiv1.ResourceCPU,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceCPU, "10", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceCPU, "6", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceCPU, "2", "10").Build(),
},
expectedScores: map[string]int64{"cluster1": 100, "cluster2": 0, "cluster3": -100},
},
{
name: "scores of ResourceAllocatableCPU with same resource value",
resource: clusterapiv1.ResourceCPU,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceCPU, "5", "10").Build(),
},
expectedScores: map[string]int64{"cluster1": 100, "cluster2": 100, "cluster3": 100},
},
{
name: "scores of ResourceAllocatableCPU with zero resource value",
resource: clusterapiv1.ResourceCPU,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
testinghelpers.NewManagedCluster("cluster2").WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
testinghelpers.NewManagedCluster("cluster3").WithResource(clusterapiv1.ResourceCPU, "0", "10").Build(),
},
expectedScores: map[string]int64{"cluster1": 100, "cluster2": 100, "cluster3": 100},
},
{
name: "scores of ResourceAllocatableCPU with no cluster resource",
resource: clusterapiv1.ResourceCPU,
algorithm: "Allocatable",
placement: testinghelpers.NewPlacement("test", "test").Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").Build(),
testinghelpers.NewManagedCluster("cluster2").Build(),
testinghelpers.NewManagedCluster("cluster3").Build(),
},
expectedScores: map[string]int64{},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
resource := &ResourcePrioritizer{
handle: testinghelpers.NewFakePluginHandle(t, nil, c.existingDecisions...),
resource: c.resource,
algorithm: c.algorithm,
}
scores, err := resource.Score(context.TODO(), c.placement, c.clusters)
if err != nil {
t.Errorf("Expect no error, but got %v", err)
}
if !apiequality.Semantic.DeepEqual(scores, c.expectedScores) {
t.Errorf("Expect score %v, but got %v", c.expectedScores, scores)
}
})
}
}

View File

@@ -9,9 +9,11 @@ import (
"github.com/openshift/library-go/pkg/controller/controllercmd"
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/rand"
apiequality "k8s.io/apimachinery/pkg/api/equality"
clusterapiv1 "open-cluster-management.io/api/cluster/v1"
clusterapiv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
controllers "open-cluster-management.io/placement/pkg/controllers"
@@ -28,6 +30,7 @@ var _ = ginkgo.Describe("Placement", func() {
var cancel context.CancelFunc
var namespace string
var placementName string
var clusterName string
var clusterSet1Name, clusterSet2Name string
var suffix string
var err error
@@ -36,6 +39,7 @@ var _ = ginkgo.Describe("Placement", 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)
clusterSet2Name = fmt.Sprintf("clusterset-%s", rand.String(5))
@@ -86,6 +90,31 @@ var _ = ginkgo.Describe("Placement", func() {
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
assertCreatingPlacementDecision := func(name string, clusterNames []string) {
ginkgo.By(fmt.Sprintf("Create placementdecision %s", name))
placementDecision := &clusterapiv1alpha1.PlacementDecision{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: name,
Labels: map[string]string{
placementLabel: name,
},
},
}
placementDecision, err = clusterClient.ClusterV1alpha1().PlacementDecisions(namespace).Create(context.Background(), placementDecision, metav1.CreateOptions{})
clusterDecisions := []clusterapiv1alpha1.ClusterDecision{}
for _, clusterName := range clusterNames {
clusterDecisions = append(clusterDecisions, clusterapiv1alpha1.ClusterDecision{
ClusterName: clusterName,
})
}
placementDecision.Status.Decisions = clusterDecisions
placementDecision, err = clusterClient.ClusterV1alpha1().PlacementDecisions(namespace).UpdateStatus(context.Background(), placementDecision, metav1.UpdateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
assertPlacementDeleted := func(placementName string) {
ginkgo.By("Check if placement is gone")
gomega.Eventually(func() bool {
@@ -121,6 +150,26 @@ var _ = ginkgo.Describe("Placement", func() {
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
}
assertClusterNamesOfDecisions := func(placementName string, desiredClusters []string) {
ginkgo.By(fmt.Sprintf("Check the cluster names of placementdecisions %s", placementName))
gomega.Eventually(func() bool {
pdl, err := clusterClient.ClusterV1alpha1().PlacementDecisions(namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: placementLabel + "=" + placementName,
})
if err != nil {
return false
}
actualClusters := []string{}
for _, pd := range pdl.Items {
for _, d := range pd.Status.Decisions {
actualClusters = append(actualClusters, d.ClusterName)
}
}
ginkgo.By(fmt.Sprintf("Expect %v, but got %v", desiredClusters, actualClusters))
return apiequality.Semantic.DeepEqual(desiredClusters, actualClusters)
}, eventuallyTimeout*2, eventuallyInterval).Should(gomega.BeTrue())
}
assertPlacementStatus := func(placementName string, numOfSelectedClusters int, satisfied bool) {
ginkgo.By("Check the status of placement")
gomega.Eventually(func() bool {
@@ -190,7 +239,52 @@ var _ = ginkgo.Describe("Placement", func() {
}
}
assertCreatingPlacement := func(name string, noc *int32, nod int) {
assertCreatingClustersWithNames := func(clusterSetName string, managedClusterNames []string) {
ginkgo.By(fmt.Sprintf("Create %d clusters", len(managedClusterNames)))
for _, name := range managedClusterNames {
cluster := &clusterapiv1.ManagedCluster{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "cluster-",
Labels: map[string]string{
clusterSetLabel: clusterSetName,
},
Name: name,
},
}
ginkgo.By(fmt.Sprintf("Create cluster %s", name))
_, err = clusterClient.ClusterV1().ManagedClusters().Create(context.Background(), cluster, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
}
assertUpdatingClusterWithClusterResources := func(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())
}
assertCreatingPlacement := func(name string, noc *int32, nod int, prioritizerPolicy clusterapiv1alpha1.PrioritizerPolicy) {
ginkgo.By("Create placement")
placement := &clusterapiv1alpha1.Placement{
ObjectMeta: metav1.ObjectMeta{
@@ -198,7 +292,8 @@ var _ = ginkgo.Describe("Placement", func() {
Name: name,
},
Spec: clusterapiv1alpha1.PlacementSpec{
NumberOfClusters: noc,
NumberOfClusters: noc,
PrioritizerPolicy: prioritizerPolicy,
},
}
placement, err = clusterClient.ClusterV1alpha1().Placements(namespace).Create(context.Background(), placement, metav1.CreateOptions{})
@@ -222,7 +317,7 @@ var _ = ginkgo.Describe("Placement", func() {
ginkgo.It("Should re-create placementdecisions successfully once placementdecisions are deleted", func() {
assertBindingClusterSet(clusterSet1Name)
assertCreatingClusters(clusterSet1Name, 5)
assertCreatingPlacement(placementName, noc(10), 5)
assertCreatingPlacement(placementName, noc(10), 5, clusterapiv1alpha1.PrioritizerPolicy{})
ginkgo.By("Delete placementdecisions")
placementDecisions, err := clusterClient.ClusterV1alpha1().PlacementDecisions(namespace).List(context.Background(), metav1.ListOptions{
@@ -246,7 +341,7 @@ var _ = ginkgo.Describe("Placement", func() {
assertBindingClusterSet(clusterSet2Name)
assertCreatingClusters(clusterSet1Name, 2)
assertCreatingClusters(clusterSet2Name, 3)
assertCreatingPlacement(placementName, noc(10), 5)
assertCreatingPlacement(placementName, noc(10), 5, clusterapiv1alpha1.PrioritizerPolicy{})
// update ClusterSets
placement, err := clusterClient.ClusterV1alpha1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
@@ -262,7 +357,7 @@ var _ = ginkgo.Describe("Placement", func() {
assertBindingClusterSet(clusterSet1Name)
assertCreatingClusters(clusterSet1Name, 2)
assertCreatingClusters(clusterSet1Name, 3, "cloud", "Amazon")
assertCreatingPlacement(placementName, noc(10), 5)
assertCreatingPlacement(placementName, noc(10), 5, clusterapiv1alpha1.PrioritizerPolicy{})
// add a predicates
placement, err := clusterClient.ClusterV1alpha1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
@@ -287,7 +382,7 @@ var _ = ginkgo.Describe("Placement", func() {
ginkgo.It("Should schedule successfully once spec.NumberOfClusters is reduced", func() {
assertBindingClusterSet(clusterSet1Name)
assertCreatingClusters(clusterSet1Name, 5)
assertCreatingPlacement(placementName, noc(10), 5)
assertCreatingPlacement(placementName, noc(10), 5, clusterapiv1alpha1.PrioritizerPolicy{})
ginkgo.By("Reduce NOC of the placement")
placement, err := clusterClient.ClusterV1alpha1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
@@ -305,7 +400,7 @@ var _ = ginkgo.Describe("Placement", func() {
ginkgo.It("Should schedule successfully once spec.NumberOfClusters is increased", func() {
assertBindingClusterSet(clusterSet1Name)
assertCreatingClusters(clusterSet1Name, 10)
assertCreatingPlacement(placementName, noc(5), 5)
assertCreatingPlacement(placementName, noc(5), 5, clusterapiv1alpha1.PrioritizerPolicy{})
ginkgo.By("Increase NOC of the placement")
placement, err := clusterClient.ClusterV1alpha1().Placements(namespace).Get(context.Background(), placementName, metav1.GetOptions{})
@@ -323,7 +418,7 @@ var _ = ginkgo.Describe("Placement", func() {
ginkgo.It("Should be satisfied once new clusters are added", func() {
assertBindingClusterSet(clusterSet1Name)
assertCreatingClusters(clusterSet1Name, 5)
assertCreatingPlacement(placementName, noc(10), 5)
assertCreatingPlacement(placementName, noc(10), 5, clusterapiv1alpha1.PrioritizerPolicy{})
// add more clusters
assertCreatingClusters(clusterSet1Name, 5)
@@ -336,7 +431,7 @@ var _ = ginkgo.Describe("Placement", func() {
ginkgo.It("Should schedule successfully once new clusterset is bound", func() {
assertBindingClusterSet(clusterSet1Name)
assertCreatingClusters(clusterSet1Name, 5)
assertCreatingPlacement(placementName, noc(10), 5)
assertCreatingPlacement(placementName, noc(10), 5, clusterapiv1alpha1.PrioritizerPolicy{})
ginkgo.By("Bind one more clusterset to the placement namespace")
assertBindingClusterSet(clusterSet2Name)
@@ -350,12 +445,217 @@ var _ = ginkgo.Describe("Placement", func() {
ginkgo.It("Should create multiple placementdecisions once scheduled", func() {
assertBindingClusterSet(clusterSet1Name)
assertCreatingClusters(clusterSet1Name, 101)
assertCreatingPlacement(placementName, nil, 101)
assertCreatingPlacement(placementName, nil, 101, clusterapiv1alpha1.PrioritizerPolicy{})
nod := 101
assertNumberOfDecisions(placementName, nod)
assertPlacementStatus(placementName, nod, true)
})
ginkgo.It("Should schedule successfully with default SchedulePolicy", func() {
// cluster settings
clusterNames := []string{
clusterName + "-1",
clusterName + "-2",
clusterName + "-3",
}
clusterResources := make([][]string, len(clusterNames))
clusterResources[0] = []string{"10", "10", "50", "100"}
clusterResources[1] = []string{"7", "10", "90", "100"}
clusterResources[2] = []string{"9", "10", "80", "100"}
// placement settings
prioritizerPolicy := clusterapiv1alpha1.PrioritizerPolicy{}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name)
assertCreatingClustersWithNames(clusterSet1Name, clusterNames)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacement(placementName, noc(2), 2, prioritizerPolicy)
assertClusterNamesOfDecisions(placementName, []string{clusterNames[0], clusterNames[1]})
})
ginkgo.It("Should schedule successfully based on SchedulePolicy ResourceRatioCPU and ResourceRatioCPU", func() {
// cluster settings
clusterNames := []string{
clusterName + "-1",
clusterName + "-2",
clusterName + "-3",
}
clusterResources := make([][]string, len(clusterNames))
clusterResources[0] = []string{"10", "10", "50", "100"}
clusterResources[1] = []string{"7", "10", "90", "100"}
clusterResources[2] = []string{"9", "10", "80", "100"}
// placement settings
prioritizerPolicy := clusterapiv1alpha1.PrioritizerPolicy{
Mode: clusterapiv1alpha1.PrioritizerPolicyModeExact,
Configurations: []clusterapiv1alpha1.PrioritizerConfig{
{
Name: "ResourceRatioCPU",
Weight: 1,
},
{
Name: "ResourceRatioMemory",
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name)
assertCreatingClustersWithNames(clusterSet1Name, clusterNames)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacement(placementName, noc(2), 2, prioritizerPolicy)
assertClusterNamesOfDecisions(placementName, []string{clusterNames[1], clusterNames[2]})
})
ginkgo.It("Should schedule successfully based on default SchedulePolicy ResourceAllocatableCPU & ResourceAllocatableMemory", func() {
// cluster settings
clusterNames := []string{
clusterName + "-1",
clusterName + "-2",
clusterName + "-3",
}
clusterResources := make([][]string, len(clusterNames))
clusterResources[0] = []string{"10", "10", "50", "100"}
clusterResources[1] = []string{"7", "10", "90", "100"}
clusterResources[2] = []string{"9", "10", "80", "100"}
// placement settings
prioritizerPolicy := clusterapiv1alpha1.PrioritizerPolicy{
Mode: clusterapiv1alpha1.PrioritizerPolicyModeExact,
Configurations: []clusterapiv1alpha1.PrioritizerConfig{
{
Name: "ResourceAllocatableCPU",
Weight: 1,
},
{
Name: "ResourceAllocatableMemory",
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name)
assertCreatingClustersWithNames(clusterSet1Name, clusterNames)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacement(placementName, noc(2), 2, prioritizerPolicy)
assertClusterNamesOfDecisions(placementName, []string{clusterNames[0], clusterNames[2]})
})
ginkgo.It("Should re-schedule successfully successfully once a new cluster added", func() {
// cluster settings
clusterNames := []string{
clusterName + "-1",
clusterName + "-2",
clusterName + "-3",
}
clusterResources := make([][]string, len(clusterNames))
clusterResources[0] = []string{"10", "10", "50", "100"}
clusterResources[1] = []string{"7", "10", "90", "100"}
clusterResources[2] = []string{"9", "10", "80", "100"}
// placement settings
prioritizerPolicy := clusterapiv1alpha1.PrioritizerPolicy{
Mode: clusterapiv1alpha1.PrioritizerPolicyModeExact,
Configurations: []clusterapiv1alpha1.PrioritizerConfig{
{
Name: "ResourceRatioCPU",
Weight: 1,
},
{
Name: "ResourceRatioMemory",
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name)
assertCreatingClustersWithNames(clusterSet1Name, clusterNames)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacement(placementName, noc(2), 2, prioritizerPolicy)
assertClusterNamesOfDecisions(placementName, []string{clusterNames[1], clusterNames[2]})
ginkgo.By("Adding a new cluster with resources")
clusterNames = append(clusterNames, clusterName+"-4")
newClusterResources := []string{"10", "10", "100", "100"}
assertCreatingClustersWithNames(clusterSet1Name, clusterNames[3:4])
assertUpdatingClusterWithClusterResources(clusterNames[3], newClusterResources)
//Checking the result of the placement
assertClusterNamesOfDecisions(placementName, []string{clusterNames[2], clusterNames[3]})
})
ginkgo.It("Should keep steady successfully even placementdecisions' balance and cluster resource changes", func() {
// cluster settings
clusterNames := []string{
clusterName + "-1",
clusterName + "-2",
clusterName + "-3",
}
clusterResources := make([][]string, len(clusterNames))
clusterResources[0] = []string{"10", "10", "50", "100"}
clusterResources[1] = []string{"7", "10", "90", "100"}
clusterResources[2] = []string{"9", "10", "80", "100"}
// placement settings
prioritizerPolicy := clusterapiv1alpha1.PrioritizerPolicy{
Mode: clusterapiv1alpha1.PrioritizerPolicyModeAdditive,
Configurations: []clusterapiv1alpha1.PrioritizerConfig{
{
Name: "Steady",
Weight: 3,
},
{
Name: "ResourceRatioCPU",
Weight: 1,
},
{
Name: "ResourceRatioMemory",
Weight: 1,
},
},
}
//Creating the clusters with resources
assertBindingClusterSet(clusterSet1Name)
assertCreatingClustersWithNames(clusterSet1Name, clusterNames)
for i, name := range clusterNames {
assertUpdatingClusterWithClusterResources(name, clusterResources[i])
}
//Checking the result of the placement
assertCreatingPlacement(placementName, noc(2), 2, prioritizerPolicy)
assertClusterNamesOfDecisions(placementName, []string{clusterNames[1], clusterNames[2]})
ginkgo.By("Adding fake placement decisions and update cluster resources")
assertCreatingPlacementDecision(placementName+"-1", []string{clusterNames[1]})
assertUpdatingClusterWithClusterResources(clusterNames[0], []string{"10", "10", "10", "100"})
//Checking the result of the placement
assertClusterNamesOfDecisions(placementName, []string{clusterNames[1], clusterNames[2]})
})
})
})