Skip to content

feat(cni): add file watcher for CNI config file#1566

Open
AAdIprog wants to merge 1 commit intokmesh-net:mainfrom
AAdIprog:feat/cni-config-watcher
Open

feat(cni): add file watcher for CNI config file#1566
AAdIprog wants to merge 1 commit intokmesh-net:mainfrom
AAdIprog:feat/cni-config-watcher

Conversation

@AAdIprog
Copy link

What type of PR is this?

/kind feature

What this PR does / why we need it:

This PR adds a file watcher for the CNI config file to address the TODO comment in pkg/cni/chained.go.

Changes:

  • Add WatchCNIConfigFile() function to monitor the CNI config file for external modifications
  • Re-apply Kmesh CNI configuration when changes are detected
  • This ensures Kmesh CNI plugin remains installed even if other CNI plugins modify the config file
  • Remove the TODO comment that was addressed

The watcher uses the same pattern as the existing WatchServiceAccountToken() function, with a 100ms debounce timer to handle rapid file changes efficiently.

Which issue(s) this PR fixes:
Fixes #1565

Special notes for your reviewer:

  • The implementation follows the existing pattern used for watching the service account token
  • Uses fsnotify via the filewatcher package already in use by the project
  • Watches for Write and Create events on the CNI config file
  • Automatically re-applies Kmesh CNI configuration when external changes are detected

Does this PR introduce a user-facing change?:

Added file watcher for CNI config file to automatically re-apply Kmesh CNI configuration when external modifications are detected.

Add WatchCNIConfigFile() function to monitor the CNI config file for
external modifications and re-apply Kmesh CNI configuration when changes
are detected. This ensures Kmesh CNI plugin remains installed even if
other CNI plugins modify the config file.

- Remove TODO comment for cniConfigFile watcher in chained.go
- Add WatchCNIConfigFile() function in install.go
- Integrate watcher in Start() function

Signed-off-by: Aadi Shah <your-email@example.com>
Signed-off-by: AAdIprog <aadishah132@gmail.com>
Copilot AI review requested due to automatic review settings January 10, 2026 12:45
@kmesh-bot
Copy link
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign okabe-rintarou-0 for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found 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

@gemini-code-assist
Copy link

Summary of Changes

Hello @AAdIprog, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the robustness of the Kmesh CNI plugin by implementing a file watcher for its configuration file. This ensures that even if other CNI plugins modify the shared CNI configuration, the Kmesh plugin's settings are automatically restored, preventing unintended disruptions to its operation.

Highlights

  • CNI Configuration File Watcher: Introduced a new file watcher mechanism to monitor the CNI configuration file for external modifications.
  • Automatic Re-application of Kmesh CNI: When changes are detected in the CNI config file, the Kmesh CNI configuration is automatically re-applied to ensure its persistence.
  • Addressed TODO Comment: This change resolves a long-standing TODO comment in pkg/cni/chained.go regarding the need for a CNI config file watcher.
  • Pattern Consistency: The implementation of the file watcher follows the existing pattern used for watching the service account token, utilizing fsnotify with a 100ms debounce timer.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


Config file shifts, Watcher wakes, Kmesh restores, Order reigns again.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a file watcher for the CNI configuration file, which is a great addition for ensuring the Kmesh CNI plugin remains active even when other plugins modify the configuration. The implementation follows the existing pattern for watching the service account token.

My review focuses on a potential issue in the new watcher's goroutine. I've identified a scenario that could lead to high CPU usage when the watcher is stopped and have provided a code suggestion to address it. This fix would also be applicable to the existing service account token watcher.

Comment on lines +143 to +166
for {
select {
case <-timerC:
timerC = nil
log.Infof("CNI config file changed, re-applying Kmesh CNI configuration")
if err := i.chainedKmeshCniPlugin(i.Mode, i.CniMountNetEtcDIR); err != nil {
log.Errorf("failed to re-apply Kmesh CNI config: %v", err)
}

case event := <-i.Watcher.Events(cniConfigPath):
log.Debugf("got CNI config event %s", event.String())
if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
if timerC == nil {
timerC = time.After(100 * time.Millisecond)
}
}

case err := <-i.Watcher.Errors(cniConfigPath):
if err != nil {
log.Errorf("error from CNI config file watcher: %v", err)
return
}
}
}

Choose a reason for hiding this comment

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

high

The current implementation of the file watcher goroutine has a potential issue. When i.Watcher.Close() is called (in Stop()), the Events and Errors channels will be closed. Reading from a closed channel returns a zero value immediately without blocking. This will cause the select statement inside the for loop to spin, consuming a CPU core.

To fix this, you should check if the channels are closed when reading from them. You can do this using the two-variable assignment value, ok := <-channel. If ok is false, the channel is closed, and the goroutine should exit.

This issue also exists in WatchServiceAccountToken. While it's outside the scope of this PR's changes, it would be good to fix it there as well for consistency and correctness.

		for {
			select {
			case <-timerC:
				timerC = nil
				log.Infof("CNI config file changed, re-applying Kmesh CNI configuration")
				if err := i.chainedKmeshCniPlugin(i.Mode, i.CniMountNetEtcDIR); err != nil {
					log.Errorf("failed to re-apply Kmesh CNI config: %v", err)
				}

			case event, ok := <-i.Watcher.Events(cniConfigPath):
				if !ok {
					log.Info("CNI config file watcher stopped")
					return
				}
				log.Debugf("got CNI config event %s", event.String())
				if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
					if timerC == nil {
						timerC = time.After(100 * time.Millisecond)
					}
				}

			case err, ok := <-i.Watcher.Errors(cniConfigPath):
				if !ok {
					log.Info("CNI config file watcher stopped")
					return
				}
				if err != nil {
					log.Errorf("error from CNI config file watcher: %v", err)
					return
				}
			}
		}

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a file watcher for the CNI config file to automatically detect and respond to external modifications by re-applying the Kmesh CNI configuration. This addresses a TODO comment in the codebase and ensures the Kmesh CNI plugin remains properly configured even when other CNI plugins modify the shared config file.

Changes:

  • Added WatchCNIConfigFile() function that monitors the CNI config file and re-applies Kmesh configuration when changes are detected
  • Integrated the watcher into the Start() function to begin monitoring after initial setup
  • Removed the TODO comment that was addressed

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
pkg/cni/install.go Adds new WatchCNIConfigFile() function following the same pattern as WatchServiceAccountToken(), with file watching, debounce logic, and automatic re-application of config; integrates the watcher into the Start() function
pkg/cni/chained.go Removes the TODO comment about adding a watcher for the CNI config file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +154 to +158
if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
if timerC == nil {
timerC = time.After(100 * time.Millisecond)
}
}
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

The watcher does not handle Remove or Rename events for the CNI config file. If the file is deleted or renamed by another CNI plugin, the watcher will stop receiving events but the goroutine will continue running. Consider adding event handlers for fsnotify.Remove and fsnotify.Rename events to either re-add the watch or take appropriate action.

Copilot uses AI. Check for mistakes.
Comment on lines +128 to +170
func (i *Installer) WatchCNIConfigFile() error {
cniConfigPath, err := i.getCniConfigPath()
if err != nil {
return fmt.Errorf("failed to get CNI config path: %v", err)
}

if err := i.Watcher.Add(cniConfigPath); err != nil {
return fmt.Errorf("failed to add %s to file watcher: %v", cniConfigPath, err)
}

// Start listening for events.
go func() {
log.Infof("start watching CNI config file %s", cniConfigPath)

var timerC <-chan time.Time
for {
select {
case <-timerC:
timerC = nil
log.Infof("CNI config file changed, re-applying Kmesh CNI configuration")
if err := i.chainedKmeshCniPlugin(i.Mode, i.CniMountNetEtcDIR); err != nil {
log.Errorf("failed to re-apply Kmesh CNI config: %v", err)
}

case event := <-i.Watcher.Events(cniConfigPath):
log.Debugf("got CNI config event %s", event.String())
if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
if timerC == nil {
timerC = time.After(100 * time.Millisecond)
}
}

case err := <-i.Watcher.Errors(cniConfigPath):
if err != nil {
log.Errorf("error from CNI config file watcher: %v", err)
return
}
}
}
}()

return nil
}
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

The WatchCNIConfigFile function lacks test coverage. Similar to WatchServiceAccountToken which has a test in install_test.go, this new function should have corresponding test coverage to ensure the file watching and re-apply logic works correctly.

Copilot uses AI. Check for mistakes.
case <-timerC:
timerC = nil
log.Infof("CNI config file changed, re-applying Kmesh CNI configuration")
if err := i.chainedKmeshCniPlugin(i.Mode, i.CniMountNetEtcDIR); err != nil {
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

Calling chainedKmeshCniPlugin will trigger a write to the CNI config file being watched, which will cause this watcher to detect its own write and trigger another re-apply. This creates an infinite loop of file writes. Consider checking if the Kmesh plugin is already present in the config before re-applying, or implement a mechanism to distinguish between external changes and self-triggered changes.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Please check, this is a dead loop

@codecov
Copy link

codecov bot commented Jan 10, 2026

Codecov Report

❌ Patch coverage is 0% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 39.40%. Comparing base (3018401) to head (108adab).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/cni/install.go 0.00% 28 Missing ⚠️

❌ Your patch check has failed because the patch coverage (0.00%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Files with missing lines Coverage Δ
pkg/cni/chained.go 38.17% <ø> (+0.20%) ⬆️
pkg/cni/install.go 26.08% <0.00%> (-11.42%) ⬇️

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7c77714...108adab. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@LiZhenCheng9527 LiZhenCheng9527 left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution.
Almost lgtm

log.Debugf("got CNI config event %s", event.String())
if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
if timerC == nil {
timerC = time.After(100 * time.Millisecond)
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be preferable to use an easily understandable constant name.

@AAdIprog
Copy link
Author

@YaoZengzeng @Okabe-Rintarou-0 Please take a look at this

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.

Add file watcher for CNI config file

4 participants