github.com/spotahome/redis-operator@v1.2.4/operator/redisfailover/service/client.go (about) 1 package service 2 3 import ( 4 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 "k8s.io/apimachinery/pkg/util/intstr" 6 7 redisfailoverv1 "github.com/spotahome/redis-operator/api/redisfailover/v1" 8 "github.com/spotahome/redis-operator/log" 9 "github.com/spotahome/redis-operator/metrics" 10 "github.com/spotahome/redis-operator/operator/redisfailover/util" 11 "github.com/spotahome/redis-operator/service/k8s" 12 ) 13 14 // RedisFailoverClient has the minimumm methods that a Redis failover controller needs to satisfy 15 // in order to talk with K8s 16 type RedisFailoverClient interface { 17 EnsureSentinelService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 18 EnsureSentinelConfigMap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 19 EnsureSentinelDeployment(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 20 EnsureRedisStatefulset(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 21 EnsureRedisService(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 22 EnsureRedisShutdownConfigMap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 23 EnsureRedisReadinessConfigMap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 24 EnsureRedisConfigMap(rFailover *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error 25 EnsureNotPresentRedisService(rFailover *redisfailoverv1.RedisFailover) error 26 } 27 28 // RedisFailoverKubeClient implements the required methods to talk with kubernetes 29 type RedisFailoverKubeClient struct { 30 K8SService k8s.Services 31 logger log.Logger 32 metricsClient metrics.Recorder 33 } 34 35 // NewRedisFailoverKubeClient creates a new RedisFailoverKubeClient 36 func NewRedisFailoverKubeClient(k8sService k8s.Services, logger log.Logger, metricsClient metrics.Recorder) *RedisFailoverKubeClient { 37 return &RedisFailoverKubeClient{ 38 K8SService: k8sService, 39 logger: logger, 40 metricsClient: metricsClient, 41 } 42 } 43 44 func generateSelectorLabels(component, name string) map[string]string { 45 return map[string]string{ 46 "app.kubernetes.io/name": name, 47 "app.kubernetes.io/component": component, 48 "app.kubernetes.io/part-of": appLabel, 49 } 50 } 51 52 func generateRedisDefaultRoleLabel() map[string]string { 53 return generateRedisSlaveRoleLabel() 54 } 55 56 func generateRedisMasterRoleLabel() map[string]string { 57 return map[string]string{ 58 redisRoleLabelKey: redisRoleLabelMaster, 59 } 60 } 61 62 func generateRedisSlaveRoleLabel() map[string]string { 63 return map[string]string{ 64 redisRoleLabelKey: redisRoleLabelSlave, 65 } 66 } 67 68 // EnsureSentinelService makes sure the sentinel service exists 69 func (r *RedisFailoverKubeClient) EnsureSentinelService(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 70 svc := generateSentinelService(rf, labels, ownerRefs) 71 err := r.K8SService.CreateOrUpdateService(rf.Namespace, svc) 72 r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "Service", rf.Name, err) 73 return err 74 } 75 76 // EnsureSentinelConfigMap makes sure the sentinel configmap exists 77 func (r *RedisFailoverKubeClient) EnsureSentinelConfigMap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 78 cm := generateSentinelConfigMap(rf, labels, ownerRefs) 79 err := r.K8SService.CreateOrUpdateConfigMap(rf.Namespace, cm) 80 r.setEnsureOperationMetrics(cm.Namespace, cm.Name, "ConfigMap", rf.Name, err) 81 return err 82 } 83 84 // EnsureSentinelDeployment makes sure the sentinel deployment exists in the desired state 85 func (r *RedisFailoverKubeClient) EnsureSentinelDeployment(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 86 if err := r.ensurePodDisruptionBudget(rf, sentinelName, sentinelRoleName, labels, ownerRefs); err != nil { 87 return err 88 } 89 d := generateSentinelDeployment(rf, labels, ownerRefs) 90 err := r.K8SService.CreateOrUpdateDeployment(rf.Namespace, d) 91 92 r.setEnsureOperationMetrics(d.Namespace, d.Name, "Deployment", rf.Name, err) 93 return err 94 } 95 96 // EnsureRedisStatefulset makes sure the redis statefulset exists in the desired state 97 func (r *RedisFailoverKubeClient) EnsureRedisStatefulset(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 98 if err := r.ensurePodDisruptionBudget(rf, redisName, redisRoleName, labels, ownerRefs); err != nil { 99 return err 100 } 101 ss := generateRedisStatefulSet(rf, labels, ownerRefs) 102 err := r.K8SService.CreateOrUpdateStatefulSet(rf.Namespace, ss) 103 104 r.setEnsureOperationMetrics(ss.Namespace, ss.Name, "StatefulSet", rf.Name, err) 105 return err 106 } 107 108 // EnsureRedisConfigMap makes sure the Redis ConfigMap exists 109 func (r *RedisFailoverKubeClient) EnsureRedisConfigMap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 110 111 password, err := k8s.GetRedisPassword(r.K8SService, rf) 112 if err != nil { 113 return err 114 } 115 116 cm := generateRedisConfigMap(rf, labels, ownerRefs, password) 117 err = r.K8SService.CreateOrUpdateConfigMap(rf.Namespace, cm) 118 119 r.setEnsureOperationMetrics(cm.Namespace, cm.Name, "ConfigMap", rf.Name, err) 120 return err 121 } 122 123 // EnsureRedisShutdownConfigMap makes sure the redis configmap with shutdown script exists 124 func (r *RedisFailoverKubeClient) EnsureRedisShutdownConfigMap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 125 if rf.Spec.Redis.ShutdownConfigMap != "" { 126 if _, err := r.K8SService.GetConfigMap(rf.Namespace, rf.Spec.Redis.ShutdownConfigMap); err != nil { 127 return err 128 } 129 } else { 130 cm := generateRedisShutdownConfigMap(rf, labels, ownerRefs) 131 err := r.K8SService.CreateOrUpdateConfigMap(rf.Namespace, cm) 132 r.setEnsureOperationMetrics(cm.Namespace, cm.Name, "ConfigMap", rf.Name, err) 133 return err 134 } 135 return nil 136 } 137 138 // EnsureRedisReadinessConfigMap makes sure the redis configmap with shutdown script exists 139 func (r *RedisFailoverKubeClient) EnsureRedisReadinessConfigMap(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 140 cm := generateRedisReadinessConfigMap(rf, labels, ownerRefs) 141 err := r.K8SService.CreateOrUpdateConfigMap(rf.Namespace, cm) 142 r.setEnsureOperationMetrics(cm.Namespace, cm.Name, "ConfigMap", rf.Name, err) 143 return err 144 } 145 146 // EnsureRedisService makes sure the redis statefulset exists 147 func (r *RedisFailoverKubeClient) EnsureRedisService(rf *redisfailoverv1.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 148 svc := generateRedisService(rf, labels, ownerRefs) 149 err := r.K8SService.CreateOrUpdateService(rf.Namespace, svc) 150 151 r.setEnsureOperationMetrics(svc.Namespace, svc.Name, "Service", rf.Name, err) 152 return err 153 } 154 155 // EnsureNotPresentRedisService makes sure the redis service is not present 156 func (r *RedisFailoverKubeClient) EnsureNotPresentRedisService(rf *redisfailoverv1.RedisFailover) error { 157 name := GetRedisName(rf) 158 namespace := rf.Namespace 159 // If the service exists (no get error), delete it 160 if _, err := r.K8SService.GetService(namespace, name); err == nil { 161 return r.K8SService.DeleteService(namespace, name) 162 } 163 return nil 164 } 165 166 // EnsureRedisStatefulset makes sure the pdb exists in the desired state 167 func (r *RedisFailoverKubeClient) ensurePodDisruptionBudget(rf *redisfailoverv1.RedisFailover, name string, component string, labels map[string]string, ownerRefs []metav1.OwnerReference) error { 168 name = generateName(name, rf.Name) 169 namespace := rf.Namespace 170 171 minAvailable := intstr.FromInt(2) 172 if rf.Spec.Redis.Replicas <= 2 { 173 minAvailable = intstr.FromInt(1) 174 } 175 176 labels = util.MergeLabels(labels, generateSelectorLabels(component, rf.Name)) 177 178 pdb := generatePodDisruptionBudget(name, namespace, labels, ownerRefs, minAvailable) 179 err := r.K8SService.CreateOrUpdatePodDisruptionBudget(namespace, pdb) 180 r.setEnsureOperationMetrics(pdb.Namespace, pdb.Name, "PodDisruptionBudget" /* pdb.TypeMeta.Kind isnt working; pdb.Kind isnt working either */, rf.Name, err) 181 return err 182 } 183 184 func (r *RedisFailoverKubeClient) setEnsureOperationMetrics(objectNamespace string, objectName string, objectKind string, ownerName string, err error) { 185 if nil != err { 186 r.metricsClient.RecordEnsureOperation(objectNamespace, objectName, objectKind, ownerName, metrics.FAIL) 187 } 188 r.metricsClient.RecordEnsureOperation(objectNamespace, objectName, objectKind, ownerName, metrics.SUCCESS) 189 }