mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Merge pull request #55251 from deads2k/admission-13-toleration
Automatic merge from submit-queue (batch tested with PRs 53747, 54528, 55279, 55251, 55311). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. update podtolerations admission to mutate and validate separately Updates the podtolerations admission plugin to mutate and validate separately. This also fixes the bug where the toleration whitelist isn't respected for memory pressure. ```release-note-action-required The `node.kubernetes.io/memory-pressure` taint now respects the configured whitelist. If you need to use it, you'll have to add it to the whitelist. ```
This commit is contained in:
commit
412271d4d3
@ -77,19 +77,7 @@ type podTolerationsPlugin struct {
|
||||
// scheduler.alpha.kubernetes.io/defaultTolerations and scheduler.alpha.kubernetes.io/tolerationsWhitelist
|
||||
// annotations keys.
|
||||
func (p *podTolerationsPlugin) Admit(a admission.Attributes) error {
|
||||
resource := a.GetResource().GroupResource()
|
||||
if resource != api.Resource("pods") {
|
||||
return nil
|
||||
}
|
||||
if a.GetSubresource() != "" {
|
||||
// only run the checks below on pods proper and not subresources
|
||||
return nil
|
||||
}
|
||||
|
||||
obj := a.GetObject()
|
||||
pod, ok := obj.(*api.Pod)
|
||||
if !ok {
|
||||
glog.Errorf("expected pod but got %s", a.GetKind().Kind)
|
||||
if shouldIgnore(a) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -97,28 +85,14 @@ func (p *podTolerationsPlugin) Admit(a admission.Attributes) error {
|
||||
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
|
||||
}
|
||||
|
||||
nsName := a.GetNamespace()
|
||||
namespace, err := p.namespaceLister.Get(nsName)
|
||||
if errors.IsNotFound(err) {
|
||||
// in case of latency in our caches, make a call direct to storage to verify that it truly exists or not
|
||||
namespace, err = p.client.Core().Namespaces().Get(nsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return errors.NewInternalError(err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return errors.NewInternalError(err)
|
||||
}
|
||||
|
||||
pod := a.GetObject().(*api.Pod)
|
||||
var finalTolerations []api.Toleration
|
||||
updateUninitialized, err := util.IsUpdatingUninitializedObject(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if a.GetOperation() == admission.Create || updateUninitialized {
|
||||
ts, err := p.getNamespaceDefaultTolerations(namespace)
|
||||
ts, err := p.getNamespaceDefaultTolerations(a.GetNamespace())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -148,9 +122,32 @@ func (p *podTolerationsPlugin) Admit(a admission.Attributes) error {
|
||||
finalTolerations = pod.Spec.Tolerations
|
||||
}
|
||||
|
||||
if qoshelper.GetPodQOS(pod) != api.PodQOSBestEffort {
|
||||
finalTolerations = tolerations.MergeTolerations(finalTolerations, []api.Toleration{
|
||||
{
|
||||
Key: algorithm.TaintNodeMemoryPressure,
|
||||
Operator: api.TolerationOpExists,
|
||||
Effect: api.TaintEffectNoSchedule,
|
||||
},
|
||||
})
|
||||
}
|
||||
pod.Spec.Tolerations = finalTolerations
|
||||
|
||||
return p.Validate(a)
|
||||
}
|
||||
func (p *podTolerationsPlugin) Validate(a admission.Attributes) error {
|
||||
if shouldIgnore(a) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !p.WaitForReady() {
|
||||
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
|
||||
}
|
||||
|
||||
// whitelist verification.
|
||||
if len(finalTolerations) > 0 {
|
||||
whitelist, err := p.getNamespaceTolerationsWhitelist(namespace)
|
||||
pod := a.GetObject().(*api.Pod)
|
||||
if len(pod.Spec.Tolerations) > 0 {
|
||||
whitelist, err := p.getNamespaceTolerationsWhitelist(a.GetNamespace())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -163,25 +160,33 @@ func (p *podTolerationsPlugin) Admit(a admission.Attributes) error {
|
||||
|
||||
if len(whitelist) > 0 {
|
||||
// check if the merged pod tolerations satisfy its namespace whitelist
|
||||
if !tolerations.VerifyAgainstWhitelist(finalTolerations, whitelist) {
|
||||
if !tolerations.VerifyAgainstWhitelist(pod.Spec.Tolerations, whitelist) {
|
||||
return fmt.Errorf("pod tolerations (possibly merged with namespace default tolerations) conflict with its namespace whitelist")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if qoshelper.GetPodQOS(pod) != api.PodQOSBestEffort {
|
||||
finalTolerations = tolerations.MergeTolerations(finalTolerations, []api.Toleration{
|
||||
{
|
||||
Key: algorithm.TaintNodeMemoryPressure,
|
||||
Operator: api.TolerationOpExists,
|
||||
Effect: api.TaintEffectNoSchedule,
|
||||
},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldIgnore(a admission.Attributes) bool {
|
||||
resource := a.GetResource().GroupResource()
|
||||
if resource != api.Resource("pods") {
|
||||
return true
|
||||
}
|
||||
if a.GetSubresource() != "" {
|
||||
// only run the checks below on pods proper and not subresources
|
||||
return true
|
||||
}
|
||||
|
||||
pod.Spec.Tolerations = finalTolerations
|
||||
return nil
|
||||
obj := a.GetObject()
|
||||
_, ok := obj.(*api.Pod)
|
||||
if !ok {
|
||||
glog.Errorf("expected pod but got %s", a.GetKind().Kind)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func NewPodTolerationsPlugin(pluginConfig *pluginapi.Configuration) *podTolerationsPlugin {
|
||||
@ -212,11 +217,38 @@ func (p *podTolerationsPlugin) ValidateInitialization() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *podTolerationsPlugin) getNamespaceDefaultTolerations(ns *api.Namespace) ([]api.Toleration, error) {
|
||||
// in exceptional cases, this can result in two live calls, but once the cache catches up, that will stop.
|
||||
func (p *podTolerationsPlugin) getNamespace(nsName string) (*api.Namespace, error) {
|
||||
namespace, err := p.namespaceLister.Get(nsName)
|
||||
if errors.IsNotFound(err) {
|
||||
// in case of latency in our caches, make a call direct to storage to verify that it truly exists or not
|
||||
namespace, err = p.client.Core().Namespaces().Get(nsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errors.NewInternalError(err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, errors.NewInternalError(err)
|
||||
}
|
||||
|
||||
return namespace, nil
|
||||
}
|
||||
|
||||
func (p *podTolerationsPlugin) getNamespaceDefaultTolerations(nsName string) ([]api.Toleration, error) {
|
||||
ns, err := p.getNamespace(nsName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return extractNSTolerations(ns, NSDefaultTolerations)
|
||||
}
|
||||
|
||||
func (p *podTolerationsPlugin) getNamespaceTolerationsWhitelist(ns *api.Namespace) ([]api.Toleration, error) {
|
||||
func (p *podTolerationsPlugin) getNamespaceTolerationsWhitelist(nsName string) ([]api.Toleration, error) {
|
||||
ns, err := p.getNamespace(nsName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return extractNSTolerations(ns, NSWLTolerations)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user