summaryrefslogtreecommitdiff
path: root/vendor/github.com/containernetworking/cni
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-07-12 09:51:31 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2018-07-12 21:45:47 +0000
commit4f699db8dad05b770b4e02d3de67137517c3463b (patch)
treea7f474b248d283dd8805da73bf2b63ca56e4fd67 /vendor/github.com/containernetworking/cni
parente615b7d67124c548a3c7b422348821204ce32775 (diff)
downloadpodman-4f699db8dad05b770b4e02d3de67137517c3463b.tar.gz
podman-4f699db8dad05b770b4e02d3de67137517c3463b.tar.bz2
podman-4f699db8dad05b770b4e02d3de67137517c3463b.zip
Support multiple networks
This is a refresh of Dan William's PR #974 with a rebase and proper vendoring of ocicni and containernetworking/cni. It adds the ability to define multiple networks as so: podman run --network=net1,net2,foobar ... Signed-off-by: baude <bbaude@redhat.com> Closes: #1082 Approved by: baude
Diffstat (limited to 'vendor/github.com/containernetworking/cni')
-rw-r--r--vendor/github.com/containernetworking/cni/README.md15
-rw-r--r--vendor/github.com/containernetworking/cni/libcni/api.go244
-rw-r--r--vendor/github.com/containernetworking/cni/libcni/conf.go3
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go42
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/invoke/exec.go104
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go4
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/types/current/types.go6
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/types/types.go12
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/version/plugin.go59
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/version/version.go4
10 files changed, 404 insertions, 89 deletions
diff --git a/vendor/github.com/containernetworking/cni/README.md b/vendor/github.com/containernetworking/cni/README.md
index 793187c79..65ccda9f9 100644
--- a/vendor/github.com/containernetworking/cni/README.md
+++ b/vendor/github.com/containernetworking/cni/README.md
@@ -1,4 +1,5 @@
-[![Build Status](https://travis-ci.org/containernetworking/cni.svg?branch=master)](https://travis-ci.org/containernetworking/cni)
+[![Linux Build Status](https://travis-ci.org/containernetworking/cni.svg?branch=master)](https://travis-ci.org/containernetworking/cni)
+[![Windows Build Status](https://ci.appveyor.com/api/projects/status/wtrkou8oow7x533e/branch/master?svg=true)](https://ci.appveyor.com/project/cni-bot/cni/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/containernetworking/cni/badge.svg?branch=master)](https://coveralls.io/github/containernetworking/cni?branch=master)
[![Slack Status](https://cryptic-tundra-43194.herokuapp.com/badge.svg)](https://cryptic-tundra-43194.herokuapp.com/)
@@ -8,7 +9,9 @@
# Community Sync Meeting
-There is a community sync meeting for users and developers every 1-2 months. The next meeting will help on a Google Hangout and the link is in the [agenda](https://docs.google.com/document/d/10ECyT2mBGewsJUcmYmS8QNo1AcNgy2ZIe2xS7lShYhE/edit?usp=sharing) (Notes from previous meeting are also in this doc). The next meeting will be held on *Wednesday, June 21th* at *3:00pm UTC* [Add to Calendar]https://www.worldtimebuddy.com/?qm=1&lid=100,5,2643743,5391959&h=100&date=2017-6-21&sln=15-16).
+There is a community sync meeting for users and developers every 1-2 months. The next meeting will help on a Google Hangout and the link is in the [agenda](https://docs.google.com/document/d/10ECyT2mBGewsJUcmYmS8QNo1AcNgy2ZIe2xS7lShYhE/edit?usp=sharing) (Notes from previous meeting are also in this doc).
+
+The next meeting will be held on *Wednesday, October 4th* at *3:00pm UTC / 11:00am EDT / 8:00am PDT* [Add to Calendar](https://www.worldtimebuddy.com/?qm=1&lid=100,5,2643743,5391959&h=100&date=2017-10-04&sln=15-16).
---
@@ -35,11 +38,11 @@ To avoid duplication, we think it is prudent to define a common interface betwee
## Who is using CNI?
### Container runtimes
- [rkt - container engine](https://coreos.com/blog/rkt-cni-networking.html)
-- [Kurma - container runtime](http://kurma.io/)
- [Kubernetes - a system to simplify container operations](http://kubernetes.io/docs/admin/network-plugins/)
- [OpenShift - Kubernetes with additional enterprise features](https://github.com/openshift/origin/blob/master/docs/openshift_networking_requirements.md)
- [Cloud Foundry - a platform for cloud applications](https://github.com/cloudfoundry-incubator/cf-networking-release)
-- [Mesos - a distributed systems kernel](https://github.com/apache/mesos/blob/master/docs/cni.md)
+- [Apache Mesos - a distributed systems kernel](https://github.com/apache/mesos/blob/master/docs/cni.md)
+- [Amazon ECS - a highly scalable, high performance container management service](https://aws.amazon.com/ecs/)
### 3rd party plugins
- [Project Calico - a layer 3 virtual network](https://github.com/projectcalico/calico-cni)
@@ -54,6 +57,10 @@ To avoid duplication, we think it is prudent to define a common interface betwee
- [Nuage CNI - Nuage Networks SDN plugin for network policy kubernetes support ](https://github.com/nuagenetworks/nuage-cni)
- [Silk - a CNI plugin designed for Cloud Foundry](https://github.com/cloudfoundry-incubator/silk)
- [Linen - a CNI plugin designed for overlay networks with Open vSwitch and fit in SDN/OpenFlow network environment](https://github.com/John-Lin/linen-cni)
+- [Vhostuser - a Dataplane network plugin - Supports OVS-DPDK & VPP](https://github.com/intel/vhost-user-net-plugin)
+- [Amazon ECS CNI Plugins - a collection of CNI Plugins to configure containers with Amazon EC2 elastic network interfaces (ENIs)](https://github.com/aws/amazon-ecs-cni-plugins)
+- [Bonding CNI - a Link aggregating plugin to address failover and high availability network](https://github.com/Intel-Corp/bond-cni)
+- [ovn-kubernetes - an container network plugin built on Open vSwitch (OVS) and Open Virtual Networking (OVN) with support for both Linux and Windows](https://github.com/openvswitch/ovn-kubernetes)
The CNI team also maintains some [core plugins in a separate repository](https://github.com/containernetworking/plugins).
diff --git a/vendor/github.com/containernetworking/cni/libcni/api.go b/vendor/github.com/containernetworking/cni/libcni/api.go
index a23cbb2c5..d494e43d4 100644
--- a/vendor/github.com/containernetworking/cni/libcni/api.go
+++ b/vendor/github.com/containernetworking/cni/libcni/api.go
@@ -15,7 +15,11 @@
package libcni
import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
"os"
+ "path/filepath"
"strings"
"github.com/containernetworking/cni/pkg/invoke"
@@ -23,6 +27,14 @@ import (
"github.com/containernetworking/cni/pkg/version"
)
+var (
+ CacheDir = "/var/lib/cni"
+)
+
+// A RuntimeConf holds the arguments to one invocation of a CNI plugin
+// excepting the network configuration, with the nested exception that
+// the `runtimeConfig` from the network configuration is included
+// here.
type RuntimeConf struct {
ContainerID string
NetNS string
@@ -34,6 +46,9 @@ type RuntimeConf struct {
// in this map which match the capabilities of the plugin are passed
// to the plugin
CapabilityArgs map[string]interface{}
+
+ // A cache directory in which to library data. Defaults to CacheDir
+ CacheDir string
}
type NetworkConfig struct {
@@ -50,25 +65,38 @@ type NetworkConfigList struct {
type CNI interface {
AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
+ GetNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error
AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
+ GetNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
DelNetwork(net *NetworkConfig, rt *RuntimeConf) error
}
type CNIConfig struct {
Path []string
+ exec invoke.Exec
}
// CNIConfig implements the CNI interface
var _ CNI = &CNIConfig{}
-func buildOneConfig(list *NetworkConfigList, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) {
+// NewCNIConfig returns a new CNIConfig object that will search for plugins
+// in the given paths and use the given exec interface to run those plugins,
+// or if the exec interface is not given, will use a default exec handler.
+func NewCNIConfig(path []string, exec invoke.Exec) *CNIConfig {
+ return &CNIConfig{
+ Path: path,
+ exec: exec,
+ }
+}
+
+func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) {
var err error
inject := map[string]interface{}{
- "name": list.Name,
- "cniVersion": list.CNIVersion,
+ "name": name,
+ "cniVersion": cniVersion,
}
// Add previous plugin result
if prevResult != nil {
@@ -119,21 +147,37 @@ func injectRuntimeConfig(orig *NetworkConfig, rt *RuntimeConf) (*NetworkConfig,
return orig, nil
}
-// AddNetworkList executes a sequence of plugins with the ADD command
-func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
- var prevResult types.Result
- for _, net := range list.Plugins {
- pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
- if err != nil {
- return nil, err
+// ensure we have a usable exec if the CNIConfig was not given one
+func (c *CNIConfig) ensureExec() invoke.Exec {
+ if c.exec == nil {
+ c.exec = &invoke.DefaultExec{
+ RawExec: &invoke.RawExec{Stderr: os.Stderr},
+ PluginDecoder: version.PluginDecoder{},
}
+ }
+ return c.exec
+}
- newConf, err := buildOneConfig(list, net, prevResult, rt)
- if err != nil {
- return nil, err
- }
+func (c *CNIConfig) addOrGetNetwork(command, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
+ c.ensureExec()
+ pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
+ if err != nil {
+ return nil, err
+ }
- prevResult, err = invoke.ExecPluginWithResult(pluginPath, newConf.Bytes, c.args("ADD", rt))
+ newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
+ if err != nil {
+ return nil, err
+ }
+
+ return invoke.ExecPluginWithResult(pluginPath, newConf.Bytes, c.args(command, rt), c.exec)
+}
+
+// Note that only GET requests should pass an initial prevResult
+func (c *CNIConfig) addOrGetNetworkList(command string, prevResult types.Result, list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
+ var err error
+ for _, net := range list.Plugins {
+ prevResult, err = c.addOrGetNetwork(command, list.Name, list.CNIVersion, net, prevResult, rt)
if err != nil {
return nil, err
}
@@ -142,68 +186,194 @@ func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (ty
return prevResult, nil
}
+func getResultCacheFilePath(netName string, rt *RuntimeConf) string {
+ cacheDir := rt.CacheDir
+ if cacheDir == "" {
+ cacheDir = CacheDir
+ }
+ return filepath.Join(cacheDir, "results", fmt.Sprintf("%s-%s", netName, rt.ContainerID))
+}
+
+func setCachedResult(result types.Result, netName string, rt *RuntimeConf) error {
+ data, err := json.Marshal(result)
+ if err != nil {
+ return err
+ }
+ fname := getResultCacheFilePath(netName, rt)
+ if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil {
+ return err
+ }
+ return ioutil.WriteFile(fname, data, 0600)
+}
+
+func delCachedResult(netName string, rt *RuntimeConf) error {
+ fname := getResultCacheFilePath(netName, rt)
+ return os.Remove(fname)
+}
+
+func getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
+ fname := getResultCacheFilePath(netName, rt)
+ data, err := ioutil.ReadFile(fname)
+ if err != nil {
+ // Ignore read errors; the cached result may not exist on-disk
+ return nil, nil
+ }
+
+ // Read the version of the cached result
+ decoder := version.ConfigDecoder{}
+ resultCniVersion, err := decoder.Decode(data)
+ if err != nil {
+ return nil, err
+ }
+
+ // Ensure we can understand the result
+ result, err := version.NewResult(resultCniVersion, data)
+ if err != nil {
+ return nil, err
+ }
+
+ // Convert to the config version to ensure plugins get prevResult
+ // in the same version as the config. The cached result version
+ // should match the config version unless the config was changed
+ // while the container was running.
+ result, err = result.GetAsVersion(cniVersion)
+ if err != nil && resultCniVersion != cniVersion {
+ return nil, fmt.Errorf("failed to convert cached result version %q to config version %q: %v", resultCniVersion, cniVersion, err)
+ }
+ return result, err
+}
+
+// AddNetworkList executes a sequence of plugins with the ADD command
+func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
+ result, err := c.addOrGetNetworkList("ADD", nil, list, rt)
+ if err != nil {
+ return nil, err
+ }
+
+ if err = setCachedResult(result, list.Name, rt); err != nil {
+ return nil, fmt.Errorf("failed to set network '%s' cached result: %v", list.Name, err)
+ }
+
+ return result, nil
+}
+
+// GetNetworkList executes a sequence of plugins with the GET command
+func (c *CNIConfig) GetNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
+ // GET was added in CNI spec version 0.4.0 and higher
+ if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil {
+ return nil, err
+ } else if !gtet {
+ return nil, fmt.Errorf("configuration version %q does not support the GET command", list.CNIVersion)
+ }
+
+ cachedResult, err := getCachedResult(list.Name, list.CNIVersion, rt)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get network '%s' cached result: %v", list.Name, err)
+ }
+ return c.addOrGetNetworkList("GET", cachedResult, list, rt)
+}
+
+func (c *CNIConfig) delNetwork(name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error {
+ c.ensureExec()
+ pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
+ if err != nil {
+ return err
+ }
+
+ newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
+ if err != nil {
+ return err
+ }
+
+ return invoke.ExecPluginWithoutResult(pluginPath, newConf.Bytes, c.args("DEL", rt), c.exec)
+}
+
// DelNetworkList executes a sequence of plugins with the DEL command
func (c *CNIConfig) DelNetworkList(list *NetworkConfigList, rt *RuntimeConf) error {
- for i := len(list.Plugins) - 1; i >= 0; i-- {
- net := list.Plugins[i]
-
- pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
- if err != nil {
- return err
- }
+ var cachedResult types.Result
- newConf, err := buildOneConfig(list, net, nil, rt)
+ // Cached result on DEL was added in CNI spec version 0.4.0 and higher
+ if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil {
+ return err
+ } else if gtet {
+ cachedResult, err = getCachedResult(list.Name, list.CNIVersion, rt)
if err != nil {
- return err
+ return fmt.Errorf("failed to get network '%s' cached result: %v", list.Name, err)
}
+ }
- if err := invoke.ExecPluginWithoutResult(pluginPath, newConf.Bytes, c.args("DEL", rt)); err != nil {
+ for i := len(list.Plugins) - 1; i >= 0; i-- {
+ net := list.Plugins[i]
+ if err := c.delNetwork(list.Name, list.CNIVersion, net, cachedResult, rt); err != nil {
return err
}
}
+ _ = delCachedResult(list.Name, rt)
return nil
}
// AddNetwork executes the plugin with the ADD command
func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
- pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
+ result, err := c.addOrGetNetwork("ADD", net.Network.Name, net.Network.CNIVersion, net, nil, rt)
if err != nil {
return nil, err
}
- net, err = injectRuntimeConfig(net, rt)
- if err != nil {
+ if err = setCachedResult(result, net.Network.Name, rt); err != nil {
+ return nil, fmt.Errorf("failed to set network '%s' cached result: %v", net.Network.Name, err)
+ }
+
+ return result, nil
+}
+
+// GetNetwork executes the plugin with the GET command
+func (c *CNIConfig) GetNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
+ // GET was added in CNI spec version 0.4.0 and higher
+ if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil {
return nil, err
+ } else if !gtet {
+ return nil, fmt.Errorf("configuration version %q does not support the GET command", net.Network.CNIVersion)
}
- return invoke.ExecPluginWithResult(pluginPath, net.Bytes, c.args("ADD", rt))
+ cachedResult, err := getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get network '%s' cached result: %v", net.Network.Name, err)
+ }
+ return c.addOrGetNetwork("GET", net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt)
}
// DelNetwork executes the plugin with the DEL command
func (c *CNIConfig) DelNetwork(net *NetworkConfig, rt *RuntimeConf) error {
- pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
- if err != nil {
+ var cachedResult types.Result
+
+ // Cached result on DEL was added in CNI spec version 0.4.0 and higher
+ if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil {
return err
+ } else if gtet {
+ cachedResult, err = getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
+ if err != nil {
+ return fmt.Errorf("failed to get network '%s' cached result: %v", net.Network.Name, err)
+ }
}
- net, err = injectRuntimeConfig(net, rt)
- if err != nil {
+ if err := c.delNetwork(net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt); err != nil {
return err
}
-
- return invoke.ExecPluginWithoutResult(pluginPath, net.Bytes, c.args("DEL", rt))
+ _ = delCachedResult(net.Network.Name, rt)
+ return nil
}
// GetVersionInfo reports which versions of the CNI spec are supported by
// the given plugin.
func (c *CNIConfig) GetVersionInfo(pluginType string) (version.PluginInfo, error) {
- pluginPath, err := invoke.FindInPath(pluginType, c.Path)
+ c.ensureExec()
+ pluginPath, err := c.exec.FindInPath(pluginType, c.Path)
if err != nil {
return nil, err
}
- return invoke.GetVersionInfo(pluginPath)
+ return invoke.GetVersionInfo(pluginPath, c.exec)
}
// =====
diff --git a/vendor/github.com/containernetworking/cni/libcni/conf.go b/vendor/github.com/containernetworking/cni/libcni/conf.go
index c7738c665..9834d715b 100644
--- a/vendor/github.com/containernetworking/cni/libcni/conf.go
+++ b/vendor/github.com/containernetworking/cni/libcni/conf.go
@@ -45,6 +45,9 @@ func ConfFromBytes(bytes []byte) (*NetworkConfig, error) {
if err := json.Unmarshal(bytes, &conf.Network); err != nil {
return nil, fmt.Errorf("error parsing configuration: %s", err)
}
+ if conf.Network.Type == "" {
+ return nil, fmt.Errorf("error parsing configuration: missing 'type'")
+ }
return conf, nil
}
diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go b/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go
index c78a69eeb..21efdf802 100644
--- a/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go
+++ b/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go
@@ -22,32 +22,54 @@ import (
"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")
+func delegateAddOrGet(command, delegatePlugin string, netconf []byte, exec Exec) (types.Result, error) {
+ if exec == nil {
+ exec = defaultExec
}
paths := filepath.SplitList(os.Getenv("CNI_PATH"))
-
- pluginPath, err := FindInPath(delegatePlugin, paths)
+ pluginPath, err := exec.FindInPath(delegatePlugin, paths)
if err != nil {
return nil, err
}
- return ExecPluginWithResult(pluginPath, netconf, ArgsFromEnv())
+ return ExecPluginWithResult(pluginPath, netconf, ArgsFromEnv(), exec)
+}
+
+// DelegateAdd calls the given delegate plugin with the CNI ADD action and
+// JSON configuration
+func DelegateAdd(delegatePlugin string, netconf []byte, exec Exec) (types.Result, error) {
+ if os.Getenv("CNI_COMMAND") != "ADD" {
+ return nil, fmt.Errorf("CNI_COMMAND is not ADD")
+ }
+ return delegateAddOrGet("ADD", delegatePlugin, netconf, exec)
+}
+
+// DelegateGet calls the given delegate plugin with the CNI GET action and
+// JSON configuration
+func DelegateGet(delegatePlugin string, netconf []byte, exec Exec) (types.Result, error) {
+ if os.Getenv("CNI_COMMAND") != "GET" {
+ return nil, fmt.Errorf("CNI_COMMAND is not GET")
+ }
+ return delegateAddOrGet("GET", delegatePlugin, netconf, exec)
}
-func DelegateDel(delegatePlugin string, netconf []byte) error {
+// DelegateDel calls the given delegate plugin with the CNI DEL action and
+// JSON configuration
+func DelegateDel(delegatePlugin string, netconf []byte, exec Exec) error {
+ if exec == nil {
+ exec = defaultExec
+ }
+
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)
+ pluginPath, err := exec.FindInPath(delegatePlugin, paths)
if err != nil {
return err
}
- return ExecPluginWithoutResult(pluginPath, netconf, ArgsFromEnv())
+ return ExecPluginWithoutResult(pluginPath, netconf, ArgsFromEnv(), exec)
}
diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go b/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
index fc47e7c82..cf019d3a0 100644
--- a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
+++ b/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
@@ -22,34 +22,62 @@ import (
"github.com/containernetworking/cni/pkg/version"
)
-func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) {
- return defaultPluginExec.WithResult(pluginPath, netconf, args)
+// Exec is an interface encapsulates all operations that deal with finding
+// and executing a CNI plugin. Tests may provide a fake implementation
+// to avoid writing fake plugins to temporary directories during the test.
+type Exec interface {
+ ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error)
+ FindInPath(plugin string, paths []string) (string, error)
+ Decode(jsonBytes []byte) (version.PluginInfo, error)
}
-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{},
-}
+// For example, a testcase could pass an instance of the following fakeExec
+// object to ExecPluginWithResult() to verify the incoming stdin and environment
+// and provide a tailored response:
+//
+//import (
+// "encoding/json"
+// "path"
+// "strings"
+//)
+//
+//type fakeExec struct {
+// version.PluginDecoder
+//}
+//
+//func (f *fakeExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) {
+// net := &types.NetConf{}
+// err := json.Unmarshal(stdinData, net)
+// if err != nil {
+// return nil, fmt.Errorf("failed to unmarshal configuration: %v", err)
+// }
+// pluginName := path.Base(pluginPath)
+// if pluginName != net.Type {
+// return nil, fmt.Errorf("plugin name %q did not match config type %q", pluginName, net.Type)
+// }
+// for _, e := range environ {
+// // Check environment for forced failure request
+// parts := strings.Split(e, "=")
+// if len(parts) > 0 && parts[0] == "FAIL" {
+// return nil, fmt.Errorf("failed to execute plugin %s", pluginName)
+// }
+// }
+// return []byte("{\"CNIVersion\":\"0.4.0\"}"), nil
+//}
+//
+//func (f *fakeExec) FindInPath(plugin string, paths []string) (string, error) {
+// if len(paths) > 0 {
+// return path.Join(paths[0], plugin), nil
+// }
+// return "", fmt.Errorf("failed to find plugin %s in paths %v", plugin, paths)
+//}
-type PluginExec struct {
- RawExec interface {
- ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error)
+func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) {
+ if exec == nil {
+ exec = defaultExec
}
- 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())
+ stdoutBytes, err := exec.ExecPlugin(pluginPath, netconf, args.AsEnv())
if err != nil {
return nil, err
}
@@ -64,8 +92,11 @@ func (e *PluginExec) WithResult(pluginPath string, netconf []byte, args CNIArgs)
return version.NewResult(confVersion, stdoutBytes)
}
-func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIArgs) error {
- _, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv())
+func ExecPluginWithoutResult(pluginPath string, netconf []byte, args CNIArgs, exec Exec) error {
+ if exec == nil {
+ exec = defaultExec
+ }
+ _, err := exec.ExecPlugin(pluginPath, netconf, args.AsEnv())
return err
}
@@ -73,7 +104,10 @@ func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIAr
// 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) {
+func GetVersionInfo(pluginPath string, exec Exec) (version.PluginInfo, error) {
+ if exec == nil {
+ exec = defaultExec
+ }
args := &Args{
Command: "VERSION",
@@ -83,7 +117,7 @@ func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, erro
Path: "dummy",
}
stdin := []byte(fmt.Sprintf(`{"cniVersion":%q}`, version.Current()))
- stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, stdin, args.AsEnv())
+ stdoutBytes, err := exec.ExecPlugin(pluginPath, stdin, args.AsEnv())
if err != nil {
if err.Error() == "unknown CNI_COMMAND: VERSION" {
return version.PluginSupports("0.1.0"), nil
@@ -91,5 +125,19 @@ func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, erro
return nil, err
}
- return e.VersionDecoder.Decode(stdoutBytes)
+ return exec.Decode(stdoutBytes)
+}
+
+// DefaultExec is an object that implements the Exec interface which looks
+// for and executes plugins from disk.
+type DefaultExec struct {
+ *RawExec
+ version.PluginDecoder
+}
+
+// DefaultExec implements the Exec interface
+var _ Exec = &DefaultExec{}
+
+var defaultExec = &DefaultExec{
+ RawExec: &RawExec{Stderr: os.Stderr},
}
diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go b/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go
index 93f1e75d9..a598f09c2 100644
--- a/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go
+++ b/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go
@@ -57,3 +57,7 @@ func pluginErr(err error, output []byte) error {
return err
}
+
+func (e *RawExec) FindInPath(plugin string, paths []string) (string, error) {
+ return FindInPath(plugin, paths)
+}
diff --git a/vendor/github.com/containernetworking/cni/pkg/types/current/types.go b/vendor/github.com/containernetworking/cni/pkg/types/current/types.go
index caac92ba7..92980c1a7 100644
--- a/vendor/github.com/containernetworking/cni/pkg/types/current/types.go
+++ b/vendor/github.com/containernetworking/cni/pkg/types/current/types.go
@@ -24,9 +24,9 @@ import (
"github.com/containernetworking/cni/pkg/types/020"
)
-const ImplementedSpecVersion string = "0.3.1"
+const ImplementedSpecVersion string = "0.4.0"
-var SupportedVersions = []string{"0.3.0", ImplementedSpecVersion}
+var SupportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion}
func NewResult(data []byte) (types.Result, error) {
result := &Result{}
@@ -196,7 +196,7 @@ func (r *Result) Version() string {
func (r *Result) GetAsVersion(version string) (types.Result, error) {
switch version {
- case "0.3.0", ImplementedSpecVersion:
+ case "0.3.0", "0.3.1", ImplementedSpecVersion:
r.CNIVersion = version
return r, nil
case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
diff --git a/vendor/github.com/containernetworking/cni/pkg/types/types.go b/vendor/github.com/containernetworking/cni/pkg/types/types.go
index 641275600..4684a3207 100644
--- a/vendor/github.com/containernetworking/cni/pkg/types/types.go
+++ b/vendor/github.com/containernetworking/cni/pkg/types/types.go
@@ -63,10 +63,12 @@ type NetConf struct {
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"`
+ IPAM IPAM `json:"ipam,omitempty"`
+ DNS DNS `json:"dns"`
+}
+
+type IPAM struct {
+ Type string `json:"type,omitempty"`
}
// NetConfList describes an ordered list of networks.
@@ -167,7 +169,7 @@ func (r *Route) UnmarshalJSON(data []byte) error {
return nil
}
-func (r *Route) MarshalJSON() ([]byte, error) {
+func (r Route) MarshalJSON() ([]byte, error) {
rt := route{
Dst: IPNet(r.Dst),
GW: r.GW,
diff --git a/vendor/github.com/containernetworking/cni/pkg/version/plugin.go b/vendor/github.com/containernetworking/cni/pkg/version/plugin.go
index 8a4672810..612335a81 100644
--- a/vendor/github.com/containernetworking/cni/pkg/version/plugin.go
+++ b/vendor/github.com/containernetworking/cni/pkg/version/plugin.go
@@ -18,6 +18,8 @@ import (
"encoding/json"
"fmt"
"io"
+ "strconv"
+ "strings"
)
// PluginInfo reports information about CNI versioning
@@ -79,3 +81,60 @@ func (*PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) {
}
return &info, nil
}
+
+// ParseVersion parses a version string like "3.0.1" or "0.4.5" into major,
+// minor, and micro numbers or returns an error
+func ParseVersion(version string) (int, int, int, error) {
+ var major, minor, micro int
+ parts := strings.Split(version, ".")
+ if len(parts) == 0 || len(parts) >= 4 {
+ return -1, -1, -1, fmt.Errorf("invalid version %q: too many or too few parts", version)
+ }
+
+ major, err := strconv.Atoi(parts[0])
+ if err != nil {
+ return -1, -1, -1, fmt.Errorf("failed to convert major version part %q: %v", parts[0], err)
+ }
+
+ if len(parts) >= 2 {
+ minor, err = strconv.Atoi(parts[1])
+ if err != nil {
+ return -1, -1, -1, fmt.Errorf("failed to convert minor version part %q: %v", parts[1], err)
+ }
+ }
+
+ if len(parts) >= 3 {
+ micro, err = strconv.Atoi(parts[2])
+ if err != nil {
+ return -1, -1, -1, fmt.Errorf("failed to convert micro version part %q: %v", parts[2], err)
+ }
+ }
+
+ return major, minor, micro, nil
+}
+
+// GreaterThanOrEqualTo takes two string versions, parses them into major/minor/micro
+// nubmers, and compares them to determine whether the first version is greater
+// than or equal to the second
+func GreaterThanOrEqualTo(version, otherVersion string) (bool, error) {
+ firstMajor, firstMinor, firstMicro, err := ParseVersion(version)
+ if err != nil {
+ return false, err
+ }
+
+ secondMajor, secondMinor, secondMicro, err := ParseVersion(otherVersion)
+ if err != nil {
+ return false, err
+ }
+
+ if firstMajor > secondMajor {
+ return true, nil
+ } else if firstMajor == secondMajor {
+ if firstMinor > secondMinor {
+ return true, nil
+ } else if firstMinor == secondMinor && firstMicro >= secondMicro {
+ return true, nil
+ }
+ }
+ return false, nil
+}
diff --git a/vendor/github.com/containernetworking/cni/pkg/version/version.go b/vendor/github.com/containernetworking/cni/pkg/version/version.go
index efe8ea871..c8e46d55b 100644
--- a/vendor/github.com/containernetworking/cni/pkg/version/version.go
+++ b/vendor/github.com/containernetworking/cni/pkg/version/version.go
@@ -24,7 +24,7 @@ import (
// Current reports the version of the CNI spec implemented by this library
func Current() string {
- return "0.3.1"
+ return "0.4.0"
}
// Legacy PluginInfo describes a plugin that is backwards compatible with the
@@ -35,7 +35,7 @@ func Current() string {
// 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 All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0")
var resultFactories = []struct {
supportedVersions []string