Skip to content

Commit a165232

Browse files
author
Aaron Schlesinger
committed
fix(boot.go,pkg/cleaner,pkg/k8s): adding and wiring up a deleted app cleaner
also adding an interface for listing kubernetes namespaces
1 parent 35e9469 commit a165232

3 files changed

Lines changed: 122 additions & 0 deletions

File tree

boot.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
cookoolog "github.com/Masterminds/cookoo/log"
1010
"github.com/codegangsta/cli"
1111
"github.com/deis/builder/pkg"
12+
"github.com/deis/builder/pkg/cleaner"
1213
"github.com/deis/builder/pkg/conf"
1314
"github.com/deis/builder/pkg/gitreceive"
1415
"github.com/deis/builder/pkg/gitreceive/storage"
@@ -68,6 +69,13 @@ func main() {
6869
healthSrvCh <- err
6970
}
7071
}()
72+
log.Printf("Starting deleted app cleaner")
73+
cleanerErrCh := make(chan error)
74+
go func() {
75+
if err := cleaner.Run(gitHomeDir, kubeClient.Namespaces(), cleanerPollDuration); err != nil {
76+
cleanerErrCh <- err
77+
}
78+
}()
7179

7280
log.Printf("Starting SSH server on %s:%d", cnf.SSHHostIP, cnf.SSHHostPort)
7381
sshCh := make(chan int)
@@ -82,6 +90,9 @@ func main() {
8290
case i := <-sshCh:
8391
log.Printf("Unexpected SSH server stop with code %d", i)
8492
os.Exit(i)
93+
case err := <-cleanerErrCh:
94+
log.Printf("Error running the deleted app cleaner (%s)", err)
95+
os.Exit(1)
8596
}
8697
},
8798
},

pkg/cleaner/cleaner.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Package cleaner is a background process that compares the kubernetes namespace list with the folders in the local git home directory, deleting what's not in the namespace list
2+
package cleaner
3+
4+
import (
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
"time"
9+
10+
"github.com/deis/builder/pkg/k8s"
11+
"github.com/deis/pkg/log"
12+
"k8s.io/kubernetes/pkg/api"
13+
"k8s.io/kubernetes/pkg/fields"
14+
"k8s.io/kubernetes/pkg/labels"
15+
)
16+
17+
func localDirs(gitHome string) ([]string, error) {
18+
var ret []string
19+
err := filepath.Walk(gitHome, func(path string, info os.FileInfo, err error) error {
20+
if err != nil {
21+
return err
22+
}
23+
if info.IsDir() {
24+
return filepath.SkipDir
25+
}
26+
ret = append(ret, filepath.Join(gitHome, path))
27+
return nil
28+
})
29+
30+
if err != nil {
31+
return nil, err
32+
}
33+
return ret, nil
34+
}
35+
36+
// getDisjunction gets the items that are in namespaceList and not in dirs or vice versa
37+
func getDisjunction(namespaceList []api.Namespace, dirs []string) []string {
38+
var ret []string
39+
namespacesSet := make(map[string]struct{})
40+
dirsSet := make(map[string]struct{})
41+
42+
// create sets of the namespaces and dirs
43+
for _, ns := range namespaceList {
44+
lowerName := strings.ToLower(ns.Name)
45+
namespacesSet[lowerName] = struct{}{}
46+
}
47+
48+
for _, dir := range dirs {
49+
lowerName := strings.ToLower(dir)
50+
dirsSet[lowerName] = struct{}{}
51+
}
52+
53+
// get dirs not in the namespaces set
54+
for _, dir := range dirs {
55+
lowerName := strings.ToLower(dir)
56+
if _, ok := namespacesSet[lowerName]; !ok {
57+
ret = append(ret, lowerName)
58+
}
59+
}
60+
61+
// get namespaces not in the dirs set
62+
for _, ns := range namespaceList {
63+
lowerName := strings.ToLower(ns.Name)
64+
if _, ok := dirsSet[lowerName]; !ok {
65+
ret = append(ret, lowerName)
66+
}
67+
}
68+
69+
return ret
70+
}
71+
72+
func Run(gitHome string, nsLister k8s.NamespaceLister, pollInterval time.Duration) error {
73+
for {
74+
nsList, err := nsLister.List(labels.Everything(), fields.Everything())
75+
if err != nil {
76+
log.Debug("Cleaner error listing namespaces (%s)", err)
77+
continue
78+
}
79+
80+
gitDirs, err := localDirs(gitHome)
81+
if err != nil {
82+
log.Debug("Cleaner error listing local git directories (%s)", err)
83+
}
84+
85+
disjunctions := getDisjunction(nsList.Items, gitDirs)
86+
for _, disj := range disjunctions {
87+
if err := os.RemoveAll(disj); err != nil {
88+
log.Debug("Cleaner error removing deleted app %s (%s)", disj, err)
89+
}
90+
}
91+
92+
time.Sleep(pollInterval)
93+
}
94+
}

pkg/k8s/namespace.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package k8s
2+
3+
import (
4+
"k8s.io/kubernetes/pkg/api"
5+
"k8s.io/kubernetes/pkg/fields"
6+
"k8s.io/kubernetes/pkg/labels"
7+
)
8+
9+
// NamespaceLister is a (k8s.io/kubernetes/pkg/client/unversioned).NamespaceInterface compatible interface which only has the List function. It's used in places that only need List to make them easier to test and more easily swappable with other implementations.
10+
//
11+
// Example usage:
12+
//
13+
// var nsl NamespaceLister
14+
// nsl = kubeClient.Namespaces()
15+
type NamespaceLister interface {
16+
List(labels.Selector, fields.Selector) (*api.NamespaceList, error)
17+
}

0 commit comments

Comments
 (0)