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
|
package tempdir
import (
"context"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"time"
"github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitaly/v16/internal/dontpanic"
"gitlab.com/gitlab-org/gitaly/v16/internal/git/housekeeping"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
)
const (
// tmpRootPrefix is the directory in which we store temporary directories.
tmpRootPrefix = config.GitalyDataPrefix + "/tmp"
// maxAge is used by ForDeleteAllRepositories. It is also a fallback for the context-scoped
// temporary directories, to ensure they get cleaned up if the cleanup at the end of the
// context failed to run.
maxAge = 7 * 24 * time.Hour
)
// StartCleaning starts tempdir cleanup in a goroutine.
func StartCleaning(locator storage.Locator, storages []config.Storage, d time.Duration) {
dontpanic.Go(func() {
for {
cleanTempDir(locator, storages)
time.Sleep(d)
}
})
}
func cleanTempDir(locator storage.Locator, storages []config.Storage) {
for _, storage := range storages {
start := time.Now()
err := clean(locator, storage)
entry := logrus.WithFields(logrus.Fields{
"time_ms": time.Since(start).Milliseconds(),
"storage": storage.Name,
})
if err != nil {
entry = entry.WithError(err)
}
entry.Info("finished tempdir cleaner walk")
}
}
type invalidCleanRoot string
func clean(locator storage.Locator, storage config.Storage) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
dir, err := locator.TempDir(storage.Name)
if err != nil {
return fmt.Errorf("temporary dir: %w", err)
}
// If we start "cleaning up" the wrong directory we may delete user data
// which is Really Bad.
if !strings.HasSuffix(dir, tmpRootPrefix) {
logrus.Print(dir)
panic(invalidCleanRoot("invalid tempdir clean root: panicking to prevent data loss"))
}
entries, err := os.ReadDir(dir)
if os.IsNotExist(err) {
return nil
}
if err != nil {
return err
}
for _, entry := range entries {
info, err := entry.Info()
if err != nil {
// It's fine if the entry has disappeared meanwhile, we wanted to remove it
// anyway.
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("statting tempdir entry: %w", err)
}
if time.Since(info.ModTime()) < maxAge {
continue
}
fullPath := filepath.Join(dir, info.Name())
if err := housekeeping.FixDirectoryPermissions(ctx, fullPath); err != nil {
return err
}
if err := os.RemoveAll(fullPath); err != nil {
return err
}
}
return nil
}
|