Skip to content

Commit 1d1b75c

Browse files
committed
Invert flag, so directory-based plugin loading happens by default.
Signed-off-by: Benjamin Leggett <[email protected]>
1 parent 83d8c6f commit 1d1b75c

File tree

4 files changed

+85
-57
lines changed

4 files changed

+85
-57
lines changed

Diff for: SPEC.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ A network configuration consists of a JSON object with the following keys:
111111
- `cniVersions` (string list): List of all CNI versions which this configuration supports. See [version selection](#version-selection) below.
112112
- `name` (string): Network name. This should be unique across all network configurations on a host (or other administrative domain). Must start with an alphanumeric character, optionally followed by any combination of one or more alphanumeric characters, underscore, dot (.) or hyphen (-). Must not contain characters disallowed in file paths. A path segment (such as a filesystem directory) with the same name as the network name, containing one or more plugin configuration JSON objects for that network, should exist at the same level as the network configuration object itself.
113113
- `disableCheck` (boolean): Either `true` or `false`. If `disableCheck` is `true`, runtimes must not call `CHECK` for this network configuration list. This allows an administrator to prevent `CHECK`ing where a combination of plugins is known to return spurious errors.
114-
- `loadPluginsFromFolder` (boolean): Either `true` or `false`. If `true`, indicates [plugin configuration objects](#plugin-configuration-objects) should be loaded from a sibling folder with the same name as the network `name` field. These sibling folders should exist at the same path as the network configuration itself. Any valid plugin configuration objects within the sibling folder will be appended to the final list of plugins for that network. If `plugins` is not present in the network configuration, `loadPluginsFromFolder` must be present, and set to true.
115-
- `plugins` (list): A list of inlined [plugin configuration objects](#plugin-configuration-objects). If this key is populated with inlined plugin objects, and `loadPluginsFromFolder` is true, the final set of plugins for a network must consist of all the plugin objects in this list, merged with all the plugins loaded from the sibling folder with the same name as the network.
114+
- `disableLoadPluginsFromPath` (boolean): Either `true` or `false`. If `false` (default), indicates [plugin configuration objects](#plugin-configuration-objects) should be loaded from a sibling directory with the same name as the network `name` field. These sibling directories should exist at the same path as the network configuration itself. Any valid plugin configuration objects within a named sibling directory will be appended to the final list of `plugins` for that network name. If set to `true`, plugin configuration objects in sibling directories will be ignored. If `plugins` is not present in the network configuration, `disableLoadPluginsFromPath` cannot be set to `true`.
115+
- `plugins` (list): A list of inlined [plugin configuration objects](#plugin-configuration-objects). If this key is populated with inlined plugin objects, and `disableLoadPluginsFromPath` is true, the final set of plugins for a network must consist of all the plugin objects in this list, merged with all the plugins loaded from the sibling folder with the same name as the network.
116116

117117
#### Plugin configuration objects:
118118
All plugin configuration objects present in a directory with the same name as a valid network configuration must be parsed, and each plugin with a parsable configuration object must be invoked.
@@ -155,7 +155,7 @@ Network configuration with no inlined plugin confs, and two loaded plugin confs:
155155
"cniVersion": "1.1.0",
156156
"cniVersions": ["0.3.1", "0.4.0", "1.0.0", "1.1.0"],
157157
"name": "dbnet",
158-
"loadPluginsFromFolder": true,
158+
"disableLoadPluginsFromPath": false,
159159
}
160160
```
161161

@@ -202,7 +202,7 @@ Network configuration with one inlined plugin conf, and one loaded plugin conf:
202202
"cniVersion": "1.1.0",
203203
"cniVersions": ["0.3.1", "0.4.0", "1.0.0", "1.1.0"],
204204
"name": "dbnet",
205-
"loadPluginsFromFolder": true,
205+
"disableLoadPluginsFromPath": false,
206206
plugins: [
207207
{
208208
"type": "bridge",
@@ -247,6 +247,7 @@ Network configuration with one inlined plugin conf, and no loaded plugin conf:
247247
"cniVersion": "1.1.0",
248248
"cniVersions": ["0.3.1", "0.4.0", "1.0.0", "1.1.0"],
249249
"name": "dbnet",
250+
"disableLoadPluginsFromPath": true,
250251
"plugins": [
251252
{
252253
"type": "bridge",

Diff for: libcni/api.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ type PluginConfig struct {
7777
}
7878

7979
type NetworkConfigList struct {
80-
Name string
81-
CNIVersion string
82-
DisableCheck bool
83-
LoadPluginsFromFolder bool
84-
Plugins []*PluginConfig
85-
Bytes []byte
80+
Name string
81+
CNIVersion string
82+
DisableCheck bool
83+
DisableLoadPluginsFromPath bool
84+
Plugins []*PluginConfig
85+
Bytes []byte
8686
}
8787

8888
type NetworkAttachment struct {

Diff for: libcni/conf.go

+28-22
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,8 @@ func NetworkPluginConfsFromFiles(networkConfPath, networkName string) ([]*Plugin
7272
pluginConfPath := filepath.Join(networkConfPath, networkName)
7373

7474
pluginConfFiles, err := ConfFiles(pluginConfPath, []string{".conf"})
75-
switch {
76-
case err != nil:
75+
if err != nil {
7776
return nil, fmt.Errorf("failed to read plugin config files in %s: %w", pluginConfPath, err)
78-
case len(pluginConfFiles) == 0:
79-
// Having 0 plugins for a given network is not necessarily a problem,
80-
// but return as error for caller to decide, since they tried to load
81-
return nil, fmt.Errorf("no plugin config found in %s", pluginConfPath)
8277
}
8378

8479
for _, pluginConfFile := range pluginConfFiles {
@@ -179,31 +174,35 @@ func NetworkConfFromBytes(confBytes []byte) (*NetworkConfigList, error) {
179174
}
180175
}
181176

182-
loadPluginsFromFolder := false
183-
if rawLoadCheck, ok := rawList["loadPluginsFromFolder"]; ok {
184-
loadPluginsFromFolder, ok = rawLoadCheck.(bool)
177+
disableLoadPluginsFromPath := false
178+
if rawLoadCheck, ok := rawList["disableLoadPluginsFromPath"]; ok {
179+
disableLoadPluginsFromPath, ok = rawLoadCheck.(bool)
185180
if !ok {
186-
return nil, fmt.Errorf("error parsing configuration list: invalid loadPluginsFromFolder type %T", rawLoadCheck)
181+
return nil, fmt.Errorf("error parsing configuration list: invalid disableLoadPluginsFromPath type %T", rawLoadCheck)
187182
}
188183
}
189184

190185
list := &NetworkConfigList{
191-
Name: name,
192-
DisableCheck: disableCheck,
193-
LoadPluginsFromFolder: loadPluginsFromFolder,
194-
CNIVersion: cniVersion,
195-
Bytes: confBytes,
186+
Name: name,
187+
DisableCheck: disableCheck,
188+
DisableLoadPluginsFromPath: disableLoadPluginsFromPath,
189+
CNIVersion: cniVersion,
190+
Bytes: confBytes,
196191
}
197192

198193
var plugins []interface{}
199194
plug, ok := rawList["plugins"]
200195
// We can have a `plugins` list key in the main conf,
201-
// We can also have `loadPluginsFromFolder == true`
202-
// They can both be present in the same config.
203-
// But if one of them is NOT present/false, the other *must* be there.
204-
if !ok && !loadPluginsFromFolder {
205-
return nil, fmt.Errorf("error parsing configuration list: `loadPluginsFromFolder` not true, and no 'plugins' key")
206-
} else if !ok && loadPluginsFromFolder {
196+
// We can also have `disableLoadPluginsFromPath == true`
197+
//
198+
// If `plugins` is there, then `disableLoadPluginsFromPath` can be true
199+
//
200+
// If plugins is NOT there, then `disableLoadPluginsFromPath` cannot be true
201+
//
202+
// We have to have at least some plugins.
203+
if !ok && disableLoadPluginsFromPath {
204+
return nil, fmt.Errorf("error parsing configuration list: `disableLoadPluginsFromPath` is true, and no 'plugins' key")
205+
} else if !ok && !disableLoadPluginsFromPath {
207206
return list, nil
208207
}
209208

@@ -240,14 +239,19 @@ func NetworkConfFromFile(filename string) (*NetworkConfigList, error) {
240239
return nil, err
241240
}
242241

243-
if conf.LoadPluginsFromFolder {
242+
if !conf.DisableLoadPluginsFromPath {
244243
plugins, err := NetworkPluginConfsFromFiles(filepath.Dir(filename), conf.Name)
245244
if err != nil {
246245
return nil, err
247246
}
248247
conf.Plugins = append(conf.Plugins, plugins...)
249248
}
250249

250+
if len(conf.Plugins) == 0 {
251+
// Having 0 plugins for a given network is not necessarily a problem,
252+
// but return as error for caller to decide, since they tried to load
253+
return nil, fmt.Errorf("no plugin configs found")
254+
}
251255
return conf, nil
252256
}
253257

@@ -283,6 +287,8 @@ func ConfFiles(dir string, extensions []string) ([]string, error) {
283287
switch {
284288
case err == nil: // break
285289
case os.IsNotExist(err):
290+
// If folder not there, return no error - only return an
291+
// error if we cannot read contents or there are no contents.
286292
return nil, nil
287293
default:
288294
return nil, err

Diff for: libcni/conf_test.go

+46-25
Original file line numberDiff line numberDiff line change
@@ -390,12 +390,12 @@ var _ = Describe("Loading configuration from disk", func() {
390390
})
391391
})
392392

393-
Context("for loadPluginsFromFolder", func() {
393+
Context("for disableLoadPluginsFromPath", func() {
394394
It("the value will be parsed", func() {
395395
configList = []byte(`{
396396
"name": "some-network",
397397
"cniVersion": "0.4.0",
398-
"loadPluginsFromFolder": true,
398+
"disableLoadPluginsFromPath": true,
399399
"plugins": [
400400
{
401401
"type": "host-local",
@@ -416,7 +416,7 @@ var _ = Describe("Loading configuration from disk", func() {
416416

417417
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
418418
Expect(err).NotTo(HaveOccurred())
419-
Expect(netConfigList.LoadPluginsFromFolder).To(BeTrue())
419+
Expect(netConfigList.DisableLoadPluginsFromPath).To(BeTrue())
420420
})
421421

422422
It("the value will be false if not in config", func() {
@@ -434,15 +434,15 @@ var _ = Describe("Loading configuration from disk", func() {
434434

435435
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
436436
Expect(err).NotTo(HaveOccurred())
437-
Expect(netConfigList.LoadPluginsFromFolder).To(BeFalse())
437+
Expect(netConfigList.DisableLoadPluginsFromPath).To(BeFalse())
438438
})
439439

440440
It("will return an error on an unrecognized value", func() {
441-
const badValue string = "spagnum"
441+
const badValue string = "sphagnum"
442442
configList = []byte(fmt.Sprintf(`{
443443
"name": "some-network",
444444
"cniVersion": "0.4.0",
445-
"loadPluginsFromFolder": "%s",
445+
"disableLoadPluginsFromPath": "%s",
446446
"plugins": [
447447
{
448448
"type": "host-local",
@@ -453,25 +453,26 @@ var _ = Describe("Loading configuration from disk", func() {
453453
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
454454

455455
_, err := libcni.LoadNetworkConf(configDir, "some-network")
456-
Expect(err).To(MatchError("error parsing configuration list: invalid loadPluginsFromFolder type string"))
456+
Expect(err).To(MatchError("error parsing configuration list: invalid disableLoadPluginsFromPath type string"))
457457
})
458458

459-
It("will return an error if `plugins` is missing and `loadPluginsFromFolder` is also missing", func() {
459+
It("will return an error if `plugins` is missing and `disableLoadPluginsFromPath` is `true`", func() {
460460
configList = []byte(`{
461461
"name": "some-network",
462-
"cniVersion": "0.4.0"
462+
"cniVersion": "0.4.0",
463+
"disableLoadPluginsFromPath": true
463464
}`)
464465
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
465466

466467
_, err := libcni.LoadNetworkConf(configDir, "some-network")
467-
Expect(err).To(MatchError("error parsing configuration list: `loadPluginsFromFolder` not true, and no 'plugins' key"))
468+
Expect(err).To(MatchError("error parsing configuration list: `disableLoadPluginsFromPath` is true, and no 'plugins' key"))
468469
})
469470

470-
It("will return no error if `plugins` is missing and `loadPluginsFromFolder` is true", func() {
471+
It("will return no error if `plugins` is missing and `disableLoadPluginsFromPath` is false", func() {
471472
configList = []byte(`{
472473
"name": "some-network",
473474
"cniVersion": "0.4.0",
474-
"loadPluginsFromFolder": true
475+
"disableLoadPluginsFromPath": false
475476
}`)
476477
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
477478

@@ -486,43 +487,62 @@ var _ = Describe("Loading configuration from disk", func() {
486487

487488
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
488489
Expect(err).NotTo(HaveOccurred())
489-
Expect(netConfigList.LoadPluginsFromFolder).To(BeTrue())
490+
Expect(netConfigList.DisableLoadPluginsFromPath).To(BeFalse())
490491
Expect(netConfigList.Plugins).To(HaveLen(1))
491492
})
492493

493-
It("will return error if `loadPluginsFromFolder` is true but no plugins subfolder with network name exists", func() {
494+
It("will return error if `disableLoadPluginsFromPath` is implicitly false + no conf plugin is defined, but no plugins subfolder with network name exists", func() {
495+
configList = []byte(`{
496+
"name": "some-network",
497+
"cniVersion": "0.4.0"
498+
}`)
499+
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
500+
501+
_, err := libcni.LoadNetworkConf(configDir, "some-network")
502+
Expect(err).To(MatchError("no plugin configs found"))
503+
})
504+
505+
It("will return NO error if `disableLoadPluginsFromPath` is implicitly false + at least 1 conf plugin is defined, but no plugins subfolder with network name exists", func() {
494506
configList = []byte(`{
495507
"name": "some-network",
496508
"cniVersion": "0.4.0",
497-
"loadPluginsFromFolder": true
509+
"plugins": [
510+
{
511+
"type": "host-local",
512+
"subnet": "10.0.0.1/24"
513+
}
514+
]
498515
}`)
499516
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
500517

501-
subDir := filepath.Join(configDir, "some-network")
502518
_, err := libcni.LoadNetworkConf(configDir, "some-network")
503-
Expect(err).To(MatchError(fmt.Sprintf("no plugin config found in %s", subDir)))
519+
Expect(err).NotTo(HaveOccurred())
504520
})
505521

506-
It("will return error if `loadPluginsFromFolder` is true and network name subfolder exists, but no plugin configs", func() {
522+
It("will return NO error if `disableLoadPluginsFromPath` is implicitly false + at least 1 conf plugin is defined and network name subfolder exists, but is empty/unreadable", func() {
507523
configList = []byte(`{
508524
"name": "some-network",
509525
"cniVersion": "0.4.0",
510-
"loadPluginsFromFolder": true
526+
"plugins": [
527+
{
528+
"type": "host-local",
529+
"subnet": "10.0.0.1/24"
530+
}
531+
]
511532
}`)
512533
Expect(os.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0o600)).To(Succeed())
513534

514535
subDir := filepath.Join(configDir, "some-network")
515536
Expect(os.MkdirAll(subDir, 0o700)).To(Succeed())
516537

517538
_, err := libcni.LoadNetworkConf(configDir, "some-network")
518-
Expect(err).To(MatchError(fmt.Sprintf("no plugin config found in %s", subDir)))
539+
Expect(err).NotTo(HaveOccurred())
519540
})
520541

521-
It("will merge loaded and inlined plugin lists if both `plugins` is set and `loadPluginsFromFolder` is true", func() {
542+
It("will merge loaded and inlined plugin lists if both `plugins` is set and `disableLoadPluginsFromPath` is false", func() {
522543
configList = []byte(`{
523544
"name": "some-network",
524545
"cniVersion": "0.4.0",
525-
"loadPluginsFromFolder": true,
526546
"plugins": [
527547
{
528548
"type": "host-local",
@@ -544,14 +564,15 @@ var _ = Describe("Loading configuration from disk", func() {
544564

545565
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
546566
Expect(err).NotTo(HaveOccurred())
547-
Expect(netConfigList.LoadPluginsFromFolder).To(BeTrue())
567+
Expect(netConfigList.DisableLoadPluginsFromPath).To(BeFalse())
548568
Expect(netConfigList.Plugins).To(HaveLen(2))
549569
})
550570

551-
It("will ignore loaded plugins if `plugins` is set and `loadPluginsFromFolder` is not present", func() {
571+
It("will ignore loaded plugins if `plugins` is set and `disableLoadPluginsFromPath` is true", func() {
552572
configList = []byte(`{
553573
"name": "some-network",
554574
"cniVersion": "0.4.0",
575+
"disableLoadPluginsFromPath": true,
555576
"plugins": [
556577
{
557578
"type": "host-local",
@@ -572,7 +593,7 @@ var _ = Describe("Loading configuration from disk", func() {
572593

573594
netConfigList, err := libcni.LoadNetworkConf(configDir, "some-network")
574595
Expect(err).NotTo(HaveOccurred())
575-
Expect(netConfigList.LoadPluginsFromFolder).To(BeFalse())
596+
Expect(netConfigList.DisableLoadPluginsFromPath).To(BeTrue())
576597
Expect(netConfigList.Plugins).To(HaveLen(1))
577598
Expect(netConfigList.Plugins[0].Network.Type).To(Equal("host-local"))
578599
})

0 commit comments

Comments
 (0)