From d1999fc17c34218a83c342855742c70b8aef59e4 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 9 Jul 2017 00:38:16 +0200 Subject: [PATCH] Remove months as a possible time interval unit as it is too volatile. Thanks to @erdgeist for pointing that out. refs #2 --- cmd/config.go | 70 +++++++++++++++++++++++++--------------- cmd/config_test.go | 6 ++-- cmd/sampleconf/zrepl.yml | 4 +-- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/cmd/config.go b/cmd/config.go index d01f8f9..e7bca2b 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -345,7 +345,7 @@ func parseRepeatStrategy(r map[string]string) (s jobrun.RepeatStrategy, err erro } if repeatStr, ok := r["interval"]; ok { - d, err := time.ParseDuration(repeatStr) + d, err := parseDuration(repeatStr) if err != nil { return nil, err } @@ -563,7 +563,43 @@ func parsePrune(e map[string]interface{}, name string) (prune *Prune, err error) return } -var retentionStringIntervalRegex *regexp.Regexp = regexp.MustCompile(`^\s*(\d+)\s*x\s*(\d+)\s*(s|min|h|d|w|mon)\s*\s*(\((.*)\))?\s*$`) +var durationStringRegex *regexp.Regexp = regexp.MustCompile(`^\s*(\d+)\s*(s|m|h|d|w)\s*$`) + +func parseDuration(e string) (d time.Duration, err error) { + comps := durationStringRegex.FindStringSubmatch(e) + if len(comps) != 3 { + err = fmt.Errorf("does not match regex: %s %#v", e, comps) + return + } + + durationFactor, err := strconv.ParseInt(comps[1], 10, 64) + if err != nil { + return + } + + var durationUnit time.Duration + switch comps[2] { + case "s": + durationUnit = time.Second + case "m": + durationUnit = time.Minute + case "h": + durationUnit = time.Hour + case "d": + durationUnit = 24 * time.Hour + case "w": + durationUnit = 24 * 7 * time.Hour + default: + err = fmt.Errorf("contains unknown time unit '%s'", comps[2]) + return + } + + d = time.Duration(durationFactor) * durationUnit + return + +} + +var retentionStringIntervalRegex *regexp.Regexp = regexp.MustCompile(`^\s*(\d+)\s*x\s*([^\(]+)\s*(\((.*)\))?\s*$`) func parseRetentionGridIntervalString(e string) (intervals []RetentionInterval, err error) { @@ -580,38 +616,20 @@ func parseRetentionGridIntervalString(e string) (intervals []RetentionInterval, return nil, fmt.Errorf("contains factor <= 0") } - durationFactor, err := strconv.ParseInt(comps[2], 10, 64) + duration, err := parseDuration(comps[2]) if err != nil { return nil, err } - var durationUnit time.Duration - switch comps[3] { - case "s": - durationUnit = time.Second - case "min": - durationUnit = time.Minute - case "h": - durationUnit = time.Hour - case "d": - durationUnit = 24 * time.Hour - case "w": - durationUnit = 24 * 7 * time.Hour - case "mon": - durationUnit = 24 * 32 * time.Hour - default: - err = fmt.Errorf("contains unknown time unit '%s'", comps[3]) - return nil, err - } - keepCount := 1 - if comps[4] != "" { + if comps[3] != "" { // Decompose key=value, comma separated // For now, only keep_count is supported re := regexp.MustCompile(`^\s*keep=(.+)\s*$`) - res := re.FindStringSubmatch(comps[5]) + res := re.FindStringSubmatch(comps[4]) if res == nil || len(res) != 2 { err = fmt.Errorf("interval parameter contains unknown parameters") + return } if res[1] == "all" { keepCount = RetentionGridKeepCountAll @@ -627,7 +645,7 @@ func parseRetentionGridIntervalString(e string) (intervals []RetentionInterval, intervals = make([]RetentionInterval, times) for i := range intervals { intervals[i] = RetentionInterval{ - Length: time.Duration(durationFactor) * durationUnit, // TODO is this conversion fututre-proof? + Length: duration, KeepCount: keepCount, } } @@ -718,7 +736,7 @@ func parseAutosnap(m interface{}, name string) (a *Autosnap, err error) { a.Prefix = i.Prefix var interval time.Duration - if interval, err = time.ParseDuration(i.Interval); err != nil { + if interval, err = parseDuration(i.Interval); err != nil { err = fmt.Errorf("cannot parse interval: %s", err) return } diff --git a/cmd/config_test.go b/cmd/config_test.go index aa677fd..59c894b 100644 --- a/cmd/config_test.go +++ b/cmd/config_test.go @@ -14,7 +14,7 @@ func TestSampleConfigFileIsParsedWithoutErrors(t *testing.T) { func TestParseRetentionGridStringParsing(t *testing.T) { - intervals, err := parseRetentionGridIntervalsString("2x10min(keep=2) | 1x1h | 3x1w") + intervals, err := parseRetentionGridIntervalsString("2x10m(keep=2) | 1x1h | 3x1w") assert.Nil(t, err) assert.Len(t, intervals, 6) @@ -36,10 +36,10 @@ func TestParseRetentionGridStringParsing(t *testing.T) { intervals, err = parseRetentionGridIntervalsString("|") assert.Error(t, err) - intervals, err = parseRetentionGridIntervalsString("2x10min") + intervals, err = parseRetentionGridIntervalsString("2x10m") assert.NoError(t, err) - intervals, err = parseRetentionGridIntervalsString("1x10min(keep=all)") + intervals, err = parseRetentionGridIntervalsString("1x10m(keep=all)") assert.NoError(t, err) assert.Len(t, intervals, 1) assert.EqualValues(t, util.RetentionGridKeepCountAll, intervals[0].KeepCount) diff --git a/cmd/sampleconf/zrepl.yml b/cmd/sampleconf/zrepl.yml index 020af24..b9984dd 100644 --- a/cmd/sampleconf/zrepl.yml +++ b/cmd/sampleconf/zrepl.yml @@ -96,7 +96,7 @@ prune: clean_backups: policy: grid - grid: 6x10min | 24x1h | 7x1d | 32 x 1d | 4 x 3mon + grid: 6x10m | 24x1h | 7x1d | 5 x 1w | 4 x 5w dataset_filter: { "tank/backups/*": ok } @@ -106,7 +106,7 @@ prune: hfbak_prune: # cleans up after hfbak autosnap job policy: grid - grid: 1x1min(keep=all) + grid: 1x1m(keep=all) dataset_filter: { "pool1*": ok }