+++ /dev/null
-// 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.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke
-
-import (
- "os"
- "strings"
-)
-
-type CNIArgs interface {
- // For use with os/exec; i.e., return nil to inherit the
- // environment from this process
- AsEnv() []string
-}
-
-type inherited struct{}
-
-var inheritArgsFromEnv inherited
-
-func (_ *inherited) AsEnv() []string {
- return nil
-}
-
-func ArgsFromEnv() CNIArgs {
- return &inheritArgsFromEnv
-}
-
-type Args struct {
- Command string
- ContainerID string
- NetNS string
- PluginArgs [][2]string
- PluginArgsStr string
- IfName string
- Path string
-}
-
-// Args implements the CNIArgs interface
-var _ CNIArgs = &Args{}
-
-func (args *Args) AsEnv() []string {
- env := os.Environ()
- pluginArgsStr := args.PluginArgsStr
- if pluginArgsStr == "" {
- pluginArgsStr = stringify(args.PluginArgs)
- }
-
- env = append(env,
- "CNI_COMMAND="+args.Command,
- "CNI_CONTAINERID="+args.ContainerID,
- "CNI_NETNS="+args.NetNS,
- "CNI_ARGS="+pluginArgsStr,
- "CNI_IFNAME="+args.IfName,
- "CNI_PATH="+args.Path)
- return env
-}
-
-// taken from rkt/networking/net_plugin.go
-func stringify(pluginArgs [][2]string) string {
- entries := make([]string, len(pluginArgs))
-
- for i, kv := range pluginArgs {
- entries[i] = strings.Join(kv[:], "=")
- }
-
- return strings.Join(entries, ";")
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke
-
-import (
- "fmt"
- "os"
- "path/filepath"
-
- "github.com/containernetworking/cni/pkg/types"
-)
-
-func DelegateAdd(delegatePlugin string, netconf []byte) (types.Result, error) {
- if os.Getenv("CNI_COMMAND") != "ADD" {
- return nil, fmt.Errorf("CNI_COMMAND is not ADD")
- }
-
- paths := filepath.SplitList(os.Getenv("CNI_PATH"))
-
- pluginPath, err := FindInPath(delegatePlugin, paths)
- if err != nil {
- return nil, err
- }
-
- return ExecPluginWithResult(pluginPath, netconf, ArgsFromEnv())
-}
-
-func DelegateDel(delegatePlugin string, netconf []byte) error {
- if os.Getenv("CNI_COMMAND") != "DEL" {
- return fmt.Errorf("CNI_COMMAND is not DEL")
- }
-
- paths := filepath.SplitList(os.Getenv("CNI_PATH"))
-
- pluginPath, err := FindInPath(delegatePlugin, paths)
- if err != nil {
- return err
- }
-
- return ExecPluginWithoutResult(pluginPath, netconf, ArgsFromEnv())
-}
+++ /dev/null
-// 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.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke
-
-import (
- "fmt"
- "os"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/version"
-)
-
-func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) {
- return defaultPluginExec.WithResult(pluginPath, netconf, args)
-}
-
-func ExecPluginWithoutResult(pluginPath string, netconf []byte, args CNIArgs) error {
- return defaultPluginExec.WithoutResult(pluginPath, netconf, args)
-}
-
-func GetVersionInfo(pluginPath string) (version.PluginInfo, error) {
- return defaultPluginExec.GetVersionInfo(pluginPath)
-}
-
-var defaultPluginExec = &PluginExec{
- RawExec: &RawExec{Stderr: os.Stderr},
- VersionDecoder: &version.PluginDecoder{},
-}
-
-type PluginExec struct {
- RawExec interface {
- ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error)
- }
- VersionDecoder interface {
- Decode(jsonBytes []byte) (version.PluginInfo, error)
- }
-}
-
-func (e *PluginExec) WithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) {
- stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv())
- if err != nil {
- return nil, err
- }
-
- // Plugin must return result in same version as specified in netconf
- versionDecoder := &version.ConfigDecoder{}
- confVersion, err := versionDecoder.Decode(netconf)
- if err != nil {
- return nil, err
- }
-
- return version.NewResult(confVersion, stdoutBytes)
-}
-
-func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIArgs) error {
- _, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv())
- return err
-}
-
-// GetVersionInfo returns the version information available about the plugin.
-// For recent-enough plugins, it uses the information returned by the VERSION
-// command. For older plugins which do not recognize that command, it reports
-// version 0.1.0
-func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, error) {
- args := &Args{
- Command: "VERSION",
-
- // set fake values required by plugins built against an older version of skel
- NetNS: "dummy",
- IfName: "dummy",
- Path: "dummy",
- }
- stdin := []byte(fmt.Sprintf(`{"cniVersion":%q}`, version.Current()))
- stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, stdin, args.AsEnv())
- if err != nil {
- if err.Error() == "unknown CNI_COMMAND: VERSION" {
- return version.PluginSupports("0.1.0"), nil
- }
- return nil, err
- }
-
- return e.VersionDecoder.Decode(stdoutBytes)
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke_test
-
-import (
- "encoding/json"
- "errors"
-
- "github.com/containernetworking/cni/pkg/invoke"
- "github.com/containernetworking/cni/pkg/invoke/fakes"
- "github.com/containernetworking/cni/pkg/types/current"
- "github.com/containernetworking/cni/pkg/version"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("Executing a plugin, unit tests", func() {
- var (
- pluginExec *invoke.PluginExec
- rawExec *fakes.RawExec
- versionDecoder *fakes.VersionDecoder
-
- pluginPath string
- netconf []byte
- cniargs *fakes.CNIArgs
- )
-
- BeforeEach(func() {
- rawExec = &fakes.RawExec{}
- rawExec.ExecPluginCall.Returns.ResultBytes = []byte(`{ "ips": [ { "version": "4", "address": "1.2.3.4/24" } ] }`)
-
- versionDecoder = &fakes.VersionDecoder{}
- versionDecoder.DecodeCall.Returns.PluginInfo = version.PluginSupports("0.42.0")
-
- pluginExec = &invoke.PluginExec{
- RawExec: rawExec,
- VersionDecoder: versionDecoder,
- }
- pluginPath = "/some/plugin/path"
- netconf = []byte(`{ "some": "stdin", "cniVersion": "0.3.1" }`)
- cniargs = &fakes.CNIArgs{}
- cniargs.AsEnvCall.Returns.Env = []string{"SOME=ENV"}
- })
-
- Describe("returning a result", func() {
- It("unmarshals the result bytes into the Result type", func() {
- r, err := pluginExec.WithResult(pluginPath, netconf, cniargs)
- Expect(err).NotTo(HaveOccurred())
-
- result, err := current.GetResult(r)
- Expect(err).NotTo(HaveOccurred())
- Expect(len(result.IPs)).To(Equal(1))
- Expect(result.IPs[0].Address.IP.String()).To(Equal("1.2.3.4"))
- })
-
- It("passes its arguments through to the rawExec", func() {
- pluginExec.WithResult(pluginPath, netconf, cniargs)
- Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath))
- Expect(rawExec.ExecPluginCall.Received.StdinData).To(Equal(netconf))
- Expect(rawExec.ExecPluginCall.Received.Environ).To(Equal([]string{"SOME=ENV"}))
- })
-
- Context("when the rawExec fails", func() {
- BeforeEach(func() {
- rawExec.ExecPluginCall.Returns.Error = errors.New("banana")
- })
- It("returns the error", func() {
- _, err := pluginExec.WithResult(pluginPath, netconf, cniargs)
- Expect(err).To(MatchError("banana"))
- })
- })
- })
-
- Describe("without returning a result", func() {
- It("passes its arguments through to the rawExec", func() {
- pluginExec.WithoutResult(pluginPath, netconf, cniargs)
- Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath))
- Expect(rawExec.ExecPluginCall.Received.StdinData).To(Equal(netconf))
- Expect(rawExec.ExecPluginCall.Received.Environ).To(Equal([]string{"SOME=ENV"}))
- })
-
- Context("when the rawExec fails", func() {
- BeforeEach(func() {
- rawExec.ExecPluginCall.Returns.Error = errors.New("banana")
- })
- It("returns the error", func() {
- err := pluginExec.WithoutResult(pluginPath, netconf, cniargs)
- Expect(err).To(MatchError("banana"))
- })
- })
- })
-
- Describe("discovering the plugin version", func() {
- BeforeEach(func() {
- rawExec.ExecPluginCall.Returns.ResultBytes = []byte(`{ "some": "version-info" }`)
- })
-
- It("execs the plugin with the command VERSION", func() {
- pluginExec.GetVersionInfo(pluginPath)
- Expect(rawExec.ExecPluginCall.Received.PluginPath).To(Equal(pluginPath))
- 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() {
- versionInfo, err := pluginExec.GetVersionInfo(pluginPath)
- Expect(err).NotTo(HaveOccurred())
- Expect(versionInfo.SupportedVersions()).To(Equal([]string{"0.42.0"}))
- Expect(versionDecoder.DecodeCall.Received.JSONBytes).To(MatchJSON(`{ "some": "version-info" }`))
- })
-
- Context("when the rawExec fails", func() {
- BeforeEach(func() {
- rawExec.ExecPluginCall.Returns.Error = errors.New("banana")
- })
- It("returns the error", func() {
- _, err := pluginExec.GetVersionInfo(pluginPath)
- Expect(err).To(MatchError("banana"))
- })
- })
-
- Context("when the plugin is too old to recognize the VERSION command", func() {
- BeforeEach(func() {
- rawExec.ExecPluginCall.Returns.Error = errors.New("unknown CNI_COMMAND: VERSION")
- })
-
- It("interprets the error as a 0.1.0 version", func() {
- versionInfo, err := pluginExec.GetVersionInfo(pluginPath)
- Expect(err).NotTo(HaveOccurred())
- Expect(versionInfo.SupportedVersions()).To(ConsistOf("0.1.0"))
- })
-
- It("sets dummy values for env vars required by very old plugins", func() {
- pluginExec.GetVersionInfo(pluginPath)
-
- env := rawExec.ExecPluginCall.Received.Environ
- Expect(env).To(ContainElement("CNI_NETNS=dummy"))
- Expect(env).To(ContainElement("CNI_IFNAME=dummy"))
- Expect(env).To(ContainElement("CNI_PATH=dummy"))
- })
- })
- })
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package fakes
-
-type CNIArgs struct {
- AsEnvCall struct {
- Returns struct {
- Env []string
- }
- }
-}
-
-func (a *CNIArgs) AsEnv() []string {
- return a.AsEnvCall.Returns.Env
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package fakes
-
-type RawExec struct {
- ExecPluginCall struct {
- Received struct {
- PluginPath string
- StdinData []byte
- Environ []string
- }
- Returns struct {
- ResultBytes []byte
- Error error
- }
- }
-}
-
-func (e *RawExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) {
- e.ExecPluginCall.Received.PluginPath = pluginPath
- e.ExecPluginCall.Received.StdinData = stdinData
- e.ExecPluginCall.Received.Environ = environ
- return e.ExecPluginCall.Returns.ResultBytes, e.ExecPluginCall.Returns.Error
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package fakes
-
-import "github.com/containernetworking/cni/pkg/version"
-
-type VersionDecoder struct {
- DecodeCall struct {
- Received struct {
- JSONBytes []byte
- }
- Returns struct {
- PluginInfo version.PluginInfo
- Error error
- }
- }
-}
-
-func (e *VersionDecoder) Decode(jsonData []byte) (version.PluginInfo, error) {
- e.DecodeCall.Received.JSONBytes = jsonData
- return e.DecodeCall.Returns.PluginInfo, e.DecodeCall.Returns.Error
-}
+++ /dev/null
-// 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.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke
-
-import (
- "fmt"
- "os"
- "path/filepath"
-)
-
-// FindInPath returns the full path of the plugin by searching in the provided path
-func FindInPath(plugin string, paths []string) (string, error) {
- if plugin == "" {
- return "", fmt.Errorf("no plugin name provided")
- }
-
- if len(paths) == 0 {
- return "", fmt.Errorf("no paths provided")
- }
-
- for _, path := range paths {
- for _, fe := range ExecutableFileExtensions {
- fullpath := filepath.Join(path, plugin) + fe
- if fi, err := os.Stat(fullpath); err == nil && fi.Mode().IsRegular() {
- return fullpath, nil
- }
- }
- }
-
- return "", fmt.Errorf("failed to find plugin %q in path %s", plugin, paths)
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke_test
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/containernetworking/cni/pkg/invoke"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("FindInPath", func() {
- var (
- multiplePaths []string
- pluginName string
- plugin2NameWithExt string
- plugin2NameWithoutExt string
- pluginDir string
- anotherTempDir string
- )
-
- BeforeEach(func() {
- tempDir, err := ioutil.TempDir("", "cni-find")
- Expect(err).NotTo(HaveOccurred())
-
- plugin, err := ioutil.TempFile(tempDir, "a-cni-plugin")
- Expect(err).NotTo(HaveOccurred())
-
- plugin2Name := "a-plugin-with-extension" + invoke.ExecutableFileExtensions[0]
- plugin2, err := os.Create(filepath.Join(tempDir, plugin2Name))
- Expect(err).NotTo(HaveOccurred())
-
- anotherTempDir, err = ioutil.TempDir("", "nothing-here")
- Expect(err).NotTo(HaveOccurred())
-
- multiplePaths = []string{anotherTempDir, tempDir}
- pluginDir, pluginName = filepath.Split(plugin.Name())
- _, plugin2NameWithExt = filepath.Split(plugin2.Name())
- plugin2NameWithoutExt = strings.Split(plugin2NameWithExt, ".")[0]
- })
-
- AfterEach(func() {
- os.RemoveAll(pluginDir)
- os.RemoveAll(anotherTempDir)
- })
-
- Context("when multiple paths are provided", func() {
- It("returns only the path to the plugin", func() {
- pluginPath, err := invoke.FindInPath(pluginName, multiplePaths)
- Expect(err).NotTo(HaveOccurred())
- Expect(pluginPath).To(Equal(filepath.Join(pluginDir, pluginName)))
- })
- })
-
- Context("when a plugin name without its file name extension is provided", func() {
- It("returns the path to the plugin, including its extension", func() {
- pluginPath, err := invoke.FindInPath(plugin2NameWithoutExt, multiplePaths)
- Expect(err).NotTo(HaveOccurred())
- Expect(pluginPath).To(Equal(filepath.Join(pluginDir, plugin2NameWithExt)))
- })
- })
-
- Context("when an error occurs", func() {
- Context("when no paths are provided", func() {
- It("returns an error noting no paths were provided", func() {
- _, err := invoke.FindInPath(pluginName, []string{})
- Expect(err).To(MatchError("no paths provided"))
- })
- })
-
- Context("when no plugin is provided", func() {
- It("returns an error noting the plugin name wasn't found", func() {
- _, err := invoke.FindInPath("", multiplePaths)
- Expect(err).To(MatchError("no plugin name provided"))
- })
- })
-
- Context("when the plugin cannot be found", func() {
- It("returns an error noting the path", func() {
- pathsWithNothing := []string{anotherTempDir}
- _, err := invoke.FindInPath(pluginName, pathsWithNothing)
- Expect(err).To(MatchError(fmt.Sprintf("failed to find plugin %q in path %s", pluginName, pathsWithNothing)))
- })
- })
- })
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke_test
-
-import (
- "io/ioutil"
- "os"
- "path/filepath"
-
- "github.com/containernetworking/cni/pkg/invoke"
- "github.com/containernetworking/cni/pkg/version"
- "github.com/containernetworking/cni/pkg/version/testhelpers"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/ginkgo/extensions/table"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("GetVersion, integration tests", func() {
- var (
- pluginDir string
- pluginPath string
- )
-
- BeforeEach(func() {
- pluginDir, err := ioutil.TempDir("", "plugins")
- Expect(err).NotTo(HaveOccurred())
- pluginPath = filepath.Join(pluginDir, "test-plugin")
- })
-
- AfterEach(func() {
- Expect(os.RemoveAll(pluginDir)).To(Succeed())
- })
-
- DescribeTable("correctly reporting plugin versions",
- func(gitRef string, pluginSource string, expectedVersions version.PluginInfo) {
- Expect(testhelpers.BuildAt([]byte(pluginSource), gitRef, pluginPath)).To(Succeed())
- versionInfo, err := invoke.GetVersionInfo(pluginPath)
- Expect(err).NotTo(HaveOccurred())
-
- Expect(versionInfo.SupportedVersions()).To(ConsistOf(expectedVersions.SupportedVersions()))
- },
-
- Entry("historical: before VERSION was introduced",
- git_ref_v010, plugin_source_no_custom_versions,
- version.PluginSupports("0.1.0"),
- ),
-
- Entry("historical: when VERSION was introduced but plugins couldn't customize it",
- git_ref_v020_no_custom_versions, plugin_source_no_custom_versions,
- version.PluginSupports("0.1.0", "0.2.0"),
- ),
-
- Entry("historical: when plugins started reporting their own version list",
- git_ref_v020_custom_versions, plugin_source_v020_custom_versions,
- version.PluginSupports("0.2.0", "0.999.0"),
- ),
-
- // this entry tracks the current behavior. Before you change it, ensure
- // that its previous behavior is captured in the most recent "historical" entry
- Entry("current",
- "HEAD", plugin_source_v020_custom_versions,
- version.PluginSupports("0.2.0", "0.999.0"),
- ),
- )
-})
-
-// a 0.2.0 plugin that can report its own versions
-const plugin_source_v020_custom_versions = `package main
-
-import (
- "github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/version"
- "fmt"
-)
-
-func c(_ *skel.CmdArgs) error { fmt.Println("{}"); return nil }
-
-func main() { skel.PluginMain(c, c, version.PluginSupports("0.2.0", "0.999.0")) }
-`
-const git_ref_v020_custom_versions = "bf31ed15"
-
-// a minimal 0.1.0 / 0.2.0 plugin that cannot report it's own version support
-const plugin_source_no_custom_versions = `package main
-
-import "github.com/containernetworking/cni/pkg/skel"
-import "fmt"
-
-func c(_ *skel.CmdArgs) error { fmt.Println("{}"); return nil }
-
-func main() { skel.PluginMain(c, c) }
-`
-
-const git_ref_v010 = "2c482f4"
-const git_ref_v020_no_custom_versions = "349d66d"
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
- "github.com/onsi/gomega/gexec"
-
- "testing"
-)
-
-func TestInvoke(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "Invoke Suite")
-}
-
-const packagePath = "github.com/containernetworking/cni/plugins/test/noop"
-
-var pathToPlugin string
-
-var _ = SynchronizedBeforeSuite(func() []byte {
- var err error
- pathToPlugin, err = gexec.Build(packagePath)
- Expect(err).NotTo(HaveOccurred())
- return []byte(pathToPlugin)
-}, func(crossNodeData []byte) {
- pathToPlugin = string(crossNodeData)
-})
-
-var _ = SynchronizedAfterSuite(func() {}, func() {
- gexec.CleanupBuildArtifacts()
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build darwin dragonfly freebsd linux netbsd opensbd solaris
-
-package invoke
-
-// Valid file extensions for plugin executables.
-var ExecutableFileExtensions = []string{""}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke
-
-// Valid file extensions for plugin executables.
-var ExecutableFileExtensions = []string{".exe", ""}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "os/exec"
-
- "github.com/containernetworking/cni/pkg/types"
-)
-
-type RawExec struct {
- Stderr io.Writer
-}
-
-func (e *RawExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) {
- stdout := &bytes.Buffer{}
-
- c := exec.Cmd{
- Env: environ,
- Path: pluginPath,
- Args: []string{pluginPath},
- Stdin: bytes.NewBuffer(stdinData),
- Stdout: stdout,
- Stderr: e.Stderr,
- }
- if err := c.Run(); err != nil {
- return nil, pluginErr(err, stdout.Bytes())
- }
-
- return stdout.Bytes(), nil
-}
-
-func pluginErr(err error, output []byte) error {
- if _, ok := err.(*exec.ExitError); ok {
- emsg := types.Error{}
- if perr := json.Unmarshal(output, &emsg); perr != nil {
- return fmt.Errorf("netplugin failed but error parsing its diagnostic message %q: %v", string(output), perr)
- }
- details := ""
- if emsg.Details != "" {
- details = fmt.Sprintf("; %v", emsg.Details)
- }
- return fmt.Errorf("%v%v", emsg.Msg, details)
- }
-
- return err
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package invoke_test
-
-import (
- "bytes"
- "io/ioutil"
- "os"
-
- "github.com/containernetworking/cni/pkg/invoke"
-
- noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("RawExec", func() {
- var (
- debugFileName string
- debug *noop_debug.Debug
- environ []string
- stdin []byte
- execer *invoke.RawExec
- )
-
- const reportResult = `{ "some": "result" }`
-
- BeforeEach(func() {
- debugFile, err := ioutil.TempFile("", "cni_debug")
- Expect(err).NotTo(HaveOccurred())
- Expect(debugFile.Close()).To(Succeed())
- debugFileName = debugFile.Name()
-
- debug = &noop_debug.Debug{
- ReportResult: reportResult,
- ReportStderr: "some stderr message",
- }
- Expect(debug.WriteDebug(debugFileName)).To(Succeed())
-
- environ = []string{
- "CNI_COMMAND=ADD",
- "CNI_CONTAINERID=some-container-id",
- "CNI_ARGS=DEBUG=" + debugFileName,
- "CNI_NETNS=/some/netns/path",
- "CNI_PATH=/some/bin/path",
- "CNI_IFNAME=some-eth0",
- }
- stdin = []byte(`{"some":"stdin-json", "cniVersion": "0.3.1"}`)
- execer = &invoke.RawExec{}
- })
-
- AfterEach(func() {
- Expect(os.Remove(debugFileName)).To(Succeed())
- })
-
- It("runs the plugin with the given stdin and environment", func() {
- _, err := execer.ExecPlugin(pathToPlugin, stdin, environ)
- Expect(err).NotTo(HaveOccurred())
-
- debug, err := noop_debug.ReadDebug(debugFileName)
- Expect(err).NotTo(HaveOccurred())
- Expect(debug.Command).To(Equal("ADD"))
- Expect(debug.CmdArgs.StdinData).To(Equal(stdin))
- Expect(debug.CmdArgs.Netns).To(Equal("/some/netns/path"))
- })
-
- It("returns the resulting stdout as bytes", func() {
- resultBytes, err := execer.ExecPlugin(pathToPlugin, stdin, environ)
- Expect(err).NotTo(HaveOccurred())
-
- Expect(resultBytes).To(BeEquivalentTo(reportResult))
- })
-
- Context("when the Stderr writer is set", func() {
- var stderrBuffer *bytes.Buffer
-
- BeforeEach(func() {
- stderrBuffer = &bytes.Buffer{}
- execer.Stderr = stderrBuffer
- })
-
- It("forwards any stderr bytes to the Stderr writer", func() {
- _, err := execer.ExecPlugin(pathToPlugin, stdin, environ)
- Expect(err).NotTo(HaveOccurred())
-
- Expect(stderrBuffer.String()).To(Equal("some stderr message"))
- })
- })
-
- Context("when the plugin errors", func() {
- BeforeEach(func() {
- debug.ReportError = "banana"
- Expect(debug.WriteDebug(debugFileName)).To(Succeed())
- })
-
- It("wraps and returns the error", func() {
- _, err := execer.ExecPlugin(pathToPlugin, stdin, environ)
- Expect(err).To(HaveOccurred())
- Expect(err).To(MatchError("banana"))
- })
- })
-
- Context("when the system is unable to execute the plugin", func() {
- It("returns the error", func() {
- _, err := execer.ExecPlugin("/tmp/some/invalid/plugin/path", stdin, environ)
- Expect(err).To(HaveOccurred())
- Expect(err).To(MatchError(ContainSubstring("/tmp/some/invalid/plugin/path")))
- })
- })
-})
"net"
"os"
- "github.com/containernetworking/cni/pkg/ns"
- "github.com/containernetworking/cni/pkg/utils/hwaddr"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/utils/hwaddr"
"github.com/vishvananda/netlink"
)
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
- "github.com/containernetworking/cni/pkg/ip"
- "github.com/containernetworking/cni/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/ip"
+ "github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl"
"os"
"github.com/containernetworking/cni/pkg/invoke"
- "github.com/containernetworking/cni/pkg/ip"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ip"
"github.com/vishvananda/netlink"
)
"net"
"syscall"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
"os"
"path/filepath"
- "github.com/containernetworking/cni/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/ns"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"golang.org/x/sys/unix"
+++ /dev/null
-// Copyright 2014-2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package skel provides skeleton code for a CNI plugin.
-// In particular, it implements argument parsing and validation.
-package skel
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "os"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/version"
-)
-
-// CmdArgs captures all the arguments passed in to the plugin
-// via both env vars and stdin
-type CmdArgs struct {
- ContainerID string
- Netns string
- IfName string
- Args string
- Path string
- StdinData []byte
-}
-
-type dispatcher struct {
- Getenv func(string) string
- Stdin io.Reader
- Stdout io.Writer
- Stderr io.Writer
-
- ConfVersionDecoder version.ConfigDecoder
- VersionReconciler version.Reconciler
-}
-
-type reqForCmdEntry map[string]bool
-
-func (t *dispatcher) getCmdArgsFromEnv() (string, *CmdArgs, error) {
- var cmd, contID, netns, ifName, args, path string
-
- vars := []struct {
- name string
- val *string
- reqForCmd reqForCmdEntry
- }{
- {
- "CNI_COMMAND",
- &cmd,
- reqForCmdEntry{
- "ADD": true,
- "DEL": true,
- },
- },
- {
- "CNI_CONTAINERID",
- &contID,
- reqForCmdEntry{
- "ADD": false,
- "DEL": false,
- },
- },
- {
- "CNI_NETNS",
- &netns,
- reqForCmdEntry{
- "ADD": true,
- "DEL": false,
- },
- },
- {
- "CNI_IFNAME",
- &ifName,
- reqForCmdEntry{
- "ADD": true,
- "DEL": true,
- },
- },
- {
- "CNI_ARGS",
- &args,
- reqForCmdEntry{
- "ADD": false,
- "DEL": false,
- },
- },
- {
- "CNI_PATH",
- &path,
- reqForCmdEntry{
- "ADD": true,
- "DEL": true,
- },
- },
- }
-
- argsMissing := false
- for _, v := range vars {
- *v.val = t.Getenv(v.name)
- if *v.val == "" {
- if v.reqForCmd[cmd] || v.name == "CNI_COMMAND" {
- fmt.Fprintf(t.Stderr, "%v env variable missing\n", v.name)
- argsMissing = true
- }
- }
- }
-
- if argsMissing {
- return "", nil, fmt.Errorf("required env variables missing")
- }
-
- stdinData, err := ioutil.ReadAll(t.Stdin)
- if err != nil {
- return "", nil, fmt.Errorf("error reading from stdin: %v", err)
- }
-
- cmdArgs := &CmdArgs{
- ContainerID: contID,
- Netns: netns,
- IfName: ifName,
- Args: args,
- Path: path,
- StdinData: stdinData,
- }
- return cmd, cmdArgs, nil
-}
-
-func createTypedError(f string, args ...interface{}) *types.Error {
- return &types.Error{
- Code: 100,
- Msg: fmt.Sprintf(f, args...),
- }
-}
-
-func (t *dispatcher) checkVersionAndCall(cmdArgs *CmdArgs, pluginVersionInfo version.PluginInfo, toCall func(*CmdArgs) error) error {
- configVersion, err := t.ConfVersionDecoder.Decode(cmdArgs.StdinData)
- if err != nil {
- return err
- }
- verErr := t.VersionReconciler.Check(configVersion, pluginVersionInfo)
- if verErr != nil {
- return &types.Error{
- Code: types.ErrIncompatibleCNIVersion,
- Msg: "incompatible CNI versions",
- Details: verErr.Details(),
- }
- }
- return toCall(cmdArgs)
-}
-
-func (t *dispatcher) pluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) *types.Error {
- cmd, cmdArgs, err := t.getCmdArgsFromEnv()
- if err != nil {
- return createTypedError(err.Error())
- }
-
- switch cmd {
- case "ADD":
- err = t.checkVersionAndCall(cmdArgs, versionInfo, cmdAdd)
- case "DEL":
- err = t.checkVersionAndCall(cmdArgs, versionInfo, cmdDel)
- case "VERSION":
- err = versionInfo.Encode(t.Stdout)
- default:
- return createTypedError("unknown CNI_COMMAND: %v", cmd)
- }
-
- if err != nil {
- if e, ok := err.(*types.Error); ok {
- // don't wrap Error in Error
- return e
- }
- return createTypedError(err.Error())
- }
- return nil
-}
-
-// PluginMainWithError is the core "main" for a plugin. It accepts
-// callback functions for add and del CNI commands and returns an error.
-//
-// The caller must also specify what CNI spec versions the plugin supports.
-//
-// It is the responsibility of the caller to check for non-nil error return.
-//
-// For a plugin to comply with the CNI spec, it must print any error to stdout
-// as JSON and then exit with nonzero status code.
-//
-// To let this package automatically handle errors and call os.Exit(1) for you,
-// use PluginMain() instead.
-func PluginMainWithError(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) *types.Error {
- return (&dispatcher{
- Getenv: os.Getenv,
- Stdin: os.Stdin,
- Stdout: os.Stdout,
- Stderr: os.Stderr,
- }).pluginMain(cmdAdd, cmdDel, versionInfo)
-}
-
-// PluginMain is the core "main" for a plugin which includes automatic error handling.
-//
-// The caller must also specify what CNI spec versions the plugin supports.
-//
-// When an error occurs in either cmdAdd or cmdDel, PluginMain will print the error
-// as JSON to stdout and call os.Exit(1).
-//
-// To have more control over error handling, use PluginMainWithError() instead.
-func PluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) {
- if e := PluginMainWithError(cmdAdd, cmdDel, versionInfo); e != nil {
- if err := e.Print(); err != nil {
- log.Print("Error writing error JSON to stdout: ", err)
- }
- os.Exit(1)
- }
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package skel
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "testing"
-)
-
-func TestSkel(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "Skel Suite")
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package skel
-
-import (
- "bytes"
- "errors"
- "strings"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/version"
-
- "github.com/containernetworking/cni/pkg/testutils"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/ginkgo/extensions/table"
- . "github.com/onsi/gomega"
-)
-
-type fakeCmd struct {
- CallCount int
- Returns struct {
- Error error
- }
- Received struct {
- CmdArgs *CmdArgs
- }
-}
-
-func (c *fakeCmd) Func(args *CmdArgs) error {
- c.CallCount++
- c.Received.CmdArgs = args
- return c.Returns.Error
-}
-
-var _ = Describe("dispatching to the correct callback", func() {
- var (
- environment map[string]string
- stdinData string
- stdout, stderr *bytes.Buffer
- cmdAdd, cmdDel *fakeCmd
- dispatch *dispatcher
- expectedCmdArgs *CmdArgs
- versionInfo version.PluginInfo
- )
-
- BeforeEach(func() {
- environment = map[string]string{
- "CNI_COMMAND": "ADD",
- "CNI_CONTAINERID": "some-container-id",
- "CNI_NETNS": "/some/netns/path",
- "CNI_IFNAME": "eth0",
- "CNI_ARGS": "some;extra;args",
- "CNI_PATH": "/some/cni/path",
- }
-
- stdinData = `{ "some": "config", "cniVersion": "9.8.7" }`
- stdout = &bytes.Buffer{}
- stderr = &bytes.Buffer{}
- versionInfo = version.PluginSupports("9.8.7")
- dispatch = &dispatcher{
- Getenv: func(key string) string { return environment[key] },
- Stdin: strings.NewReader(stdinData),
- Stdout: stdout,
- Stderr: stderr,
- }
- cmdAdd = &fakeCmd{}
- cmdDel = &fakeCmd{}
- expectedCmdArgs = &CmdArgs{
- ContainerID: "some-container-id",
- Netns: "/some/netns/path",
- IfName: "eth0",
- Args: "some;extra;args",
- Path: "/some/cni/path",
- StdinData: []byte(stdinData),
- }
- })
-
- var envVarChecker = func(envVar string, isRequired bool) {
- delete(environment, envVar)
-
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
- if isRequired {
- Expect(err).To(Equal(&types.Error{
- Code: 100,
- Msg: "required env variables missing",
- }))
- Expect(stderr.String()).To(ContainSubstring(envVar + " env variable missing\n"))
- } else {
- Expect(err).NotTo(HaveOccurred())
- }
- }
-
- Context("when the CNI_COMMAND is ADD", func() {
- It("extracts env vars and stdin data and calls cmdAdd", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).NotTo(HaveOccurred())
- Expect(cmdAdd.CallCount).To(Equal(1))
- Expect(cmdDel.CallCount).To(Equal(0))
- Expect(cmdAdd.Received.CmdArgs).To(Equal(expectedCmdArgs))
- })
-
- It("does not call cmdDel", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).NotTo(HaveOccurred())
- Expect(cmdDel.CallCount).To(Equal(0))
- })
-
- DescribeTable("required / optional env vars", envVarChecker,
- Entry("command", "CNI_COMMAND", true),
- Entry("container id", "CNI_CONTAINERID", false),
- Entry("net ns", "CNI_NETNS", true),
- Entry("if name", "CNI_IFNAME", true),
- Entry("args", "CNI_ARGS", false),
- Entry("path", "CNI_PATH", true),
- )
-
- Context("when multiple required env vars are missing", func() {
- BeforeEach(func() {
- delete(environment, "CNI_NETNS")
- delete(environment, "CNI_IFNAME")
- delete(environment, "CNI_PATH")
- })
-
- It("reports that all of them are missing, not just the first", func() {
- Expect(dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)).NotTo(Succeed())
- log := stderr.String()
- Expect(log).To(ContainSubstring("CNI_NETNS env variable missing\n"))
- Expect(log).To(ContainSubstring("CNI_IFNAME env variable missing\n"))
- Expect(log).To(ContainSubstring("CNI_PATH env variable missing\n"))
-
- })
- })
-
- Context("when the stdin data is missing the required cniVersion config", func() {
- BeforeEach(func() {
- dispatch.Stdin = strings.NewReader(`{ "some": "config" }`)
- })
-
- Context("when the plugin supports version 0.1.0", func() {
- BeforeEach(func() {
- versionInfo = version.PluginSupports("0.1.0")
- expectedCmdArgs.StdinData = []byte(`{ "some": "config" }`)
- })
-
- It("infers the config is 0.1.0 and calls the cmdAdd callback", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
- Expect(err).NotTo(HaveOccurred())
-
- Expect(cmdAdd.CallCount).To(Equal(1))
- Expect(cmdAdd.Received.CmdArgs).To(Equal(expectedCmdArgs))
- })
- })
-
- Context("when the plugin does not support 0.1.0", func() {
- BeforeEach(func() {
- versionInfo = version.PluginSupports("4.3.2")
- })
-
- It("immediately returns a useful error", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
- Expect(err.Code).To(Equal(types.ErrIncompatibleCNIVersion)) // see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
- Expect(err.Msg).To(Equal("incompatible CNI versions"))
- Expect(err.Details).To(Equal(`config is "0.1.0", plugin supports ["4.3.2"]`))
- })
-
- It("does not call either callback", func() {
- dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
- Expect(cmdAdd.CallCount).To(Equal(0))
- Expect(cmdDel.CallCount).To(Equal(0))
- })
- })
- })
- })
-
- Context("when the CNI_COMMAND is DEL", func() {
- BeforeEach(func() {
- environment["CNI_COMMAND"] = "DEL"
- })
-
- It("calls cmdDel with the env vars and stdin data", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).NotTo(HaveOccurred())
- Expect(cmdDel.CallCount).To(Equal(1))
- Expect(cmdDel.Received.CmdArgs).To(Equal(expectedCmdArgs))
- })
-
- It("does not call cmdAdd", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).NotTo(HaveOccurred())
- Expect(cmdAdd.CallCount).To(Equal(0))
- })
-
- DescribeTable("required / optional env vars", envVarChecker,
- Entry("command", "CNI_COMMAND", true),
- Entry("container id", "CNI_CONTAINERID", false),
- Entry("net ns", "CNI_NETNS", false),
- Entry("if name", "CNI_IFNAME", true),
- Entry("args", "CNI_ARGS", false),
- Entry("path", "CNI_PATH", true),
- )
- })
-
- Context("when the CNI_COMMAND is VERSION", func() {
- BeforeEach(func() {
- environment["CNI_COMMAND"] = "VERSION"
- })
-
- It("prints the version to stdout", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).NotTo(HaveOccurred())
- Expect(stdout).To(MatchJSON(`{
- "cniVersion": "0.3.1",
- "supportedVersions": ["9.8.7"]
- }`))
- })
-
- It("does not call cmdAdd or cmdDel", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).NotTo(HaveOccurred())
- Expect(cmdAdd.CallCount).To(Equal(0))
- Expect(cmdDel.CallCount).To(Equal(0))
- })
-
- DescribeTable("VERSION does not need the usual env vars", envVarChecker,
- Entry("command", "CNI_COMMAND", true),
- Entry("container id", "CNI_CONTAINERID", false),
- Entry("net ns", "CNI_NETNS", false),
- Entry("if name", "CNI_IFNAME", false),
- Entry("args", "CNI_ARGS", false),
- Entry("path", "CNI_PATH", false),
- )
-
- Context("when the stdin is empty", func() {
- BeforeEach(func() {
- dispatch.Stdin = strings.NewReader("")
- })
-
- It("succeeds without error", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).NotTo(HaveOccurred())
- Expect(stdout).To(MatchJSON(`{
- "cniVersion": "0.3.1",
- "supportedVersions": ["9.8.7"]
- }`))
- })
- })
- })
-
- Context("when the CNI_COMMAND is unrecognized", func() {
- BeforeEach(func() {
- environment["CNI_COMMAND"] = "NOPE"
- })
-
- It("does not call any cmd callback", func() {
- dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(cmdAdd.CallCount).To(Equal(0))
- Expect(cmdDel.CallCount).To(Equal(0))
- })
-
- It("returns an error", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).To(Equal(&types.Error{
- Code: 100,
- Msg: "unknown CNI_COMMAND: NOPE",
- }))
- })
- })
-
- Context("when stdin cannot be read", func() {
- BeforeEach(func() {
- dispatch.Stdin = &testutils.BadReader{}
- })
-
- It("does not call any cmd callback", func() {
- dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(cmdAdd.CallCount).To(Equal(0))
- Expect(cmdDel.CallCount).To(Equal(0))
- })
-
- It("wraps and returns the error", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).To(Equal(&types.Error{
- Code: 100,
- Msg: "error reading from stdin: banana",
- }))
- })
- })
-
- Context("when the callback returns an error", func() {
- Context("when it is a typed Error", func() {
- BeforeEach(func() {
- cmdAdd.Returns.Error = &types.Error{
- Code: 1234,
- Msg: "insufficient something",
- }
- })
-
- It("returns the error as-is", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).To(Equal(&types.Error{
- Code: 1234,
- Msg: "insufficient something",
- }))
- })
- })
-
- Context("when it is an unknown error", func() {
- BeforeEach(func() {
- cmdAdd.Returns.Error = errors.New("potato")
- })
-
- It("wraps and returns the error", func() {
- err := dispatch.pluginMain(cmdAdd.Func, cmdDel.Func, versionInfo)
-
- Expect(err).To(Equal(&types.Error{
- Code: 100,
- Msg: "potato",
- }))
- })
- })
- })
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package types020
-
-import (
- "encoding/json"
- "fmt"
- "net"
- "os"
-
- "github.com/containernetworking/cni/pkg/types"
-)
-
-const ImplementedSpecVersion string = "0.2.0"
-
-var SupportedVersions = []string{"", "0.1.0", ImplementedSpecVersion}
-
-// Compatibility types for CNI version 0.1.0 and 0.2.0
-
-func NewResult(data []byte) (types.Result, error) {
- result := &Result{}
- if err := json.Unmarshal(data, result); err != nil {
- return nil, err
- }
- return result, nil
-}
-
-func GetResult(r types.Result) (*Result, error) {
- // We expect version 0.1.0/0.2.0 results
- result020, err := r.GetAsVersion(ImplementedSpecVersion)
- if err != nil {
- return nil, err
- }
- result, ok := result020.(*Result)
- if !ok {
- return nil, fmt.Errorf("failed to convert result")
- }
- return result, nil
-}
-
-// Result is what gets returned from the plugin (via stdout) to the caller
-type Result struct {
- CNIVersion string `json:"cniVersion,omitempty"`
- IP4 *IPConfig `json:"ip4,omitempty"`
- IP6 *IPConfig `json:"ip6,omitempty"`
- DNS types.DNS `json:"dns,omitempty"`
-}
-
-func (r *Result) Version() string {
- return ImplementedSpecVersion
-}
-
-func (r *Result) GetAsVersion(version string) (types.Result, error) {
- for _, supportedVersion := range SupportedVersions {
- if version == supportedVersion {
- r.CNIVersion = version
- return r, nil
- }
- }
- return nil, fmt.Errorf("cannot convert version %q to %s", SupportedVersions, version)
-}
-
-func (r *Result) Print() error {
- data, err := json.MarshalIndent(r, "", " ")
- if err != nil {
- return err
- }
- _, err = os.Stdout.Write(data)
- return err
-}
-
-// String returns a formatted string in the form of "[IP4: $1,][ IP6: $2,] DNS: $3" where
-// $1 represents the receiver's IPv4, $2 represents the receiver's IPv6 and $3 the
-// receiver's DNS. If $1 or $2 are nil, they won't be present in the returned string.
-func (r *Result) String() string {
- var str string
- if r.IP4 != nil {
- str = fmt.Sprintf("IP4:%+v, ", *r.IP4)
- }
- if r.IP6 != nil {
- str += fmt.Sprintf("IP6:%+v, ", *r.IP6)
- }
- return fmt.Sprintf("%sDNS:%+v", str, r.DNS)
-}
-
-// IPConfig contains values necessary to configure an interface
-type IPConfig struct {
- IP net.IPNet
- Gateway net.IP
- Routes []types.Route
-}
-
-// net.IPNet is not JSON (un)marshallable so this duality is needed
-// for our custom IPNet type
-
-// JSON (un)marshallable types
-type ipConfig struct {
- IP types.IPNet `json:"ip"`
- Gateway net.IP `json:"gateway,omitempty"`
- Routes []types.Route `json:"routes,omitempty"`
-}
-
-func (c *IPConfig) MarshalJSON() ([]byte, error) {
- ipc := ipConfig{
- IP: types.IPNet(c.IP),
- Gateway: c.Gateway,
- Routes: c.Routes,
- }
-
- return json.Marshal(ipc)
-}
-
-func (c *IPConfig) UnmarshalJSON(data []byte) error {
- ipc := ipConfig{}
- if err := json.Unmarshal(data, &ipc); err != nil {
- return err
- }
-
- c.IP = net.IPNet(ipc.IP)
- c.Gateway = ipc.Gateway
- c.Routes = ipc.Routes
- return nil
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package types020_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "testing"
-)
-
-func TestTypes010(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "0.1.0/0.2.0 Types Suite")
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package types020_test
-
-import (
- "io/ioutil"
- "net"
- "os"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/types/020"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("Ensures compatibility with the 0.1.0/0.2.0 spec", func() {
- It("correctly encodes a 0.1.0/0.2.0 Result", func() {
- ipv4, err := types.ParseCIDR("1.2.3.30/24")
- Expect(err).NotTo(HaveOccurred())
- Expect(ipv4).NotTo(BeNil())
-
- routegwv4, routev4, err := net.ParseCIDR("15.5.6.8/24")
- Expect(err).NotTo(HaveOccurred())
- Expect(routev4).NotTo(BeNil())
- Expect(routegwv4).NotTo(BeNil())
-
- ipv6, err := types.ParseCIDR("abcd:1234:ffff::cdde/64")
- Expect(err).NotTo(HaveOccurred())
- Expect(ipv6).NotTo(BeNil())
-
- routegwv6, routev6, err := net.ParseCIDR("1111:dddd::aaaa/80")
- Expect(err).NotTo(HaveOccurred())
- Expect(routev6).NotTo(BeNil())
- Expect(routegwv6).NotTo(BeNil())
-
- // Set every field of the struct to ensure source compatibility
- res := types020.Result{
- CNIVersion: types020.ImplementedSpecVersion,
- IP4: &types020.IPConfig{
- IP: *ipv4,
- Gateway: net.ParseIP("1.2.3.1"),
- Routes: []types.Route{
- {Dst: *routev4, GW: routegwv4},
- },
- },
- IP6: &types020.IPConfig{
- IP: *ipv6,
- Gateway: net.ParseIP("abcd:1234:ffff::1"),
- Routes: []types.Route{
- {Dst: *routev6, GW: routegwv6},
- },
- },
- DNS: types.DNS{
- Nameservers: []string{"1.2.3.4", "1::cafe"},
- Domain: "acompany.com",
- Search: []string{"somedomain.com", "otherdomain.net"},
- Options: []string{"foo", "bar"},
- },
- }
-
- Expect(res.String()).To(Equal("IP4:{IP:{IP:1.2.3.30 Mask:ffffff00} Gateway:1.2.3.1 Routes:[{Dst:{IP:15.5.6.0 Mask:ffffff00} GW:15.5.6.8}]}, IP6:{IP:{IP:abcd:1234:ffff::cdde Mask:ffffffffffffffff0000000000000000} Gateway:abcd:1234:ffff::1 Routes:[{Dst:{IP:1111:dddd:: Mask:ffffffffffffffffffff000000000000} GW:1111:dddd::aaaa}]}, DNS:{Nameservers:[1.2.3.4 1::cafe] Domain:acompany.com Search:[somedomain.com otherdomain.net] Options:[foo bar]}"))
-
- // Redirect stdout to capture JSON result
- oldStdout := os.Stdout
- r, w, err := os.Pipe()
- Expect(err).NotTo(HaveOccurred())
-
- os.Stdout = w
- err = res.Print()
- w.Close()
- Expect(err).NotTo(HaveOccurred())
-
- // parse the result
- out, err := ioutil.ReadAll(r)
- os.Stdout = oldStdout
- Expect(err).NotTo(HaveOccurred())
-
- Expect(string(out)).To(Equal(`{
- "cniVersion": "0.2.0",
- "ip4": {
- "ip": "1.2.3.30/24",
- "gateway": "1.2.3.1",
- "routes": [
- {
- "dst": "15.5.6.0/24",
- "gw": "15.5.6.8"
- }
- ]
- },
- "ip6": {
- "ip": "abcd:1234:ffff::cdde/64",
- "gateway": "abcd:1234:ffff::1",
- "routes": [
- {
- "dst": "1111:dddd::/80",
- "gw": "1111:dddd::aaaa"
- }
- ]
- },
- "dns": {
- "nameservers": [
- "1.2.3.4",
- "1::cafe"
- ],
- "domain": "acompany.com",
- "search": [
- "somedomain.com",
- "otherdomain.net"
- ],
- "options": [
- "foo",
- "bar"
- ]
- }
-}`))
- })
-})
+++ /dev/null
-// 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.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package types
-
-import (
- "encoding"
- "fmt"
- "reflect"
- "strings"
-)
-
-// UnmarshallableBool typedef for builtin bool
-// because builtin type's methods can't be declared
-type UnmarshallableBool bool
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// Returns boolean true if the string is "1" or "[Tt]rue"
-// Returns boolean false if the string is "0" or "[Ff]alse"
-func (b *UnmarshallableBool) UnmarshalText(data []byte) error {
- s := strings.ToLower(string(data))
- switch s {
- case "1", "true":
- *b = true
- case "0", "false":
- *b = false
- default:
- return fmt.Errorf("Boolean unmarshal error: invalid input %s", s)
- }
- return nil
-}
-
-// UnmarshallableString typedef for builtin string
-type UnmarshallableString string
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// Returns the string
-func (s *UnmarshallableString) UnmarshalText(data []byte) error {
- *s = UnmarshallableString(data)
- return nil
-}
-
-// CommonArgs contains the IgnoreUnknown argument
-// and must be embedded by all Arg structs
-type CommonArgs struct {
- IgnoreUnknown UnmarshallableBool `json:"ignoreunknown,omitempty"`
-}
-
-// GetKeyField is a helper function to receive Values
-// Values that represent a pointer to a struct
-func GetKeyField(keyString string, v reflect.Value) reflect.Value {
- return v.Elem().FieldByName(keyString)
-}
-
-// LoadArgs parses args from a string in the form "K=V;K2=V2;..."
-func LoadArgs(args string, container interface{}) error {
- if args == "" {
- return nil
- }
-
- containerValue := reflect.ValueOf(container)
-
- pairs := strings.Split(args, ";")
- unknownArgs := []string{}
- for _, pair := range pairs {
- kv := strings.Split(pair, "=")
- if len(kv) != 2 {
- return fmt.Errorf("ARGS: invalid pair %q", pair)
- }
- keyString := kv[0]
- valueString := kv[1]
- keyField := GetKeyField(keyString, containerValue)
- if !keyField.IsValid() {
- unknownArgs = append(unknownArgs, pair)
- continue
- }
-
- u := keyField.Addr().Interface().(encoding.TextUnmarshaler)
- err := u.UnmarshalText([]byte(valueString))
- if err != nil {
- return fmt.Errorf("ARGS: error parsing value of pair %q: %v)", pair, err)
- }
- }
-
- isIgnoreUnknown := GetKeyField("IgnoreUnknown", containerValue).Bool()
- if len(unknownArgs) > 0 && !isIgnoreUnknown {
- return fmt.Errorf("ARGS: unknown args %q", unknownArgs)
- }
- return nil
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package types_test
-
-import (
- "reflect"
-
- . "github.com/containernetworking/cni/pkg/types"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/ginkgo/extensions/table"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("UnmarshallableBool UnmarshalText", func() {
- DescribeTable("string to bool detection should succeed in all cases",
- func(inputs []string, expected bool) {
- for _, s := range inputs {
- var ub UnmarshallableBool
- err := ub.UnmarshalText([]byte(s))
- Expect(err).ToNot(HaveOccurred())
- Expect(ub).To(Equal(UnmarshallableBool(expected)))
- }
- },
- Entry("parse to true", []string{"True", "true", "1"}, true),
- Entry("parse to false", []string{"False", "false", "0"}, false),
- )
-
- Context("When passed an invalid value", func() {
- It("should result in an error", func() {
- var ub UnmarshallableBool
- err := ub.UnmarshalText([]byte("invalid"))
- Expect(err).To(HaveOccurred())
- })
- })
-})
-
-var _ = Describe("UnmarshallableString UnmarshalText", func() {
- DescribeTable("string to string detection should succeed in all cases",
- func(inputs []string, expected string) {
- for _, s := range inputs {
- var us UnmarshallableString
- err := us.UnmarshalText([]byte(s))
- Expect(err).ToNot(HaveOccurred())
- Expect(string(us)).To(Equal(expected))
- }
- },
- Entry("parse empty string", []string{""}, ""),
- Entry("parse non-empty string", []string{"notempty"}, "notempty"),
- )
-})
-
-var _ = Describe("GetKeyField", func() {
- type testcontainer struct {
- Valid string `json:"valid,omitempty"`
- }
- var (
- container = testcontainer{Valid: "valid"}
- containerInterface = func(i interface{}) interface{} { return i }(&container)
- containerValue = reflect.ValueOf(containerInterface)
- )
- Context("When a valid field is provided", func() {
- It("should return the correct field", func() {
- field := GetKeyField("Valid", containerValue)
- Expect(field.String()).To(Equal("valid"))
- })
- })
-})
-
-var _ = Describe("LoadArgs", func() {
- Context("When no arguments are passed", func() {
- It("LoadArgs should succeed", func() {
- err := LoadArgs("", struct{}{})
- Expect(err).NotTo(HaveOccurred())
- })
- })
-
- Context("When unknown arguments are passed and ignored", func() {
- It("LoadArgs should succeed", func() {
- ca := CommonArgs{}
- err := LoadArgs("IgnoreUnknown=True;Unk=nown", &ca)
- Expect(err).NotTo(HaveOccurred())
- })
- })
-
- Context("When unknown arguments are passed and not ignored", func() {
- It("LoadArgs should fail", func() {
- ca := CommonArgs{}
- err := LoadArgs("Unk=nown", &ca)
- Expect(err).To(HaveOccurred())
- })
- })
-
- Context("When unknown arguments are passed and explicitly not ignored", func() {
- It("LoadArgs should fail", func() {
- ca := CommonArgs{}
- err := LoadArgs("IgnoreUnknown=0, Unk=nown", &ca)
- Expect(err).To(HaveOccurred())
- })
- })
-
- Context("When known arguments are passed", func() {
- It("LoadArgs should succeed", func() {
- ca := CommonArgs{}
- err := LoadArgs("IgnoreUnknown=1", &ca)
- Expect(err).NotTo(HaveOccurred())
- })
- })
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package current
-
-import (
- "encoding/json"
- "fmt"
- "net"
- "os"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/types/020"
-)
-
-const ImplementedSpecVersion string = "0.3.1"
-
-var SupportedVersions = []string{"0.3.0", ImplementedSpecVersion}
-
-func NewResult(data []byte) (types.Result, error) {
- result := &Result{}
- if err := json.Unmarshal(data, result); err != nil {
- return nil, err
- }
- return result, nil
-}
-
-func GetResult(r types.Result) (*Result, error) {
- resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion)
- if err != nil {
- return nil, err
- }
- result, ok := resultCurrent.(*Result)
- if !ok {
- return nil, fmt.Errorf("failed to convert result")
- }
- return result, nil
-}
-
-var resultConverters = []struct {
- versions []string
- convert func(types.Result) (*Result, error)
-}{
- {types020.SupportedVersions, convertFrom020},
- {SupportedVersions, convertFrom030},
-}
-
-func convertFrom020(result types.Result) (*Result, error) {
- oldResult, err := types020.GetResult(result)
- if err != nil {
- return nil, err
- }
-
- newResult := &Result{
- CNIVersion: ImplementedSpecVersion,
- DNS: oldResult.DNS,
- Routes: []*types.Route{},
- }
-
- if oldResult.IP4 != nil {
- newResult.IPs = append(newResult.IPs, &IPConfig{
- Version: "4",
- Interface: -1,
- Address: oldResult.IP4.IP,
- Gateway: oldResult.IP4.Gateway,
- })
- for _, route := range oldResult.IP4.Routes {
- gw := route.GW
- if gw == nil {
- gw = oldResult.IP4.Gateway
- }
- newResult.Routes = append(newResult.Routes, &types.Route{
- Dst: route.Dst,
- GW: gw,
- })
- }
- }
-
- if oldResult.IP6 != nil {
- newResult.IPs = append(newResult.IPs, &IPConfig{
- Version: "6",
- Interface: -1,
- Address: oldResult.IP6.IP,
- Gateway: oldResult.IP6.Gateway,
- })
- for _, route := range oldResult.IP6.Routes {
- gw := route.GW
- if gw == nil {
- gw = oldResult.IP6.Gateway
- }
- newResult.Routes = append(newResult.Routes, &types.Route{
- Dst: route.Dst,
- GW: gw,
- })
- }
- }
-
- if len(newResult.IPs) == 0 {
- return nil, fmt.Errorf("cannot convert: no valid IP addresses")
- }
-
- return newResult, nil
-}
-
-func convertFrom030(result types.Result) (*Result, error) {
- newResult, ok := result.(*Result)
- if !ok {
- return nil, fmt.Errorf("failed to convert result")
- }
- newResult.CNIVersion = ImplementedSpecVersion
- return newResult, nil
-}
-
-func NewResultFromResult(result types.Result) (*Result, error) {
- version := result.Version()
- for _, converter := range resultConverters {
- for _, supportedVersion := range converter.versions {
- if version == supportedVersion {
- return converter.convert(result)
- }
- }
- }
- return nil, fmt.Errorf("unsupported CNI result22 version %q", version)
-}
-
-// Result is what gets returned from the plugin (via stdout) to the caller
-type Result struct {
- CNIVersion string `json:"cniVersion,omitempty"`
- Interfaces []*Interface `json:"interfaces,omitempty"`
- IPs []*IPConfig `json:"ips,omitempty"`
- Routes []*types.Route `json:"routes,omitempty"`
- DNS types.DNS `json:"dns,omitempty"`
-}
-
-// Convert to the older 0.2.0 CNI spec Result type
-func (r *Result) convertTo020() (*types020.Result, error) {
- oldResult := &types020.Result{
- CNIVersion: types020.ImplementedSpecVersion,
- DNS: r.DNS,
- }
-
- for _, ip := range r.IPs {
- // Only convert the first IP address of each version as 0.2.0
- // and earlier cannot handle multiple IP addresses
- if ip.Version == "4" && oldResult.IP4 == nil {
- oldResult.IP4 = &types020.IPConfig{
- IP: ip.Address,
- Gateway: ip.Gateway,
- }
- } else if ip.Version == "6" && oldResult.IP6 == nil {
- oldResult.IP6 = &types020.IPConfig{
- IP: ip.Address,
- Gateway: ip.Gateway,
- }
- }
-
- if oldResult.IP4 != nil && oldResult.IP6 != nil {
- break
- }
- }
-
- for _, route := range r.Routes {
- is4 := route.Dst.IP.To4() != nil
- if is4 && oldResult.IP4 != nil {
- oldResult.IP4.Routes = append(oldResult.IP4.Routes, types.Route{
- Dst: route.Dst,
- GW: route.GW,
- })
- } else if !is4 && oldResult.IP6 != nil {
- oldResult.IP6.Routes = append(oldResult.IP6.Routes, types.Route{
- Dst: route.Dst,
- GW: route.GW,
- })
- }
- }
-
- if oldResult.IP4 == nil && oldResult.IP6 == nil {
- return nil, fmt.Errorf("cannot convert: no valid IP addresses")
- }
-
- return oldResult, nil
-}
-
-func (r *Result) Version() string {
- return ImplementedSpecVersion
-}
-
-func (r *Result) GetAsVersion(version string) (types.Result, error) {
- switch version {
- case "0.3.0", ImplementedSpecVersion:
- r.CNIVersion = version
- return r, nil
- case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
- return r.convertTo020()
- }
- return nil, fmt.Errorf("cannot convert version 0.3.x to %q", version)
-}
-
-func (r *Result) Print() error {
- data, err := json.MarshalIndent(r, "", " ")
- if err != nil {
- return err
- }
- _, err = os.Stdout.Write(data)
- return err
-}
-
-// String returns a formatted string in the form of "[Interfaces: $1,][ IP: $2,] DNS: $3" where
-// $1 represents the receiver's Interfaces, $2 represents the receiver's IP addresses and $3 the
-// receiver's DNS. If $1 or $2 are nil, they won't be present in the returned string.
-func (r *Result) String() string {
- var str string
- if len(r.Interfaces) > 0 {
- str += fmt.Sprintf("Interfaces:%+v, ", r.Interfaces)
- }
- if len(r.IPs) > 0 {
- str += fmt.Sprintf("IP:%+v, ", r.IPs)
- }
- if len(r.Routes) > 0 {
- str += fmt.Sprintf("Routes:%+v, ", r.Routes)
- }
- return fmt.Sprintf("%sDNS:%+v", str, r.DNS)
-}
-
-// Convert this old version result to the current CNI version result
-func (r *Result) Convert() (*Result, error) {
- return r, nil
-}
-
-// Interface contains values about the created interfaces
-type Interface struct {
- Name string `json:"name"`
- Mac string `json:"mac,omitempty"`
- Sandbox string `json:"sandbox,omitempty"`
-}
-
-func (i *Interface) String() string {
- return fmt.Sprintf("%+v", *i)
-}
-
-// IPConfig contains values necessary to configure an IP address on an interface
-type IPConfig struct {
- // IP version, either "4" or "6"
- Version string
- // Index into Result structs Interfaces list
- Interface int
- Address net.IPNet
- Gateway net.IP
-}
-
-func (i *IPConfig) String() string {
- return fmt.Sprintf("%+v", *i)
-}
-
-// JSON (un)marshallable types
-type ipConfig struct {
- Version string `json:"version"`
- Interface int `json:"interface,omitempty"`
- Address types.IPNet `json:"address"`
- Gateway net.IP `json:"gateway,omitempty"`
-}
-
-func (c *IPConfig) MarshalJSON() ([]byte, error) {
- ipc := ipConfig{
- Version: c.Version,
- Interface: c.Interface,
- Address: types.IPNet(c.Address),
- Gateway: c.Gateway,
- }
-
- return json.Marshal(ipc)
-}
-
-func (c *IPConfig) UnmarshalJSON(data []byte) error {
- ipc := ipConfig{}
- if err := json.Unmarshal(data, &ipc); err != nil {
- return err
- }
-
- c.Version = ipc.Version
- c.Interface = ipc.Interface
- c.Address = net.IPNet(ipc.Address)
- c.Gateway = ipc.Gateway
- return nil
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package current_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "testing"
-)
-
-func TestTypesCurrent(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "Current Types Suite")
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package current_test
-
-import (
- "io/ioutil"
- "net"
- "os"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/types/current"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-func testResult() *current.Result {
- ipv4, err := types.ParseCIDR("1.2.3.30/24")
- Expect(err).NotTo(HaveOccurred())
- Expect(ipv4).NotTo(BeNil())
-
- routegwv4, routev4, err := net.ParseCIDR("15.5.6.8/24")
- Expect(err).NotTo(HaveOccurred())
- Expect(routev4).NotTo(BeNil())
- Expect(routegwv4).NotTo(BeNil())
-
- ipv6, err := types.ParseCIDR("abcd:1234:ffff::cdde/64")
- Expect(err).NotTo(HaveOccurred())
- Expect(ipv6).NotTo(BeNil())
-
- routegwv6, routev6, err := net.ParseCIDR("1111:dddd::aaaa/80")
- Expect(err).NotTo(HaveOccurred())
- Expect(routev6).NotTo(BeNil())
- Expect(routegwv6).NotTo(BeNil())
-
- // Set every field of the struct to ensure source compatibility
- return ¤t.Result{
- CNIVersion: "0.3.1",
- Interfaces: []*current.Interface{
- {
- Name: "eth0",
- Mac: "00:11:22:33:44:55",
- Sandbox: "/proc/3553/ns/net",
- },
- },
- IPs: []*current.IPConfig{
- {
- Version: "4",
- Interface: 0,
- Address: *ipv4,
- Gateway: net.ParseIP("1.2.3.1"),
- },
- {
- Version: "6",
- Interface: 0,
- Address: *ipv6,
- Gateway: net.ParseIP("abcd:1234:ffff::1"),
- },
- },
- Routes: []*types.Route{
- {Dst: *routev4, GW: routegwv4},
- {Dst: *routev6, GW: routegwv6},
- },
- DNS: types.DNS{
- Nameservers: []string{"1.2.3.4", "1::cafe"},
- Domain: "acompany.com",
- Search: []string{"somedomain.com", "otherdomain.net"},
- Options: []string{"foo", "bar"},
- },
- }
-}
-
-var _ = Describe("Current types operations", func() {
- It("correctly encodes a 0.3.x Result", func() {
- res := testResult()
-
- Expect(res.String()).To(Equal("Interfaces:[{Name:eth0 Mac:00:11:22:33:44:55 Sandbox:/proc/3553/ns/net}], IP:[{Version:4 Interface:0 Address:{IP:1.2.3.30 Mask:ffffff00} Gateway:1.2.3.1} {Version:6 Interface:0 Address:{IP:abcd:1234:ffff::cdde Mask:ffffffffffffffff0000000000000000} Gateway:abcd:1234:ffff::1}], Routes:[{Dst:{IP:15.5.6.0 Mask:ffffff00} GW:15.5.6.8} {Dst:{IP:1111:dddd:: Mask:ffffffffffffffffffff000000000000} GW:1111:dddd::aaaa}], DNS:{Nameservers:[1.2.3.4 1::cafe] Domain:acompany.com Search:[somedomain.com otherdomain.net] Options:[foo bar]}"))
-
- // Redirect stdout to capture JSON result
- oldStdout := os.Stdout
- r, w, err := os.Pipe()
- Expect(err).NotTo(HaveOccurred())
-
- os.Stdout = w
- err = res.Print()
- w.Close()
- Expect(err).NotTo(HaveOccurred())
-
- // parse the result
- out, err := ioutil.ReadAll(r)
- os.Stdout = oldStdout
- Expect(err).NotTo(HaveOccurred())
-
- Expect(string(out)).To(Equal(`{
- "cniVersion": "0.3.1",
- "interfaces": [
- {
- "name": "eth0",
- "mac": "00:11:22:33:44:55",
- "sandbox": "/proc/3553/ns/net"
- }
- ],
- "ips": [
- {
- "version": "4",
- "address": "1.2.3.30/24",
- "gateway": "1.2.3.1"
- },
- {
- "version": "6",
- "address": "abcd:1234:ffff::cdde/64",
- "gateway": "abcd:1234:ffff::1"
- }
- ],
- "routes": [
- {
- "dst": "15.5.6.0/24",
- "gw": "15.5.6.8"
- },
- {
- "dst": "1111:dddd::/80",
- "gw": "1111:dddd::aaaa"
- }
- ],
- "dns": {
- "nameservers": [
- "1.2.3.4",
- "1::cafe"
- ],
- "domain": "acompany.com",
- "search": [
- "somedomain.com",
- "otherdomain.net"
- ],
- "options": [
- "foo",
- "bar"
- ]
- }
-}`))
- })
-
- It("correctly encodes a 0.1.0 Result", func() {
- res, err := testResult().GetAsVersion("0.1.0")
- Expect(err).NotTo(HaveOccurred())
-
- Expect(res.String()).To(Equal("IP4:{IP:{IP:1.2.3.30 Mask:ffffff00} Gateway:1.2.3.1 Routes:[{Dst:{IP:15.5.6.0 Mask:ffffff00} GW:15.5.6.8}]}, IP6:{IP:{IP:abcd:1234:ffff::cdde Mask:ffffffffffffffff0000000000000000} Gateway:abcd:1234:ffff::1 Routes:[{Dst:{IP:1111:dddd:: Mask:ffffffffffffffffffff000000000000} GW:1111:dddd::aaaa}]}, DNS:{Nameservers:[1.2.3.4 1::cafe] Domain:acompany.com Search:[somedomain.com otherdomain.net] Options:[foo bar]}"))
-
- // Redirect stdout to capture JSON result
- oldStdout := os.Stdout
- r, w, err := os.Pipe()
- Expect(err).NotTo(HaveOccurred())
-
- os.Stdout = w
- err = res.Print()
- w.Close()
- Expect(err).NotTo(HaveOccurred())
-
- // parse the result
- out, err := ioutil.ReadAll(r)
- os.Stdout = oldStdout
- Expect(err).NotTo(HaveOccurred())
-
- Expect(string(out)).To(Equal(`{
- "cniVersion": "0.2.0",
- "ip4": {
- "ip": "1.2.3.30/24",
- "gateway": "1.2.3.1",
- "routes": [
- {
- "dst": "15.5.6.0/24",
- "gw": "15.5.6.8"
- }
- ]
- },
- "ip6": {
- "ip": "abcd:1234:ffff::cdde/64",
- "gateway": "abcd:1234:ffff::1",
- "routes": [
- {
- "dst": "1111:dddd::/80",
- "gw": "1111:dddd::aaaa"
- }
- ]
- },
- "dns": {
- "nameservers": [
- "1.2.3.4",
- "1::cafe"
- ],
- "domain": "acompany.com",
- "search": [
- "somedomain.com",
- "otherdomain.net"
- ],
- "options": [
- "foo",
- "bar"
- ]
- }
-}`))
- })
-})
+++ /dev/null
-// 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.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package types
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "net"
- "os"
-)
-
-// like net.IPNet but adds JSON marshalling and unmarshalling
-type IPNet net.IPNet
-
-// ParseCIDR takes a string like "10.2.3.1/24" and
-// return IPNet with "10.2.3.1" and /24 mask
-func ParseCIDR(s string) (*net.IPNet, error) {
- ip, ipn, err := net.ParseCIDR(s)
- if err != nil {
- return nil, err
- }
-
- ipn.IP = ip
- return ipn, nil
-}
-
-func (n IPNet) MarshalJSON() ([]byte, error) {
- return json.Marshal((*net.IPNet)(&n).String())
-}
-
-func (n *IPNet) UnmarshalJSON(data []byte) error {
- var s string
- if err := json.Unmarshal(data, &s); err != nil {
- return err
- }
-
- tmp, err := ParseCIDR(s)
- if err != nil {
- return err
- }
-
- *n = IPNet(*tmp)
- return nil
-}
-
-// NetConf describes a network.
-type NetConf struct {
- CNIVersion string `json:"cniVersion,omitempty"`
-
- Name string `json:"name,omitempty"`
- Type string `json:"type,omitempty"`
- Capabilities map[string]bool `json:"capabilities,omitempty"`
- IPAM struct {
- Type string `json:"type,omitempty"`
- } `json:"ipam,omitempty"`
- DNS DNS `json:"dns"`
-}
-
-// NetConfList describes an ordered list of networks.
-type NetConfList struct {
- CNIVersion string `json:"cniVersion,omitempty"`
-
- Name string `json:"name,omitempty"`
- Plugins []*NetConf `json:"plugins,omitempty"`
-}
-
-type ResultFactoryFunc func([]byte) (Result, error)
-
-// Result is an interface that provides the result of plugin execution
-type Result interface {
- // The highest CNI specification result verison the result supports
- // without having to convert
- Version() string
-
- // Returns the result converted into the requested CNI specification
- // result version, or an error if conversion failed
- GetAsVersion(version string) (Result, error)
-
- // Prints the result in JSON format to stdout
- Print() error
-
- // Returns a JSON string representation of the result
- String() string
-}
-
-func PrintResult(result Result, version string) error {
- newResult, err := result.GetAsVersion(version)
- if err != nil {
- return err
- }
- return newResult.Print()
-}
-
-// DNS contains values interesting for DNS resolvers
-type DNS struct {
- Nameservers []string `json:"nameservers,omitempty"`
- Domain string `json:"domain,omitempty"`
- Search []string `json:"search,omitempty"`
- Options []string `json:"options,omitempty"`
-}
-
-type Route struct {
- Dst net.IPNet
- GW net.IP
-}
-
-func (r *Route) String() string {
- return fmt.Sprintf("%+v", *r)
-}
-
-// Well known error codes
-// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
-const (
- ErrUnknown uint = iota // 0
- ErrIncompatibleCNIVersion // 1
- ErrUnsupportedField // 2
-)
-
-type Error struct {
- Code uint `json:"code"`
- Msg string `json:"msg"`
- Details string `json:"details,omitempty"`
-}
-
-func (e *Error) Error() string {
- return e.Msg
-}
-
-func (e *Error) Print() error {
- return prettyPrint(e)
-}
-
-// net.IPNet is not JSON (un)marshallable so this duality is needed
-// for our custom IPNet type
-
-// JSON (un)marshallable types
-type route struct {
- Dst IPNet `json:"dst"`
- GW net.IP `json:"gw,omitempty"`
-}
-
-func (r *Route) UnmarshalJSON(data []byte) error {
- rt := route{}
- if err := json.Unmarshal(data, &rt); err != nil {
- return err
- }
-
- r.Dst = net.IPNet(rt.Dst)
- r.GW = rt.GW
- return nil
-}
-
-func (r *Route) MarshalJSON() ([]byte, error) {
- rt := route{
- Dst: IPNet(r.Dst),
- GW: r.GW,
- }
-
- return json.Marshal(rt)
-}
-
-func prettyPrint(obj interface{}) error {
- data, err := json.MarshalIndent(obj, "", " ")
- if err != nil {
- return err
- }
- _, err = os.Stdout.Write(data)
- return err
-}
-
-// NotImplementedError is used to indicate that a method is not implemented for the given platform
-var NotImplementedError = errors.New("Not Implemented")
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package types_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "testing"
-)
-
-func TestTypes(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "Types Suite")
-}
import (
"net"
- "github.com/containernetworking/cni/pkg/utils/hwaddr"
+ "github.com/containernetworking/plugins/pkg/utils/hwaddr"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version
-
-import (
- "encoding/json"
- "fmt"
-)
-
-// ConfigDecoder can decode the CNI version available in network config data
-type ConfigDecoder struct{}
-
-func (*ConfigDecoder) Decode(jsonBytes []byte) (string, error) {
- var conf struct {
- CNIVersion string `json:"cniVersion"`
- }
- err := json.Unmarshal(jsonBytes, &conf)
- if err != nil {
- return "", fmt.Errorf("decoding version from network config: %s", err)
- }
- if conf.CNIVersion == "" {
- return "0.1.0", nil
- }
- return conf.CNIVersion, nil
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version_test
-
-import (
- "github.com/containernetworking/cni/pkg/version"
-
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("Decoding the version of network config", func() {
- var (
- decoder *version.ConfigDecoder
- configBytes []byte
- )
-
- BeforeEach(func() {
- decoder = &version.ConfigDecoder{}
- configBytes = []byte(`{ "cniVersion": "4.3.2" }`)
- })
-
- Context("when the version is explict", func() {
- It("returns the version", func() {
- version, err := decoder.Decode(configBytes)
- Expect(err).NotTo(HaveOccurred())
-
- Expect(version).To(Equal("4.3.2"))
- })
- })
-
- Context("when the version is not present in the config", func() {
- BeforeEach(func() {
- configBytes = []byte(`{ "not-a-version-field": "foo" }`)
- })
-
- It("assumes the config is version 0.1.0", func() {
- version, err := decoder.Decode(configBytes)
- Expect(err).NotTo(HaveOccurred())
-
- Expect(version).To(Equal("0.1.0"))
- })
- })
-
- Context("when the config data is malformed", func() {
- BeforeEach(func() {
- configBytes = []byte(`{{{`)
- })
-
- It("returns a useful error", func() {
- _, err := decoder.Decode(configBytes)
- Expect(err).To(MatchError(HavePrefix(
- "decoding version from network config: invalid character",
- )))
- })
- })
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package legacy_examples
-
-// An ExampleRuntime is a small program that uses libcni to invoke a network plugin.
-// It should call ADD and DELETE, verifying all intermediate steps
-// and data structures.
-type ExampleRuntime struct {
- Example
- NetConfs []string // The network configuration names to pass
-}
-
-// NetConfs are various versioned network configuration files. Examples should
-// specify which version they expect
-var NetConfs = map[string]string{
- "unversioned": `{
- "name": "default",
- "type": "ptp",
- "ipam": {
- "type": "host-local",
- "subnet": "10.1.2.0/24"
- }
-}`,
- "0.1.0": `{
- "cniVersion": "0.1.0",
- "name": "default",
- "type": "ptp",
- "ipam": {
- "type": "host-local",
- "subnet": "10.1.2.0/24"
- }
-}`,
-}
-
-// V010_Runtime creates a simple ptp network configuration, then
-// executes libcni against the currently-built plugins.
-var V010_Runtime = ExampleRuntime{
- NetConfs: []string{"unversioned", "0.1.0"},
- Example: Example{
- Name: "example_invoker_v010",
- CNIRepoGitRef: "c0d34c69", //version with ns.Do
- PluginSource: `package main
-
-import (
- "fmt"
- "io/ioutil"
- "net"
- "os"
-
- "github.com/containernetworking/cni/pkg/ns"
- "github.com/containernetworking/cni/libcni"
-)
-
-func main(){
- code := exec()
- os.Exit(code)
-}
-
-func exec() int {
- confBytes, err := ioutil.ReadAll(os.Stdin)
- if err != nil {
- fmt.Printf("could not read netconfig from stdin: %+v", err)
- return 1
- }
-
- netConf, err := libcni.ConfFromBytes(confBytes)
- if err != nil {
- fmt.Printf("could not parse netconfig: %+v", err)
- return 1
- }
- fmt.Printf("Parsed network configuration: %+v\n", netConf.Network)
-
- if len(os.Args) == 1 {
- fmt.Printf("Expect CNI plugin paths in argv")
- return 1
- }
-
- targetNs, err := ns.NewNS()
- if err != nil {
- fmt.Printf("Could not create ns: %+v", err)
- return 1
- }
- defer targetNs.Close()
-
- ifName := "eth0"
-
- runtimeConf := &libcni.RuntimeConf{
- ContainerID: "some-container-id",
- NetNS: targetNs.Path(),
- IfName: ifName,
- }
-
- cniConfig := &libcni.CNIConfig{Path: os.Args[1:]}
-
- result, err := cniConfig.AddNetwork(netConf, runtimeConf)
- if err != nil {
- fmt.Printf("AddNetwork failed: %+v", err)
- return 2
- }
- fmt.Printf("AddNetwork result: %+v", result)
-
- expectedIP := result.IP4.IP
-
- err = targetNs.Do(func(ns.NetNS) error {
- netif, err := net.InterfaceByName(ifName)
- if err != nil {
- return fmt.Errorf("could not retrieve interface: %v", err)
- }
-
- addrs, err := netif.Addrs()
- if err != nil {
- return fmt.Errorf("could not retrieve addresses, %+v", err)
- }
-
- found := false
- for _, addr := range addrs {
- if addr.String() == expectedIP.String() {
- found = true
- break
- }
- }
-
- if !found {
- return fmt.Errorf("Far-side link did not have expected address %s", expectedIP)
- }
- return nil
- })
- if err != nil {
- fmt.Println(err)
- return 4
- }
-
- err = cniConfig.DelNetwork(netConf, runtimeConf)
- if err != nil {
- fmt.Printf("DelNetwork failed: %v", err)
- return 5
- }
-
- err = targetNs.Do(func(ns.NetNS) error {
- _, err := net.InterfaceByName(ifName)
- if err == nil {
- return fmt.Errorf("interface was not deleted")
- }
- return nil
- })
- if err != nil {
- fmt.Println(err)
- return 6
- }
-
- return 0
-}
-`,
- },
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package legacy_examples contains sample code from prior versions of
-// the CNI library, for use in verifying backwards compatibility.
-package legacy_examples
-
-import (
- "io/ioutil"
- "net"
- "path/filepath"
- "sync"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/types/020"
- "github.com/containernetworking/cni/pkg/version/testhelpers"
-)
-
-// An Example is a Git reference to the CNI repo and a Golang CNI plugin that
-// builds against that version of the repo.
-//
-// By convention, every Example plugin returns an ADD result that is
-// semantically equivalent to the ExpectedResult.
-type Example struct {
- Name string
- CNIRepoGitRef string
- PluginSource string
-}
-
-var buildDir = ""
-var buildDirLock sync.Mutex
-
-func ensureBuildDirExists() error {
- buildDirLock.Lock()
- defer buildDirLock.Unlock()
-
- if buildDir != "" {
- return nil
- }
-
- var err error
- buildDir, err = ioutil.TempDir("", "cni-example-plugins")
- return err
-}
-
-// Build builds the example, returning the path to the binary
-func (e Example) Build() (string, error) {
- if err := ensureBuildDirExists(); err != nil {
- return "", err
- }
-
- outBinPath := filepath.Join(buildDir, e.Name)
-
- if err := testhelpers.BuildAt([]byte(e.PluginSource), e.CNIRepoGitRef, outBinPath); err != nil {
- return "", err
- }
- return outBinPath, nil
-}
-
-// V010 acts like a CNI plugin from the v0.1.0 era
-var V010 = Example{
- Name: "example_v010",
- CNIRepoGitRef: "2c482f4",
- PluginSource: `package main
-
-import (
- "net"
-
- "github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/types"
-)
-
-var result = types.Result{
- IP4: &types.IPConfig{
- IP: net.IPNet{
- IP: net.ParseIP("10.1.2.3"),
- Mask: net.CIDRMask(24, 32),
- },
- Gateway: net.ParseIP("10.1.2.1"),
- Routes: []types.Route{
- types.Route{
- Dst: net.IPNet{
- IP: net.ParseIP("0.0.0.0"),
- Mask: net.CIDRMask(0, 32),
- },
- GW: net.ParseIP("10.1.0.1"),
- },
- },
- },
- DNS: types.DNS{
- Nameservers: []string{"8.8.8.8"},
- Domain: "example.com",
- },
-}
-
-func c(_ *skel.CmdArgs) error { result.Print(); return nil }
-
-func main() { skel.PluginMain(c, c) }
-`,
-}
-
-// ExpectedResult is the current representation of the plugin result
-// that is expected from each of the examples.
-//
-// As we change the CNI spec, the Result type and this value may change.
-// The text of the example plugins should not.
-var ExpectedResult = &types020.Result{
- IP4: &types020.IPConfig{
- IP: net.IPNet{
- IP: net.ParseIP("10.1.2.3"),
- Mask: net.CIDRMask(24, 32),
- },
- Gateway: net.ParseIP("10.1.2.1"),
- Routes: []types.Route{
- types.Route{
- Dst: net.IPNet{
- IP: net.ParseIP("0.0.0.0"),
- Mask: net.CIDRMask(0, 32),
- },
- GW: net.ParseIP("10.1.0.1"),
- },
- },
- },
- DNS: types.DNS{
- Nameservers: []string{"8.8.8.8"},
- Domain: "example.com",
- },
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package legacy_examples_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "testing"
-)
-
-func TestLegacyExamples(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "LegacyExamples Suite")
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package legacy_examples_test
-
-import (
- "os"
- "path/filepath"
-
- "github.com/containernetworking/cni/pkg/version/legacy_examples"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("The v0.1.0 Example", func() {
- It("builds ok", func() {
- example := legacy_examples.V010
- pluginPath, err := example.Build()
- Expect(err).NotTo(HaveOccurred())
-
- Expect(filepath.Base(pluginPath)).To(Equal(example.Name))
-
- Expect(os.RemoveAll(pluginPath)).To(Succeed())
- })
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version
-
-import (
- "encoding/json"
- "fmt"
- "io"
-)
-
-// PluginInfo reports information about CNI versioning
-type PluginInfo interface {
- // SupportedVersions returns one or more CNI spec versions that the plugin
- // supports. If input is provided in one of these versions, then the plugin
- // promises to use the same CNI version in its response
- SupportedVersions() []string
-
- // Encode writes this CNI version information as JSON to the given Writer
- Encode(io.Writer) error
-}
-
-type pluginInfo struct {
- CNIVersion_ string `json:"cniVersion"`
- SupportedVersions_ []string `json:"supportedVersions,omitempty"`
-}
-
-// pluginInfo implements the PluginInfo interface
-var _ PluginInfo = &pluginInfo{}
-
-func (p *pluginInfo) Encode(w io.Writer) error {
- return json.NewEncoder(w).Encode(p)
-}
-
-func (p *pluginInfo) SupportedVersions() []string {
- return p.SupportedVersions_
-}
-
-// PluginSupports returns a new PluginInfo that will report the given versions
-// as supported
-func PluginSupports(supportedVersions ...string) PluginInfo {
- if len(supportedVersions) < 1 {
- panic("programmer error: you must support at least one version")
- }
- return &pluginInfo{
- CNIVersion_: Current(),
- SupportedVersions_: supportedVersions,
- }
-}
-
-// PluginDecoder can decode the response returned by a plugin's VERSION command
-type PluginDecoder struct{}
-
-func (*PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) {
- var info pluginInfo
- err := json.Unmarshal(jsonBytes, &info)
- if err != nil {
- return nil, fmt.Errorf("decoding version info: %s", err)
- }
- if info.CNIVersion_ == "" {
- return nil, fmt.Errorf("decoding version info: missing field cniVersion")
- }
- if len(info.SupportedVersions_) == 0 {
- if info.CNIVersion_ == "0.2.0" {
- return PluginSupports("0.1.0", "0.2.0"), nil
- }
- return nil, fmt.Errorf("decoding version info: missing field supportedVersions")
- }
- return &info, nil
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version_test
-
-import (
- "github.com/containernetworking/cni/pkg/version"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("Decoding versions reported by a plugin", func() {
- var (
- decoder *version.PluginDecoder
- versionStdout []byte
- )
-
- BeforeEach(func() {
- decoder = &version.PluginDecoder{}
- versionStdout = []byte(`{
- "cniVersion": "some-library-version",
- "supportedVersions": [ "some-version", "some-other-version" ]
- }`)
- })
-
- It("returns a PluginInfo that represents the given json bytes", func() {
- pluginInfo, err := decoder.Decode(versionStdout)
- Expect(err).NotTo(HaveOccurred())
- Expect(pluginInfo).NotTo(BeNil())
- Expect(pluginInfo.SupportedVersions()).To(Equal([]string{
- "some-version",
- "some-other-version",
- }))
- })
-
- Context("when the bytes cannot be decoded as json", func() {
- BeforeEach(func() {
- versionStdout = []byte(`{{{`)
- })
-
- It("returns a meaningful error", func() {
- _, err := decoder.Decode(versionStdout)
- Expect(err).To(MatchError("decoding version info: invalid character '{' looking for beginning of object key string"))
- })
- })
-
- Context("when the json bytes are missing the required CNIVersion field", func() {
- BeforeEach(func() {
- versionStdout = []byte(`{ "supportedVersions": [ "foo" ] }`)
- })
-
- It("returns a meaningful error", func() {
- _, err := decoder.Decode(versionStdout)
- Expect(err).To(MatchError("decoding version info: missing field cniVersion"))
- })
- })
-
- Context("when there are no supported versions", func() {
- BeforeEach(func() {
- versionStdout = []byte(`{ "cniVersion": "0.2.0" }`)
- })
-
- It("assumes that the supported versions are 0.1.0 and 0.2.0", func() {
- pluginInfo, err := decoder.Decode(versionStdout)
- Expect(err).NotTo(HaveOccurred())
- Expect(pluginInfo).NotTo(BeNil())
- Expect(pluginInfo.SupportedVersions()).To(Equal([]string{
- "0.1.0",
- "0.2.0",
- }))
- })
- })
-
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version
-
-import "fmt"
-
-type ErrorIncompatible struct {
- Config string
- Supported []string
-}
-
-func (e *ErrorIncompatible) Details() string {
- return fmt.Sprintf("config is %q, plugin supports %q", e.Config, e.Supported)
-}
-
-func (e *ErrorIncompatible) Error() string {
- return fmt.Sprintf("incompatible CNI versions: %s", e.Details())
-}
-
-type Reconciler struct{}
-
-func (r *Reconciler) Check(configVersion string, pluginInfo PluginInfo) *ErrorIncompatible {
- return r.CheckRaw(configVersion, pluginInfo.SupportedVersions())
-}
-
-func (*Reconciler) CheckRaw(configVersion string, supportedVersions []string) *ErrorIncompatible {
- for _, supportedVersion := range supportedVersions {
- if configVersion == supportedVersion {
- return nil
- }
- }
-
- return &ErrorIncompatible{
- Config: configVersion,
- Supported: supportedVersions,
- }
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version_test
-
-import (
- "github.com/containernetworking/cni/pkg/version"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("Reconcile versions of net config with versions supported by plugins", func() {
- var (
- reconciler *version.Reconciler
- pluginInfo version.PluginInfo
- )
-
- BeforeEach(func() {
- reconciler = &version.Reconciler{}
- pluginInfo = version.PluginSupports("1.2.3", "4.3.2")
- })
-
- It("succeeds if the config version is supported by the plugin", func() {
- err := reconciler.Check("4.3.2", pluginInfo)
- Expect(err).NotTo(HaveOccurred())
- })
-
- Context("when the config version is not supported by the plugin", func() {
- It("returns a helpful error", func() {
- err := reconciler.Check("0.1.0", pluginInfo)
-
- Expect(err).To(Equal(&version.ErrorIncompatible{
- Config: "0.1.0",
- Supported: []string{"1.2.3", "4.3.2"},
- }))
-
- Expect(err.Error()).To(Equal(`incompatible CNI versions: config is "0.1.0", plugin supports ["1.2.3" "4.3.2"]`))
- })
- })
-})
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package testhelpers supports testing of CNI components of different versions
-//
-// For example, to build a plugin against an old version of the CNI library,
-// we can pass the plugin's source and the old git commit reference to BuildAt.
-// We could then test how the built binary responds when called by the latest
-// version of this library.
-package testhelpers
-
-import (
- "fmt"
- "io/ioutil"
- "math/rand"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "time"
-)
-
-const packageBaseName = "github.com/containernetworking/cni"
-
-func run(cmd *exec.Cmd) error {
- out, err := cmd.CombinedOutput()
- if err != nil {
- command := strings.Join(cmd.Args, " ")
- return fmt.Errorf("running %q: %s", command, out)
- }
- return nil
-}
-
-func goBuildEnviron(gopath string) []string {
- environ := os.Environ()
- for i, kvp := range environ {
- if strings.HasPrefix(kvp, "GOPATH=") {
- environ[i] = "GOPATH=" + gopath
- return environ
- }
- }
- environ = append(environ, "GOPATH="+gopath)
- return environ
-}
-
-func buildGoProgram(gopath, packageName, outputFilePath string) error {
- cmd := exec.Command("go", "build", "-o", outputFilePath, packageName)
- cmd.Env = goBuildEnviron(gopath)
- return run(cmd)
-}
-
-func createSingleFilePackage(gopath, packageName string, fileContents []byte) error {
- dirName := filepath.Join(gopath, "src", packageName)
- err := os.MkdirAll(dirName, 0700)
- if err != nil {
- return err
- }
-
- return ioutil.WriteFile(filepath.Join(dirName, "main.go"), fileContents, 0600)
-}
-
-func removePackage(gopath, packageName string) error {
- dirName := filepath.Join(gopath, "src", packageName)
- return os.RemoveAll(dirName)
-}
-
-func isRepoRoot(path string) bool {
- _, err := ioutil.ReadDir(filepath.Join(path, ".git"))
- return (err == nil) && (filepath.Base(path) == "cni")
-}
-
-func LocateCurrentGitRepo() (string, error) {
- dir, err := os.Getwd()
- if err != nil {
- return "", err
- }
-
- for i := 0; i < 5; i++ {
- if isRepoRoot(dir) {
- return dir, nil
- }
-
- dir, err = filepath.Abs(filepath.Dir(dir))
- if err != nil {
- return "", fmt.Errorf("abs(dir(%q)): %s", dir, err)
- }
- }
-
- return "", fmt.Errorf("unable to find cni repo root, landed at %q", dir)
-}
-
-func gitCloneThisRepo(cloneDestination string) error {
- err := os.MkdirAll(cloneDestination, 0700)
- if err != nil {
- return err
- }
-
- currentGitRepo, err := LocateCurrentGitRepo()
- if err != nil {
- return err
- }
-
- return run(exec.Command("git", "clone", currentGitRepo, cloneDestination))
-}
-
-func gitCheckout(localRepo string, gitRef string) error {
- return run(exec.Command("git", "-C", localRepo, "checkout", gitRef))
-}
-
-// BuildAt builds the go programSource using the version of the CNI library
-// at gitRef, and saves the resulting binary file at outputFilePath
-func BuildAt(programSource []byte, gitRef string, outputFilePath string) error {
- tempGoPath, err := ioutil.TempDir("", "cni-git-")
- if err != nil {
- return err
- }
- defer os.RemoveAll(tempGoPath)
-
- cloneDestination := filepath.Join(tempGoPath, "src", packageBaseName)
- err = gitCloneThisRepo(cloneDestination)
- if err != nil {
- return err
- }
-
- err = gitCheckout(cloneDestination, gitRef)
- if err != nil {
- return err
- }
-
- rand.Seed(time.Now().UnixNano())
- testPackageName := fmt.Sprintf("test-package-%x", rand.Int31())
-
- err = createSingleFilePackage(tempGoPath, testPackageName, programSource)
- if err != nil {
- return err
- }
- defer removePackage(tempGoPath, testPackageName)
-
- err = buildGoProgram(tempGoPath, testPackageName, outputFilePath)
- if err != nil {
- return err
- }
-
- return nil
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package testhelpers_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "testing"
-)
-
-func TestTesthelpers(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "Testhelpers Suite")
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package testhelpers_test
-
-import (
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
-
- "github.com/containernetworking/cni/pkg/version/testhelpers"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("BuildAt", func() {
- var (
- gitRef string
- outputFilePath string
- outputDir string
- programSource []byte
- )
- BeforeEach(func() {
- programSource = []byte(`package main
-
-import "github.com/containernetworking/cni/pkg/skel"
-
-func c(_ *skel.CmdArgs) error { return nil }
-
-func main() { skel.PluginMain(c, c) }
-`)
- gitRef = "f4364185253"
-
- var err error
- outputDir, err = ioutil.TempDir("", "bin")
- Expect(err).NotTo(HaveOccurred())
- outputFilePath = filepath.Join(outputDir, "some-binary")
- })
-
- AfterEach(func() {
- Expect(os.RemoveAll(outputDir)).To(Succeed())
- })
-
- It("builds the provided source code using the CNI library at the given git ref", func() {
- Expect(outputFilePath).NotTo(BeAnExistingFile())
-
- err := testhelpers.BuildAt(programSource, gitRef, outputFilePath)
- Expect(err).NotTo(HaveOccurred())
-
- Expect(outputFilePath).To(BeAnExistingFile())
-
- cmd := exec.Command(outputFilePath)
- cmd.Env = []string{"CNI_COMMAND=VERSION"}
- output, err := cmd.CombinedOutput()
- Expect(err).To(BeAssignableToTypeOf(&exec.ExitError{}))
- Expect(output).To(ContainSubstring("unknown CNI_COMMAND: VERSION"))
- })
-})
-
-var _ = Describe("LocateCurrentGitRepo", func() {
- It("returns the path to the root of the CNI git repo", func() {
- path, err := testhelpers.LocateCurrentGitRepo()
- Expect(err).NotTo(HaveOccurred())
-
- AssertItIsTheCNIRepoRoot(path)
- })
-
- Context("when run from a different directory", func() {
- BeforeEach(func() {
- os.Chdir("..")
- })
-
- It("still finds the CNI repo root", func() {
- path, err := testhelpers.LocateCurrentGitRepo()
- Expect(err).NotTo(HaveOccurred())
-
- AssertItIsTheCNIRepoRoot(path)
- })
- })
-})
-
-func AssertItIsTheCNIRepoRoot(path string) {
- Expect(path).To(BeADirectory())
- files, err := ioutil.ReadDir(path)
- Expect(err).NotTo(HaveOccurred())
-
- names := []string{}
- for _, file := range files {
- names = append(names, file.Name())
- }
-
- Expect(names).To(ContainElement("SPEC.md"))
- Expect(names).To(ContainElement("libcni"))
- Expect(names).To(ContainElement("cnitool"))
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version
-
-import (
- "fmt"
-
- "github.com/containernetworking/cni/pkg/types"
- "github.com/containernetworking/cni/pkg/types/020"
- "github.com/containernetworking/cni/pkg/types/current"
-)
-
-// Current reports the version of the CNI spec implemented by this library
-func Current() string {
- return "0.3.1"
-}
-
-// Legacy PluginInfo describes a plugin that is backwards compatible with the
-// CNI spec version 0.1.0. In particular, a runtime compiled against the 0.1.0
-// library ought to work correctly with a plugin that reports support for
-// Legacy versions.
-//
-// Any future CNI spec versions which meet this definition should be added to
-// this list.
-var Legacy = PluginSupports("0.1.0", "0.2.0")
-var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1")
-
-var resultFactories = []struct {
- supportedVersions []string
- newResult types.ResultFactoryFunc
-}{
- {current.SupportedVersions, current.NewResult},
- {types020.SupportedVersions, types020.NewResult},
-}
-
-// Finds a Result object matching the requested version (if any) and asks
-// that object to parse the plugin result, returning an error if parsing failed.
-func NewResult(version string, resultBytes []byte) (types.Result, error) {
- reconciler := &Reconciler{}
- for _, resultFactory := range resultFactories {
- err := reconciler.CheckRaw(version, resultFactory.supportedVersions)
- if err == nil {
- // Result supports this version
- return resultFactory.newResult(resultBytes)
- }
- }
-
- return nil, fmt.Errorf("unsupported CNI result version %q", version)
-}
+++ /dev/null
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package version_test
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "testing"
-)
-
-func TestVersion(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "Version Suite")
-}
"github.com/d2g/dhcp4client"
"github.com/vishvananda/netlink"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/types"
+ "github.com/containernetworking/plugins/pkg/ns"
)
// RFC 2131 suggests using exponential backoff, starting with 4sec
"net"
"os"
- "github.com/containernetworking/cni/pkg/ip"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ip"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend"
)
"strings"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/020"
"github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/testutils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"runtime"
"syscall"
- "github.com/containernetworking/cni/pkg/ip"
- "github.com/containernetworking/cni/pkg/ipam"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
- "github.com/containernetworking/cni/pkg/utils"
"github.com/containernetworking/cni/pkg/version"
+ "github.com/containernetworking/plugins/pkg/ip"
+ "github.com/containernetworking/plugins/pkg/ipam"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/utils"
"github.com/vishvananda/netlink"
)
"strings"
"syscall"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/020"
"github.com/containernetworking/cni/pkg/types/current"
-
- "github.com/containernetworking/cni/pkg/utils/hwaddr"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
+ "github.com/containernetworking/plugins/pkg/utils/hwaddr"
"github.com/vishvananda/netlink"
"fmt"
"runtime"
- "github.com/containernetworking/cni/pkg/ip"
- "github.com/containernetworking/cni/pkg/ipam"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/cni/pkg/version"
+ "github.com/containernetworking/plugins/pkg/ip"
+ "github.com/containernetworking/plugins/pkg/ipam"
+ "github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
)
"net"
"syscall"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
"github.com/vishvananda/netlink"
package main
import (
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/cni/pkg/version"
+ "github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
)
"os/exec"
"strings"
- "github.com/containernetworking/cni/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/ns"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
"net"
"runtime"
- "github.com/containernetworking/cni/pkg/ip"
- "github.com/containernetworking/cni/pkg/ipam"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
- "github.com/containernetworking/cni/pkg/utils/sysctl"
"github.com/containernetworking/cni/pkg/version"
+ "github.com/containernetworking/plugins/pkg/ip"
+ "github.com/containernetworking/plugins/pkg/ipam"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/utils/sysctl"
"github.com/vishvananda/netlink"
)
"net"
"syscall"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
- "github.com/containernetworking/cni/pkg/utils/hwaddr"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
+ "github.com/containernetworking/plugins/pkg/utils/hwaddr"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netlink"
- "github.com/containernetworking/cni/pkg/ip"
- "github.com/containernetworking/cni/pkg/ipam"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
- "github.com/containernetworking/cni/pkg/utils"
"github.com/containernetworking/cni/pkg/version"
+ "github.com/containernetworking/plugins/pkg/ip"
+ "github.com/containernetworking/plugins/pkg/ipam"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/utils"
)
func init() {
package main
import (
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
"github.com/vishvananda/netlink"
"fmt"
"runtime"
- "github.com/containernetworking/cni/pkg/ip"
- "github.com/containernetworking/cni/pkg/ipam"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/cni/pkg/version"
+ "github.com/containernetworking/plugins/pkg/ip"
+ "github.com/containernetworking/plugins/pkg/ipam"
+ "github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
)
"net"
"syscall"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
"github.com/vishvananda/netlink"
"io/ioutil"
"os"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"path/filepath"
"strings"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/cni/pkg/version"
+ "github.com/containernetworking/plugins/pkg/ns"
)
// TuningConf represents the network tuning configuration.
import (
"fmt"
- "github.com/containernetworking/cni/pkg/ns"
"github.com/containernetworking/cni/pkg/skel"
- "github.com/containernetworking/cni/pkg/testutils"
+ "github.com/containernetworking/plugins/pkg/ns"
+ "github.com/containernetworking/plugins/pkg/testutils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
echo "Running tests"
-TESTABLE="plugins/ipam/dhcp plugins/ipam/host-local plugins/ipam/host-local/backend/allocator plugins/main/loopback plugins/main/ipvlan plugins/main/macvlan plugins/main/bridge plugins/main/ptp plugins/meta/flannel plugins/main/vlan plugins/sample"
+TESTABLE="plugins/ipam/dhcp plugins/ipam/host-local plugins/ipam/host-local/backend/allocator plugins/main/loopback plugins/main/ipvlan plugins/main/macvlan plugins/main/bridge plugins/main/ptp plugins/meta/flannel plugins/main/vlan plugins/sample pkg/ip pkg/ipam pkg/ns pkg/utils pkg/utils/hwaddr pkg/utils/sysctl"
# user has not provided PKG override
if [ -z "$PKG" ]; then