Skip to content

Commit 587aee7

Browse files
committed
implement Evict
1 parent 44c8701 commit 587aee7

File tree

17 files changed

+140
-233
lines changed

17 files changed

+140
-233
lines changed

pkg/handler/deschedule.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type descheduleHandler struct {
1212

1313
func (dh *descheduleHandler) Handle(event Event) {
1414
if timer.IsOutOfTime() {
15-
fmt.Println("Deschedule event aborted by timer.")
15+
fmt.Println("Deschedule event aborted by timer")
1616
return
1717
}
1818

@@ -21,12 +21,15 @@ func (dh *descheduleHandler) Handle(event Event) {
2121
if !ok {
2222
return
2323
}
24-
fmt.Println("descheduleHandler: Deschedule Triggered, start picking Pods.")
25-
_, err := predictor.GetEvictablePods(busyNodes)
24+
fmt.Println("descheduleHandler: Deschedule Triggered, start picking Pods")
25+
evictSize := 2
26+
pods, err := predictor.GetEvictPods(busyNodes, evictSize)
2627
if err != nil {
2728
fmt.Println(err)
2829
return
2930
}
31+
fmt.Println("descheduleHandler: Pods picking done, start to evict")
32+
predictor.Evict(pods)
3033
isRecovering = true
3134
fmt.Println("deschedule event handled")
3235
}

pkg/predictor/node.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type nodeScore struct {
1919
// Splite node into high spared nodes list and low spared state nodes list
2020
func GetBusyNodes() ([]*api_v1.Node, bool) {
2121
operatableNodes, _ := getOperatableNodes()
22+
// TODO: remove Comment marks
2223
/*if len(operatableNodes) < 2 {
2324
fmt.Println("Deschedule event droped because Operatable node is less than 2")
2425
return []*api_v1.Node{}, []*api_v1.Node{}, false

pkg/predictor/pod.go

Lines changed: 89 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,57 @@ package predictor
33
import (
44
"fmt"
55

6-
"github.com/kubernetes/kubernetes/pkg/kubelet/types"
76
api_v1 "k8s.io/api/core/v1"
7+
policy "k8s.io/api/policy/v1beta1"
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
89
"k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/fields"
1011
api "k8s.io/kubernetes/pkg/apis/core"
12+
"k8s.io/kubernetes/pkg/kubelet/types"
1113
)
1214

13-
func GetEvictablePods(nodes []*api_v1.Node) ([]*api_v1.Pod, error) {
14-
pods, err := getPodsOnNode(nodes[0])
15+
func GetEvictPods(nodes []*api_v1.Node, evictSize int) ([]*api_v1.Pod, error) {
16+
var evictPods []*api_v1.Pod
17+
for _, node := range nodes {
18+
pods, err := getEvictablePods(node)
19+
if err != nil {
20+
fmt.Printf("Get evictable pods on %v failed, skipping this node. %v\n", node.ObjectMeta.Name, err)
21+
}
22+
rankedPods := rankEvictablePods(pods)
23+
evictPods = append(evictPods, rankedPods...)
24+
if len(evictPods) >= evictSize {
25+
evictPods = evictPods[:evictSize]
26+
break
27+
}
28+
}
29+
return evictPods, nil
30+
}
31+
32+
func rankEvictablePods(pods []*api_v1.Pod) []*api_v1.Pod {
33+
return pods
34+
}
35+
36+
func getUnfitPods(node *api_v1.Node) []*api_v1.Pod {
37+
return []*api_v1.Pod{}
38+
}
39+
40+
func CheckReplicas(pods []*api_v1.Pod) []*api_v1.Pod {
41+
for _, pod := range pods {
42+
ownerRefList := ownerRef(pod)
43+
if isReplicaSetPod(ownerRefList) {
44+
45+
}
46+
}
47+
return []*api_v1.Pod{}
48+
49+
}
50+
51+
func getPodsHaveReplicas(node *api_v1.Node) []*api_v1.Pod {
52+
return []*api_v1.Pod{}
53+
}
54+
55+
func getEvictablePods(node *api_v1.Node) ([]*api_v1.Pod, error) {
56+
pods, err := getPodsOnNode(node)
1557
if err != nil {
1658
return []*api_v1.Pod{}, err
1759
}
@@ -46,6 +88,15 @@ func ownerRef(pod *api_v1.Pod) []v1.OwnerReference {
4688
return pod.ObjectMeta.GetOwnerReferences()
4789
}
4890

91+
func isReplicaSetPod(ownerRefList []v1.OwnerReference) bool {
92+
for _, ownerRef := range ownerRefList {
93+
if ownerRef.Kind == "ReplicaSet" {
94+
return true
95+
}
96+
}
97+
return false
98+
}
99+
49100
func isDaemonsetPod(ownerRefList []v1.OwnerReference) bool {
50101
for _, ownerRef := range ownerRefList {
51102
if ownerRef.Kind == "DaemonSet" {
@@ -74,19 +125,6 @@ func isCriticalPod(pod *api_v1.Pod) bool {
74125
return types.IsCriticalPod(pod)
75126
}
76127

77-
func getUnfitPods(node *api_v1.Node) []*api_v1.Pod {
78-
return []*api_v1.Pod{}
79-
}
80-
81-
func isWithReplica(node *api_v1.Node) []*api_v1.Pod {
82-
return []*api_v1.Pod{}
83-
84-
}
85-
86-
func getPodsHaveReplicas(node *api_v1.Node) []*api_v1.Pod {
87-
return []*api_v1.Pod{}
88-
}
89-
90128
func getPodsOnNode(node *api_v1.Node) ([]*api_v1.Pod, error) {
91129
fieldSelector, err := fields.ParseSelector("spec.nodeName=" + node.Name + ",status.phase!=" + string(api.PodFailed))
92130
if err != nil {
@@ -105,3 +143,38 @@ func getPodsOnNode(node *api_v1.Node) ([]*api_v1.Pod, error) {
105143
}
106144
return pods, nil
107145
}
146+
147+
func Evict(pods []*api_v1.Pod) {
148+
for _, pod := range pods {
149+
evictPod(pod)
150+
}
151+
}
152+
153+
func evictPod(pod *api_v1.Pod) (bool, error) {
154+
if conf.DryRun {
155+
return true, nil
156+
}
157+
deleteOptions := &v1.DeleteOptions{}
158+
evictionVersion, _ := supportEviction()
159+
eviction := &policy.Eviction{
160+
TypeMeta: v1.TypeMeta{
161+
APIVersion: evictionVersion,
162+
Kind: "Eviction",
163+
},
164+
ObjectMeta: v1.ObjectMeta{
165+
Name: pod.Name,
166+
Namespace: pod.Namespace,
167+
},
168+
DeleteOptions: deleteOptions,
169+
}
170+
err := client.Policy().Evictions(eviction.Namespace).Evict(eviction)
171+
if err == nil {
172+
return true, nil
173+
} else if apierrors.IsTooManyRequests(err) {
174+
return false, fmt.Errorf("error when evicting pod (ignoring) %q: %v", pod.Name, err)
175+
} else if apierrors.IsNotFound(err) {
176+
return true, fmt.Errorf("pod not found when evicting %q: %v", pod.Name, err)
177+
} else {
178+
return false, err
179+
}
180+
}

pkg/predictor/predictor.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,35 @@ func scoreResource(usage, maxUsage, maxSpared, usageScore, sparedScore, normalSc
5454
}
5555
return usageScore, sparedScore, normalScore
5656
}
57+
58+
// SupportEviction uses Discovery API to find out if the server support eviction subresource
59+
// If support, it will return its groupVersion; Otherwise, it will return ""
60+
func supportEviction() (string, error) {
61+
discoveryClient := client.Discovery()
62+
groupList, err := discoveryClient.ServerGroups()
63+
if err != nil {
64+
return "", err
65+
}
66+
foundPolicyGroup := false
67+
var policyGroupVersion string
68+
for _, group := range groupList.Groups {
69+
if group.Name == "policy" {
70+
foundPolicyGroup = true
71+
policyGroupVersion = group.PreferredVersion.GroupVersion
72+
break
73+
}
74+
}
75+
if !foundPolicyGroup {
76+
return "", nil
77+
}
78+
resourceList, err := discoveryClient.ServerResourcesForGroupVersion("v1")
79+
if err != nil {
80+
return "", err
81+
}
82+
for _, resource := range resourceList.APIResources {
83+
if resource.Name == "pods/eviction" && resource.Kind == "Eviction" {
84+
return policyGroupVersion, nil
85+
}
86+
}
87+
return "", nil
88+
}

0 commit comments

Comments
 (0)