diff --git a/server/pkg/api/server_add_instance.go b/server/pkg/api/server_add_instance.go index 2351f2b..36f1a82 100644 --- a/server/pkg/api/server_add_instance.go +++ b/server/pkg/api/server_add_instance.go @@ -231,7 +231,9 @@ func schedule(targets []targetHost, limitOverCommit uint64) (*targetHost, error) return nil, ErrNoValidHost } - return &schedulableTargets[rand.Intn(len(schedulableTargets))], nil + minTargets := getMinTargets(schedulableTargets) + + return &minTargets[rand.Intn(len(minTargets))], nil } // parseAlias parse user input @@ -270,3 +272,19 @@ func parseAlias(input string) (*api.InstanceSource, error) { Alias: input, }, nil } + +func getMinTargets(hosts []targetHost) []targetHost { + var minTargets []targetHost + // use lowest over-commit instance + // if there is more than one the lowest ones, it picks up from them randomly + minTargetOverCommit := hosts[0].percentOverCommit + for _, t := range hosts { + if minTargetOverCommit > t.percentOverCommit { + minTargetOverCommit = t.percentOverCommit + minTargets = []targetHost{t} + } else if minTargetOverCommit == t.percentOverCommit { + minTargets = append(minTargets, t) + } + } + return minTargets +} diff --git a/server/pkg/api/server_add_instance_test.go b/server/pkg/api/server_add_instance_test.go new file mode 100644 index 0000000..cfe9022 --- /dev/null +++ b/server/pkg/api/server_add_instance_test.go @@ -0,0 +1,60 @@ +package api + +import ( + "reflect" + "testing" +) + +func Test_getMinTargets(t *testing.T) { + var ( + hostA = targetHost{percentOverCommit: 1} + hostA2 = targetHost{percentOverCommit: 1} + hostB = targetHost{percentOverCommit: 2} + hostC = targetHost{percentOverCommit: 3} + ) + + type args struct { + hosts []targetHost + } + tests := []struct { + name string + args args + want []targetHost + }{ + { + name: "Single host", + args: args{ + hosts: []targetHost{hostA}, + }, + want: []targetHost{hostA}, + }, + { + name: "Multiple host", + args: args{ + hosts: []targetHost{hostA, hostB, hostC}, + }, + want: []targetHost{hostA}, + }, + { + name: "Multiple host (random order)", + args: args{ + hosts: []targetHost{hostC, hostA, hostB}, + }, + want: []targetHost{hostA}, + }, + { + name: "Multiple host result", + args: args{ + hosts: []targetHost{hostA, hostA2, hostB, hostC}, + }, + want: []targetHost{hostA, hostA2}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getMinTargets(tt.args.hosts); !reflect.DeepEqual(got, tt.want) { + t.Errorf("getMinTargets() = %v, want %v", got, tt.want) + } + }) + } +}