mirror of
				https://github.com/rancher/plugins.git
				synced 2025-11-04 02:11:05 +00:00 
			
		
		
		
	plugins: remove flannel
Now that the flannel CNI plugin has been moved to https://github.com/flannel-io/cni-plugin, we should remove it from here. Signed-off-by: Casey Callendrello <cdc@redhat.com>
This commit is contained in:
		@@ -23,7 +23,6 @@ Read [CONTRIBUTING](CONTRIBUTING.md) for build and test instructions.
 | 
			
		||||
* `static`:  Allocate a static IPv4/IPv6 addresses to container and it's useful in debugging purpose.
 | 
			
		||||
 | 
			
		||||
### Meta: other plugins
 | 
			
		||||
* `flannel`: Generates an interface corresponding to a flannel config file
 | 
			
		||||
* `tuning`: Tweaks sysctl parameters of an existing interface
 | 
			
		||||
* `portmap`: An iptables-based portmapping plugin. Maps ports from the host's address space to the container.
 | 
			
		||||
* `bandwidth`: Allows bandwidth-limiting through use of traffic control tbf (ingress/egress).
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							@@ -519,7 +519,6 @@ github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA85
 | 
			
		||||
github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
 | 
			
		||||
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
 | 
			
		||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
 | 
			
		||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns=
 | 
			
		||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
 | 
			
		||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
 | 
			
		||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
 | 
			
		||||
@@ -696,7 +695,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
			
		||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 h1:g9s1Ppvvun/fI+BptTMj909BBIcGrzQ32k9FNlcevOE=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								plugins/main/windows/win-bridge/sample-v1.conf
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										43
									
								
								plugins/main/windows/win-bridge/sample-v1.conf
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@@ -1,22 +1,20 @@
 | 
			
		||||
{
 | 
			
		||||
    "name":"cbr0",
 | 
			
		||||
    "type":"flannel",
 | 
			
		||||
    "delegate":{
 | 
			
		||||
        "type":"win-bridge",
 | 
			
		||||
        "dns":{
 | 
			
		||||
            "nameservers":[
 | 
			
		||||
  "name": "cbr0",
 | 
			
		||||
  "type": "win-bridge",
 | 
			
		||||
  "dns": {
 | 
			
		||||
    "nameservers": [
 | 
			
		||||
      "11.0.0.10"
 | 
			
		||||
    ],
 | 
			
		||||
            "search":[
 | 
			
		||||
    "search": [
 | 
			
		||||
      "svc.cluster.local"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
        "policies":[
 | 
			
		||||
  "policies": [
 | 
			
		||||
    {
 | 
			
		||||
                "name":"EndpointPolicy",
 | 
			
		||||
                "value":{
 | 
			
		||||
                    "Type":"OutBoundNAT",
 | 
			
		||||
                    "ExceptionList":[
 | 
			
		||||
      "name": "EndpointPolicy",
 | 
			
		||||
      "value": {
 | 
			
		||||
        "Type": "OutBoundNAT",
 | 
			
		||||
        "ExceptionList": [
 | 
			
		||||
          "192.168.0.0/16",
 | 
			
		||||
          "11.0.0.0/8",
 | 
			
		||||
          "10.137.196.0/23"
 | 
			
		||||
@@ -24,22 +22,21 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
                "name":"EndpointPolicy",
 | 
			
		||||
                "value":{
 | 
			
		||||
                    "Type":"ROUTE",
 | 
			
		||||
                    "DestinationPrefix":"11.0.0.0/8",
 | 
			
		||||
                    "NeedEncap":true
 | 
			
		||||
      "name": "EndpointPolicy",
 | 
			
		||||
      "value": {
 | 
			
		||||
        "Type": "ROUTE",
 | 
			
		||||
        "DestinationPrefix": "11.0.0.0/8",
 | 
			
		||||
        "NeedEncap": true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
                "name":"EndpointPolicy",
 | 
			
		||||
                "value":{
 | 
			
		||||
                    "Type":"ROUTE",
 | 
			
		||||
                    "DestinationPrefix":"10.137.198.27/32",
 | 
			
		||||
                    "NeedEncap":true
 | 
			
		||||
      "name": "EndpointPolicy",
 | 
			
		||||
      "value": {
 | 
			
		||||
        "Type": "ROUTE",
 | 
			
		||||
        "DestinationPrefix": "10.137.198.27/32",
 | 
			
		||||
        "NeedEncap": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "loopbackDSR": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								plugins/main/windows/win-overlay/sample.conf
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										35
									
								
								plugins/main/windows/win-overlay/sample.conf
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@@ -1,36 +1,33 @@
 | 
			
		||||
{
 | 
			
		||||
    "cniVersion":"0.2.0",
 | 
			
		||||
    "name":"vxlan0",
 | 
			
		||||
    "type":"flannel",
 | 
			
		||||
    "delegate":{
 | 
			
		||||
        "type":"win-overlay",
 | 
			
		||||
        "dns":{
 | 
			
		||||
            "nameservers":[
 | 
			
		||||
  "cniVersion": "0.2.0",
 | 
			
		||||
  "name": "vxlan0",
 | 
			
		||||
  "type": "win-overlay",
 | 
			
		||||
  "dns": {
 | 
			
		||||
    "nameservers": [
 | 
			
		||||
      "11.0.0.10"
 | 
			
		||||
    ],
 | 
			
		||||
            "search":[
 | 
			
		||||
    "search": [
 | 
			
		||||
      "svc.cluster.local"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
        "policies":[
 | 
			
		||||
  "policies": [
 | 
			
		||||
    {
 | 
			
		||||
                "name":"EndpointPolicy",
 | 
			
		||||
                "value":{
 | 
			
		||||
                    "Type":"OutBoundNAT",
 | 
			
		||||
                    "ExceptionList":[
 | 
			
		||||
      "name": "EndpointPolicy",
 | 
			
		||||
      "value": {
 | 
			
		||||
        "Type": "OutBoundNAT",
 | 
			
		||||
        "ExceptionList": [
 | 
			
		||||
          "192.168.0.0/16",
 | 
			
		||||
          "11.0.0.0/8"
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
                "name":"EndpointPolicy",
 | 
			
		||||
                "value":{
 | 
			
		||||
                    "Type":"ROUTE",
 | 
			
		||||
                    "DestinationPrefix":"11.0.0.0/8",
 | 
			
		||||
                    "NeedEncap":true
 | 
			
		||||
      "name": "EndpointPolicy",
 | 
			
		||||
      "value": {
 | 
			
		||||
        "Type": "ROUTE",
 | 
			
		||||
        "DestinationPrefix": "11.0.0.0/8",
 | 
			
		||||
        "NeedEncap": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
 | 
			
		||||
This document has moved to the [containernetworking/cni.dev](https://github.com/containernetworking/cni.dev) repo.
 | 
			
		||||
 | 
			
		||||
You can find it online here: https://cni.dev/plugins/current/meta/flannel/
 | 
			
		||||
 | 
			
		||||
@@ -1,279 +0,0 @@
 | 
			
		||||
// Copyright 2015 CNI authors
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
// This is a "meta-plugin". It reads in its own netconf, combines it with
 | 
			
		||||
// the data from flannel generated subnet file and then invokes a plugin
 | 
			
		||||
// like bridge or ipvlan to do the real work.
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/invoke"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/skel"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/types"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/version"
 | 
			
		||||
 | 
			
		||||
	bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	defaultSubnetFile = "/run/flannel/subnet.env"
 | 
			
		||||
	defaultDataDir    = "/var/lib/cni/flannel"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type NetConf struct {
 | 
			
		||||
	types.NetConf
 | 
			
		||||
 | 
			
		||||
	// IPAM field "replaces" that of types.NetConf which is incomplete
 | 
			
		||||
	IPAM          map[string]interface{} `json:"ipam,omitempty"`
 | 
			
		||||
	SubnetFile    string                 `json:"subnetFile"`
 | 
			
		||||
	DataDir       string                 `json:"dataDir"`
 | 
			
		||||
	Delegate      map[string]interface{} `json:"delegate"`
 | 
			
		||||
	RuntimeConfig map[string]interface{} `json:"runtimeConfig,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type subnetEnv struct {
 | 
			
		||||
	nw     *net.IPNet
 | 
			
		||||
	sn     *net.IPNet
 | 
			
		||||
	ip6Nw  *net.IPNet
 | 
			
		||||
	ip6Sn  *net.IPNet
 | 
			
		||||
	mtu    *uint
 | 
			
		||||
	ipmasq *bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (se *subnetEnv) missing() string {
 | 
			
		||||
	m := []string{}
 | 
			
		||||
 | 
			
		||||
	if se.nw == nil && se.ip6Nw == nil {
 | 
			
		||||
		m = append(m, []string{"FLANNEL_NETWORK", "FLANNEL_IPV6_NETWORK"}...)
 | 
			
		||||
	}
 | 
			
		||||
	if se.sn == nil && se.ip6Sn == nil {
 | 
			
		||||
		m = append(m, []string{"FLANNEL_SUBNET", "FLANNEL_IPV6_SUBNET"}...)
 | 
			
		||||
	}
 | 
			
		||||
	if se.mtu == nil {
 | 
			
		||||
		m = append(m, "FLANNEL_MTU")
 | 
			
		||||
	}
 | 
			
		||||
	if se.ipmasq == nil {
 | 
			
		||||
		m = append(m, "FLANNEL_IPMASQ")
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(m, ", ")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func loadFlannelNetConf(bytes []byte) (*NetConf, error) {
 | 
			
		||||
	n := &NetConf{
 | 
			
		||||
		SubnetFile: defaultSubnetFile,
 | 
			
		||||
		DataDir:    defaultDataDir,
 | 
			
		||||
	}
 | 
			
		||||
	if err := json.Unmarshal(bytes, n); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to load netconf: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getIPAMRoutes(n *NetConf) ([]types.Route, error) {
 | 
			
		||||
	rtes := []types.Route{}
 | 
			
		||||
 | 
			
		||||
	if n.IPAM != nil && hasKey(n.IPAM, "routes") {
 | 
			
		||||
		buf, _ := json.Marshal(n.IPAM["routes"])
 | 
			
		||||
		if err := json.Unmarshal(buf, &rtes); err != nil {
 | 
			
		||||
			return rtes, fmt.Errorf("failed to parse ipam.routes: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return rtes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func loadFlannelSubnetEnv(fn string) (*subnetEnv, error) {
 | 
			
		||||
	f, err := os.Open(fn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	se := &subnetEnv{}
 | 
			
		||||
 | 
			
		||||
	s := bufio.NewScanner(f)
 | 
			
		||||
	for s.Scan() {
 | 
			
		||||
		parts := strings.SplitN(s.Text(), "=", 2)
 | 
			
		||||
		switch parts[0] {
 | 
			
		||||
		case "FLANNEL_NETWORK":
 | 
			
		||||
			_, se.nw, err = net.ParseCIDR(parts[1])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "FLANNEL_SUBNET":
 | 
			
		||||
			_, se.sn, err = net.ParseCIDR(parts[1])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "FLANNEL_IPV6_NETWORK":
 | 
			
		||||
			_, se.ip6Nw, err = net.ParseCIDR(parts[1])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "FLANNEL_IPV6_SUBNET":
 | 
			
		||||
			_, se.ip6Sn, err = net.ParseCIDR(parts[1])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "FLANNEL_MTU":
 | 
			
		||||
			mtu, err := strconv.ParseUint(parts[1], 10, 32)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			se.mtu = new(uint)
 | 
			
		||||
			*se.mtu = uint(mtu)
 | 
			
		||||
 | 
			
		||||
		case "FLANNEL_IPMASQ":
 | 
			
		||||
			ipmasq := parts[1] == "true"
 | 
			
		||||
			se.ipmasq = &ipmasq
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.Err(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if m := se.missing(); m != "" {
 | 
			
		||||
		return nil, fmt.Errorf("%v is missing %v", fn, m)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return se, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func saveScratchNetConf(containerID, dataDir string, netconf []byte) error {
 | 
			
		||||
	if err := os.MkdirAll(dataDir, 0700); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	path := filepath.Join(dataDir, containerID)
 | 
			
		||||
	return ioutil.WriteFile(path, netconf, 0600)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func consumeScratchNetConf(containerID, dataDir string) (func(error), []byte, error) {
 | 
			
		||||
	path := filepath.Join(dataDir, containerID)
 | 
			
		||||
 | 
			
		||||
	// cleanup will do clean job when no error happens in consuming/using process
 | 
			
		||||
	cleanup := func(err error) {
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			// Ignore errors when removing - Per spec safe to continue during DEL
 | 
			
		||||
			_ = os.Remove(path)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	netConfBytes, err := ioutil.ReadFile(path)
 | 
			
		||||
 | 
			
		||||
	return cleanup, netConfBytes, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func delegateAdd(cid, dataDir, cniVersion string, netconf map[string]interface{}) error {
 | 
			
		||||
	netconfBytes, err := json.Marshal(netconf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("error serializing delegate netconf: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// save the rendered netconf for cmdDel
 | 
			
		||||
	if err = saveScratchNetConf(cid, dataDir, netconfBytes); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := invoke.DelegateAdd(context.TODO(), netconf["type"].(string), netconfBytes, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return types.PrintResult(result, cniVersion)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasKey(m map[string]interface{}, k string) bool {
 | 
			
		||||
	_, ok := m[k]
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isString(i interface{}) bool {
 | 
			
		||||
	_, ok := i.(string)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdAdd(args *skel.CmdArgs) error {
 | 
			
		||||
	n, err := loadFlannelNetConf(args.StdinData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fenv, err := loadFlannelSubnetEnv(n.SubnetFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if n.Delegate == nil {
 | 
			
		||||
		n.Delegate = make(map[string]interface{})
 | 
			
		||||
	} else {
 | 
			
		||||
		if hasKey(n.Delegate, "type") && !isString(n.Delegate["type"]) {
 | 
			
		||||
			return fmt.Errorf("'delegate' dictionary, if present, must have (string) 'type' field")
 | 
			
		||||
		}
 | 
			
		||||
		if hasKey(n.Delegate, "name") {
 | 
			
		||||
			return fmt.Errorf("'delegate' dictionary must not have 'name' field, it'll be set by flannel")
 | 
			
		||||
		}
 | 
			
		||||
		if hasKey(n.Delegate, "ipam") {
 | 
			
		||||
			return fmt.Errorf("'delegate' dictionary must not have 'ipam' field, it'll be set by flannel")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if n.RuntimeConfig != nil {
 | 
			
		||||
		n.Delegate["runtimeConfig"] = n.RuntimeConfig
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delegate CNI config version must match flannel plugin config version
 | 
			
		||||
	n.Delegate["cniVersion"] = n.CNIVersion
 | 
			
		||||
 | 
			
		||||
	return doCmdAdd(args, n.CNIVersion, n, fenv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdDel(args *skel.CmdArgs) error {
 | 
			
		||||
	nc, err := loadFlannelNetConf(args.StdinData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if nc.RuntimeConfig != nil {
 | 
			
		||||
		if nc.Delegate == nil {
 | 
			
		||||
			nc.Delegate = make(map[string]interface{})
 | 
			
		||||
		}
 | 
			
		||||
		nc.Delegate["runtimeConfig"] = nc.RuntimeConfig
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return doCmdDel(args, nc)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, bv.BuildString("flannel"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cmdCheck(args *skel.CmdArgs) error {
 | 
			
		||||
	// TODO: implement
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -1,132 +0,0 @@
 | 
			
		||||
// Copyright 2018 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.
 | 
			
		||||
 | 
			
		||||
// This is a "meta-plugin". It reads in its own netconf, combines it with
 | 
			
		||||
// the data from flannel generated subnet file and then invokes a plugin
 | 
			
		||||
// like bridge or ipvlan to do the real work.
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/invoke"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/skel"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/types"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Return IPAM section for Delegate using input IPAM if present and replacing
 | 
			
		||||
// or complementing as needed.
 | 
			
		||||
func getDelegateIPAM(n *NetConf, fenv *subnetEnv) (map[string]interface{}, error) {
 | 
			
		||||
	ipam := n.IPAM
 | 
			
		||||
	if ipam == nil {
 | 
			
		||||
		ipam = map[string]interface{}{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !hasKey(ipam, "type") {
 | 
			
		||||
		ipam["type"] = "host-local"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var rangesSlice [][]map[string]interface{}
 | 
			
		||||
 | 
			
		||||
	if fenv.sn != nil && fenv.sn.String() != "" {
 | 
			
		||||
		rangesSlice = append(rangesSlice, []map[string]interface{}{
 | 
			
		||||
			{"subnet": fenv.sn.String()},
 | 
			
		||||
		},
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	if fenv.ip6Sn != nil && fenv.ip6Sn.String() != "" {
 | 
			
		||||
		rangesSlice = append(rangesSlice, []map[string]interface{}{
 | 
			
		||||
			{"subnet": fenv.ip6Sn.String()},
 | 
			
		||||
		},
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	ipam["ranges"] = rangesSlice
 | 
			
		||||
 | 
			
		||||
	rtes, err := getIPAMRoutes(n)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to read IPAM routes: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	if fenv.nw != nil {
 | 
			
		||||
		rtes = append(rtes, types.Route{Dst: *fenv.nw})
 | 
			
		||||
	}
 | 
			
		||||
	if fenv.ip6Nw != nil {
 | 
			
		||||
		rtes = append(rtes, types.Route{Dst: *fenv.ip6Nw})
 | 
			
		||||
	}
 | 
			
		||||
	ipam["routes"] = rtes
 | 
			
		||||
 | 
			
		||||
	return ipam, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func doCmdAdd(args *skel.CmdArgs, cniVersion string, n *NetConf, fenv *subnetEnv) error {
 | 
			
		||||
	n.Delegate["name"] = n.Name
 | 
			
		||||
 | 
			
		||||
	if !hasKey(n.Delegate, "type") {
 | 
			
		||||
		n.Delegate["type"] = "bridge"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !hasKey(n.Delegate, "ipMasq") {
 | 
			
		||||
		// if flannel is not doing ipmasq, we should
 | 
			
		||||
		ipmasq := !*fenv.ipmasq
 | 
			
		||||
		n.Delegate["ipMasq"] = ipmasq
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !hasKey(n.Delegate, "mtu") {
 | 
			
		||||
		mtu := fenv.mtu
 | 
			
		||||
		n.Delegate["mtu"] = mtu
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if n.Delegate["type"].(string) == "bridge" {
 | 
			
		||||
		if !hasKey(n.Delegate, "isGateway") {
 | 
			
		||||
			n.Delegate["isGateway"] = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if n.CNIVersion != "" {
 | 
			
		||||
		n.Delegate["cniVersion"] = n.CNIVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ipam, err := getDelegateIPAM(n, fenv)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to assemble Delegate IPAM: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	n.Delegate["ipam"] = ipam
 | 
			
		||||
 | 
			
		||||
	return delegateAdd(args.ContainerID, n.DataDir, cniVersion, n.Delegate)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func doCmdDel(args *skel.CmdArgs, n *NetConf) (err error) {
 | 
			
		||||
	cleanup, netConfBytes, err := consumeScratchNetConf(args.ContainerID, n.DataDir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			// Per spec should ignore error if resources are missing / already removed
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// cleanup will work when no error happens
 | 
			
		||||
	defer func() {
 | 
			
		||||
		cleanup(err)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	nc := &types.NetConf{}
 | 
			
		||||
	if err = json.Unmarshal(netConfBytes, nc); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to parse netconf: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return invoke.DelegateDel(context.TODO(), nc.Type, netConfBytes, nil)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,697 +0,0 @@
 | 
			
		||||
// Copyright 2015 CNI authors
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/skel"
 | 
			
		||||
	current "github.com/containernetworking/cni/pkg/types/100"
 | 
			
		||||
	"github.com/containernetworking/plugins/pkg/ns"
 | 
			
		||||
	"github.com/containernetworking/plugins/pkg/testutils"
 | 
			
		||||
 | 
			
		||||
	. "github.com/onsi/ginkgo"
 | 
			
		||||
	. "github.com/onsi/gomega"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = Describe("Flannel", func() {
 | 
			
		||||
	var (
 | 
			
		||||
		originalNS          ns.NetNS
 | 
			
		||||
		targetNS            ns.NetNS
 | 
			
		||||
		onlyIpv4Input       string
 | 
			
		||||
		onlyIpv6Input       string
 | 
			
		||||
		dualStackInput      string
 | 
			
		||||
		onlyIpv4SubnetFile  string
 | 
			
		||||
		onlyIpv6SubnetFile  string
 | 
			
		||||
		dualStackSubnetFile string
 | 
			
		||||
		dataDir             string
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	const inputTemplate = `{
 | 
			
		||||
	"name": "cni-flannel",
 | 
			
		||||
	"type": "flannel",
 | 
			
		||||
	"cniVersion": "%s",
 | 
			
		||||
	"subnetFile": "%s",
 | 
			
		||||
	"dataDir": "%s"%s
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
	const inputIPAMTemplate = `
 | 
			
		||||
    "unknown-param": "unknown-value",
 | 
			
		||||
    "routes": [%s]%s`
 | 
			
		||||
 | 
			
		||||
	const inputIPAMType = "my-ipam"
 | 
			
		||||
 | 
			
		||||
	const inputIPAMNoTypeTemplate = `
 | 
			
		||||
{
 | 
			
		||||
    "unknown-param": "unknown-value",
 | 
			
		||||
    "routes": [%s]%s
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
	const inputIPAMRoutes = `
 | 
			
		||||
      { "dst": "10.96.0.0/12" },
 | 
			
		||||
      { "dst": "192.168.244.0/24", "gw": "10.1.17.20" }`
 | 
			
		||||
 | 
			
		||||
	const onlyIpv4FlannelSubnetEnv = `
 | 
			
		||||
FLANNEL_NETWORK=10.1.0.0/16
 | 
			
		||||
FLANNEL_SUBNET=10.1.17.1/24
 | 
			
		||||
FLANNEL_MTU=1472
 | 
			
		||||
FLANNEL_IPMASQ=true
 | 
			
		||||
`
 | 
			
		||||
	const onlyIpv6FlannelSubnetEnv = `
 | 
			
		||||
FLANNEL_IPV6_NETWORK=fc00::/48
 | 
			
		||||
FLANNEL_IPV6_SUBNET=fc00::1/64
 | 
			
		||||
FLANNEL_MTU=1472
 | 
			
		||||
FLANNEL_IPMASQ=true
 | 
			
		||||
`
 | 
			
		||||
	const dualStackFlannelSubnetEnv = `
 | 
			
		||||
FLANNEL_NETWORK=10.1.0.0/16
 | 
			
		||||
FLANNEL_SUBNET=10.1.17.1/24
 | 
			
		||||
FLANNEL_IPV6_NETWORK=fc00::/48
 | 
			
		||||
FLANNEL_IPV6_SUBNET=fc00::1/64
 | 
			
		||||
FLANNEL_MTU=1472
 | 
			
		||||
FLANNEL_IPMASQ=true
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
	const IFNAME = "eth0"
 | 
			
		||||
 | 
			
		||||
	var writeSubnetEnv = func(contents string) string {
 | 
			
		||||
		file, err := ioutil.TempFile("", "subnet.env")
 | 
			
		||||
		Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
		_, err = file.WriteString(contents)
 | 
			
		||||
		Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
		return file.Name()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var makeInputIPAM = func(ipamType, routes, extra string) string {
 | 
			
		||||
		c := "{\n"
 | 
			
		||||
		if len(ipamType) > 0 {
 | 
			
		||||
			c += fmt.Sprintf("    \"type\": \"%s\",", ipamType)
 | 
			
		||||
		}
 | 
			
		||||
		c += fmt.Sprintf(inputIPAMTemplate, routes, extra)
 | 
			
		||||
		c += "\n}"
 | 
			
		||||
 | 
			
		||||
		return c
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var makeInput = func(cniVersion, inputIPAM string, subnetFile string) string {
 | 
			
		||||
		ipamPart := ""
 | 
			
		||||
		if len(inputIPAM) > 0 {
 | 
			
		||||
			ipamPart = ",\n  \"ipam\":\n" + inputIPAM
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return fmt.Sprintf(inputTemplate, cniVersion, subnetFile, dataDir, ipamPart)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var makeHostLocalIPAM = func(dataDir string) string {
 | 
			
		||||
		return fmt.Sprintf(`{
 | 
			
		||||
			"type": "host-local",
 | 
			
		||||
			"dataDir": "%s"
 | 
			
		||||
		}`, dataDir)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BeforeEach(func() {
 | 
			
		||||
		var err error
 | 
			
		||||
		originalNS, err = testutils.NewNS()
 | 
			
		||||
		Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
		targetNS, err = testutils.NewNS()
 | 
			
		||||
		Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
		// flannel subnet.env
 | 
			
		||||
		onlyIpv4SubnetFile = writeSubnetEnv(onlyIpv4FlannelSubnetEnv)
 | 
			
		||||
		onlyIpv6SubnetFile = writeSubnetEnv(onlyIpv6FlannelSubnetEnv)
 | 
			
		||||
		dualStackSubnetFile = writeSubnetEnv(dualStackFlannelSubnetEnv)
 | 
			
		||||
 | 
			
		||||
		// flannel state dir
 | 
			
		||||
		dataDir, err = ioutil.TempDir("", "dataDir")
 | 
			
		||||
		Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	AfterEach(func() {
 | 
			
		||||
		Expect(targetNS.Close()).To(Succeed())
 | 
			
		||||
		Expect(testutils.UnmountNS(targetNS)).To(Succeed())
 | 
			
		||||
		Expect(originalNS.Close()).To(Succeed())
 | 
			
		||||
		Expect(testutils.UnmountNS(originalNS)).To(Succeed())
 | 
			
		||||
 | 
			
		||||
		os.Remove(onlyIpv4SubnetFile)
 | 
			
		||||
		os.Remove(onlyIpv6SubnetFile)
 | 
			
		||||
		os.Remove(dualStackSubnetFile)
 | 
			
		||||
		Expect(os.RemoveAll(dataDir)).To(Succeed())
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Describe("CNI lifecycle", func() {
 | 
			
		||||
		for _, ver := range testutils.AllSpecVersions {
 | 
			
		||||
			// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
 | 
			
		||||
			// See Gingkgo's "Patterns for dynamically generating tests" documentation.
 | 
			
		||||
			ver := ver
 | 
			
		||||
 | 
			
		||||
			Context("when using only ipv4 stack", func() {
 | 
			
		||||
				It(fmt.Sprintf("[%s] uses dataDir for storing network configuration with ipv4 stack", ver), func() {
 | 
			
		||||
					inputIPAM := makeHostLocalIPAM(dataDir)
 | 
			
		||||
					args := &skel.CmdArgs{
 | 
			
		||||
						ContainerID: "some-container-id-ipv4",
 | 
			
		||||
						Netns:       targetNS.Path(),
 | 
			
		||||
						IfName:      IFNAME,
 | 
			
		||||
						StdinData:   []byte(makeInput(ver, inputIPAM, onlyIpv4SubnetFile)),
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					err := originalNS.Do(func(ns.NetNS) error {
 | 
			
		||||
						defer GinkgoRecover()
 | 
			
		||||
 | 
			
		||||
						By("calling ADD with ipv4 stack")
 | 
			
		||||
						GinkgoT().Logf("dataDir is %s", dataDir)
 | 
			
		||||
						GinkgoT().Logf("conf is %s", args.StdinData)
 | 
			
		||||
						resI, _, err := testutils.CmdAddWithArgs(args, func() error {
 | 
			
		||||
							return cmdAdd(args)
 | 
			
		||||
						})
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						By("check that plugin writes the net config to dataDir with ipv4 stack")
 | 
			
		||||
						path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-ipv4")
 | 
			
		||||
						Expect(path).Should(BeAnExistingFile())
 | 
			
		||||
 | 
			
		||||
						netConfBytes, err := ioutil.ReadFile(path)
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
						expected := fmt.Sprintf(`{
 | 
			
		||||
						    "cniVersion": "%s",
 | 
			
		||||
						    "ipMasq": false,
 | 
			
		||||
						    "ipam": {
 | 
			
		||||
							"routes": [
 | 
			
		||||
							    {
 | 
			
		||||
								"dst": "10.1.0.0/16"
 | 
			
		||||
							    }
 | 
			
		||||
							],
 | 
			
		||||
							"ranges": [
 | 
			
		||||
							    [{
 | 
			
		||||
								"subnet": "10.1.17.0/24"
 | 
			
		||||
							    }]
 | 
			
		||||
							],
 | 
			
		||||
							"type": "host-local",
 | 
			
		||||
							"dataDir": "%s"
 | 
			
		||||
						    },
 | 
			
		||||
						    "isGateway": true,
 | 
			
		||||
						    "mtu": 1472,
 | 
			
		||||
						    "name": "cni-flannel",
 | 
			
		||||
						    "type": "bridge"
 | 
			
		||||
						}`, ver, dataDir)
 | 
			
		||||
						Expect(netConfBytes).Should(MatchJSON(expected))
 | 
			
		||||
 | 
			
		||||
						result, err := current.NewResultFromResult(resI)
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
						Expect(result.IPs).To(HaveLen(1))
 | 
			
		||||
 | 
			
		||||
						By("calling DEL with ipv4 stack")
 | 
			
		||||
						err = testutils.CmdDelWithArgs(args, func() error {
 | 
			
		||||
							return cmdDel(args)
 | 
			
		||||
						})
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						By("check that plugin removes net config from state dir with ipv4 stack")
 | 
			
		||||
						Expect(path).ShouldNot(BeAnExistingFile())
 | 
			
		||||
 | 
			
		||||
						By("calling DEL again with ipv4 stack")
 | 
			
		||||
						err = testutils.CmdDelWithArgs(args, func() error {
 | 
			
		||||
							return cmdDel(args)
 | 
			
		||||
						})
 | 
			
		||||
						By("check that plugin does not fail due to missing net config with ipv4 stack")
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						return nil
 | 
			
		||||
					})
 | 
			
		||||
					Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			Context("when using only ipv6 stack", func() {
 | 
			
		||||
				It(fmt.Sprintf("[%s] uses dataDir for storing network configuration with ipv6 stack", ver), func() {
 | 
			
		||||
					inputIPAM := makeHostLocalIPAM(dataDir)
 | 
			
		||||
					args := &skel.CmdArgs{
 | 
			
		||||
						ContainerID: "some-container-id-ipv6",
 | 
			
		||||
						Netns:       targetNS.Path(),
 | 
			
		||||
						IfName:      IFNAME,
 | 
			
		||||
						StdinData:   []byte(makeInput(ver, inputIPAM, onlyIpv6SubnetFile)),
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					err := originalNS.Do(func(ns.NetNS) error {
 | 
			
		||||
						defer GinkgoRecover()
 | 
			
		||||
 | 
			
		||||
						By("calling ADD with ipv6 stack")
 | 
			
		||||
						resI, _, err := testutils.CmdAddWithArgs(args, func() error {
 | 
			
		||||
							return cmdAdd(args)
 | 
			
		||||
						})
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						By("check that plugin writes the net config to dataDir with ipv6 stack")
 | 
			
		||||
						path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-ipv6")
 | 
			
		||||
						Expect(path).Should(BeAnExistingFile())
 | 
			
		||||
 | 
			
		||||
						netConfBytes, err := ioutil.ReadFile(path)
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
						expected := fmt.Sprintf(`{
 | 
			
		||||
						    "cniVersion": "%s",
 | 
			
		||||
						    "ipMasq": false,
 | 
			
		||||
						    "ipam": {
 | 
			
		||||
							"routes": [
 | 
			
		||||
							    {
 | 
			
		||||
								"dst": "fc00::/48"
 | 
			
		||||
							    }
 | 
			
		||||
							],
 | 
			
		||||
							"ranges": [
 | 
			
		||||
							    [{
 | 
			
		||||
								"subnet": "fc00::/64"
 | 
			
		||||
							    }]
 | 
			
		||||
							],
 | 
			
		||||
							"type": "host-local",
 | 
			
		||||
							"dataDir": "%s"
 | 
			
		||||
						    },
 | 
			
		||||
						    "isGateway": true,
 | 
			
		||||
						    "mtu": 1472,
 | 
			
		||||
						    "name": "cni-flannel",
 | 
			
		||||
						    "type": "bridge"
 | 
			
		||||
						}`, ver, dataDir)
 | 
			
		||||
						Expect(netConfBytes).Should(MatchJSON(expected))
 | 
			
		||||
 | 
			
		||||
						result, err := current.NewResultFromResult(resI)
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
						Expect(result.IPs).To(HaveLen(1))
 | 
			
		||||
 | 
			
		||||
						By("calling DEL with ipv6 stack")
 | 
			
		||||
						err = testutils.CmdDelWithArgs(args, func() error {
 | 
			
		||||
							return cmdDel(args)
 | 
			
		||||
						})
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						By("check that plugin removes net config from state dir with ipv6 stack")
 | 
			
		||||
						Expect(path).ShouldNot(BeAnExistingFile())
 | 
			
		||||
 | 
			
		||||
						By("calling DEL again with ipv6 stack")
 | 
			
		||||
						err = testutils.CmdDelWithArgs(args, func() error {
 | 
			
		||||
							return cmdDel(args)
 | 
			
		||||
						})
 | 
			
		||||
						By("check that plugin does not fail due to missing net config with ipv6 stack")
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						return nil
 | 
			
		||||
					})
 | 
			
		||||
					Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			Context("when using dual stack", func() {
 | 
			
		||||
				It(fmt.Sprintf("[%s] uses dataDir for storing network configuration with dual stack", ver), func() {
 | 
			
		||||
					inputIPAM := makeHostLocalIPAM(dataDir)
 | 
			
		||||
					args := &skel.CmdArgs{
 | 
			
		||||
						ContainerID: "some-container-id-dual-stack",
 | 
			
		||||
						Netns:       targetNS.Path(),
 | 
			
		||||
						IfName:      IFNAME,
 | 
			
		||||
						StdinData:   []byte(makeInput(ver, inputIPAM, dualStackSubnetFile)),
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					err := originalNS.Do(func(ns.NetNS) error {
 | 
			
		||||
						defer GinkgoRecover()
 | 
			
		||||
 | 
			
		||||
						By("calling ADD with dual stack")
 | 
			
		||||
						resI, _, err := testutils.CmdAddWithArgs(args, func() error {
 | 
			
		||||
							return cmdAdd(args)
 | 
			
		||||
						})
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						By("check that plugin writes the net config to dataDir with dual stack")
 | 
			
		||||
						path := fmt.Sprintf("%s/%s", dataDir, "some-container-id-dual-stack")
 | 
			
		||||
						Expect(path).Should(BeAnExistingFile())
 | 
			
		||||
 | 
			
		||||
						netConfBytes, err := ioutil.ReadFile(path)
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
						expected := fmt.Sprintf(`{
 | 
			
		||||
						    "cniVersion": "%s",
 | 
			
		||||
						    "ipMasq": false,
 | 
			
		||||
						    "ipam": {
 | 
			
		||||
							"routes": [
 | 
			
		||||
							    {
 | 
			
		||||
								"dst": "10.1.0.0/16"
 | 
			
		||||
							    },
 | 
			
		||||
							    {
 | 
			
		||||
								"dst": "fc00::/48"
 | 
			
		||||
							    }
 | 
			
		||||
							],
 | 
			
		||||
							"ranges": [
 | 
			
		||||
							    [{
 | 
			
		||||
								"subnet": "10.1.17.0/24"
 | 
			
		||||
							    }],
 | 
			
		||||
							    [{
 | 
			
		||||
								"subnet": "fc00::/64"
 | 
			
		||||
							    }]
 | 
			
		||||
							],
 | 
			
		||||
							"type": "host-local",
 | 
			
		||||
							"dataDir": "%s"
 | 
			
		||||
						    },
 | 
			
		||||
						    "isGateway": true,
 | 
			
		||||
						    "mtu": 1472,
 | 
			
		||||
						    "name": "cni-flannel",
 | 
			
		||||
						    "type": "bridge"
 | 
			
		||||
						}`, ver, dataDir)
 | 
			
		||||
						Expect(netConfBytes).Should(MatchJSON(expected))
 | 
			
		||||
 | 
			
		||||
						result, err := current.NewResultFromResult(resI)
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
						Expect(result.IPs).To(HaveLen(2))
 | 
			
		||||
 | 
			
		||||
						By("calling DEL with dual stack")
 | 
			
		||||
						err = testutils.CmdDelWithArgs(args, func() error {
 | 
			
		||||
							return cmdDel(args)
 | 
			
		||||
						})
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						By("check that plugin removes net config from state dir with dual stack")
 | 
			
		||||
						Expect(path).ShouldNot(BeAnExistingFile())
 | 
			
		||||
 | 
			
		||||
						By("calling DEL again with dual stack")
 | 
			
		||||
						err = testutils.CmdDelWithArgs(args, func() error {
 | 
			
		||||
							return cmdDel(args)
 | 
			
		||||
						})
 | 
			
		||||
						By("check that plugin does not fail due to missing net config with dual stack")
 | 
			
		||||
						Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
						return nil
 | 
			
		||||
					})
 | 
			
		||||
					Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Describe("loadFlannelNetConf", func() {
 | 
			
		||||
		var (
 | 
			
		||||
			onlyIpv4Input  string
 | 
			
		||||
			onlyIpv6Input  string
 | 
			
		||||
			dualStackInput string
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		BeforeEach(func() {
 | 
			
		||||
			onlyIpv4Input = makeInput(current.ImplementedSpecVersion, "", onlyIpv4SubnetFile)
 | 
			
		||||
			onlyIpv6Input = makeInput(current.ImplementedSpecVersion, "", onlyIpv6SubnetFile)
 | 
			
		||||
			dualStackInput = makeInput(current.ImplementedSpecVersion, "", dualStackSubnetFile)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when subnetFile and dataDir are specified with ipv4 stack", func() {
 | 
			
		||||
			It("loads flannel network config with ipv4 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				Expect(conf.Name).To(Equal("cni-flannel"))
 | 
			
		||||
				Expect(conf.Type).To(Equal("flannel"))
 | 
			
		||||
				Expect(conf.SubnetFile).To(Equal(onlyIpv4SubnetFile))
 | 
			
		||||
				Expect(conf.DataDir).To(Equal(dataDir))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when subnetFile and dataDir are specified with ipv6 stack", func() {
 | 
			
		||||
			It("loads flannel network config with ipv6 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				Expect(conf.Name).To(Equal("cni-flannel"))
 | 
			
		||||
				Expect(conf.Type).To(Equal("flannel"))
 | 
			
		||||
				Expect(conf.SubnetFile).To(Equal(onlyIpv6SubnetFile))
 | 
			
		||||
				Expect(conf.DataDir).To(Equal(dataDir))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when subnetFile and dataDir are specified with dual stack", func() {
 | 
			
		||||
			It("loads flannel network config with dual stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(dualStackInput))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				Expect(conf.Name).To(Equal("cni-flannel"))
 | 
			
		||||
				Expect(conf.Type).To(Equal("flannel"))
 | 
			
		||||
				Expect(conf.SubnetFile).To(Equal(dualStackSubnetFile))
 | 
			
		||||
				Expect(conf.DataDir).To(Equal(dataDir))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when defaulting subnetFile and dataDir with ipv4 stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				onlyIpv4Input = `{
 | 
			
		||||
"name": "cni-flannel",
 | 
			
		||||
"type": "flannel"
 | 
			
		||||
}`
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			It("loads flannel network config with defaults with ipv4 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				Expect(conf.Name).To(Equal("cni-flannel"))
 | 
			
		||||
				Expect(conf.Type).To(Equal("flannel"))
 | 
			
		||||
				Expect(conf.SubnetFile).To(Equal(defaultSubnetFile))
 | 
			
		||||
				Expect(conf.DataDir).To(Equal(defaultDataDir))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when defaulting subnetFile and dataDir with ipv6 stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				onlyIpv6Input = `{
 | 
			
		||||
"name": "cni-flannel",
 | 
			
		||||
"type": "flannel"
 | 
			
		||||
}`
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			It("loads flannel network config with defaults with ipv6 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				Expect(conf.Name).To(Equal("cni-flannel"))
 | 
			
		||||
				Expect(conf.Type).To(Equal("flannel"))
 | 
			
		||||
				Expect(conf.SubnetFile).To(Equal(defaultSubnetFile))
 | 
			
		||||
				Expect(conf.DataDir).To(Equal(defaultDataDir))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when defaulting subnetFile and dataDir with dual stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				dualStackInput = `{
 | 
			
		||||
"name": "cni-flannel",
 | 
			
		||||
"type": "flannel"
 | 
			
		||||
}`
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			It("loads flannel network config with defaults with dual stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(dualStackInput))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				Expect(conf.Name).To(Equal("cni-flannel"))
 | 
			
		||||
				Expect(conf.Type).To(Equal("flannel"))
 | 
			
		||||
				Expect(conf.SubnetFile).To(Equal(defaultSubnetFile))
 | 
			
		||||
				Expect(conf.DataDir).To(Equal(defaultDataDir))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Describe("loadFlannelSubnetEnv", func() {
 | 
			
		||||
			Context("when flannel subnet env is valid with ipv4 stack", func() {
 | 
			
		||||
				It("loads flannel subnet config with ipv4 stack", func() {
 | 
			
		||||
					conf, err := loadFlannelSubnetEnv(onlyIpv4SubnetFile)
 | 
			
		||||
					Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
					Expect(conf.nw.String()).To(Equal("10.1.0.0/16"))
 | 
			
		||||
					Expect(conf.sn.String()).To(Equal("10.1.17.0/24"))
 | 
			
		||||
					var mtu uint = 1472
 | 
			
		||||
					Expect(*conf.mtu).To(Equal(mtu))
 | 
			
		||||
					Expect(*conf.ipmasq).To(BeTrue())
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			Context("when flannel subnet env is valid with ipv6 stack", func() {
 | 
			
		||||
				It("loads flannel subnet config with ipv6 stack", func() {
 | 
			
		||||
					conf, err := loadFlannelSubnetEnv(onlyIpv6SubnetFile)
 | 
			
		||||
					Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
					Expect(conf.ip6Nw.String()).To(Equal("fc00::/48"))
 | 
			
		||||
					Expect(conf.ip6Sn.String()).To(Equal("fc00::/64"))
 | 
			
		||||
					var mtu uint = 1472
 | 
			
		||||
					Expect(*conf.mtu).To(Equal(mtu))
 | 
			
		||||
					Expect(*conf.ipmasq).To(BeTrue())
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			Context("when flannel subnet env is valid with dual stack", func() {
 | 
			
		||||
				It("loads flannel subnet config with dual stack", func() {
 | 
			
		||||
					conf, err := loadFlannelSubnetEnv(dualStackSubnetFile)
 | 
			
		||||
					Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
					Expect(conf.nw.String()).To(Equal("10.1.0.0/16"))
 | 
			
		||||
					Expect(conf.sn.String()).To(Equal("10.1.17.0/24"))
 | 
			
		||||
					Expect(conf.ip6Nw.String()).To(Equal("fc00::/48"))
 | 
			
		||||
					Expect(conf.ip6Sn.String()).To(Equal("fc00::/64"))
 | 
			
		||||
					var mtu uint = 1472
 | 
			
		||||
					Expect(*conf.mtu).To(Equal(mtu))
 | 
			
		||||
					Expect(*conf.ipmasq).To(BeTrue())
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			Context("when flannel subnet env is invalid with ipv4 stack", func() {
 | 
			
		||||
				BeforeEach(func() {
 | 
			
		||||
					onlyIpv4SubnetFile = writeSubnetEnv("foo=bar")
 | 
			
		||||
				})
 | 
			
		||||
				It("returns an error", func() {
 | 
			
		||||
					_, err := loadFlannelSubnetEnv(onlyIpv4SubnetFile)
 | 
			
		||||
					Expect(err).To(MatchError(ContainSubstring("missing FLANNEL_NETWORK, FLANNEL_IPV6_NETWORK, FLANNEL_SUBNET, FLANNEL_IPV6_SUBNET, FLANNEL_MTU, FLANNEL_IPMASQ")))
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			Context("when flannel subnet env is invalid with ipv6 stack", func() {
 | 
			
		||||
				BeforeEach(func() {
 | 
			
		||||
					onlyIpv6SubnetFile = writeSubnetEnv("foo=bar")
 | 
			
		||||
				})
 | 
			
		||||
				It("returns an error", func() {
 | 
			
		||||
					_, err := loadFlannelSubnetEnv(onlyIpv6SubnetFile)
 | 
			
		||||
					Expect(err).To(MatchError(ContainSubstring("missing FLANNEL_NETWORK, FLANNEL_IPV6_NETWORK, FLANNEL_SUBNET, FLANNEL_IPV6_SUBNET, FLANNEL_MTU, FLANNEL_IPMASQ")))
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			Context("when flannel subnet env is invalid with dual stack", func() {
 | 
			
		||||
				BeforeEach(func() {
 | 
			
		||||
					dualStackSubnetFile = writeSubnetEnv("foo=bar")
 | 
			
		||||
				})
 | 
			
		||||
				It("returns an error", func() {
 | 
			
		||||
					_, err := loadFlannelSubnetEnv(dualStackSubnetFile)
 | 
			
		||||
					Expect(err).To(MatchError(ContainSubstring("missing FLANNEL_NETWORK, FLANNEL_IPV6_NETWORK, FLANNEL_SUBNET, FLANNEL_IPV6_SUBNET, FLANNEL_MTU, FLANNEL_IPMASQ")))
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Describe("getDelegateIPAM", func() {
 | 
			
		||||
		Context("when input IPAM is provided with ipv4 stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
 | 
			
		||||
				onlyIpv4Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv4SubnetFile)
 | 
			
		||||
			})
 | 
			
		||||
			It("configures Delegate IPAM accordingly with ipv4 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				fenv, err := loadFlannelSubnetEnv(onlyIpv4SubnetFile)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				ipam, err := getDelegateIPAM(conf, fenv)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				podsRoute := "{ \"dst\": \"10.1.0.0/16\" }\n"
 | 
			
		||||
				subnet := "\"ranges\": [[{\"subnet\": \"10.1.17.0/24\"}]]"
 | 
			
		||||
				expected := makeInputIPAM(inputIPAMType, inputIPAMRoutes+",\n"+podsRoute, ",\n"+subnet)
 | 
			
		||||
				buf, _ := json.Marshal(ipam)
 | 
			
		||||
				Expect(buf).Should(MatchJSON(expected))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when input IPAM is provided with ipv6 stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
 | 
			
		||||
				onlyIpv6Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv6SubnetFile)
 | 
			
		||||
			})
 | 
			
		||||
			It("configures Delegate IPAM accordingly with ipv6 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				fenv, err := loadFlannelSubnetEnv(onlyIpv6SubnetFile)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				ipam, err := getDelegateIPAM(conf, fenv)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				podsRoute := "{ \"dst\": \"fc00::/48\" }\n"
 | 
			
		||||
				subnet := "\"ranges\": [[{ \"subnet\": \"fc00::/64\" }]]"
 | 
			
		||||
				expected := makeInputIPAM(inputIPAMType, inputIPAMRoutes+",\n"+podsRoute, ",\n"+subnet)
 | 
			
		||||
				buf, _ := json.Marshal(ipam)
 | 
			
		||||
				Expect(buf).Should(MatchJSON(expected))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when input IPAM is provided with dual stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				inputIPAM := makeInputIPAM(inputIPAMType, inputIPAMRoutes, "")
 | 
			
		||||
				dualStackInput = makeInput(current.ImplementedSpecVersion, inputIPAM, dualStackSubnetFile)
 | 
			
		||||
			})
 | 
			
		||||
			It("configures Delegate IPAM accordingly with dual stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(dualStackInput))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				fenv, err := loadFlannelSubnetEnv(dualStackSubnetFile)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				ipam, err := getDelegateIPAM(conf, fenv)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				podsRoute := "{ \"dst\": \"10.1.0.0/16\" }" + ",\n" + "{ \"dst\": \"fc00::/48\" }\n"
 | 
			
		||||
				subnet := "\"ranges\": [[{ \"subnet\": \"10.1.17.0/24\" }],\n[{ \"subnet\": \"fc00::/64\" }]]"
 | 
			
		||||
				expected := makeInputIPAM(inputIPAMType, inputIPAMRoutes+",\n"+podsRoute, ",\n"+subnet)
 | 
			
		||||
				buf, _ := json.Marshal(ipam)
 | 
			
		||||
				Expect(buf).Should(MatchJSON(expected))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when input IPAM is provided without 'type' with ipv4 stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
 | 
			
		||||
				onlyIpv4Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv4SubnetFile)
 | 
			
		||||
			})
 | 
			
		||||
			It("configures Delegate IPAM with 'host-local' ipam with ipv4 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv4Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				fenv, err := loadFlannelSubnetEnv(onlyIpv4SubnetFile)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				ipam, err := getDelegateIPAM(conf, fenv)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				podsRoute := "{ \"dst\": \"10.1.0.0/16\" }\n"
 | 
			
		||||
				subnet := "\"ranges\": [[{\"subnet\": \"10.1.17.0/24\"}]]"
 | 
			
		||||
				expected := makeInputIPAM("host-local", inputIPAMRoutes+",\n"+podsRoute, ",\n"+subnet)
 | 
			
		||||
				buf, _ := json.Marshal(ipam)
 | 
			
		||||
				Expect(buf).Should(MatchJSON(expected))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when input IPAM is provided without 'type' with ipv6 stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
 | 
			
		||||
				onlyIpv6Input = makeInput(current.ImplementedSpecVersion, inputIPAM, onlyIpv6SubnetFile)
 | 
			
		||||
			})
 | 
			
		||||
			It("configures Delegate IPAM with 'host-local' ipam with ipv6 stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(onlyIpv6Input))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				fenv, err := loadFlannelSubnetEnv(onlyIpv6SubnetFile)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				ipam, err := getDelegateIPAM(conf, fenv)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				podsRoute := "{ \"dst\": \"fc00::/48\" }\n"
 | 
			
		||||
				subnet := "\"ranges\": [[{ \"subnet\": \"fc00::/64\" }]]"
 | 
			
		||||
				expected := makeInputIPAM("host-local", inputIPAMRoutes+",\n"+podsRoute, ",\n"+subnet)
 | 
			
		||||
				buf, _ := json.Marshal(ipam)
 | 
			
		||||
				Expect(buf).Should(MatchJSON(expected))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		Context("when input IPAM is provided without 'type' with dual stack", func() {
 | 
			
		||||
			BeforeEach(func() {
 | 
			
		||||
				inputIPAM := makeInputIPAM("", inputIPAMRoutes, "")
 | 
			
		||||
				dualStackInput = makeInput(current.ImplementedSpecVersion, inputIPAM, dualStackSubnetFile)
 | 
			
		||||
			})
 | 
			
		||||
			It("configures Delegate IPAM with 'host-local' ipam with dual stack", func() {
 | 
			
		||||
				conf, err := loadFlannelNetConf([]byte(dualStackInput))
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				fenv, err := loadFlannelSubnetEnv(dualStackSubnetFile)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
				ipam, err := getDelegateIPAM(conf, fenv)
 | 
			
		||||
				Expect(err).ShouldNot(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
				podsRoute := "{ \"dst\": \"10.1.0.0/16\" }" + ",\n" + "{ \"dst\": \"fc00::/48\" }\n"
 | 
			
		||||
				subnet := "\"ranges\": [[{ \"subnet\": \"10.1.17.0/24\" }],\n[{ \"subnet\": \"fc00::/64\" }]]"
 | 
			
		||||
				expected := makeInputIPAM("host-local", inputIPAMRoutes+",\n"+podsRoute, ",\n"+subnet)
 | 
			
		||||
				buf, _ := json.Marshal(ipam)
 | 
			
		||||
				Expect(buf).Should(MatchJSON(expected))
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
})
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
// Copyright 2015 CNI authors
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	. "github.com/onsi/ginkgo"
 | 
			
		||||
	. "github.com/onsi/gomega"
 | 
			
		||||
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestFlannel(t *testing.T) {
 | 
			
		||||
	RegisterFailHandler(Fail)
 | 
			
		||||
	RunSpecs(t, "plugins/meta/flannel")
 | 
			
		||||
}
 | 
			
		||||
@@ -1,80 +0,0 @@
 | 
			
		||||
// Copyright 2018 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.
 | 
			
		||||
 | 
			
		||||
// This is a "meta-plugin". It reads in its own netconf, combines it with
 | 
			
		||||
// the data from flannel generated subnet file and then invokes a plugin
 | 
			
		||||
// like bridge or ipvlan to do the real work.
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/invoke"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/skel"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/types"
 | 
			
		||||
	"github.com/containernetworking/cni/pkg/types/020"
 | 
			
		||||
	"github.com/containernetworking/plugins/pkg/hns"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func doCmdAdd(args *skel.CmdArgs, cniVersion string, n *NetConf, fenv *subnetEnv) error {
 | 
			
		||||
	n.Delegate["name"] = n.Name
 | 
			
		||||
 | 
			
		||||
	if !hasKey(n.Delegate, "type") {
 | 
			
		||||
		n.Delegate["type"] = "win-bridge"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if flannel needs ipmasq - get the plugin to configure it
 | 
			
		||||
	// (this is the opposite of how linux works - on linux the flannel daemon configure ipmasq)
 | 
			
		||||
	n.Delegate["ipMasq"] = *fenv.ipmasq
 | 
			
		||||
	n.Delegate["ipMasqNetwork"] = fenv.nw.String()
 | 
			
		||||
 | 
			
		||||
	n.Delegate["cniVersion"] = types020.ImplementedSpecVersion
 | 
			
		||||
	if len(n.CNIVersion) != 0 {
 | 
			
		||||
		n.Delegate["cniVersion"] = n.CNIVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n.Delegate["ipam"] = map[string]interface{}{
 | 
			
		||||
		"type":   "host-local",
 | 
			
		||||
		"subnet": fenv.sn.String(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sandboxID := hns.GetSandboxContainerID(args.ContainerID, args.Netns)
 | 
			
		||||
	return delegateAdd(sandboxID, n.DataDir, cniVersion, n.Delegate)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func doCmdDel(args *skel.CmdArgs, n *NetConf) (err error) {
 | 
			
		||||
	cleanup, netConfBytes, err := consumeScratchNetConf(hns.GetSandboxContainerID(args.ContainerID, args.Netns), n.DataDir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			// Per spec should ignore error if resources are missing / already removed
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// cleanup will work when no error happens
 | 
			
		||||
	defer func() {
 | 
			
		||||
		cleanup(err)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	nc := &types.NetConf{}
 | 
			
		||||
	if err = json.Unmarshal(netConfBytes, nc); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to parse netconf: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return invoke.DelegateDel(context.TODO(), nc.Type, netConfBytes, nil)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
plugins/ipam/host-local
 | 
			
		||||
plugins/main/windows/win-bridge
 | 
			
		||||
plugins/main/windows/win-overlay
 | 
			
		||||
plugins/meta/flannel
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user