Skip to content

Commit

Permalink
refactor: watch statefulset to make creation process faster
Browse files Browse the repository at this point in the history
Signed-off-by: drivebyer <[email protected]>
  • Loading branch information
drivebyer committed Jun 14, 2024
1 parent 46ded9f commit dd362ad
Show file tree
Hide file tree
Showing 18 changed files with 51 additions and 78 deletions.
31 changes: 5 additions & 26 deletions controllers/rediscluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ package controllers

import (
"context"
"strconv"
"time"

"github.com/OT-CONTAINER-KIT/redis-operator/api/status"
redisv1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/v1beta2"
"github.com/OT-CONTAINER-KIT/redis-operator/k8sutils"
intctrlutil "github.com/OT-CONTAINER-KIT/redis-operator/pkg/controllerutil"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/api/errors"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -123,15 +122,6 @@ func (r *RedisClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request
return intctrlutil.RequeueWithError(err, reqLogger, "")
}

// todo: remove me after watch statefulset in controller
redisLeaderInfo, err := k8sutils.GetStatefulSet(r.K8sClient, r.Log, instance.GetNamespace(), instance.GetName()+"-leader")
if err != nil {
if errors.IsNotFound(err) {
return intctrlutil.RequeueAfter(reqLogger, time.Second*60, "")
}
return intctrlutil.RequeueWithError(err, reqLogger, "")
}

if r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-leader") {
// Mark the cluster status as initializing if there are no follower nodes
if (instance.Status.ReadyLeaderReplicas == 0 && instance.Status.ReadyFollowerReplicas == 0) ||
Expand All @@ -157,21 +147,9 @@ func (r *RedisClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request
return intctrlutil.RequeueWithError(err, reqLogger, "")
}
}
// todo: remove me after watch statefulset in controller
redisFollowerInfo, err := k8sutils.GetStatefulSet(r.K8sClient, r.Log, instance.GetNamespace(), instance.GetName()+"-follower")
if err != nil {
if errors.IsNotFound(err) {
return intctrlutil.RequeueAfter(reqLogger, time.Second*60, "")
}
return intctrlutil.RequeueWithError(err, reqLogger, "")
}

if leaderReplicas == 0 {
return intctrlutil.RequeueAfter(reqLogger, time.Second*60, "Redis leaders Cannot be 0", "Ready.Replicas", strconv.Itoa(int(redisLeaderInfo.Status.ReadyReplicas)), "Expected.Replicas", leaderReplicas)
}

if !(r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-leader") && r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-follower")) {
return intctrlutil.RequeueAfter(reqLogger, time.Second*60, "Redis leader and follower nodes are not ready yet")
return intctrlutil.Reconciled()
}

// Mark the cluster status as bootstrapping if all the leader and follower nodes are ready
Expand All @@ -183,7 +161,7 @@ func (r *RedisClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request
}

if nc := k8sutils.CheckRedisNodeCount(ctx, r.K8sClient, r.Log, instance, ""); nc != totalReplicas {
reqLogger.Info("Creating redis cluster by executing cluster creation commands", "Leaders.Ready", redisLeaderInfo.Status.ReadyReplicas, "Followers.Ready", redisFollowerInfo.Status.ReadyReplicas)
reqLogger.Info("Creating redis cluster by executing cluster creation commands")

Check warning on line 164 in controllers/rediscluster_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/rediscluster_controller.go#L164

Added line #L164 was not covered by tests
leaderCount := k8sutils.CheckRedisNodeCount(ctx, r.K8sClient, r.Log, instance, "leader")
if leaderCount != leaderReplicas {
reqLogger.Info("Not all leader are part of the cluster...", "Leaders.Count", leaderCount, "Instance.Size", leaderReplicas)
Expand All @@ -199,7 +177,7 @@ func (r *RedisClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request
}
}
} else {
if followerReplicas > 0 && redisFollowerInfo.Status.ReadyReplicas == followerReplicas {
if followerReplicas > 0 {

Check warning on line 180 in controllers/rediscluster_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/rediscluster_controller.go#L180

Added line #L180 was not covered by tests
reqLogger.Info("All leader are part of the cluster, adding follower/replicas", "Leaders.Count", leaderCount, "Instance.Size", leaderReplicas, "Follower.Replicas", followerReplicas)
k8sutils.ExecuteRedisReplicationCommand(ctx, r.K8sClient, r.Log, instance)
} else {
Expand Down Expand Up @@ -239,5 +217,6 @@ func (r *RedisClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request
func (r *RedisClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&redisv1beta2.RedisCluster{}).
Owns(&appsv1.StatefulSet{}).
Complete(r)
}
24 changes: 7 additions & 17 deletions controllers/redisreplication_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package controllers

import (
"context"
"strconv"
"time"

redisv1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/v1beta2"
"github.com/OT-CONTAINER-KIT/redis-operator/k8sutils"
intctrlutil "github.com/OT-CONTAINER-KIT/redis-operator/pkg/controllerutil"
"github.com/go-logr/logr"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
Expand All @@ -21,6 +21,7 @@ import (
type RedisReplicationReconciler struct {
client.Client
k8sutils.Pod
k8sutils.StatefulSet
K8sClient kubernetes.Interface
Dk8sClient dynamic.Interface
Log logr.Logger
Expand All @@ -46,10 +47,6 @@ func (r *RedisReplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
return intctrlutil.RequeueAfter(reqLogger, time.Second*10, "found skip reconcile annotation")
}

leaderReplicas := int32(1)
followerReplicas := instance.Spec.GetReplicationCounts("replication") - leaderReplicas
totalReplicas := leaderReplicas + followerReplicas

if err = k8sutils.AddFinalizer(instance, k8sutils.RedisReplicationFinalizer, r.Client); err != nil {
return intctrlutil.RequeueWithError(err, reqLogger, "")
}
Expand All @@ -63,22 +60,14 @@ func (r *RedisReplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
return intctrlutil.RequeueWithError(err, reqLogger, "")
}

// Set Pod distruptiuon Budget Later

redisReplicationInfo, err := k8sutils.GetStatefulSet(r.K8sClient, r.Log, instance.GetNamespace(), instance.GetName())
if err != nil {
return intctrlutil.RequeueAfter(reqLogger, time.Second*60, "")
}

// Check that the Leader and Follower are ready in redis replication
if redisReplicationInfo.Status.ReadyReplicas != totalReplicas {
return intctrlutil.RequeueAfter(reqLogger, time.Second*60, "Redis replication nodes are not ready yet", "Ready.Replicas", redisReplicationInfo.Status.ReadyReplicas, "Expected.Replicas", totalReplicas)
if !r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name) {
return intctrlutil.Reconciled()
}

var realMaster string
masterNodes := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, r.Log, instance, "master")
if len(masterNodes) > int(leaderReplicas) {
reqLogger.Info("Creating redis replication by executing replication creation commands", "Replication.Ready", strconv.Itoa(int(redisReplicationInfo.Status.ReadyReplicas)))
if len(masterNodes) > 1 {
reqLogger.Info("Creating redis replication by executing replication creation commands")

Check warning on line 70 in controllers/redisreplication_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/redisreplication_controller.go#L69-L70

Added lines #L69 - L70 were not covered by tests
slaveNodes := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, r.Log, instance, "slave")
realMaster = k8sutils.GetRedisReplicationRealMaster(ctx, r.K8sClient, r.Log, instance, masterNodes)
if len(slaveNodes) == 0 {
Expand Down Expand Up @@ -138,5 +127,6 @@ func (r *RedisReplicationReconciler) UpdateRedisPodRoleLabel(ctx context.Context
func (r *RedisReplicationReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&redisv1beta2.RedisReplication{}).
Owns(&appsv1.StatefulSet{}).
Complete(r)
}
15 changes: 9 additions & 6 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,24 @@ var _ = BeforeSuite(func() {
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

rrLog := ctrl.Log.WithName("controllers").WithName("RedisReplication")
rcLog := ctrl.Log.WithName("controllers").WithName("RedisCluster")
err = (&RedisClusterReconciler{
Client: k8sManager.GetClient(),
K8sClient: k8sClient,
Dk8sClient: dk8sClient,
Scheme: k8sManager.GetScheme(),
StatefulSet: k8sutils.NewStatefulSetService(k8sClient, rrLog),
StatefulSet: k8sutils.NewStatefulSetService(k8sClient, rcLog),
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

rrLog := ctrl.Log.WithName("controllers").WithName("RedisReplication")
err = (&RedisReplicationReconciler{
Client: k8sManager.GetClient(),
K8sClient: k8sClient,
Dk8sClient: dk8sClient,
Scheme: k8sManager.GetScheme(),
Client: k8sManager.GetClient(),
K8sClient: k8sClient,
Dk8sClient: dk8sClient,
Scheme: k8sManager.GetScheme(),
StatefulSet: k8sutils.NewStatefulSetService(k8sClient, rrLog),
Pod: k8sutils.NewPodService(k8sClient, rrLog),
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

Expand Down
13 changes: 7 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,13 @@ func main() {
}
rrLog := ctrl.Log.WithName("controllers").WithName("RedisReplication")
if err = (&controllers.RedisReplicationReconciler{
Client: mgr.GetClient(),
K8sClient: k8sclient,
Dk8sClient: dk8sClient,
Log: rrLog,
Scheme: mgr.GetScheme(),
Pod: k8sutils.NewPodService(k8sclient, rrLog),
Client: mgr.GetClient(),
K8sClient: k8sclient,
Dk8sClient: dk8sClient,
Log: rrLog,
Scheme: mgr.GetScheme(),
Pod: k8sutils.NewPodService(k8sclient, rrLog),
StatefulSet: k8sutils.NewStatefulSetService(k8sclient, rrLog),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "RedisReplication")
os.Exit(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,7 @@ spec:
selector: control-plane=redis-operator
container: manager
tail: -1 # tail all logs
- name: Sleep for five minutes
try:
- sleep:
duration: 5m

- name: Ping Cluster Nodes
try:
- script:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ spec:
timeout: 5m
content: |
sudo apt install redis-tools -y
- name: Sleep for five minutes
try:
- sleep:
duration: 5m
- name: Ping Redis Cluster from every node
try:
- script:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ spec:
file: ready-svc.yaml
- assert:
file: ready-pvc.yaml
- name: Sleep for five minutes
try:
- sleep:
duration: 5m

- name: Ping Cluster
try:
- script:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ spec:
file: ready-pvc.yaml
- assert:
file: secret.yaml
- name: Sleep for five minutes
try:
- sleep:
duration: 5m

- name: Ping Cluster With Password
try:
- script:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ kind: RedisCluster
metadata:
name: redis-cluster-v1beta2
status:
state: Ready
reason: RedisCluster is ready
readyLeaderReplicas: 3
readyFollowerReplicas: 3
state: Ready
reason: RedisCluster is ready
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ spec:
selector: control-plane=redis-operator
container: manager
tail: -1 # tail all logs
# no need to wait for 5 minutes, when we have ready-cluster.yaml, we can proceed
# - name: Sleep for five minutes
# try:
# - sleep:
# duration: 3m

- name: Ping Cluster
try:
- script:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ metadata:
status:
readyFollowerReplicas: 3
readyLeaderReplicas: 3
state: Ready
reason: RedisCluster is ready

0 comments on commit dd362ad

Please sign in to comment.