-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: allow TTL to be a duration in days, weeks, etc.. #9345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
iTrooz
wants to merge
19
commits into
vmware-tanzu:main
Choose a base branch
from
iTrooz:day_duration
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 4 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
e6c4481
feat: allow TTL to be a duration in days
iTrooz 1c169b7
clean
iTrooz 4ab1933
update doc
iTrooz e5b0a77
add changelog
iTrooz e6414e2
fix
iTrooz 1dd35eb
handle nanoseconds, ..., milliseconds
iTrooz facb612
fix
iTrooz 97cf8d7
update tests
iTrooz 8241f0c
update doc
iTrooz 9357aba
update CRDs
iTrooz 759b1b5
Update pkg/apis/velero/v1/backup_types.go
iTrooz ee33caf
update CRDs
iTrooz c3d1119
explain days/months/years static durations
iTrooz f5a4cce
add fractional support
iTrooz 4cac3c3
do not test all units
iTrooz a010487
set years suffix to y
iTrooz efde95d
make 1mo=31d and 1y=366d
iTrooz b1a63ce
test with a number > 32bits
iTrooz b3e0744
update doc to mention 1mo=31d and 1y=366d
iTrooz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Make TTL accept day/week/month/year units |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| package flag | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "strconv" | ||
| "strings" | ||
| "time" | ||
| "unicode" | ||
|
|
||
| "k8s.io/apimachinery/pkg/util/duration" | ||
| ) | ||
|
|
||
| // Wrapper around time.Duration with a parser that accepts days, months, years as valid units. | ||
| type Duration struct { | ||
| time.Duration | ||
| } | ||
|
|
||
| // unit map: symbol -> seconds | ||
| var unitMap = map[string]int64{ | ||
| "yr": 365 * 24 * 3600, | ||
| "mo": 30 * 24 * 3600, | ||
| "w": 7 * 24 * 3600, | ||
| "d": 24 * 3600, | ||
| "h": 3600, | ||
| "m": 60, | ||
| "s": 1, | ||
| } | ||
iTrooz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // ParseDuration parses strings like "2d5h10m" | ||
iTrooz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| func ParseDuration(s string) (Duration, error) { | ||
| s = strings.TrimSpace(s) | ||
| if s == "" { | ||
| return Duration{Duration: 0}, nil | ||
| } | ||
|
|
||
| var total int64 | ||
| i := 0 | ||
| n := len(s) | ||
|
|
||
| for i < n { | ||
| // Get number | ||
| j := i | ||
| for j < n && unicode.IsDigit(rune(s[j])) { | ||
| j++ | ||
| } | ||
| if j == i { | ||
| return Duration{}, fmt.Errorf("expected number at pos %d", i) | ||
| } | ||
| numStr := s[i:j] | ||
| num, err := strconv.ParseInt(numStr, 10, 64) | ||
| if err != nil { | ||
| return Duration{}, err | ||
| } | ||
|
|
||
| // Get unit | ||
| k := j | ||
| for k < n && unicode.IsLetter(rune(s[k])) { | ||
| k++ | ||
| } | ||
| if k == j { | ||
| return Duration{}, fmt.Errorf("missing unit after number at pos %d", j) | ||
| } | ||
| unit := strings.ToLower(s[j:k]) | ||
|
|
||
| // Query value for unit | ||
| val, ok := unitMap[unit] | ||
| if !ok { | ||
| return Duration{}, fmt.Errorf("unknown unit %q", unit) | ||
| } | ||
| // Add to total | ||
| total += num * val | ||
|
|
||
| i = k | ||
| for i < n && s[i] == ' ' { | ||
| i++ | ||
| } | ||
| } | ||
|
|
||
| // Convert integer seconds into time.Duration | ||
| return Duration{Duration: time.Duration(total) * time.Second}, nil | ||
| } | ||
|
|
||
| func (d *Duration) String() string { return duration.ShortHumanDuration(d.Duration) } | ||
|
|
||
| func (d *Duration) Set(s string) error { | ||
| parsed, err := ParseDuration(s) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| *d = parsed | ||
| return nil | ||
| } | ||
|
|
||
| func (d *Duration) Type() string { return "duration" } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| package flag | ||
|
|
||
| import ( | ||
| "testing" | ||
| "time" | ||
| ) | ||
|
|
||
| func TestParseDuration(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| input string | ||
| expected time.Duration | ||
| wantErr bool | ||
| }{ | ||
| // Valid cases | ||
| { | ||
| name: "empty string", | ||
| input: "", | ||
| expected: 0, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "whitespace only", | ||
| input: " ", | ||
| expected: 0, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "seconds only", | ||
| input: "30s", | ||
| expected: 30 * time.Second, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "minutes only", | ||
| input: "5m", | ||
| expected: 5 * time.Minute, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "hours only", | ||
| input: "2h", | ||
| expected: 2 * time.Hour, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "days only", | ||
| input: "3d", | ||
| expected: 3 * 24 * time.Hour, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "weeks only", | ||
| input: "1w", | ||
| expected: 7 * 24 * time.Hour, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "months only", | ||
| input: "2mo", | ||
| expected: 2 * 30 * 24 * time.Hour, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "years only", | ||
| input: "1yr", | ||
| expected: 365 * 24 * time.Hour, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "combined units", | ||
| input: "2d5h10m30s", | ||
| expected: 2*24*time.Hour + 5*time.Hour + 10*time.Minute + 30*time.Second, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "combined with spaces", | ||
| input: "1d 12h 30m", | ||
| expected: 24*time.Hour + 12*time.Hour + 30*time.Minute, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "mixed case units", | ||
| input: "1D 2H 3M 4S", | ||
| expected: 24*time.Hour + 2*time.Hour + 3*time.Minute + 4*time.Second, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "zero values", | ||
| input: "0d0h0m0s", | ||
| expected: 0, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "large numbers", | ||
| input: "100d", | ||
| expected: 100 * 24 * time.Hour, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "all units combined", | ||
| input: "1yr2mo1w3d4h5m6s", | ||
| expected: 365*24*time.Hour + 2*30*24*time.Hour + 7*24*time.Hour + 3*24*time.Hour + 4*time.Hour + 5*time.Minute + 6*time.Second, | ||
| wantErr: false, | ||
| }, | ||
|
|
||
| // Error cases | ||
| { | ||
| name: "invalid character at start", | ||
| input: "abc", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "missing unit", | ||
| input: "123", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "invalid unit", | ||
| input: "5x", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "number with invalid character", | ||
| input: "5a5s", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "empty unit", | ||
| input: "5", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "negative number", | ||
| input: "-5s", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "decimal number", | ||
| input: "5.5s", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "unit without number", | ||
| input: "s", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| { | ||
| name: "mixed valid and invalid", | ||
| input: "5s10x", | ||
| expected: 0, | ||
| wantErr: true, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| result, err := ParseDuration(tt.input) | ||
|
|
||
| if tt.wantErr { | ||
| if err == nil { | ||
| t.Errorf("ParseDuration(%q) expected error, got nil", tt.input) | ||
| } | ||
| return | ||
| } | ||
|
|
||
| if err != nil { | ||
| t.Errorf("ParseDuration(%q) unexpected error: %v", tt.input, err) | ||
| return | ||
| } | ||
|
|
||
| if result.Duration != tt.expected { | ||
| t.Errorf("ParseDuration(%q) = %v, want %v", tt.input, result.Duration, tt.expected) | ||
| } | ||
| }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.