Pass exporter args as env vars where possible (#639)

In recent versions of Solr (>=8.8) the prometheus exporter has an
env-var equivalent for each CLI argument taken by its start script.

This commit switches the operator over to providing values using this
env-var capability where possible.  Hopefully this makes the created
resources a little cleaner and easier-to-read for administrators and
users.
diff --git a/controllers/solrprometheusexporter_controller_test.go b/controllers/solrprometheusexporter_controller_test.go
index 5c25917..712a535 100644
--- a/controllers/solrprometheusexporter_controller_test.go
+++ b/controllers/solrprometheusexporter_controller_test.go
@@ -103,14 +103,29 @@
 			Expect(deployment.Spec.Template.Spec.Containers).To(HaveLen(1), "Wrong number of containers for the Deployment")
 			Expect(deployment.Spec.Template.Spec.InitContainers).To(BeEmpty(), "Wrong number of initContainers for the Deployment")
 
-			expectedArgs := []string{
-				"-p", strconv.Itoa(util.SolrMetricsPort),
-				"-n", strconv.Itoa(int(testNumThreads)),
-				"-s", strconv.Itoa(int(testScrapeInterval)),
-				"-z", testZkCnxString + testZKChroot,
-				"-f", "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml",
+			exporterArgEnvVars := []corev1.EnvVar{
+				{
+					Name:  "PORT",
+					Value: strconv.Itoa(util.SolrMetricsPort),
+				},
+				{
+					Name:  "NUM_THREADS",
+					Value: strconv.Itoa(int(testNumThreads)),
+				},
+				{
+					Name:  "SCRAPE_INTERVAL",
+					Value: strconv.Itoa(int(testScrapeInterval)),
+				},
+				{
+					Name:  "ZK_HOST",
+					Value: testZkCnxString + testZKChroot,
+				},
+				{
+					Name:  "CONFIG_FILE",
+					Value: "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml",
+				},
 			}
-			Expect(deployment.Spec.Template.Spec.Containers[0].Args).To(Equal(expectedArgs), "Incorrect arguments for the SolrPrometheusExporter container")
+			Expect(deployment.Spec.Template.Spec.Containers[0].Env).To(ContainElements(exporterArgEnvVars), "Incorrect arguments for the SolrPrometheusExporter container")
 			Expect(deployment.Spec.Template.Spec.Containers[0].Command).To(Equal([]string{util.DefaultPrometheusExporterEntrypoint}), "Incorrect command for the SolrPrometheusExporter container")
 		})
 	})
@@ -198,15 +213,30 @@
 			Expect(deployment.Spec.Template.Spec.InitContainers).To(HaveLen(len(extraContainers2)), "Wrong number of initContainers for the Deployment")
 			Expect(deployment.Spec.Template.Spec.InitContainers).To(Equal(extraContainers2), "Incorrect init containers")
 
-			expectedArgs := []string{
-				"-p", strconv.Itoa(util.SolrMetricsPort),
-				"-n", strconv.Itoa(int(testNumThreads)),
-				"-s", strconv.Itoa(int(testScrapeInterval)),
-				"-z", testZkCnxString + testZKChroot,
-				"-f", "/opt/solr-exporter/solr-prometheus-exporter.xml",
+			exporterArgEnvVars := []corev1.EnvVar{
+				{
+					Name:  "PORT",
+					Value: strconv.Itoa(util.SolrMetricsPort),
+				},
+				{
+					Name:  "NUM_THREADS",
+					Value: strconv.Itoa(int(testNumThreads)),
+				},
+				{
+					Name:  "SCRAPE_INTERVAL",
+					Value: strconv.Itoa(int(testScrapeInterval)),
+				},
+				{
+					Name:  "ZK_HOST",
+					Value: testZkCnxString + testZKChroot,
+				},
+				{
+					Name:  "CONFIG_FILE",
+					Value: "/opt/solr-exporter/solr-prometheus-exporter.xml",
+				},
 			}
-			Expect(deployment.Spec.Template.Spec.Containers[0].Args).To(Equal(expectedArgs), "Incorrect arguments for the SolrPrometheusExporter container")
 			Expect(deployment.Spec.Template.Spec.Containers[0].Command).To(Equal([]string{util.DefaultPrometheusExporterEntrypoint}), "Incorrect command for the SolrPrometheusExporter container")
+			Expect(deployment.Spec.Template.Spec.Containers[0].Env).To(ContainElements(exporterArgEnvVars), "Incorrect or missing environment variables used by the exporter script")
 
 			By("testing the SolrPrometheusExporter Deployment Custom Options")
 			Expect(deployment.Spec.Template.Spec.PriorityClassName).To(Equal(testPriorityClass), "Incorrect Priority class name for Pod Spec")
@@ -215,7 +245,7 @@
 			Expect(deployment.Spec.Template.Spec.NodeSelector).To(Equal(testNodeSelectors), "Incorrect pod node selectors")
 
 			// Other Pod Options
-			Expect(deployment.Spec.Template.Spec.Containers[0].Env).To(Equal(addBuiltInEnvVars(extraVars)), "Extra Env Vars are not the same as the ones provided in podOptions")
+			Expect(deployment.Spec.Template.Spec.Containers[0].Env).To(ContainElements(addBuiltInEnvVars(extraVars)), "Extra Env Vars are not the same as the ones provided in podOptions")
 			Expect(*deployment.Spec.Template.Spec.SecurityContext).To(Equal(testPodSecurityContext), "PodSecurityContext is not the same as the one provided in podOptions")
 			Expect(deployment.Spec.Template.Spec.Affinity).To(Equal(testAffinity), "Affinity is not the same as the one provided in podOptions")
 			Expect(deployment.Spec.Template.Spec.Containers[0].Resources.Limits).To(Equal(testResources.Limits), "Resources.Limits is not the same as the one provided in podOptions")
@@ -328,13 +358,7 @@
 		FIt("has the correct resources", func(ctx context.Context) {
 			By("testing the SolrPrometheusExporter Deployment")
 			expectDeploymentWithChecks(ctx, solrPrometheusExporter, solrPrometheusExporter.MetricsDeploymentName(), func(g Gomega, found *appsv1.Deployment) {
-				expectedArgs := []string{
-					"-p", strconv.Itoa(util.SolrMetricsPort),
-					"-n", strconv.Itoa(1),
-					"-z", testZkCnxString + testZKChroot,
-					"-f", "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml",
-				}
-				g.Expect(found.Spec.Template.Spec.Containers[0].Args).To(Equal(expectedArgs), "Incorrect arguments for the SolrPrometheusExporter container")
+
 				g.Expect(found.Spec.Template.Spec.Containers[0].Command).To(Equal([]string{util.DefaultPrometheusExporterEntrypoint}), "Incorrect command for the SolrPrometheusExporter container")
 				g.Expect(found.Spec.Template.Spec.Containers[0].Image).To(Equal(solrv1beta1.DefaultSolrRepo+":should-be-the-same"), "Incorrect image, should be pulled from the SolrCloud")
 				g.Expect(found.Spec.Template.Spec.Containers[0].ImagePullPolicy).To(Equal(corev1.PullAlways), "Incorrect imagePullPolicy, should be pulled from the SolrCloud")
@@ -346,6 +370,24 @@
 				}
 				foundEnv := found.Spec.Template.Spec.Containers[0].Env
 				f := false
+				exporterArgEnvVars := []corev1.EnvVar{
+					{
+						Name:  "PORT",
+						Value: strconv.Itoa(util.SolrMetricsPort),
+					},
+					{
+						Name:  "NUM_THREADS",
+						Value: strconv.Itoa(1),
+					},
+					{
+						Name:  "ZK_HOST",
+						Value: testZkCnxString + testZKChroot,
+					},
+					{
+						Name:  "CONFIG_FILE",
+						Value: "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml",
+					},
+				}
 				zkAclEnvVars := []corev1.EnvVar{
 					{
 						Name: "ZK_ALL_ACL_USERNAME",
@@ -399,8 +441,9 @@
 				for _, extraVar := range extraVars {
 					expectedEnvVars[extraVar.Name] = extraVar.Value
 				}
-				g.Expect(foundEnv[0:7]).To(Equal(addBuiltInEnvVars(zkAclEnvVars)), "ZK ACL Env Vars are not correct")
-				g.Expect(foundEnv[7:len(foundEnv)-1]).To(Equal(extraVars), "Extra Env Vars are not the same as the ones provided in podOptions")
+				for _, exporterArgEnvVar := range exporterArgEnvVars {
+					expectedEnvVars[exporterArgEnvVar.Name] = exporterArgEnvVar.Value
+				}
 				testPodEnvVariablesWithGomega(g, expectedEnvVars, foundEnv)
 			})
 			By("Changing the ZKConnection String of the SolrCloud")
@@ -415,13 +458,13 @@
 
 			By("making sure the PrometheusExporter Deployment updates to use the new ZK Connection String")
 			expectDeploymentWithChecks(ctx, solrPrometheusExporter, solrPrometheusExporter.MetricsDeploymentName(), func(g Gomega, found *appsv1.Deployment) {
-				expectedArgs := []string{
-					"-p", strconv.Itoa(util.SolrMetricsPort),
-					"-n", strconv.Itoa(1),
-					"-z", newZkCnxString + testZKChroot,
-					"-f", "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml",
+				expectedEnvVars := map[string]string{
+					"PORT":        strconv.Itoa(util.SolrMetricsPort),
+					"NUM_THREADS": strconv.Itoa(1),
+					"ZK_HOST":     newZkCnxString + testZKChroot,
+					"CONFIG_FILE": "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml",
 				}
-				g.Expect(found.Spec.Template.Spec.Containers[0].Args).To(Equal(expectedArgs), "Incorrect arguments for the SolrPrometheusExporter container, Zookeeper info not updated after SolrCloud changed")
+				testPodEnvVariablesWithGomega(g, expectedEnvVars, found.Spec.Template.Spec.Containers[0].Env)
 			})
 		})
 	})
diff --git a/controllers/util/prometheus_exporter_util.go b/controllers/util/prometheus_exporter_util.go
index 81599b6..00a8233 100644
--- a/controllers/util/prometheus_exporter_util.go
+++ b/controllers/util/prometheus_exporter_util.go
@@ -97,23 +97,27 @@
 				},
 			},
 		},
+		{
+			Name:  "PORT",
+			Value: strconv.Itoa(SolrMetricsPort),
+		},
+		{
+			Name:  "NUM_THREADS",
+			Value: strconv.Itoa(int(solrPrometheusExporter.Spec.NumThreads)),
+		},
 	}
 	var allJavaOpts []string
 
 	var solrVolumes []corev1.Volume
 	var volumeMounts []corev1.VolumeMount
-	exporterArgs := []string{
-		"-p", strconv.Itoa(SolrMetricsPort),
-		"-n", strconv.Itoa(int(solrPrometheusExporter.Spec.NumThreads)),
-	}
 
 	if solrPrometheusExporter.Spec.ScrapeInterval > 0 {
-		exporterArgs = append(exporterArgs, "-s", strconv.Itoa(int(solrPrometheusExporter.Spec.ScrapeInterval)))
+		envVars = append(envVars, corev1.EnvVar{Name: "SCRAPE_INTERVAL", Value: strconv.Itoa(int(solrPrometheusExporter.Spec.ScrapeInterval))})
 	}
 
 	// Setup the solrConnectionInfo
 	if solrConnectionInfo.CloudZkConnnectionInfo != nil {
-		exporterArgs = append(exporterArgs, "-z", solrConnectionInfo.CloudZkConnnectionInfo.ZkConnectionString())
+		envVars = append(envVars, corev1.EnvVar{Name: "ZK_HOST", Value: solrConnectionInfo.CloudZkConnnectionInfo.ZkConnectionString()})
 
 		// Add ACL information, if given, through Env Vars
 		if hasACLs, aclEnvs := AddACLsToEnv(solrConnectionInfo.CloudZkConnnectionInfo.AllACL, solrConnectionInfo.CloudZkConnnectionInfo.ReadOnlyACL); hasACLs {
@@ -123,7 +127,7 @@
 			allJavaOpts = append(allJavaOpts, "$(SOLR_ZK_CREDS_AND_ACLS)")
 		}
 	} else if solrConnectionInfo.StandaloneAddress != "" {
-		exporterArgs = append(exporterArgs, "-b", solrConnectionInfo.StandaloneAddress)
+		envVars = append(envVars, corev1.EnvVar{Name: "SOLR_URL", Value: solrConnectionInfo.StandaloneAddress})
 	}
 
 	// Only add the config if it is passed in from the user. Otherwise, use the default.
@@ -152,9 +156,9 @@
 
 		volumeMounts = []corev1.VolumeMount{{Name: "solr-prometheus-exporter-xml", MountPath: "/opt/solr-exporter", ReadOnly: true}}
 
-		exporterArgs = append(exporterArgs, "-f", "/opt/solr-exporter/"+PrometheusExporterConfigMapKey)
+		envVars = append(envVars, corev1.EnvVar{Name: "CONFIG_FILE", Value: "/opt/solr-exporter/" + PrometheusExporterConfigMapKey})
 	} else {
-		exporterArgs = append(exporterArgs, "-f", "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml")
+		envVars = append(envVars, corev1.EnvVar{Name: "CONFIG_FILE", Value: "/opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml"})
 	}
 
 	entrypoint := DefaultPrometheusExporterEntrypoint
@@ -216,7 +220,6 @@
 			Ports:           []corev1.ContainerPort{{ContainerPort: SolrMetricsPort, Name: SolrMetricsPortName, Protocol: corev1.ProtocolTCP}},
 			VolumeMounts:    volumeMounts,
 			Command:         []string{entrypoint},
-			Args:            exporterArgs,
 			Env:             envVars,
 
 			StartupProbe: &corev1.Probe{
diff --git a/docs/solr-prometheus-exporter/README.md b/docs/solr-prometheus-exporter/README.md
index f223904..0f033e1 100644
--- a/docs/solr-prometheus-exporter/README.md
+++ b/docs/solr-prometheus-exporter/README.md
@@ -26,9 +26,6 @@
 You can also provide a custom Prometheus Exporter config, Solr version, and exporter options as described in the
 [Solr ref-guide](https://solr.apache.org/guide/monitoring-solr-with-prometheus-and-grafana.html#command-line-parameters).
 
-Note that a few of the official Solr docker images do not enable the Prometheus Exporter.
-Versions `6.6` - `7.x` and `8.2` - `master` should have the exporter available. 
-
 ## Finding the Solr Cluster to monitor
 
 The Prometheus Exporter supports metrics for both standalone solr as well as Solr Cloud.
@@ -316,5 +313,3 @@
 Once logged into Grafana, import the Solr dashboard JSON corresponding to the version of Solr you're running.
 
 Solr does not export any useful metrics until you have at least one collection defined.
-
-_Note: Solr 8.8.0 and newer versions include an updated dashboard that provides better metrics for monitoring query performance._