From f534133ec76eefbedccfccd1fcf718bdbe09f752 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 28 Jan 2021 14:53:45 -0600 Subject: [PATCH] static: increase test coverage to 1.0.0 and older spec versions Signed-off-by: Dan Williams --- plugins/ipam/static/static_test.go | 844 +++++++++++++++-------------- 1 file changed, 435 insertions(+), 409 deletions(-) diff --git a/plugins/ipam/static/static_test.go b/plugins/ipam/static/static_test.go index 13df8f63..f75d6342 100644 --- a/plugins/ipam/static/static_test.go +++ b/plugins/ipam/static/static_test.go @@ -15,12 +15,13 @@ package main import ( + "fmt" "net" "strings" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" - current "github.com/containernetworking/cni/pkg/types/100" + "github.com/containernetworking/cni/pkg/types/100" "github.com/containernetworking/plugins/pkg/testutils" . "github.com/onsi/ginkgo" @@ -28,18 +29,101 @@ import ( ) var _ = Describe("static Operations", func() { - It("allocates and releases addresses with ADD/DEL", func() { - const ifname string = "eth0" - const nspath string = "/some/where" + 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 - conf := `{ - "cniVersion": "0.3.1", - "name": "mynet", - "type": "ipvlan", - "master": "foo0", - "ipam": { - "type": "static", - "addresses": [ { + It(fmt.Sprintf("[%s] allocates and releases addresses with ADD/DEL", ver), func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "ipam": { + "type": "static", + "addresses": [ { + "address": "10.10.0.1/24", + "gateway": "10.10.0.254" + }, + { + "address": "3ffe:ffff:0:01ff::1/64", + "gateway": "3ffe:ffff:0::1" + }], + "routes": [ + { "dst": "0.0.0.0/0" }, + { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }, + { "dst": "3ffe:ffff:0:01ff::1/64" }], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } + } + }`, ver) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), + } + + // Allocate the IP + r, raw, err := testutils.CmdAddWithArgs(args, func() error { + return cmdAdd(args) + }) + Expect(err).NotTo(HaveOccurred()) + if testutils.SpecVersionHasIPVersion(ver) { + Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) + } + + result, err := types100.GetResult(r) + Expect(err).NotTo(HaveOccurred()) + + // Gomega is cranky about slices with different caps + Expect(*result.IPs[0]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("10.10.0.1/24"), + Gateway: net.ParseIP("10.10.0.254"), + })) + + Expect(*result.IPs[1]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), + Gateway: net.ParseIP("3ffe:ffff:0::1"), + }, + )) + Expect(len(result.IPs)).To(Equal(2)) + + Expect(result.Routes).To(Equal([]*types.Route{ + {Dst: mustCIDR("0.0.0.0/0")}, + {Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")}, + {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64")}, + })) + + // Release the IP + err = testutils.CmdDelWithArgs(args, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It(fmt.Sprintf("[%s] doesn't error when passed an unknown ID on DEL", ver), func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "ipam": { + "type": "static", + "addresses": [ { "address": "10.10.0.1/24", "gateway": "10.10.0.254" }, @@ -47,428 +131,370 @@ var _ = Describe("static Operations", func() { "address": "3ffe:ffff:0:01ff::1/64", "gateway": "3ffe:ffff:0::1" }], - "routes": [ + "routes": [ { "dst": "0.0.0.0/0" }, { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }, { "dst": "3ffe:ffff:0:01ff::1/64" }], - "dns": { - "nameservers" : ["8.8.8.8"], - "domain": "example.com", - "search": [ "example.com" ] + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } } + }`, ver) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), } - }` - args := &skel.CmdArgs{ - ContainerID: "dummy", - Netns: nspath, - IfName: ifname, - StdinData: []byte(conf), - } - - // Allocate the IP - r, raw, err := testutils.CmdAddWithArgs(args, func() error { - return cmdAdd(args) + // Release the IP + err := testutils.CmdDelWithArgs(args, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) }) - Expect(err).NotTo(HaveOccurred()) - Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) - result, err := current.GetResult(r) - Expect(err).NotTo(HaveOccurred()) + It(fmt.Sprintf("[%s] allocates and releases addresses with ADD/DEL, with ENV variables", ver), func() { + const ifname string = "eth0" + const nspath string = "/some/where" - // Gomega is cranky about slices with different caps - Expect(*result.IPs[0]).To(Equal( - current.IPConfig{ - Address: mustCIDR("10.10.0.1/24"), - Gateway: net.ParseIP("10.10.0.254"), + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "ipam": { + "type": "static", + "routes": [ + { "dst": "0.0.0.0/0" }, + { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } + } + }`, ver) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), + Args: "IP=10.10.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()) + if testutils.SpecVersionHasIPVersion(ver) { + Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) + } + + result, err := types100.GetResult(r) + Expect(err).NotTo(HaveOccurred()) + + // Gomega is cranky about slices with different caps + Expect(*result.IPs[0]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("10.10.0.1/24"), + Gateway: net.ParseIP("10.10.0.254"), + })) + + Expect(len(result.IPs)).To(Equal(1)) + + Expect(result.Routes).To(Equal([]*types.Route{ + {Dst: mustCIDR("0.0.0.0/0")}, + {Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")}, })) - Expect(*result.IPs[1]).To(Equal( - current.IPConfig{ - Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), - Gateway: net.ParseIP("3ffe:ffff:0::1"), - }, - )) - Expect(len(result.IPs)).To(Equal(2)) - - Expect(result.Routes).To(Equal([]*types.Route{ - {Dst: mustCIDR("0.0.0.0/0")}, - {Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")}, - {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64")}, - })) - - // Release the IP - err = testutils.CmdDelWithArgs(args, func() error { - return cmdDel(args) + // Release the IP + err = testutils.CmdDelWithArgs(args, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) }) - Expect(err).NotTo(HaveOccurred()) - }) - It("doesn't error when passed an unknown ID on DEL", func() { - const ifname string = "eth0" - const nspath string = "/some/where" + It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, with ENV variables", ver), func() { + const ifname string = "eth0" + const nspath string = "/some/where" - conf := `{ - "cniVersion": "0.3.0", - "name": "mynet", - "type": "ipvlan", - "master": "foo0", - "ipam": { - "type": "static", - "addresses": [ { - "address": "10.10.0.1/24", - "gateway": "10.10.0.254" + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "ipam": { + "type": "static" + } + }`, ver) + + 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) + }) + if !testutils.SpecVersionHasMultipleIPs(ver) { + errStr := fmt.Sprintf("CNI version %s does not support more than 1 address per family", ver) + Expect(err).To(MatchError(errStr)) + return + } + + Expect(err).NotTo(HaveOccurred()) + if testutils.SpecVersionHasIPVersion(ver) { + Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) + } + + result, err := types100.GetResult(r) + Expect(err).NotTo(HaveOccurred()) + + // Gomega is cranky about slices with different caps + Expect(*result.IPs[0]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("10.10.0.1/24"), + Gateway: net.ParseIP("10.10.0.254"), + })) + Expect(*result.IPs[1]).To(Equal( + types100.IPConfig{ + 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()) + }) + + It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig", ver), func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "capabilities": {"ips": true}, + "ipam": { + "type": "static", + "routes": [ + { "dst": "0.0.0.0/0", "gw": "10.10.0.254" }, + { "dst": "3ffe:ffff:0:01ff::1/64", + "gw": "3ffe:ffff:0::1" } ], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } }, - { - "address": "3ffe:ffff:0:01ff::1/64", - "gateway": "3ffe:ffff:0::1" - }], - "routes": [ - { "dst": "0.0.0.0/0" }, - { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }, - { "dst": "3ffe:ffff:0:01ff::1/64" }], - "dns": { - "nameservers" : ["8.8.8.8"], - "domain": "example.com", - "search": [ "example.com" ] - }}}` - - args := &skel.CmdArgs{ - ContainerID: "dummy", - Netns: nspath, - IfName: ifname, - StdinData: []byte(conf), - } - - // Release the IP - err := testutils.CmdDelWithArgs(args, func() error { - return cmdDel(args) - }) - Expect(err).NotTo(HaveOccurred()) - }) - - It("allocates and releases 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", - "routes": [ - { "dst": "0.0.0.0/0" }, - { "dst": "192.168.0.0/16", "gw": "10.10.5.1" }], - "dns": { - "nameservers" : ["8.8.8.8"], - "domain": "example.com", - "search": [ "example.com" ] - } - } - }` - - args := &skel.CmdArgs{ - ContainerID: "dummy", - Netns: nspath, - IfName: ifname, - StdinData: []byte(conf), - Args: "IP=10.10.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{ - Address: mustCIDR("10.10.0.1/24"), - Gateway: net.ParseIP("10.10.0.254"), - })) - - Expect(len(result.IPs)).To(Equal(1)) - - Expect(result.Routes).To(Equal([]*types.Route{ - {Dst: mustCIDR("0.0.0.0/0")}, - {Dst: mustCIDR("192.168.0.0/16"), GW: net.ParseIP("10.10.5.1")}, - })) - - // Release the IP - err = testutils.CmdDelWithArgs(args, func() error { - return cmdDel(args) - }) - 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{ - Address: mustCIDR("10.10.0.1/24"), - Gateway: net.ParseIP("10.10.0.254"), - })) - Expect(*result.IPs[1]).To(Equal( - current.IPConfig{ - 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()) - }) - - It("allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig", func() { - const ifname string = "eth0" - const nspath string = "/some/where" - - conf := `{ - "cniVersion": "0.3.1", - "name": "mynet", - "type": "ipvlan", - "master": "foo0", - "capabilities": {"ips": true}, - "ipam": { - "type": "static", - "routes": [ - { "dst": "0.0.0.0/0", "gw": "10.10.0.254" }, - { "dst": "3ffe:ffff:0:01ff::1/64", - "gw": "3ffe:ffff:0::1" } ], - "dns": { - "nameservers" : ["8.8.8.8"], - "domain": "example.com", - "search": [ "example.com" ] - } - }, - "RuntimeConfig": { - "ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"] - } - }` - - args := &skel.CmdArgs{ - ContainerID: "dummy", - Netns: nspath, - IfName: ifname, - StdinData: []byte(conf), - } - - // 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{ - Address: mustCIDR("10.10.0.1/24"), - })) - Expect(*result.IPs[1]).To(Equal( - current.IPConfig{ - Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), - }, - )) - Expect(len(result.IPs)).To(Equal(2)) - Expect(result.Routes).To(Equal([]*types.Route{ - {Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, - {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")}, - })) - - // Release the IP - err = testutils.CmdDelWithArgs(args, func() error { - return cmdDel(args) - }) - Expect(err).NotTo(HaveOccurred()) - }) - - It("allocates and releases multiple addresses with ADD/DEL, from args", func() { - const ifname string = "eth0" - const nspath string = "/some/where" - - conf := `{ - "cniVersion": "0.3.1", - "name": "mynet", - "type": "ipvlan", - "master": "foo0", - "ipam": { - "type": "static", - "routes": [ - { "dst": "0.0.0.0/0", "gw": "10.10.0.254" }, - { "dst": "3ffe:ffff:0:01ff::1/64", - "gw": "3ffe:ffff:0::1" } ], - "dns": { - "nameservers" : ["8.8.8.8"], - "domain": "example.com", - "search": [ "example.com" ] - } - }, - "args": { - "cni": { + "RuntimeConfig": { "ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"] - } + } + }`, ver) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), } - }` - args := &skel.CmdArgs{ - ContainerID: "dummy", - Netns: nspath, - IfName: ifname, - StdinData: []byte(conf), - } - - // 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{ - Address: mustCIDR("10.10.0.1/24"), - })) - Expect(*result.IPs[1]).To(Equal( - current.IPConfig{ - Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), - }, - )) - Expect(len(result.IPs)).To(Equal(2)) - Expect(result.Routes).To(Equal([]*types.Route{ - {Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, - {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")}, - })) - - // Release the IP - err = testutils.CmdDelWithArgs(args, func() error { - return cmdDel(args) - }) - Expect(err).NotTo(HaveOccurred()) - }) - - It("allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig/ARGS/CNI_ARGS", func() { - const ifname string = "eth0" - const nspath string = "/some/where" - - conf := `{ - "cniVersion": "0.3.1", - "name": "mynet", - "type": "ipvlan", - "master": "foo0", - "capabilities": {"ips": true}, - "ipam": { - "type": "static", - "routes": [ - { "dst": "0.0.0.0/0", "gw": "10.10.0.254" }, - { "dst": "3ffe:ffff:0:01ff::1/64", - "gw": "3ffe:ffff:0::1" } ], - "dns": { - "nameservers" : ["8.8.8.8"], - "domain": "example.com", - "search": [ "example.com" ] - } - }, - "RuntimeConfig": { - "ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"] - }, - "args": { - "cni": { - "ips" : ["10.10.0.2/24", "3ffe:ffff:0:01ff::2/64"] - } + // Allocate the IP + r, raw, err := testutils.CmdAddWithArgs(args, func() error { + return cmdAdd(args) + }) + Expect(err).NotTo(HaveOccurred()) + if testutils.SpecVersionHasIPVersion(ver) { + Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) } - }` - args := &skel.CmdArgs{ - ContainerID: "dummy", - Netns: nspath, - IfName: ifname, - StdinData: []byte(conf), - Args: "IP=10.10.0.3/24,11.11.0.3/24;GATEWAY=10.10.0.254", - } + result, err := types100.GetResult(r) + Expect(err).NotTo(HaveOccurred()) - // 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()) - - // only addresses in runtimeConfig configured because of its priorities - Expect(*result.IPs[0]).To(Equal( - current.IPConfig{ - Address: mustCIDR("10.10.0.1/24"), + // Gomega is cranky about slices with different caps + Expect(*result.IPs[0]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("10.10.0.1/24"), + })) + Expect(*result.IPs[1]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), + }, + )) + Expect(len(result.IPs)).To(Equal(2)) + Expect(result.Routes).To(Equal([]*types.Route{ + {Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, + {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")}, })) - Expect(*result.IPs[1]).To(Equal( - current.IPConfig{ - Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), - }, - )) - Expect(len(result.IPs)).To(Equal(2)) - Expect(result.Routes).To(Equal([]*types.Route{ - {Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, - {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")}, - })) - // Release the IP - err = testutils.CmdDelWithArgs(args, func() error { - return cmdDel(args) + // Release the IP + err = testutils.CmdDelWithArgs(args, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) }) - Expect(err).NotTo(HaveOccurred()) - }) + It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, from args", ver), func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "ipam": { + "type": "static", + "routes": [ + { "dst": "0.0.0.0/0", "gw": "10.10.0.254" }, + { "dst": "3ffe:ffff:0:01ff::1/64", + "gw": "3ffe:ffff:0::1" } ], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } + }, + "args": { + "cni": { + "ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"] + } + } + }`, ver) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), + } + + // Allocate the IP + r, raw, err := testutils.CmdAddWithArgs(args, func() error { + return cmdAdd(args) + }) + Expect(err).NotTo(HaveOccurred()) + if testutils.SpecVersionHasIPVersion(ver) { + Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) + } + + result, err := types100.GetResult(r) + Expect(err).NotTo(HaveOccurred()) + + // Gomega is cranky about slices with different caps + Expect(*result.IPs[0]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("10.10.0.1/24"), + })) + Expect(*result.IPs[1]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), + }, + )) + Expect(len(result.IPs)).To(Equal(2)) + Expect(result.Routes).To(Equal([]*types.Route{ + {Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, + {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")}, + })) + + // Release the IP + err = testutils.CmdDelWithArgs(args, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It(fmt.Sprintf("[%s] allocates and releases multiple addresses with ADD/DEL, from RuntimeConfig/ARGS/CNI_ARGS", ver), func() { + const ifname string = "eth0" + const nspath string = "/some/where" + + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ipvlan", + "master": "foo0", + "capabilities": {"ips": true}, + "ipam": { + "type": "static", + "routes": [ + { "dst": "0.0.0.0/0", "gw": "10.10.0.254" }, + { "dst": "3ffe:ffff:0:01ff::1/64", + "gw": "3ffe:ffff:0::1" } ], + "dns": { + "nameservers" : ["8.8.8.8"], + "domain": "example.com", + "search": [ "example.com" ] + } + }, + "RuntimeConfig": { + "ips" : ["10.10.0.1/24", "3ffe:ffff:0:01ff::1/64"] + }, + "args": { + "cni": { + "ips" : ["10.10.0.2/24", "3ffe:ffff:0:01ff::2/64"] + } + } + }`, ver) + + args := &skel.CmdArgs{ + ContainerID: "dummy", + Netns: nspath, + IfName: ifname, + StdinData: []byte(conf), + Args: "IP=10.10.0.3/24,11.11.0.3/24;GATEWAY=10.10.0.254", + } + + // Allocate the IP + r, raw, err := testutils.CmdAddWithArgs(args, func() error { + return cmdAdd(args) + }) + Expect(err).NotTo(HaveOccurred()) + if testutils.SpecVersionHasIPVersion(ver) { + Expect(strings.Index(string(raw), "\"version\":")).Should(BeNumerically(">", 0)) + } + + result, err := types100.GetResult(r) + Expect(err).NotTo(HaveOccurred()) + + // only addresses in runtimeConfig configured because of its priorities + Expect(*result.IPs[0]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("10.10.0.1/24"), + })) + Expect(*result.IPs[1]).To(Equal( + types100.IPConfig{ + Address: mustCIDR("3ffe:ffff:0:01ff::1/64"), + }, + )) + Expect(len(result.IPs)).To(Equal(2)) + Expect(result.Routes).To(Equal([]*types.Route{ + {Dst: mustCIDR("0.0.0.0/0"), GW: net.ParseIP("10.10.0.254")}, + {Dst: mustCIDR("3ffe:ffff:0:01ff::1/64"), GW: net.ParseIP("3ffe:ffff:0::1")}, + })) + + // Release the IP + err = testutils.CmdDelWithArgs(args, func() error { + return cmdDel(args) + }) + Expect(err).NotTo(HaveOccurred()) + }) + } }) func mustCIDR(s string) net.IPNet {