Skip to content

Commit cc1a584

Browse files
aalubinlwolf
authored andcommitted
Feature/v1.9 (#13)
* Add support for K8s 1.9, add support for deletion of pending job getting stuck
1 parent 1183f6f commit cc1a584

File tree

5 files changed

+69
-21
lines changed

5 files changed

+69
-21
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ bin/
77
.idea/
88
# Test binary, build with `go test -c`
99
*.test
10+
*.iml
1011

1112
# Output of the go coverage tool, specifically when used with LiteIDE
1213
*.out
1314

1415
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
15-
vendor/
16+
vendor/

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
NAME := kube-cleanup-operator
22
AUTHOR=lwolf
3-
VERSION ?= 0.3
3+
VERSION ?= 0.4
44
REGISTRY ?= quay.io
55
GIT_SHA=$(shell git --no-pager describe --always --dirty)
66
BUILD_TIME=$(shell date '+%s')

README.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,22 @@ Usage of ./bin/kube-cleanup-operator:
4040
-run-outside-cluster
4141
Set this flag when running outside of the cluster.
4242
-keep-successful
43-
the number of days to keep a succesfull job
43+
the number of hours to keep a succesfull job
4444
-1 - forever
4545
0 - never (default)
46-
>0 - number of days
46+
>0 - number of hours
4747
-keep-failures
48-
the number of days to keep a succesfull job
48+
the number of hours to keep a succesfull job
4949
-1 - forever (default)
5050
0 - never
51-
>0 - number of days
51+
>0 - number of hours
52+
-keep-pending
53+
the number of hours to keep a pending job
54+
-1 - forever (default)
55+
0 - forever
56+
>0 - number of hours
5257
-dry run
5358
Perform dry run, print only
5459
55-
$ ./bin/kube-cleanup-operator --run-outside-cluster --namespace=default --keep-successful=-1 --keep-failure=0
60+
$ ./bin/kube-cleanup-operator --run-outside-cluster --namespace=default --keep-successful=0 --keep-failure=-1 --keep-pending=-1
5661
```

cmd/main.go

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func main() {
3131
namespace := flag.String("namespace", "", "Watch only this namespaces")
3232
keepSuccessHours := flag.Int("keep-successful", 0, "Number of hours to keep successful jobs, -1 - forever, 0 - never (default), >0 number of hours")
3333
keepFailedHours := flag.Int("keep-failures", -1, "Number of hours to keep faild jobs, -1 - forever (default) 0 - never, >0 number of hours")
34+
keepPendingHours := flag.Int("keep-pending", -1, "Number of hours to keep pending jobs, -1 - forever (default) >0 number of hours")
3435
dryRun := flag.Bool("dry-run", false, "Print only, do not delete anything.")
3536
flag.Parse()
3637

@@ -45,6 +46,7 @@ func main() {
4546
"namespace": *namespace,
4647
"keepSuccessHours": strconv.Itoa(*keepSuccessHours),
4748
"keepFailedHours": strconv.Itoa(*keepFailedHours),
49+
"keepPendingHours": strconv.Itoa(*keepPendingHours),
4850
"dryRun": strconv.FormatBool(*dryRun),
4951
}
5052
if *dryRun {

pkg/controller/controller.go

+54-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"k8s.io/client-go/kubernetes"
99
"k8s.io/client-go/pkg/api/v1"
1010
"k8s.io/client-go/tools/cache"
11+
"k8s.io/apimachinery/pkg/version"
1112
"log"
1213
"reflect"
1314
"strconv"
@@ -41,7 +42,14 @@ func NewPodController(kclient *kubernetes.Clientset, opts map[string]string) *Po
4142

4243
keepSuccessHours, _ := strconv.Atoi(opts["keepSuccessHours"])
4344
keepFailedHours, _ := strconv.Atoi(opts["keepFailedHours"])
45+
keepPendingHours, _ := strconv.Atoi(opts["keepPendingHours"])
4446
dryRun, _ := strconv.ParseBool(opts["dryRun"])
47+
version, err := kclient.ServerVersion()
48+
49+
if err != nil{
50+
log.Fatalf("Failed to retrieve server version %v", err)
51+
}
52+
4553
// Create informer for watching Namespaces
4654
podInformer := cache.NewSharedIndexInformer(
4755
&cache.ListWatch{
@@ -59,11 +67,11 @@ func NewPodController(kclient *kubernetes.Clientset, opts map[string]string) *Po
5967
)
6068
podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
6169
AddFunc: func(cur interface{}) {
62-
podWatcher.doTheMagic(cur, keepSuccessHours, keepFailedHours, dryRun)
70+
podWatcher.doTheMagic(cur, keepSuccessHours, keepFailedHours, keepPendingHours, dryRun, *version)
6371
},
6472
UpdateFunc: func(old, cur interface{}) {
6573
if !reflect.DeepEqual(old, cur) {
66-
podWatcher.doTheMagic(cur, keepSuccessHours, keepFailedHours, dryRun)
74+
podWatcher.doTheMagic(cur, keepSuccessHours, keepFailedHours, keepPendingHours, dryRun, *version)
6775
}
6876
},
6977
})
@@ -90,12 +98,13 @@ func (c *PodController) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
9098
<-stopCh
9199
}
92100

93-
func (c *PodController) doTheMagic(cur interface{}, keepSuccessHours int, keepFailedHours int, dryRun bool) {
101+
func (c *PodController) doTheMagic(cur interface{}, keepSuccessHours int, keepFailedHours int, keepPendingHours int, dryRun bool, version version.Info) {
102+
94103
podObj := cur.(*v1.Pod)
95-
// handle jobs only
96-
var createdMeta CreatedByAnnotation
97-
json.Unmarshal([]byte(podObj.ObjectMeta.Annotations["kubernetes.io/created-by"]), &createdMeta)
98-
if createdMeta.Reference.Kind != "Job" {
104+
parentJobName := c.getParentJobName(podObj, version)
105+
// if we couldn't find a prent job name, ignore this pod
106+
if parentJobName == ""{
107+
log.Printf("Pod %s was not created by a job, ignoring.", podObj.Name)
99108
return
100109
}
101110

@@ -104,11 +113,15 @@ func (c *PodController) doTheMagic(cur interface{}, keepSuccessHours int, keepFa
104113
switch podObj.Status.Phase {
105114
case v1.PodSucceeded:
106115
if keepSuccessHours == 0 || (keepSuccessHours > 0 && executionTimeHours > float32(keepSuccessHours)) {
107-
c.deleteObjects(podObj, createdMeta, dryRun)
116+
c.deleteObjects(podObj, parentJobName, dryRun)
108117
}
109118
case v1.PodFailed:
110119
if keepFailedHours == 0 || (keepFailedHours > 0 && executionTimeHours > float32(keepFailedHours)) {
111-
c.deleteObjects(podObj, createdMeta, dryRun)
120+
c.deleteObjects(podObj, parentJobName, dryRun)
121+
}
122+
case v1.PodPending:
123+
if keepPendingHours > 0 && executionTimeHours > float32(keepPendingHours) {
124+
c.deleteObjects(podObj, parentJobName, dryRun)
112125
}
113126
default:
114127
return
@@ -132,7 +145,7 @@ func (c *PodController) getExecutionTimeHours(podObj *v1.Pod) (executionTimeHour
132145
return
133146
}
134147

135-
func (c *PodController) deleteObjects(podObj *v1.Pod, createdMeta CreatedByAnnotation, dryRun bool) {
148+
func (c *PodController) deleteObjects(podObj *v1.Pod, parentJobName string, dryRun bool) {
136149
// Delete Pod
137150
if !dryRun {
138151
log.Printf("Deleting pod '%s'", podObj.Name)
@@ -143,12 +156,39 @@ func (c *PodController) deleteObjects(podObj *v1.Pod, createdMeta CreatedByAnnot
143156
}
144157
// Delete Job itself
145158
if !dryRun {
146-
log.Printf("Deleting job '%s'", createdMeta.Reference.Name)
159+
log.Printf("Deleting job '%s'", parentJobName)
147160
var jo metav1.DeleteOptions
148-
c.kclient.BatchV1Client.Jobs(createdMeta.Reference.Namespace).Delete(createdMeta.Reference.Name, &jo)
161+
c.kclient.BatchV1Client.Jobs(podObj.Namespace).Delete(parentJobName, &jo)
149162
} else {
150-
log.Printf("Job '%s' would have been deleted", createdMeta.Reference.Name)
163+
log.Printf("Job '%s' would have been deleted", parentJobName)
151164
}
152165
return
153-
154166
}
167+
168+
169+
func (c *PodController) getParentJobName(podObj *v1.Pod, version version.Info) (parentJobName string) {
170+
171+
oldVersion := false
172+
173+
major,_ := strconv.Atoi(version.Major)
174+
minor,_ := strconv.Atoi(version.Minor)
175+
if major < 2 && minor < 8{
176+
oldVersion = true
177+
}
178+
179+
if oldVersion {
180+
var createdMeta CreatedByAnnotation
181+
json.Unmarshal([]byte(podObj.ObjectMeta.Annotations["kubernetes.io/created-by"]), &createdMeta)
182+
if createdMeta.Reference.Kind == "Job" {
183+
parentJobName = createdMeta.Reference.Name
184+
}
185+
}else {
186+
// Going all over the owners, looking for a job, usually there is only one owner
187+
for _, ow := range podObj.OwnerReferences {
188+
if ow.Kind == "Job" {
189+
parentJobName = ow.Name
190+
}
191+
}
192+
}
193+
return
194+
}

0 commit comments

Comments
 (0)