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

     1  package installer
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"go.uber.org/zap"
    11  	appv1 "k8s.io/api/apps/v1"
    12  	corev1 "k8s.io/api/core/v1"
    13  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    14  	apiresource "k8s.io/apimachinery/pkg/api/resource"
    15  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  	"k8s.io/apimachinery/pkg/labels"
    17  	"k8s.io/apimachinery/pkg/runtime/schema"
    18  	"k8s.io/apimachinery/pkg/util/intstr"
    19  	"k8s.io/client-go/kubernetes"
    20  	"sigs.k8s.io/controller-runtime/pkg/client"
    21  
    22  	"github.com/argoproj/argo-events/common"
    23  	"github.com/argoproj/argo-events/controllers"
    24  	controllerscommon "github.com/argoproj/argo-events/controllers/common"
    25  	"github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1"
    26  )
    27  
    28  const (
    29  	clientPort  = int32(4222)
    30  	clusterPort = int32(6222)
    31  	monitorPort = int32(8222)
    32  
    33  	// annotation key on serverAuthSecret and clientAuthsecret
    34  	authStrategyAnnoKey = "strategy"
    35  	// key of client auth secret
    36  	clientAuthSecretKey = "client-auth"
    37  	// key of server auth secret
    38  	serverAuthSecretKey = "auth"
    39  	// key of stan.conf in the configmap
    40  	configMapKey = "stan-config"
    41  
    42  	// default nats streaming version to be installed
    43  	defaultSTANVersion = "0.22.1"
    44  )
    45  
    46  // natsInstaller is used create a NATS installation.
    47  type natsInstaller struct {
    48  	client     client.Client
    49  	kubeClient kubernetes.Interface
    50  	eventBus   *v1alpha1.EventBus
    51  	config     *controllers.GlobalConfig
    52  	labels     map[string]string
    53  	logger     *zap.SugaredLogger
    54  }
    55  
    56  // NewNATSInstaller returns a new NATS installer
    57  func NewNATSInstaller(client client.Client, eventBus *v1alpha1.EventBus, config *controllers.GlobalConfig, labels map[string]string, kubeClient kubernetes.Interface, logger *zap.SugaredLogger) Installer {
    58  	return &natsInstaller{
    59  		client:     client,
    60  		kubeClient: kubeClient,
    61  		eventBus:   eventBus,
    62  		config:     config,
    63  		labels:     labels,
    64  		logger:     logger.Named("nats"),
    65  	}
    66  }
    67  
    68  // Install creats a StatefulSet and a Service for NATS
    69  func (i *natsInstaller) Install(ctx context.Context) (*v1alpha1.BusConfig, error) {
    70  	natsObj := i.eventBus.Spec.NATS
    71  	if natsObj == nil || natsObj.Native == nil {
    72  		return nil, fmt.Errorf("invalid request")
    73  	}
    74  
    75  	svc, err := i.createStanService(ctx)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	cm, err := i.createConfigMap(ctx)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	// default to none
    84  	defaultAuthStrategy := v1alpha1.AuthStrategyNone
    85  	authStrategy := natsObj.Native.Auth
    86  	if authStrategy == nil {
    87  		authStrategy = &defaultAuthStrategy
    88  	}
    89  	serverAuthSecret, clientAuthSecret, err := i.createAuthSecrets(ctx, *authStrategy)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	if err := i.createStatefulSet(ctx, svc.Name, cm.Name, serverAuthSecret.Name); err != nil {
    95  		return nil, err
    96  	}
    97  	i.eventBus.Status.MarkDeployed("Succeeded", "NATS is deployed")
    98  	clusterID := generateClusterID(i.eventBus)
    99  	busConfig := &v1alpha1.BusConfig{
   100  		NATS: &v1alpha1.NATSConfig{
   101  			URL:       fmt.Sprintf("nats://%s:%s", generateServiceName(i.eventBus), strconv.Itoa(int(clientPort))),
   102  			ClusterID: &clusterID,
   103  			Auth:      authStrategy,
   104  		},
   105  	}
   106  	if *authStrategy != v1alpha1.AuthStrategyNone {
   107  		busConfig.NATS.AccessSecret = &corev1.SecretKeySelector{
   108  			Key: clientAuthSecretKey,
   109  			LocalObjectReference: corev1.LocalObjectReference{
   110  				Name: clientAuthSecret.Name,
   111  			},
   112  		}
   113  	}
   114  	return busConfig, nil
   115  }
   116  
   117  // Uninstall deletes those objects not handeled by cascade deletion.
   118  func (i *natsInstaller) Uninstall(ctx context.Context) error {
   119  	return i.uninstallPVCs(ctx)
   120  }
   121  
   122  func (i *natsInstaller) uninstallPVCs(ctx context.Context) error {
   123  	// StatefulSet doesn't clean up PVC, needs to do it separately
   124  	// https://github.com/kubernetes/kubernetes/issues/55045
   125  	log := i.logger
   126  	pvcs, err := i.getPVCs(ctx, i.labels)
   127  	if err != nil {
   128  		log.Errorw("Failed to get PVCs created by nats streaming statefulset when uninstalling", zap.Error(err))
   129  		return err
   130  	}
   131  	for _, pvc := range pvcs {
   132  		err = i.client.Delete(ctx, &pvc)
   133  		if err != nil {
   134  			log.Errorw("Failed to delete pvc when uninstalling", zap.Any("pvcName", pvc.Name), zap.Error(err))
   135  			return err
   136  		}
   137  		log.Infow("Pvc deleted", "pvcName", pvc.Name)
   138  	}
   139  	return nil
   140  }
   141  
   142  // Create a service for nats streaming
   143  func (i *natsInstaller) createStanService(ctx context.Context) (*corev1.Service, error) {
   144  	log := i.logger
   145  	svc, err := i.getStanService(ctx)
   146  	if err != nil && !apierrors.IsNotFound(err) {
   147  		i.eventBus.Status.MarkDeployFailed("GetServiceFailed", "Get existing service failed")
   148  		log.Errorw("Error getting existing service", zap.Error(err))
   149  		return nil, err
   150  	}
   151  	expectedSvc, err := i.buildStanService()
   152  	if err != nil {
   153  		i.eventBus.Status.MarkDeployFailed("BuildServiceFailed", "Failed to build a service spec")
   154  		log.Errorw("Error building service spec", zap.Error(err))
   155  		return nil, err
   156  	}
   157  	if svc != nil {
   158  		// TODO: potential issue here - if service spec is updated manually, reconciler will not change it back.
   159  		// Revisit it later to see if it is needed to compare the spec.
   160  		if svc.Annotations != nil && svc.Annotations[common.AnnotationResourceSpecHash] != expectedSvc.Annotations[common.AnnotationResourceSpecHash] {
   161  			svc.Spec = expectedSvc.Spec
   162  			svc.SetLabels(expectedSvc.Labels)
   163  			svc.Annotations[common.AnnotationResourceSpecHash] = expectedSvc.Annotations[common.AnnotationResourceSpecHash]
   164  			err = i.client.Update(ctx, svc)
   165  			if err != nil {
   166  				i.eventBus.Status.MarkDeployFailed("UpdateServiceFailed", "Failed to update existing service")
   167  				log.Errorw("Error updating existing service", zap.Error(err))
   168  				return nil, err
   169  			}
   170  			log.Infow("Service is updated", "serviceName", svc.Name)
   171  		}
   172  		return svc, nil
   173  	}
   174  	err = i.client.Create(ctx, expectedSvc)
   175  	if err != nil {
   176  		i.eventBus.Status.MarkDeployFailed("CreateServiceFailed", "Failed to create a service")
   177  		log.Errorw("Error creating a service", zap.Error(err))
   178  		return nil, err
   179  	}
   180  	log.Infow("Service is created", "serviceName", expectedSvc.Name)
   181  	return expectedSvc, nil
   182  }
   183  
   184  // Create a Configmap for NATS config
   185  func (i *natsInstaller) createConfigMap(ctx context.Context) (*corev1.ConfigMap, error) {
   186  	log := i.logger
   187  	cm, err := i.getConfigMap(ctx)
   188  	if err != nil && !apierrors.IsNotFound(err) {
   189  		i.eventBus.Status.MarkDeployFailed("GetConfigMapFailed", "Failed to get existing configmap")
   190  		log.Errorw("Error getting existing configmap", zap.Error(err))
   191  		return nil, err
   192  	}
   193  	expectedCm, err := i.buildConfigMap()
   194  	if err != nil {
   195  		i.eventBus.Status.MarkDeployFailed("BuildConfigMapFailed", "Failed to build a configmap spec")
   196  		log.Errorw("Error building configmap spec", zap.Error(err))
   197  		return nil, err
   198  	}
   199  	if cm != nil {
   200  		// TODO: Potential issue about comparing hash
   201  		if cm.Annotations != nil && cm.Annotations[common.AnnotationResourceSpecHash] != expectedCm.Annotations[common.AnnotationResourceSpecHash] {
   202  			cm.Data = expectedCm.Data
   203  			cm.SetLabels(expectedCm.Labels)
   204  			cm.Annotations[common.AnnotationResourceSpecHash] = expectedCm.Annotations[common.AnnotationResourceSpecHash]
   205  			err := i.client.Update(ctx, cm)
   206  			if err != nil {
   207  				i.eventBus.Status.MarkDeployFailed("UpdateConfigMapFailed", "Failed to update existing configmap")
   208  				log.Errorw("Error updating configmap", zap.Error(err))
   209  				return nil, err
   210  			}
   211  			log.Infow("Updated configmap", "configmapName", cm.Name)
   212  		}
   213  		return cm, nil
   214  	}
   215  	err = i.client.Create(ctx, expectedCm)
   216  	if err != nil {
   217  		i.eventBus.Status.MarkDeployFailed("CreateConfigMapFailed", "Failed to create configmap")
   218  		log.Errorw("Error creating a configmap", zap.Error(err))
   219  		return nil, err
   220  	}
   221  	log.Infow("Created configmap", "configmapName", expectedCm.Name)
   222  	return expectedCm, nil
   223  }
   224  
   225  // create server and client auth secrets
   226  func (i *natsInstaller) createAuthSecrets(ctx context.Context, strategy v1alpha1.AuthStrategy) (*corev1.Secret, *corev1.Secret, error) {
   227  	log := i.logger
   228  	sSecret, err := i.getServerAuthSecret(ctx)
   229  	if err != nil && !apierrors.IsNotFound(err) {
   230  		i.eventBus.Status.MarkDeployFailed("GetServerAuthSecretFailed", "Failed to get existing server auth secret")
   231  		log.Errorw("Error getting existing server auth secret", zap.Error(err))
   232  		return nil, nil, err
   233  	}
   234  	cSecret, err := i.getClientAuthSecret(ctx)
   235  	if err != nil && !apierrors.IsNotFound(err) {
   236  		i.eventBus.Status.MarkDeployFailed("GetClientAuthSecretFailed", "Failed to get existing client auth secret")
   237  		log.Errorw("Error getting existing client auth secret", zap.Error(err))
   238  		return nil, nil, err
   239  	}
   240  	if strategy != v1alpha1.AuthStrategyNone { // Do not checkout AuthStrategyNone because it only has server auth secret
   241  		if sSecret != nil && cSecret != nil && sSecret.Annotations != nil && cSecret.Annotations != nil {
   242  			if sSecret.Annotations[authStrategyAnnoKey] == string(strategy) && cSecret.Annotations[authStrategyAnnoKey] == string(strategy) {
   243  				// If the secrets are already existing, and strategy didn't change, reuse them without updating.
   244  				return sSecret, cSecret, nil
   245  			}
   246  		}
   247  	}
   248  
   249  	switch strategy {
   250  	case v1alpha1.AuthStrategyNone:
   251  		// Clean up client auth secret if existing
   252  		if cSecret != nil {
   253  			err = i.client.Delete(ctx, cSecret)
   254  			if err != nil {
   255  				i.eventBus.Status.MarkDeployFailed("DeleteClientAuthSecretFailed", "Failed to delete the client auth secret")
   256  				log.Errorw("Error deleting client auth secret", zap.Error(err))
   257  				return nil, nil, err
   258  			}
   259  			log.Info("Deleted server auth secret")
   260  		}
   261  		if sSecret != nil && sSecret.Annotations != nil && sSecret.Annotations[authStrategyAnnoKey] == string(strategy) && len(sSecret.Data[serverAuthSecretKey]) == 0 {
   262  			// If the server auth secret is already existing, strategy didn't change, and the secret is empty string, reuse it without updating.
   263  			return sSecret, nil, nil
   264  		}
   265  		// Only create an empty server auth secret
   266  		expectedSSecret, err := i.buildServerAuthSecret(strategy, "")
   267  		if err != nil {
   268  			i.eventBus.Status.MarkDeployFailed("BuildServerAuthSecretFailed", "Failed to build a server auth secret spec")
   269  			log.Errorw("Error building server auth secret spec", zap.Error(err))
   270  			return nil, nil, err
   271  		}
   272  		if sSecret != nil {
   273  			sSecret.ObjectMeta.Labels = expectedSSecret.Labels
   274  			sSecret.ObjectMeta.Annotations = expectedSSecret.Annotations
   275  			sSecret.Data = expectedSSecret.Data
   276  			err = i.client.Update(ctx, sSecret)
   277  			if err != nil {
   278  				i.eventBus.Status.MarkDeployFailed("UpdateServerAuthSecretFailed", "Failed to update the server auth secret")
   279  				log.Errorw("Error updating server auth secret", zap.Error(err))
   280  				return nil, nil, err
   281  			}
   282  			log.Infow("Updated server auth secret", "serverAuthSecretName", sSecret.Name)
   283  			return sSecret, nil, nil
   284  		}
   285  		err = i.client.Create(ctx, expectedSSecret)
   286  		if err != nil {
   287  			i.eventBus.Status.MarkDeployFailed("CreateServerAuthSecretFailed", "Failed to create a server auth secret")
   288  			log.Errorw("Error creating server auth secret", zap.Error(err))
   289  			return nil, nil, err
   290  		}
   291  		log.Infow("Created server auth secret", "serverAuthSecretName", expectedSSecret.Name)
   292  		return expectedSSecret, nil, nil
   293  	case v1alpha1.AuthStrategyToken:
   294  		token := common.RandomString(64)
   295  		serverAuthText := fmt.Sprintf(`authorization {
   296    token: "%s"
   297  }`, token)
   298  		clientAuthText := fmt.Sprintf("token: \"%s\"", token)
   299  		// Create server auth secret
   300  		expectedSSecret, err := i.buildServerAuthSecret(strategy, serverAuthText)
   301  		if err != nil {
   302  			i.eventBus.Status.MarkDeployFailed("BuildServerAuthSecretFailed", "Failed to build a server auth secret spec")
   303  			log.Errorw("Error building server auth secret spec", zap.Error(err))
   304  			return nil, nil, err
   305  		}
   306  		returnedSSecret := expectedSSecret
   307  		if sSecret == nil {
   308  			err = i.client.Create(ctx, expectedSSecret)
   309  			if err != nil {
   310  				i.eventBus.Status.MarkDeployFailed("CreateServerAuthSecretFailed", "Failed to create a server auth secret")
   311  				log.Errorw("Error creating server auth secret", zap.Error(err))
   312  				return nil, nil, err
   313  			}
   314  			log.Infow("Created server auth secret", "serverAuthSecretName", expectedSSecret.Name)
   315  		} else {
   316  			sSecret.Data = expectedSSecret.Data
   317  			sSecret.SetLabels(expectedSSecret.Labels)
   318  			sSecret.SetAnnotations(expectedSSecret.Annotations)
   319  			err = i.client.Update(ctx, sSecret)
   320  			if err != nil {
   321  				i.eventBus.Status.MarkDeployFailed("UpdateServerAuthSecretFailed", "Failed to update the server auth secret")
   322  				log.Errorw("Error updating server auth secret", zap.Error(err))
   323  				return nil, nil, err
   324  			}
   325  			log.Infow("Updated server auth secret", "serverAuthSecretName", sSecret.Name)
   326  			returnedSSecret = sSecret
   327  		}
   328  		// create client auth secret
   329  		expectedCSecret, err := i.buildClientAuthSecret(strategy, clientAuthText)
   330  		if err != nil {
   331  			i.eventBus.Status.MarkDeployFailed("BuildClientAuthSecretFailed", "Failed to build a client auth secret spec")
   332  			log.Errorw("Error building client auth secret spec", zap.Error(err))
   333  			return nil, nil, err
   334  		}
   335  		returnedCSecret := expectedCSecret
   336  		if cSecret == nil {
   337  			err = i.client.Create(ctx, expectedCSecret)
   338  			if err != nil {
   339  				i.eventBus.Status.MarkDeployFailed("CreateClientAuthSecretFailed", "Failed to create a client auth secret")
   340  				log.Errorw("Error creating client auth secret", zap.Error(err))
   341  				return nil, nil, err
   342  			}
   343  			log.Infow("Created client auth secret", "clientAuthSecretName", expectedCSecret.Name)
   344  		} else {
   345  			cSecret.Data = expectedCSecret.Data
   346  			cSecret.SetLabels(expectedCSecret.Labels)
   347  			cSecret.SetAnnotations(expectedCSecret.Annotations)
   348  			err = i.client.Update(ctx, cSecret)
   349  			if err != nil {
   350  				i.eventBus.Status.MarkDeployFailed("UpdateClientAuthSecretFailed", "Failed to update the client auth secret")
   351  				log.Errorw("Error updating client auth secret", zap.Error(err))
   352  				return nil, nil, err
   353  			}
   354  			log.Infow("Updated client auth secret", "clientAuthSecretName", cSecret.Name)
   355  			returnedCSecret = cSecret
   356  		}
   357  		return returnedSSecret, returnedCSecret, nil
   358  	default:
   359  		i.eventBus.Status.MarkDeployFailed("UnsupportedAuthStrategy", "Unsupported auth strategy")
   360  		return nil, nil, fmt.Errorf("unsupported auth strategy")
   361  	}
   362  }
   363  
   364  // Create a StatefulSet
   365  func (i *natsInstaller) createStatefulSet(ctx context.Context, serviceName, configmapName, authSecretName string) error {
   366  	log := i.logger
   367  	ss, err := i.getStatefulSet(ctx)
   368  	if err != nil && !apierrors.IsNotFound(err) {
   369  		i.eventBus.Status.MarkDeployFailed("GetStatefulSetFailed", "Failed to get existing statefulset")
   370  		log.Errorw("Error getting existing statefulset", zap.Error(err))
   371  		return err
   372  	}
   373  	expectedSs, err := i.buildStatefulSet(serviceName, configmapName, authSecretName)
   374  	if err != nil {
   375  		i.eventBus.Status.MarkDeployFailed("BuildStatefulSetFailed", "Failed to build a statefulset spec")
   376  		log.Errorw("Error building statefulset spec", zap.Error(err))
   377  		return err
   378  	}
   379  	if ss != nil {
   380  		if ss.Annotations != nil && ss.Annotations[common.AnnotationResourceSpecHash] == expectedSs.Annotations[common.AnnotationResourceSpecHash] {
   381  			return nil
   382  		}
   383  		ss.SetLabels(expectedSs.Labels)
   384  		ss.Annotations[common.AnnotationResourceSpecHash] = expectedSs.Annotations[common.AnnotationResourceSpecHash]
   385  		ss.Spec = expectedSs.Spec
   386  		if err := i.client.Update(ctx, ss); err != nil {
   387  			i.eventBus.Status.MarkDeployFailed("UpdateStatefulSetFailed", "Failed to update a statefulset")
   388  			log.Errorw("Error updating a statefulset", zap.Error(err))
   389  			return err
   390  		}
   391  		log.Infow("Statefulset is updated", "statefulsetName", ss.Name)
   392  		return nil
   393  	}
   394  	if err := i.client.Create(ctx, expectedSs); err != nil {
   395  		i.eventBus.Status.MarkDeployFailed("CreateStatefulSetFailed", "Failed to create a statefulset")
   396  		log.Errorw("Error creating a statefulset", zap.Error(err))
   397  		return err
   398  	}
   399  	log.Infow("Statefulset is created", "statefulsetName", expectedSs.Name)
   400  	return nil
   401  }
   402  
   403  // buildStanService builds a Service for NATS streaming
   404  func (i *natsInstaller) buildStanService() (*corev1.Service, error) {
   405  	svc := &corev1.Service{
   406  		ObjectMeta: metav1.ObjectMeta{
   407  			Name:      generateServiceName(i.eventBus),
   408  			Namespace: i.eventBus.Namespace,
   409  			Labels:    i.mergeEventBusLabels(stanServiceLabels(i.labels)),
   410  		},
   411  		Spec: corev1.ServiceSpec{
   412  			ClusterIP: corev1.ClusterIPNone,
   413  			Ports: []corev1.ServicePort{
   414  				// Prefix tcp- to enable clients to connect from
   415  				// an istio-enabled namespace, following:
   416  				// https://github.com/nats-io/nats-operator/issues/88
   417  				// https://github.com/istio/istio/issues/28623
   418  				{Name: "tcp-client", Port: clientPort},
   419  				{Name: "cluster", Port: clusterPort},
   420  				{Name: "monitor", Port: monitorPort},
   421  			},
   422  			Type:     corev1.ServiceTypeClusterIP,
   423  			Selector: i.labels,
   424  		},
   425  	}
   426  	if err := controllerscommon.SetObjectMeta(i.eventBus, svc, v1alpha1.SchemaGroupVersionKind); err != nil {
   427  		return nil, err
   428  	}
   429  	return svc, nil
   430  }
   431  
   432  // buildConfigMap builds a ConfigMap for NATS streaming
   433  func (i *natsInstaller) buildConfigMap() (*corev1.ConfigMap, error) {
   434  	clusterID := generateClusterID(i.eventBus)
   435  	svcName := generateServiceName(i.eventBus)
   436  	ssName := generateStatefulSetName(i.eventBus)
   437  	replicas := i.eventBus.Spec.NATS.Native.GetReplicas()
   438  	if replicas < 3 {
   439  		replicas = 3
   440  	}
   441  	maxAge := common.STANMaxAge
   442  	if i.eventBus.Spec.NATS.Native.MaxAge != nil {
   443  		maxAge = *i.eventBus.Spec.NATS.Native.MaxAge
   444  	}
   445  	_, err := time.ParseDuration(maxAge)
   446  	if err != nil {
   447  		return nil, err
   448  	}
   449  	maxMsgs := common.STANMaxMsgs
   450  	if i.eventBus.Spec.NATS.Native.MaxMsgs != nil {
   451  		maxMsgs = *i.eventBus.Spec.NATS.Native.MaxMsgs
   452  	}
   453  	maxSubs := common.STANMaxSubs
   454  	if i.eventBus.Spec.NATS.Native.MaxSubs != nil {
   455  		maxSubs = *i.eventBus.Spec.NATS.Native.MaxSubs
   456  	}
   457  	maxBytes := common.STANMaxBytes
   458  	if i.eventBus.Spec.NATS.Native.MaxBytes != nil {
   459  		maxBytes = *i.eventBus.Spec.NATS.Native.MaxBytes
   460  	}
   461  	maxPayload := common.STANMaxPayload
   462  	if i.eventBus.Spec.NATS.Native.MaxPayload != nil {
   463  		maxPayload = *i.eventBus.Spec.NATS.Native.MaxPayload
   464  	}
   465  	raftHeartbeatTimeout := common.STANRaftHeartbeatTimeout
   466  	if i.eventBus.Spec.NATS.Native.RaftHeartbeatTimeout != nil {
   467  		raftHeartbeatTimeout = *i.eventBus.Spec.NATS.Native.RaftHeartbeatTimeout
   468  	}
   469  	_, err = time.ParseDuration(raftHeartbeatTimeout)
   470  	if err != nil {
   471  		return nil, err
   472  	}
   473  	raftElectionTimeout := common.STANRaftElectionTimeout
   474  	if i.eventBus.Spec.NATS.Native.RaftElectionTimeout != nil {
   475  		raftElectionTimeout = *i.eventBus.Spec.NATS.Native.RaftElectionTimeout
   476  	}
   477  	_, err = time.ParseDuration(raftElectionTimeout)
   478  	if err != nil {
   479  		return nil, err
   480  	}
   481  	raftLeaseTimeout := common.STANRaftLeaseTimeout
   482  	if i.eventBus.Spec.NATS.Native.RaftLeaseTimeout != nil {
   483  		raftLeaseTimeout = *i.eventBus.Spec.NATS.Native.RaftLeaseTimeout
   484  	}
   485  	_, err = time.ParseDuration(raftLeaseTimeout)
   486  	if err != nil {
   487  		return nil, err
   488  	}
   489  	raftCommitTimeout := common.STANRaftCommitTimeout
   490  	if i.eventBus.Spec.NATS.Native.RaftCommitTimeout != nil {
   491  		raftCommitTimeout = *i.eventBus.Spec.NATS.Native.RaftCommitTimeout
   492  	}
   493  	_, err = time.ParseDuration(raftCommitTimeout)
   494  	if err != nil {
   495  		return nil, err
   496  	}
   497  	peers := []string{}
   498  	routes := []string{}
   499  	for j := 0; j < replicas; j++ {
   500  		peers = append(peers, fmt.Sprintf("\"%s-%s\"", ssName, strconv.Itoa(j)))
   501  		routes = append(routes, fmt.Sprintf("nats://%s-%s.%s.%s.svc:%s", ssName, strconv.Itoa(j), svcName, i.eventBus.Namespace, strconv.Itoa(int(clusterPort))))
   502  	}
   503  	conf := fmt.Sprintf(`http: %s
   504  include ./auth.conf
   505  cluster {
   506    port: %s
   507    routes: [%s]
   508    cluster_advertise: $CLUSTER_ADVERTISE
   509    connect_retries: 10
   510  }
   511  max_payload: %s
   512  streaming {
   513    id: %s
   514    store: file
   515    dir: /data/stan/store
   516    cluster {
   517  	node_id: $POD_NAME
   518  	peers: [%s]
   519  	log_path: /data/stan/logs
   520  	raft_heartbeat_timeout: "%s"
   521  	raft_election_timeout: "%s"
   522  	raft_lease_timeout: "%s"
   523  	raft_commit_timeout: "%s"
   524    }
   525    store_limits {
   526      max_age: %s
   527  	max_msgs: %v
   528  	max_bytes: %s
   529  	max_subs: %v
   530    }
   531  }`, strconv.Itoa(int(monitorPort)), strconv.Itoa(int(clusterPort)), strings.Join(routes, ","), maxPayload, clusterID, strings.Join(peers, ","), raftHeartbeatTimeout, raftElectionTimeout, raftLeaseTimeout, raftCommitTimeout, maxAge, maxMsgs, maxBytes, maxSubs)
   532  	cm := &corev1.ConfigMap{
   533  		ObjectMeta: metav1.ObjectMeta{
   534  			Namespace: i.eventBus.Namespace,
   535  			Name:      generateConfigMapName(i.eventBus),
   536  			Labels:    i.mergeEventBusLabels(i.labels),
   537  		},
   538  		Data: map[string]string{
   539  			configMapKey: conf,
   540  		},
   541  	}
   542  	if err := controllerscommon.SetObjectMeta(i.eventBus, cm, v1alpha1.SchemaGroupVersionKind); err != nil {
   543  		return nil, err
   544  	}
   545  	return cm, nil
   546  }
   547  
   548  // buildServerAuthSecret builds a secret for NATS auth config
   549  // Parameter - authStrategy: will be added to annoations
   550  // Parameter - secret
   551  // Example:
   552  //
   553  //	authorization {
   554  //	  token: "abcd1234"
   555  //	}
   556  func (i *natsInstaller) buildServerAuthSecret(authStrategy v1alpha1.AuthStrategy, secret string) (*corev1.Secret, error) {
   557  	s := &corev1.Secret{
   558  		ObjectMeta: metav1.ObjectMeta{
   559  			Namespace:   i.eventBus.Namespace,
   560  			Name:        generateServerAuthSecretName(i.eventBus),
   561  			Labels:      serverAuthSecretLabels(i.labels),
   562  			Annotations: map[string]string{authStrategyAnnoKey: string(authStrategy)},
   563  		},
   564  		Type: corev1.SecretTypeOpaque,
   565  		Data: map[string][]byte{
   566  			serverAuthSecretKey: []byte(secret),
   567  		},
   568  	}
   569  	if err := controllerscommon.SetObjectMeta(i.eventBus, s, v1alpha1.SchemaGroupVersionKind); err != nil {
   570  		return nil, err
   571  	}
   572  	return s, nil
   573  }
   574  
   575  // buildClientAuthSecret builds a secret for NATS client auth
   576  func (i *natsInstaller) buildClientAuthSecret(authStrategy v1alpha1.AuthStrategy, secret string) (*corev1.Secret, error) {
   577  	s := &corev1.Secret{
   578  		ObjectMeta: metav1.ObjectMeta{
   579  			Namespace:   i.eventBus.Namespace,
   580  			Name:        generateClientAuthSecretName(i.eventBus),
   581  			Labels:      clientAuthSecretLabels(i.labels),
   582  			Annotations: map[string]string{authStrategyAnnoKey: string(authStrategy)},
   583  		},
   584  		Type: corev1.SecretTypeOpaque,
   585  		Data: map[string][]byte{
   586  			clientAuthSecretKey: []byte(secret),
   587  		},
   588  	}
   589  	if err := controllerscommon.SetObjectMeta(i.eventBus, s, v1alpha1.SchemaGroupVersionKind); err != nil {
   590  		return nil, err
   591  	}
   592  	return s, nil
   593  }
   594  
   595  // buildStatefulSet builds a StatefulSet for nats streaming
   596  func (i *natsInstaller) buildStatefulSet(serviceName, configmapName, authSecretName string) (*appv1.StatefulSet, error) {
   597  	// Use provided serviceName, configMapName to build the spec
   598  	// to avoid issues when naming convention changes
   599  	spec, err := i.buildStatefulSetSpec(serviceName, configmapName, authSecretName)
   600  	if err != nil {
   601  		return nil, err
   602  	}
   603  	ss := &appv1.StatefulSet{
   604  		ObjectMeta: metav1.ObjectMeta{
   605  			Namespace: i.eventBus.Namespace,
   606  			Name:      generateStatefulSetName(i.eventBus),
   607  			Labels:    i.mergeEventBusLabels(i.labels),
   608  		},
   609  		Spec: *spec,
   610  	}
   611  	if err := controllerscommon.SetObjectMeta(i.eventBus, ss, v1alpha1.SchemaGroupVersionKind); err != nil {
   612  		return nil, err
   613  	}
   614  	return ss, nil
   615  }
   616  
   617  func (i *natsInstaller) buildStatefulSetSpec(serviceName, configmapName, authSecretName string) (*appv1.StatefulSetSpec, error) {
   618  	stanVersion, err := i.config.GetSTANVersion(defaultSTANVersion)
   619  	if err != nil {
   620  		return nil, fmt.Errorf("failed to get nats streaming version, err: %w", err)
   621  	}
   622  	// Streaming requires minimal size 3.
   623  	replicas := i.eventBus.Spec.NATS.Native.Replicas
   624  	if replicas < 3 {
   625  		replicas = 3
   626  	}
   627  	var stanContainerPullPolicy, metricsContainerPullPolicy corev1.PullPolicy
   628  	var stanContainerSecurityContext, metricsContainerSecurityContext *corev1.SecurityContext
   629  	stanContainerResources := corev1.ResourceRequirements{
   630  		Requests: corev1.ResourceList{
   631  			corev1.ResourceCPU: apiresource.MustParse("0"),
   632  		},
   633  	}
   634  	containerTmpl := i.eventBus.Spec.NATS.Native.ContainerTemplate
   635  	if containerTmpl != nil {
   636  		stanContainerResources = containerTmpl.Resources
   637  		stanContainerPullPolicy = containerTmpl.ImagePullPolicy
   638  		stanContainerSecurityContext = containerTmpl.SecurityContext
   639  	}
   640  	metricsContainerResources := corev1.ResourceRequirements{}
   641  	metricsContainerTmpl := i.eventBus.Spec.NATS.Native.MetricsContainerTemplate
   642  	if metricsContainerTmpl != nil {
   643  		metricsContainerResources = metricsContainerTmpl.Resources
   644  		metricsContainerPullPolicy = metricsContainerTmpl.ImagePullPolicy
   645  		metricsContainerSecurityContext = metricsContainerTmpl.SecurityContext
   646  	}
   647  
   648  	podTemplateLabels := make(map[string]string)
   649  	if i.eventBus.Spec.NATS.Native.Metadata != nil &&
   650  		len(i.eventBus.Spec.NATS.Native.Metadata.Labels) > 0 {
   651  		for k, v := range i.eventBus.Spec.NATS.Native.Metadata.Labels {
   652  			podTemplateLabels[k] = v
   653  		}
   654  	}
   655  	for k, v := range i.labels {
   656  		podTemplateLabels[k] = v
   657  	}
   658  	spec := appv1.StatefulSetSpec{
   659  		Replicas:    &replicas,
   660  		ServiceName: serviceName,
   661  		Selector: &metav1.LabelSelector{
   662  			MatchLabels: i.labels,
   663  		},
   664  		Template: corev1.PodTemplateSpec{
   665  			ObjectMeta: metav1.ObjectMeta{
   666  				Labels: podTemplateLabels,
   667  			},
   668  			Spec: corev1.PodSpec{
   669  				NodeSelector:       i.eventBus.Spec.NATS.Native.NodeSelector,
   670  				Tolerations:        i.eventBus.Spec.NATS.Native.Tolerations,
   671  				SecurityContext:    i.eventBus.Spec.NATS.Native.SecurityContext,
   672  				ImagePullSecrets:   i.eventBus.Spec.NATS.Native.ImagePullSecrets,
   673  				ServiceAccountName: i.eventBus.Spec.NATS.Native.ServiceAccountName,
   674  				PriorityClassName:  i.eventBus.Spec.NATS.Native.PriorityClassName,
   675  				Priority:           i.eventBus.Spec.NATS.Native.Priority,
   676  				Affinity:           i.eventBus.Spec.NATS.Native.Affinity,
   677  				Volumes: []corev1.Volume{
   678  					{
   679  						Name: "config-volume",
   680  						VolumeSource: corev1.VolumeSource{
   681  							Projected: &corev1.ProjectedVolumeSource{
   682  								Sources: []corev1.VolumeProjection{
   683  									{
   684  										ConfigMap: &corev1.ConfigMapProjection{
   685  											LocalObjectReference: corev1.LocalObjectReference{
   686  												Name: configmapName,
   687  											},
   688  											Items: []corev1.KeyToPath{
   689  												{
   690  													Key:  configMapKey,
   691  													Path: "stan.conf",
   692  												},
   693  											},
   694  										},
   695  									},
   696  									{
   697  										Secret: &corev1.SecretProjection{
   698  											LocalObjectReference: corev1.LocalObjectReference{
   699  												Name: authSecretName,
   700  											},
   701  											Items: []corev1.KeyToPath{
   702  												{
   703  													Key:  serverAuthSecretKey,
   704  													Path: "auth.conf",
   705  												},
   706  											},
   707  										},
   708  									},
   709  								},
   710  							},
   711  						},
   712  					},
   713  				},
   714  				Containers: []corev1.Container{
   715  					{
   716  						Name:            "stan",
   717  						Image:           stanVersion.NATSStreamingImage,
   718  						ImagePullPolicy: stanContainerPullPolicy,
   719  						Ports: []corev1.ContainerPort{
   720  							{Name: "client", ContainerPort: clientPort},
   721  							{Name: "cluster", ContainerPort: clusterPort},
   722  							{Name: "monitor", ContainerPort: monitorPort},
   723  						},
   724  						Command: []string{"/nats-streaming-server", "-sc", "/etc/stan-config/stan.conf"},
   725  						Env: []corev1.EnvVar{
   726  							{Name: "POD_NAME", ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.name"}}},
   727  							{Name: "POD_NAMESPACE", ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.namespace"}}},
   728  							{Name: "CLUSTER_ADVERTISE", Value: "$(POD_NAME)." + generateServiceName(i.eventBus) + ".$(POD_NAMESPACE).svc"},
   729  						},
   730  						VolumeMounts: []corev1.VolumeMount{
   731  							{Name: "config-volume", MountPath: "/etc/stan-config"},
   732  						},
   733  						Resources:       stanContainerResources,
   734  						SecurityContext: stanContainerSecurityContext,
   735  						LivenessProbe: &corev1.Probe{
   736  							ProbeHandler: corev1.ProbeHandler{
   737  								HTTPGet: &corev1.HTTPGetAction{
   738  									Path: "/",
   739  									Port: intstr.FromInt(int(monitorPort)),
   740  								},
   741  							},
   742  							InitialDelaySeconds: 10,
   743  							TimeoutSeconds:      5,
   744  						},
   745  					},
   746  					{
   747  						Name:            "metrics",
   748  						Image:           stanVersion.MetricsExporterImage,
   749  						ImagePullPolicy: metricsContainerPullPolicy,
   750  						Ports: []corev1.ContainerPort{
   751  							{Name: "metrics", ContainerPort: common.EventBusMetricsPort},
   752  						},
   753  						Args:            []string{"-connz", "-routez", "-subz", "-varz", "-channelz", "-serverz", fmt.Sprintf("http://localhost:%s", strconv.Itoa(int(monitorPort)))},
   754  						Resources:       metricsContainerResources,
   755  						SecurityContext: metricsContainerSecurityContext,
   756  					},
   757  				},
   758  			},
   759  		},
   760  	}
   761  	if i.eventBus.Spec.NATS.Native.Metadata != nil {
   762  		spec.Template.SetAnnotations(i.eventBus.Spec.NATS.Native.Metadata.Annotations)
   763  	}
   764  	if i.eventBus.Spec.NATS.Native.Persistence != nil {
   765  		volMode := corev1.PersistentVolumeFilesystem
   766  		pvcName := generatePVCName(i.eventBus)
   767  		// Default volume size
   768  		volSize := apiresource.MustParse("10Gi")
   769  		if i.eventBus.Spec.NATS.Native.Persistence.VolumeSize != nil {
   770  			volSize = *i.eventBus.Spec.NATS.Native.Persistence.VolumeSize
   771  		}
   772  		// Default to ReadWriteOnce
   773  		accessMode := corev1.ReadWriteOnce
   774  		if i.eventBus.Spec.NATS.Native.Persistence.AccessMode != nil {
   775  			accessMode = *i.eventBus.Spec.NATS.Native.Persistence.AccessMode
   776  		}
   777  		spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{
   778  			{
   779  				ObjectMeta: metav1.ObjectMeta{
   780  					Name: pvcName,
   781  				},
   782  				Spec: corev1.PersistentVolumeClaimSpec{
   783  					AccessModes: []corev1.PersistentVolumeAccessMode{
   784  						accessMode,
   785  					},
   786  					VolumeMode:       &volMode,
   787  					StorageClassName: i.eventBus.Spec.NATS.Native.Persistence.StorageClassName,
   788  					Resources: corev1.ResourceRequirements{
   789  						Requests: corev1.ResourceList{
   790  							corev1.ResourceStorage: volSize,
   791  						},
   792  					},
   793  				},
   794  			},
   795  		}
   796  		volumeMounts := spec.Template.Spec.Containers[0].VolumeMounts
   797  		volumeMounts = append(volumeMounts, corev1.VolumeMount{Name: pvcName, MountPath: "/data/stan"})
   798  		spec.Template.Spec.Containers[0].VolumeMounts = volumeMounts
   799  	} else {
   800  		// When the POD is runasnonroot, it can not create the dir /data/stan
   801  		// Use an emptyDirVolume to workaround the issue
   802  		emptyDirVolName := "stan-data"
   803  		volumes := spec.Template.Spec.Volumes
   804  		volumes = append(volumes, corev1.Volume{Name: emptyDirVolName, VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}})
   805  		spec.Template.Spec.Volumes = volumes
   806  		volumeMounts := spec.Template.Spec.Containers[0].VolumeMounts
   807  		volumeMounts = append(volumeMounts, corev1.VolumeMount{Name: emptyDirVolName, MountPath: "/data/stan"})
   808  		spec.Template.Spec.Containers[0].VolumeMounts = volumeMounts
   809  	}
   810  	return &spec, nil
   811  }
   812  
   813  func (i *natsInstaller) getStanService(ctx context.Context) (*corev1.Service, error) {
   814  	return i.getService(ctx, stanServiceLabels(i.labels))
   815  }
   816  
   817  func (i *natsInstaller) getService(ctx context.Context, labels map[string]string) (*corev1.Service, error) {
   818  	// Why not using getByName()?
   819  	// Naming convention might be changed.
   820  	sl := &corev1.ServiceList{}
   821  	err := i.client.List(ctx, sl, &client.ListOptions{
   822  		Namespace:     i.eventBus.Namespace,
   823  		LabelSelector: labelSelector(labels),
   824  	})
   825  	if err != nil {
   826  		return nil, err
   827  	}
   828  	for _, svc := range sl.Items {
   829  		if metav1.IsControlledBy(&svc, i.eventBus) {
   830  			return &svc, nil
   831  		}
   832  	}
   833  	return nil, apierrors.NewNotFound(schema.GroupResource{}, "")
   834  }
   835  
   836  func (i *natsInstaller) getConfigMap(ctx context.Context) (*corev1.ConfigMap, error) {
   837  	cml := &corev1.ConfigMapList{}
   838  	err := i.client.List(ctx, cml, &client.ListOptions{
   839  		Namespace:     i.eventBus.Namespace,
   840  		LabelSelector: labelSelector(i.labels),
   841  	})
   842  	if err != nil {
   843  		return nil, err
   844  	}
   845  	for _, cm := range cml.Items {
   846  		if metav1.IsControlledBy(&cm, i.eventBus) {
   847  			return &cm, nil
   848  		}
   849  	}
   850  	return nil, apierrors.NewNotFound(schema.GroupResource{}, "")
   851  }
   852  
   853  // get server auth secret
   854  func (i *natsInstaller) getServerAuthSecret(ctx context.Context) (*corev1.Secret, error) {
   855  	return i.getSecret(ctx, serverAuthSecretLabels(i.labels))
   856  }
   857  
   858  // get client auth secret
   859  func (i *natsInstaller) getClientAuthSecret(ctx context.Context) (*corev1.Secret, error) {
   860  	return i.getSecret(ctx, clientAuthSecretLabels(i.labels))
   861  }
   862  
   863  func (i *natsInstaller) getSecret(ctx context.Context, labels map[string]string) (*corev1.Secret, error) {
   864  	sl, err := i.kubeClient.CoreV1().Secrets(i.eventBus.Namespace).List(ctx, metav1.ListOptions{LabelSelector: labelSelector(labels).String()})
   865  	if err != nil {
   866  		return nil, err
   867  	}
   868  	for _, s := range sl.Items {
   869  		if metav1.IsControlledBy(&s, i.eventBus) {
   870  			return &s, nil
   871  		}
   872  	}
   873  	return nil, apierrors.NewNotFound(schema.GroupResource{}, "")
   874  }
   875  
   876  func (i *natsInstaller) getStatefulSet(ctx context.Context) (*appv1.StatefulSet, error) {
   877  	// Why not using getByName()?
   878  	// Naming convention might be changed.
   879  	ssl := &appv1.StatefulSetList{}
   880  	err := i.client.List(ctx, ssl, &client.ListOptions{
   881  		Namespace:     i.eventBus.Namespace,
   882  		LabelSelector: labelSelector(i.labels),
   883  	})
   884  	if err != nil {
   885  		return nil, err
   886  	}
   887  	for _, ss := range ssl.Items {
   888  		if metav1.IsControlledBy(&ss, i.eventBus) {
   889  			return &ss, nil
   890  		}
   891  	}
   892  	return nil, apierrors.NewNotFound(schema.GroupResource{}, "")
   893  }
   894  
   895  // get PVCs created by streaming statefulset
   896  // they have same labels as the statefulset
   897  func (i *natsInstaller) getPVCs(ctx context.Context, labels map[string]string) ([]corev1.PersistentVolumeClaim, error) {
   898  	pvcl := &corev1.PersistentVolumeClaimList{}
   899  	err := i.client.List(ctx, pvcl, &client.ListOptions{
   900  		Namespace:     i.eventBus.Namespace,
   901  		LabelSelector: labelSelector(labels),
   902  	})
   903  	if err != nil {
   904  		return nil, err
   905  	}
   906  	return pvcl.Items, nil
   907  }
   908  
   909  func (i *natsInstaller) mergeEventBusLabels(given map[string]string) map[string]string {
   910  	result := map[string]string{}
   911  	if i.eventBus.Labels != nil {
   912  		for k, v := range i.eventBus.Labels {
   913  			result[k] = v
   914  		}
   915  	}
   916  	for k, v := range given {
   917  		result[k] = v
   918  	}
   919  	return result
   920  }
   921  
   922  func serverAuthSecretLabels(given map[string]string) map[string]string {
   923  	result := map[string]string{"server-auth-secret": "yes"}
   924  	for k, v := range given {
   925  		result[k] = v
   926  	}
   927  	return result
   928  }
   929  
   930  func clientAuthSecretLabels(given map[string]string) map[string]string {
   931  	result := map[string]string{"client-auth-secret": "yes"}
   932  	for k, v := range given {
   933  		result[k] = v
   934  	}
   935  	return result
   936  }
   937  
   938  func stanServiceLabels(given map[string]string) map[string]string {
   939  	result := map[string]string{"stan": "yes"}
   940  	for k, v := range given {
   941  		result[k] = v
   942  	}
   943  	return result
   944  }
   945  
   946  func labelSelector(labelMap map[string]string) labels.Selector {
   947  	return labels.SelectorFromSet(labelMap)
   948  }
   949  
   950  func generateServiceName(eventBus *v1alpha1.EventBus) string {
   951  	return fmt.Sprintf("eventbus-%s-stan-svc", eventBus.Name)
   952  }
   953  
   954  func generateConfigMapName(eventBus *v1alpha1.EventBus) string {
   955  	return fmt.Sprintf("eventbus-%s-stan-configmap", eventBus.Name)
   956  }
   957  
   958  func generateServerAuthSecretName(eventBus *v1alpha1.EventBus) string {
   959  	return fmt.Sprintf("eventbus-%s-server", eventBus.Name)
   960  }
   961  
   962  func generateClientAuthSecretName(eventBus *v1alpha1.EventBus) string {
   963  	return fmt.Sprintf("eventbus-%s-client", eventBus.Name)
   964  }
   965  
   966  func generateStatefulSetName(eventBus *v1alpha1.EventBus) string {
   967  	return fmt.Sprintf("eventbus-%s-stan", eventBus.Name)
   968  }
   969  
   970  func generateClusterID(eventBus *v1alpha1.EventBus) string {
   971  	return fmt.Sprintf("eventbus-%s", eventBus.Name)
   972  }
   973  
   974  // PVC name used in streaming statefulset
   975  func generatePVCName(eventBus *v1alpha1.EventBus) string {
   976  	return fmt.Sprintf("stan-%s-vol", eventBus.Name)
   977  }