diff --git a/cmd/kube-scheduler/app/options/options_test.go b/cmd/kube-scheduler/app/options/options_test.go index b6d6dd15dba3..0f94b9171151 100644 --- a/cmd/kube-scheduler/app/options/options_test.go +++ b/cmd/kube-scheduler/app/options/options_test.go @@ -407,7 +407,7 @@ profiles: { SchedulerName: "default-scheduler", Plugins: defaults.PluginsV1beta2, - PluginConfig: defaults.PluginConfigs, + PluginConfig: defaults.PluginConfigsV1beta2, }, }, }, @@ -480,7 +480,7 @@ profiles: { SchedulerName: "default-scheduler", Plugins: defaults.PluginsV1beta1, - PluginConfig: defaults.PluginConfigs, + PluginConfig: defaults.PluginConfigsV1beta1, }, }, }, @@ -584,7 +584,7 @@ profiles: { SchedulerName: "default-scheduler", Plugins: defaults.PluginsV1beta2, - PluginConfig: defaults.PluginConfigs, + PluginConfig: defaults.PluginConfigsV1beta2, }, }, }, @@ -656,7 +656,7 @@ profiles: { SchedulerName: "default-scheduler", Plugins: defaults.PluginsV1beta2, - PluginConfig: defaults.PluginConfigs, + PluginConfig: defaults.PluginConfigsV1beta2, }, }, }, @@ -748,12 +748,11 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &kubeschedulerconfig.NodeResourcesFitArgs{}, - }, - { - Name: "NodeResourcesLeastAllocated", - Args: &kubeschedulerconfig.NodeResourcesLeastAllocatedArgs{ - Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + Args: &kubeschedulerconfig.NodeResourcesFitArgs{ + ScoringStrategy: &kubeschedulerconfig.ScoringStrategy{ + Type: kubeschedulerconfig.LeastAllocated, + Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, }, }, { @@ -866,7 +865,12 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &kubeschedulerconfig.NodeResourcesFitArgs{}, + Args: &kubeschedulerconfig.NodeResourcesFitArgs{ + ScoringStrategy: &kubeschedulerconfig.ScoringStrategy{ + Type: kubeschedulerconfig.LeastAllocated, + Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, }, { Name: "NodeResourcesLeastAllocated", @@ -946,7 +950,7 @@ profiles: }, }, }, - PluginConfig: defaults.PluginConfigs, + PluginConfig: defaults.PluginConfigsV1beta2, }, { SchedulerName: "bar-profile", @@ -983,12 +987,11 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &kubeschedulerconfig.NodeResourcesFitArgs{}, - }, - { - Name: "NodeResourcesLeastAllocated", - Args: &kubeschedulerconfig.NodeResourcesLeastAllocatedArgs{ - Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + Args: &kubeschedulerconfig.NodeResourcesFitArgs{ + ScoringStrategy: &kubeschedulerconfig.ScoringStrategy{ + Type: kubeschedulerconfig.LeastAllocated, + Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, }, }, { @@ -1063,7 +1066,7 @@ profiles: }, }, }, - PluginConfig: defaults.PluginConfigs, + PluginConfig: defaults.PluginConfigsV1beta1, }, { SchedulerName: "bar-profile", @@ -1100,7 +1103,12 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &kubeschedulerconfig.NodeResourcesFitArgs{}, + Args: &kubeschedulerconfig.NodeResourcesFitArgs{ + ScoringStrategy: &kubeschedulerconfig.ScoringStrategy{ + Type: kubeschedulerconfig.LeastAllocated, + Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, }, { Name: "NodeResourcesLeastAllocated", diff --git a/pkg/scheduler/apis/config/scheme/scheme_test.go b/pkg/scheduler/apis/config/scheme/scheme_test.go index 98a0944b4997..564cdec4cd89 100644 --- a/pkg/scheduler/apis/config/scheme/scheme_test.go +++ b/pkg/scheduler/apis/config/scheme/scheme_test.go @@ -119,7 +119,16 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &config.NodeResourcesFitArgs{IgnoredResources: []string{"foo"}}, + Args: &config.NodeResourcesFitArgs{ + IgnoredResources: []string{"foo"}, + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, + }, }, { Name: "RequestedToCapacityRatio", @@ -207,7 +216,7 @@ profiles: Name: "NodeLabel", Args: &config.NodeLabelArgs{PresentLabels: []string{"bars"}}, }, - }, defaults.PluginConfigs...), + }, defaults.PluginConfigsV1beta1...), }, }, }, @@ -281,12 +290,12 @@ profiles: Raw: []byte(`{"foo":"bar"}`), }, }, - }, defaults.PluginConfigs...), + }, defaults.PluginConfigsV1beta1...), }, }, }, { - name: "empty and no plugin args", + name: "empty and no plugin args v1beta1", data: []byte(` apiVersion: kubescheduler.config.k8s.io/v1beta1 kind: KubeSchedulerConfiguration @@ -325,7 +334,15 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &config.NodeResourcesFitArgs{}, + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, + }, }, {Name: "OutOfTreePlugin"}, { @@ -378,28 +395,12 @@ profiles: - name: NodeResourcesFit args: ignoredResources: ["foo"] - - name: RequestedToCapacityRatio - args: - shape: - - utilization: 1 - name: PodTopologySpread args: defaultConstraints: - maxSkew: 1 topologyKey: zone whenUnsatisfiable: ScheduleAnyway - - name: NodeResourcesLeastAllocated - args: - resources: - - name: cpu - weight: 2 - - name: unknown - weight: 1 - - name: NodeResourcesMostAllocated - args: - resources: - - name: memory - weight: 1 - name: VolumeBinding args: bindTimeoutSeconds: 300 @@ -428,13 +429,15 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &config.NodeResourcesFitArgs{IgnoredResources: []string{"foo"}}, - }, - { - Name: "RequestedToCapacityRatio", - Args: &config.RequestedToCapacityRatioArgs{ - Shape: []config.UtilizationShapePoint{{Utilization: 1}}, - Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + Args: &config.NodeResourcesFitArgs{ + IgnoredResources: []string{"foo"}, + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, }, }, { @@ -446,18 +449,6 @@ profiles: DefaultingType: config.SystemDefaulting, }, }, - { - Name: "NodeResourcesLeastAllocated", - Args: &config.NodeResourcesLeastAllocatedArgs{ - Resources: []config.ResourceSpec{{Name: "cpu", Weight: 2}, {Name: "unknown", Weight: 1}}, - }, - }, - { - Name: "NodeResourcesMostAllocated", - Args: &config.NodeResourcesMostAllocatedArgs{ - Resources: []config.ResourceSpec{{Name: "memory", Weight: 1}}, - }, - }, { Name: "VolumeBinding", Args: &config.VolumeBindingArgs{ @@ -522,12 +513,14 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &config.NodeResourcesFitArgs{}, - }, - { - Name: "NodeResourcesLeastAllocated", - Args: &config.NodeResourcesLeastAllocatedArgs{ - Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, }, }, { @@ -561,37 +554,37 @@ profiles: wantErr: `decoding .profiles[0].pluginConfig[0]: args for plugin DefaultPreemption were not of type DefaultPreemptionArgs.kubescheduler.config.k8s.io, got InterPodAffinityArgs.kubescheduler.config.k8s.io`, }, { - name: "v1beta2 RequestedToCapacityRatioArgs shape encoding is strict", + name: "v1beta2 NodResourcesFitArgs shape encoding is strict", data: []byte(` apiVersion: kubescheduler.config.k8s.io/v1beta2 kind: KubeSchedulerConfiguration profiles: - pluginConfig: - - name: RequestedToCapacityRatio + - name: NodeResourcesFit args: - shape: - - Utilization: 1 - Score: 2 + scoringStrategy: + requestedToCapacityRatio: + shape: + - Score: 2 + Utilization: 1 `), - wantErr: `decoding .profiles[0].pluginConfig[0]: decoding args for plugin RequestedToCapacityRatio: strict decoder error for {"shape":[{"Score":2,"Utilization":1}]}: v1beta2.RequestedToCapacityRatioArgs.Shape: []v1beta2.UtilizationShapePoint: v1beta2.UtilizationShapePoint.ReadObject: found unknown field: Score, error found in #10 byte of ...|:[{"Score":2,"Utiliz|..., bigger context ...|{"shape":[{"Score":2,"Utilization":1}]}|...`, + wantErr: `decoding .profiles[0].pluginConfig[0]: decoding args for plugin NodeResourcesFit: strict decoder error for {"scoringStrategy":{"requestedToCapacityRatio":{"shape":[{"Score":2,"Utilization":1}]}}}: v1beta2.NodeResourcesFitArgs.ScoringStrategy: v1beta2.ScoringStrategy.RequestedToCapacityRatio: v1beta2.RequestedToCapacityRatioParam.Shape: []v1beta2.UtilizationShapePoint: v1beta2.UtilizationShapePoint.ReadObject: found unknown field: Score, error found in #10 byte of ...|:[{"Score":2,"Utiliz|..., bigger context ...|gy":{"requestedToCapacityRatio":{"shape":[{"Score":2,"Utilization":1}]}}}|...`, }, { - name: "v1beta2 RequestedToCapacityRatioArgs resources encoding is strict", + name: "v1beta2 NodeResourcesFitArgs resources encoding is strict", data: []byte(` apiVersion: kubescheduler.config.k8s.io/v1beta2 kind: KubeSchedulerConfiguration profiles: - pluginConfig: - - name: RequestedToCapacityRatio + - name: NodeResourcesFit args: - shape: - - utilization: 1 - score: 2 - resources: - - Name: 1 - Weight: 2 + scoringStrategy: + resources: + - Name: cpu + Weight: 1 `), - wantErr: `decoding .profiles[0].pluginConfig[0]: decoding args for plugin RequestedToCapacityRatio: strict decoder error for {"resources":[{"Name":1,"Weight":2}],"shape":[{"score":2,"utilization":1}]}: v1beta2.RequestedToCapacityRatioArgs.Shape: []v1beta2.UtilizationShapePoint: Resources: []v1beta2.ResourceSpec: v1beta2.ResourceSpec.ReadObject: found unknown field: Name, error found in #10 byte of ...|":[{"Name":1,"Weight|..., bigger context ...|{"resources":[{"Name":1,"Weight":2}],"shape":[{"score":2,"utilization":|...`, + wantErr: `decoding .profiles[0].pluginConfig[0]: decoding args for plugin NodeResourcesFit: strict decoder error for {"scoringStrategy":{"resources":[{"Name":"cpu","Weight":1}]}}: v1beta2.NodeResourcesFitArgs.ScoringStrategy: v1beta2.ScoringStrategy.Resources: []v1beta2.ResourceSpec: v1beta2.ResourceSpec.ReadObject: found unknown field: Name, error found in #10 byte of ...|":[{"Name":"cpu","We|..., bigger context ...|{"scoringStrategy":{"resources":[{"Name":"cpu","Weight":1}]}}|...`, }, { name: "out-of-tree plugin args", @@ -616,7 +609,7 @@ profiles: Raw: []byte(`{"foo":"bar"}`), }, }, - }, defaults.PluginConfigs...), + }, defaults.PluginConfigsV1beta2...), }, }, }, @@ -634,10 +627,6 @@ profiles: - name: NodeResourcesFit - name: OutOfTreePlugin args: - - name: NodeResourcesLeastAllocated - args: - - name: NodeResourcesMostAllocated - args: - name: VolumeBinding args: - name: PodTopologySpread @@ -660,21 +649,17 @@ profiles: }, { Name: "NodeResourcesFit", - Args: &config.NodeResourcesFitArgs{}, - }, - {Name: "OutOfTreePlugin"}, - { - Name: "NodeResourcesLeastAllocated", - Args: &config.NodeResourcesLeastAllocatedArgs{ - Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, - }, - }, - { - Name: "NodeResourcesMostAllocated", - Args: &config.NodeResourcesMostAllocatedArgs{ - Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, }, }, + {Name: "OutOfTreePlugin"}, { Name: "VolumeBinding", Args: &config.VolumeBindingArgs{ @@ -964,24 +949,17 @@ profiles: }, }, { - Name: "RequestedToCapacityRatio", - Args: runtime.RawExtension{ - Object: &v1beta2.RequestedToCapacityRatioArgs{ - Shape: []v1beta2.UtilizationShapePoint{ - {Utilization: 1, Score: 2}, - }, - Resources: []v1beta2.ResourceSpec{ - {Name: "cpu", Weight: 2}, - }, - }, - }, - }, - { - Name: "NodeResourcesLeastAllocated", + Name: "NodeResourcesFit", Args: runtime.RawExtension{ - Object: &v1beta2.NodeResourcesLeastAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "mem", Weight: 2}, + Object: &v1beta2.NodeResourcesFitArgs{ + ScoringStrategy: &v1beta2.ScoringStrategy{ + Type: v1beta2.RequestedToCapacityRatio, + Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}}, + RequestedToCapacityRatio: &v1beta2.RequestedToCapacityRatioParam{ + Shape: []v1beta2.UtilizationShapePoint{ + {Utilization: 1, Score: 2}, + }, + }, }, }, }, @@ -1034,21 +1012,17 @@ profiles: name: VolumeBinding - args: apiVersion: kubescheduler.config.k8s.io/v1beta2 - kind: RequestedToCapacityRatioArgs - resources: - - name: cpu - weight: 2 - shape: - - score: 2 - utilization: 1 - name: RequestedToCapacityRatio - - args: - apiVersion: kubescheduler.config.k8s.io/v1beta2 - kind: NodeResourcesLeastAllocatedArgs - resources: - - name: mem - weight: 2 - name: NodeResourcesLeastAllocated + kind: NodeResourcesFitArgs + scoringStrategy: + requestedToCapacityRatio: + shape: + - score: 2 + utilization: 1 + resources: + - name: cpu + weight: 1 + type: RequestedToCapacityRatio + name: NodeResourcesFit - args: apiVersion: kubescheduler.config.k8s.io/v1beta2 kind: PodTopologySpreadArgs @@ -1073,9 +1047,12 @@ profiles: }, }, { - Name: "NodeResourcesMostAllocated", - Args: &config.NodeResourcesMostAllocatedArgs{ - Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}}, + Name: "NodeResourcesFit", + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}}, + }, }, }, { @@ -1131,11 +1108,13 @@ profiles: name: InterPodAffinity - args: apiVersion: kubescheduler.config.k8s.io/v1beta2 - kind: NodeResourcesMostAllocatedArgs - resources: - - name: cpu - weight: 1 - name: NodeResourcesMostAllocated + kind: NodeResourcesFitArgs + scoringStrategy: + resources: + - name: cpu + weight: 1 + type: LeastAllocated + name: NodeResourcesFit - args: apiVersion: kubescheduler.config.k8s.io/v1beta2 bindTimeoutSeconds: 300 diff --git a/pkg/scheduler/apis/config/testing/defaults/defaults.go b/pkg/scheduler/apis/config/testing/defaults/defaults.go index ad087a5371a7..0aeb66187d22 100644 --- a/pkg/scheduler/apis/config/testing/defaults/defaults.go +++ b/pkg/scheduler/apis/config/testing/defaults/defaults.go @@ -102,6 +102,55 @@ var PluginsV1beta1 = &config.Plugins{ }, } +// PluginConfigsV1beta1 default plugin configurations. This could get versioned, but since +// all available versions produce the same defaults, we just have one for now. +var PluginConfigsV1beta1 = []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.DefaultPreemptionArgs{ + MinCandidateNodesPercentage: 10, + MinCandidateNodesAbsolute: 100, + }, + }, + { + Name: "InterPodAffinity", + Args: &config.InterPodAffinityArgs{ + HardPodAffinityWeight: 1, + }, + }, + { + Name: "NodeAffinity", + Args: &config.NodeAffinityArgs{}, + }, + { + Name: "NodeResourcesFit", + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, + }, + { + Name: "NodeResourcesLeastAllocated", + Args: &config.NodeResourcesLeastAllocatedArgs{ + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{ + DefaultingType: config.SystemDefaulting, + }, + }, + { + Name: "VolumeBinding", + Args: &config.VolumeBindingArgs{ + BindTimeoutSeconds: 600, + }, + }, +} + // PluginsV1beta2 default set of v1beta2 plugins. var PluginsV1beta2 = &config.Plugins{ QueueSort: config.PluginSet{ @@ -156,7 +205,7 @@ var PluginsV1beta2 = &config.Plugins{ {Name: names.NodeResourcesBalancedAllocation, Weight: 1}, {Name: names.ImageLocality, Weight: 1}, {Name: names.InterPodAffinity, Weight: 1}, - {Name: names.NodeResourcesLeastAllocated, Weight: 1}, + {Name: names.NodeResourcesFit, Weight: 1}, {Name: names.NodeAffinity, Weight: 1}, // Weight is doubled because: // - This is a score coming from user preference. @@ -182,9 +231,9 @@ var PluginsV1beta2 = &config.Plugins{ }, } -// PluginConfigs default plugin configurations. This could get versioned, but since +// PluginConfigsV1beta2 default plugin configurations. This could get versioned, but since // all available versions produce the same defaults, we just have one for now. -var PluginConfigs = []config.PluginConfig{ +var PluginConfigsV1beta2 = []config.PluginConfig{ { Name: "DefaultPreemption", Args: &config.DefaultPreemptionArgs{ @@ -204,12 +253,11 @@ var PluginConfigs = []config.PluginConfig{ }, { Name: "NodeResourcesFit", - Args: &config.NodeResourcesFitArgs{}, - }, - { - Name: "NodeResourcesLeastAllocated", - Args: &config.NodeResourcesLeastAllocatedArgs{ - Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, }, }, { diff --git a/pkg/scheduler/apis/config/types_pluginargs.go b/pkg/scheduler/apis/config/types_pluginargs.go index cdcdb02cac3e..de3abacb4a32 100644 --- a/pkg/scheduler/apis/config/types_pluginargs.go +++ b/pkg/scheduler/apis/config/types_pluginargs.go @@ -88,6 +88,9 @@ type NodeResourcesFitArgs struct { // with "example.com", such as "example.com/aaa" and "example.com/bbb". // A resource group name can't contain '/'. IgnoredResourceGroups []string + + // ScoringStrategy selects the node resource scoring strategy. + ScoringStrategy *ScoringStrategy } // PodTopologySpreadConstraintsDefaulting defines how to set default constraints @@ -227,3 +230,37 @@ type NodeAffinityArgs struct { // a specific Node (such as Daemonset Pods) might remain unschedulable. AddedAffinity *v1.NodeAffinity } + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allcoated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allcoated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + Resources []ResourceSpec + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + Shape []UtilizationShapePoint +} diff --git a/pkg/scheduler/apis/config/v1beta1/defaults.go b/pkg/scheduler/apis/config/v1beta1/defaults.go index 5cb2d806337b..b5961b5d7de5 100644 --- a/pkg/scheduler/apis/config/v1beta1/defaults.go +++ b/pkg/scheduler/apis/config/v1beta1/defaults.go @@ -267,6 +267,13 @@ func SetDefaults_RequestedToCapacityRatioArgs(obj *v1beta1.RequestedToCapacityRa // If no resources specified, used the default set. obj.Resources = append(obj.Resources, defaultResourceSpec...) } + + // If resource weight is 0, use default weight(1) instead. + for i := range obj.Resources { + if obj.Resources[i].Weight == 0 { + obj.Resources[i].Weight = 1 + } + } } func SetDefaults_VolumeBindingArgs(obj *v1beta1.VolumeBindingArgs) { @@ -290,3 +297,21 @@ func SetDefaults_PodTopologySpreadArgs(obj *v1beta1.PodTopologySpreadArgs) { obj.DefaultingType = v1beta1.ListDefaulting } } + +func SetDefaults_NodeResourcesFitArgs(obj *v1beta1.NodeResourcesFitArgs) { + if obj.ScoringStrategy == nil { + obj.ScoringStrategy = &v1beta1.ScoringStrategy{ + Type: v1beta1.ScoringStrategyType(config.LeastAllocated), + Resources: defaultResourceSpec, + } + } + if len(obj.ScoringStrategy.Resources) == 0 { + // If no resources specified, use the default set. + obj.ScoringStrategy.Resources = append(obj.ScoringStrategy.Resources, defaultResourceSpec...) + } + for i := range obj.ScoringStrategy.Resources { + if obj.ScoringStrategy.Resources[i].Weight == 0 { + obj.ScoringStrategy.Resources[i].Weight = 1 + } + } +} diff --git a/pkg/scheduler/apis/config/v1beta1/defaults_test.go b/pkg/scheduler/apis/config/v1beta1/defaults_test.go index 8cb7d9621e54..b094603ecce6 100644 --- a/pkg/scheduler/apis/config/v1beta1/defaults_test.go +++ b/pkg/scheduler/apis/config/v1beta1/defaults_test.go @@ -75,6 +75,10 @@ var pluginConfigs = []v1beta1.PluginConfig{ Kind: "NodeResourcesFitArgs", APIVersion: "kubescheduler.config.k8s.io/v1beta1", }, + ScoringStrategy: &v1beta1.ScoringStrategy{ + Type: v1beta1.LeastAllocated, + Resources: []v1beta1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, }}, }, { @@ -283,6 +287,10 @@ func TestSchedulerDefaults(t *testing.T) { Kind: "NodeResourcesFitArgs", APIVersion: "kubescheduler.config.k8s.io/v1beta1", }, + ScoringStrategy: &v1beta1.ScoringStrategy{ + Type: v1beta1.LeastAllocated, + Resources: []v1beta1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, }}, }, { @@ -668,6 +676,30 @@ func TestPluginArgsDefaults(t *testing.T) { DefaultingType: v1beta1.ListDefaulting, }, }, + { + name: "NodeResourcesFitArgs not set", + in: &v1beta1.NodeResourcesFitArgs{}, + want: &v1beta1.NodeResourcesFitArgs{ + ScoringStrategy: &v1beta1.ScoringStrategy{ + Type: v1beta1.LeastAllocated, + Resources: defaultResourceSpec, + }, + }, + }, + { + name: "NodeResourcesFitArgs Resources empty", + in: &v1beta1.NodeResourcesFitArgs{ + ScoringStrategy: &v1beta1.ScoringStrategy{ + Type: v1beta1.MostAllocated, + }, + }, + want: &v1beta1.NodeResourcesFitArgs{ + ScoringStrategy: &v1beta1.ScoringStrategy{ + Type: v1beta1.MostAllocated, + Resources: defaultResourceSpec, + }, + }, + }, } for _, tc := range tests { scheme := runtime.NewScheme() diff --git a/pkg/scheduler/apis/config/v1beta1/zz_generated.conversion.go b/pkg/scheduler/apis/config/v1beta1/zz_generated.conversion.go index b7011164fcbd..863bb6fcbb4e 100644 --- a/pkg/scheduler/apis/config/v1beta1/zz_generated.conversion.go +++ b/pkg/scheduler/apis/config/v1beta1/zz_generated.conversion.go @@ -175,6 +175,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1beta1.RequestedToCapacityRatioParam)(nil), (*config.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(a.(*v1beta1.RequestedToCapacityRatioParam), b.(*config.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.RequestedToCapacityRatioParam)(nil), (*v1beta1.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_RequestedToCapacityRatioParam_To_v1beta1_RequestedToCapacityRatioParam(a.(*config.RequestedToCapacityRatioParam), b.(*v1beta1.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1beta1.ResourceSpec)(nil), (*config.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_ResourceSpec_To_config_ResourceSpec(a.(*v1beta1.ResourceSpec), b.(*config.ResourceSpec), scope) }); err != nil { @@ -185,6 +195,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1beta1.ScoringStrategy)(nil), (*config.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_ScoringStrategy_To_config_ScoringStrategy(a.(*v1beta1.ScoringStrategy), b.(*config.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ScoringStrategy)(nil), (*v1beta1.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ScoringStrategy_To_v1beta1_ScoringStrategy(a.(*config.ScoringStrategy), b.(*v1beta1.ScoringStrategy), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1beta1.ServiceAffinityArgs)(nil), (*config.ServiceAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_ServiceAffinityArgs_To_config_ServiceAffinityArgs(a.(*v1beta1.ServiceAffinityArgs), b.(*config.ServiceAffinityArgs), scope) }); err != nil { @@ -538,6 +558,7 @@ func Convert_config_NodeLabelArgs_To_v1beta1_NodeLabelArgs(in *config.NodeLabelA func autoConvert_v1beta1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1beta1.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*config.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) return nil } @@ -549,6 +570,7 @@ func Convert_v1beta1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1b func autoConvert_config_NodeResourcesFitArgs_To_v1beta1_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1beta1.NodeResourcesFitArgs, s conversion.Scope) error { out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*v1beta1.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) return nil } @@ -780,6 +802,26 @@ func Convert_config_RequestedToCapacityRatioArgs_To_v1beta1_RequestedToCapacityR return autoConvert_config_RequestedToCapacityRatioArgs_To_v1beta1_RequestedToCapacityRatioArgs(in, out, s) } +func autoConvert_v1beta1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta1.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1beta1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_v1beta1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta1.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_v1beta1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_config_RequestedToCapacityRatioParam_To_v1beta1_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta1.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]v1beta1.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_RequestedToCapacityRatioParam_To_v1beta1_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_config_RequestedToCapacityRatioParam_To_v1beta1_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta1.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_config_RequestedToCapacityRatioParam_To_v1beta1_RequestedToCapacityRatioParam(in, out, s) +} + func autoConvert_v1beta1_ResourceSpec_To_config_ResourceSpec(in *v1beta1.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { out.Name = in.Name out.Weight = in.Weight @@ -802,6 +844,30 @@ func Convert_config_ResourceSpec_To_v1beta1_ResourceSpec(in *config.ResourceSpec return autoConvert_config_ResourceSpec_To_v1beta1_ResourceSpec(in, out, s) } +func autoConvert_v1beta1_ScoringStrategy_To_config_ScoringStrategy(in *v1beta1.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + out.Type = config.ScoringStrategyType(in.Type) + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*config.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_v1beta1_ScoringStrategy_To_config_ScoringStrategy is an autogenerated conversion function. +func Convert_v1beta1_ScoringStrategy_To_config_ScoringStrategy(in *v1beta1.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + return autoConvert_v1beta1_ScoringStrategy_To_config_ScoringStrategy(in, out, s) +} + +func autoConvert_config_ScoringStrategy_To_v1beta1_ScoringStrategy(in *config.ScoringStrategy, out *v1beta1.ScoringStrategy, s conversion.Scope) error { + out.Type = v1beta1.ScoringStrategyType(in.Type) + out.Resources = *(*[]v1beta1.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*v1beta1.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_config_ScoringStrategy_To_v1beta1_ScoringStrategy is an autogenerated conversion function. +func Convert_config_ScoringStrategy_To_v1beta1_ScoringStrategy(in *config.ScoringStrategy, out *v1beta1.ScoringStrategy, s conversion.Scope) error { + return autoConvert_config_ScoringStrategy_To_v1beta1_ScoringStrategy(in, out, s) +} + func autoConvert_v1beta1_ServiceAffinityArgs_To_config_ServiceAffinityArgs(in *v1beta1.ServiceAffinityArgs, out *config.ServiceAffinityArgs, s conversion.Scope) error { out.AffinityLabels = *(*[]string)(unsafe.Pointer(&in.AffinityLabels)) out.AntiAffinityLabelsPreference = *(*[]string)(unsafe.Pointer(&in.AntiAffinityLabelsPreference)) diff --git a/pkg/scheduler/apis/config/v1beta1/zz_generated.defaults.go b/pkg/scheduler/apis/config/v1beta1/zz_generated.defaults.go index cd3c50689bb5..128ab07a0d75 100644 --- a/pkg/scheduler/apis/config/v1beta1/zz_generated.defaults.go +++ b/pkg/scheduler/apis/config/v1beta1/zz_generated.defaults.go @@ -34,6 +34,7 @@ func RegisterDefaults(scheme *runtime.Scheme) error { scheme.AddTypeDefaultingFunc(&v1beta1.KubeSchedulerConfiguration{}, func(obj interface{}) { SetObjectDefaults_KubeSchedulerConfiguration(obj.(*v1beta1.KubeSchedulerConfiguration)) }) + scheme.AddTypeDefaultingFunc(&v1beta1.NodeResourcesFitArgs{}, func(obj interface{}) { SetObjectDefaults_NodeResourcesFitArgs(obj.(*v1beta1.NodeResourcesFitArgs)) }) scheme.AddTypeDefaultingFunc(&v1beta1.NodeResourcesLeastAllocatedArgs{}, func(obj interface{}) { SetObjectDefaults_NodeResourcesLeastAllocatedArgs(obj.(*v1beta1.NodeResourcesLeastAllocatedArgs)) }) @@ -60,6 +61,10 @@ func SetObjectDefaults_KubeSchedulerConfiguration(in *v1beta1.KubeSchedulerConfi SetDefaults_KubeSchedulerConfiguration(in) } +func SetObjectDefaults_NodeResourcesFitArgs(in *v1beta1.NodeResourcesFitArgs) { + SetDefaults_NodeResourcesFitArgs(in) +} + func SetObjectDefaults_NodeResourcesLeastAllocatedArgs(in *v1beta1.NodeResourcesLeastAllocatedArgs) { SetDefaults_NodeResourcesLeastAllocatedArgs(in) } diff --git a/pkg/scheduler/apis/config/v1beta2/default_plugins.go b/pkg/scheduler/apis/config/v1beta2/default_plugins.go index d6a9cb602725..accbddd1eaf7 100644 --- a/pkg/scheduler/apis/config/v1beta2/default_plugins.go +++ b/pkg/scheduler/apis/config/v1beta2/default_plugins.go @@ -81,11 +81,11 @@ func getDefaultPlugins() *v1beta2.Plugins { {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)}, {Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)}, {Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)}, - {Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32Ptr(1)}, {Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)}, // Weight is doubled because: // - This is a score coming from user preference. - // - It makes its signal comparable to NodeResourcesLeastAllocated. + // - It makes its signal comparable to NodeResourcesFit.LeastAllocated. {Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)}, {Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)}, }, diff --git a/pkg/scheduler/apis/config/v1beta2/default_plugins_test.go b/pkg/scheduler/apis/config/v1beta2/default_plugins_test.go index d4b4ca11185f..d1f609d0758a 100644 --- a/pkg/scheduler/apis/config/v1beta2/default_plugins_test.go +++ b/pkg/scheduler/apis/config/v1beta2/default_plugins_test.go @@ -90,7 +90,7 @@ func TestApplyFeatureGates(t *testing.T) { {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)}, {Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)}, {Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)}, - {Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32Ptr(1)}, {Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)}, {Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)}, {Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)}, @@ -172,7 +172,7 @@ func TestApplyFeatureGates(t *testing.T) { {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)}, {Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)}, {Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)}, - {Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32Ptr(1)}, {Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)}, {Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)}, {Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)}, diff --git a/pkg/scheduler/apis/config/v1beta2/defaults.go b/pkg/scheduler/apis/config/v1beta2/defaults.go index f8f18e028158..fd62188fbbdf 100644 --- a/pkg/scheduler/apis/config/v1beta2/defaults.go +++ b/pkg/scheduler/apis/config/v1beta2/defaults.go @@ -241,27 +241,6 @@ func SetDefaults_InterPodAffinityArgs(obj *v1beta2.InterPodAffinityArgs) { } } -func SetDefaults_NodeResourcesLeastAllocatedArgs(obj *v1beta2.NodeResourcesLeastAllocatedArgs) { - if len(obj.Resources) == 0 { - // If no resources specified, used the default set. - obj.Resources = append(obj.Resources, defaultResourceSpec...) - } -} - -func SetDefaults_NodeResourcesMostAllocatedArgs(obj *v1beta2.NodeResourcesMostAllocatedArgs) { - if len(obj.Resources) == 0 { - // If no resources specified, used the default set. - obj.Resources = append(obj.Resources, defaultResourceSpec...) - } -} - -func SetDefaults_RequestedToCapacityRatioArgs(obj *v1beta2.RequestedToCapacityRatioArgs) { - if len(obj.Resources) == 0 { - // If no resources specified, used the default set. - obj.Resources = append(obj.Resources, defaultResourceSpec...) - } -} - func SetDefaults_VolumeBindingArgs(obj *v1beta2.VolumeBindingArgs) { if obj.BindTimeoutSeconds == nil { obj.BindTimeoutSeconds = pointer.Int64Ptr(600) @@ -279,3 +258,21 @@ func SetDefaults_PodTopologySpreadArgs(obj *v1beta2.PodTopologySpreadArgs) { obj.DefaultingType = v1beta2.ListDefaulting } } + +func SetDefaults_NodeResourcesFitArgs(obj *v1beta2.NodeResourcesFitArgs) { + if obj.ScoringStrategy == nil { + obj.ScoringStrategy = &v1beta2.ScoringStrategy{ + Type: v1beta2.ScoringStrategyType(config.LeastAllocated), + Resources: defaultResourceSpec, + } + } + if len(obj.ScoringStrategy.Resources) == 0 { + // If no resources specified, use the default set. + obj.ScoringStrategy.Resources = append(obj.ScoringStrategy.Resources, defaultResourceSpec...) + } + for i := range obj.ScoringStrategy.Resources { + if obj.ScoringStrategy.Resources[i].Weight == 0 { + obj.ScoringStrategy.Resources[i].Weight = 1 + } + } +} diff --git a/pkg/scheduler/apis/config/v1beta2/defaults_test.go b/pkg/scheduler/apis/config/v1beta2/defaults_test.go index 9b41bd0dadfc..42a84030c077 100644 --- a/pkg/scheduler/apis/config/v1beta2/defaults_test.go +++ b/pkg/scheduler/apis/config/v1beta2/defaults_test.go @@ -76,16 +76,10 @@ var pluginConfigs = []v1beta2.PluginConfig{ Kind: "NodeResourcesFitArgs", APIVersion: "kubescheduler.config.k8s.io/v1beta2", }, - }}, - }, - { - Name: "NodeResourcesLeastAllocated", - Args: runtime.RawExtension{Object: &v1beta2.NodeResourcesLeastAllocatedArgs{ - TypeMeta: metav1.TypeMeta{ - Kind: "NodeResourcesLeastAllocatedArgs", - APIVersion: "kubescheduler.config.k8s.io/v1beta2", + ScoringStrategy: &v1beta2.ScoringStrategy{ + Type: v1beta2.LeastAllocated, + Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, }, - Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, }}, }, { @@ -286,16 +280,10 @@ func TestSchedulerDefaults(t *testing.T) { Kind: "NodeResourcesFitArgs", APIVersion: "kubescheduler.config.k8s.io/v1beta2", }, - }}, - }, - { - Name: "NodeResourcesLeastAllocated", - Args: runtime.RawExtension{Object: &v1beta2.NodeResourcesLeastAllocatedArgs{ - TypeMeta: metav1.TypeMeta{ - Kind: "NodeResourcesLeastAllocatedArgs", - APIVersion: "kubescheduler.config.k8s.io/v1beta2", + ScoringStrategy: &v1beta2.ScoringStrategy{ + Type: v1beta2.LeastAllocated, + Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, }, - Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, }}, }, { @@ -375,7 +363,7 @@ func TestSchedulerDefaults(t *testing.T) { {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)}, {Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)}, {Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)}, - {Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32Ptr(1)}, {Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)}, {Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)}, {Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)}, @@ -623,75 +611,6 @@ func TestPluginArgsDefaults(t *testing.T) { HardPodAffinityWeight: pointer.Int32Ptr(5), }, }, - { - name: "NodeResourcesLeastAllocatedArgs resources empty", - in: &v1beta2.NodeResourcesLeastAllocatedArgs{}, - want: &v1beta2.NodeResourcesLeastAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "cpu", Weight: 1}, - {Name: "memory", Weight: 1}, - }, - }, - }, - { - name: "NodeResourcesLeastAllocatedArgs resources with value", - in: &v1beta2.NodeResourcesLeastAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "resource", Weight: 2}, - }, - }, - want: &v1beta2.NodeResourcesLeastAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "resource", Weight: 2}, - }, - }, - }, - { - name: "NodeResourcesMostAllocatedArgs resources empty", - in: &v1beta2.NodeResourcesMostAllocatedArgs{}, - want: &v1beta2.NodeResourcesMostAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "cpu", Weight: 1}, - {Name: "memory", Weight: 1}, - }, - }, - }, - { - name: "NodeResourcesMostAllocatedArgs resources with value", - in: &v1beta2.NodeResourcesMostAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "resource", Weight: 2}, - }, - }, - want: &v1beta2.NodeResourcesMostAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "resource", Weight: 2}, - }, - }, - }, - { - name: "NodeResourcesMostAllocatedArgs resources empty", - in: &v1beta2.NodeResourcesMostAllocatedArgs{}, - want: &v1beta2.NodeResourcesMostAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "cpu", Weight: 1}, - {Name: "memory", Weight: 1}, - }, - }, - }, - { - name: "NodeResourcesMostAllocatedArgs resources with value", - in: &v1beta2.NodeResourcesMostAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "resource", Weight: 2}, - }, - }, - want: &v1beta2.NodeResourcesMostAllocatedArgs{ - Resources: []v1beta2.ResourceSpec{ - {Name: "resource", Weight: 2}, - }, - }, - }, { name: "PodTopologySpreadArgs resources empty", in: &v1beta2.PodTopologySpreadArgs{}, @@ -731,6 +650,30 @@ func TestPluginArgsDefaults(t *testing.T) { DefaultingType: v1beta2.ListDefaulting, }, }, + { + name: "NodeResourcesFitArgs not set", + in: &v1beta2.NodeResourcesFitArgs{}, + want: &v1beta2.NodeResourcesFitArgs{ + ScoringStrategy: &v1beta2.ScoringStrategy{ + Type: v1beta2.LeastAllocated, + Resources: defaultResourceSpec, + }, + }, + }, + { + name: "NodeResourcesFitArgs Resources empty", + in: &v1beta2.NodeResourcesFitArgs{ + ScoringStrategy: &v1beta2.ScoringStrategy{ + Type: v1beta2.MostAllocated, + }, + }, + want: &v1beta2.NodeResourcesFitArgs{ + ScoringStrategy: &v1beta2.ScoringStrategy{ + Type: v1beta2.MostAllocated, + Resources: defaultResourceSpec, + }, + }, + }, } for _, tc := range tests { scheme := runtime.NewScheme() diff --git a/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go b/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go index 4362b96fa711..76656e11de34 100644 --- a/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go +++ b/pkg/scheduler/apis/config/v1beta2/zz_generated.conversion.go @@ -100,26 +100,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta2.NodeResourcesLeastAllocatedArgs)(nil), (*config.NodeResourcesLeastAllocatedArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_NodeResourcesLeastAllocatedArgs_To_config_NodeResourcesLeastAllocatedArgs(a.(*v1beta2.NodeResourcesLeastAllocatedArgs), b.(*config.NodeResourcesLeastAllocatedArgs), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*config.NodeResourcesLeastAllocatedArgs)(nil), (*v1beta2.NodeResourcesLeastAllocatedArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_config_NodeResourcesLeastAllocatedArgs_To_v1beta2_NodeResourcesLeastAllocatedArgs(a.(*config.NodeResourcesLeastAllocatedArgs), b.(*v1beta2.NodeResourcesLeastAllocatedArgs), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta2.NodeResourcesMostAllocatedArgs)(nil), (*config.NodeResourcesMostAllocatedArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_NodeResourcesMostAllocatedArgs_To_config_NodeResourcesMostAllocatedArgs(a.(*v1beta2.NodeResourcesMostAllocatedArgs), b.(*config.NodeResourcesMostAllocatedArgs), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*config.NodeResourcesMostAllocatedArgs)(nil), (*v1beta2.NodeResourcesMostAllocatedArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_config_NodeResourcesMostAllocatedArgs_To_v1beta2_NodeResourcesMostAllocatedArgs(a.(*config.NodeResourcesMostAllocatedArgs), b.(*v1beta2.NodeResourcesMostAllocatedArgs), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*v1beta2.Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_Plugin_To_config_Plugin(a.(*v1beta2.Plugin), b.(*config.Plugin), scope) }); err != nil { @@ -170,13 +150,13 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta2.RequestedToCapacityRatioArgs)(nil), (*config.RequestedToCapacityRatioArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta2_RequestedToCapacityRatioArgs_To_config_RequestedToCapacityRatioArgs(a.(*v1beta2.RequestedToCapacityRatioArgs), b.(*config.RequestedToCapacityRatioArgs), scope) + if err := s.AddGeneratedConversionFunc((*v1beta2.RequestedToCapacityRatioParam)(nil), (*config.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(a.(*v1beta2.RequestedToCapacityRatioParam), b.(*config.RequestedToCapacityRatioParam), scope) }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*config.RequestedToCapacityRatioArgs)(nil), (*v1beta2.RequestedToCapacityRatioArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_config_RequestedToCapacityRatioArgs_To_v1beta2_RequestedToCapacityRatioArgs(a.(*config.RequestedToCapacityRatioArgs), b.(*v1beta2.RequestedToCapacityRatioArgs), scope) + if err := s.AddGeneratedConversionFunc((*config.RequestedToCapacityRatioParam)(nil), (*v1beta2.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(a.(*config.RequestedToCapacityRatioParam), b.(*v1beta2.RequestedToCapacityRatioParam), scope) }); err != nil { return err } @@ -190,6 +170,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1beta2.ScoringStrategy)(nil), (*config.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(a.(*v1beta2.ScoringStrategy), b.(*config.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ScoringStrategy)(nil), (*v1beta2.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(a.(*config.ScoringStrategy), b.(*v1beta2.ScoringStrategy), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1beta2.UtilizationShapePoint)(nil), (*config.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta2_UtilizationShapePoint_To_config_UtilizationShapePoint(a.(*v1beta2.UtilizationShapePoint), b.(*config.UtilizationShapePoint), scope) }); err != nil { @@ -492,6 +482,7 @@ func Convert_config_NodeAffinityArgs_To_v1beta2_NodeAffinityArgs(in *config.Node func autoConvert_v1beta2_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1beta2.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*config.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) return nil } @@ -503,6 +494,7 @@ func Convert_v1beta2_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1b func autoConvert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1beta2.NodeResourcesFitArgs, s conversion.Scope) error { out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*v1beta2.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) return nil } @@ -511,46 +503,6 @@ func Convert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs(in *con return autoConvert_config_NodeResourcesFitArgs_To_v1beta2_NodeResourcesFitArgs(in, out, s) } -func autoConvert_v1beta2_NodeResourcesLeastAllocatedArgs_To_config_NodeResourcesLeastAllocatedArgs(in *v1beta2.NodeResourcesLeastAllocatedArgs, out *config.NodeResourcesLeastAllocatedArgs, s conversion.Scope) error { - out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) - return nil -} - -// Convert_v1beta2_NodeResourcesLeastAllocatedArgs_To_config_NodeResourcesLeastAllocatedArgs is an autogenerated conversion function. -func Convert_v1beta2_NodeResourcesLeastAllocatedArgs_To_config_NodeResourcesLeastAllocatedArgs(in *v1beta2.NodeResourcesLeastAllocatedArgs, out *config.NodeResourcesLeastAllocatedArgs, s conversion.Scope) error { - return autoConvert_v1beta2_NodeResourcesLeastAllocatedArgs_To_config_NodeResourcesLeastAllocatedArgs(in, out, s) -} - -func autoConvert_config_NodeResourcesLeastAllocatedArgs_To_v1beta2_NodeResourcesLeastAllocatedArgs(in *config.NodeResourcesLeastAllocatedArgs, out *v1beta2.NodeResourcesLeastAllocatedArgs, s conversion.Scope) error { - out.Resources = *(*[]v1beta2.ResourceSpec)(unsafe.Pointer(&in.Resources)) - return nil -} - -// Convert_config_NodeResourcesLeastAllocatedArgs_To_v1beta2_NodeResourcesLeastAllocatedArgs is an autogenerated conversion function. -func Convert_config_NodeResourcesLeastAllocatedArgs_To_v1beta2_NodeResourcesLeastAllocatedArgs(in *config.NodeResourcesLeastAllocatedArgs, out *v1beta2.NodeResourcesLeastAllocatedArgs, s conversion.Scope) error { - return autoConvert_config_NodeResourcesLeastAllocatedArgs_To_v1beta2_NodeResourcesLeastAllocatedArgs(in, out, s) -} - -func autoConvert_v1beta2_NodeResourcesMostAllocatedArgs_To_config_NodeResourcesMostAllocatedArgs(in *v1beta2.NodeResourcesMostAllocatedArgs, out *config.NodeResourcesMostAllocatedArgs, s conversion.Scope) error { - out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) - return nil -} - -// Convert_v1beta2_NodeResourcesMostAllocatedArgs_To_config_NodeResourcesMostAllocatedArgs is an autogenerated conversion function. -func Convert_v1beta2_NodeResourcesMostAllocatedArgs_To_config_NodeResourcesMostAllocatedArgs(in *v1beta2.NodeResourcesMostAllocatedArgs, out *config.NodeResourcesMostAllocatedArgs, s conversion.Scope) error { - return autoConvert_v1beta2_NodeResourcesMostAllocatedArgs_To_config_NodeResourcesMostAllocatedArgs(in, out, s) -} - -func autoConvert_config_NodeResourcesMostAllocatedArgs_To_v1beta2_NodeResourcesMostAllocatedArgs(in *config.NodeResourcesMostAllocatedArgs, out *v1beta2.NodeResourcesMostAllocatedArgs, s conversion.Scope) error { - out.Resources = *(*[]v1beta2.ResourceSpec)(unsafe.Pointer(&in.Resources)) - return nil -} - -// Convert_config_NodeResourcesMostAllocatedArgs_To_v1beta2_NodeResourcesMostAllocatedArgs is an autogenerated conversion function. -func Convert_config_NodeResourcesMostAllocatedArgs_To_v1beta2_NodeResourcesMostAllocatedArgs(in *config.NodeResourcesMostAllocatedArgs, out *v1beta2.NodeResourcesMostAllocatedArgs, s conversion.Scope) error { - return autoConvert_config_NodeResourcesMostAllocatedArgs_To_v1beta2_NodeResourcesMostAllocatedArgs(in, out, s) -} - func autoConvert_v1beta2_Plugin_To_config_Plugin(in *v1beta2.Plugin, out *config.Plugin, s conversion.Scope) error { out.Name = in.Name if err := v1.Convert_Pointer_int32_To_int32(&in.Weight, &out.Weight, s); err != nil { @@ -771,26 +723,24 @@ func Convert_config_PodTopologySpreadArgs_To_v1beta2_PodTopologySpreadArgs(in *c return autoConvert_config_PodTopologySpreadArgs_To_v1beta2_PodTopologySpreadArgs(in, out, s) } -func autoConvert_v1beta2_RequestedToCapacityRatioArgs_To_config_RequestedToCapacityRatioArgs(in *v1beta2.RequestedToCapacityRatioArgs, out *config.RequestedToCapacityRatioArgs, s conversion.Scope) error { +func autoConvert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta2.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) - out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) return nil } -// Convert_v1beta2_RequestedToCapacityRatioArgs_To_config_RequestedToCapacityRatioArgs is an autogenerated conversion function. -func Convert_v1beta2_RequestedToCapacityRatioArgs_To_config_RequestedToCapacityRatioArgs(in *v1beta2.RequestedToCapacityRatioArgs, out *config.RequestedToCapacityRatioArgs, s conversion.Scope) error { - return autoConvert_v1beta2_RequestedToCapacityRatioArgs_To_config_RequestedToCapacityRatioArgs(in, out, s) +// Convert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1beta2.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_v1beta2_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in, out, s) } -func autoConvert_config_RequestedToCapacityRatioArgs_To_v1beta2_RequestedToCapacityRatioArgs(in *config.RequestedToCapacityRatioArgs, out *v1beta2.RequestedToCapacityRatioArgs, s conversion.Scope) error { +func autoConvert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta2.RequestedToCapacityRatioParam, s conversion.Scope) error { out.Shape = *(*[]v1beta2.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) - out.Resources = *(*[]v1beta2.ResourceSpec)(unsafe.Pointer(&in.Resources)) return nil } -// Convert_config_RequestedToCapacityRatioArgs_To_v1beta2_RequestedToCapacityRatioArgs is an autogenerated conversion function. -func Convert_config_RequestedToCapacityRatioArgs_To_v1beta2_RequestedToCapacityRatioArgs(in *config.RequestedToCapacityRatioArgs, out *v1beta2.RequestedToCapacityRatioArgs, s conversion.Scope) error { - return autoConvert_config_RequestedToCapacityRatioArgs_To_v1beta2_RequestedToCapacityRatioArgs(in, out, s) +// Convert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1beta2.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_config_RequestedToCapacityRatioParam_To_v1beta2_RequestedToCapacityRatioParam(in, out, s) } func autoConvert_v1beta2_ResourceSpec_To_config_ResourceSpec(in *v1beta2.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { @@ -815,6 +765,30 @@ func Convert_config_ResourceSpec_To_v1beta2_ResourceSpec(in *config.ResourceSpec return autoConvert_config_ResourceSpec_To_v1beta2_ResourceSpec(in, out, s) } +func autoConvert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(in *v1beta2.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + out.Type = config.ScoringStrategyType(in.Type) + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*config.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_v1beta2_ScoringStrategy_To_config_ScoringStrategy is an autogenerated conversion function. +func Convert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(in *v1beta2.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + return autoConvert_v1beta2_ScoringStrategy_To_config_ScoringStrategy(in, out, s) +} + +func autoConvert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(in *config.ScoringStrategy, out *v1beta2.ScoringStrategy, s conversion.Scope) error { + out.Type = v1beta2.ScoringStrategyType(in.Type) + out.Resources = *(*[]v1beta2.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*v1beta2.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_config_ScoringStrategy_To_v1beta2_ScoringStrategy is an autogenerated conversion function. +func Convert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(in *config.ScoringStrategy, out *v1beta2.ScoringStrategy, s conversion.Scope) error { + return autoConvert_config_ScoringStrategy_To_v1beta2_ScoringStrategy(in, out, s) +} + func autoConvert_v1beta2_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1beta2.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { out.Utilization = in.Utilization out.Score = in.Score diff --git a/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go b/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go index 4aa5e3b0257e..85930a528bde 100644 --- a/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go +++ b/pkg/scheduler/apis/config/v1beta2/zz_generated.defaults.go @@ -34,16 +34,8 @@ func RegisterDefaults(scheme *runtime.Scheme) error { scheme.AddTypeDefaultingFunc(&v1beta2.KubeSchedulerConfiguration{}, func(obj interface{}) { SetObjectDefaults_KubeSchedulerConfiguration(obj.(*v1beta2.KubeSchedulerConfiguration)) }) - scheme.AddTypeDefaultingFunc(&v1beta2.NodeResourcesLeastAllocatedArgs{}, func(obj interface{}) { - SetObjectDefaults_NodeResourcesLeastAllocatedArgs(obj.(*v1beta2.NodeResourcesLeastAllocatedArgs)) - }) - scheme.AddTypeDefaultingFunc(&v1beta2.NodeResourcesMostAllocatedArgs{}, func(obj interface{}) { - SetObjectDefaults_NodeResourcesMostAllocatedArgs(obj.(*v1beta2.NodeResourcesMostAllocatedArgs)) - }) + scheme.AddTypeDefaultingFunc(&v1beta2.NodeResourcesFitArgs{}, func(obj interface{}) { SetObjectDefaults_NodeResourcesFitArgs(obj.(*v1beta2.NodeResourcesFitArgs)) }) scheme.AddTypeDefaultingFunc(&v1beta2.PodTopologySpreadArgs{}, func(obj interface{}) { SetObjectDefaults_PodTopologySpreadArgs(obj.(*v1beta2.PodTopologySpreadArgs)) }) - scheme.AddTypeDefaultingFunc(&v1beta2.RequestedToCapacityRatioArgs{}, func(obj interface{}) { - SetObjectDefaults_RequestedToCapacityRatioArgs(obj.(*v1beta2.RequestedToCapacityRatioArgs)) - }) scheme.AddTypeDefaultingFunc(&v1beta2.VolumeBindingArgs{}, func(obj interface{}) { SetObjectDefaults_VolumeBindingArgs(obj.(*v1beta2.VolumeBindingArgs)) }) return nil } @@ -60,22 +52,14 @@ func SetObjectDefaults_KubeSchedulerConfiguration(in *v1beta2.KubeSchedulerConfi SetDefaults_KubeSchedulerConfiguration(in) } -func SetObjectDefaults_NodeResourcesLeastAllocatedArgs(in *v1beta2.NodeResourcesLeastAllocatedArgs) { - SetDefaults_NodeResourcesLeastAllocatedArgs(in) -} - -func SetObjectDefaults_NodeResourcesMostAllocatedArgs(in *v1beta2.NodeResourcesMostAllocatedArgs) { - SetDefaults_NodeResourcesMostAllocatedArgs(in) +func SetObjectDefaults_NodeResourcesFitArgs(in *v1beta2.NodeResourcesFitArgs) { + SetDefaults_NodeResourcesFitArgs(in) } func SetObjectDefaults_PodTopologySpreadArgs(in *v1beta2.PodTopologySpreadArgs) { SetDefaults_PodTopologySpreadArgs(in) } -func SetObjectDefaults_RequestedToCapacityRatioArgs(in *v1beta2.RequestedToCapacityRatioArgs) { - SetDefaults_RequestedToCapacityRatioArgs(in) -} - func SetObjectDefaults_VolumeBindingArgs(in *v1beta2.VolumeBindingArgs) { SetDefaults_VolumeBindingArgs(in) } diff --git a/pkg/scheduler/apis/config/validation/validation.go b/pkg/scheduler/apis/config/validation/validation.go index 64bbcc89acf0..1c9fc2806af6 100644 --- a/pkg/scheduler/apis/config/validation/validation.go +++ b/pkg/scheduler/apis/config/validation/validation.go @@ -97,10 +97,50 @@ var removedPluginsByVersion = []removedPlugins{ }, { schemeGroupVersion: v1beta2.SchemeGroupVersion.String(), - plugins: []string{"NodeLabel", "ServiceAffinity", "NodePreferAvoidPods"}, + plugins: []string{ + "NodeLabel", + "ServiceAffinity", + "NodePreferAvoidPods", + "NodeResourcesLeastAllocated", + "NodeResourcesMostAllocated", + "RequestedToCapacityRatio", + }, }, } +// conflictScorePluginsByVersion maintains a map of conflict plugins in each version. +// Remember to add an entry to that list when creating a new component config +// version (even if the list of conflict plugins is empty). +var conflictScorePluginsByVersion = map[string]map[string]sets.String{ + v1beta1.SchemeGroupVersion.String(): { + "NodeResourcesFit": sets.NewString( + "NodeResourcesLeastAllocated", + "NodeResourcesMostAllocated", + "RequestedToCapacityRatio"), + }, + v1beta2.SchemeGroupVersion.String(): nil, +} + +// isScorePluginConflict checks if a given plugin was conflict with other plugin in the given component +// config version or earlier. +func isScorePluginConflict(apiVersion string, name string, profile *config.KubeSchedulerProfile) []string { + var conflictPlugins []string + cp, ok := conflictScorePluginsByVersion[apiVersion] + if !ok { + return nil + } + plugin, ok := cp[name] + if !ok { + return nil + } + for _, p := range profile.Plugins.Score.Enabled { + if plugin.Has(p.Name) { + conflictPlugins = append(conflictPlugins, p.Name) + } + } + return conflictPlugins +} + // isPluginRemoved checks if a given plugin was removed in the given component // config version or earlier. func isPluginRemoved(apiVersion string, name string) (bool, string) { @@ -127,6 +167,16 @@ func validatePluginSetForRemovedPlugins(path *field.Path, apiVersion string, ps return errs } +func validateScorePluginSetForConflictPlugins(path *field.Path, apiVersion string, profile *config.KubeSchedulerProfile) []error { + var errs []error + for i, plugin := range profile.Plugins.Score.Enabled { + if cp := isScorePluginConflict(apiVersion, plugin.Name, profile); len(cp) > 0 { + errs = append(errs, field.Invalid(path.Child("enabled").Index(i), plugin.Name, fmt.Sprintf("was conflict with %q in version %q (KubeSchedulerConfiguration is version %q)", cp, apiVersion, apiVersion))) + } + } + return errs +} + func validateKubeSchedulerProfile(path *field.Path, apiVersion string, profile *config.KubeSchedulerProfile) []error { var errs []error if len(profile.SchedulerName) == 0 { @@ -175,30 +225,29 @@ func validatePluginConfig(path *field.Path, apiVersion string, profile *config.K } } } + if profile.Plugins != nil { + stagesToPluginSet := map[string]config.PluginSet{ + "queueSort": profile.Plugins.QueueSort, + "preFilter": profile.Plugins.PreFilter, + "filter": profile.Plugins.Filter, + "postFilter": profile.Plugins.PostFilter, + "preScore": profile.Plugins.PreScore, + "score": profile.Plugins.Score, + "reserve": profile.Plugins.Reserve, + "permit": profile.Plugins.Permit, + "preBind": profile.Plugins.PreBind, + "bind": profile.Plugins.Bind, + "postBind": profile.Plugins.PostBind, + } + pluginsPath := path.Child("plugins") - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("queueSort"), apiVersion, profile.Plugins.QueueSort)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("preFilter"), apiVersion, profile.Plugins.PreFilter)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("filter"), apiVersion, profile.Plugins.Filter)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("postFilter"), apiVersion, profile.Plugins.PostFilter)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("preScore"), apiVersion, profile.Plugins.PreScore)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("score"), apiVersion, profile.Plugins.Score)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("reserve"), apiVersion, profile.Plugins.Reserve)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("permit"), apiVersion, profile.Plugins.Permit)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("preBind"), apiVersion, profile.Plugins.PreBind)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("bind"), apiVersion, profile.Plugins.Bind)...) - errs = append(errs, validatePluginSetForRemovedPlugins( - pluginsPath.Child("postBind"), apiVersion, profile.Plugins.PostBind)...) + for s, p := range stagesToPluginSet { + errs = append(errs, validatePluginSetForRemovedPlugins( + pluginsPath.Child(s), apiVersion, p)...) + } + errs = append(errs, validateScorePluginSetForConflictPlugins( + pluginsPath.Child("score"), apiVersion, profile)...) } return errs } diff --git a/pkg/scheduler/apis/config/validation/validation_pluginargs.go b/pkg/scheduler/apis/config/validation/validation_pluginargs.go index 93ad7df59576..9fb3855ea291 100644 --- a/pkg/scheduler/apis/config/validation/validation_pluginargs.go +++ b/pkg/scheduler/apis/config/validation/validation_pluginargs.go @@ -324,6 +324,13 @@ func ValidateNodeResourcesFitArgs(path *field.Path, args *config.NodeResourcesFi } } + if args.ScoringStrategy != nil { + allErrs = append(allErrs, validateResources(args.ScoringStrategy.Resources, path.Child("resources"))...) + if args.ScoringStrategy.RequestedToCapacityRatio != nil && len(args.ScoringStrategy.RequestedToCapacityRatio.Shape) > 0 { + allErrs = append(allErrs, validateFunctionShape(args.ScoringStrategy.RequestedToCapacityRatio.Shape, path.Child("shape"))...) + } + } + if len(allErrs) == 0 { return nil } diff --git a/pkg/scheduler/apis/config/validation/validation_pluginargs_test.go b/pkg/scheduler/apis/config/validation/validation_pluginargs_test.go index bbeab2b9d3bc..7751ead0971f 100644 --- a/pkg/scheduler/apis/config/validation/validation_pluginargs_test.go +++ b/pkg/scheduler/apis/config/validation/validation_pluginargs_test.go @@ -988,6 +988,13 @@ func TestValidateVolumeBindingArgs(t *testing.T) { } func TestValidateFitArgs(t *testing.T) { + defaultScoringStrategy := &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + } argsTest := []struct { name string args config.NodeResourcesFitArgs @@ -997,6 +1004,7 @@ func TestValidateFitArgs(t *testing.T) { name: "IgnoredResources: too long value", args: config.NodeResourcesFitArgs{ IgnoredResources: []string{fmt.Sprintf("longvalue%s", strings.Repeat("a", 64))}, + ScoringStrategy: defaultScoringStrategy, }, expect: "name part must be no more than 63 characters", }, @@ -1004,6 +1012,7 @@ func TestValidateFitArgs(t *testing.T) { name: "IgnoredResources: name is empty", args: config.NodeResourcesFitArgs{ IgnoredResources: []string{"example.com/"}, + ScoringStrategy: defaultScoringStrategy, }, expect: "name part must be non-empty", }, @@ -1011,6 +1020,7 @@ func TestValidateFitArgs(t *testing.T) { name: "IgnoredResources: name has too many slash", args: config.NodeResourcesFitArgs{ IgnoredResources: []string{"example.com/aaa/bbb"}, + ScoringStrategy: defaultScoringStrategy, }, expect: "a qualified name must consist of alphanumeric characters", }, @@ -1018,18 +1028,21 @@ func TestValidateFitArgs(t *testing.T) { name: "IgnoredResources: valid args", args: config.NodeResourcesFitArgs{ IgnoredResources: []string{"example.com"}, + ScoringStrategy: defaultScoringStrategy, }, }, { name: "IgnoredResourceGroups: valid args ", args: config.NodeResourcesFitArgs{ IgnoredResourceGroups: []string{"example.com"}, + ScoringStrategy: defaultScoringStrategy, }, }, { name: "IgnoredResourceGroups: illegal args", args: config.NodeResourcesFitArgs{ IgnoredResourceGroups: []string{"example.com/"}, + ScoringStrategy: defaultScoringStrategy, }, expect: "name part must be non-empty", }, @@ -1037,6 +1050,7 @@ func TestValidateFitArgs(t *testing.T) { name: "IgnoredResourceGroups: name is too long", args: config.NodeResourcesFitArgs{ IgnoredResourceGroups: []string{strings.Repeat("a", 64)}, + ScoringStrategy: defaultScoringStrategy, }, expect: "name part must be no more than 63 characters", }, @@ -1044,14 +1058,20 @@ func TestValidateFitArgs(t *testing.T) { name: "IgnoredResourceGroups: name cannot be contain slash", args: config.NodeResourcesFitArgs{ IgnoredResourceGroups: []string{"example.com/aa"}, + ScoringStrategy: defaultScoringStrategy, }, expect: "resource group name can't contain '/'", }, + { + name: "ScoringStrategy: field is required", + args: config.NodeResourcesFitArgs{}, + expect: "ScoringStrategy field is required", + }, } for _, test := range argsTest { t.Run(test.name, func(t *testing.T) { - if err := ValidateNodeResourcesFitArgs(nil, &test.args); err != nil && !strings.Contains(err.Error(), test.expect) { + if err := ValidateNodeResourcesFitArgs(nil, &test.args); err != nil && (!strings.Contains(err.Error(), test.expect)) { t.Errorf("case[%v]: error details do not include %v", test.name, err) } }) diff --git a/pkg/scheduler/apis/config/validation/validation_test.go b/pkg/scheduler/apis/config/validation/validation_test.go index ed8368d57dfa..5cef752b3160 100644 --- a/pkg/scheduler/apis/config/validation/validation_test.go +++ b/pkg/scheduler/apis/config/validation/validation_test.go @@ -213,13 +213,16 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) { BindVerb: "bar", }) - badRemovedPlugins1 := validConfig.DeepCopy() // defalt v1beta2 + badRemovedPlugins1 := validConfig.DeepCopy() // default v1beta2 badRemovedPlugins1.Profiles[0].Plugins.Score.Enabled = append(badRemovedPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "ServiceAffinity", Weight: 2}) badRemovedPlugins2 := validConfig.DeepCopy() badRemovedPlugins2.APIVersion = "kubescheduler.config.k8s.io/v1beta3" // hypothetical, v1beta3 doesn't exist badRemovedPlugins2.Profiles[0].Plugins.Score.Enabled = append(badRemovedPlugins2.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "ServiceAffinity", Weight: 2}) + badRemovedPlugins3 := validConfig.DeepCopy() // default v1beta2 + badRemovedPlugins3.Profiles[0].Plugins.Score.Enabled = append(badRemovedPlugins3.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesMostAllocated", Weight: 2}) + goodRemovedPlugins1 := validConfig.DeepCopy() // ServiceAffinity is okay in v1beta1. goodRemovedPlugins1.APIVersion = v1beta1.SchemeGroupVersion.String() goodRemovedPlugins1.Profiles[0].Plugins.Score.Enabled = append(goodRemovedPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "ServiceAffinity", Weight: 2}) @@ -227,9 +230,34 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) { goodRemovedPlugins2 := validConfig.DeepCopy() goodRemovedPlugins2.Profiles[0].Plugins.Score.Enabled = append(goodRemovedPlugins2.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) + goodRemovedPlugins3 := validConfig.DeepCopy() + goodRemovedPlugins3.APIVersion = v1beta1.SchemeGroupVersion.String() + goodRemovedPlugins3.Profiles[0].Plugins.Score.Enabled = append(goodRemovedPlugins3.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesMostAllocated", Weight: 2}) + + badConflictPlugins1 := validConfig.DeepCopy() + badConflictPlugins1.APIVersion = v1beta1.SchemeGroupVersion.String() + badConflictPlugins1.Profiles[0].Plugins.Score.Enabled = append(badConflictPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesFit", Weight: 2}) + badConflictPlugins1.Profiles[0].Plugins.Score.Enabled = append(badConflictPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesLeastAllocated", Weight: 2}) + badConflictPlugins1.Profiles[0].Plugins.Score.Enabled = append(badConflictPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesMostAllocated", Weight: 2}) + badConflictPlugins1.Profiles[0].Plugins.Score.Enabled = append(badConflictPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "RequestedToCapacityRatio", Weight: 2}) + + goodConflictPlugins1 := validConfig.DeepCopy() + goodConflictPlugins1.APIVersion = v1beta1.SchemeGroupVersion.String() + goodConflictPlugins1.Profiles[0].Plugins.Score.Enabled = append(goodConflictPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesLeastAllocated", Weight: 2}) + goodConflictPlugins1.Profiles[0].Plugins.Score.Enabled = append(goodConflictPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesMostAllocated", Weight: 2}) + goodConflictPlugins1.Profiles[0].Plugins.Score.Enabled = append(goodConflictPlugins1.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "RequestedToCapacityRatio", Weight: 2}) + + goodConflictPlugins2 := validConfig.DeepCopy() + goodConflictPlugins2.APIVersion = v1beta1.SchemeGroupVersion.String() + goodConflictPlugins2.Profiles[0].Plugins.Filter.Enabled = append(goodConflictPlugins2.Profiles[0].Plugins.Filter.Enabled, config.Plugin{Name: "NodeResourcesFit", Weight: 2}) + goodConflictPlugins2.Profiles[0].Plugins.Score.Enabled = append(goodConflictPlugins2.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesLeastAllocated", Weight: 2}) + goodConflictPlugins2.Profiles[0].Plugins.Score.Enabled = append(goodConflictPlugins2.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "NodeResourcesMostAllocated", Weight: 2}) + goodConflictPlugins2.Profiles[0].Plugins.Score.Enabled = append(goodConflictPlugins2.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "RequestedToCapacityRatio", Weight: 2}) + scenarios := map[string]struct { expectedToFail bool config *config.KubeSchedulerConfiguration + errorString string }{ "good": { expectedToFail: false, @@ -327,6 +355,10 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) { expectedToFail: true, config: badRemovedPlugins2, }, + "bad-removed-plugins-3": { + expectedToFail: true, + config: badRemovedPlugins3, + }, "good-removed-plugins-1": { expectedToFail: false, config: goodRemovedPlugins1, @@ -335,6 +367,23 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) { expectedToFail: false, config: goodRemovedPlugins2, }, + "good-removed-plugins-3": { + expectedToFail: false, + config: goodRemovedPlugins3, + }, + "bad-conflict-plugins-1": { + expectedToFail: true, + config: badConflictPlugins1, + errorString: "profiles[0].plugins.score.enabled[0]: Invalid value: \"NodeResourcesFit\": was conflict with [\"NodeResourcesLeastAllocated\" \"NodeResourcesMostAllocated\" \"RequestedToCapacityRatio\"] in version \"kubescheduler.config.k8s.io/v1beta1\" (KubeSchedulerConfiguration is version \"kubescheduler.config.k8s.io/v1beta1\")", + }, + "good-conflict-plugins-1": { + expectedToFail: false, + config: goodConflictPlugins1, + }, + "good-conflict-plugins-2": { + expectedToFail: false, + config: goodConflictPlugins2, + }, } for name, scenario := range scenarios { @@ -346,6 +395,11 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) { if errs != nil && !scenario.expectedToFail { t.Errorf("Unexpected failure: %+v", errs) } + fmt.Println(errs) + + if errs != nil && scenario.errorString != "" && errs.Error() != scenario.errorString { + t.Errorf("Unexpected error string\n want:\t%s\n got:\t%s", scenario.errorString, errs.Error()) + } }) } } diff --git a/pkg/scheduler/apis/config/zz_generated.deepcopy.go b/pkg/scheduler/apis/config/zz_generated.deepcopy.go index ae389777afa7..2abc6ff48a96 100644 --- a/pkg/scheduler/apis/config/zz_generated.deepcopy.go +++ b/pkg/scheduler/apis/config/zz_generated.deepcopy.go @@ -345,6 +345,11 @@ func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } return } @@ -752,6 +757,27 @@ func (in *RequestedToCapacityRatioArguments) DeepCopy() *RequestedToCapacityRati return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { + *out = *in + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { + if in == nil { + return nil + } + out := new(RequestedToCapacityRatioParam) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { *out = *in @@ -826,6 +852,32 @@ func (in *SchedulerPolicySource) DeepCopy() *SchedulerPolicySource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceAffinity) DeepCopyInto(out *ServiceAffinity) { *out = *in diff --git a/pkg/scheduler/core/generic_scheduler_test.go b/pkg/scheduler/core/generic_scheduler_test.go index 4336cacdb33f..7d4f3692b71f 100644 --- a/pkg/scheduler/core/generic_scheduler_test.go +++ b/pkg/scheduler/core/generic_scheduler_test.go @@ -1308,9 +1308,9 @@ func TestZeroRequest(t *testing.T) { pluginRegistrations := []st.RegisterPluginFunc{ st.RegisterQueueSortPlugin(queuesort.Name, queuesort.New), - st.RegisterScorePlugin(noderesources.LeastAllocatedName, + st.RegisterScorePlugin(noderesources.FitName, func(plArgs apiruntime.Object, fh framework.Handle) (framework.Plugin, error) { - return noderesources.NewLeastAllocated(plArgs, fh, feature.Features{}) + return noderesources.NewFit(plArgs, fh, feature.Features{}) }, 1), st.RegisterScorePlugin(noderesources.BalancedAllocationName, func(plArgs apiruntime.Object, fh framework.Handle) (framework.Plugin, error) { diff --git a/pkg/scheduler/factory_test.go b/pkg/scheduler/factory_test.go index 7dffa46b8f1e..8d262a4e7353 100644 --- a/pkg/scheduler/factory_test.go +++ b/pkg/scheduler/factory_test.go @@ -126,7 +126,15 @@ func TestCreateFromConfig(t *testing.T) { }, { Name: noderesources.FitName, - Args: &schedulerapi.NodeResourcesFitArgs{}, + Args: &schedulerapi.NodeResourcesFitArgs{ + ScoringStrategy: &schedulerapi.ScoringStrategy{ + Type: schedulerapi.LeastAllocated, + Resources: []schedulerapi.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, + }, }, { Name: noderesources.LeastAllocatedName, @@ -342,7 +350,15 @@ func TestCreateFromConfig(t *testing.T) { }, { Name: "NodeResourcesFit", - Args: &schedulerapi.NodeResourcesFitArgs{}, + Args: &schedulerapi.NodeResourcesFitArgs{ + ScoringStrategy: &schedulerapi.ScoringStrategy{ + Type: schedulerapi.LeastAllocated, + Resources: []schedulerapi.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, + }, }, }, wantPlugins: &schedulerapi.Plugins{ diff --git a/pkg/scheduler/framework/plugins/legacy_registry.go b/pkg/scheduler/framework/plugins/legacy_registry.go index 0c216a8e3e5d..ceb9eac93be5 100644 --- a/pkg/scheduler/framework/plugins/legacy_registry.go +++ b/pkg/scheduler/framework/plugins/legacy_registry.go @@ -20,6 +20,7 @@ import ( "fmt" "sort" + "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/util/feature" "k8s.io/klog/v2" @@ -383,16 +384,31 @@ func NewLegacyRegistry() *LegacyRegistry { plugins.Score = appendToPluginSet(plugins.Score, nodepreferavoidpods.Name, &args.Weight) }) registry.registerPriorityConfigProducer(MostRequestedPriority, - func(args ConfigProducerArgs, plugins *config.Plugins, _ *[]config.PluginConfig) { + func(args ConfigProducerArgs, plugins *config.Plugins, pluginConfig *[]config.PluginConfig) { plugins.Score = appendToPluginSet(plugins.Score, noderesources.MostAllocatedName, &args.Weight) + *pluginConfig = append(*pluginConfig, + config.PluginConfig{Name: noderesources.MostAllocatedName, Args: &config.NodeResourcesMostAllocatedArgs{ + Resources: []config.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, + }, + }}) + }) registry.registerPriorityConfigProducer(BalancedResourceAllocation, func(args ConfigProducerArgs, plugins *config.Plugins, _ *[]config.PluginConfig) { plugins.Score = appendToPluginSet(plugins.Score, noderesources.BalancedAllocationName, &args.Weight) }) registry.registerPriorityConfigProducer(LeastRequestedPriority, - func(args ConfigProducerArgs, plugins *config.Plugins, _ *[]config.PluginConfig) { + func(args ConfigProducerArgs, plugins *config.Plugins, pluginConfig *[]config.PluginConfig) { plugins.Score = appendToPluginSet(plugins.Score, noderesources.LeastAllocatedName, &args.Weight) + *pluginConfig = append(*pluginConfig, + config.PluginConfig{Name: noderesources.LeastAllocatedName, Args: &config.NodeResourcesLeastAllocatedArgs{ + Resources: []config.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, + }, + }}) }) registry.registerPriorityConfigProducer(noderesources.RequestedToCapacityRatioName, func(args ConfigProducerArgs, plugins *config.Plugins, pluginConfig *[]config.PluginConfig) { diff --git a/pkg/scheduler/framework/plugins/legacy_registry_test.go b/pkg/scheduler/framework/plugins/legacy_registry_test.go index 75aa4ee59dd1..78c148ab3ad2 100644 --- a/pkg/scheduler/framework/plugins/legacy_registry_test.go +++ b/pkg/scheduler/framework/plugins/legacy_registry_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/util/feature" "k8s.io/component-base/featuregate" @@ -145,6 +146,15 @@ func TestAppendPriorityConfigs(t *testing.T) { DefaultingType: config.SystemDefaulting, }, }, + { + Name: noderesources.LeastAllocatedName, + Args: &config.NodeResourcesLeastAllocatedArgs{ + Resources: []config.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, + }, + }, + }, }, }, { diff --git a/pkg/scheduler/framework/plugins/noderesources/fit.go b/pkg/scheduler/framework/plugins/noderesources/fit.go index d17115bda779..268783a43771 100644 --- a/pkg/scheduler/framework/plugins/noderesources/fit.go +++ b/pkg/scheduler/framework/plugins/noderesources/fit.go @@ -35,6 +35,7 @@ import ( var _ framework.PreFilterPlugin = &Fit{} var _ framework.FilterPlugin = &Fit{} var _ framework.EnqueueExtensions = &Fit{} +var _ framework.ScorePlugin = &Fit{} const ( // FitName is the name of the plugin used in the plugin registry and configurations. @@ -45,11 +46,46 @@ const ( preFilterStateKey = "PreFilter" + FitName ) +// nodeResourceStrategyTypeMap maps strategy to scorer implementation +var nodeResourceStrategyTypeMap = map[config.ScoringStrategyType]scorer{ + config.LeastAllocated: func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer { + resToWeightMap := resourcesToWeightMap(args.ScoringStrategy.Resources) + return &resourceAllocationScorer{ + Name: LeastAllocatedName, + scorer: leastResourceScorer(resToWeightMap), + resourceToWeightMap: resToWeightMap, + } + }, + config.MostAllocated: func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer { + resToWeightMap := resourcesToWeightMap(args.ScoringStrategy.Resources) + return &resourceAllocationScorer{ + Name: MostAllocatedName, + scorer: mostResourceScorer(resToWeightMap), + resourceToWeightMap: resToWeightMap, + } + }, + config.RequestedToCapacityRatio: func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer { + resToWeightMap := resourcesToWeightMap(args.ScoringStrategy.Resources) + return &resourceAllocationScorer{ + Name: RequestedToCapacityRatioName, + scorer: requestedToCapacityRatioScorer(resToWeightMap, args.ScoringStrategy.RequestedToCapacityRatio.Shape), + resourceToWeightMap: resToWeightMap, + } + }, +} + // Fit is a plugin that checks if a node has sufficient resources. type Fit struct { ignoredResources sets.String ignoredResourceGroups sets.String enablePodOverhead bool + handle framework.Handle + resourceAllocationScorer +} + +// ScoreExtensions of the Score plugin. +func (f *Fit) ScoreExtensions() framework.ScoreExtensions { + return nil } // preFilterState computed at PreFilter and used at Filter. @@ -68,7 +104,7 @@ func (f *Fit) Name() string { } // NewFit initializes a new plugin and returns it. -func NewFit(plArgs runtime.Object, _ framework.Handle, fts feature.Features) (framework.Plugin, error) { +func NewFit(plArgs runtime.Object, h framework.Handle, fts feature.Features) (framework.Plugin, error) { args, ok := plArgs.(*config.NodeResourcesFitArgs) if !ok { return nil, fmt.Errorf("want args to be of type NodeResourcesFitArgs, got %T", plArgs) @@ -76,10 +112,23 @@ func NewFit(plArgs runtime.Object, _ framework.Handle, fts feature.Features) (fr if err := validation.ValidateNodeResourcesFitArgs(nil, args); err != nil { return nil, err } + + if args.ScoringStrategy == nil { + return nil, fmt.Errorf("scoring strategy not specified") + } + + strategy := args.ScoringStrategy.Type + scorePlugin, ok := nodeResourceStrategyTypeMap[strategy] + if !ok { + return nil, fmt.Errorf("scoring strategy %s is not supported", strategy) + } + return &Fit{ - ignoredResources: sets.NewString(args.IgnoredResources...), - ignoredResourceGroups: sets.NewString(args.IgnoredResourceGroups...), - enablePodOverhead: fts.EnablePodOverhead, + ignoredResources: sets.NewString(args.IgnoredResources...), + ignoredResourceGroups: sets.NewString(args.IgnoredResourceGroups...), + enablePodOverhead: fts.EnablePodOverhead, + handle: h, + resourceAllocationScorer: *scorePlugin(args), }, nil } @@ -278,3 +327,13 @@ func fitsRequest(podRequest *preFilterState, nodeInfo *framework.NodeInfo, ignor return insufficientResources } + +// Score invoked at the Score extension point. +func (f *Fit) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + nodeInfo, err := f.handle.SnapshotSharedLister().NodeInfos().Get(nodeName) + if err != nil { + return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err)) + } + + return f.score(pod, nodeInfo) +} diff --git a/pkg/scheduler/framework/plugins/noderesources/fit_test.go b/pkg/scheduler/framework/plugins/noderesources/fit_test.go index ec2ed8471f87..fcf4e03d7c00 100644 --- a/pkg/scheduler/framework/plugins/noderesources/fit_test.go +++ b/pkg/scheduler/framework/plugins/noderesources/fit_test.go @@ -30,6 +30,8 @@ import ( "k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/framework" plfeature "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" + "k8s.io/kubernetes/pkg/scheduler/framework/runtime" + "k8s.io/kubernetes/pkg/scheduler/internal/cache" ) var ( @@ -105,6 +107,14 @@ func getErrReason(rn v1.ResourceName) string { return fmt.Sprintf("Insufficient %v", rn) } +var defaultScoringStrategy = &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, +} + func TestEnoughRequests(t *testing.T) { enoughPodsTests := []struct { pod *v1.Pod @@ -414,6 +424,10 @@ func TestEnoughRequests(t *testing.T) { node := v1.Node{Status: v1.NodeStatus{Capacity: makeResources(10, 20, 32, 5, 20, 5).Capacity, Allocatable: makeAllocatableResources(10, 20, 32, 5, 20, 5)}} test.nodeInfo.SetNode(&node) + if test.args.ScoringStrategy == nil { + test.args.ScoringStrategy = defaultScoringStrategy + } + p, err := NewFit(&test.args, nil, plfeature.Features{EnablePodOverhead: true}) if err != nil { t.Fatal(err) @@ -442,7 +456,7 @@ func TestPreFilterDisabled(t *testing.T) { nodeInfo := framework.NewNodeInfo() node := v1.Node{} nodeInfo.SetNode(&node) - p, err := NewFit(&config.NodeResourcesFitArgs{}, nil, plfeature.Features{EnablePodOverhead: true}) + p, err := NewFit(&config.NodeResourcesFitArgs{ScoringStrategy: defaultScoringStrategy}, nil, plfeature.Features{EnablePodOverhead: true}) if err != nil { t.Fatal(err) } @@ -492,7 +506,7 @@ func TestNotEnoughRequests(t *testing.T) { node := v1.Node{Status: v1.NodeStatus{Capacity: v1.ResourceList{}, Allocatable: makeAllocatableResources(10, 20, 1, 0, 0, 0)}} test.nodeInfo.SetNode(&node) - p, err := NewFit(&config.NodeResourcesFitArgs{}, nil, plfeature.Features{EnablePodOverhead: true}) + p, err := NewFit(&config.NodeResourcesFitArgs{ScoringStrategy: defaultScoringStrategy}, nil, plfeature.Features{EnablePodOverhead: true}) if err != nil { t.Fatal(err) } @@ -564,7 +578,7 @@ func TestStorageRequests(t *testing.T) { node := v1.Node{Status: v1.NodeStatus{Capacity: makeResources(10, 20, 32, 5, 20, 5).Capacity, Allocatable: makeAllocatableResources(10, 20, 32, 5, 20, 5)}} test.nodeInfo.SetNode(&node) - p, err := NewFit(&config.NodeResourcesFitArgs{}, nil, plfeature.Features{EnablePodOverhead: true}) + p, err := NewFit(&config.NodeResourcesFitArgs{ScoringStrategy: defaultScoringStrategy}, nil, plfeature.Features{EnablePodOverhead: true}) if err != nil { t.Fatal(err) } @@ -582,3 +596,119 @@ func TestStorageRequests(t *testing.T) { } } + +func TestFitScore(t *testing.T) { + type test struct { + name string + requestedPod *v1.Pod + nodes []*v1.Node + scheduledPods []*v1.Pod + expectedPriorities framework.NodeScoreList + nodeResourcesFitArgs config.NodeResourcesFitArgs + } + + tests := []test{ + { + name: "test case for ScoringStrategy RequestedToCapacityRatio case1", + requestedPod: makePod("", 3000, 5000), + nodes: []*v1.Node{makeNode("node1", 4000, 10000), makeNode("node2", 6000, 10000)}, + scheduledPods: []*v1.Pod{makePod("node1", 2000, 4000), makePod("node2", 1000, 2000)}, + expectedPriorities: []framework.NodeScore{{Name: "node1", Score: 10}, {Name: "node2", Score: 32}}, + nodeResourcesFitArgs: config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.RequestedToCapacityRatio, + Resources: []config.ResourceSpec{ + {Name: "memory", Weight: 1}, + {Name: "cpu", Weight: 1}, + }, + RequestedToCapacityRatio: &config.RequestedToCapacityRatioParam{ + Shape: []config.UtilizationShapePoint{ + {Utilization: 0, Score: 10}, + {Utilization: 100, Score: 0}, + }, + }, + }, + }, + }, + { + name: "test case for ScoringStrategy RequestedToCapacityRatio case2", + requestedPod: makePod("", 3000, 5000), + nodes: []*v1.Node{makeNode("node1", 4000, 10000), makeNode("node2", 6000, 10000)}, + scheduledPods: []*v1.Pod{makePod("node1", 2000, 4000), makePod("node2", 1000, 2000)}, + expectedPriorities: []framework.NodeScore{{Name: "node1", Score: 95}, {Name: "node2", Score: 68}}, + nodeResourcesFitArgs: config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.RequestedToCapacityRatio, + Resources: []config.ResourceSpec{ + {Name: "memory", Weight: 1}, + {Name: "cpu", Weight: 1}, + }, + RequestedToCapacityRatio: &config.RequestedToCapacityRatioParam{ + Shape: []config.UtilizationShapePoint{ + {Utilization: 0, Score: 0}, + {Utilization: 100, Score: 10}, + }, + }, + }, + }, + }, + { + name: "test case for ScoringStrategy MostAllocated", + requestedPod: makePod("", 1000, 2000), + nodes: []*v1.Node{makeNode("node1", 4000, 10000), makeNode("node2", 6000, 10000)}, + scheduledPods: []*v1.Pod{makePod("node1", 2000, 4000), makePod("node2", 1000, 2000)}, + expectedPriorities: []framework.NodeScore{{Name: "node1", Score: 67}, {Name: "node2", Score: 36}}, + nodeResourcesFitArgs: config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.MostAllocated, + Resources: []config.ResourceSpec{ + {Name: "memory", Weight: 1}, + {Name: "cpu", Weight: 1}, + }, + }, + }, + }, + { + name: "test case for ScoringStrategy LeastAllocated", + requestedPod: makePod("", 1000, 2000), + nodes: []*v1.Node{makeNode("node1", 4000, 10000), makeNode("node2", 6000, 10000)}, + scheduledPods: []*v1.Pod{makePod("node1", 2000, 4000), makePod("node2", 1000, 2000)}, + expectedPriorities: []framework.NodeScore{{Name: "node1", Score: 32}, {Name: "node2", Score: 63}}, + nodeResourcesFitArgs: config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "memory", Weight: 1}, + {Name: "cpu", Weight: 1}, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + state := framework.NewCycleState() + snapshot := cache.NewSnapshot(test.scheduledPods, test.nodes) + fh, _ := runtime.NewFramework(nil, nil, runtime.WithSnapshotSharedLister(snapshot)) + args := test.nodeResourcesFitArgs + p, err := NewFit(&args, fh, plfeature.Features{EnablePodOverhead: true}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + var gotPriorities framework.NodeScoreList + for _, n := range test.nodes { + score, status := p.(framework.ScorePlugin).Score(context.Background(), state, test.requestedPod, n.Name) + if !status.IsSuccess() { + t.Errorf("unexpected error: %v", status) + } + gotPriorities = append(gotPriorities, framework.NodeScore{Name: n.Name, Score: score}) + } + + if !reflect.DeepEqual(test.expectedPriorities, gotPriorities) { + t.Errorf("expected:\n\t%+v,\ngot:\n\t%+v", test.expectedPriorities, gotPriorities) + } + }) + } +} diff --git a/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go b/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go index 6e6f6fba34bd..fb52409a3ea0 100644 --- a/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go +++ b/pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go @@ -43,35 +43,18 @@ func NewRequestedToCapacityRatio(plArgs runtime.Object, handle framework.Handle, if err != nil { return nil, err } + if err := validation.ValidateRequestedToCapacityRatioArgs(nil, &args); err != nil { return nil, err } - shape := make([]helper.FunctionShapePoint, 0, len(args.Shape)) - for _, point := range args.Shape { - shape = append(shape, helper.FunctionShapePoint{ - Utilization: int64(point.Utilization), - // MaxCustomPriorityScore may diverge from the max score used in the scheduler and defined by MaxNodeScore, - // therefore we need to scale the score returned by requested to capacity ratio to the score range - // used by the scheduler. - Score: int64(point.Score) * (framework.MaxNodeScore / config.MaxCustomPriorityScore), - }) - } - - resourceToWeightMap := make(resourceToWeightMap) - for _, resource := range args.Resources { - resourceToWeightMap[v1.ResourceName(resource.Name)] = resource.Weight - if resource.Weight == 0 { - // Apply the default weight. - resourceToWeightMap[v1.ResourceName(resource.Name)] = 1 - } - } + resourceToWeightMap := resourcesToWeightMap(args.Resources) return &RequestedToCapacityRatio{ handle: handle, resourceAllocationScorer: resourceAllocationScorer{ Name: RequestedToCapacityRatioName, - scorer: buildRequestedToCapacityRatioScorerFunction(shape, resourceToWeightMap), + scorer: requestedToCapacityRatioScorer(resourceToWeightMap, args.Shape), resourceToWeightMap: resourceToWeightMap, enablePodOverhead: fts.EnablePodOverhead, }, @@ -138,3 +121,18 @@ func buildRequestedToCapacityRatioScorerFunction(scoringFunctionShape helper.Fun return int64(math.Round(float64(nodeScore) / float64(weightSum))) } } + +func requestedToCapacityRatioScorer(weightMap resourceToWeightMap, shape []config.UtilizationShapePoint) func(resourceToValueMap, resourceToValueMap) int64 { + shapes := make([]helper.FunctionShapePoint, 0, len(shape)) + for _, point := range shape { + shapes = append(shapes, helper.FunctionShapePoint{ + Utilization: int64(point.Utilization), + // MaxCustomPriorityScore may diverge from the max score used in the scheduler and defined by MaxNodeScore, + // therefore we need to scale the score returned by requested to capacity ratio to the score range + // used by the scheduler. + Score: int64(point.Score) * (framework.MaxNodeScore / config.MaxCustomPriorityScore), + }) + } + + return buildRequestedToCapacityRatioScorerFunction(shapes, weightMap) +} diff --git a/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go b/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go index a1d93d68fdf7..349daad50340 100644 --- a/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go +++ b/pkg/scheduler/framework/plugins/noderesources/resource_allocation.go @@ -19,6 +19,7 @@ package noderesources import ( v1 "k8s.io/api/core/v1" "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/framework" schedutil "k8s.io/kubernetes/pkg/scheduler/util" ) @@ -26,6 +27,9 @@ import ( // resourceToWeightMap contains resource name and weight. type resourceToWeightMap map[v1.ResourceName]int64 +// scorer is decorator for resourceAllocationScorer +type scorer func(args *config.NodeResourcesFitArgs) *resourceAllocationScorer + // defaultRequestedRatioResources is used to set default requestToWeight map for CPU and memory var defaultRequestedRatioResources = resourceToWeightMap{v1.ResourceMemory: 1, v1.ResourceCPU: 1} @@ -124,3 +128,12 @@ func calculatePodResourceRequest(pod *v1.Pod, resource v1.ResourceName, enablePo return podRequest } + +// resourcesToWeightMap make weightmap from resources spec +func resourcesToWeightMap(resources []config.ResourceSpec) resourceToWeightMap { + resourceToWeightMap := make(resourceToWeightMap) + for _, resource := range resources { + resourceToWeightMap[v1.ResourceName(resource.Name)] = resource.Weight + } + return resourceToWeightMap +} diff --git a/staging/src/k8s.io/kube-scheduler/config/v1beta1/types_pluginargs.go b/staging/src/k8s.io/kube-scheduler/config/v1beta1/types_pluginargs.go index 61408d196b50..bcdab36fa598 100644 --- a/staging/src/k8s.io/kube-scheduler/config/v1beta1/types_pluginargs.go +++ b/staging/src/k8s.io/kube-scheduler/config/v1beta1/types_pluginargs.go @@ -85,15 +85,19 @@ type NodeResourcesFitArgs struct { metav1.TypeMeta `json:",inline"` // IgnoredResources is the list of resources that NodeResources fit filter - // should ignore. + // should ignore. This doesn't apply to scoring. // +listType=atomic IgnoredResources []string `json:"ignoredResources,omitempty"` // IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. // e.g. if group is ["example.com"], it will ignore all resource names that begin // with "example.com", such as "example.com/aaa" and "example.com/bbb". - // A resource group name can't contain '/'. + // A resource group name can't contain '/'. This doesn't apply to scoring. // +listType=atomic IgnoredResourceGroups []string `json:"ignoredResourceGroups,omitempty"` + + // ScoringStrategy selects the node resource scoring strategy. + // The default strategy is LeastAllocated with an equal "cpu" and "memory" weight. + ScoringStrategy *ScoringStrategy `json:"scoringStrategy,omitempty"` } // PodTopologySpreadConstraintsDefaulting defines how to set default constraints @@ -239,3 +243,40 @@ type NodeAffinityArgs struct { // +optional AddedAffinity *corev1.NodeAffinity `json:"addedAffinity,omitempty"` } + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allcoated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allcoated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType `json:"type,omitempty"` + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + // +listType=map + // +listMapKey=name + Resources []ResourceSpec `json:"resources,omitempty"` + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam `json:"requestedToCapacityRatio,omitempty"` +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} diff --git a/staging/src/k8s.io/kube-scheduler/config/v1beta1/zz_generated.deepcopy.go b/staging/src/k8s.io/kube-scheduler/config/v1beta1/zz_generated.deepcopy.go index 4aeaf44d8c3c..8748a8f62b16 100644 --- a/staging/src/k8s.io/kube-scheduler/config/v1beta1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/kube-scheduler/config/v1beta1/zz_generated.deepcopy.go @@ -312,6 +312,11 @@ func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } return } @@ -599,6 +604,27 @@ func (in *RequestedToCapacityRatioArgs) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { + *out = *in + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { + if in == nil { + return nil + } + out := new(RequestedToCapacityRatioParam) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { *out = *in @@ -615,6 +641,32 @@ func (in *ResourceSpec) DeepCopy() *ResourceSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceAffinityArgs) DeepCopyInto(out *ServiceAffinityArgs) { *out = *in diff --git a/staging/src/k8s.io/kube-scheduler/config/v1beta2/register.go b/staging/src/k8s.io/kube-scheduler/config/v1beta2/register.go index 7c13a31dbad9..c63b100e2b71 100644 --- a/staging/src/k8s.io/kube-scheduler/config/v1beta2/register.go +++ b/staging/src/k8s.io/kube-scheduler/config/v1beta2/register.go @@ -42,9 +42,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { &InterPodAffinityArgs{}, &NodeResourcesFitArgs{}, &PodTopologySpreadArgs{}, - &RequestedToCapacityRatioArgs{}, - &NodeResourcesLeastAllocatedArgs{}, - &NodeResourcesMostAllocatedArgs{}, &VolumeBindingArgs{}, &NodeAffinityArgs{}, ) diff --git a/staging/src/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go b/staging/src/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go index 7372cbcaa325..69a09c721f86 100644 --- a/staging/src/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go +++ b/staging/src/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go @@ -61,15 +61,19 @@ type NodeResourcesFitArgs struct { metav1.TypeMeta `json:",inline"` // IgnoredResources is the list of resources that NodeResources fit filter - // should ignore. + // should ignore. This doesn't apply to scoring. // +listType=atomic IgnoredResources []string `json:"ignoredResources,omitempty"` // IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. // e.g. if group is ["example.com"], it will ignore all resource names that begin // with "example.com", such as "example.com/aaa" and "example.com/bbb". - // A resource group name can't contain '/'. + // A resource group name can't contain '/'. This doesn't apply to scoring. // +listType=atomic IgnoredResourceGroups []string `json:"ignoredResourceGroups,omitempty"` + + // ScoringStrategy selects the node resource scoring strategy. + // The default strategy is LeastAllocated with an equal "cpu" and "memory" weight. + ScoringStrategy *ScoringStrategy `json:"scoringStrategy,omitempty"` } // PodTopologySpreadConstraintsDefaulting defines how to set default constraints @@ -112,46 +116,6 @@ type PodTopologySpreadArgs struct { DefaultingType PodTopologySpreadConstraintsDefaulting `json:"defaultingType,omitempty"` } -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// RequestedToCapacityRatioArgs holds arguments used to configure RequestedToCapacityRatio plugin. -type RequestedToCapacityRatioArgs struct { - metav1.TypeMeta `json:",inline"` - - // Points defining priority function shape - // +listType=atomic - Shape []UtilizationShapePoint `json:"shape"` - // Resources to be managed - // +listType=atomic - Resources []ResourceSpec `json:"resources,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// NodeResourcesLeastAllocatedArgs holds arguments used to configure NodeResourcesLeastAllocated plugin. -type NodeResourcesLeastAllocatedArgs struct { - metav1.TypeMeta `json:",inline"` - - // Resources to be managed, if no resource is provided, default resource set with both - // the weight of "cpu" and "memory" set to "1" will be applied. - // Resource with "0" weight will not accountable for the final score. - // +listType=atomic - Resources []ResourceSpec `json:"resources,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// NodeResourcesMostAllocatedArgs holds arguments used to configure NodeResourcesMostAllocated plugin. -type NodeResourcesMostAllocatedArgs struct { - metav1.TypeMeta `json:",inline"` - - // Resources to be managed, if no resource is provided, default resource set with both - // the weight of "cpu" and "memory" set to "1" will be applied. - // Resource with "0" weight will not accountable for the final score. - // +listType=atomic - Resources []ResourceSpec `json:"resources,omitempty"` -} - // UtilizationShapePoint represents single point of priority function shape. type UtilizationShapePoint struct { // Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. @@ -195,3 +159,40 @@ type NodeAffinityArgs struct { // +optional AddedAffinity *corev1.NodeAffinity `json:"addedAffinity,omitempty"` } + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allcoated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allcoated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType `json:"type,omitempty"` + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + // +listType=map + // +listMapKey=topologyKey + Resources []ResourceSpec `json:"resources,omitempty"` + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam `json:"requestedToCapacityRatio,omitempty"` +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} diff --git a/staging/src/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go b/staging/src/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go index e7cb4e7b3e92..40eca8163320 100644 --- a/staging/src/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/kube-scheduler/config/v1beta2/zz_generated.deepcopy.go @@ -267,6 +267,11 @@ func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } return } @@ -288,66 +293,6 @@ func (in *NodeResourcesFitArgs) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NodeResourcesLeastAllocatedArgs) DeepCopyInto(out *NodeResourcesLeastAllocatedArgs) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = make([]ResourceSpec, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesLeastAllocatedArgs. -func (in *NodeResourcesLeastAllocatedArgs) DeepCopy() *NodeResourcesLeastAllocatedArgs { - if in == nil { - return nil - } - out := new(NodeResourcesLeastAllocatedArgs) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NodeResourcesLeastAllocatedArgs) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NodeResourcesMostAllocatedArgs) DeepCopyInto(out *NodeResourcesMostAllocatedArgs) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = make([]ResourceSpec, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesMostAllocatedArgs. -func (in *NodeResourcesMostAllocatedArgs) DeepCopy() *NodeResourcesMostAllocatedArgs { - if in == nil { - return nil - } - out := new(NodeResourcesMostAllocatedArgs) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NodeResourcesMostAllocatedArgs) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Plugin) DeepCopyInto(out *Plugin) { *out = *in @@ -476,40 +421,26 @@ func (in *PodTopologySpreadArgs) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RequestedToCapacityRatioArgs) DeepCopyInto(out *RequestedToCapacityRatioArgs) { +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { *out = *in - out.TypeMeta = in.TypeMeta if in.Shape != nil { in, out := &in.Shape, &out.Shape *out = make([]UtilizationShapePoint, len(*in)) copy(*out, *in) } - if in.Resources != nil { - in, out := &in.Resources, &out.Resources - *out = make([]ResourceSpec, len(*in)) - copy(*out, *in) - } return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioArgs. -func (in *RequestedToCapacityRatioArgs) DeepCopy() *RequestedToCapacityRatioArgs { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { if in == nil { return nil } - out := new(RequestedToCapacityRatioArgs) + out := new(RequestedToCapacityRatioParam) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RequestedToCapacityRatioArgs) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { *out = *in @@ -526,6 +457,32 @@ func (in *ResourceSpec) DeepCopy() *ResourceSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) { *out = *in