github.com/argoproj/argo-events@v1.9.1/controllers/sensor/controller.go (about)

     1  /*
     2  Copyright 2020 BlackRock, Inc.
     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 sensor
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"go.uber.org/zap"
    24  	"k8s.io/apimachinery/pkg/api/equality"
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	ctrl "sigs.k8s.io/controller-runtime"
    29  	"sigs.k8s.io/controller-runtime/pkg/client"
    30  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    31  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    32  
    33  	"github.com/argoproj/argo-events/common"
    34  	"github.com/argoproj/argo-events/common/logging"
    35  	eventbusv1alpha1 "github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1"
    36  	"github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1"
    37  )
    38  
    39  const (
    40  	// ControllerName is name of the controller
    41  	ControllerName = "sensor-controller"
    42  
    43  	finalizerName = ControllerName
    44  )
    45  
    46  type reconciler struct {
    47  	client client.Client
    48  	scheme *runtime.Scheme
    49  
    50  	sensorImage string
    51  	logger      *zap.SugaredLogger
    52  }
    53  
    54  // NewReconciler returns a new reconciler
    55  func NewReconciler(client client.Client, scheme *runtime.Scheme, sensorImage string, logger *zap.SugaredLogger) reconcile.Reconciler {
    56  	return &reconciler{client: client, scheme: scheme, sensorImage: sensorImage, logger: logger}
    57  }
    58  
    59  func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    60  	sensor := &v1alpha1.Sensor{}
    61  	if err := r.client.Get(ctx, req.NamespacedName, sensor); err != nil {
    62  		if apierrors.IsNotFound(err) {
    63  			r.logger.Warnw("WARNING: sensor not found", "request", req)
    64  			return reconcile.Result{}, nil
    65  		}
    66  		r.logger.Errorw("unable to get sensor ctl", zap.Any("request", req), zap.Error(err))
    67  		return ctrl.Result{}, err
    68  	}
    69  	log := r.logger.With("namespace", sensor.Namespace).With("sensor", sensor.Name)
    70  	ctx = logging.WithLogger(ctx, log)
    71  	sensorCopy := sensor.DeepCopy()
    72  	reconcileErr := r.reconcile(ctx, sensorCopy)
    73  	if reconcileErr != nil {
    74  		log.Errorw("reconcile error", zap.Error(reconcileErr))
    75  	}
    76  	if r.needsUpdate(sensor, sensorCopy) {
    77  		// Use a DeepCopy to update, because it will be mutated afterwards, with empty Status.
    78  		if err := r.client.Update(ctx, sensorCopy.DeepCopy()); err != nil {
    79  			return reconcile.Result{}, err
    80  		}
    81  	}
    82  	if err := r.client.Status().Update(ctx, sensorCopy); err != nil {
    83  		return reconcile.Result{}, err
    84  	}
    85  	return ctrl.Result{}, reconcileErr
    86  }
    87  
    88  // reconcile does the real logic
    89  func (r *reconciler) reconcile(ctx context.Context, sensor *v1alpha1.Sensor) error {
    90  	log := logging.FromContext(ctx)
    91  	if !sensor.DeletionTimestamp.IsZero() {
    92  		log.Info("deleting sensor")
    93  		if controllerutil.ContainsFinalizer(sensor, finalizerName) {
    94  			// Finalizer logic should be added here.
    95  			controllerutil.RemoveFinalizer(sensor, finalizerName)
    96  		}
    97  		return nil
    98  	}
    99  	controllerutil.AddFinalizer(sensor, finalizerName)
   100  
   101  	sensor.Status.InitConditions()
   102  
   103  	eventBus := &eventbusv1alpha1.EventBus{}
   104  	eventBusName := common.DefaultEventBusName
   105  	if len(sensor.Spec.EventBusName) > 0 {
   106  		eventBusName = sensor.Spec.EventBusName
   107  	}
   108  	err := r.client.Get(ctx, types.NamespacedName{Namespace: sensor.Namespace, Name: eventBusName}, eventBus)
   109  	if err != nil {
   110  		if apierrors.IsNotFound(err) {
   111  			sensor.Status.MarkDeployFailed("EventBusNotFound", "EventBus not found.")
   112  			log.Errorw("EventBus not found", "eventBusName", eventBusName, "error", err)
   113  			return fmt.Errorf("eventbus %s not found", eventBusName)
   114  		}
   115  		sensor.Status.MarkDeployFailed("GetEventBusFailed", "Failed to get EventBus.")
   116  		log.Errorw("failed to get EventBus", "eventBusName", eventBusName, "error", err)
   117  		return err
   118  	}
   119  
   120  	if err := ValidateSensor(sensor, eventBus); err != nil {
   121  		log.Errorw("validation error", "error", err)
   122  		return err
   123  	}
   124  	args := &AdaptorArgs{
   125  		Image:  r.sensorImage,
   126  		Sensor: sensor,
   127  		Labels: map[string]string{
   128  			"controller":           "sensor-controller",
   129  			common.LabelSensorName: sensor.Name,
   130  			common.LabelOwnerName:  sensor.Name,
   131  		},
   132  	}
   133  	return Reconcile(r.client, eventBus, args, log)
   134  }
   135  
   136  func (r *reconciler) needsUpdate(old, new *v1alpha1.Sensor) bool {
   137  	if old == nil {
   138  		return true
   139  	}
   140  	if !equality.Semantic.DeepEqual(old.Finalizers, new.Finalizers) {
   141  		return true
   142  	}
   143  	return false
   144  }