Skip to content

Commit

Permalink
Generate New HAProxy Service For Redis Replication (#40)
Browse files Browse the repository at this point in the history
This Pull Request presents a different method compared to [Add Redis
Slave Endpoint to HAProxy Service
configuration](#35).
Here, the redis-operator will establish a completely new HAProxy
service, designed to route traffic specifically to Redis instances
functioning as slaves.
  • Loading branch information
rurkss authored Jan 18, 2024
1 parent b36b764 commit 2e211f7
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 62 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Also check this project's [releases](https://github.com/powerhome/redis-operator

## Unreleased

### Added
- [Set up a new HAProxy service for routing traffic specifically to Redis nodes set as slaves][https://github.com/powerhome/redis-operator/pull/40]

## [v1.8.0] - 2024-01-16

### Fixed
Expand Down
54 changes: 48 additions & 6 deletions mocks/operator/redisfailover/service/RedisFailoverClient.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 16 additions & 3 deletions operator/redisfailover/ensurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,34 @@ func (w *RedisFailoverHandler) Ensure(rf *redisfailoverv1.RedisFailover, labels
}

if rf.Spec.Haproxy != nil {
if err := w.rfService.EnsureHAProxyService(rf, labels, or); err != nil {
if err := w.rfService.EnsureHAProxyRedisMasterService(rf, labels, or); err != nil {
return err
}

if err := w.rfService.EnsureRedisHeadlessService(rf, labels, or); err != nil {
return err
}

if err := w.rfService.EnsureHAProxyConfigmap(rf, labels, or); err != nil {
if err := w.rfService.EnsureHAProxyRedisMasterConfigmap(rf, labels, or); err != nil {
return err
}

if err := w.rfService.EnsureHAProxyDeployment(rf, labels, or); err != nil {
if err := w.rfService.EnsureHAProxyRedisMasterDeployment(rf, labels, or); err != nil {
return err
}

if err := w.rfService.EnsureHAProxyRedisSlaveService(rf, labels, or); err != nil {
return err
}

if err := w.rfService.EnsureHAProxyRedisSlaveConfigmap(rf, labels, or); err != nil {
return err
}

if err := w.rfService.EnsureHAProxyRedisSlaveDeployment(rf, labels, or); err != nil {
return err
}

}

if err := w.rfService.EnsureRedisMasterService(rf, labels, or); err != nil {
Expand Down
25 changes: 25 additions & 0 deletions operator/redisfailover/ensurer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func TestEnsure(t *testing.T) {
exporter bool
bootstrapping bool
bootstrappingAllowSentinels bool
haproxy bool
}{
{
name: "Call everything, use exporter",
Expand All @@ -89,6 +90,13 @@ func TestEnsure(t *testing.T) {
bootstrapping: true,
bootstrappingAllowSentinels: true,
},
{
name: "with haproxy enabled",
exporter: false,
bootstrapping: false,
bootstrappingAllowSentinels: false,
haproxy: true,
},
}

for _, test := range tests {
Expand All @@ -98,6 +106,12 @@ func TestEnsure(t *testing.T) {
rf := generateRF(test.exporter, test.bootstrapping)
if test.bootstrapping {
rf.Spec.BootstrapNode.AllowSentinels = test.bootstrappingAllowSentinels
} else {
rf.Spec.BootstrapNode = nil
}

if test.haproxy {
rf.Spec.Haproxy = &redisfailoverv1.HaproxySettings{}
}

config := generateConfig()
Expand All @@ -119,6 +133,17 @@ func TestEnsure(t *testing.T) {
mrfs.On("DestroySentinelResources", rf, mock.Anything, mock.Anything).Once().Return(nil)
}

if test.haproxy {
mrfs.On("EnsureHAProxyRedisMasterService", rf, mock.Anything, mock.Anything).Once().Return(nil)
mrfs.On("EnsureRedisHeadlessService", rf, mock.Anything, mock.Anything).Once().Return(nil)
mrfs.On("EnsureHAProxyRedisMasterConfigmap", rf, mock.Anything, mock.Anything).Once().Return(nil)
mrfs.On("EnsureHAProxyRedisMasterDeployment", rf, mock.Anything, mock.Anything).Once().Return(nil)

mrfs.On("EnsureHAProxyRedisSlaveService", rf, mock.Anything, mock.Anything).Once().Return(nil)
mrfs.On("EnsureHAProxyRedisSlaveConfigmap", rf, mock.Anything, mock.Anything).Once().Return(nil)
mrfs.On("EnsureHAProxyRedisSlaveDeployment", rf, mock.Anything, mock.Anything).Once().Return(nil)
}

mrfs.On("EnsureRedisMasterService", rf, mock.Anything, mock.Anything).Once().Return(nil)
mrfs.On("EnsureRedisSlaveService", rf, mock.Anything, mock.Anything).Once().Return(nil)
mrfs.On("EnsureRedisConfigMap", rf, mock.Anything, mock.Anything).Once().Return(nil)
Expand Down
2 changes: 1 addition & 1 deletion operator/redisfailover/service/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ func (r *RedisFailoverChecker) IsHAProxyRunning(rFailover *redisfailoverv1.Redis
if rFailover.Spec.Haproxy == nil {
return true
}
haproxyName := rFailover.GenerateName(redisHAProxyName)
haproxyName := GetHaproxyMasterName(rFailover)
dp, err := r.k8sService.GetDeploymentPods(rFailover.Namespace, haproxyName)
return err == nil && len(dp.Items) > int(rFailover.Spec.Haproxy.Replicas-1) && AreAllRunning(dp, int(rFailover.Spec.Haproxy.Replicas))
}
Expand Down
59 changes: 44 additions & 15 deletions operator/redisfailover/service/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
// RedisFailoverClient has the minimumm methods that a Redis failover controller needs to satisfy
// in order to talk with K8s
type RedisFailoverClient interface {
EnsureHAProxyDeployment(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureHAProxyConfigmap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureHAProxyService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureHAProxyRedisMasterDeployment(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureHAProxyRedisMasterConfigmap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureHAProxyRedisMasterService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureRedisHeadlessService(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
Expand All @@ -33,6 +33,10 @@ type RedisFailoverClient interface {
EnsureRedisConfigMap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureNotPresentRedisService(rFailover *redisfailoverv1.RedisFailover) error

EnsureHAProxyRedisSlaveService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureHAProxyRedisSlaveConfigmap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error
EnsureHAProxyRedisSlaveDeployment(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error

DestroySentinelResources(rFailover *redisfailoverv1.RedisFailover) error
UpdateStatus(rFailover *redisfailoverv1.RedisFailover) (*redisfailoverv1.RedisFailover, error)
}
Expand Down Expand Up @@ -99,11 +103,11 @@ func (r *RedisFailoverKubeClient) EnsureSentinelNetworkPolicy(rf *redisfailoverv
return err
}

// EnsureHAProxyService makes sure the HAProxy service exists
func (r *RedisFailoverKubeClient) EnsureHAProxyService(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
svc := generateHAProxyService(rf, labels, ownerRefs)
// EnsureHAProxyRedisMasterService makes sure the HAProxy service exists
func (r *RedisFailoverKubeClient) EnsureHAProxyRedisMasterService(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
svc := generateHAProxyRedisMasterService(rf, labels, ownerRefs)
err := r.K8SService.CreateOrUpdateService(rf.Namespace, svc)
r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureHAProxyService", rf.Name, err)
r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureHAProxyRedisMasterService", rf.Name, err)
return err
}

Expand All @@ -115,20 +119,45 @@ func (r *RedisFailoverKubeClient) EnsureRedisHeadlessService(rf *redisfailoverv1
return err
}

// EnsureHAProxyConfigmap makes sure the HAProxy configmap exists
func (r *RedisFailoverKubeClient) EnsureHAProxyConfigmap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
svc := generateHAProxyConfigmap(rf, labels, ownerRefs)
// EnsureHAProxyRedisMasterConfigmap makes sure the HAProxy configmap exists
func (r *RedisFailoverKubeClient) EnsureHAProxyRedisMasterConfigmap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
svc := generateHAProxyRedisMasterConfigmap(rf, labels, ownerRefs)
err := r.K8SService.CreateOrUpdateConfigMap(rf.Namespace, svc)
r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureHAProxyRedisMasterConfigmap", rf.Name, err)
return err
}

// EnsureHAProxyRedisMasterDeployment makes sure the sentinel deployment exists in the desired state
func (r *RedisFailoverKubeClient) EnsureHAProxyRedisMasterDeployment(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
d := generateHAProxyRedisMasterDeployment(rf, labels, ownerRefs)
err := r.K8SService.CreateOrUpdateDeployment(rf.Namespace, d)

r.setEnsureOperationMetrics(d.Namespace, d.Name, "EnsureHAProxyRedisMasterDeployment", rf.Name, err)
return err
}

// EnsureHAProxyRedisSlaveService makes sure the HAProxy service exists
func (r *RedisFailoverKubeClient) EnsureHAProxyRedisSlaveService(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
svc := generateHAProxyRedisSlaveService(rf, labels, ownerRefs)
err := r.K8SService.CreateOrUpdateService(rf.Namespace, svc)
r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureHAProxyRedisMasterService", rf.Name, err)
return err
}

// EnsureHAProxyRedisSlaveConfigmap makes sure the HAProxy configmap exists
func (r *RedisFailoverKubeClient) EnsureHAProxyRedisSlaveConfigmap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
svc := generateHAProxyRedisSlaveConfigmap(rf, labels, ownerRefs)
err := r.K8SService.CreateOrUpdateConfigMap(rf.Namespace, svc)
r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureHAProxyConfigmap", rf.Name, err)
r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "EnsureHAProxyRedisMasterConfigmap", rf.Name, err)
return err
}

// EnsureHAProxyDeployment makes sure the sentinel deployment exists in the desired state
func (r *RedisFailoverKubeClient) EnsureHAProxyDeployment(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
d := generateHAProxyDeployment(rf, labels, ownerRefs)
// EnsureHAProxyRedisSlaveDeployment makes sure the deployment exists in the desired state
func (r *RedisFailoverKubeClient) EnsureHAProxyRedisSlaveDeployment(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error {
d := generateHAProxyRedisSlaveDeployment(rf, labels, ownerRefs)
err := r.K8SService.CreateOrUpdateDeployment(rf.Namespace, d)

r.setEnsureOperationMetrics(d.Namespace, d.Name, "EnsureHAProxyDeployment", rf.Name, err)
r.setEnsureOperationMetrics(d.Namespace, d.Name, "EnsureHAProxyRedisMasterDeployment", rf.Name, err)
return err
}

Expand Down
32 changes: 17 additions & 15 deletions operator/redisfailover/service/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ const (
)

const (
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"
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"
redisHAProxySlaveRedisName = "rs-haproxy"
redisHAProxyMasterRedisName = "rm-haproxy"
)

const (
Expand Down
Loading

0 comments on commit 2e211f7

Please sign in to comment.