diff --git a/charts/dragonfly-operator/templates/deployment.yaml b/charts/dragonfly-operator/templates/deployment.yaml index 0c24699..ec600c2 100644 --- a/charts/dragonfly-operator/templates/deployment.yaml +++ b/charts/dragonfly-operator/templates/deployment.yaml @@ -36,8 +36,8 @@ spec: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ + - --secure-listen-address=[::]:8443 + - --upstream=http://[::1]:8080/ - --logtostderr=true - --v=0 image: "{{ .Values.rbacProxy.image.repository }}:{{ .Values.rbacProxy.image.tag }}" @@ -55,7 +55,7 @@ spec: - name: manager args: - --health-probe-bind-address=:8081 - - --metrics-bind-address=127.0.0.1:8080 + - --metrics-bind-address=[::1]:8080 - --leader-elect command: - /manager diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml index 801e9bb..b2c1c4d 100644 --- a/config/default/manager_auth_proxy_patch.yaml +++ b/config/default/manager_auth_proxy_patch.yaml @@ -33,8 +33,8 @@ spec: - "ALL" image: gcr.io/kubebuilder/kube-rbac-proxy:v0.16.0 args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8080/" + - "--secure-listen-address=[::]:8443" + - "--upstream=http://[::1]:8080/" - "--logtostderr=true" - "--v=0" ports: @@ -51,5 +51,5 @@ spec: - name: manager args: - "--health-probe-bind-address=:8081" - - "--metrics-bind-address=127.0.0.1:8080" + - "--metrics-bind-address=[::1]:8080" - "--leader-elect" diff --git a/internal/controller/dragonfly_instance.go b/internal/controller/dragonfly_instance.go index 0e2b143..671e9f2 100644 --- a/internal/controller/dragonfly_instance.go +++ b/internal/controller/dragonfly_instance.go @@ -207,7 +207,7 @@ func (dfi *DragonflyInstance) configureReplica(ctx context.Context, pod *corev1. // connected to the right master func (dfi *DragonflyInstance) checkReplicaRole(ctx context.Context, pod *corev1.Pod, masterIp string) (bool, error) { redisClient := redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("%s:%d", pod.Status.PodIP, resources.DragonflyAdminPort), + Addr: net.JoinHostPort(pod.Status.PodIP, strconv.Itoa(resources.DragonflyAdminPort)), }) defer redisClient.Close() @@ -235,8 +235,12 @@ func (dfi *DragonflyInstance) checkReplicaRole(ctx context.Context, pod *corev1. } } - if masterIp != redisMasterIp && masterIp != pod.Labels[resources.MasterIp] { - return false, nil + // for compatibily, to be remove in futur version + // check if the masterIp matches either the label (for compatibility) or the annotation + if masterIp != redisMasterIp { + if masterIp != pod.Labels[resources.MasterIpLabel] && masterIp != pod.Annotations[resources.MasterIp] { + return false, nil + } } return true, nil @@ -335,8 +339,11 @@ func (dfi *DragonflyInstance) replicaOf(ctx context.Context, pod *corev1.Pod, ma }) defer redisClient.Close() + // Sanitize masterIp in case ipv6 + masterIp = sanitizeIp(masterIp) + dfi.log.Info("Trying to invoke SLAVE OF command", "pod", pod.Name, "master", masterIp, "addr", redisClient.Options().Addr) - resp, err := redisClient.SlaveOf(ctx, masterIp, fmt.Sprint(resources.DragonflyAdminPort)).Result() + resp, err := redisClient.SlaveOf(ctx, masterIp, strconv.Itoa(resources.DragonflyAdminPort)).Result() if err != nil { return fmt.Errorf("error running SLAVE OF command: %s", err) } @@ -345,11 +352,20 @@ func (dfi *DragonflyInstance) replicaOf(ctx context.Context, pod *corev1.Pod, ma return fmt.Errorf("response of `SLAVE OF` on replica is not OK: %s", resp) } - dfi.log.Info("Marking pod role as replica", "pod", pod.Name) + dfi.log.Info("Marking pod role as replica", "pod", pod.Name, "masterIp", masterIp) pod.Labels[resources.Role] = resources.Replica - pod.Labels[resources.MasterIp] = masterIp + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + pod.Annotations[resources.MasterIp] = masterIp + + // for compatibily, to be remove in futur version + if !strings.Contains(masterIp, ":") { + pod.Labels[resources.MasterIpLabel] = masterIp + } + if err := dfi.client.Update(ctx, pod); err != nil { - return fmt.Errorf("could not update replica label") + return fmt.Errorf("could not update replica metadatas: %w", err) } return nil @@ -373,8 +389,20 @@ func (dfi *DragonflyInstance) replicaOfNoOne(ctx context.Context, pod *corev1.Po return fmt.Errorf("response of `SLAVE OF NO ONE` on master is not OK: %s", resp) } - dfi.log.Info("Marking pod role as master", "pod", pod.Name) + masterIp := pod.Status.PodIP + + dfi.log.Info("Marking pod role as master", "pod", pod.Name, "masterIp", masterIp) pod.Labels[resources.Role] = resources.Master + // for compatibily, to be remove in futur version + if !strings.Contains(masterIp, ":") { + pod.Labels[resources.MasterIpLabel] = masterIp + } + + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + pod.Annotations[resources.MasterIp] = masterIp + if err := dfi.client.Update(ctx, pod); err != nil { return err } diff --git a/internal/controller/util.go b/internal/controller/util.go index 562be1c..0bfb977 100644 --- a/internal/controller/util.go +++ b/internal/controller/util.go @@ -20,6 +20,8 @@ import ( "context" "errors" "fmt" + "net" + "strconv" "strings" "github.com/dragonflydb/dragonfly-operator/internal/resources" @@ -89,7 +91,7 @@ func getLatestReplica(ctx context.Context, c client.Client, statefulSet *appsv1. // replTakeover runs the replTakeOver on the given replica pod func replTakeover(ctx context.Context, c client.Client, newMaster *corev1.Pod) error { redisClient := redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("%s:%d", newMaster.Status.PodIP, resources.DragonflyAdminPort), + Addr: net.JoinHostPort(newMaster.Status.PodIP, strconv.Itoa(resources.DragonflyPort)), }) defer redisClient.Close() @@ -117,7 +119,7 @@ func isStableState(ctx context.Context, pod *corev1.Pod) (bool, error) { } redisClient := redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("%s:%d", pod.Status.PodIP, resources.DragonflyAdminPort), + Addr: net.JoinHostPort(pod.Status.PodIP, strconv.Itoa(resources.DragonflyAdminPort)), }) defer redisClient.Close() @@ -135,14 +137,7 @@ func isStableState(ctx context.Context, pod *corev1.Pod) (bool, error) { return false, errors.New("empty info") } - data := map[string]string{} - for _, line := range strings.Split(info, "\n") { - if line == "" || strings.HasPrefix(line, "#") { - continue - } - kv := strings.Split(line, ":") - data[kv[0]] = strings.TrimSuffix(kv[1], "\r") - } + data := parseRedisInfo(info) if data["master_sync_in_progress"] == "1" { return false, nil @@ -158,3 +153,23 @@ func isStableState(ctx context.Context, pod *corev1.Pod) (bool, error) { return true, nil } + +// Helper function to parse Redis INFO data +func parseRedisInfo(info string) map[string]string { + data := map[string]string{} + for _, line := range strings.Split(info, "\n") { + if line == "" || strings.HasPrefix(line, "#") { + continue + } + kv := strings.Split(line, ":") + if len(kv) == 2 { + data[kv[0]] = strings.TrimSuffix(kv[1], "\r") + } + } + return data +} + +// sanitizeIp Ipv6 +func sanitizeIp(masterIp string) string { + return strings.Trim(masterIp, "[]") +} diff --git a/internal/resources/const.go b/internal/resources/const.go index ec6a3b5..8f9d10f 100644 --- a/internal/resources/const.go +++ b/internal/resources/const.go @@ -56,7 +56,8 @@ const ( // KubernetesPartOfLabel is the name of a higher level application this one is part of KubernetesPartOfLabelKey = "app.kubernetes.io/part-of" - MasterIp string = "master-ip" + MasterIpLabel string = "master-ip" + MasterIp string = "operator.dragonflydb.io/masterIP" Role string = "role" @@ -68,6 +69,8 @@ const ( var DefaultDragonflyArgs = []string{ "--alsologtostderr", "--primary_port_http_enabled=false", + "--bind=::", + "--admin_bind=::", fmt.Sprintf("--admin_port=%d", DragonflyAdminPort), "--admin_nopass", } diff --git a/manifests/dragonfly-operator.yaml b/manifests/dragonfly-operator.yaml index 6cf779a..b11c219 100644 --- a/manifests/dragonfly-operator.yaml +++ b/manifests/dragonfly-operator.yaml @@ -2072,8 +2072,8 @@ spec: - linux containers: - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ + - --secure-listen-address=[::]:8443 + - --upstream=http://[::1]:8080/ - --logtostderr=true - --v=0 image: gcr.io/kubebuilder/kube-rbac-proxy:v0.16.0 @@ -2096,7 +2096,7 @@ spec: - ALL - args: - --health-probe-bind-address=:8081 - - --metrics-bind-address=127.0.0.1:8080 + - --metrics-bind-address=[::1]:8080 - --leader-elect command: - /manager