Skip to content

Commit

Permalink
🌱 placement support decision groups (#200)
Browse files Browse the repository at this point in the history
* placement support decision groups

Signed-off-by: haoqing0110 <qhao@redhat.com>

* update decision generation flow

Signed-off-by: haoqing0110 <qhao@redhat.com>

* fix label update issue

Signed-off-by: haoqing0110 <qhao@redhat.com>

* update decision group logic

Signed-off-by: haoqing0110 <qhao@redhat.com>

* update placement and decision with patcher

Signed-off-by: haoqing0110 <qhao@redhat.com>

* modify code based on review comments

Signed-off-by: haoqing0110 <qhao@redhat.com>

---------

Signed-off-by: haoqing0110 <qhao@redhat.com>
  • Loading branch information
haoqing0110 authored Jul 10, 2023
1 parent 3ff63d9 commit 6649834
Show file tree
Hide file tree
Showing 10 changed files with 1,101 additions and 311 deletions.
21 changes: 7 additions & 14 deletions pkg/placement/controllers/scheduling/schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ type ScheduleResult interface {
// PrioritizerScores returns total score for each cluster
PrioritizerScores() PrioritizerScore

// Decisions returns the decisions of the schedule
Decisions() []clusterapiv1beta1.ClusterDecision
// Decision returns the decision groups of the schedule
Decisions() []*clusterapiv1.ManagedCluster

// NumOfUnscheduled returns the number of unscheduled.
NumOfUnscheduled() int
Expand All @@ -82,7 +82,7 @@ type PrioritizerResult struct {
// ScheduleResult is the result for a certain schedule.
type scheduleResult struct {
feasibleClusters []*clusterapiv1.ManagedCluster
scheduledDecisions []clusterapiv1beta1.ClusterDecision
scheduledDecisions []*clusterapiv1.ManagedCluster
unscheduledDecisions int

filteredRecords map[string][]*clusterapiv1.ManagedCluster
Expand Down Expand Up @@ -290,9 +290,8 @@ func (s *pluginScheduler) Schedule(
return results, finalStatus
}

// makeClusterDecisions selects clusters based on given cluster slice and then creates
// cluster decisions.
func selectClusters(placement *clusterapiv1beta1.Placement, clusters []*clusterapiv1.ManagedCluster) []clusterapiv1beta1.ClusterDecision {
// selects clusters based on given cluster slice and number of clusters
func selectClusters(placement *clusterapiv1beta1.Placement, clusters []*clusterapiv1.ManagedCluster) []*clusterapiv1.ManagedCluster {
numOfDecisions := len(clusters)
if placement.Spec.NumberOfClusters != nil {
numOfDecisions = int(*placement.Spec.NumberOfClusters)
Expand All @@ -304,13 +303,7 @@ func selectClusters(placement *clusterapiv1beta1.Placement, clusters []*clustera
clusters = clusters[:numOfDecisions]
}

decisions := []clusterapiv1beta1.ClusterDecision{}
for _, cluster := range clusters {
decisions = append(decisions, clusterapiv1beta1.ClusterDecision{
ClusterName: cluster.Name,
})
}
return decisions
return clusters
}

// setRequeueAfter selects minimal time.Duration as requeue time
Expand Down Expand Up @@ -427,7 +420,7 @@ func (r *scheduleResult) PrioritizerScores() PrioritizerScore {
return r.scoreSum
}

func (r *scheduleResult) Decisions() []clusterapiv1beta1.ClusterDecision {
func (r *scheduleResult) Decisions() []*clusterapiv1.ManagedCluster {
return r.scheduledDecisions
}

Expand Down
100 changes: 38 additions & 62 deletions pkg/placement/controllers/scheduling/schedule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ func TestSchedule(t *testing.T) {
placement *clusterlisterv1beta1.Placement
initObjs []runtime.Object
clusters []*clusterapiv1.ManagedCluster
decisions []runtime.Object
expectedFilterResult []FilterResult
expectedScoreResult []PrioritizerResult
expectedDecisions []clusterapiv1beta1.ClusterDecision
expectedDecisions []*clusterapiv1.ManagedCluster
expectedUnScheduled int
expectedStatus framework.Status
}{
Expand All @@ -45,9 +44,13 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewClusterSet(clusterSetName).Build(),
testinghelpers.NewClusterSetBinding(placementNamespace, clusterSetName),
},
decisions: []runtime.Object{},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(
clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(
clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand All @@ -71,10 +74,6 @@ func TestSchedule(t *testing.T) {
Scores: PrioritizerScore{"cluster1": 0},
},
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(
clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedUnScheduled: 0,
expectedStatus: *framework.NewStatus("", framework.Success, ""),
},
Expand All @@ -85,12 +84,11 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewClusterSet(clusterSetName).Build(),
testinghelpers.NewClusterSetBinding(placementNamespace, clusterSetName),
},
decisions: []runtime.Object{},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -128,11 +126,10 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewClusterSet(clusterSetName).Build(),
testinghelpers.NewClusterSetBinding(placementNamespace, clusterSetName),
},
decisions: []runtime.Object{},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{},
expectedDecisions: []*clusterapiv1.ManagedCluster{},
expectedFilterResult: []FilterResult{
{
Name: "Predicate",
Expand All @@ -157,19 +154,14 @@ func TestSchedule(t *testing.T) {
WithLabel(clusterapiv1beta1.PlacementLabel, placementName).
WithDecisions("cluster1", "cluster2").Build(),
},
decisions: []runtime.Object{
testinghelpers.NewPlacementDecision(placementNamespace, placementDecisionName(placementName, 1)).
WithLabel(clusterapiv1beta1.PlacementLabel, placementName).
WithDecisions("cluster1", "cluster2").Build(),
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster2"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -203,9 +195,8 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewClusterSet(clusterSetName).Build(),
testinghelpers.NewClusterSetBinding(placementNamespace, clusterSetName),
},
decisions: []runtime.Object{},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -267,10 +258,15 @@ func TestSchedule(t *testing.T) {
}).Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
decisions: []runtime.Object{},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster3"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithTaint(
&clusterapiv1.Taint{
Key: "key1",
Value: "value1",
Effect: clusterapiv1.TaintEffectNoSelect,
TimeAdded: metav1.Time{},
}).Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -312,10 +308,9 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
},
decisions: []runtime.Object{},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster2"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "100", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -364,10 +359,9 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "0", "100").Build(),
},
decisions: []runtime.Object{},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster2"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "100", "100").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).WithResource(clusterapiv1.ResourceMemory, "50", "100").Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -408,14 +402,9 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
decisions: []runtime.Object{
testinghelpers.NewPlacementDecision(placementNamespace, placementDecisionName(placementName, 1)).
WithLabel(clusterapiv1beta1.PlacementLabel, placementName).
WithDecisions("cluster1").Build(),
},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster2"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -451,17 +440,13 @@ func TestSchedule(t *testing.T) {
testinghelpers.NewPlacementDecision(placementNamespace, placementDecisionName("others", 1)).
WithDecisions("cluster1", "cluster2").Build(),
},
decisions: []runtime.Object{
testinghelpers.NewPlacementDecision(placementNamespace, placementDecisionName("others", 1)).
WithDecisions("cluster1", "cluster2").Build(),
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster3"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down Expand Up @@ -502,22 +487,13 @@ func TestSchedule(t *testing.T) {
WithLabel(clusterapiv1beta1.PlacementLabel, placementName).
WithDecisions("cluster3").Build(),
},
decisions: []runtime.Object{
testinghelpers.NewPlacementDecision(placementNamespace, placementDecisionName("others", 1)).
WithDecisions("cluster2", "cluster3").Build(),
testinghelpers.NewPlacementDecision(placementNamespace, placementDecisionName("others", 2)).
WithDecisions("cluster1", "cluster2").Build(),
testinghelpers.NewPlacementDecision(placementNamespace, placementDecisionName(placementName, 1)).
WithLabel(clusterapiv1beta1.PlacementLabel, placementName).
WithDecisions("cluster3").Build(),
},
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedDecisions: []clusterapiv1beta1.ClusterDecision{
{ClusterName: "cluster3"},
expectedDecisions: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster3").WithLabel(clusterapiv1beta2.ClusterSetLabel, clusterSetName).Build(),
},
expectedFilterResult: []FilterResult{
{
Expand Down
Loading

0 comments on commit 6649834

Please sign in to comment.