-
Notifications
You must be signed in to change notification settings - Fork 319
/
clean.go
128 lines (118 loc) · 2.85 KB
/
clean.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
import (
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"sync"
"github.com/baidu/openedge/logger"
openedge "github.com/baidu/openedge/sdk/openedge-go"
"github.com/baidu/openedge/utils"
)
type cleaner struct {
count int32
prefix string
target string
last *openedge.AppConfig
log logger.Logger
sync.Mutex
}
func newCleaner(prefix, target string, log logger.Logger) *cleaner {
return &cleaner{
count: 3,
prefix: prefix,
target: target,
log: log,
}
}
func (c *cleaner) reset(prepare func(openedge.VolumeInfo) (*openedge.AppConfig, string, error), cfg openedge.VolumeInfo) (*openedge.AppConfig, string, error) {
c.Lock()
defer c.Unlock()
appcfg, hostdir, err := prepare(cfg)
c.count = 3
c.last = appcfg
return appcfg, hostdir, err
}
func (c *cleaner) do(version string) {
if version == "" {
c.log.Debugf("report version is empty")
return
}
c.Lock()
defer c.Unlock()
// not clean if last app config is not cached,
// for example, when agent is restarted
if c.last == nil {
c.log.Debugf("last app config is not cached")
return
}
// not clean if last app config version is not matched,
// for example, openedge master reload task is not finised or failed.
if c.last.Version != version {
c.log.Debugf("report version is not matched")
return
}
// delay three reporting cycles and then clean up
c.count--
if c.count != 0 {
return
}
c.log.Infof("start to clean '%s'", c.target)
defer utils.Trace("end to clean,", c.log.Infof)()
// list folders to remove
remove, err := list(c.prefix, c.target, c.last.Volumes)
if err != nil {
c.log.WithError(err).Warnf("failed to list old volumes")
return
}
for _, v := range remove {
err := os.RemoveAll(v)
if err != nil {
c.log.WithError(err).Warnf("failed to remove old volumes")
}
c.log.Infof("old volume is removed: %s", v)
}
}
func list(prefix, target string, volumes []openedge.VolumeInfo) ([]string, error) {
keep := map[string]bool{}
for _, v := range volumes {
// remove prefix from path
p, err := filepath.Rel(prefix, v.Path)
if err != nil {
continue
}
ps := strings.Split(p, string(filepath.Separator))
if len(ps) == 0 {
// ignore the case that v.Path equals prefix
continue
}
if ps[0] == ".." {
// ignore the case that v.Path out of prefix
continue
}
keep[ps[0]] = len(ps) > 1
}
infos, err := ioutil.ReadDir(target)
if err != nil {
return nil, err
}
remove := []string{}
for _, info := range infos {
// skip the files and only clean folders,
if !info.IsDir() {
continue
}
next, ok := keep[info.Name()]
if !ok {
remove = append(remove, filepath.Join(target, info.Name()))
} else if next {
nextremove, err := list(path.Join(prefix, info.Name()), path.Join(target, info.Name()), volumes)
if err != nil {
return nil, err
}
remove = append(remove, nextremove...)
}
}
return remove, err
}