forked from evergreen-ci/evergreen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
directory.go
138 lines (115 loc) · 3.6 KB
/
directory.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
129
130
131
132
133
134
135
136
137
138
package agent
import (
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"os"
"os/user"
"path/filepath"
"strings"
"github.com/mongodb/grip"
"github.com/mongodb/grip/recovery"
)
// createTaskDirectory makes a directory for the agent to execute
// the current task within. It changes the necessary variables
// so that all of the agent's operations will use this folder.
func (a *Agent) createTaskDirectory(tc *taskContext) (string, error) {
h := md5.New()
_, err := h.Write([]byte(
fmt.Sprintf("%s_%d_%d", tc.taskConfig.Task.Id, tc.taskConfig.Task.Execution, os.Getpid())))
if err != nil {
tc.logger.Execution().Errorf("Error creating task directory name: %v", err)
return "", err
}
dirName := hex.EncodeToString(h.Sum(nil))
newDir := filepath.Join(tc.taskConfig.Distro.WorkDir, dirName)
tc.logger.Execution().Infof("Making new folder for task execution: %v", newDir)
err = os.MkdirAll(newDir, 0777)
if err != nil {
tc.logger.Execution().Errorf("Error creating task directory: %v", err)
return "", err
}
return newDir, nil
}
// removeTaskDirectory removes the folder the agent created for the task it
// was executing. It does not return an error because it is executed at the end of
// a task run, and the agent loop will start another task regardless of how this
// exits.
func (a *Agent) removeTaskDirectory(tc *taskContext) {
if tc.taskDirectory == "" {
grip.Info("Task directory is not set, not removing")
return
}
grip.Infof("Deleting directory for completed task: %s", tc.taskDirectory)
if err := os.RemoveAll(tc.taskDirectory); err != nil {
grip.Criticalf("Error removing working directory for the task: %v", err)
}
}
// tryCleanupDirectory is a very conservative function that attempts
// to cleanup the working directory when the agent starts. Without
// this function, if an agent attempts to start on a system where a
// previous agent has run but crashed for some reason, the new agent
// could easily run out of disk space and will have no way to clean up
// for itself, which leads to an increased maintenance burden for
// static, and other long running hosts.
//
// By conservative, the operation does not return an error or attempt
// to retry in the case of an error, so running this function does not
// ensure that any files are necessarily removed, but the hope is that
// its better than not doing anything.
//
// Additionally the function does *not* handle log rotation or
// management, and only attempts to clean up the agent's working
// directory, so files not located in a directory may still cause
// issues.
func tryCleanupDirectory(dir string) {
defer recovery.LogStackTraceAndContinue("clean up directories")
if dir == "" {
return
}
stat, err := os.Stat(dir)
if os.IsNotExist(err) {
return
}
if !stat.IsDir() {
return
}
usr, err := user.Current()
if err != nil {
grip.Warning(err)
return
}
if strings.HasPrefix(dir, usr.HomeDir) || strings.Contains(dir, "cygwin") {
grip.Notice("not cleaning up directory, because it is in the home directory.")
return
}
paths := []string{}
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == dir {
return nil
}
if strings.HasPrefix(info.Name(), ".") {
return nil
}
if strings.HasSuffix(path, ".git") {
grip.Warning("don't run the agent in the development environment")
return errors.New("skip cleanup in development environments")
}
if info.IsDir() {
paths = append(paths, path)
}
return nil
})
if err != nil {
return
}
for _, p := range paths {
if err = os.RemoveAll(p); err != nil {
grip.Notice(err)
}
}
}