Skip to content

[release-4.20] OCPBUGS-113989: frr-k8s: use Recreate strategy for webhook server deployment on SNO - #3142

Merged
openshift-merge-bot[bot] merged 4 commits into
openshift:release-4.20from
andreaskaris:fix/OCPBUGS-113989
Aug 27, 2026
Merged

[release-4.20] OCPBUGS-113989: frr-k8s: use Recreate strategy for webhook server deployment on SNO#3142
openshift-merge-bot[bot] merged 4 commits into
openshift:release-4.20from
andreaskaris:fix/OCPBUGS-113989

Conversation

@andreaskaris

@andreaskaris andreaskaris commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Manual backport of github.com//pull/3135 to release 4.20.


A few issues during the backport process.

a) The template changes in newer versions are applied to node-status-cleaner.yaml, here they must be made to webhook.yaml

b) In 4.21 and beyond, the GVK is registered automatically, and thus test TestStatusManager_set passes even though it does not explicitly register the test/test/test GVK. In 4.20, this automatic registration does not happen, so we must explicitly register that GVK in the FakeClusterClient's scheme to make that test pass.

From Claude:

  The GVK test/test/test is registered dynamically by controller-runtime's fake client itself.
 
  When the test calls set(t, client, obj) at line 259 (which does Create on the CRClient), the
  controller-runtime fake client's Create method calls addToSchemeIfUnknownAndUnstructuredOrPartial (line
  1869). Since obj is an *unstructured.Unstructured, it hits line 1886-1887:

  if !c.scheme.Recognizes(gvk) {
      c.scheme.AddKnownTypeWithName(gvk, obj)
  }   

  This mutates the scheme to add test/test/test at the time of the first Create call. After that, the GVK
  is known to the scheme.

  However, the RESTMapper() on the FakeClusterClient (line 136-138 of fake_client.go) calls
  testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme) — which creates a new mapper from the scheme on
  every call. Since the scheme was already mutated by the Create above, the mapper built at line 219 of
  status_manager.go will include the test group and its test kind, so KindFor succeeds.
  
  In short: the controller-runtime fake client auto-registers unknown unstructured GVKs into the scheme as
  a side effect of Create, and because RESTMapper() rebuilds from that same (now-mutated) scheme each
  time, KindFor works despite no explicit registration.

And here are the changes to the vendor directory where addToSchemeIfUnknownAndUnstructuredOrPartial is added (4.21 and beyond):

[akaris@workstation 4.21 (release-4.21)]$ git blame /media/psf/Home/development/cluster-network-operator/release/4.21/vendor/sigs.k8s.io/controller-ru
ntime/pkg/client/fake/client.go | grep 'addToSchemeIfUnknownAndUnstructuredOrPartial(' -B2
8c2b9f99df (Anil Vishnoi          2020-05-05 12:28:01 -0700  612) 
34e6b52190 (Jamo Luhrsen          2022-09-26 11:05:59 -0700  613) func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Objec
t, opts ...client.GetOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  614)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  659) 
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  660) func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...clie
nt.ListOption) (watch.Interface, error) {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  661)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(list); err != nil {
--
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  681) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  682) func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client
.ListOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  683)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400  850) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  851) func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.C
reateOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  852)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  909) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  910) func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.D
eleteOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  911)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  961) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  962) func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...cli
ent.DeleteAllOfOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  963)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1017) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1018) func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.UpdateO
ption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1019)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1128) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1129) func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client.Pat
chOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1130)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
c2467eea0c (Arti Sood             2025-03-25 13:01:44 -0400 1867) }
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1868) 
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1869) func (c *fakeClient) addToSchemeIfUnknownAndUnstructuredOrPartial(obj runtime.Object
) error {

In 4.20, that's missing:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep addToSchemeIfUnknownAndUnstructuredOrPartial /media/psf/Home/develo
pment/cluster-network-operator/release/4.20/vendor/sigs.k8s.io/controller-runtime/ -R
[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ 

Meaning that's due to the change in controller-runtime:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep controller-runtime go.mod 
        sigs.k8s.io/controller-runtime v0.21.0
[akaris@workstation 4.21 (release-4.21)]$ grep controller-runtime go.mod 
        sigs.k8s.io/controller-runtime v0.22.4

This commit adds helper functions to testutil_test.go that are used
by component rendering tests to verify rendered Kubernetes objects:

- mustFindRenderedObj: Finds and converts unstructured objects using generics
- mustFindContainer: Finds a container by name in a container list
- findExecCommand: Extracts exec command strings from container command args

These utilities facilitate testing of rendered manifests and container
configurations across multiple components.

Signed-off-by: Tom Pantelis <tompantelis@gmail.com>
Co-Authored-By: Ori Braunshtein <obraunsh@redhat.com>
(cherry picked from commit c617131)

Cherry-pick not clean:
- dropped definiton of mustFindContainer and findExecCommand (otherwise
  lint fails)

(cherry picked from commit cedf0d7)
(cherry picked from commit 3730249)
Signed-off-by: Andreas Karis <ak.karis@gmail.com>
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. labels Aug 26, 2026
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0a895894-78d0-474b-b764-00494aaf3f39

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@openshift-ci-robot openshift-ci-robot added the jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. label Aug 26, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@andreaskaris: This pull request references Jira Issue OCPBUGS-113989, which is valid. The bug has been moved to the POST state.

7 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.20.z) matches configured target version for branch (4.20.z)
  • bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)
  • release note type set to "Release Note Not Required"
  • dependent bug Jira Issue OCPBUGS-112789 is in the state Verified, which is one of the valid states (VERIFIED, RELEASE PENDING, CLOSED (ERRATA), CLOSED (CURRENT RELEASE), CLOSED (DONE), CLOSED (DONE-ERRATA))
  • dependent Jira Issue OCPBUGS-112789 targets the "4.21.z" version, which is one of the valid target versions: 4.21.0, 4.21.z
  • bug has dependents

No GitHub users were found matching the public email listed for the QA contact in Jira (jechen@redhat.com), skipping review request.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Manual backport of github.com//pull/3135 to release 4.20.


A few issues during the backport process.

a) The template changes in newer versions are applied to node-status-cleaner.yaml, here they must be made to webhook.yaml

b) In 4.21 and beyond, the GVK is registered automatically.

Claude:

 The GVK test/test/test is registered dynamically by controller-runtime's fake client itself.

 When the test calls set(t, client, obj) at line 259 (which does Create on the CRClient), the
 controller-runtime fake client's Create method calls addToSchemeIfUnknownAndUnstructuredOrPartial (line
 1869). Since obj is an *unstructured.Unstructured, it hits line 1886-1887:

 if !c.scheme.Recognizes(gvk) {
     c.scheme.AddKnownTypeWithName(gvk, obj)
 }   

 This mutates the scheme to add test/test/test at the time of the first Create call. After that, the GVK
 is known to the scheme.

 However, the RESTMapper() on the FakeClusterClient (line 136-138 of fake_client.go) calls
 testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme) — which creates a new mapper from the scheme on
 every call. Since the scheme was already mutated by the Create above, the mapper built at line 219 of
 status_manager.go will include the test group and its test kind, so KindFor succeeds.
 
 In short: the controller-runtime fake client auto-registers unknown unstructured GVKs into the scheme as
 a side effect of Create, and because RESTMapper() rebuilds from that same (now-mutated) scheme each
 time, KindFor works despite no explicit registration.
[akaris@workstation 4.21 (release-4.21)]$ git blame /media/psf/Home/development/cluster-network-operator/release/4.21/vendor/sigs.k8s.io/controller-ru
ntime/pkg/client/fake/client.go | grep 'addToSchemeIfUnknownAndUnstructuredOrPartial(' -B2
8c2b9f99df (Anil Vishnoi          2020-05-05 12:28:01 -0700  612) 
34e6b52190 (Jamo Luhrsen          2022-09-26 11:05:59 -0700  613) func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Objec
t, opts ...client.GetOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  614)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  659) 
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  660) func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...clie
nt.ListOption) (watch.Interface, error) {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  661)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(list); err != nil {
--
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  681) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  682) func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client
.ListOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  683)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400  850) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  851) func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.C
reateOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  852)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  909) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  910) func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.D
eleteOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  911)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  961) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  962) func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...cli
ent.DeleteAllOfOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  963)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1017) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1018) func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.UpdateO
ption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1019)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1128) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1129) func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client.Pat
chOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1130)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
c2467eea0c (Arti Sood             2025-03-25 13:01:44 -0400 1867) }
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1868) 
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1869) func (c *fakeClient) addToSchemeIfUnknownAndUnstructuredOrPartial(obj runtime.Object
) error {

In 4.20, that's missing:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep addToSchemeIfUnknownAndUnstructuredOrPartial /media/psf/Home/develo
pment/cluster-network-operator/release/4.20/vendor/sigs.k8s.io/controller-runtime/ -R
[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ 

Meaning that's due to the change in controller-runtim:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep controller-runtime go.mod 
       sigs.k8s.io/controller-runtime v0.21.0
[akaris@workstation 4.21 (release-4.21)]$ grep controller-runtime go.mod 
       sigs.k8s.io/controller-runtime v0.22.4

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
openshift-ci Bot requested review from arghosh93 and oribon August 26, 2026 11:52
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@andreaskaris: This pull request references Jira Issue OCPBUGS-113989, which is valid.

7 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.20.z) matches configured target version for branch (4.20.z)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)
  • release note type set to "Release Note Not Required"
  • dependent bug Jira Issue OCPBUGS-112789 is in the state Verified, which is one of the valid states (VERIFIED, RELEASE PENDING, CLOSED (ERRATA), CLOSED (CURRENT RELEASE), CLOSED (DONE), CLOSED (DONE-ERRATA))
  • dependent Jira Issue OCPBUGS-112789 targets the "4.21.z" version, which is one of the valid target versions: 4.21.0, 4.21.z
  • bug has dependents

No GitHub users were found matching the public email listed for the QA contact in Jira (jechen@redhat.com), skipping review request.

Details

In response to this:

Manual backport of github.com//pull/3135 to release 4.20.


A few issues during the backport process.

a) The template changes in newer versions are applied to node-status-cleaner.yaml, here they must be made to webhook.yaml

b) In 4.21 and beyond, the GVK is registered automatically, and thus test TestStatusManager_set passes even though it does not explicitly register the test/test/test GVK. Explicitly register that GVK in the FakeClusterClient's scheme to make that test pass.

From Claude:

 The GVK test/test/test is registered dynamically by controller-runtime's fake client itself.

 When the test calls set(t, client, obj) at line 259 (which does Create on the CRClient), the
 controller-runtime fake client's Create method calls addToSchemeIfUnknownAndUnstructuredOrPartial (line
 1869). Since obj is an *unstructured.Unstructured, it hits line 1886-1887:

 if !c.scheme.Recognizes(gvk) {
     c.scheme.AddKnownTypeWithName(gvk, obj)
 }   

 This mutates the scheme to add test/test/test at the time of the first Create call. After that, the GVK
 is known to the scheme.

 However, the RESTMapper() on the FakeClusterClient (line 136-138 of fake_client.go) calls
 testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme) — which creates a new mapper from the scheme on
 every call. Since the scheme was already mutated by the Create above, the mapper built at line 219 of
 status_manager.go will include the test group and its test kind, so KindFor succeeds.
 
 In short: the controller-runtime fake client auto-registers unknown unstructured GVKs into the scheme as
 a side effect of Create, and because RESTMapper() rebuilds from that same (now-mutated) scheme each
 time, KindFor works despite no explicit registration.

And here are the changes to the vendor directory:

[akaris@workstation 4.21 (release-4.21)]$ git blame /media/psf/Home/development/cluster-network-operator/release/4.21/vendor/sigs.k8s.io/controller-ru
ntime/pkg/client/fake/client.go | grep 'addToSchemeIfUnknownAndUnstructuredOrPartial(' -B2
8c2b9f99df (Anil Vishnoi          2020-05-05 12:28:01 -0700  612) 
34e6b52190 (Jamo Luhrsen          2022-09-26 11:05:59 -0700  613) func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Objec
t, opts ...client.GetOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  614)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  659) 
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  660) func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...clie
nt.ListOption) (watch.Interface, error) {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  661)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(list); err != nil {
--
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  681) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  682) func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client
.ListOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  683)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400  850) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  851) func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.C
reateOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  852)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  909) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  910) func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.D
eleteOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  911)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  961) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  962) func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...cli
ent.DeleteAllOfOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  963)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1017) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1018) func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.UpdateO
ption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1019)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1128) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1129) func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client.Pat
chOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1130)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
c2467eea0c (Arti Sood             2025-03-25 13:01:44 -0400 1867) }
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1868) 
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1869) func (c *fakeClient) addToSchemeIfUnknownAndUnstructuredOrPartial(obj runtime.Object
) error {

In 4.20, that's missing:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep addToSchemeIfUnknownAndUnstructuredOrPartial /media/psf/Home/develo
pment/cluster-network-operator/release/4.20/vendor/sigs.k8s.io/controller-runtime/ -R
[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ 

Meaning that's due to the change in controller-runtim:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep controller-runtime go.mod 
       sigs.k8s.io/controller-runtime v0.21.0
[akaris@workstation 4.21 (release-4.21)]$ grep controller-runtime go.mod 
       sigs.k8s.io/controller-runtime v0.22.4

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

fedepaol and others added 2 commits August 26, 2026 14:04
The statuscleaner deployment uses hostNetwork with a fixed port (9123).
With the default RollingUpdate strategy, upgrades on SNO clusters get
stuck because the new pod cannot bind the host port already held by the
old pod. Switching to Recreate ensures the old pod is terminated before
the new one starts.

Signed-off-by: Federico Paolinelli <fpaoline@redhat.com>
Co-Authored-By: Ori Braunshtein <obraunsh@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3d86b75)

Cherry-pick not clean:
- added bootstrap result wiring to additionalRoutingCapibilities (that
  was already there for 5.0), aligned existing unit test with
  fakeBootstrapResult() as in 5.0

(cherry picked from commit a5752d9)

Conflicts:
	pkg/network/render.go preserving
Very small conflict due to the presence of isSupportedDualStackPlatform.
Resolution: keep isSupportedDualStackPlatform + add bootstrapResult to
renderAdditionalRoutingCapabilities.

(cherry picked from commit 9d495a4)

Conflicts:
On release-4.20 the hostNetwork deployment is frr-k8s-webhook-server, not
frr-k8s-statuscleaner (which was split out in 4.21). Update the strategy
unit test to target the correct deployment name and make the template
change in webhook.yaml.

Co-Authored-By: Jean Chen <jechen@redhat.com>
Signed-off-by: Andreas Karis <ak.karis@gmail.com>
On upgrade, the frr-k8s-statuscleaner Deployment has rollingUpdate
fields defaulted by the API server. SSA cannot remove fields it does
not own, so switching strategy.type to Recreate fails with:

    spec.strategy.rollingUpdate: Forbidden: may not be specified when
    strategy `type` is 'Recreate'

Add a generic pre-patch annotation:

    networkoperator.openshift.io/pre-patch

that applies a strategic-merge-patch to the live object before SSA. This
lets the template atomically set type=Recreate and remove rollingUpdate
in a single patch, before SSA takes over.

Also explicitly set strategy to RollingUpdate with rollingUpdate fields
on non-SNO clusters so that CNO owns these fields going forward,
preventing the issue from recurring in case we have to make the same
switch for non-SNO clusters in the future.

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 8ebb78e)
(cherry picked from commit d59aba6)
(cherry picked from commit 4342f64)

Conflicts:
File node-status-cleaner.yaml does not exist, instead make the changes
in webhook.yaml

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
@andreaskaris
andreaskaris force-pushed the fix/OCPBUGS-113989 branch 2 times, most recently from 6dbb1d7 to ee9b308 Compare August 26, 2026 12:13
Add tests for ApplyObject's pre-patch behavior: strategic-merge-patch
runs before SSA, NotFound is tolerated, other errors stop reconciliation,
and objects without the annotation skip pre-patch entirely.

Remove fakeRESTMapper and replace it with
testrestmapper.TetsOnlyStaticRESTMapper to return a proper mapper,
and return scheme.Scheme from Scheme(). Both changes needed by
ApplyObject under test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Andreas Karis <ak.karis@gmail.com>
(cherry picked from commit 6ca59b1)
(cherry picked from commit b1775c9)

Not clean cherry-pick:
Make the linter happy by applying the changes to pkg/apply from
openshift#3138. See
that PR for further details.

(cherry picked from commit 216d5c2)

Issues / manual changes:
controller-runtime v0.21.0 does not have
addToSchemeIfUnknownAndUnstructuredOrPartial, so GVK test/test/test
is not added automatically and TestStatusManager_set would fail.
Instead, add a new scheme to the FakeClusterClient and register the
GVK there for backwards compatibility.

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
@andreaskaris

Copy link
Copy Markdown
Contributor Author

/pipeline required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e-aws-ovn-hypershift-conformance
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-upgrade
/test e2e-aws-ovn-upgrade-ipsec
/test e2e-aws-ovn-windows
/test e2e-azure-ovn-upgrade
/test e2e-gcp-ovn
/test e2e-gcp-ovn-upgrade
/test e2e-metal-ipi-ovn-dualstack-bgp
/test e2e-metal-ipi-ovn-dualstack-bgp-local-gw
/test e2e-metal-ipi-ovn-ipv6
/test e2e-metal-ipi-ovn-ipv6-ipsec
/test e2e-ovn-ipsec-step-registry
/test hypershift-e2e-aks

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test frrk8s-e2e

@andreaskaris

Copy link
Copy Markdown
Contributor Author

/retest

@jechen0648

Copy link
Copy Markdown

/verified by pre-merge testing by @jechen0648

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Aug 26, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@jechen0648: This PR has been marked as verified by pre-merge testing by @jechen0648.

Details

In response to this:

/verified by pre-merge testing by @jechen0648

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@andreaskaris

Copy link
Copy Markdown
Contributor Author

/retest

@fedepaol

Copy link
Copy Markdown
Member

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Aug 26, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Tests from second stage were triggered manually. Pipeline can be controlled only manually, until HEAD changes. Use command to trigger second stage.

@jcaamano

Copy link
Copy Markdown
Contributor

/approve
/label backport-risk-assessed

@openshift-ci openshift-ci Bot added the backport-risk-assessed Indicates a PR to a release branch has been evaluated and considered safe to accept. label Aug 26, 2026
@openshift-ci

openshift-ci Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: andreaskaris, fedepaol, jcaamano

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 26, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD e39d57b and 2 for PR HEAD 5baae22 in total

@andreaskaris

Copy link
Copy Markdown
Contributor Author

/retest

2 similar comments
@andreaskaris

Copy link
Copy Markdown
Contributor Author

/retest

@andreaskaris

Copy link
Copy Markdown
Contributor Author

/retest

@openshift-ci

openshift-ci Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

@andreaskaris: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security 5baae22 link false /test security

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot
openshift-merge-bot Bot merged commit 907dc8b into openshift:release-4.20 Aug 27, 2026
24 of 25 checks passed
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@andreaskaris: Jira Issue Verification Checks: Jira Issue OCPBUGS-113989
✔️ This pull request was pre-merge verified.
✔️ All associated pull requests have merged.
✔️ All associated, merged pull requests were pre-merge verified.

Jira Issue OCPBUGS-113989 has been moved to the MODIFIED state and will move to the VERIFIED state when the change is available in an accepted nightly payload. 🕓

Details

In response to this:

Manual backport of github.com//pull/3135 to release 4.20.


A few issues during the backport process.

a) The template changes in newer versions are applied to node-status-cleaner.yaml, here they must be made to webhook.yaml

b) In 4.21 and beyond, the GVK is registered automatically, and thus test TestStatusManager_set passes even though it does not explicitly register the test/test/test GVK. In 4.20, this automatic registration does not happen, so we must explicitly register that GVK in the FakeClusterClient's scheme to make that test pass.

From Claude:

 The GVK test/test/test is registered dynamically by controller-runtime's fake client itself.

 When the test calls set(t, client, obj) at line 259 (which does Create on the CRClient), the
 controller-runtime fake client's Create method calls addToSchemeIfUnknownAndUnstructuredOrPartial (line
 1869). Since obj is an *unstructured.Unstructured, it hits line 1886-1887:

 if !c.scheme.Recognizes(gvk) {
     c.scheme.AddKnownTypeWithName(gvk, obj)
 }   

 This mutates the scheme to add test/test/test at the time of the first Create call. After that, the GVK
 is known to the scheme.

 However, the RESTMapper() on the FakeClusterClient (line 136-138 of fake_client.go) calls
 testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme) — which creates a new mapper from the scheme on
 every call. Since the scheme was already mutated by the Create above, the mapper built at line 219 of
 status_manager.go will include the test group and its test kind, so KindFor succeeds.
 
 In short: the controller-runtime fake client auto-registers unknown unstructured GVKs into the scheme as
 a side effect of Create, and because RESTMapper() rebuilds from that same (now-mutated) scheme each
 time, KindFor works despite no explicit registration.

And here are the changes to the vendor directory where addToSchemeIfUnknownAndUnstructuredOrPartial is added (4.21 and beyond):

[akaris@workstation 4.21 (release-4.21)]$ git blame /media/psf/Home/development/cluster-network-operator/release/4.21/vendor/sigs.k8s.io/controller-ru
ntime/pkg/client/fake/client.go | grep 'addToSchemeIfUnknownAndUnstructuredOrPartial(' -B2
8c2b9f99df (Anil Vishnoi          2020-05-05 12:28:01 -0700  612) 
34e6b52190 (Jamo Luhrsen          2022-09-26 11:05:59 -0700  613) func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Objec
t, opts ...client.GetOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  614)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  659) 
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  660) func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...clie
nt.ListOption) (watch.Interface, error) {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  661)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(list); err != nil {
--
6194226f73 (qJkee                 2021-12-20 18:50:53 -0500  681) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  682) func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client
.ListOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  683)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400  850) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  851) func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.C
reateOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  852)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  909) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  910) func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.D
eleteOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  911)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
ca9c0d2515 (Casey Callendrello    2018-11-02 14:12:27 +0100  961) 
1f33245b8a (Jacob Tanenbaum       2021-04-28 13:28:32 -0400  962) func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...cli
ent.DeleteAllOfOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800  963)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1017) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1018) func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.UpdateO
ption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1019)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1128) 
db57a477b1 (Tim Rozet             2023-06-01 18:44:35 -0400 1129) func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client.Pat
chOption) error {
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1130)       if err := c.addToSchemeIfUnknownAndUnstructuredOrPartial(obj); err != nil {
--
c2467eea0c (Arti Sood             2025-03-25 13:01:44 -0400 1867) }
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1868) 
b8cdede8e3 (Jamo Luhrsen          2025-11-07 12:16:55 -0800 1869) func (c *fakeClient) addToSchemeIfUnknownAndUnstructuredOrPartial(obj runtime.Object
) error {

In 4.20, that's missing:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep addToSchemeIfUnknownAndUnstructuredOrPartial /media/psf/Home/develo
pment/cluster-network-operator/release/4.20/vendor/sigs.k8s.io/controller-runtime/ -R
[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ 

Meaning that's due to the change in controller-runtime:

[akaris@workstation OCPBUGS-113989 (jechen0648/OCPBUGS-113989)]$ grep controller-runtime go.mod 
       sigs.k8s.io/controller-runtime v0.21.0
[akaris@workstation 4.21 (release-4.21)]$ grep controller-runtime go.mod 
       sigs.k8s.io/controller-runtime v0.22.4

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. backport-risk-assessed Indicates a PR to a release branch has been evaluated and considered safe to accept. jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants