|
|
@ -15,10 +15,8 @@ import ( |
|
|
|
corev1 "k8s.io/api/core/v1" |
|
|
|
"k8s.io/apimachinery/pkg/api/errors" |
|
|
|
"k8s.io/apimachinery/pkg/runtime" |
|
|
|
"k8s.io/apimachinery/pkg/types" |
|
|
|
"sigs.k8s.io/controller-runtime/pkg/client" |
|
|
|
"sigs.k8s.io/controller-runtime/pkg/controller" |
|
|
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" |
|
|
|
"sigs.k8s.io/controller-runtime/pkg/handler" |
|
|
|
"sigs.k8s.io/controller-runtime/pkg/manager" |
|
|
|
"sigs.k8s.io/controller-runtime/pkg/reconcile" |
|
|
@ -88,6 +86,7 @@ type ReconcileRedis struct { |
|
|
|
scheme *runtime.Scheme |
|
|
|
} |
|
|
|
|
|
|
|
// Reconcile means magic begins
|
|
|
|
func (r *ReconcileRedis) Reconcile(request reconcile.Request) (reconcile.Result, error) { |
|
|
|
reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) |
|
|
|
reqLogger.Info("Reconciling Redis") |
|
|
@ -113,37 +112,10 @@ sentinel parallel-syncs redismaster 2 |
|
|
|
` |
|
|
|
configSentinelData := map[string]string{"sentinel.conf": fmt.Sprintf(configSentinelTemplate, instance.Name+"-sentinel", instance.Spec.Quorum)} |
|
|
|
|
|
|
|
newConfigmap := generateConfigmap(instance, configSentinelName, configSentinelData) |
|
|
|
|
|
|
|
if err := controllerutil.SetControllerReference(instance, &newConfigmap, r.scheme); err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
if _, err := r.ReconcileConfigmap(reqLogger, instance, configSentinelName, configSentinelData); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
foundConfigmap := corev1.ConfigMap{} |
|
|
|
err = r.client.Get(context.TODO(), types.NamespacedName{Name: newConfigmap.Name, Namespace: newConfigmap.Namespace}, &foundConfigmap) |
|
|
|
if err != nil && errors.IsNotFound(err) { |
|
|
|
reqLogger.Info("Creating a Sentinel Configmap", "Namespace", newConfigmap.Namespace, "Name", newConfigmap.Name) |
|
|
|
err = r.client.Create(context.TODO(), &newConfigmap) |
|
|
|
if err != nil { |
|
|
|
reqLogger.Info("Creating Sentinel Configmap error", "Namespace", newConfigmap.Namespace, "Name", newConfigmap.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else if err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} else { |
|
|
|
if reconcileRequired, reconService := reconcileConfigmap(foundConfigmap, newConfigmap); reconcileRequired { |
|
|
|
reqLogger.Info("Updating Sentinel Configmap", "Namespace", reconService.Namespace, "Name", reconService.Name) |
|
|
|
if err = r.client.Update(context.TODO(), &reconService); err != nil { |
|
|
|
reqLogger.Info("Reconcile Sentinel Configmap error", "Namespace", foundConfigmap.Namespace, "Name", foundConfigmap.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
configRedisName := instance.Name + "-redis" |
|
|
|
configRedisData := map[string]string{"redis.conf": ` |
|
|
|
slaveof 127.0.0.1 6379 |
|
|
@ -152,37 +124,10 @@ save 900 1 |
|
|
|
save 300 10 |
|
|
|
`} |
|
|
|
|
|
|
|
newConfigmap = generateConfigmap(instance, configRedisName, configRedisData) |
|
|
|
|
|
|
|
if err := controllerutil.SetControllerReference(instance, &newConfigmap, r.scheme); err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
if _, err := r.ReconcileConfigmap(reqLogger, instance, configRedisName, configRedisData); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
foundConfigmap = corev1.ConfigMap{} |
|
|
|
err = r.client.Get(context.TODO(), types.NamespacedName{Name: newConfigmap.Name, Namespace: newConfigmap.Namespace}, &foundConfigmap) |
|
|
|
if err != nil && errors.IsNotFound(err) { |
|
|
|
reqLogger.Info("Creating a Redis Configmap", "Namespace", newConfigmap.Namespace, "Name", newConfigmap.Name) |
|
|
|
err = r.client.Create(context.TODO(), &newConfigmap) |
|
|
|
if err != nil { |
|
|
|
reqLogger.Info("Creating Redis Configmap error", "Namespace", newConfigmap.Namespace, "Name", newConfigmap.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else if err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} else { |
|
|
|
if reconcileRequired, reconService := reconcileConfigmap(foundConfigmap, newConfigmap); reconcileRequired { |
|
|
|
reqLogger.Info("Updating Redis Configmap", "Namespace", reconService.Namespace, "Name", reconService.Name) |
|
|
|
if err = r.client.Update(context.TODO(), &reconService); err != nil { |
|
|
|
reqLogger.Info("Reconcile Redis Configmap error", "Namespace", foundConfigmap.Namespace, "Name", foundConfigmap.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
configFailoverName := instance.Name + "-failover" |
|
|
|
configFailoverData := map[string]string{"failover.conf": ` |
|
|
|
MASTER_HOST=$(redis-cli -h ${SENTINEL_SERVICE} -p 26379 --csv SENTINEL get-master-addr-by-name redismaster | tr ',' ' ' | tr -d '\"' |cut -d' ' -f1) |
|
|
@ -191,173 +136,45 @@ if [[ ${MASTER_HOST} == $(hostname -i) ]]; then |
|
|
|
fi |
|
|
|
`} |
|
|
|
|
|
|
|
newConfigmap = generateConfigmap(instance, configFailoverName, configFailoverData) |
|
|
|
|
|
|
|
if err := controllerutil.SetControllerReference(instance, &newConfigmap, r.scheme); err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
foundConfigmap = corev1.ConfigMap{} |
|
|
|
err = r.client.Get(context.TODO(), types.NamespacedName{Name: newConfigmap.Name, Namespace: newConfigmap.Namespace}, &foundConfigmap) |
|
|
|
if err != nil && errors.IsNotFound(err) { |
|
|
|
reqLogger.Info("Creating a Failover Configmap", "Namespace", newConfigmap.Namespace, "Name", newConfigmap.Name) |
|
|
|
err = r.client.Create(context.TODO(), &newConfigmap) |
|
|
|
if err != nil { |
|
|
|
reqLogger.Info("Creating Failover Configmap error", "Namespace", newConfigmap.Namespace, "Name", newConfigmap.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else if err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
if _, err := r.ReconcileConfigmap(reqLogger, instance, configFailoverName, configFailoverData); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} else { |
|
|
|
if reconcileRequired, reconService := reconcileConfigmap(foundConfigmap, newConfigmap); reconcileRequired { |
|
|
|
reqLogger.Info("Updating Failover Configmap", "Namespace", reconService.Namespace, "Name", reconService.Name) |
|
|
|
if err = r.client.Update(context.TODO(), &reconService); err != nil { |
|
|
|
reqLogger.Info("Reconcile Failover Configmap error", "Namespace", foundConfigmap.Namespace, "Name", foundConfigmap.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// reconcile deployment
|
|
|
|
// reconcile Sentinel deployment
|
|
|
|
newSentinelDeployment := generateDeployment(instance) |
|
|
|
|
|
|
|
if err := controllerutil.SetControllerReference(instance, &newSentinelDeployment, r.scheme); err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
if _, err := r.ReconcileDeployment(reqLogger, instance, newSentinelDeployment); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
// controller deployment
|
|
|
|
foundSentinelDeployment := v1.Deployment{} |
|
|
|
err = r.client.Get(context.TODO(), types.NamespacedName{Name: newSentinelDeployment.Name, Namespace: newSentinelDeployment.Namespace}, &foundSentinelDeployment) |
|
|
|
if err != nil && errors.IsNotFound(err) { |
|
|
|
reqLogger.Info("Creating Sentinel Deployment", "Namespace", newSentinelDeployment.Namespace, "Name", newSentinelDeployment.Name) |
|
|
|
err = r.client.Create(context.TODO(), &newSentinelDeployment) |
|
|
|
if err != nil { |
|
|
|
reqLogger.Info("Creating Sentinel Deployment error", "Namespace", newSentinelDeployment.Namespace, "Name", newSentinelDeployment.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else if err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} else { |
|
|
|
if reconcileRequired, reconDeployment := reconcileDeployment(foundSentinelDeployment, newSentinelDeployment); reconcileRequired { |
|
|
|
reqLogger.Info("Updating Sentinel Deployment", "Namespace", reconDeployment.Namespace, "Name", reconDeployment.Name) |
|
|
|
if err = r.client.Update(context.TODO(), &reconDeployment); err != nil { |
|
|
|
reqLogger.Info("Reconcile Sentinel Deployment error", "Namespace", foundSentinelDeployment.Namespace, "Name", foundSentinelDeployment.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// reconcile Redis StatefulSet
|
|
|
|
newRedisStatefulset := generateStatefulSet(instance) |
|
|
|
|
|
|
|
if err := controllerutil.SetControllerReference(instance, &newRedisStatefulset, r.scheme); err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
// controller statefulset
|
|
|
|
foundRedisStatefulset := v1.StatefulSet{} |
|
|
|
err = r.client.Get(context.TODO(), types.NamespacedName{Name: newRedisStatefulset.Name, Namespace: newRedisStatefulset.Namespace}, &foundRedisStatefulset) |
|
|
|
if err != nil && errors.IsNotFound(err) { |
|
|
|
reqLogger.Info("Creating a new Redis Statefulset", "Namespace", newRedisStatefulset.Namespace, "Name", newRedisStatefulset.Name) |
|
|
|
err = r.client.Create(context.TODO(), &newRedisStatefulset) |
|
|
|
if err != nil { |
|
|
|
reqLogger.Info("Creating Redis Statefulset error", "Namespace", newRedisStatefulset.Namespace, "Name", newRedisStatefulset.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else if err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} else { |
|
|
|
if reconcileRequired, reconDeployment := reconcileStatefulset(foundRedisStatefulset, newRedisStatefulset); reconcileRequired { |
|
|
|
reqLogger.Info("Updating Redis Statefulset", "Namespace", reconDeployment.Namespace, "Name", reconDeployment.Name) |
|
|
|
if err = r.client.Update(context.TODO(), &reconDeployment); err != nil { |
|
|
|
reqLogger.Info("Reconcile Redis Statefulset error", "Namespace", foundRedisStatefulset.Namespace, "Name", foundRedisStatefulset.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// reconcile Sentinel Service
|
|
|
|
newSentinelService := generateService(instance, instance.Name+"-sentinel", "sentinel", int32(26379), map[string]string{"component": "sentinel"}) |
|
|
|
|
|
|
|
if err := controllerutil.SetControllerReference(instance, &newSentinelService, r.scheme); err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
if _, err := r.ReconcileStatefulSet(reqLogger, instance, newRedisStatefulset); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
foundSentinelService := corev1.Service{} |
|
|
|
err = r.client.Get(context.TODO(), types.NamespacedName{Name: newSentinelService.Name, Namespace: newSentinelService.Namespace}, &foundSentinelService) |
|
|
|
if err != nil && errors.IsNotFound(err) { |
|
|
|
reqLogger.Info("Creating a new Sentinel Service", "Namespace", newSentinelService.Namespace, "Name", newSentinelService.Name) |
|
|
|
err = r.client.Create(context.TODO(), &newSentinelService) |
|
|
|
if err != nil { |
|
|
|
reqLogger.Info("Creating Sentinel Service error", "Namespace", newSentinelService.Namespace, "Name", newSentinelService.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else if err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
// create sentinel and redis services
|
|
|
|
serviceName := instance.Name + "-sentinel" |
|
|
|
servicePortName := "sentinel" |
|
|
|
servicePort := int32(26379) |
|
|
|
serviceSelector := map[string]string{"component": "sentinel"} |
|
|
|
if _, err := r.ReconcileService(reqLogger, instance, serviceName, servicePortName, servicePort, serviceSelector); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} else { |
|
|
|
if reconcileRequired, reconService := reconcileService(foundSentinelService, newSentinelService); reconcileRequired { |
|
|
|
reqLogger.Info("Updating Sentinel Service", "Namespace", reconService.Namespace, "Name", reconService.Name) |
|
|
|
if err = r.client.Update(context.TODO(), &reconService); err != nil { |
|
|
|
reqLogger.Info("Reconcile Sentinel Service error", "Namespace", foundSentinelService.Namespace, "Name", foundSentinelService.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// reconcile Redis Service
|
|
|
|
newRedisService := generateService(instance, instance.Name+"-redis", "redis", int32(6379), map[string]string{"component": "redis"}) |
|
|
|
|
|
|
|
if err := controllerutil.SetControllerReference(instance, &newRedisService, r.scheme); err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
serviceName = instance.Name + "-redis" |
|
|
|
servicePortName = "redis" |
|
|
|
servicePort = int32(6379) |
|
|
|
serviceSelector = map[string]string{"component": "redis"} |
|
|
|
if _, err := r.ReconcileService(reqLogger, instance, serviceName, servicePortName, servicePort, serviceSelector); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
foundRedisService := corev1.Service{} |
|
|
|
err = r.client.Get(context.TODO(), types.NamespacedName{Name: newRedisService.Name, Namespace: newRedisService.Namespace}, &foundRedisService) |
|
|
|
if err != nil && errors.IsNotFound(err) { |
|
|
|
reqLogger.Info("Creating a new Redis Service", "Namespace", newRedisService.Namespace, "Name", newRedisService.Name) |
|
|
|
err = r.client.Create(context.TODO(), &newRedisService) |
|
|
|
if err != nil { |
|
|
|
reqLogger.Info("Creating Redis Service error", "Namespace", newRedisService.Namespace, "Name", newRedisService.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else if err != nil { |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} else { |
|
|
|
if reconcileRequired, reconService := reconcileService(foundRedisService, newRedisService); reconcileRequired { |
|
|
|
reqLogger.Info("Updating Redis Service", "Namespace", reconService.Namespace, "Name", reconService.Name) |
|
|
|
if err = r.client.Update(context.TODO(), &reconService); err != nil { |
|
|
|
reqLogger.Info("Reconcile Redis Service error", "Namespace", foundRedisService.Namespace, "Name", foundRedisService.Name, "Error", err) |
|
|
|
raven.CaptureErrorAndWait(err, nil) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// check health of pods
|
|
|
|
// set Redis master
|
|
|
|
|
|
|
|
podList := &corev1.PodList{} |
|
|
|
labelSelector := labels.SelectorFromSet(foundRedisStatefulset.Labels) |
|
|
|
labelSelector := labels.SelectorFromSet(newRedisStatefulset.Labels) |
|
|
|
listOpts := &client.ListOptions{ |
|
|
|
Namespace: foundRedisStatefulset.Namespace, |
|
|
|
Namespace: newRedisStatefulset.Namespace, |
|
|
|
LabelSelector: labelSelector, |
|
|
|
} |
|
|
|
err = r.client.List(context.TODO(), listOpts, podList) |
|
|
@ -377,55 +194,137 @@ fi |
|
|
|
}) |
|
|
|
|
|
|
|
newMasterIP := "" |
|
|
|
podIPs := []string{} |
|
|
|
|
|
|
|
for _, pod := range podList.Items { |
|
|
|
if newMasterIP == "" { |
|
|
|
newMasterIP = pod.Status.PodIP |
|
|
|
reqLogger.Info("New master ip", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
if err := querySetMaster(newMasterIP); err != nil { |
|
|
|
reqLogger.Error(err, "Error! New master ip", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else { |
|
|
|
reqLogger.Info("Redis", pod.Name, "slaveof", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
if err := querySetSlaveOf(pod.Status.PodIP, newMasterIP); err != nil { |
|
|
|
reqLogger.Error(err, "Error! Redis", pod.Name, "slaveof", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
return reconcile.Result{}, err |
|
|
|
// pod will be deleted, skip
|
|
|
|
if pod.GetObjectMeta().GetDeletionTimestamp() != nil { |
|
|
|
continue |
|
|
|
} |
|
|
|
|
|
|
|
if pod.Status.Phase == corev1.PodPending || pod.Status.Phase == corev1.PodRunning { |
|
|
|
// for haproxy if enabled
|
|
|
|
podIPs = append(podIPs, pod.Status.PodIP) |
|
|
|
|
|
|
|
if newMasterIP == "" { |
|
|
|
newMasterIP = pod.Status.PodIP |
|
|
|
reqLogger.Info("New master ip", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
if err := querySetMaster(newMasterIP); err != nil { |
|
|
|
reqLogger.Error(err, "Error! New master ip", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} else { |
|
|
|
reqLogger.Info("Redis", pod.Name, "slaveof", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
if err := querySetSlaveOf(pod.Status.PodIP, newMasterIP); err != nil { |
|
|
|
reqLogger.Error(err, "Error! Redis", pod.Name, "slaveof", newMasterIP, instance.Namespace, "Name", instance.Name) |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// haproxy
|
|
|
|
|
|
|
|
// check if you need haproxy
|
|
|
|
if instance.Spec.UseHAProxy { |
|
|
|
// check if you need haproxy
|
|
|
|
if instance.Spec.UseHAProxy { |
|
|
|
|
|
|
|
configHaproxyShepherdName := instance.Name + "-haproxy-shepherd" |
|
|
|
configHaproxyShepherdData := map[string]string{"shepherd.sh": ` |
|
|
|
#!/bin/sh |
|
|
|
echo "Start" |
|
|
|
MONFILE='/usr/local/etc/haproxy/haproxy.cfg' |
|
|
|
PIDFILE='/run/haproxy.pid' |
|
|
|
MD5FILE='/tmp/haproxy.cfg.md5' |
|
|
|
|
|
|
|
touch ${MD5FILE} |
|
|
|
|
|
|
|
while true |
|
|
|
do |
|
|
|
MD5LAST="$(cat ${MD5FILE})" |
|
|
|
echo "Read MD5 of ${MD5FILE}: ${MD5LAST}" |
|
|
|
if [ -z "${MD5LAST}" ] |
|
|
|
then |
|
|
|
echo "First time check, md5 file is empty" |
|
|
|
echo "$(md5sum ${MONFILE})" > ${MD5FILE} |
|
|
|
else |
|
|
|
echo "Get md5 and compare with last time" |
|
|
|
MD5CURRENT="$(md5sum ${MONFILE})" |
|
|
|
if [ "${MD5CURRENT}" != "${MD5LAST}" ] |
|
|
|
then |
|
|
|
echo "Send signal to haproxy" |
|
|
|
kill -HUP $(cat ${PIDFILE}) |
|
|
|
echo "${MD5CURRENT}" > ${MD5FILE} |
|
|
|
fi |
|
|
|
fi |
|
|
|
# sleep 5 seconds, it will be enough to not disturb haproxy while pods rapidly creates or dies |
|
|
|
sleep 5 |
|
|
|
done |
|
|
|
`} |
|
|
|
|
|
|
|
for _, pod := range podList.Items { |
|
|
|
if pod.GetObjectMeta().GetDeletionTimestamp() != nil { |
|
|
|
continue |
|
|
|
if _, err := r.ReconcileConfigmap(reqLogger, instance, configHaproxyShepherdName, configHaproxyShepherdData); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
if pod.Status.Phase == corev1.PodPending || pod.Status.Phase == corev1.PodRunning { |
|
|
|
// ok, got pod name, check status
|
|
|
|
|
|
|
|
redisEndpointTemplate := " server redis_backend_%v %v:6379 maxconn 1024 check inter 1s\n" |
|
|
|
redisEndpoints := "" |
|
|
|
|
|
|
|
for num, ip := range podIPs { |
|
|
|
redisEndpoints = redisEndpoints + fmt.Sprintf(redisEndpointTemplate, num, ip) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// deploy haproxy and shepherd
|
|
|
|
if err := c.haproxyDeployment(redis.Redis); err != nil { |
|
|
|
c.logger.Println("haproxyDeployment error", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// create haproxy endpoint
|
|
|
|
if err := c.haproxyServiceProcess(redis.Redis); err != nil { |
|
|
|
c.logger.Println("haproxyServiceProcess error", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
// create endpoints of redis slaves
|
|
|
|
if err := c.redisSlavesServiceProcess(redis.Redis); err != nil { |
|
|
|
c.logger.Println("redisSlavesServiceProcess error", err) |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
configHaproxyConfigName := instance.Name + "-haproxy" |
|
|
|
configHaproxyConfigData := map[string]string{"haproxy.cfg": ` |
|
|
|
global |
|
|
|
pidfile /run/haproxy.pid |
|
|
|
defaults |
|
|
|
mode tcp |
|
|
|
timeout connect 3s |
|
|
|
timeout server 6s |
|
|
|
timeout client 6s |
|
|
|
listen stats |
|
|
|
mode http |
|
|
|
bind :9000 |
|
|
|
stats enable |
|
|
|
stats hide-version |
|
|
|
stats realm Haproxy\ Statistics |
|
|
|
stats uri /haproxy_stats |
|
|
|
frontend ft_redis |
|
|
|
mode tcp |
|
|
|
bind *:6379 |
|
|
|
default_backend bk_redis |
|
|
|
backend bk_redis |
|
|
|
mode tcp |
|
|
|
option tcp-check |
|
|
|
tcp-check send PING\r\n |
|
|
|
tcp-check expect string +PONG |
|
|
|
tcp-check send info\ replication\r\n |
|
|
|
tcp-check expect string role:master |
|
|
|
tcp-check send QUIT\r\n |
|
|
|
tcp-check expect string +OK |
|
|
|
`} |
|
|
|
|
|
|
|
configHaproxyConfigData["haproxy.cfg"] = configHaproxyConfigData["haproxy.cfg"] + redisEndpoints |
|
|
|
|
|
|
|
if _, err := r.ReconcileConfigmap(reqLogger, instance, configHaproxyConfigName, configHaproxyConfigData); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
// reconcile HAProxy deployment
|
|
|
|
newHAProxyDeployment := generateHaproxyDeployment(instance) |
|
|
|
if _, err := r.ReconcileDeployment(reqLogger, instance, newHAProxyDeployment); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
// create haproxy service
|
|
|
|
serviceName = instance.Name + "-haproxy" |
|
|
|
servicePortName = "haproxy" |
|
|
|
servicePort = int32(6379) |
|
|
|
serviceSelector = map[string]string{"component": "haproxy"} |
|
|
|
if _, err := r.ReconcileService(reqLogger, instance, serviceName, servicePortName, servicePort, serviceSelector); err != nil { |
|
|
|
return reconcile.Result{}, err |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
reqLogger.Info("Reconcile complete", "Namespace", instance.Namespace, "Name", instance.Name) |
|
|
|
return reconcile.Result{}, nil |
|
|
|