Skip to content

Conversation

@sbahar619
Copy link
Contributor

@sbahar619 sbahar619 commented Mar 27, 2025

Short description:

Add update method to handle consecutive updates safely

More details:

Add update method to handle consecutive updates safely

Added an update method in NodeNetworkConfigurationPolicy to wait for
NNCP status updates before applying changes. This prevents API failures
caused by the admission webhook rejecting updates while NNCP is still
in progress.
What this PR does / why we need it:

Example of failure:

failed on teardown with "kubernetes.dynamic.exceptions.ForbiddenError: 403
Reason: Forbidden
HTTP response headers: HTTPHeaderDict({'Audit-Id': 'f10ebbbc-01e8-456d-a1c5-e55298504ece', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': '559d612b-12c3-4f4d-9114-023ee53b8190', 'X-Kubernetes-Pf-Prioritylevel-Uid': '205f5378-334e-481f-94f3-6ad523816633', 'Date': 'Mon, 24 Mar 2025 09:41:26 GMT', 'Content-Length': '475'})
HTTP response body: b'{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"admission webhook \\"nodenetworkconfigurationpolicies-update-validate.nmstate.io\\" denied the request: failed to admit NodeNetworkConfigurationPolicy dhcp-vlan-client-2-nncp: message: policy dhcp-vlan-client-2-nncp is still in progress. ","reason":"failed to admit NodeNetworkConfigurationPolicy dhcp-vlan-client-2-nncp: message: policy dhcp-vlan-client-2-nncp is still in progress. ","code":403}\n'
Which issue(s) this PR fixes:
Special notes for reviewer:
Bug:

Summary by CodeRabbit

  • New Features
    • Enhanced the network configuration update process with integrated status monitoring to ensure reliable and accurate policy updates.

Added an update method in NodeNetworkConfigurationPolicy to wait for
NNCP status updates before applying changes. This prevents API failures
caused by the admission webhook rejecting updates while NNCP is still
in progress.

Signed-off-by: Shahaf Bahar <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Mar 27, 2025

Walkthrough

The pull request introduces a new method update in the NodeNetworkConfigurationPolicy class. This method accepts a resource_dict parameter and retrieves the last successful transition time before invoking the superclass's update method. If the resource_dict contains a "spec" key and a valid initial_success_status_time, it calls _wait_for_nncp_status_update. The changes also remove previous logic from the _absent_interface method, altering control flow and error handling related to status updates.

Changes

File Change Summary
ocp_resources/node_network_configuration_policy.py Added a new update method in the NodeNetworkConfigurationPolicy class to manage status checks after updating the resource. Removed old logic from _absent_interface related to status updates.

Possibly related PRs

Suggested labels

size/S, verified, can-be-merged, approved-myakove

Suggested reviewers

  • rnetser
  • dbasunag
  • EdDev
  • myakove

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d657ac and 9a9f2a3.

📒 Files selected for processing (1)
  • ocp_resources/node_network_configuration_policy.py (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: python-module-install
  • GitHub Check: tox
  • GitHub Check: conventional-title
🔇 Additional comments (2)
ocp_resources/node_network_configuration_policy.py (2)

15-15: New import for type annotation.

The addition of Any from typing aligns with best practices, enabling precise type hints for the resource dictionary in the new update method.


357-362: Ensures concurrency for consecutive updates.

The implementation correctly waits for the NNCP’s status to reflect a successful transition before applying further updates, mitigating admission webhook rejections. You may also consider aligning the approach used in _absent_interface() with this new method for consistency, though it can be addressed in a future PR if desired.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@redhat-qe-bot
Copy link
Contributor

Report bugs in Issues

The following are automatically added:

  • Add reviewers from OWNER file (in the root of the repository) under reviewers section.
  • Set PR size label.
  • New issue is created for the PR. (Closed when PR is merged/closed)
  • Run pre-commit if .pre-commit-config.yaml exists in the repo.

Available user actions:

  • To mark PR as WIP comment /wip to the PR, To remove it from the PR comment /wip cancel to the PR.
  • To block merging of PR comment /hold, To un-block merging of PR comment /hold cancel.
  • To mark PR as verified comment /verified to the PR, to un-verify comment /verified cancel to the PR.
    verified label removed on each new commit push.
  • To cherry pick a merged PR comment /cherry-pick <target branch to cherry-pick to> in the PR.
    • Multiple target branches can be cherry-picked, separated by spaces. (/cherry-pick branch1 branch2)
    • Cherry-pick will be started when PR is merged
  • To build and push container image command /build-and-push-container in the PR (tag will be the PR number).
    • You can add extra args to the Podman build command
      • Example: /build-and-push-container --build-arg OPENSHIFT_PYTHON_WRAPPER_COMMIT=<commit_hash>
  • To add a label by comment use /<label name>, to remove, use /<label name> cancel
  • To assign reviewers based on OWNERS file use /assign-reviewers
  • To check if PR can be merged use /check-can-merge
  • to assign reviewer to PR use /assign-reviewer @<reviewer>
Supported /retest check runs
  • /retest tox: Retest tox
  • /retest python-module-install: Retest python-module-install
  • /retest conventional-title: Retest conventional-title
  • /retest all: Retest all
Supported labels
  • hold
  • verified
  • wip
  • lgtm

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
ocp_resources/node_network_configuration_policy.py (2)

364-369: Check for KeyError exceptions.

The current implementation may raise a KeyError if resource_dict doesn't contain a "spec" key. While this might be an expected contract from callers, it's safer to handle this case explicitly.

-        if resource_dict["spec"] and initial_success_status_time:
+        if "spec" in resource_dict and resource_dict["spec"] and initial_success_status_time:

364-369: Consider adding documentation.

This method implements an important safeguard for consecutive updates. Adding a docstring would help developers understand its purpose and behavior.

     def update(self, resource_dict: dict[str, Any]) -> None:
+        """
+        Updates the resource with the provided resource dictionary and waits for status updates.
+        
+        This method waits for the status of the NodeNetworkConfigurationPolicy to update before
+        applying changes to prevent API failures when the admission webhook rejects updates 
+        while the NNCP is still processing.
+        
+        Args:
+            resource_dict: Dictionary containing the resource configuration to update
+        """
         initial_success_status_time = self._get_last_successful_transition_time()
         super().update(resource_dict=resource_dict)
         if resource_dict["spec"] and initial_success_status_time:
             self._wait_for_nncp_status_update(initial_transition_time=initial_success_status_time)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d62ce3c and 51323c9.

📒 Files selected for processing (1)
  • ocp_resources/node_network_configuration_policy.py (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: tox
  • GitHub Check: python-module-install
  • GitHub Check: conventional-title
🔇 Additional comments (3)
ocp_resources/node_network_configuration_policy.py (3)

15-15: Good addition of type hints.

Adding the Any type import will help with type annotations in the new method.


364-369: Align with the existing pattern in _absent_interface.

The method introduces a pattern similar to what already exists in the _absent_interface method (lines 329-336). This confirms that the approach is consistent with the codebase's existing practices, which is good.


364-369:

❓ Verification inconclusive

Consider potential timeouts.

The _wait_for_nncp_status_update method has a timeout of 1 minute (TIMEOUT_1MINUTE). Consider whether this is sufficient for all environments and use cases. In certain scenarios with high system load, this timeout might be too short.

Let's check if there are any contextual clues about appropriate timeout values in the codebase:


🏁 Script executed:

#!/bin/bash
# Check for TIMEOUT constants used with NNCP operations
rg "TIMEOUT_" --type py "ocp_resources/node_network_configuration"

Length of output: 145


Timeout Value Consideration – Please Verify

The current implementation uses a 1-minute timeout in the _wait_for_nncp_status_update method. When searching for TIMEOUT-related constants, the initial script didn’t return results—likely because it targeted a non-existent directory rather than the actual file. Please manually verify that the 1-minute duration (TIMEOUT_1MINUTE) is defined and appropriate. In environments with high load or complex processing, this value might need to be adjusted.

  • Location: ocp_resources/node_network_configuration_policy.py (lines 364–369)
  • Next Steps:
    • Confirm the definition and usage of TIMEOUT_1MINUTE in the file.
    • Assess whether a longer timeout might be more robust across diverse environments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ocp_resources/node_network_configuration_policy.py (1)

364-369: Great implementation of safe consecutive updates.

This new update method addresses the issue mentioned in the PR objectives where the admission webhook might reject updates while the NNCP is still processing. By waiting for status updates before applying changes, it prevents API failures during consecutive updates.

I appreciate the robust check using resource_dict.get("spec") which handles cases where the key might not exist.

Consider adding logging statements for improved visibility:

    def update(self, resource_dict: dict[str, Any]) -> None:
        initial_success_status_time = self._get_last_successful_transition_time()
+       self.logger.debug(f"Updating {self.name} with resource_dict: {resource_dict}")
        super().update(resource_dict=resource_dict)
        if resource_dict.get("spec") and initial_success_status_time:
+           self.logger.debug(f"Waiting for status update after initial time: {initial_success_status_time}")
            self._wait_for_nncp_status_update(initial_transition_time=initial_success_status_time)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51323c9 and 8d657ac.

📒 Files selected for processing (1)
  • ocp_resources/node_network_configuration_policy.py (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: tox
  • GitHub Check: python-module-install
  • GitHub Check: conventional-title
🔇 Additional comments (1)
ocp_resources/node_network_configuration_policy.py (1)

15-15: Appropriate type import for the new method.

Good addition of the Any type from typing module to properly type-hint the dictionary parameter in the new update method.

return True
return False

def update(self, resource_dict: dict[str, Any]) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, the call to update() from _absent_interface() goes through here.
If I am indeed correct, then I think that your PR, which presents a more robust solution because it covers all the cases of calling nncp.update() (and not only the specific case of removing an interface on teardown) should include removal of the time-stamp verification in _absent_interface.
WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The update call in the _absent_interfaces method currently uses the update method of the ResourceEditor object instead of the NNCP object. I can replace it with the new update method of NNCP and remove the related logic accordingly.
Maybe in a follow up PR?

Copy link
Contributor

@yossisegev yossisegev Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I initially thought as well, but then I followed the flow and found that although ResourceEditor does not inherit from Resource, the update() flow does go through update() of Resource class.
IIRC, if you visually trace the code, eventually you can trace the code that leads to that (it's quite cumbersome).
Anyway, to make sure I ran a little check now:
I added this print to Resource.update():

self.logger.info("\n\n******************* going via Resource.update() *******************\n\n")

Then I ran a test that involves NNCP creation and teardown, and indeed found this print in the teardown flow:

-------------------------------------------------------------------------------------------------------------------------- TEARDOWN --------------------------------------------------------------------------------------------------------------------------
2025-03-27T15:49:55.436437 timeout_sampler INFO Elapsed time: 0.00023365020751953125 [0:00:00.000234]
2025-03-27T15:49:55.436839 timeout_sampler INFO Waiting for 60 seconds [0:01:00], retry every 1 seconds. (Function: tests.network.utils.<locals>.lambda: nncp.status)
2025-03-27T15:49:55.646993 timeout_sampler INFO Elapsed time: 0.0002613067626953125 [0:00:00.000261]
2025-03-27T15:49:55.647681 ocp_resources.resource INFO Trying to get client via new_client_from_config
2025-03-27T15:49:55.671476 ocp_resources.resource INFO kind: NodeNetworkState api version: nmstate.io/v1beta1
2025-03-27T15:49:56.875371 ocp_resources.resource INFO ResourceEdits: Updating data for resource NodeNetworkConfigurationPolicy restart-nmstate-net-ys-419-lrlqb-worker-0-qlz29
2025-03-27T15:49:56.875511 ocp_resources NodeNetworkConfigurationPolicy INFO 

******************* going via Resource.update() *******************


2025-03-27T15:49:56.875573 ocp_resources NodeNetworkConfigurationPolicy INFO Update NodeNetworkConfigurationPolicy restart-nmstate-net-ys-419-lrlqb-worker-0-qlz29:
{'spec': {'desiredState': {'interfaces': [{'name': 'br-nmstate', 'type': 'linux-bridge', 'state': 'absent', 'bridge': {'options': {'stp': {'enabled': False}}, 'port': [{'name': 'enp5s0'}]}, 'ipv4': {'enabled': False, 'dhcp': False, 'auto-dns': True}, 'ipv6': {'enabled': False, 'dhcp': False, 'auto-dns': True, 'autoconf': False}}, {'name': 'enp5s0', 'type': 'ethernet', 'state': 'up', 'ipv4': {'dhcp': False, 'enabled': False}, 'ipv6': {'autoconf': False, 'dhcp': False, 'enabled': False}}]}}, 'metadata': {'name': 'restart-nmstate-net-ys-419-lrlqb-worker-0-qlz29'}}
2025-03-27T15:49:57.080747 timeout_sampler INFO Waiting for 60 seconds [0:01:00], retry every 5 seconds. (Function: ocp_resources.node_network_configuration_policy._wait_for_nncp_status_update Args: (<utilities.network.LinuxBridgeNodeNetworkConfigurationPolicy object at 0x7f1ce7233fb0>,) Kwargs: {'initial_transition_time': '2025-03-27T13:49:52Z'})
2025-03-27T15:50:02.507453 timeout_sampler INFO Elapsed time: 5.198873996734619 [0:00:05.198874]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @sbahar619 .
Please resolve this comment (the author can do that, the reviewer cannot).

@redhat-qe-bot1 redhat-qe-bot1 requested a review from myakove April 1, 2025 04:42
@sbahar619
Copy link
Contributor Author

This solution was not accepted by the maintainers.

@sbahar619 sbahar619 closed this Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants