build(deps): bump github.com/containernetworking/cni from 0.6.0 to 0.8.1 (#293)
This commit is contained in:
parent
a6d50a8046
commit
9a9131d965
2
go.mod
2
go.mod
@ -5,7 +5,7 @@ go 1.17
|
|||||||
require (
|
require (
|
||||||
github.com/awalterschulze/gographviz v0.0.0-20181013152038-b2885df04310
|
github.com/awalterschulze/gographviz v0.0.0-20181013152038-b2885df04310
|
||||||
github.com/campoy/embedmd v1.0.0
|
github.com/campoy/embedmd v1.0.0
|
||||||
github.com/containernetworking/cni v0.6.0
|
github.com/containernetworking/cni v0.8.1
|
||||||
github.com/containernetworking/plugins v0.6.0
|
github.com/containernetworking/plugins v0.6.0
|
||||||
github.com/coreos/go-iptables v0.4.0
|
github.com/coreos/go-iptables v0.4.0
|
||||||
github.com/go-kit/kit v0.9.0
|
github.com/go-kit/kit v0.9.0
|
||||||
|
4
go.sum
4
go.sum
@ -68,8 +68,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
|||||||
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/containernetworking/cni v0.6.0 h1:FXICGBZNMtdHlW65trpoHviHctQD3seWhRRcqp2hMOU=
|
github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI=
|
||||||
github.com/containernetworking/cni v0.6.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||||
github.com/containernetworking/plugins v0.6.0 h1:bqPT7yYisnWs+FrtgY5/qLEB9QZ/6z11wMNCwSdzZm0=
|
github.com/containernetworking/plugins v0.6.0 h1:bqPT7yYisnWs+FrtgY5/qLEB9QZ/6z11wMNCwSdzZm0=
|
||||||
github.com/containernetworking/plugins v0.6.0/go.mod h1:dagHaAhNjXjT9QYOklkKJDGaQPTg4pf//FrUcJeb7FU=
|
github.com/containernetworking/plugins v0.6.0/go.mod h1:dagHaAhNjXjT9QYOklkKJDGaQPTg4pf//FrUcJeb7FU=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
|
562
vendor/github.com/containernetworking/cni/libcni/api.go
generated
vendored
562
vendor/github.com/containernetworking/cni/libcni/api.go
generated
vendored
@ -15,14 +15,32 @@
|
|||||||
package libcni
|
package libcni
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/invoke"
|
"github.com/containernetworking/cni/pkg/invoke"
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
"github.com/containernetworking/cni/pkg/utils"
|
||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CacheDir = "/var/lib/cni"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CNICacheV1 = "cniCacheV1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 {
|
type RuntimeConf struct {
|
||||||
ContainerID string
|
ContainerID string
|
||||||
NetNS string
|
NetNS string
|
||||||
@ -34,6 +52,9 @@ type RuntimeConf struct {
|
|||||||
// in this map which match the capabilities of the plugin are passed
|
// in this map which match the capabilities of the plugin are passed
|
||||||
// to the plugin
|
// to the plugin
|
||||||
CapabilityArgs map[string]interface{}
|
CapabilityArgs map[string]interface{}
|
||||||
|
|
||||||
|
// DEPRECATED. Will be removed in a future release.
|
||||||
|
CacheDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetworkConfig struct {
|
type NetworkConfig struct {
|
||||||
@ -42,33 +63,64 @@ type NetworkConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type NetworkConfigList struct {
|
type NetworkConfigList struct {
|
||||||
Name string
|
Name string
|
||||||
CNIVersion string
|
CNIVersion string
|
||||||
Plugins []*NetworkConfig
|
DisableCheck bool
|
||||||
Bytes []byte
|
Plugins []*NetworkConfig
|
||||||
|
Bytes []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type CNI interface {
|
type CNI interface {
|
||||||
AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
|
AddNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
|
||||||
DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error
|
CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
|
||||||
|
DelNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
|
||||||
|
GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
|
||||||
|
GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
|
||||||
|
|
||||||
AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
||||||
DelNetwork(net *NetworkConfig, rt *RuntimeConf) error
|
CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
|
||||||
|
DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
|
||||||
|
GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
||||||
|
GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
|
||||||
|
|
||||||
|
ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error)
|
||||||
|
ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type CNIConfig struct {
|
type CNIConfig struct {
|
||||||
Path []string
|
Path []string
|
||||||
|
exec invoke.Exec
|
||||||
|
cacheDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
// CNIConfig implements the CNI interface
|
// CNIConfig implements the CNI interface
|
||||||
var _ CNI = &CNIConfig{}
|
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 NewCNIConfigWithCacheDir(path, "", exec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCNIConfigWithCacheDir returns a new CNIConfig object that will search for plugins
|
||||||
|
// in the given paths use the given exec interface to run those plugins,
|
||||||
|
// or if the exec interface is not given, will use a default exec handler.
|
||||||
|
// The given cache directory will be used for temporary data storage when needed.
|
||||||
|
func NewCNIConfigWithCacheDir(path []string, cacheDir string, exec invoke.Exec) *CNIConfig {
|
||||||
|
return &CNIConfig{
|
||||||
|
Path: path,
|
||||||
|
cacheDir: cacheDir,
|
||||||
|
exec: exec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
inject := map[string]interface{}{
|
inject := map[string]interface{}{
|
||||||
"name": list.Name,
|
"name": name,
|
||||||
"cniVersion": list.CNIVersion,
|
"cniVersion": cniVersion,
|
||||||
}
|
}
|
||||||
// Add previous plugin result
|
// Add previous plugin result
|
||||||
if prevResult != nil {
|
if prevResult != nil {
|
||||||
@ -92,7 +144,7 @@ func buildOneConfig(list *NetworkConfigList, orig *NetworkConfig, prevResult typ
|
|||||||
// These capabilities arguments are filtered through the plugin's advertised
|
// These capabilities arguments are filtered through the plugin's advertised
|
||||||
// capabilities from its config JSON, and any keys in the CapabilityArgs
|
// capabilities from its config JSON, and any keys in the CapabilityArgs
|
||||||
// matching plugin capabilities are added to the "runtimeConfig" dictionary
|
// matching plugin capabilities are added to the "runtimeConfig" dictionary
|
||||||
// sent to the plugin via JSON on stdin. For exmaple, if the plugin's
|
// sent to the plugin via JSON on stdin. For example, if the plugin's
|
||||||
// capabilities include "portMappings", and the CapabilityArgs map includes a
|
// capabilities include "portMappings", and the CapabilityArgs map includes a
|
||||||
// "portMappings" key, that key and its value are added to the "runtimeConfig"
|
// "portMappings" key, that key and its value are added to the "runtimeConfig"
|
||||||
// dictionary to be passed to the plugin's stdin.
|
// dictionary to be passed to the plugin's stdin.
|
||||||
@ -119,45 +171,309 @@ func injectRuntimeConfig(orig *NetworkConfig, rt *RuntimeConf) (*NetworkConfig,
|
|||||||
return orig, nil
|
return orig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
type cachedInfo struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
ContainerID string `json:"containerId"`
|
||||||
|
Config []byte `json:"config"`
|
||||||
|
IfName string `json:"ifName"`
|
||||||
|
NetworkName string `json:"networkName"`
|
||||||
|
CniArgs [][2]string `json:"cniArgs,omitempty"`
|
||||||
|
CapabilityArgs map[string]interface{} `json:"capabilityArgs,omitempty"`
|
||||||
|
RawResult map[string]interface{} `json:"result,omitempty"`
|
||||||
|
Result types.Result `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCacheDir returns the cache directory in this order:
|
||||||
|
// 1) global cacheDir from CNIConfig object
|
||||||
|
// 2) deprecated cacheDir from RuntimeConf object
|
||||||
|
// 3) fall back to default cache directory
|
||||||
|
func (c *CNIConfig) getCacheDir(rt *RuntimeConf) string {
|
||||||
|
if c.cacheDir != "" {
|
||||||
|
return c.cacheDir
|
||||||
|
}
|
||||||
|
if rt.CacheDir != "" {
|
||||||
|
return rt.CacheDir
|
||||||
|
}
|
||||||
|
return CacheDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) getCacheFilePath(netName string, rt *RuntimeConf) (string, error) {
|
||||||
|
if netName == "" || rt.ContainerID == "" || rt.IfName == "" {
|
||||||
|
return "", fmt.Errorf("cache file path requires network name (%q), container ID (%q), and interface name (%q)", netName, rt.ContainerID, rt.IfName)
|
||||||
|
}
|
||||||
|
return filepath.Join(c.getCacheDir(rt), "results", fmt.Sprintf("%s-%s-%s", netName, rt.ContainerID, rt.IfName)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) cacheAdd(result types.Result, config []byte, netName string, rt *RuntimeConf) error {
|
||||||
|
cached := cachedInfo{
|
||||||
|
Kind: CNICacheV1,
|
||||||
|
ContainerID: rt.ContainerID,
|
||||||
|
Config: config,
|
||||||
|
IfName: rt.IfName,
|
||||||
|
NetworkName: netName,
|
||||||
|
CniArgs: rt.Args,
|
||||||
|
CapabilityArgs: rt.CapabilityArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to get type.Result into cachedInfo as JSON map
|
||||||
|
// Marshal to []byte, then Unmarshal into cached.RawResult
|
||||||
|
data, err := json.Marshal(result)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, &cached.RawResult)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newBytes, err := json.Marshal(&cached)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fname, err := c.getCacheFilePath(netName, rt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(fname, newBytes, 0600)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) cacheDel(netName string, rt *RuntimeConf) error {
|
||||||
|
fname, err := c.getCacheFilePath(netName, rt)
|
||||||
|
if err != nil {
|
||||||
|
// Ignore error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return os.Remove(fname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) getCachedConfig(netName string, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||||
|
var bytes []byte
|
||||||
|
|
||||||
|
fname, err := c.getCacheFilePath(netName, rt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
bytes, err = ioutil.ReadFile(fname)
|
||||||
|
if err != nil {
|
||||||
|
// Ignore read errors; the cached result may not exist on-disk
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
unmarshaled := cachedInfo{}
|
||||||
|
if err := json.Unmarshal(bytes, &unmarshaled); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to unmarshal cached network %q config: %v", netName, err)
|
||||||
|
}
|
||||||
|
if unmarshaled.Kind != CNICacheV1 {
|
||||||
|
return nil, nil, fmt.Errorf("read cached network %q config has wrong kind: %v", netName, unmarshaled.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
newRt := *rt
|
||||||
|
if unmarshaled.CniArgs != nil {
|
||||||
|
newRt.Args = unmarshaled.CniArgs
|
||||||
|
}
|
||||||
|
newRt.CapabilityArgs = unmarshaled.CapabilityArgs
|
||||||
|
|
||||||
|
return unmarshaled.Config, &newRt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
|
||||||
|
fname, err := c.getCacheFilePath(netName, rt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
|
||||||
|
fname, err := c.getCacheFilePath(netName, rt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fdata, err := ioutil.ReadFile(fname)
|
||||||
|
if err != nil {
|
||||||
|
// Ignore read errors; the cached result may not exist on-disk
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedInfo := cachedInfo{}
|
||||||
|
if err := json.Unmarshal(fdata, &cachedInfo); err != nil || cachedInfo.Kind != CNICacheV1 {
|
||||||
|
return c.getLegacyCachedResult(netName, cniVersion, rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
newBytes, err := json.Marshal(&cachedInfo.RawResult)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal cached network %q config: %v", netName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the version of the cached result
|
||||||
|
decoder := version.ConfigDecoder{}
|
||||||
|
resultCniVersion, err := decoder.Decode(newBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we can understand the result
|
||||||
|
result, err := version.NewResult(resultCniVersion, newBytes)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkListCachedResult returns the cached Result of the previous
|
||||||
|
// AddNetworkList() operation for a network list, or an error.
|
||||||
|
func (c *CNIConfig) GetNetworkListCachedResult(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
|
||||||
|
return c.getCachedResult(list.Name, list.CNIVersion, rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkCachedResult returns the cached Result of the previous
|
||||||
|
// AddNetwork() operation for a network, or an error.
|
||||||
|
func (c *CNIConfig) GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
|
||||||
|
return c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkListCachedConfig copies the input RuntimeConf to output
|
||||||
|
// RuntimeConf with fields updated with info from the cached Config.
|
||||||
|
func (c *CNIConfig) GetNetworkListCachedConfig(list *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||||
|
return c.getCachedConfig(list.Name, rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkCachedConfig copies the input RuntimeConf to output
|
||||||
|
// RuntimeConf with fields updated with info from the cached Config.
|
||||||
|
func (c *CNIConfig) GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||||
|
return c.getCachedConfig(net.Network.Name, rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) addNetwork(ctx context.Context, 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
|
||||||
|
}
|
||||||
|
if err := utils.ValidateContainerID(rt.ContainerID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := utils.ValidateNetworkName(name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := utils.ValidateInterfaceName(rt.IfName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return invoke.ExecPluginWithResult(ctx, pluginPath, newConf.Bytes, c.args("ADD", rt), c.exec)
|
||||||
|
}
|
||||||
|
|
||||||
// AddNetworkList executes a sequence of plugins with the ADD command
|
// AddNetworkList executes a sequence of plugins with the ADD command
|
||||||
func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
|
func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
|
||||||
var prevResult types.Result
|
var err error
|
||||||
|
var result types.Result
|
||||||
for _, net := range list.Plugins {
|
for _, net := range list.Plugins {
|
||||||
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
result, err = c.addNetwork(ctx, list.Name, list.CNIVersion, net, result, rt)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newConf, err := buildOneConfig(list, net, prevResult, rt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
prevResult, err = invoke.ExecPluginWithResult(pluginPath, newConf.Bytes, c.args("ADD", rt))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return prevResult, nil
|
if err = c.cacheAdd(result, list.Bytes, list.Name, rt); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to set network %q cached result: %v", list.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelNetworkList executes a sequence of plugins with the DEL command
|
func (c *CNIConfig) checkNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error {
|
||||||
func (c *CNIConfig) DelNetworkList(list *NetworkConfigList, rt *RuntimeConf) error {
|
c.ensureExec()
|
||||||
for i := len(list.Plugins) - 1; i >= 0; i-- {
|
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
|
||||||
net := list.Plugins[i]
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newConf, err := buildOneConfig(list, net, nil, rt)
|
return invoke.ExecPluginWithoutResult(ctx, pluginPath, newConf.Bytes, c.args("CHECK", rt), c.exec)
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := invoke.ExecPluginWithoutResult(pluginPath, newConf.Bytes, c.args("DEL", rt)); err != nil {
|
// CheckNetworkList executes a sequence of plugins with the CHECK command
|
||||||
|
func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) error {
|
||||||
|
// CHECK 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 {
|
||||||
|
return fmt.Errorf("configuration version %q does not support the CHECK command", list.CNIVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if list.DisableCheck {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedResult, err := c.getCachedResult(list.Name, list.CNIVersion, rt)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, net := range list.Plugins {
|
||||||
|
if err := c.checkNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,45 +481,183 @@ func (c *CNIConfig) DelNetworkList(list *NetworkConfigList, rt *RuntimeConf) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CNIConfig) delNetwork(ctx context.Context, 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(ctx, pluginPath, newConf.Bytes, c.args("DEL", rt), c.exec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelNetworkList executes a sequence of plugins with the DEL command
|
||||||
|
func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) error {
|
||||||
|
var cachedResult types.Result
|
||||||
|
|
||||||
|
// 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 = c.getCachedResult(list.Name, list.CNIVersion, rt)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(list.Plugins) - 1; i >= 0; i-- {
|
||||||
|
net := list.Plugins[i]
|
||||||
|
if err := c.delNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = c.cacheDel(list.Name, rt)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AddNetwork executes the plugin with the ADD command
|
// AddNetwork executes the plugin with the ADD command
|
||||||
func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
|
func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
|
||||||
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
result, err := c.addNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, nil, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
net, err = injectRuntimeConfig(net, rt)
|
if err = c.cacheAdd(result, net.Bytes, net.Network.Name, rt); err != nil {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("failed to set network %q cached result: %v", net.Network.Name, err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return invoke.ExecPluginWithResult(pluginPath, net.Bytes, c.args("ADD", rt))
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckNetwork executes the plugin with the CHECK command
|
||||||
|
func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error {
|
||||||
|
// CHECK 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 {
|
||||||
|
return fmt.Errorf("configuration version %q does not support the CHECK command", net.Network.CNIVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err)
|
||||||
|
}
|
||||||
|
return c.checkNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelNetwork executes the plugin with the DEL command
|
// DelNetwork executes the plugin with the DEL command
|
||||||
func (c *CNIConfig) DelNetwork(net *NetworkConfig, rt *RuntimeConf) error {
|
func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error {
|
||||||
pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)
|
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 = c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.delNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = c.cacheDel(net.Network.Name, rt)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateNetworkList checks that a configuration is reasonably valid.
|
||||||
|
// - all the specified plugins exist on disk
|
||||||
|
// - every plugin supports the desired version.
|
||||||
|
//
|
||||||
|
// Returns a list of all capabilities supported by the configuration, or error
|
||||||
|
func (c *CNIConfig) ValidateNetworkList(ctx context.Context, list *NetworkConfigList) ([]string, error) {
|
||||||
|
version := list.CNIVersion
|
||||||
|
|
||||||
|
// holding map for seen caps (in case of duplicates)
|
||||||
|
caps := map[string]interface{}{}
|
||||||
|
|
||||||
|
errs := []error{}
|
||||||
|
for _, net := range list.Plugins {
|
||||||
|
if err := c.validatePlugin(ctx, net.Network.Type, version); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
for c, enabled := range net.Network.Capabilities {
|
||||||
|
if !enabled {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
caps[c] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("%v", errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make caps list
|
||||||
|
cc := make([]string, 0, len(caps))
|
||||||
|
for c := range caps {
|
||||||
|
cc = append(cc, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateNetwork checks that a configuration is reasonably valid.
|
||||||
|
// It uses the same logic as ValidateNetworkList)
|
||||||
|
// Returns a list of capabilities
|
||||||
|
func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error) {
|
||||||
|
caps := []string{}
|
||||||
|
for c, ok := range net.Network.Capabilities {
|
||||||
|
if ok {
|
||||||
|
caps = append(caps, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.validatePlugin(ctx, net.Network.Type, net.Network.CNIVersion); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return caps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validatePlugin checks that an individual plugin's configuration is sane
|
||||||
|
func (c *CNIConfig) validatePlugin(ctx context.Context, pluginName, expectedVersion string) error {
|
||||||
|
c.ensureExec()
|
||||||
|
pluginPath, err := c.exec.FindInPath(pluginName, c.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if expectedVersion == "" {
|
||||||
|
expectedVersion = "0.1.0"
|
||||||
|
}
|
||||||
|
|
||||||
net, err = injectRuntimeConfig(net, rt)
|
vi, err := invoke.GetVersionInfo(ctx, pluginPath, c.exec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for _, vers := range vi.SupportedVersions() {
|
||||||
return invoke.ExecPluginWithoutResult(pluginPath, net.Bytes, c.args("DEL", rt))
|
if vers == expectedVersion {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("plugin %s does not support config version %q", pluginName, expectedVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersionInfo reports which versions of the CNI spec are supported by
|
// GetVersionInfo reports which versions of the CNI spec are supported by
|
||||||
// the given plugin.
|
// the given plugin.
|
||||||
func (c *CNIConfig) GetVersionInfo(pluginType string) (version.PluginInfo, error) {
|
func (c *CNIConfig) GetVersionInfo(ctx context.Context, 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return invoke.GetVersionInfo(pluginPath)
|
return invoke.GetVersionInfo(ctx, pluginPath, c.exec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====
|
// =====
|
||||||
|
22
vendor/github.com/containernetworking/cni/libcni/conf.go
generated
vendored
22
vendor/github.com/containernetworking/cni/libcni/conf.go
generated
vendored
@ -45,6 +45,9 @@ func ConfFromBytes(bytes []byte) (*NetworkConfig, error) {
|
|||||||
if err := json.Unmarshal(bytes, &conf.Network); err != nil {
|
if err := json.Unmarshal(bytes, &conf.Network); err != nil {
|
||||||
return nil, fmt.Errorf("error parsing configuration: %s", err)
|
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
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,10 +83,19 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disableCheck := false
|
||||||
|
if rawDisableCheck, ok := rawList["disableCheck"]; ok {
|
||||||
|
disableCheck, ok = rawDisableCheck.(bool)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("error parsing configuration list: invalid disableCheck type %T", rawDisableCheck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
list := &NetworkConfigList{
|
list := &NetworkConfigList{
|
||||||
Name: name,
|
Name: name,
|
||||||
CNIVersion: cniVersion,
|
DisableCheck: disableCheck,
|
||||||
Bytes: bytes,
|
CNIVersion: cniVersion,
|
||||||
|
Bytes: bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
var plugins []interface{}
|
var plugins []interface{}
|
||||||
@ -102,11 +114,11 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
|||||||
for i, conf := range plugins {
|
for i, conf := range plugins {
|
||||||
newBytes, err := json.Marshal(conf)
|
newBytes, err := json.Marshal(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to marshal plugin config %d: %v", i, err)
|
return nil, fmt.Errorf("failed to marshal plugin config %d: %v", i, err)
|
||||||
}
|
}
|
||||||
netConf, err := ConfFromBytes(newBytes)
|
netConf, err := ConfFromBytes(newBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to parse plugin config %d: %v", i, err)
|
return nil, fmt.Errorf("failed to parse plugin config %d: %v", i, err)
|
||||||
}
|
}
|
||||||
list.Plugins = append(list.Plugins, netConf)
|
list.Plugins = append(list.Plugins, netConf)
|
||||||
}
|
}
|
||||||
|
70
vendor/github.com/containernetworking/cni/pkg/invoke/args.go
generated
vendored
70
vendor/github.com/containernetworking/cni/pkg/invoke/args.go
generated
vendored
@ -15,6 +15,7 @@
|
|||||||
package invoke
|
package invoke
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -22,6 +23,8 @@ import (
|
|||||||
type CNIArgs interface {
|
type CNIArgs interface {
|
||||||
// For use with os/exec; i.e., return nil to inherit the
|
// For use with os/exec; i.e., return nil to inherit the
|
||||||
// environment from this process
|
// environment from this process
|
||||||
|
// For use in delegation; inherit the environment from this
|
||||||
|
// process and allow overrides
|
||||||
AsEnv() []string
|
AsEnv() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +32,7 @@ type inherited struct{}
|
|||||||
|
|
||||||
var inheritArgsFromEnv inherited
|
var inheritArgsFromEnv inherited
|
||||||
|
|
||||||
func (_ *inherited) AsEnv() []string {
|
func (*inherited) AsEnv() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,17 +60,17 @@ func (args *Args) AsEnv() []string {
|
|||||||
pluginArgsStr = stringify(args.PluginArgs)
|
pluginArgsStr = stringify(args.PluginArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the custom values are first, so any value present in
|
// Duplicated values which come first will be overridden, so we must put the
|
||||||
// the process environment won't override them.
|
// custom values in the end to avoid being overridden by the process environments.
|
||||||
env = append([]string{
|
env = append(env,
|
||||||
"CNI_COMMAND=" + args.Command,
|
"CNI_COMMAND="+args.Command,
|
||||||
"CNI_CONTAINERID=" + args.ContainerID,
|
"CNI_CONTAINERID="+args.ContainerID,
|
||||||
"CNI_NETNS=" + args.NetNS,
|
"CNI_NETNS="+args.NetNS,
|
||||||
"CNI_ARGS=" + pluginArgsStr,
|
"CNI_ARGS="+pluginArgsStr,
|
||||||
"CNI_IFNAME=" + args.IfName,
|
"CNI_IFNAME="+args.IfName,
|
||||||
"CNI_PATH=" + args.Path,
|
"CNI_PATH="+args.Path,
|
||||||
}, env...)
|
)
|
||||||
return env
|
return dedupEnv(env)
|
||||||
}
|
}
|
||||||
|
|
||||||
// taken from rkt/networking/net_plugin.go
|
// taken from rkt/networking/net_plugin.go
|
||||||
@ -80,3 +83,46 @@ func stringify(pluginArgs [][2]string) string {
|
|||||||
|
|
||||||
return strings.Join(entries, ";")
|
return strings.Join(entries, ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DelegateArgs implements the CNIArgs interface
|
||||||
|
// used for delegation to inherit from environments
|
||||||
|
// and allow some overrides like CNI_COMMAND
|
||||||
|
var _ CNIArgs = &DelegateArgs{}
|
||||||
|
|
||||||
|
type DelegateArgs struct {
|
||||||
|
Command string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DelegateArgs) AsEnv() []string {
|
||||||
|
env := os.Environ()
|
||||||
|
|
||||||
|
// The custom values should come in the end to override the existing
|
||||||
|
// process environment of the same key.
|
||||||
|
env = append(env,
|
||||||
|
"CNI_COMMAND="+d.Command,
|
||||||
|
)
|
||||||
|
return dedupEnv(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedupEnv returns a copy of env with any duplicates removed, in favor of later values.
|
||||||
|
// Items not of the normal environment "key=value" form are preserved unchanged.
|
||||||
|
func dedupEnv(env []string) []string {
|
||||||
|
out := make([]string, 0, len(env))
|
||||||
|
envMap := map[string]string{}
|
||||||
|
|
||||||
|
for _, kv := range env {
|
||||||
|
// find the first "=" in environment, if not, just keep it
|
||||||
|
eq := strings.Index(kv, "=")
|
||||||
|
if eq < 0 {
|
||||||
|
out = append(out, kv)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
envMap[kv[:eq]] = kv[eq+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range envMap {
|
||||||
|
out = append(out, fmt.Sprintf("%s=%s", k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
57
vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go
generated
vendored
57
vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go
generated
vendored
@ -15,39 +15,66 @@
|
|||||||
package invoke
|
package invoke
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DelegateAdd(delegatePlugin string, netconf []byte) (types.Result, error) {
|
func delegateCommon(delegatePlugin string, exec Exec) (string, Exec, error) {
|
||||||
if os.Getenv("CNI_COMMAND") != "ADD" {
|
if exec == nil {
|
||||||
return nil, fmt.Errorf("CNI_COMMAND is not ADD")
|
exec = defaultExec
|
||||||
}
|
}
|
||||||
|
|
||||||
paths := filepath.SplitList(os.Getenv("CNI_PATH"))
|
paths := filepath.SplitList(os.Getenv("CNI_PATH"))
|
||||||
|
pluginPath, err := exec.FindInPath(delegatePlugin, paths)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
pluginPath, err := FindInPath(delegatePlugin, paths)
|
return pluginPath, exec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelegateAdd calls the given delegate plugin with the CNI ADD action and
|
||||||
|
// JSON configuration
|
||||||
|
func DelegateAdd(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) (types.Result, error) {
|
||||||
|
pluginPath, realExec, err := delegateCommon(delegatePlugin, exec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExecPluginWithResult(pluginPath, netconf, ArgsFromEnv())
|
// DelegateAdd will override the original "CNI_COMMAND" env from process with ADD
|
||||||
|
return ExecPluginWithResult(ctx, pluginPath, netconf, delegateArgs("ADD"), realExec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DelegateDel(delegatePlugin string, netconf []byte) error {
|
// DelegateCheck calls the given delegate plugin with the CNI CHECK action and
|
||||||
if os.Getenv("CNI_COMMAND") != "DEL" {
|
// JSON configuration
|
||||||
return fmt.Errorf("CNI_COMMAND is not DEL")
|
func DelegateCheck(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error {
|
||||||
}
|
pluginPath, realExec, err := delegateCommon(delegatePlugin, exec)
|
||||||
|
|
||||||
paths := filepath.SplitList(os.Getenv("CNI_PATH"))
|
|
||||||
|
|
||||||
pluginPath, err := FindInPath(delegatePlugin, paths)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExecPluginWithoutResult(pluginPath, netconf, ArgsFromEnv())
|
// DelegateCheck will override the original CNI_COMMAND env from process with CHECK
|
||||||
|
return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("CHECK"), realExec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelegateDel calls the given delegate plugin with the CNI DEL action and
|
||||||
|
// JSON configuration
|
||||||
|
func DelegateDel(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error {
|
||||||
|
pluginPath, realExec, err := delegateCommon(delegatePlugin, exec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelegateDel will override the original CNI_COMMAND env from process with DEL
|
||||||
|
return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("DEL"), realExec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return CNIArgs used by delegation
|
||||||
|
func delegateArgs(action string) *DelegateArgs {
|
||||||
|
return &DelegateArgs{
|
||||||
|
Command: action,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
105
vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
generated
vendored
105
vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
generated
vendored
@ -15,6 +15,7 @@
|
|||||||
package invoke
|
package invoke
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -22,34 +23,62 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) {
|
// Exec is an interface encapsulates all operations that deal with finding
|
||||||
return defaultPluginExec.WithResult(pluginPath, netconf, args)
|
// 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(ctx context.Context, 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 {
|
// For example, a testcase could pass an instance of the following fakeExec
|
||||||
return defaultPluginExec.WithoutResult(pluginPath, netconf, args)
|
// 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)
|
||||||
|
//}
|
||||||
|
|
||||||
func GetVersionInfo(pluginPath string) (version.PluginInfo, error) {
|
func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) {
|
||||||
return defaultPluginExec.GetVersionInfo(pluginPath)
|
if exec == nil {
|
||||||
}
|
exec = defaultExec
|
||||||
|
|
||||||
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 := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv())
|
||||||
stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -64,8 +93,11 @@ func (e *PluginExec) WithResult(pluginPath string, netconf []byte, args CNIArgs)
|
|||||||
return version.NewResult(confVersion, stdoutBytes)
|
return version.NewResult(confVersion, stdoutBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIArgs) error {
|
func ExecPluginWithoutResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) error {
|
||||||
_, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv())
|
if exec == nil {
|
||||||
|
exec = defaultExec
|
||||||
|
}
|
||||||
|
_, err := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +105,10 @@ func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIAr
|
|||||||
// For recent-enough plugins, it uses the information returned by the VERSION
|
// For recent-enough plugins, it uses the information returned by the VERSION
|
||||||
// command. For older plugins which do not recognize that command, it reports
|
// command. For older plugins which do not recognize that command, it reports
|
||||||
// version 0.1.0
|
// version 0.1.0
|
||||||
func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, error) {
|
func GetVersionInfo(ctx context.Context, pluginPath string, exec Exec) (version.PluginInfo, error) {
|
||||||
|
if exec == nil {
|
||||||
|
exec = defaultExec
|
||||||
|
}
|
||||||
args := &Args{
|
args := &Args{
|
||||||
Command: "VERSION",
|
Command: "VERSION",
|
||||||
|
|
||||||
@ -83,7 +118,7 @@ func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, erro
|
|||||||
Path: "dummy",
|
Path: "dummy",
|
||||||
}
|
}
|
||||||
stdin := []byte(fmt.Sprintf(`{"cniVersion":%q}`, version.Current()))
|
stdin := []byte(fmt.Sprintf(`{"cniVersion":%q}`, version.Current()))
|
||||||
stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, stdin, args.AsEnv())
|
stdoutBytes, err := exec.ExecPlugin(ctx, pluginPath, stdin, args.AsEnv())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "unknown CNI_COMMAND: VERSION" {
|
if err.Error() == "unknown CNI_COMMAND: VERSION" {
|
||||||
return version.PluginSupports("0.1.0"), nil
|
return version.PluginSupports("0.1.0"), nil
|
||||||
@ -91,5 +126,19 @@ func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, erro
|
|||||||
return nil, err
|
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},
|
||||||
}
|
}
|
||||||
|
5
vendor/github.com/containernetworking/cni/pkg/invoke/find.go
generated
vendored
5
vendor/github.com/containernetworking/cni/pkg/invoke/find.go
generated
vendored
@ -18,6 +18,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FindInPath returns the full path of the plugin by searching in the provided path
|
// FindInPath returns the full path of the plugin by searching in the provided path
|
||||||
@ -26,6 +27,10 @@ func FindInPath(plugin string, paths []string) (string, error) {
|
|||||||
return "", fmt.Errorf("no plugin name provided")
|
return "", fmt.Errorf("no plugin name provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.ContainsRune(plugin, os.PathSeparator) {
|
||||||
|
return "", fmt.Errorf("invalid plugin name: %s", plugin)
|
||||||
|
}
|
||||||
|
|
||||||
if len(paths) == 0 {
|
if len(paths) == 0 {
|
||||||
return "", fmt.Errorf("no paths provided")
|
return "", fmt.Errorf("no paths provided")
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go
generated
vendored
2
vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go
generated
vendored
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build darwin dragonfly freebsd linux netbsd opensbd solaris
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||||
|
|
||||||
package invoke
|
package invoke
|
||||||
|
|
||||||
|
67
vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go
generated
vendored
67
vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go
generated
vendored
@ -16,10 +16,13 @@ package invoke
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
)
|
)
|
||||||
@ -28,32 +31,58 @@ type RawExec struct {
|
|||||||
Stderr io.Writer
|
Stderr io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *RawExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) {
|
func (e *RawExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData []byte, environ []string) ([]byte, error) {
|
||||||
stdout := &bytes.Buffer{}
|
stdout := &bytes.Buffer{}
|
||||||
|
stderr := &bytes.Buffer{}
|
||||||
|
c := exec.CommandContext(ctx, pluginPath)
|
||||||
|
c.Env = environ
|
||||||
|
c.Stdin = bytes.NewBuffer(stdinData)
|
||||||
|
c.Stdout = stdout
|
||||||
|
c.Stderr = stderr
|
||||||
|
|
||||||
c := exec.Cmd{
|
// Retry the command on "text file busy" errors
|
||||||
Env: environ,
|
for i := 0; i <= 5; i++ {
|
||||||
Path: pluginPath,
|
err := c.Run()
|
||||||
Args: []string{pluginPath},
|
|
||||||
Stdin: bytes.NewBuffer(stdinData),
|
// Command succeeded
|
||||||
Stdout: stdout,
|
if err == nil {
|
||||||
Stderr: e.Stderr,
|
break
|
||||||
}
|
}
|
||||||
if err := c.Run(); err != nil {
|
|
||||||
return nil, pluginErr(err, stdout.Bytes())
|
// If the plugin is currently about to be written, then we wait a
|
||||||
|
// second and try it again
|
||||||
|
if strings.Contains(err.Error(), "text file busy") {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other errors except than the busy text file
|
||||||
|
return nil, e.pluginErr(err, stdout.Bytes(), stderr.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy stderr to caller's buffer in case plugin printed to both
|
||||||
|
// stdout and stderr for some reason. Ignore failures as stderr is
|
||||||
|
// only informational.
|
||||||
|
if e.Stderr != nil && stderr.Len() > 0 {
|
||||||
|
_, _ = stderr.WriteTo(e.Stderr)
|
||||||
|
}
|
||||||
return stdout.Bytes(), nil
|
return stdout.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pluginErr(err error, output []byte) error {
|
func (e *RawExec) pluginErr(err error, stdout, stderr []byte) error {
|
||||||
if _, ok := err.(*exec.ExitError); ok {
|
emsg := types.Error{}
|
||||||
emsg := types.Error{}
|
if len(stdout) == 0 {
|
||||||
if perr := json.Unmarshal(output, &emsg); perr != nil {
|
if len(stderr) == 0 {
|
||||||
emsg.Msg = fmt.Sprintf("netplugin failed but error parsing its diagnostic message %q: %v", string(output), perr)
|
emsg.Msg = fmt.Sprintf("netplugin failed with no error message: %v", err)
|
||||||
|
} else {
|
||||||
|
emsg.Msg = fmt.Sprintf("netplugin failed: %q", string(stderr))
|
||||||
}
|
}
|
||||||
return &emsg
|
} else if perr := json.Unmarshal(stdout, &emsg); perr != nil {
|
||||||
|
emsg.Msg = fmt.Sprintf("netplugin failed but error parsing its diagnostic message %q: %v", string(stdout), perr)
|
||||||
}
|
}
|
||||||
|
return &emsg
|
||||||
return err
|
}
|
||||||
|
|
||||||
|
func (e *RawExec) FindInPath(plugin string, paths []string) (string, error) {
|
||||||
|
return FindInPath(plugin, paths)
|
||||||
}
|
}
|
||||||
|
21
vendor/github.com/containernetworking/cni/pkg/types/020/types.go
generated
vendored
21
vendor/github.com/containernetworking/cni/pkg/types/020/types.go
generated
vendored
@ -17,6 +17,7 @@ package types020
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -73,28 +74,18 @@ func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) Print() error {
|
func (r *Result) Print() error {
|
||||||
|
return r.PrintTo(os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) PrintTo(writer io.Writer) error {
|
||||||
data, err := json.MarshalIndent(r, "", " ")
|
data, err := json.MarshalIndent(r, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = os.Stdout.Write(data)
|
_, err = writer.Write(data)
|
||||||
return err
|
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
|
// IPConfig contains values necessary to configure an interface
|
||||||
type IPConfig struct {
|
type IPConfig struct {
|
||||||
IP net.IPNet
|
IP net.IPNet
|
||||||
|
2
vendor/github.com/containernetworking/cni/pkg/types/args.go
generated
vendored
2
vendor/github.com/containernetworking/cni/pkg/types/args.go
generated
vendored
@ -36,7 +36,7 @@ func (b *UnmarshallableBool) UnmarshalText(data []byte) error {
|
|||||||
case "0", "false":
|
case "0", "false":
|
||||||
*b = false
|
*b = false
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Boolean unmarshal error: invalid input %s", s)
|
return fmt.Errorf("boolean unmarshal error: invalid input %s", s)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
46
vendor/github.com/containernetworking/cni/pkg/types/current/types.go
generated
vendored
46
vendor/github.com/containernetworking/cni/pkg/types/current/types.go
generated
vendored
@ -17,6 +17,7 @@ package current
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -24,9 +25,9 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/types/020"
|
"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) {
|
func NewResult(data []byte) (types.Result, error) {
|
||||||
result := &Result{}
|
result := &Result{}
|
||||||
@ -75,13 +76,9 @@ func convertFrom020(result types.Result) (*Result, error) {
|
|||||||
Gateway: oldResult.IP4.Gateway,
|
Gateway: oldResult.IP4.Gateway,
|
||||||
})
|
})
|
||||||
for _, route := range oldResult.IP4.Routes {
|
for _, route := range oldResult.IP4.Routes {
|
||||||
gw := route.GW
|
|
||||||
if gw == nil {
|
|
||||||
gw = oldResult.IP4.Gateway
|
|
||||||
}
|
|
||||||
newResult.Routes = append(newResult.Routes, &types.Route{
|
newResult.Routes = append(newResult.Routes, &types.Route{
|
||||||
Dst: route.Dst,
|
Dst: route.Dst,
|
||||||
GW: gw,
|
GW: route.GW,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,21 +90,13 @@ func convertFrom020(result types.Result) (*Result, error) {
|
|||||||
Gateway: oldResult.IP6.Gateway,
|
Gateway: oldResult.IP6.Gateway,
|
||||||
})
|
})
|
||||||
for _, route := range oldResult.IP6.Routes {
|
for _, route := range oldResult.IP6.Routes {
|
||||||
gw := route.GW
|
|
||||||
if gw == nil {
|
|
||||||
gw = oldResult.IP6.Gateway
|
|
||||||
}
|
|
||||||
newResult.Routes = append(newResult.Routes, &types.Route{
|
newResult.Routes = append(newResult.Routes, &types.Route{
|
||||||
Dst: route.Dst,
|
Dst: route.Dst,
|
||||||
GW: gw,
|
GW: route.GW,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(newResult.IPs) == 0 {
|
|
||||||
return nil, fmt.Errorf("cannot convert: no valid IP addresses")
|
|
||||||
}
|
|
||||||
|
|
||||||
return newResult, nil
|
return newResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +185,7 @@ func (r *Result) Version() string {
|
|||||||
|
|
||||||
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
||||||
switch version {
|
switch version {
|
||||||
case "0.3.0", ImplementedSpecVersion:
|
case "0.3.0", "0.3.1", ImplementedSpecVersion:
|
||||||
r.CNIVersion = version
|
r.CNIVersion = version
|
||||||
return r, nil
|
return r, nil
|
||||||
case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
|
case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
|
||||||
@ -206,31 +195,18 @@ func (r *Result) GetAsVersion(version string) (types.Result, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result) Print() error {
|
func (r *Result) Print() error {
|
||||||
|
return r.PrintTo(os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) PrintTo(writer io.Writer) error {
|
||||||
data, err := json.MarshalIndent(r, "", " ")
|
data, err := json.MarshalIndent(r, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = os.Stdout.Write(data)
|
_, err = writer.Write(data)
|
||||||
return err
|
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
|
// Convert this old version result to the current CNI version result
|
||||||
func (r *Result) Convert() (*Result, error) {
|
func (r *Result) Convert() (*Result, error) {
|
||||||
return r, nil
|
return r, nil
|
||||||
|
52
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
52
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
@ -16,8 +16,8 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
@ -63,25 +63,31 @@ type NetConf struct {
|
|||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Capabilities map[string]bool `json:"capabilities,omitempty"`
|
Capabilities map[string]bool `json:"capabilities,omitempty"`
|
||||||
IPAM struct {
|
IPAM IPAM `json:"ipam,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
DNS DNS `json:"dns"`
|
||||||
} `json:"ipam,omitempty"`
|
|
||||||
DNS DNS `json:"dns"`
|
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
|
||||||
|
PrevResult Result `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IPAM struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetConfList describes an ordered list of networks.
|
// NetConfList describes an ordered list of networks.
|
||||||
type NetConfList struct {
|
type NetConfList struct {
|
||||||
CNIVersion string `json:"cniVersion,omitempty"`
|
CNIVersion string `json:"cniVersion,omitempty"`
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Plugins []*NetConf `json:"plugins,omitempty"`
|
DisableCheck bool `json:"disableCheck,omitempty"`
|
||||||
|
Plugins []*NetConf `json:"plugins,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResultFactoryFunc func([]byte) (Result, error)
|
type ResultFactoryFunc func([]byte) (Result, error)
|
||||||
|
|
||||||
// Result is an interface that provides the result of plugin execution
|
// Result is an interface that provides the result of plugin execution
|
||||||
type Result interface {
|
type Result interface {
|
||||||
// The highest CNI specification result verison the result supports
|
// The highest CNI specification result version the result supports
|
||||||
// without having to convert
|
// without having to convert
|
||||||
Version() string
|
Version() string
|
||||||
|
|
||||||
@ -92,8 +98,8 @@ type Result interface {
|
|||||||
// Prints the result in JSON format to stdout
|
// Prints the result in JSON format to stdout
|
||||||
Print() error
|
Print() error
|
||||||
|
|
||||||
// Returns a JSON string representation of the result
|
// Prints the result in JSON format to provided writer
|
||||||
String() string
|
PrintTo(writer io.Writer) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrintResult(result Result, version string) error {
|
func PrintResult(result Result, version string) error {
|
||||||
@ -124,9 +130,16 @@ func (r *Route) String() string {
|
|||||||
// Well known error codes
|
// Well known error codes
|
||||||
// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
|
// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
|
||||||
const (
|
const (
|
||||||
ErrUnknown uint = iota // 0
|
ErrUnknown uint = iota // 0
|
||||||
ErrIncompatibleCNIVersion // 1
|
ErrIncompatibleCNIVersion // 1
|
||||||
ErrUnsupportedField // 2
|
ErrUnsupportedField // 2
|
||||||
|
ErrUnknownContainer // 3
|
||||||
|
ErrInvalidEnvironmentVariables // 4
|
||||||
|
ErrIOFailure // 5
|
||||||
|
ErrDecodingFailure // 6
|
||||||
|
ErrInvalidNetworkConfig // 7
|
||||||
|
ErrTryAgainLater uint = 11
|
||||||
|
ErrInternal uint = 999
|
||||||
)
|
)
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
@ -135,6 +148,14 @@ type Error struct {
|
|||||||
Details string `json:"details,omitempty"`
|
Details string `json:"details,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewError(code uint, msg, details string) *Error {
|
||||||
|
return &Error{
|
||||||
|
Code: code,
|
||||||
|
Msg: msg,
|
||||||
|
Details: details,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
details := ""
|
details := ""
|
||||||
if e.Details != "" {
|
if e.Details != "" {
|
||||||
@ -167,7 +188,7 @@ func (r *Route) UnmarshalJSON(data []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Route) MarshalJSON() ([]byte, error) {
|
func (r Route) MarshalJSON() ([]byte, error) {
|
||||||
rt := route{
|
rt := route{
|
||||||
Dst: IPNet(r.Dst),
|
Dst: IPNet(r.Dst),
|
||||||
GW: r.GW,
|
GW: r.GW,
|
||||||
@ -184,6 +205,3 @@ func prettyPrint(obj interface{}) error {
|
|||||||
_, err = os.Stdout.Write(data)
|
_, err = os.Stdout.Write(data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotImplementedError is used to indicate that a method is not implemented for the given platform
|
|
||||||
var NotImplementedError = errors.New("Not Implemented")
|
|
||||||
|
84
vendor/github.com/containernetworking/cni/pkg/utils/utils.go
generated
vendored
Normal file
84
vendor/github.com/containernetworking/cni/pkg/utils/utils.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Copyright 2019 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 utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// cniValidNameChars is the regexp used to validate valid characters in
|
||||||
|
// containerID and networkName
|
||||||
|
cniValidNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.\-]`
|
||||||
|
|
||||||
|
// maxInterfaceNameLength is the length max of a valid interface name
|
||||||
|
maxInterfaceNameLength = 15
|
||||||
|
)
|
||||||
|
|
||||||
|
var cniReg = regexp.MustCompile(`^` + cniValidNameChars + `*$`)
|
||||||
|
|
||||||
|
// ValidateContainerID will validate that the supplied containerID is not empty does not contain invalid characters
|
||||||
|
func ValidateContainerID(containerID string) *types.Error {
|
||||||
|
|
||||||
|
if containerID == "" {
|
||||||
|
return types.NewError(types.ErrUnknownContainer, "missing containerID", "")
|
||||||
|
}
|
||||||
|
if !cniReg.MatchString(containerID) {
|
||||||
|
return types.NewError(types.ErrInvalidEnvironmentVariables, "invalid characters in containerID", containerID)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateNetworkName will validate that the supplied networkName does not contain invalid characters
|
||||||
|
func ValidateNetworkName(networkName string) *types.Error {
|
||||||
|
|
||||||
|
if networkName == "" {
|
||||||
|
return types.NewError(types.ErrInvalidNetworkConfig, "missing network name:", "")
|
||||||
|
}
|
||||||
|
if !cniReg.MatchString(networkName) {
|
||||||
|
return types.NewError(types.ErrInvalidNetworkConfig, "invalid characters found in network name", networkName)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateInterfaceName will validate the interface name based on the three rules below
|
||||||
|
// 1. The name must not be empty
|
||||||
|
// 2. The name must be less than 16 characters
|
||||||
|
// 3. The name must not be "." or ".."
|
||||||
|
// 3. The name must not contain / or : or any whitespace characters
|
||||||
|
// ref to https://github.com/torvalds/linux/blob/master/net/core/dev.c#L1024
|
||||||
|
func ValidateInterfaceName(ifName string) *types.Error {
|
||||||
|
if len(ifName) == 0 {
|
||||||
|
return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is empty", "")
|
||||||
|
}
|
||||||
|
if len(ifName) > maxInterfaceNameLength {
|
||||||
|
return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is too long", fmt.Sprintf("interface name should be less than %d characters", maxInterfaceNameLength+1))
|
||||||
|
}
|
||||||
|
if ifName == "." || ifName == ".." {
|
||||||
|
return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is . or ..", "")
|
||||||
|
}
|
||||||
|
for _, r := range bytes.Runes([]byte(ifName)) {
|
||||||
|
if r == '/' || r == ':' || unicode.IsSpace(r) {
|
||||||
|
return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name contains / or : or whitespace characters", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
63
vendor/github.com/containernetworking/cni/pkg/version/plugin.go
generated
vendored
63
vendor/github.com/containernetworking/cni/pkg/version/plugin.go
generated
vendored
@ -18,6 +18,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PluginInfo reports information about CNI versioning
|
// PluginInfo reports information about CNI versioning
|
||||||
@ -79,3 +81,64 @@ func (*PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) {
|
|||||||
}
|
}
|
||||||
return &info, nil
|
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
|
||||||
|
if version == "" {
|
||||||
|
return -1, -1, -1, fmt.Errorf("invalid version %q: the version is empty", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(version, ".")
|
||||||
|
if len(parts) >= 4 {
|
||||||
|
return -1, -1, -1, fmt.Errorf("invalid version %q: too many 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
|
||||||
|
// numbers, 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
|
||||||
|
}
|
||||||
|
26
vendor/github.com/containernetworking/cni/pkg/version/version.go
generated
vendored
26
vendor/github.com/containernetworking/cni/pkg/version/version.go
generated
vendored
@ -15,6 +15,7 @@
|
|||||||
package version
|
package version
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containernetworking/cni/pkg/types"
|
"github.com/containernetworking/cni/pkg/types"
|
||||||
@ -24,7 +25,7 @@ import (
|
|||||||
|
|
||||||
// Current reports the version of the CNI spec implemented by this library
|
// Current reports the version of the CNI spec implemented by this library
|
||||||
func Current() string {
|
func Current() string {
|
||||||
return "0.3.1"
|
return "0.4.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legacy PluginInfo describes a plugin that is backwards compatible with the
|
// Legacy PluginInfo describes a plugin that is backwards compatible with the
|
||||||
@ -35,7 +36,7 @@ func Current() string {
|
|||||||
// Any future CNI spec versions which meet this definition should be added to
|
// Any future CNI spec versions which meet this definition should be added to
|
||||||
// this list.
|
// this list.
|
||||||
var Legacy = PluginSupports("0.1.0", "0.2.0")
|
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 {
|
var resultFactories = []struct {
|
||||||
supportedVersions []string
|
supportedVersions []string
|
||||||
@ -59,3 +60,24 @@ func NewResult(version string, resultBytes []byte) (types.Result, error) {
|
|||||||
|
|
||||||
return nil, fmt.Errorf("unsupported CNI result version %q", version)
|
return nil, fmt.Errorf("unsupported CNI result version %q", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParsePrevResult parses a prevResult in a NetConf structure and sets
|
||||||
|
// the NetConf's PrevResult member to the parsed Result object.
|
||||||
|
func ParsePrevResult(conf *types.NetConf) error {
|
||||||
|
if conf.RawPrevResult == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resultBytes, err := json.Marshal(conf.RawPrevResult)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not serialize prevResult: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.RawPrevResult = nil
|
||||||
|
conf.PrevResult, err = NewResult(conf.CNIVersion, resultBytes)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse prevResult: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -16,13 +16,14 @@ github.com/campoy/embedmd/embedmd
|
|||||||
# github.com/cespare/xxhash/v2 v2.1.1
|
# github.com/cespare/xxhash/v2 v2.1.1
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
github.com/cespare/xxhash/v2
|
github.com/cespare/xxhash/v2
|
||||||
# github.com/containernetworking/cni v0.6.0
|
# github.com/containernetworking/cni v0.8.1
|
||||||
## explicit
|
## explicit
|
||||||
github.com/containernetworking/cni/libcni
|
github.com/containernetworking/cni/libcni
|
||||||
github.com/containernetworking/cni/pkg/invoke
|
github.com/containernetworking/cni/pkg/invoke
|
||||||
github.com/containernetworking/cni/pkg/types
|
github.com/containernetworking/cni/pkg/types
|
||||||
github.com/containernetworking/cni/pkg/types/020
|
github.com/containernetworking/cni/pkg/types/020
|
||||||
github.com/containernetworking/cni/pkg/types/current
|
github.com/containernetworking/cni/pkg/types/current
|
||||||
|
github.com/containernetworking/cni/pkg/utils
|
||||||
github.com/containernetworking/cni/pkg/version
|
github.com/containernetworking/cni/pkg/version
|
||||||
# github.com/containernetworking/plugins v0.6.0
|
# github.com/containernetworking/plugins v0.6.0
|
||||||
## explicit
|
## explicit
|
||||||
|
Loading…
Reference in New Issue
Block a user