diff --git a/pkg/controllers/status/cluster_status_controller.go b/pkg/controllers/status/cluster_status_controller.go index e17142ab5..550b53ff7 100644 --- a/pkg/controllers/status/cluster_status_controller.go +++ b/pkg/controllers/status/cluster_status_controller.go @@ -10,7 +10,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" @@ -497,38 +496,24 @@ func getClusterAllocatable(nodeList []*corev1.Node) (allocatable corev1.Resource } func getAllocatingResource(podList []*corev1.Pod) corev1.ResourceList { - var requestCPU, requestMem int64 + allocating := util.EmptyResource() for _, pod := range podList { if len(pod.Spec.NodeName) == 0 { - podRes := util.CalculateRequestResource(pod) - requestCPU += podRes.MilliCPU - requestMem += podRes.Memory + allocating.AddPodRequest(pod) } } - allocating := corev1.ResourceList{ - corev1.ResourceCPU: *resource.NewMilliQuantity(requestCPU, resource.DecimalSI), - corev1.ResourceMemory: *resource.NewQuantity(requestMem, resource.BinarySI), - } - - return allocating + return allocating.ResourceList() } func getAllocatedResource(podList []*corev1.Pod) corev1.ResourceList { - var requestCPU, requestMem int64 + allocated := util.EmptyResource() for _, pod := range podList { // When the phase of a pod is Succeeded or Failed, kube-scheduler would not consider its resource occupation. if len(pod.Spec.NodeName) != 0 && pod.Status.Phase != corev1.PodSucceeded && pod.Status.Phase != corev1.PodFailed { - podRes := util.CalculateRequestResource(pod) - requestCPU += podRes.MilliCPU - requestMem += podRes.Memory + allocated.AddPodRequest(pod) } } - allocated := corev1.ResourceList{ - corev1.ResourceCPU: *resource.NewMilliQuantity(requestCPU, resource.DecimalSI), - corev1.ResourceMemory: *resource.NewQuantity(requestMem, resource.BinarySI), - } - - return allocated + return allocated.ResourceList() } diff --git a/pkg/util/resource.go b/pkg/util/resource.go index 6503e232f..17acddcb6 100644 --- a/pkg/util/resource.go +++ b/pkg/util/resource.go @@ -1,11 +1,19 @@ package util -import corev1 "k8s.io/api/core/v1" +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + schedutil "k8s.io/kubernetes/pkg/scheduler/util" +) // Resource is a collection of compute resource. type Resource struct { MilliCPU int64 Memory int64 + + // ScalarResources + ScalarResources map[corev1.ResourceName]int64 } // EmptyResource creates a empty resource object and returns. @@ -26,7 +34,9 @@ func (r *Resource) Add(rl corev1.ResourceList) { case corev1.ResourceMemory: r.Memory += rQuant.Value() default: - continue + if schedutil.IsScalarResourceName(rName) { + r.AddScalar(rName, rQuant.Value()) + } } } } @@ -48,32 +58,55 @@ func (r *Resource) SetMaxResource(rl corev1.ResourceList) { r.Memory = mem } default: - continue + if schedutil.IsScalarResourceName(rName) { + if value := rQuant.Value(); value > r.ScalarResources[rName] { + r.SetScalar(rName, value) + } + } } } } -// CalculateRequestResourceWithoutInitContainers returns Pod's resource request, it does not contain -// init containers' resource request. -func CalculateRequestResourceWithoutInitContainers(pod *corev1.Pod) *Resource { - result := EmptyResource() - for _, container := range pod.Spec.Containers { - result.Add(container.Resources.Requests) - } +// AddScalar adds a resource by a scalar value of this resource. +func (r *Resource) AddScalar(name corev1.ResourceName, quantity int64) { + r.SetScalar(name, r.ScalarResources[name]+quantity) +} +// SetScalar sets a resource by a scalar value of this resource. +func (r *Resource) SetScalar(name corev1.ResourceName, quantity int64) { + // Lazily allocate scalar resource map. + if r.ScalarResources == nil { + r.ScalarResources = map[corev1.ResourceName]int64{} + } + r.ScalarResources[name] = quantity +} + +// ResourceList returns a resource list of this resource. +func (r *Resource) ResourceList() corev1.ResourceList { + result := corev1.ResourceList{ + corev1.ResourceCPU: *resource.NewMilliQuantity(r.MilliCPU, resource.DecimalSI), + corev1.ResourceMemory: *resource.NewQuantity(r.Memory, resource.BinarySI), + } + for rName, rQuant := range r.ScalarResources { + if v1helper.IsHugePageResourceName(rName) { + result[rName] = *resource.NewQuantity(rQuant, resource.BinarySI) + } else { + result[rName] = *resource.NewQuantity(rQuant, resource.DecimalSI) + } + } return result } -// CalculateRequestResource calculates the resource required for pod, that is the higher of: +// AddPodRequest add the effective request resource of a pod to the origin resource. +// The Pod's effective request is the higher of: // - the sum of all app containers(spec.Containers) request for a resource. // - the effective init containers(spec.InitContainers) request for a resource. // The effective init containers request is the highest request on all init containers. -func CalculateRequestResource(pod *corev1.Pod) *Resource { - result := CalculateRequestResourceWithoutInitContainers(pod) - - for _, container := range pod.Spec.InitContainers { - result.SetMaxResource(container.Resources.Requests) +func (r *Resource) AddPodRequest(pod *corev1.Pod) { + for _, container := range pod.Spec.Containers { + r.Add(container.Resources.Requests) + } + for _, container := range pod.Spec.InitContainers { + r.SetMaxResource(container.Resources.Requests) } - - return result } diff --git a/vendor/k8s.io/component-helpers/scheduling/corev1/doc.go b/vendor/k8s.io/component-helpers/scheduling/corev1/doc.go new file mode 100644 index 000000000..c6cf8132a --- /dev/null +++ b/vendor/k8s.io/component-helpers/scheduling/corev1/doc.go @@ -0,0 +1,23 @@ +/* +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 corev1 defines functions which should satisfy one of the following: +// +// - Be used by more than one core component (kube-scheduler, kubelet, kube-apiserver, etc.) +// - Be used by a core component and another kubernetes project (cluster-autoscaler, descheduler) +// +// And be a scheduling feature. +package corev1 // import "k8s.io/component-helpers/scheduling/corev1" diff --git a/vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go b/vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go new file mode 100644 index 000000000..57f916c26 --- /dev/null +++ b/vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go @@ -0,0 +1,45 @@ +/* +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 corev1 + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/component-helpers/scheduling/corev1/nodeaffinity" +) + +// PodPriority returns priority of the given pod. +func PodPriority(pod *v1.Pod) int32 { + if pod.Spec.Priority != nil { + return *pod.Spec.Priority + } + // When priority of a running pod is nil, it means it was created at a time + // that there was no global default priority class and the priority class + // name of the pod was empty. So, we resolve to the static default priority. + return 0 +} + +// MatchNodeSelectorTerms checks whether the node labels and fields match node selector terms in ORed; +// nil or empty term matches no objects. +func MatchNodeSelectorTerms( + node *v1.Node, + nodeSelector *v1.NodeSelector, +) (bool, error) { + if node == nil { + return false, nil + } + return nodeaffinity.NewLazyErrorNodeSelector(nodeSelector).Match(node) +} diff --git a/vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go b/vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go new file mode 100644 index 000000000..efca431e6 --- /dev/null +++ b/vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go @@ -0,0 +1,262 @@ +/* +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 nodeaffinity + +import ( + "fmt" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/util/errors" +) + +// NodeSelector is a runtime representation of v1.NodeSelector. +type NodeSelector struct { + lazy LazyErrorNodeSelector +} + +// LazyErrorNodeSelector is a runtime representation of v1.NodeSelector that +// only reports parse errors when no terms match. +type LazyErrorNodeSelector struct { + terms []nodeSelectorTerm +} + +// NewNodeSelector returns a NodeSelector or all parsing errors found. +func NewNodeSelector(ns *v1.NodeSelector) (*NodeSelector, error) { + lazy := NewLazyErrorNodeSelector(ns) + var errs []error + for _, term := range lazy.terms { + if term.parseErr != nil { + errs = append(errs, term.parseErr) + } + } + if len(errs) != 0 { + return nil, errors.NewAggregate(errs) + } + return &NodeSelector{lazy: *lazy}, nil +} + +// NewLazyErrorNodeSelector creates a NodeSelector that only reports parse +// errors when no terms match. +func NewLazyErrorNodeSelector(ns *v1.NodeSelector) *LazyErrorNodeSelector { + parsedTerms := make([]nodeSelectorTerm, 0, len(ns.NodeSelectorTerms)) + for _, term := range ns.NodeSelectorTerms { + // nil or empty term selects no objects + if isEmptyNodeSelectorTerm(&term) { + continue + } + parsedTerms = append(parsedTerms, newNodeSelectorTerm(&term)) + } + return &LazyErrorNodeSelector{ + terms: parsedTerms, + } +} + +// Match checks whether the node labels and fields match the selector terms, ORed; +// nil or empty term matches no objects. +func (ns *NodeSelector) Match(node *v1.Node) bool { + // parse errors are reported in NewNodeSelector. + match, _ := ns.lazy.Match(node) + return match +} + +// Match checks whether the node labels and fields match the selector terms, ORed; +// nil or empty term matches no objects. +// Parse errors are only returned if no terms matched. +func (ns *LazyErrorNodeSelector) Match(node *v1.Node) (bool, error) { + if node == nil { + return false, nil + } + nodeLabels := labels.Set(node.Labels) + nodeFields := extractNodeFields(node) + + var errs []error + for _, term := range ns.terms { + match, err := term.match(nodeLabels, nodeFields) + if err != nil { + errs = append(errs, term.parseErr) + continue + } + if match { + return true, nil + } + } + return false, errors.NewAggregate(errs) +} + +// PreferredSchedulingTerms is a runtime representation of []v1.PreferredSchedulingTerms. +type PreferredSchedulingTerms struct { + terms []preferredSchedulingTerm +} + +// NewPreferredSchedulingTerms returns a PreferredSchedulingTerms or all the parsing errors found. +// If a v1.PreferredSchedulingTerm has a 0 weight, its parsing is skipped. +func NewPreferredSchedulingTerms(terms []v1.PreferredSchedulingTerm) (*PreferredSchedulingTerms, error) { + var errs []error + parsedTerms := make([]preferredSchedulingTerm, 0, len(terms)) + for _, term := range terms { + if term.Weight == 0 || isEmptyNodeSelectorTerm(&term.Preference) { + continue + } + parsedTerm := preferredSchedulingTerm{ + nodeSelectorTerm: newNodeSelectorTerm(&term.Preference), + weight: int(term.Weight), + } + if parsedTerm.parseErr != nil { + errs = append(errs, parsedTerm.parseErr) + } else { + parsedTerms = append(parsedTerms, parsedTerm) + } + } + if len(errs) != 0 { + return nil, errors.NewAggregate(errs) + } + return &PreferredSchedulingTerms{terms: parsedTerms}, nil +} + +// Score returns a score for a Node: the sum of the weights of the terms that +// match the Node. +func (t *PreferredSchedulingTerms) Score(node *v1.Node) int64 { + var score int64 + nodeLabels := labels.Set(node.Labels) + nodeFields := extractNodeFields(node) + for _, term := range t.terms { + // parse errors are reported in NewPreferredSchedulingTerms. + if ok, _ := term.match(nodeLabels, nodeFields); ok { + score += int64(term.weight) + } + } + return score +} + +func isEmptyNodeSelectorTerm(term *v1.NodeSelectorTerm) bool { + return len(term.MatchExpressions) == 0 && len(term.MatchFields) == 0 +} + +func extractNodeFields(n *v1.Node) fields.Set { + f := make(fields.Set) + if len(n.Name) > 0 { + f["metadata.name"] = n.Name + } + return f +} + +type nodeSelectorTerm struct { + matchLabels labels.Selector + matchFields fields.Selector + parseErr error +} + +func newNodeSelectorTerm(term *v1.NodeSelectorTerm) nodeSelectorTerm { + var parsedTerm nodeSelectorTerm + if len(term.MatchExpressions) != 0 { + parsedTerm.matchLabels, parsedTerm.parseErr = nodeSelectorRequirementsAsSelector(term.MatchExpressions) + if parsedTerm.parseErr != nil { + return parsedTerm + } + } + if len(term.MatchFields) != 0 { + parsedTerm.matchFields, parsedTerm.parseErr = nodeSelectorRequirementsAsFieldSelector(term.MatchFields) + } + return parsedTerm +} + +func (t *nodeSelectorTerm) match(nodeLabels labels.Set, nodeFields fields.Set) (bool, error) { + if t.parseErr != nil { + return false, t.parseErr + } + if t.matchLabels != nil && !t.matchLabels.Matches(nodeLabels) { + return false, nil + } + if t.matchFields != nil && len(nodeFields) > 0 && !t.matchFields.Matches(nodeFields) { + return false, nil + } + return true, nil +} + +// nodeSelectorRequirementsAsSelector converts the []NodeSelectorRequirement api type into a struct that implements +// labels.Selector. +func nodeSelectorRequirementsAsSelector(nsm []v1.NodeSelectorRequirement) (labels.Selector, error) { + if len(nsm) == 0 { + return labels.Nothing(), nil + } + selector := labels.NewSelector() + for _, expr := range nsm { + var op selection.Operator + switch expr.Operator { + case v1.NodeSelectorOpIn: + op = selection.In + case v1.NodeSelectorOpNotIn: + op = selection.NotIn + case v1.NodeSelectorOpExists: + op = selection.Exists + case v1.NodeSelectorOpDoesNotExist: + op = selection.DoesNotExist + case v1.NodeSelectorOpGt: + op = selection.GreaterThan + case v1.NodeSelectorOpLt: + op = selection.LessThan + default: + return nil, fmt.Errorf("%q is not a valid node selector operator", expr.Operator) + } + r, err := labels.NewRequirement(expr.Key, op, expr.Values) + if err != nil { + return nil, err + } + selector = selector.Add(*r) + } + return selector, nil +} + +// nodeSelectorRequirementsAsFieldSelector converts the []NodeSelectorRequirement core type into a struct that implements +// fields.Selector. +func nodeSelectorRequirementsAsFieldSelector(nsr []v1.NodeSelectorRequirement) (fields.Selector, error) { + if len(nsr) == 0 { + return fields.Nothing(), nil + } + + var selectors []fields.Selector + for _, expr := range nsr { + switch expr.Operator { + case v1.NodeSelectorOpIn: + if len(expr.Values) != 1 { + return nil, fmt.Errorf("unexpected number of value (%d) for node field selector operator %q", + len(expr.Values), expr.Operator) + } + selectors = append(selectors, fields.OneTermEqualSelector(expr.Key, expr.Values[0])) + + case v1.NodeSelectorOpNotIn: + if len(expr.Values) != 1 { + return nil, fmt.Errorf("unexpected number of value (%d) for node field selector operator %q", + len(expr.Values), expr.Operator) + } + selectors = append(selectors, fields.OneTermNotEqualSelector(expr.Key, expr.Values[0])) + + default: + return nil, fmt.Errorf("%q is not a valid node field selector operator", expr.Operator) + } + } + + return fields.AndSelectors(selectors...), nil +} + +type preferredSchedulingTerm struct { + nodeSelectorTerm + weight int +} diff --git a/vendor/k8s.io/kube-scheduler/LICENSE b/vendor/k8s.io/kube-scheduler/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/LICENSE @@ -0,0 +1,202 @@ + + 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. diff --git a/vendor/k8s.io/kube-scheduler/extender/v1/doc.go b/vendor/k8s.io/kube-scheduler/extender/v1/doc.go new file mode 100644 index 000000000..202572083 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/extender/v1/doc.go @@ -0,0 +1,20 @@ +/* +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 // import "k8s.io/kube-scheduler/extender/v1" diff --git a/vendor/k8s.io/kube-scheduler/extender/v1/types.go b/vendor/k8s.io/kube-scheduler/extender/v1/types.go new file mode 100644 index 000000000..4557c8fd0 --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/extender/v1/types.go @@ -0,0 +1,126 @@ +/* +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 + // 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 diff --git a/vendor/k8s.io/kube-scheduler/extender/v1/zz_generated.deepcopy.go b/vendor/k8s.io/kube-scheduler/extender/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..e568fe00a --- /dev/null +++ b/vendor/k8s.io/kube-scheduler/extender/v1/zz_generated.deepcopy.go @@ -0,0 +1,339 @@ +// +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 + } + } + 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 +} diff --git a/vendor/k8s.io/kubernetes/pkg/features/BUILD b/vendor/k8s.io/kubernetes/pkg/features/BUILD new file mode 100644 index 000000000..1f1b927d7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/features/BUILD @@ -0,0 +1,31 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = ["kube_features.go"], + importpath = "k8s.io/kubernetes/pkg/features", + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/features:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/component-base/featuregate:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/kubernetes/pkg/features/OWNERS b/vendor/k8s.io/kubernetes/pkg/features/OWNERS new file mode 100644 index 000000000..05b08249a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/features/OWNERS @@ -0,0 +1,4 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: +- feature-approvers diff --git a/vendor/k8s.io/kubernetes/pkg/features/kube_features.go b/vendor/k8s.io/kubernetes/pkg/features/kube_features.go new file mode 100644 index 000000000..575a0a2e1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/features/kube_features.go @@ -0,0 +1,848 @@ +/* +Copyright 2017 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 features + +import ( + "k8s.io/apimachinery/pkg/util/runtime" + genericfeatures "k8s.io/apiserver/pkg/features" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/component-base/featuregate" +) + +const ( + // Every feature gate should add method here following this template: + // + // // owner: @username + // // alpha: v1.X + // MyFeature featuregate.Feature = "MyFeature" + + // owner: @tallclair + // beta: v1.4 + AppArmor featuregate.Feature = "AppArmor" + + // owner: @mtaufen + // alpha: v1.4 + // beta: v1.11 + DynamicKubeletConfig featuregate.Feature = "DynamicKubeletConfig" + + // owner: @pweil- + // alpha: v1.5 + // + // Default userns=host for containers that are using other host namespaces, host mounts, the pod + // contains a privileged container, or specific non-namespaced capabilities (MKNOD, SYS_MODULE, + // SYS_TIME). This should only be enabled if user namespace remapping is enabled in the docker daemon. + ExperimentalHostUserNamespaceDefaultingGate featuregate.Feature = "ExperimentalHostUserNamespaceDefaulting" + + // owner: @jiayingz + // beta: v1.10 + // + // Enables support for Device Plugins + DevicePlugins featuregate.Feature = "DevicePlugins" + + // owner: @dxist + // alpha: v1.16 + // + // Enables support of HPA scaling to zero pods when an object or custom metric is configured. + HPAScaleToZero featuregate.Feature = "HPAScaleToZero" + + // owner: @mikedanese + // alpha: v1.7 + // beta: v1.12 + // + // Gets a server certificate for the kubelet from the Certificate Signing + // Request API instead of generating one self signed and auto rotates the + // certificate as expiration approaches. + RotateKubeletServerCertificate featuregate.Feature = "RotateKubeletServerCertificate" + + // owner: @mikedanese + // beta: v1.8 + // ga: v1.19 + // + // Automatically renews the client certificate used for communicating with + // the API server as the certificate approaches expiration. + RotateKubeletClientCertificate featuregate.Feature = "RotateKubeletClientCertificate" + + // owner: @jinxu + // beta: v1.10 + // + // New local storage types to support local storage capacity isolation + LocalStorageCapacityIsolation featuregate.Feature = "LocalStorageCapacityIsolation" + + // owner: @gnufied + // beta: v1.11 + // Ability to Expand persistent volumes + ExpandPersistentVolumes featuregate.Feature = "ExpandPersistentVolumes" + + // owner: @mlmhl + // beta: v1.15 + // Ability to expand persistent volumes' file system without unmounting volumes. + ExpandInUsePersistentVolumes featuregate.Feature = "ExpandInUsePersistentVolumes" + + // owner: @gnufied + // alpha: v1.14 + // beta: v1.16 + // Ability to expand CSI volumes + ExpandCSIVolumes featuregate.Feature = "ExpandCSIVolumes" + + // owner: @verb + // alpha: v1.16 + // + // Allows running an ephemeral container in pod namespaces to troubleshoot a running pod. + EphemeralContainers featuregate.Feature = "EphemeralContainers" + + // owner: @sjenning + // alpha: v1.11 + // + // Allows resource reservations at the QoS level preventing pods at lower QoS levels from + // bursting into resources requested at higher QoS levels (memory only for now) + QOSReserved featuregate.Feature = "QOSReserved" + + // owner: @ConnorDoyle + // alpha: v1.8 + // beta: v1.10 + // + // Alternative container-level CPU affinity policies. + CPUManager featuregate.Feature = "CPUManager" + + // owner: @szuecs + // alpha: v1.12 + // + // Enable nodes to change CPUCFSQuotaPeriod + CPUCFSQuotaPeriod featuregate.Feature = "CustomCPUCFSQuotaPeriod" + + // owner: @lmdaly + // alpha: v1.16 + // beta: v1.18 + // + // Enable resource managers to make NUMA aligned decisions + TopologyManager featuregate.Feature = "TopologyManager" + + // owner: @sjenning + // beta: v1.11 + // + // Enable pods to set sysctls on a pod + Sysctls featuregate.Feature = "Sysctls" + + // owner @smarterclayton + // alpha: v1.16 + // beta: v1.19 + // + // Enable legacy behavior to vary cluster functionality on the node-role.kubernetes.io labels. On by default (legacy), will be turned off in 1.18. + LegacyNodeRoleBehavior featuregate.Feature = "LegacyNodeRoleBehavior" + + // owner @brendandburns + // alpha: v1.9 + // beta: v1.19 + // + // Enable nodes to exclude themselves from service load balancers + ServiceNodeExclusion featuregate.Feature = "ServiceNodeExclusion" + + // owner @smarterclayton + // alpha: v1.16 + // beta: v1.19 + // + // Enable nodes to exclude themselves from network disruption checks + NodeDisruptionExclusion featuregate.Feature = "NodeDisruptionExclusion" + + // owner: @saad-ali + // alpha: v1.12 + // beta: v1.14 + // GA: v1.18 + // Enable all logic related to the CSIDriver API object in storage.k8s.io + CSIDriverRegistry featuregate.Feature = "CSIDriverRegistry" + + // owner: @verult + // alpha: v1.12 + // beta: v1.14 + // ga: v1.17 + // Enable all logic related to the CSINode API object in storage.k8s.io + CSINodeInfo featuregate.Feature = "CSINodeInfo" + + // owner: @screeley44 + // alpha: v1.9 + // beta: v1.13 + // ga: v1.18 + // + // Enable Block volume support in containers. + BlockVolume featuregate.Feature = "BlockVolume" + + // owner: @pospispa + // GA: v1.11 + // + // Postpone deletion of a PV or a PVC when they are being used + StorageObjectInUseProtection featuregate.Feature = "StorageObjectInUseProtection" + + // owner: @dims, @derekwaynecarr + // alpha: v1.10 + // beta: v1.14 + // GA: v1.20 + // + // Implement support for limiting pids in pods + SupportPodPidsLimit featuregate.Feature = "SupportPodPidsLimit" + + // owner: @feiskyer + // alpha: v1.10 + // + // Enable Hyper-V containers on Windows + // Deprecated in 1.20 and removed in 1.21 + HyperVContainer featuregate.Feature = "HyperVContainer" + + // owner: @mikedanese + // beta: v1.12 + // ga: v1.20 + // + // Implement TokenRequest endpoint on service account resources. + TokenRequest featuregate.Feature = "TokenRequest" + + // owner: @mikedanese + // beta: v1.12 + // ga: v1.20 + // + // Enable ServiceAccountTokenVolumeProjection support in ProjectedVolumes. + TokenRequestProjection featuregate.Feature = "TokenRequestProjection" + + // owner: @mikedanese + // alpha: v1.13 + // + // Migrate ServiceAccount volumes to use a projected volume consisting of a + // ServiceAccountTokenVolumeProjection. This feature adds new required flags + // to the API server. + BoundServiceAccountTokenVolume featuregate.Feature = "BoundServiceAccountTokenVolume" + + // owner: @mtaufen + // alpha: v1.18 + // beta: v1.20 + // + // Enable OIDC discovery endpoints (issuer and JWKS URLs) for the service + // account issuer in the API server. + // Note these endpoints serve minimally-compliant discovery docs that are + // intended to be used for service account token verification. + ServiceAccountIssuerDiscovery featuregate.Feature = "ServiceAccountIssuerDiscovery" + + // owner: @Random-Liu + // beta: v1.11 + // + // Enable container log rotation for cri container runtime + CRIContainerLogRotation featuregate.Feature = "CRIContainerLogRotation" + + // owner: @krmayankk + // beta: v1.14 + // + // Enables control over the primary group ID of containers' init processes. + RunAsGroup featuregate.Feature = "RunAsGroup" + + // owner: @saad-ali + // ga + // + // Allow mounting a subpath of a volume in a container + // Do not remove this feature gate even though it's GA + VolumeSubpath featuregate.Feature = "VolumeSubpath" + + // owner: @gnufied + // beta : v1.12 + // GA : v1.17 + + // + // Add support for volume plugins to report node specific + // volume limits + AttachVolumeLimit featuregate.Feature = "AttachVolumeLimit" + + // owner: @ravig + // alpha: v1.11 + // + // Include volume count on node to be considered for balanced resource allocation while scheduling. + // A node which has closer cpu,memory utilization and volume count is favoured by scheduler + // while making decisions. + BalanceAttachedNodeVolumes featuregate.Feature = "BalanceAttachedNodeVolumes" + + // owner: @vladimirvivien + // alpha: v1.11 + // beta: v1.14 + // ga: v1.18 + // + // Enables CSI to use raw block storage volumes + CSIBlockVolume featuregate.Feature = "CSIBlockVolume" + + // owner: @pohly + // alpha: v1.14 + // beta: v1.16 + // + // Enables CSI Inline volumes support for pods + CSIInlineVolume featuregate.Feature = "CSIInlineVolume" + + // owner: @pohly + // alpha: v1.19 + // + // Enables tracking of available storage capacity that CSI drivers provide. + CSIStorageCapacity featuregate.Feature = "CSIStorageCapacity" + + // owner: @alculquicondor + // beta: v1.20 + // + // Enables the use of PodTopologySpread scheduling plugin to do default + // spreading and disables legacy SelectorSpread plugin. + DefaultPodTopologySpread featuregate.Feature = "DefaultPodTopologySpread" + + // owner: @pohly + // alpha: v1.19 + // + // Enables generic ephemeral inline volume support for pods + GenericEphemeralVolume featuregate.Feature = "GenericEphemeralVolume" + + // owner: @tallclair + // alpha: v1.12 + // beta: v1.14 + // GA: v1.20 + // + // Enables RuntimeClass, for selecting between multiple runtimes to run a pod. + RuntimeClass featuregate.Feature = "RuntimeClass" + + // owner: @mtaufen + // alpha: v1.12 + // beta: v1.14 + // GA: v1.17 + // + // Kubelet uses the new Lease API to report node heartbeats, + // (Kube) Node Lifecycle Controller uses these heartbeats as a node health signal. + NodeLease featuregate.Feature = "NodeLease" + + // owner: @janosi + // alpha: v1.12 + // beta: v1.18 + // GA: v1.20 + // + // Enables SCTP as new protocol for Service ports, NetworkPolicy, and ContainerPort in Pod/Containers definition + SCTPSupport featuregate.Feature = "SCTPSupport" + + // owner: @xing-yang + // alpha: v1.12 + // beta: v1.17 + // GA: v1.20 + // + // Enable volume snapshot data source support. + VolumeSnapshotDataSource featuregate.Feature = "VolumeSnapshotDataSource" + + // owner: @jessfraz + // alpha: v1.12 + // + // Enables control over ProcMountType for containers. + ProcMountType featuregate.Feature = "ProcMountType" + + // owner: @janetkuo + // alpha: v1.12 + // + // Allow TTL controller to clean up Pods and Jobs after they finish. + TTLAfterFinished featuregate.Feature = "TTLAfterFinished" + + // owner: @dashpole + // alpha: v1.13 + // beta: v1.15 + // + // Enables the kubelet's pod resources grpc endpoint + KubeletPodResources featuregate.Feature = "KubeletPodResources" + + // owner: @davidz627 + // alpha: v1.14 + // beta: v1.17 + // + // Enables the in-tree storage to CSI Plugin migration feature. + CSIMigration featuregate.Feature = "CSIMigration" + + // owner: @davidz627 + // alpha: v1.14 + // beta: v1.17 + // + // Enables the GCE PD in-tree driver to GCE CSI Driver migration feature. + CSIMigrationGCE featuregate.Feature = "CSIMigrationGCE" + + // owner: @davidz627 + // alpha: v1.17 + // + // Disables the GCE PD in-tree driver. + // Expects GCE PD CSI Driver to be installed and configured on all nodes. + CSIMigrationGCEComplete featuregate.Feature = "CSIMigrationGCEComplete" + + // owner: @leakingtapan + // alpha: v1.14 + // beta: v1.17 + // + // Enables the AWS EBS in-tree driver to AWS EBS CSI Driver migration feature. + CSIMigrationAWS featuregate.Feature = "CSIMigrationAWS" + + // owner: @leakingtapan + // alpha: v1.17 + // + // Disables the AWS EBS in-tree driver. + // Expects AWS EBS CSI Driver to be installed and configured on all nodes. + CSIMigrationAWSComplete featuregate.Feature = "CSIMigrationAWSComplete" + + // owner: @andyzhangx + // alpha: v1.15 + // beta: v1.19 + // + // Enables the Azure Disk in-tree driver to Azure Disk Driver migration feature. + CSIMigrationAzureDisk featuregate.Feature = "CSIMigrationAzureDisk" + + // owner: @andyzhangx + // alpha: v1.17 + // + // Disables the Azure Disk in-tree driver. + // Expects Azure Disk CSI Driver to be installed and configured on all nodes. + CSIMigrationAzureDiskComplete featuregate.Feature = "CSIMigrationAzureDiskComplete" + + // owner: @andyzhangx + // alpha: v1.15 + // + // Enables the Azure File in-tree driver to Azure File Driver migration feature. + CSIMigrationAzureFile featuregate.Feature = "CSIMigrationAzureFile" + + // owner: @andyzhangx + // alpha: v1.17 + // + // Disables the Azure File in-tree driver. + // Expects Azure File CSI Driver to be installed and configured on all nodes. + CSIMigrationAzureFileComplete featuregate.Feature = "CSIMigrationAzureFileComplete" + + // owner: @divyenpatel + // beta: v1.19 (requires: vSphere vCenter/ESXi Version: 7.0u1, HW Version: VM version 15) + // + // Enables the vSphere in-tree driver to vSphere CSI Driver migration feature. + CSIMigrationvSphere featuregate.Feature = "CSIMigrationvSphere" + + // owner: @divyenpatel + // beta: v1.19 (requires: vSphere vCenter/ESXi Version: 7.0u1, HW Version: VM version 15) + // + // Disables the vSphere in-tree driver. + // Expects vSphere CSI Driver to be installed and configured on all nodes. + CSIMigrationvSphereComplete featuregate.Feature = "CSIMigrationvSphereComplete" + + // owner: @huffmanca + // alpha: v1.19 + // beta: v1.20 + // + // Determines if a CSI Driver supports applying fsGroup. + CSIVolumeFSGroupPolicy featuregate.Feature = "CSIVolumeFSGroupPolicy" + + // owner: @gnufied + // alpha: v1.18 + // beta: v1.20 + // Allows user to configure volume permission change policy for fsGroups when mounting + // a volume in a Pod. + ConfigurableFSGroupPolicy featuregate.Feature = "ConfigurableFSGroupPolicy" + + // owner: @RobertKrawitz, @derekwaynecarr + // beta: v1.15 + // GA: v1.20 + // + // Implement support for limiting pids in nodes + SupportNodePidsLimit featuregate.Feature = "SupportNodePidsLimit" + + // owner: @wk8 + // alpha: v1.14 + // beta: v1.16 + // + // Enables GMSA support for Windows workloads. + WindowsGMSA featuregate.Feature = "WindowsGMSA" + + // owner: @bclau + // alpha: v1.16 + // beta: v1.17 + // GA: v1.18 + // + // Enables support for running container entrypoints as different usernames than their default ones. + WindowsRunAsUserName featuregate.Feature = "WindowsRunAsUserName" + + // owner: @adisky + // alpha: v1.14 + // beta: v1.18 + // + // Enables the OpenStack Cinder in-tree driver to OpenStack Cinder CSI Driver migration feature. + CSIMigrationOpenStack featuregate.Feature = "CSIMigrationOpenStack" + + // owner: @adisky + // alpha: v1.17 + // + // Disables the OpenStack Cinder in-tree driver. + // Expects the OpenStack Cinder CSI Driver to be installed and configured on all nodes. + CSIMigrationOpenStackComplete featuregate.Feature = "CSIMigrationOpenStackComplete" + + // owner: @RobertKrawitz + // alpha: v1.15 + // + // Allow use of filesystems for ephemeral storage monitoring. + // Only applies if LocalStorageCapacityIsolation is set. + LocalStorageCapacityIsolationFSQuotaMonitoring featuregate.Feature = "LocalStorageCapacityIsolationFSQuotaMonitoring" + + // owner: @denkensk + // alpha: v1.15 + // beta: v1.19 + // + // Enables NonPreempting option for priorityClass and pod. + NonPreemptingPriority featuregate.Feature = "NonPreemptingPriority" + + // owner: @j-griffith + // alpha: v1.15 + // beta: v1.16 + // GA: v1.18 + // + // Enable support for specifying an existing PVC as a DataSource + VolumePVCDataSource featuregate.Feature = "VolumePVCDataSource" + + // owner: @egernst + // alpha: v1.16 + // beta: v1.18 + // + // Enables PodOverhead, for accounting pod overheads which are specific to a given RuntimeClass + PodOverhead featuregate.Feature = "PodOverhead" + + // owner: @khenidak + // alpha: v1.15 + // + // Enables ipv6 dual stack + IPv6DualStack featuregate.Feature = "IPv6DualStack" + + // owner: @robscott @freehan + // alpha: v1.16 + // + // Enable Endpoint Slices for more scalable Service endpoints. + EndpointSlice featuregate.Feature = "EndpointSlice" + + // owner: @robscott @freehan + // alpha: v1.18 + // beta: v1.19 + // + // Enable Endpoint Slice consumption by kube-proxy for improved scalability. + EndpointSliceProxying featuregate.Feature = "EndpointSliceProxying" + + // owner: @robscott @kumarvin123 + // alpha: v1.19 + // + // Enable Endpoint Slice consumption by kube-proxy in Windows for improved scalability. + WindowsEndpointSliceProxying featuregate.Feature = "WindowsEndpointSliceProxying" + + // owner: @Huang-Wei + // alpha: v1.16 + // beta: v1.18 + // GA: v1.19 + // + // Schedule pods evenly across available topology domains. + EvenPodsSpread featuregate.Feature = "EvenPodsSpread" + + // owner: @matthyx + // alpha: v1.16 + // beta: v1.18 + // GA: v1.20 + // + // Enables the startupProbe in kubelet worker. + StartupProbe featuregate.Feature = "StartupProbe" + + // owner: @deads2k + // beta: v1.17 + // + // Enables the users to skip TLS verification of kubelets on pod logs requests + AllowInsecureBackendProxy featuregate.Feature = "AllowInsecureBackendProxy" + + // owner: @mortent + // alpha: v1.3 + // beta: v1.5 + // + // Enable all logic related to the PodDisruptionBudget API object in policy + PodDisruptionBudget featuregate.Feature = "PodDisruptionBudget" + + // owner: @alaypatel07, @soltysh + // alpha: v1.20 + // beta: v1.21 + // + // CronJobControllerV2 controls whether the controller manager starts old cronjob + // controller or new one which is implemented with informers and delaying queue + // + // This feature is deprecated, and will be removed in v1.22. + CronJobControllerV2 featuregate.Feature = "CronJobControllerV2" + + // owner: @m1093782566 + // alpha: v1.17 + // + // Enables topology aware service routing + ServiceTopology featuregate.Feature = "ServiceTopology" + + // owner: @robscott + // alpha: v1.18 + // beta: v1.19 + // ga: v1.20 + // + // Enables AppProtocol field for Services and Endpoints. + ServiceAppProtocol featuregate.Feature = "ServiceAppProtocol" + + // owner: @wojtek-t + // alpha: v1.18 + // beta: v1.19 + // + // Enables a feature to make secrets and configmaps data immutable. + ImmutableEphemeralVolumes featuregate.Feature = "ImmutableEphemeralVolumes" + + // owner: @bart0sh + // alpha: v1.18 + // beta: v1.19 + // + // Enables usage of HugePages- in a volume medium, + // e.g. emptyDir: + // medium: HugePages-1Gi + HugePageStorageMediumSize featuregate.Feature = "HugePageStorageMediumSize" + + // owner: @derekwaynecarr + // alpha: v1.20 + // + // Enables usage of hugepages- in downward API. + DownwardAPIHugePages featuregate.Feature = "DownwardAPIHugePages" + + // owner: @freehan + // GA: v1.18 + // + // Enable ExternalTrafficPolicy for Service ExternalIPs. + // This is for bug fix #69811 + ExternalPolicyForExternalIP featuregate.Feature = "ExternalPolicyForExternalIP" + + // owner: @bswartz + // alpha: v1.18 + // + // Enables usage of any object for volume data source in PVCs + AnyVolumeDataSource featuregate.Feature = "AnyVolumeDataSource" + + // owner: @javidiaz + // alpha: v1.19 + // beta: v1.20 + // + // Allow setting the Fully Qualified Domain Name (FQDN) in the hostname of a Pod. If a Pod does not + // have FQDN, this feature has no effect. + SetHostnameAsFQDN featuregate.Feature = "SetHostnameAsFQDN" + + // owner: @ksubrmnn + // alpha: v1.14 + // beta: v1.20 + // + // Allows kube-proxy to run in Overlay mode for Windows + WinOverlay featuregate.Feature = "WinOverlay" + + // owner: @ksubrmnn + // alpha: v1.14 + // + // Allows kube-proxy to create DSR loadbalancers for Windows + WinDSR featuregate.Feature = "WinDSR" + + // owner: @RenaudWasTaken @dashpole + // alpha: v1.19 + // beta: v1.20 + // + // Disables Accelerator Metrics Collected by Kubelet + DisableAcceleratorUsageMetrics featuregate.Feature = "DisableAcceleratorUsageMetrics" + + // owner: @arjunrn @mwielgus @josephburnett + // alpha: v1.20 + // + // Add support for the HPA to scale based on metrics from individual containers + // in target pods + HPAContainerMetrics featuregate.Feature = "HPAContainerMetrics" + + // owner: @zshihang + // alpha: v1.13 + // beta: v1.20 + // + // Allows kube-controller-manager to publish kube-root-ca.crt configmap to + // every namespace. This feature is a prerequisite of BoundServiceAccountTokenVolume. + RootCAConfigMap featuregate.Feature = "RootCAConfigMap" + + // owner: @andrewsykim + // alpha: v1.20 + // + // Enable Terminating condition in Endpoint Slices. + EndpointSliceTerminatingCondition featuregate.Feature = "EndpointSliceTerminatingCondition" + + // owner: @robscott + // alpha: v1.20 + // + // Enable NodeName field on Endpoint Slices. + EndpointSliceNodeName featuregate.Feature = "EndpointSliceNodeName" + + // owner: @derekwaynecarr + // alpha: v1.20 + // + // Enables kubelet support to size memory backed volumes + SizeMemoryBackedVolumes featuregate.Feature = "SizeMemoryBackedVolumes" + + // owner: @andrewsykim @SergeyKanzhelev + // GA: v1.20 + // + // Ensure kubelet respects exec probe timeouts. Feature gate exists in-case existing workloads + // may depend on old behavior where exec probe timeouts were ignored. + // Lock to default in v1.21 and remove in v1.22. + ExecProbeTimeout featuregate.Feature = "ExecProbeTimeout" + + // owner: @andrewsykim + // alpha: v1.20 + // + // Enable kubelet exec plugins for image pull credentials. + KubeletCredentialProviders featuregate.Feature = "KubeletCredentialProviders" + + // owner: @zshihang + // alpha: v1.20 + // + // Enable kubelet to pass pod's service account token to NodePublishVolume + // call of CSI driver which is mounting volumes for that pod. + CSIServiceAccountToken featuregate.Feature = "CSIServiceAccountToken" + + // owner: @bobbypage + // alpha: v1.20 + // Adds support for kubelet to detect node shutdown and gracefully terminate pods prior to the node being shutdown. + GracefulNodeShutdown featuregate.Feature = "GracefulNodeShutdown" + + // owner: @andrewsykim @uablrek + // alpha: v1.20 + // + // Allows control if NodePorts shall be created for services with "type: LoadBalancer" by defining the spec.AllocateLoadBalancerNodePorts field (bool) + ServiceLBNodePortControl featuregate.Feature = "ServiceLBNodePortControl" + + // owner: @janosi + // alpha: v1.20 + // + // Enables the usage of different protocols in the same Service with type=LoadBalancer + MixedProtocolLBService featuregate.Feature = "MixedProtocolLBService" +) + +func init() { + runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates)) +} + +// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys. +// To add a new feature, define a key for it above and add it here. The features will be +// available throughout Kubernetes binaries. +var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ + AppArmor: {Default: true, PreRelease: featuregate.Beta}, + DynamicKubeletConfig: {Default: true, PreRelease: featuregate.Beta}, + ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: featuregate.Beta}, + DevicePlugins: {Default: true, PreRelease: featuregate.Beta}, + RotateKubeletServerCertificate: {Default: true, PreRelease: featuregate.Beta}, + RotateKubeletClientCertificate: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 + LocalStorageCapacityIsolation: {Default: true, PreRelease: featuregate.Beta}, + Sysctls: {Default: true, PreRelease: featuregate.Beta}, + EphemeralContainers: {Default: false, PreRelease: featuregate.Alpha}, + QOSReserved: {Default: false, PreRelease: featuregate.Alpha}, + ExpandPersistentVolumes: {Default: true, PreRelease: featuregate.Beta}, + ExpandInUsePersistentVolumes: {Default: true, PreRelease: featuregate.Beta}, + ExpandCSIVolumes: {Default: true, PreRelease: featuregate.Beta}, + AttachVolumeLimit: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.19 + CPUManager: {Default: true, PreRelease: featuregate.Beta}, + CPUCFSQuotaPeriod: {Default: false, PreRelease: featuregate.Alpha}, + TopologyManager: {Default: true, PreRelease: featuregate.Beta}, + ServiceNodeExclusion: {Default: true, PreRelease: featuregate.Beta}, + NodeDisruptionExclusion: {Default: true, PreRelease: featuregate.Beta}, + CSIDriverRegistry: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 + CSINodeInfo: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.19 + BlockVolume: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 + StorageObjectInUseProtection: {Default: true, PreRelease: featuregate.GA}, + SupportPodPidsLimit: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23 + SupportNodePidsLimit: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23 + HyperVContainer: {Default: false, PreRelease: featuregate.Deprecated}, + TokenRequest: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21 + TokenRequestProjection: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21 + BoundServiceAccountTokenVolume: {Default: false, PreRelease: featuregate.Alpha}, + ServiceAccountIssuerDiscovery: {Default: true, PreRelease: featuregate.Beta}, + CRIContainerLogRotation: {Default: true, PreRelease: featuregate.Beta}, + CSIMigration: {Default: true, PreRelease: featuregate.Beta}, + CSIMigrationGCE: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires GCE PD CSI Driver) + CSIMigrationGCEComplete: {Default: false, PreRelease: featuregate.Alpha}, + CSIMigrationAWS: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires AWS EBS CSI driver) + CSIMigrationAWSComplete: {Default: false, PreRelease: featuregate.Alpha}, + CSIMigrationAzureDisk: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires Azure Disk CSI driver) + CSIMigrationAzureDiskComplete: {Default: false, PreRelease: featuregate.Alpha}, + CSIMigrationAzureFile: {Default: false, PreRelease: featuregate.Alpha}, + CSIMigrationAzureFileComplete: {Default: false, PreRelease: featuregate.Alpha}, + CSIMigrationvSphere: {Default: false, PreRelease: featuregate.Beta}, + CSIMigrationvSphereComplete: {Default: false, PreRelease: featuregate.Beta}, + RunAsGroup: {Default: true, PreRelease: featuregate.Beta}, + CSIMigrationOpenStack: {Default: false, PreRelease: featuregate.Beta}, // Off by default (requires OpenStack Cinder CSI driver) + CSIMigrationOpenStackComplete: {Default: false, PreRelease: featuregate.Alpha}, + VolumeSubpath: {Default: true, PreRelease: featuregate.GA}, + ConfigurableFSGroupPolicy: {Default: true, PreRelease: featuregate.Beta}, + BalanceAttachedNodeVolumes: {Default: false, PreRelease: featuregate.Alpha}, + CSIBlockVolume: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 + CSIInlineVolume: {Default: true, PreRelease: featuregate.Beta}, + CSIStorageCapacity: {Default: false, PreRelease: featuregate.Alpha}, + CSIServiceAccountToken: {Default: false, PreRelease: featuregate.Alpha}, + GenericEphemeralVolume: {Default: false, PreRelease: featuregate.Alpha}, + CSIVolumeFSGroupPolicy: {Default: true, PreRelease: featuregate.Beta}, + RuntimeClass: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23 + NodeLease: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, + SCTPSupport: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22 + VolumeSnapshotDataSource: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21 + ProcMountType: {Default: false, PreRelease: featuregate.Alpha}, + TTLAfterFinished: {Default: false, PreRelease: featuregate.Alpha}, + KubeletPodResources: {Default: true, PreRelease: featuregate.Beta}, + WindowsGMSA: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 + WindowsRunAsUserName: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 + LocalStorageCapacityIsolationFSQuotaMonitoring: {Default: false, PreRelease: featuregate.Alpha}, + NonPreemptingPriority: {Default: true, PreRelease: featuregate.Beta}, + VolumePVCDataSource: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.20 + PodOverhead: {Default: true, PreRelease: featuregate.Beta}, + IPv6DualStack: {Default: false, PreRelease: featuregate.Alpha}, + EndpointSlice: {Default: true, PreRelease: featuregate.Beta}, + EndpointSliceProxying: {Default: true, PreRelease: featuregate.Beta}, + EndpointSliceTerminatingCondition: {Default: false, PreRelease: featuregate.Alpha}, + EndpointSliceNodeName: {Default: false, PreRelease: featuregate.Alpha}, + WindowsEndpointSliceProxying: {Default: false, PreRelease: featuregate.Alpha}, + EvenPodsSpread: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21 + StartupProbe: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23 + AllowInsecureBackendProxy: {Default: true, PreRelease: featuregate.Beta}, + PodDisruptionBudget: {Default: true, PreRelease: featuregate.Beta}, + CronJobControllerV2: {Default: false, PreRelease: featuregate.Alpha}, + ServiceTopology: {Default: false, PreRelease: featuregate.Alpha}, + ServiceAppProtocol: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, + ImmutableEphemeralVolumes: {Default: true, PreRelease: featuregate.Beta}, + HugePageStorageMediumSize: {Default: true, PreRelease: featuregate.Beta}, + DownwardAPIHugePages: {Default: false, PreRelease: featuregate.Alpha}, + ExternalPolicyForExternalIP: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22 + AnyVolumeDataSource: {Default: false, PreRelease: featuregate.Alpha}, + DefaultPodTopologySpread: {Default: true, PreRelease: featuregate.Beta}, + SetHostnameAsFQDN: {Default: true, PreRelease: featuregate.Beta}, + WinOverlay: {Default: true, PreRelease: featuregate.Beta}, + WinDSR: {Default: false, PreRelease: featuregate.Alpha}, + DisableAcceleratorUsageMetrics: {Default: true, PreRelease: featuregate.Beta}, + HPAContainerMetrics: {Default: false, PreRelease: featuregate.Alpha}, + RootCAConfigMap: {Default: true, PreRelease: featuregate.Beta}, + SizeMemoryBackedVolumes: {Default: false, PreRelease: featuregate.Alpha}, + ExecProbeTimeout: {Default: true, PreRelease: featuregate.GA}, // lock to default in v1.21 and remove in v1.22 + KubeletCredentialProviders: {Default: false, PreRelease: featuregate.Alpha}, + GracefulNodeShutdown: {Default: false, PreRelease: featuregate.Alpha}, + ServiceLBNodePortControl: {Default: false, PreRelease: featuregate.Alpha}, + MixedProtocolLBService: {Default: false, PreRelease: featuregate.Alpha}, + + // inherited features from generic apiserver, relisted here to get a conflict if it is changed + // unintentionally on either side: + genericfeatures.StreamingProxyRedirects: {Default: true, PreRelease: featuregate.Deprecated}, + genericfeatures.ValidateProxyRedirects: {Default: true, PreRelease: featuregate.Beta}, + genericfeatures.AdvancedAuditing: {Default: true, PreRelease: featuregate.GA}, + genericfeatures.APIResponseCompression: {Default: true, PreRelease: featuregate.Beta}, + genericfeatures.APIListChunking: {Default: true, PreRelease: featuregate.Beta}, + genericfeatures.DryRun: {Default: true, PreRelease: featuregate.GA}, + genericfeatures.ServerSideApply: {Default: true, PreRelease: featuregate.Beta}, + genericfeatures.APIPriorityAndFairness: {Default: true, PreRelease: featuregate.Beta}, + genericfeatures.WarningHeaders: {Default: true, PreRelease: featuregate.Beta}, + + // features that enable backwards compatibility but are scheduled to be removed + // ... + HPAScaleToZero: {Default: false, PreRelease: featuregate.Alpha}, + LegacyNodeRoleBehavior: {Default: true, PreRelease: featuregate.Beta}, +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/util/BUILD b/vendor/k8s.io/kubernetes/pkg/scheduler/util/BUILD new file mode 100644 index 000000000..3e7f83465 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/util/BUILD @@ -0,0 +1,70 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_test( + name = "go_default_test", + srcs = [ + "non_zero_test.go", + "topologies_test.go", + "utils_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/selection:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", + "//staging/src/k8s.io/client-go/testing:go_default_library", + "//staging/src/k8s.io/kube-scheduler/extender/v1:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +go_library( + name = "go_default_library", + srcs = [ + "clock.go", + "non_zero.go", + "topologies.go", + "utils.go", + ], + importpath = "k8s.io/kubernetes/pkg/scheduler/util", + deps = [ + "//pkg/apis/core/v1/helper:go_default_library", + "//pkg/features:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes:go_default_library", + "//staging/src/k8s.io/component-helpers/scheduling/corev1:go_default_library", + "//staging/src/k8s.io/kube-scheduler/extender/v1:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/util/clock.go b/vendor/k8s.io/kubernetes/pkg/scheduler/util/clock.go new file mode 100644 index 000000000..e17c759db --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/util/clock.go @@ -0,0 +1,34 @@ +/* +Copyright 2018 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 util + +import ( + "time" +) + +// Clock provides an interface for getting the current time +type Clock interface { + Now() time.Time +} + +// RealClock implements a clock using time +type RealClock struct{} + +// Now returns the current time with time.Now +func (RealClock) Now() time.Time { + return time.Now() +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/util/non_zero.go b/vendor/k8s.io/kubernetes/pkg/scheduler/util/non_zero.go new file mode 100644 index 000000000..bf8c47c53 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/util/non_zero.go @@ -0,0 +1,84 @@ +/* +Copyright 2016 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 util + +import ( + v1 "k8s.io/api/core/v1" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" +) + +// For each of these resources, a pod that doesn't request the resource explicitly +// will be treated as having requested the amount indicated below, for the purpose +// of computing priority only. This ensures that when scheduling zero-request pods, such +// pods will not all be scheduled to the machine with the smallest in-use request, +// and that when scheduling regular pods, such pods will not see zero-request pods as +// consuming no resources whatsoever. We chose these values to be similar to the +// resources that we give to cluster addon pods (#10653). But they are pretty arbitrary. +// As described in #11713, we use request instead of limit to deal with resource requirements. +const ( + // DefaultMilliCPURequest defines default milli cpu request number. + DefaultMilliCPURequest int64 = 100 // 0.1 core + // DefaultMemoryRequest defines default memory request size. + DefaultMemoryRequest int64 = 200 * 1024 * 1024 // 200 MB +) + +// GetNonzeroRequests returns the default cpu and memory resource request if none is found or +// what is provided on the request. +func GetNonzeroRequests(requests *v1.ResourceList) (int64, int64) { + return GetNonzeroRequestForResource(v1.ResourceCPU, requests), + GetNonzeroRequestForResource(v1.ResourceMemory, requests) +} + +// GetNonzeroRequestForResource returns the default resource request if none is found or +// what is provided on the request. +func GetNonzeroRequestForResource(resource v1.ResourceName, requests *v1.ResourceList) int64 { + switch resource { + case v1.ResourceCPU: + // Override if un-set, but not if explicitly set to zero + if _, found := (*requests)[v1.ResourceCPU]; !found { + return DefaultMilliCPURequest + } + return requests.Cpu().MilliValue() + case v1.ResourceMemory: + // Override if un-set, but not if explicitly set to zero + if _, found := (*requests)[v1.ResourceMemory]; !found { + return DefaultMemoryRequest + } + return requests.Memory().Value() + case v1.ResourceEphemeralStorage: + // if the local storage capacity isolation feature gate is disabled, pods request 0 disk. + if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) { + return 0 + } + + quantity, found := (*requests)[v1.ResourceEphemeralStorage] + if !found { + return 0 + } + return quantity.Value() + default: + if IsScalarResourceName(resource) { + quantity, found := (*requests)[resource] + if !found { + return 0 + } + return quantity.Value() + } + } + return 0 +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/util/topologies.go b/vendor/k8s.io/kubernetes/pkg/scheduler/util/topologies.go new file mode 100644 index 000000000..bf5ee53ac --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/util/topologies.go @@ -0,0 +1,81 @@ +/* +Copyright 2016 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 util + +import ( + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/sets" +) + +// GetNamespacesFromPodAffinityTerm returns a set of names +// according to the namespaces indicated in podAffinityTerm. +// If namespaces is empty it considers the given pod's namespace. +func GetNamespacesFromPodAffinityTerm(pod *v1.Pod, podAffinityTerm *v1.PodAffinityTerm) sets.String { + names := sets.String{} + if len(podAffinityTerm.Namespaces) == 0 { + names.Insert(pod.Namespace) + } else { + names.Insert(podAffinityTerm.Namespaces...) + } + return names +} + +// PodMatchesTermsNamespaceAndSelector returns true if the given +// matches the namespace and selector defined by `s . +func PodMatchesTermsNamespaceAndSelector(pod *v1.Pod, namespaces sets.String, selector labels.Selector) bool { + if !namespaces.Has(pod.Namespace) { + return false + } + + if !selector.Matches(labels.Set(pod.Labels)) { + return false + } + return true +} + +// NodesHaveSameTopologyKey checks if nodeA and nodeB have same label value with given topologyKey as label key. +// Returns false if topologyKey is empty. +func NodesHaveSameTopologyKey(nodeA, nodeB *v1.Node, topologyKey string) bool { + if len(topologyKey) == 0 { + return false + } + + if nodeA.Labels == nil || nodeB.Labels == nil { + return false + } + + nodeALabel, okA := nodeA.Labels[topologyKey] + nodeBLabel, okB := nodeB.Labels[topologyKey] + + // If found label in both nodes, check the label + if okB && okA { + return nodeALabel == nodeBLabel + } + + return false +} + +// Topologies contains topologies information of nodes. +type Topologies struct { + DefaultKeys []string +} + +// NodesHaveSameTopologyKey checks if nodeA and nodeB have same label value with given topologyKey as label key. +func (tps *Topologies) NodesHaveSameTopologyKey(nodeA, nodeB *v1.Node, topologyKey string) bool { + return NodesHaveSameTopologyKey(nodeA, nodeB, topologyKey) +} diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/util/utils.go b/vendor/k8s.io/kubernetes/pkg/scheduler/util/utils.go new file mode 100644 index 000000000..93ed14f39 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/util/utils.go @@ -0,0 +1,172 @@ +/* +Copyright 2017 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 util + +import ( + "context" + "encoding/json" + "fmt" + "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/client-go/kubernetes" + corev1helpers "k8s.io/component-helpers/scheduling/corev1" + "k8s.io/klog/v2" + extenderv1 "k8s.io/kube-scheduler/extender/v1" + v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" +) + +// GetPodFullName returns a name that uniquely identifies a pod. +func GetPodFullName(pod *v1.Pod) string { + // Use underscore as the delimiter because it is not allowed in pod name + // (DNS subdomain format). + return pod.Name + "_" + pod.Namespace +} + +// GetPodStartTime returns start time of the given pod or current timestamp +// if it hasn't started yet. +func GetPodStartTime(pod *v1.Pod) *metav1.Time { + if pod.Status.StartTime != nil { + return pod.Status.StartTime + } + // Assumed pods and bound pods that haven't started don't have a StartTime yet. + return &metav1.Time{Time: time.Now()} +} + +// GetEarliestPodStartTime returns the earliest start time of all pods that +// have the highest priority among all victims. +func GetEarliestPodStartTime(victims *extenderv1.Victims) *metav1.Time { + if len(victims.Pods) == 0 { + // should not reach here. + klog.Errorf("victims.Pods is empty. Should not reach here.") + return nil + } + + earliestPodStartTime := GetPodStartTime(victims.Pods[0]) + maxPriority := corev1helpers.PodPriority(victims.Pods[0]) + + for _, pod := range victims.Pods { + if corev1helpers.PodPriority(pod) == maxPriority { + if GetPodStartTime(pod).Before(earliestPodStartTime) { + earliestPodStartTime = GetPodStartTime(pod) + } + } else if corev1helpers.PodPriority(pod) > maxPriority { + maxPriority = corev1helpers.PodPriority(pod) + earliestPodStartTime = GetPodStartTime(pod) + } + } + + return earliestPodStartTime +} + +// MoreImportantPod return true when priority of the first pod is higher than +// the second one. If two pods' priorities are equal, compare their StartTime. +// It takes arguments of the type "interface{}" to be used with SortableList, +// but expects those arguments to be *v1.Pod. +func MoreImportantPod(pod1, pod2 *v1.Pod) bool { + p1 := corev1helpers.PodPriority(pod1) + p2 := corev1helpers.PodPriority(pod2) + if p1 != p2 { + return p1 > p2 + } + return GetPodStartTime(pod1).Before(GetPodStartTime(pod2)) +} + +// GetPodAffinityTerms gets pod affinity terms by a pod affinity object. +func GetPodAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffinityTerm) { + if affinity != nil && affinity.PodAffinity != nil { + if len(affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 { + terms = affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution + } + // TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution. + //if len(affinity.PodAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 { + // terms = append(terms, affinity.PodAffinity.RequiredDuringSchedulingRequiredDuringExecution...) + //} + } + return terms +} + +// GetPodAntiAffinityTerms gets pod affinity terms by a pod anti-affinity. +func GetPodAntiAffinityTerms(affinity *v1.Affinity) (terms []v1.PodAffinityTerm) { + if affinity != nil && affinity.PodAntiAffinity != nil { + if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 { + terms = affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution + } + // TODO: Uncomment this block when implement RequiredDuringSchedulingRequiredDuringExecution. + //if len(affinity.PodAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution) != 0 { + // terms = append(terms, affinity.PodAntiAffinity.RequiredDuringSchedulingRequiredDuringExecution...) + //} + } + return terms +} + +// PatchPod calculates the delta bytes change from to , +// and then submit a request to API server to patch the pod changes. +func PatchPod(cs kubernetes.Interface, old *v1.Pod, new *v1.Pod) error { + oldData, err := json.Marshal(old) + if err != nil { + return err + } + + newData, err := json.Marshal(new) + if err != nil { + return err + } + patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, &v1.Pod{}) + if err != nil { + return fmt.Errorf("failed to create merge patch for pod %q/%q: %v", old.Namespace, old.Name, err) + } + + if "{}" == string(patchBytes) { + return nil + } + + _, err = cs.CoreV1().Pods(old.Namespace).Patch(context.TODO(), old.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") + return err +} + +// DeletePod deletes the given from API server +func DeletePod(cs kubernetes.Interface, pod *v1.Pod) error { + return cs.CoreV1().Pods(pod.Namespace).Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}) +} + +// ClearNominatedNodeName internally submit a patch request to API server +// to set each pods[*].Status.NominatedNodeName> to "". +func ClearNominatedNodeName(cs kubernetes.Interface, pods ...*v1.Pod) utilerrors.Aggregate { + var errs []error + for _, p := range pods { + if len(p.Status.NominatedNodeName) == 0 { + continue + } + podCopy := p.DeepCopy() + podCopy.Status.NominatedNodeName = "" + if err := PatchPod(cs, p, podCopy); err != nil { + errs = append(errs, err) + } + } + return utilerrors.NewAggregate(errs) +} + +// IsScalarResourceName validates the resource for Extended, Hugepages, Native and AttachableVolume resources +func IsScalarResourceName(name v1.ResourceName) bool { + return v1helper.IsExtendedResourceName(name) || v1helper.IsHugePageResourceName(name) || + v1helper.IsPrefixedNativeResource(name) || v1helper.IsAttachableVolumeResourceName(name) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 860e16d94..8898932d2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -810,6 +810,8 @@ k8s.io/component-base/version # k8s.io/component-helpers v0.20.6 => k8s.io/component-helpers v0.20.6 ## explicit k8s.io/component-helpers/apimachinery/lease +k8s.io/component-helpers/scheduling/corev1 +k8s.io/component-helpers/scheduling/corev1/nodeaffinity # k8s.io/gengo v0.0.0-20201113003025-83324d819ded k8s.io/gengo/args k8s.io/gengo/examples/deepcopy-gen/generators @@ -835,11 +837,15 @@ k8s.io/kube-openapi/pkg/schemaconv k8s.io/kube-openapi/pkg/util k8s.io/kube-openapi/pkg/util/proto k8s.io/kube-openapi/pkg/util/sets +# k8s.io/kube-scheduler v0.0.0 => k8s.io/kube-scheduler v0.20.6 +k8s.io/kube-scheduler/extender/v1 # k8s.io/kubernetes v1.20.6 ## explicit k8s.io/kubernetes/pkg/apis/core k8s.io/kubernetes/pkg/apis/core/helper k8s.io/kubernetes/pkg/apis/core/v1/helper +k8s.io/kubernetes/pkg/features +k8s.io/kubernetes/pkg/scheduler/util # k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 ## explicit k8s.io/utils/buffer