Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

networkpolicy pkg: add new methods to multi network policy #792

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions pkg/networkpolicy/multinetegressrule.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/golang/glog"
"github.com/k8snetworkplumbingwg/multi-networkpolicy/pkg/apis/k8s.cni.cncf.io/v1beta1"
"github.com/openshift-kni/eco-goinfra/pkg/msg"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
Expand Down Expand Up @@ -54,6 +55,52 @@ func (builder *EgressRuleBuilder) WithPortAndProtocol(port uint16, protocol core
return builder
}

// WithProtocol appends new item with only protocol to Ports list.
func (builder *EgressRuleBuilder) WithProtocol(protocol corev1.Protocol) *EgressRuleBuilder {
klaskosk marked this conversation as resolved.
Show resolved Hide resolved
if valid, _ := builder.validate(); !valid {
return builder
}

glog.V(100).Infof("Adding protocol %s to EgressRule", protocol)

if !(protocol == corev1.ProtocolTCP || protocol == corev1.ProtocolUDP || protocol == corev1.ProtocolSCTP) {
glog.V(100).Infof("invalid protocol argument. Allowed protocols: TCP, UDP & SCTP ")

builder.errorMsg = "invalid protocol argument. Allowed protocols: TCP, UDP & SCTP"

return builder
}

builder.definition.Ports = append(
builder.definition.Ports, v1beta1.MultiNetworkPolicyPort{Protocol: &protocol})

return builder
}

// WithPort appends new item with only port to Ports list.
func (builder *EgressRuleBuilder) WithPort(port uint16) *EgressRuleBuilder {
if valid, _ := builder.validate(); !valid {
return builder
}

glog.V(100).Infof("Adding port %d to EgressRule", port)
klaskosk marked this conversation as resolved.
Show resolved Hide resolved

if port == 0 {
glog.V(100).Infof("Cannot set port number to 0")

builder.errorMsg = "port number cannot be 0"

return builder
}

formattedPort := intstr.FromInt(int(port))

builder.definition.Ports = append(
builder.definition.Ports, v1beta1.MultiNetworkPolicyPort{Port: &formattedPort})

return builder
}

// WithOptions adds generic options to Egress rule.
func (builder *EgressRuleBuilder) WithOptions(options ...EgressAdditionalOptions) *EgressRuleBuilder {
glog.V(100).Infof("Setting EgressRule additional options")
Expand Down Expand Up @@ -88,6 +135,69 @@ func (builder *EgressRuleBuilder) WithPeerPodSelector(podSelector metav1.LabelSe
return builder
}

// WithPeerNamespaceSelector appends new item with only NamespaceSelector into To Peer list.
func (builder *EgressRuleBuilder) WithPeerNamespaceSelector(nsSelector metav1.LabelSelector) *EgressRuleBuilder {
if valid, _ := builder.validate(); !valid {
return builder
}

glog.V(100).Infof("Adding peer namespace selector %v to EgressRule", nsSelector)

builder.definition.To = append(builder.definition.To, v1beta1.MultiNetworkPolicyPeer{NamespaceSelector: &nsSelector})

return builder
}

// WithCIDR edits last item's IPBlock on Egress/To list or adds new item with only IPBlock into
// Egress/To list if the Egress/To list is empty.
func (builder *EgressRuleBuilder) WithCIDR(cidr string, except ...[]string) *EgressRuleBuilder {
if valid, _ := builder.validate(); !valid {
return builder
}

glog.V(100).Infof("Adding peer CIDR %s to Egress Rule", cidr)
klaskosk marked this conversation as resolved.
Show resolved Hide resolved

if len(except) != 0 {
glog.V(100).Infof("Adding CIDR except %v to Egress Rule", except[0])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can move it to the block:

	if len(except) > 0 {
		builder.definition.To[len(builder.definition.To)-1].IPBlock.Except = except[0]
	}

}

_, _, err := net.ParseCIDR(cidr)

if err != nil {
glog.V(100).Infof("Invalid CIDR %s", cidr)

builder.errorMsg = fmt.Sprintf("invalid CIDR argument %s", cidr)

return builder
}

builder.definition.To = append(builder.definition.To, v1beta1.MultiNetworkPolicyPeer{})

// Append IPBlock config to the previously added Peer
builder.definition.To[len(builder.definition.To)-1].IPBlock = &v1beta1.IPBlock{CIDR: cidr}

if len(except) > 0 {
builder.definition.To[len(builder.definition.To)-1].IPBlock.Except = except[0]
}
klaskosk marked this conversation as resolved.
Show resolved Hide resolved

return builder
}

// WithPeerPodAndNamespaceSelector appends new item to Egress/To list with PodSelector and NamespaceSelector.
func (builder *EgressRuleBuilder) WithPeerPodAndNamespaceSelector(
podSelector, nsSelector metav1.LabelSelector) *EgressRuleBuilder {
if valid, _ := builder.validate(); !valid {
return builder
}

glog.V(100).Infof("Adding peer pod selector %v namespace selector %v to EgressRule", podSelector, nsSelector)

builder.definition.To = append(builder.definition.To, v1beta1.MultiNetworkPolicyPeer{
PodSelector: &podSelector, NamespaceSelector: &nsSelector})

return builder
}

// WithPeerPodSelectorAndCIDR adds pod selector and CIDR to Egress rule.
func (builder *EgressRuleBuilder) WithPeerPodSelectorAndCIDR(
podSelector metav1.LabelSelector, cidr string, except ...[]string) *EgressRuleBuilder {
Expand Down Expand Up @@ -129,3 +239,27 @@ func (builder *EgressRuleBuilder) GetEgressRuleCfg() (*v1beta1.MultiNetworkPolic

return builder.definition, nil
}

func (builder *EgressRuleBuilder) validate() (bool, error) {
objectName := "multiNetworkPolicyEgressRule"

if builder == nil {
glog.V(100).Infof("The %s builder is uninitialized", objectName)

return false, fmt.Errorf("error: received nil %s builder", objectName)
}

if builder.definition == nil {
glog.V(100).Infof("The %s is undefined", objectName)

builder.errorMsg = msg.UndefinedCrdObjectErrString(objectName)
}

if builder.errorMsg != "" {
glog.V(100).Infof("The %s builder has error message: %s", objectName, builder.errorMsg)

return false, fmt.Errorf(builder.errorMsg)
}

return true, nil
}
131 changes: 131 additions & 0 deletions pkg/networkpolicy/multinetegressrule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -28,6 +29,46 @@ func TestEgressWithPortAndProtocol(t *testing.T) {
assert.Equal(t, builder.errorMsg, "port number can not be 0")
}

func TestEgressWithProtocol(t *testing.T) {
testCases := []struct {
klaskosk marked this conversation as resolved.
Show resolved Hide resolved
protocol v1.Protocol
expectedError string
}{
{protocol: v1.ProtocolTCP, expectedError: ""},
{protocol: v1.ProtocolUDP, expectedError: ""},
{protocol: v1.ProtocolSCTP, expectedError: ""},
{protocol: "dummy", expectedError: "invalid protocol argument. Allowed protocols: TCP, UDP & SCTP"},
}
for _, testCase := range testCases {
builder := NewEgressRuleBuilder().WithProtocol(testCase.protocol)
assert.Equal(t, testCase.expectedError, builder.errorMsg)

if testCase.expectedError == "" {
assert.Equal(t, testCase.protocol, *builder.definition.Ports[0].Protocol)
}
}
}

func TestEgressWithPort(t *testing.T) {
testCases := []struct {
port uint16
expectedError string
}{
{
port: 5001,
expectedError: "",
},
{
port: 0,
expectedError: "port number cannot be 0",
},
}
for _, testCase := range testCases {
builder := NewEgressRuleBuilder().WithPort(testCase.port)
assert.Equal(t, testCase.expectedError, builder.errorMsg)
}
}

func TestEgressWithOptions(t *testing.T) {
testCases := []struct {
testOptions []EgressAdditionalOptions
Expand Down Expand Up @@ -84,6 +125,72 @@ func TestEgressWithPeerPodSelector(t *testing.T) {
assert.Len(t, builder.definition.To, 1)
}

func TestEgressWithPeerNamespaceSelector(t *testing.T) {
testCases := []struct {
namespaceSelector metav1.LabelSelector
expectedError string
}{
{
namespaceSelector: metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}},
expectedError: "",
},
{
namespaceSelector: metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "app",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"nginx"},
},
}},
},
}
for _, testCase := range testCases {
builder := NewEgressRuleBuilder().WithPeerNamespaceSelector(testCase.namespaceSelector)
assert.Equal(t, testCase.expectedError, builder.errorMsg)
assert.Equal(t, &testCase.namespaceSelector, builder.definition.To[0].NamespaceSelector)
}
}

func TestEgressWithCIDR(t *testing.T) {
klaskosk marked this conversation as resolved.
Show resolved Hide resolved
testCases := []struct {
cidr string
except string
expectedLength int
}{
{
cidr: "192.168.1.1/24",
expectedLength: 1,
},
{
cidr: "192.168.1.1",
expectedLength: 0,
},
{
cidr: "192.168.1.1/24",
except: "192.168.1.10/32",
expectedLength: 1,
},
}
for _, testCase := range testCases {
if len(testCase.except) != 0 {
builder := NewEgressRuleBuilder().WithCIDR(testCase.cidr, []string{testCase.except})
assert.Equal(t, testCase.expectedLength, len(builder.definition.To))
assert.Equal(t, testCase.except, builder.definition.To[0].IPBlock.Except[0])

if len(builder.definition.To) != 0 {
assert.Equal(t, testCase.cidr, builder.definition.To[0].IPBlock.CIDR)
}
} else {
builder := NewEgressRuleBuilder().WithCIDR(testCase.cidr)
assert.Equal(t, testCase.expectedLength, len(builder.definition.To))

if len(builder.definition.To) != 0 {
assert.Equal(t, testCase.cidr, builder.definition.To[0].IPBlock.CIDR)
}
}
}
}

func TestEgressWithPeerPodSelectorAndCIDR(t *testing.T) {
builder := NewEgressRuleBuilder()

Expand Down Expand Up @@ -116,6 +223,30 @@ func TestEgressWithPeerPodSelectorAndCIDR(t *testing.T) {
assert.Equal(t, builder.definition.To[0].IPBlock.Except[0], "192.168.1.1")
}

func TestEgressWithPeerPodAndNamespaceSelector(t *testing.T) {
testCases := []struct {
podSelector metav1.LabelSelector
namespaceSelector metav1.LabelSelector
expectedError string
}{
{
podSelector: metav1.LabelSelector{MatchLabels: map[string]string{"app": "nginx"}},
namespaceSelector: metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "app",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"nginx"},
}}},
expectedError: "",
},
}
for _, testCase := range testCases {
builder := NewEgressRuleBuilder().WithPeerPodAndNamespaceSelector(testCase.podSelector, testCase.namespaceSelector)
assert.Equal(t, testCase.expectedError, builder.errorMsg)
assert.Equal(t, &testCase.podSelector, builder.definition.To[0].PodSelector)
assert.Equal(t, &testCase.namespaceSelector, builder.definition.To[0].NamespaceSelector)
}
}

func TestEgressGetEgressRuleCfg(t *testing.T) {
builder := NewEgressRuleBuilder()

Expand Down
Loading
Loading