Merge pull request #30740 from yongtang/29999-prune-filter-label

Add `label` filter for `docker system prune`
This commit is contained in:
Vincent Demeester 2017-04-10 19:38:01 +02:00 committed by GitHub
commit ec9d4dbdc6
7 changed files with 47 additions and 9 deletions

View File

@ -49,7 +49,7 @@ const warning = `WARNING! This will remove all stopped containers.
Are you sure you want to continue?` Are you sure you want to continue?`
func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) { func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
pruneFilters := opts.filter.Value() pruneFilters := command.PruneFilters(dockerCli, opts.filter.Value())
if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) { if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return return

View File

@ -58,6 +58,7 @@ Are you sure you want to continue?`
func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) { func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
pruneFilters := opts.filter.Value() pruneFilters := opts.filter.Value()
pruneFilters.Add("dangling", fmt.Sprintf("%v", !opts.all)) pruneFilters.Add("dangling", fmt.Sprintf("%v", !opts.all))
pruneFilters = command.PruneFilters(dockerCli, pruneFilters)
warning := danglingWarning warning := danglingWarning
if opts.all { if opts.all {

View File

@ -48,7 +48,7 @@ const warning = `WARNING! This will remove all networks not used by at least one
Are you sure you want to continue?` Are you sure you want to continue?`
func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (output string, err error) { func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (output string, err error) {
pruneFilters := opts.filter.Value() pruneFilters := command.PruneFilters(dockerCli, opts.filter.Value())
if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) { if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return return

View File

@ -37,7 +37,7 @@ func RunContainerPrune(dockerCli *command.DockerCli, filter opts.FilterOpt) (uin
// RunVolumePrune executes a prune command for volumes // RunVolumePrune executes a prune command for volumes
func RunVolumePrune(dockerCli *command.DockerCli, filter opts.FilterOpt) (uint64, string, error) { func RunVolumePrune(dockerCli *command.DockerCli, filter opts.FilterOpt) (uint64, string, error) {
return volume.RunPrune(dockerCli) return volume.RunPrune(dockerCli, filter)
} }
// RunImagePrune executes a prune command for images // RunImagePrune executes a prune command for images

View File

@ -9,6 +9,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
) )
@ -85,3 +86,34 @@ func PromptForConfirmation(ins *InStream, outs *OutStream, message string) bool
answer, _, _ := reader.ReadLine() answer, _, _ := reader.ReadLine()
return strings.ToLower(string(answer)) == "y" return strings.ToLower(string(answer)) == "y"
} }
// PruneFilters returns consolidated prune filters obtained from config.json and cli
func PruneFilters(dockerCli Cli, pruneFilters filters.Args) filters.Args {
if dockerCli.ConfigFile() == nil {
return pruneFilters
}
for _, f := range dockerCli.ConfigFile().PruneFilters {
parts := strings.SplitN(f, "=", 2)
if len(parts) != 2 {
continue
}
if parts[0] == "label" {
// CLI label filter supersede config.json.
// If CLI label filter conflict with config.json,
// skip adding label! filter in config.json.
if pruneFilters.Include("label!") && pruneFilters.ExactMatch("label!", parts[1]) {
continue
}
} else if parts[0] == "label!" {
// CLI label! filter supersede config.json.
// If CLI label! filter conflict with config.json,
// skip adding label filter in config.json.
if pruneFilters.Include("label") && pruneFilters.ExactMatch("label", parts[1]) {
continue
}
}
pruneFilters.Add(parts[0], parts[1])
}
return pruneFilters
}

View File

@ -3,9 +3,9 @@ package volume
import ( import (
"fmt" "fmt"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/opts"
units "github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -13,11 +13,12 @@ import (
type pruneOptions struct { type pruneOptions struct {
force bool force bool
filter opts.FilterOpt
} }
// NewPruneCommand returns a new cobra prune command for volumes // NewPruneCommand returns a new cobra prune command for volumes
func NewPruneCommand(dockerCli command.Cli) *cobra.Command { func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
var opts pruneOptions opts := pruneOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "prune [OPTIONS]", Use: "prune [OPTIONS]",
@ -39,6 +40,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVarP(&opts.force, "force", "f", false, "Do not prompt for confirmation") flags.BoolVarP(&opts.force, "force", "f", false, "Do not prompt for confirmation")
flags.Var(&opts.filter, "filter", "Provide filter values (e.g. 'label=<label>')")
return cmd return cmd
} }
@ -47,11 +49,13 @@ const warning = `WARNING! This will remove all volumes not used by at least one
Are you sure you want to continue?` Are you sure you want to continue?`
func runPrune(dockerCli command.Cli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) { func runPrune(dockerCli command.Cli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
pruneFilters := command.PruneFilters(dockerCli, opts.filter.Value())
if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) { if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return return
} }
report, err := dockerCli.Client().VolumesPrune(context.Background(), filters.Args{}) report, err := dockerCli.Client().VolumesPrune(context.Background(), pruneFilters)
if err != nil { if err != nil {
return return
} }
@ -69,6 +73,6 @@ func runPrune(dockerCli command.Cli, opts pruneOptions) (spaceReclaimed uint64,
// RunPrune calls the Volume Prune API // RunPrune calls the Volume Prune API
// This returns the amount of space reclaimed and a detailed output string // This returns the amount of space reclaimed and a detailed output string
func RunPrune(dockerCli *command.DockerCli) (uint64, string, error) { func RunPrune(dockerCli *command.DockerCli, filter opts.FilterOpt) (uint64, string, error) {
return runPrune(dockerCli, pruneOptions{force: true}) return runPrune(dockerCli, pruneOptions{force: true, filter: filter})
} }

View File

@ -39,6 +39,7 @@ type ConfigFile struct {
TasksFormat string `json:"tasksFormat,omitempty"` TasksFormat string `json:"tasksFormat,omitempty"`
SecretFormat string `json:"secretFormat,omitempty"` SecretFormat string `json:"secretFormat,omitempty"`
NodesFormat string `json:"nodesFormat,omitempty"` NodesFormat string `json:"nodesFormat,omitempty"`
PruneFilters []string `json:"pruneFilters,omitempty"`
} }
// LegacyLoadFromReader reads the non-nested configuration data given and sets up the // LegacyLoadFromReader reads the non-nested configuration data given and sets up the