diff --git a/operator/redisfailover/ensurer.go b/operator/redisfailover/ensurer.go index a16087e66..074f875ad 100644 --- a/operator/redisfailover/ensurer.go +++ b/operator/redisfailover/ensurer.go @@ -5,6 +5,9 @@ import ( redisfailoverv1 "github.com/spotahome/redis-operator/api/redisfailover/v1" "github.com/spotahome/redis-operator/metrics" + "github.com/spotahome/redis-operator/operator/redisfailover/util" + + rfservice "github.com/spotahome/redis-operator/operator/redisfailover/service" ) // Ensure is called to ensure all of the resources associated with a RedisFailover are created @@ -29,6 +32,8 @@ func (w *RedisFailoverHandler) Ensure(rf *redisfailoverv1.RedisFailover, labels } if rf.Spec.Haproxy != nil { + labels = util.MergeLabels(labels, rfservice.GetHAProxyRedisLabels()) + if err := w.rfService.EnsureHAProxyService(rf, labels, or); err != nil { return err } @@ -86,5 +91,21 @@ func (w *RedisFailoverHandler) Ensure(rf *redisfailoverv1.RedisFailover, labels } } + if rf.Spec.BootstrapNode != nil { + labels = util.MergeLabels(labels, rfservice.GetHAProxyRedisSlaveLabels()) + + if err := w.rfService.EnsureHAProxyService(rf, labels, or); err != nil { + return err + } + + if err := w.rfService.EnsureHAProxyConfigmap(rf, labels, or); err != nil { + return err + } + + if err := w.rfService.EnsureHAProxyDeployment(rf, labels, or); err != nil { + return err + } + } + return nil } diff --git a/operator/redisfailover/ensurer_test.go b/operator/redisfailover/ensurer_test.go index 4395f17f0..0b2be63ab 100644 --- a/operator/redisfailover/ensurer_test.go +++ b/operator/redisfailover/ensurer_test.go @@ -126,6 +126,10 @@ func TestEnsure(t *testing.T) { mrfs.On("EnsureRedisReadinessConfigMap", rf, mock.Anything, mock.Anything).Once().Return(nil) mrfs.On("EnsureRedisStatefulset", rf, mock.Anything, mock.Anything).Once().Return(nil) + mrfs.On("EnsureHAProxyService", rf, mock.Anything, mock.Anything).Once().Return(nil) + mrfs.On("EnsureHAProxyConfigmap", rf, mock.Anything, mock.Anything).Once().Return(nil) + mrfs.On("EnsureHAProxyDeployment", rf, mock.Anything, mock.Anything).Once().Return(nil) + // Create the Kops client and call the valid logic. handler := rfOperator.NewRedisFailoverHandler(config, mrfs, mrfc, mrfh, mk, metrics.Dummy, log.Dummy) err := handler.Ensure(rf, map[string]string{}, []metav1.OwnerReference{}, metrics.Dummy) diff --git a/operator/redisfailover/service/generator.go b/operator/redisfailover/service/generator.go index d4bb94faa..2c11603be 100644 --- a/operator/redisfailover/service/generator.go +++ b/operator/redisfailover/service/generator.go @@ -50,11 +50,32 @@ sentinel parallel-syncs mymaster 2` graceTime = 30 ) -const redisHAProxyName = "redis-haproxy" +const ( + rfLabelInstance = "app.kubernetes.io/instance" + redisHAProxyName = "redis-haproxy" + redisSlaveHAProxyName = "redis-s-haproxy" +) + +var ( + haproxyRedisSlaveLabels = map[string]string{ + rfLabelInstance: redisSlaveHAProxyName, + } + haproxyRedisLabels = map[string]string{ + rfLabelInstance: redisHAProxyName, + } +) + +func GetHAProxyRedisLabels() map[string]string { + return haproxyRedisLabels +} + +func GetHAProxyRedisSlaveLabels() map[string]string { + return haproxyRedisSlaveLabels +} func generateHAProxyDeployment(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *appsv1.Deployment { - name := rf.GenerateName(redisHAProxyName) + name := rf.GenerateName(labels[rfLabelInstance]) namespace := rf.Namespace @@ -131,7 +152,7 @@ func generateHAProxyDeployment(rf *redisfailoverv1.RedisFailover, labels map[str } func generateHAProxyConfigmap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *corev1.ConfigMap { - name := rf.GenerateName(redisHAProxyName) + name := rf.GenerateName(labels[rfLabelInstance]) redisName := rf.GenerateName("redis") namespace := rf.Namespace @@ -140,6 +161,11 @@ func generateHAProxyConfigmap(rf *redisfailoverv1.RedisFailover, labels map[stri "app.kubernetes.io/component": "redis", }) + redisRole := "role:master" + if labels[rfLabelInstance] == redisSlaveHAProxyName { + redisRole = "role:slave" + } + port := rf.Spec.Redis.Port haproxyCfg := fmt.Sprintf(`global daemon @@ -173,20 +199,20 @@ func generateHAProxyConfigmap(rf *redisfailoverv1.RedisFailover, labels map[stri hold valid 10s hold obsolete 10s - frontend redis-master + frontend redis-instance bind *:%d - default_backend redis-master + default_backend redis-instance - backend redis-master + backend redis-instance mode tcp balance first option tcp-check tcp-check send info\ replication\r\n - tcp-check expect string role:master + tcp-check expect string %s server-template redis %d _redis._tcp.%s.%s.svc.cluster.local:%d check inter 1s resolvers k8s init-addr none -`, port, rf.Spec.Redis.Replicas, redisName, namespace, port) +`, port, redisRole, rf.Spec.Redis.Replicas, redisName, namespace, port) - if rf.Spec.Haproxy.CustomConfig != "" { + if rf.Spec.Haproxy.CustomConfig != "" && labels[rfLabelInstance] != redisSlaveHAProxyName { haproxyCfg = rf.Spec.Haproxy.CustomConfig } @@ -239,9 +265,10 @@ func generateRedisHeadlessService(rf *redisfailoverv1.RedisFailover, labels map[ func generateHAProxyService(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *corev1.Service { name := rf.Spec.Haproxy.RedisHost - if name == "" { - name = redisHAProxyName + if name == "" || labels[rfLabelInstance] == redisSlaveHAProxyName { + name = rf.GenerateName(labels[rfLabelInstance]) } + namespace := rf.Namespace redisTargetPort := intstr.FromInt(int(rf.Spec.Redis.Port)) selectorLabels := map[string]string{ @@ -255,7 +282,7 @@ func generateHAProxyService(rf *redisfailoverv1.RedisFailover, labels map[string Type: "ClusterIP", Ports: []corev1.ServicePort{ { - Name: "redis-master", + Name: "redis-instance", Port: rf.Spec.Redis.Port.ToInt32(), TargetPort: redisTargetPort, Protocol: "TCP", diff --git a/operator/redisfailover/service/generator_test.go b/operator/redisfailover/service/generator_test.go index bb89f5b12..685c7f3f7 100644 --- a/operator/redisfailover/service/generator_test.go +++ b/operator/redisfailover/service/generator_test.go @@ -1295,8 +1295,8 @@ func TestRedisService(t *testing.T) { } func TestHaproxyService(t *testing.T) { - haproxyName := "redis-haproxy" - portName := "redis-master" + haproxyName := "redis-haproxy-test" + portName := "redis-instance" defaultRedisPort := redisfailoverv1.Port(6379) customClusterIP := "10.1.1.100" tests := []struct { @@ -1312,6 +1312,7 @@ func TestHaproxyService(t *testing.T) { { name: "with defaults", rfRedisPort: defaultRedisPort, + rfLabels: rfservice.GetHAProxyRedisLabels(), expectedService: corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: haproxyName, @@ -1321,12 +1322,16 @@ func TestHaproxyService(t *testing.T) { Name: "testing", }, }, + Labels: map[string]string{ + "app.kubernetes.io/instance": "redis-haproxy", + }, }, Spec: corev1.ServiceSpec{ Type: corev1.ServiceTypeClusterIP, Selector: map[string]string{ "app.kubernetes.io/component": "redis", "redisfailovers.databases.spotahome.com/component": "haproxy", + "app.kubernetes.io/instance": "redis-haproxy", }, Ports: []corev1.ServicePort{ { @@ -1342,6 +1347,7 @@ func TestHaproxyService(t *testing.T) { { name: "with custom ClusterIP", rfRedisPort: defaultRedisPort, + rfLabels: rfservice.GetHAProxyRedisLabels(), haproxy: redisfailoverv1.HaproxySettings{ Service: &redisfailoverv1.ServiceSettings{ ClusterIP: customClusterIP, @@ -1356,6 +1362,9 @@ func TestHaproxyService(t *testing.T) { Name: "testing", }, }, + Labels: map[string]string{ + "app.kubernetes.io/instance": "redis-haproxy", + }, }, Spec: corev1.ServiceSpec{ Type: corev1.ServiceTypeClusterIP, @@ -1363,6 +1372,42 @@ func TestHaproxyService(t *testing.T) { Selector: map[string]string{ "app.kubernetes.io/component": "redis", "redisfailovers.databases.spotahome.com/component": "haproxy", + "app.kubernetes.io/instance": "redis-haproxy", + }, + Ports: []corev1.ServicePort{ + { + Name: portName, + Port: defaultRedisPort.ToInt32(), + TargetPort: intstr.FromInt(int(defaultRedisPort)), + Protocol: corev1.ProtocolTCP, + }, + }, + }, + }, + }, + { + name: "with HAProxy Redis Slave Labels", + rfRedisPort: defaultRedisPort, + rfLabels: rfservice.GetHAProxyRedisSlaveLabels(), + expectedService: corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "redis-s-haproxy-test", + Namespace: namespace, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "testing", + }, + }, + Labels: map[string]string{ + "app.kubernetes.io/instance": "redis-s-haproxy", + }, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Selector: map[string]string{ + "app.kubernetes.io/component": "redis", + "redisfailovers.databases.spotahome.com/component": "haproxy", + "app.kubernetes.io/instance": "redis-s-haproxy", }, Ports: []corev1.ServicePort{ {