/
clean.go
122 lines (100 loc) · 3.74 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
package commands // import "code.cloudfoundry.org/grootfs/commands"
import (
"fmt"
"os"
"path/filepath"
"code.cloudfoundry.org/commandrunner/linux_command_runner"
"code.cloudfoundry.org/lager"
unpackerpkg "code.cloudfoundry.org/grootfs/base_image_puller/unpacker"
"code.cloudfoundry.org/grootfs/commands/config"
"code.cloudfoundry.org/grootfs/groot"
"code.cloudfoundry.org/grootfs/metrics"
storepkg "code.cloudfoundry.org/grootfs/store"
"code.cloudfoundry.org/grootfs/store/dependency_manager"
"code.cloudfoundry.org/grootfs/store/filesystems/namespaced"
"code.cloudfoundry.org/grootfs/store/garbage_collector"
imageClonerpkg "code.cloudfoundry.org/grootfs/store/image_cloner"
locksmithpkg "code.cloudfoundry.org/grootfs/store/locksmith"
errorspkg "github.com/pkg/errors"
"github.com/urfave/cli"
)
var CleanCommand = cli.Command{
Name: "clean",
Usage: "clean",
Description: "Cleans up unused layers",
Flags: []cli.Flag{
cli.Int64Flag{
Name: "threshold-bytes",
Usage: "Disk usage of the store directory at which cleanup should trigger",
},
},
Action: func(ctx *cli.Context) error {
logger := ctx.App.Metadata["logger"].(lager.Logger)
logger = logger.Session("clean")
newExitError := newErrorHandler(logger, "clean")
configBuilder := ctx.App.Metadata["configBuilder"].(*config.Builder)
configBuilder.WithCleanThresholdBytes(ctx.Int64("threshold-bytes"),
ctx.IsSet("threshold-bytes"))
cfg, err := configBuilder.Build()
logger.Debug("clean-config", lager.Data{"currentConfig": cfg})
if err != nil {
logger.Error("config-builder-failed", err)
return newExitError(err.Error(), 1)
}
storePath := cfg.StorePath
if _, err = os.Stat(storePath); os.IsNotExist(err) {
err = errorspkg.Errorf("no store found at %s", storePath)
logger.Error("store-path-failed", err, nil)
return newExitError(err.Error(), 0)
}
fsDriver, err := createFileSystemDriver(cfg)
if err != nil {
logger.Error("failed-to-initialise-filesystem-driver", err)
return newExitError(err.Error(), 1)
}
imageCloner := imageClonerpkg.NewImageCloner(fsDriver, storePath)
metricsEmitter := metrics.NewEmitter()
locksmith := locksmithpkg.NewExclusiveFileSystem(storePath, metricsEmitter)
dependencyManager := dependency_manager.NewDependencyManager(
filepath.Join(storePath, storepkg.MetaDirName, "dependencies"),
)
storeNamespacer := groot.NewStoreNamespacer(storePath)
idMappings, err := storeNamespacer.Read()
if err != nil {
logger.Error("reading-namespace-file", err)
return newExitError(err.Error(), 1)
}
runner := linux_command_runner.New()
idMapper := unpackerpkg.NewIDMapper(cfg.NewuidmapBin, cfg.NewgidmapBin, runner)
nsFsDriver := namespaced.New(fsDriver, idMappings, idMapper, runner)
sm := storepkg.NewStoreMeasurer(storePath, fsDriver)
gc := garbage_collector.NewGC(nsFsDriver, imageCloner, dependencyManager, "")
cleaner := groot.IamCleaner(locksmith, sm, gc, metricsEmitter)
defer func() {
unusedVols, err := gc.UnusedVolumes(logger)
if err != nil {
logger.Error("getting-unused-layers-failed", err)
return
}
metricsEmitter.TryEmitUsage(logger, "UnusedLayersSize", sm.CacheUsage(logger, unusedVols), "bytes")
}()
noop, err := cleaner.Clean(logger, cfg.Clean.ThresholdBytes)
if err != nil {
logger.Error("cleaning-up-unused-resources", err)
return newExitError(err.Error(), 1)
}
if noop {
fmt.Println("threshold not reached: skipping clean")
return nil
}
fmt.Println("clean completed")
usage, err := sm.Usage(logger)
if err != nil {
logger.Error("measuring-store", err)
return newExitError(err.Error(), 1)
}
metricsEmitter.TryIncrementRunCount("clean", nil)
metricsEmitter.TryEmitUsage(logger, "StoreUsage", usage, "bytes")
return nil
},
}