-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathprune.go
More file actions
138 lines (119 loc) · 4.22 KB
/
prune.go
File metadata and controls
138 lines (119 loc) · 4.22 KB
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 volume
import (
"context"
"errors"
"fmt"
"strings"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/system/pruner"
"github.com/docker/cli/internal/prompt"
"github.com/docker/cli/opts"
"github.com/docker/go-units"
"github.com/moby/moby/client"
"github.com/spf13/cobra"
)
func init() {
// Register the prune command to run as part of "docker system prune"
if err := pruner.Register(pruner.TypeVolume, pruneFn); err != nil {
panic(err)
}
}
type pruneOptions struct {
all bool
force bool
filter opts.FilterOpt
}
// newPruneCommand returns a new cobra prune command for volumes
func newPruneCommand(dockerCLI command.Cli) *cobra.Command {
options := pruneOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
Use: "prune [OPTIONS]",
Short: "Remove unused local volumes",
Args: cli.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
spaceReclaimed, output, err := runPrune(cmd.Context(), dockerCLI, options)
if err != nil {
return err
}
if output != "" {
fmt.Fprintln(dockerCLI.Out(), output)
}
fmt.Fprintln(dockerCLI.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
Annotations: map[string]string{"version": "1.25"},
ValidArgsFunction: cobra.NoFileCompletions,
DisableFlagsInUseLine: true,
}
flags := cmd.Flags()
flags.BoolVarP(&options.all, "all", "a", false, "Remove all unused volumes, not just anonymous ones")
flags.SetAnnotation("all", "version", []string{"1.42"})
flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
flags.Var(&options.filter, "filter", `Provide filter values (e.g. "label=<label>")`)
return cmd
}
const (
unusedVolumesWarning = `WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue?`
allVolumesWarning = `WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue?`
)
func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint64, output string, _ error) {
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
warning := unusedVolumesWarning
if options.all {
if _, ok := pruneFilters["all"]; ok {
return 0, "", invalidParamErr{errors.New("conflicting options: cannot specify both --all and --filter all=1")}
}
pruneFilters.Add("all", "true")
warning = allVolumesWarning
}
if !options.force {
r, err := prompt.Confirm(ctx, dockerCli.In(), dockerCli.Out(), warning)
if err != nil {
return 0, "", err
}
if !r {
return 0, "", cancelledErr{errors.New("volume prune has been cancelled")}
}
}
res, err := dockerCli.Client().VolumePrune(ctx, client.VolumePruneOptions{
Filters: pruneFilters,
})
if err != nil {
return 0, "", err
}
var out strings.Builder
if len(res.Report.VolumesDeleted) > 0 {
out.WriteString("Deleted Volumes:\n")
for _, id := range res.Report.VolumesDeleted {
out.WriteString(id + "\n")
}
spaceReclaimed = res.Report.SpaceReclaimed
}
return spaceReclaimed, out.String(), nil
}
type invalidParamErr struct{ error }
func (invalidParamErr) InvalidParameter() {}
type cancelledErr struct{ error }
func (cancelledErr) Cancelled() {}
// pruneFn calls the Volume Prune API for use in "docker system prune",
// and returns the amount of space reclaimed and a detailed output string.
func pruneFn(ctx context.Context, dockerCli command.Cli, options pruner.PruneOptions) (uint64, string, error) {
// TODO version this once "until" filter is supported for volumes
// Ideally, this check wasn't done on the CLI because the list of
// filters that is supported by the daemon may evolve over time.
if _, ok := options.Filter.Value()["until"]; ok {
return 0, "", errors.New(`ERROR: The "until" filter is not supported with "--volumes"`)
}
if !options.Confirmed {
// Dry-run: perform validation and produce confirmation before pruning.
confirmMsg := "all anonymous volumes not used by at least one container"
return 0, confirmMsg, cancelledErr{errors.New("volume prune has been cancelled")}
}
return runPrune(ctx, dockerCli, pruneOptions{
force: true,
filter: options.Filter,
})
}