-
Notifications
You must be signed in to change notification settings - Fork 158
feat(cni): add file watcher for CNI config file #1566
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -121,6 +121,54 @@ func (i *Installer) WatchServiceAccountToken() error { | |
| return nil | ||
| } | ||
|
|
||
| // WatchCNIConfigFile watches the CNI config file for external modifications | ||
| // and re-applies Kmesh CNI configuration when changes are detected. | ||
| // This ensures Kmesh CNI plugin remains installed even if other CNI plugins | ||
| // modify the config file. | ||
| 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) | ||
|
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. It would be preferable to use an easily understandable constant name. |
||
| } | ||
| } | ||
|
Comment on lines
+154
to
+158
|
||
|
|
||
| case err := <-i.Watcher.Errors(cniConfigPath): | ||
| if err != nil { | ||
| log.Errorf("error from CNI config file watcher: %v", err) | ||
| return | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+143
to
+166
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. The current implementation of the file watcher goroutine has a potential issue. When To fix this, you should check if the channels are closed when reading from them. You can do this using the two-variable assignment This issue also exists in 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
}
}
} |
||
| }() | ||
|
|
||
| return nil | ||
| } | ||
|
Comment on lines
+128
to
+170
|
||
|
|
||
| func (i *Installer) Start() error { | ||
| if i.Mode == constants.KernelNativeMode || i.Mode == constants.DualEngineMode { | ||
| log.Info("start write CNI config") | ||
|
|
@@ -133,6 +181,10 @@ func (i *Installer) Start() error { | |
| if err := i.WatchServiceAccountToken(); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := i.WatchCNIConfigFile(); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
|
|
||
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.
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.
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.
Please check, this is a dead loop