forget: Add policy to keep snapshots before a date

This commit is contained in:
Matthew Holt 2018-04-23 14:34:37 -06:00 committed by Alexander Neumann
parent 159badf5ba
commit b52f2aa9a4
4 changed files with 137 additions and 28 deletions

View file

@ -5,6 +5,7 @@ import (
"encoding/json"
"sort"
"strings"
"time"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
@ -27,13 +28,14 @@ data after 'forget' was run successfully, see the 'prune' command. `,
// ForgetOptions collects all options for the forget command.
type ForgetOptions struct {
Last int
Hourly int
Daily int
Weekly int
Monthly int
Yearly int
KeepTags restic.TagLists
Last int
Hourly int
Daily int
Weekly int
Monthly int
Yearly int
NewerThan time.Duration
KeepTags restic.TagLists
Host string
Tags restic.TagLists
@ -58,6 +60,7 @@ func init() {
f.IntVarP(&forgetOptions.Weekly, "keep-weekly", "w", 0, "keep the last `n` weekly snapshots")
f.IntVarP(&forgetOptions.Monthly, "keep-monthly", "m", 0, "keep the last `n` monthly snapshots")
f.IntVarP(&forgetOptions.Yearly, "keep-yearly", "y", 0, "keep the last `n` yearly snapshots")
f.DurationVar(&forgetOptions.NewerThan, "keep-newer-than", 0, "keep snapshots that were created within this timeframe")
f.Var(&forgetOptions.KeepTags, "keep-tag", "keep snapshots with this `taglist` (can be specified multiple times)")
// Sadly the commonly used shortcut `H` is already used.
@ -163,14 +166,20 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
}
}
var ageCutoff time.Time
if opts.NewerThan > 0 {
ageCutoff = time.Now().Add(-opts.NewerThan)
}
policy := restic.ExpirePolicy{
Last: opts.Last,
Hourly: opts.Hourly,
Daily: opts.Daily,
Weekly: opts.Weekly,
Monthly: opts.Monthly,
Yearly: opts.Yearly,
Tags: opts.KeepTags,
Last: opts.Last,
Hourly: opts.Hourly,
Daily: opts.Daily,
Weekly: opts.Weekly,
Monthly: opts.Monthly,
Yearly: opts.Yearly,
NewerThan: ageCutoff,
Tags: opts.KeepTags,
}
if policy.Empty() && len(args) == 0 {

View file

@ -10,13 +10,14 @@ import (
// ExpirePolicy configures which snapshots should be automatically removed.
type ExpirePolicy struct {
Last int // keep the last n snapshots
Hourly int // keep the last n hourly snapshots
Daily int // keep the last n daily snapshots
Weekly int // keep the last n weekly snapshots
Monthly int // keep the last n monthly snapshots
Yearly int // keep the last n yearly snapshots
Tags []TagList // keep all snapshots that include at least one of the tag lists.
Last int // keep the last n snapshots
Hourly int // keep the last n hourly snapshots
Daily int // keep the last n daily snapshots
Weekly int // keep the last n weekly snapshots
Monthly int // keep the last n monthly snapshots
Yearly int // keep the last n yearly snapshots
NewerThan time.Time // keep snapshots newer than this time
Tags []TagList // keep all snapshots that include at least one of the tag lists.
}
func (e ExpirePolicy) String() (s string) {
@ -39,15 +40,11 @@ func (e ExpirePolicy) String() (s string) {
if e.Yearly > 0 {
keeps = append(keeps, fmt.Sprintf("%d yearly", e.Yearly))
}
s = "keep the last "
for _, k := range keeps {
s += k + ", "
if !e.NewerThan.IsZero() {
keeps = append(keeps, fmt.Sprintf("snapshots newer than %s", e.NewerThan))
}
s = strings.Trim(s, ", ")
s += " snapshots"
return s
return fmt.Sprintf("keep the last %s snapshots", strings.Join(keeps, ", "))
}
// Sum returns the maximum number of snapshots to be kept according to this
@ -133,6 +130,11 @@ func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots) {
}
}
// If a timestamp is specified, it's a hard cutoff for older snapshots.
if !p.NewerThan.IsZero() && cur.Time.After(p.NewerThan) {
keepSnap = true
}
// Now update the other buckets and see if they have some counts left.
for i, b := range buckets {
if b.Count > 0 {

View file

@ -171,6 +171,7 @@ var expireTests = []restic.ExpirePolicy{
{Tags: []restic.TagList{{"foo"}}},
{Tags: []restic.TagList{{"foo", "bar"}}},
{Tags: []restic.TagList{{"foo"}, {"bar"}}},
{NewerThan: parseTimeUTC("2016-01-01 01:00:00")},
}
func TestApplyPolicy(t *testing.T) {

View file

@ -0,0 +1,97 @@
[
{
"time": "2016-01-18T12:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-12T21:08:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-12T21:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-09T21:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-08T20:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-07T10:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-06T08:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-05T09:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T16:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:30:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:28:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:24:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T12:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T11:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-04T10:23:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-03T07:02:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-01T07:08:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-01T01:03:03Z",
"tree": null,
"paths": null
},
{
"time": "2016-01-01T01:02:03Z",
"tree": null,
"paths": null
}
]