Skip to content

Commit d4dd779

Browse files
committed
ocicni: watch bindirs too
Config validation involves finding and execing the config's plugin to determine the CNI spec versions the plugin binary supports. If the config is written to disk before or concurrently with the plugin binary then the validation may race with the binary and fail to either find it or exec it. Watch bindirs for changes and resync network config when plugin binaries change. Signed-off-by: Dan Williams <[email protected]>
1 parent 2eb3d07 commit d4dd779

File tree

2 files changed

+61
-11
lines changed

2 files changed

+61
-11
lines changed

pkg/ocicni/ocicni.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,12 @@ func (plugin *cniNetworkPlugin) podUnlock(podNetwork PodNetwork) {
117117
}
118118
}
119119

120-
func newWatcher(confDir string) (*fsnotify.Watcher, error) {
121-
// Ensure plugin directory exists, because the following monitoring logic
122-
// relies on that.
123-
if err := os.MkdirAll(confDir, 0755); err != nil {
124-
return nil, fmt.Errorf("failed to create directory %q: %v", confDir, err)
120+
func newWatcher(dirs []string) (*fsnotify.Watcher, error) {
121+
// Ensure directories exist because the fsnotify watch logic depends on it
122+
for _, dir := range dirs {
123+
if err := os.MkdirAll(dir, 0755); err != nil {
124+
return nil, fmt.Errorf("failed to create directory %q: %v", dir, err)
125+
}
125126
}
126127

127128
watcher, err := fsnotify.NewWatcher()
@@ -135,8 +136,10 @@ func newWatcher(confDir string) (*fsnotify.Watcher, error) {
135136
}
136137
}()
137138

138-
if err = watcher.Add(confDir); err != nil {
139-
return nil, fmt.Errorf("failed to add watch on %q: %v", confDir, err)
139+
for _, dir := range dirs {
140+
if err = watcher.Add(dir); err != nil {
141+
return nil, fmt.Errorf("failed to add watch on %q: %v", dir, err)
142+
}
140143
}
141144

142145
return watcher, nil
@@ -152,8 +155,9 @@ func (plugin *cniNetworkPlugin) monitorConfDir(start *sync.WaitGroup) {
152155
logrus.Infof("CNI monitoring event %v", event)
153156

154157
var defaultDeleted bool
155-
createWrite := (event.Op&fsnotify.Create == fsnotify.Create ||
156-
event.Op&fsnotify.Write == fsnotify.Write)
158+
createWriteRename := (event.Op&fsnotify.Create == fsnotify.Create ||
159+
event.Op&fsnotify.Write == fsnotify.Write ||
160+
event.Op&fsnotify.Rename > 0)
157161
if event.Op&fsnotify.Remove == fsnotify.Remove {
158162
// Care about the event if the default network
159163
// was just deleted
@@ -163,7 +167,7 @@ func (plugin *cniNetworkPlugin) monitorConfDir(start *sync.WaitGroup) {
163167
}
164168

165169
}
166-
if !createWrite && !defaultDeleted {
170+
if !createWriteRename && !defaultDeleted {
167171
continue
168172
}
169173

@@ -251,7 +255,7 @@ func initCNI(exec cniinvoke.Exec, cacheDir, defaultNetName string, confDir strin
251255
plugin.syncNetworkConfig()
252256

253257
if useInotify {
254-
plugin.watcher, err = newWatcher(plugin.confDir)
258+
plugin.watcher, err = newWatcher(append([]string{plugin.confDir}, binDirs...))
255259
if err != nil {
256260
return nil, err
257261
}

pkg/ocicni/ocicni_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ type fakeExec struct {
7070
delIndex int
7171
chkIndex int
7272
plugins []*fakePlugin
73+
74+
failFind bool
7375
}
7476

7577
type TestConf struct {
@@ -167,6 +169,10 @@ func (f *fakeExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData
167169

168170
func (f *fakeExec) FindInPath(plugin string, paths []string) (string, error) {
169171
Expect(len(paths)).To(BeNumerically(">", 0))
172+
173+
if f.failFind {
174+
return "", fmt.Errorf("failed to find plugin %q in path %s", plugin, paths)
175+
}
170176
return filepath.Join(paths[0], plugin), nil
171177
}
172178

@@ -180,6 +186,7 @@ func ensureCIDR(cidr string) *net.IPNet {
180186
var _ = Describe("ocicni operations", func() {
181187
var (
182188
tmpDir string
189+
tmpBinDir string
183190
cacheDir string
184191
networkNS ns.NetNS
185192
)
@@ -188,6 +195,8 @@ var _ = Describe("ocicni operations", func() {
188195
var err error
189196
tmpDir, err = ioutil.TempDir("", "ocicni_tmp")
190197
Expect(err).NotTo(HaveOccurred())
198+
tmpBinDir, err = ioutil.TempDir("", "ocicni_tmp_bin")
199+
Expect(err).NotTo(HaveOccurred())
191200
cacheDir, err = ioutil.TempDir("", "ocicni_cache")
192201
Expect(err).NotTo(HaveOccurred())
193202

@@ -201,6 +210,8 @@ var _ = Describe("ocicni operations", func() {
201210

202211
err := os.RemoveAll(tmpDir)
203212
Expect(err).NotTo(HaveOccurred())
213+
err = os.RemoveAll(tmpBinDir)
214+
Expect(err).NotTo(HaveOccurred())
204215
err = os.RemoveAll(cacheDir)
205216
Expect(err).NotTo(HaveOccurred())
206217
})
@@ -247,6 +258,41 @@ var _ = Describe("ocicni operations", func() {
247258
ocicni.Shutdown()
248259
})
249260

261+
It("finds an asynchronously written default network configuration whose plugin is written later", func() {
262+
fExec := &fakeExec{failFind: true}
263+
ocicni, err := initCNI(fExec, "", "test", tmpDir, true, tmpBinDir)
264+
Expect(err).NotTo(HaveOccurred())
265+
266+
_, _, err = writeConfig(tmpDir, "10-test.conf", "test", "myplugin", "0.3.1")
267+
Expect(err).NotTo(HaveOccurred())
268+
Consistently(ocicni.Status, 5).ShouldNot(Succeed())
269+
270+
// Write a file in the bindir to trigger the fsnotify code to resync
271+
fExec.failFind = false
272+
err = ioutil.WriteFile(filepath.Join(tmpBinDir, "myplugin"), []byte("adsfasdfsafd"), 0755)
273+
Expect(err).NotTo(HaveOccurred())
274+
275+
tmp := ocicni.(*cniNetworkPlugin)
276+
Eventually(func() error {
277+
net := tmp.getDefaultNetwork()
278+
if net == nil {
279+
return fmt.Errorf("no default net")
280+
}
281+
if net.name != "test" {
282+
return fmt.Errorf("name not test")
283+
}
284+
if len(net.config.Plugins) == 0 {
285+
return fmt.Errorf("no plugins")
286+
}
287+
if net.config.Plugins[0].Network.Type != "myplugin" {
288+
return fmt.Errorf("wrong plugin type")
289+
}
290+
return nil
291+
}, 10).Should(Succeed())
292+
293+
ocicni.Shutdown()
294+
})
295+
250296
It("finds and refinds an asynchronously written default network configuration", func() {
251297
ocicni, err := initCNI(&fakeExec{}, "", "test", tmpDir, true, "/opt/cni/bin")
252298
Expect(err).NotTo(HaveOccurred())

0 commit comments

Comments
 (0)