@@ -2,23 +2,71 @@ package kube_janitor
22
33import (
44 "context"
5+ "encoding/json"
56 "log/slog"
67
8+ jmespath "github.com/jmespath-community/go-jmespath"
79 "github.com/prometheus/client_golang/prometheus"
810 "github.com/webdevops/go-common/log/slogger"
911 prometheusCommon "github.com/webdevops/go-common/prometheus"
1012 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12- "k8s.io/apimachinery/pkg/runtime/schema"
1314)
1415
15- func (j * Janitor ) checkResourceTtlAndTriggerDeleteIfExpired (ctx context.Context , logger * slogger.Logger , gvr schema.GroupVersionResource , resource unstructured.Unstructured , ttlValue string , metricResourceTtl * prometheusCommon.MetricList , labels prometheus.Labels ) error {
16+ func (j * Janitor ) checkResourceIsSkippedByJmesPath (resource unstructured.Unstructured , jmesPath jmespath.JMESPath ) (bool , error ) {
17+
18+ resourceRaw , err := resource .MarshalJSON ()
19+ if err != nil {
20+ return true , err
21+ }
22+ var data any
23+ err = json .Unmarshal (resourceRaw , & data )
24+ if err != nil {
25+ return true , err
26+ }
27+
28+ // check if resource is valid by JMES path
29+ result , err := jmesPath .Search (data )
30+ if err != nil {
31+ return true , err
32+ }
33+
34+ switch v := result .(type ) {
35+ case string :
36+ // skip if string is empty
37+ if len (v ) == 0 {
38+ return true , nil
39+ }
40+ case bool :
41+ // skip if false (not selected)
42+ return ! v , nil
43+ case nil :
44+ // nil? jmes path didn't find anything? better skip the resource
45+ return true , nil
46+ }
47+
48+ return false , nil
49+ }
50+
51+ func (j * Janitor ) checkResourceTtlAndTriggerDeleteIfExpired (ctx context.Context , logger * slogger.Logger , resourceConfig * ConfigResource , resource unstructured.Unstructured , ttlValue string , metricResourceTtl * prometheusCommon.MetricList , labels prometheus.Labels ) error {
1652 resourceLogger := logger .With (
1753 slog .String ("namespace" , resource .GetNamespace ()),
1854 slog .String ("resource" , resource .GetName ()),
1955 slog .String ("ttl" , ttlValue ),
2056 )
2157
58+ if resourceConfig .JmesPath != "" {
59+ skipped , err := j .checkResourceIsSkippedByJmesPath (resource , resourceConfig .CompiledJmesPath ())
60+ if err != nil {
61+ return err
62+ }
63+
64+ if skipped {
65+ resourceLogger .Debug ("resource skipped by JMES path" )
66+ return nil
67+ }
68+ }
69+
2270 parsedDate , expired , err := j .checkExpiryDate (resource .GetCreationTimestamp ().Time , ttlValue )
2371 if err != nil {
2472 resourceLogger .Error ("unable to parse expiration date" , slog .String ("raw" , ttlValue ), slog .Any ("error" , err ))
@@ -39,7 +87,7 @@ func (j *Janitor) checkResourceTtlAndTriggerDeleteIfExpired(ctx context.Context,
3987 resourceLogger .Info ("resource is expired, would delete resource (DRY-RUN)" , slog .Time ("expirationDate" , * parsedDate ))
4088 } else {
4189 resourceLogger .Info ("deleting expired resource" , slog .Time ("expirationDate" , * parsedDate ))
42- err := j .dynClient .Resource (gvr ).Namespace (resource .GetNamespace ()).Delete (ctx , resource .GetName (), metav1.DeleteOptions {})
90+ err := j .dynClient .Resource (resourceConfig . AsGVR () ).Namespace (resource .GetNamespace ()).Delete (ctx , resource .GetName (), metav1.DeleteOptions {})
4391 if err != nil {
4492 return err
4593 }
0 commit comments