diff --git a/cmd/whereabouts_test.go b/cmd/whereabouts_test.go index e80f8a170..ba7633cd1 100644 --- a/cmd/whereabouts_test.go +++ b/cmd/whereabouts_test.go @@ -47,7 +47,6 @@ func AllocateAndReleaseAddressesTest(ipVersion string, ipamConf *whereaboutstype ifname string = "eth0" nspath string = "/some/where" cniVersion = "0.3.1" - podName = "dummyPOD" podNamespace = "dummyNS" ) @@ -62,12 +61,13 @@ func AllocateAndReleaseAddressesTest(ipVersion string, ipamConf *whereaboutstype fakek8sclient.NewSimpleClientset(), 0) for i := 0; i < len(expectedAddresses); i++ { + ipamConf.PodName = fmt.Sprintf("pod-%d", i) args := &skel.CmdArgs{ ContainerID: fmt.Sprintf("dummy-%d", i), Netns: nspath, IfName: ifname, StdinData: cniConf, - Args: cniArgs(podNamespace, podName), + Args: cniArgs(podNamespace, ipamConf.PodName), } client := mutateK8sIPAM(args.ContainerID, ipamConf, wbClient) @@ -956,6 +956,8 @@ var _ = Describe("Whereabouts operations", func() { var ipArgs []*skel.CmdArgs // allocate 8 IPs (192.168.1.5 - 192.168.1.12); the entirety of the pool defined above for i := 0; i < 8; i++ { + podName := fmt.Sprintf("pod-%d", i) + ipamConf.PodName = podName args := &skel.CmdArgs{ ContainerID: fmt.Sprintf("dummy-%d", i), Netns: nspath, @@ -982,7 +984,7 @@ var _ = Describe("Whereabouts operations", func() { })) ipArgs = append(ipArgs, args) } - + ipamConf.PodName = podName // assigning more IPs should result in error due to the defined range_start - range_end args := &skel.CmdArgs{ ContainerID: "dummy-failure", @@ -1014,6 +1016,8 @@ var _ = Describe("Whereabouts operations", func() { It("detects IPv4 addresses used in other ranges, to allow for overlapping IP address ranges", func() { const ifname string = "eth0" const nspath string = "/some/where" + const podName1 string = "pod-1" + const podName2 string = "pod-2" // ----------------------------- range 1 @@ -1037,12 +1041,12 @@ var _ = Describe("Whereabouts operations", func() { Netns: nspath, IfName: ifname, StdinData: []byte(conf), - Args: cniArgs(podNamespace, podName), + Args: cniArgs(podNamespace, podName1), } confPath := filepath.Join(tmpDir, "whereabouts.conf") Expect(os.WriteFile(confPath, []byte(conf), 0755)).To(Succeed()) - ipamConf, cniVersion, err := config.LoadIPAMConfig([]byte(conf), cniArgs(podNamespace, podName), confPath) + ipamConf, cniVersion, err := config.LoadIPAMConfig([]byte(conf), cniArgs(podNamespace, podName1), confPath) Expect(err).NotTo(HaveOccurred()) Expect(ipamConf.IPRanges).NotTo(BeEmpty()) wbClient := *kubernetes.NewKubernetesClient( @@ -1090,12 +1094,12 @@ var _ = Describe("Whereabouts operations", func() { Netns: nspath, IfName: ifname, StdinData: []byte(confsecond), - Args: cniArgs(podNamespace, podName), + Args: cniArgs(podNamespace, podName2), } secondConfPath := filepath.Join(tmpDir, "whereabouts.conf") Expect(os.WriteFile(confPath, []byte(confsecond), 0755)).To(Succeed()) - secondIPAMConf, secondCNIVersion, err := config.LoadIPAMConfig([]byte(confsecond), cniArgs(podNamespace, podName), secondConfPath) + secondIPAMConf, secondCNIVersion, err := config.LoadIPAMConfig([]byte(confsecond), cniArgs(podNamespace, podName2), secondConfPath) Expect(err).NotTo(HaveOccurred()) // Allocate the IP @@ -1134,6 +1138,8 @@ var _ = Describe("Whereabouts operations", func() { It("detects IPv6 addresses used in other ranges, to allow for overlapping IP address ranges", func() { const ifname string = "eth0" const nspath string = "/some/where" + const podName1 string = "pod-1" + const podName2 string = "pod-2" // ----------------------------- range 1 @@ -1157,12 +1163,12 @@ var _ = Describe("Whereabouts operations", func() { Netns: nspath, IfName: ifname, StdinData: []byte(conf), - Args: cniArgs(podNamespace, podName), + Args: cniArgs(podNamespace, podName1), } confPath := filepath.Join(tmpDir, "whereabouts.conf") Expect(os.WriteFile(confPath, []byte(conf), 0755)).To(Succeed()) - ipamConf, cniVersion, err := config.LoadIPAMConfig([]byte(conf), cniArgs(podNamespace, podName), confPath) + ipamConf, cniVersion, err := config.LoadIPAMConfig([]byte(conf), cniArgs(podNamespace, podName1), confPath) Expect(err).NotTo(HaveOccurred()) Expect(ipamConf.IPRanges).NotTo(BeEmpty()) wbClient := *kubernetes.NewKubernetesClient( @@ -1210,12 +1216,12 @@ var _ = Describe("Whereabouts operations", func() { Netns: nspath, IfName: ifname, StdinData: []byte(confsecond), - Args: cniArgs(podNamespace, podName), + Args: cniArgs(podNamespace, podName2), } secondConfPath := filepath.Join(tmpDir, "whereabouts.conf") Expect(os.WriteFile(confPath, []byte(confsecond), 0755)).To(Succeed()) - secondIPAMConf, secondCNIVersion, err := config.LoadIPAMConfig([]byte(confsecond), cniArgs(podNamespace, podName), secondConfPath) + secondIPAMConf, secondCNIVersion, err := config.LoadIPAMConfig([]byte(confsecond), cniArgs(podNamespace, podName2), secondConfPath) Expect(err).NotTo(HaveOccurred()) // Allocate the IP diff --git a/pkg/allocate/allocate.go b/pkg/allocate/allocate.go index 88dead47f..ee7c0dedd 100644 --- a/pkg/allocate/allocate.go +++ b/pkg/allocate/allocate.go @@ -37,9 +37,9 @@ func AssignIP(ipamConf types.RangeConfiguration, reservelist []types.IPReservati } // DeallocateIP assigns an IP using a range and a reserve list. -func DeallocateIP(reservelist []types.IPReservation, containerID string) ([]types.IPReservation, net.IP, error) { +func DeallocateIP(reservelist []types.IPReservation, podRef string) ([]types.IPReservation, net.IP, error) { - updatedreservelist, hadip, err := IterateForDeallocation(reservelist, containerID, getMatchingIPReservationIndex) + updatedreservelist, hadip, err := IterateForDeallocation(reservelist, podRef, getMatchingIPReservationIndex) if err != nil { return nil, nil, err } @@ -52,13 +52,13 @@ func DeallocateIP(reservelist []types.IPReservation, containerID string) ([]type // IterateForDeallocation iterates overs currently reserved IPs and the deallocates given the container id. func IterateForDeallocation( reservelist []types.IPReservation, - containerID string, + podRef string, matchingFunction func(reservation []types.IPReservation, id string) int) ([]types.IPReservation, net.IP, error) { - foundidx := matchingFunction(reservelist, containerID) + foundidx := matchingFunction(reservelist, podRef) // Check if it's a valid index if foundidx < 0 { - return reservelist, nil, fmt.Errorf("did not find reserved IP for container %v", containerID) + return reservelist, nil, fmt.Errorf("did not find reserved IP for container %v", podRef) } returnip := reservelist[foundidx].IP @@ -70,7 +70,7 @@ func IterateForDeallocation( func getMatchingIPReservationIndex(reservelist []types.IPReservation, id string) int { foundidx := -1 for idx, v := range reservelist { - if v.ContainerID == id { + if v.PodRef == id { foundidx = idx break } @@ -102,6 +102,15 @@ func IterateForAssignment(ipnet net.IPNet, rangeStart net.IP, rangeEnd net.IP, r // Build reserved map. reserved := make(map[string]bool) for _, r := range reserveList { + if r.PodRef == podRef { + // If this IP has been reserved for this pod, return it. + if r.ContainerID != containerID { + // update the containerID if it has changed + r.ContainerID = containerID + } + logging.Debugf("Returning reserved IP: |%v|", r.IP.String()+" "+podRef) + return r.IP, reserveList, nil + } reserved[r.IP.String()] = true } @@ -118,7 +127,6 @@ func IterateForAssignment(ipnet net.IPNet, rangeStart net.IP, rangeEnd net.IP, r // Iterate over every IP address in the range, accounting for reserved IPs and exclude ranges. Make sure that ip is // within ipnet, and make sure that ip is smaller than lastIP. for ip := firstIP; ipnet.Contains(ip) && iphelpers.CompareIPs(ip, lastIP) <= 0; ip = iphelpers.IncIP(ip) { - // If already reserved, skip it. if reserved[ip.String()] { continue } @@ -129,7 +137,7 @@ func IterateForAssignment(ipnet net.IPNet, rangeStart net.IP, rangeEnd net.IP, r continue } // Assign and reserve the IP and return. - logging.Debugf("Reserving IP: |%v|", ip.String()+" "+containerID) + logging.Debugf("Reserving IP: |%v|", ip.String()+" "+podRef) reserveList = append(reserveList, types.IPReservation{IP: ip, ContainerID: containerID, PodRef: podRef}) return ip, reserveList, nil } diff --git a/pkg/allocate/allocate_test.go b/pkg/allocate/allocate_test.go index d88ed9696..04196245e 100644 --- a/pkg/allocate/allocate_test.go +++ b/pkg/allocate/allocate_test.go @@ -27,7 +27,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation var exrange []string - newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("192.168.1.1")) @@ -43,7 +43,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation var exrange []string - newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("caa5::1")) @@ -59,7 +59,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation var exrange []string - newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("::1")) @@ -77,7 +77,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation var exrange []string - newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("fd::1")) @@ -93,7 +93,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation var exrange []string - newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("100::2:1")) }) @@ -108,7 +108,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"192.168.0.0/30"} - newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(fmt.Sprint(newip)).To(Equal("192.168.0.4")) }) @@ -122,7 +122,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"192.168.0.1"} - newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("192.168.0.2")) }) @@ -136,7 +136,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"192.168.0.1/123"} - _, _, err = IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + _, _, err = IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).To(MatchError(HavePrefix("could not parse exclude range"))) }) @@ -150,7 +150,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"100::2:1/126"} - newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(fmt.Sprint(newip)).To(Equal("100::2:4")) }) @@ -164,7 +164,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"100::2:1"} - newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(fmt.Sprint(newip)).To(Equal("100::2:2")) }) @@ -177,7 +177,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"100::2::1"} - _, _, err = IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + _, _, err = IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).To(MatchError(HavePrefix("could not parse exclude range"))) }) @@ -191,7 +191,7 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"2001:db8::0/32"} - newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(fmt.Sprint(newip)).To(Equal("2001:db9::")) }) @@ -206,11 +206,11 @@ var _ = Describe("Allocation operations", func() { var ipres []types.IPReservation exrange := []string{"192.168.0.0/30", "192.168.0.6/31", "192.168.0.8/31", "192.168.0.4/30"} - newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, _ := IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(fmt.Sprint(newip)).To(Equal("192.168.0.10")) exrange = []string{"192.168.0.0/30", "192.168.0.14/31", "192.168.0.4/30", "192.168.0.6/31", "192.168.0.8/31"} - newip, _, _ = IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "") + newip, _, _ = IterateForAssignment(*ipnet, calculatedrangestart, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(fmt.Sprint(newip)).To(Equal("192.168.0.10")) }) @@ -222,19 +222,19 @@ var _ = Describe("Allocation operations", func() { ipres := []types.IPReservation{ { IP: net.ParseIP("192.168.0.4"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.5"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.6"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, } exrange := []string{"192.168.0.0/30"} - _, _, err = IterateForAssignment(*ipnet, firstip, nil, ipres, exrange, "0xdeadbeef", "") + _, _, err = IterateForAssignment(*ipnet, firstip, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).To(MatchError(HavePrefix("Could not allocate IP in range"))) }) @@ -246,23 +246,47 @@ var _ = Describe("Allocation operations", func() { ipres := []types.IPReservation{ { IP: net.ParseIP("192.168.0.1"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.2"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.3"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, } exrange := []string{"192.168.0.4/30"} - _, _, err = IterateForAssignment(*ipnet, firstip, nil, ipres, exrange, "0xdeadbeef", "") + _, _, err = IterateForAssignment(*ipnet, firstip, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).To(MatchError(HavePrefix("Could not allocate IP in range"))) }) + It("can IterateForAssignment on an IPv4 address that has been allocated to the same pod", func() { + + firstip, ipnet, err := net.ParseCIDR("192.168.0.0/29") + Expect(err).NotTo(HaveOccurred()) + ip := net.ParseIP("192.168.0.2") + + ipres := []types.IPReservation{ + { + IP: ip, + ContainerID: "0xdeadbeff", + PodRef: "default/pod2:fakeUID", + }, + { + IP: net.ParseIP("192.168.0.1"), + ContainerID: "0xdeadbfff", + PodRef: "default/pod1:fakeUID", + }, + } + exrange := []string{"192.168.0.4/30"} + assignedIP, _, err := IterateForAssignment(*ipnet, firstip, nil, ipres, exrange, "0xdeadbeef", ipres[0].PodRef) + Expect(err).NotTo(HaveOccurred()) + Expect(assignedIP.String()).To(Equal(ip.String())) + }) + It("can IterateForAssignment on an IPv6 address excluding a range and respect the requested range", func() { firstip, ipnet, err := net.ParseCIDR("100::2:1/125") @@ -271,20 +295,20 @@ var _ = Describe("Allocation operations", func() { ipres := []types.IPReservation{ { IP: net.ParseIP("100::2:1"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("100::2:2"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("100::2:3"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, } exrange := []string{"100::2:4/126"} - _, _, err = IterateForAssignment(*ipnet, firstip, nil, ipres, exrange, "0xdeadbeef", "") + _, _, err = IterateForAssignment(*ipnet, firstip, nil, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).To(MatchError(HavePrefix("Could not allocate IP in range"))) }) @@ -297,7 +321,7 @@ var _ = Describe("Allocation operations", func() { _, ipnet, err := net.ParseCIDR("192.168.0.0/29") Expect(err).NotTo(HaveOccurred()) rangeStart := net.ParseIP("192.168.0.0") // Network address, out of bounds. - newip, _, err := IterateForAssignment(*ipnet, rangeStart, nil, nil, nil, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, rangeStart, nil, nil, nil, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("192.168.0.1")) }) @@ -309,7 +333,7 @@ var _ = Describe("Allocation operations", func() { Expect(err).NotTo(HaveOccurred()) rangeStart := net.ParseIP("192.168.0.0") // Network address, out of bounds. rangeEnd := net.ParseIP("192.168.0.8") // Broadcast address, out of bounds. - newip, _, err := IterateForAssignment(*ipnet, rangeStart, rangeEnd, nil, nil, "0xdeadbeef", "") + newip, _, err := IterateForAssignment(*ipnet, rangeStart, rangeEnd, nil, nil, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).NotTo(HaveOccurred()) Expect(fmt.Sprint(newip)).To(Equal("192.168.0.1")) }) @@ -325,19 +349,19 @@ var _ = Describe("Allocation operations", func() { ipres := []types.IPReservation{ { IP: net.ParseIP("192.168.0.1"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.2"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.3"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, } exrange := []string{"192.168.0.4/30"} - _, _, err = IterateForAssignment(*ipnet, startip, lastip, ipres, exrange, "0xdeadbeef", "") + _, _, err = IterateForAssignment(*ipnet, startip, lastip, ipres, exrange, "0xdeadbeef", "default/newPod:fakeUID") Expect(err).To(MatchError(HavePrefix("Could not allocate IP in range"))) }) @@ -367,15 +391,15 @@ var _ = Describe("Allocation operations", func() { ipres := []types.IPReservation{ { IP: net.ParseIP("192.168.0.1"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.2"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.3"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, } @@ -396,15 +420,15 @@ var _ = Describe("Allocation operations", func() { ipres := []types.IPReservation{ { IP: net.ParseIP("192.168.0.1"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.2"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, { IP: net.ParseIP("192.168.0.5"), - PodRef: "default/pod1", + PodRef: "default/pod1:fakeUID", }, } @@ -416,3 +440,26 @@ var _ = Describe("Allocation operations", func() { }) }) }) + +var _ = Describe("Deallocation operations", func() { + It("can IterateForDeallocation on an IPv4 address", func() { + + ip := net.ParseIP("192.168.0.1") + podRef := "default/pod1:fakeUID" + reservelist := []types.IPReservation{ + { + IP: ip, + PodRef: podRef, + }, + { + IP: net.ParseIP("192.168.0.2"), + PodRef: "default/pod2:fakeUID", + }, + } + + _, deallocatedIP, err := IterateForDeallocation(reservelist, podRef, getMatchingIPReservationIndex) + Expect(err).NotTo(HaveOccurred()) + Expect(deallocatedIP.String()).To(Equal(ip.String())) + + }) +}) diff --git a/pkg/storage/kubernetes/ipam.go b/pkg/storage/kubernetes/ipam.go index ae5c358e1..f91ff3bb8 100644 --- a/pkg/storage/kubernetes/ipam.go +++ b/pkg/storage/kubernetes/ipam.go @@ -200,13 +200,13 @@ func (i *KubernetesIPAM) GetOverlappingRangeStore() (storage.OverlappingRangeSto // IsAllocatedInOverlappingRange checks for IP addresses to see if they're allocated cluster wide, for overlapping // ranges. func (c *KubernetesOverlappingRangeStore) IsAllocatedInOverlappingRange(ctx context.Context, ip net.IP, - networkName string) (bool, error) { + networkName string, podRef string) (bool, error) { normalizedIP := normalizeIP(ip, networkName) logging.Debugf("OverlappingRangewide allocation check; normalized IP: %q, IP: %q, networkName: %q", normalizedIP, ip, networkName) - _, err := c.client.WhereaboutsV1alpha1().OverlappingRangeIPReservations(c.namespace).Get(ctx, normalizedIP, metav1.GetOptions{}) + reservedIP, err := c.client.WhereaboutsV1alpha1().OverlappingRangeIPReservations(c.namespace).Get(ctx, normalizedIP, metav1.GetOptions{}) if err != nil && errors.IsNotFound(err) { // cluster ip reservation does not exist, this appears to be good news. // logging.Debugf("IP %v is not reserved cluster wide, allowing.", ip) @@ -215,6 +215,10 @@ func (c *KubernetesOverlappingRangeStore) IsAllocatedInOverlappingRange(ctx cont logging.Errorf("k8s get OverlappingRangeIPReservation error: %s", err) return false, fmt.Errorf("k8s get OverlappingRangeIPReservation error: %s", err) } + if reservedIP.Spec.PodRef == podRef { + logging.Debugf("IP %v is reserved for pod %s, allowing.", ip, podRef) + return false, nil + } logging.Debugf("Normalized IP is reserved; normalized IP: %q, IP: %q, networkName: %q", normalizedIP, ip, networkName) @@ -244,6 +248,20 @@ func (c *KubernetesOverlappingRangeStore) UpdateOverlappingRangeAllocation(ctx c _, err = c.client.WhereaboutsV1alpha1().OverlappingRangeIPReservations(c.namespace).Create( ctx, clusteripres, metav1.CreateOptions{}) + if errors.IsAlreadyExists(err) { + var res *whereaboutsv1alpha1.OverlappingRangeIPReservation + res, err = c.client.WhereaboutsV1alpha1().OverlappingRangeIPReservations(c.namespace).Get( + ctx, normalizedIP, metav1.GetOptions{}) + if err != nil { + return err + } + res.Spec = clusteripres.Spec + _, err = c.client.WhereaboutsV1alpha1().OverlappingRangeIPReservations(c.namespace).Update( + ctx, res, metav1.UpdateOptions{}) + if err != nil { + return err + } + } case whereaboutstypes.Deallocate: verb = "deallocate" @@ -525,7 +543,7 @@ func IPManagementKubernetesUpdate(ctx context.Context, mode int, ipam *Kubernete // And we try again. if ipamConf.OverlappingRanges { isAllocated, err := overlappingrangestore.IsAllocatedInOverlappingRange(requestCtx, newip.IP, - ipamConf.NetworkName) + ipamConf.NetworkName, podRef) if err != nil { logging.Errorf("Error checking overlappingrange allocation: %v", err) return newips, err @@ -542,7 +560,7 @@ func IPManagementKubernetesUpdate(ctx context.Context, mode int, ipam *Kubernete } case whereaboutstypes.Deallocate: - updatedreservelist, ipforoverlappingrangeupdate, err = allocate.DeallocateIP(reservelist, containerID) + updatedreservelist, ipforoverlappingrangeupdate, err = allocate.DeallocateIP(reservelist, podRef) if err != nil { logging.Errorf("Error deallocating IP: %v", err) return newips, err diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 52660eee2..2d679a37c 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -33,7 +33,7 @@ type Store interface { // OverlappingRangeStore is an interface for wrapping overlappingrange storage options type OverlappingRangeStore interface { - IsAllocatedInOverlappingRange(ctx context.Context, ip net.IP, networkName string) (bool, error) + IsAllocatedInOverlappingRange(ctx context.Context, ip net.IP, networkName string, podRef string) (bool, error) UpdateOverlappingRangeAllocation(ctx context.Context, mode int, ip net.IP, containerID string, podRef, networkName string) error }