diff --git a/cmd/reconciler/ip_test.go b/cmd/reconciler/ip_test.go index 8fac94a5b..5e270c51c 100644 --- a/cmd/reconciler/ip_test.go +++ b/cmd/reconciler/ip_test.go @@ -252,6 +252,37 @@ var _ = Describe("Whereabouts IP reconciler", func() { Expect(clusterWideIPAllocations.Items).To(HaveLen(expectedClusterWideIPs)) }) }) + + Context("a pod in pending state, without an IP in its network-status", func() { + const poolName = "pool1" + + var pod *v1.Pod + var pool *v1alpha1.IPPool + + BeforeEach(func() { + var err error + pod, err = k8sClientSet.CoreV1().Pods(namespace).Create( + context.TODO(), + generatePendingPod(namespace, podName), + metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + pool = generateIPPoolSpec(ipRange, namespace, poolName, pod.Name) + Expect(k8sClient.Create(context.Background(), pool)).NotTo(HaveOccurred()) + + reconcileLooper, err = reconciler.NewReconcileLooperWithKubeconfig(kubeConfigPath, context.TODO()) + Expect(err).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + Expect(k8sClient.Delete(context.Background(), pool)).NotTo(HaveOccurred()) + Expect(k8sClientSet.CoreV1().Pods(namespace).Delete(context.TODO(), pod.GetName(), metav1.DeleteOptions{})) + }) + + It("cannot be reconciled", func() { + Expect(reconcileLooper.ReconcileIPPools()).To(BeEmpty()) + }) + }) }) func generateIPPoolSpec(ipRange string, namespace string, poolName string, podNames ...string) *v1alpha1.IPPool { @@ -300,9 +331,16 @@ func generatePod(namespace string, podName string, ipNetworks ...ipInNetwork) *v }, }, }, + Status: v1.PodStatus{Phase: v1.PodRunning}, } } +func generatePendingPod(namespace string, podName string, ipNetworks ...ipInNetwork) *v1.Pod { + pod := generatePod(namespace, podName, ipNetworks...) + pod.Status.Phase = v1.PodPending + return pod +} + func generatePodAnnotations(ipNetworks ...ipInNetwork) map[string]string { var networks []string for _, ipNetworkInfo := range ipNetworks { diff --git a/pkg/reconciler/iploop.go b/pkg/reconciler/iploop.go index 46b4584b1..ecf4a3c3f 100644 --- a/pkg/reconciler/iploop.go +++ b/pkg/reconciler/iploop.go @@ -108,7 +108,7 @@ func (rl ReconcileLooper) isPodAlive(podRef string, ip string) bool { ip, livePodIPs) _, isFound := livePodIPs[ip] - return isFound + return isFound || livePod.phase == v1.PodPending } } return false diff --git a/pkg/reconciler/wrappedPod.go b/pkg/reconciler/wrappedPod.go index 154a8d3a4..86acbbfda 100644 --- a/pkg/reconciler/wrappedPod.go +++ b/pkg/reconciler/wrappedPod.go @@ -3,9 +3,9 @@ package reconciler import ( "encoding/json" + k8snetworkplumbingwgv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" "github.com/k8snetworkplumbingwg/whereabouts/pkg/logging" "github.com/k8snetworkplumbingwg/whereabouts/pkg/storage" - k8snetworkplumbingwgv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" v1 "k8s.io/api/core/v1" ) @@ -18,7 +18,8 @@ const ( ) type podWrapper struct { - ips map[string]void + ips map[string]void + phase v1.PodPhase } type void struct{} @@ -26,6 +27,7 @@ type void struct{} func wrapPod(pod v1.Pod) *podWrapper { return &podWrapper{ ips: getFlatIPSet(pod), + phase: pod.Status.Phase, } }