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
}