1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-26 05:14:13 +01:00

Changes and file reorganization

This commit is contained in:
ravisantoshgudimetla
2017-09-01 23:54:02 -04:00
parent 39d3fa7776
commit c1140e7b02
5 changed files with 321 additions and 138 deletions

View File

@@ -0,0 +1,82 @@
/*
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 node
import (
"fmt"
"testing"
"github.com/aveshagarwal/rescheduler/test"
"k8s.io/apimachinery/pkg/runtime"
core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
)
func TestReadyNodes(t *testing.T) {
fakeClient := &fake.Clientset{}
node1 := test.BuildTestNode("node1", 1000, 2000, 9)
node1.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue}}
node2 := test.BuildTestNode("node2", 1000, 2000, 9)
node3 := test.BuildTestNode("node3", 1000, 2000, 9)
node3.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeMemoryPressure, Status: v1.ConditionTrue}}
node4 := test.BuildTestNode("node4", 1000, 2000, 9)
node4.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeNetworkUnavailable, Status: v1.ConditionTrue}}
node5 := test.BuildTestNode("node5", 1000, 2000, 9)
node5.Spec.Unschedulable = true
node6 := test.BuildTestNode("node6", 1000, 2000, 9)
node6.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionFalse}}
fakeClient.Fake.AddReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) {
getAction := action.(core.GetAction)
switch getAction.GetName() {
case node1.Name:
return true, node1, nil
case node2.Name:
return true, node2, nil
case node3.Name:
return true, node3, nil
case node4.Name:
return true, node4, nil
case node5.Name:
return true, node5, nil
case node6.Name:
return true, node6, nil
}
return true, nil, fmt.Errorf("Wrong node: %v", getAction.GetName())
})
if !IsReady(node1) {
t.Errorf("Expected %v to be ready", node1.Name)
}
if !IsReady(node2) {
t.Errorf("Expected %v to be ready", node2.Name)
}
if !IsReady(node3) {
t.Errorf("Expected %v to be ready", node3.Name)
}
if !IsReady(node4) {
t.Errorf("Expected %v to be ready", node4.Name)
}
if !IsReady(node5) {
t.Errorf("Expected %v to be ready", node5.Name)
}
if IsReady(node6) {
t.Errorf("Expected %v to be not ready", node6.Name)
}
}

View File

@@ -0,0 +1,76 @@
/*
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 pod
import (
"testing"
"k8s.io/apimachinery/pkg/api/resource"
"github.com/aveshagarwal/rescheduler/test"
"k8s.io/kubernetes/pkg/api/v1"
)
func TestPodTypes(t *testing.T) {
n1 := test.BuildTestNode("node1", 1000, 2000, 9)
p1 := test.BuildTestPod("p1", 400, 0, n1.Name)
// These won't be evicted.
p2 := test.BuildTestPod("p2", 400, 0, n1.Name)
p3 := test.BuildTestPod("p3", 400, 0, n1.Name)
p4 := test.BuildTestPod("p4", 400, 0, n1.Name)
p5 := test.BuildTestPod("p5", 400, 0, n1.Name)
p1.Annotations = test.GetReplicaSetAnnotation()
// The following 4 pods won't get evicted.
// A daemonset.
p2.Annotations = test.GetDaemonSetAnnotation()
// A pod with local storage.
p3.Annotations = test.GetNormalPodAnnotation()
p3.Spec.Volumes = []v1.Volume{
{
Name: "sample",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{Path: "somePath"},
EmptyDir: &v1.EmptyDirVolumeSource{
SizeLimit: *resource.NewQuantity(int64(10), resource.BinarySI)},
},
},
}
// A Mirror Pod.
p4.Annotations = test.GetMirrorPodAnnotation()
// A Critical Pod.
p5.Namespace = "kube-system"
p5.Annotations = test.GetCriticalPodAnnotation()
if !IsMirrorPod(p4) {
t.Errorf("Expected p4 to be a mirror pod.")
}
if !IsCriticalPod(p5) {
t.Errorf("Expected p5 to be a critical pod.")
}
if !IsPodWithLocalStorage(p3) {
t.Errorf("Expected p3 to be a pod with local storage.")
}
sr, _ := CreatorRef(p2)
if !IsDaemonsetPod(sr) {
t.Errorf("Expected p2 to be a daemonset pod.")
}
sr, _ = CreatorRef(p1)
if IsDaemonsetPod(sr) || IsPodWithLocalStorage(p1) || IsCriticalPod(p1) || IsMirrorPod(p1) {
t.Errorf("Expected p1 to be a normal pod.")
}
}

View File

@@ -17,135 +17,37 @@ limitations under the License.
package strategies
import (
"fmt"
"testing"
"github.com/aveshagarwal/rescheduler/test"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
)
// TODO:@ravisantoshgudimetla. As of now building some test pods here. This needs to
// move to utils after refactor.
// buildTestPod creates a test pod with given parameters.
func buildTestPod(name string, cpu int64, memory int64, nodeName string) *v1.Pod {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: name,
SelfLink: fmt.Sprintf("/api/v1/namespaces/default/pods/%s", name),
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{},
},
},
},
NodeName: nodeName,
},
}
if cpu >= 0 {
pod.Spec.Containers[0].Resources.Requests[v1.ResourceCPU] = *resource.NewMilliQuantity(cpu, resource.DecimalSI)
}
if memory >= 0 {
pod.Spec.Containers[0].Resources.Requests[v1.ResourceMemory] = *resource.NewQuantity(memory, resource.DecimalSI)
}
return pod
}
// buildTestNode creates a node with specified capacity.
func buildTestNode(name string, millicpu int64, mem int64, pods int64) *v1.Node {
node := &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: name,
SelfLink: fmt.Sprintf("/api/v1/nodes/%s", name),
Labels: map[string]string{},
},
Status: v1.NodeStatus{
Capacity: v1.ResourceList{
v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI),
v1.ResourceCPU: *resource.NewMilliQuantity(millicpu, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(mem, resource.DecimalSI),
},
Allocatable: v1.ResourceList{
v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI),
v1.ResourceCPU: *resource.NewMilliQuantity(millicpu, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(mem, resource.DecimalSI),
},
Phase: v1.NodeRunning,
Conditions: []v1.NodeCondition{
{Type: v1.NodeReady, Status: v1.ConditionTrue},
},
},
}
return node
}
// getMirrorPodAnnotation returns the annotation needed for mirror pod.
func getMirrorPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
"kubernetes.io/config.source": "api",
"kubernetes.io/config.mirror": "mirror",
}
}
// getNormalPodAnnotation returns the annotation needed for a pod.
func getNormalPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
}
}
// getReplicaSetAnnotation returns the annotation needed for replicaset pod.
func getReplicaSetAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicaSet\"}}",
}
}
// getDaemonSetAnnotation returns the annotation needed for daemonset pod.
func getDaemonSetAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"DaemonSet\"}}",
}
}
// getCriticalPodAnnotation returns the annotation needed for critical pod.
func getCriticalPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
"scheduler.alpha.kubernetes.io/critical-pod": "",
}
}
//TODO:@ravisantoshgudimetla This could be made table driven.
func TestFindDuplicatePods(t *testing.T) {
node := buildTestNode("n1", 2000, 3000, 10)
p1 := buildTestPod("p1", 100, 0, node.Name)
p2 := buildTestPod("p2", 100, 0, node.Name)
p3 := buildTestPod("p3", 100, 0, node.Name)
p4 := buildTestPod("p4", 100, 0, node.Name)
p5 := buildTestPod("p5", 100, 0, node.Name)
p6 := buildTestPod("p6", 100, 0, node.Name)
p7 := buildTestPod("p7", 100, 0, node.Name)
node := test.BuildTestNode("n1", 2000, 3000, 10)
p1 := test.BuildTestPod("p1", 100, 0, node.Name)
p2 := test.BuildTestPod("p2", 100, 0, node.Name)
p3 := test.BuildTestPod("p3", 100, 0, node.Name)
p4 := test.BuildTestPod("p4", 100, 0, node.Name)
p5 := test.BuildTestPod("p5", 100, 0, node.Name)
p6 := test.BuildTestPod("p6", 100, 0, node.Name)
p7 := test.BuildTestPod("p7", 100, 0, node.Name)
// All the following pods expect for one will be evicted.
p1.Annotations = getReplicaSetAnnotation()
p2.Annotations = getReplicaSetAnnotation()
p3.Annotations = getReplicaSetAnnotation()
p1.Annotations = test.GetReplicaSetAnnotation()
p2.Annotations = test.GetReplicaSetAnnotation()
p3.Annotations = test.GetReplicaSetAnnotation()
// The following 4 pods won't get evicted.
// A daemonset.
p4.Annotations = getDaemonSetAnnotation()
p4.Annotations = test.GetDaemonSetAnnotation()
// A pod with local storage.
p5.Annotations = getNormalPodAnnotation()
p5.Annotations = test.GetNormalPodAnnotation()
p5.Spec.Volumes = []v1.Volume{
{
Name: "sample",
@@ -157,10 +59,10 @@ func TestFindDuplicatePods(t *testing.T) {
},
}
// A Mirror Pod.
p6.Annotations = getMirrorPodAnnotation()
p6.Annotations = test.GetMirrorPodAnnotation()
// A Critical Pod.
p7.Namespace = "kube-system"
p7.Annotations = getCriticalPodAnnotation()
p7.Annotations = test.GetCriticalPodAnnotation()
expectedEvictedPodCount := 2
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {

View File

@@ -18,14 +18,15 @@ package strategies
import (
"fmt"
"strings"
"testing"
"github.com/aveshagarwal/rescheduler/test"
"github.com/aveshagarwal/rescheduler/pkg/api"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
"strings"
"testing"
)
// TODO: Make this table driven.
@@ -37,29 +38,29 @@ func TestLowNodeUtilization(t *testing.T) {
targetThresholds[v1.ResourceCPU] = 50
targetThresholds[v1.ResourcePods] = 50
n1 := buildTestNode("n1", 4000, 3000, 9)
n2 := buildTestNode("n2", 4000, 3000, 10)
p1 := buildTestPod("p1", 400, 0, n1.Name)
p2 := buildTestPod("p2", 400, 0, n1.Name)
p3 := buildTestPod("p3", 400, 0, n1.Name)
p4 := buildTestPod("p4", 400, 0, n1.Name)
p5 := buildTestPod("p5", 400, 0, n1.Name)
n1 := test.BuildTestNode("n1", 4000, 3000, 9)
n2 := test.BuildTestNode("n2", 4000, 3000, 10)
p1 := test.BuildTestPod("p1", 400, 0, n1.Name)
p2 := test.BuildTestPod("p2", 400, 0, n1.Name)
p3 := test.BuildTestPod("p3", 400, 0, n1.Name)
p4 := test.BuildTestPod("p4", 400, 0, n1.Name)
p5 := test.BuildTestPod("p5", 400, 0, n1.Name)
// These won't be evicted.
p6 := buildTestPod("p6", 400, 0, n1.Name)
p7 := buildTestPod("p7", 400, 0, n1.Name)
p8 := buildTestPod("p8", 400, 0, n1.Name)
p6 := test.BuildTestPod("p6", 400, 0, n1.Name)
p7 := test.BuildTestPod("p7", 400, 0, n1.Name)
p8 := test.BuildTestPod("p8", 400, 0, n1.Name)
p1.Annotations = getReplicaSetAnnotation()
p2.Annotations = getReplicaSetAnnotation()
p3.Annotations = getReplicaSetAnnotation()
p4.Annotations = getReplicaSetAnnotation()
p5.Annotations = getReplicaSetAnnotation()
p1.Annotations = test.GetReplicaSetAnnotation()
p2.Annotations = test.GetReplicaSetAnnotation()
p3.Annotations = test.GetReplicaSetAnnotation()
p4.Annotations = test.GetReplicaSetAnnotation()
p5.Annotations = test.GetReplicaSetAnnotation()
// The following 4 pods won't get evicted.
// A daemonset.
p6.Annotations = getDaemonSetAnnotation()
p6.Annotations = test.GetDaemonSetAnnotation()
// A pod with local storage.
p7.Annotations = getNormalPodAnnotation()
p7.Annotations = test.GetNormalPodAnnotation()
p7.Spec.Volumes = []v1.Volume{
{
Name: "sample",
@@ -71,12 +72,12 @@ func TestLowNodeUtilization(t *testing.T) {
},
}
// A Mirror Pod.
p7.Annotations = getMirrorPodAnnotation()
p7.Annotations = test.GetMirrorPodAnnotation()
// A Critical Pod.
p8.Namespace = "kube-system"
p8.Annotations = getCriticalPodAnnotation()
p9 := buildTestPod("p9", 400, 0, n1.Name)
p9.Annotations = getReplicaSetAnnotation()
p8.Annotations = test.GetCriticalPodAnnotation()
p9 := test.BuildTestPod("p9", 400, 0, n1.Name)
p9.Annotations = test.GetReplicaSetAnnotation()
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {
list := action.(core.ListAction)
@@ -103,7 +104,7 @@ func TestLowNodeUtilization(t *testing.T) {
npm := CreateNodePodsMap(fakeClient, []*v1.Node{n1, n2})
lowNodes, targetNodes, _ := classifyNodes(npm, thresholds, targetThresholds)
podsEvicted := evictPodsFromTargetNodes(fakeClient, "v1", targetNodes, lowNodes, targetThresholds)
if expectedPodsEvicted != podsEvicted {
if expectedPodsEvicted != podsEvicted {
t.Errorf("Expected %#v pods to be evicted but %#v got evicted", expectedPodsEvicted)
}

122
test/test_utils.go Normal file
View File

@@ -0,0 +1,122 @@
/*
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 test
import ("fmt"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api/v1"
)
// TODO:@ravisantoshgudimetla. As of now building some test pods here. This needs to
// move to utils after refactor.
// buildTestPod creates a test pod with given parameters.
func BuildTestPod(name string, cpu int64, memory int64, nodeName string) *v1.Pod {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: name,
SelfLink: fmt.Sprintf("/api/v1/namespaces/default/pods/%s", name),
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{},
},
},
},
NodeName: nodeName,
},
}
if cpu >= 0 {
pod.Spec.Containers[0].Resources.Requests[v1.ResourceCPU] = *resource.NewMilliQuantity(cpu, resource.DecimalSI)
}
if memory >= 0 {
pod.Spec.Containers[0].Resources.Requests[v1.ResourceMemory] = *resource.NewQuantity(memory, resource.DecimalSI)
}
return pod
}
// GetMirrorPodAnnotation returns the annotation needed for mirror pod.
func GetMirrorPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
"kubernetes.io/config.source": "api",
"kubernetes.io/config.mirror": "mirror",
}
}
// GetNormalPodAnnotation returns the annotation needed for a pod.
func GetNormalPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
}
}
// GetReplicaSetAnnotation returns the annotation needed for replicaset pod.
func GetReplicaSetAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicaSet\"}}",
}
}
// GetDaemonSetAnnotation returns the annotation needed for daemonset pod.
func GetDaemonSetAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"DaemonSet\"}}",
}
}
// GetCriticalPodAnnotation returns the annotation needed for critical pod.
func GetCriticalPodAnnotation() map[string]string {
return map[string]string{
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"Pod\"}}",
"scheduler.alpha.kubernetes.io/critical-pod": "",
}
}
// BuildTestNode creates a node with specified capacity.
func BuildTestNode(name string, millicpu int64, mem int64, pods int64) *v1.Node {
node := &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: name,
SelfLink: fmt.Sprintf("/api/v1/nodes/%s", name),
Labels: map[string]string{},
},
Status: v1.NodeStatus{
Capacity: v1.ResourceList{
v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI),
v1.ResourceCPU: *resource.NewMilliQuantity(millicpu, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(mem, resource.DecimalSI),
},
Allocatable: v1.ResourceList{
v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI),
v1.ResourceCPU: *resource.NewMilliQuantity(millicpu, resource.DecimalSI),
v1.ResourceMemory: *resource.NewQuantity(mem, resource.DecimalSI),
},
Phase: v1.NodeRunning,
Conditions: []v1.NodeCondition{
{Type: v1.NodeReady, Status: v1.ConditionTrue},
},
},
}
return node
}