-// Copyright 2015 CoreOS, Inc.
+// Copyright 2015 CNI authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
if netdir == "" {
netdir = DefaultNetDir
}
- netconf, err := libcni.LoadConf(netdir, os.Args[2])
+ netconf, err := libcni.LoadConfList(netdir, os.Args[2])
if err != nil {
exit(err)
}
switch os.Args[1] {
case CmdAdd:
- _, err := cninet.AddNetwork(netconf, rt)
+ result, err := cninet.AddNetworkList(netconf, rt)
+ if result != nil {
+ _ = result.Print()
+ }
exit(err)
case CmdDel:
- exit(cninet.DelNetwork(netconf, rt))
+ exit(cninet.DelNetworkList(netconf, rt))
}
}
import (
"encoding/json"
+ "errors"
"fmt"
"io/ioutil"
"os"
"sort"
)
+type NotFoundError struct {
+ Dir string
+ Name string
+}
+
+func (e NotFoundError) Error() string {
+ return fmt.Sprintf(`no net configuration with name "%s" in %s`, e.Name, e.Dir)
+}
+
+var NoConfigsFoundError = errors.New("no net configurations found")
+
func ConfFromBytes(bytes []byte) (*NetworkConfig, error) {
conf := &NetworkConfig{Bytes: bytes}
if err := json.Unmarshal(bytes, &conf.Network); err != nil {
case err != nil:
return nil, err
case len(files) == 0:
- return nil, fmt.Errorf("no net configurations found")
+ return nil, NoConfigsFoundError
}
sort.Strings(files)
return conf, nil
}
}
- return nil, fmt.Errorf(`no net configuration with name "%s" in %s`, name, dir)
+ return nil, NotFoundError{dir, name}
}
func LoadConfList(dir, name string) (*NetworkConfigList, error) {
files, err := ConfFiles(dir, []string{".conflist"})
- switch {
- case err != nil:
+ if err != nil {
return nil, err
- case len(files) == 0:
- return nil, fmt.Errorf("no net configuration lists found")
}
sort.Strings(files)
return conf, nil
}
}
- return nil, fmt.Errorf(`no net configuration list with name "%s" in %s`, name, dir)
+
+ // Try and load a network configuration file (instead of list)
+ // from the same name, then upconvert.
+ singleConf, err := LoadConf(dir, name)
+ if err != nil {
+ // A little extra logic so the error makes sense
+ switch {
+ // neither configlists nor config files found
+ case len(files) == 0 && err == NoConfigsFoundError:
+ return nil, err
+ // config lists found but no config files found
+ case len(files) != 0 && err == NoConfigsFoundError:
+ return nil, NotFoundError{dir, name}
+ default: // either not found or parse error
+ return nil, err
+ }
+ }
+ return ConfListFromConf(singleConf)
}
func InjectConf(original *NetworkConfig, key string, newValue interface{}) (*NetworkConfig, error) {
return ConfFromBytes(newBytes)
}
+
+// ConfListFromConf "upconverts" a network config in to a NetworkConfigList,
+// with the single network as the only entry in the list.
+func ConfListFromConf(original *NetworkConfig) (*NetworkConfigList, error) {
+ // Re-deserialize the config's json, then make a raw map configlist.
+ // This may seem a bit strange, but it's to make the Bytes fields
+ // actually make sense. Otherwise, the generated json is littered with
+ // golang default values.
+
+ rawConfig := make(map[string]interface{})
+ if err := json.Unmarshal(original.Bytes, &rawConfig); err != nil {
+ return nil, err
+ }
+
+ rawConfigList := map[string]interface{}{
+ "name": original.Network.Name,
+ "cniVersion": original.Network.CNIVersion,
+ "plugins": []interface{}{rawConfig},
+ }
+
+ b, err := json.Marshal(rawConfigList)
+ if err != nil {
+ return nil, err
+ }
+ return ConfListFromBytes(b)
+}
}))
})
+ Context("when there is a config file with the same name as the list", func() {
+ BeforeEach(func() {
+ configFile := []byte(`{
+ "name": "some-list",
+ "cniVersion": "0.2.0",
+ "type": "bridge"
+ }`)
+ Expect(ioutil.WriteFile(filepath.Join(configDir, "49-whatever.conf"), configFile, 0600)).To(Succeed())
+ })
+
+ It("Loads the config list first", func() {
+ netConfigList, err := libcni.LoadConfList(configDir, "some-list")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(len(netConfigList.Plugins)).To(Equal(3))
+ })
+
+ It("falls back to the config file", func() {
+ Expect(os.Remove(filepath.Join(configDir, "50-whatever.conflist"))).To(Succeed())
+
+ netConfigList, err := libcni.LoadConfList(configDir, "some-list")
+ Expect(err).NotTo(HaveOccurred())
+ Expect(len(netConfigList.Plugins)).To(Equal(1))
+ Expect(netConfigList.Plugins[0].Network.Type).To(Equal("bridge"))
+ })
+ })
+
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"))
+ Expect(err).To(MatchError("no net configurations 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`)))
+ Expect(err).To(MatchError(libcni.NotFoundError{configDir, "some-other-plugin"}))
})
})
It("will not find the config", func() {
_, err := libcni.LoadConfList(configDir, "deep")
- Expect(err).To(MatchError(HavePrefix("no net configuration list with name")))
+ Expect(err).To(MatchError(HavePrefix("no net configuration with name")))
})
})
})
})
})
})
+
+var _ = Describe("ConfListFromConf", func() {
+ var testNetConfig *libcni.NetworkConfig
+
+ BeforeEach(func() {
+ pb := []byte(`{"name":"some-plugin","cniVersion":"0.3.0" }`)
+ tc, err := libcni.ConfFromBytes(pb)
+ Expect(err).NotTo(HaveOccurred())
+ testNetConfig = tc
+ })
+
+ It("correctly upconverts a NetworkConfig to a NetworkConfigList", func() {
+ ncl, err := libcni.ConfListFromConf(testNetConfig)
+ Expect(err).NotTo(HaveOccurred())
+ bytes := ncl.Bytes
+
+ // null out the json - we don't care about the exact marshalling
+ ncl.Bytes = nil
+ ncl.Plugins[0].Bytes = nil
+ testNetConfig.Bytes = nil
+
+ Expect(ncl).To(Equal(&libcni.NetworkConfigList{
+ Name: "some-plugin",
+ CNIVersion: "0.3.0",
+ Plugins: []*libcni.NetworkConfig{testNetConfig},
+ }))
+
+ //Test that the json unmarshals to the same data
+ ncl2, err := libcni.ConfListFromBytes(bytes)
+ Expect(err).NotTo(HaveOccurred())
+ ncl2.Bytes = nil
+ ncl2.Plugins[0].Bytes = nil
+
+ Expect(ncl2).To(Equal(ncl))
+ })
+
+})