diff --git a/CHANGELOG.md b/CHANGELOG.md index ab8998033..b931b2611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ # Changelog -Check [releases](https://github.com/spotahome/redis-operator/releases) section for Changelog +Check [releases](https://github.com/powerhome/redis-operator/releases) section for Changelog ## Unreleased +## [v1.7.1] - 2023-12-14 + +- [Use finer grained NetworkPolicies](https://github.com/powerhome/redis-operator/pull/25) - [Fix PodDisruptionBudget deprecation warnings on kube 1.21+](https://github.com/powerhome/redis-operator/pull/19) ## [v1.1.0-rc.3] - 2022-01-19 diff --git a/Makefile b/Makefile index 9b313a939..d0ca2deaa 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION := v1.3.0-rc0 +VERSION := v1.7.1 # Name of this service/application SERVICE_NAME := redis-operator @@ -31,11 +31,11 @@ BRANCH=$(shell git rev-parse --abbrev-ref HEAD) TAG := $(GITTAG) ifneq ($(COMMIT), $(GITTAG_COMMIT)) - TAG := $(COMMIT) + TAG := $(COMMIT) endif ifneq ($(shell git status --porcelain),) - TAG := $(TAG)-dirty + TAG := $(TAG)-dirty endif diff --git a/mocks/operator/redisfailover/service/RedisFailoverClient.go b/mocks/operator/redisfailover/service/RedisFailoverClient.go index 37e5b9c6a..29e56e160 100644 --- a/mocks/operator/redisfailover/service/RedisFailoverClient.go +++ b/mocks/operator/redisfailover/service/RedisFailoverClient.go @@ -56,20 +56,6 @@ func (_m *RedisFailoverClient) EnsureHAProxyService(rFailover *v1.RedisFailover, return r0 } -// EnsureNetworkPolicy provides a mock function with given fields: rFailover, labels, ownerRefs -func (_m *RedisFailoverClient) EnsureNetworkPolicy(rFailover *v1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { - ret := _m.Called(rFailover, labels, ownerRefs) - - var r0 error - if rf, ok := ret.Get(0).(func(*v1.RedisFailover, map[string]string, []metav1.OwnerReference) error); ok { - r0 = rf(rFailover, labels, ownerRefs) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // EnsureNotPresentRedisService provides a mock function with given fields: rFailover func (_m *RedisFailoverClient) EnsureNotPresentRedisService(rFailover *v1.RedisFailover) error { ret := _m.Called(rFailover) @@ -126,6 +112,20 @@ func (_m *RedisFailoverClient) EnsureRedisMasterService(rFailover *v1.RedisFailo return r0 } +// EnsureRedisNetworkPolicy provides a mock function with given fields: rFailover, labels, ownerRefs +func (_m *RedisFailoverClient) EnsureRedisNetworkPolicy(rFailover *v1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { + ret := _m.Called(rFailover, labels, ownerRefs) + + var r0 error + if rf, ok := ret.Get(0).(func(*v1.RedisFailover, map[string]string, []metav1.OwnerReference) error); ok { + r0 = rf(rFailover, labels, ownerRefs) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // EnsureRedisReadinessConfigMap provides a mock function with given fields: rFailover, labels, ownerRefs func (_m *RedisFailoverClient) EnsureRedisReadinessConfigMap(rFailover *v1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { ret := _m.Called(rFailover, labels, ownerRefs) @@ -224,6 +224,20 @@ func (_m *RedisFailoverClient) EnsureSentinelDeployment(rFailover *v1.RedisFailo return r0 } +// EnsureSentinelNetworkPolicy provides a mock function with given fields: rFailover, labels, ownerRefs +func (_m *RedisFailoverClient) EnsureSentinelNetworkPolicy(rFailover *v1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { + ret := _m.Called(rFailover, labels, ownerRefs) + + var r0 error + if rf, ok := ret.Get(0).(func(*v1.RedisFailover, map[string]string, []metav1.OwnerReference) error); ok { + r0 = rf(rFailover, labels, ownerRefs) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // EnsureSentinelService provides a mock function with given fields: rFailover, labels, ownerRefs func (_m *RedisFailoverClient) EnsureSentinelService(rFailover *v1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { ret := _m.Called(rFailover, labels, ownerRefs) diff --git a/operator/redisfailover/ensurer.go b/operator/redisfailover/ensurer.go index 533427fe5..bf49d45c6 100644 --- a/operator/redisfailover/ensurer.go +++ b/operator/redisfailover/ensurer.go @@ -20,7 +20,10 @@ func (w *RedisFailoverHandler) Ensure(rf *redisfailoverv1.RedisFailover, labels } if !(len(rf.Spec.NetworkPolicyNsList) == 0) { - if err := w.rfService.EnsureNetworkPolicy(rf, labels, or); err != nil { + if err := w.rfService.EnsureRedisNetworkPolicy(rf, labels, or); err != nil { + return err + } + if err := w.rfService.EnsureSentinelNetworkPolicy(rf, labels, or); err != nil { return err } } diff --git a/operator/redisfailover/service/client.go b/operator/redisfailover/service/client.go index 7c8d347fc..3dbaba5f4 100644 --- a/operator/redisfailover/service/client.go +++ b/operator/redisfailover/service/client.go @@ -18,7 +18,8 @@ type RedisFailoverClient interface { EnsureHAProxyConfigmap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureHAProxyService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureRedisHeadlessService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error - EnsureNetworkPolicy(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error + EnsureRedisNetworkPolicy(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error + EnsureSentinelNetworkPolicy(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureSentinelService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureSentinelConfigMap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error EnsureSentinelDeployment(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error @@ -80,11 +81,19 @@ func generateComponentLabel(componentType string) map[string]string { } } -// EnsureNetworkPolicy makes sure the network policy exists -func (r *RedisFailoverKubeClient) EnsureNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { - svc := generateNetworkPolicy(rf, labels, ownerRefs) +// EnsureRedisNetworkPolicy makes sure the redis network policy exists +func (r *RedisFailoverKubeClient) EnsureRedisNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { + svc := generateRedisNetworkPolicy(rf, labels, ownerRefs) err := r.K8SService.CreateOrUpdateNetworkPolicy(rf.Namespace, svc) - r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "NetworkPolicy", rf.Name, err) + r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureRedisNetworkPolicy", rf.Name, err) + return err +} + +// EnsureSentinelNetworkPolicy makes sure the redis network policy exists +func (r *RedisFailoverKubeClient) EnsureSentinelNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { + svc := generateSentinelNetworkPolicy(rf, labels, ownerRefs) + err := r.K8SService.CreateOrUpdateNetworkPolicy(rf.Namespace, svc) + r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureSentinelNetworkPolicy", rf.Name, err) return err } diff --git a/operator/redisfailover/service/constants.go b/operator/redisfailover/service/constants.go index 9cc2d06aa..ef320fd0f 100644 --- a/operator/redisfailover/service/constants.go +++ b/operator/redisfailover/service/constants.go @@ -14,20 +14,21 @@ const ( ) const ( - baseName = "rf" - sentinelName = "s" - sentinelRoleName = "sentinel" - sentinelConfigFileName = "sentinel.conf" - redisConfigFileName = "redis.conf" - redisName = "r" - redisMasterName = "rm" - redisSlaveName = "rs" - redisShutdownName = "r-s" - redisReadinessName = "r-readiness" - redisRoleName = "redis" - appLabel = "redis-failover" - hostnameTopologyKey = "kubernetes.io/hostname" - networkPolicyName = "network-policy" + baseName = "rf" + sentinelName = "s" + sentinelRoleName = "sentinel" + sentinelConfigFileName = "sentinel.conf" + sentinelNetworkPolicyName = "s-np" + redisConfigFileName = "redis.conf" + redisName = "r" + redisNetworkPolicyName = "r-np" + redisMasterName = "rm" + redisSlaveName = "rs" + redisShutdownName = "r-s" + redisReadinessName = "r-readiness" + redisRoleName = "redis" + appLabel = "redis-failover" + hostnameTopologyKey = "kubernetes.io/hostname" ) const ( diff --git a/operator/redisfailover/service/generator.go b/operator/redisfailover/service/generator.go index 3cd0cbf36..d7c1cbe5e 100644 --- a/operator/redisfailover/service/generator.go +++ b/operator/redisfailover/service/generator.go @@ -281,16 +281,15 @@ func generateHAProxyService(rf *redisfailoverv1.RedisFailover, labels map[string } } -func generateNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *np.NetworkPolicy { - name := GetNetworkPolicyName(rf) +func generateRedisNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *np.NetworkPolicy { + name := GetRedisNetworkPolicyName(rf) namespace := rf.Namespace networkPolicyNsList := rf.Spec.NetworkPolicyNsList - selectorLabels := generateSelectorLabels(networkPolicyName, rf.Name) + selectorLabels := generateSelectorLabels(redisRoleName, rf.Name) labels = util.MergeLabels(labels, selectorLabels) - sentinelTargetPort := intstr.FromInt(int(rf.Spec.Sentinel.Port)) metricsTargetPort := intstr.FromInt(9121) redisTargetPort := intstr.FromInt(int(rf.Spec.Redis.Port)) @@ -313,7 +312,59 @@ func generateNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string] Port: &redisTargetPort, }, np.NetworkPolicyPort{ Port: &metricsTargetPort, - }, np.NetworkPolicyPort{ + }) + + return &np.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: labels, + OwnerReferences: ownerRefs, + }, + Spec: np.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: util.MergeLabels( + map[string]string{"redisfailovers.databases.spotahome.com/name": rf.Name}, + generateComponentLabel("redis"), + ), + }, + Ingress: []np.NetworkPolicyIngressRule{ + np.NetworkPolicyIngressRule{ + From: peers, + Ports: ports, + }, + }, + }, + } +} + +func generateSentinelNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *np.NetworkPolicy { + name := GetSentinelNetworkPolicyName(rf) + namespace := rf.Namespace + + networkPolicyNsList := rf.Spec.NetworkPolicyNsList + + selectorLabels := generateSelectorLabels(sentinelRoleName, rf.Name) + labels = util.MergeLabels(labels, selectorLabels) + + sentinelTargetPort := intstr.FromInt(int(rf.Spec.Sentinel.Port)) + + peers := []np.NetworkPolicyPeer{} + + for _, inputPeer := range networkPolicyNsList { + + labelKey := inputPeer.MatchLabelKey + labelValue := inputPeer.MatchLabelValue + + peers = append(peers, np.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{labelKey: labelValue}, + }, + }) + } + + ports := make([]np.NetworkPolicyPort, 0) + ports = append(ports, np.NetworkPolicyPort{ Port: &sentinelTargetPort, }) @@ -326,7 +377,10 @@ func generateNetworkPolicy(rf *redisfailoverv1.RedisFailover, labels map[string] }, Spec: np.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{"redisfailovers.databases.spotahome.com/name": rf.Name}, + MatchLabels: util.MergeLabels( + map[string]string{"redisfailovers.databases.spotahome.com/name": rf.Name}, + generateComponentLabel("sentinel"), + ), }, Ingress: []np.NetworkPolicyIngressRule{ np.NetworkPolicyIngressRule{ diff --git a/operator/redisfailover/service/generator_test.go b/operator/redisfailover/service/generator_test.go index 124f16fcd..bb89f5b12 100644 --- a/operator/redisfailover/service/generator_test.go +++ b/operator/redisfailover/service/generator_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/mock" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -1409,6 +1410,477 @@ func TestHaproxyService(t *testing.T) { } } +func TestRedisNetworkPolicy(t *testing.T) { + tests := []struct { + name string + rfName string + rfNamespace string + rfRedisPort int + rfNetworkPolicyNamespaceEntries []redisfailoverv1.NetworkPolicyNamespaceEntry + rfLabels map[string]string + expected networkingv1.NetworkPolicy + }{ + { + name: "with defaults", + rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: namespace, + }, + }, + expected: networkingv1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rfr-np-" + name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "redis", + "app.kubernetes.io/name": name, + "app.kubernetes.io/part-of": "redis-failover", + }, + Annotations: nil, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "testing", + }, + }, + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "redisfailovers.databases.spotahome.com/component": "redis", + "redisfailovers.databases.spotahome.com/name": name, + }, + }, + Ingress: []networkingv1.NetworkPolicyIngressRule{ + networkingv1.NetworkPolicyIngressRule{ + From: []networkingv1.NetworkPolicyPeer{ + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": namespace, + }, + }, + }, + }, + Ports: []networkingv1.NetworkPolicyPort{ + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 6379, + Type: intstr.Int, + }, + }, + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 9121, + Type: intstr.Int, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "with custom redis Port", + rfRedisPort: 6698, + rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: namespace, + }, + }, + expected: networkingv1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rfr-np-" + name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "redis", + "app.kubernetes.io/name": name, + "app.kubernetes.io/part-of": "redis-failover", + }, + Annotations: nil, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "testing", + }, + }, + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "redisfailovers.databases.spotahome.com/component": "redis", + "redisfailovers.databases.spotahome.com/name": name, + }, + }, + Ingress: []networkingv1.NetworkPolicyIngressRule{ + networkingv1.NetworkPolicyIngressRule{ + From: []networkingv1.NetworkPolicyPeer{ + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": namespace, + }, + }, + }, + }, + Ports: []networkingv1.NetworkPolicyPort{ + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 6698, + Type: intstr.Int, + }, + }, + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 9121, + Type: intstr.Int, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "with custom NetorkPolicyNamespaceEntries", + rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: namespace, + }, + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: "extra-namespace", + }, + }, + expected: networkingv1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rfr-np-" + name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "redis", + "app.kubernetes.io/name": name, + "app.kubernetes.io/part-of": "redis-failover", + }, + Annotations: nil, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "testing", + }, + }, + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "redisfailovers.databases.spotahome.com/component": "redis", + "redisfailovers.databases.spotahome.com/name": name, + }, + }, + Ingress: []networkingv1.NetworkPolicyIngressRule{ + networkingv1.NetworkPolicyIngressRule{ + From: []networkingv1.NetworkPolicyPeer{ + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": namespace, + }, + }, + }, + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": "extra-namespace", + }, + }, + }, + }, + Ports: []networkingv1.NetworkPolicyPort{ + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 6379, + Type: intstr.Int, + }, + }, + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 9121, + Type: intstr.Int, + }, + }, + }, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert := assert.New(t) + + // Generate a default RedisFailover and attaching the required annotations + rf := generateRF() + if test.rfName != "" { + rf.Name = test.rfName + } + if test.rfNamespace != "" { + rf.Namespace = test.rfNamespace + } + if test.rfRedisPort <= 0 { + rf.Spec.Redis.Port = 6379 + + } else { + rf.Spec.Redis.Port = redisfailoverv1.Port(test.rfRedisPort) + } + if test.rfNetworkPolicyNamespaceEntries != nil { + rf.Spec.NetworkPolicyNsList = test.rfNetworkPolicyNamespaceEntries + } + + generated := networkingv1.NetworkPolicy{} + + ms := &mK8SService.Services{} + ms.On("CreateOrUpdateNetworkPolicy", rf.Namespace, mock.Anything).Once().Run(func(args mock.Arguments) { + s := args.Get(1).(*networkingv1.NetworkPolicy) + generated = *s + }).Return(nil) + + client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy) + err := client.EnsureRedisNetworkPolicy(rf, test.rfLabels, []metav1.OwnerReference{{Name: "testing"}}) + + assert.Equal(test.expected, generated) + assert.NoError(err) + }) + } +} + +func TestSentinelNetworkPolicy(t *testing.T) { + tests := []struct { + name string + rfName string + rfNamespace string + rfSentinelPort int + rfNetworkPolicyNamespaceEntries []redisfailoverv1.NetworkPolicyNamespaceEntry + rfLabels map[string]string + expected networkingv1.NetworkPolicy + }{ + { + name: "with defaults", + rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: namespace, + }, + }, + expected: networkingv1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rfs-np-" + name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "sentinel", + "app.kubernetes.io/name": name, + "app.kubernetes.io/part-of": "redis-failover", + }, + Annotations: nil, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "testing", + }, + }, + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "redisfailovers.databases.spotahome.com/component": "sentinel", + "redisfailovers.databases.spotahome.com/name": name, + }, + }, + Ingress: []networkingv1.NetworkPolicyIngressRule{ + networkingv1.NetworkPolicyIngressRule{ + From: []networkingv1.NetworkPolicyPeer{ + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": namespace, + }, + }, + }, + }, + Ports: []networkingv1.NetworkPolicyPort{ + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 26379, + Type: intstr.Int, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "with custom sentinel Port", + rfSentinelPort: 17781, + rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: namespace, + }, + }, + expected: networkingv1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rfs-np-" + name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "sentinel", + "app.kubernetes.io/name": name, + "app.kubernetes.io/part-of": "redis-failover", + }, + Annotations: nil, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "testing", + }, + }, + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "redisfailovers.databases.spotahome.com/component": "sentinel", + "redisfailovers.databases.spotahome.com/name": name, + }, + }, + Ingress: []networkingv1.NetworkPolicyIngressRule{ + networkingv1.NetworkPolicyIngressRule{ + From: []networkingv1.NetworkPolicyPeer{ + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": namespace, + }, + }, + }, + }, + Ports: []networkingv1.NetworkPolicyPort{ + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 17781, + Type: intstr.Int, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "with custom NetorkPolicyNamespaceEntries", + rfNetworkPolicyNamespaceEntries: []redisfailoverv1.NetworkPolicyNamespaceEntry{ + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: namespace, + }, + redisfailoverv1.NetworkPolicyNamespaceEntry{ + MatchLabelKey: "app.kubernetes.io/instance", + MatchLabelValue: "extra-namespace", + }, + }, + expected: networkingv1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rfs-np-" + name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "sentinel", + "app.kubernetes.io/name": name, + "app.kubernetes.io/part-of": "redis-failover", + }, + Annotations: nil, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "testing", + }, + }, + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "redisfailovers.databases.spotahome.com/component": "sentinel", + "redisfailovers.databases.spotahome.com/name": name, + }, + }, + Ingress: []networkingv1.NetworkPolicyIngressRule{ + networkingv1.NetworkPolicyIngressRule{ + From: []networkingv1.NetworkPolicyPeer{ + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": namespace, + }, + }, + }, + networkingv1.NetworkPolicyPeer{ + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/instance": "extra-namespace", + }, + }, + }, + }, + Ports: []networkingv1.NetworkPolicyPort{ + networkingv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + IntVal: 26379, + Type: intstr.Int, + }, + }, + }, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert := assert.New(t) + + // Generate a default RedisFailover and attaching the required annotations + rf := generateRF() + if test.rfName != "" { + rf.Name = test.rfName + } + if test.rfNamespace != "" { + rf.Namespace = test.rfNamespace + } + if test.rfSentinelPort != 0 { + rf.Spec.Sentinel.Port = redisfailoverv1.Port(test.rfSentinelPort) + } + if test.rfNetworkPolicyNamespaceEntries != nil { + rf.Spec.NetworkPolicyNsList = test.rfNetworkPolicyNamespaceEntries + } + + generated := networkingv1.NetworkPolicy{} + + ms := &mK8SService.Services{} + ms.On("CreateOrUpdateNetworkPolicy", rf.Namespace, mock.Anything).Once().Run(func(args mock.Arguments) { + s := args.Get(1).(*networkingv1.NetworkPolicy) + generated = *s + }).Return(nil) + + client := rfservice.NewRedisFailoverKubeClient(ms, log.Dummy, metrics.Dummy) + err := client.EnsureSentinelNetworkPolicy(rf, test.rfLabels, []metav1.OwnerReference{{Name: "testing"}}) + + assert.Equal(test.expected, generated) + assert.NoError(err) + }) + } +} + func TestRedisMasterService(t *testing.T) { tests := []struct { name string diff --git a/operator/redisfailover/service/names.go b/operator/redisfailover/service/names.go index 7d4352ba0..9dc985b67 100644 --- a/operator/redisfailover/service/names.go +++ b/operator/redisfailover/service/names.go @@ -34,9 +34,14 @@ func GetSentinelName(rf *redisfailoverv1.RedisFailover) string { return generateName(sentinelName, rf.Name) } -// GetSentinelName returns the name for sentinel resources -func GetNetworkPolicyName(rf *redisfailoverv1.RedisFailover) string { - return generateName(networkPolicyName, rf.Name) +// GetRedisNetworkPolicyName returns the name for the redis network policy +func GetRedisNetworkPolicyName(rf *redisfailoverv1.RedisFailover) string { + return generateName(redisNetworkPolicyName, rf.Name) +} + +// GetSentinelNetworkPolicyName returns the name for the sentinel network policy +func GetSentinelNetworkPolicyName(rf *redisfailoverv1.RedisFailover) string { + return generateName(sentinelNetworkPolicyName, rf.Name) } func GetRedisMasterName(rf *redisfailoverv1.RedisFailover) string {