Skip to content

When CNI ADD success, return all interfaces #10382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions cni-plugin/pkg/k8s/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,12 +532,21 @@ func CmdAddK8s(ctx context.Context, args *skel.CmdArgs, conf types.NetConf, epID
logger.Info("Wrote updated endpoint to datastore")

// Add the interface created above to the CNI result.
result.Interfaces = append(result.Interfaces, &cniv1.Interface{
Name: endpoint.Spec.InterfaceName,
Mac: endpoint.Spec.MAC,
hostInterface := &cniv1.Interface{
Name: hostVethName,
}
contInterface := &cniv1.Interface{
Name: args.IfName,
Mac: contVethMac,
Mtu: conf.MTU,
Sandbox: args.Netns,
})
}

result.Interfaces = append(result.Interfaces, hostInterface, contInterface)

for _, ip := range result.IPs {
ip.Interface = cniv1.Int(1)
}

// Conditionally wait for host-local Felix to program the policy for this WEP.
// Error if negative, ignore if 0.
Expand Down
15 changes: 12 additions & 3 deletions cni-plugin/pkg/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,12 +508,21 @@ func cmdAdd(args *skel.CmdArgs) (err error) {
logger.WithField("endpoint", endpoint).Info("Wrote endpoint to datastore")

// Add the interface created above to the CNI result.
result.Interfaces = append(result.Interfaces, &cniv1.Interface{
Name: endpoint.Spec.InterfaceName,
hostInterface := &cniv1.Interface{
Name: endpoint.Spec.InterfaceName,
}
contInterface := &cniv1.Interface{
Name: args.IfName,
Mac: endpoint.Spec.MAC,
Mtu: conf.MTU,
Sandbox: args.Netns,
})
}

result.Interfaces = append(result.Interfaces, hostInterface, contInterface)

for _, ip := range result.IPs {
ip.Interface = cniv1.Int(1)
}
}

// Handle profile creation - this is only done if there isn't a specific policy handler.
Expand Down
177 changes: 176 additions & 1 deletion cni-plugin/tests/calico_cni_k8s_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
cniv1 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/ns"
cnitestutils "github.com/containernetworking/plugins/pkg/testutils"
"github.com/mcuadros/go-version"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
api "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
Expand Down Expand Up @@ -2581,7 +2582,9 @@ var _ = Describe("Kubernetes CNI tests", func() {
// The MAC address will be different, since we create a new veth.
Expect(len(resultSecondAdd.Interfaces)).Should(Equal(len(result.Interfaces)))
for i := range resultSecondAdd.Interfaces {
Expect(resultSecondAdd.Interfaces[i].Mac).ShouldNot(Equal(result.Interfaces[i].Mac))
if resultSecondAdd.Interfaces[i].Mac != "" {
Expect(resultSecondAdd.Interfaces[i].Mac).ShouldNot(Equal(result.Interfaces[i].Mac))
}
resultSecondAdd.Interfaces[i].Mac = ""
result.Interfaces[i].Mac = ""
}
Expand Down Expand Up @@ -3396,6 +3399,178 @@ var _ = Describe("Kubernetes CNI tests", func() {
Expect(err).To(HaveOccurred())
})
})

Context("When CNI ADD success, return all interfaces", func() {
var nc types.NetConf
var netconf string
var ipPool4CIDR *net.IPNet
var ipPool6CIDR *net.IPNet
var ipPool4 = "50.80.0.0/16"
var ipPool6 = "fd80:50::/96"
var clientset *kubernetes.Clientset
var testNS = testutils.K8S_TEST_NS

BeforeEach(func() {
if version.Compare(cniVersion, "0.3.0", "<") {
Skip("Skipping test because of CNI version < 0.3.0")
}
// Build the network config for this set of tests.
nc = types.NetConf{
CNIVersion: cniVersion,
Name: "calico-uts",
Type: "calico",
EtcdEndpoints: fmt.Sprintf("http://%s:2379", os.Getenv("ETCD_IP")),
DatastoreType: os.Getenv("DATASTORE_TYPE"),
Kubernetes: types.Kubernetes{Kubeconfig: "/home/user/certs/kubeconfig"},
Policy: types.Policy{PolicyType: "k8s"},
NodenameFileOptional: true,
LogLevel: "debug",
Nodename: testNodeName,
}
nc.IPAM.Type = "calico-ipam"
ncb, err := json.Marshal(nc)
Expect(err).NotTo(HaveOccurred())
netconf = string(ncb)

// Create clients.
clientset = getKubernetesClient()

// Make sure the namespace exists.
ensureNamespace(clientset, testutils.K8S_TEST_NS)

_, ipPool4CIDR, err = net.ParseCIDR(ipPool4)
Expect(err).NotTo(HaveOccurred())

_, ipPool6CIDR, err = net.ParseCIDR(ipPool6)
Expect(err).NotTo(HaveOccurred())

// Create a new IP Pool.
testutils.MustCreateNewIPPool(calicoClient, ipPool4, false, false, true)
testutils.MustCreateNewIPPool(calicoClient, ipPool6, false, false, true)

})

AfterEach(func() {
// Delete pod
ensurePodDeleted(clientset, testNS, testPodName)

// Delete the IP Pool.
testutils.MustDeleteIPPool(calicoClient, ipPool4)
testutils.MustDeleteIPPool(calicoClient, ipPool6)
})

It("should allocate IPv4 only", func() {
// Now create a K8s pod passing in an IP pool.
ensurePodCreated(clientset, testNS, &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: testPodName,
Annotations: map[string]string{
"cni.projectcalico.org/ipv4pools": "[\"50.80.0.0/16\"]",
},
},
Spec: v1.PodSpec{
Containers: []v1.Container{{
Name: testPodName,
Image: "ignore",
}},
NodeName: testNodeName,
},
})

// Run the CNI plugin.
_, result, _, contAddresses, _, contNs, err := testutils.CreateContainer(netconf, testPodName, testNS, "")
Expect(err).NotTo(HaveOccurred())

Expect(len(contAddresses)).Should(Equal(1))

for _, ip := range contAddresses {
podIP := ip.IP
if podIP.To4() != nil {
Expect(ipPool4CIDR.Contains(podIP)).Should(BeTrue())
} else {
Expect(ipPool6CIDR.Contains(podIP)).Should(BeTrue())
}
}

interfaces := result.Interfaces

Expect(len(interfaces)).Should(Equal(2))
Expect(len(result.IPs)).Should(Equal(1))

for _, ip := range result.IPs {
interfaceIndex := ip.Interface
Expect(interfaceIndex).ShouldNot(BeNil())
iface := interfaces[*interfaceIndex]
Expect(iface).ShouldNot(BeNil())
Expect(iface.Name).Should(Equal("eth0"))
Expect(iface.Mac).ShouldNot(BeEmpty())
Expect(iface.Sandbox).ShouldNot(BeEmpty())
}

// Delete the container.
_, err = testutils.DeleteContainer(netconf, contNs.Path(), testPodName, testNS)
Expect(err).ShouldNot(HaveOccurred())
})

It("should allocate IPv4 and IPv6 addresses and handle dual stack", func() {
// Now create a K8s pod passing in an IP pool.
ensurePodCreated(clientset, testNS, &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: testPodName,
Annotations: map[string]string{
"cni.projectcalico.org/ipv4pools": "[\"50.80.0.0/16\"]",
"cni.projectcalico.org/ipv6pools": "[\"fd80:50::/96\"]",
},
},
Spec: v1.PodSpec{
Containers: []v1.Container{{
Name: testPodName,
Image: "ignore",
}},
NodeName: testNodeName,
},
})
assignIpv6 := "true"
nc.IPAM.AssignIpv6 = &assignIpv6
ncb, err := json.Marshal(nc)
Expect(err).NotTo(HaveOccurred())
netconf = string(ncb)

// Run the CNI plugin.
_, result, _, contAddresses, _, contNs, err := testutils.CreateContainer(netconf, testPodName, testNS, "")
Expect(err).NotTo(HaveOccurred())

Expect(len(contAddresses)).Should(Equal(2))

for _, ip := range contAddresses {
podIP := ip.IP
if podIP.To4() != nil {
Expect(ipPool4CIDR.Contains(podIP)).Should(BeTrue())
} else {
Expect(ipPool6CIDR.Contains(podIP)).Should(BeTrue())
}
}

interfaces := result.Interfaces

Expect(len(interfaces)).Should(Equal(2))
Expect(len(result.IPs)).Should(Equal(2))

for _, ip := range result.IPs {
interfaceIndex := ip.Interface
Expect(interfaceIndex).ShouldNot(BeNil())
iface := interfaces[*interfaceIndex]
Expect(iface).ShouldNot(BeNil())
Expect(iface.Name).Should(Equal("eth0"))
Expect(iface.Mac).ShouldNot(BeEmpty())
Expect(iface.Sandbox).ShouldNot(BeEmpty())
}

// Delete the container.
_, err = testutils.DeleteContainer(netconf, contNs.Path(), testPodName, testNS)
Expect(err).ShouldNot(HaveOccurred())
})
})
})

func checkPodIPAnnotations(clientset *kubernetes.Clientset, ns, name, expectedIP, expectedIPs string) {
Expand Down
58 changes: 58 additions & 0 deletions cni-plugin/tests/calico_cni_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

cniv1 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/mcuadros/go-version"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
Expand Down Expand Up @@ -935,6 +936,63 @@ var _ = Describe("CalicoCni", func() {
}, 10)

})

Context("When CNI ADD success, return all interfaces", func() {
ipPool4 := "10.0.0.0/8"
netconf := fmt.Sprintf(`
{
"cniVersion": "%s",
"name": "net1",
"type": "calico",
"etcd_endpoints": "http://%s:2379",
"nodename_file_optional": true,
"datastore_type": "%s",
"ipam": {
"type": "host-local",
"subnet": "%s"
}
}`, cniVersion, os.Getenv("ETCD_IP"), os.Getenv("DATASTORE_TYPE"), ipPool4)

BeforeEach(func() {
if version.Compare(cniVersion, "0.3.0", "<") {
Skip("Skipping test because of CNI version < 0.3.0")
}
})

It("should allocate IPv4 only", func() {
_, ipPool4CIDR, err := net.ParseCIDR(ipPool4)
Expect(err).NotTo(HaveOccurred())

_, result, _, contAddresses, _, contNs, err := testutils.CreateContainer(netconf, "", testutils.TEST_DEFAULT_NS, "")
Expect(err).ShouldNot(HaveOccurred())

Expect(len(contAddresses)).Should(Equal(1))

for _, ip := range contAddresses {
podIP := ip.IP
Expect(ipPool4CIDR.Contains(podIP)).Should(BeTrue())
}

interfaces := result.Interfaces

Expect(len(interfaces)).Should(Equal(2))
Expect(len(result.IPs)).Should(Equal(1))

for _, ip := range result.IPs {
interfaceIndex := ip.Interface
Expect(interfaceIndex).ShouldNot(BeNil())
iface := interfaces[*interfaceIndex]
Expect(iface).ShouldNot(BeNil())
Expect(iface.Name).Should(Equal("eth0"))
Expect(iface.Mac).ShouldNot(BeEmpty())
Expect(iface.Sandbox).ShouldNot(BeEmpty())
}

// Delete the container.
_, err = testutils.DeleteContainer(netconf, contNs.Path(), "", testutils.TEST_DEFAULT_NS)
Expect(err).ShouldNot(HaveOccurred())
})
})
})

func netlinkDefaultCIDR() *net.IPNet {
Expand Down