github.com/spotahome/redis-operator@v1.2.4/operator/redisfailover/handler.go (about)

     1  package redisfailover
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"regexp"
     7  
     8  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     9  	"k8s.io/apimachinery/pkg/runtime"
    10  
    11  	redisfailoverv1 "github.com/spotahome/redis-operator/api/redisfailover/v1"
    12  	"github.com/spotahome/redis-operator/log"
    13  	"github.com/spotahome/redis-operator/metrics"
    14  	rfservice "github.com/spotahome/redis-operator/operator/redisfailover/service"
    15  	"github.com/spotahome/redis-operator/operator/redisfailover/util"
    16  	"github.com/spotahome/redis-operator/service/k8s"
    17  )
    18  
    19  const (
    20  	rfLabelManagedByKey = "app.kubernetes.io/managed-by"
    21  	rfLabelNameKey      = "redisfailovers.databases.spotahome.com/name"
    22  )
    23  
    24  var (
    25  	defaultLabels = map[string]string{
    26  		rfLabelManagedByKey: operatorName,
    27  	}
    28  )
    29  
    30  // RedisFailoverHandler is the Redis Failover handler. This handler will create the required
    31  // resources that a RF needs.
    32  type RedisFailoverHandler struct {
    33  	config     Config
    34  	k8sservice k8s.Service
    35  	rfService  rfservice.RedisFailoverClient
    36  	rfChecker  rfservice.RedisFailoverCheck
    37  	rfHealer   rfservice.RedisFailoverHeal
    38  	mClient    metrics.Recorder
    39  	logger     log.Logger
    40  }
    41  
    42  // NewRedisFailoverHandler returns a new RF handler
    43  func NewRedisFailoverHandler(config Config, rfService rfservice.RedisFailoverClient, rfChecker rfservice.RedisFailoverCheck, rfHealer rfservice.RedisFailoverHeal, k8sservice k8s.Service, mClient metrics.Recorder, logger log.Logger) *RedisFailoverHandler {
    44  	return &RedisFailoverHandler{
    45  		config:     config,
    46  		rfService:  rfService,
    47  		rfChecker:  rfChecker,
    48  		rfHealer:   rfHealer,
    49  		mClient:    mClient,
    50  		k8sservice: k8sservice,
    51  		logger:     logger,
    52  	}
    53  }
    54  
    55  // Handle will ensure the redis failover is in the expected state.
    56  func (r *RedisFailoverHandler) Handle(_ context.Context, obj runtime.Object) error {
    57  	rf, ok := obj.(*redisfailoverv1.RedisFailover)
    58  	if !ok {
    59  		return fmt.Errorf("can't handle the received object: not a redisfailover")
    60  	}
    61  
    62  	if err := rf.Validate(); err != nil {
    63  		r.mClient.SetClusterError(rf.Namespace, rf.Name)
    64  		return err
    65  	}
    66  
    67  	// Create owner refs so the objects manager by this handler have ownership to the
    68  	// received RF.
    69  	oRefs := r.createOwnerReferences(rf)
    70  
    71  	// Create the labels every object derived from this need to have.
    72  	labels := r.getLabels(rf)
    73  
    74  	if err := r.Ensure(rf, labels, oRefs, r.mClient); err != nil {
    75  		r.mClient.SetClusterError(rf.Namespace, rf.Name)
    76  		return err
    77  	}
    78  
    79  	if err := r.CheckAndHeal(rf); err != nil {
    80  		r.mClient.SetClusterError(rf.Namespace, rf.Name)
    81  		return err
    82  	}
    83  
    84  	r.mClient.SetClusterOK(rf.Namespace, rf.Name)
    85  	return nil
    86  }
    87  
    88  // getLabels merges the labels (dynamic and operator static ones).
    89  func (r *RedisFailoverHandler) getLabels(rf *redisfailoverv1.RedisFailover) map[string]string {
    90  	dynLabels := map[string]string{
    91  		rfLabelNameKey: rf.Name,
    92  	}
    93  
    94  	// Filter the labels based on the whitelist
    95  	filteredCustomLabels := make(map[string]string)
    96  	if rf.Spec.LabelWhitelist != nil && len(rf.Spec.LabelWhitelist) != 0 {
    97  		for _, regex := range rf.Spec.LabelWhitelist {
    98  			compiledRegexp, err := regexp.Compile(regex)
    99  			if err != nil {
   100  				r.logger.Errorf("Unable to compile label whitelist regex '%s', ignoring it.", regex)
   101  				continue
   102  			}
   103  			for labelKey, labelValue := range rf.Labels {
   104  				if match := compiledRegexp.MatchString(labelKey); match {
   105  					filteredCustomLabels[labelKey] = labelValue
   106  				}
   107  			}
   108  		}
   109  	} else {
   110  		// If no whitelist is specified then don't filter the labels.
   111  		filteredCustomLabels = rf.Labels
   112  	}
   113  	return util.MergeLabels(defaultLabels, dynLabels, filteredCustomLabels)
   114  }
   115  
   116  func (w *RedisFailoverHandler) createOwnerReferences(rf *redisfailoverv1.RedisFailover) []metav1.OwnerReference {
   117  	rfvk := redisfailoverv1.VersionKind(redisfailoverv1.RFKind)
   118  	return []metav1.OwnerReference{
   119  		*metav1.NewControllerRef(rf, rfvk),
   120  	}
   121  }