-
Notifications
You must be signed in to change notification settings - Fork 312
[release-4.20] OCPBUGS-113989: frr-k8s: use Recreate strategy for webhook server deployment on SNO #3141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[release-4.20] OCPBUGS-113989: frr-k8s: use Recreate strategy for webhook server deployment on SNO #3141
Changes from all commits
e050163
d9b2fa7
79005b9
0a9ed9a
e564d5d
8b97f6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| package apply | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "testing" | ||
|
|
||
| "github.com/openshift/cluster-network-operator/pkg/client/fake" | ||
| "github.com/openshift/cluster-network-operator/pkg/names" | ||
|
|
||
| . "github.com/onsi/gomega" | ||
|
|
||
| apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
| "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
| "k8s.io/apimachinery/pkg/runtime" | ||
| "k8s.io/apimachinery/pkg/runtime/schema" | ||
| "k8s.io/apimachinery/pkg/types" | ||
| fakedynamic "k8s.io/client-go/dynamic/fake" | ||
| clienttesting "k8s.io/client-go/testing" | ||
| ) | ||
|
|
||
| const prePatchValue = `{"spec":{"strategy":{"type":"Recreate","rollingUpdate":null}}}` | ||
|
|
||
| func newTestDeployment(annotations map[string]string) *unstructured.Unstructured { | ||
| obj := &unstructured.Unstructured{} | ||
| obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}) | ||
| obj.SetName("test-deployment") | ||
| obj.SetNamespace("test-ns") | ||
| obj.SetAnnotations(annotations) | ||
| return obj | ||
| } | ||
|
|
||
| func patchRecorder(patchTypes *[]types.PatchType, prePatchBody *string, prePatchErr error) func(action clienttesting.Action) (bool, runtime.Object, error) { | ||
| return func(action clienttesting.Action) (bool, runtime.Object, error) { | ||
| patchAction := action.(clienttesting.PatchAction) | ||
| *patchTypes = append(*patchTypes, patchAction.GetPatchType()) | ||
| if patchAction.GetPatchType() == types.StrategicMergePatchType { | ||
| *prePatchBody = string(patchAction.GetPatch()) | ||
| if prePatchErr != nil { | ||
| return true, nil, prePatchErr | ||
| } | ||
| } | ||
| return true, newTestDeployment(nil), nil | ||
| } | ||
| } | ||
|
|
||
| func TestApplyObjectPrePatchRunsBeforeSSA(t *testing.T) { | ||
| g := NewWithT(t) | ||
|
|
||
| client := fake.NewFakeClient() | ||
|
|
||
| var patchTypes []types.PatchType | ||
| var prePatchBody string | ||
| pr := patchRecorder(&patchTypes, &prePatchBody, nil) | ||
| client.Default().Dynamic().(*fakedynamic.FakeDynamicClient).PrependReactor("patch", "deployments", pr) | ||
|
|
||
| obj := newTestDeployment(map[string]string{ | ||
| names.PrePatchAnnotation: prePatchValue, | ||
| }) | ||
|
|
||
| err := ApplyObject(t.Context(), client, obj, "test-controller") | ||
| g.Expect(err).To(Succeed()) | ||
| g.Expect(patchTypes).To(HaveLen(2)) | ||
| g.Expect(patchTypes[0]).To(Equal(types.StrategicMergePatchType), "pre-patch should be strategic-merge-patch") | ||
| g.Expect(patchTypes[1]).To(Equal(types.ApplyPatchType), "second patch should be SSA apply") | ||
| g.Expect(prePatchBody).To(Equal(prePatchValue), "pre-patch body should match annotation value") | ||
| } | ||
|
|
||
| func TestApplyObjectPrePatchNotFoundAllowsSSA(t *testing.T) { | ||
| g := NewWithT(t) | ||
|
|
||
| client := fake.NewFakeClient() | ||
|
|
||
| var patchTypes []types.PatchType | ||
| var prePatchBody string | ||
| pr := patchRecorder(&patchTypes, &prePatchBody, apierrors.NewNotFound( | ||
| schema.GroupResource{Group: "apps", Resource: "deployments"}, "test-deployment")) | ||
| client.Default().Dynamic().(*fakedynamic.FakeDynamicClient).PrependReactor("patch", "deployments", pr) | ||
|
|
||
| obj := newTestDeployment(map[string]string{ | ||
| names.PrePatchAnnotation: prePatchValue, | ||
| }) | ||
|
|
||
| err := ApplyObject(t.Context(), client, obj, "test-controller") | ||
| g.Expect(err).To(Succeed()) | ||
| g.Expect(patchTypes).To(HaveLen(2)) | ||
| g.Expect(patchTypes[0]).To(Equal(types.StrategicMergePatchType), "pre-patch was attempted") | ||
| g.Expect(patchTypes[1]).To(Equal(types.ApplyPatchType), "SSA apply still proceeded") | ||
| g.Expect(prePatchBody).To(Equal(prePatchValue), "pre-patch body should match annotation value") | ||
| } | ||
|
|
||
| func TestApplyObjectPrePatchErrorStopsReconciliation(t *testing.T) { | ||
| g := NewWithT(t) | ||
|
|
||
| client := fake.NewFakeClient() | ||
|
|
||
| var patchTypes []types.PatchType | ||
| var prePatchBody string | ||
| pr := patchRecorder(&patchTypes, &prePatchBody, fmt.Errorf("API server error")) | ||
| client.Default().Dynamic().(*fakedynamic.FakeDynamicClient).PrependReactor("patch", "deployments", pr) | ||
|
|
||
| obj := newTestDeployment(map[string]string{ | ||
| names.PrePatchAnnotation: prePatchValue, | ||
| }) | ||
|
|
||
| err := ApplyObject(t.Context(), client, obj, "test-controller") | ||
| g.Expect(err).To(HaveOccurred()) | ||
| g.Expect(err.Error()).To(ContainSubstring("failed to pre-patch")) | ||
| g.Expect(patchTypes).To(HaveLen(1), "SSA apply should not have been reached") | ||
| g.Expect(patchTypes[0]).To(Equal(types.StrategicMergePatchType), "pre-patch should be strategic-merge-patch") | ||
| g.Expect(prePatchBody).To(Equal(prePatchValue), "pre-patch body should match annotation value") | ||
| } | ||
|
|
||
| func TestApplyObjectNoPrePatchAnnotationSkipsPrePatch(t *testing.T) { | ||
| g := NewWithT(t) | ||
|
|
||
| client := fake.NewFakeClient() | ||
|
|
||
| var patchTypes []types.PatchType | ||
| var prePatchBody string | ||
| pr := patchRecorder(&patchTypes, &prePatchBody, nil) | ||
| client.Default().Dynamic().(*fakedynamic.FakeDynamicClient).PrependReactor("patch", "deployments", pr) | ||
|
|
||
| obj := newTestDeployment(nil) | ||
|
|
||
| err := ApplyObject(t.Context(), client, obj, "test-controller") | ||
| g.Expect(err).To(Succeed()) | ||
| g.Expect(patchTypes).To(HaveLen(1)) | ||
| g.Expect(patchTypes[0]).To(Equal(types.ApplyPatchType), "only SSA apply should have run") | ||
| g.Expect(prePatchBody).To(BeEmpty(), "no pre-patch should have been sent") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,13 +9,15 @@ import ( | |
| "github.com/openshift/cluster-network-operator/pkg/client/fake" | ||
| "github.com/openshift/cluster-network-operator/pkg/hypershift" | ||
| "github.com/stretchr/testify/assert" | ||
| appsv1 "k8s.io/api/apps/v1" | ||
| "k8s.io/client-go/kubernetes/scheme" | ||
|
|
||
| "testing" | ||
|
|
||
| configv1 "github.com/openshift/api/config/v1" | ||
| operv1 "github.com/openshift/api/operator/v1" | ||
| "github.com/openshift/cluster-network-operator/pkg/bootstrap" | ||
| "github.com/openshift/cluster-network-operator/pkg/names" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| ) | ||
|
|
||
|
|
@@ -644,11 +646,50 @@ func Test_renderAdditionalRoutingCapabilities(t *testing.T) { | |
| } | ||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| got, err := renderAdditionalRoutingCapabilities(tt.args.operConf, manifestDir) | ||
| got, err := renderAdditionalRoutingCapabilities(tt.args.operConf, fakeBootstrapResult(), manifestDir) | ||
| if !reflect.DeepEqual(tt.expectedErr, err) { | ||
| t.Errorf("renderAdditionalRoutingCapabilities() err = %v, want %v", err, tt.expectedErr) | ||
| } | ||
| assert.Equalf(t, tt.want, len(got), "renderAdditionalRoutingCapabilities(%v, %v)", tt.args.operConf, manifestDir) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func Test_renderFRRWebhookServerStrategy(t *testing.T) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to squash this commit into commit |
||
| // On 4.20 the hostNetwork workload is frr-k8s-webhook-server; statuscleaner was split out in 4.21. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that comment here isn't necessary |
||
| frrConf := &operv1.NetworkSpec{ | ||
| AdditionalRoutingCapabilities: &operv1.AdditionalRoutingCapabilities{ | ||
| Providers: []operv1.RoutingCapabilitiesProvider{ | ||
| operv1.RoutingCapabilitiesProviderFRR, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| render := func(replicaCount int) *appsv1.Deployment { | ||
| g := NewWithT(t) | ||
| br := fakeBootstrapResult() | ||
| br.OVN.ControlPlaneReplicaCount = replicaCount | ||
| objs, err := renderAdditionalRoutingCapabilities(frrConf, br, manifestDir) | ||
| g.Expect(err).NotTo(HaveOccurred()) | ||
| return mustFindRenderedObj[*appsv1.Deployment](t, objs, "Deployment", "frr-k8s-webhook-server") | ||
| } | ||
|
|
||
| t.Run("SNO: strategy is Recreate", func(t *testing.T) { | ||
| g := NewWithT(t) | ||
| d := render(1) | ||
| g.Expect(d.Spec.Strategy.Type).To(Equal(appsv1.RecreateDeploymentStrategyType)) | ||
| g.Expect(d.Annotations).To( | ||
| HaveKeyWithValue( | ||
| names.PrePatchAnnotation, | ||
| `{"spec":{"strategy":{"type":"Recreate","rollingUpdate":null}}}`, | ||
| ), | ||
| ) | ||
| }) | ||
|
|
||
| t.Run("HA: strategy is RollingUpdate", func(t *testing.T) { | ||
| g := NewWithT(t) | ||
| d := render(3) | ||
| g.Expect(d.Spec.Strategy.Type).To(Equal(appsv1.RollingUpdateDeploymentStrategyType)) | ||
| g.Expect(d.Annotations).NotTo(HaveKey(names.PrePatchAnnotation)) | ||
| }) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this commit here makes no sense - the unit test is exactly the same in 4.21 where it passes without problems, meaning if there are problems, they lie elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found a better solution (IMO). I'll push it in a bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #3142