Showing preview only (250K chars total). Download the full file or copy to clipboard to get everything.
Repository: kubernetes/kube-scheduler
Branch: master
Commit: e9dbc14fbb8d
Files: 33
Total size: 239.0 KB
Directory structure:
gitextract_ew82_piy/
├── .github/
│ └── PULL_REQUEST_TEMPLATE.md
├── CONTRIBUTING.md
├── LICENSE
├── OWNERS
├── README.md
├── SECURITY_CONTACTS
├── code-of-conduct.md
├── config/
│ ├── OWNERS
│ └── v1/
│ ├── doc.go
│ ├── register.go
│ ├── types.go
│ ├── types_pluginargs.go
│ ├── zz_generated.deepcopy.go
│ └── zz_generated.model_name.go
├── doc.go
├── extender/
│ ├── OWNERS
│ └── v1/
│ ├── doc.go
│ ├── types.go
│ ├── types_test.go
│ └── zz_generated.deepcopy.go
├── framework/
│ ├── api_calls.go
│ ├── api_dispatcher.go
│ ├── cycle_state.go
│ ├── extender.go
│ ├── interface.go
│ ├── interface_test.go
│ ├── listers.go
│ ├── signers.go
│ ├── signers_test.go
│ ├── types.go
│ └── types_test.go
├── go.mod
└── go.sum
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
Sorry, we do not accept changes directly against this repository. Please see
CONTRIBUTING.md for information on where and how to contribute instead.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing guidelines
Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes.
This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/kube-scheduler](https://git.k8s.io/kubernetes/staging/src/k8s.io/kube-scheduler) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot).
Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/sig-architecture/staging.md) for more information
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: OWNERS
================================================
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- sig-scheduling-maintainers
- sttts
- luxas
reviewers:
- sig-scheduling
- luxas
- sttts
labels:
- sig/scheduling
================================================
FILE: README.md
================================================
> ⚠️ **This is an automatically published [staged repository](https://git.k8s.io/kubernetes/staging#external-repository-staging-area) for Kubernetes**.
> Contributions, including issues and pull requests, should be made to the main Kubernetes repository: [https://github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes).
> This repository is read-only for importing, and not used for direct contributions.
> See [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
# kube-scheduler
Implements [KEP 115 - Moving ComponentConfig API types to staging repos](https://git.k8s.io/enhancements/keps/sig-cluster-lifecycle/wgs/115-componentconfig#kube-scheduler-changes)
This repo provides external, versioned ComponentConfig API types for configuring the kube-scheduler.
These external types can easily be vendored and used by any third-party tool writing Kubernetes
ComponentConfig objects.
## Compatibility
HEAD of this repo will match HEAD of k8s.io/apiserver, k8s.io/apimachinery, and k8s.io/client-go.
## Where does it come from?
This repo is synced from https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/kube-scheduler.
Code changes are made in that location, merged into `k8s.io/kubernetes` and later synced here by a bot.
================================================
FILE: SECURITY_CONTACTS
================================================
# Defined below are the security contacts for this repo.
#
# They are the contact point for the Product Security Committee to reach out
# to for triaging and handling of incoming issues.
#
# The below names agree to abide by the
# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy)
# and will be removed and replaced if they violate that agreement.
#
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/
cjcullen
joelsmith
liggitt
philips
tallclair
================================================
FILE: code-of-conduct.md
================================================
# Kubernetes Community Code of Conduct
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
================================================
FILE: config/OWNERS
================================================
# See the OWNERS docs at https://go.k8s.io/owners
# Disable inheritance as this is an api owners file
options:
no_parent_owners: true
approvers:
- api-approvers
- sig-scheduling-api-approvers
reviewers:
- api-reviewers
labels:
- kind/api-change
================================================
FILE: config/v1/doc.go
================================================
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true
// +k8s:openapi-model-package=io.k8s.kube-scheduler.config.v1
// +groupName=kubescheduler.config.k8s.io
package v1
================================================
FILE: config/v1/register.go
================================================
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name used in this package
const GroupName = "kubescheduler.config.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
var (
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
// AddToScheme is a global function that registers this API group & version to a scheme
AddToScheme = SchemeBuilder.AddToScheme
)
// addKnownTypes registers known types to the given scheme
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&KubeSchedulerConfiguration{},
&DefaultPreemptionArgs{},
&InterPodAffinityArgs{},
&NodeResourcesBalancedAllocationArgs{},
&NodeResourcesFitArgs{},
&PodTopologySpreadArgs{},
&VolumeBindingArgs{},
&NodeAffinityArgs{},
&DynamicResourcesArgs{},
)
return nil
}
================================================
FILE: config/v1/types.go
================================================
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"bytes"
"fmt"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1"
"sigs.k8s.io/yaml"
)
const (
// SchedulerDefaultLockObjectNamespace defines default scheduler lock object namespace ("kube-system")
SchedulerDefaultLockObjectNamespace string = metav1.NamespaceSystem
// SchedulerDefaultLockObjectName defines default scheduler lock object name ("kube-scheduler")
SchedulerDefaultLockObjectName = "kube-scheduler"
// SchedulerDefaultProviderName defines the default provider names
SchedulerDefaultProviderName = "DefaultProvider"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// KubeSchedulerConfiguration configures a scheduler
type KubeSchedulerConfiguration struct {
metav1.TypeMeta `json:",inline"`
// Parallelism defines the amount of parallelism in algorithms for scheduling a Pods. Must be greater than 0. Defaults to 16
Parallelism *int32 `json:"parallelism,omitempty"`
// LeaderElection defines the configuration of leader election client.
LeaderElection componentbaseconfigv1alpha1.LeaderElectionConfiguration `json:"leaderElection"`
// ClientConnection specifies the kubeconfig file and client connection
// settings for the proxy server to use when communicating with the apiserver.
ClientConnection componentbaseconfigv1alpha1.ClientConnectionConfiguration `json:"clientConnection"`
// DebuggingConfiguration holds configuration for Debugging related features
// TODO: We might wanna make this a substruct like Debugging componentbaseconfigv1alpha1.DebuggingConfiguration
componentbaseconfigv1alpha1.DebuggingConfiguration `json:",inline"`
// PercentageOfNodesToScore is the percentage of all nodes that once found feasible
// for running a pod, the scheduler stops its search for more feasible nodes in
// the cluster. This helps improve scheduler's performance. Scheduler always tries to find
// at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is.
// Example: if the cluster size is 500 nodes and the value of this flag is 30,
// then scheduler stops finding further feasible nodes once it finds 150 feasible ones.
// When the value is 0, default percentage (5%--50% based on the size of the cluster) of the
// nodes will be scored. It is overridden by profile level PercentageOfNodesToScore.
PercentageOfNodesToScore *int32 `json:"percentageOfNodesToScore,omitempty"`
// PodInitialBackoffSeconds is the initial backoff for unschedulable pods.
// If specified, it must be greater than 0. If this value is null, the default value (1s)
// will be used.
PodInitialBackoffSeconds *int64 `json:"podInitialBackoffSeconds,omitempty"`
// PodMaxBackoffSeconds is the max backoff for unschedulable pods.
// If specified, it must be greater than podInitialBackoffSeconds. If this value is null,
// the default value (10s) will be used.
PodMaxBackoffSeconds *int64 `json:"podMaxBackoffSeconds,omitempty"`
// Profiles are scheduling profiles that kube-scheduler supports. Pods can
// choose to be scheduled under a particular profile by setting its associated
// scheduler name. Pods that don't specify any scheduler name are scheduled
// with the "default-scheduler" profile, if present here.
// +listType=map
// +listMapKey=schedulerName
Profiles []KubeSchedulerProfile `json:"profiles,omitempty"`
// Extenders are the list of scheduler extenders, each holding the values of how to communicate
// with the extender. These extenders are shared by all scheduler profiles.
// +listType=set
Extenders []Extender `json:"extenders,omitempty"`
// DelayCacheUntilActive specifies when to start caching. If this is true and leader election is enabled,
// the scheduler will wait to fill informer caches until it is the leader. Doing so will have slower
// failover with the benefit of lower memory overhead while waiting to become leader.
// Defaults to false.
DelayCacheUntilActive bool `json:"delayCacheUntilActive,omitempty"`
}
// DecodeNestedObjects decodes plugin args for known types.
func (c *KubeSchedulerConfiguration) DecodeNestedObjects(d runtime.Decoder) error {
var strictDecodingErrs []error
for i := range c.Profiles {
prof := &c.Profiles[i]
for j := range prof.PluginConfig {
err := prof.PluginConfig[j].decodeNestedObjects(d)
if err != nil {
decodingErr := fmt.Errorf("decoding .profiles[%d].pluginConfig[%d]: %w", i, j, err)
if runtime.IsStrictDecodingError(err) {
strictDecodingErrs = append(strictDecodingErrs, decodingErr)
} else {
return decodingErr
}
}
}
}
if len(strictDecodingErrs) > 0 {
return runtime.NewStrictDecodingError(strictDecodingErrs)
}
return nil
}
// EncodeNestedObjects encodes plugin args.
func (c *KubeSchedulerConfiguration) EncodeNestedObjects(e runtime.Encoder) error {
for i := range c.Profiles {
prof := &c.Profiles[i]
for j := range prof.PluginConfig {
err := prof.PluginConfig[j].encodeNestedObjects(e)
if err != nil {
return fmt.Errorf("encoding .profiles[%d].pluginConfig[%d]: %w", i, j, err)
}
}
}
return nil
}
// KubeSchedulerProfile is a scheduling profile.
type KubeSchedulerProfile struct {
// SchedulerName is the name of the scheduler associated to this profile.
// If SchedulerName matches with the pod's "spec.schedulerName", then the pod
// is scheduled with this profile.
SchedulerName *string `json:"schedulerName,omitempty"`
// PercentageOfNodesToScore is the percentage of all nodes that once found feasible
// for running a pod, the scheduler stops its search for more feasible nodes in
// the cluster. This helps improve scheduler's performance. Scheduler always tries to find
// at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is.
// Example: if the cluster size is 500 nodes and the value of this flag is 30,
// then scheduler stops finding further feasible nodes once it finds 150 feasible ones.
// When the value is 0, default percentage (5%--50% based on the size of the cluster) of the
// nodes will be scored. It will override global PercentageOfNodesToScore. If it is empty,
// global PercentageOfNodesToScore will be used.
PercentageOfNodesToScore *int32 `json:"percentageOfNodesToScore,omitempty"`
// Plugins specify the set of plugins that should be enabled or disabled.
// Enabled plugins are the ones that should be enabled in addition to the
// default plugins. Disabled plugins are any of the default plugins that
// should be disabled.
// When no enabled or disabled plugin is specified for an extension point,
// default plugins for that extension point will be used if there is any.
// If a QueueSort plugin is specified, the same QueueSort Plugin and
// PluginConfig must be specified for all profiles.
Plugins *Plugins `json:"plugins,omitempty"`
// PluginConfig is an optional set of custom plugin arguments for each plugin.
// Omitting config args for a plugin is equivalent to using the default config
// for that plugin.
// +listType=map
// +listMapKey=name
PluginConfig []PluginConfig `json:"pluginConfig,omitempty"`
}
// Plugins include multiple extension points. When specified, the list of plugins for
// a particular extension point are the only ones enabled. If an extension point is
// omitted from the config, then the default set of plugins is used for that extension point.
// Enabled plugins are called in the order specified here, after default plugins. If they need to
// be invoked before default plugins, default plugins must be disabled and re-enabled here in desired order.
type Plugins struct {
// PreEnqueue is a list of plugins that should be invoked before adding pods to the scheduling queue.
PreEnqueue PluginSet `json:"preEnqueue,omitempty"`
// QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue.
QueueSort PluginSet `json:"queueSort,omitempty"`
// PreFilter is a list of plugins that should be invoked at "PreFilter" extension point of the scheduling framework.
PreFilter PluginSet `json:"preFilter,omitempty"`
// Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod.
Filter PluginSet `json:"filter,omitempty"`
// PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod.
PostFilter PluginSet `json:"postFilter,omitempty"`
// PreScore is a list of plugins that are invoked before scoring.
PreScore PluginSet `json:"preScore,omitempty"`
// Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase.
Score PluginSet `json:"score,omitempty"`
// Reserve is a list of plugins invoked when reserving/unreserving resources
// after a node is assigned to run the pod.
Reserve PluginSet `json:"reserve,omitempty"`
// Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod.
Permit PluginSet `json:"permit,omitempty"`
// PreBind is a list of plugins that should be invoked before a pod is bound.
PreBind PluginSet `json:"preBind,omitempty"`
// Bind is a list of plugins that should be invoked at "Bind" extension point of the scheduling framework.
// The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success.
Bind PluginSet `json:"bind,omitempty"`
// PostBind is a list of plugins that should be invoked after a pod is successfully bound.
PostBind PluginSet `json:"postBind,omitempty"`
// MultiPoint is a simplified config section to enable plugins for all valid extension points.
// Plugins enabled through MultiPoint will automatically register for every individual extension
// point the plugin has implemented. Disabling a plugin through MultiPoint disables that behavior.
// The same is true for disabling "*" through MultiPoint (no default plugins will be automatically registered).
// Plugins can still be disabled through their individual extension points.
//
// In terms of precedence, plugin config follows this basic hierarchy
// 1. Specific extension points
// 2. Explicitly configured MultiPoint plugins
// 3. The set of default plugins, as MultiPoint plugins
// This implies that a higher precedence plugin will run first and overwrite any settings within MultiPoint.
// Explicitly user-configured plugins also take a higher precedence over default plugins.
// Within this hierarchy, an Enabled setting takes precedence over Disabled. For example, if a plugin is
// set in both `multiPoint.Enabled` and `multiPoint.Disabled`, the plugin will be enabled. Similarly,
// including `multiPoint.Disabled = '*'` and `multiPoint.Enabled = pluginA` will still register that specific
// plugin through MultiPoint. This follows the same behavior as all other extension point configurations.
MultiPoint PluginSet `json:"multiPoint,omitempty"`
// PlacementGenerate is a list of plugins that should be invoked during pod group scheduling cycle when determining placements for a pod group.
PlacementGenerate PluginSet `json:"placementGenerate,omitempty"`
// PlacementScore is a list of plugins that should be invoked during workload scheduling cycle when ranking pod group assignments.
PlacementScore PluginSet `json:"placementScore,omitempty"`
}
// PluginSet specifies enabled and disabled plugins for an extension point.
// If an array is empty, missing, or nil, default plugins at that extension point will be used.
type PluginSet struct {
// Enabled specifies plugins that should be enabled in addition to default plugins.
// If the default plugin is also configured in the scheduler config file, the weight of plugin will
// be overridden accordingly.
// These are called after default plugins and in the same order specified here.
// +listType=atomic
Enabled []Plugin `json:"enabled,omitempty"`
// Disabled specifies default plugins that should be disabled.
// When all default plugins need to be disabled, an array containing only one "*" should be provided.
// +listType=map
// +listMapKey=name
Disabled []Plugin `json:"disabled,omitempty"`
}
// Plugin specifies a plugin name and its weight when applicable. Weight is used only for Score and PlacementScore plugins.
type Plugin struct {
// Name defines the name of plugin
Name string `json:"name"`
// Weight defines the weight of plugin, only used for Score and PlacementScore plugins.
Weight *int32 `json:"weight,omitempty"`
}
// PluginConfig specifies arguments that should be passed to a plugin at the time of initialization.
// A plugin that is invoked at multiple extension points is initialized once. Args can have arbitrary structure.
// It is up to the plugin to process these Args.
type PluginConfig struct {
// Name defines the name of plugin being configured
Name string `json:"name"`
// Args defines the arguments passed to the plugins at the time of initialization. Args can have arbitrary structure.
Args runtime.RawExtension `json:"args,omitempty"`
}
func (c *PluginConfig) decodeNestedObjects(d runtime.Decoder) error {
gvk := SchemeGroupVersion.WithKind(c.Name + "Args")
// dry-run to detect and skip out-of-tree plugin args.
if _, _, err := d.Decode(nil, &gvk, nil); runtime.IsNotRegisteredError(err) {
return nil
}
var strictDecodingErr error
obj, parsedGvk, err := d.Decode(c.Args.Raw, &gvk, nil)
if err != nil {
decodingArgsErr := fmt.Errorf("decoding args for plugin %s: %w", c.Name, err)
if obj != nil && runtime.IsStrictDecodingError(err) {
strictDecodingErr = runtime.NewStrictDecodingError([]error{decodingArgsErr})
} else {
return decodingArgsErr
}
}
if parsedGvk.GroupKind() != gvk.GroupKind() {
return fmt.Errorf("args for plugin %s were not of type %s, got %s", c.Name, gvk.GroupKind(), parsedGvk.GroupKind())
}
c.Args.Object = obj
return strictDecodingErr
}
func (c *PluginConfig) encodeNestedObjects(e runtime.Encoder) error {
if c.Args.Object == nil {
return nil
}
var buf bytes.Buffer
err := e.Encode(c.Args.Object, &buf)
if err != nil {
return err
}
// The <e> encoder might be a YAML encoder, but the parent encoder expects
// JSON output, so we convert YAML back to JSON.
// This is a no-op if <e> produces JSON.
json, err := yaml.YAMLToJSON(buf.Bytes())
if err != nil {
return err
}
c.Args.Raw = json
return nil
}
// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty,
// it is assumed that the extender chose not to provide that extension.
type Extender struct {
// URLPrefix at which the extender is available
URLPrefix string `json:"urlPrefix"`
// Verb for the filter call, empty if not supported. This verb is appended to the URLPrefix when issuing the filter call to extender.
FilterVerb string `json:"filterVerb,omitempty"`
// Verb for the preempt call, empty if not supported. This verb is appended to the URLPrefix when issuing the preempt call to extender.
PreemptVerb string `json:"preemptVerb,omitempty"`
// Verb for the prioritize call, empty if not supported. This verb is appended to the URLPrefix when issuing the prioritize call to extender.
PrioritizeVerb string `json:"prioritizeVerb,omitempty"`
// The numeric multiplier for the node scores that the prioritize call generates.
// The weight should be a positive integer
Weight int64 `json:"weight,omitempty"`
// Verb for the bind call, empty if not supported. This verb is appended to the URLPrefix when issuing the bind call to extender.
// If this method is implemented by the extender, it is the extender's responsibility to bind the pod to apiserver. Only one extender
// can implement this function.
BindVerb string `json:"bindVerb,omitempty"`
// EnableHTTPS specifies whether https should be used to communicate with the extender
EnableHTTPS bool `json:"enableHTTPS,omitempty"`
// TLSConfig specifies the transport layer security config
TLSConfig *ExtenderTLSConfig `json:"tlsConfig,omitempty"`
// HTTPTimeout specifies the timeout duration for a call to the extender. Filter timeout fails the scheduling of the pod. Prioritize
// timeout is ignored, k8s/other extenders priorities are used to select the node.
HTTPTimeout metav1.Duration `json:"httpTimeout,omitempty"`
// NodeCacheCapable specifies that the extender is capable of caching node information,
// so the scheduler should only send minimal information about the eligible nodes
// assuming that the extender already cached full details of all nodes in the cluster
NodeCacheCapable bool `json:"nodeCacheCapable,omitempty"`
// ManagedResources is a list of extended resources that are managed by
// this extender.
// - A pod will be sent to the extender on the Filter, Prioritize and Bind
// (if the extender is the binder) phases iff the pod requests at least
// one of the extended resources in this list. If empty or unspecified,
// all pods will be sent to this extender.
// - If IgnoredByScheduler is set to true for a resource, kube-scheduler
// will skip checking the resource in predicates.
// +optional
// +listType=atomic
ManagedResources []ExtenderManagedResource `json:"managedResources,omitempty"`
// Ignorable specifies if the extender is ignorable, i.e. scheduling should not
// fail when the extender returns an error or is not reachable.
Ignorable bool `json:"ignorable,omitempty"`
}
// ExtenderManagedResource describes the arguments of extended resources
// managed by an extender.
type ExtenderManagedResource struct {
// Name is the extended resource name.
Name string `json:"name"`
// IgnoredByScheduler indicates whether kube-scheduler should ignore this
// resource when applying predicates.
IgnoredByScheduler bool `json:"ignoredByScheduler,omitempty"`
}
// ExtenderTLSConfig contains settings to enable TLS with extender
type ExtenderTLSConfig struct {
// Server should be accessed without verifying the TLS certificate. For testing only.
Insecure bool `json:"insecure,omitempty"`
// ServerName is passed to the server for SNI and is used in the client to check server
// certificates against. If ServerName is empty, the hostname used to contact the
// server is used.
ServerName string `json:"serverName,omitempty"`
// Server requires TLS client certificate authentication
CertFile string `json:"certFile,omitempty"`
// Server requires TLS client certificate authentication
KeyFile string `json:"keyFile,omitempty"`
// Trusted root certificates for server
CAFile string `json:"caFile,omitempty"`
// CertData holds PEM-encoded bytes (typically read from a client certificate file).
// CertData takes precedence over CertFile
// +listType=atomic
CertData []byte `json:"certData,omitempty"`
// KeyData holds PEM-encoded bytes (typically read from a client certificate key file).
// KeyData takes precedence over KeyFile
// +listType=atomic
KeyData []byte `json:"keyData,omitempty"`
// CAData holds PEM-encoded bytes (typically read from a root certificates bundle).
// CAData takes precedence over CAFile
// +listType=atomic
CAData []byte `json:"caData,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// DynamicResourcesArgs holds arguments used to configure the DynamicResources plugin.
type DynamicResourcesArgs struct {
metav1.TypeMeta `json:",inline"`
// FilterTimeout limits the amount of time that the filter operation may
// take per node to search for devices that can be allocated to scheduler
// a pod to that node.
//
// In typical scenarios, this operation should complete in 10 to 200
// milliseconds, but could also be longer depending on the number of
// requests per ResourceClaim, number of ResourceClaims, number of
// published devices in ResourceSlices, and the complexity of the
// requests. Other checks besides CEL evaluation also take time (usage
// checks, match attributes, etc.).
//
// Therefore the scheduler plugin applies this timeout. If the timeout
// is reached, the Pod is considered unschedulable for the node.
// If filtering succeeds for some other node(s), those are picked instead.
// If filtering fails for all of them, the Pod is placed in the
// unschedulable queue. It will get checked again if changes in
// e.g. ResourceSlices or ResourceClaims indicate that
// another scheduling attempt might succeed. If this fails repeatedly,
// exponential backoff slows down future attempts.
//
// The default is 10 seconds.
// This is sufficient to prevent worst-case scenarios while not impacting normal
// usage of DRA. However, slow filtering can slow down Pod scheduling
// also for Pods not using DRA. Administators can reduce the timeout
// after checking the
// `scheduler_framework_extension_point_duration_seconds` metrics.
//
// Setting it to zero completely disables the timeout.
FilterTimeout *metav1.Duration `json:"filterTimeout"`
// BindingTimeout limits how long the PreBind extension point may wait for
// ResourceClaim device BindingConditions to become satisfied when such
// conditions are present. While waiting, the scheduler periodically checks
// device status. If the timeout elapses before all required conditions are
// true (or any bindingFailureConditions become true), the allocation is
// cleared and the Pod re-enters scheduling queue. Note that the same or other node may be
// chosen if feasible; otherwise the Pod is placed in the unschedulable queue and
// retried based on cluster changes and backoff.
//
// Defaults & feature gates:
// - Defaults to 10 minutes when the DRADeviceBindingConditions feature gate is enabled.
// - Has effect only when BOTH DRADeviceBindingConditions and
// DRAResourceClaimDeviceStatus are enabled; otherwise omit this field.
// - When DRADeviceBindingConditions is disabled, setting this field is considered an error.
//
// Valid values:
// - >=1s (non-zero). No upper bound is enforced.
//
// Tuning guidance:
// - Lower values reduce time-to-retry when devices aren’t ready but can
// increase churn if drivers typically need longer to report readiness.
// - Review scheduler latency metrics (e.g. PreBind duration in
// `scheduler_framework_extension_point_duration_seconds`) and driver
// readiness behavior before tightening this timeout.
BindingTimeout *metav1.Duration `json:"bindingTimeout,omitempty"`
}
const DynamicResourcesFilterTimeoutDefault = 10 * time.Second
const DynamicResourcesBindingTimeoutDefault = 600 * time.Second
================================================
FILE: config/v1/types_pluginargs.go
================================================
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// DefaultPreemptionArgs holds arguments used to configure the
// DefaultPreemption plugin.
type DefaultPreemptionArgs struct {
metav1.TypeMeta `json:",inline"`
// MinCandidateNodesPercentage is the minimum number of candidates to
// shortlist when dry running preemption as a percentage of number of nodes.
// Must be in the range [0, 100]. Defaults to 10% of the cluster size if
// unspecified.
MinCandidateNodesPercentage *int32 `json:"minCandidateNodesPercentage,omitempty"`
// MinCandidateNodesAbsolute is the absolute minimum number of candidates to
// shortlist. The likely number of candidates enumerated for dry running
// preemption is given by the formula:
// numCandidates = max(numNodes * minCandidateNodesPercentage, minCandidateNodesAbsolute)
// We say "likely" because there are other factors such as PDB violations
// that play a role in the number of candidates shortlisted. Must be at least
// 0 nodes. Defaults to 100 nodes if unspecified.
MinCandidateNodesAbsolute *int32 `json:"minCandidateNodesAbsolute,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// InterPodAffinityArgs holds arguments used to configure the InterPodAffinity plugin.
type InterPodAffinityArgs struct {
metav1.TypeMeta `json:",inline"`
// HardPodAffinityWeight is the scoring weight for existing pods with a
// matching hard affinity to the incoming pod.
HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"`
// IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity
// rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.
IgnorePreferredTermsOfExistingPods bool `json:"ignorePreferredTermsOfExistingPods"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// NodeResourcesFitArgs holds arguments used to configure the NodeResourcesFit plugin.
type NodeResourcesFitArgs struct {
metav1.TypeMeta `json:",inline"`
// IgnoredResources is the list of resources that NodeResources fit filter
// 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 '/'. 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
// for the PodTopologySpread plugin.
type PodTopologySpreadConstraintsDefaulting string
const (
// SystemDefaulting instructs to use the kubernetes defined default.
SystemDefaulting PodTopologySpreadConstraintsDefaulting = "System"
// ListDefaulting instructs to use the config provided default.
ListDefaulting PodTopologySpreadConstraintsDefaulting = "List"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PodTopologySpreadArgs holds arguments used to configure the PodTopologySpread plugin.
type PodTopologySpreadArgs struct {
metav1.TypeMeta `json:",inline"`
// DefaultConstraints defines topology spread constraints to be applied to
// Pods that don't define any in `pod.spec.topologySpreadConstraints`.
// `.defaultConstraints[*].labelSelectors` must be empty, as they are
// deduced from the Pod's membership to Services, ReplicationControllers,
// ReplicaSets or StatefulSets.
// When not empty, .defaultingType must be "List".
// +optional
// +listType=atomic
DefaultConstraints []corev1.TopologySpreadConstraint `json:"defaultConstraints,omitempty"`
// DefaultingType determines how .defaultConstraints are deduced. Can be one
// of "System" or "List".
//
// - "System": Use kubernetes defined constraints that spread Pods among
// Nodes and Zones.
// - "List": Use constraints defined in .defaultConstraints.
//
// Defaults to "System".
// +optional
DefaultingType PodTopologySpreadConstraintsDefaulting `json:"defaultingType,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// NodeResourcesBalancedAllocationArgs holds arguments used to configure NodeResourcesBalancedAllocation plugin.
type NodeResourcesBalancedAllocationArgs struct {
metav1.TypeMeta `json:",inline"`
// Resources to be managed, the default is "cpu" and "memory" if not specified.
// +listType=map
// +listMapKey=name
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.
Utilization int32 `json:"utilization"`
// Score assigned to given utilization (y axis). Valid values are 0 to 10.
Score int32 `json:"score"`
}
// ResourceSpec represents a single resource.
type ResourceSpec struct {
// Name of the resource.
Name string `json:"name"`
// Weight of the resource.
Weight int64 `json:"weight,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// VolumeBindingArgs holds arguments used to configure the VolumeBinding plugin.
type VolumeBindingArgs struct {
metav1.TypeMeta `json:",inline"`
// BindTimeoutSeconds is the timeout in seconds in volume binding operation.
// Value must be non-negative integer. The value zero indicates no waiting.
// If this value is nil, the default value (600) will be used.
BindTimeoutSeconds *int64 `json:"bindTimeoutSeconds,omitempty"`
// Shape specifies the points defining the score function shape, which is
// used to score nodes based on the utilization of provisioned PVs.
// The utilization is calculated by dividing the total requested
// storage of the pod by the total capacity of feasible PVs on each node.
// Each point contains utilization (ranges from 0 to 100) and its
// associated score (ranges from 0 to 10). You can turn the priority by
// specifying different scores for different utilization numbers.
// The default shape points are:
// 1) 10 for 0 utilization
// 2) 0 for 100 utilization
// All points must be sorted in increasing order by utilization.
// +featureGate=StorageCapacityScoring
// +optional
// +listType=atomic
Shape []UtilizationShapePoint `json:"shape,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// NodeAffinityArgs holds arguments to configure the NodeAffinity plugin.
type NodeAffinityArgs struct {
metav1.TypeMeta `json:",inline"`
// AddedAffinity is applied to all Pods additionally to the NodeAffinity
// specified in the PodSpec. That is, Nodes need to satisfy AddedAffinity
// AND .spec.NodeAffinity. AddedAffinity is empty by default (all Nodes
// match).
// When AddedAffinity is used, some Pods with affinity requirements that match
// a specific Node (such as Daemonset Pods) might remain unschedulable.
// +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 allocated resources.
LeastAllocated ScoringStrategyType = "LeastAllocated"
// MostAllocated strategy prioritizes nodes with most allocated 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"`
}
================================================
FILE: config/v1/zz_generated.deepcopy.go
================================================
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DefaultPreemptionArgs) DeepCopyInto(out *DefaultPreemptionArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.MinCandidateNodesPercentage != nil {
in, out := &in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage
*out = new(int32)
**out = **in
}
if in.MinCandidateNodesAbsolute != nil {
in, out := &in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultPreemptionArgs.
func (in *DefaultPreemptionArgs) DeepCopy() *DefaultPreemptionArgs {
if in == nil {
return nil
}
out := new(DefaultPreemptionArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DefaultPreemptionArgs) 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 *DynamicResourcesArgs) DeepCopyInto(out *DynamicResourcesArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.FilterTimeout != nil {
in, out := &in.FilterTimeout, &out.FilterTimeout
*out = new(metav1.Duration)
**out = **in
}
if in.BindingTimeout != nil {
in, out := &in.BindingTimeout, &out.BindingTimeout
*out = new(metav1.Duration)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicResourcesArgs.
func (in *DynamicResourcesArgs) DeepCopy() *DynamicResourcesArgs {
if in == nil {
return nil
}
out := new(DynamicResourcesArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DynamicResourcesArgs) 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 *Extender) DeepCopyInto(out *Extender) {
*out = *in
if in.TLSConfig != nil {
in, out := &in.TLSConfig, &out.TLSConfig
*out = new(ExtenderTLSConfig)
(*in).DeepCopyInto(*out)
}
out.HTTPTimeout = in.HTTPTimeout
if in.ManagedResources != nil {
in, out := &in.ManagedResources, &out.ManagedResources
*out = make([]ExtenderManagedResource, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extender.
func (in *Extender) DeepCopy() *Extender {
if in == nil {
return nil
}
out := new(Extender)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderManagedResource) DeepCopyInto(out *ExtenderManagedResource) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderManagedResource.
func (in *ExtenderManagedResource) DeepCopy() *ExtenderManagedResource {
if in == nil {
return nil
}
out := new(ExtenderManagedResource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderTLSConfig) DeepCopyInto(out *ExtenderTLSConfig) {
*out = *in
if in.CertData != nil {
in, out := &in.CertData, &out.CertData
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.KeyData != nil {
in, out := &in.KeyData, &out.KeyData
*out = make([]byte, len(*in))
copy(*out, *in)
}
if in.CAData != nil {
in, out := &in.CAData, &out.CAData
*out = make([]byte, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderTLSConfig.
func (in *ExtenderTLSConfig) DeepCopy() *ExtenderTLSConfig {
if in == nil {
return nil
}
out := new(ExtenderTLSConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InterPodAffinityArgs) DeepCopyInto(out *InterPodAffinityArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.HardPodAffinityWeight != nil {
in, out := &in.HardPodAffinityWeight, &out.HardPodAffinityWeight
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterPodAffinityArgs.
func (in *InterPodAffinityArgs) DeepCopy() *InterPodAffinityArgs {
if in == nil {
return nil
}
out := new(InterPodAffinityArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *InterPodAffinityArgs) 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 *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Parallelism != nil {
in, out := &in.Parallelism, &out.Parallelism
*out = new(int32)
**out = **in
}
in.LeaderElection.DeepCopyInto(&out.LeaderElection)
out.ClientConnection = in.ClientConnection
in.DebuggingConfiguration.DeepCopyInto(&out.DebuggingConfiguration)
if in.PercentageOfNodesToScore != nil {
in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore
*out = new(int32)
**out = **in
}
if in.PodInitialBackoffSeconds != nil {
in, out := &in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds
*out = new(int64)
**out = **in
}
if in.PodMaxBackoffSeconds != nil {
in, out := &in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds
*out = new(int64)
**out = **in
}
if in.Profiles != nil {
in, out := &in.Profiles, &out.Profiles
*out = make([]KubeSchedulerProfile, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Extenders != nil {
in, out := &in.Extenders, &out.Extenders
*out = make([]Extender, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerConfiguration.
func (in *KubeSchedulerConfiguration) DeepCopy() *KubeSchedulerConfiguration {
if in == nil {
return nil
}
out := new(KubeSchedulerConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *KubeSchedulerConfiguration) 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 *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) {
*out = *in
if in.SchedulerName != nil {
in, out := &in.SchedulerName, &out.SchedulerName
*out = new(string)
**out = **in
}
if in.PercentageOfNodesToScore != nil {
in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore
*out = new(int32)
**out = **in
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(Plugins)
(*in).DeepCopyInto(*out)
}
if in.PluginConfig != nil {
in, out := &in.PluginConfig, &out.PluginConfig
*out = make([]PluginConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerProfile.
func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile {
if in == nil {
return nil
}
out := new(KubeSchedulerProfile)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeAffinityArgs) DeepCopyInto(out *NodeAffinityArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.AddedAffinity != nil {
in, out := &in.AddedAffinity, &out.AddedAffinity
*out = new(corev1.NodeAffinity)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAffinityArgs.
func (in *NodeAffinityArgs) DeepCopy() *NodeAffinityArgs {
if in == nil {
return nil
}
out := new(NodeAffinityArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NodeAffinityArgs) 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 *NodeResourcesBalancedAllocationArgs) DeepCopyInto(out *NodeResourcesBalancedAllocationArgs) {
*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 NodeResourcesBalancedAllocationArgs.
func (in *NodeResourcesBalancedAllocationArgs) DeepCopy() *NodeResourcesBalancedAllocationArgs {
if in == nil {
return nil
}
out := new(NodeResourcesBalancedAllocationArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NodeResourcesBalancedAllocationArgs) 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 *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.IgnoredResources != nil {
in, out := &in.IgnoredResources, &out.IgnoredResources
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.IgnoredResourceGroups != nil {
in, out := &in.IgnoredResourceGroups, &out.IgnoredResourceGroups
*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
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesFitArgs.
func (in *NodeResourcesFitArgs) DeepCopy() *NodeResourcesFitArgs {
if in == nil {
return nil
}
out := new(NodeResourcesFitArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NodeResourcesFitArgs) 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
if in.Weight != nil {
in, out := &in.Weight, &out.Weight
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin.
func (in *Plugin) DeepCopy() *Plugin {
if in == nil {
return nil
}
out := new(Plugin)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PluginConfig) DeepCopyInto(out *PluginConfig) {
*out = *in
in.Args.DeepCopyInto(&out.Args)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig.
func (in *PluginConfig) DeepCopy() *PluginConfig {
if in == nil {
return nil
}
out := new(PluginConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PluginSet) DeepCopyInto(out *PluginSet) {
*out = *in
if in.Enabled != nil {
in, out := &in.Enabled, &out.Enabled
*out = make([]Plugin, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Disabled != nil {
in, out := &in.Disabled, &out.Disabled
*out = make([]Plugin, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet.
func (in *PluginSet) DeepCopy() *PluginSet {
if in == nil {
return nil
}
out := new(PluginSet)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Plugins) DeepCopyInto(out *Plugins) {
*out = *in
in.PreEnqueue.DeepCopyInto(&out.PreEnqueue)
in.QueueSort.DeepCopyInto(&out.QueueSort)
in.PreFilter.DeepCopyInto(&out.PreFilter)
in.Filter.DeepCopyInto(&out.Filter)
in.PostFilter.DeepCopyInto(&out.PostFilter)
in.PreScore.DeepCopyInto(&out.PreScore)
in.Score.DeepCopyInto(&out.Score)
in.Reserve.DeepCopyInto(&out.Reserve)
in.Permit.DeepCopyInto(&out.Permit)
in.PreBind.DeepCopyInto(&out.PreBind)
in.Bind.DeepCopyInto(&out.Bind)
in.PostBind.DeepCopyInto(&out.PostBind)
in.MultiPoint.DeepCopyInto(&out.MultiPoint)
in.PlacementGenerate.DeepCopyInto(&out.PlacementGenerate)
in.PlacementScore.DeepCopyInto(&out.PlacementScore)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins.
func (in *Plugins) DeepCopy() *Plugins {
if in == nil {
return nil
}
out := new(Plugins)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodTopologySpreadArgs) DeepCopyInto(out *PodTopologySpreadArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.DefaultConstraints != nil {
in, out := &in.DefaultConstraints, &out.DefaultConstraints
*out = make([]corev1.TopologySpreadConstraint, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTopologySpreadArgs.
func (in *PodTopologySpreadArgs) DeepCopy() *PodTopologySpreadArgs {
if in == nil {
return nil
}
out := new(PodTopologySpreadArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PodTopologySpreadArgs) 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 *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
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec.
func (in *ResourceSpec) DeepCopy() *ResourceSpec {
if in == nil {
return nil
}
out := new(ResourceSpec)
in.DeepCopyInto(out)
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
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint.
func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint {
if in == nil {
return nil
}
out := new(UtilizationShapePoint)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VolumeBindingArgs) DeepCopyInto(out *VolumeBindingArgs) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.BindTimeoutSeconds != nil {
in, out := &in.BindTimeoutSeconds, &out.BindTimeoutSeconds
*out = new(int64)
**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 VolumeBindingArgs.
func (in *VolumeBindingArgs) DeepCopy() *VolumeBindingArgs {
if in == nil {
return nil
}
out := new(VolumeBindingArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *VolumeBindingArgs) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
================================================
FILE: config/v1/zz_generated.model_name.go
================================================
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by openapi-gen. DO NOT EDIT.
package v1
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in DefaultPreemptionArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.DefaultPreemptionArgs"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in DynamicResourcesArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.DynamicResourcesArgs"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in Extender) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.Extender"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in ExtenderManagedResource) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.ExtenderManagedResource"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in ExtenderTLSConfig) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.ExtenderTLSConfig"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in InterPodAffinityArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.InterPodAffinityArgs"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in KubeSchedulerConfiguration) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.KubeSchedulerConfiguration"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in KubeSchedulerProfile) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.KubeSchedulerProfile"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in NodeAffinityArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.NodeAffinityArgs"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in NodeResourcesBalancedAllocationArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.NodeResourcesBalancedAllocationArgs"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in NodeResourcesFitArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.NodeResourcesFitArgs"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in Plugin) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.Plugin"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in PluginConfig) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.PluginConfig"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in PluginSet) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.PluginSet"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in Plugins) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.Plugins"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in PodTopologySpreadArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.PodTopologySpreadArgs"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in RequestedToCapacityRatioParam) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.RequestedToCapacityRatioParam"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in ResourceSpec) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.ResourceSpec"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in ScoringStrategy) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.ScoringStrategy"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in UtilizationShapePoint) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.UtilizationShapePoint"
}
// OpenAPIModelName returns the OpenAPI model name for this type.
func (in VolumeBindingArgs) OpenAPIModelName() string {
return "io.k8s.kube-scheduler.config.v1.VolumeBindingArgs"
}
================================================
FILE: doc.go
================================================
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubescheduler
================================================
FILE: extender/OWNERS
================================================
# See the OWNERS docs at https://go.k8s.io/owners
# Disable inheritance as this is an api owners file
options:
no_parent_owners: true
approvers:
- api-approvers
reviewers:
- api-reviewers
- sig-scheduling
labels:
- kind/api-change
- sig/scheduling
================================================
FILE: extender/v1/doc.go
================================================
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package
// Package v1 contains scheduler API objects.
package v1
================================================
FILE: extender/v1/types.go
================================================
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)
const (
// MinExtenderPriority defines the min priority value for extender.
MinExtenderPriority int64 = 0
// MaxExtenderPriority defines the max priority value for extender.
MaxExtenderPriority int64 = 10
)
// ExtenderPreemptionResult represents the result returned by preemption phase of extender.
type ExtenderPreemptionResult struct {
NodeNameToMetaVictims map[string]*MetaVictims
}
// ExtenderPreemptionArgs represents the arguments needed by the extender to preempt pods on nodes.
type ExtenderPreemptionArgs struct {
// Pod being scheduled
Pod *v1.Pod
// Victims map generated by scheduler preemption phase
// Only set NodeNameToMetaVictims if Extender.NodeCacheCapable == true. Otherwise, only set NodeNameToVictims.
NodeNameToVictims map[string]*Victims
NodeNameToMetaVictims map[string]*MetaVictims
}
// Victims represents:
//
// pods: a group of pods expected to be preempted.
// numPDBViolations: the count of violations of PodDisruptionBudget
type Victims struct {
Pods []*v1.Pod
NumPDBViolations int64
}
// MetaPod represent identifier for a v1.Pod
type MetaPod struct {
UID string
}
// MetaVictims represents:
//
// pods: a group of pods expected to be preempted.
// Only Pod identifiers will be sent and user are expect to get v1.Pod in their own way.
// numPDBViolations: the count of violations of PodDisruptionBudget
type MetaVictims struct {
Pods []*MetaPod
NumPDBViolations int64
}
// ExtenderArgs represents the arguments needed by the extender to filter/prioritize
// nodes for a pod.
type ExtenderArgs struct {
// Pod being scheduled
Pod *v1.Pod
// List of candidate nodes where the pod can be scheduled; to be populated
// only if Extender.NodeCacheCapable == false
Nodes *v1.NodeList
// List of candidate node names where the pod can be scheduled; to be
// populated only if Extender.NodeCacheCapable == true
NodeNames *[]string
}
// FailedNodesMap represents the filtered out nodes, with node names and failure messages
type FailedNodesMap map[string]string
// ExtenderFilterResult represents the results of a filter call to an extender
type ExtenderFilterResult struct {
// Filtered set of nodes where the pod can be scheduled; to be populated
// only if Extender.NodeCacheCapable == false
Nodes *v1.NodeList
// Filtered set of nodes where the pod can be scheduled; to be populated
// only if Extender.NodeCacheCapable == true
NodeNames *[]string
// Filtered out nodes where the pod can't be scheduled and the failure messages
FailedNodes FailedNodesMap
// Filtered out nodes where the pod can't be scheduled and preemption would
// not change anything. The value is the failure message same as FailedNodes.
// Nodes specified here takes precedence over FailedNodes.
FailedAndUnresolvableNodes FailedNodesMap
// Error message indicating failure
Error string
}
// ExtenderBindingArgs represents the arguments to an extender for binding a pod to a node.
type ExtenderBindingArgs struct {
// PodName is the name of the pod being bound
PodName string
// PodNamespace is the namespace of the pod being bound
PodNamespace string
// PodUID is the UID of the pod being bound
PodUID types.UID
// Node selected by the scheduler
Node string
}
// ExtenderBindingResult represents the result of binding of a pod to a node from an extender.
type ExtenderBindingResult struct {
// Error message indicating failure
Error string
}
// HostPriority represents the priority of scheduling to a particular host, higher priority is better.
type HostPriority struct {
// Name of the host
Host string
// Score associated with the host
Score int64
}
// HostPriorityList declares a []HostPriority type.
type HostPriorityList []HostPriority
================================================
FILE: extender/v1/types_test.go
================================================
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
// TestCompatibility verifies that the types in extender/v1 can be successfully encoded to json and decoded back, even when lowercased,
// since these types were written around JSON tags and we need to enforce consistency on them now.
// @TODO(88634): v2 of these types should be defined with proper JSON tags to enforce field casing to a single approach
func TestCompatibility(t *testing.T) {
testcases := []struct {
emptyObj interface{}
obj interface{}
expectJSON string
}{
{
emptyObj: &ExtenderPreemptionResult{},
obj: &ExtenderPreemptionResult{
NodeNameToMetaVictims: map[string]*MetaVictims{"foo": {Pods: []*MetaPod{{UID: "myuid"}}, NumPDBViolations: 1}},
},
expectJSON: `{"NodeNameToMetaVictims":{"foo":{"Pods":[{"UID":"myuid"}],"NumPDBViolations":1}}}`,
},
{
emptyObj: &ExtenderPreemptionArgs{},
obj: &ExtenderPreemptionArgs{
Pod: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "podname"}},
NodeNameToVictims: map[string]*Victims{"foo": {Pods: []*corev1.Pod{{ObjectMeta: metav1.ObjectMeta{Name: "podname"}}}, NumPDBViolations: 1}},
NodeNameToMetaVictims: map[string]*MetaVictims{"foo": {Pods: []*MetaPod{{UID: "myuid"}}, NumPDBViolations: 1}},
},
expectJSON: `{"Pod":{"metadata":{"name":"podname"},"spec":{"containers":null},"status":{}},"NodeNameToVictims":{"foo":{"Pods":[{"metadata":{"name":"podname"},"spec":{"containers":null},"status":{}}],"NumPDBViolations":1}},"NodeNameToMetaVictims":{"foo":{"Pods":[{"UID":"myuid"}],"NumPDBViolations":1}}}`,
},
{
emptyObj: &ExtenderArgs{},
obj: &ExtenderArgs{
Pod: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "podname"}},
Nodes: &corev1.NodeList{Items: []corev1.Node{{ObjectMeta: metav1.ObjectMeta{Name: "nodename"}}}},
NodeNames: &[]string{"node1"},
},
expectJSON: `{"Pod":{"metadata":{"name":"podname"},"spec":{"containers":null},"status":{}},"Nodes":{"metadata":{},"items":[{"metadata":{"name":"nodename"},"spec":{},"status":{"daemonEndpoints":{"kubeletEndpoint":{"Port":0}},"nodeInfo":{"machineID":"","systemUUID":"","bootID":"","kernelVersion":"","osImage":"","containerRuntimeVersion":"","kubeletVersion":"","kubeProxyVersion":"","operatingSystem":"","architecture":""}}}]},"NodeNames":["node1"]}`,
},
{
emptyObj: &ExtenderFilterResult{},
obj: &ExtenderFilterResult{
Nodes: &corev1.NodeList{Items: []corev1.Node{{ObjectMeta: metav1.ObjectMeta{Name: "nodename"}}}},
NodeNames: &[]string{"node1"},
FailedNodes: FailedNodesMap{"foo": "bar"},
FailedAndUnresolvableNodes: FailedNodesMap{"baz": "qux"},
Error: "myerror",
},
expectJSON: `{"Nodes":{"metadata":{},"items":[{"metadata":{"name":"nodename"},"spec":{},"status":{"daemonEndpoints":{"kubeletEndpoint":{"Port":0}},"nodeInfo":{"machineID":"","systemUUID":"","bootID":"","kernelVersion":"","osImage":"","containerRuntimeVersion":"","kubeletVersion":"","kubeProxyVersion":"","operatingSystem":"","architecture":""}}}]},"NodeNames":["node1"],"FailedNodes":{"foo":"bar"},"FailedAndUnresolvableNodes":{"baz":"qux"},"Error":"myerror"}`,
},
{
emptyObj: &ExtenderBindingArgs{},
obj: &ExtenderBindingArgs{
PodName: "mypodname",
PodNamespace: "mypodnamespace",
PodUID: types.UID("mypoduid"),
Node: "mynode",
},
expectJSON: `{"PodName":"mypodname","PodNamespace":"mypodnamespace","PodUID":"mypoduid","Node":"mynode"}`,
},
{
emptyObj: &ExtenderBindingResult{},
obj: &ExtenderBindingResult{Error: "myerror"},
expectJSON: `{"Error":"myerror"}`,
},
{
emptyObj: &HostPriority{},
obj: &HostPriority{Host: "myhost", Score: 1},
expectJSON: `{"Host":"myhost","Score":1}`,
},
}
for _, tc := range testcases {
t.Run(reflect.TypeOf(tc.obj).String(), func(t *testing.T) {
data, err := json.Marshal(tc.obj)
if err != nil {
t.Fatal(err)
}
if string(data) != tc.expectJSON {
t.Fatalf("expected %s, got %s", tc.expectJSON, string(data))
}
if err := json.Unmarshal([]byte(strings.ToLower(string(data))), tc.emptyObj); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(tc.emptyObj, tc.obj) {
t.Fatalf("round-tripped case-insensitive diff: %s", cmp.Diff(tc.obj, tc.emptyObj))
}
})
}
}
================================================
FILE: extender/v1/zz_generated.deepcopy.go
================================================
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1
import (
corev1 "k8s.io/api/core/v1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderArgs) DeepCopyInto(out *ExtenderArgs) {
*out = *in
if in.Pod != nil {
in, out := &in.Pod, &out.Pod
*out = new(corev1.Pod)
(*in).DeepCopyInto(*out)
}
if in.Nodes != nil {
in, out := &in.Nodes, &out.Nodes
*out = new(corev1.NodeList)
(*in).DeepCopyInto(*out)
}
if in.NodeNames != nil {
in, out := &in.NodeNames, &out.NodeNames
*out = new([]string)
if **in != nil {
in, out := *in, *out
*out = make([]string, len(*in))
copy(*out, *in)
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderArgs.
func (in *ExtenderArgs) DeepCopy() *ExtenderArgs {
if in == nil {
return nil
}
out := new(ExtenderArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderBindingArgs) DeepCopyInto(out *ExtenderBindingArgs) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderBindingArgs.
func (in *ExtenderBindingArgs) DeepCopy() *ExtenderBindingArgs {
if in == nil {
return nil
}
out := new(ExtenderBindingArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderBindingResult) DeepCopyInto(out *ExtenderBindingResult) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderBindingResult.
func (in *ExtenderBindingResult) DeepCopy() *ExtenderBindingResult {
if in == nil {
return nil
}
out := new(ExtenderBindingResult)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderFilterResult) DeepCopyInto(out *ExtenderFilterResult) {
*out = *in
if in.Nodes != nil {
in, out := &in.Nodes, &out.Nodes
*out = new(corev1.NodeList)
(*in).DeepCopyInto(*out)
}
if in.NodeNames != nil {
in, out := &in.NodeNames, &out.NodeNames
*out = new([]string)
if **in != nil {
in, out := *in, *out
*out = make([]string, len(*in))
copy(*out, *in)
}
}
if in.FailedNodes != nil {
in, out := &in.FailedNodes, &out.FailedNodes
*out = make(FailedNodesMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.FailedAndUnresolvableNodes != nil {
in, out := &in.FailedAndUnresolvableNodes, &out.FailedAndUnresolvableNodes
*out = make(FailedNodesMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderFilterResult.
func (in *ExtenderFilterResult) DeepCopy() *ExtenderFilterResult {
if in == nil {
return nil
}
out := new(ExtenderFilterResult)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderPreemptionArgs) DeepCopyInto(out *ExtenderPreemptionArgs) {
*out = *in
if in.Pod != nil {
in, out := &in.Pod, &out.Pod
*out = new(corev1.Pod)
(*in).DeepCopyInto(*out)
}
if in.NodeNameToVictims != nil {
in, out := &in.NodeNameToVictims, &out.NodeNameToVictims
*out = make(map[string]*Victims, len(*in))
for key, val := range *in {
var outVal *Victims
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(Victims)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
}
}
if in.NodeNameToMetaVictims != nil {
in, out := &in.NodeNameToMetaVictims, &out.NodeNameToMetaVictims
*out = make(map[string]*MetaVictims, len(*in))
for key, val := range *in {
var outVal *MetaVictims
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(MetaVictims)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderPreemptionArgs.
func (in *ExtenderPreemptionArgs) DeepCopy() *ExtenderPreemptionArgs {
if in == nil {
return nil
}
out := new(ExtenderPreemptionArgs)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExtenderPreemptionResult) DeepCopyInto(out *ExtenderPreemptionResult) {
*out = *in
if in.NodeNameToMetaVictims != nil {
in, out := &in.NodeNameToMetaVictims, &out.NodeNameToMetaVictims
*out = make(map[string]*MetaVictims, len(*in))
for key, val := range *in {
var outVal *MetaVictims
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(MetaVictims)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderPreemptionResult.
func (in *ExtenderPreemptionResult) DeepCopy() *ExtenderPreemptionResult {
if in == nil {
return nil
}
out := new(ExtenderPreemptionResult)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in FailedNodesMap) DeepCopyInto(out *FailedNodesMap) {
{
in := &in
*out = make(FailedNodesMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailedNodesMap.
func (in FailedNodesMap) DeepCopy() FailedNodesMap {
if in == nil {
return nil
}
out := new(FailedNodesMap)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HostPriority) DeepCopyInto(out *HostPriority) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPriority.
func (in *HostPriority) DeepCopy() *HostPriority {
if in == nil {
return nil
}
out := new(HostPriority)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in HostPriorityList) DeepCopyInto(out *HostPriorityList) {
{
in := &in
*out = make(HostPriorityList, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPriorityList.
func (in HostPriorityList) DeepCopy() HostPriorityList {
if in == nil {
return nil
}
out := new(HostPriorityList)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MetaPod) DeepCopyInto(out *MetaPod) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetaPod.
func (in *MetaPod) DeepCopy() *MetaPod {
if in == nil {
return nil
}
out := new(MetaPod)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MetaVictims) DeepCopyInto(out *MetaVictims) {
*out = *in
if in.Pods != nil {
in, out := &in.Pods, &out.Pods
*out = make([]*MetaPod, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(MetaPod)
**out = **in
}
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetaVictims.
func (in *MetaVictims) DeepCopy() *MetaVictims {
if in == nil {
return nil
}
out := new(MetaVictims)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Victims) DeepCopyInto(out *Victims) {
*out = *in
if in.Pods != nil {
in, out := &in.Pods, &out.Pods
*out = make([]*corev1.Pod, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(corev1.Pod)
(*in).DeepCopyInto(*out)
}
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Victims.
func (in *Victims) DeepCopy() *Victims {
if in == nil {
return nil
}
out := new(Victims)
in.DeepCopyInto(out)
return out
}
================================================
FILE: framework/api_calls.go
================================================
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
"context"
v1 "k8s.io/api/core/v1"
)
// APICacher defines methods that send API calls through the scheduler's cache
// before they are executed asynchronously by the APIDispatcher.
// This ensures the scheduler's internal state is updated optimistically,
// reflecting the intended outcome of the call.
// This methods should be used only if the SchedulerAsyncAPICalls feature gate is enabled.
type APICacher interface {
// PatchPodStatus sends a patch request for a Pod's status.
// The patch could be first applied to the cached Pod object and then the API call is executed asynchronously.
// It returns a channel that can be used to wait for the call's completion.
PatchPodStatus(pod *v1.Pod, condition *v1.PodCondition, nominatingInfo *NominatingInfo) (<-chan error, error)
// BindPod sends a binding request. The binding could be first applied to the cached Pod object
// and then the API call is executed asynchronously.
// It returns a channel that can be used to wait for the call's completion.
BindPod(binding *v1.Binding) (<-chan error, error)
// WaitOnFinish blocks until the result of an API call is sent to the given onFinish channel
// (returned by methods BindPod or PreemptPod).
//
// It returns the error received from the channel.
// It also returns nil if the call was skipped or overwritten,
// as these are considered successful lifecycle outcomes.
// Direct onFinish channel read can be used to access these results.
WaitOnFinish(ctx context.Context, onFinish <-chan error) error
}
// APICallImplementations define constructors for each APICall that is used by the scheduler internally.
type APICallImplementations[T, K APICall] struct {
// PodStatusPatch is a constructor used to create APICall object for pod status patch.
PodStatusPatch func(pod *v1.Pod, condition *v1.PodCondition, nominatingInfo *NominatingInfo) T
// PodBinding is a constructor used to create APICall object for pod binding.
PodBinding func(binding *v1.Binding) K
}
================================================
FILE: framework/api_dispatcher.go
================================================
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
"context"
"errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
clientset "k8s.io/client-go/kubernetes"
)
var (
// ErrCallSkipped is returned by APIDispatcher.Add or sent to the OnFinish channel when the call is skipped and will not be executed.
ErrCallSkipped = errors.New("call skipped")
// ErrCallOverwritten is sent to the OnFinish channel when an enqueued call is overwritten by a newer or more relevant call.
ErrCallOverwritten = errors.New("call overwritten")
)
// IsUnexpectedError returns true if the given error is not nil and is not one of the expected
// dispatcher lifecycle errors (ErrCallSkipped, ErrCallOverwritten). This can be used to
// filter for errors that may require logging or special handling.
func IsUnexpectedError(err error) bool {
return err != nil && !errors.Is(err, ErrCallSkipped) && !errors.Is(err, ErrCallOverwritten)
}
// APICallType defines a call type name that governs how the dispatcher handles multiple pending calls for the same object.
//
// The type determines if two calls for the same object are mergeable
// or if one should overwrite the other based on relevance:
// - Calls with the same type should be merged.
// - When calls have different types, their scores in APICallRelevances are used to determine precedence.
//
// Each APICall implementation should have a unique type within a given dispatcher.
type APICallType string
// APICallRelevances maps all possible APICallTypes to a relevance value.
// A more relevant API call should overwrite a less relevant one for the same object.
// Types of the same relevance should only be defined for different object types.
type APICallRelevances map[APICallType]int
// APICall defines the interface for an API call that can be processed by an APIDispatcher.
type APICall interface {
// CallType returns the type of the API call.
// See the APICallType and APICallRelevances comments on how to define the APICallType.
CallType() APICallType
// UID returns the UID of the object this call refers to.
// This is used to identify and potentially merge or skip calls for the same object.
UID() types.UID
// Execute performs the actual API call.
Execute(ctx context.Context, client clientset.Interface) error
// Merge merges the state of an older call for the same object into the current (receiver) call.
// The receiver should incorporate all necessary information from oldCall, as oldCall will be discarded.
// After this method is called, IsNoOp() should be checked to see if the call can be skipped.
Merge(oldCall APICall) error
// Sync synchronizes the state of this call with the given object.
// It may apply changes to the object or store information from the object needed for later execution.
// The implementation should return a copy of the object if it is modified.
// After this method is called, IsNoOp() should be checked to see if the call can be skipped.
Sync(obj metav1.Object) (metav1.Object, error)
// IsNoOp returns true if the call represents a no-operation and should be skipped by the dispatcher.
// A call may be a no-op from its creation or become one after a Merge or Update.
IsNoOp() bool
}
// APICallOptions defines options for an API call.
type APICallOptions struct {
// OnFinish is an optional channel to receive the final result of a call's lifecycle.
//
// The result is sent in a non-blocking way. If this channel is unbuffered and has no
// ready receiver, the result will be dropped.
//
// Note that receiving an error does not guarantee the API call itself was executed.
// For instance, an ErrCallOverwritten or ErrCallSkipped error may be sent.
//
// To opt out of receiving a result, leave this channel nil.
OnFinish chan<- error
}
// APIDispatcher defines the interface for a dispatcher that queues and asynchronously executes API calls.
type APIDispatcher interface {
// Add adds an API call to the dispatcher's queue. It returns an error if the call is not enqueued
// (e.g., if it's skipped). The caller should handle ErrCallSkipped if returned.
Add(incomingAPICall APICall, opts APICallOptions) error
// SyncObject performs a two-way synchronization between the given object
// and a pending API call held within the dispatcher.
// This can be called by the scheduler's event handlers on object updates
// to enrich the cached state and the call.
//
// If a call for the object exists there, this method:
// 1. Applies the call's pending changes to the object, providing an optimistic preview of its state.
// 2. Allows the call to update its own internal state from the object,
// ensuring it has the most recent data before its eventual execution.
//
// It returns the modified object. If no call is pending for the object,
// the original object is returned unmodified.
SyncObject(obj metav1.Object) (metav1.Object, error)
}
================================================
FILE: framework/cycle_state.go
================================================
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
"errors"
"k8s.io/apimachinery/pkg/util/sets"
)
var (
// ErrNotFound is the not found error message.
ErrNotFound = errors.New("not found")
)
// StateData is a generic type for arbitrary data stored in CycleState.
type StateData interface {
// Clone is an interface to make a copy of StateData. For performance reasons,
// clone should make shallow copies for members (e.g., slices or maps) that are not
// impacted by PreFilter's optional AddPod/RemovePod methods.
Clone() StateData
}
// StateKey is the type of keys stored in CycleState.
type StateKey string
// CycleState provides a mechanism for plugins to store and retrieve arbitrary data.
// StateData stored by one plugin can be read, altered, or deleted by another plugin.
// CycleState does not provide any data protection, as all plugins are assumed to be
// trusted.
type CycleState interface {
// ShouldRecordPluginMetrics returns whether metrics.PluginExecutionDuration metrics
// should be recorded.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
ShouldRecordPluginMetrics() bool
// GetSkipFilterPlugins returns plugins that will be skipped in the Filter extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
GetSkipFilterPlugins() sets.Set[string]
// SetSkipFilterPlugins sets plugins that should be skipped in the Filter extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
SetSkipFilterPlugins(plugins sets.Set[string])
// GetSkipScorePlugins returns plugins that will be skipped in the Score extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
GetSkipScorePlugins() sets.Set[string]
// SetSkipScorePlugins sets plugins that should be skipped in the Score extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
SetSkipScorePlugins(plugins sets.Set[string])
// GetSkipPreBindPlugins returns plugins that will be skipped in the PreBind extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
GetSkipPreBindPlugins() sets.Set[string]
// SetSkipPreBindPlugins sets plugins that should be skipped in the PerBind extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
SetSkipPreBindPlugins(plugins sets.Set[string])
// GetParallelPreBindPlugins returns plugins that can be run in parallel with other plugins
// in the PreBind extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
GetParallelPreBindPlugins() sets.Set[string]
// GetParallelPreBindPlugins returns plugins that can be run in parallel with other plugins
// in the PreBind extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
SetParallelPreBindPlugins(plugins sets.Set[string])
// ShouldSkipAllPostFilterPlugins returns whether all plugins should be skipped in the PostFilter extension point.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
ShouldSkipAllPostFilterPlugins() bool
// Read retrieves data with the given "key" from CycleState. If the key is not
// present, ErrNotFound is returned.
//
// See CycleState for notes on concurrency.
Read(key StateKey) (StateData, error)
// Write stores the given "val" in CycleState with the given "key".
//
// See CycleState for notes on concurrency.
Write(key StateKey, val StateData)
// Delete deletes data with the given key from CycleState.
//
// See CycleState for notes on concurrency.
Delete(key StateKey)
// Clone creates a copy of CycleState and returns its pointer. Clone returns
// nil if the context being cloned is nil.
Clone() CycleState
// IsPodGroupSchedulingCycle returns true if this cycle is a pod group scheduling cycle.
// If set to false, it means that the pod referencing this CycleState either passed the pod group cycle
// or doesn't belong to any pod group.
// This field can only be set to true when GenericWorkload feature flag is enabled.
IsPodGroupSchedulingCycle() bool
// GetPodGroupSchedulingCycle gets the cycle state of the PodGroup for a Pod.
// This should be only used when GenericWorkload feature flag is enabled.
GetPodGroupSchedulingCycle() PodGroupCycleState
// SetPodGroupSchedulingCycle sets the cycle state of the PodGroup for a Pod.
// This should be only used when GenericWorkload feature flag is enabled.
SetPodGroupSchedulingCycle(PodGroupCycleState)
}
// PodGroupCycleState provides a mechanism for plugins that operate on pod groups to store and retrieve arbitrary data.
// StateData stored by one plugin can be read, altered, or deleted by another plugin that operates on a pod group.
// PodGroupCycleState does not provide any data protection, as all plugins are assumed to be
// trusted.
type PodGroupCycleState interface {
// ShouldRecordPluginMetrics returns whether metrics.PluginExecutionDuration metrics
// should be recorded.
// This function is mostly for the scheduling framework runtime, plugins usually don't have to use it.
ShouldRecordPluginMetrics() bool
// Read retrieves data with the given "key" from PodGroupCycleState. If the key is not
// present, ErrNotFound is returned.
//
// See PodGroupCycleState for notes on concurrency.
Read(key StateKey) (StateData, error)
// Write stores the given "val" in PodGroupCycleState with the given "key".
//
// See PodGroupCycleState for notes on concurrency.
Write(key StateKey, val StateData)
// Delete deletes data with the given key from PodGroupCycleState.
//
// See PodGroupCycleState for notes on concurrency.
Delete(key StateKey)
}
================================================
FILE: framework/extender.go
================================================
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
v1 "k8s.io/api/core/v1"
extenderv1 "k8s.io/kube-scheduler/extender/v1"
)
// Extender is an interface for external processes to influence scheduling
// decisions made by Kubernetes. This is typically needed for resources not directly
// managed by Kubernetes.
type Extender interface {
// Name returns a unique name that identifies the extender.
Name() string
// Filter based on extender-implemented predicate functions. The filtered list is
// expected to be a subset of the supplied list.
// The failedNodes and failedAndUnresolvableNodes optionally contains the list
// of failed nodes and failure reasons, except nodes in the latter are
// unresolvable.
Filter(pod *v1.Pod, nodes []NodeInfo) (filteredNodes []NodeInfo, failedNodesMap extenderv1.FailedNodesMap, failedAndUnresolvable extenderv1.FailedNodesMap, err error)
// Prioritize based on extender-implemented priority functions. The returned scores & weight
// are used to compute the weighted score for an extender. The weighted scores are added to
// the scores computed by Kubernetes scheduler. The total scores are used to do the host selection.
Prioritize(pod *v1.Pod, nodes []NodeInfo) (hostPriorities *extenderv1.HostPriorityList, weight int64, err error)
// Bind delegates the action of binding a pod to a node to the extender.
Bind(binding *v1.Binding) error
// IsBinder returns whether this extender is configured for the Bind method.
IsBinder() bool
// IsInterested returns true if at least one extended resource requested by
// this pod is managed by this extender.
IsInterested(pod *v1.Pod) bool
// IsPrioritizer returns whether this extender is configured for the Prioritize method.
IsPrioritizer() bool
// IsFilter returns whether this extender is configured for the Filter method.
IsFilter() bool
// ProcessPreemption returns nodes with their victim pods processed by extender based on
// given:
// 1. Pod to schedule
// 2. Candidate nodes and victim pods (nodeNameToVictims) generated by previous scheduling process.
// The possible changes made by extender may include:
// 1. Subset of given candidate nodes after preemption phase of extender.
// 2. A different set of victim pod for every given candidate node after preemption phase of extender.
ProcessPreemption(
pod *v1.Pod,
nodeNameToVictims map[string]*extenderv1.Victims,
nodeInfos NodeInfoLister,
) (map[string]*extenderv1.Victims, error)
// SupportsPreemption returns if the scheduler extender support preemption or not.
SupportsPreemption() bool
// IsIgnorable returns true indicates scheduling should not fail when this extender
// is unavailable. This gives scheduler ability to fail fast and tolerate non-critical extenders as well.
// Both Filter and Bind actions are supported.
IsIgnorable() bool
}
================================================
FILE: framework/interface.go
================================================
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// This file defines the scheduling framework plugin interfaces.
package framework
import (
"context"
"errors"
"math"
"slices"
"strings"
"time"
"github.com/google/go-cmp/cmp" //nolint:depguard
"github.com/google/go-cmp/cmp/cmpopts" //nolint:depguard
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/events"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
)
// Code is the Status code/type which is returned from plugins.
type Code int
// These are predefined codes used in a Status.
// Note: when you add a new status, you have to add it in `codes` slice below.
const (
// Success means that plugin ran correctly and found pod schedulable.
// NOTE: A nil status is also considered as "Success".
Success Code = iota
// Error is one of the failures, used for internal plugin errors, unexpected input, etc.
// Plugin shouldn't return this code for expected failures, like Unschedulable.
// Since it's the unexpected failure, the scheduling queue registers the pod without unschedulable plugins.
// Meaning, the Pod will be requeued to activeQ/backoffQ soon.
Error
// Unschedulable is one of the failures, used when a plugin finds a pod unschedulable.
// If it's returned from PreFilter or Filter, the scheduler might attempt to
// run other postFilter plugins like preemption to get this pod scheduled.
// Use UnschedulableAndUnresolvable to make the scheduler skipping other postFilter plugins.
// The accompanying status message should explain why the pod is unschedulable.
//
// We regard the backoff as a penalty of wasting the scheduling cycle.
// When the scheduling queue requeues Pods, which was rejected with Unschedulable in the last scheduling,
// the Pod goes through backoff.
Unschedulable
// UnschedulableAndUnresolvable is used when a plugin finds a pod unschedulable and
// other postFilter plugins like preemption would not change anything.
// See the comment on PostFilter interface for more details about how PostFilter should handle this status.
// Plugins should return Unschedulable if it is possible that the pod can get scheduled
// after running other postFilter plugins.
// The accompanying status message should explain why the pod is unschedulable.
//
// We regard the backoff as a penalty of wasting the scheduling cycle.
// When the scheduling queue requeues Pods, which was rejected with UnschedulableAndUnresolvable in the last scheduling,
// the Pod goes through backoff.
UnschedulableAndUnresolvable
// Wait is used when a Permit plugin finds a pod scheduling should wait.
Wait
// Skip is used in the following scenarios:
// - when a Bind plugin chooses to skip binding.
// - when a PreFilter plugin returns Skip so that coupled Filter plugin/PreFilterExtensions() will be skipped.
// - when a PreScore plugin returns Skip so that coupled Score plugin will be skipped.
Skip
// Pending means that the scheduling process is finished successfully,
// but the plugin wants to stop the scheduling cycle/binding cycle here.
//
// For example, if your plugin has to notify the scheduling result to an external component,
// and wait for it to complete something **before** binding.
// It's different from when to return Unschedulable/UnschedulableAndUnresolvable,
// because in this case, the scheduler decides where the Pod can go successfully,
// but we need to wait for the external component to do something based on that scheduling result.
//
// We regard the backoff as a penalty of wasting the scheduling cycle.
// In the case of returning Pending, we cannot say the scheduling cycle is wasted
// because the scheduling result is used to proceed the Pod's scheduling forward,
// that particular scheduling cycle is failed though.
// So, Pods rejected by such reasons don't need to suffer a penalty (backoff).
// When the scheduling queue requeues Pods, which was rejected with Pending in the last scheduling,
// the Pod goes to activeQ directly ignoring backoff.
Pending
)
// This list should be exactly the same as the codes iota defined above in the same order.
var codes = []string{"Success", "Error", "Unschedulable", "UnschedulableAndUnresolvable", "Wait", "Skip", "Pending"}
func (c Code) String() string {
return codes[c]
}
// Status indicates the result of running a plugin. It consists of a code, a
// message, (optionally) an error, and a plugin name it fails by.
// When the status code is not Success, the reasons should explain why.
// And, when code is Success, all the other fields should be empty.
// NOTE: A nil Status is also considered as Success.
type Status struct {
code Code
reasons []string
err error
// plugin is an optional field that records the plugin name causes this status.
// It's set by the framework when code is Unschedulable, UnschedulableAndUnresolvable or Pending.
plugin string
}
func (s *Status) WithError(err error) *Status {
s.err = err
return s
}
// Code returns code of the Status.
func (s *Status) Code() Code {
if s == nil {
return Success
}
return s.code
}
// Message returns a concatenated message on reasons of the Status.
func (s *Status) Message() string {
if s == nil {
return ""
}
return strings.Join(s.Reasons(), ", ")
}
// SetPlugin sets the given plugin name to s.plugin.
func (s *Status) SetPlugin(plugin string) {
s.plugin = plugin
}
// WithPlugin sets the given plugin name to s.plugin,
// and returns the given status object.
func (s *Status) WithPlugin(plugin string) *Status {
s.SetPlugin(plugin)
return s
}
// Plugin returns the plugin name which caused this status.
func (s *Status) Plugin() string {
return s.plugin
}
// Reasons returns reasons of the Status.
func (s *Status) Reasons() []string {
if s.err != nil {
return append([]string{s.err.Error()}, s.reasons...)
}
return s.reasons
}
// AppendReason appends given reason to the Status.
func (s *Status) AppendReason(reason string) {
s.reasons = append(s.reasons, reason)
}
// IsSuccess returns true if and only if "Status" is nil or Code is "Success".
func (s *Status) IsSuccess() bool {
return s.Code() == Success
}
// IsWait returns true if and only if "Status" is non-nil and its Code is "Wait".
func (s *Status) IsWait() bool {
return s.Code() == Wait
}
// IsSkip returns true if and only if "Status" is non-nil and its Code is "Skip".
func (s *Status) IsSkip() bool {
return s.Code() == Skip
}
// IsRejected returns true if "Status" is Unschedulable (Unschedulable, UnschedulableAndUnresolvable, or Pending).
func (s *Status) IsRejected() bool {
code := s.Code()
return code == Unschedulable || code == UnschedulableAndUnresolvable || code == Pending
}
// IsError returns true if and only if "Status" is non-nil and its Code is "Error".
func (s *Status) IsError() bool {
return s.Code() == Error
}
// AsError returns nil if the status is a success, a wait or a skip; otherwise returns an "error" object
// with a concatenated message on reasons of the Status.
func (s *Status) AsError() error {
if s.IsSuccess() || s.IsWait() || s.IsSkip() {
return nil
}
if s.err != nil {
return s.err
}
return errors.New(s.Message())
}
// Equal checks equality of two statuses. This is useful for testing with
// cmp.Equal.
func (s *Status) Equal(x *Status) bool {
if s == nil || x == nil {
return s.IsSuccess() && x.IsSuccess()
}
if s.code != x.code {
return false
}
if !cmp.Equal(s.err, x.err, cmpopts.EquateErrors()) {
return false
}
if !cmp.Equal(s.reasons, x.reasons) {
return false
}
return cmp.Equal(s.plugin, x.plugin)
}
func (s *Status) String() string {
return s.Message()
}
// Clone clones the entire Status and returns a copy.
func (s *Status) Clone() *Status {
return &Status{
code: s.code,
reasons: slices.Clone(s.reasons),
err: s.err,
plugin: s.plugin,
}
}
// NewStatus makes a Status out of the given arguments and returns its pointer.
func NewStatus(code Code, reasons ...string) *Status {
s := &Status{
code: code,
reasons: reasons,
}
return s
}
// AsStatus wraps an error in a Status.
func AsStatus(err error) *Status {
if err == nil {
return nil
}
return &Status{
code: Error,
err: err,
}
}
// NodeToStatusReader is a read-only interface of NodeToStatus passed to each PostFilter plugin.
type NodeToStatusReader interface {
// Get returns the status for given nodeName.
// If the node is not in the map, the AbsentNodesStatus is returned.
Get(nodeName string) *Status
// NodesForStatusCode returns a list of NodeInfos for the nodes that have a given status code.
// It returns the NodeInfos for all matching nodes denoted by AbsentNodesStatus as well.
NodesForStatusCode(nodeLister NodeInfoLister, code Code) ([]NodeInfo, error)
}
// NodeScoreList declares a list of nodes and their scores.
type NodeScoreList []NodeScore
// NodeScore is a struct with node name and score.
type NodeScore struct {
Name string
Score int64
}
// NodePluginScores is a struct with node name and scores for that node.
type NodePluginScores struct {
// Name is node name.
Name string
// Scores is scores from plugins and extenders.
Scores []PluginScore
// TotalScore is the total score in Scores.
TotalScore int64
// Randomizer is used to provide randomness
// when randomizing nodes within a common score.
Randomizer int
}
// PluginScore is a struct with plugin/extender name and score.
type PluginScore struct {
// Name is the name of plugin or extender.
Name string
Score int64
}
// PlacementPluginScores stores scores for a given placement.
type PlacementPluginScores struct {
// Placement is the placement info that can be used to identify a specific placement.
Placement *Placement
// Scores is scores from plugins and extenders.
Scores []PluginScore
// TotalScore is the total score in Scores.
TotalScore int64
// Randomizer is used to provide randomness
// when randomizing placements within a common score.
Randomizer int
}
const (
// MaxNodeScore is the maximum score a Score plugin is expected to return.
//
// Deprecated: use MaxScore instead.
MaxNodeScore int64 = MaxScore
// MinNodeScore is the minimum score a Score plugin is expected to return.
//
// Deprecated: use MinScore instead.
MinNodeScore int64 = MinScore
// MaxScore is the maximum score a Score or PlacementScore plugin is expected to return.
MaxScore int64 = 100
// MinScore is the minimum score a Score or PlacementScore plugin is expected to return.
MinScore int64 = 0
// MaxTotalScore is the maximum total score.
MaxTotalScore int64 = math.MaxInt64
)
type NominatingMode int
const (
ModeNoop NominatingMode = iota
ModeOverride
)
type NominatingInfo struct {
NominatedNodeName string
NominatingMode NominatingMode
}
func (ni *NominatingInfo) Mode() NominatingMode {
if ni == nil {
return ModeNoop
}
return ni.NominatingMode
}
// WaitingPod represents a pod currently waiting in the permit phase.
type WaitingPod interface {
// GetPod returns a reference to the waiting pod.
GetPod() *v1.Pod
// GetPendingPlugins returns a list of pending Permit plugin's name.
GetPendingPlugins() []string
// Allow declares the waiting pod is allowed to be scheduled by the plugin named as "pluginName".
// If this is the last remaining plugin to allow, then a success signal is delivered
// to unblock the pod.
Allow(pluginName string)
// Reject declares the waiting pod unschedulable.
Reject(pluginName, msg string) bool
// Preempt preempts the waiting pod. Compared to reject it does not mark the pod as unschedulable,
// allowing it to be rescheduled.
Preempt(pluginName, msg string) bool
}
// PodInPreBind represents a pod currently in preBind phase.
type PodInPreBind interface {
// CancelPod cancels the context attached to a goroutine running binding cycle of this pod
// if the pod is not marked as prebound.
// Returns true if the cancel was successfully run.
CancelPod(reason string) bool
// MarkPrebound marks the pod as prebound, making it impossible to cancel the context of binding cycle
// via PodInPreBind
// Returns false if the context was already canceled.
MarkPrebound() bool
}
// PreFilterResult wraps needed info for scheduler framework to act upon PreFilter phase.
type PreFilterResult struct {
// The set of nodes that should be considered downstream; if nil then
// all nodes are eligible.
NodeNames sets.Set[string]
}
func (p *PreFilterResult) AllNodes() bool {
return p == nil || p.NodeNames == nil
}
func (p *PreFilterResult) Merge(in *PreFilterResult) *PreFilterResult {
if p.AllNodes() && in.AllNodes() {
return nil
}
r := PreFilterResult{}
if p.AllNodes() {
r.NodeNames = in.NodeNames.Clone()
return &r
}
if in.AllNodes() {
r.NodeNames = p.NodeNames.Clone()
return &r
}
r.NodeNames = p.NodeNames.Intersection(in.NodeNames)
return &r
}
// PostFilterResult wraps needed info for scheduler framework to act upon PostFilter phase.
type PostFilterResult struct {
*NominatingInfo
}
// PreBindPreFlightResult wraps needed info for scheduler framework to act upon PreBindPreFlight phase.
type PreBindPreFlightResult struct {
// AllowParallel indicates whether this plugin's PreBind method can be run
// in parallel with other plugins during PreBind phase.
// The scheduler groups consecutive plugins that return AllowParallel: true
// and runs them in parallel.
// A plugin that returns AllowParallel: false breaks the parallel group
// and runs sequentially.
// Note: skipped plugins are effectively ignored, but if a skipped plugin returns
// AllowParallel: false, it still breaks the parallel group of adjacent plugins.
AllowParallel bool
}
// Plugin is the parent type for all the scheduling framework plugins.
type Plugin interface {
Name() string
}
// PreEnqueuePlugin is an interface that must be implemented by "PreEnqueue" plugins.
// These plugins are called prior to adding Pods to activeQ or backoffQ.
// Note: an preEnqueue plugin is expected to be lightweight and efficient, so it's not expected to
// involve expensive calls like accessing external endpoints; otherwise it'd block other
// Pods' enqueuing in event handlers.
type PreEnqueuePlugin interface {
Plugin
// PreEnqueue is called prior to adding Pods to activeQ or backoffQ.
PreEnqueue(ctx context.Context, p *v1.Pod) *Status
}
// LessFunc is the function to sort pod info
type LessFunc func(podInfo1, podInfo2 QueuedPodInfo) bool
// QueueSortPlugin is an interface that must be implemented by "QueueSort" plugins.
// These plugins are used to sort pods in the scheduling queue. Only one queue sort
// plugin may be enabled at a time.
type QueueSortPlugin interface {
Plugin
// Less are used to sort pods in the scheduling queue.
Less(QueuedPodInfo, QueuedPodInfo) bool
}
// EnqueueExtensions is an optional interface that plugins can implement to efficiently
// move unschedulable Pods in internal scheduling queues.
// In the scheduler, Pods can be unschedulable by PreEnqueue, PreFilter, Filter, Reserve, and Permit plugins,
// and Pods rejected by these plugins are requeued based on this extension point.
// Failures from other extension points are regarded as temporal errors (e.g., network failure),
// and the scheduler requeue Pods without this extension point - always requeue Pods to activeQ after backoff.
// This is because such temporal errors cannot be resolved by specific cluster events,
// and we have no choose but keep retrying scheduling until the failure is resolved.
//
// Plugins that make pod unschedulable (PreEnqueue, PreFilter, Filter, Reserve, and Permit plugins) must implement this interface,
// otherwise the default implementation will be used, which is less efficient in requeueing Pods rejected by the plugin.
//
// Also, if EventsToRegister returns an empty list, that means the Pods failed by the plugin are not requeued by any events,
// which doesn't make sense in most cases (very likely misuse)
// since the pods rejected by the plugin could be stuck in the unschedulable pod pool forever.
//
// If plugins other than above extension points support this interface, they are just ignored.
type EnqueueExtensions interface {
Plugin
// EventsToRegister returns a series of possible events that may cause a Pod
// failed by this plugin schedulable. Each event has a callback function that
// filters out events to reduce useless retry of Pod's scheduling.
// The events will be registered when instantiating the internal scheduling queue,
// and leveraged to build event handlers dynamically.
// When it returns an error, the scheduler fails to start.
// Note: the returned list needs to be determined at a startup,
// and the scheduler only evaluates it once during start up.
// Do not change the result during runtime, for example, based on the cluster's state etc.
//
// Appropriate implementation of this function will make Pod's re-scheduling accurate and performant.
EventsToRegister(context.Context) ([]ClusterEventWithHint, error)
}
// PreFilterExtensions is an interface that is included in plugins that allow specifying
// callbacks to make incremental updates to its supposedly pre-calculated
// state.
type PreFilterExtensions interface {
// AddPod is called by the framework while trying to evaluate the impact
// of adding podToAdd to the node while scheduling podToSchedule.
AddPod(ctx context.Context, state CycleState, podToSchedule *v1.Pod, podInfoToAdd PodInfo, nodeInfo NodeInfo) *Status
// RemovePod is called by the framework while trying to evaluate the impact
// of removing podToRemove from the node while scheduling podToSchedule.
RemovePod(ctx context.Context, state CycleState, podToSchedule *v1.Pod, podInfoToRemove PodInfo, nodeInfo NodeInfo) *Status
}
// PreFilterPlugin is an interface that must be implemented by "PreFilter" plugins.
// These plugins are called at the beginning of the scheduling cycle. Plugins that implement PreFilterPlugin should
// also implement SignPlugin to enable batching optimizations.
type PreFilterPlugin interface {
Plugin
// PreFilter is called at the beginning of the scheduling cycle. All PreFilter
// plugins must return success or the pod will be rejected. PreFilter could optionally
// return a PreFilterResult to influence which nodes to evaluate downstream. This is useful
// for cases where it is possible to determine the subset of nodes to process in O(1) time.
// When PreFilterResult filters out some Nodes, the framework considers Nodes that are filtered out as getting "UnschedulableAndUnresolvable".
// i.e., those Nodes will be out of the candidates of the preemption.
//
// When it returns Skip status, returned PreFilterResult and other fields in status are just ignored,
// and coupled Filter plugin/PreFilterExtensions() will be skipped in this scheduling cycle.
PreFilter(ctx context.Context, state CycleState, p *v1.Pod, nodes []NodeInfo) (*PreFilterResult, *Status)
// PreFilterExtensions returns a PreFilterExtensions interface if the plugin implements one,
// or nil if it does not. A Pre-filter plugin can provide extensions to incrementally
// modify its pre-processed info. The framework guarantees that the extensions
// AddPod/RemovePod will only be called after PreFilter, possibly on a cloned
// CycleState, and may call those functions more than once before calling
// Filter again on a specific node.
PreFilterExtensions() PreFilterExtensions
}
// FilterPlugin is an interface for Filter plugins. These plugins are called at the
// filter extension point for filtering out hosts that cannot run a pod.
// This concept used to be called 'predicate' in the original scheduler.
// These plugins should return "Success", "Unschedulable" or "Error" in Status.code.
// However, the scheduler accepts other valid codes as well.
// Anything other than "Success" will lead to exclusion of the given host from
// running the pod. Plugins that implement FilterPlugin should
// also implement SignPlugin to enable batching optimizations.
type FilterPlugin interface {
Plugin
// Filter is called by the scheduling framework.
// All FilterPlugins should return "Success" to declare that
// the given node fits the pod. If Filter doesn't return "Success",
// it will return "Unschedulable", "UnschedulableAndUnresolvable" or "Error".
//
// "Error" aborts pod scheduling and puts the pod into the backoff queue.
//
// For the node being evaluated, Filter plugins should look at the passed
// nodeInfo reference for this particular node's information (e.g., pods
// considered to be running on the node) instead of looking it up in the
// NodeInfoSnapshot because we don't guarantee that they will be the same.
// For example, during preemption, we may pass a copy of the original
// nodeInfo object that has some pods removed from it to evaluate the
// possibility of preempting them to schedule the target pod.
//
// Plugins are encouraged to check the context for cancellation.
// Once canceled, they should return as soon as possible with
// an UnschedulableAndUnresolvable status that includes the
// `context.Cause(ctx)` error explanation. For example, the
// context gets canceled when a sufficient number of suitable
// nodes have been found and searching for more isn't necessary
// anymore.
Filter(ctx context.Context, state CycleState, pod *v1.Pod, nodeInfo NodeInfo) *Status
}
// PostFilterPlugin is an interface for "PostFilter" plugins. These plugins are called
// after a pod cannot be scheduled.
type PostFilterPlugin interface {
Plugin
// PostFilter is called by the scheduling framework
// when the scheduling cycle failed at PreFilter or Filter by Unschedulable or UnschedulableAndUnresolvable.
// NodeToStatusReader has statuses that each Node got in PreFilter or Filter phase.
//
// If you're implementing a custom preemption with PostFilter, ignoring Nodes with UnschedulableAndUnresolvable is the responsibility of your plugin,
// meaning NodeToStatusReader could have Nodes with UnschedulableAndUnresolvable
// and the scheduling framework does call PostFilter plugins even when all Nodes in NodeToStatusReader are UnschedulableAndUnresolvable.
//
// A PostFilter plugin should return one of the following statuses:
// - Unschedulable: the plugin gets executed successfully but the pod cannot be made schedulable.
// - Success: the plugin gets executed successfully and the pod can be made schedulable.
// - Error: the plugin aborts due to some internal error.
//
// Informational plugins should be configured ahead of other ones, and always return Unschedulable status.
// Optionally, a non-nil PostFilterResult may be returned along with a Success status. For example,
// a preemption plugin may choose to return nominatedNodeName, so that framework can reuse that to update the
// preemptor pod's .spec.status.nominatedNodeName field.
PostFilter(ctx context.Context, state CycleState, pod *v1.Pod, filteredNodeStatusMap NodeToStatusReader) (*PostFilterResult, *Status)
}
// PreScorePlugin is an interface for "PreScore" plugin. PreScore is an
// informational extension point. Plugins will be called with a list of nodes
// that passed the filtering phase. A plugin may use this data to update internal
// state or to generate logs/metrics. Plugins that implement PreScorePlugin should
// also implement SignPlugin to enable batching optimizations.
type PreScorePlugin interface {
Plugin
// PreScore is called by the scheduling framework after a list of nodes
// passed the filtering phase. All prescore plugins must return success or
// the pod will be rejected
// When it returns Skip status, other fields in status are just ignored,
// and coupled Score plugin will be skipped in this scheduling cycle.
PreScore(ctx context.Context, state CycleState, pod *v1.Pod, nodes []NodeInfo) *Status
}
// ScoreExtensions is an interface for Score extended functionality.
type ScoreExtensions interface {
// NormalizeScore is called for all node scores produced by the same plugin's "Score"
// method. A successful run of NormalizeScore will update the scores list and return
// a success status.
NormalizeScore(ctx context.Context, state CycleState, p *v1.Pod, scores NodeScoreList) *Status
}
// ScorePlugin is an interface that must be implemented by "Score" plugins to rank
// nodes that passed the filtering phase. Plugins that implement ScorePlugin should
// also implement SignPlugin to enable batching optimizations.
type ScorePlugin interface {
Plugin
// Score is called on each filtered node. It must return success and an integer
// indicating the rank of the node. All scoring plugins must return success or
// the pod will be rejected.
Score(ctx context.Context, state CycleState, p *v1.Pod, nodeInfo NodeInfo) (int64, *Status)
// ScoreExtensions returns a ScoreExtensions interface if it implements one, or nil if does not.
ScoreExtensions() ScoreExtensions
}
// ReservePlugin is an interface for plugins with Reserve and Unreserve
// methods. These are meant to update the state of the plugin. This concept
// used to be called 'assume' in the original scheduler. These plugins should
// return only Success or Error in Status.code. However, the scheduler accepts
// other valid codes as well. Anything other than Success will lead to
// rejection of the pod.
type ReservePlugin interface {
Plugin
// Reserve is called by the scheduling framework when the scheduler cache is
// updated. If this method returns a failed Status, the scheduler will call
// the Unreserve method for all enabled ReservePlugins.
Reserve(ctx context.Context, state CycleState, p *v1.Pod, nodeName string) *Status
// Unreserve is called by the scheduling framework when a reserved pod was
// rejected, an error occurred during reservation of subsequent plugins, or
// in a later phase. The Unreserve method implementation must be idempotent
// and may be called by the scheduler even if the corresponding Reserve
// method for the same plugin was not called.
Unreserve(ctx context.Context, state CycleState, p *v1.Pod, nodeName string)
}
// PreBindPlugin is an interface that must be implemented by "PreBind" plugins.
// These plugins are called before a pod being scheduled.
type PreBindPlugin interface {
Plugin
// PreBindPreFlight is called before PreBind, and the plugin is supposed to return two values:
// - PreBindPreFlightResult (nil is valid, and means results with the zero values on all fields).
// - Success, Skip, or Error status.
// If it returns Success, it means this PreBind plugin will handle this pod.
// If it returns Skip, it means this PreBind plugin has nothing to do with the pod, and PreBind will be skipped.
// This function should be lightweight, and shouldn't do any actual operation, e.g., creating a volume etc.
PreBindPreFlight(ctx context.Context, state CycleState, p *v1.Pod, nodeName string) (*PreBindPreFlightResult, *Status)
// PreBind is called before binding a pod. All prebind plugins must return
// success or the pod will be rejected and won't be sent for binding.
PreBind(ctx context.Context, state CycleState, p *v1.Pod, nodeName string) *Status
}
// PostBindPlugin is an interface that must be implemented by "PostBind" plugins.
// These plugins are called after a pod is successfully bound to a node.
type PostBindPlugin interface {
Plugin
// PostBind is called after a pod is successfully bound. These plugins are
// informational. A common application of this extension point is for cleaning
// up. If a plugin needs to clean-up its state after a pod is scheduled and
// bound, PostBind is the extension point that it should register.
PostBind(ctx context.Context, state CycleState, p *v1.Pod, nodeName string)
}
// PermitPlugin is an interface that must be implemented by "Permit" plugins.
// These plugins are called before a pod is bound to a node.
type PermitPlugin interface {
Plugin
// Permit is called before binding a pod (and before prebind plugins). Permit
// plugins are used to prevent or delay the binding of a Pod. A permit plugin
// must return success or wait with timeout duration, or the pod will be rejected.
// The pod will also be rejected if the wait timeout or the pod is rejected while
// waiting. Note that if the plugin returns "wait", the framework will wait only
// after running the remaining plugins given that no other plugin rejects the pod.
Permit(ctx context.Context, state CycleState, p *v1.Pod, nodeName string) (*Status, time.Duration)
}
// BindPlugin is an interface that must be implemented by "Bind" plugins. Bind
// plugins are used to bind a pod to a Node.
type BindPlugin interface {
Plugin
// Bind plugins will not be called until all pre-bind plugins have completed. Each
// bind plugin is called in the configured order. A bind plugin may choose whether
// or not to handle the given Pod. If a bind plugin chooses to handle a Pod, the
// remaining bind plugins are skipped. When a bind plugin does not handle a pod,
// it must return Skip in its Status code. If a bind plugin returns an Error, the
// pod is rejected and will not be bound.
Bind(ctx context.Context, state CycleState, p *v1.Pod, nodeName string) *Status
}
// A portion of a pod signature. The sign fragments from all plugins are combined
// together to create a unified signature.
type SignFragment struct {
// Pod signature fragments are identified by a key, i.e., fragments with the same key
// should contain the same value for the same pod. Plugin authors can return the same SignFragment
// from multiple plugins, the framework just ignores duplicates. This allows plugins to share signers easily.
//
// Fragment names can be found in k8s.io/kube-scheduler/framework/signers.go. New fragment names for
// in-tree plugins should be added there, and custom plugins can also use them.
// Simple SignFragments which return a field should have names that follow the field name they return.
// So a SignFragment that returns NodeName would have the key:
//
// "v1.Pod.Spec.NodeName"
//
// If a SignFragment does some processing on the resource, its name should include the path to the base of the state it uses,
// and then suffix this with a descriptive function name followed by (). So, for example, a SignFragment that only returns
// Ephemeral volumes might use the key:
//
// "v1.Pod.Volumes.EphemeralVolumes()"
Key string
// The value of a SignFragment must be a json-marshallable object. Remember that we need to compare these across pods, so
// plugins should ensure that lists where order doesn't matter are sorted, for example.
Value any
}
// The signature for a given pod after all of the results from plugins are consolidated.
type PodSignature []byte
// SignPlugin is an interface that should be implemented by plugins that either filter or score
// pods to enable batching and gang scheduling optimizations.
// Each plugin returns SignFragments used to build a single signature per pod entering the scheduling cycle,
// and the scheduler uses signatures to determine whether it can use a cached scheduling result, or needs to
// recompute the prioritized nodes.
//
// If an enabled plugin that does Scoring, Prescoring, Filtering or Prefiltering does not implement this interface we will turn off batching for all pods.
type SignPlugin interface {
Plugin
// SignPod returns SignFragments for use in batching. This is called at every scheduling cycle
// and is used to construct a signature builder used for pods. (KEP-5598).
//
// The sign fragments from all the plugins are combined to create a single signature. Only one fragment
// with a given key will be included.
//
// Status means:
// - Success: the signer can sign the pod, accompanied by a set of signature fragments to be included.
// - Unschedulable: the signer refuses to sign the pod, meaning the pod is not eligible for opportunistic batching optimization.
// - Error: the signer hits something _unexpected_ and cannot build sign(s). A framework runtime just
// proceeds with scheduling this pod without opportunistic batching optimization like Unschedulable,
// but just report errors to logs.
SignPod(ctx context.Context, pod *v1.Pod) ([]SignFragment, *Status)
}
// GeneratePlacementsResult represents the result of the PlacementGeneratePlugin.
type GeneratePlacementsResult struct {
// Placements is the set of placements that the plugin wants to partition the resources into.
// The partitions can overlap.
//
// To represent no valid partitions, set the array to nil or empty.
Placements []*Placement
}
// PlacementGeneratePlugin is an interface for plugins that generate candidate Placements.
type PlacementGeneratePlugin interface {
Plugin
// GeneratePlacements generates a list of potential Placements for the given PodGroup within the parent placement.
// Each Placement represents a candidate set of resources, e.g., nodes matching a selector.
GeneratePlacements(ctx context.Context, state PodGroupCycleState, podGroup PodGroupInfo, parentPlacement *Placement) (*GeneratePlacementsResult, *Status)
}
// PlacementScore stores result of a placement score plugin to be later used for normalization.
type PlacementScore struct {
// Placement is the placement for which the score was computed
Placement *Placement
// Score is the score for a given placement, which is used to rank the placements and pick the best one.
Score int64
}
// PlacementScoreExtensions is an interface for PlacementScore extended functionality.
type PlacementScoreExtensions interface {
// NormalizePlacementScore is called for all placement scores produced by the same plugin's "ScorePlacement"
// method. A successful run of NormalizePlacementScore will update the scores list and return
// a success status.
NormalizePlacementScore(ctx context.Context, state PodGroupCycleState, podGroup PodGroupInfo, placementScores []PlacementScore) *Status
}
// PlacementScorePlugin is an interface for plugins that score feasible Placements.
type PlacementScorePlugin interface {
Plugin
// ScorePlacement calculates a score for a given Placement.
// This function is called only for Placements that have been deemed feasible for the sufficient number of pods in the PodGroup scheduling cycle.
// The PodGroupAssignments indicates the node assigned to each pod within this Placement.
// The returned score is a int64 with higher scores generally indicating more preferable Placements.
// Plugins can implement various scoring strategies, such as bin packing to minimize resource fragmentation.
ScorePlacement(ctx context.Context, state PodGroupCycleState, podGroup PodGroupInfo, placement *PodGroupAssignments) (int64, *Status)
// PlacementScoreExtensions returns a PlacementScoreExtensions interface if it implements one, or nil if does not.
PlacementScoreExtensions() PlacementScoreExtensions
}
// Handle provides data and some tools that plugins can use. It is
// passed to the plugin factories at the time of plugin initialization. Plugins
// must store and use this handle to call framework functions.
type Handle interface {
// PodNominator abstracts operations to maintain nominated Pods.
PodNominator
// PluginsRunner abstracts operations to run some plugins.
PluginsRunner
// PodActivator abstracts operations in the scheduling queue.
PodActivator
// SnapshotSharedLister returns listers from the latest NodeInfo Snapshot. The snapshot
// is taken at the beginning of a scheduling cycle and remains unchanged until
// a pod finishes "Permit" point.
//
// It should be used only during scheduling cycle:
// - There is no guarantee that the information remains unchanged in the binding phase of scheduling.
// So, plugins shouldn't use it in the binding cycle (pre-bind/bind/post-bind/un-reserve plugin)
// otherwise, a concurrent read/write error might occur.
// - There is no guarantee that the information is always up-to-date.
// So, plugins shouldn't use it in QueueingHint and PreEnqueue
// otherwise, they might make a decision based on stale information.
//
// Instead, they should use the resources getting from Informer created from SharedInformerFactory().
SnapshotSharedLister() SharedLister
// IterateOverWaitingPods acquires a read lock and iterates over the WaitingPods map.
IterateOverWaitingPods(callback func(WaitingPod))
// GetWaitingPod returns a waiting pod given its UID.
GetWaitingPod(uid types.UID) WaitingPod
// RejectWaitingPod rejects a waiting pod given its UID.
// The return value indicates if the pod is waiting or not.
RejectWaitingPod(uid types.UID) bool
// AddPodInPreBind adds a pod to the pods in preBind list.
AddPodInPreBind(uid types.UID, cancel context.CancelCauseFunc)
// GetPodInPreBind returns a pod that is in the binding cycle but before it is bound given its UID.
GetPodInPreBind(uid types.UID) PodInPreBind
// RemovePodInPreBind removes a pod from the pods in preBind list.
RemovePodInPreBind(uid types.UID)
// ClientSet returns a kubernetes clientSet.
ClientSet() clientset.Interface
// KubeConfig returns the raw kube config.
KubeConfig() *restclient.Config
// EventRecorder returns an event recorder.
EventRecorder() events.EventRecorderLogger
SharedInformerFactory() informers.SharedInformerFactory
// SharedDRAManager can be used to obtain DRA objects, and track modifications to them in-memory - mainly by the DRA plugin.
// A non-default implementation can be plugged into the framework to simulate the state of DRA objects.
SharedDRAManager() SharedDRAManager
// SharedCSIManager can be used to obtain CSINode objects, and track changes to them in-memory.
// A non-default implementation can be plugged into the framework to simulate the state of CSINode objects.
SharedCSIManager() CSIManager
// RunFilterPluginsWithNominatedPods runs the set of configured filter plugins for nominated pod on the given node.
RunFilterPluginsWithNominatedPods(ctx context.Context, state CycleState, pod *v1.Pod, info NodeInfo) *Status
// Extenders returns registered scheduler extenders.
Extenders() []Extender
// Parallelizer returns a parallelizer holding parallelism for scheduler.
Parallelizer() Parallelizer
// APIDispatcher returns a APIDispatcher that can be used to dispatch API calls directly.
// This is non-nil if the SchedulerAsyncAPICalls feature gate is enabled.
APIDispatcher() APIDispatcher
// APICacher returns an APICacher that coordinates API calls with the scheduler's internal cache.
// Use this to ensure the scheduler's view of the cluster remains consistent.
// This is non-nil if the SchedulerAsyncAPICalls feature gate is enabled.
APICacher() APICacher
// ProfileName returns the profile name associated to a profile.
ProfileName() string
// PodGroupManager provides an interface for runtime information about pod groups from scheduler's cache.
PodGroupManager() PodGroupManager
// SignPod creates a PodSignature for a pod.
SignPod(ctx context.Context, pod *v1.Pod) PodSignature
}
// Parallelizer helps run scheduling operations in parallel chunks where possible, to improve performance and CPU utilization.
type Parallelizer interface {
// Until executes the given func doWorkPiece in parallel chunks, if applicable. Max number of chunks is param pieces.
Until(ctx context.Context, pieces int, doWorkPiece workqueue.DoWorkPieceFunc, operation string)
}
// PodActivator abstracts operations in the scheduling queue.
type PodActivator interface {
// Activate moves the given pods to activeQ.
// If a pod isn't found in unschedulablePods or backoffQ and it's in-flight,
// the wildcard event is registered so that the pod will be requeued when it comes back.
// But, if a pod isn't found in unschedulablePods or backoffQ and it's not in-flight (i.e., completely unknown pod),
// Activate would ignore the pod.
Activate(logger klog.Logger, pods map[string]*v1.Pod)
}
// PodNominator abstracts operations to maintain nominated Pods.
type PodNominator interface {
// AddNominatedPod adds the given pod to the nominator or
// updates it if it already exists.
AddNominatedPod(logger klog.Logger, pod PodInfo, nominatingInfo *NominatingInfo)
// DeleteNominatedPodIfExists deletes nominatedPod from internal cache. It's a no-op if it doesn't exist.
DeleteNominatedPodIfExists(pod *v1.Pod)
// UpdateNominatedPod updates the <oldPod> with <newPod>.
UpdateNominatedPod(logger klog.Logger, oldPod *v1.Pod, newPodInfo PodInfo)
// NominatedPodsForNode returns nominatedPods on the given node.
NominatedPodsForNode(nodeName string) []PodInfo
}
// PluginsRunner abstracts operations to run some plugins.
// This is used by preemption PostFilter plugins when evaluating the feasibility of
// scheduling the pod on nodes when certain running pods get evicted.
type PluginsRunner interface {
// RunPreScorePlugins runs the set of configured PreScore plugins. If any
// of these plugins returns any status other than "Success", the given pod is rejected.
RunPreScorePlugins(context.Context, CycleState, *v1.Pod, []NodeInfo) *Status
// RunScorePlugins runs the set of configured scoring plugins.
// It returns a list that stores scores from each plugin and total score for each Node.
// It also returns *Status, which is set to non-success if any of the plugins returns
// a non-success status.
RunScorePlugins(context.Context, CycleState, *v1.Pod, []NodeInfo) ([]NodePluginScores, *Status)
// RunFilterPlugins runs the set of configured Filter plugins for pod on
// the given node. Note that for the node being evaluated, the passed nodeInfo
// reference could be different from the one in NodeInfoSnapshot map (e.g., pods
// considered to be running on the node could be different). For example, during
// preemption, we may pass a copy of the original nodeInfo object that has some pods
// removed from it to evaluate the possibility of preempting them to
// schedule the target pod.
RunFilterPlugins(context.Context, CycleState, *v1.Pod, NodeInfo) *Status
// RunPreFilterExtensionAddPod calls the AddPod interface for the set of configured
// PreFilter plugins. It returns directly if any of the plugins return any
// status other than Success.
RunPreFilterExtensionAddPod(ctx context.Context, state CycleState, podToSchedule *v1.Pod, podInfoToAdd PodInfo, nodeInfo NodeInfo) *Status
// RunPreFilterExtensionRemovePod calls the RemovePod interface for the set of configured
// PreFilter plugins. It returns directly if any of the plugins return any
// status other than Success.
RunPreFilterExtensionRemovePod(ctx context.Context, state CycleState, podToSchedule *v1.Pod, podInfoToRemove PodInfo, nodeInfo NodeInfo) *Status
}
================================================
FILE: framework/interface_test.go
================================================
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
"errors"
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/util/sets"
)
var errorStatus = NewStatus(Error, "internal error")
var statusWithErr = AsStatus(errors.New("internal error"))
func TestStatus(t *testing.T) {
tests := []struct {
name string
status *Status
expectedCode Code
expectedMessage string
expectedIsSuccess bool
expectedIsWait bool
expectedIsSkip bool
expectedAsError error
}{
{
name: "success status",
status: NewStatus(Success, ""),
expectedCode: Success,
expectedMessage: "",
expectedIsSuccess: true,
expectedIsWait: false,
expectedIsSkip: false,
expectedAsError: nil,
},
{
name: "wait status",
status: NewStatus(Wait, ""),
expectedCode: Wait,
expectedMessage: "",
expectedIsSuccess: false,
expectedIsWait: true,
expectedIsSkip: false,
expectedAsError: nil,
},
{
name: "error status",
status: NewStatus(Error, "unknown error"),
expectedCode: Error,
expectedMessage: "unknown error",
expectedIsSuccess: false,
expectedIsWait: false,
expectedIsSkip: false,
expectedAsError: errors.New("unknown error"),
},
{
name: "skip status",
status: NewStatus(Skip, ""),
expectedCode: Skip,
expectedMessage: "",
expectedIsSuccess: false,
expectedIsWait: false,
expectedIsSkip: true,
expectedAsError: nil,
},
{
name: "nil status",
status: nil,
expectedCode: Success,
expectedMessage: "",
expectedIsSuccess: true,
expectedIsSkip: false,
expectedAsError: nil,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.status.Code() != test.expectedCode {
t.Errorf("expect status.Code() returns %v, but %v", test.expectedCode, test.status.Code())
}
if test.status.Message() != test.expectedMessage {
t.Errorf("expect status.Message() returns %v, but %v", test.expectedMessage, test.status.Message())
}
if test.status.IsSuccess() != test.expectedIsSuccess {
t.Errorf("expect status.IsSuccess() returns %v, but %v", test.expectedIsSuccess, test.status.IsSuccess())
}
if test.status.IsWait() != test.expectedIsWait {
t.Errorf("status.IsWait() returns %v, but want %v", test.status.IsWait(), test.expectedIsWait)
}
if test.status.IsSkip() != test.expectedIsSkip {
t.Errorf("status.IsSkip() returns %v, but want %v", test.status.IsSkip(), test.expectedIsSkip)
}
if errors.Is(test.status.AsError(), test.expectedAsError) {
return
}
if test.status.AsError().Error() != test.expectedAsError.Error() {
t.Errorf("expect status.AsError() returns %v, but %v", test.expectedAsError, test.status.AsError())
}
})
}
}
func TestPreFilterResultMerge(t *testing.T) {
tests := map[string]struct {
receiver *PreFilterResult
in *PreFilterResult
want *PreFilterResult
}{
"all nil": {},
"nil receiver empty input": {
in: &PreFilterResult{NodeNames: sets.New[string]()},
want: &PreFilterResult{NodeNames: sets.New[string]()},
},
"empty receiver nil input": {
receiver: &PreFilterResult{NodeNames: sets.New[string]()},
want: &PreFilterResult{NodeNames: sets.New[string]()},
},
"empty receiver empty input": {
receiver: &PreFilterResult{NodeNames: sets.New[string]()},
in: &PreFilterResult{NodeNames: sets.New[string]()},
want: &PreFilterResult{NodeNames: sets.New[string]()},
},
"nil receiver populated input": {
in: &PreFilterResult{NodeNames: sets.New("node1")},
want: &PreFilterResult{NodeNames: sets.New("node1")},
},
"empty receiver populated input": {
receiver: &PreFilterResult{NodeNames: sets.New[string]()},
in: &PreFilterResult{NodeNames: sets.New("node1")},
want: &PreFilterResult{NodeNames: sets.New[string]()},
},
"populated receiver nil input": {
receiver: &PreFilterResult{NodeNames: sets.New("node1")},
want: &PreFilterResult{NodeNames: sets.New("node1")},
},
"populated receiver empty input": {
receiver: &PreFilterResult{NodeNames: sets.New("node1")},
in: &PreFilterResult{NodeNames: sets.New[string]()},
want: &PreFilterResult{NodeNames: sets.New[string]()},
},
"populated receiver and input": {
receiver: &PreFilterResult{NodeNames: sets.New("node1", "node2")},
in: &PreFilterResult{NodeNames: sets.New("node2", "node3")},
want: &PreFilterResult{NodeNames: sets.New("node2")},
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
got := test.receiver.Merge(test.in)
if diff := cmp.Diff(test.want, got); diff != "" {
t.Errorf("unexpected diff (-want, +got):\n%s", diff)
}
})
}
}
func TestIsStatusEqual(t *testing.T) {
tests := []struct {
name string
x, y *Status
want bool
}{
{
name: "two nil should be equal",
x: nil,
y: nil,
want: true,
},
{
name: "nil should be equal to success status",
x: nil,
y: NewStatus(Success),
want: true,
},
{
name: "nil should not be equal with status except success",
x: nil,
y: NewStatus(Error, "internal error"),
want: false,
},
{
name: "one status should be equal to itself",
x: errorStatus,
y: errorStatus,
want: true,
},
{
name: "same type statuses without reasons should be equal",
x: NewStatus(Success),
y: NewStatus(Success),
want: true,
},
{
name: "statuses with same message should be equal",
x: NewStatus(Unschedulable, "unschedulable"),
y: NewStatus(Unschedulable, "unschedulable"),
want: true,
},
{
name: "error statuses with same message should be equal",
x: NewStatus(Error, "error"),
y: NewStatus(Error, "error"),
want: true,
},
{
name: "statuses with different reasons should not be equal",
x: NewStatus(Unschedulable, "unschedulable"),
y: NewStatus(Unschedulable, "unschedulable", "injected filter status"),
want: false,
},
{
name: "statuses with different codes should not be equal",
x: NewStatus(Error, "internal error"),
y: NewStatus(Unschedulable, "internal error"),
want: false,
},
{
name: "wrap error status should be equal with original one",
x: statusWithErr,
y: AsStatus(fmt.Errorf("error: %w", statusWithErr.AsError())),
want: true,
},
{
name: "statues with different errors that have the same message shouldn't be equal",
x: AsStatus(errors.New("error")),
y: AsStatus(errors.New("error")),
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.x.Equal(tt.y); got != tt.want {
t.Errorf("cmp.Equal() = %v, want %v", got, tt.want)
}
})
}
}
================================================
FILE: framework/listers.go
================================================
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
v1 "k8s.io/api/core/v1"
resourceapi "k8s.io/api/resource/v1"
schedulingapi "k8s.io/api/scheduling/v1alpha2"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/dynamic-resource-allocation/structured"
)
// NodeInfoLister interface represents anything that can list/get NodeInfo objects from node name.
type NodeInfoLister interface {
// List returns the list of NodeInfos.
List() ([]NodeInfo, error)
// HavePodsWithAffinityList returns the list of NodeInfos of nodes with pods with affinity terms.
HavePodsWithAffinityList() ([]NodeInfo, error)
// HavePodsWithRequiredAntiAffinityList returns the list of NodeInfos of nodes with pods with required anti-affinity terms.
HavePodsWithRequiredAntiAffinityList() ([]NodeInfo, error)
// Get returns the NodeInfo of the given node name.
Get(nodeName string) (NodeInfo, error)
}
// StorageInfoLister interface represents anything that handles storage-related operations and resources.
type StorageInfoLister interface {
// IsPVCUsedByPods returns true/false on whether the PVC is used by one or more scheduled pods,
// keyed in the format "namespace/name".
IsPVCUsedByPods(key string) bool
}
// SharedLister groups scheduler-specific listers.
type SharedLister interface {
NodeInfos() NodeInfoLister
StorageInfos() StorageInfoLister
PodGroupStates() PodGroupStateLister
}
// PodGroupStateLister provides read access to pod group states.
type PodGroupStateLister interface {
// Get returns the PodGroupState of the given pod group.
Get(namespace string, podGroupName string) (PodGroupState, error)
}
type CSINodeLister interface {
// List returns a list of all CSINodes.
List() ([]*storagev1.CSINode, error)
// Get returns the CSINode with the given name.
Get(name string) (*storagev1.CSINode, error)
}
// ResourceSliceLister can be used to obtain ResourceSlices.
type ResourceSliceLister interface {
// ListWithDeviceTaintRules returns a list of all ResourceSlices with DeviceTaintRules applied
// if the DRADeviceTaints feature is enabled, otherwise without them.
//
// k8s.io/dynamic-resource-allocation/resourceslice/tracker provides an implementation
// of the necessary logic. That tracker can be instantiated as a replacement for
// a normal ResourceSlice informer and provides a ListPatchedResourceSlices method.
ListWithDeviceTaintRules() ([]*resourceapi.ResourceSlice, error)
}
// DeviceClassLister can be used to obtain DeviceClasses.
type DeviceClassLister interface {
// List returns a list of all DeviceClasses.
List() ([]*resourceapi.DeviceClass, error)
// Get returns the DeviceClass with the given className.
Get(className string) (*resourceapi.DeviceClass, error)
}
// ResourceClaimTracker can be used to obtain ResourceClaims, and track changes to ResourceClaims in-memory.
//
// If the claims are meant to be allocated in the API during the binding phase (when used by scheduler), the tracker helps avoid
// race conditions between scheduling and binding phases (as well as between the binding phase and the informer cache update).
//
// If the binding phase is not run (e.g. when used by Cluster Autoscaler which only runs the scheduling phase, and simulates binding in-memory),
// the tracker allows the framework user to obtain the claim allocations produced by the DRA plugin, and persist them outside of the API (e.g. in-memory).
type ResourceClaimTracker interface {
// List lists ResourceClaims. The result is guaranteed to immediately include any changes made via AssumeClaimAfterAPICall(),
// and SignalClaimPendingAllocation().
List() ([]*resourceapi.ResourceClaim, error)
// Get works like List(), but for a single claim.
Get(namespace, claimName string) (*resourceapi.ResourceClaim, error)
// ListAllAllocatedDevices lists all allocated Devices from allocated ResourceClaims. The result is guaranteed to immediately include
// any changes made via AssumeClaimAfterAPICall(), and SignalClaimPendingAllocation().
ListAllAllocatedDevices() (sets.Set[structured.DeviceID], error)
// GatherAllocatedState gathers information about allocated devices from allocated ResourceClaims. The result is guaranteed to immediately include
// any changes made via AssumeClaimAfterAPICall(), and SignalClaimPendingAllocation().
GatherAllocatedState() (*structured.AllocatedState, error)
// SignalClaimPendingAllocation signals to the tracker that the given ResourceClaim will be allocated via an API call in the
// binding phase, therefore the given ResourceClaim must be non-nil and have a non-nil Status.Allocation.
// If the claim already has a pending allocation, then the allocation becomes shared. The same number of SignalClaimPendingAllocation() callers
// for a given claimUID is expected to eventually call MaybeRemoveClaimPendingAllocation() for that claimUID.
// This change is immediately reflected in the result of List() and the other accessors.
SignalClaimPendingAllocation(claimUID types.UID, allocatedClaim *resourceapi.ResourceClaim) error
// ClaimHasPendingAllocation answers whether a given claim has a pending allocation during the binding phase. It can be used to avoid
// race conditions in subsequent scheduling phases.
GetPendingAllocation(claimUID types.UID) *resourceapi.AllocationResult
// MaybeRemoveClaimPendingAllocation might remove the pending allocation for the given ResourceClaim from the tracker if any was signaled via
// SignalClaimPendingAllocation(). When `forceRemove` is true, it always removes the pending allocation. Otherwise, it removes the pending
// allocation only when no other pods are still using that pending allocation (from SignalClaimPendingAllocation and AcquirePendingAllocation).
// Returns whether there was a pending allocation and it was removed.
// List() and the other accessors immediately stop reflecting the pending allocation in the results when the pending allocation is removed.
MaybeRemoveClaimPendingAllocation(claimUID types.UID, forceRemove bool) (deleted bool)
// AssumeClaimAfterAPICall signals to the tracker that an API call modifying the given ResourceClaim was made in the binding phase, and the
// changes should be reflected in informers very soon. This change is immediately reflected in the result of List() and the other accessors.
// This mechanism can be used to avoid race conditions between the informer update and subsequent scheduling phases.
AssumeClaimAfterAPICall(claim *resourceapi.ResourceClaim) error
// AssumedClaimRestore signals to the tracker that something went wrong with the API call modifying the given ResourceClaim, and
// the changes won't be reflected in informers after all. List() and the other accessors immediately stop reflecting the assumed change,
// and go back to the informer version.
AssumedClaimRestore(namespace, claimName string)
}
// DeviceClassResolver resolves device class names from extended resource names.
type DeviceClassResolver interface {
// GetDeviceClass returns the device class for the given extended resource name.
// Returns nil if no mapping exists for the resource name or
// the DRAExtendedResource feature is disabled.
GetDeviceClass(resourceName v1.ResourceName) *resourceapi.DeviceClass
}
// PodGroupLister can be used to obtain PodGroups.
type PodGroupLister interface {
// Get returns the PodGroup with the given podGroupName.
Get(namespace, podGroupName string) (*schedulingapi.PodGroup, error)
}
// SharedDRAManager can be used to obtain DRA objects, and track modifications to them in-memory - mainly by the DRA plugin.
// The plugin's default implementation obtains the objects from the API. A different implementation can be
// plugged into the framework in order to simulate the state of DRA objects. For example, Cluster Autoscaler
// can use this to provide the correct DRA object state to the DRA plugin when simulating scheduling changes in-memory.
type SharedDRAManager interface {
ResourceClaims() ResourceClaimTracker
ResourceSlices() ResourceSliceLister
DeviceClasses() DeviceClassLister
DeviceClassResolver() DeviceClassResolver
PodGroups() PodGroupLister
}
// CSIManager can be used to obtain CSINode objects, and track changes to CSINode objects in-memory.
// The plugin's default implementation obtains the objects from the API. A different implementation can be
// plugged into the framework in order to simulate the state of CSINode objects. For example, Cluster Autoscaler
// can use this to provide the correct CSINode object state to the CSINode plugin when simulating scheduling changes in-memory.
type CSIManager interface {
CSINodes() CSINodeLister
}
// PodGroupManager provides an interface for runtime information about pod groups in the scheduler cache.
type PodGroupManager interface {
// PodGroupStates returns the PodGroupStateLister.
PodGroupStates() PodGroupStateLister
}
// PodGroupState provides an interface to view the state of a single pod group.
type PodGroupState interface {
// AllPods returns the UIDs of all pods known to the scheduler for this group.
AllPods() sets.Set[types.UID]
// AllPodsCount returns the number of all pods known to the scheduler for this group.
AllPodsCount() int
// UnscheduledPods returns all pods that are unscheduled for this group,
// i.e., are neither assumed nor assigned.
// The returned map type corresponds to the argument of the PodActivator.Activate method.
UnscheduledPods() map[string]*v1.Pod
// AssumedPods returns the UIDs of all pods for this group in the "assumed" state,
// i.e., passed the Reserve gate.
AssumedPods() sets.Set[types.UID]
// AssignedPods returns the UIDs of all pods already assigned (bound) for this group.
AssignedPods() sets.Set[types.UID]
// ScheduledPods returns the pods that are either assumed or assigned for this pod group.
ScheduledPods() []*v1.Pod
// ScheduledPodsCount returns the number of pods for this group that are either assumed or assigned.
ScheduledPodsCount() int
}
================================================
FILE: framework/signers.go
================================================
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
"encoding/json"
"slices"
"sort"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets"
)
// This file contains the names and implementations of various functions used
// to compute pod signatures for use in batching and other scheduling optimizations.
// See the definition of BatchablePlugin for more details.
// Signer names
const (
DynamicResourcesSignerName = "v1.Pod.Spec.DynamicResources"
ImageNamesSignerName = "v1.Pod.Spec.CanonicalImageNames()"
LabelsSignerName = "v1.Pod.Labels"
NodeNameSignerName = "v1.Pod.Spec.NodeName"
NodeAffinitySignerName = "v1.Pod.Spec.Affinity.NodeAffinity"
NodeSelectorSignerName = "v1.Pod.Spec.Affinity.NodeSelector"
HostPortsSignerName = "v1.Pod.Spec.HostPorts()"
ResourcesSignerName = "v1.Pod.Spec.ContainerRequestsAndOverheads()"
SchedulerNameSignerName = "v1.Pod.Spec.SchedulerName"
TolerationsSignerName = "v1.Pod.Spec.Tolerations"
VolumesSignerName = "v1.Pod.Spec.Volumes.NonSyntheticSources()"
FeaturesSignerName = "v1.Pod.Spec.RequiredFeatures()"
)
// Common signers. These are either generic or shared across plugins.
func HostPortsSigner(pod *v1.Pod) any {
portSet := sets.New[int32]()
containers := []v1.Container{}
containers = append(containers, pod.Spec.Containers...)
containers = append(containers, pod.Spec.InitContainers...)
for _, container := range containers {
for _, port := range container.Ports {
if port.HostPort != 0 {
portSet.Insert(port.HostPort)
}
}
}
ports := portSet.UnsortedList()
slices.Sort(ports)
return ports
}
func NodeSelectorRequirementsSigner(reqs []v1.NodeSelectorRequirement) ([]string, error) {
ret := make([]string, len(reqs))
for i, req := range reqs {
t := req.DeepCopy()
slices.Sort(t.Values)
v, err := json.Marshal(t)
if err != nil {
return nil, err
}
ret[i] = string(v)
}
slices.Sort(ret)
return ret, nil
}
type nodeSelTermSignResult struct {
MatchExpressions []string
MatchFields []string
}
func NodeSelectorTermSigner(t *v1.NodeSelectorTerm) (nodeSelTermSignResult, error) {
exp, err := NodeSelectorRequirementsSigner(t.MatchExpressions)
if err != nil {
return nodeSelTermSignResult{}, err
}
fld, err := NodeSelectorRequirementsSigner(t.MatchFields)
if err != nil {
return nodeSelTermSignResult{}, err
}
return nodeSelTermSignResult{
MatchExpressions: exp,
MatchFields: fld,
}, nil
}
type prefSchedTermSignResult struct {
Weight int32
Preference nodeSelTermSignResult
}
func PreferredSchedulingTermSigner(terms []v1.PreferredSchedulingTerm) ([]string, error) {
newTerms := make([]string, len(terms))
for i, t := range terms {
pref, err := NodeSelectorTermSigner(&t.Preference)
if err != nil {
return nil, err
}
termStr, err := json.Marshal(prefSchedTermSignResult{
Weight: t.Weight,
Preference: pref,
})
if err != nil {
return nil, err
}
newTerms[i] = string(termStr)
}
slices.Sort(newTerms)
return newTerms, nil
}
func NodeSelectorTermsSigner(terms []v1.NodeSelectorTerm) ([]string, error) {
req := make([]string, len(terms))
for i, t := range terms {
nst, err := NodeSelectorTermSigner(&t)
if err != nil {
return nil, err
}
tStr, err := json.Marshal(nst)
if err != nil {
return nil, err
}
req[i] = string(tStr)
}
slices.Sort(req)
return req, nil
}
type nodeAffinitySignerResult struct {
Required []string
Preferred []string
}
func NodeAffinitySigner(pod *v1.Pod) (any, error) {
if pod.Spec.Affinity != nil {
if pod.Spec.Affinity.NodeAffinity != nil {
n := pod.Spec.Affinity.NodeAffinity
pref := []string{}
var err error
if n.PreferredDuringSchedulingIgnoredDuringExecution != nil {
pref, err = PreferredSchedulingTermSigner(n.PreferredDuringSchedulingIgnoredDuringExecution)
if err != nil {
return nil, err
}
}
req := []string{}
if n.RequiredDuringSchedulingIgnoredDuringExecution != nil {
req, err = NodeSelectorTermsSigner(n.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms)
if err != nil {
return nil, err
}
}
return nodeAffinitySignerResult{
Required: req,
Preferred: pref,
}, nil
}
}
return nil, nil
}
func TolerationsSigner(pod *v1.Pod) any {
ret := []v1.Toleration{}
ret = append(ret, pod.Spec.Tolerations...)
sort.Slice(ret, func(i, j int) bool {
return ret[i].Key < ret[j].Key || (ret[i].Key == ret[j].Key && ret[i].Value < ret[j].Value)
})
return ret
}
// We special case volumes because config and secret volumes don't
// impact scheduling but are very specific to individual pods. If we
// don't exclude them no pods will have matching signatures.
func VolumesSigner(pod *v1.Pod) any {
ret := []string{}
for _, vol := range pod.Spec.Volumes {
if vol.VolumeSource.ConfigMap == nil && vol.VolumeSource.Secret == nil {
volStr, err := json.Marshal(vol.VolumeSource)
if err != nil {
return nil
}
ret = append(ret, string(volStr))
}
}
slices.Sort(ret)
return ret
}
================================================
FILE: framework/signers_test.go
================================================
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
"encoding/json"
"errors"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
v1 "k8s.io/api/core/v1"
)
func TestHostPortsSigner(t *testing.T) {
tests := []struct {
name string
pod *v1.Pod
want []int32
}{
{
name: "no containers",
pod: &v1.Pod{},
want: []int32{},
},
{
name: "containers without host ports",
pod: &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{Ports: []v1.ContainerPort{{ContainerPort: 80}}},
},
},
},
want: []int32{},
},
{
name: "single container with host port",
pod: &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{Ports: []v1.ContainerPort{{HostPort: 8080}}},
},
},
},
want: []int32{8080},
},
{
name: "multiple containers, unsorted host ports, duplicates",
pod: &v1.Pod{
Spec: v1.PodSpec{
InitContainers: []v1.Container{
{Ports: []v1.ContainerPort{{HostPort: 9090}}},
},
Containers: []v1.Container{
{Ports: []v1.ContainerPort{{HostPort: 80}}},
{Ports: []v1.ContainerPort{{HostPort: 443}, {HostPort: 80}}}, // duplicate 80
},
},
},
want: []int32{80, 443, 9090},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := HostPortsSigner(tt.pod)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("HostPortsSigner() = %v, want %v", got, tt.want)
}
})
}
}
func TestTolerationsSigner(t *testing.T) {
tests := []struct {
name string
pod *v1.Pod
want []v1.Toleration
}{
{
name: "no tolerations",
pod: &v1.Pod{},
want: []v1.Toleration{},
},
{
name: "single toleration",
pod: &v1.Pod{
Spec: v1.PodSpec{
Tolerations: []v1.Toleration{
{Key: "key1", Value: "value1", Effect: v1.TaintEffectNoSchedule},
},
},
},
want: []v1.Toleration{
{Key: "key1", Value: "value1", Effect: v1.TaintEffectNoSchedule},
},
},
{
name: "multiple tolerations, unsorted",
pod: &v1.Pod{
Spec: v1.PodSpec{
Tolerations: []v1.Toleration{
{Key: "b", Value: "2"},
{Key: "a", Value: "1"},
{Key: "b", Value: "1"},
},
},
},
want: []v1.Toleration{
{Key: "a", Value: "1"},
{Key: "b", Value: "1"},
{Key: "b", Value: "2"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := TolerationsSigner(tt.pod)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("TolerationsSigner() = %v, want %v", got, tt.want)
}
})
}
}
func TestVolumesSigner(t *testing.T) {
hostPath := v1.VolumeSource{HostPath: &v1.HostPathVolumeSource{Path: "/tmp"}}
emptyDir := v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}
configMap := v1.VolumeSource{ConfigMap: &v1.ConfigMapVolumeSource{LocalObjectReference: v1.LocalObjectReference{Name: "cm"}}}
secret := v1.VolumeSource{Secret: &v1.SecretVolumeSource{SecretName: "secret"}}
marshal := func(vs v1.VolumeSource) string {
b, _ := json.Marshal(vs)
return string(b)
}
tests := []struct {
name string
pod *v1.Pod
want []string
}{
{
name: "no volumes",
pod: &v1.Pod{},
want: []string{},
},
{
name: "only ignored volumes (ConfigMap, Secret)",
pod: &v1.Pod{
Spec: v1.PodSpec{
Volumes: []v1.Volume{
{Name: "v1", VolumeSource: configMap},
{Name: "v2", VolumeSource: secret},
},
},
},
want: []string{},
},
{
name: "mixed volumes, should be filtered and sorted",
pod: &v1.Pod{
Spec: v1.PodSpec{
Volumes: []v1.Volume{
{Name: "v1", VolumeSource: hostPath}, // e.g. {"hostPath":{"path":"/tmp"}}
{Name: "v2", VolumeSource: configMap}, // ignored
{Name: "v3", VolumeSource: emptyDir}, // e.g. {"emptyDir":{}}
},
},
},
// Expected sort order depends on the exact JSON string.
// {"emptyDir":{}} comes before {"hostPath":...} alphabetically.
want: []string{marshal(emptyDir), marshal(hostPath)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := VolumesSigner(tt.pod)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VolumesSigner() = %v, want %v", got, tt.want)
}
})
}
}
func TestNodeAffinitySigner(t *testing.T) {
table := []struct {
name string
input *v1.Pod
expected any
expectedErr error
}{
{
name: "nil affinity",
input: &v1.Pod{},
expected: nil,
expectedErr: nil,
},
{
name: "empty affinity",
input: &v1.Pod{
Spec: v1.PodSpec{
Affinity: &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{},
},
},
},
},
expected: nodeAffinitySignerResult{Required: []string{}, Preferred: []string{}},
expectedErr: nil,
},
{
name: "affinity unsorted",
input: &v1.Pod{
Spec: v1.PodSpec{
Affinity: &v1.Affinity{
NodeAffinity: &v1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{Key: "kk3", Operator: v1.NodeSelectorOpIn, Values: []string{"v3", "kv4"}},
{Key: "kk2", Operator: v1.NodeSelectorOpIn, Values: []string{"kv1", "v2"}},
},
MatchFields: []v1.NodeSelectorRequirement{
{Key: "kk1", Operator: v1.NodeSelectorOpIn, Values: []string{"kv3", "v4"}},
},
},
{
MatchExpressions: []v1.NodeSelectorRequirement{
{Key: "k2", Operator: v1.NodeSelectorOpIn, Values: []string{"v1", "v2"}},
},
MatchFields: []v1.NodeSelectorRequirement{
{Key: "k1", Operator: v1.NodeSelectorOpIn, Values: []string{"v3", "v4"}},
},
},
},
},
PreferredDuringSchedulingIgnoredDuringExecution: []v1.PreferredSchedulingTerm{
{
Weight: 3,
Preference: v1.NodeSelectorTerm{
MatchExpressions: []v1.NodeSelectorRequirement{
{Key: "ppk2", Operator: v1.NodeSelectorOpIn, Values: []string{"ppv1", "v2"}},
},
MatchFields: []v1.NodeSelectorRequirement{
{Key: "ppk1", Operator: v1.NodeSelectorOpIn, Values: []string{"ppv3", "v4"}},
},
},
},
{
Weight: 1,
Preference: v1.NodeSelectorTerm{
MatchExpressions: []v1.NodeSelectorRequirement{
{Key: "pk2", Operator: v1.NodeSelectorOpIn, Values: []string{"pv1", "v2"}},
},
MatchFields: []v1.NodeSelectorRequirement{
{Key: "pk1", Operator: v1.NodeSelectorOpIn, Values: []string{"pv3", "v4"}},
},
},
},
},
},
},
},
},
expected: nodeAffinitySignerResult{
Required: []string{
`{"MatchExpressions":["{\"key\":\"k2\",\"operator\":\"In\",\"values\":[\"v1\",\"v2\"]}"],"MatchFields":["{\"key\":\"k1\",\"operator\":\"In\",\"values\":[\"v3\",\"v4\"]}"]}`,
`{"MatchExpressions":["{\"key\":\"kk2\",\"operator\":\"In\",\"values\":[\"kv1\",\"v2\"]}","{\"key\":\"kk3\",\"operator\":\"In\",\"values\":[\"kv4\",\"v3\"]}"],"MatchFields":["{\"key\":\"kk1\",\"operator\":\"In\",\"values\":[\"kv3\",\"v4\"]}"]}`,
},
Preferred: []string{
`{"Weight":1,"Preference":{"MatchExpressions":["{\"key\":\"pk2\",\"operator\":\"In\",\"values\":[\"pv1\",\"v2\"]}"],"MatchFields":["{\"key\":\"pk1\",\"operator\":\"In\",\"values\":[\"pv3\",\"v4\"]}"]}}`,
`{"Weight":3,"Preference":{"MatchExpressions":["{\"key\":\"ppk2\",\"operator\":\"In\",\"values\":[\"ppv1\",\"v2\"]}"],"MatchFields":["{\"key\":\"ppk1\",\"operator\":\"In\",\"values\":[\"ppv3\",\"v4\"]}"]}}`,
},
},
expectedErr: nil,
},
}
for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
res, err := NodeAffinitySigner(tt.input)
if !errors.Is(err, tt.expectedErr) {
t.Fatalf("unexpected error %v, expected %v", err, tt.expectedErr)
}
if diff := cmp.Diff(res, tt.expected); diff != "" {
t.Fatalf("unexpected result %s", diff)
}
})
}
}
================================================
FILE: framework/types.go
================================================
/*
Copyright 2025 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package framework
import (
"fmt"
"time"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
ndf "k8s.io/component-helpers/nodedeclaredfeatures"
"k8s.io/klog/v2"
)
// ActionType is an integer to represent one type of resource change.
// Different ActionTypes can be bit-wised to compose new semantics.
type ActionType int64
// Constants for ActionTypes.
// CAUTION for contributors: When you add a new ActionType, you must update the following:
// - The list of basicActionTypes, podActionTypes, and nodeActionTypes at k/k/pkg/scheduler/framework/types.go
// - String() method.
const (
Add ActionType = 1 << iota
Delete
// UpdateNodeXYZ is only applicable for Node events.
// If you use UpdateNodeXYZ,
// your plugin's QueueingHint is only executed for the specific sub-Update event.
// It's better to narrow down the scope of the event by using them instead of just using Update event
// for better performance in requeueing.
UpdateNodeAllocatable
UpdateNodeLabel
// UpdateNodeTaint is an update for node's taints or node.Spec.Unschedulable.
UpdateNodeTaint
UpdateNodeCondition
UpdateNodeAnnotation
// UpdateNodeDeclaredFeature is an update for node's declared features.
UpdateNodeDeclaredFeature
// UpdatePodXYZ is only applicable for Pod events.
// If you use UpdatePodXYZ,
// your plugin's QueueingHint is only executed for the specific sub-Update event.
// It's better to narrow down the scope of the event by using them instead of Update event
// for better performance in requeueing.
UpdatePodLabel
// UpdatePodScaleDown is an update for pod's scale down (i.e., any resource request is reduced).
UpdatePodScaleDown
// UpdatePodToleration is an addition for pod's tolerations.
// (Due to API validation, we can add, but cannot modify or remove tolerations.)
UpdatePodToleration
// UpdatePodSchedulingGatesEliminated is an update for pod's scheduling gates, which eliminates all scheduling gates in the Pod.
UpdatePodSchedulingGatesEliminated
// UpdatePodGeneratedResourceClaim is an update of the list of ResourceClaims generated for the pod.
// Depends on the DynamicResourceAllocation feature gate.
UpdatePodGeneratedResourceClaim
All ActionType = 1<<iota - 1
// Use the general Update type if you don't either know or care the specific sub-Update type to use.
Update = UpdateNodeAllocatable | UpdateNodeLabel | UpdateNodeTaint | UpdateNodeCondition | UpdateNodeAnnotation | UpdateNodeDeclaredFeature | UpdatePodLabel | UpdatePodScaleDown | UpdatePodToleration | UpdatePodSchedulingGatesEliminated | UpdatePodGeneratedResourceClaim
// None is a special ActionType that is only used internally.
None ActionType = 0
)
func (a ActionType) String() string {
switch a {
case Add:
return "Add"
case Delete:
return "Delete"
case UpdateNodeAllocatable:
return "UpdateNodeAllocatable"
case UpdateNodeLabel:
return "UpdateNodeLabel"
case UpdateNodeTaint:
return "UpdateNodeTaint"
case UpdateNodeCondition:
return "UpdateNodeCondition"
case UpdateNodeAnnotation:
return "UpdateNodeAnnotation"
case UpdateNodeDeclaredFeature:
return "UpdateNodeDeclaredFeature"
case UpdatePodLabel:
return "UpdatePodLabel"
case UpdatePodScaleDown:
return "UpdatePodScaleDown"
case UpdatePodToleration:
return "UpdatePodToleration"
case UpdatePodSchedulingGatesEliminated:
return "UpdatePodSchedulingGatesEliminated"
case UpdatePodGeneratedResourceClaim:
return "UpdatePodGeneratedResourceClaim"
case All:
return "All"
case Update:
return "Update"
}
// Shouldn't reach here.
return ""
}
// EventResource is basically short for group/version/kind, which can uniquely represent a particular API resource.
type EventResource string
// Constants for GVKs.
//
// CAUTION for contributors: When you add a new EventResource, you must register a new one to allResources at k/k/pkg/scheduler/framework/types.go
//
// Note:
// - UpdatePodXYZ or UpdateNodeXYZ: triggered by updating particular parts of a Pod or a Node, e.g. updatePodLabel.
// Use specific events rather than general ones (updatePodLabel vs update) can make the requeueing process more efficient
// and consume less memory as less events will be cached at scheduler.
const (
// There are a couple of notes about how the scheduler notifies the events of Pods:
// - Add: add events could be triggered by either a newly created Pod or an existing Pod that is scheduled to a Node.
// - Delete: delete events could be triggered by:
// - a Pod that is deleted
// - a Pod that was assumed, but gets un-assumed due to some errors in the binding cycle.
// - an existing Pod that was unscheduled but gets scheduled to a Node.
//
// Note that the Pod event type includes the events for the unscheduled Pod itself.
// i.e., when unscheduled Pods are updated, the scheduling queue checks with Pod/Update QueueingHint(s) whether the update may make the pods schedulable,
// and requeues them to activeQ/backoffQ when at least one QueueingHint(s) return Queue.
// Plugins **have to** implement a QueueingHint for Pod/Update event
// if the rejection from them could be resolved by updating unscheduled Pods themselves.
// Example: Pods that require excessive resources may be rejected by the noderesources plugin,
// if this unscheduled pod is updated to require fewer resources,
// the previous rejection from noderesources plugin can be resolved.
// this plugin would implement QueueingHint for Pod/Update event
// that returns Queue when such label changes are made in unscheduled Pods.
//
// There is one general pod resource: Pod, that contains three specific pod resources: AssignedPod, UnscheduledPod, and TargetPod.
// Plugins can and are expected to register to specific pod events for better performance.
Pod EventResource = "Pod"
// AssignedPod resource is associated with the cluster event that gets triggered when a scheduled pod is updated.
AssignedPod EventResource = "AssignedPod"
// UnscheduledPod resource is associated with the cluster event that gets triggered when an unscheduled pod is updated, other than the target pod.
UnscheduledPod EventResource = "UnscheduledPod"
// TargetPod resource is associated with the cluster event that gets triggered when an unscheduled pod itself is updated.
TargetPod EventResource = "TargetPod"
Node EventResource = "Node"
PersistentVolume EventResource = "PersistentVolume"
PersistentVolumeClaim EventResource = "PersistentVolumeClaim"
CSINode EventResource = "storage.k8s.io/CSINode"
CSIDriver EventResource = "storage.k8s.io/CSIDriver"
VolumeAttachment EventResource = "storage.k8s.io/VolumeAttachment"
CSIStorageCapacity EventResource = "storage.k8s.io/CSIStorageCapacity"
StorageClass EventResource = "storage.k8s.io/StorageClass"
ResourceClaim EventResource = "resource.k8s.io/ResourceClaim"
ResourceSlice EventResource = "resource.k8s.io/ResourceSlice"
DeviceClass EventResource = "resource.k8s.io/DeviceClass"
PodGroup EventResource = "scheduling.k8s.io/PodGroup"
// WildCard is a special EventResource to match all resources.
// e.g., If you register `{Resource: "*", ActionType: All}` in EventsToRegister,
// all coming clusterEvents will be admitted. Be careful to register it, it will
// increase the computing pressure in requeueing unless you really need it.
//
// Meanwhile, if the coming clusterEvent is a wildcard one, all pods
// will be moved from unschedulablePod pool to activeQ/backoffQ forcibly.
WildCard EventResource = "*"
)
type ClusterEven
gitextract_ew82_piy/ ├── .github/ │ └── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── LICENSE ├── OWNERS ├── README.md ├── SECURITY_CONTACTS ├── code-of-conduct.md ├── config/ │ ├── OWNERS │ └── v1/ │ ├── doc.go │ ├── register.go │ ├── types.go │ ├── types_pluginargs.go │ ├── zz_generated.deepcopy.go │ └── zz_generated.model_name.go ├── doc.go ├── extender/ │ ├── OWNERS │ └── v1/ │ ├── doc.go │ ├── types.go │ ├── types_test.go │ └── zz_generated.deepcopy.go ├── framework/ │ ├── api_calls.go │ ├── api_dispatcher.go │ ├── cycle_state.go │ ├── extender.go │ ├── interface.go │ ├── interface_test.go │ ├── listers.go │ ├── signers.go │ ├── signers_test.go │ ├── types.go │ └── types_test.go ├── go.mod └── go.sum
SYMBOL INDEX (368 symbols across 19 files)
FILE: config/v1/register.go
constant GroupName (line 25) | GroupName = "kubescheduler.config.k8s.io"
function addKnownTypes (line 38) | func addKnownTypes(scheme *runtime.Scheme) error {
FILE: config/v1/types.go
constant SchedulerDefaultLockObjectNamespace (line 32) | SchedulerDefaultLockObjectNamespace string = metav1.NamespaceSystem
constant SchedulerDefaultLockObjectName (line 35) | SchedulerDefaultLockObjectName = "kube-scheduler"
constant SchedulerDefaultProviderName (line 38) | SchedulerDefaultProviderName = "DefaultProvider"
type KubeSchedulerConfiguration (line 44) | type KubeSchedulerConfiguration struct
method DecodeNestedObjects (line 102) | func (c *KubeSchedulerConfiguration) DecodeNestedObjects(d runtime.Dec...
method EncodeNestedObjects (line 125) | func (c *KubeSchedulerConfiguration) EncodeNestedObjects(e runtime.Enc...
type KubeSchedulerProfile (line 139) | type KubeSchedulerProfile struct
type Plugins (line 179) | type Plugins struct
type PluginSet (line 245) | type PluginSet struct
type Plugin (line 260) | type Plugin struct
type PluginConfig (line 270) | type PluginConfig struct
method decodeNestedObjects (line 277) | func (c *PluginConfig) decodeNestedObjects(d runtime.Decoder) error {
method encodeNestedObjects (line 301) | func (c *PluginConfig) encodeNestedObjects(e runtime.Encoder) error {
type Extender (line 323) | type Extender struct
type ExtenderManagedResource (line 368) | type ExtenderManagedResource struct
type ExtenderTLSConfig (line 377) | type ExtenderTLSConfig struct
type DynamicResourcesArgs (line 409) | type DynamicResourcesArgs struct
constant DynamicResourcesFilterTimeoutDefault (line 469) | DynamicResourcesFilterTimeoutDefault = 10 * time.Second
constant DynamicResourcesBindingTimeoutDefault (line 470) | DynamicResourcesBindingTimeoutDefault = 600 * time.Second
FILE: config/v1/types_pluginargs.go
type DefaultPreemptionArgs (line 28) | type DefaultPreemptionArgs struct
type InterPodAffinityArgs (line 49) | type InterPodAffinityArgs struct
type NodeResourcesFitArgs (line 64) | type NodeResourcesFitArgs struct
type PodTopologySpreadConstraintsDefaulting (line 85) | type PodTopologySpreadConstraintsDefaulting
constant SystemDefaulting (line 89) | SystemDefaulting PodTopologySpreadConstraintsDefaulting = "System"
constant ListDefaulting (line 91) | ListDefaulting PodTopologySpreadConstraintsDefaulting = "List"
type PodTopologySpreadArgs (line 97) | type PodTopologySpreadArgs struct
type NodeResourcesBalancedAllocationArgs (line 125) | type NodeResourcesBalancedAllocationArgs struct
type UtilizationShapePoint (line 135) | type UtilizationShapePoint struct
type ResourceSpec (line 143) | type ResourceSpec struct
type VolumeBindingArgs (line 153) | type VolumeBindingArgs struct
type NodeAffinityArgs (line 181) | type NodeAffinityArgs struct
type ScoringStrategyType (line 195) | type ScoringStrategyType
constant LeastAllocated (line 199) | LeastAllocated ScoringStrategyType = "LeastAllocated"
constant MostAllocated (line 201) | MostAllocated ScoringStrategyType = "MostAllocated"
constant RequestedToCapacityRatio (line 204) | RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio"
type ScoringStrategy (line 208) | type ScoringStrategy struct
type RequestedToCapacityRatioParam (line 225) | type RequestedToCapacityRatioParam struct
FILE: config/v1/zz_generated.deepcopy.go
method DeepCopyInto (line 31) | func (in *DefaultPreemptionArgs) DeepCopyInto(out *DefaultPreemptionArgs) {
method DeepCopy (line 48) | func (in *DefaultPreemptionArgs) DeepCopy() *DefaultPreemptionArgs {
method DeepCopyObject (line 58) | func (in *DefaultPreemptionArgs) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 66) | func (in *DynamicResourcesArgs) DeepCopyInto(out *DynamicResourcesArgs) {
method DeepCopy (line 83) | func (in *DynamicResourcesArgs) DeepCopy() *DynamicResourcesArgs {
method DeepCopyObject (line 93) | func (in *DynamicResourcesArgs) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 101) | func (in *Extender) DeepCopyInto(out *Extender) {
method DeepCopy (line 118) | func (in *Extender) DeepCopy() *Extender {
method DeepCopyInto (line 128) | func (in *ExtenderManagedResource) DeepCopyInto(out *ExtenderManagedReso...
method DeepCopy (line 134) | func (in *ExtenderManagedResource) DeepCopy() *ExtenderManagedResource {
method DeepCopyInto (line 144) | func (in *ExtenderTLSConfig) DeepCopyInto(out *ExtenderTLSConfig) {
method DeepCopy (line 165) | func (in *ExtenderTLSConfig) DeepCopy() *ExtenderTLSConfig {
method DeepCopyInto (line 175) | func (in *InterPodAffinityArgs) DeepCopyInto(out *InterPodAffinityArgs) {
method DeepCopy (line 187) | func (in *InterPodAffinityArgs) DeepCopy() *InterPodAffinityArgs {
method DeepCopyObject (line 197) | func (in *InterPodAffinityArgs) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 205) | func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerCon...
method DeepCopy (line 249) | func (in *KubeSchedulerConfiguration) DeepCopy() *KubeSchedulerConfigura...
method DeepCopyObject (line 259) | func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 267) | func (in *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) {
method DeepCopy (line 295) | func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile {
method DeepCopyInto (line 305) | func (in *NodeAffinityArgs) DeepCopyInto(out *NodeAffinityArgs) {
method DeepCopy (line 317) | func (in *NodeAffinityArgs) DeepCopy() *NodeAffinityArgs {
method DeepCopyObject (line 327) | func (in *NodeAffinityArgs) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 335) | func (in *NodeResourcesBalancedAllocationArgs) DeepCopyInto(out *NodeRes...
method DeepCopy (line 347) | func (in *NodeResourcesBalancedAllocationArgs) DeepCopy() *NodeResources...
method DeepCopyObject (line 357) | func (in *NodeResourcesBalancedAllocationArgs) DeepCopyObject() runtime....
method DeepCopyInto (line 365) | func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) {
method DeepCopy (line 387) | func (in *NodeResourcesFitArgs) DeepCopy() *NodeResourcesFitArgs {
method DeepCopyObject (line 397) | func (in *NodeResourcesFitArgs) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 405) | func (in *Plugin) DeepCopyInto(out *Plugin) {
method DeepCopy (line 416) | func (in *Plugin) DeepCopy() *Plugin {
method DeepCopyInto (line 426) | func (in *PluginConfig) DeepCopyInto(out *PluginConfig) {
method DeepCopy (line 433) | func (in *PluginConfig) DeepCopy() *PluginConfig {
method DeepCopyInto (line 443) | func (in *PluginSet) DeepCopyInto(out *PluginSet) {
method DeepCopy (line 463) | func (in *PluginSet) DeepCopy() *PluginSet {
method DeepCopyInto (line 473) | func (in *Plugins) DeepCopyInto(out *Plugins) {
method DeepCopy (line 494) | func (in *Plugins) DeepCopy() *Plugins {
method DeepCopyInto (line 504) | func (in *PodTopologySpreadArgs) DeepCopyInto(out *PodTopologySpreadArgs) {
method DeepCopy (line 518) | func (in *PodTopologySpreadArgs) DeepCopy() *PodTopologySpreadArgs {
method DeepCopyObject (line 528) | func (in *PodTopologySpreadArgs) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 536) | func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCa...
method DeepCopy (line 547) | func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacity...
method DeepCopyInto (line 557) | func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) {
method DeepCopy (line 563) | func (in *ResourceSpec) DeepCopy() *ResourceSpec {
method DeepCopyInto (line 573) | func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) {
method DeepCopy (line 589) | func (in *ScoringStrategy) DeepCopy() *ScoringStrategy {
method DeepCopyInto (line 599) | func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) {
method DeepCopy (line 605) | func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint {
method DeepCopyInto (line 615) | func (in *VolumeBindingArgs) DeepCopyInto(out *VolumeBindingArgs) {
method DeepCopy (line 632) | func (in *VolumeBindingArgs) DeepCopy() *VolumeBindingArgs {
method DeepCopyObject (line 642) | func (in *VolumeBindingArgs) DeepCopyObject() runtime.Object {
FILE: config/v1/zz_generated.model_name.go
method OpenAPIModelName (line 25) | func (in DefaultPreemptionArgs) OpenAPIModelName() string {
method OpenAPIModelName (line 30) | func (in DynamicResourcesArgs) OpenAPIModelName() string {
method OpenAPIModelName (line 35) | func (in Extender) OpenAPIModelName() string {
method OpenAPIModelName (line 40) | func (in ExtenderManagedResource) OpenAPIModelName() string {
method OpenAPIModelName (line 45) | func (in ExtenderTLSConfig) OpenAPIModelName() string {
method OpenAPIModelName (line 50) | func (in InterPodAffinityArgs) OpenAPIModelName() string {
method OpenAPIModelName (line 55) | func (in KubeSchedulerConfiguration) OpenAPIModelName() string {
method OpenAPIModelName (line 60) | func (in KubeSchedulerProfile) OpenAPIModelName() string {
method OpenAPIModelName (line 65) | func (in NodeAffinityArgs) OpenAPIModelName() string {
method OpenAPIModelName (line 70) | func (in NodeResourcesBalancedAllocationArgs) OpenAPIModelName() string {
method OpenAPIModelName (line 75) | func (in NodeResourcesFitArgs) OpenAPIModelName() string {
method OpenAPIModelName (line 80) | func (in Plugin) OpenAPIModelName() string {
method OpenAPIModelName (line 85) | func (in PluginConfig) OpenAPIModelName() string {
method OpenAPIModelName (line 90) | func (in PluginSet) OpenAPIModelName() string {
method OpenAPIModelName (line 95) | func (in Plugins) OpenAPIModelName() string {
method OpenAPIModelName (line 100) | func (in PodTopologySpreadArgs) OpenAPIModelName() string {
method OpenAPIModelName (line 105) | func (in RequestedToCapacityRatioParam) OpenAPIModelName() string {
method OpenAPIModelName (line 110) | func (in ResourceSpec) OpenAPIModelName() string {
method OpenAPIModelName (line 115) | func (in ScoringStrategy) OpenAPIModelName() string {
method OpenAPIModelName (line 120) | func (in UtilizationShapePoint) OpenAPIModelName() string {
method OpenAPIModelName (line 125) | func (in VolumeBindingArgs) OpenAPIModelName() string {
FILE: extender/v1/types.go
constant MinExtenderPriority (line 26) | MinExtenderPriority int64 = 0
constant MaxExtenderPriority (line 29) | MaxExtenderPriority int64 = 10
type ExtenderPreemptionResult (line 33) | type ExtenderPreemptionResult struct
type ExtenderPreemptionArgs (line 38) | type ExtenderPreemptionArgs struct
type Victims (line 51) | type Victims struct
type MetaPod (line 57) | type MetaPod struct
type MetaVictims (line 66) | type MetaVictims struct
type ExtenderArgs (line 73) | type ExtenderArgs struct
type FailedNodesMap (line 85) | type FailedNodesMap
type ExtenderFilterResult (line 88) | type ExtenderFilterResult struct
type ExtenderBindingArgs (line 106) | type ExtenderBindingArgs struct
type ExtenderBindingResult (line 118) | type ExtenderBindingResult struct
type HostPriority (line 124) | type HostPriority struct
type HostPriorityList (line 132) | type HostPriorityList
FILE: extender/v1/types_test.go
function TestCompatibility (line 35) | func TestCompatibility(t *testing.T) {
FILE: extender/v1/zz_generated.deepcopy.go
method DeepCopyInto (line 29) | func (in *ExtenderArgs) DeepCopyInto(out *ExtenderArgs) {
method DeepCopy (line 54) | func (in *ExtenderArgs) DeepCopy() *ExtenderArgs {
method DeepCopyInto (line 64) | func (in *ExtenderBindingArgs) DeepCopyInto(out *ExtenderBindingArgs) {
method DeepCopy (line 70) | func (in *ExtenderBindingArgs) DeepCopy() *ExtenderBindingArgs {
method DeepCopyInto (line 80) | func (in *ExtenderBindingResult) DeepCopyInto(out *ExtenderBindingResult) {
method DeepCopy (line 86) | func (in *ExtenderBindingResult) DeepCopy() *ExtenderBindingResult {
method DeepCopyInto (line 96) | func (in *ExtenderFilterResult) DeepCopyInto(out *ExtenderFilterResult) {
method DeepCopy (line 130) | func (in *ExtenderFilterResult) DeepCopy() *ExtenderFilterResult {
method DeepCopyInto (line 140) | func (in *ExtenderPreemptionArgs) DeepCopyInto(out *ExtenderPreemptionAr...
method DeepCopy (line 181) | func (in *ExtenderPreemptionArgs) DeepCopy() *ExtenderPreemptionArgs {
method DeepCopyInto (line 191) | func (in *ExtenderPreemptionResult) DeepCopyInto(out *ExtenderPreemption...
method DeepCopy (line 212) | func (in *ExtenderPreemptionResult) DeepCopy() *ExtenderPreemptionResult {
method DeepCopyInto (line 222) | func (in FailedNodesMap) DeepCopyInto(out *FailedNodesMap) {
method DeepCopy (line 234) | func (in FailedNodesMap) DeepCopy() FailedNodesMap {
method DeepCopyInto (line 244) | func (in *HostPriority) DeepCopyInto(out *HostPriority) {
method DeepCopy (line 250) | func (in *HostPriority) DeepCopy() *HostPriority {
method DeepCopyInto (line 260) | func (in HostPriorityList) DeepCopyInto(out *HostPriorityList) {
method DeepCopy (line 270) | func (in HostPriorityList) DeepCopy() HostPriorityList {
method DeepCopyInto (line 280) | func (in *MetaPod) DeepCopyInto(out *MetaPod) {
method DeepCopy (line 286) | func (in *MetaPod) DeepCopy() *MetaPod {
method DeepCopyInto (line 296) | func (in *MetaVictims) DeepCopyInto(out *MetaVictims) {
method DeepCopy (line 313) | func (in *MetaVictims) DeepCopy() *MetaVictims {
method DeepCopyInto (line 323) | func (in *Victims) DeepCopyInto(out *Victims) {
method DeepCopy (line 340) | func (in *Victims) DeepCopy() *Victims {
FILE: framework/api_calls.go
type APICacher (line 30) | type APICacher interface
type APICallImplementations (line 52) | type APICallImplementations struct
FILE: framework/api_dispatcher.go
function IsUnexpectedError (line 38) | func IsUnexpectedError(err error) bool {
type APICallType (line 50) | type APICallType
type APICallRelevances (line 55) | type APICallRelevances
type APICall (line 58) | type APICall interface
type APICallOptions (line 82) | type APICallOptions struct
type APIDispatcher (line 96) | type APIDispatcher interface
FILE: framework/cycle_state.go
type StateData (line 31) | type StateData interface
type StateKey (line 39) | type StateKey
type CycleState (line 45) | type CycleState interface
type PodGroupCycleState (line 113) | type PodGroupCycleState interface
FILE: framework/extender.go
type Extender (line 27) | type Extender interface
FILE: framework/interface.go
type Code (line 43) | type Code
method String (line 106) | func (c Code) String() string {
constant Success (line 50) | Success Code = iota
constant Error (line 55) | Error
constant Unschedulable (line 65) | Unschedulable
constant UnschedulableAndUnresolvable (line 76) | UnschedulableAndUnresolvable
constant Wait (line 78) | Wait
constant Skip (line 83) | Skip
constant Pending (line 100) | Pending
type Status (line 115) | type Status struct
method WithError (line 124) | func (s *Status) WithError(err error) *Status {
method Code (line 130) | func (s *Status) Code() Code {
method Message (line 138) | func (s *Status) Message() string {
method SetPlugin (line 146) | func (s *Status) SetPlugin(plugin string) {
method WithPlugin (line 152) | func (s *Status) WithPlugin(plugin string) *Status {
method Plugin (line 158) | func (s *Status) Plugin() string {
method Reasons (line 163) | func (s *Status) Reasons() []string {
method AppendReason (line 171) | func (s *Status) AppendReason(reason string) {
method IsSuccess (line 176) | func (s *Status) IsSuccess() bool {
method IsWait (line 181) | func (s *Status) IsWait() bool {
method IsSkip (line 186) | func (s *Status) IsSkip() bool {
method IsRejected (line 191) | func (s *Status) IsRejected() bool {
method IsError (line 197) | func (s *Status) IsError() bool {
method AsError (line 203) | func (s *Status) AsError() error {
method Equal (line 215) | func (s *Status) Equal(x *Status) bool {
method String (line 231) | func (s *Status) String() string {
method Clone (line 236) | func (s *Status) Clone() *Status {
function NewStatus (line 246) | func NewStatus(code Code, reasons ...string) *Status {
function AsStatus (line 255) | func AsStatus(err error) *Status {
type NodeToStatusReader (line 266) | type NodeToStatusReader interface
type NodeScoreList (line 276) | type NodeScoreList
type NodeScore (line 279) | type NodeScore struct
type NodePluginScores (line 285) | type NodePluginScores struct
type PluginScore (line 298) | type PluginScore struct
type PlacementPluginScores (line 305) | type PlacementPluginScores struct
constant MaxNodeScore (line 321) | MaxNodeScore int64 = MaxScore
constant MinNodeScore (line 326) | MinNodeScore int64 = MinScore
constant MaxScore (line 329) | MaxScore int64 = 100
constant MinScore (line 332) | MinScore int64 = 0
constant MaxTotalScore (line 335) | MaxTotalScore int64 = math.MaxInt64
type NominatingMode (line 338) | type NominatingMode
constant ModeNoop (line 341) | ModeNoop NominatingMode = iota
constant ModeOverride (line 342) | ModeOverride
type NominatingInfo (line 345) | type NominatingInfo struct
method Mode (line 350) | func (ni *NominatingInfo) Mode() NominatingMode {
type WaitingPod (line 358) | type WaitingPod interface
type PodInPreBind (line 375) | type PodInPreBind interface
type PreFilterResult (line 388) | type PreFilterResult struct
method AllNodes (line 394) | func (p *PreFilterResult) AllNodes() bool {
method Merge (line 398) | func (p *PreFilterResult) Merge(in *PreFilterResult) *PreFilterResult {
type PostFilterResult (line 418) | type PostFilterResult struct
type PreBindPreFlightResult (line 423) | type PreBindPreFlightResult struct
type Plugin (line 436) | type Plugin interface
type PreEnqueuePlugin (line 445) | type PreEnqueuePlugin interface
type LessFunc (line 452) | type LessFunc
type QueueSortPlugin (line 457) | type QueueSortPlugin interface
type EnqueueExtensions (line 480) | type EnqueueExtensions interface
type PreFilterExtensions (line 499) | type PreFilterExtensions interface
type PreFilterPlugin (line 511) | type PreFilterPlugin interface
type FilterPlugin (line 540) | type FilterPlugin interface
type PostFilterPlugin (line 569) | type PostFilterPlugin interface
type PreScorePlugin (line 596) | type PreScorePlugin interface
type ScoreExtensions (line 607) | type ScoreExtensions interface
type ScorePlugin (line 617) | type ScorePlugin interface
type ReservePlugin (line 634) | type ReservePlugin interface
type PreBindPlugin (line 650) | type PreBindPlugin interface
type PostBindPlugin (line 667) | type PostBindPlugin interface
type PermitPlugin (line 678) | type PermitPlugin interface
type BindPlugin (line 691) | type BindPlugin interface
type SignFragment (line 704) | type SignFragment struct
type PodSignature (line 729) | type PodSignature
type SignPlugin (line 738) | type SignPlugin interface
type GeneratePlacementsResult (line 756) | type GeneratePlacementsResult struct
type PlacementGeneratePlugin (line 765) | type PlacementGeneratePlugin interface
type PlacementScore (line 774) | type PlacementScore struct
type PlacementScoreExtensions (line 782) | type PlacementScoreExtensions interface
type PlacementScorePlugin (line 790) | type PlacementScorePlugin interface
type Handle (line 807) | type Handle interface
type Parallelizer (line 896) | type Parallelizer interface
type PodActivator (line 902) | type PodActivator interface
type PodNominator (line 912) | type PodNominator interface
type PluginsRunner (line 927) | type PluginsRunner interface
FILE: framework/interface_test.go
function TestStatus (line 32) | func TestStatus(t *testing.T) {
function TestPreFilterResultMerge (line 127) | func TestPreFilterResultMerge(t *testing.T) {
function TestIsStatusEqual (line 182) | func TestIsStatusEqual(t *testing.T) {
FILE: framework/listers.go
type NodeInfoLister (line 30) | type NodeInfoLister interface
type StorageInfoLister (line 42) | type StorageInfoLister interface
type SharedLister (line 49) | type SharedLister interface
type PodGroupStateLister (line 56) | type PodGroupStateLister interface
type CSINodeLister (line 61) | type CSINodeLister interface
type ResourceSliceLister (line 69) | type ResourceSliceLister interface
type DeviceClassLister (line 80) | type DeviceClassLister interface
type ResourceClaimTracker (line 94) | type ResourceClaimTracker interface
type DeviceClassResolver (line 134) | type DeviceClassResolver interface
type PodGroupLister (line 142) | type PodGroupLister interface
type SharedDRAManager (line 151) | type SharedDRAManager interface
type CSIManager (line 163) | type CSIManager interface
type PodGroupManager (line 168) | type PodGroupManager interface
type PodGroupState (line 174) | type PodGroupState interface
FILE: framework/signers.go
constant DynamicResourcesSignerName (line 34) | DynamicResourcesSignerName = "v1.Pod.Spec.DynamicResources"
constant ImageNamesSignerName (line 35) | ImageNamesSignerName = "v1.Pod.Spec.CanonicalImageNames()"
constant LabelsSignerName (line 36) | LabelsSignerName = "v1.Pod.Labels"
constant NodeNameSignerName (line 37) | NodeNameSignerName = "v1.Pod.Spec.NodeName"
constant NodeAffinitySignerName (line 38) | NodeAffinitySignerName = "v1.Pod.Spec.Affinity.NodeAffinity"
constant NodeSelectorSignerName (line 39) | NodeSelectorSignerName = "v1.Pod.Spec.Affinity.NodeSelector"
constant HostPortsSignerName (line 40) | HostPortsSignerName = "v1.Pod.Spec.HostPorts()"
constant ResourcesSignerName (line 41) | ResourcesSignerName = "v1.Pod.Spec.ContainerRequestsAndOverheads()"
constant SchedulerNameSignerName (line 42) | SchedulerNameSignerName = "v1.Pod.Spec.SchedulerName"
constant TolerationsSignerName (line 43) | TolerationsSignerName = "v1.Pod.Spec.Tolerations"
constant VolumesSignerName (line 44) | VolumesSignerName = "v1.Pod.Spec.Volumes.NonSyntheticSources()"
constant FeaturesSignerName (line 45) | FeaturesSignerName = "v1.Pod.Spec.RequiredFeatures()"
function HostPortsSigner (line 50) | func HostPortsSigner(pod *v1.Pod) any {
function NodeSelectorRequirementsSigner (line 67) | func NodeSelectorRequirementsSigner(reqs []v1.NodeSelectorRequirement) (...
type nodeSelTermSignResult (line 82) | type nodeSelTermSignResult struct
function NodeSelectorTermSigner (line 87) | func NodeSelectorTermSigner(t *v1.NodeSelectorTerm) (nodeSelTermSignResu...
type prefSchedTermSignResult (line 102) | type prefSchedTermSignResult struct
function PreferredSchedulingTermSigner (line 107) | func PreferredSchedulingTermSigner(terms []v1.PreferredSchedulingTerm) (...
function NodeSelectorTermsSigner (line 127) | func NodeSelectorTermsSigner(terms []v1.NodeSelectorTerm) ([]string, err...
type nodeAffinitySignerResult (line 145) | type nodeAffinitySignerResult struct
function NodeAffinitySigner (line 150) | func NodeAffinitySigner(pod *v1.Pod) (any, error) {
function TolerationsSigner (line 180) | func TolerationsSigner(pod *v1.Pod) any {
function VolumesSigner (line 192) | func VolumesSigner(pod *v1.Pod) any {
FILE: framework/signers_test.go
function TestHostPortsSigner (line 29) | func TestHostPortsSigner(t *testing.T) {
function TestTolerationsSigner (line 89) | func TestTolerationsSigner(t *testing.T) {
function TestVolumesSigner (line 142) | func TestVolumesSigner(t *testing.T) {
function TestNodeAffinitySigner (line 202) | func TestNodeAffinitySigner(t *testing.T) {
FILE: framework/types.go
type ActionType (line 34) | type ActionType
method String (line 84) | func (a ActionType) String() string {
constant Add (line 41) | Add ActionType = 1 << iota
constant Delete (line 42) | Delete
constant UpdateNodeAllocatable (line 49) | UpdateNodeAllocatable
constant UpdateNodeLabel (line 50) | UpdateNodeLabel
constant UpdateNodeTaint (line 52) | UpdateNodeTaint
constant UpdateNodeCondition (line 53) | UpdateNodeCondition
constant UpdateNodeAnnotation (line 54) | UpdateNodeAnnotation
constant UpdateNodeDeclaredFeature (line 56) | UpdateNodeDeclaredFeature
constant UpdatePodLabel (line 63) | UpdatePodLabel
constant UpdatePodScaleDown (line 65) | UpdatePodScaleDown
constant UpdatePodToleration (line 68) | UpdatePodToleration
constant UpdatePodSchedulingGatesEliminated (line 70) | UpdatePodSchedulingGatesEliminated
constant UpdatePodGeneratedResourceClaim (line 73) | UpdatePodGeneratedResourceClaim
constant All (line 75) | All ActionType = 1<<iota - 1
constant Update (line 78) | Update = UpdateNodeAllocatable | UpdateNodeLabel | UpdateNodeTaint | Upd...
constant None (line 81) | None ActionType = 0
type EventResource (line 123) | type EventResource
constant Pod (line 154) | Pod EventResource = "Pod"
constant AssignedPod (line 156) | AssignedPod EventResource = "AssignedPod"
constant UnscheduledPod (line 158) | UnscheduledPod EventResource = "UnscheduledPod"
constant TargetPod (line 160) | TargetPod EventResource = "TargetPod"
constant Node (line 162) | Node EventResource = "Node"
constant PersistentVolume (line 163) | PersistentVolume EventResource = "PersistentVolume"
constant PersistentVolumeClaim (line 164) | PersistentVolumeClaim EventResource = "PersistentVolumeClaim"
constant CSINode (line 165) | CSINode EventResource = "storage.k8s.io/CSINode"
constant CSIDriver (line 166) | CSIDriver EventResource = "storage.k8s.io/CSIDriver"
constant VolumeAttachment (line 167) | VolumeAttachment EventResource = "storage.k8s.io/VolumeAttachment"
constant CSIStorageCapacity (line 168) | CSIStorageCapacity EventResource = "storage.k8s.io/CSIStorageCapacity"
constant StorageClass (line 169) | StorageClass EventResource = "storage.k8s.io/StorageClass"
constant ResourceClaim (line 170) | ResourceClaim EventResource = "resource.k8s.io/ResourceClaim"
constant ResourceSlice (line 171) | ResourceSlice EventResource = "resource.k8s.io/ResourceSlice"
constant DeviceClass (line 172) | DeviceClass EventResource = "resource.k8s.io/DeviceClass"
constant PodGroup (line 173) | PodGroup EventResource = "scheduling.k8s.io/PodGroup"
constant WildCard (line 182) | WildCard EventResource = "*"
type ClusterEventWithHint (line 185) | type ClusterEventWithHint struct
type QueueingHintFn (line 206) | type QueueingHintFn
type QueueingHint (line 208) | type QueueingHint
method String (line 219) | func (s QueueingHint) String() string {
constant QueueSkip (line 213) | QueueSkip QueueingHint = iota
constant Queue (line 216) | Queue
type ClusterEvent (line 232) | type ClusterEvent struct
method Label (line 243) | func (ce ClusterEvent) Label() string {
type NodeInfo (line 252) | type NodeInfo interface
type QueuedPodInfo (line 305) | type QueuedPodInfo interface
type PodInfo (line 358) | type PodInfo interface
type PodResource (line 374) | type PodResource struct
type AffinityTerm (line 381) | type AffinityTerm struct
method Matches (line 389) | func (at *AffinityTerm) Matches(pod *v1.Pod, nsLabels labels.Set) bool {
type WeightedAffinityTerm (line 397) | type WeightedAffinityTerm struct
function GetAffinityTerms (line 404) | func GetAffinityTerms(pod *v1.Pod, v1Terms []v1.PodAffinityTerm) ([]Affi...
function newAffinityTerm (line 421) | func newAffinityTerm(pod *v1.Pod, term *v1.PodAffinityTerm) (*AffinityTe...
function getNamespacesFromPodAffinityTerm (line 438) | func getNamespacesFromPodAffinityTerm(pod *v1.Pod, podAffinityTerm *v1.P...
function GetPodAffinityTerms (line 449) | func GetPodAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffinityT...
function GetWeightedAffinityTerms (line 463) | func GetWeightedAffinityTerms(pod *v1.Pod, v1Terms []v1.WeightedPodAffin...
function GetPodAntiAffinityTerms (line 481) | func GetPodAntiAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffin...
type Resource (line 495) | type Resource interface
type ImageStateSummary (line 509) | type ImageStateSummary struct
method Snapshot (line 521) | func (iss *ImageStateSummary) Snapshot() *ImageStateSummary {
constant DefaultBindAllHostIP (line 529) | DefaultBindAllHostIP = "0.0.0.0"
type ProtocolPort (line 532) | type ProtocolPort struct
function NewProtocolPort (line 538) | func NewProtocolPort(protocol string, port int32) *ProtocolPort {
type HostPortInfo (line 552) | type HostPortInfo
method Add (line 555) | func (h HostPortInfo) Add(ip, protocol string, port int32) {
method Remove (line 574) | func (h HostPortInfo) Remove(ip, protocol string, port int32) {
method Len (line 591) | func (h HostPortInfo) Len() int {
method CheckConflict (line 601) | func (h HostPortInfo) CheckConflict(ip, protocol string, port int32) b...
method sanitize (line 633) | func (h HostPortInfo) sanitize(ip, protocol *string) {
type PodGroupInfo (line 644) | type PodGroupInfo interface
type Placement (line 659) | type Placement struct
type ProposedAssignment (line 670) | type ProposedAssignment interface
type PodGroupAssignments (line 679) | type PodGroupAssignments struct
type NodeAllocatableDRAClaimState (line 688) | type NodeAllocatableDRAClaimState struct
method Snapshot (line 694) | func (s *NodeAllocatableDRAClaimState) Snapshot() *NodeAllocatableDRAC...
FILE: framework/types_test.go
type hostPortInfoParam (line 29) | type hostPortInfoParam struct
function TestHostPortInfo_AddRemove (line 34) | func TestHostPortInfo_AddRemove(t *testing.T) {
function TestHostPortInfo_Check (line 141) | func TestHostPortInfo_Check(t *testing.T) {
function TestGetNamespacesFromPodAffinityTerm (line 243) | func TestGetNamespacesFromPodAffinityTerm(t *testing.T) {
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (261K chars).
[
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 149,
"preview": "Sorry, we do not accept changes directly against this repository. Please see\nCONTRIBUTING.md for information on where an"
},
{
"path": "CONTRIBUTING.md",
"chars": 750,
"preview": "# Contributing guidelines\n\nDo not open pull requests directly against this repository, they will be ignored. Instead, pl"
},
{
"path": "LICENSE",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "OWNERS",
"chars": 190,
"preview": "# See the OWNERS docs at https://go.k8s.io/owners\n\napprovers:\n - sig-scheduling-maintainers\n - sttts\n - luxas\nreviewe"
},
{
"path": "README.md",
"chars": 1281,
"preview": "> ⚠️ **This is an automatically published [staged repository](https://git.k8s.io/kubernetes/staging#external-repository-"
},
{
"path": "SECURITY_CONTACTS",
"chars": 563,
"preview": "# Defined below are the security contacts for this repo.\n#\n# They are the contact point for the Product Security Committ"
},
{
"path": "code-of-conduct.md",
"chars": 148,
"preview": "# Kubernetes Community Code of Conduct\n\nPlease refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/co"
},
{
"path": "config/OWNERS",
"chars": 256,
"preview": "# See the OWNERS docs at https://go.k8s.io/owners\n\n# Disable inheritance as this is an api owners file\noptions:\n no_par"
},
{
"path": "config/v1/doc.go",
"chars": 742,
"preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "config/v1/register.go",
"chars": 1641,
"preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "config/v1/types.go",
"chars": 23198,
"preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "config/v1/types_pluginargs.go",
"chars": 9708,
"preview": "/*\nCopyright 2022 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "config/v1/zz_generated.deepcopy.go",
"chars": 19108,
"preview": "//go:build !ignore_autogenerated\n// +build !ignore_autogenerated\n\n/*\nCopyright The Kubernetes Authors.\n\nLicensed under t"
},
{
"path": "config/v1/zz_generated.model_name.go",
"chars": 4612,
"preview": "//go:build !ignore_autogenerated\n// +build !ignore_autogenerated\n\n/*\nCopyright The Kubernetes Authors.\n\nLicensed under t"
},
{
"path": "doc.go",
"chars": 593,
"preview": "/*\nCopyright 2021 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "extender/OWNERS",
"chars": 261,
"preview": "# See the OWNERS docs at https://go.k8s.io/owners\n\n# Disable inheritance as this is an api owners file\noptions:\n no_par"
},
{
"path": "extender/v1/doc.go",
"chars": 658,
"preview": "/*\nCopyright 2019 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "extender/v1/types.go",
"chars": 4390,
"preview": "/*\nCopyright 2019 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "extender/v1/types_test.go",
"chars": 5135,
"preview": "/*\nCopyright 2020 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "extender/v1/zz_generated.deepcopy.go",
"chars": 9307,
"preview": "//go:build !ignore_autogenerated\n// +build !ignore_autogenerated\n\n/*\nCopyright The Kubernetes Authors.\n\nLicensed under t"
},
{
"path": "framework/api_calls.go",
"chars": 2586,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/api_dispatcher.go",
"chars": 5469,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/cycle_state.go",
"chars": 6546,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/extender.go",
"chars": 3405,
"preview": "/*\nCopyright 2020 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/interface.go",
"chars": 43402,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/interface_test.go",
"chars": 7522,
"preview": "/*\nCopyright 2019 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/listers.go",
"chars": 10570,
"preview": "/*\nCopyright 2019 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/signers.go",
"chars": 5642,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/signers_test.go",
"chars": 8663,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/types.go",
"chars": 29019,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "framework/types_test.go",
"chars": 7064,
"preview": "/*\nCopyright 2025 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "go.mod",
"chars": 3937,
"preview": "// This is a generated file. Do not edit directly.\n\nmodule k8s.io/kube-scheduler\n\ngo 1.26.0\n\ngodebug default=go1.26\n\nreq"
},
{
"path": "go.sum",
"chars": 16892,
"preview": "cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=\ncel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ"
}
]
About this extraction
This page contains the full source code of the kubernetes/kube-scheduler GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (239.0 KB), approximately 66.4k tokens, and a symbol index with 368 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.