mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-03 23:40:03 +00:00 
			
		
		
		
	- refactor test cases to table driven testing style - more scenarios are covered for TaintNodesByCondition - update bazel stuff
		
			
				
	
	
		
			675 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			675 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
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 scheduler
 | 
						|
 | 
						|
// This file tests the Taint feature.
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"k8s.io/api/core/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						|
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						|
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
						|
	restclient "k8s.io/client-go/rest"
 | 
						|
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
 | 
						|
	internalinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
 | 
						|
	"k8s.io/kubernetes/pkg/controller/nodelifecycle"
 | 
						|
	kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
 | 
						|
	"k8s.io/kubernetes/pkg/scheduler/algorithm"
 | 
						|
	"k8s.io/kubernetes/pkg/scheduler/algorithmprovider"
 | 
						|
	"k8s.io/kubernetes/plugin/pkg/admission/podtolerationrestriction"
 | 
						|
	pluginapi "k8s.io/kubernetes/plugin/pkg/admission/podtolerationrestriction/apis/podtolerationrestriction"
 | 
						|
)
 | 
						|
 | 
						|
func newPod(nsName, name string, req, limit v1.ResourceList) *v1.Pod {
 | 
						|
	return &v1.Pod{
 | 
						|
		ObjectMeta: metav1.ObjectMeta{
 | 
						|
			Name:      name,
 | 
						|
			Namespace: nsName,
 | 
						|
		},
 | 
						|
		Spec: v1.PodSpec{
 | 
						|
			Containers: []v1.Container{
 | 
						|
				{
 | 
						|
					Name:  "busybox",
 | 
						|
					Image: "busybox",
 | 
						|
					Resources: v1.ResourceRequirements{
 | 
						|
						Requests: req,
 | 
						|
						Limits:   limit,
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// TestTaintNodeByCondition tests related cases for TaintNodeByCondition feature.
 | 
						|
func TestTaintNodeByCondition(t *testing.T) {
 | 
						|
	enabled := utilfeature.DefaultFeatureGate.Enabled("TaintNodesByCondition")
 | 
						|
	defer func() {
 | 
						|
		if !enabled {
 | 
						|
			utilfeature.DefaultFeatureGate.Set("TaintNodesByCondition=False")
 | 
						|
		}
 | 
						|
	}()
 | 
						|
	// Enable TaintNodeByCondition
 | 
						|
	utilfeature.DefaultFeatureGate.Set("TaintNodesByCondition=True")
 | 
						|
 | 
						|
	// Build PodToleration Admission.
 | 
						|
	admission := podtolerationrestriction.NewPodTolerationsPlugin(&pluginapi.Configuration{})
 | 
						|
 | 
						|
	context := initTestMaster(t, "default", admission)
 | 
						|
 | 
						|
	// Build clientset and informers for controllers.
 | 
						|
	internalClientset := internalclientset.NewForConfigOrDie(&restclient.Config{
 | 
						|
		QPS:           -1,
 | 
						|
		Host:          context.httpServer.URL,
 | 
						|
		ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}})
 | 
						|
	internalInformers := internalinformers.NewSharedInformerFactory(internalClientset, time.Second)
 | 
						|
 | 
						|
	kubeadmission.WantsInternalKubeClientSet(admission).SetInternalKubeClientSet(internalClientset)
 | 
						|
	kubeadmission.WantsInternalKubeInformerFactory(admission).SetInternalKubeInformerFactory(internalInformers)
 | 
						|
 | 
						|
	controllerCh := make(chan struct{})
 | 
						|
	defer close(controllerCh)
 | 
						|
 | 
						|
	// Apply feature gates to enable TaintNodesByCondition
 | 
						|
	algorithmprovider.ApplyFeatureGates()
 | 
						|
 | 
						|
	context = initTestScheduler(t, context, controllerCh, false, nil)
 | 
						|
	cs := context.clientSet
 | 
						|
	informers := context.informerFactory
 | 
						|
	nsName := context.ns.Name
 | 
						|
 | 
						|
	// Start NodeLifecycleController for taint.
 | 
						|
	nc, err := nodelifecycle.NewNodeLifecycleController(
 | 
						|
		informers.Core().V1().Pods(),
 | 
						|
		informers.Core().V1().Nodes(),
 | 
						|
		informers.Extensions().V1beta1().DaemonSets(),
 | 
						|
		nil, // CloudProvider
 | 
						|
		cs,
 | 
						|
		time.Second, // Node monitor grace period
 | 
						|
		time.Second, // Node startup grace period
 | 
						|
		time.Second, // Node monitor period
 | 
						|
		time.Second, // Pod eviction timeout
 | 
						|
		100,         // Eviction limiter QPS
 | 
						|
		100,         // Secondary eviction limiter QPS
 | 
						|
		100,         // Large cluster threshold
 | 
						|
		100,         // Unhealthy zone threshold
 | 
						|
		true,        // Run taint manager
 | 
						|
		true,        // Use taint based evictions
 | 
						|
		true,        // Enabled TaintNodeByCondition feature
 | 
						|
	)
 | 
						|
	if err != nil {
 | 
						|
		t.Errorf("Failed to create node controller: %v", err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	go nc.Run(controllerCh)
 | 
						|
 | 
						|
	// Waiting for all controller sync.
 | 
						|
	internalInformers.Start(controllerCh)
 | 
						|
	internalInformers.WaitForCacheSync(controllerCh)
 | 
						|
 | 
						|
	// -------------------------------------------
 | 
						|
	// Test TaintNodeByCondition feature.
 | 
						|
	// -------------------------------------------
 | 
						|
	nodeRes := v1.ResourceList{
 | 
						|
		v1.ResourceCPU:    resource.MustParse("4000m"),
 | 
						|
		v1.ResourceMemory: resource.MustParse("16Gi"),
 | 
						|
		v1.ResourcePods:   resource.MustParse("110"),
 | 
						|
	}
 | 
						|
 | 
						|
	podRes := v1.ResourceList{
 | 
						|
		v1.ResourceCPU:    resource.MustParse("100m"),
 | 
						|
		v1.ResourceMemory: resource.MustParse("100Mi"),
 | 
						|
	}
 | 
						|
 | 
						|
	notReadyToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodeNotReady,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	unreachableToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodeUnreachable,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	unschedulableToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodeUnschedulable,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	outOfDiskToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodeOutOfDisk,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	memoryPressureToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodeMemoryPressure,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	diskPressureToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodeDiskPressure,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	networkUnavailableToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodeNetworkUnavailable,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	pidPressureToleration := v1.Toleration{
 | 
						|
		Key:      algorithm.TaintNodePIDPressure,
 | 
						|
		Operator: v1.TolerationOpExists,
 | 
						|
		Effect:   v1.TaintEffectNoSchedule,
 | 
						|
	}
 | 
						|
 | 
						|
	bestEffortPod := newPod(nsName, "besteffort-pod", nil, nil)
 | 
						|
	burstablePod := newPod(nsName, "burstable-pod", podRes, nil)
 | 
						|
	guaranteePod := newPod(nsName, "guarantee-pod", podRes, podRes)
 | 
						|
 | 
						|
	type podCase struct {
 | 
						|
		pod         *v1.Pod
 | 
						|
		tolerations []v1.Toleration
 | 
						|
		fits        bool
 | 
						|
	}
 | 
						|
 | 
						|
	// switch to table driven testings
 | 
						|
	tests := []struct {
 | 
						|
		name           string
 | 
						|
		existingTaints []v1.Taint
 | 
						|
		nodeConditions []v1.NodeCondition
 | 
						|
		unschedulable  bool
 | 
						|
		expectedTaints []v1.Taint
 | 
						|
		pods           []podCase
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "not-ready node",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionFalse,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeNotReady,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{notReadyToleration},
 | 
						|
					fits:        true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "unreachable node",
 | 
						|
			existingTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeUnreachable,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionUnknown, // node status is "Unknown"
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeUnreachable,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{unreachableToleration},
 | 
						|
					fits:        true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:          "unschedulable node",
 | 
						|
			unschedulable: true, // node.spec.unschedulable = true
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeUnschedulable,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{unschedulableToleration},
 | 
						|
					fits:        true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "out of disk node",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeOutOfDisk,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeOutOfDisk,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			// In OutOfDisk condition, only pods with toleration can be scheduled.
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{outOfDiskToleration},
 | 
						|
					fits:        true,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{diskPressureToleration},
 | 
						|
					fits:        false,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "memory pressure node",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeMemoryPressure,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeMemoryPressure,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			// In MemoryPressure condition, both Burstable and Guarantee pods are scheduled;
 | 
						|
			// BestEffort pod with toleration are also scheduled.
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{memoryPressureToleration},
 | 
						|
					fits:        true,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{diskPressureToleration},
 | 
						|
					fits:        false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: true,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "disk pressure node",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeDiskPressure,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeDiskPressure,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			// In DiskPressure condition, only pods with toleration can be scheduled.
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{diskPressureToleration},
 | 
						|
					fits:        true,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{memoryPressureToleration},
 | 
						|
					fits:        false,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "network unavailable and node is ready",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeNetworkUnavailable,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeNetworkUnavailable,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod: burstablePod,
 | 
						|
					tolerations: []v1.Toleration{
 | 
						|
						networkUnavailableToleration,
 | 
						|
					},
 | 
						|
					fits: true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "network unavailable and node is not ready",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodeNetworkUnavailable,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionFalse,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeNetworkUnavailable,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeNotReady,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod: burstablePod,
 | 
						|
					tolerations: []v1.Toleration{
 | 
						|
						networkUnavailableToleration,
 | 
						|
					},
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod: burstablePod,
 | 
						|
					tolerations: []v1.Toleration{
 | 
						|
						networkUnavailableToleration,
 | 
						|
						notReadyToleration,
 | 
						|
					},
 | 
						|
					fits: true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "pid pressure node",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodePIDPressure,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodePIDPressure,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			pods: []podCase{
 | 
						|
				{
 | 
						|
					pod:  bestEffortPod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  burstablePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:  guaranteePod,
 | 
						|
					fits: false,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					pod:         bestEffortPod,
 | 
						|
					tolerations: []v1.Toleration{pidPressureToleration},
 | 
						|
					fits:        true,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "multi taints on node",
 | 
						|
			nodeConditions: []v1.NodeCondition{
 | 
						|
				{
 | 
						|
					Type:   v1.NodePIDPressure,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeMemoryPressure,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeDiskPressure,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Type:   v1.NodeReady,
 | 
						|
					Status: v1.ConditionTrue,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expectedTaints: []v1.Taint{
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeDiskPressure,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodeMemoryPressure,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
				{
 | 
						|
					Key:    algorithm.TaintNodePIDPressure,
 | 
						|
					Effect: v1.TaintEffectNoSchedule,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			node := &v1.Node{
 | 
						|
				ObjectMeta: metav1.ObjectMeta{
 | 
						|
					Name: "node-1",
 | 
						|
				},
 | 
						|
				Spec: v1.NodeSpec{
 | 
						|
					Unschedulable: test.unschedulable,
 | 
						|
					Taints:        test.existingTaints,
 | 
						|
				},
 | 
						|
				Status: v1.NodeStatus{
 | 
						|
					Capacity:    nodeRes,
 | 
						|
					Allocatable: nodeRes,
 | 
						|
					Conditions:  test.nodeConditions,
 | 
						|
				},
 | 
						|
			}
 | 
						|
 | 
						|
			if _, err := cs.CoreV1().Nodes().Create(node); err != nil {
 | 
						|
				t.Errorf("Failed to create node, err: %v", err)
 | 
						|
			}
 | 
						|
			if err := waitForNodeTaints(cs, node, test.expectedTaints); err != nil {
 | 
						|
				t.Errorf("Failed to taint node, err: %v", err)
 | 
						|
			}
 | 
						|
 | 
						|
			var pods []*v1.Pod
 | 
						|
			for i, p := range test.pods {
 | 
						|
				pod := p.pod.DeepCopy()
 | 
						|
				pod.Name = fmt.Sprintf("%s-%d", pod.Name, i)
 | 
						|
				pod.Spec.Tolerations = p.tolerations
 | 
						|
 | 
						|
				createdPod, err := cs.CoreV1().Pods(pod.Namespace).Create(pod)
 | 
						|
				if err != nil {
 | 
						|
					t.Fatalf("Failed to create pod %s/%s, error: %v",
 | 
						|
						pod.Namespace, pod.Name, err)
 | 
						|
				}
 | 
						|
 | 
						|
				pods = append(pods, createdPod)
 | 
						|
 | 
						|
				if p.fits {
 | 
						|
					if err := waitForPodToSchedule(cs, createdPod); err != nil {
 | 
						|
						t.Errorf("Failed to schedule pod %s/%s on the node, err: %v",
 | 
						|
							pod.Namespace, pod.Name, err)
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					if err := waitForPodUnschedulable(cs, createdPod); err != nil {
 | 
						|
						t.Errorf("Unschedulable pod %s/%s gets scheduled on the node, err: %v",
 | 
						|
							pod.Namespace, pod.Name, err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			cleanupPods(cs, t, pods)
 | 
						|
			cleanupNodes(cs, t)
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |