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

     1  package installer
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"go.uber.org/zap"
     8  	"k8s.io/client-go/kubernetes"
     9  	"sigs.k8s.io/controller-runtime/pkg/client"
    10  
    11  	"github.com/argoproj/argo-events/common"
    12  	"github.com/argoproj/argo-events/controllers"
    13  	"github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1"
    14  	eventsourcev1alpha1 "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1"
    15  	sensorv1alpha1 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1"
    16  )
    17  
    18  // Installer is an interface for event bus installation
    19  type Installer interface {
    20  	Install(ctx context.Context) (*v1alpha1.BusConfig, error)
    21  	// Uninsall only needs to handle those resources not cascade deleted.
    22  	// For example, undeleted PVCs not automatically deleted when deleting a StatefulSet
    23  	Uninstall(ctx context.Context) error
    24  }
    25  
    26  // Install function installs the event bus
    27  func Install(ctx context.Context, eventBus *v1alpha1.EventBus, client client.Client, kubeClient kubernetes.Interface, config *controllers.GlobalConfig, logger *zap.SugaredLogger) error {
    28  	installer, err := getInstaller(eventBus, client, kubeClient, config, logger)
    29  	if err != nil {
    30  		logger.Errorw("failed to an installer", zap.Error(err))
    31  		return err
    32  	}
    33  	busConfig, err := installer.Install(ctx)
    34  	if err != nil {
    35  		logger.Errorw("installation error", zap.Error(err))
    36  		return err
    37  	}
    38  	eventBus.Status.Config = *busConfig
    39  	return nil
    40  }
    41  
    42  // GetInstaller returns Installer implementation
    43  func getInstaller(eventBus *v1alpha1.EventBus, client client.Client, kubeClient kubernetes.Interface, config *controllers.GlobalConfig, logger *zap.SugaredLogger) (Installer, error) {
    44  	if nats := eventBus.Spec.NATS; nats != nil {
    45  		if nats.Exotic != nil {
    46  			return NewExoticNATSInstaller(eventBus, logger), nil
    47  		} else if nats.Native != nil {
    48  			return NewNATSInstaller(client, eventBus, config, getLabels(eventBus), kubeClient, logger), nil
    49  		}
    50  	} else if js := eventBus.Spec.JetStream; js != nil {
    51  		return NewJetStreamInstaller(client, eventBus, config, getLabels(eventBus), kubeClient, logger), nil
    52  	} else if kafka := eventBus.Spec.Kafka; kafka != nil {
    53  		return NewExoticKafkaInstaller(eventBus, logger), nil
    54  	} else if js := eventBus.Spec.JetStreamExotic; js != nil {
    55  		return NewExoticJetStreamInstaller(eventBus, logger), nil
    56  	}
    57  	return nil, fmt.Errorf("invalid eventbus spec")
    58  }
    59  
    60  func getLabels(bus *v1alpha1.EventBus) map[string]string {
    61  	return map[string]string{
    62  		"controller":          "eventbus-controller",
    63  		"eventbus-name":       bus.Name,
    64  		common.LabelOwnerName: bus.Name,
    65  	}
    66  }
    67  
    68  // Uninstall function will be run before the EventBus object is deleted,
    69  // usually it could be used to uninstall the extra resources who would not be cleaned
    70  // up when an EventBus is deleted. Most of the time this is not needed as all
    71  // the dependency resources should have been deleted by owner references cascade
    72  // deletion, but things like PVC created by StatefulSet need to be cleaned up
    73  // separately.
    74  //
    75  // It could also be used to check if the EventBus object can be safely deleted.
    76  func Uninstall(ctx context.Context, eventBus *v1alpha1.EventBus, client client.Client, kubeClient kubernetes.Interface, config *controllers.GlobalConfig, logger *zap.SugaredLogger) error {
    77  	linkedEventSources, err := linkedEventSources(ctx, eventBus.Namespace, eventBus.Name, client)
    78  	if err != nil {
    79  		logger.Errorw("failed to query linked EventSources", zap.Error(err))
    80  		return fmt.Errorf("failed to check if there is any EventSource linked, %w", err)
    81  	}
    82  	if linkedEventSources > 0 {
    83  		return fmt.Errorf("can not delete an EventBus with %v EventSources connected", linkedEventSources)
    84  	}
    85  
    86  	linkedSensors, err := linkedSensors(ctx, eventBus.Namespace, eventBus.Name, client)
    87  	if err != nil {
    88  		logger.Errorw("failed to query linked Sensors", zap.Error(err))
    89  		return fmt.Errorf("failed to check if there is any Sensor linked, %w", err)
    90  	}
    91  	if linkedSensors > 0 {
    92  		return fmt.Errorf("can not delete an EventBus with %v Sensors connected", linkedSensors)
    93  	}
    94  
    95  	installer, err := getInstaller(eventBus, client, kubeClient, config, logger)
    96  	if err != nil {
    97  		logger.Errorw("failed to get an installer", zap.Error(err))
    98  		return err
    99  	}
   100  	return installer.Uninstall(ctx)
   101  }
   102  
   103  func linkedEventSources(ctx context.Context, namespace, eventBusName string, c client.Client) (int, error) {
   104  	esl := &eventsourcev1alpha1.EventSourceList{}
   105  	if err := c.List(ctx, esl, &client.ListOptions{
   106  		Namespace: namespace,
   107  	}); err != nil {
   108  		return 0, err
   109  	}
   110  	result := 0
   111  	for _, es := range esl.Items {
   112  		ebName := es.Spec.EventBusName
   113  		if ebName == "" {
   114  			ebName = common.DefaultEventBusName
   115  		}
   116  		if ebName == eventBusName {
   117  			result++
   118  		}
   119  	}
   120  	return result, nil
   121  }
   122  
   123  func linkedSensors(ctx context.Context, namespace, eventBusName string, c client.Client) (int, error) {
   124  	sl := &sensorv1alpha1.SensorList{}
   125  	if err := c.List(ctx, sl, &client.ListOptions{
   126  		Namespace: namespace,
   127  	}); err != nil {
   128  		return 0, err
   129  	}
   130  	result := 0
   131  	for _, s := range sl.Items {
   132  		sName := s.Spec.EventBusName
   133  		if sName == "" {
   134  			sName = common.DefaultEventBusName
   135  		}
   136  		if sName == eventBusName {
   137  			result++
   138  		}
   139  	}
   140  	return result, nil
   141  }