package libcni_test
import (
+ "encoding/json"
+ "fmt"
"io/ioutil"
"net"
"path/filepath"
. "github.com/onsi/gomega"
)
-var _ = Describe("Invoking the plugin", func() {
- var (
- debugFilePath string
- debug *noop_debug.Debug
- cniBinPath string
- pluginConfig string
- cniConfig libcni.CNIConfig
- netConfig *libcni.NetworkConfig
- runtimeConfig *libcni.RuntimeConf
-
- expectedCmdArgs skel.CmdArgs
- )
-
- BeforeEach(func() {
- debugFile, err := ioutil.TempFile("", "cni_debug")
- Expect(err).NotTo(HaveOccurred())
- Expect(debugFile.Close()).To(Succeed())
- debugFilePath = debugFile.Name()
-
- debug = &noop_debug.Debug{
- ReportResult: `{ "ip4": { "ip": "10.1.2.3/24" }, "dns": {} }`,
- }
- Expect(debug.WriteDebug(debugFilePath)).To(Succeed())
-
- cniBinPath = filepath.Dir(pluginPaths["noop"])
- pluginConfig = `{ "type": "noop", "some-key": "some-value", "cniVersion": "0.2.0" }`
- cniConfig = libcni.CNIConfig{Path: []string{cniBinPath}}
- netConfig = &libcni.NetworkConfig{
- Network: &types.NetConf{
- Type: "noop",
- },
- Bytes: []byte(pluginConfig),
- }
- runtimeConfig = &libcni.RuntimeConf{
- ContainerID: "some-container-id",
- NetNS: "/some/netns/path",
- IfName: "some-eth0",
- Args: [][2]string{[2]string{"DEBUG", debugFilePath}},
- }
-
- expectedCmdArgs = skel.CmdArgs{
- ContainerID: "some-container-id",
- Netns: "/some/netns/path",
- IfName: "some-eth0",
- Args: "DEBUG=" + debugFilePath,
- Path: cniBinPath,
- StdinData: []byte(pluginConfig),
- }
- })
+type pluginInfo struct {
+ debugFilePath string
+ debug *noop_debug.Debug
+ config string
+}
- Describe("AddNetwork", func() {
- It("executes the plugin with command ADD", func() {
- result, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
- Expect(err).NotTo(HaveOccurred())
+func addNameToConfig(name, config string) ([]byte, error) {
+ obj := make(map[string]interface{})
+ err := json.Unmarshal([]byte(config), &obj)
+ if err != nil {
+ return nil, fmt.Errorf("unmarshal existing network bytes: %s", err)
+ }
+ obj["name"] = name
+ return json.Marshal(obj)
+}
- Expect(result).To(Equal(&types.Result{
- IP4: &types.IPConfig{
- IP: net.IPNet{
- IP: net.ParseIP("10.1.2.3"),
- Mask: net.IPv4Mask(255, 255, 255, 0),
- },
+func newPluginInfo(configKey, configValue, prevResult string, injectDebugFilePath bool, result string) pluginInfo {
+ debugFile, err := ioutil.TempFile("", "cni_debug")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(debugFile.Close()).To(Succeed())
+ debugFilePath := debugFile.Name()
+
+ debug := &noop_debug.Debug{
+ ReportResult: result,
+ }
+ Expect(debug.WriteDebug(debugFilePath)).To(Succeed())
+
+ config := fmt.Sprintf(`{"type": "noop", "%s": "%s", "cniVersion": "0.2.0"`, configKey, configValue)
+ if prevResult != "" {
+ config += fmt.Sprintf(`, "prevResult": %s`, prevResult)
+ }
+ if injectDebugFilePath {
+ config += fmt.Sprintf(`, "debugFile": "%s"`, debugFilePath)
+ }
+ config += "}"
+
+ return pluginInfo{
+ debugFilePath: debugFilePath,
+ debug: debug,
+ config: config,
+ }
+}
+
+var _ = Describe("Invoking plugins", func() {
+ Describe("Invoking a single plugin", func() {
+ var (
+ plugin pluginInfo
+ cniBinPath string
+ cniConfig libcni.CNIConfig
+ netConfig *libcni.NetworkConfig
+ runtimeConfig *libcni.RuntimeConf
+
+ expectedCmdArgs skel.CmdArgs
+ )
+
+ BeforeEach(func() {
+ pluginResult := `{ "ip4": { "ip": "10.1.2.3/24" }, "dns": {} }`
+ plugin = newPluginInfo("some-key", "some-value", "", false, pluginResult)
+
+ cniBinPath = filepath.Dir(pluginPaths["noop"])
+ cniConfig = libcni.CNIConfig{Path: []string{cniBinPath}}
+ netConfig = &libcni.NetworkConfig{
+ Network: &types.NetConf{
+ Type: "noop",
},
- }))
+ Bytes: []byte(plugin.config),
+ }
+ runtimeConfig = &libcni.RuntimeConf{
+ ContainerID: "some-container-id",
+ NetNS: "/some/netns/path",
+ IfName: "some-eth0",
+ Args: [][2]string{{"DEBUG", plugin.debugFilePath}},
+ }
- debug, err := noop_debug.ReadDebug(debugFilePath)
- Expect(err).NotTo(HaveOccurred())
- Expect(debug.Command).To(Equal("ADD"))
- Expect(debug.CmdArgs).To(Equal(expectedCmdArgs))
+ expectedCmdArgs = skel.CmdArgs{
+ ContainerID: "some-container-id",
+ Netns: "/some/netns/path",
+ IfName: "some-eth0",
+ Args: "DEBUG=" + plugin.debugFilePath,
+ Path: cniBinPath,
+ StdinData: []byte(plugin.config),
+ }
})
- Context("when finding the plugin fails", func() {
- BeforeEach(func() {
- netConfig.Network.Type = "does-not-exist"
- })
+ Describe("AddNetwork", func() {
+ It("executes the plugin with command ADD", func() {
+ result, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(result).To(Equal(&types.Result{
+ IP4: &types.IPConfig{
+ IP: net.IPNet{
+ IP: net.ParseIP("10.1.2.3"),
+ Mask: net.IPv4Mask(255, 255, 255, 0),
+ },
+ },
+ }))
- It("returns the error", func() {
- _, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
- Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ debug, err := noop_debug.ReadDebug(plugin.debugFilePath)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(debug.Command).To(Equal("ADD"))
+ Expect(debug.CmdArgs).To(Equal(expectedCmdArgs))
})
- })
- Context("when the plugin errors", func() {
- BeforeEach(func() {
- debug.ReportError = "plugin error: banana"
- Expect(debug.WriteDebug(debugFilePath)).To(Succeed())
+ Context("when finding the plugin fails", func() {
+ BeforeEach(func() {
+ netConfig.Network.Type = "does-not-exist"
+ })
+
+ It("returns the error", func() {
+ _, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
+ Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ })
})
- It("unmarshals and returns the error", func() {
- result, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
- Expect(result).To(BeNil())
- Expect(err).To(MatchError("plugin error: banana"))
+
+ Context("when the plugin errors", func() {
+ BeforeEach(func() {
+ plugin.debug.ReportError = "plugin error: banana"
+ Expect(plugin.debug.WriteDebug(plugin.debugFilePath)).To(Succeed())
+ })
+ It("unmarshals and returns the error", func() {
+ result, err := cniConfig.AddNetwork(netConfig, runtimeConfig)
+ Expect(result).To(BeNil())
+ Expect(err).To(MatchError("plugin error: banana"))
+ })
})
})
- })
- Describe("DelNetwork", func() {
- It("executes the plugin with command DEL", func() {
- err := cniConfig.DelNetwork(netConfig, runtimeConfig)
- Expect(err).NotTo(HaveOccurred())
+ Describe("DelNetwork", func() {
+ It("executes the plugin with command DEL", func() {
+ err := cniConfig.DelNetwork(netConfig, runtimeConfig)
+ Expect(err).NotTo(HaveOccurred())
- debug, err := noop_debug.ReadDebug(debugFilePath)
- Expect(err).NotTo(HaveOccurred())
- Expect(debug.Command).To(Equal("DEL"))
- Expect(debug.CmdArgs).To(Equal(expectedCmdArgs))
- })
+ debug, err := noop_debug.ReadDebug(plugin.debugFilePath)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(debug.Command).To(Equal("DEL"))
+ Expect(debug.CmdArgs).To(Equal(expectedCmdArgs))
+ })
- Context("when finding the plugin fails", func() {
- BeforeEach(func() {
- netConfig.Network.Type = "does-not-exist"
+ Context("when finding the plugin fails", func() {
+ BeforeEach(func() {
+ netConfig.Network.Type = "does-not-exist"
+ })
+
+ It("returns the error", func() {
+ err := cniConfig.DelNetwork(netConfig, runtimeConfig)
+ Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ })
})
- It("returns the error", func() {
- err := cniConfig.DelNetwork(netConfig, runtimeConfig)
- Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ Context("when the plugin errors", func() {
+ BeforeEach(func() {
+ plugin.debug.ReportError = "plugin error: banana"
+ Expect(plugin.debug.WriteDebug(plugin.debugFilePath)).To(Succeed())
+ })
+ It("unmarshals and returns the error", func() {
+ err := cniConfig.DelNetwork(netConfig, runtimeConfig)
+ Expect(err).To(MatchError("plugin error: banana"))
+ })
})
})
- Context("when the plugin errors", func() {
- BeforeEach(func() {
- debug.ReportError = "plugin error: banana"
- Expect(debug.WriteDebug(debugFilePath)).To(Succeed())
+ Describe("GetVersionInfo", func() {
+ It("executes the plugin with the command VERSION", func() {
+ versionInfo, err := cniConfig.GetVersionInfo("noop")
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(versionInfo).NotTo(BeNil())
+ Expect(versionInfo.SupportedVersions()).To(Equal([]string{
+ "0.-42.0", "0.1.0", "0.2.0",
+ }))
})
- It("unmarshals and returns the error", func() {
- err := cniConfig.DelNetwork(netConfig, runtimeConfig)
- Expect(err).To(MatchError("plugin error: banana"))
+
+ Context("when finding the plugin fails", func() {
+ It("returns the error", func() {
+ _, err := cniConfig.GetVersionInfo("does-not-exist")
+ Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ })
})
})
})
- Describe("GetVersionInfo", func() {
- It("executes the plugin with the command VERSION", func() {
- versionInfo, err := cniConfig.GetVersionInfo("noop")
+ Describe("Invoking a plugin list", func() {
+ var (
+ plugins []pluginInfo
+ cniBinPath string
+ cniConfig libcni.CNIConfig
+ netConfigList *libcni.NetworkConfigList
+ runtimeConfig *libcni.RuntimeConf
+
+ expectedCmdArgs skel.CmdArgs
+ )
+
+ BeforeEach(func() {
+ plugins = make([]pluginInfo, 3, 3)
+ plugins[0] = newPluginInfo("some-key", "some-value", "", true, `{"dns":{},"ip4":{"ip": "10.1.2.3/24"}}`)
+ plugins[1] = newPluginInfo("some-key", "some-other-value", `{"dns":{},"ip4":{"ip": "10.1.2.3/24"}}`, true, "PASSTHROUGH")
+ plugins[2] = newPluginInfo("some-key", "yet-another-value", `{"dns":{},"ip4":{"ip": "10.1.2.3/24"}}`, true, "INJECT-DNS")
+
+ configList := []byte(fmt.Sprintf(`{
+ "name": "some-list",
+ "cniVersion": "0.2.0",
+ "plugins": [
+ %s,
+ %s,
+ %s
+ ]
+}`, plugins[0].config, plugins[1].config, plugins[2].config))
+
+ var err error
+ netConfigList, err = libcni.ConfListFromBytes(configList)
Expect(err).NotTo(HaveOccurred())
- Expect(versionInfo).NotTo(BeNil())
- Expect(versionInfo.SupportedVersions()).To(Equal([]string{
- "0.-42.0", "0.1.0", "0.2.0",
- }))
+ cniBinPath = filepath.Dir(pluginPaths["noop"])
+ cniConfig = libcni.CNIConfig{Path: []string{cniBinPath}}
+ runtimeConfig = &libcni.RuntimeConf{
+ ContainerID: "some-container-id",
+ NetNS: "/some/netns/path",
+ IfName: "some-eth0",
+ Args: [][2]string{{"FOO", "BAR"}},
+ }
+
+ expectedCmdArgs = skel.CmdArgs{
+ ContainerID: "some-container-id",
+ Netns: "/some/netns/path",
+ IfName: "some-eth0",
+ Args: "FOO=BAR",
+ Path: cniBinPath,
+ }
+ })
+
+ Describe("AddNetworkList", func() {
+ It("executes all plugins with command ADD and returns an intermediate result", func() {
+ result, err := cniConfig.AddNetworkList(netConfigList, runtimeConfig)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(result).To(Equal(&types.Result{
+ // IP4 added by first plugin
+ IP4: &types.IPConfig{
+ IP: net.IPNet{
+ IP: net.ParseIP("10.1.2.3"),
+ Mask: net.IPv4Mask(255, 255, 255, 0),
+ },
+ },
+ // DNS injected by last plugin
+ DNS: types.DNS{
+ Nameservers: []string{"1.2.3.4"},
+ },
+ }))
+
+ for i := 0; i < len(plugins); i++ {
+ debug, err := noop_debug.ReadDebug(plugins[i].debugFilePath)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(debug.Command).To(Equal("ADD"))
+ newConfig, err := addNameToConfig("some-list", plugins[i].config)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Must explicitly match JSON due to dict element ordering
+ debugJSON := debug.CmdArgs.StdinData
+ debug.CmdArgs.StdinData = nil
+ Expect(debugJSON).To(MatchJSON(newConfig))
+ Expect(debug.CmdArgs).To(Equal(expectedCmdArgs))
+ }
+ })
+
+ Context("when finding the plugin fails", func() {
+ BeforeEach(func() {
+ netConfigList.Plugins[1].Network.Type = "does-not-exist"
+ })
+
+ It("returns the error", func() {
+ _, err := cniConfig.AddNetworkList(netConfigList, runtimeConfig)
+ Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ })
+ })
+
+ Context("when the second plugin errors", func() {
+ BeforeEach(func() {
+ plugins[1].debug.ReportError = "plugin error: banana"
+ Expect(plugins[1].debug.WriteDebug(plugins[1].debugFilePath)).To(Succeed())
+ })
+ It("unmarshals and returns the error", func() {
+ result, err := cniConfig.AddNetworkList(netConfigList, runtimeConfig)
+ Expect(result).To(BeNil())
+ Expect(err).To(MatchError("plugin error: banana"))
+ })
+ })
})
- Context("when finding the plugin fails", func() {
- It("returns the error", func() {
- _, err := cniConfig.GetVersionInfo("does-not-exist")
- Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ Describe("DelNetworkList", func() {
+ It("executes all the plugins in reverse order with command DEL", func() {
+ err := cniConfig.DelNetworkList(netConfigList, runtimeConfig)
+ Expect(err).NotTo(HaveOccurred())
+
+ for i := 0; i < len(plugins); i++ {
+ debug, err := noop_debug.ReadDebug(plugins[i].debugFilePath)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(debug.Command).To(Equal("DEL"))
+ newConfig, err := addNameToConfig("some-list", plugins[i].config)
+ Expect(err).NotTo(HaveOccurred())
+
+ // Must explicitly match JSON due to dict element ordering
+ debugJSON := debug.CmdArgs.StdinData
+ debug.CmdArgs.StdinData = nil
+ Expect(debugJSON).To(MatchJSON(newConfig))
+ Expect(debug.CmdArgs).To(Equal(expectedCmdArgs))
+ }
+ })
+
+ Context("when finding the plugin fails", func() {
+ BeforeEach(func() {
+ netConfigList.Plugins[1].Network.Type = "does-not-exist"
+ })
+
+ It("returns the error", func() {
+ err := cniConfig.DelNetworkList(netConfigList, runtimeConfig)
+ Expect(err).To(MatchError(ContainSubstring(`failed to find plugin "does-not-exist"`)))
+ })
+ })
+
+ Context("when the plugin errors", func() {
+ BeforeEach(func() {
+ plugins[1].debug.ReportError = "plugin error: banana"
+ Expect(plugins[1].debug.WriteDebug(plugins[1].debugFilePath)).To(Succeed())
+ })
+ It("unmarshals and returns the error", func() {
+ err := cniConfig.DelNetworkList(netConfigList, runtimeConfig)
+ Expect(err).To(MatchError("plugin error: banana"))
+ })
})
})
+
})
})
return ConfFromBytes(bytes)
}
-func ConfFiles(dir string) ([]string, error) {
+func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
+ rawList := make(map[string]interface{})
+ if err := json.Unmarshal(bytes, &rawList); err != nil {
+ return nil, fmt.Errorf("error parsing configuration list: %s", err)
+ }
+
+ rawName, ok := rawList["name"]
+ if !ok {
+ return nil, fmt.Errorf("error parsing configuration list: no name")
+ }
+ name, ok := rawName.(string)
+ if !ok {
+ return nil, fmt.Errorf("error parsing configuration list: invalid name type %T", rawName)
+ }
+
+ var cniVersion string
+ rawVersion, ok := rawList["cniVersion"]
+ if ok {
+ cniVersion, ok = rawVersion.(string)
+ if !ok {
+ return nil, fmt.Errorf("error parsing configuration list: invalid cniVersion type %T", rawVersion)
+ }
+ }
+
+ list := &NetworkConfigList{
+ Name: name,
+ CNIVersion: cniVersion,
+ Bytes: bytes,
+ }
+
+ var plugins []interface{}
+ plug, ok := rawList["plugins"]
+ if !ok {
+ return nil, fmt.Errorf("error parsing configuration list: no 'plugins' key")
+ }
+ plugins, ok = plug.([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("error parsing configuration list: invalid 'plugins' type %T", plug)
+ }
+ if len(plugins) == 0 {
+ return nil, fmt.Errorf("error parsing configuration list: no plugins in list")
+ }
+
+ for i, conf := range plugins {
+ newBytes, err := json.Marshal(conf)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal plugin config %d: %v", i, err)
+ }
+ netConf, err := ConfFromBytes(newBytes)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to parse plugin config %d: %v", i, err)
+ }
+ list.Plugins = append(list.Plugins, netConf)
+ }
+
+ return list, nil
+}
+
+func ConfListFromFile(filename string) (*NetworkConfigList, error) {
+ bytes, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, fmt.Errorf("error reading %s: %s", filename, err)
+ }
+ return ConfListFromBytes(bytes)
+}
+
+func ConfFiles(dir string, extensions []string) ([]string, error) {
// In part, adapted from rkt/networking/podenv.go#listFiles
files, err := ioutil.ReadDir(dir)
switch {
continue
}
fileExt := filepath.Ext(f.Name())
- if fileExt == ".conf" || fileExt == ".json" {
- confFiles = append(confFiles, filepath.Join(dir, f.Name()))
+ for _, ext := range extensions {
+ if fileExt == ext {
+ confFiles = append(confFiles, filepath.Join(dir, f.Name()))
+ }
}
}
return confFiles, nil
}
func LoadConf(dir, name string) (*NetworkConfig, error) {
- files, err := ConfFiles(dir)
+ files, err := ConfFiles(dir, []string{".conf", ".json"})
switch {
case err != nil:
return nil, err
return nil, fmt.Errorf(`no net configuration with name "%s" in %s`, name, dir)
}
+func LoadConfList(dir, name string) (*NetworkConfigList, error) {
+ files, err := ConfFiles(dir, []string{".conflist"})
+ switch {
+ case err != nil:
+ return nil, err
+ case len(files) == 0:
+ return nil, fmt.Errorf("no net configuration lists found")
+ }
+ sort.Strings(files)
+
+ for _, confFile := range files {
+ conf, err := ConfListFromFile(confFile)
+ if err != nil {
+ return nil, err
+ }
+ if conf.Name == name {
+ return conf, nil
+ }
+ }
+ return nil, fmt.Errorf(`no net configuration list with name "%s" in %s`, name, dir)
+}
+
func InjectConf(original *NetworkConfig, key string, newValue interface{}) (*NetworkConfig, error) {
config := make(map[string]interface{})
err := json.Unmarshal(original.Bytes, &config)
)
var _ = Describe("Loading configuration from disk", func() {
- var (
- configDir string
- pluginConfig []byte
- testNetConfig *libcni.NetworkConfig
- )
-
- BeforeEach(func() {
- var err error
- configDir, err = ioutil.TempDir("", "plugin-conf")
- Expect(err).NotTo(HaveOccurred())
-
- pluginConfig = []byte(`{ "name": "some-plugin", "some-key": "some-value" }`)
- Expect(ioutil.WriteFile(filepath.Join(configDir, "50-whatever.conf"), pluginConfig, 0600)).To(Succeed())
-
- testNetConfig = &libcni.NetworkConfig{Network: &types.NetConf{Name: "some-plugin"},
- Bytes: []byte(`{ "name": "some-plugin" }`)}
- })
+ Describe("LoadConf", func() {
+ var (
+ configDir string
+ pluginConfig []byte
+ )
+
+ BeforeEach(func() {
+ var err error
+ configDir, err = ioutil.TempDir("", "plugin-conf")
+ Expect(err).NotTo(HaveOccurred())
- AfterEach(func() {
- Expect(os.RemoveAll(configDir)).To(Succeed())
- })
+ pluginConfig = []byte(`{ "name": "some-plugin", "some-key": "some-value" }`)
+ Expect(ioutil.WriteFile(filepath.Join(configDir, "50-whatever.conf"), pluginConfig, 0600)).To(Succeed())
+ })
+
+ AfterEach(func() {
+ Expect(os.RemoveAll(configDir)).To(Succeed())
+ })
- Describe("LoadConf", func() {
It("finds the network config file for the plugin of the given type", func() {
netConfig, err := libcni.LoadConf(configDir, "some-plugin")
Expect(err).NotTo(HaveOccurred())
})
})
+ Describe("LoadConfList", func() {
+ var (
+ configDir string
+ configList []byte
+ )
+
+ BeforeEach(func() {
+ var err error
+ configDir, err = ioutil.TempDir("", "plugin-conf")
+ Expect(err).NotTo(HaveOccurred())
+
+ configList = []byte(`{
+ "name": "some-list",
+ "cniVersion": "0.2.0",
+ "plugins": [
+ {
+ "type": "host-local",
+ "subnet": "10.0.0.1/24"
+ },
+ {
+ "type": "bridge",
+ "mtu": 1400
+ },
+ {
+ "type": "port-forwarding",
+ "ports": {"20.0.0.1:8080": "80"}
+ }
+ ]
+}`)
+ Expect(ioutil.WriteFile(filepath.Join(configDir, "50-whatever.conflist"), configList, 0600)).To(Succeed())
+ })
+
+ AfterEach(func() {
+ Expect(os.RemoveAll(configDir)).To(Succeed())
+ })
+
+ It("finds the network config file for the plugin of the given type", func() {
+ netConfigList, err := libcni.LoadConfList(configDir, "some-list")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(netConfigList).To(Equal(&libcni.NetworkConfigList{
+ Name: "some-list",
+ CNIVersion: "0.2.0",
+ Plugins: []*libcni.NetworkConfig{
+ {
+ Network: &types.NetConf{Type: "host-local"},
+ Bytes: []byte(`{"subnet":"10.0.0.1/24","type":"host-local"}`),
+ },
+ {
+ Network: &types.NetConf{Type: "bridge"},
+ Bytes: []byte(`{"mtu":1400,"type":"bridge"}`),
+ },
+ {
+ Network: &types.NetConf{Type: "port-forwarding"},
+ Bytes: []byte(`{"ports":{"20.0.0.1:8080":"80"},"type":"port-forwarding"}`),
+ },
+ },
+ Bytes: configList,
+ }))
+ })
+
+ Context("when the config directory does not exist", func() {
+ BeforeEach(func() {
+ Expect(os.RemoveAll(configDir)).To(Succeed())
+ })
+
+ It("returns a useful error", func() {
+ _, err := libcni.LoadConfList(configDir, "some-plugin")
+ Expect(err).To(MatchError("no net configuration lists found"))
+ })
+ })
+
+ Context("when there is no config for the desired plugin list", func() {
+ It("returns a useful error", func() {
+ _, err := libcni.LoadConfList(configDir, "some-other-plugin")
+ Expect(err).To(MatchError(ContainSubstring(`no net configuration list with name "some-other-plugin" in`)))
+ })
+ })
+
+ Context("when a config file is malformed", func() {
+ BeforeEach(func() {
+ Expect(ioutil.WriteFile(filepath.Join(configDir, "00-bad.conflist"), []byte(`{`), 0600)).To(Succeed())
+ })
+
+ It("returns a useful error", func() {
+ _, err := libcni.LoadConfList(configDir, "some-plugin")
+ Expect(err).To(MatchError(`error parsing configuration list: unexpected end of JSON input`))
+ })
+ })
+
+ Context("when the config is in a nested subdir", func() {
+ BeforeEach(func() {
+ subdir := filepath.Join(configDir, "subdir1", "subdir2")
+ Expect(os.MkdirAll(subdir, 0700)).To(Succeed())
+
+ configList = []byte(`{
+ "name": "deep",
+ "cniVersion": "0.2.0",
+ "plugins": [
+ {
+ "type": "host-local",
+ "subnet": "10.0.0.1/24"
+ },
+ ]
+}`)
+ Expect(ioutil.WriteFile(filepath.Join(subdir, "90-deep.conflist"), configList, 0600)).To(Succeed())
+ })
+
+ It("will not find the config", func() {
+ _, err := libcni.LoadConfList(configDir, "deep")
+ Expect(err).To(MatchError(HavePrefix("no net configuration list with name")))
+ })
+ })
+ })
+
+ Describe("ConfListFromFile", func() {
+ Context("when the file cannot be opened", func() {
+ It("returns a useful error", func() {
+ _, err := libcni.ConfListFromFile("/tmp/nope/not-here")
+ Expect(err).To(MatchError(HavePrefix(`error reading /tmp/nope/not-here: open /tmp/nope/not-here`)))
+ })
+ })
+ })
+
Describe("InjectConf", func() {
+ var testNetConfig *libcni.NetworkConfig
+
+ BeforeEach(func() {
+ testNetConfig = &libcni.NetworkConfig{Network: &types.NetConf{Name: "some-plugin"},
+ Bytes: []byte(`{ "name": "some-plugin" }`)}
+ })
+
Context("when function parameters are incorrect", func() {
It("returns unmarshal error", func() {
conf := &libcni.NetworkConfig{Network: &types.NetConf{Name: "some-plugin"},