func (c *CNIConfig) GetNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
	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)
}
GetNetworkList executes a sequence of plugins with the GET command
package libcni
import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"github.com/containernetworking/cni/pkg/invoke"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/version"
)
var (
	CacheDir = "/var/lib/cni"
)
type RuntimeConf struct {
	ContainerID string
	NetNS       string
	IfName      string
	Args        [][2]string
	CapabilityArgs map[string]interface{}
	CacheDir string
}
type NetworkConfig struct {
	Network *types.NetConf
	Bytes   []byte
}
type NetworkConfigList struct {
	Name       string
	CNIVersion string
	Plugins    []*NetworkConfig
	Bytes      []byte
}
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
	ValidateNetworkList(net *NetworkConfigList) ([]string, error)
	ValidateNetwork(net *NetworkConfig) ([]string, error)
}
type CNIConfig struct {
	Path []string
	exec invoke.Exec
}
var _ CNI = &CNIConfig{}
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":       name,
		"cniVersion": cniVersion,
	}
	if prevResult != nil {
		inject["prevResult"] = prevResult
	}
	orig, err = InjectConf(orig, inject)
	if err != nil {
		return nil, err
	}
	return injectRuntimeConfig(orig, rt)
}
func injectRuntimeConfig(orig *NetworkConfig, rt *RuntimeConf) (*NetworkConfig, error) {
	var err error
	rc := make(map[string]interface{})
	for capability, supported := range orig.Network.Capabilities {
		if !supported {
			continue
		}
		if data, ok := rt.CapabilityArgs[capability]; ok {
			rc[capability] = data
		}
	}
	if len(rc) > 0 {
		orig, err = InjectConf(orig, map[string]interface{}{"runtimeConfig": rc})
		if err != nil {
			return nil, err
		}
	}
	return orig, nil
}
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
}
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
	}
	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)
}
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
		}
	}
	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 {
		return nil, nil
	}
	decoder := version.ConfigDecoder{}
	resultCniVersion, err := decoder.Decode(data)
	if err != nil {
		return nil, err
	}
	result, err := version.NewResult(resultCniVersion, data)
	if err != nil {
		return nil, err
	}
	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) 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
}