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