@@ -4,11 +4,14 @@ import (
4
4
"fmt"
5
5
"os"
6
6
"regexp"
7
+ "strconv"
7
8
"strings"
9
+ "time"
8
10
9
11
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10
12
11
13
"github.com/openshift/library-go/pkg/certs/cert-inspection/certgraphapi"
14
+ "github.com/openshift/library-go/pkg/operator/certrotation"
12
15
corev1 "k8s.io/api/core/v1"
13
16
)
14
17
@@ -158,8 +161,32 @@ var (
158
161
secret .Name = strings .ReplaceAll (secret .Name , hash , "<hash>" )
159
162
},
160
163
}
164
+ RewriteRefreshPeriod = & metadataOptions {
165
+ rewriteSecretFn : func (secret * corev1.Secret ) {
166
+ humanizeRefreshPeriodFromMetadata (secret .Annotations )
167
+ },
168
+ rewriteConfigMapFn : func (configMap * corev1.ConfigMap ) {
169
+ humanizeRefreshPeriodFromMetadata (configMap .Annotations )
170
+ },
171
+ }
161
172
)
162
173
174
+ func humanizeRefreshPeriodFromMetadata (annotations map [string ]string ) {
175
+ period , ok := annotations [certrotation .CertificateRefreshPeriodAnnotation ]
176
+ if ! ok {
177
+ return
178
+ }
179
+ d , err := time .ParseDuration (period )
180
+ if err != nil {
181
+ fmt .Fprintf (os .Stderr , "Failed to parse certificate refresh period %q: %v\n " , period , err )
182
+ return
183
+ }
184
+ humanReadableDate := durationToHumanReadableString (d )
185
+ annotations [certrotation .CertificateRefreshPeriodAnnotation ] = humanReadableDate
186
+ annotations [rewritePrefix + "RewriteRefreshPeriod" ] = period
187
+ return
188
+ }
189
+
163
190
// skipRevisionedInOnDiskLocation returns true if location is for revisioned certificate and needs to be skipped
164
191
func skipRevisionedInOnDiskLocation (location certgraphapi.OnDiskLocation ) bool {
165
192
if len (location .Path ) == 0 {
@@ -235,3 +262,62 @@ func StripRootFSMountPoint(rootfsMount string) *metadataOptions {
235
262
},
236
263
}
237
264
}
265
+
266
+ // durationToHumanReadableString formats a duration into a human-readable string.
267
+ // Unlike Go's built-in `time.Duration.String()`, which returns a string like "72h0m0s", this function returns a more concise format like "3d" or "5d4h25m".
268
+ // Implementation is based on https://github.com/gomodules/sprig/blob/master/date.go#L97-L139,
269
+ // but it doesn't round the duration to the nearest largest value but converts it precisely
270
+ // This function rounds duration to the nearest second and handles negative durations by taking the absolute value.
271
+ func durationToHumanReadableString (d time.Duration ) string {
272
+ if d == 0 {
273
+ return "0s"
274
+ }
275
+ // Handle negative durations by taking the absolute value
276
+ // This also rounds the duration to the nearest second
277
+ u := uint64 (d .Abs ().Seconds ())
278
+
279
+ var b strings.Builder
280
+
281
+ writeUnit := func (value uint64 , suffix string ) {
282
+ if value > 0 {
283
+ b .WriteString (strconv .FormatUint (value , 10 ))
284
+ b .WriteString (suffix )
285
+ }
286
+ }
287
+
288
+ const (
289
+ // Unit values in seconds
290
+ year = 60 * 60 * 24 * 365
291
+ month = 60 * 60 * 24 * 30
292
+ day = 60 * 60 * 24
293
+ hour = 60 * 60
294
+ minute = 60
295
+ second = 1
296
+ )
297
+
298
+ years := u / year
299
+ u %= year
300
+ writeUnit (years , "y" )
301
+
302
+ months := u / month
303
+ u %= month
304
+ writeUnit (months , "mo" )
305
+
306
+ days := u / day
307
+ u %= day
308
+ writeUnit (days , "d" )
309
+
310
+ hours := u / hour
311
+ u %= hour
312
+ writeUnit (hours , "h" )
313
+
314
+ minutes := u / minute
315
+ u %= minute
316
+ writeUnit (minutes , "m" )
317
+
318
+ seconds := u / second
319
+ u %= second
320
+ writeUnit (seconds , "s" )
321
+
322
+ return b .String ()
323
+ }
0 commit comments