• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

chideat / valkey-operator / 13214360144

08 Feb 2025 09:25AM UTC coverage: 13.534%. First build
13214360144

push

github

web-flow
feat: added features for user, added suit tests (#2)

* chore: updated github actions

* feat: added user recocile, added suit tests

* fix: upgrade x/net for high cve

* fix: update test command

* chore: updated github actions

* chore: updated docker file

108 of 501 new or added lines in 31 files covered. (21.56%)

3048 of 22521 relevant lines covered (13.53%)

0.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

17.07
/internal/controller/failover_controller.go
1
/*
2
Copyright 2024 chideat.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package controller
18

19
import (
20
        "context"
21
        "fmt"
22
        "reflect"
23
        "time"
24

25
        appsv1 "k8s.io/api/apps/v1"
26
        corev1 "k8s.io/api/core/v1"
27
        "k8s.io/apimachinery/pkg/api/errors"
28
        "k8s.io/apimachinery/pkg/runtime"
29
        "k8s.io/client-go/tools/record"
30
        ctrl "sigs.k8s.io/controller-runtime"
31
        "sigs.k8s.io/controller-runtime/pkg/client"
32
        "sigs.k8s.io/controller-runtime/pkg/controller"
33
        "sigs.k8s.io/controller-runtime/pkg/log"
34

35
        "github.com/chideat/valkey-operator/api/v1alpha1"
36
        "github.com/chideat/valkey-operator/internal/builder/certbuilder"
37
        "github.com/chideat/valkey-operator/internal/builder/sentinelbuilder"
38
        "github.com/chideat/valkey-operator/internal/config"
39
        "github.com/chideat/valkey-operator/internal/ops"
40
)
41

42
// FailoverReconciler reconciles a Failover object
43
type FailoverReconciler struct {
44
        client.Client
45
        Scheme        *runtime.Scheme
46
        EventRecorder record.EventRecorder
47
        Engine        *ops.OpEngine
48
}
49

50
// +kubebuilder:rbac:groups=valkey.buf.red,resources=failovers,verbs=get;list;watch;create;update;patch;delete
51
// +kubebuilder:rbac:groups=valkey.buf.red,resources=failovers/status,verbs=get;update;patch
52
// +kubebuilder:rbac:groups=valkey.buf.red,resources=failovers/finalizers,verbs=update
53

54
// Reconcile is part of the main kubernetes reconciliation loop which aims to
55
// move the current state of the cluster closer to the desired state.
56
func (r *FailoverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
1✔
57
        logger := log.FromContext(ctx).WithValues("target", req.String())
1✔
58

1✔
59
        var instance v1alpha1.Failover
1✔
60
        if err := r.Get(ctx, req.NamespacedName, &instance); errors.IsNotFound(err) {
1✔
NEW
61
                return ctrl.Result{}, nil
×
62
        } else if err != nil {
1✔
NEW
63
                logger.Error(err, "get resource failed")
×
NEW
64
                return ctrl.Result{}, err
×
NEW
65
        }
×
66

67
        // err := instance.Validate()
68
        // if err != nil {
69
        //         instance.Status.Message = err.Error()
70
        //         instance.Status.Phase = v1alpha1.Fail
71
        //         if err := r.Status().Update(ctx, &instance); err != nil {
72
        //                 logger.Error(err, "update status failed")
73
        //                 return ctrl.Result{}, err
74
        //         }
75
        //         return ctrl.Result{}, err
76
        // }
77

78
        if crVersion := instance.Annotations[config.CRVersionKey]; crVersion == "" {
2✔
79
                if config.GetOperatorVersion() != "" {
2✔
80
                        if instance.Annotations == nil {
2✔
81
                                instance.Annotations = make(map[string]string)
1✔
82
                        }
1✔
83
                        instance.Annotations[config.CRVersionKey] = config.GetOperatorVersion()
1✔
84
                        if err := r.Client.Update(ctx, &instance); err != nil {
1✔
NEW
85
                                logger.Error(err, "update instance actor version failed")
×
NEW
86
                        }
×
87
                        return ctrl.Result{RequeueAfter: time.Second}, nil
1✔
88
                }
89
        }
90

NEW
91
        {
×
NEW
92
                var (
×
NEW
93
                        nodes       []v1alpha1.SentinelMonitorNode
×
NEW
94
                        serviceName = sentinelbuilder.SentinelHeadlessServiceName(instance.GetName())
×
NEW
95
                        status      = &instance.Status
×
NEW
96
                        oldStatus   = instance.Status.DeepCopy()
×
NEW
97
                )
×
NEW
98
                if instance.Spec.Sentinel == nil {
×
NEW
99
                        status.Monitor = v1alpha1.MonitorStatus{
×
NEW
100
                                Policy: v1alpha1.ManualFailoverPolicy,
×
NEW
101
                        }
×
NEW
102
                } else {
×
NEW
103
                        // TODO: use DNS SRV replace config all sentinel node address, which will cause data pods restart
×
NEW
104
                        for i := 0; i < int(instance.Spec.Sentinel.Replicas); i++ {
×
NEW
105
                                podName := sentinelbuilder.SentinelPodServiceName(instance.GetName(), i)
×
NEW
106
                                srv := fmt.Sprintf("%s.%s.%s", podName, serviceName, instance.GetNamespace())
×
NEW
107
                                nodes = append(nodes, v1alpha1.SentinelMonitorNode{IP: srv, Port: 26379})
×
NEW
108
                        }
×
109

NEW
110
                        status.Monitor.Policy = v1alpha1.SentinelFailoverPolicy
×
NEW
111
                        if instance.Spec.Sentinel.SentinelReference == nil {
×
NEW
112
                                // HARDCODE: use mymaster as sentinel monitor name
×
NEW
113
                                status.Monitor.Name = "mymaster"
×
NEW
114

×
NEW
115
                                // append history password secrets
×
NEW
116
                                // NOTE: here recorded empty password
×
NEW
117
                                passwordSecret := instance.Spec.Sentinel.Access.DefaultPasswordSecret
×
NEW
118
                                if status.Monitor.PasswordSecret != passwordSecret {
×
NEW
119
                                        status.Monitor.OldPasswordSecret = status.Monitor.PasswordSecret
×
NEW
120
                                        status.Monitor.PasswordSecret = passwordSecret
×
NEW
121
                                }
×
122

NEW
123
                                if instance.Spec.Sentinel.Access.EnableTLS {
×
NEW
124
                                        if instance.Spec.Sentinel.Access.ExternalTLSSecret != "" {
×
NEW
125
                                                status.Monitor.TLSSecret = instance.Spec.Sentinel.Access.ExternalTLSSecret
×
NEW
126
                                        } else {
×
NEW
127
                                                status.Monitor.TLSSecret = certbuilder.GenerateSSLSecretName(instance.GetName())
×
NEW
128
                                        }
×
129
                                }
NEW
130
                                status.Monitor.Nodes = nodes
×
NEW
131
                        } else {
×
NEW
132
                                status.Monitor.Name = fmt.Sprintf("%s.%s", instance.GetNamespace(), instance.GetName())
×
NEW
133
                                status.Monitor.OldPasswordSecret = status.Monitor.PasswordSecret
×
NEW
134
                                status.Monitor.PasswordSecret = instance.Spec.Sentinel.SentinelReference.Auth.PasswordSecret
×
NEW
135
                                status.Monitor.TLSSecret = instance.Spec.Sentinel.SentinelReference.Auth.TLSSecret
×
NEW
136
                                status.Monitor.Nodes = instance.Spec.Sentinel.SentinelReference.Nodes
×
NEW
137
                        }
×
138
                }
NEW
139
                if !reflect.DeepEqual(status, oldStatus) {
×
NEW
140
                        if err := r.Status().Update(ctx, &instance); err != nil {
×
NEW
141
                                logger.Error(err, "update status failed")
×
NEW
142
                                return ctrl.Result{}, err
×
NEW
143
                        }
×
NEW
144
                        return ctrl.Result{RequeueAfter: time.Second}, nil
×
145
                }
146
        }
NEW
147
        return r.Engine.Run(ctx, &instance)
×
148
}
149

150
// SetupWithManager sets up the controller with the Manager.
151
func (r *FailoverReconciler) SetupWithManager(mgr ctrl.Manager) error {
×
152
        return ctrl.NewControllerManagedBy(mgr).
×
NEW
153
                For(&v1alpha1.Failover{}).
×
NEW
154
                WithOptions(controller.Options{MaxConcurrentReconciles: 8}).
×
NEW
155
                Owns(&v1alpha1.Sentinel{}).
×
NEW
156
                Owns(&appsv1.StatefulSet{}).
×
NEW
157
                Owns(&corev1.Service{}).
×
NEW
158
                Owns(&corev1.ConfigMap{}).
×
NEW
159
                Owns(&corev1.Secret{}).
×
160
                Complete(r)
×
161
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc