Skip to content

Commit 81d15e9

Browse files
authored
Merge pull request #1052 from bleggett/bleggett/multi-dir-pluginconfig
RFC - Support safe subdirectory-based plugin conf loading
2 parents 309b6bb + 4254258 commit 81d15e9

File tree

10 files changed

+457
-142
lines changed

10 files changed

+457
-142
lines changed

Diff for: SPEC.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,16 @@ A network configuration consists of a JSON object with the following keys:
109109

110110
- `cniVersion` (string): [Semantic Version 2.0](https://semver.org) of CNI specification to which this configuration list and all the individual configurations conform. Currently "1.1.0"
111111
- `cniVersions` (string list): List of all CNI versions which this configuration supports. See [version selection](#version-selection) below.
112-
- `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 (-).
112+
- `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.
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.
114114
- `disableGC` (boolean): Either `true` or `false`. If `disableGC` is `true`, runtimes must not call `GC` for this network configuration list. This allows an administrator to prevent `GC`ing when it is known that garbage collection may have undesired effects (e.g. shared configuration between multiple runtimes).
115-
- `plugins` (list): A list of CNI plugins and their configuration, which is a list of plugin configuration objects.
115+
- `loadOnlyInlinedPlugins` (boolean): Either `true` or `false`. If `false` (default), indicates [plugin configuration objects](#plugin-configuration-objects) can be aggregated from multiple sources. Any valid plugin configuration objects aggregated from other sources must be appended to the final list of `plugins` for that network name. If set to `true`, indicates that valid plugin configuration objects aggregated from sources other than the main network configuration will be ignored. If `plugins` is not present in the network configuration, `loadOnlyInlinedPlugins` cannot be set to `true`.
116+
- `plugins` (list): A list of inlined [plugin configuration objects](#plugin-configuration-objects). If this key is populated with inlined plugin objects, and `loadOnlyInlinedPlugins` 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.
116117

117118
#### Plugin configuration objects:
118-
Plugin configuration objects may contain additional fields than the ones defined here.
119-
The runtime MUST pass through these fields, unchanged, to the plugin, as defined in section 3.
119+
Runtimes may aggregate plugin configuration objects from multiple sources, and must unambiguously associate each loaded plugin configuration object with a single, valid network configuration. All aggregated plugin configuration objects must be validated, and each plugin with a valid configuration object must be invoked.
120+
121+
Plugin configuration objects may contain additional fields beyond the ones defined here. The runtime MUST pass through these fields, unchanged, to the invoked plugin, as defined in section 3.
120122

121123
**Required keys:**
122124
- `type` (string): Matches the name of the CNI plugin binary on disk. Must not contain characters disallowed in file paths for the system (e.g. / or \\).
@@ -147,6 +149,7 @@ Plugins that consume any of these configuration keys should respect their intend
147149
Plugins may define additional fields that they accept and may generate an error if called with unknown fields. Runtimes must preserve unknown fields in plugin configuration objects when transforming for execution.
148150

149151
#### Example configuration
152+
The following is an example JSON representation of a network configuration `dbnet` with three plugin configurations (`bridge`, `tuning`, and `portmap`).
150153
```jsonc
151154
{
152155
"cniVersion": "1.1.0",
@@ -158,7 +161,7 @@ Plugins may define additional fields that they accept and may generate an error
158161
// plugin specific parameters
159162
"bridge": "cni0",
160163
"keyA": ["some more", "plugin specific", "configuration"],
161-
164+
162165
"ipam": {
163166
"type": "host-local",
164167
// ipam specific
@@ -375,8 +378,6 @@ Resources may, for example, include:
375378

376379
A plugin SHOULD remove as many stale resources as possible. For example, a plugin should remove any IPAM reservations associated with attachments not in the provided list. The plugin MAY assume that the isolation domain (e.g. network namespace) has been deleted, and thus any resources (e.g. network interfaces) therein have been removed.
377380

378-
Garbage collection is a per-network operation. If a plugin manages resources shared across multiple networks, it must only remove stale resources known to belong to the network provided in the `GC `action.
379-
380381
Plugins should generally complete a `GC` action without error. If an error is encountered, a plugin should continue; removing as many resources as possible, and report the errors back to the runtime.
381382

382383
Plugins MUST, additionally, forward any GC calls to delegated plugins they are configured to use (see section 4).

Diff for: cnitool/cnitool.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func main() {
6868
if netdir == "" {
6969
netdir = DefaultNetDir
7070
}
71-
netconf, err := libcni.LoadConfList(netdir, os.Args[2])
71+
netconf, err := libcni.LoadNetworkConf(netdir, os.Args[2])
7272
if err != nil {
7373
exit(err)
7474
}

Diff for: libcni/api.go

+33-28
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,23 @@ type RuntimeConf struct {
6767
CacheDir string
6868
}
6969

70-
type NetworkConfig struct {
71-
Network *types.NetConf
70+
// Deprecated: Use PluginConfig instead of NetworkConfig, the NetworkConfig
71+
// backwards-compat alias will be removed in a future release.
72+
type NetworkConfig = PluginConfig
73+
74+
type PluginConfig struct {
75+
Network *types.PluginConf
7276
Bytes []byte
7377
}
7478

7579
type NetworkConfigList struct {
76-
Name string
77-
CNIVersion string
78-
DisableCheck bool
79-
DisableGC bool
80-
Plugins []*NetworkConfig
81-
Bytes []byte
80+
Name string
81+
CNIVersion string
82+
DisableCheck bool
83+
DisableGC bool
84+
LoadOnlyInlinedPlugins bool
85+
Plugins []*PluginConfig
86+
Bytes []byte
8287
}
8388

8489
type NetworkAttachment struct {
@@ -102,14 +107,14 @@ type CNI interface {
102107
GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
103108
GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
104109

105-
AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
106-
CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
107-
DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
108-
GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
109-
GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
110+
AddNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) (types.Result, error)
111+
CheckNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error
112+
DelNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error
113+
GetNetworkCachedResult(net *PluginConfig, rt *RuntimeConf) (types.Result, error)
114+
GetNetworkCachedConfig(net *PluginConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
110115

111116
ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error)
112-
ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)
117+
ValidateNetwork(ctx context.Context, net *PluginConfig) ([]string, error)
113118

114119
GCNetworkList(ctx context.Context, net *NetworkConfigList, args *GCArgs) error
115120
GetStatusNetworkList(ctx context.Context, net *NetworkConfigList) error
@@ -147,7 +152,7 @@ func NewCNIConfigWithCacheDir(path []string, cacheDir string, exec invoke.Exec)
147152
}
148153
}
149154

150-
func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) {
155+
func buildOneConfig(name, cniVersion string, orig *PluginConfig, prevResult types.Result, rt *RuntimeConf) (*PluginConfig, error) {
151156
var err error
152157

153158
inject := map[string]interface{}{
@@ -183,7 +188,7 @@ func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult typ
183188
// capabilities include "portMappings", and the CapabilityArgs map includes a
184189
// "portMappings" key, that key and its value are added to the "runtimeConfig"
185190
// dictionary to be passed to the plugin's stdin.
186-
func injectRuntimeConfig(orig *NetworkConfig, rt *RuntimeConf) (*NetworkConfig, error) {
191+
func injectRuntimeConfig(orig *PluginConfig, rt *RuntimeConf) (*PluginConfig, error) {
187192
var err error
188193

189194
rc := make(map[string]interface{})
@@ -404,7 +409,7 @@ func (c *CNIConfig) GetNetworkListCachedResult(list *NetworkConfigList, rt *Runt
404409

405410
// GetNetworkCachedResult returns the cached Result of the previous
406411
// AddNetwork() operation for a network, or an error.
407-
func (c *CNIConfig) GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
412+
func (c *CNIConfig) GetNetworkCachedResult(net *PluginConfig, rt *RuntimeConf) (types.Result, error) {
408413
return c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
409414
}
410415

@@ -416,7 +421,7 @@ func (c *CNIConfig) GetNetworkListCachedConfig(list *NetworkConfigList, rt *Runt
416421

417422
// GetNetworkCachedConfig copies the input RuntimeConf to output
418423
// RuntimeConf with fields updated with info from the cached Config.
419-
func (c *CNIConfig) GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
424+
func (c *CNIConfig) GetNetworkCachedConfig(net *PluginConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
420425
return c.getCachedConfig(net.Network.Name, rt)
421426
}
422427

@@ -482,7 +487,7 @@ func (c *CNIConfig) GetCachedAttachments(containerID string) ([]*NetworkAttachme
482487
return attachments, nil
483488
}
484489

485-
func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
490+
func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
486491
c.ensureExec()
487492
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
488493
if err != nil {
@@ -524,7 +529,7 @@ func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList,
524529
return result, nil
525530
}
526531

527-
func (c *CNIConfig) checkNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error {
532+
func (c *CNIConfig) checkNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) error {
528533
c.ensureExec()
529534
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
530535
if err != nil {
@@ -566,7 +571,7 @@ func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigLis
566571
return nil
567572
}
568573

569-
func (c *CNIConfig) delNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error {
574+
func (c *CNIConfig) delNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) error {
570575
c.ensureExec()
571576
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
572577
if err != nil {
@@ -607,7 +612,7 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
607612
return nil
608613
}
609614

610-
func pluginDescription(net *types.NetConf) string {
615+
func pluginDescription(net *types.PluginConf) string {
611616
if net == nil {
612617
return "<missing>"
613618
}
@@ -621,7 +626,7 @@ func pluginDescription(net *types.NetConf) string {
621626
}
622627

623628
// AddNetwork executes the plugin with the ADD command
624-
func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
629+
func (c *CNIConfig) AddNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) (types.Result, error) {
625630
result, err := c.addNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, nil, rt)
626631
if err != nil {
627632
return nil, err
@@ -635,7 +640,7 @@ func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
635640
}
636641

637642
// CheckNetwork executes the plugin with the CHECK command
638-
func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error {
643+
func (c *CNIConfig) CheckNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error {
639644
// CHECK was added in CNI spec version 0.4.0 and higher
640645
if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil {
641646
return err
@@ -651,7 +656,7 @@ func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *Ru
651656
}
652657

653658
// DelNetwork executes the plugin with the DEL command
654-
func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error {
659+
func (c *CNIConfig) DelNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error {
655660
var cachedResult types.Result
656661

657662
// Cached result on DEL was added in CNI spec version 0.4.0 and higher
@@ -711,7 +716,7 @@ func (c *CNIConfig) ValidateNetworkList(ctx context.Context, list *NetworkConfig
711716
// ValidateNetwork checks that a configuration is reasonably valid.
712717
// It uses the same logic as ValidateNetworkList)
713718
// Returns a list of capabilities
714-
func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error) {
719+
func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *PluginConfig) ([]string, error) {
715720
caps := []string{}
716721
for c, ok := range net.Network.Capabilities {
717722
if ok {
@@ -836,7 +841,7 @@ func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList,
836841
return errors.Join(errs...)
837842
}
838843

839-
func (c *CNIConfig) gcNetwork(ctx context.Context, net *NetworkConfig) error {
844+
func (c *CNIConfig) gcNetwork(ctx context.Context, net *PluginConfig) error {
840845
c.ensureExec()
841846
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
842847
if err != nil {
@@ -871,7 +876,7 @@ func (c *CNIConfig) GetStatusNetworkList(ctx context.Context, list *NetworkConfi
871876
return nil
872877
}
873878

874-
func (c *CNIConfig) getStatusNetwork(ctx context.Context, net *NetworkConfig) error {
879+
func (c *CNIConfig) getStatusNetwork(ctx context.Context, net *PluginConfig) error {
875880
c.ensureExec()
876881
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
877882
if err != nil {

Diff for: libcni/api_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ var _ = Describe("Invoking plugins", func() {
176176
pluginConfig []byte
177177
cniConfig *libcni.CNIConfig
178178
runtimeConfig *libcni.RuntimeConf
179-
netConfig *libcni.NetworkConfig
179+
netConfig *libcni.PluginConfig
180180
ctx context.Context
181181
)
182182

@@ -295,7 +295,7 @@ var _ = Describe("Invoking plugins", func() {
295295
debug *noop_debug.Debug
296296
pluginConfig string
297297
cniConfig *libcni.CNIConfig
298-
netConfig *libcni.NetworkConfig
298+
netConfig *libcni.PluginConfig
299299
runtimeConfig *libcni.RuntimeConf
300300
ctx context.Context
301301

@@ -1636,7 +1636,7 @@ var _ = Describe("Invoking plugins", func() {
16361636
cniBinPath string
16371637
pluginConfig string
16381638
cniConfig *libcni.CNIConfig
1639-
netConfig *libcni.NetworkConfig
1639+
netConfig *libcni.PluginConfig
16401640
runtimeConfig *libcni.RuntimeConf
16411641
netConfigList *libcni.NetworkConfigList
16421642
)
@@ -1809,7 +1809,7 @@ var _ = Describe("Invoking plugins", func() {
18091809
cniBinPath string
18101810
pluginConfig string
18111811
cniConfig *libcni.CNIConfig
1812-
netConfig *libcni.NetworkConfig
1812+
netConfig *libcni.PluginConfig
18131813
runtimeConfig *libcni.RuntimeConf
18141814

18151815
ctx context.Context
@@ -1931,14 +1931,14 @@ var _ = Describe("Invoking plugins", func() {
19311931
Context("when the RuntimeConf is incomplete", func() {
19321932
var (
19331933
testRt *libcni.RuntimeConf
1934-
testNetConf *libcni.NetworkConfig
1934+
testNetConf *libcni.PluginConfig
19351935
testNetConfList *libcni.NetworkConfigList
19361936
)
19371937

19381938
BeforeEach(func() {
19391939
testRt = &libcni.RuntimeConf{}
1940-
testNetConf = &libcni.NetworkConfig{
1941-
Network: &types.NetConf{},
1940+
testNetConf = &libcni.PluginConfig{
1941+
Network: &types.PluginConf{},
19421942
}
19431943
testNetConfList = &libcni.NetworkConfigList{}
19441944
})

0 commit comments

Comments
 (0)