Compare commits
65 Commits
kubernetes
...
master
Author | SHA1 | Date |
---|---|---|
|
b951e7b647 | |
|
8180eb29f0 | |
|
b7d91c8e34 | |
|
c3447f03d0 | |
|
bf6c6b859a | |
|
cf6c0db284 | |
|
e1eb80f820 | |
|
95b15852f6 | |
|
ebdc23a6fd | |
|
f502df2683 | |
|
34108578d3 | |
|
f86d55a8f9 | |
|
e5f83c4ff2 | |
|
52d0691604 | |
|
9fd9552640 | |
|
f145b2e12d | |
|
c1e58612a9 | |
|
d28eb7e196 | |
|
90476f839a | |
|
aea0dbb576 | |
|
612a394639 | |
|
835043145f | |
|
deb0ae0c26 | |
|
5fbfce88d1 | |
|
8bcd68e2f6 | |
|
b735441737 | |
|
77d19a8b0f | |
|
7c8c18b82f | |
|
1af5fcf12f | |
|
824faf12a5 | |
|
70e59a10f8 | |
|
abb3e174a8 | |
|
ecb4d2e7ca | |
|
2157dec6c7 | |
|
ac29f412fb | |
|
f65a8bcf0c | |
|
32ba459578 | |
|
6daf946169 | |
|
d64e7790c3 | |
|
fe5b8efed2 | |
|
3b41df4c1f | |
|
ebc40342fa | |
|
b015230743 | |
|
8a23cdb44d | |
|
33df0de86d | |
|
5ec275beed | |
|
5f7bf9aed8 | |
|
cc44b0d478 | |
|
caa370896c | |
|
34076283f2 | |
|
fb9033cab2 | |
|
5a2cc3888e | |
|
b112986049 | |
|
309b78e742 | |
|
916cc08b10 | |
|
b838f30e82 | |
|
b0cf8348cc | |
|
448e5deba2 | |
|
901d4e7246 | |
|
8570145cb0 | |
|
c323b9dee8 | |
|
daa154f652 | |
|
ba21bb45ec | |
|
184327d628 | |
|
32448588e8 |
2
OWNERS
2
OWNERS
|
@ -8,3 +8,5 @@ reviewers:
|
|||
- sig-scheduling
|
||||
- luxas
|
||||
- sttts
|
||||
labels:
|
||||
- sig/scheduling
|
||||
|
|
|
@ -5,9 +5,8 @@ options:
|
|||
no_parent_owners: true
|
||||
approvers:
|
||||
- api-approvers
|
||||
- sig-scheduling-api-approvers
|
||||
reviewers:
|
||||
- api-reviewers
|
||||
- sig-scheduling-api-reviewers
|
||||
- sig-scheduling-api-approvers
|
||||
labels:
|
||||
- kind/api-change
|
||||
|
|
|
@ -159,17 +159,17 @@ type VolumeBindingArgs struct {
|
|||
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 statically provisioned
|
||||
// PVs. The utilization is calculated by dividing the total requested
|
||||
// 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) 0 for 0 utilization
|
||||
// 2) 10 for 100 utilization
|
||||
// 1) 10 for 0 utilization
|
||||
// 2) 0 for 100 utilization
|
||||
// All points must be sorted in increasing order by utilization.
|
||||
// +featureGate=VolumeCapacityPriority
|
||||
// +featureGate=StorageCapacityScoring
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
Shape []UtilizationShapePoint `json:"shape,omitempty"`
|
||||
|
|
|
@ -52,7 +52,7 @@ func TestCompatibility(t *testing.T) {
|
|||
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","creationTimestamp":null},"spec":{"containers":null},"status":{}},"NodeNameToVictims":{"foo":{"Pods":[{"metadata":{"name":"podname","creationTimestamp":null},"spec":{"containers":null},"status":{}}],"NumPDBViolations":1}},"NodeNameToMetaVictims":{"foo":{"Pods":[{"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{},
|
||||
|
@ -61,7 +61,7 @@ func TestCompatibility(t *testing.T) {
|
|||
Nodes: &corev1.NodeList{Items: []corev1.Node{{ObjectMeta: metav1.ObjectMeta{Name: "nodename"}}}},
|
||||
NodeNames: &[]string{"node1"},
|
||||
},
|
||||
expectJSON: `{"Pod":{"metadata":{"name":"podname","creationTimestamp":null},"spec":{"containers":null},"status":{}},"Nodes":{"metadata":{},"items":[{"metadata":{"name":"nodename","creationTimestamp":null},"spec":{},"status":{"daemonEndpoints":{"kubeletEndpoint":{"Port":0}},"nodeInfo":{"machineID":"","systemUUID":"","bootID":"","kernelVersion":"","osImage":"","containerRuntimeVersion":"","kubeletVersion":"","kubeProxyVersion":"","operatingSystem":"","architecture":""}}}]},"NodeNames":["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{},
|
||||
|
@ -72,7 +72,7 @@ func TestCompatibility(t *testing.T) {
|
|||
FailedAndUnresolvableNodes: FailedNodesMap{"baz": "qux"},
|
||||
Error: "myerror",
|
||||
},
|
||||
expectJSON: `{"Nodes":{"metadata":{},"items":[{"metadata":{"name":"nodename","creationTimestamp":null},"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"}`,
|
||||
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{},
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
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])
|
||||
// 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
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
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 (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-cmp/cmp" //nolint:depguard
|
||||
"github.com/google/go-cmp/cmp/cmpopts" //nolint:depguard
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
"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
|
||||
|
||||
// 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 | 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 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.
|
||||
Pod EventResource = "Pod"
|
||||
|
||||
// A note about NodeAdd event and UpdateNodeTaint event:
|
||||
// When QHint is disabled, NodeAdd often isn't worked expectedly because of the internal feature called preCheck.
|
||||
// It's definitely not something expected for plugin developers,
|
||||
// and registering UpdateNodeTaint event is the only mitigation for now.
|
||||
// So, kube-scheduler registers UpdateNodeTaint event for plugins that has NodeAdded event, but don't have UpdateNodeTaint event.
|
||||
// It has a bad impact for the requeuing efficiency though, a lot better than some Pods being stuck in the
|
||||
// unschedulable pod pool.
|
||||
// This problematic preCheck feature is disabled when QHint is enabled,
|
||||
// and eventually will be removed along with QHint graduation.
|
||||
// See: https://github.com/kubernetes/kubernetes/issues/110175
|
||||
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"
|
||||
|
||||
// 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 ClusterEventWithHint struct {
|
||||
Event ClusterEvent
|
||||
// QueueingHintFn is executed for the Pod rejected by this plugin when the above Event happens,
|
||||
// and filters out events to reduce useless retry of Pod's scheduling.
|
||||
// It's an optional field. If not set,
|
||||
// the scheduling of Pods will be always retried with backoff when this Event happens.
|
||||
// (the same as Queue)
|
||||
QueueingHintFn QueueingHintFn
|
||||
}
|
||||
|
||||
// QueueingHintFn returns a hint that signals whether the event can make a Pod,
|
||||
// which was rejected by this plugin in the past scheduling cycle, schedulable or not.
|
||||
// It's called before a Pod gets moved from unschedulableQ to backoffQ or activeQ.
|
||||
// If it returns an error, we'll take the returned QueueingHint as `Queue` at the caller whatever we returned here so that
|
||||
// we can prevent the Pod from being stuck in the unschedulable pod pool.
|
||||
//
|
||||
// - `pod`: the Pod to be enqueued, which is rejected by this plugin in the past.
|
||||
// - `oldObj` `newObj`: the object involved in that event.
|
||||
// - For example, the given event is "Node deleted", the `oldObj` will be that deleted Node.
|
||||
// - `oldObj` is nil if the event is add event.
|
||||
// - `newObj` is nil if the event is delete event.
|
||||
type QueueingHintFn func(logger klog.Logger, pod *v1.Pod, oldObj, newObj interface{}) (QueueingHint, error)
|
||||
|
||||
type QueueingHint int
|
||||
|
||||
const (
|
||||
// QueueSkip implies that the cluster event has no impact on
|
||||
// scheduling of the pod.
|
||||
QueueSkip QueueingHint = iota
|
||||
|
||||
// Queue implies that the Pod may be schedulable by the event.
|
||||
Queue
|
||||
)
|
||||
|
||||
func (s QueueingHint) String() string {
|
||||
switch s {
|
||||
case QueueSkip:
|
||||
return "QueueSkip"
|
||||
case Queue:
|
||||
return "Queue"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ClusterEvent abstracts how a system resource's state gets changed.
|
||||
// Resource represents the standard API resources such as Pod, Node, etc.
|
||||
// ActionType denotes the specific change such as Add, Update or Delete.
|
||||
type ClusterEvent struct {
|
||||
Resource EventResource
|
||||
ActionType ActionType
|
||||
|
||||
// CustomLabel describes this cluster event.
|
||||
// It's an optional field to control Label(), which is used in logging and metrics.
|
||||
// Normally, it's not necessary to set this field; only used for special events like UnschedulableTimeout.
|
||||
CustomLabel string
|
||||
}
|
||||
|
||||
// Label is used for logging and metrics.
|
||||
func (ce ClusterEvent) Label() string {
|
||||
if ce.CustomLabel != "" {
|
||||
return ce.CustomLabel
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v%v", ce.Resource, ce.ActionType)
|
||||
}
|
37
go.mod
37
go.mod
|
@ -2,37 +2,34 @@
|
|||
|
||||
module k8s.io/kube-scheduler
|
||||
|
||||
go 1.23.0
|
||||
go 1.24.0
|
||||
|
||||
godebug default=go1.23
|
||||
|
||||
godebug winsymlink=0
|
||||
godebug default=go1.24
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.6.0
|
||||
k8s.io/api v0.0.0-20250211114750-4629116ef3ab
|
||||
k8s.io/apimachinery v0.0.0-20250211114440-46c230ea8d65
|
||||
k8s.io/component-base v0.0.0-20250206205508-05a58ccfe08d
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
k8s.io/api v0.0.0-20250703010437-9ca4bf8538e0
|
||||
k8s.io/apimachinery v0.0.0-20250703010150-b86b632271cf
|
||||
k8s.io/component-base v0.0.0-20250703012258-22a26817cb48
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
sigs.k8s.io/yaml v1.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
)
|
||||
|
||||
replace k8s.io/client-go => k8s.io/client-go v0.0.0-20250211115216-8683d2da3be9
|
||||
|
|
67
go.sum
67
go.sum
|
@ -2,18 +2,16 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
|
@ -25,22 +23,27 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -50,8 +53,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -60,8 +63,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
|
@ -77,19 +80,23 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.0.0-20250211114750-4629116ef3ab h1:bBsQSUPkp7s90RsTrNPfVKWOeX1jqXxYDgnoc1bjs8Y=
|
||||
k8s.io/api v0.0.0-20250211114750-4629116ef3ab/go.mod h1:9+9XPWTbyV1YwAc5YizzbMHBe4gp7BY2PPZ3+DxXjxw=
|
||||
k8s.io/apimachinery v0.0.0-20250211114440-46c230ea8d65 h1:RADrjyqn52TmFg79piA2+zmjMJYBRxeR65d4YnqNhQE=
|
||||
k8s.io/apimachinery v0.0.0-20250211114440-46c230ea8d65/go.mod h1:pvurfgWU15pkR11HFlMI9tdxY59XU+Wzo22Rx2iSD+g=
|
||||
k8s.io/component-base v0.0.0-20250206205508-05a58ccfe08d h1:ucGaCLCdQDECgSOvEVYGRNTkUPamA+Of3SfwVWovZUE=
|
||||
k8s.io/component-base v0.0.0-20250206205508-05a58ccfe08d/go.mod h1:m0Zr1J4qm4/+KLOEn4YxoHUVMkKFWyrm1TRORDgE9sY=
|
||||
k8s.io/api v0.0.0-20250703010437-9ca4bf8538e0 h1:iS/S3wfNTxgeC+HNybNhVSLt7y9E1XDkUlzPRXd1c6U=
|
||||
k8s.io/api v0.0.0-20250703010437-9ca4bf8538e0/go.mod h1:2FUvtol5X8X7D4iFOQdd1W2Q6BoMhvE/DSSRzyWQ2yU=
|
||||
k8s.io/apimachinery v0.0.0-20250703010150-b86b632271cf h1:5z7lkImscG/qu7KON0TOD0aSsycwXXiWue9mrjDasu4=
|
||||
k8s.io/apimachinery v0.0.0-20250703010150-b86b632271cf/go.mod h1:Th679JJyaVRDNFk3vKPKY43ypziDeoGnbEiEgBCz8s4=
|
||||
k8s.io/component-base v0.0.0-20250703012258-22a26817cb48 h1:bgA0NLAleN9Rl3z3oq1qc1pxD3hJRPTIVMqWPCZpMXg=
|
||||
k8s.io/component-base v0.0.0-20250703012258-22a26817cb48/go.mod h1:t81Uof8wYmumUbjkD/V/shpkjxjPcK+dYKWuJGVI1Lw=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
|
Loading…
Reference in New Issue