Skip to content

Commit 13e0a39

Browse files
committed
fix(NPC): check if pod is actionable
Check if the Pod is actionable before taking NetworkPolicy actions which includes both adding KUBE-POD-FW and KUBE-NWPLCY chains for it. Checks have now been consolidated to a single isNetPolActionable() function which checks for pod phases that we don't want NetworkPolicy for like: Failed, Completed, and Succeeded, missing pod IP addresses, and pods with HostNetwork enabled. fixes cloudnativelabs#1056
1 parent fa8d69e commit 13e0a39

File tree

4 files changed

+110
-9
lines changed

4 files changed

+110
-9
lines changed

pkg/controllers/netpol/pod.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,8 @@ func (npc *NetworkPolicyController) getIngressNetworkPolicyEnabledPods(networkPo
226226
for _, obj := range npc.podLister.List() {
227227
pod := obj.(*api.Pod)
228228

229-
// ignore the pods running on the different node or running in host network
230-
if strings.Compare(pod.Status.HostIP, nodeIP) != 0 || pod.Spec.HostNetwork {
229+
// ignore the pods running on the different node and pods that are not actionable
230+
if strings.Compare(pod.Status.HostIP, nodeIP) != 0 || !isNetPolActionable(pod) {
231231
continue
232232
}
233233

@@ -246,8 +246,8 @@ func (npc *NetworkPolicyController) getIngressNetworkPolicyEnabledPods(networkPo
246246
}
247247
}
248248
}
249-
return &nodePods, nil
250249

250+
return &nodePods, nil
251251
}
252252

253253
func (npc *NetworkPolicyController) getEgressNetworkPolicyEnabledPods(networkPoliciesInfo []networkPolicyInfo, nodeIP string) (*map[string]podInfo, error) {
@@ -257,10 +257,11 @@ func (npc *NetworkPolicyController) getEgressNetworkPolicyEnabledPods(networkPol
257257
for _, obj := range npc.podLister.List() {
258258
pod := obj.(*api.Pod)
259259

260-
// ignore the pods running on the different node or running in host network
261-
if strings.Compare(pod.Status.HostIP, nodeIP) != 0 || pod.Spec.HostNetwork {
260+
// ignore the pods running on the different node and pods that are not actionable
261+
if strings.Compare(pod.Status.HostIP, nodeIP) != 0 || !isNetPolActionable(pod) {
262262
continue
263263
}
264+
264265
for _, policy := range networkPoliciesInfo {
265266
if policy.namespace != pod.ObjectMeta.Namespace {
266267
continue
@@ -276,6 +277,7 @@ func (npc *NetworkPolicyController) getEgressNetworkPolicyEnabledPods(networkPol
276277
}
277278
}
278279
}
280+
279281
return &nodePods, nil
280282
}
281283

pkg/controllers/netpol/policy.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ func (npc *NetworkPolicyController) buildNetworkPoliciesInfo() ([]networkPolicyI
483483
namedPort2IngressEps := make(namedPort2eps)
484484
if err == nil {
485485
for _, matchingPod := range matchingPods {
486-
if matchingPod.Status.PodIP == "" {
486+
if !isNetPolActionable(matchingPod) {
487487
continue
488488
}
489489
newPolicy.targetPods[matchingPod.Status.PodIP] = podInfo{ip: matchingPod.Status.PodIP,
@@ -519,7 +519,7 @@ func (npc *NetworkPolicyController) buildNetworkPoliciesInfo() ([]networkPolicyI
519519
for _, peer := range specIngressRule.From {
520520
if peerPods, err := npc.evalPodPeer(policy, peer); err == nil {
521521
for _, peerPod := range peerPods {
522-
if peerPod.Status.PodIP == "" {
522+
if !isNetPolActionable(peerPod) {
523523
continue
524524
}
525525
ingressRule.srcPods = append(ingressRule.srcPods,
@@ -560,7 +560,7 @@ func (npc *NetworkPolicyController) buildNetworkPoliciesInfo() ([]networkPolicyI
560560
if policyRulePortsHasNamedPort(specEgressRule.Ports) {
561561
matchingPeerPods, _ := npc.ListPodsByNamespaceAndLabels(policy.Namespace, labels.Everything())
562562
for _, peerPod := range matchingPeerPods {
563-
if peerPod.Status.PodIP == "" {
563+
if !isNetPolActionable(peerPod) {
564564
continue
565565
}
566566
npc.grabNamedPortFromPod(peerPod, &namedPort2EgressEps)
@@ -571,7 +571,7 @@ func (npc *NetworkPolicyController) buildNetworkPoliciesInfo() ([]networkPolicyI
571571
for _, peer := range specEgressRule.To {
572572
if peerPods, err := npc.evalPodPeer(policy, peer); err == nil {
573573
for _, peerPod := range peerPods {
574-
if peerPod.Status.PodIP == "" {
574+
if !isNetPolActionable(peerPod) {
575575
continue
576576
}
577577
egressRule.dstPods = append(egressRule.dstPods,

pkg/controllers/netpol/utils.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,26 @@ import (
44
"fmt"
55
"regexp"
66
"strconv"
7+
8+
api "k8s.io/api/core/v1"
9+
)
10+
11+
const (
12+
PodCompleted api.PodPhase = "Completed"
713
)
814

15+
func isNetPolActionable(pod *api.Pod) bool {
16+
return !isFinished(pod) && pod.Status.PodIP != "" && !pod.Spec.HostNetwork
17+
}
18+
19+
func isFinished(pod *api.Pod) bool {
20+
switch pod.Status.Phase {
21+
case api.PodFailed, api.PodSucceeded, PodCompleted:
22+
return true
23+
}
24+
return false
25+
}
26+
927
func validateNodePortRange(nodePortOption string) (string, error) {
1028
nodePortValidator := regexp.MustCompile(`^([0-9]+)[:-]([0-9]+)$`)
1129
if matched := nodePortValidator.MatchString(nodePortOption); !matched {

pkg/controllers/netpol/utils_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,89 @@ import (
44
"testing"
55

66
"github.com/stretchr/testify/assert"
7+
api "k8s.io/api/core/v1"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
79
)
810

11+
var (
12+
fakePod = api.Pod{
13+
TypeMeta: metav1.TypeMeta{
14+
Kind: "Pod",
15+
APIVersion: "v1",
16+
},
17+
ObjectMeta: metav1.ObjectMeta{
18+
Name: "testpod",
19+
Namespace: "testnamespace",
20+
Labels: map[string]string{"foo": "bar"}},
21+
Spec: api.PodSpec{
22+
Containers: []api.Container{
23+
{
24+
Image: "k8s.gcr.io/busybox",
25+
},
26+
},
27+
},
28+
Status: api.PodStatus{
29+
PodIP: "172.16.0.1",
30+
PodIPs: []api.PodIP{
31+
{
32+
IP: "172.16.0.1",
33+
},
34+
},
35+
HostIP: "10.0.0.1",
36+
Phase: api.PodRunning,
37+
},
38+
}
39+
)
40+
41+
func Test_isPodFinished(t *testing.T) {
42+
t.Run("Failed pod should be detected as finished", func(t *testing.T) {
43+
fakePod.Status.Phase = api.PodFailed
44+
assert.True(t, isFinished(&fakePod))
45+
})
46+
t.Run("Succeeded pod should be detected as finished", func(t *testing.T) {
47+
fakePod.Status.Phase = api.PodSucceeded
48+
assert.True(t, isFinished(&fakePod))
49+
})
50+
t.Run("Completed pod should be detected as finished", func(t *testing.T) {
51+
fakePod.Status.Phase = PodCompleted
52+
assert.True(t, isFinished(&fakePod))
53+
})
54+
t.Run("Running pod should NOT be detected as finished", func(t *testing.T) {
55+
fakePod.Status.Phase = api.PodRunning
56+
assert.False(t, isFinished(&fakePod))
57+
})
58+
t.Run("Pending pod should NOT be detected as finished", func(t *testing.T) {
59+
fakePod.Status.Phase = api.PodPending
60+
assert.False(t, isFinished(&fakePod))
61+
})
62+
t.Run("Unknown pod should NOT be detected as finished", func(t *testing.T) {
63+
fakePod.Status.Phase = api.PodUnknown
64+
assert.False(t, isFinished(&fakePod))
65+
})
66+
}
67+
68+
func Test_isNetPolActionable(t *testing.T) {
69+
t.Run("Normal pod should be actionable", func(t *testing.T) {
70+
assert.True(t, isNetPolActionable(&fakePod))
71+
})
72+
t.Run("Pod without Pod IP should not be actionable", func(t *testing.T) {
73+
fakePod.Status.PodIP = ""
74+
assert.False(t, isNetPolActionable(&fakePod))
75+
})
76+
t.Run("Finished Pod should not be actionable", func(t *testing.T) {
77+
fakePod.Status.Phase = api.PodFailed
78+
assert.False(t, isNetPolActionable(&fakePod))
79+
fakePod.Status.Phase = api.PodSucceeded
80+
assert.False(t, isNetPolActionable(&fakePod))
81+
fakePod.Status.Phase = PodCompleted
82+
assert.False(t, isNetPolActionable(&fakePod))
83+
})
84+
t.Run("Host Networked Pod should not be actionable", func(t *testing.T) {
85+
fakePod.Spec.HostNetwork = true
86+
assert.False(t, isNetPolActionable(&fakePod))
87+
})
88+
}
89+
990
func Test_NewNetworkPolicyController(t *testing.T) {
1091
t.Run("Node Port range specified with a hyphen should pass validation", func(t *testing.T) {
1192
portRange, err := validateNodePortRange("1000-2000")

0 commit comments

Comments
 (0)