From 5d843d1f083a537fe3b96b15dfebd02329fd65b0 Mon Sep 17 00:00:00 2001 From: Adi Yadav Date: Thu, 11 Apr 2019 23:24:20 -0400 Subject: [PATCH] Added manual changes. --- cmd/descheduler/app/options/options.go | 2 ++ pkg/apis/componentconfig/types.go | 3 +++ pkg/apis/componentconfig/v1alpha1/types.go | 3 +++ pkg/descheduler/pod/pods.go | 8 ++++---- pkg/descheduler/strategies/duplicates.go | 10 +++++----- pkg/descheduler/strategies/duplicates_test.go | 2 +- pkg/descheduler/strategies/lownodeutilization.go | 10 +++++----- pkg/descheduler/strategies/lownodeutilization_test.go | 4 ++-- pkg/descheduler/strategies/node_affinity.go | 6 +++--- pkg/descheduler/strategies/node_affinity_test.go | 2 +- pkg/descheduler/strategies/pod_antiaffinity.go | 6 +++--- pkg/descheduler/strategies/pod_antiaffinity_test.go | 4 ++-- 12 files changed, 34 insertions(+), 26 deletions(-) diff --git a/cmd/descheduler/app/options/options.go b/cmd/descheduler/app/options/options.go index d59e51c75..72bfb4163 100644 --- a/cmd/descheduler/app/options/options.go +++ b/cmd/descheduler/app/options/options.go @@ -57,4 +57,6 @@ func (rs *DeschedulerServer) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&rs.NodeSelector, "node-selector", rs.NodeSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") // max-no-pods-to-evict limits the maximum number of pods to be evicted per node by descheduler. fs.IntVar(&rs.MaxNoOfPodsToEvictPerNode, "max-pods-to-evict-per-node", rs.MaxNoOfPodsToEvictPerNode, "Limits the maximum number of pods to be evicted per node by descheduler") + // evict-local-storage-pods allows eviction of pods that are using local storage. This is false by default. + fs.BoolVar(&rs.EvictLocalStoragePods, "evict-local-storage-pods", rs.EvictLocalStoragePods, "Enables evicting pods using local storage by descheduler") } diff --git a/pkg/apis/componentconfig/types.go b/pkg/apis/componentconfig/types.go index b5cb1600a..1588d59f5 100644 --- a/pkg/apis/componentconfig/types.go +++ b/pkg/apis/componentconfig/types.go @@ -45,4 +45,7 @@ type DeschedulerConfiguration struct { // MaxNoOfPodsToEvictPerNode restricts maximum of pods to be evicted per node. MaxNoOfPodsToEvictPerNode int + + // EvictLocalStoragePods allows pods using local storage to be evicted. + EvictLocalStoragePods bool } diff --git a/pkg/apis/componentconfig/v1alpha1/types.go b/pkg/apis/componentconfig/v1alpha1/types.go index 96780293d..69121ea63 100644 --- a/pkg/apis/componentconfig/v1alpha1/types.go +++ b/pkg/apis/componentconfig/v1alpha1/types.go @@ -45,4 +45,7 @@ type DeschedulerConfiguration struct { // MaxNoOfPodsToEvictPerNode restricts maximum of pods to be evicted per node. MaxNoOfPodsToEvictPerNode int `json:"maxNoOfPodsToEvictPerNode,omitempty"` + + // EvictLocalStoragePods allows pods using local storage to be evicted. + EvictLocalStoragePods bool `json:"evictLocalStoragePods,omitempty"` } diff --git a/pkg/descheduler/pod/pods.go b/pkg/descheduler/pod/pods.go index 84508fbbd..26b85f400 100644 --- a/pkg/descheduler/pod/pods.go +++ b/pkg/descheduler/pod/pods.go @@ -52,23 +52,23 @@ func IsLatencySensitivePod(pod *v1.Pod) bool { } // IsEvictable checks if a pod is evictable or not. -func IsEvictable(pod *v1.Pod) bool { +func IsEvictable(pod *v1.Pod, evictLocalStoragePods bool) bool { ownerRefList := OwnerRef(pod) - if IsMirrorPod(pod) || IsPodWithLocalStorage(pod) || len(ownerRefList) == 0 || IsDaemonsetPod(ownerRefList) || IsCriticalPod(pod) { + if IsMirrorPod(pod) || (!evictLocalStoragePods && IsPodWithLocalStorage(pod)) || len(ownerRefList) == 0 || IsDaemonsetPod(ownerRefList) || IsCriticalPod(pod) { return false } return true } // ListEvictablePodsOnNode returns the list of evictable pods on node. -func ListEvictablePodsOnNode(client clientset.Interface, node *v1.Node) ([]*v1.Pod, error) { +func ListEvictablePodsOnNode(client clientset.Interface, node *v1.Node, evictLocalStoragePods bool) ([]*v1.Pod, error) { pods, err := ListPodsOnANode(client, node) if err != nil { return []*v1.Pod{}, err } evictablePods := make([]*v1.Pod, 0) for _, pod := range pods { - if !IsEvictable(pod) { + if !IsEvictable(pod, evictLocalStoragePods) { continue } else { evictablePods = append(evictablePods, pod) diff --git a/pkg/descheduler/strategies/duplicates.go b/pkg/descheduler/strategies/duplicates.go index 37a4d53ac..607c297ee 100644 --- a/pkg/descheduler/strategies/duplicates.go +++ b/pkg/descheduler/strategies/duplicates.go @@ -40,15 +40,15 @@ func RemoveDuplicatePods(ds *options.DeschedulerServer, strategy api.Descheduler if !strategy.Enabled { return } - deleteDuplicatePods(ds.Client, policyGroupVersion, nodes, ds.DryRun, nodepodCount, ds.MaxNoOfPodsToEvictPerNode) + deleteDuplicatePods(ds.Client, policyGroupVersion, nodes, ds.DryRun, nodepodCount, ds.MaxNoOfPodsToEvictPerNode, ds.EvictLocalStoragePods) } // deleteDuplicatePods evicts the pod from node and returns the count of evicted pods. -func deleteDuplicatePods(client clientset.Interface, policyGroupVersion string, nodes []*v1.Node, dryRun bool, nodepodCount nodePodEvictedCount, maxPodsToEvict int) int { +func deleteDuplicatePods(client clientset.Interface, policyGroupVersion string, nodes []*v1.Node, dryRun bool, nodepodCount nodePodEvictedCount, maxPodsToEvict int, evictLocalStoragePods bool) int { podsEvicted := 0 for _, node := range nodes { glog.V(1).Infof("Processing node: %#v", node.Name) - dpm := ListDuplicatePodsOnANode(client, node) + dpm := ListDuplicatePodsOnANode(client, node, evictLocalStoragePods) for creator, pods := range dpm { if len(pods) > 1 { glog.V(1).Infof("%#v", creator) @@ -73,8 +73,8 @@ func deleteDuplicatePods(client clientset.Interface, policyGroupVersion string, } // ListDuplicatePodsOnANode lists duplicate pods on a given node. -func ListDuplicatePodsOnANode(client clientset.Interface, node *v1.Node) DuplicatePodsMap { - pods, err := podutil.ListEvictablePodsOnNode(client, node) +func ListDuplicatePodsOnANode(client clientset.Interface, node *v1.Node, evictLocalStoragePods bool) DuplicatePodsMap { + pods, err := podutil.ListEvictablePodsOnNode(client, node, evictLocalStoragePods) if err != nil { return nil } diff --git a/pkg/descheduler/strategies/duplicates_test.go b/pkg/descheduler/strategies/duplicates_test.go index d642d642a..a35838dc9 100644 --- a/pkg/descheduler/strategies/duplicates_test.go +++ b/pkg/descheduler/strategies/duplicates_test.go @@ -77,7 +77,7 @@ func TestFindDuplicatePods(t *testing.T) { }) npe := nodePodEvictedCount{} npe[node] = 0 - podsEvicted := deleteDuplicatePods(fakeClient, "v1", []*v1.Node{node}, false, npe, 2) + podsEvicted := deleteDuplicatePods(fakeClient, "v1", []*v1.Node{node}, false, npe, 2, false) if podsEvicted != expectedEvictedPodCount { t.Errorf("Unexpected no of pods evicted") } diff --git a/pkg/descheduler/strategies/lownodeutilization.go b/pkg/descheduler/strategies/lownodeutilization.go index a840171c8..79229ff88 100644 --- a/pkg/descheduler/strategies/lownodeutilization.go +++ b/pkg/descheduler/strategies/lownodeutilization.go @@ -61,7 +61,7 @@ func LowNodeUtilization(ds *options.DeschedulerServer, strategy api.DeschedulerS } npm := createNodePodsMap(ds.Client, nodes) - lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds) + lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds, ds.EvictLocalStoragePods) glog.V(1).Infof("Criteria for a node under utilization: CPU: %v, Mem: %v, Pods: %v", thresholds[v1.ResourceCPU], thresholds[v1.ResourceMemory], thresholds[v1.ResourcePods]) @@ -131,10 +131,10 @@ func validateTargetThresholds(targetThresholds api.ResourceThresholds) bool { // classifyNodes classifies the nodes into low-utilization or high-utilization nodes. If a node lies between // low and high thresholds, it is simply ignored. -func classifyNodes(npm NodePodsMap, thresholds api.ResourceThresholds, targetThresholds api.ResourceThresholds) ([]NodeUsageMap, []NodeUsageMap) { +func classifyNodes(npm NodePodsMap, thresholds api.ResourceThresholds, targetThresholds api.ResourceThresholds, evictLocalStoragePods bool) ([]NodeUsageMap, []NodeUsageMap) { lowNodes, targetNodes := []NodeUsageMap{}, []NodeUsageMap{} for node, pods := range npm { - usage, allPods, nonRemovablePods, bePods, bPods, gPods := NodeUtilization(node, pods) + usage, allPods, nonRemovablePods, bePods, bPods, gPods := NodeUtilization(node, pods, evictLocalStoragePods) nuMap := NodeUsageMap{node, usage, allPods, nonRemovablePods, bePods, bPods, gPods} // Check if node is underutilized and if we can schedule pods on it. @@ -351,7 +351,7 @@ func IsNodeWithLowUtilization(nodeThresholds api.ResourceThresholds, thresholds } // Nodeutilization returns the current usage of node. -func NodeUtilization(node *v1.Node, pods []*v1.Pod) (api.ResourceThresholds, []*v1.Pod, []*v1.Pod, []*v1.Pod, []*v1.Pod, []*v1.Pod) { +func NodeUtilization(node *v1.Node, pods []*v1.Pod, evictLocalStoragePods bool) (api.ResourceThresholds, []*v1.Pod, []*v1.Pod, []*v1.Pod, []*v1.Pod, []*v1.Pod) { bePods := []*v1.Pod{} nonRemovablePods := []*v1.Pod{} bPods := []*v1.Pod{} @@ -359,7 +359,7 @@ func NodeUtilization(node *v1.Node, pods []*v1.Pod) (api.ResourceThresholds, []* totalReqs := map[v1.ResourceName]resource.Quantity{} for _, pod := range pods { // We need to compute the usage of nonRemovablePods unless it is a best effort pod. So, cannot use podutil.ListEvictablePodsOnNode - if !podutil.IsEvictable(pod) { + if !podutil.IsEvictable(pod, evictLocalStoragePods) { nonRemovablePods = append(nonRemovablePods, pod) if podutil.IsBestEffortPod(pod) { continue diff --git a/pkg/descheduler/strategies/lownodeutilization_test.go b/pkg/descheduler/strategies/lownodeutilization_test.go index c4cb1cb62..54df11f12 100644 --- a/pkg/descheduler/strategies/lownodeutilization_test.go +++ b/pkg/descheduler/strategies/lownodeutilization_test.go @@ -112,7 +112,7 @@ func TestLowNodeUtilizationWithoutPriority(t *testing.T) { }) expectedPodsEvicted := 3 npm := createNodePodsMap(fakeClient, []*v1.Node{n1, n2, n3}) - lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds) + lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds, false) if len(lowNodes) != 1 { t.Errorf("After ignoring unschedulable nodes, expected only one node to be under utilized.") } @@ -217,7 +217,7 @@ func TestLowNodeUtilizationWithPriorities(t *testing.T) { }) expectedPodsEvicted := 3 npm := createNodePodsMap(fakeClient, []*v1.Node{n1, n2, n3}) - lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds) + lowNodes, targetNodes := classifyNodes(npm, thresholds, targetThresholds, false) if len(lowNodes) != 1 { t.Errorf("After ignoring unschedulable nodes, expected only one node to be under utilized.") } diff --git a/pkg/descheduler/strategies/node_affinity.go b/pkg/descheduler/strategies/node_affinity.go index b8c35088a..667313df1 100644 --- a/pkg/descheduler/strategies/node_affinity.go +++ b/pkg/descheduler/strategies/node_affinity.go @@ -27,10 +27,10 @@ import ( ) func RemovePodsViolatingNodeAffinity(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, evictionPolicyGroupVersion string, nodes []*v1.Node, nodePodCount nodePodEvictedCount) { - removePodsViolatingNodeAffinityCount(ds, strategy, evictionPolicyGroupVersion, nodes, nodePodCount, ds.MaxNoOfPodsToEvictPerNode) + removePodsViolatingNodeAffinityCount(ds, strategy, evictionPolicyGroupVersion, nodes, nodePodCount, ds.MaxNoOfPodsToEvictPerNode, ds.EvictLocalStoragePods) } -func removePodsViolatingNodeAffinityCount(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, evictionPolicyGroupVersion string, nodes []*v1.Node, nodepodCount nodePodEvictedCount, maxPodsToEvict int) int { +func removePodsViolatingNodeAffinityCount(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, evictionPolicyGroupVersion string, nodes []*v1.Node, nodepodCount nodePodEvictedCount, maxPodsToEvict int, evictLocalStoragePods bool) int { evictedPodCount := 0 if !strategy.Enabled { return evictedPodCount @@ -44,7 +44,7 @@ func removePodsViolatingNodeAffinityCount(ds *options.DeschedulerServer, strateg for _, node := range nodes { glog.V(1).Infof("Processing node: %#v\n", node.Name) - pods, err := podutil.ListEvictablePodsOnNode(ds.Client, node) + pods, err := podutil.ListEvictablePodsOnNode(ds.Client, node, evictLocalStoragePods) if err != nil { glog.Errorf("failed to get pods from %v: %v", node.Name, err) } diff --git a/pkg/descheduler/strategies/node_affinity_test.go b/pkg/descheduler/strategies/node_affinity_test.go index 8ba14fe14..bedae1893 100644 --- a/pkg/descheduler/strategies/node_affinity_test.go +++ b/pkg/descheduler/strategies/node_affinity_test.go @@ -176,7 +176,7 @@ func TestRemovePodsViolatingNodeAffinity(t *testing.T) { Client: fakeClient, } - actualEvictedPodCount := removePodsViolatingNodeAffinityCount(&ds, tc.strategy, "v1", tc.nodes, tc.npe, tc.maxPodsToEvict) + actualEvictedPodCount := removePodsViolatingNodeAffinityCount(&ds, tc.strategy, "v1", tc.nodes, tc.npe, tc.maxPodsToEvict, false) if actualEvictedPodCount != tc.expectedEvictedPodCount { t.Errorf("Test %#v failed, expected %v pod evictions, but got %v pod evictions\n", tc.description, tc.expectedEvictedPodCount, actualEvictedPodCount) } diff --git a/pkg/descheduler/strategies/pod_antiaffinity.go b/pkg/descheduler/strategies/pod_antiaffinity.go index 06c74ebab..3cbf74c46 100644 --- a/pkg/descheduler/strategies/pod_antiaffinity.go +++ b/pkg/descheduler/strategies/pod_antiaffinity.go @@ -35,15 +35,15 @@ func RemovePodsViolatingInterPodAntiAffinity(ds *options.DeschedulerServer, stra if !strategy.Enabled { return } - removePodsWithAffinityRules(ds.Client, policyGroupVersion, nodes, ds.DryRun, nodePodCount, ds.MaxNoOfPodsToEvictPerNode) + removePodsWithAffinityRules(ds.Client, policyGroupVersion, nodes, ds.DryRun, nodePodCount, ds.MaxNoOfPodsToEvictPerNode, ds.EvictLocalStoragePods) } // removePodsWithAffinityRules evicts pods on the node which are having a pod affinity rules. -func removePodsWithAffinityRules(client clientset.Interface, policyGroupVersion string, nodes []*v1.Node, dryRun bool, nodePodCount nodePodEvictedCount, maxPodsToEvict int) int { +func removePodsWithAffinityRules(client clientset.Interface, policyGroupVersion string, nodes []*v1.Node, dryRun bool, nodePodCount nodePodEvictedCount, maxPodsToEvict int, evictLocalStoragePods bool) int { podsEvicted := 0 for _, node := range nodes { glog.V(1).Infof("Processing node: %#v\n", node.Name) - pods, err := podutil.ListEvictablePodsOnNode(client, node) + pods, err := podutil.ListEvictablePodsOnNode(client, node, evictLocalStoragePods) if err != nil { return 0 } diff --git a/pkg/descheduler/strategies/pod_antiaffinity_test.go b/pkg/descheduler/strategies/pod_antiaffinity_test.go index 8ec8bdb5c..f4a5b2d86 100644 --- a/pkg/descheduler/strategies/pod_antiaffinity_test.go +++ b/pkg/descheduler/strategies/pod_antiaffinity_test.go @@ -55,13 +55,13 @@ func TestPodAntiAffinity(t *testing.T) { npe := nodePodEvictedCount{} npe[node] = 0 expectedEvictedPodCount := 3 - podsEvicted := removePodsWithAffinityRules(fakeClient, "v1", []*v1.Node{node}, false, npe, 0) + podsEvicted := removePodsWithAffinityRules(fakeClient, "v1", []*v1.Node{node}, false, npe, 0, false) if podsEvicted != expectedEvictedPodCount { t.Errorf("Unexpected no of pods evicted: pods evicted: %d, expected: %d", podsEvicted, expectedEvictedPodCount) } npe[node] = 0 expectedEvictedPodCount = 1 - podsEvicted = removePodsWithAffinityRules(fakeClient, "v1", []*v1.Node{node}, false, npe, 1) + podsEvicted = removePodsWithAffinityRules(fakeClient, "v1", []*v1.Node{node}, false, npe, 1, false) if podsEvicted != expectedEvictedPodCount { t.Errorf("Unexpected no of pods evicted: pods evicted: %d, expected: %d", podsEvicted, expectedEvictedPodCount) }