Skip to content

Commit 1c611d4

Browse files
kkumardamyan
authored andcommitted
Add test for IPAM plugin
1 parent 891f940 commit 1c611d4

File tree

3 files changed

+413
-0
lines changed

3 files changed

+413
-0
lines changed

internal/kubernetes/client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ func SetClient(client *client.Client) {
4444
func GetClient() client.Client { return kubeClient }
4545

4646
func GetConfig() *rest.Config { return cfg }
47+
48+
func SetConfig(c *rest.Config) {
49+
cfg = c
50+
}

plugins/ipam/plugin_test.go

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
2+
// SPDX-License-Identifier: MIT
3+
4+
package ipam
5+
6+
import (
7+
"net"
8+
"os"
9+
"strings"
10+
11+
"github.com/insomniacslk/dhcp/dhcpv6"
12+
"github.com/ironcore-dev/fedhcp/internal/api"
13+
ipamv1alpha1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1"
14+
"github.com/mdlayher/netx/eui64"
15+
. "github.com/onsi/ginkgo/v2"
16+
. "github.com/onsi/gomega"
17+
"gopkg.in/yaml.v2"
18+
corev1 "k8s.io/api/core/v1"
19+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20+
. "sigs.k8s.io/controller-runtime/pkg/envtest/komega"
21+
)
22+
23+
var _ = Describe("IPAM Plugin", func() {
24+
var (
25+
testConfigPath string
26+
err error
27+
linkLocalIPV6Addr net.IP
28+
ipv6 *ipamv1alpha1.IP
29+
)
30+
31+
ns := SetupTest()
32+
33+
BeforeEach(func(ctx SpecContext) {
34+
// Setup temporary test config file
35+
testConfigPath = "test_config.yaml"
36+
config := &api.IPAMConfig{
37+
Namespace: ns.Name,
38+
Subnets: []string{"ipam-subnet1", "ipam-subnet2"},
39+
}
40+
configData, err := yaml.Marshal(config)
41+
Expect(err).NotTo(HaveOccurred())
42+
err = os.WriteFile(testConfigPath, configData, 0644)
43+
Expect(err).NotTo(HaveOccurred())
44+
45+
mac := machineWithIPAddressMACAddress
46+
m, err := net.ParseMAC(mac)
47+
Expect(err).NotTo(HaveOccurred())
48+
i := net.ParseIP(linkLocalIPV6Prefix)
49+
linkLocalIPV6Addr, err = eui64.ParseMAC(i, m)
50+
Expect(err).NotTo(HaveOccurred())
51+
52+
sanitizedMAC := strings.Replace(mac, ":", "", -1)
53+
ipv6Addr, err := ipamv1alpha1.IPAddrFromString(linkLocalIPV6Addr.String())
54+
Expect(err).NotTo(HaveOccurred())
55+
ipv6 = &ipamv1alpha1.IP{
56+
ObjectMeta: metav1.ObjectMeta{
57+
Namespace: ns.Name,
58+
GenerateName: "test-",
59+
Labels: map[string]string{
60+
"mac": sanitizedMAC,
61+
},
62+
},
63+
Spec: ipamv1alpha1.IPSpec{
64+
Subnet: corev1.LocalObjectReference{
65+
Name: "foo",
66+
},
67+
IP: ipv6Addr,
68+
},
69+
}
70+
Expect(k8sClientTest.Create(ctx, ipv6)).To(Succeed())
71+
DeferCleanup(k8sClientTest.Delete, ipv6)
72+
73+
Eventually(UpdateStatus(ipv6, func() {
74+
ipv6.Status.Reserved = ipv6Addr
75+
})).Should(Succeed())
76+
})
77+
78+
AfterEach(func() {
79+
// Cleanup temporary config file
80+
err = os.Remove(testConfigPath)
81+
Expect(err).NotTo(HaveOccurred())
82+
})
83+
84+
Describe("Configuration Loading", func() {
85+
It("should successfully load a valid configuration file", func() {
86+
config, err := loadConfig(testConfigPath)
87+
Expect(err).NotTo(HaveOccurred())
88+
Expect(config).NotTo(BeNil())
89+
Expect(config.Subnets[len(config.Subnets)-1]).To(Equal("ipam-subnet2"))
90+
})
91+
92+
It("should return an error if the configuration file is missing", func() {
93+
_, err := loadConfig("nonexistent.yaml")
94+
Expect(err).To(HaveOccurred())
95+
})
96+
97+
It("should return an error if the configuration file is invalid", func() {
98+
err = os.WriteFile(testConfigPath, []byte("Invalid YAML"), 0644)
99+
Expect(err).NotTo(HaveOccurred())
100+
_, err = loadConfig(testConfigPath)
101+
Expect(err).To(HaveOccurred())
102+
})
103+
})
104+
105+
Describe("Plugin Setup6", func() {
106+
It("should successfully initialize the plugin with a valid config", func() {
107+
handler, err := setup6(testConfigPath)
108+
Expect(err).NotTo(HaveOccurred())
109+
Expect(handler).NotTo(BeNil())
110+
})
111+
112+
It("should not return an error for empty ipam config", func() {
113+
invalidConfig := &api.IPAMConfig{}
114+
invalidConfigData, err := yaml.Marshal(invalidConfig)
115+
Expect(err).NotTo(HaveOccurred())
116+
err = os.WriteFile(testConfigPath, invalidConfigData, 0644)
117+
Expect(err).NotTo(HaveOccurred())
118+
119+
_, err = setup6(testConfigPath)
120+
Expect(err).NotTo(HaveOccurred())
121+
})
122+
123+
It("Setup6 should return error if less arguments are provided", func() {
124+
_, err := setup6()
125+
Expect(err).To(HaveOccurred())
126+
})
127+
128+
It("Setup6 should return error if more arguments are provided", func() {
129+
_, err := setup6("foo", "bar")
130+
Expect(err).To(HaveOccurred())
131+
})
132+
133+
It("Setup6 should return error if config file does not exist", func() {
134+
_, err := setup6("does-not-exist.yaml")
135+
Expect(err).To(HaveOccurred())
136+
})
137+
})
138+
139+
Describe("Plugin handler6", func() {
140+
It("Should return and break plugin chain, if getting an IPv6 DHCP request directly (no relay)", func(ctx SpecContext) {
141+
req, _ := dhcpv6.NewMessage()
142+
req.MessageType = dhcpv6.MessageTypeRequest
143+
144+
stub, _ := dhcpv6.NewMessage()
145+
stub.MessageType = dhcpv6.MessageTypeReply
146+
resp, breakChain := handler6(req, stub)
147+
148+
Eventually(resp).Should(BeNil())
149+
Eventually(breakChain).Should(BeTrue())
150+
})
151+
152+
It("should successfully handle request", func() {
153+
// //sanitizedMAC := strings.Replace(mac, ":", "", -1)
154+
// ipv6Addr, _ := ipamv1alpha1.IPAddrFromString(linkLocalIPV6Addr.String())
155+
156+
// ipv6 := &ipamv1alpha1.IP{
157+
// ObjectMeta: metav1.ObjectMeta{
158+
// Namespace: ns.Name,
159+
// GenerateName: "test-",
160+
// },
161+
// Spec: ipamv1alpha1.IPSpec{
162+
// Subnet: corev1.LocalObjectReference{
163+
// Name: "foo",
164+
// },
165+
// IP: ipv6Addr,
166+
// },
167+
// }
168+
169+
// err3 := k8sClientTest.Create(context.TODO(), ipv6)
170+
// Expect(err3).To(BeNil())
171+
172+
// createdSubnet := &ipamv1alpha1.Subnet{
173+
// ObjectMeta: metav1.ObjectMeta{
174+
// Name: "foo",
175+
// Namespace: ns.Name,
176+
// },
177+
// }
178+
179+
// err5 := k8sClientTest.Create(context.TODO(), createdSubnet)
180+
// Expect(err5).To(BeNil())
181+
182+
// subnet := &ipamv1alpha1.Subnet{
183+
// ObjectMeta: metav1.ObjectMeta{
184+
// Name: "foo",
185+
// Namespace: ns.Name,
186+
// },
187+
// }
188+
// existingSubnet := subnet.DeepCopy()
189+
// err4 := k8sClientTest.Get(context.TODO(), client.ObjectKeyFromObject(subnet), existingSubnet)
190+
// Expect(err4).To(BeNil())
191+
192+
//Expect(k8sClientTest.Create(context.TODO(), ipv6)).To(Succeed())
193+
// clientset, err2 := ipam.NewForConfig(cfg)
194+
// Expect(err2).NotTo(HaveOccurred())
195+
// createdSubnet, err1 := clientset.IpamV1alpha1().Subnets(ns.Name).Create(context.TODO(), subnet, v1.CreateOptions{})
196+
// Expect(err1).NotTo(HaveOccurred())
197+
// Expect(createdSubnet).NotTo(BeNil())
198+
199+
//fmt.Printf("createdSubnet: %v", createdSubnet)
200+
201+
// mac, _ := net.ParseMAC(machineWithIPAddressMACAddress)
202+
// ip := net.ParseIP(linkLocalIPV6Prefix)
203+
// linkLocalIPV6Addr, _ := eui64.ParseMAC(ip, mac)
204+
205+
req, _ := dhcpv6.NewMessage()
206+
req.MessageType = dhcpv6.MessageTypeRequest
207+
relayedRequest, _ := dhcpv6.EncapsulateRelay(req, dhcpv6.MessageTypeRelayForward, net.IPv6loopback, linkLocalIPV6Addr)
208+
209+
stub, err := dhcpv6.NewMessage()
210+
Expect(err).To(BeNil())
211+
resp, stop := handler6(relayedRequest, stub)
212+
Expect(stop).To(BeFalse())
213+
Expect(resp).NotTo(BeNil())
214+
})
215+
})
216+
217+
Describe("K8s Client tests", func() {
218+
It("should successfully match the subnet", func() {
219+
k8sClient, err := NewK8sClient(ns.Name, []string{"foo"})
220+
Expect(err).NotTo(HaveOccurred())
221+
Expect(k8sClient).NotTo(BeNil())
222+
223+
subnet, err := k8sClient.getMatchingSubnet("foo", linkLocalIPV6Addr)
224+
Expect(err).NotTo(HaveOccurred())
225+
Expect(subnet).To(BeNil())
226+
})
227+
228+
// It("should successfully match the subnet", func() {
229+
// err := k8sClient.doCreateIpamIP(ipv6)
230+
// Expect(err).NotTo(HaveOccurred())
231+
// })
232+
})
233+
234+
Describe("Common tests", func() {
235+
It("return true checks the ip in CIDR", func() {
236+
checkIP := checkIPv6InCIDR(linkLocalIPV6Addr, "fe80::/64")
237+
Expect(checkIP).To(BeTrue())
238+
})
239+
240+
It("return false, if invalid CIDR", func() {
241+
checkIP := checkIPv6InCIDR(linkLocalIPV6Addr, "fe80::")
242+
Expect(checkIP).To(BeFalse())
243+
})
244+
245+
It("return formrted string, if valid ipv6", func() {
246+
longIP := getLongIPv6(net.ParseIP("fe80::"))
247+
Expect(longIP).To(Equal("fe80-0000-0000-0000-0000-0000-0000-0000"))
248+
})
249+
250+
It("return panic, if invalid ipv6", func() {
251+
Expect(func() {
252+
getLongIPv6(net.ParseIP("fe80::bcd::ccd::bcd"))
253+
}).To(Panic())
254+
})
255+
256+
It("return pretty fromated string for ipamv1alpha1.IPSpec", func() {
257+
ipv6Addr, err := ipamv1alpha1.IPAddrFromString(linkLocalIPV6Addr.String())
258+
Expect(err).NotTo(HaveOccurred())
259+
ipv6 := &ipamv1alpha1.IP{
260+
Spec: ipamv1alpha1.IPSpec{
261+
Subnet: corev1.LocalObjectReference{
262+
Name: "foo",
263+
},
264+
IP: ipv6Addr,
265+
},
266+
}
267+
format := prettyFormat(ipv6.Spec)
268+
Expect(format).ShouldNot(BeEmpty())
269+
})
270+
})
271+
})

0 commit comments

Comments
 (0)