Skip to content

Commit 314f483

Browse files
committed
test,e2e: Test pod connectivity over localnet using CUDN CR
Signed-off-by: Or Mergi <[email protected]>
1 parent ef20f88 commit 314f483

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
"time"
9+
10+
. "github.com/onsi/ginkgo/v2"
11+
. "github.com/onsi/gomega"
12+
13+
corev1 "k8s.io/api/core/v1"
14+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/util/rand"
16+
17+
nadapi "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
18+
19+
e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"
20+
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
21+
)
22+
23+
var _ = Describe("Network Segmentation: Localnet", func() {
24+
f := wrappedTestFramework("network-segmentation-localnet")
25+
f.SkipNamespaceCreation = true
26+
27+
It("using ClusterUserDefinedNetwork CR, pods in different namespaces, should communicate over localnet topology", func() {
28+
const (
29+
vlan = 200
30+
testPort = 9000
31+
subnetIPv4 = "192.168.100.0/24"
32+
subnetIPv6 = "2001:dbb::/64"
33+
excludeSubnetIPv4 = "192.168.100.0/29"
34+
excludeSubnetIPv6 = "2001:dbb::/120"
35+
secondaryIfaceName = "eth1"
36+
ovsBrName = "ovsbr-eth1"
37+
)
38+
// use unique names to avoid conflicts with tests running in parallel
39+
nsBlue := uniqueMetaName("blue")
40+
nsRed := uniqueMetaName("red")
41+
cudnName := uniqueMetaName("localnet-test")
42+
physicalNetworkName := uniqueMetaName("localnet1")
43+
44+
By("setup the localnet underlay")
45+
ovsPods := ovsPods(f.ClientSet)
46+
Expect(ovsPods).NotTo(BeEmpty())
47+
DeferCleanup(func() {
48+
By("teardown the localnet underlay")
49+
Expect(teardownUnderlay(ovsPods, ovsBrName)).To(Succeed())
50+
})
51+
c := networkAttachmentConfig{networkAttachmentConfigParams: networkAttachmentConfigParams{networkName: physicalNetworkName, vlanID: vlan}}
52+
Expect(setupUnderlay(ovsPods, ovsBrName, secondaryIfaceName, c)).To(Succeed())
53+
54+
By("create test namespaces")
55+
_, err := f.ClientSet.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: nsRed}}, metav1.CreateOptions{})
56+
Expect(err).NotTo(HaveOccurred())
57+
_, err = f.ClientSet.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: nsBlue}}, metav1.CreateOptions{})
58+
Expect(err).NotTo(HaveOccurred())
59+
DeferCleanup(func() {
60+
By("cleanup test namespaces")
61+
Expect(f.ClientSet.CoreV1().Namespaces().Delete(context.Background(), nsBlue, metav1.DeleteOptions{})).To(Succeed())
62+
Expect(f.ClientSet.CoreV1().Namespaces().Delete(context.Background(), nsRed, metav1.DeleteOptions{})).To(Succeed())
63+
})
64+
65+
By("create CR selecting the test namespaces")
66+
netConf := networkAttachmentConfigParams{
67+
name: cudnName,
68+
physicalNetworkName: physicalNetworkName,
69+
vlanID: vlan,
70+
cidr: correctCIDRFamily(subnetIPv4, subnetIPv6),
71+
excludeCIDRs: selectCIDRs(excludeSubnetIPv4, excludeSubnetIPv6),
72+
}
73+
cudnYAML := newLocalnetCUDNYaml(netConf, nsBlue, nsRed)
74+
cleanup, err := createManifest("", cudnYAML)
75+
Expect(err).NotTo(HaveOccurred())
76+
DeferCleanup(func() {
77+
By("cleanup CUDN CR")
78+
cleanup()
79+
By(fmt.Sprintf("delete pods in namespace %q to unblock CUDN CR & associate NAD deletion", nsBlue))
80+
Expect(f.ClientSet.CoreV1().Pods(nsBlue).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})).To(Succeed())
81+
By(fmt.Sprintf("delete pods in namespace %q to unblock CUDN CR & associate NAD deletion", nsRed))
82+
Expect(f.ClientSet.CoreV1().Pods(nsRed).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})).To(Succeed())
83+
_, err := e2ekubectl.RunKubectl("", "delete", "clusteruserdefinednetwork", cudnName, "--wait", fmt.Sprintf("--timeout=%ds", 120))
84+
Expect(err).NotTo(HaveOccurred())
85+
})
86+
Eventually(clusterUserDefinedNetworkReadyFunc(f.DynamicClient, cudnName)).WithTimeout(5*time.Second).WithPolling(time.Second).
87+
Should(Succeed(), "CUDN CR is not ready")
88+
89+
By("create test pods")
90+
serverPodCfg := podConfiguration{
91+
name: "test-server",
92+
namespace: nsBlue,
93+
attachments: []nadapi.NetworkSelectionElement{{Name: cudnName}},
94+
containerCmd: httpServerContainerCmd(testPort),
95+
}
96+
clientPodCfg := podConfiguration{
97+
name: "test-client",
98+
namespace: nsRed,
99+
attachments: []nadapi.NetworkSelectionElement{{Name: cudnName}},
100+
}
101+
serverPod, err := f.ClientSet.CoreV1().Pods(serverPodCfg.namespace).Create(context.Background(), generatePodSpec(serverPodCfg), metav1.CreateOptions{})
102+
Expect(err).NotTo(HaveOccurred())
103+
clientPod, err := f.ClientSet.CoreV1().Pods(clientPodCfg.namespace).Create(context.Background(), generatePodSpec(clientPodCfg), metav1.CreateOptions{})
104+
Expect(err).NotTo(HaveOccurred())
105+
Expect(e2epod.WaitForPodNameRunningInNamespace(context.Background(), f.ClientSet, clientPod.Name, clientPod.Namespace)).To(Succeed())
106+
Expect(e2epod.WaitForPodNameRunningInNamespace(context.Background(), f.ClientSet, serverPod.Name, serverPod.Namespace)).To(Succeed())
107+
108+
By("assert pods interface's MTU is set with default MTU (1500)")
109+
for _, cfg := range []podConfiguration{serverPodCfg, clientPodCfg} {
110+
mtuRAW, err := e2ekubectl.RunKubectl(cfg.namespace, "exec", cfg.name, "--", "cat", "/sys/class/net/net1/mtu")
111+
Expect(err).NotTo(HaveOccurred())
112+
Expect(mtuRAW).To(ContainSubstring("1500"))
113+
}
114+
115+
By("assert pods IPs not in exclude range")
116+
serverIPs, err := podIPsForAttachment(f.ClientSet, serverPodCfg.namespace, serverPodCfg.name, cudnName)
117+
Expect(err).NotTo(HaveOccurred())
118+
clientIPs, err := podIPsForAttachment(f.ClientSet, clientPodCfg.namespace, clientPodCfg.name, cudnName)
119+
Expect(err).NotTo(HaveOccurred())
120+
podIPs := append(serverIPs, clientIPs...)
121+
for _, excludedRange := range netConf.excludeCIDRs {
122+
for _, podIP := range podIPs {
123+
Expect(inRange(excludedRange, podIP)).To(
124+
MatchError(fmt.Errorf("ip [%s] is NOT in range %s", podIP, excludedRange)))
125+
}
126+
}
127+
128+
for _, serverIP := range serverIPs {
129+
By(fmt.Sprintf("asserting the *client* pod can contact the server pod exposed endpoint [%s:%d]", serverIP, testPort))
130+
Eventually(func() error {
131+
return reachServerPodFromClient(f.ClientSet, serverPodCfg, clientPodCfg, serverIP, testPort)
132+
}).WithTimeout(2 * time.Minute).WithPolling(6 * time.Second).Should(Succeed())
133+
}
134+
})
135+
})
136+
137+
func newLocalnetCUDNYaml(params networkAttachmentConfigParams, selectedNamespaces ...string) string {
138+
selectedNs := strings.Join(selectedNamespaces, ",")
139+
excludeSubnets := strings.Join(params.excludeCIDRs, ",")
140+
return `
141+
apiVersion: k8s.ovn.org/v1
142+
kind: ClusterUserDefinedNetwork
143+
metadata:
144+
name: ` + params.name + `
145+
spec:
146+
namespaceSelector:
147+
matchExpressions:
148+
- key: kubernetes.io/metadata.name
149+
operator: In
150+
values: [ ` + selectedNs + `]
151+
network:
152+
topology: Localnet
153+
localnet:
154+
role: Secondary
155+
physicalNetworkName: ` + params.physicalNetworkName + `
156+
subnets: [` + params.cidr + `]
157+
excludeSubnets: [` + excludeSubnets + `]
158+
vlan:
159+
mode: Access
160+
access: {id: ` + strconv.Itoa(params.vlanID) + `}
161+
`
162+
}
163+
164+
// uniqueMetaName generate unique name from given string that complies with metadata object name.
165+
func uniqueMetaName(originalName string) string {
166+
const randomStringLength = 5
167+
return fmt.Sprintf("%s-%s", originalName, rand.String(randomStringLength))
168+
}

0 commit comments

Comments
 (0)