From aceb7d5068420b79c7cbfddf9a67312cc1bbf421 Mon Sep 17 00:00:00 2001
From: Khaled Emara
Date: Wed, 21 Aug 2024 22:32:58 +0300
Subject: [PATCH] feat(gctx): retry logic (#10796)
Signed-off-by: Khaled Emara
---
.../v2alpha1/global_context_entry_types.go | 6 +++++
.../kyverno.io_globalcontextentries.yaml | 6 +++++
.../kyverno.io_globalcontextentries.yaml | 6 +++++
config/install-latest-testing.yaml | 6 +++++
docs/user/crd/index.html | 12 +++++++++
docs/user/crd/kyverno.v2alpha1.html | 27 +++++++++++++++++++
.../kyverno/v2alpha1/externalapicall.go | 9 +++++++
pkg/globalcontext/externalapi/entry.go | 22 ++++++++++++---
.../apicall-correct/chainsaw-test.yaml | 4 ++-
.../apicall-correct/main-deployment.yaml | 14 +++++++---
.../apicall-correct/new-deployment.yaml | 14 +++++++---
.../apicall-failed/gctxentry.yaml | 2 +-
.../gctxentry-not-exist/chainsaw-test.yaml | 2 ++
.../gctxentry-not-exist/main-deployment.yaml | 14 +++++++---
.../not-ready/chainsaw-test.yaml | 6 +++--
.../globalcontext/not-ready/gctxentry.yaml | 2 +-
.../not-ready/main-deployment.yaml | 14 +++++++---
.../not-ready/new-deployment.yaml | 14 +++++++---
.../resource-correct/chainsaw-test.yaml | 4 ++-
.../resource-correct/main-deployment.yaml | 14 +++++++---
.../resource-correct/new-deployment.yaml | 14 +++++++---
.../validate-crd/valid-context.yaml | 2 +-
22 files changed, 176 insertions(+), 38 deletions(-)
diff --git a/api/kyverno/v2alpha1/global_context_entry_types.go b/api/kyverno/v2alpha1/global_context_entry_types.go
index 81e70e15d63c..5223658ca904 100644
--- a/api/kyverno/v2alpha1/global_context_entry_types.go
+++ b/api/kyverno/v2alpha1/global_context_entry_types.go
@@ -157,6 +157,12 @@ type ExternalAPICall struct {
// +kubebuilder:validation:Format=duration
// +kubebuilder:default=`10m`
RefreshInterval *metav1.Duration `json:"refreshInterval,omitempty"`
+ // RetryLimit defines the number of times the APICall should be retried in case of failure.
+ // +kubebuilder:validation:Minimum=1
+ // +kubebuilder:default=3
+ // +kubebuilder:validation:Optional
+ // +optional
+ RetryLimit int `json:"retryLimit,omitempty"`
}
// Validate implements programmatic validation
diff --git a/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml b/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml
index 2af691846a9e..e0d085d843d2 100644
--- a/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml
+++ b/charts/kyverno/charts/crds/templates/kyverno.io/kyverno.io_globalcontextentries.yaml
@@ -105,6 +105,12 @@ spec:
such as "300ms", "1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
format: duration
type: string
+ retryLimit:
+ default: 3
+ description: RetryLimit defines the number of times the APICall
+ should be retried in case of failure.
+ minimum: 1
+ type: integer
service:
description: |-
Service is an API call to a JSON web service.
diff --git a/config/crds/kyverno/kyverno.io_globalcontextentries.yaml b/config/crds/kyverno/kyverno.io_globalcontextentries.yaml
index ad2fb3ea027b..b2c19f280c10 100644
--- a/config/crds/kyverno/kyverno.io_globalcontextentries.yaml
+++ b/config/crds/kyverno/kyverno.io_globalcontextentries.yaml
@@ -99,6 +99,12 @@ spec:
such as "300ms", "1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
format: duration
type: string
+ retryLimit:
+ default: 3
+ description: RetryLimit defines the number of times the APICall
+ should be retried in case of failure.
+ minimum: 1
+ type: integer
service:
description: |-
Service is an API call to a JSON web service.
diff --git a/config/install-latest-testing.yaml b/config/install-latest-testing.yaml
index 542b0e1c9ebb..a9e97ae4ca37 100644
--- a/config/install-latest-testing.yaml
+++ b/config/install-latest-testing.yaml
@@ -24369,6 +24369,12 @@ spec:
such as "300ms", "1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
format: duration
type: string
+ retryLimit:
+ default: 3
+ description: RetryLimit defines the number of times the APICall
+ should be retried in case of failure.
+ minimum: 1
+ type: integer
service:
description: |-
Service is an API call to a JSON web service.
diff --git a/docs/user/crd/index.html b/docs/user/crd/index.html
index faea1f31dd83..553be8585551 100644
--- a/docs/user/crd/index.html
+++ b/docs/user/crd/index.html
@@ -7112,6 +7112,18 @@ ExternalAPICall
such as “300ms”, “1.5h” or “2h45m”. Valid time units are “ns”, “us” (or “µs”), “ms”, “s”, “m”, “h”.
+
+
+retryLimit
+
+int
+
+ |
+
+(Optional)
+ RetryLimit defines the number of times the APICall should be retried in case of failure.
+ |
+
diff --git a/docs/user/crd/kyverno.v2alpha1.html b/docs/user/crd/kyverno.v2alpha1.html
index 142ff319a683..5cd82e14f338 100644
--- a/docs/user/crd/kyverno.v2alpha1.html
+++ b/docs/user/crd/kyverno.v2alpha1.html
@@ -337,6 +337,33 @@ ExternalAPICall
+
+
+
+ retryLimit
+
+
+
+
+
+
+ int
+
+
+ |
+
+
+
+ RetryLimit defines the number of times the APICall should be retried in case of failure.
+
+
+
+
+
+ |
+
+
+
diff --git a/pkg/client/applyconfigurations/kyverno/v2alpha1/externalapicall.go b/pkg/client/applyconfigurations/kyverno/v2alpha1/externalapicall.go
index f8ef7c870189..df833c1c7509 100644
--- a/pkg/client/applyconfigurations/kyverno/v2alpha1/externalapicall.go
+++ b/pkg/client/applyconfigurations/kyverno/v2alpha1/externalapicall.go
@@ -29,6 +29,7 @@ import (
type ExternalAPICallApplyConfiguration struct {
v1.APICallApplyConfiguration `json:",omitempty,inline"`
RefreshInterval *metav1.Duration `json:"refreshInterval,omitempty"`
+ RetryLimit *int `json:"retryLimit,omitempty"`
}
// ExternalAPICallApplyConfiguration constructs an declarative configuration of the ExternalAPICall type for use with
@@ -81,3 +82,11 @@ func (b *ExternalAPICallApplyConfiguration) WithRefreshInterval(value metav1.Dur
b.RefreshInterval = &value
return b
}
+
+// WithRetryLimit sets the RetryLimit field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the RetryLimit field is set to the value of the last call.
+func (b *ExternalAPICallApplyConfiguration) WithRetryLimit(value int) *ExternalAPICallApplyConfiguration {
+ b.RetryLimit = &value
+ return b
+}
diff --git a/pkg/globalcontext/externalapi/entry.go b/pkg/globalcontext/externalapi/entry.go
index 4fd35b5f138f..6960e00fb264 100644
--- a/pkg/globalcontext/externalapi/entry.go
+++ b/pkg/globalcontext/externalapi/entry.go
@@ -59,7 +59,7 @@ func New(
caller := apicall.NewExecutor(logger, "globalcontext", client, config)
wait.UntilWithContext(ctx, func(ctx context.Context) {
- if data, err := doCall(ctx, caller, call); err != nil {
+ if data, err := doCall(ctx, caller, call, gce.Spec.APICall.RetryLimit); err != nil {
e.setData(nil, err)
logger.Error(err, "failed to get data from api caller")
@@ -127,8 +127,24 @@ func (e *entry) setData(data any, err error) {
}
}
-func doCall(ctx context.Context, caller apicall.Executor, call kyvernov1.APICall) (any, error) {
- return caller.Execute(ctx, &call)
+func doCall(ctx context.Context, caller apicall.Executor, call kyvernov1.APICall, retryLimit int) (any, error) {
+ var result any
+ backoff := wait.Backoff{
+ Duration: retry.DefaultBackoff.Duration,
+ Factor: retry.DefaultBackoff.Factor,
+ Jitter: retry.DefaultBackoff.Jitter,
+ Steps: retryLimit,
+ }
+
+ retryError := retry.OnError(backoff, func(err error) bool {
+ return err != nil
+ }, func() error {
+ var exeErr error
+ result, exeErr = caller.Execute(ctx, &call)
+ return exeErr
+ })
+
+ return result, retryError
}
func updateStatus(ctx context.Context, gceName string, kyvernoClient versioned.Interface, ready bool, reason string) error {
diff --git a/test/conformance/chainsaw/globalcontext/apicall-correct/chainsaw-test.yaml b/test/conformance/chainsaw/globalcontext/apicall-correct/chainsaw-test.yaml
index b077033504de..836d646b3ac3 100755
--- a/test/conformance/chainsaw/globalcontext/apicall-correct/chainsaw-test.yaml
+++ b/test/conformance/chainsaw/globalcontext/apicall-correct/chainsaw-test.yaml
@@ -14,9 +14,11 @@ spec:
- apply:
file: gctxentry.yaml
- sleep:
- duration: 15s
+ duration: 3s
- apply:
file: clusterpolicy.yaml
+ - sleep:
+ duration: 3s
- assert:
file: clusterpolicy-ready.yaml
- apply:
diff --git a/test/conformance/chainsaw/globalcontext/apicall-correct/main-deployment.yaml b/test/conformance/chainsaw/globalcontext/apicall-correct/main-deployment.yaml
index 09fac90b00d5..de449d2cd9f8 100755
--- a/test/conformance/chainsaw/globalcontext/apicall-correct/main-deployment.yaml
+++ b/test/conformance/chainsaw/globalcontext/apicall-correct/main-deployment.yaml
@@ -16,7 +16,13 @@ spec:
app: main-deployment
spec:
containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
+ - name: pause
+ image: registry.k8s.io/pause:latest
+ resources:
+ requests:
+ cpu: 10m
+ memory: 10Mi
+ limits:
+ cpu: 10m
+ memory: 10Mi
+ terminationGracePeriodSeconds: 0
diff --git a/test/conformance/chainsaw/globalcontext/apicall-correct/new-deployment.yaml b/test/conformance/chainsaw/globalcontext/apicall-correct/new-deployment.yaml
index c162c0a48bbd..72d3039d3afe 100755
--- a/test/conformance/chainsaw/globalcontext/apicall-correct/new-deployment.yaml
+++ b/test/conformance/chainsaw/globalcontext/apicall-correct/new-deployment.yaml
@@ -16,7 +16,13 @@ spec:
app: new-deployment
spec:
containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
+ - name: pause
+ image: registry.k8s.io/pause:latest
+ resources:
+ requests:
+ cpu: 10m
+ memory: 10Mi
+ limits:
+ cpu: 10m
+ memory: 10Mi
+ terminationGracePeriodSeconds: 0
diff --git a/test/conformance/chainsaw/globalcontext/apicall-failed/gctxentry.yaml b/test/conformance/chainsaw/globalcontext/apicall-failed/gctxentry.yaml
index e1cc305a275e..e5d1f981683b 100755
--- a/test/conformance/chainsaw/globalcontext/apicall-failed/gctxentry.yaml
+++ b/test/conformance/chainsaw/globalcontext/apicall-failed/gctxentry.yaml
@@ -5,4 +5,4 @@ metadata:
spec:
apiCall:
urlPath: "/apis/apps/v1/namespaces/default/unknown"
- refreshInterval: 10s
+ refreshInterval: 1h
diff --git a/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/chainsaw-test.yaml b/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/chainsaw-test.yaml
index 0016dbdea870..7875ffb948f6 100755
--- a/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/chainsaw-test.yaml
+++ b/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/chainsaw-test.yaml
@@ -15,5 +15,7 @@ spec:
try:
- apply:
file: clusterpolicy.yaml
+ - sleep:
+ duration: 3s
- assert:
file: clusterpolicy-assert.yaml
diff --git a/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/main-deployment.yaml b/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/main-deployment.yaml
index a79c3f841f5b..73fd896c82e7 100755
--- a/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/main-deployment.yaml
+++ b/test/conformance/chainsaw/globalcontext/gctxentry-not-exist/main-deployment.yaml
@@ -16,7 +16,13 @@ spec:
app: main-deployment
spec:
containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
+ - name: pause
+ image: registry.k8s.io/pause:latest
+ resources:
+ requests:
+ cpu: 10m
+ memory: 10Mi
+ limits:
+ cpu: 10m
+ memory: 10Mi
+ terminationGracePeriodSeconds: 0
diff --git a/test/conformance/chainsaw/globalcontext/not-ready/chainsaw-test.yaml b/test/conformance/chainsaw/globalcontext/not-ready/chainsaw-test.yaml
index 4349ddc67b5b..0aa3e2a7375a 100755
--- a/test/conformance/chainsaw/globalcontext/not-ready/chainsaw-test.yaml
+++ b/test/conformance/chainsaw/globalcontext/not-ready/chainsaw-test.yaml
@@ -14,9 +14,11 @@ spec:
- apply:
file: gctxentry.yaml
- sleep:
- duration: 15s
+ duration: 3s
- apply:
file: clusterpolicy.yaml
+ - sleep:
+ duration: 3s
- assert:
file: clusterpolicy-ready.yaml
- delete:
@@ -25,7 +27,7 @@ spec:
kind: GlobalContextEntry
name: gctx-not-ready
- sleep:
- duration: 5s
+ duration: 3s
- assert:
file: clusterpolicy-failed.yaml
- apply:
diff --git a/test/conformance/chainsaw/globalcontext/not-ready/gctxentry.yaml b/test/conformance/chainsaw/globalcontext/not-ready/gctxentry.yaml
index 68e4359cdebf..641a33af4886 100755
--- a/test/conformance/chainsaw/globalcontext/not-ready/gctxentry.yaml
+++ b/test/conformance/chainsaw/globalcontext/not-ready/gctxentry.yaml
@@ -5,4 +5,4 @@ metadata:
spec:
apiCall:
urlPath: "/apis/apps/v1/namespaces/test-globalcontext-not-ready/deployments"
- refreshInterval: 10s
+ refreshInterval: 1h
diff --git a/test/conformance/chainsaw/globalcontext/not-ready/main-deployment.yaml b/test/conformance/chainsaw/globalcontext/not-ready/main-deployment.yaml
index 05c7d1ae44fa..d40d62748dc0 100755
--- a/test/conformance/chainsaw/globalcontext/not-ready/main-deployment.yaml
+++ b/test/conformance/chainsaw/globalcontext/not-ready/main-deployment.yaml
@@ -16,7 +16,13 @@ spec:
app: main-deployment
spec:
containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
+ - name: pause
+ image: registry.k8s.io/pause:latest
+ resources:
+ requests:
+ cpu: 10m
+ memory: 10Mi
+ limits:
+ cpu: 10m
+ memory: 10Mi
+ terminationGracePeriodSeconds: 0
diff --git a/test/conformance/chainsaw/globalcontext/not-ready/new-deployment.yaml b/test/conformance/chainsaw/globalcontext/not-ready/new-deployment.yaml
index 53e0128f2fb0..533c62614e22 100755
--- a/test/conformance/chainsaw/globalcontext/not-ready/new-deployment.yaml
+++ b/test/conformance/chainsaw/globalcontext/not-ready/new-deployment.yaml
@@ -16,7 +16,13 @@ spec:
app: new-deployment
spec:
containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
+ - name: pause
+ image: registry.k8s.io/pause:latest
+ resources:
+ requests:
+ cpu: 10m
+ memory: 10Mi
+ limits:
+ cpu: 10m
+ memory: 10Mi
+ terminationGracePeriodSeconds: 0
diff --git a/test/conformance/chainsaw/globalcontext/resource-correct/chainsaw-test.yaml b/test/conformance/chainsaw/globalcontext/resource-correct/chainsaw-test.yaml
index 4a2dde9d2e2a..2d1d0e11f643 100755
--- a/test/conformance/chainsaw/globalcontext/resource-correct/chainsaw-test.yaml
+++ b/test/conformance/chainsaw/globalcontext/resource-correct/chainsaw-test.yaml
@@ -14,9 +14,11 @@ spec:
- apply:
file: gctxentry.yaml
- sleep:
- duration: 5s
+ duration: 3s
- apply:
file: clusterpolicy.yaml
+ - sleep:
+ duration: 3s
- assert:
file: clusterpolicy-ready.yaml
- apply:
diff --git a/test/conformance/chainsaw/globalcontext/resource-correct/main-deployment.yaml b/test/conformance/chainsaw/globalcontext/resource-correct/main-deployment.yaml
index ca3b3654785e..c8c737aa3196 100755
--- a/test/conformance/chainsaw/globalcontext/resource-correct/main-deployment.yaml
+++ b/test/conformance/chainsaw/globalcontext/resource-correct/main-deployment.yaml
@@ -16,7 +16,13 @@ spec:
app: main-deployment
spec:
containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
+ - name: pause
+ image: registry.k8s.io/pause:latest
+ resources:
+ requests:
+ cpu: 10m
+ memory: 10Mi
+ limits:
+ cpu: 10m
+ memory: 10Mi
+ terminationGracePeriodSeconds: 0
diff --git a/test/conformance/chainsaw/globalcontext/resource-correct/new-deployment.yaml b/test/conformance/chainsaw/globalcontext/resource-correct/new-deployment.yaml
index c9812eda735a..2773a6a689e0 100755
--- a/test/conformance/chainsaw/globalcontext/resource-correct/new-deployment.yaml
+++ b/test/conformance/chainsaw/globalcontext/resource-correct/new-deployment.yaml
@@ -16,7 +16,13 @@ spec:
app: new-deployment
spec:
containers:
- - name: nginx
- image: nginx:1.14.2
- ports:
- - containerPort: 80
+ - name: pause
+ image: registry.k8s.io/pause:latest
+ resources:
+ requests:
+ cpu: 10m
+ memory: 10Mi
+ limits:
+ cpu: 10m
+ memory: 10Mi
+ terminationGracePeriodSeconds: 0
diff --git a/test/conformance/chainsaw/globalcontext/validate-crd/valid-context.yaml b/test/conformance/chainsaw/globalcontext/validate-crd/valid-context.yaml
index 140c37f0bb4b..5745a3f62654 100644
--- a/test/conformance/chainsaw/globalcontext/validate-crd/valid-context.yaml
+++ b/test/conformance/chainsaw/globalcontext/validate-crd/valid-context.yaml
@@ -11,4 +11,4 @@ spec:
-----BEGIN CERTIFICATE-----
-----REDACTED-----
-----END CERTIFICATE-----
- refreshInterval: 10ns
+ refreshInterval: 1h