Skip to content

Commit 1dd5a39

Browse files
authored
fix: Unassigned slots and abnormal status in single-node cluster (#1483)
* Fix the issue where slots are not allocated and the cluster is not initialized when only one cluster shard is started in single instance Signed-off-by: tcxdgit <[email protected]> * File is not properly formatted Signed-off-by: tcxdgit <[email protected]> * refactor code for improved organization and clarity Signed-off-by: tcxdgit <[email protected]> * refactor code for improved organization and clarity Signed-off-by: tcxdgit <[email protected]> --------- Signed-off-by: tcxdgit <[email protected]>
1 parent c805ffb commit 1dd5a39

File tree

4 files changed

+74
-0
lines changed

4 files changed

+74
-0
lines changed

internal/cmd/manager/cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ func setupControllers(mgr ctrl.Manager, k8sClient kubernetes.Interface, maxConcu
242242
Client: mgr.GetClient(),
243243
K8sClient: k8sClient,
244244
Healer: healer,
245+
Checker: redis.NewChecker(k8sClient),
245246
Recorder: mgr.GetEventRecorderFor("rediscluster-controller"),
246247
StatefulSet: k8sutils.NewStatefulSetService(k8sClient),
247248
}).SetupWithManager(mgr, controller.Options{MaxConcurrentReconciles: maxConcurrentReconciles}); err != nil {

internal/controller/common/redis/check.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strings"
88

99
commonapi "github.com/OT-CONTAINER-KIT/redis-operator/api/common/v1beta2"
10+
rcvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/rediscluster/v1beta2"
1011
rr "github.com/OT-CONTAINER-KIT/redis-operator/api/redisreplication/v1beta2"
1112
"github.com/OT-CONTAINER-KIT/redis-operator/internal/service/redis"
1213
corev1 "k8s.io/api/core/v1"
@@ -17,6 +18,7 @@ import (
1718
type Checker interface {
1819
GetMasterFromReplication(ctx context.Context, rr *rr.RedisReplication) (corev1.Pod, error)
1920
GetPassword(ctx context.Context, ns string, secret *commonapi.ExistingPasswordSecret) (string, error)
21+
CheckClusterSlotsAssigned(ctx context.Context, cr *rcvb2.RedisCluster) (bool, error)
2022
}
2123

2224
type checker struct {
@@ -101,3 +103,28 @@ func (c *checker) GetMasterFromReplication(ctx context.Context, rr *rr.RedisRepl
101103
}
102104
return realMasterPod, nil
103105
}
106+
107+
// CheckClusterSlotsAssigned verifies if all Redis cluster slots (16384 total) are properly assigned
108+
func (c *checker) CheckClusterSlotsAssigned(ctx context.Context, cr *rcvb2.RedisCluster) (bool, error) {
109+
leaderPodName := cr.Name + "-leader-0"
110+
pod, err := c.k8s.CoreV1().Pods(cr.Namespace).Get(ctx, leaderPodName, metav1.GetOptions{})
111+
if err != nil {
112+
return false, err
113+
}
114+
115+
password, err := c.GetPassword(ctx, cr.Namespace, cr.Spec.KubernetesConfig.ExistingPasswordSecret)
116+
if err != nil {
117+
return false, err
118+
}
119+
120+
connInfo := createConnectionInfo(ctx, *pod, password, cr.Spec.TLS, c.k8s, cr.Namespace, "6379")
121+
122+
clusterStatus, err := c.redis.Connect(connInfo).GetClusterInfo(ctx)
123+
if err != nil {
124+
return false, err
125+
}
126+
127+
allAssigned := clusterStatus.SlotsAssigned == 16384
128+
129+
return allAssigned, nil
130+
}

internal/controller/rediscluster/rediscluster_controller.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type Reconciler struct {
4848
client.Client
4949
k8sutils.StatefulSet
5050
Healer redis.Healer
51+
Checker redis.Checker
5152
K8sClient kubernetes.Interface
5253
Recorder record.EventRecorder
5354
}
@@ -190,6 +191,19 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
190191
}
191192
}
192193

194+
// When the number of leader replicas is 1 (single-node cluster)
195+
if leaderReplicas == 1 {
196+
// Check if the Redis cluster has no unassigned slots (i.e., all slots are properly allocated)
197+
if slotsAssigned, err := r.Checker.CheckClusterSlotsAssigned(ctx, instance); err != nil {
198+
return intctrlutil.RequeueE(ctx, err, "failed to get cluster slots")
199+
} else {
200+
if !slotsAssigned {
201+
logger.Info("Start creating a single-node redis cluster")
202+
k8sutils.ExecuteRedisClusterCommand(ctx, r.K8sClient, instance)
203+
}
204+
}
205+
}
206+
193207
if nc := k8sutils.CheckRedisNodeCount(ctx, r.K8sClient, instance, ""); nc != totalReplicas {
194208
logger.Info("Creating redis cluster by executing cluster creation commands")
195209
leaderCount := k8sutils.CheckRedisNodeCount(ctx, r.K8sClient, instance, "leader")

internal/service/redis/client.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ type ConnectionInfo struct {
2424
TLSConfig *tls.Config
2525
}
2626

27+
// ClusterStatus cluster status information, including the number of assigned slots
28+
type ClusterStatus struct {
29+
SlotsAssigned int // Total number of assigned slots
30+
}
31+
2732
// GetAddress returns the connection address
2833
func (c *ConnectionInfo) GetAddress() string {
2934
return net.JoinHostPort(c.Host, c.Port)
@@ -50,6 +55,7 @@ type Service interface {
5055
GetAttachedReplicaCount(ctx context.Context) (int, error)
5156
SentinelMonitor(ctx context.Context, master *ConnectionInfo, masterGroupName, quorum string) error
5257
SentinelReset(ctx context.Context, masterGroupName string) error
58+
GetClusterInfo(ctx context.Context) (*ClusterStatus, error)
5359
}
5460

5561
type service struct {
@@ -175,3 +181,29 @@ func (c *service) GetAttachedReplicaCount(ctx context.Context) (int, error) {
175181
}
176182
return count, nil
177183
}
184+
185+
// GetClusterInfo get cluster information by checking slot allocation
186+
func (c *service) GetClusterInfo(ctx context.Context) (*ClusterStatus, error) {
187+
client := c.createClient()
188+
if client == nil {
189+
return nil, nil
190+
}
191+
defer client.Close()
192+
193+
slots, err := client.ClusterSlots(ctx).Result()
194+
if err != nil {
195+
return nil, err
196+
}
197+
198+
status := &ClusterStatus{
199+
SlotsAssigned: 0,
200+
}
201+
202+
for _, slot := range slots {
203+
if slot.Start <= slot.End && len(slot.Nodes) > 0 {
204+
status.SlotsAssigned += slot.End - slot.Start + 1
205+
}
206+
}
207+
208+
return status, nil
209+
}

0 commit comments

Comments
 (0)