Skip to content

Commit 645bc68

Browse files
Merge pull request #335 from caseydavenport/fix-multi-rules
Fix bug with multiple rules in Kubernetes datastore driver
2 parents f60d01d + aa4fc3d commit 645bc68

File tree

2 files changed

+162
-2
lines changed

2 files changed

+162
-2
lines changed

lib/backend/k8s/conversion.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
kapiv1 "k8s.io/client-go/pkg/api/v1"
3333
extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
3434
metav1 "k8s.io/client-go/pkg/apis/meta/v1"
35+
"k8s.io/client-go/pkg/util/intstr"
3536
)
3637

3738
var (
@@ -322,10 +323,26 @@ func (c converter) k8sIngressRuleToCalico(r extensions.NetworkPolicyIngressRule,
322323

323324
// Built up a list of the sources and a list of the destinations.
324325
for _, f := range r.From {
325-
peers = append(peers, &f)
326+
// We need to add a copy of the peer so all the rules don't
327+
// point to the same location.
328+
peers = append(peers, &extensions.NetworkPolicyPeer{
329+
NamespaceSelector: f.NamespaceSelector,
330+
PodSelector: f.PodSelector,
331+
})
326332
}
327333
for _, p := range r.Ports {
328-
ports = append(ports, &p)
334+
// We need to add a copy of the port so all the rules don't
335+
// point to the same location.
336+
port := extensions.NetworkPolicyPort{}
337+
if p.Port != nil {
338+
portval := intstr.FromString(p.Port.String())
339+
port.Port = &portval
340+
}
341+
if p.Protocol != nil {
342+
protval := kapiv1.Protocol(fmt.Sprintf("%s", *p.Protocol))
343+
port.Protocol = &protval
344+
}
345+
ports = append(ports, &port)
329346
}
330347

331348
// If there no peers, or no ports, represent that as nil.
@@ -337,6 +354,8 @@ func (c converter) k8sIngressRuleToCalico(r extensions.NetworkPolicyIngressRule,
337354
}
338355

339356
// Combine desintations with sources to generate rules.
357+
// TODO: This currently creates a lot of rules by making every combination of from / ports
358+
// into a rule. We can combine these so that we don't need as many rules!
340359
for _, port := range ports {
341360
for _, peer := range peers {
342361
// Build rule and append to list.

lib/backend/k8s/conversion_test.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
. "github.com/onsi/gomega"
2020

2121
"github.com/projectcalico/libcalico-go/lib/backend/model"
22+
"github.com/projectcalico/libcalico-go/lib/numorstring"
23+
2224
k8sapi "k8s.io/client-go/pkg/api/v1"
2325
extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
2426
metav1 "k8s.io/client-go/pkg/apis/meta/v1"
@@ -267,6 +269,145 @@ var _ = Describe("Test NetworkPolicy conversion", func() {
267269
Expect(len(pol.Value.(*model.Policy).OutboundRules)).To(Equal(0))
268270
})
269271

272+
It("should parse a NetworkPolicy with multiple peers", func() {
273+
np := extensions.NetworkPolicy{
274+
ObjectMeta: k8sapi.ObjectMeta{
275+
Name: "testPolicy",
276+
Namespace: "default",
277+
},
278+
Spec: extensions.NetworkPolicySpec{
279+
PodSelector: metav1.LabelSelector{
280+
MatchLabels: map[string]string{"label": "value"},
281+
},
282+
Ingress: []extensions.NetworkPolicyIngressRule{
283+
extensions.NetworkPolicyIngressRule{
284+
Ports: []extensions.NetworkPolicyPort{
285+
extensions.NetworkPolicyPort{},
286+
},
287+
From: []extensions.NetworkPolicyPeer{
288+
extensions.NetworkPolicyPeer{
289+
PodSelector: &metav1.LabelSelector{
290+
MatchLabels: map[string]string{
291+
"k": "v",
292+
},
293+
},
294+
},
295+
extensions.NetworkPolicyPeer{
296+
PodSelector: &metav1.LabelSelector{
297+
MatchLabels: map[string]string{
298+
"k2": "v2",
299+
},
300+
},
301+
},
302+
},
303+
},
304+
},
305+
},
306+
}
307+
308+
var pol *model.KVPair
309+
var err error
310+
By("parsing the policy", func() {
311+
pol, err = c.networkPolicyToPolicy(&np)
312+
Expect(err).NotTo(HaveOccurred())
313+
Expect(pol.Key.(model.PolicyKey).Name).To(Equal("np.projectcalico.org/default.testPolicy"))
314+
Expect(int(*pol.Value.(*model.Policy).Order)).To(Equal(1000))
315+
})
316+
317+
By("having the correct endpoint selector", func() {
318+
Expect(pol.Value.(*model.Policy).Selector).To(Equal("calico/k8s_ns == 'default' && label == 'value'"))
319+
})
320+
321+
By("having the correct peer selectors", func() {
322+
Expect(len(pol.Value.(*model.Policy).InboundRules)).To(Equal(2))
323+
Expect(len(pol.Value.(*model.Policy).OutboundRules)).To(Equal(0))
324+
Expect(pol.Value.(*model.Policy).InboundRules[0].SrcSelector).To(Equal("calico/k8s_ns == 'default' && k == 'v'"))
325+
Expect(pol.Value.(*model.Policy).InboundRules[1].SrcSelector).To(Equal("calico/k8s_ns == 'default' && k2 == 'v2'"))
326+
})
327+
})
328+
329+
It("should parse a NetworkPolicy with multiple peers and ports", func() {
330+
tcp := k8sapi.ProtocolTCP
331+
udp := k8sapi.ProtocolUDP
332+
eighty := intstr.FromInt(80)
333+
ninety := intstr.FromInt(90)
334+
335+
np := extensions.NetworkPolicy{
336+
ObjectMeta: k8sapi.ObjectMeta{
337+
Name: "testPolicy",
338+
Namespace: "default",
339+
},
340+
Spec: extensions.NetworkPolicySpec{
341+
PodSelector: metav1.LabelSelector{
342+
MatchLabels: map[string]string{"label": "value"},
343+
},
344+
Ingress: []extensions.NetworkPolicyIngressRule{
345+
extensions.NetworkPolicyIngressRule{
346+
Ports: []extensions.NetworkPolicyPort{
347+
extensions.NetworkPolicyPort{
348+
Port: &ninety,
349+
Protocol: &udp,
350+
},
351+
extensions.NetworkPolicyPort{
352+
Port: &eighty,
353+
Protocol: &tcp,
354+
},
355+
},
356+
From: []extensions.NetworkPolicyPeer{
357+
extensions.NetworkPolicyPeer{
358+
PodSelector: &metav1.LabelSelector{
359+
MatchLabels: map[string]string{
360+
"k": "v",
361+
},
362+
},
363+
},
364+
extensions.NetworkPolicyPeer{
365+
PodSelector: &metav1.LabelSelector{
366+
MatchLabels: map[string]string{
367+
"k2": "v2",
368+
},
369+
},
370+
},
371+
},
372+
},
373+
},
374+
},
375+
}
376+
377+
var pol *model.KVPair
378+
var err error
379+
By("parsing the policy", func() {
380+
pol, err = c.networkPolicyToPolicy(&np)
381+
Expect(err).NotTo(HaveOccurred())
382+
Expect(pol.Key.(model.PolicyKey).Name).To(Equal("np.projectcalico.org/default.testPolicy"))
383+
Expect(int(*pol.Value.(*model.Policy).Order)).To(Equal(1000))
384+
})
385+
386+
By("having the correct endpoint selector", func() {
387+
Expect(pol.Value.(*model.Policy).Selector).To(Equal("calico/k8s_ns == 'default' && label == 'value'"))
388+
})
389+
390+
By("having the correct peer selectors", func() {
391+
eighty, _ := numorstring.PortFromString("80")
392+
ninety, _ := numorstring.PortFromString("90")
393+
Expect(len(pol.Value.(*model.Policy).InboundRules)).To(Equal(4))
394+
Expect(len(pol.Value.(*model.Policy).OutboundRules)).To(Equal(0))
395+
396+
Expect(pol.Value.(*model.Policy).InboundRules[0].SrcSelector).To(Equal("calico/k8s_ns == 'default' && k == 'v'"))
397+
Expect(pol.Value.(*model.Policy).InboundRules[0].DstPorts).To(Equal([]numorstring.Port{ninety}))
398+
399+
Expect(pol.Value.(*model.Policy).InboundRules[1].SrcSelector).To(Equal("calico/k8s_ns == 'default' && k2 == 'v2'"))
400+
Expect(pol.Value.(*model.Policy).InboundRules[1].DstPorts).To(Equal([]numorstring.Port{ninety}))
401+
402+
Expect(pol.Value.(*model.Policy).InboundRules[2].SrcSelector).To(Equal("calico/k8s_ns == 'default' && k == 'v'"))
403+
Expect(pol.Value.(*model.Policy).InboundRules[2].DstPorts).To(Equal([]numorstring.Port{eighty}))
404+
405+
Expect(pol.Value.(*model.Policy).InboundRules[3].SrcSelector).To(Equal("calico/k8s_ns == 'default' && k2 == 'v2'"))
406+
Expect(pol.Value.(*model.Policy).InboundRules[3].DstPorts).To(Equal([]numorstring.Port{eighty}))
407+
408+
})
409+
})
410+
270411
It("should parse a NetworkPolicy with empty podSelector", func() {
271412
np := extensions.NetworkPolicy{
272413
ObjectMeta: k8sapi.ObjectMeta{

0 commit comments

Comments
 (0)