dispense replicas for job
Signed-off-by: Garrybest <garrybest@foxmail.com>
This commit is contained in:
parent
73a1b8236e
commit
2dd48e029a
|
@ -247,7 +247,7 @@ func divideReplicasByJobCompletions(workload *unstructured.Unstructured, cluster
|
||||||
}
|
}
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
targetClusters = util.DivideReplicasByTargetCluster(clusters, int32(completions))
|
targetClusters = helper.SpreadReplicasByTargetClusters(int32(completions), clusters, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return targetClusters, nil
|
return targetClusters, nil
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
|
||||||
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
||||||
"github.com/karmada-io/karmada/pkg/util"
|
"github.com/karmada-io/karmada/pkg/util"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -140,10 +141,10 @@ func assignByStaticWeightStrategy(state *assignState) ([]workv1alpha2.TargetClus
|
||||||
}
|
}
|
||||||
weightList := getStaticWeightInfoList(state.candidates, state.strategy.WeightPreference.StaticWeightList)
|
weightList := getStaticWeightInfoList(state.candidates, state.strategy.WeightPreference.StaticWeightList)
|
||||||
|
|
||||||
disp := newDispenser(state.spec.Replicas, nil)
|
disp := helper.NewDispenser(state.spec.Replicas, nil)
|
||||||
disp.takeByWeight(weightList)
|
disp.TakeByWeight(weightList)
|
||||||
|
|
||||||
return disp.result, nil
|
return disp.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func assignByDynamicStrategy(state *assignState) ([]workv1alpha2.TargetCluster, error) {
|
func assignByDynamicStrategy(state *assignState) ([]workv1alpha2.TargetCluster, error) {
|
||||||
|
|
|
@ -18,55 +18,6 @@ func (a TargetClustersList) Len() int { return len(a) }
|
||||||
func (a TargetClustersList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
func (a TargetClustersList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
func (a TargetClustersList) Less(i, j int) bool { return a[i].Replicas > a[j].Replicas }
|
func (a TargetClustersList) Less(i, j int) bool { return a[i].Replicas > a[j].Replicas }
|
||||||
|
|
||||||
type dispenser struct {
|
|
||||||
numReplicas int32
|
|
||||||
result []workv1alpha2.TargetCluster
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDispenser(numReplicas int32, init []workv1alpha2.TargetCluster) *dispenser {
|
|
||||||
cp := make([]workv1alpha2.TargetCluster, len(init))
|
|
||||||
copy(cp, init)
|
|
||||||
return &dispenser{numReplicas: numReplicas, result: cp}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *dispenser) done() bool {
|
|
||||||
return a.numReplicas == 0 && len(a.result) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *dispenser) takeByWeight(w helper.ClusterWeightInfoList) {
|
|
||||||
if a.done() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sum := w.GetWeightSum()
|
|
||||||
if sum == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(w)
|
|
||||||
|
|
||||||
result := make([]workv1alpha2.TargetCluster, 0, w.Len())
|
|
||||||
remain := a.numReplicas
|
|
||||||
for _, info := range w {
|
|
||||||
replicas := int32(info.Weight * int64(a.numReplicas) / sum)
|
|
||||||
result = append(result, workv1alpha2.TargetCluster{
|
|
||||||
Name: info.ClusterName,
|
|
||||||
Replicas: replicas,
|
|
||||||
})
|
|
||||||
remain -= replicas
|
|
||||||
}
|
|
||||||
// TODO(Garrybest): take rest replicas by fraction part
|
|
||||||
for i := range result {
|
|
||||||
if remain == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
result[i].Replicas++
|
|
||||||
remain--
|
|
||||||
}
|
|
||||||
|
|
||||||
a.numReplicas = remain
|
|
||||||
a.result = util.MergeTargetClusters(a.result, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStaticWeightInfoList(clusters []*clusterv1alpha1.Cluster, weightList []policyv1alpha1.StaticClusterWeight) helper.ClusterWeightInfoList {
|
func getStaticWeightInfoList(clusters []*clusterv1alpha1.Cluster, weightList []policyv1alpha1.StaticClusterWeight) helper.ClusterWeightInfoList {
|
||||||
list := make(helper.ClusterWeightInfoList, 0)
|
list := make(helper.ClusterWeightInfoList, 0)
|
||||||
for _, cluster := range clusters {
|
for _, cluster := range clusters {
|
||||||
|
@ -94,17 +45,6 @@ func getStaticWeightInfoList(clusters []*clusterv1alpha1.Cluster, weightList []p
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStaticWeightInfoListByTargetClusters(tcs []workv1alpha2.TargetCluster) helper.ClusterWeightInfoList {
|
|
||||||
weightList := make(helper.ClusterWeightInfoList, 0, len(tcs))
|
|
||||||
for _, result := range tcs {
|
|
||||||
weightList = append(weightList, helper.ClusterWeightInfo{
|
|
||||||
ClusterName: result.Name,
|
|
||||||
Weight: int64(result.Replicas),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return weightList
|
|
||||||
}
|
|
||||||
|
|
||||||
// dynamicDivideReplicas assigns a total number of replicas to the selected clusters by preference according to the resource.
|
// dynamicDivideReplicas assigns a total number of replicas to the selected clusters by preference according to the resource.
|
||||||
func dynamicDivideReplicas(state *assignState) ([]workv1alpha2.TargetCluster, error) {
|
func dynamicDivideReplicas(state *assignState) ([]workv1alpha2.TargetCluster, error) {
|
||||||
if state.availableReplicas < state.targetReplicas {
|
if state.availableReplicas < state.targetReplicas {
|
||||||
|
@ -125,10 +65,7 @@ func dynamicDivideReplicas(state *assignState) ([]workv1alpha2.TargetCluster, er
|
||||||
case DynamicWeightStrategy:
|
case DynamicWeightStrategy:
|
||||||
// Set the availableClusters as the weight, scheduledClusters as init result, target as the dispenser object.
|
// Set the availableClusters as the weight, scheduledClusters as init result, target as the dispenser object.
|
||||||
// After dispensing, the target cluster will be the combination of init result and weighted result for target replicas.
|
// After dispensing, the target cluster will be the combination of init result and weighted result for target replicas.
|
||||||
weightList := getStaticWeightInfoListByTargetClusters(state.availableClusters)
|
return helper.SpreadReplicasByTargetClusters(state.targetReplicas, state.availableClusters, state.scheduledClusters), nil
|
||||||
disp := newDispenser(state.targetReplicas, state.scheduledClusters)
|
|
||||||
disp.takeByWeight(weightList)
|
|
||||||
return disp.result, nil
|
|
||||||
default:
|
default:
|
||||||
// should never happen
|
// should never happen
|
||||||
return nil, fmt.Errorf("undefined strategy type: %s", state.strategyType)
|
return nil, fmt.Errorf("undefined strategy type: %s", state.strategyType)
|
||||||
|
|
|
@ -87,13 +87,13 @@ func Test_dispenser_takeByWeight(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
a := newDispenser(tt.numReplicas, tt.result)
|
a := utilhelper.NewDispenser(tt.numReplicas, tt.result)
|
||||||
a.takeByWeight(tt.weightList)
|
a.TakeByWeight(tt.weightList)
|
||||||
if a.done() != tt.done {
|
if a.Done() != tt.done {
|
||||||
t.Errorf("expected after takeByWeight: %v, but got: %v", tt.done, a.done())
|
t.Errorf("expected after takeByWeight: %v, but got: %v", tt.done, a.Done())
|
||||||
}
|
}
|
||||||
if !helper.IsScheduleResultEqual(a.result, tt.desired) {
|
if !helper.IsScheduleResultEqual(a.Result, tt.desired) {
|
||||||
t.Errorf("expected result after takeByWeight: %v, but got: %v", tt.desired, a.result)
|
t.Errorf("expected result after takeByWeight: %v, but got: %v", tt.desired, a.Result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,36 +55,6 @@ func ConvertToClusterNames(clusters []workv1alpha2.TargetCluster) sets.String {
|
||||||
return clusterNames
|
return clusterNames
|
||||||
}
|
}
|
||||||
|
|
||||||
// DivideReplicasByTargetCluster will divide the sum number by the weight of target clusters.
|
|
||||||
func DivideReplicasByTargetCluster(clusters []workv1alpha2.TargetCluster, sum int32) []workv1alpha2.TargetCluster {
|
|
||||||
res := make([]workv1alpha2.TargetCluster, len(clusters))
|
|
||||||
if len(clusters) == 0 {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
sumWeight := int32(0)
|
|
||||||
allocatedReplicas := int32(0)
|
|
||||||
for i := range clusters {
|
|
||||||
sumWeight += clusters[i].Replicas
|
|
||||||
}
|
|
||||||
for i := range clusters {
|
|
||||||
res[i].Name = clusters[i].Name
|
|
||||||
if sumWeight > 0 {
|
|
||||||
res[i].Replicas = clusters[i].Replicas * sum / sumWeight
|
|
||||||
}
|
|
||||||
allocatedReplicas += res[i].Replicas
|
|
||||||
}
|
|
||||||
if remainReplicas := sum - allocatedReplicas; remainReplicas > 0 {
|
|
||||||
for i := 0; remainReplicas > 0; i++ {
|
|
||||||
if i == len(res) {
|
|
||||||
i = 0
|
|
||||||
}
|
|
||||||
res[i].Replicas++
|
|
||||||
remainReplicas--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeTargetClusters will merge the replicas in two TargetCluster
|
// MergeTargetClusters will merge the replicas in two TargetCluster
|
||||||
func MergeTargetClusters(old, new []workv1alpha2.TargetCluster) []workv1alpha2.TargetCluster {
|
func MergeTargetClusters(old, new []workv1alpha2.TargetCluster) []workv1alpha2.TargetCluster {
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -15,157 +15,8 @@ import (
|
||||||
const (
|
const (
|
||||||
ClusterMember1 = "member1"
|
ClusterMember1 = "member1"
|
||||||
ClusterMember2 = "member2"
|
ClusterMember2 = "member2"
|
||||||
ClusterMember3 = "member3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDivideReplicasByTargetCluster(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
clusters []workv1alpha2.TargetCluster
|
|
||||||
sum int32
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want []workv1alpha2.TargetCluster
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "empty clusters",
|
|
||||||
args: args{
|
|
||||||
clusters: []workv1alpha2.TargetCluster{},
|
|
||||||
sum: 10,
|
|
||||||
},
|
|
||||||
want: []workv1alpha2.TargetCluster{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "1 cluster, 5 replicas, 10 sum",
|
|
||||||
args: args{
|
|
||||||
clusters: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sum: 10,
|
|
||||||
},
|
|
||||||
want: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "3 cluster, 1:1:1, 12 sum",
|
|
||||||
args: args{
|
|
||||||
clusters: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember2,
|
|
||||||
Replicas: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember3,
|
|
||||||
Replicas: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sum: 12,
|
|
||||||
},
|
|
||||||
want: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember2,
|
|
||||||
Replicas: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember3,
|
|
||||||
Replicas: 4,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "3 cluster, 1:1:1, 10 sum",
|
|
||||||
args: args{
|
|
||||||
clusters: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember2,
|
|
||||||
Replicas: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember3,
|
|
||||||
Replicas: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sum: 10,
|
|
||||||
},
|
|
||||||
want: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember2,
|
|
||||||
Replicas: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember3,
|
|
||||||
Replicas: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "3 cluster, 1:2:3, 13 sum",
|
|
||||||
args: args{
|
|
||||||
clusters: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember2,
|
|
||||||
Replicas: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember3,
|
|
||||||
Replicas: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sum: 13,
|
|
||||||
},
|
|
||||||
want: []workv1alpha2.TargetCluster{
|
|
||||||
{
|
|
||||||
Name: ClusterMember1,
|
|
||||||
Replicas: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember2,
|
|
||||||
Replicas: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: ClusterMember3,
|
|
||||||
Replicas: 6,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if got := DivideReplicasByTargetCluster(tt.args.clusters, tt.args.sum); !testhelper.IsScheduleResultEqual(got, tt.want) {
|
|
||||||
t.Errorf("DivideReplicasByTargetCluster() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetBindingClusterNames(t *testing.T) {
|
func TestGetBindingClusterNames(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
@ -68,6 +68,81 @@ func (p ClusterWeightInfoList) GetWeightSum() int64 {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dispenser aims to divide replicas among clusters by different weights.
|
||||||
|
type Dispenser struct {
|
||||||
|
// Target replicas, should be a positive integer.
|
||||||
|
NumReplicas int32
|
||||||
|
// Final result.
|
||||||
|
Result []workv1alpha2.TargetCluster
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDispenser will construct a dispenser with target replicas and a prescribed initial result.
|
||||||
|
func NewDispenser(numReplicas int32, init []workv1alpha2.TargetCluster) *Dispenser {
|
||||||
|
cp := make([]workv1alpha2.TargetCluster, len(init))
|
||||||
|
copy(cp, init)
|
||||||
|
return &Dispenser{NumReplicas: numReplicas, Result: cp}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done indicates whether finish dispensing.
|
||||||
|
func (a *Dispenser) Done() bool {
|
||||||
|
return a.NumReplicas == 0 && len(a.Result) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// TakeByWeight divide replicas by a weight list and merge the result into previous result.
|
||||||
|
func (a *Dispenser) TakeByWeight(w ClusterWeightInfoList) {
|
||||||
|
if a.Done() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sum := w.GetWeightSum()
|
||||||
|
if sum == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(w)
|
||||||
|
|
||||||
|
result := make([]workv1alpha2.TargetCluster, 0, w.Len())
|
||||||
|
remain := a.NumReplicas
|
||||||
|
for _, info := range w {
|
||||||
|
replicas := int32(info.Weight * int64(a.NumReplicas) / sum)
|
||||||
|
result = append(result, workv1alpha2.TargetCluster{
|
||||||
|
Name: info.ClusterName,
|
||||||
|
Replicas: replicas,
|
||||||
|
})
|
||||||
|
remain -= replicas
|
||||||
|
}
|
||||||
|
// TODO(Garrybest): take rest replicas by fraction part
|
||||||
|
for i := range result {
|
||||||
|
if remain == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result[i].Replicas++
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
|
||||||
|
a.NumReplicas = remain
|
||||||
|
a.Result = util.MergeTargetClusters(a.Result, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStaticWeightInfoListByTargetClusters constructs a weight list by target cluster slice.
|
||||||
|
func GetStaticWeightInfoListByTargetClusters(tcs []workv1alpha2.TargetCluster) ClusterWeightInfoList {
|
||||||
|
weightList := make(ClusterWeightInfoList, 0, len(tcs))
|
||||||
|
for _, result := range tcs {
|
||||||
|
weightList = append(weightList, ClusterWeightInfo{
|
||||||
|
ClusterName: result.Name,
|
||||||
|
Weight: int64(result.Replicas),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return weightList
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpreadReplicasByTargetClusters divides replicas by the weight of a target cluster list.
|
||||||
|
func SpreadReplicasByTargetClusters(numReplicas int32, tcs, init []workv1alpha2.TargetCluster) []workv1alpha2.TargetCluster {
|
||||||
|
weightList := GetStaticWeightInfoListByTargetClusters(tcs)
|
||||||
|
disp := NewDispenser(numReplicas, init)
|
||||||
|
disp.TakeByWeight(weightList)
|
||||||
|
return disp.Result
|
||||||
|
}
|
||||||
|
|
||||||
// IsBindingScheduled will check if resourceBinding/clusterResourceBinding is successfully scheduled.
|
// IsBindingScheduled will check if resourceBinding/clusterResourceBinding is successfully scheduled.
|
||||||
func IsBindingScheduled(status *workv1alpha2.ResourceBindingStatus) bool {
|
func IsBindingScheduled(status *workv1alpha2.ResourceBindingStatus) bool {
|
||||||
return meta.IsStatusConditionTrue(status.Conditions, workv1alpha2.Scheduled)
|
return meta.IsStatusConditionTrue(status.Conditions, workv1alpha2.Scheduled)
|
||||||
|
|
|
@ -24,8 +24,163 @@ import (
|
||||||
"github.com/karmada-io/karmada/pkg/util/fedinformer/keys"
|
"github.com/karmada-io/karmada/pkg/util/fedinformer/keys"
|
||||||
"github.com/karmada-io/karmada/pkg/util/gclient"
|
"github.com/karmada-io/karmada/pkg/util/gclient"
|
||||||
"github.com/karmada-io/karmada/pkg/util/names"
|
"github.com/karmada-io/karmada/pkg/util/names"
|
||||||
|
testhelper "github.com/karmada-io/karmada/test/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClusterMember1 = "member1"
|
||||||
|
ClusterMember2 = "member2"
|
||||||
|
ClusterMember3 = "member3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDispenseReplicasByTargetClusters(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
clusters []workv1alpha2.TargetCluster
|
||||||
|
sum int32
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want []workv1alpha2.TargetCluster
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty clusters",
|
||||||
|
args: args{
|
||||||
|
clusters: []workv1alpha2.TargetCluster{},
|
||||||
|
sum: 10,
|
||||||
|
},
|
||||||
|
want: []workv1alpha2.TargetCluster{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1 cluster, 5 replicas, 10 sum",
|
||||||
|
args: args{
|
||||||
|
clusters: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sum: 10,
|
||||||
|
},
|
||||||
|
want: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3 cluster, 1:1:1, 12 sum",
|
||||||
|
args: args{
|
||||||
|
clusters: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember2,
|
||||||
|
Replicas: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember3,
|
||||||
|
Replicas: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sum: 12,
|
||||||
|
},
|
||||||
|
want: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember2,
|
||||||
|
Replicas: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember3,
|
||||||
|
Replicas: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3 cluster, 1:1:1, 10 sum",
|
||||||
|
args: args{
|
||||||
|
clusters: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember2,
|
||||||
|
Replicas: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember3,
|
||||||
|
Replicas: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sum: 10,
|
||||||
|
},
|
||||||
|
want: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember2,
|
||||||
|
Replicas: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember3,
|
||||||
|
Replicas: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3 cluster, 1:2:3, 13 sum",
|
||||||
|
args: args{
|
||||||
|
clusters: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember2,
|
||||||
|
Replicas: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember3,
|
||||||
|
Replicas: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sum: 13,
|
||||||
|
},
|
||||||
|
want: []workv1alpha2.TargetCluster{
|
||||||
|
{
|
||||||
|
Name: ClusterMember1,
|
||||||
|
Replicas: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember2,
|
||||||
|
Replicas: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ClusterMember3,
|
||||||
|
Replicas: 7,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := SpreadReplicasByTargetClusters(tt.args.sum, tt.args.clusters, nil); !testhelper.IsScheduleResultEqual(got, tt.want) {
|
||||||
|
t.Errorf("SpreadReplicasByTargetClusters() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHasScheduledReplica(t *testing.T) {
|
func TestHasScheduledReplica(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
Loading…
Reference in New Issue