func()

in controllers/solrprometheusexporter_controller.go [66:270]


func (r *SolrPrometheusExporterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	logger := log.FromContext(ctx)

	// Fetch the SolrPrometheusExporter instance
	prometheusExporter := &solrv1beta1.SolrPrometheusExporter{}
	err := r.Get(ctx, req.NamespacedName, prometheusExporter)
	if err != nil {
		if errors.IsNotFound(err) {
			// Object not found, return.  Created objects are automatically garbage collected.
			// For additional cleanup logic use finalizers.
			return ctrl.Result{}, nil
		}
		// Error reading the object - requeue the req.
		return ctrl.Result{}, err
	}

	changed := prometheusExporter.WithDefaults()
	if changed {
		logger.Info("Setting default settings for Solr PrometheusExporter")
		if err := r.Update(ctx, prometheusExporter); err != nil {
			return ctrl.Result{}, err
		}
		return ctrl.Result{Requeue: true}, nil
	}

	requeueOrNot := ctrl.Result{}

	configMapKey := util.PrometheusExporterConfigMapKey
	configXmlMd5 := ""
	if prometheusExporter.Spec.Config == "" && prometheusExporter.Spec.CustomKubeOptions.ConfigMapOptions != nil && prometheusExporter.Spec.CustomKubeOptions.ConfigMapOptions.ProvidedConfigMap != "" {
		foundConfigMap := &corev1.ConfigMap{}
		err = r.Get(ctx, types.NamespacedName{Name: prometheusExporter.Spec.CustomKubeOptions.ConfigMapOptions.ProvidedConfigMap, Namespace: prometheusExporter.Namespace}, foundConfigMap)
		if err != nil {
			return requeueOrNot, err
		}

		if foundConfigMap.Data != nil {
			configXml, ok := foundConfigMap.Data[configMapKey]
			if ok {
				configXmlMd5 = fmt.Sprintf("%x", md5.Sum([]byte(configXml)))
			} else {
				return requeueOrNot, fmt.Errorf("required '%s' key not found in provided ConfigMap %s",
					configMapKey, prometheusExporter.Spec.CustomKubeOptions.ConfigMapOptions.ProvidedConfigMap)
			}
		} else {
			return requeueOrNot, fmt.Errorf("provided ConfigMap %s has no data",
				prometheusExporter.Spec.CustomKubeOptions.ConfigMapOptions.ProvidedConfigMap)
		}
	}

	if prometheusExporter.Spec.Config != "" {
		// Generate ConfigMap
		configMap := util.GenerateMetricsConfigMap(prometheusExporter)

		// capture the MD5 for the default config XML, otherwise we already computed it above
		if configXmlMd5 == "" {
			configXmlMd5 = fmt.Sprintf("%x", md5.Sum([]byte(configMap.Data[configMapKey])))
		}

		// Check if the ConfigMap already exists
		configMapLogger := logger.WithValues("configMap", configMap.Name)
		foundConfigMap := &corev1.ConfigMap{}
		err = r.Get(ctx, types.NamespacedName{Name: configMap.Name, Namespace: configMap.Namespace}, foundConfigMap)
		if err != nil && errors.IsNotFound(err) {
			configMapLogger.Info("Creating ConfigMap")
			if err = controllerutil.SetControllerReference(prometheusExporter, configMap, r.Scheme); err == nil {
				err = r.Create(ctx, configMap)
			}
		} else if err == nil {
			var needsUpdate bool
			needsUpdate, err = util.OvertakeControllerRef(prometheusExporter, foundConfigMap, r.Scheme)
			needsUpdate = util.CopyConfigMapFields(configMap, foundConfigMap, configMapLogger) || needsUpdate

			// Update the found ConfigMap and write the result back if there are any changes
			if needsUpdate && err == nil {
				configMapLogger.Info("Updating ConfigMap")
				err = r.Update(ctx, foundConfigMap)
			}
		}
		if err != nil {
			return requeueOrNot, err
		}
	}

	// Generate Metrics Service
	metricsService := util.GenerateSolrMetricsService(prometheusExporter)

	// Check if the Metrics Service already exists
	serviceLogger := logger.WithValues("service", metricsService.Name)
	foundMetricsService := &corev1.Service{}
	err = r.Get(ctx, types.NamespacedName{Name: metricsService.Name, Namespace: metricsService.Namespace}, foundMetricsService)
	if err != nil && errors.IsNotFound(err) {
		serviceLogger.Info("Creating Service")
		if err = controllerutil.SetControllerReference(prometheusExporter, metricsService, r.Scheme); err == nil {
			err = r.Create(ctx, metricsService)
		}
	} else if err == nil {
		var needsUpdate bool
		needsUpdate, err = util.OvertakeControllerRef(prometheusExporter, foundMetricsService, r.Scheme)
		needsUpdate = util.CopyServiceFields(metricsService, foundMetricsService, serviceLogger) || needsUpdate

		// Update the found Metrics Service and write the result back if there are any changes
		if needsUpdate && err == nil {
			serviceLogger.Info("Updating Service")
			err = r.Update(ctx, foundMetricsService)
		}
	}
	if err != nil {
		return requeueOrNot, err
	}

	// Get the ZkConnectionString to connect to
	solrConnectionInfo := util.SolrConnectionInfo{}
	var solrCloudImage *solrv1beta1.ContainerImage
	if solrConnectionInfo, solrCloudImage, err = getSolrConnectionInfo(ctx, r, prometheusExporter); err != nil {
		return requeueOrNot, err
	}

	// Make sure the TLS config is in order
	var tls *util.TLSCerts = nil
	if prometheusExporter.Spec.SolrReference.SolrTLS != nil {
		tls, err = r.reconcileTLSConfig(prometheusExporter)
		if err != nil {
			return requeueOrNot, err
		}
	}

	basicAuthMd5 := ""
	if prometheusExporter.Spec.SolrReference.BasicAuthSecret != "" {
		basicAuthSecret := &corev1.Secret{}
		err := r.Get(ctx, types.NamespacedName{Name: prometheusExporter.Spec.SolrReference.BasicAuthSecret, Namespace: prometheusExporter.Namespace}, basicAuthSecret)
		if err != nil {
			return reconcile.Result{}, err
		}

		err = util.ValidateBasicAuthSecret(basicAuthSecret)
		if err != nil {
			return reconcile.Result{}, err
		}
		creds := fmt.Sprintf("%s:%s", basicAuthSecret.Data[corev1.BasicAuthUsernameKey], basicAuthSecret.Data[corev1.BasicAuthPasswordKey])
		basicAuthMd5 = fmt.Sprintf("%x", md5.Sum([]byte(creds)))
	}

	deploy := util.GenerateSolrPrometheusExporterDeployment(prometheusExporter, solrConnectionInfo, solrCloudImage, configXmlMd5, tls, basicAuthMd5)

	ready := false
	// Check if the Metrics Deployment already exists
	deploymentLogger := logger.WithValues("deployment", deploy.Name)
	foundDeploy := &appsv1.Deployment{}
	err = r.Get(ctx, types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, foundDeploy)

	// Set the annotation for a scheduled restart, if necessary.
	if nextRestartAnnotation, reconcileWaitDuration, err := util.ScheduleNextRestart(prometheusExporter.Spec.RestartSchedule, foundDeploy.Spec.Template.Annotations); err != nil {
		logger.Error(err, "Cannot parse restartSchedule cron", "cron", prometheusExporter.Spec.RestartSchedule)
	} else {
		if nextRestartAnnotation != "" {
			if deploy.Spec.Template.Annotations == nil {
				deploy.Spec.Template.Annotations = make(map[string]string, 1)
			}
			// Set the new restart time annotation
			deploy.Spec.Template.Annotations[util.SolrScheduledRestartAnnotation] = nextRestartAnnotation
			// TODO: Create event for the CRD.
		} else if existingRestartAnnotation, exists := foundDeploy.Spec.Template.Annotations[util.SolrScheduledRestartAnnotation]; exists {
			if deploy.Spec.Template.Annotations == nil {
				deploy.Spec.Template.Annotations = make(map[string]string, 1)
			}
			// Keep the existing nextRestart annotation if it exists and we aren't setting a new one.
			deploy.Spec.Template.Annotations[util.SolrScheduledRestartAnnotation] = existingRestartAnnotation
		}
		if reconcileWaitDuration != nil {
			// Set the requeueAfter if it has not been set, or is greater than the time we need to wait to restart again
			updateRequeueAfter(&requeueOrNot, *reconcileWaitDuration)
		}
	}

	if err != nil && errors.IsNotFound(err) {
		deploymentLogger.Info("Creating Deployment")
		if err = controllerutil.SetControllerReference(prometheusExporter, deploy, r.Scheme); err == nil {
			err = r.Create(ctx, deploy)
		}
	} else if err == nil {
		var needsUpdate bool
		needsUpdate, err = util.OvertakeControllerRef(prometheusExporter, foundDeploy, r.Scheme)
		needsUpdate = util.CopyDeploymentFields(deploy, foundDeploy, deploymentLogger) || needsUpdate

		// Update the found Metrics Service and write the result back if there are any changes
		if needsUpdate && err == nil {
			deploymentLogger.Info("Updating Deployment")
			err = r.Update(ctx, foundDeploy)
		}
		ready = foundDeploy.Status.ReadyReplicas > 0
	}
	if err != nil {
		return requeueOrNot, err
	}

	if ready != prometheusExporter.Status.Ready {
		originalPrometheusExporter := prometheusExporter.DeepCopy()
		prometheusExporter.Status.Ready = ready
		logger.Info("Updating status for solr-prometheus-exporter")
		err = r.Status().Patch(ctx, prometheusExporter, client.MergeFrom(originalPrometheusExporter))
	}

	return requeueOrNot, err
}