Skip to content

Commit 4676e37

Browse files
committed
add relative duration parsing
- allows unixtimestmaps - allows relative timestamps (using fortio.org/duration) using creation date Signed-off-by: Markus Blaschke <[email protected]>
1 parent 1c5e769 commit 4676e37

File tree

6 files changed

+94
-23
lines changed

6 files changed

+94
-23
lines changed

README.md

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,26 @@ Help Options:
3838

3939
Supported absolute timestamps
4040

41-
- 2006-01-02 15:04:05 +07:00
42-
- 2006-01-02 15:04:05 MST
43-
- 2006-01-02 15:04:05
44-
- 02 Jan 06 15:04 MST (RFC822)
45-
- 02 Jan 06 15:04 -0700 (RFC822Z)
46-
- Monday, 02-Jan-06 15:04:05 MST (RFC850)
47-
- Mon, 02 Jan 2006 15:04:05 MST (RFC1123)
48-
- Mon, 02 Jan 2006 15:04:05 -0700 (RFC1123Z)
49-
- 2006-01-02T15:04:05Z07:00 (RFC3339)
50-
- 2006-01-02T15:04:05.999999999Z07:00 (RFC3339Nano)
51-
- 2006-01-02
41+
- `2006-01-02 15:04:05 +07:00`
42+
- `2006-01-02 15:04:05 MST`
43+
- `2006-01-02 15:04:05`
44+
- `02 Jan 06 15:04 MST` (RFC822)
45+
- `02 Jan 06 15:04 -0700` (RFC822Z)
46+
- `Monday, 02-Jan-06 15:04:05 MST` (RFC850)
47+
- `Mon, 02 Jan 2006 15:04:05 MST` (RFC1123)
48+
- `Mon, 02 Jan 2006 15:04:05 -0700` (RFC1123Z)
49+
- `2006-01-02T15:04:05Z07:00` (RFC3339)
50+
- `2006-01-02T15:04:05.999999999Z07:00` (RFC3339Nano)
51+
- `2006-01-02`
52+
53+
Supported relative timestamps ([`time.Duration`](https://pkg.go.dev/time) and [`fortio.org/duration`](https://github.com/fortio/duration))
54+
55+
- `1m` (minute)
56+
- `1h` (hour)
57+
- `1d` (day)
58+
- `1d6h` (1 day, 6 hours)
59+
- `1w` (1 week)
60+
- `1w2d6h` (1 week, 2 days, 6 hours)
5261

5362
## Metrics
5463

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/webdevops/kube-janitor
33
go 1.25.5
44

55
require (
6+
fortio.org/duration v1.0.4
67
github.com/go-logr/logr v1.4.3
78
github.com/goccy/go-yaml v1.19.0
89
github.com/jessevdk/go-flags v1.6.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
fortio.org/duration v1.0.4 h1:TB07ng4UsMZPDRujJRkTJIcNqMTLM283zob10nb9K24=
2+
fortio.org/duration v1.0.4/go.mod h1:RuBVqdcCKRwMmI8WIdVq8kd7ngQPCIe6G7AU0NC0XDw=
13
github.com/KimMachineGun/automemlimit v0.7.5 h1:RkbaC0MwhjL1ZuBKunGDjE/ggwAX43DwZrJqVwyveTk=
24
github.com/KimMachineGun/automemlimit v0.7.5/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
35
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=

kube_janitor/expiry.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package kube_janitor
22

33
import (
44
"fmt"
5+
"strconv"
56
"strings"
67
"time"
8+
9+
"fortio.org/duration"
710
)
811

912
var (
@@ -29,20 +32,36 @@ var (
2932
}
3033
)
3134

32-
func (j *Janitor) checkExpiryDate(value string) (parsedTime *time.Time, expired bool, err error) {
35+
func (j *Janitor) checkExpiryDate(createdAt time.Time, expiry string) (parsedTime *time.Time, expired bool, err error) {
3336
expired = false
3437

3538
// sanity checks
36-
value = strings.TrimSpace(value)
37-
if value == "" {
39+
expiry = strings.TrimSpace(expiry)
40+
if expiry == "" || expiry == "0" {
3841
return
3942
}
4043

44+
// parse as unix timestamp
45+
if unixTimestamp, err := strconv.ParseInt(expiry, 10, 64); err == nil {
46+
expiryTime := time.Unix(unixTimestamp, 0)
47+
parsedTime = &expiryTime
48+
}
49+
50+
// parse duration
51+
if !createdAt.IsZero() {
52+
if expiryDuration, err := duration.Parse(expiry); err == nil && expiryDuration.Seconds() > 1 {
53+
expiryTime := createdAt.Add(expiryDuration)
54+
parsedTime = &expiryTime
55+
}
56+
}
57+
4158
// parse time
42-
for _, timeFormat := range janitorTimeFormats {
43-
if parseVal, parseErr := time.Parse(timeFormat, value); parseErr == nil && parseVal.Unix() > 0 {
44-
parsedTime = &parseVal
45-
break
59+
if parsedTime == nil {
60+
for _, timeFormat := range janitorTimeFormats {
61+
if parseVal, parseErr := time.Parse(timeFormat, expiry); parseErr == nil && parseVal.Unix() > 0 {
62+
parsedTime = &parseVal
63+
break
64+
}
4665
}
4766
}
4867

@@ -51,7 +70,7 @@ func (j *Janitor) checkExpiryDate(value string) (parsedTime *time.Time, expired
5170
// check if parsed time is before NOW -> expired
5271
expired = parsedTime.Before(time.Now())
5372
} else {
54-
err = fmt.Errorf("unable to parse time '%s'", value)
73+
err = fmt.Errorf("unable to parse time '%s'", expiry)
5574
}
5675

5776
return

kube_janitor/manager.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,17 @@ func (j *Janitor) Run() error {
155155
gvkLogger.Debug("checking resources")
156156

157157
err := j.kubeEachResource(ctx, resourceType.AsGVR(), func(resource unstructured.Unstructured) error {
158-
resourceLogger := gvkLogger.With("namespace", resource.GetNamespace(), "resource", resource.GetName())
159158

160-
if expiryDate := resource.GetLabels()[j.config.Label]; expiryDate != "" {
161-
parsedDate, expired, err := j.checkExpiryDate(expiryDate)
159+
if ttl := resource.GetLabels()[j.config.Label]; ttl != "" {
160+
resourceLogger := gvkLogger.With(
161+
slog.String("namespace", resource.GetNamespace()),
162+
slog.String("resource", resource.GetName()),
163+
slog.String("ttl", ttl),
164+
)
165+
166+
parsedDate, expired, err := j.checkExpiryDate(resource.GetCreationTimestamp().Time, ttl)
162167
if err != nil {
163-
resourceLogger.Error("unable to parse expiration date", slog.String("raw", expiryDate), slog.Any("error", err))
168+
resourceLogger.Error("unable to parse expiration date", slog.String("raw", ttl), slog.Any("error", err))
164169
return nil
165170
}
166171

tests/configmap.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,38 @@ metadata:
1111
name: foo2
1212
labels:
1313
ttl: 2026-01-01
14+
---
15+
apiVersion: v1
16+
kind: ConfigMap
17+
metadata:
18+
name: foo-rel-1m
19+
labels:
20+
ttl: 1m
21+
---
22+
apiVersion: v1
23+
kind: ConfigMap
24+
metadata:
25+
name: foo-rel-1d
26+
labels:
27+
ttl: "1d"
28+
---
29+
apiVersion: v1
30+
kind: ConfigMap
31+
metadata:
32+
name: foo-rel-5d
33+
labels:
34+
ttl: "5d"
35+
---
36+
apiVersion: v1
37+
kind: ConfigMap
38+
metadata:
39+
name: foo-rel-1d6h
40+
labels:
41+
ttl: "1d6h"
42+
---
43+
apiVersion: v1
44+
kind: ConfigMap
45+
metadata:
46+
name: foo-invalid
47+
labels:
48+
ttl: "1237123123"

0 commit comments

Comments
 (0)