skel: Plugins require a cniVersion in the NetConf
This commit is contained in:
parent
56032390fe
commit
fd150a4c97
@ -69,6 +69,7 @@ Start out by creating a netconf file to describe a network:
|
|||||||
$ mkdir -p /etc/cni/net.d
|
$ mkdir -p /etc/cni/net.d
|
||||||
$ cat >/etc/cni/net.d/10-mynet.conf <<EOF
|
$ cat >/etc/cni/net.d/10-mynet.conf <<EOF
|
||||||
{
|
{
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"type": "bridge",
|
"type": "bridge",
|
||||||
"bridge": "cni0",
|
"bridge": "cni0",
|
||||||
@ -85,6 +86,7 @@ $ cat >/etc/cni/net.d/10-mynet.conf <<EOF
|
|||||||
EOF
|
EOF
|
||||||
$ cat >/etc/cni/net.d/99-loopback.conf <<EOF
|
$ cat >/etc/cni/net.d/99-loopback.conf <<EOF
|
||||||
{
|
{
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"type": "loopback"
|
"type": "loopback"
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
@ -53,7 +53,7 @@ var _ = Describe("Invoking the plugin", func() {
|
|||||||
Expect(debug.WriteDebug(debugFilePath)).To(Succeed())
|
Expect(debug.WriteDebug(debugFilePath)).To(Succeed())
|
||||||
|
|
||||||
cniBinPath = filepath.Dir(pathToPlugin)
|
cniBinPath = filepath.Dir(pathToPlugin)
|
||||||
pluginConfig = `{ "type": "noop", "some-key": "some-value" }`
|
pluginConfig = `{ "type": "noop", "some-key": "some-value", "cniVersion": "0.2.0" }`
|
||||||
cniConfig = libcni.CNIConfig{Path: []string{cniBinPath}}
|
cniConfig = libcni.CNIConfig{Path: []string{cniBinPath}}
|
||||||
netConfig = &libcni.NetworkConfig{
|
netConfig = &libcni.NetworkConfig{
|
||||||
Network: &types.NetConf{
|
Network: &types.NetConf{
|
||||||
|
@ -16,6 +16,7 @@ package invoke
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
@ -77,7 +78,8 @@ func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, erro
|
|||||||
IfName: "dummy",
|
IfName: "dummy",
|
||||||
Path: "dummy",
|
Path: "dummy",
|
||||||
}
|
}
|
||||||
stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, nil, args.AsEnv())
|
stdin := []byte(fmt.Sprintf(`{"cniVersion":%q}`, version.Current()))
|
||||||
|
stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, stdin, args.AsEnv())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "unknown CNI_COMMAND: VERSION" {
|
if err.Error() == "unknown CNI_COMMAND: VERSION" {
|
||||||
return version.PluginSupports("0.1.0"), nil
|
return version.PluginSupports("0.1.0"), nil
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package invoke_test
|
package invoke_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/invoke"
|
"github.com/containernetworking/cni/pkg/invoke"
|
||||||
@ -48,7 +49,7 @@ var _ = Describe("Executing a plugin, unit tests", func() {
|
|||||||
VersionDecoder: versionDecoder,
|
VersionDecoder: versionDecoder,
|
||||||
}
|
}
|
||||||
pluginPath = "/some/plugin/path"
|
pluginPath = "/some/plugin/path"
|
||||||
netconf = []byte(`{ "some": "stdin" }`)
|
netconf = []byte(`{ "some": "stdin", "cniVersion": "0.2.0" }`)
|
||||||
cniargs = &fakes.CNIArgs{}
|
cniargs = &fakes.CNIArgs{}
|
||||||
cniargs.AsEnvCall.Returns.Env = []string{"SOME=ENV"}
|
cniargs.AsEnvCall.Returns.Env = []string{"SOME=ENV"}
|
||||||
})
|
})
|
||||||
@ -105,8 +106,9 @@ var _ = Describe("Executing a plugin, unit tests", func() {
|
|||||||
It("execs the plugin with the command VERSION", func() {
|
It("execs the plugin with the command VERSION", func() {
|
||||||
pluginExec.GetVersionInfo(pluginPath)
|
pluginExec.GetVersionInfo(pluginPath)
|
||||||
Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath))
|
Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath))
|
||||||
Expect(rawExec.ExecPluginCall.Received.StdinData).To(BeNil())
|
|
||||||
Expect(rawExec.ExecPluginCall.Received.Environ).To(ContainElement("CNI_COMMAND=VERSION"))
|
Expect(rawExec.ExecPluginCall.Received.Environ).To(ContainElement("CNI_COMMAND=VERSION"))
|
||||||
|
expectedStdin, _ := json.Marshal(map[string]string{"cniVersion": version.Current()})
|
||||||
|
Expect(rawExec.ExecPluginCall.Received.StdinData).To(MatchJSON(expectedStdin))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("decodes and returns the version info", func() {
|
It("decodes and returns the version info", func() {
|
||||||
@ -146,6 +148,5 @@ var _ = Describe("Executing a plugin, unit tests", func() {
|
|||||||
Expect(env).To(ContainElement("CNI_PATH=dummy"))
|
Expect(env).To(ContainElement("CNI_PATH=dummy"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -58,7 +58,7 @@ var _ = Describe("RawExec", func() {
|
|||||||
"CNI_PATH=/some/bin/path",
|
"CNI_PATH=/some/bin/path",
|
||||||
"CNI_IFNAME=some-eth0",
|
"CNI_IFNAME=some-eth0",
|
||||||
}
|
}
|
||||||
stdin = []byte(`{"some":"stdin-json"}`)
|
stdin = []byte(`{"some":"stdin-json", "cniVersion": "0.2.0"}`)
|
||||||
execer = &invoke.RawExec{}
|
execer = &invoke.RawExec{}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package skel
|
package skel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -143,12 +144,28 @@ func createTypedError(f string, args ...interface{}) *types.Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *dispatcher) validateVersion(stdinData []byte) error {
|
||||||
|
var netconf types.NetConf
|
||||||
|
if err := json.Unmarshal(stdinData, &netconf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if netconf.CNIVersion == "" {
|
||||||
|
return fmt.Errorf("missing required config cniVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *dispatcher) pluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) *types.Error {
|
func (t *dispatcher) pluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) *types.Error {
|
||||||
cmd, cmdArgs, err := t.getCmdArgsFromEnv()
|
cmd, cmdArgs, err := t.getCmdArgsFromEnv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return createTypedError(err.Error())
|
return createTypedError(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = t.validateVersion(cmdArgs.StdinData); err != nil {
|
||||||
|
return createTypedError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "ADD":
|
case "ADD":
|
||||||
err = cmdAdd(cmdArgs)
|
err = cmdAdd(cmdArgs)
|
||||||
|
@ -17,7 +17,6 @@ package skel
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
@ -48,7 +47,7 @@ func (c *fakeCmd) Func(args *CmdArgs) error {
|
|||||||
var _ = Describe("dispatching to the correct callback", func() {
|
var _ = Describe("dispatching to the correct callback", func() {
|
||||||
var (
|
var (
|
||||||
environment map[string]string
|
environment map[string]string
|
||||||
stdin io.Reader
|
stdinData string
|
||||||
stdout, stderr *bytes.Buffer
|
stdout, stderr *bytes.Buffer
|
||||||
cmdAdd, cmdDel *fakeCmd
|
cmdAdd, cmdDel *fakeCmd
|
||||||
dispatch *dispatcher
|
dispatch *dispatcher
|
||||||
@ -65,13 +64,14 @@ var _ = Describe("dispatching to the correct callback", func() {
|
|||||||
"CNI_ARGS": "some;extra;args",
|
"CNI_ARGS": "some;extra;args",
|
||||||
"CNI_PATH": "/some/cni/path",
|
"CNI_PATH": "/some/cni/path",
|
||||||
}
|
}
|
||||||
stdin = strings.NewReader(`{ "some": "config" }`)
|
|
||||||
|
stdinData = `{ "some": "config", "cniVersion": "9.8.7" }`
|
||||||
stdout = &bytes.Buffer{}
|
stdout = &bytes.Buffer{}
|
||||||
stderr = &bytes.Buffer{}
|
stderr = &bytes.Buffer{}
|
||||||
versionInfo = version.PluginSupports("9.8.7")
|
versionInfo = version.PluginSupports("9.8.7")
|
||||||
dispatch = &dispatcher{
|
dispatch = &dispatcher{
|
||||||
Getenv: func(key string) string { return environment[key] },
|
Getenv: func(key string) string { return environment[key] },
|
||||||
Stdin: stdin,
|
Stdin: strings.NewReader(stdinData),
|
||||||
Stdout: stdout,
|
Stdout: stdout,
|
||||||
Stderr: stderr,
|
Stderr: stderr,
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ var _ = Describe("dispatching to the correct callback", func() {
|
|||||||
IfName: "eth0",
|
IfName: "eth0",
|
||||||
Args: "some;extra;args",
|
Args: "some;extra;args",
|
||||||
Path: "/some/cni/path",
|
Path: "/some/cni/path",
|
||||||
StdinData: []byte(`{ "some": "config" }`),
|
StdinData: []byte(stdinData),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -144,6 +144,22 @@ var _ = Describe("dispatching to the correct callback", func() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("when the stdin data is missing the required cniVersion config", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
dispatch.Stdin = strings.NewReader(`{ "some": "config" }`)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("immediately returns a useful error", func() {
|
||||||
|
err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
|
||||||
|
Expect(err).To(MatchError("missing required config cniVersion"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("does not call either callback", func() {
|
||||||
|
Expect(cmdAdd.CallCount).To(Equal(0))
|
||||||
|
Expect(cmdDel.CallCount).To(Equal(0))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("when the CNI_COMMAND is DEL", func() {
|
Context("when the CNI_COMMAND is DEL", func() {
|
||||||
|
@ -56,6 +56,7 @@ func PluginSupports(supportedVersions ...string) PluginInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PluginDecoder can decode the response returned by a plugin's VERSION command
|
||||||
type PluginDecoder struct{}
|
type PluginDecoder struct{}
|
||||||
|
|
||||||
func (_ *PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) {
|
func (_ *PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) {
|
||||||
|
@ -51,6 +51,7 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
|
|
||||||
conf := &NetConf{
|
conf := &NetConf{
|
||||||
NetConf: types.NetConf{
|
NetConf: types.NetConf{
|
||||||
|
CNIVersion: "0.2.0",
|
||||||
Name: "testConfig",
|
Name: "testConfig",
|
||||||
Type: "bridge",
|
Type: "bridge",
|
||||||
},
|
},
|
||||||
@ -95,6 +96,7 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
|
|
||||||
conf := &NetConf{
|
conf := &NetConf{
|
||||||
NetConf: types.NetConf{
|
NetConf: types.NetConf{
|
||||||
|
CNIVersion: "0.2.0",
|
||||||
Name: "testConfig",
|
Name: "testConfig",
|
||||||
Type: "bridge",
|
Type: "bridge",
|
||||||
},
|
},
|
||||||
@ -126,12 +128,14 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"type": "bridge",
|
"type": "bridge",
|
||||||
"bridge": "%s",
|
"bridge": "%s",
|
||||||
"isDefaultGateway": true,
|
"isDefaultGateway": true,
|
||||||
"ipMasq": false,
|
"ipMasq": false,
|
||||||
"ipam": {
|
"ipam": {
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"type": "host-local",
|
"type": "host-local",
|
||||||
"subnet": "%s"
|
"subnet": "%s"
|
||||||
}
|
}
|
||||||
@ -253,13 +257,13 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("ensure bridge address", func() {
|
It("ensure bridge address", func() {
|
||||||
|
|
||||||
const IFNAME = "bridge0"
|
const IFNAME = "bridge0"
|
||||||
const EXPECTED_IP = "10.0.0.0/8"
|
const EXPECTED_IP = "10.0.0.0/8"
|
||||||
const CHANGED_EXPECTED_IP = "10.1.2.3/16"
|
const CHANGED_EXPECTED_IP = "10.1.2.3/16"
|
||||||
|
|
||||||
conf := &NetConf{
|
conf := &NetConf{
|
||||||
NetConf: types.NetConf{
|
NetConf: types.NetConf{
|
||||||
|
CNIVersion: "0.2.0",
|
||||||
Name: "testConfig",
|
Name: "testConfig",
|
||||||
Type: "bridge",
|
Type: "bridge",
|
||||||
},
|
},
|
||||||
@ -320,5 +324,4 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -63,6 +63,7 @@ var _ = Describe("ipvlan Operations", func() {
|
|||||||
It("creates an ipvlan link in a non-default namespace", func() {
|
It("creates an ipvlan link in a non-default namespace", func() {
|
||||||
conf := &NetConf{
|
conf := &NetConf{
|
||||||
NetConf: types.NetConf{
|
NetConf: types.NetConf{
|
||||||
|
CNIVersion: "0.2.0",
|
||||||
Name: "testConfig",
|
Name: "testConfig",
|
||||||
Type: "ipvlan",
|
Type: "ipvlan",
|
||||||
},
|
},
|
||||||
@ -101,10 +102,12 @@ var _ = Describe("ipvlan Operations", func() {
|
|||||||
const IFNAME = "ipvl0"
|
const IFNAME = "ipvl0"
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"type": "ipvlan",
|
"type": "ipvlan",
|
||||||
"master": "%s",
|
"master": "%s",
|
||||||
"ipam": {
|
"ipam": {
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"type": "host-local",
|
"type": "host-local",
|
||||||
"subnet": "10.1.2.0/24"
|
"subnet": "10.1.2.0/24"
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ var _ = Describe("Loopback", func() {
|
|||||||
fmt.Sprintf("CNI_ARGS=%s", "none"),
|
fmt.Sprintf("CNI_ARGS=%s", "none"),
|
||||||
fmt.Sprintf("CNI_PATH=%s", "/some/test/path"),
|
fmt.Sprintf("CNI_PATH=%s", "/some/test/path"),
|
||||||
}
|
}
|
||||||
command.Stdin = strings.NewReader("this doesn't matter")
|
command.Stdin = strings.NewReader(`{ "cniVersion": "0.1.0" }`)
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
@ -64,6 +64,7 @@ var _ = Describe("macvlan Operations", func() {
|
|||||||
It("creates an macvlan link in a non-default namespace", func() {
|
It("creates an macvlan link in a non-default namespace", func() {
|
||||||
conf := &NetConf{
|
conf := &NetConf{
|
||||||
NetConf: types.NetConf{
|
NetConf: types.NetConf{
|
||||||
|
CNIVersion: "0.2.0",
|
||||||
Name: "testConfig",
|
Name: "testConfig",
|
||||||
Type: "macvlan",
|
Type: "macvlan",
|
||||||
},
|
},
|
||||||
@ -101,10 +102,12 @@ var _ = Describe("macvlan Operations", func() {
|
|||||||
const IFNAME = "macvl0"
|
const IFNAME = "macvl0"
|
||||||
|
|
||||||
conf := fmt.Sprintf(`{
|
conf := fmt.Sprintf(`{
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"type": "macvlan",
|
"type": "macvlan",
|
||||||
"master": "%s",
|
"master": "%s",
|
||||||
"ipam": {
|
"ipam": {
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"type": "host-local",
|
"type": "host-local",
|
||||||
"subnet": "10.1.2.0/24"
|
"subnet": "10.1.2.0/24"
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,13 @@ var _ = Describe("ptp Operations", func() {
|
|||||||
const IFNAME = "ptp0"
|
const IFNAME = "ptp0"
|
||||||
|
|
||||||
conf := `{
|
conf := `{
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"type": "ptp",
|
"type": "ptp",
|
||||||
"ipMasq": true,
|
"ipMasq": true,
|
||||||
"mtu": 5000,
|
"mtu": 5000,
|
||||||
"ipam": {
|
"ipam": {
|
||||||
|
"cniVersion": "0.2.0",
|
||||||
"type": "host-local",
|
"type": "host-local",
|
||||||
"subnet": "10.1.2.0/24"
|
"subnet": "10.1.2.0/24"
|
||||||
}
|
}
|
||||||
|
@ -60,14 +60,14 @@ var _ = Describe("No-op plugin", func() {
|
|||||||
"CNI_IFNAME=some-eth0",
|
"CNI_IFNAME=some-eth0",
|
||||||
"CNI_PATH=/some/bin/path",
|
"CNI_PATH=/some/bin/path",
|
||||||
}
|
}
|
||||||
cmd.Stdin = strings.NewReader(`{"some":"stdin-json"}`)
|
cmd.Stdin = strings.NewReader(`{"some":"stdin-json", "cniVersion": "0.2.0"}`)
|
||||||
expectedCmdArgs = skel.CmdArgs{
|
expectedCmdArgs = skel.CmdArgs{
|
||||||
ContainerID: "some-container-id",
|
ContainerID: "some-container-id",
|
||||||
Netns: "/some/netns/path",
|
Netns: "/some/netns/path",
|
||||||
IfName: "some-eth0",
|
IfName: "some-eth0",
|
||||||
Args: "DEBUG=" + debugFileName,
|
Args: "DEBUG=" + debugFileName,
|
||||||
Path: "/some/bin/path",
|
Path: "/some/bin/path",
|
||||||
StdinData: []byte(`{"some":"stdin-json"}`),
|
StdinData: []byte(`{"some":"stdin-json", "cniVersion": "0.2.0"}`),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user