mirror of
https://github.com/containers/podman.git
synced 2025-12-07 14:20:44 +08:00
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
This commit is contained in:
42
vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go
generated
vendored
42
vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
func DelegateDel(delegatePlugin string, netconf []byte) error {
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
104
vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
generated
vendored
104
vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
generated
vendored
@@ -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)
|
||||
}
|
||||
// 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)
|
||||
//}
|
||||
|
||||
func GetVersionInfo(pluginPath string) (version.PluginInfo, error) {
|
||||
return defaultPluginExec.GetVersionInfo(pluginPath)
|
||||
}
|
||||
|
||||
var defaultPluginExec = &PluginExec{
|
||||
RawExec: &RawExec{Stderr: os.Stderr},
|
||||
VersionDecoder: &version.PluginDecoder{},
|
||||
}
|
||||
|
||||
type PluginExec struct {
|
||||
RawExec interface {
|
||||
ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error)
|
||||
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},
|
||||
}
|
||||
|
||||
4
vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go
generated
vendored
4
vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go
generated
vendored
@@ -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)
|
||||
}
|
||||
|
||||
6
vendor/github.com/containernetworking/cni/pkg/types/current/types.go
generated
vendored
6
vendor/github.com/containernetworking/cni/pkg/types/current/types.go
generated
vendored
@@ -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]:
|
||||
|
||||
12
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
12
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
@@ -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,
|
||||
|
||||
59
vendor/github.com/containernetworking/cni/pkg/version/plugin.go
generated
vendored
59
vendor/github.com/containernetworking/cni/pkg/version/plugin.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
4
vendor/github.com/containernetworking/cni/pkg/version/version.go
generated
vendored
4
vendor/github.com/containernetworking/cni/pkg/version/version.go
generated
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user