diff --git a/vendor.conf b/vendor.conf index 04fe652363..a907780a4b 100644 --- a/vendor.conf +++ b/vendor.conf @@ -44,8 +44,8 @@ github.com/gotestyourself/gotestyourself 44dbf532bbf5767611f6f2a61bded572e337010 github.com/google/go-cmp v0.1.0 # cri dependencies -github.com/containerd/cri f117382467baf182382c44332bfbf488effc34bb # release/1.0 -github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7 +github.com/containerd/cri ac043660063cf4fd93aa17aeb8bfcaf2d7d249ab # release/1.0 +github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90 github.com/blang/semver v3.1.0 github.com/containernetworking/cni v0.6.0 github.com/containernetworking/plugins v0.7.0 diff --git a/vendor/github.com/containerd/cri/pkg/server/container_status.go b/vendor/github.com/containerd/cri/pkg/server/container_status.go index 51d356d037..16ba83eff6 100644 --- a/vendor/github.com/containerd/cri/pkg/server/container_status.go +++ b/vendor/github.com/containerd/cri/pkg/server/container_status.go @@ -99,7 +99,8 @@ func toCRIContainerStatus(container containerstore.Container, spec *runtime.Imag } } -type containerInfo struct { +// ContainerInfo is extra information for a container. +type ContainerInfo struct { // TODO(random-liu): Add sandboxID in CRI container status. SandboxID string `json:"sandboxID"` Pid uint32 `json:"pid"` @@ -122,7 +123,7 @@ func toCRIContainerInfo(ctx context.Context, container containerstore.Container, status := container.Status.Get() // TODO(random-liu): Change CRI status info to use array instead of map. - ci := &containerInfo{ + ci := &ContainerInfo{ SandboxID: container.SandboxID, Pid: status.Pid, Removing: status.Removing, diff --git a/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go b/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go index 5d4628a8e0..b19930181d 100644 --- a/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go +++ b/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go @@ -100,8 +100,9 @@ func toCRISandboxStatus(meta sandboxstore.Metadata, status sandboxstore.Status, } } +// SandboxInfo is extra information for sandbox. // TODO (mikebrow): discuss predefining constants structures for some or all of these field names in CRI -type sandboxInfo struct { +type SandboxInfo struct { Pid uint32 `json:"pid"` Status string `json:"processStatus"` NetNSClosed bool `json:"netNamespaceClosed"` @@ -131,7 +132,7 @@ func toCRISandboxInfo(ctx context.Context, sandbox sandboxstore.Sandbox) (map[st processStatus = taskStatus.Status } - si := &sandboxInfo{ + si := &SandboxInfo{ Pid: sandbox.Status.Get().Pid, Status: string(processStatus), Config: sandbox.Config, diff --git a/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go b/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go index 2d5b3ca338..e0f2033093 100644 --- a/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go +++ b/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go @@ -17,7 +17,6 @@ limitations under the License. package server import ( - "os" "time" "github.com/containerd/containerd" @@ -60,23 +59,21 @@ func (c *criService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandb } // Teardown network for sandbox. - if sandbox.NetNSPath != "" && sandbox.NetNS != nil { - if _, err := os.Stat(sandbox.NetNSPath); err != nil { - if !os.IsNotExist(err) { - return nil, errors.Wrapf(err, "failed to stat network namespace path %s", sandbox.NetNSPath) - } - } else { - if teardownErr := c.teardownPod(id, sandbox.NetNSPath, sandbox.Config); teardownErr != nil { - return nil, errors.Wrapf(teardownErr, "failed to destroy network for sandbox %q", id) - } + if sandbox.NetNSPath != "" { + netNSPath := sandbox.NetNSPath + if sandbox.NetNS == nil || sandbox.NetNS.Closed() { + // Use empty netns path if netns is not available. This is defined in: + // https://github.com/containernetworking/cni/blob/v0.7.0-alpha1/SPEC.md + netNSPath = "" } - /*TODO:It is still possible that containerd crashes after we teardown the network, but before we remove the network namespace. - In that case, we'll not be able to remove the sandbox anymore. The chance is slim, but we should be aware of that. - In the future, once TearDownPod is idempotent, this will be fixed.*/ - - //Close the sandbox network namespace if it was created - if err = sandbox.NetNS.Remove(); err != nil { - return nil, errors.Wrapf(err, "failed to remove network namespace for sandbox %q", id) + if err := c.teardownPod(id, netNSPath, sandbox.Config); err != nil { + return nil, errors.Wrapf(err, "failed to destroy network for sandbox %q", id) + } + // Close the sandbox network namespace if it was created + if sandbox.NetNS != nil { + if err = sandbox.NetNS.Remove(); err != nil { + return nil, errors.Wrapf(err, "failed to remove network namespace for sandbox %q", id) + } } } diff --git a/vendor/github.com/containerd/cri/pkg/server/service.go b/vendor/github.com/containerd/cri/pkg/server/service.go index c8d0a4c95e..13dc9255b8 100644 --- a/vendor/github.com/containerd/cri/pkg/server/service.go +++ b/vendor/github.com/containerd/cri/pkg/server/service.go @@ -148,7 +148,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi // Try to load the config if it exists. Just log the error if load fails // This is not disruptive for containerd to panic - if err := c.netPlugin.Load(cni.WithLoNetwork(), cni.WithDefaultConf()); err != nil { + if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err != nil { logrus.WithError(err).Error("Failed to load cni during init, please check CRI plugin status before setting up network for pods") } // prepare streaming server diff --git a/vendor/github.com/containerd/cri/pkg/server/status.go b/vendor/github.com/containerd/cri/pkg/server/status.go index 0590362392..d799b9e330 100644 --- a/vendor/github.com/containerd/cri/pkg/server/status.go +++ b/vendor/github.com/containerd/cri/pkg/server/status.go @@ -44,7 +44,7 @@ func (c *criService) Status(ctx context.Context, r *runtime.StatusRequest) (*run // Check the status of the cni initialization if err := c.netPlugin.Status(); err != nil { // If it is not initialized, then load the config and retry - if err = c.netPlugin.Load(cni.WithLoNetwork(), cni.WithDefaultConf()); err != nil { + if err = c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err != nil { networkCondition.Status = false networkCondition.Reason = networkNotReadyReason networkCondition.Message = fmt.Sprintf("Network plugin returns error: %v", err) diff --git a/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go b/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go index 8682da66d0..0f55aedf8e 100644 --- a/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go +++ b/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go @@ -52,7 +52,7 @@ func (c *criService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateR if err := c.netPlugin.Status(); err == nil { logrus.Infof("Network plugin is ready, skip generating cni config from template %q", confTemplate) return &runtime.UpdateRuntimeConfigResponse{}, nil - } else if err := c.netPlugin.Load(cni.WithLoNetwork(), cni.WithDefaultConf()); err == nil { + } else if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err == nil { logrus.Infof("CNI config is successfully loaded, skip generating cni config from template %q", confTemplate) return &runtime.UpdateRuntimeConfigResponse{}, nil } diff --git a/vendor/github.com/containerd/cri/pkg/store/sandbox/netns.go b/vendor/github.com/containerd/cri/pkg/store/sandbox/netns.go index 5d56d92220..3ad67b620b 100644 --- a/vendor/github.com/containerd/cri/pkg/store/sandbox/netns.go +++ b/vendor/github.com/containerd/cri/pkg/store/sandbox/netns.go @@ -28,6 +28,13 @@ import ( osinterface "github.com/containerd/cri/pkg/os" ) +// The NetNS library assumes only containerd manages the lifecycle of the +// network namespace mount. The only case that netns will be unmounted by +// someone else is node reboot. +// If this assumption is broken, NetNS won't be aware of the external +// unmount, and there will be a state mismatch. +// TODO(random-liu): Don't cache state, always load from the system. + // ErrClosedNetNS is the error returned when network namespace is closed. var ErrClosedNetNS = errors.New("network namespace is closed") diff --git a/vendor/github.com/containerd/cri/vendor.conf b/vendor/github.com/containerd/cri/vendor.conf index 381bcbddf1..bc0b6c157d 100644 --- a/vendor/github.com/containerd/cri/vendor.conf +++ b/vendor/github.com/containerd/cri/vendor.conf @@ -7,7 +7,7 @@ github.com/containerd/console 4d8a41f4ce5b9bae77c41786ea2458330f43f081 github.com/containerd/containerd 57508dcb0b5776efaacd0828ed42f819fab5ba07 github.com/containerd/continuity a60600ad77f38aaa70165825f61e2ea72e51c9b1 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c -github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7 +github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90 github.com/containerd/go-runc bcb223a061a3dd7de1a89c0b402a60f4dd9bd307 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 github.com/containernetworking/cni v0.6.0 diff --git a/vendor/github.com/containerd/go-cni/README.md b/vendor/github.com/containerd/go-cni/README.md index 900b42440a..c0856aebcd 100644 --- a/vendor/github.com/containerd/go-cni/README.md +++ b/vendor/github.com/containerd/go-cni/README.md @@ -1,7 +1,10 @@ +[![Build Status](https://travis-ci.org/containerd/go-cni.svg?branch=master)](https://travis-ci.org/containerd/go-cni) + # go-cni A generic CNI library to provide APIs for CNI plugin interactions. The library provides APIs to: +- Load CNI network config from different sources - Setup networks for container namespace - Remove networks from container namespace - Query status of CNI network plugin initialization @@ -16,11 +19,17 @@ func main() { defaultIfName := "eth0" // Initialize library l = gocni.New(gocni.WithMinNetworkCount(2), - gocni.WithLoNetwork(), gocni.WithPluginConfDir("/etc/mycni/net.d"), gocni.WithPluginDir([]string{"/opt/mycni/bin", "/opt/cni/bin"}), gocni.WithDefaultIfName(defaultIfName)) - + + // Load the cni configuration + err:= l.Load(gocni.WithLoNetwork,gocni.WithDefaultConf) + if err != nil{ + log.Errorf("failed to load cni configuration: %v", err) + return + } + // Setup network for namespace. labels := map[string]string{ "K8S_POD_NAMESPACE": "namespace1", @@ -29,16 +38,10 @@ func main() { } result, err := l.Setup(id, netns, gocni.WithLabels(labels)) if err != nil { - return nil, fmt.Errorf("failed to setup network for namespace %q: %v", id, err) + log.Errorf("failed to setup network for namespace %q: %v",id, err) + return } - defer func() { - if retErr != nil { - // Teardown network if an error is returned. - if err := l.Remove(id, netns, gocni.WithLabels(labels)); err != nil { - fmt.Errorf("Failed to destroy network for namespace %q", id) - } - } - }() + // Get IP of the default interface IP := result.Interfaces[defaultIfName].IPConfigs[0].IP.String() fmt.Printf("IP of the default interface %s:%s", defaultIfName, IP) diff --git a/vendor/github.com/containerd/go-cni/cni.go b/vendor/github.com/containerd/go-cni/cni.go index 89f0dbc04a..31350e3049 100644 --- a/vendor/github.com/containerd/go-cni/cni.go +++ b/vendor/github.com/containerd/go-cni/cni.go @@ -18,6 +18,7 @@ package cni import ( "fmt" + "strings" "sync" cnilibrary "github.com/containernetworking/cni/libcni" @@ -31,7 +32,7 @@ type CNI interface { // Remove tears down the network of the namespace. Remove(id string, path string, opts ...NamespaceOpts) error // Load loads the cni network config - Load(opts ...LoadOption) error + Load(opts ...CNIOpt) error // Status checks the status of the cni initialization Status() error } @@ -59,7 +60,7 @@ func defaultCNIConfig() *libcni { } } -func New(config ...ConfigOption) (CNI, error) { +func New(config ...CNIOpt) (CNI, error) { cni := defaultCNIConfig() var err error for _, c := range config { @@ -70,8 +71,10 @@ func New(config ...ConfigOption) (CNI, error) { return cni, nil } -func (c *libcni) Load(opts ...LoadOption) error { +func (c *libcni) Load(opts ...CNIOpt) error { var err error + c.Lock() + defer c.Unlock() // Reset the networks on a load operation to ensure // config happens on a clean slate c.reset() @@ -81,30 +84,27 @@ func (c *libcni) Load(opts ...LoadOption) error { return errors.Wrapf(ErrLoad, fmt.Sprintf("cni config load failed: %v", err)) } } - return c.Status() + return nil } func (c *libcni) Status() error { c.RLock() defer c.RUnlock() - if len(c.networks) < c.networkCount { - return ErrCNINotInitialized - } - return nil + return c.status() } // Setup setups the network in the namespace func (c *libcni) Setup(id string, path string, opts ...NamespaceOpts) (*CNIResult, error) { - if err:=c.Status();err!=nil{ - return nil,err + c.RLock() + defer c.RUnlock() + if err := c.status(); err != nil { + return nil, err } ns, err := newNamespace(id, path, opts...) if err != nil { return nil, err } var results []*current.Result - c.RLock() - defer c.RUnlock() for _, network := range c.networks { r, err := network.Attach(ns) if err != nil { @@ -117,17 +117,26 @@ func (c *libcni) Setup(id string, path string, opts ...NamespaceOpts) (*CNIResul // Remove removes the network config from the namespace func (c *libcni) Remove(id string, path string, opts ...NamespaceOpts) error { - if err:=c.Status();err!=nil{ - return err - } + c.RLock() + defer c.RUnlock() + if err := c.status(); err != nil { + return err + } ns, err := newNamespace(id, path, opts...) if err != nil { return err } - c.RLock() - defer c.RUnlock() for _, network := range c.networks { if err := network.Remove(ns); err != nil { + // Based on CNI spec v0.7.0, empty network namespace is allowed to + // do best effort cleanup. However, it is not handled consistently + // right now: + // https://github.com/containernetworking/plugins/issues/210 + // TODO(random-liu): Remove the error handling when the issue is + // fixed and the CNI spec v0.6.0 support is deprecated. + if path == "" && strings.Contains(err.Error(), "no such file or directory") { + continue + } return err } } @@ -135,7 +144,12 @@ func (c *libcni) Remove(id string, path string, opts ...NamespaceOpts) error { } func (c *libcni) reset() { - c.Lock() - defer c.Unlock() c.networks = nil } + +func (c *libcni) status() error { + if len(c.networks) < c.networkCount { + return ErrCNINotInitialized + } + return nil +} diff --git a/vendor/github.com/containerd/go-cni/opts.go b/vendor/github.com/containerd/go-cni/opts.go index ada1daa0c4..be533f16e0 100644 --- a/vendor/github.com/containerd/go-cni/opts.go +++ b/vendor/github.com/containerd/go-cni/opts.go @@ -24,11 +24,11 @@ import ( "github.com/pkg/errors" ) -type ConfigOption func(c *libcni) error +type CNIOpt func(c *libcni) error // WithInterfacePrefix sets the prefix for network interfaces // e.g. eth or wlan -func WithInterfacePrefix(prefix string) ConfigOption { +func WithInterfacePrefix(prefix string) CNIOpt { return func(c *libcni) error { c.prefix = prefix return nil @@ -37,7 +37,7 @@ func WithInterfacePrefix(prefix string) ConfigOption { // WithPluginDir can be used to set the locations of // the cni plugin binaries -func WithPluginDir(dirs []string) ConfigOption { +func WithPluginDir(dirs []string) CNIOpt { return func(c *libcni) error { c.pluginDirs = dirs c.cniConfig = &cnilibrary.CNIConfig{Path: dirs} @@ -47,7 +47,7 @@ func WithPluginDir(dirs []string) ConfigOption { // WithPluginConfDir can be used to configure the // cni configuration directory. -func WithPluginConfDir(dir string) ConfigOption { +func WithPluginConfDir(dir string) CNIOpt { return func(c *libcni) error { c.pluginConfDir = dir return nil @@ -57,23 +57,17 @@ func WithPluginConfDir(dir string) ConfigOption { // WithMinNetworkCount can be used to configure the // minimum networks to be configured and initalized // for the status to report success. By default its 1. -func WithMinNetworkCount(count int) ConfigOption { +func WithMinNetworkCount(count int) CNIOpt { return func(c *libcni) error { c.networkCount = count return nil } } -// LoadOption can be used with Load API -// to load network configuration from different -// sources. -type LoadOption func(c *libcni) error - // WithLoNetwork can be used to load the loopback // network config. -func WithLoNetwork() LoadOption { - return func(c *libcni) error { - loConfig, _ := cnilibrary.ConfListFromBytes([]byte(`{ +func WithLoNetwork(c *libcni) error { + loConfig, _ := cnilibrary.ConfListFromBytes([]byte(`{ "cniVersion": "0.3.1", "name": "cni-loopback", "plugins": [{ @@ -81,20 +75,17 @@ func WithLoNetwork() LoadOption { }] }`)) - c.Lock() - defer c.Unlock() - c.networks = append(c.networks,&Network{ - cni: c.cniConfig, - config: loConfig, - ifName: "lo", - }) - return nil - } + c.networks = append(c.networks, &Network{ + cni: c.cniConfig, + config: loConfig, + ifName: "lo", + }) + return nil } // WithConf can be used to load config directly // from byte. -func WithConf(bytes []byte) LoadOption { +func WithConf(bytes []byte) CNIOpt { return func(c *libcni) error { conf, err := cnilibrary.ConfFromBytes(bytes) if err != nil { @@ -104,8 +95,6 @@ func WithConf(bytes []byte) LoadOption { if err != nil { return err } - c.Lock() - defer c.Unlock() c.networks = append(c.networks, &Network{ cni: c.cniConfig, config: confList, @@ -118,7 +107,7 @@ func WithConf(bytes []byte) LoadOption { // WithConfFile can be used to load network config // from an .conf file. Supported with absolute fileName // with path only. -func WithConfFile(fileName string) LoadOption { +func WithConfFile(fileName string) CNIOpt { return func(c *libcni) error { conf, err := cnilibrary.ConfFromFile(fileName) if err != nil { @@ -129,8 +118,6 @@ func WithConfFile(fileName string) LoadOption { if err != nil { return err } - c.Lock() - defer c.Unlock() c.networks = append(c.networks, &Network{ cni: c.cniConfig, config: confList, @@ -143,84 +130,101 @@ func WithConfFile(fileName string) LoadOption { // WithConfListFile can be used to load network config // from an .conflist file. Supported with absolute fileName // with path only. -func WithConfListFile(fileName string) LoadOption { +func WithConfListFile(fileName string) CNIOpt { return func(c *libcni) error { confList, err := cnilibrary.ConfListFromFile(fileName) if err != nil { return err } - c.Lock() - defer c.Unlock() - c.networks = append(c.networks,&Network{ + i := len(c.networks) + c.networks = append(c.networks, &Network{ cni: c.cniConfig, config: confList, - ifName: getIfName(c.prefix, 0), + ifName: getIfName(c.prefix, i), }) return nil } } -// WithDefaultConf can be used to detect network config +// WithDefaultConf can be used to detect the default network +// config file from the configured cni config directory and load +// it. +// Since the CNI spec does not specify a way to detect default networks, +// the convention chosen is - the first network configuration in the sorted +// list of network conf files as the default network. +func WithDefaultConf(c *libcni) error { + return loadFromConfDir(c, 1) +} + +// WithAllConf can be used to detect all network config // files from the configured cni config directory and load // them. -func WithDefaultConf() LoadOption { - return func(c *libcni) error { - files, err := cnilibrary.ConfFiles(c.pluginConfDir, []string{".conf", ".conflist", ".json"}) - switch { - case err != nil: - return errors.Wrapf(ErrRead, "failed to read config file: %v", err) - case len(files) == 0: - return errors.Wrapf(ErrCNINotInitialized, "no network config found in %s", c.pluginConfDir) - } +func WithAllConf(c *libcni) error { + return loadFromConfDir(c, 0) +} - // files contains the network config files associated with cni network. - // Use lexicographical way as a defined order for network config files. - sort.Strings(files) - // Since the CNI spec does not specify a way to detect default networks, - // the convention chosen is - the first network configuration in the sorted - // list of network conf files as the default network and choose the default - // interface provided during init as the network interface for this default - // network. For every other network use a generated interface id. - i := 0 - c.Lock() - defer c.Unlock() - for _, confFile := range files { - var confList *cnilibrary.NetworkConfigList - if strings.HasSuffix(confFile, ".conflist") { - confList, err = cnilibrary.ConfListFromFile(confFile) - if err != nil { - return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config list file %s: %v", confFile, err) - } - } else { - conf, err := cnilibrary.ConfFromFile(confFile) - if err != nil { - return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config file %s: %v", confFile, err) - } - // Ensure the config has a "type" so we know what plugin to run. - // Also catches the case where somebody put a conflist into a conf file. - if conf.Network.Type == "" { - return errors.Wrapf(ErrInvalidConfig, "network type not found in %s", confFile) - } +// loadFromConfDir detects network config files from the +// configured cni config directory and load them. max is +// the maximum network config to load (max i<= 0 means no limit). +func loadFromConfDir(c *libcni, max int) error { + files, err := cnilibrary.ConfFiles(c.pluginConfDir, []string{".conf", ".conflist", ".json"}) + switch { + case err != nil: + return errors.Wrapf(ErrRead, "failed to read config file: %v", err) + case len(files) == 0: + return errors.Wrapf(ErrCNINotInitialized, "no network config found in %s", c.pluginConfDir) + } - confList, err = cnilibrary.ConfListFromConf(conf) - if err != nil { - return errors.Wrapf(ErrInvalidConfig, "failed to convert CNI config file %s to list: %v", confFile, err) - } + // files contains the network config files associated with cni network. + // Use lexicographical way as a defined order for network config files. + sort.Strings(files) + // Since the CNI spec does not specify a way to detect default networks, + // the convention chosen is - the first network configuration in the sorted + // list of network conf files as the default network and choose the default + // interface provided during init as the network interface for this default + // network. For every other network use a generated interface id. + i := 0 + var networks []*Network + for _, confFile := range files { + var confList *cnilibrary.NetworkConfigList + if strings.HasSuffix(confFile, ".conflist") { + confList, err = cnilibrary.ConfListFromFile(confFile) + if err != nil { + return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config list file %s: %v", confFile, err) + } + } else { + conf, err := cnilibrary.ConfFromFile(confFile) + if err != nil { + return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config file %s: %v", confFile, err) + } + // Ensure the config has a "type" so we know what plugin to run. + // Also catches the case where somebody put a conflist into a conf file. + if conf.Network.Type == "" { + return errors.Wrapf(ErrInvalidConfig, "network type not found in %s", confFile) } - if len(confList.Plugins) == 0 { - return errors.Wrapf(ErrInvalidConfig, "CNI config list %s has no networks, skipping", confFile) + confList, err = cnilibrary.ConfListFromConf(conf) + if err != nil { + return errors.Wrapf(ErrInvalidConfig, "failed to convert CNI config file %s to list: %v", confFile, err) } - c.networks = append(c.networks, &Network{ - cni: c.cniConfig, - config: confList, - ifName: getIfName(c.prefix, i), - }) - i++ } - if len(c.networks) == 0 { - return errors.Wrapf(ErrCNINotInitialized, "no valid networks found in %s", c.pluginDirs) + if len(confList.Plugins) == 0 { + return errors.Wrapf(ErrInvalidConfig, "CNI config list %s has no networks, skipping", confFile) + + } + networks = append(networks, &Network{ + cni: c.cniConfig, + config: confList, + ifName: getIfName(c.prefix, i), + }) + i++ + if i == max { + break } - return nil + } + if len(networks) == 0 { + return errors.Wrapf(ErrCNINotInitialized, "no valid networks found in %s", c.pluginDirs) } + c.networks = append(c.networks, networks...) + return nil }