@@ -701,6 +701,176 @@ var _ = Describe("Pod controller integration test suite", func() {
701
701
Expect (k8sClient .Delete (context .Background (), pod , client .GracePeriodSeconds (0 ))).NotTo (HaveOccurred ())
702
702
})
703
703
704
+ It ("Check ip reserved only after pod terminated" , func () {
705
+ By ("create a stateful pod requiring IPv4 address" )
706
+ var ipInstanceName string
707
+ pod := simplePodRender (podName , node1Name )
708
+ pod .OwnerReferences = []metav1.OwnerReference {ownerReference }
709
+ Expect (k8sClient .Create (context .Background (), pod )).Should (Succeed ())
710
+
711
+ By ("check the first allocated IPv4 address" )
712
+ Eventually (
713
+ func (g Gomega ) {
714
+ ipInstances , err := utils .ListAllocatedIPInstancesOfPod (context .Background (), k8sClient , pod )
715
+ g .Expect (err ).NotTo (HaveOccurred ())
716
+ g .Expect (ipInstances ).To (HaveLen (1 ))
717
+
718
+ ipInstance := ipInstances [0 ]
719
+ ipInstanceName = ipInstance .Name
720
+ g .Expect (ipInstance .Spec .Address .Version ).To (Equal (networkingv1 .IPv4 ))
721
+ g .Expect (ipInstance .Spec .Binding .PodUID ).To (Equal (pod .UID ))
722
+ g .Expect (ipInstance .Spec .Binding .PodName ).To (Equal (pod .Name ))
723
+ g .Expect (ipInstance .Spec .Binding .NodeName ).To (Equal (node1Name ))
724
+ g .Expect (ipInstance .Spec .Binding .ReferredObject ).To (Equal (networkingv1.ObjectMeta {
725
+ Kind : ownerReference .Kind ,
726
+ Name : ownerReference .Name ,
727
+ UID : ownerReference .UID ,
728
+ }))
729
+
730
+ g .Expect (ipInstance .Spec .Binding .Stateful ).NotTo (BeNil ())
731
+ g .Expect (ipInstance .Spec .Binding .Stateful .Index ).NotTo (BeNil ())
732
+
733
+ idx := * ipInstance .Spec .Binding .Stateful .Index
734
+ g .Expect (pod .Name ).To (Equal (fmt .Sprintf ("pod-%d" , idx )))
735
+
736
+ g .Expect (ipInstance .Spec .Network ).To (Equal (underlayNetworkName ))
737
+ g .Expect (ipInstance .Spec .Subnet ).To (BeElementOf (underlaySubnetName ))
738
+ }).
739
+ WithTimeout (30 * time .Second ).
740
+ WithPolling (time .Second ).
741
+ Should (Succeed ())
742
+
743
+ By ("update to make sure pod not terminated" )
744
+ patch := client .MergeFrom (pod .DeepCopy ())
745
+ pod .Status .ContainerStatuses = []corev1.ContainerStatus {
746
+ {
747
+ Name : "test" ,
748
+ State : corev1.ContainerState {
749
+ Terminated : nil ,
750
+ },
751
+ },
752
+ }
753
+ Expect (k8sClient .Status ().Patch (context .Background (), pod , patch )).NotTo (HaveOccurred ())
754
+
755
+ By ("try to delete stateful pod into terminating state" )
756
+ Expect (k8sClient .Delete (context .Background (), pod , client .GracePeriodSeconds (0 ))).NotTo (HaveOccurred ())
757
+
758
+ By ("check allocated IPv4 address still not reserved after 30s" )
759
+ Consistently (
760
+ func (g Gomega ) {
761
+ ipInstances , err := utils .ListAllocatedIPInstancesOfPod (context .Background (), k8sClient , pod )
762
+ g .Expect (err ).NotTo (HaveOccurred ())
763
+ g .Expect (ipInstances ).To (HaveLen (1 ))
764
+
765
+ ipInstance := ipInstances [0 ]
766
+ g .Expect (ipInstance .Spec .Binding .NodeName ).NotTo (BeEmpty ())
767
+
768
+ }).
769
+ WithTimeout (30 * time .Second ).
770
+ WithPolling (5 * time .Second ).
771
+ Should (Succeed ())
772
+
773
+ By ("update to make sure pod terminated" )
774
+ patch = client .MergeFrom (pod .DeepCopy ())
775
+ pod .Status .ContainerStatuses = []corev1.ContainerStatus {
776
+ {
777
+ Name : "test" ,
778
+ State : corev1.ContainerState {
779
+ Terminated : & corev1.ContainerStateTerminated {},
780
+ },
781
+ },
782
+ }
783
+ Expect (k8sClient .Status ().Patch (context .Background (), pod , patch )).NotTo (HaveOccurred ())
784
+
785
+ By ("check the allocated IPv4 address is reserved" )
786
+ Eventually (
787
+ func (g Gomega ) {
788
+ ipInstances , err := utils .ListAllocatedIPInstancesOfPod (context .Background (), k8sClient , pod )
789
+ g .Expect (err ).NotTo (HaveOccurred ())
790
+ g .Expect (ipInstances ).To (HaveLen (1 ))
791
+
792
+ ipInstance := ipInstances [0 ]
793
+ g .Expect (ipInstance .Name ).To (Equal (ipInstanceName ))
794
+ g .Expect (ipInstance .Spec .Address .Version ).To (Equal (networkingv1 .IPv4 ))
795
+ g .Expect (ipInstance .Spec .Binding .PodUID ).To (BeEmpty ())
796
+ g .Expect (ipInstance .Spec .Binding .PodName ).To (Equal (pod .Name ))
797
+ g .Expect (ipInstance .Spec .Binding .NodeName ).To (BeEmpty ())
798
+ g .Expect (ipInstance .Spec .Binding .ReferredObject ).To (Equal (networkingv1.ObjectMeta {
799
+ Kind : ownerReference .Kind ,
800
+ Name : ownerReference .Name ,
801
+ UID : ownerReference .UID ,
802
+ }))
803
+
804
+ g .Expect (ipInstance .Spec .Binding .Stateful ).NotTo (BeNil ())
805
+ g .Expect (ipInstance .Spec .Binding .Stateful .Index ).NotTo (BeNil ())
806
+
807
+ idx := * ipInstance .Spec .Binding .Stateful .Index
808
+ g .Expect (pod .Name ).To (Equal (fmt .Sprintf ("pod-%d" , idx )))
809
+
810
+ g .Expect (ipInstance .Spec .Network ).To (Equal (underlayNetworkName ))
811
+ g .Expect (ipInstance .Spec .Subnet ).To (BeElementOf (underlaySubnetName ))
812
+ }).
813
+ WithTimeout (30 * time .Second ).
814
+ WithPolling (time .Second ).
815
+ Should (Succeed ())
816
+
817
+ By ("make sure pod deleted" )
818
+ Eventually (
819
+ func (g Gomega ) {
820
+ err := k8sClient .Get (context .Background (),
821
+ types.NamespacedName {
822
+ Namespace : pod .Namespace ,
823
+ Name : podName ,
824
+ },
825
+ & corev1.Pod {})
826
+ g .Expect (err ).NotTo (BeNil ())
827
+ g .Expect (errors .IsNotFound (err )).To (BeTrue ())
828
+ }).
829
+ WithTimeout (30 * time .Second ).
830
+ WithPolling (time .Second ).
831
+ Should (Succeed ())
832
+
833
+ By ("recreate the stateful pod" )
834
+ pod = simplePodRender (podName , node1Name )
835
+ pod .OwnerReferences = []metav1.OwnerReference {ownerReference }
836
+ Expect (k8sClient .Create (context .Background (), pod )).NotTo (HaveOccurred ())
837
+
838
+ By ("check the allocated IPv4 address is retained and reused" )
839
+ Eventually (
840
+ func (g Gomega ) {
841
+ ipInstances , err := utils .ListAllocatedIPInstancesOfPod (context .Background (), k8sClient , pod )
842
+ g .Expect (err ).NotTo (HaveOccurred ())
843
+ g .Expect (ipInstances ).To (HaveLen (1 ))
844
+
845
+ ipInstance := ipInstances [0 ]
846
+ g .Expect (ipInstance .Name ).To (Equal (ipInstanceName ))
847
+ g .Expect (ipInstance .Spec .Address .Version ).To (Equal (networkingv1 .IPv4 ))
848
+ g .Expect (ipInstance .Spec .Binding .PodUID ).To (Equal (pod .UID ))
849
+ g .Expect (ipInstance .Spec .Binding .PodName ).To (Equal (pod .Name ))
850
+ g .Expect (ipInstance .Spec .Binding .NodeName ).To (Equal (node1Name ))
851
+ g .Expect (ipInstance .Spec .Binding .ReferredObject ).To (Equal (networkingv1.ObjectMeta {
852
+ Kind : ownerReference .Kind ,
853
+ Name : ownerReference .Name ,
854
+ UID : ownerReference .UID ,
855
+ }))
856
+
857
+ g .Expect (ipInstance .Spec .Binding .Stateful ).NotTo (BeNil ())
858
+ g .Expect (ipInstance .Spec .Binding .Stateful .Index ).NotTo (BeNil ())
859
+
860
+ idx := * ipInstance .Spec .Binding .Stateful .Index
861
+ g .Expect (pod .Name ).To (Equal (fmt .Sprintf ("pod-%d" , idx )))
862
+
863
+ g .Expect (ipInstance .Spec .Network ).To (Equal (underlayNetworkName ))
864
+ g .Expect (ipInstance .Spec .Subnet ).To (BeElementOf (underlaySubnetName ))
865
+ }).
866
+ WithTimeout (30 * time .Second ).
867
+ WithPolling (time .Second ).
868
+ Should (Succeed ())
869
+
870
+ By ("remove the test pod" )
871
+ Expect (k8sClient .Delete (context .Background (), pod , client .GracePeriodSeconds (0 ))).NotTo (HaveOccurred ())
872
+ })
873
+
704
874
AfterEach (func () {
705
875
By ("make sure test ip instances cleaned up" )
706
876
Expect (k8sClient .DeleteAllOf (
0 commit comments