diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index fd7fc87a..90fb3ea7 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -11,31 +11,11 @@ "Comment": "v0.5.2", "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" }, - { - "ImportPath": "github.com/containernetworking/cni/pkg/ip", - "Comment": "v0.5.2", - "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" - }, - { - "ImportPath": "github.com/containernetworking/cni/pkg/ipam", - "Comment": "v0.5.2", - "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" - }, - { - "ImportPath": "github.com/containernetworking/cni/pkg/ns", - "Comment": "v0.5.2", - "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" - }, { "ImportPath": "github.com/containernetworking/cni/pkg/skel", "Comment": "v0.5.2", "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" }, - { - "ImportPath": "github.com/containernetworking/cni/pkg/testutils", - "Comment": "v0.5.2", - "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" - }, { "ImportPath": "github.com/containernetworking/cni/pkg/types", "Comment": "v0.5.2", @@ -51,21 +31,6 @@ "Comment": "v0.5.2", "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" }, - { - "ImportPath": "github.com/containernetworking/cni/pkg/utils", - "Comment": "v0.5.2", - "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" - }, - { - "ImportPath": "github.com/containernetworking/cni/pkg/utils/hwaddr", - "Comment": "v0.5.2", - "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" - }, - { - "ImportPath": "github.com/containernetworking/cni/pkg/utils/sysctl", - "Comment": "v0.5.2", - "Rev": "137b4975ecab6e1f0c24c1e3c228a50a3cfba75e" - }, { "ImportPath": "github.com/containernetworking/cni/pkg/version", "Comment": "v0.5.2", @@ -99,6 +64,11 @@ "Comment": "v1.2.0-29-g7f8ab55", "Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700" }, + { + "ImportPath": "github.com/onsi/ginkgo/extensions/table", + "Comment": "v1.2.0-29-g7f8ab55", + "Rev": "7f8ab55aaf3b86885aa55b762e803744d1674700" + }, { "ImportPath": "github.com/onsi/ginkgo/internal/codelocation", "Comment": "v1.2.0-29-g7f8ab55", diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/cidr.go b/pkg/ip/cidr.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ip/cidr.go rename to pkg/ip/cidr.go diff --git a/pkg/ip/ip_suite_test.go b/pkg/ip/ip_suite_test.go new file mode 100644 index 00000000..3fdd57e4 --- /dev/null +++ b/pkg/ip/ip_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2016 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 ip_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestIp(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Ip Suite") +} diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/ipforward.go b/pkg/ip/ipforward.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ip/ipforward.go rename to pkg/ip/ipforward.go diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/ipmasq.go b/pkg/ip/ipmasq.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ip/ipmasq.go rename to pkg/ip/ipmasq.go diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/link.go b/pkg/ip/link.go similarity index 98% rename from vendor/github.com/containernetworking/cni/pkg/ip/link.go rename to pkg/ip/link.go index a9842627..fb8d3d50 100644 --- a/vendor/github.com/containernetworking/cni/pkg/ip/link.go +++ b/pkg/ip/link.go @@ -21,8 +21,8 @@ import ( "net" "os" - "github.com/containernetworking/cni/pkg/ns" - "github.com/containernetworking/cni/pkg/utils/hwaddr" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/utils/hwaddr" "github.com/vishvananda/netlink" ) diff --git a/pkg/ip/link_test.go b/pkg/ip/link_test.go new file mode 100644 index 00000000..a20a1582 --- /dev/null +++ b/pkg/ip/link_test.go @@ -0,0 +1,273 @@ +// Copyright 2016 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 ip_test + +import ( + "bytes" + "crypto/rand" + "fmt" + "net" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/containernetworking/plugins/pkg/ip" + "github.com/containernetworking/plugins/pkg/ns" + + "github.com/vishvananda/netlink" + "github.com/vishvananda/netlink/nl" +) + +func getHwAddr(linkname string) string { + veth, err := netlink.LinkByName(linkname) + Expect(err).NotTo(HaveOccurred()) + return fmt.Sprintf("%s", veth.Attrs().HardwareAddr) +} + +var _ = Describe("Link", func() { + const ( + ifaceFormatString string = "i%d" + mtu int = 1400 + ip4onehwaddr = "0a:58:01:01:01:01" + ) + var ( + hostNetNS ns.NetNS + containerNetNS ns.NetNS + ifaceCounter int = 0 + hostVeth net.Interface + containerVeth net.Interface + hostVethName string + containerVethName string + + ip4one = net.ParseIP("1.1.1.1") + ip4two = net.ParseIP("1.1.1.2") + originalRandReader = rand.Reader + ) + + BeforeEach(func() { + var err error + + hostNetNS, err = ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + + containerNetNS, err = ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + + fakeBytes := make([]byte, 20) + //to be reset in AfterEach block + rand.Reader = bytes.NewReader(fakeBytes) + + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + hostVeth, containerVeth, err = ip.SetupVeth(fmt.Sprintf(ifaceFormatString, ifaceCounter), mtu, hostNetNS) + if err != nil { + return err + } + Expect(err).NotTo(HaveOccurred()) + + hostVethName = hostVeth.Name + containerVethName = containerVeth.Name + + return nil + }) + }) + + AfterEach(func() { + Expect(containerNetNS.Close()).To(Succeed()) + Expect(hostNetNS.Close()).To(Succeed()) + ifaceCounter++ + rand.Reader = originalRandReader + }) + + It("SetupVeth must put the veth endpoints into the separate namespaces", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + containerVethFromName, err := netlink.LinkByName(containerVethName) + Expect(err).NotTo(HaveOccurred()) + Expect(containerVethFromName.Attrs().Index).To(Equal(containerVeth.Index)) + + return nil + }) + + _ = hostNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + hostVethFromName, err := netlink.LinkByName(hostVethName) + Expect(err).NotTo(HaveOccurred()) + Expect(hostVethFromName.Attrs().Index).To(Equal(hostVeth.Index)) + + return nil + }) + }) + + Context("when container already has an interface with the same name", func() { + It("returns useful error", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + _, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS) + Expect(err.Error()).To(Equal(fmt.Sprintf("container veth name provided (%s) already exists", containerVethName))) + + return nil + }) + }) + }) + + Context("deleting an non-existent device", func() { + It("returns known error", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + // This string should match the expected error codes in the cmdDel functions of some of the plugins + _, err := ip.DelLinkByNameAddr("THIS_DONT_EXIST", netlink.FAMILY_V4) + Expect(err).To(Equal(ip.ErrLinkNotFound)) + + return nil + }) + }) + }) + + Context("when there is no name available for the host-side", func() { + BeforeEach(func() { + //adding different interface to container ns + containerVethName += "0" + }) + It("returns useful error", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + _, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS) + Expect(err.Error()).To(Equal("failed to move veth to host netns: file exists")) + + return nil + }) + }) + }) + + Context("when there is no name conflict for the host or container interfaces", func() { + BeforeEach(func() { + //adding different interface to container and host ns + containerVethName += "0" + rand.Reader = originalRandReader + }) + It("successfully creates the second veth pair", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + hostVeth, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS) + Expect(err).NotTo(HaveOccurred()) + hostVethName = hostVeth.Name + return nil + }) + + //verify veths are in different namespaces + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + _, err := netlink.LinkByName(containerVethName) + Expect(err).NotTo(HaveOccurred()) + + return nil + }) + + _ = hostNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + _, err := netlink.LinkByName(hostVethName) + Expect(err).NotTo(HaveOccurred()) + + return nil + }) + }) + + }) + + It("DelLinkByName must delete the veth endpoints", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + // this will delete the host endpoint too + err := ip.DelLinkByName(containerVethName) + Expect(err).NotTo(HaveOccurred()) + + _, err = netlink.LinkByName(containerVethName) + Expect(err).To(HaveOccurred()) + + return nil + }) + + _ = hostNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + _, err := netlink.LinkByName(hostVethName) + Expect(err).To(HaveOccurred()) + + return nil + }) + }) + + It("DelLinkByNameAddr must throw an error for configured interfaces", func() { + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + // this will delete the host endpoint too + addr, err := ip.DelLinkByNameAddr(containerVethName, nl.FAMILY_V4) + Expect(err).To(HaveOccurred()) + + var ipNetNil *net.IPNet + Expect(addr).To(Equal(ipNetNil)) + return nil + }) + }) + + It("SetHWAddrByIP must change the interface hwaddr and be predictable", func() { + + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + var err error + hwaddrBefore := getHwAddr(containerVethName) + + err = ip.SetHWAddrByIP(containerVethName, ip4one, nil) + Expect(err).NotTo(HaveOccurred()) + hwaddrAfter1 := getHwAddr(containerVethName) + + Expect(hwaddrBefore).NotTo(Equal(hwaddrAfter1)) + Expect(hwaddrAfter1).To(Equal(ip4onehwaddr)) + + return nil + }) + }) + + It("SetHWAddrByIP must be injective", func() { + + _ = containerNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + err := ip.SetHWAddrByIP(containerVethName, ip4one, nil) + Expect(err).NotTo(HaveOccurred()) + hwaddrAfter1 := getHwAddr(containerVethName) + + err = ip.SetHWAddrByIP(containerVethName, ip4two, nil) + Expect(err).NotTo(HaveOccurred()) + hwaddrAfter2 := getHwAddr(containerVethName) + + Expect(hwaddrAfter1).NotTo(Equal(hwaddrAfter2)) + return nil + }) + }) +}) diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/route.go b/pkg/ip/route.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ip/route.go rename to pkg/ip/route.go diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/route_linux.go b/pkg/ip/route_linux.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ip/route_linux.go rename to pkg/ip/route_linux.go diff --git a/vendor/github.com/containernetworking/cni/pkg/ip/route_unspecified.go b/pkg/ip/route_unspecified.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ip/route_unspecified.go rename to pkg/ip/route_unspecified.go diff --git a/vendor/github.com/containernetworking/cni/pkg/ipam/ipam.go b/pkg/ipam/ipam.go similarity index 98% rename from vendor/github.com/containernetworking/cni/pkg/ipam/ipam.go rename to pkg/ipam/ipam.go index b76780f0..54f80c0e 100644 --- a/vendor/github.com/containernetworking/cni/pkg/ipam/ipam.go +++ b/pkg/ipam/ipam.go @@ -20,9 +20,9 @@ import ( "os" "github.com/containernetworking/cni/pkg/invoke" - "github.com/containernetworking/cni/pkg/ip" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/plugins/pkg/ip" "github.com/vishvananda/netlink" ) diff --git a/pkg/ipam/ipam_suite_test.go b/pkg/ipam/ipam_suite_test.go new file mode 100644 index 00000000..e80c8675 --- /dev/null +++ b/pkg/ipam/ipam_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2016 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 ipam_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestIpam(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Ipam Suite") +} diff --git a/pkg/ipam/ipam_test.go b/pkg/ipam/ipam_test.go new file mode 100644 index 00000000..844867f2 --- /dev/null +++ b/pkg/ipam/ipam_test.go @@ -0,0 +1,258 @@ +// 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 ipam + +import ( + "net" + "syscall" + + "github.com/containernetworking/cni/pkg/types" + "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/plugins/pkg/ns" + + "github.com/vishvananda/netlink" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const LINK_NAME = "eth0" + +func ipNetEqual(a, b *net.IPNet) bool { + aPrefix, aBits := a.Mask.Size() + bPrefix, bBits := b.Mask.Size() + if aPrefix != bPrefix || aBits != bBits { + return false + } + return a.IP.Equal(b.IP) +} + +var _ = Describe("IPAM Operations", func() { + var originalNS ns.NetNS + var ipv4, ipv6, routev4, routev6 *net.IPNet + var ipgw4, ipgw6, routegwv4, routegwv6 net.IP + var result *current.Result + + BeforeEach(func() { + // Create a new NetNS so we don't modify the host + var err error + originalNS, err = ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + + err = originalNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + // Add master + err = netlink.LinkAdd(&netlink.Dummy{ + LinkAttrs: netlink.LinkAttrs{ + Name: LINK_NAME, + }, + }) + Expect(err).NotTo(HaveOccurred()) + _, err = netlink.LinkByName(LINK_NAME) + Expect(err).NotTo(HaveOccurred()) + return nil + }) + Expect(err).NotTo(HaveOccurred()) + + ipv4, err = types.ParseCIDR("1.2.3.30/24") + Expect(err).NotTo(HaveOccurred()) + Expect(ipv4).NotTo(BeNil()) + + _, routev4, err = net.ParseCIDR("15.5.6.8/24") + Expect(err).NotTo(HaveOccurred()) + Expect(routev4).NotTo(BeNil()) + routegwv4 = net.ParseIP("1.2.3.5") + Expect(routegwv4).NotTo(BeNil()) + + ipgw4 = net.ParseIP("1.2.3.1") + Expect(ipgw4).NotTo(BeNil()) + + ipv6, err = types.ParseCIDR("abcd:1234:ffff::cdde/64") + Expect(err).NotTo(HaveOccurred()) + Expect(ipv6).NotTo(BeNil()) + + _, routev6, err = net.ParseCIDR("1111:dddd::aaaa/80") + Expect(err).NotTo(HaveOccurred()) + Expect(routev6).NotTo(BeNil()) + routegwv6 = net.ParseIP("abcd:1234:ffff::10") + Expect(routegwv6).NotTo(BeNil()) + + ipgw6 = net.ParseIP("abcd:1234:ffff::1") + Expect(ipgw6).NotTo(BeNil()) + + result = ¤t.Result{ + Interfaces: []*current.Interface{ + { + Name: "eth0", + Mac: "00:11:22:33:44:55", + Sandbox: "/proc/3553/ns/net", + }, + { + Name: "fake0", + Mac: "00:33:44:55:66:77", + Sandbox: "/proc/1234/ns/net", + }, + }, + IPs: []*current.IPConfig{ + { + Version: "4", + Interface: 0, + Address: *ipv4, + Gateway: ipgw4, + }, + { + Version: "6", + Interface: 0, + Address: *ipv6, + Gateway: ipgw6, + }, + }, + Routes: []*types.Route{ + {Dst: *routev4, GW: routegwv4}, + {Dst: *routev6, GW: routegwv6}, + }, + } + }) + + AfterEach(func() { + Expect(originalNS.Close()).To(Succeed()) + }) + + It("configures a link with addresses and routes", func() { + err := originalNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + err := ConfigureIface(LINK_NAME, result) + Expect(err).NotTo(HaveOccurred()) + + link, err := netlink.LinkByName(LINK_NAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().Name).To(Equal(LINK_NAME)) + + v4addrs, err := netlink.AddrList(link, syscall.AF_INET) + Expect(err).NotTo(HaveOccurred()) + Expect(len(v4addrs)).To(Equal(1)) + Expect(ipNetEqual(v4addrs[0].IPNet, ipv4)).To(Equal(true)) + + v6addrs, err := netlink.AddrList(link, syscall.AF_INET6) + Expect(err).NotTo(HaveOccurred()) + Expect(len(v6addrs)).To(Equal(2)) + + var found bool + for _, a := range v6addrs { + if ipNetEqual(a.IPNet, ipv6) { + found = true + break + } + } + Expect(found).To(Equal(true)) + + // Ensure the v4 route, v6 route, and subnet route + routes, err := netlink.RouteList(link, 0) + Expect(err).NotTo(HaveOccurred()) + + var v4found, v6found bool + for _, route := range routes { + isv4 := route.Dst.IP.To4() != nil + if isv4 && ipNetEqual(route.Dst, routev4) && route.Gw.Equal(routegwv4) { + v4found = true + } + if !isv4 && ipNetEqual(route.Dst, routev6) && route.Gw.Equal(routegwv6) { + v6found = true + } + + if v4found && v6found { + break + } + } + Expect(v4found).To(Equal(true)) + Expect(v6found).To(Equal(true)) + + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It("configures a link with routes using address gateways", func() { + result.Routes[0].GW = nil + result.Routes[1].GW = nil + err := originalNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + err := ConfigureIface(LINK_NAME, result) + Expect(err).NotTo(HaveOccurred()) + + link, err := netlink.LinkByName(LINK_NAME) + Expect(err).NotTo(HaveOccurred()) + Expect(link.Attrs().Name).To(Equal(LINK_NAME)) + + // Ensure the v4 route, v6 route, and subnet route + routes, err := netlink.RouteList(link, 0) + Expect(err).NotTo(HaveOccurred()) + + var v4found, v6found bool + for _, route := range routes { + isv4 := route.Dst.IP.To4() != nil + if isv4 && ipNetEqual(route.Dst, routev4) && route.Gw.Equal(ipgw4) { + v4found = true + } + if !isv4 && ipNetEqual(route.Dst, routev6) && route.Gw.Equal(ipgw6) { + v6found = true + } + + if v4found && v6found { + break + } + } + Expect(v4found).To(Equal(true)) + Expect(v6found).To(Equal(true)) + + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It("returns an error when the interface index doesn't match the link name", func() { + result.IPs[0].Interface = 1 + err := originalNS.Do(func(ns.NetNS) error { + return ConfigureIface(LINK_NAME, result) + }) + Expect(err).To(HaveOccurred()) + }) + + It("returns an error when the interface index is too big", func() { + result.IPs[0].Interface = 2 + err := originalNS.Do(func(ns.NetNS) error { + return ConfigureIface(LINK_NAME, result) + }) + Expect(err).To(HaveOccurred()) + }) + + It("returns an error when there are no interfaces to configure", func() { + result.Interfaces = []*current.Interface{} + err := originalNS.Do(func(ns.NetNS) error { + return ConfigureIface(LINK_NAME, result) + }) + Expect(err).To(HaveOccurred()) + }) + + It("returns an error when configuring the wrong interface", func() { + err := originalNS.Do(func(ns.NetNS) error { + return ConfigureIface("asdfasdf", result) + }) + Expect(err).To(HaveOccurred()) + }) +}) diff --git a/vendor/github.com/containernetworking/cni/pkg/ns/README.md b/pkg/ns/README.md similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ns/README.md rename to pkg/ns/README.md diff --git a/vendor/github.com/containernetworking/cni/pkg/ns/ns.go b/pkg/ns/ns.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ns/ns.go rename to pkg/ns/ns.go diff --git a/vendor/github.com/containernetworking/cni/pkg/ns/ns_linux.go b/pkg/ns/ns_linux.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ns/ns_linux.go rename to pkg/ns/ns_linux.go diff --git a/pkg/ns/ns_suite_test.go b/pkg/ns/ns_suite_test.go new file mode 100644 index 00000000..e2adaa4e --- /dev/null +++ b/pkg/ns/ns_suite_test.go @@ -0,0 +1,34 @@ +// Copyright 2016 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 ns_test + +import ( + "math/rand" + "runtime" + + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/config" + . "github.com/onsi/gomega" + + "testing" +) + +func TestNs(t *testing.T) { + rand.Seed(config.GinkgoConfig.RandomSeed) + runtime.LockOSThread() + + RegisterFailHandler(Fail) + RunSpecs(t, "pkg/ns Suite") +} diff --git a/pkg/ns/ns_test.go b/pkg/ns/ns_test.go new file mode 100644 index 00000000..e47517da --- /dev/null +++ b/pkg/ns/ns_test.go @@ -0,0 +1,252 @@ +// Copyright 2016 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 ns_test + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/containernetworking/plugins/pkg/ns" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "golang.org/x/sys/unix" +) + +func getInodeCurNetNS() (uint64, error) { + curNS, err := ns.GetCurrentNS() + if err != nil { + return 0, err + } + defer curNS.Close() + return getInodeNS(curNS) +} + +func getInodeNS(netns ns.NetNS) (uint64, error) { + return getInodeFd(int(netns.Fd())) +} + +func getInode(path string) (uint64, error) { + file, err := os.Open(path) + if err != nil { + return 0, err + } + defer file.Close() + return getInodeFd(int(file.Fd())) +} + +func getInodeFd(fd int) (uint64, error) { + stat := &unix.Stat_t{} + err := unix.Fstat(fd, stat) + return stat.Ino, err +} + +var _ = Describe("Linux namespace operations", func() { + Describe("WithNetNS", func() { + var ( + originalNetNS ns.NetNS + targetNetNS ns.NetNS + ) + + BeforeEach(func() { + var err error + + originalNetNS, err = ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + + targetNetNS, err = ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + Expect(targetNetNS.Close()).To(Succeed()) + Expect(originalNetNS.Close()).To(Succeed()) + }) + + It("executes the callback within the target network namespace", func() { + expectedInode, err := getInodeNS(targetNetNS) + Expect(err).NotTo(HaveOccurred()) + + err = targetNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + actualInode, err := getInodeCurNetNS() + Expect(err).NotTo(HaveOccurred()) + Expect(actualInode).To(Equal(expectedInode)) + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It("provides the original namespace as the argument to the callback", func() { + // Ensure we start in originalNetNS + err := originalNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + origNSInode, err := getInodeNS(originalNetNS) + Expect(err).NotTo(HaveOccurred()) + + err = targetNetNS.Do(func(hostNS ns.NetNS) error { + defer GinkgoRecover() + + hostNSInode, err := getInodeNS(hostNS) + Expect(err).NotTo(HaveOccurred()) + Expect(hostNSInode).To(Equal(origNSInode)) + return nil + }) + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + + Context("when the callback returns an error", func() { + It("restores the calling thread to the original namespace before returning", func() { + err := originalNetNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + preTestInode, err := getInodeCurNetNS() + Expect(err).NotTo(HaveOccurred()) + + _ = targetNetNS.Do(func(ns.NetNS) error { + return errors.New("potato") + }) + + postTestInode, err := getInodeCurNetNS() + Expect(err).NotTo(HaveOccurred()) + Expect(postTestInode).To(Equal(preTestInode)) + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) + + It("returns the error from the callback", func() { + err := targetNetNS.Do(func(ns.NetNS) error { + return errors.New("potato") + }) + Expect(err).To(MatchError("potato")) + }) + }) + + Describe("validating inode mapping to namespaces", func() { + It("checks that different namespaces have different inodes", func() { + origNSInode, err := getInodeNS(originalNetNS) + Expect(err).NotTo(HaveOccurred()) + + testNsInode, err := getInodeNS(targetNetNS) + Expect(err).NotTo(HaveOccurred()) + + Expect(testNsInode).NotTo(Equal(0)) + Expect(testNsInode).NotTo(Equal(origNSInode)) + }) + + It("should not leak a closed netns onto any threads in the process", func() { + By("creating a new netns") + createdNetNS, err := ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + + By("discovering the inode of the created netns") + createdNetNSInode, err := getInodeNS(createdNetNS) + Expect(err).NotTo(HaveOccurred()) + createdNetNS.Close() + + By("comparing against the netns inode of every thread in the process") + for _, netnsPath := range allNetNSInCurrentProcess() { + netnsInode, err := getInode(netnsPath) + Expect(err).NotTo(HaveOccurred()) + Expect(netnsInode).NotTo(Equal(createdNetNSInode)) + } + }) + + It("fails when the path is not a namespace", func() { + tempFile, err := ioutil.TempFile("", "nstest") + Expect(err).NotTo(HaveOccurred()) + defer tempFile.Close() + + nspath := tempFile.Name() + defer os.Remove(nspath) + + _, err = ns.GetNS(nspath) + Expect(err).To(HaveOccurred()) + Expect(err).To(BeAssignableToTypeOf(ns.NSPathNotNSErr{})) + Expect(err).NotTo(BeAssignableToTypeOf(ns.NSPathNotExistErr{})) + }) + }) + + Describe("closing a network namespace", func() { + It("should prevent further operations", func() { + createdNetNS, err := ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + + err = createdNetNS.Close() + Expect(err).NotTo(HaveOccurred()) + + err = createdNetNS.Do(func(ns.NetNS) error { return nil }) + Expect(err).To(HaveOccurred()) + + err = createdNetNS.Set() + Expect(err).To(HaveOccurred()) + }) + + It("should only work once", func() { + createdNetNS, err := ns.NewNS() + Expect(err).NotTo(HaveOccurred()) + + err = createdNetNS.Close() + Expect(err).NotTo(HaveOccurred()) + + err = createdNetNS.Close() + Expect(err).To(HaveOccurred()) + }) + }) + }) + + Describe("IsNSorErr", func() { + It("should detect a namespace", func() { + createdNetNS, err := ns.NewNS() + err = ns.IsNSorErr(createdNetNS.Path()) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should refuse other paths", func() { + tempFile, err := ioutil.TempFile("", "nstest") + Expect(err).NotTo(HaveOccurred()) + defer tempFile.Close() + + nspath := tempFile.Name() + defer os.Remove(nspath) + + err = ns.IsNSorErr(nspath) + Expect(err).To(HaveOccurred()) + Expect(err).To(BeAssignableToTypeOf(ns.NSPathNotNSErr{})) + Expect(err).NotTo(BeAssignableToTypeOf(ns.NSPathNotExistErr{})) + }) + + It("should error on non-existing paths", func() { + err := ns.IsNSorErr("/tmp/IDoNotExist") + Expect(err).To(HaveOccurred()) + Expect(err).To(BeAssignableToTypeOf(ns.NSPathNotExistErr{})) + Expect(err).NotTo(BeAssignableToTypeOf(ns.NSPathNotNSErr{})) + }) + }) +}) + +func allNetNSInCurrentProcess() []string { + pid := unix.Getpid() + paths, err := filepath.Glob(fmt.Sprintf("/proc/%d/task/*/ns/net", pid)) + Expect(err).NotTo(HaveOccurred()) + return paths +} diff --git a/vendor/github.com/containernetworking/cni/pkg/ns/ns_unspecified.go b/pkg/ns/ns_unspecified.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/ns/ns_unspecified.go rename to pkg/ns/ns_unspecified.go diff --git a/vendor/github.com/containernetworking/cni/pkg/testutils/bad_reader.go b/pkg/testutils/bad_reader.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/testutils/bad_reader.go rename to pkg/testutils/bad_reader.go diff --git a/vendor/github.com/containernetworking/cni/pkg/testutils/cmd.go b/pkg/testutils/cmd.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/testutils/cmd.go rename to pkg/testutils/cmd.go diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/hwaddr/hwaddr.go b/pkg/utils/hwaddr/hwaddr.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/utils/hwaddr/hwaddr.go rename to pkg/utils/hwaddr/hwaddr.go diff --git a/pkg/utils/hwaddr/hwaddr_suite_test.go b/pkg/utils/hwaddr/hwaddr_suite_test.go new file mode 100644 index 00000000..e3bbfe97 --- /dev/null +++ b/pkg/utils/hwaddr/hwaddr_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2016 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 hwaddr_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestHwaddr(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Hwaddr Suite") +} diff --git a/pkg/utils/hwaddr/hwaddr_test.go b/pkg/utils/hwaddr/hwaddr_test.go new file mode 100644 index 00000000..ab89a58e --- /dev/null +++ b/pkg/utils/hwaddr/hwaddr_test.go @@ -0,0 +1,74 @@ +// Copyright 2016 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 hwaddr_test + +import ( + "net" + + "github.com/containernetworking/plugins/pkg/utils/hwaddr" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Hwaddr", func() { + Context("Generate Hardware Address", func() { + It("generate hardware address based on ipv4 address", func() { + testCases := []struct { + ip net.IP + expectedMAC net.HardwareAddr + }{ + { + ip: net.ParseIP("10.0.0.2"), + expectedMAC: (net.HardwareAddr)(append(hwaddr.PrivateMACPrefix, 0x0a, 0x00, 0x00, 0x02)), + }, + { + ip: net.ParseIP("10.250.0.244"), + expectedMAC: (net.HardwareAddr)(append(hwaddr.PrivateMACPrefix, 0x0a, 0xfa, 0x00, 0xf4)), + }, + { + ip: net.ParseIP("172.17.0.2"), + expectedMAC: (net.HardwareAddr)(append(hwaddr.PrivateMACPrefix, 0xac, 0x11, 0x00, 0x02)), + }, + { + ip: net.IPv4(byte(172), byte(17), byte(0), byte(2)), + expectedMAC: (net.HardwareAddr)(append(hwaddr.PrivateMACPrefix, 0xac, 0x11, 0x00, 0x02)), + }, + } + + for _, tc := range testCases { + mac, err := hwaddr.GenerateHardwareAddr4(tc.ip, hwaddr.PrivateMACPrefix) + Expect(err).NotTo(HaveOccurred()) + Expect(mac).To(Equal(tc.expectedMAC)) + } + }) + + It("return error if input is not ipv4 address", func() { + testCases := []net.IP{ + net.ParseIP(""), + net.ParseIP("2001:db8:0:1:1:1:1:1"), + } + for _, tc := range testCases { + _, err := hwaddr.GenerateHardwareAddr4(tc, hwaddr.PrivateMACPrefix) + Expect(err).To(BeAssignableToTypeOf(hwaddr.SupportIp4OnlyErr{})) + } + }) + + It("return error if prefix is invalid", func() { + _, err := hwaddr.GenerateHardwareAddr4(net.ParseIP("10.0.0.2"), []byte{0x58}) + Expect(err).To(BeAssignableToTypeOf(hwaddr.InvalidPrefixLengthErr{})) + }) + }) +}) diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/sysctl/sysctl_linux.go b/pkg/utils/sysctl/sysctl_linux.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/utils/sysctl/sysctl_linux.go rename to pkg/utils/sysctl/sysctl_linux.go diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/utils.go b/pkg/utils/utils.go similarity index 100% rename from vendor/github.com/containernetworking/cni/pkg/utils/utils.go rename to pkg/utils/utils.go diff --git a/pkg/utils/utils_suite_test.go b/pkg/utils/utils_suite_test.go new file mode 100644 index 00000000..ee614a70 --- /dev/null +++ b/pkg/utils/utils_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2016 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 utils_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestUtils(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Utils Suite") +} diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go new file mode 100644 index 00000000..d703de42 --- /dev/null +++ b/pkg/utils/utils_test.go @@ -0,0 +1,51 @@ +// Copyright 2016 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 utils + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Utils", func() { + It("must format a short name", func() { + chain := FormatChainName("test", "1234") + Expect(len(chain)).To(Equal(maxChainLength)) + Expect(chain).To(Equal("CNI-2bbe0c48b91a7d1b8a6753a8")) + }) + + It("must truncate a long name", func() { + chain := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + Expect(len(chain)).To(Equal(maxChainLength)) + Expect(chain).To(Equal("CNI-374f33fe84ab0ed84dcdebe3")) + }) + + It("must be predictable", func() { + chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + Expect(len(chain1)).To(Equal(maxChainLength)) + Expect(len(chain2)).To(Equal(maxChainLength)) + Expect(chain1).To(Equal(chain2)) + }) + + It("must change when a character changes", func() { + chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234") + chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1235") + Expect(len(chain1)).To(Equal(maxChainLength)) + Expect(len(chain2)).To(Equal(maxChainLength)) + Expect(chain1).To(Equal("CNI-374f33fe84ab0ed84dcdebe3")) + Expect(chain1).NotTo(Equal(chain2)) + }) +}) diff --git a/plugins/ipam/dhcp/lease.go b/plugins/ipam/dhcp/lease.go index a202720d..ca34eec4 100644 --- a/plugins/ipam/dhcp/lease.go +++ b/plugins/ipam/dhcp/lease.go @@ -26,8 +26,8 @@ import ( "github.com/d2g/dhcp4client" "github.com/vishvananda/netlink" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/types" + "github.com/containernetworking/plugins/pkg/ns" ) // RFC 2131 suggests using exponential backoff, starting with 4sec diff --git a/plugins/ipam/host-local/backend/allocator/allocator.go b/plugins/ipam/host-local/backend/allocator/allocator.go index 87b4fa19..56b8bdf0 100644 --- a/plugins/ipam/host-local/backend/allocator/allocator.go +++ b/plugins/ipam/host-local/backend/allocator/allocator.go @@ -20,9 +20,9 @@ import ( "net" "os" - "github.com/containernetworking/cni/pkg/ip" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/plugins/pkg/ip" "github.com/containernetworking/plugins/plugins/ipam/host-local/backend" ) diff --git a/plugins/ipam/host-local/host_local_test.go b/plugins/ipam/host-local/host_local_test.go index f1578d09..5e2c69c4 100644 --- a/plugins/ipam/host-local/host_local_test.go +++ b/plugins/ipam/host-local/host_local_test.go @@ -23,10 +23,10 @@ import ( "strings" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/020" "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/plugins/pkg/testutils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" diff --git a/plugins/main/bridge/bridge.go b/plugins/main/bridge/bridge.go index 876cb5bb..83468d9c 100644 --- a/plugins/main/bridge/bridge.go +++ b/plugins/main/bridge/bridge.go @@ -22,14 +22,14 @@ import ( "runtime" "syscall" - "github.com/containernetworking/cni/pkg/ip" - "github.com/containernetworking/cni/pkg/ipam" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" - "github.com/containernetworking/cni/pkg/utils" "github.com/containernetworking/cni/pkg/version" + "github.com/containernetworking/plugins/pkg/ip" + "github.com/containernetworking/plugins/pkg/ipam" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/utils" "github.com/vishvananda/netlink" ) diff --git a/plugins/main/bridge/bridge_test.go b/plugins/main/bridge/bridge_test.go index 65f083b7..8fe56fc0 100644 --- a/plugins/main/bridge/bridge_test.go +++ b/plugins/main/bridge/bridge_test.go @@ -20,14 +20,13 @@ import ( "strings" "syscall" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/020" "github.com/containernetworking/cni/pkg/types/current" - - "github.com/containernetworking/cni/pkg/utils/hwaddr" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/testutils" + "github.com/containernetworking/plugins/pkg/utils/hwaddr" "github.com/vishvananda/netlink" diff --git a/plugins/main/ipvlan/ipvlan.go b/plugins/main/ipvlan/ipvlan.go index 4fba4327..b9c7b1b3 100644 --- a/plugins/main/ipvlan/ipvlan.go +++ b/plugins/main/ipvlan/ipvlan.go @@ -20,13 +20,13 @@ import ( "fmt" "runtime" - "github.com/containernetworking/cni/pkg/ip" - "github.com/containernetworking/cni/pkg/ipam" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/cni/pkg/version" + "github.com/containernetworking/plugins/pkg/ip" + "github.com/containernetworking/plugins/pkg/ipam" + "github.com/containernetworking/plugins/pkg/ns" "github.com/vishvananda/netlink" ) diff --git a/plugins/main/ipvlan/ipvlan_test.go b/plugins/main/ipvlan/ipvlan_test.go index 41a56256..a2b92179 100644 --- a/plugins/main/ipvlan/ipvlan_test.go +++ b/plugins/main/ipvlan/ipvlan_test.go @@ -19,11 +19,11 @@ import ( "net" "syscall" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/testutils" "github.com/vishvananda/netlink" diff --git a/plugins/main/loopback/loopback.go b/plugins/main/loopback/loopback.go index 6441ba5c..08c84a5d 100644 --- a/plugins/main/loopback/loopback.go +++ b/plugins/main/loopback/loopback.go @@ -15,10 +15,10 @@ package main import ( - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/cni/pkg/version" + "github.com/containernetworking/plugins/pkg/ns" "github.com/vishvananda/netlink" ) diff --git a/plugins/main/loopback/loopback_test.go b/plugins/main/loopback/loopback_test.go index f71595b0..c5dec3cb 100644 --- a/plugins/main/loopback/loopback_test.go +++ b/plugins/main/loopback/loopback_test.go @@ -20,7 +20,7 @@ import ( "os/exec" "strings" - "github.com/containernetworking/cni/pkg/ns" + "github.com/containernetworking/plugins/pkg/ns" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" diff --git a/plugins/main/macvlan/macvlan.go b/plugins/main/macvlan/macvlan.go index 0d34a4c7..4ee9abb4 100644 --- a/plugins/main/macvlan/macvlan.go +++ b/plugins/main/macvlan/macvlan.go @@ -21,14 +21,14 @@ import ( "net" "runtime" - "github.com/containernetworking/cni/pkg/ip" - "github.com/containernetworking/cni/pkg/ipam" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" - "github.com/containernetworking/cni/pkg/utils/sysctl" "github.com/containernetworking/cni/pkg/version" + "github.com/containernetworking/plugins/pkg/ip" + "github.com/containernetworking/plugins/pkg/ipam" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/utils/sysctl" "github.com/vishvananda/netlink" ) diff --git a/plugins/main/macvlan/macvlan_test.go b/plugins/main/macvlan/macvlan_test.go index e17b14f3..7ae26f30 100644 --- a/plugins/main/macvlan/macvlan_test.go +++ b/plugins/main/macvlan/macvlan_test.go @@ -19,12 +19,12 @@ import ( "net" "syscall" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" - "github.com/containernetworking/cni/pkg/utils/hwaddr" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/testutils" + "github.com/containernetworking/plugins/pkg/utils/hwaddr" "github.com/vishvananda/netlink" diff --git a/plugins/main/ptp/ptp.go b/plugins/main/ptp/ptp.go index f90bafbc..af93312d 100644 --- a/plugins/main/ptp/ptp.go +++ b/plugins/main/ptp/ptp.go @@ -24,14 +24,14 @@ import ( "github.com/vishvananda/netlink" - "github.com/containernetworking/cni/pkg/ip" - "github.com/containernetworking/cni/pkg/ipam" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" - "github.com/containernetworking/cni/pkg/utils" "github.com/containernetworking/cni/pkg/version" + "github.com/containernetworking/plugins/pkg/ip" + "github.com/containernetworking/plugins/pkg/ipam" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/utils" ) func init() { diff --git a/plugins/main/ptp/ptp_test.go b/plugins/main/ptp/ptp_test.go index b30fd31c..a562af7e 100644 --- a/plugins/main/ptp/ptp_test.go +++ b/plugins/main/ptp/ptp_test.go @@ -15,9 +15,9 @@ package main import ( - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/testutils" "github.com/vishvananda/netlink" diff --git a/plugins/main/vlan/vlan.go b/plugins/main/vlan/vlan.go index 56735ee1..b9aa4fee 100644 --- a/plugins/main/vlan/vlan.go +++ b/plugins/main/vlan/vlan.go @@ -20,13 +20,13 @@ import ( "fmt" "runtime" - "github.com/containernetworking/cni/pkg/ip" - "github.com/containernetworking/cni/pkg/ipam" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/cni/pkg/version" + "github.com/containernetworking/plugins/pkg/ip" + "github.com/containernetworking/plugins/pkg/ipam" + "github.com/containernetworking/plugins/pkg/ns" "github.com/vishvananda/netlink" ) diff --git a/plugins/main/vlan/vlan_test.go b/plugins/main/vlan/vlan_test.go index c46aa739..06005bb5 100644 --- a/plugins/main/vlan/vlan_test.go +++ b/plugins/main/vlan/vlan_test.go @@ -19,11 +19,11 @@ import ( "net" "syscall" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/testutils" "github.com/vishvananda/netlink" diff --git a/plugins/meta/flannel/flannel_test.go b/plugins/meta/flannel/flannel_test.go index a4a8bc7b..0380729c 100644 --- a/plugins/meta/flannel/flannel_test.go +++ b/plugins/meta/flannel/flannel_test.go @@ -18,9 +18,9 @@ import ( "io/ioutil" "os" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/testutils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" diff --git a/plugins/meta/tuning/tuning.go b/plugins/meta/tuning/tuning.go index 9d8e9002..98a242f6 100644 --- a/plugins/meta/tuning/tuning.go +++ b/plugins/meta/tuning/tuning.go @@ -24,11 +24,11 @@ import ( "path/filepath" "strings" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/cni/pkg/version" + "github.com/containernetworking/plugins/pkg/ns" ) // TuningConf represents the network tuning configuration. diff --git a/plugins/sample/sample_test.go b/plugins/sample/sample_test.go index 9d2688cc..d0b64982 100644 --- a/plugins/sample/sample_test.go +++ b/plugins/sample/sample_test.go @@ -17,9 +17,9 @@ package main import ( "fmt" - "github.com/containernetworking/cni/pkg/ns" "github.com/containernetworking/cni/pkg/skel" - "github.com/containernetworking/cni/pkg/testutils" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/containernetworking/plugins/pkg/testutils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) diff --git a/test.sh b/test.sh index 82253f3a..06888aa8 100755 --- a/test.sh +++ b/test.sh @@ -10,7 +10,7 @@ source ./build.sh echo "Running tests" -TESTABLE="plugins/ipam/dhcp plugins/ipam/host-local plugins/ipam/host-local/backend/allocator plugins/main/loopback plugins/main/ipvlan plugins/main/macvlan plugins/main/bridge plugins/main/ptp plugins/meta/flannel plugins/main/vlan plugins/sample" +TESTABLE="plugins/ipam/dhcp plugins/ipam/host-local plugins/ipam/host-local/backend/allocator plugins/main/loopback plugins/main/ipvlan plugins/main/macvlan plugins/main/bridge plugins/main/ptp plugins/meta/flannel plugins/main/vlan plugins/sample pkg/ip pkg/ipam pkg/ns pkg/utils pkg/utils/hwaddr pkg/utils/sysctl" # user has not provided PKG override if [ -z "$PKG" ]; then diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table.go b/vendor/github.com/onsi/ginkgo/extensions/table/table.go new file mode 100644 index 00000000..ae8ab7d2 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table.go @@ -0,0 +1,98 @@ +/* + +Table provides a simple DSL for Ginkgo-native Table-Driven Tests + +The godoc documentation describes Table's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/ginkgo#table-driven-tests + +*/ + +package table + +import ( + "fmt" + "reflect" + + "github.com/onsi/ginkgo" +) + +/* +DescribeTable describes a table-driven test. + +For example: + + DescribeTable("a simple table", + func(x int, y int, expected bool) { + Ω(x > y).Should(Equal(expected)) + }, + Entry("x > y", 1, 0, true), + Entry("x == y", 0, 0, false), + Entry("x < y", 0, 1, false), + ) + +The first argument to `DescribeTable` is a string description. +The second argument is a function that will be run for each table entry. Your assertions go here - the function is equivalent to a Ginkgo It. +The subsequent arguments must be of type `TableEntry`. We recommend using the `Entry` convenience constructors. + +The `Entry` constructor takes a string description followed by an arbitrary set of parameters. These parameters are passed into your function. + +Under the hood, `DescribeTable` simply generates a new Ginkgo `Describe`. Each `Entry` is turned into an `It` within the `Describe`. + +It's important to understand that the `Describe`s and `It`s are generated at evaluation time (i.e. when Ginkgo constructs the tree of tests and before the tests run). + +Individual Entries can be focused (with FEntry) or marked pending (with PEntry or XEntry). In addition, the entire table can be focused or marked pending with FDescribeTable and PDescribeTable/XDescribeTable. +*/ +func DescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, false, false) + return true +} + +/* +You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`. +*/ +func FDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, false, true) + return true +} + +/* +You can mark a table as pending with `PDescribeTable`. This is equivalent to `PDescribe`. +*/ +func PDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, true, false) + return true +} + +/* +You can mark a table as pending with `XDescribeTable`. This is equivalent to `XDescribe`. +*/ +func XDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, true, false) + return true +} + +func describeTable(description string, itBody interface{}, entries []TableEntry, pending bool, focused bool) { + itBodyValue := reflect.ValueOf(itBody) + if itBodyValue.Kind() != reflect.Func { + panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody)) + } + + if pending { + ginkgo.PDescribe(description, func() { + for _, entry := range entries { + entry.generateIt(itBodyValue) + } + }) + } else if focused { + ginkgo.FDescribe(description, func() { + for _, entry := range entries { + entry.generateIt(itBodyValue) + } + }) + } else { + ginkgo.Describe(description, func() { + for _, entry := range entries { + entry.generateIt(itBodyValue) + } + }) + } +} diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go b/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go new file mode 100644 index 00000000..a6a9e3cc --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go @@ -0,0 +1,72 @@ +package table + +import ( + "reflect" + + "github.com/onsi/ginkgo" +) + +/* +TableEntry represents an entry in a table test. You generally use the `Entry` constructor. +*/ +type TableEntry struct { + Description string + Parameters []interface{} + Pending bool + Focused bool +} + +func (t TableEntry) generateIt(itBody reflect.Value) { + if t.Pending { + ginkgo.PIt(t.Description) + return + } + + values := []reflect.Value{} + for _, param := range t.Parameters { + values = append(values, reflect.ValueOf(param)) + } + + body := func() { + itBody.Call(values) + } + + if t.Focused { + ginkgo.FIt(t.Description, body) + } else { + ginkgo.It(t.Description, body) + } +} + +/* +Entry constructs a TableEntry. + +The first argument is a required description (this becomes the content of the generated Ginkgo `It`). +Subsequent parameters are saved off and sent to the callback passed in to `DescribeTable`. + +Each Entry ends up generating an individual Ginkgo It. +*/ +func Entry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, false, false} +} + +/* +You can focus a particular entry with FEntry. This is equivalent to FIt. +*/ +func FEntry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, false, true} +} + +/* +You can mark a particular entry as pending with PEntry. This is equivalent to PIt. +*/ +func PEntry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, true, false} +} + +/* +You can mark a particular entry as pending with XEntry. This is equivalent to XIt. +*/ +func XEntry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, true, false} +}