Skip to content

Commit

Permalink
Merge pull request #107 from m00g3n/add-requeue-tests
Browse files Browse the repository at this point in the history
Add requeue tests
  • Loading branch information
kyma-bot authored Dec 20, 2023
2 parents 8fdee32 + cb3b335 commit e2814c5
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 46 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21
require (
github.com/gardener/gardener v1.85.0
github.com/go-logr/logr v1.3.0
github.com/onsi/ginkgo/v2 v2.13.0
github.com/onsi/ginkgo/v2 v2.13.2
github.com/onsi/gomega v1.30.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.16.0
Expand Down Expand Up @@ -55,11 +55,11 @@ require (
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.13.0 // indirect
golang.org/x/tools v0.14.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -167,6 +169,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
Expand All @@ -185,6 +189,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
19 changes: 19 additions & 0 deletions internal/controller/find_last_sync_time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package controller

import (
"time"
)

func findLastSyncTime(annotations map[string]string) (time.Time, bool) {
_, found := annotations[lastKubeconfigSyncAnnotation]
if !found {
return time.Time{}, false
}

lastSyncTimeString := annotations[lastKubeconfigSyncAnnotation]
lastSyncTime, err := time.Parse(time.RFC3339, lastSyncTimeString)
if err != nil {
return time.Time{}, false
}
return lastSyncTime, true
}
27 changes: 27 additions & 0 deletions internal/controller/find_last_sync_time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package controller

import (
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("findLastSyncTime", func() {

DescribeTable("should return expected values when",
func(annotations map[string]string, expectedFound bool, expectedTime time.Time) {
lastSyncTime, found := findLastSyncTime(annotations)
Expect(found).To(Equal(expectedFound))
Expect(lastSyncTime).To(Equal(expectedTime))
},
Entry("receives empty annotation map", make(map[string]string), false, time.Time{}),
Entry("receives annotation map containing valid date value",
map[string]string{lastKubeconfigSyncAnnotation: "2023-01-01T12:00:00Z"}, true,
func() time.Time {
t, _ := time.Parse(time.RFC3339, "2023-01-01T12:00:00Z")
return t
}()),
Entry("receives annotation map containing invalid date value", map[string]string{lastKubeconfigSyncAnnotation: "invalid"}, false, time.Time{}),
)
})
54 changes: 11 additions & 43 deletions internal/controller/gardener_cluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (controller *GardenerClusterController) Reconcile(ctx context.Context, req
}

if err == nil {
controller.log.Info("Secret has been deleted.", loggingContext(req)...)
controller.log.Info("The gardener cluster does not exist the coresponding secret has been deleted.", loggingContext(req)...)
}

return controller.resultWithoutRequeue(&cluster), err
Expand All @@ -113,7 +113,7 @@ func (controller *GardenerClusterController) Reconcile(ctx context.Context, req
annotations = secret.Annotations
}

_, lastSyncTime := findLastSyncTime(annotations)
lastSyncTime, _ := findLastSyncTime(annotations)
now := time.Now().UTC()
requeueAfter := nextRequeue(now, lastSyncTime, controller.rotationPeriod, rotationPeriodRatio)

Expand Down Expand Up @@ -259,7 +259,7 @@ func (controller *GardenerClusterController) handleKubeconfig(ctx context.Contex
return ksRotated, nil
}

if !secretNeedsToBeRotated(cluster, secret, controller.rotationPeriod) {
if !secretNeedsToBeRotated(cluster, secret, controller.rotationPeriod, now) {
message := fmt.Sprintf("Secret %s in namespace %s does not need to be rotated yet.", cluster.Spec.Kubeconfig.Secret.Name, cluster.Spec.Kubeconfig.Secret.Namespace)
controller.log.Info(message, loggingContextFromCluster(cluster)...)
cluster.UpdateConditionForReadyState(imv1.ConditionTypeKubeconfigManagement, imv1.ConditionReasonKubeconfigSecretCreated, metav1.ConditionTrue)
Expand All @@ -273,57 +273,25 @@ func (controller *GardenerClusterController) handleKubeconfig(ctx context.Contex
return ksCreated, controller.createNewSecret(ctx, kubeconfig, cluster, now)
}

func secretNeedsToBeRotated(cluster *imv1.GardenerCluster, secret *corev1.Secret, rotationPeriod time.Duration) bool {
return secretRotationTimePassed(secret, rotationPeriod) || secretRotationForced(cluster)
func secretNeedsToBeRotated(cluster *imv1.GardenerCluster, secret *corev1.Secret, rotationPeriod time.Duration, now time.Time) bool {
return secretRotationTimePassed(secret, rotationPeriod, now) || secretRotationForced(cluster)
}

func findLastSyncTime(annotations map[string]string) (bool, time.Time) {
_, found := annotations[lastKubeconfigSyncAnnotation]
if !found {
return false, time.Time{}
}

lastSyncTimeString := annotations[lastKubeconfigSyncAnnotation]
lastSyncTime, err := time.Parse(time.RFC3339, lastSyncTimeString)
if err != nil {
return false, time.Time{}
}
return true, lastSyncTime
}

// nextRequeue - predicts duration for next requeue of GardenerCluster CR
func nextRequeue(now, lastSyncTime time.Time, rotationPeriod time.Duration, modifier float64) time.Duration {
rotationPeriodWithModifier := modifier * rotationPeriod.Minutes()
minutesToRequeue := rotationPeriodWithModifier - now.Sub(lastSyncTime).Minutes()
if minutesToRequeue <= 0 {
return time.Duration(rotationPeriodWithModifier * float64(time.Minute))
}

return time.Duration(minutesToRequeue * float64(time.Minute))
}

func secretRotationTimePassed(secret *corev1.Secret, rotationPeriod time.Duration) bool {
func secretRotationTimePassed(secret *corev1.Secret, rotationPeriod time.Duration, now time.Time) bool {
if secret == nil {
return true
}

annotations := secret.GetAnnotations()

_, found := annotations[lastKubeconfigSyncAnnotation]

lastSyncTime, found := findLastSyncTime(annotations)
if !found {
return true
}

lastSyncTimeString := annotations[lastKubeconfigSyncAnnotation]
lastSyncTime, err := time.Parse(time.RFC3339, lastSyncTimeString)
if err != nil {
return true
}
now := time.Now()
alreadyValidFor := now.Sub(lastSyncTime)
minutesToRotate := now.Sub(lastSyncTime).Minutes()
minutesInRotationPeriod := rotationPeriodRatio * rotationPeriod.Minutes()

return alreadyValidFor.Minutes() >= rotationPeriodRatio*rotationPeriod.Minutes()
return minutesToRotate >= minutesInRotationPeriod
}

func secretRotationForced(cluster *imv1.GardenerCluster) bool {
Expand Down Expand Up @@ -413,7 +381,7 @@ func (controller *GardenerClusterController) removeForceRotationAnnotation(ctx c
delete(annotations, forceKubeconfigRotationAnnotation)
clusterToUpdate.SetAnnotations(annotations)

return controller.Client.Update(ctx, &clusterToUpdate)
return controller.Update(ctx, &clusterToUpdate)
}

return nil
Expand Down
16 changes: 16 additions & 0 deletions internal/controller/next_requeue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package controller

import (
"time"
)

// nextRequeue - predicts duration for next requeue of GardenerCluster CR
func nextRequeue(now, lastSyncTime time.Time, rotationPeriod time.Duration, modifier float64) time.Duration {
rotationPeriodWithModifier := modifier * rotationPeriod.Minutes()
minutesToRequeue := rotationPeriodWithModifier - now.Sub(lastSyncTime).Minutes()
if minutesToRequeue <= 0 {
return time.Duration(rotationPeriodWithModifier * float64(time.Minute))
}

return time.Duration(minutesToRequeue * float64(time.Minute))
}
28 changes: 28 additions & 0 deletions internal/controller/next_requeue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package controller

import (
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("nextRequeueAfter", func() {
var (
now = time.Now()
newYear, _ = time.Parse(time.RFC3339, "2024-01-01T00:00:01Z00:00")
)

DescribeTable("should return expected values when",
func(now, lastSyncTime time.Time, rotationPeriod time.Duration, modifier float64, expectedDuration time.Duration) {
result := nextRequeue(now, lastSyncTime, rotationPeriod, modifier)
Expect(result).To(BeNumerically("~", expectedDuration, 1))
},
Entry("receives all zero arguments", now, time.Time{}, time.Duration(0), 0.0, time.Duration(0)),
Entry("receives arguments (now, zero, 1[m], 0.95)", now, time.Time{}, time.Minute, 0.95, time.Second*57),
Entry("receives arguments (now, now-30[s], 1[m], 0.95)", now, now.Add(-30*time.Second), time.Minute, 0.95, time.Nanosecond*26999999999),
Entry("receives arguments (now, now-900[s], 1[m], 0.95)", now, now.Add(-900*time.Second), time.Minute, 0.95, time.Second*57),
Entry("receives arguments (now, now, 1[m], 0.95)", now, now, time.Minute, 0.95, time.Second*57),
Entry("receives arguments (newYear, newYear-45[m], 1[h], 0.95)", newYear, newYear.Add(-45*time.Minute), time.Hour, 0.95, time.Nanosecond*719999999999),
)
})

0 comments on commit e2814c5

Please sign in to comment.