Support multiple IP addresses in CNI_ARGS

This commit is contained in:
Tomofumi Hayashi 2018-09-06 15:32:50 +09:00
parent 321467bf1b
commit 61c136126f
3 changed files with 88 additions and 16 deletions

View File

@ -48,7 +48,7 @@ static IPAM is very simple IPAM plugin that assigns IPv4 and IPv6 addresses stat
The following [CNI_ARGS](https://github.com/containernetworking/cni/blob/master/SPEC.md#parameters) are supported: The following [CNI_ARGS](https://github.com/containernetworking/cni/blob/master/SPEC.md#parameters) are supported:
* `IP`: request a specific CIDR notation IP address * `IP`: request a specific CIDR notation IP addresses, comma separated
* `GATEWAY`: request a specific gateway address * `GATEWAY`: request a specific gateway address
(example: CNI_ARGS="IP=10.10.0.1/24;GATEWAY=10.10.0.254") (example: CNI_ARGS="IP=10.10.0.1/24;GATEWAY=10.10.0.254")

View File

@ -18,6 +18,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net" "net"
"strings"
"github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
@ -46,7 +47,7 @@ type IPAMConfig struct {
type IPAMEnvArgs struct { type IPAMEnvArgs struct {
types.CommonArgs types.CommonArgs
IP types.UnmarshallableString `json:"ip,omitempty"` IP types.UnmarshallableString `json:"ip,omitempty"`
GATEWAY net.IP `json:"gateway,omitempty"` GATEWAY types.UnmarshallableString `json:"gateway,omitempty"`
} }
type Address struct { type Address struct {
@ -124,23 +125,39 @@ func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
} }
if e.IP != "" { if e.IP != "" {
ip, subnet, err := net.ParseCIDR(string(e.IP)) for _, item := range strings.Split(string(e.IP), ",") {
if err != nil { ipstr := strings.TrimSpace(item)
return nil, "", fmt.Errorf("invalid CIDR %s: %s", e.IP, err)
}
addr := Address{Address: net.IPNet{IP: ip, Mask: subnet.Mask}} ip, subnet, err := net.ParseCIDR(ipstr)
if e.GATEWAY != nil { if err != nil {
addr.Gateway = e.GATEWAY return nil, "", fmt.Errorf("invalid CIDR %s: %s", e.IP, err)
}
addr := Address{Address: net.IPNet{IP: ip, Mask: subnet.Mask}}
if addr.Address.IP.To4() != nil {
addr.Version = "4"
numV4++
} else {
addr.Version = "6"
numV6++
}
n.IPAM.Addresses = append(n.IPAM.Addresses, addr)
} }
if addr.Address.IP.To4() != nil { }
addr.Version = "4"
numV4++ if e.GATEWAY != "" {
} else { for _, item := range strings.Split(string(e.GATEWAY), ",") {
addr.Version = "6" gwip := net.ParseIP(strings.TrimSpace(item))
numV6++ if gwip == nil {
return nil, "", fmt.Errorf("invalid gateway address: %s", item)
}
for i := range n.IPAM.Addresses {
if n.IPAM.Addresses[i].Address.Contains(gwip) {
n.IPAM.Addresses[i].Gateway = gwip
}
}
} }
n.IPAM.Addresses = append(n.IPAM.Addresses, addr)
} }
} }

View File

@ -210,6 +210,61 @@ var _ = Describe("static Operations", func() {
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
It("allocates and releases multiple addresses with ADD/DEL, with ENV variables", func() {
const ifname string = "eth0"
const nspath string = "/some/where"
conf := `{
"cniVersion": "0.3.1",
"name": "mynet",
"type": "ipvlan",
"master": "foo0",
"ipam": {
"type": "static"
}
}`
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: nspath,
IfName: ifname,
StdinData: []byte(conf),
Args: "IP=10.10.0.1/24,11.11.0.1/24;GATEWAY=10.10.0.254",
}
// Allocate the IP
r, raw, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0))
result, err := current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
// Gomega is cranky about slices with different caps
Expect(*result.IPs[0]).To(Equal(
current.IPConfig{
Version: "4",
Address: mustCIDR("10.10.0.1/24"),
Gateway: net.ParseIP("10.10.0.254"),
}))
Expect(*result.IPs[1]).To(Equal(
current.IPConfig{
Version: "4",
Address: mustCIDR("11.11.0.1/24"),
Gateway: nil,
}))
Expect(len(result.IPs)).To(Equal(2))
// Release the IP
err = testutils.CmdDelWithArgs(args, func() error {
return cmdDel(args)
})
Expect(err).NotTo(HaveOccurred())
})
}) })
func mustCIDR(s string) net.IPNet { func mustCIDR(s string) net.IPNet {