diff options
-rw-r--r-- | pkg/api/server/register_volumes.go | 6 | ||||
-rw-r--r-- | pkg/domain/filters/volumes.go | 15 | ||||
-rw-r--r-- | test/apiv2/30-volumes.at | 47 |
3 files changed, 59 insertions, 9 deletions
diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go index e5d6cf195..d58bf0662 100644 --- a/pkg/api/server/register_volumes.go +++ b/pkg/api/server/register_volumes.go @@ -88,7 +88,8 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // description: | // JSON encoded value of filters (a map[string][]string) to match volumes against before pruning. // Available filters: - // - label (label=<key>, label=<key>=<value>, label!=<key>, or label!=<key>=<value>) Prune volumes with (or without, in case label!=... is used) the specified labels. + // - `until=<timestamp>` Prune volumes created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. + // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. // responses: // '200': // "$ref": "#/responses/VolumePruneResponse" @@ -268,7 +269,8 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // description: | // JSON encoded value of filters (a map[string][]string) to match volumes against before pruning. // Available filters: - // - label (label=<key>, label=<key>=<value>, label!=<key>, or label!=<key>=<value>) Prune volumes with (or without, in case label!=... is used) the specified labels. + // - `until=<timestamp>` Prune volumes created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time. + // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune volumes with (or without, in case `label!=...` is used) the specified labels. // responses: // '200': // "$ref": "#/responses/DockerVolumePruneResponse" diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go index 9a08adf82..df23c31c0 100644 --- a/pkg/domain/filters/volumes.go +++ b/pkg/domain/filters/volumes.go @@ -86,11 +86,22 @@ func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, erro var vf []libpod.VolumeFilter for filter, v := range filters { for _, val := range v { + filterVal := val switch filter { case "label": - filter := val vf = append(vf, func(v *libpod.Volume) bool { - return util.MatchLabelFilters([]string{filter}, v.Labels()) + return util.MatchLabelFilters([]string{filterVal}, v.Labels()) + }) + case "until": + until, err := util.ComputeUntilTimestamp([]string{filterVal}) + if err != nil { + return nil, err + } + vf = append(vf, func(v *libpod.Volume) bool { + if !until.IsZero() && v.CreatedTime().Before(until) { + return true + } + return false }) default: return nil, errors.Errorf("%q is an invalid volume filter", filter) diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at index ed606134a..5feceea7b 100644 --- a/test/apiv2/30-volumes.at +++ b/test/apiv2/30-volumes.at @@ -125,11 +125,6 @@ t POST libpod/volumes/prune?filters='{"label":["tes' 500 \ t POST libpod/volumes/prune?filters='{"label":["testlabel"]}' 200 t GET libpod/volumes/json?filters='{"label":["testlabel"]}' 200 length=0 -## Prune volumes -t POST libpod/volumes/prune 200 -#After prune volumes, there should be no volume existing -t GET libpod/volumes/json 200 length=0 - # libpod api: do not use list filters for prune t POST libpod/volumes/prune?filters='{"name":["anyname"]}' 500 \ .cause="\"name\" is an invalid volume filter" @@ -146,4 +141,46 @@ t POST volumes/prune?filters='{"driver":["anydriver"]}' 500 \ t POST volumes/prune?filters='{"scope":["anyscope"]}' 500 \ .cause="\"scope\" is an invalid volume filter" +## Prune volumes using until filter +t POST libpod/volumes/create \ + Name=foo5 \ + Label='{"testuntil":""}' \ + Options='{"type":"tmpfs","o":"nodev,noexec"}}' \ + 201 \ + .Name=foo5 \ + .Labels.testuntil="" \ + .Options.type=tmpfs \ + .Options.o=nodev,noexec + +# with date way back in the past, volume should not be deleted +t POST libpod/volumes/prune?filters='{"until":["500000"]}' 200 +t GET libpod/volumes/json?filters='{"label":["testuntil"]}' 200 length=1 + +# with date far in the future, volume should be deleted +t POST libpod/volumes/prune?filters='{"until":["5000000000"]}' 200 +t GET libpod/volumes/json?filters='{"label":["testuntil"]}' 200 length=0 + +t POST libpod/volumes/create \ + Name=foo6 \ + Label='{"testuntilcompat":""}' \ + Options='{"type":"tmpfs","o":"nodev,noexec"}}' \ + 201 \ + .Name=foo6 \ + .Labels.testuntilcompat="" \ + .Options.type=tmpfs \ + .Options.o=nodev,noexec + +# with date way back in the past, volume should not be deleted (compat api) +t POST volumes/prune?filters='{"until":["500000"]}' 200 +t GET libpod/volumes/json?filters='{"label":["testuntilcompat"]}' 200 length=1 + +# with date far in the future, volume should be deleted (compat api) +t POST volumes/prune?filters='{"until":["5000000000"]}' 200 +t GET libpod/volumes/json?filters='{"label":["testuntilcompat"]}' 200 length=0 + +## Prune volumes +t POST libpod/volumes/prune 200 +#After prune volumes, there should be no volume existing +t GET libpod/volumes/json 200 length=0 + # vim: filetype=sh |