Add ephemeral option for zk storage. (#284)

Adds an option for the storage type of the provided ZK cluster. Ephemeral or Persistent.

If the user does not provide either option, then the Solr Operator will use whatever type is used by the Solr pods. (which defaults to ephemeral if none is provided).
diff --git a/Makefile b/Makefile
index d306a8b..debdf03 100644
--- a/Makefile
+++ b/Makefile
@@ -102,6 +102,7 @@
 
 # Generate manifests e.g. CRD, RBAC etc.
 manifests:
+	rm -rf generated-check/api
 	controller-gen $(CRD_OPTIONS) rbac:roleName=solr-operator-role webhook paths="./..." output:rbac:artifacts:config=$(or $(TMP_CONFIG_OUTPUT_DIRECTORY),config)/rbac output:crd:artifacts:config=$(or $(TMP_CONFIG_OUTPUT_DIRECTORY),config)/crd/bases
 	CONFIG_DIRECTORY=$(or $(TMP_CONFIG_OUTPUT_DIRECTORY),config) HELM_DIRECTORY=$(or $(TMP_HELM_OUTPUT_DIRECTORY),helm) ./hack/config/copy_crds_roles_helm.sh
 	CONFIG_DIRECTORY=$(or $(TMP_CONFIG_OUTPUT_DIRECTORY),config) ./hack/config/add_crds_roles_headers.sh
diff --git a/api/v1beta1/solrcloud_types.go b/api/v1beta1/solrcloud_types.go
index 471fb32..f08639e 100644
--- a/api/v1beta1/solrcloud_types.go
+++ b/api/v1beta1/solrcloud_types.go
@@ -570,7 +570,7 @@
 		changed = ref.ConnectionInfo.withDefaults() || changed
 	}
 	if ref.ProvidedZookeeper != nil {
-		changed = ref.ProvidedZookeeper.withDefaults() || changed
+		changed = ref.ProvidedZookeeper.WithDefaults() || changed
 	}
 	return changed
 }
@@ -600,9 +600,15 @@
 
 	// Persistence is the configuration for zookeeper persistent layer.
 	// PersistentVolumeClaimSpec and VolumeReclaimPolicy can be specified in here.
+	// At anypoint only one of Persistence or Ephemeral should be present in the manifest
 	// +optional
 	Persistence *zk.Persistence `json:"persistence,omitempty"`
 
+	// Ephemeral is the configuration which helps create ephemeral storage
+	// At anypoint only one of Persistence or Ephemeral should be present in the manifest
+	// +optional
+	Ephemeral *zk.Ephemeral `json:"ephemeral,omitempty"`
+
 	// Pod resources for zookeeper pod
 	// +optional
 	ZookeeperPod ZookeeperPodPolicy `json:"zookeeperPodPolicy,omitempty"`
@@ -622,7 +628,7 @@
 	ReadOnlyACL *ZookeeperACL `json:"readOnlyAcl,omitempty"`
 }
 
-func (z *ZookeeperSpec) withDefaults() (changed bool) {
+func (z *ZookeeperSpec) WithDefaults() (changed bool) {
 	if z.Replicas == nil {
 		changed = true
 		r := DefaultZkReplicas
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
index b7e44f4..f693e7d 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -1352,6 +1352,11 @@
 		*out = new(zookeeperv1beta1.Persistence)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.Ephemeral != nil {
+		in, out := &in.Ephemeral, &out.Ephemeral
+		*out = new(zookeeperv1beta1.Ephemeral)
+		(*in).DeepCopyInto(*out)
+	}
 	in.ZookeeperPod.DeepCopyInto(&out.ZookeeperPod)
 	if in.AllACL != nil {
 		in, out := &in.AllACL, &out.AllACL
diff --git a/config/crd/bases/solr.apache.org_solrclouds.yaml b/config/crd/bases/solr.apache.org_solrclouds.yaml
index 61420ac..e52277c 100644
--- a/config/crd/bases/solr.apache.org_solrclouds.yaml
+++ b/config/crd/bases/solr.apache.org_solrclouds.yaml
@@ -4748,6 +4748,24 @@
                       chroot:
                         description: The ChRoot to connect solr at
                         type: string
+                      ephemeral:
+                        description: Ephemeral is the configuration which helps create ephemeral storage At anypoint only one of Persistence or Ephemeral should be present in the manifest
+                        properties:
+                          emptydirvolumesource:
+                            description: EmptyDirVolumeSource is optional and this will create the emptydir volume It has two parameters Medium and SizeLimit which are optional as well Medium specifies What type of storage medium should back this directory. SizeLimit specifies Total amount of local storage required for this EmptyDir volume.
+                            properties:
+                              medium:
+                                description: 'What type of storage medium should back this directory. The default is "" which means to use the node''s default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+                                type: string
+                              sizeLimit:
+                                anyOf:
+                                - type: integer
+                                - type: string
+                                description: 'Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+                                pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                                x-kubernetes-int-or-string: true
+                            type: object
+                        type: object
                       image:
                         description: Image of Zookeeper to run
                         properties:
@@ -4762,7 +4780,7 @@
                             type: string
                         type: object
                       persistence:
-                        description: Persistence is the configuration for zookeeper persistent layer. PersistentVolumeClaimSpec and VolumeReclaimPolicy can be specified in here.
+                        description: Persistence is the configuration for zookeeper persistent layer. PersistentVolumeClaimSpec and VolumeReclaimPolicy can be specified in here. At anypoint only one of Persistence or Ephemeral should be present in the manifest
                         properties:
                           reclaimPolicy:
                             description: VolumeReclaimPolicy is a zookeeper operator configuration. If it's set to Delete, the corresponding PVCs will be deleted by the operator when zookeeper cluster is deleted. The default value is Retain.
diff --git a/controllers/controller_utils_test.go b/controllers/controller_utils_test.go
index 103bf01..ba48ec2 100644
--- a/controllers/controller_utils_test.go
+++ b/controllers/controller_utils_test.go
@@ -21,6 +21,7 @@
 	b64 "encoding/base64"
 	"fmt"
 	"github.com/apache/solr-operator/controllers/util"
+	zkv1beta1 "github.com/pravega/zookeeper-operator/pkg/apis/zookeeper/v1beta1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"reflect"
 	"strings"
@@ -488,6 +489,9 @@
 		// Solr Operator CRDs, modify this list whenever CRDs are added/deleted
 		&solr.SolrCloud{}, &solr.SolrBackup{}, &solr.SolrPrometheusExporter{},
 
+		// Dependency CRDs
+		&zkv1beta1.ZookeeperCluster{},
+
 		// All dependent Kubernetes types, in order of dependence (deployment then replicaSet then pod)
 		&corev1.ConfigMap{}, &batchv1.Job{}, &extv1.Ingress{},
 		&corev1.PersistentVolumeClaim{}, &corev1.PersistentVolume{},
@@ -677,6 +681,8 @@
 	}
 	one                = int64(1)
 	two                = int64(2)
+	four               = int32(4)
+	five               = int32(5)
 	podSecurityContext = corev1.PodSecurityContext{
 		RunAsUser:  &one,
 		RunAsGroup: &two,
diff --git a/controllers/solrcloud_controller_test.go b/controllers/solrcloud_controller_test.go
index 45b06a9..1e9a3e6 100644
--- a/controllers/solrcloud_controller_test.go
+++ b/controllers/solrcloud_controller_test.go
@@ -49,6 +49,7 @@
 	cloudHsKey           = types.NamespacedName{Name: "foo-clo-solrcloud-headless", Namespace: "default"}
 	cloudIKey            = types.NamespacedName{Name: "foo-clo-solrcloud-common", Namespace: "default"}
 	cloudCMKey           = types.NamespacedName{Name: "foo-clo-solrcloud-configmap", Namespace: "default"}
+	cloudZkKey           = types.NamespacedName{Name: "foo-clo-solrcloud-zookeeper", Namespace: "default"}
 )
 
 func TestCloudReconcile(t *testing.T) {
@@ -319,90 +320,6 @@
 	testMapsEqual(t, "common service annotations", testHeadlessServiceAnnotations, headlessService.Annotations)
 }
 
-func TestCloudWithProvidedZookeeperReconcile(t *testing.T) {
-	UseZkCRD(true)
-	g := gomega.NewGomegaWithT(t)
-	instance := &solr.SolrCloud{
-		ObjectMeta: metav1.ObjectMeta{Name: expectedCloudRequest.Name, Namespace: expectedCloudRequest.Namespace},
-		Spec: solr.SolrCloudSpec{
-			ZookeeperRef: &solr.ZookeeperRef{
-				ProvidedZookeeper: &solr.ZookeeperSpec{
-					ChRoot: "a-ch/root",
-				},
-			},
-			UpdateStrategy: solr.SolrUpdateStrategy{
-				Method: solr.ManualUpdate,
-			},
-		},
-	}
-
-	// Setup the Manager and Controller.  Wrap the Controller Reconcile function so it writes each request to a
-	// channel when it is finished.
-	mgr, err := manager.New(testCfg, manager.Options{})
-	g.Expect(err).NotTo(gomega.HaveOccurred())
-	testClient = mgr.GetClient()
-
-	// Blocked until https://github.com/pravega/zookeeper-operator/pull/99 is merged
-	//g.Expect(zookeepercluster.AddZookeeperReconciler(mgr)).NotTo(gomega.HaveOccurred())
-
-	solrCloudReconciler := &SolrCloudReconciler{
-		Client: testClient,
-		Log:    ctrl.Log.WithName("controllers").WithName("SolrCloud"),
-	}
-	newRec, requests := SetupTestReconcile(solrCloudReconciler)
-	g.Expect(solrCloudReconciler.SetupWithManagerAndReconciler(mgr, newRec)).NotTo(gomega.HaveOccurred())
-
-	stopMgr, mgrStopped := StartTestManager(mgr, g)
-
-	defer func() {
-		close(stopMgr)
-		mgrStopped.Wait()
-	}()
-
-	cleanupTest(g, instance.Namespace)
-
-	// Create the SolrCloud object and expect the Reconcile and StatefulSet to be created
-	err = testClient.Create(context.TODO(), instance)
-	g.Expect(err).NotTo(gomega.HaveOccurred())
-	defer testClient.Delete(context.TODO(), instance)
-	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
-	// Add an additional check for reconcile, so that the zkCluster will have been created
-	// Otherwise the reconciler will have 'blockReconciliationOfStatefulSet' set to true, and the stateful set will not be created
-	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
-	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
-
-	g.Eventually(func() error { return testClient.Get(context.TODO(), expectedCloudRequest.NamespacedName, instance) }, timeout).Should(gomega.Succeed())
-
-	// Check that the ZkConnectionInformation is correct
-	expectedZkConnStr := "foo-clo-solrcloud-zookeeper-0.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-1.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-2.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181"
-	assert.Equal(t, expectedZkConnStr, instance.Status.ZookeeperConnectionInfo.InternalConnectionString, "Wrong zkConnectionString in status")
-	assert.Equal(t, "/a-ch/root", instance.Status.ZookeeperConnectionInfo.ChRoot, "Wrong zk chRoot in status")
-	assert.Nil(t, instance.Status.ZookeeperConnectionInfo.ExternalConnectionString, "Since a provided zk is used, the externalConnectionString in the status should be Nil")
-
-	// Check that the statefulSet has been created, using the given chRoot
-	statefulSet := expectStatefulSet(t, g, requests, expectedCloudRequest, cloudSsKey)
-
-	assert.Equal(t, 1, len(statefulSet.Spec.Template.Spec.Containers), "Solr StatefulSet requires a container.")
-	expectedZKHost := expectedZkConnStr + "/a-ch/root"
-	expectedEnvVars := map[string]string{
-		"ZK_HOST":   expectedZKHost,
-		"SOLR_HOST": "$(POD_HOSTNAME)." + cloudHsKey.Name + "." + cloudHsKey.Namespace,
-		"ZK_SERVER": expectedZkConnStr,
-		"ZK_CHROOT": "/a-ch/root",
-		"SOLR_PORT": "8983",
-		"GC_TUNE":   "",
-	}
-	expectedStatefulSetAnnotations := map[string]string{util.SolrZKConnectionStringAnnotation: expectedZKHost}
-	testPodEnvVariables(t, expectedEnvVars, statefulSet.Spec.Template.Spec.Containers[0].Env)
-	testMapsEqual(t, "statefulSet annotations", expectedStatefulSetAnnotations, statefulSet.Annotations)
-	assert.EqualValues(t, []string{"sh", "-c", "solr zk ls ${ZK_CHROOT} -z ${ZK_SERVER} || solr zk mkroot ${ZK_CHROOT} -z ${ZK_SERVER}"}, statefulSet.Spec.Template.Spec.Containers[0].Lifecycle.PostStart.Exec.Command, "Incorrect post-start command")
-	assert.Empty(t, statefulSet.Spec.Template.Spec.ServiceAccountName, "No custom serviceAccountName specified, so the field should be empty.")
-
-	// Check the update strategy
-	assert.EqualValues(t, appsv1.OnDeleteStatefulSetStrategyType, statefulSet.Spec.UpdateStrategy.Type, "Incorrect statefulset update strategy")
-	assert.EqualValues(t, appsv1.ParallelPodManagement, statefulSet.Spec.PodManagementPolicy, "Incorrect statefulset pod management policy")
-}
-
 func TestCloudWithExternalZookeeperChroot(t *testing.T) {
 	UseZkCRD(true)
 	g := gomega.NewGomegaWithT(t)
@@ -476,6 +393,7 @@
 	testPodEnvVariables(t, expectedEnvVars, statefulSet.Spec.Template.Spec.Containers[0].Env)
 	testMapsEqual(t, "statefulSet annotations", expectedStatefulSetAnnotations, statefulSet.Annotations)
 	assert.EqualValues(t, []string{"sh", "-c", "solr zk ls ${ZK_CHROOT} -z ${ZK_SERVER} || solr zk mkroot ${ZK_CHROOT} -z ${ZK_SERVER}"}, statefulSet.Spec.Template.Spec.Containers[0].Lifecycle.PostStart.Exec.Command, "Incorrect post-start command")
+	assert.Empty(t, statefulSet.Spec.Template.Spec.ServiceAccountName, "No custom serviceAccountName specified, so the field should be empty.")
 }
 
 func TestDefaults(t *testing.T) {
diff --git a/controllers/solrcloud_controller_zk_test.go b/controllers/solrcloud_controller_zk_test.go
index 36699fc..bb2b249 100644
--- a/controllers/solrcloud_controller_zk_test.go
+++ b/controllers/solrcloud_controller_zk_test.go
@@ -19,6 +19,10 @@
 
 import (
 	"fmt"
+	"github.com/apache/solr-operator/controllers/util"
+	zkv1beta1 "github.com/pravega/zookeeper-operator/pkg/apis/zookeeper/v1beta1"
+	"github.com/pravega/zookeeper-operator/pkg/controller/zookeepercluster"
+	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"testing"
@@ -36,6 +40,246 @@
 
 var _ reconcile.Reconciler = &SolrCloudReconciler{}
 
+func expectZookeeperCluster(g *gomega.GomegaWithT, requests chan reconcile.Request, expectedRequest reconcile.Request, zookeeperClusterKey types.NamespacedName) *zkv1beta1.ZookeeperCluster {
+	zk := &zkv1beta1.ZookeeperCluster{}
+	g.Eventually(func() error { return testClient.Get(context.TODO(), zookeeperClusterKey, zk) }, timeout).
+		Should(gomega.Succeed())
+
+	// Delete the ZK and expect Reconcile to be called for ZK deletion
+	g.Expect(testClient.Delete(context.TODO(), zk)).NotTo(gomega.HaveOccurred())
+	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
+	g.Eventually(func() error { return testClient.Get(context.TODO(), zookeeperClusterKey, zk) }, timeout).
+		Should(gomega.Succeed())
+
+	// Manually delete ZK since GC isn't enabled in the test control plane
+	g.Eventually(func() error { return testClient.Delete(context.TODO(), zk) }, timeout).
+		Should(gomega.MatchError("zookeeperclusters.zookeeper.pravega.io \"" + zookeeperClusterKey.Name + "\" not found"))
+
+	return zk
+}
+
+func TestCloudWithProvidedEphemeralZookeeperReconcile(t *testing.T) {
+	UseZkCRD(true)
+	g := gomega.NewGomegaWithT(t)
+	instance := &solr.SolrCloud{
+		ObjectMeta: metav1.ObjectMeta{Name: expectedCloudRequest.Name, Namespace: expectedCloudRequest.Namespace},
+		Spec: solr.SolrCloudSpec{
+			ZookeeperRef: &solr.ZookeeperRef{
+				ProvidedZookeeper: &solr.ZookeeperSpec{
+					Replicas: &four,
+					Ephemeral: &zkv1beta1.Ephemeral{
+						EmptyDirVolumeSource: corev1.EmptyDirVolumeSource{
+							Medium: "Memory",
+						},
+					},
+					ZookeeperPod: solr.ZookeeperPodPolicy{
+						Affinity:           affinity,
+						NodeSelector:       testNodeSelectors,
+						Tolerations:        testTolerations,
+						Env:                extraVars,
+						Resources:          resources,
+						ServiceAccountName: testServiceAccountName,
+					},
+					ChRoot: "a-ch/root",
+				},
+			},
+			UpdateStrategy: solr.SolrUpdateStrategy{
+				Method: solr.ManualUpdate,
+			},
+		},
+	}
+
+	// Setup the Manager and Controller.  Wrap the Controller Reconcile function so it writes each request to a
+	// channel when it is finished.
+	mgr, err := manager.New(testCfg, manager.Options{})
+	g.Expect(err).NotTo(gomega.HaveOccurred())
+	testClient = mgr.GetClient()
+
+	// Include ZK Operator since we are creating a ZK Cluster
+	g.Expect(zookeepercluster.AddZookeeperReconciler(mgr)).NotTo(gomega.HaveOccurred())
+
+	solrCloudReconciler := &SolrCloudReconciler{
+		Client: testClient,
+		Log:    ctrl.Log.WithName("controllers").WithName("SolrCloud"),
+	}
+	newRec, requests := SetupTestReconcile(solrCloudReconciler)
+	g.Expect(solrCloudReconciler.SetupWithManagerAndReconciler(mgr, newRec)).NotTo(gomega.HaveOccurred())
+
+	stopMgr, mgrStopped := StartTestManager(mgr, g)
+
+	defer func() {
+		close(stopMgr)
+		mgrStopped.Wait()
+	}()
+
+	cleanupTest(g, instance.Namespace)
+
+	// Create the SolrCloud object and expect the Reconcile and StatefulSet to be created
+	err = testClient.Create(context.TODO(), instance)
+	g.Expect(err).NotTo(gomega.HaveOccurred())
+	defer testClient.Delete(context.TODO(), instance)
+	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
+	// Add an additional check for reconcile, so that the zkCluster will have been created
+	// Otherwise the reconciler will have 'blockReconciliationOfStatefulSet' set to true, and the stateful set will not be created
+	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
+	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
+
+	g.Eventually(func() error { return testClient.Get(context.TODO(), expectedCloudRequest.NamespacedName, instance) }, timeout).Should(gomega.Succeed())
+
+	// Check that the ZkConnectionInformation is correct
+	expectedZkConnStr := "foo-clo-solrcloud-zookeeper-0.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-1.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-2.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-3.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181"
+	assert.Equal(t, expectedZkConnStr, instance.Status.ZookeeperConnectionInfo.InternalConnectionString, "Wrong zkConnectionString in status")
+	assert.Equal(t, "/a-ch/root", instance.Status.ZookeeperConnectionInfo.ChRoot, "Wrong zk chRoot in status")
+	assert.Nil(t, instance.Status.ZookeeperConnectionInfo.ExternalConnectionString, "Since a provided zk is used, the externalConnectionString in the status should be Nil")
+
+	// Check that the statefulSet has been created, using the given chRoot
+	statefulSet := expectStatefulSet(t, g, requests, expectedCloudRequest, cloudSsKey)
+
+	assert.Equal(t, 1, len(statefulSet.Spec.Template.Spec.Containers), "Solr StatefulSet requires a container.")
+	expectedZKHost := expectedZkConnStr + "/a-ch/root"
+	expectedEnvVars := map[string]string{
+		"ZK_HOST":   expectedZKHost,
+		"SOLR_HOST": "$(POD_HOSTNAME)." + cloudHsKey.Name + "." + cloudHsKey.Namespace,
+		"ZK_SERVER": expectedZkConnStr,
+		"ZK_CHROOT": "/a-ch/root",
+		"SOLR_PORT": "8983",
+		"GC_TUNE":   "",
+	}
+	expectedStatefulSetAnnotations := map[string]string{util.SolrZKConnectionStringAnnotation: expectedZKHost}
+	testPodEnvVariables(t, expectedEnvVars, statefulSet.Spec.Template.Spec.Containers[0].Env)
+	testMapsEqual(t, "statefulSet annotations", expectedStatefulSetAnnotations, statefulSet.Annotations)
+	assert.EqualValues(t, []string{"sh", "-c", "solr zk ls ${ZK_CHROOT} -z ${ZK_SERVER} || solr zk mkroot ${ZK_CHROOT} -z ${ZK_SERVER}"}, statefulSet.Spec.Template.Spec.Containers[0].Lifecycle.PostStart.Exec.Command, "Incorrect post-start command")
+	assert.Empty(t, statefulSet.Spec.Template.Spec.ServiceAccountName, "No custom serviceAccountName specified, so the field should be empty.")
+
+	// Check the update strategy
+	assert.EqualValues(t, appsv1.OnDeleteStatefulSetStrategyType, statefulSet.Spec.UpdateStrategy.Type, "Incorrect statefulset update strategy")
+	assert.EqualValues(t, appsv1.ParallelPodManagement, statefulSet.Spec.PodManagementPolicy, "Incorrect statefulset pod management policy")
+
+	// Check that the Zookeeper Cluster has been created
+	zkCluster := expectZookeeperCluster(g, requests, expectedCloudRequest, cloudZkKey)
+
+	// Check the settings of the Zookeeper Cluster
+	assert.EqualValues(t, four, zkCluster.Spec.Replicas, "Incorrect zkCluster replicas")
+	assert.EqualValues(t, "ephemeral", zkCluster.Spec.StorageType, "Incorrect zkCluster storage type")
+	assert.NotNil(t, zkCluster.Spec.Ephemeral, "ZkCluster.spec.ephemeral should not be nil")
+	assert.EqualValues(t, "Memory", zkCluster.Spec.Ephemeral.EmptyDirVolumeSource.Medium, "Incorrect EmptyDir medium for ZK Cluster ephemeral storage")
+
+	// Check ZK Pod Options
+	assert.EqualValues(t, affinity, zkCluster.Spec.Pod.Affinity, "Incorrect zkCluster affinity")
+	assert.EqualValues(t, testTolerations, zkCluster.Spec.Pod.Tolerations, "Incorrect zkCluster tolerations")
+	assert.EqualValues(t, testNodeSelectors, zkCluster.Spec.Pod.NodeSelector, "Incorrect zkCluster nodeSelectors")
+	assert.EqualValues(t, resources, zkCluster.Spec.Pod.Resources, "Incorrect zkCluster resources")
+	assert.EqualValues(t, extraVars, zkCluster.Spec.Pod.Env, "Incorrect zkCluster env vars")
+	assert.EqualValues(t, testServiceAccountName, zkCluster.Spec.Pod.ServiceAccountName, "Incorrect zkCluster serviceAccountName")
+}
+
+func TestCloudWithProvidedPersistentZookeeperReconcile(t *testing.T) {
+	UseZkCRD(true)
+	g := gomega.NewGomegaWithT(t)
+	instance := &solr.SolrCloud{
+		ObjectMeta: metav1.ObjectMeta{Name: expectedCloudRequest.Name, Namespace: expectedCloudRequest.Namespace},
+		Spec: solr.SolrCloudSpec{
+			ZookeeperRef: &solr.ZookeeperRef{
+				ProvidedZookeeper: &solr.ZookeeperSpec{
+					Replicas: &four,
+					Image: &solr.ContainerImage{
+						Repository: "test-repo",
+						Tag:        "test-tag",
+						PullPolicy: corev1.PullNever,
+						// TODO: Test when ZK operator v0.2.10 is supported
+						ImagePullSecret: testImagePullSecretName,
+					},
+					Persistence: &zkv1beta1.Persistence{
+						VolumeReclaimPolicy: zkv1beta1.VolumeReclaimPolicyRetain,
+					},
+				},
+			},
+			UpdateStrategy: solr.SolrUpdateStrategy{
+				Method: solr.ManualUpdate,
+			},
+		},
+	}
+
+	// Setup the Manager and Controller.  Wrap the Controller Reconcile function so it writes each request to a
+	// channel when it is finished.
+	mgr, err := manager.New(testCfg, manager.Options{})
+	g.Expect(err).NotTo(gomega.HaveOccurred())
+	testClient = mgr.GetClient()
+
+	// Include ZK Operator since we are creating a ZK Cluster
+	g.Expect(zookeepercluster.AddZookeeperReconciler(mgr)).NotTo(gomega.HaveOccurred())
+
+	solrCloudReconciler := &SolrCloudReconciler{
+		Client: testClient,
+		Log:    ctrl.Log.WithName("controllers").WithName("SolrCloud"),
+	}
+	newRec, requests := SetupTestReconcile(solrCloudReconciler)
+	g.Expect(solrCloudReconciler.SetupWithManagerAndReconciler(mgr, newRec)).NotTo(gomega.HaveOccurred())
+
+	stopMgr, mgrStopped := StartTestManager(mgr, g)
+
+	defer func() {
+		close(stopMgr)
+		mgrStopped.Wait()
+	}()
+
+	cleanupTest(g, instance.Namespace)
+
+	// Create the SolrCloud object and expect the Reconcile and StatefulSet to be created
+	err = testClient.Create(context.TODO(), instance)
+	g.Expect(err).NotTo(gomega.HaveOccurred())
+	defer testClient.Delete(context.TODO(), instance)
+	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
+	// Add an additional check for reconcile, so that the zkCluster will have been created
+	// Otherwise the reconciler will have 'blockReconciliationOfStatefulSet' set to true, and the stateful set will not be created
+	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
+	g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCloudRequest)))
+
+	g.Eventually(func() error { return testClient.Get(context.TODO(), expectedCloudRequest.NamespacedName, instance) }, timeout).Should(gomega.Succeed())
+
+	// Check that the ZkConnectionInformation is correct
+	expectedZkConnStr := "foo-clo-solrcloud-zookeeper-0.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-1.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-2.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181,foo-clo-solrcloud-zookeeper-3.foo-clo-solrcloud-zookeeper-headless.default.svc.cluster.local:2181"
+	assert.Equal(t, expectedZkConnStr, instance.Status.ZookeeperConnectionInfo.InternalConnectionString, "Wrong zkConnectionString in status")
+	assert.Equal(t, "/", instance.Status.ZookeeperConnectionInfo.ChRoot, "Wrong zk chRoot in status")
+	assert.Nil(t, instance.Status.ZookeeperConnectionInfo.ExternalConnectionString, "Since a provided zk is used, the externalConnectionString in the status should be Nil")
+
+	// Check that the statefulSet has been created, using the given chRoot
+	statefulSet := expectStatefulSet(t, g, requests, expectedCloudRequest, cloudSsKey)
+
+	assert.Equal(t, 1, len(statefulSet.Spec.Template.Spec.Containers), "Solr StatefulSet requires a container.")
+	expectedZKHost := expectedZkConnStr + "/"
+	expectedEnvVars := map[string]string{
+		"ZK_HOST":   expectedZKHost,
+		"SOLR_HOST": "$(POD_HOSTNAME)." + cloudHsKey.Name + "." + cloudHsKey.Namespace,
+		"ZK_SERVER": expectedZkConnStr,
+		"ZK_CHROOT": "/",
+		"SOLR_PORT": "8983",
+		"GC_TUNE":   "",
+	}
+	expectedStatefulSetAnnotations := map[string]string{util.SolrZKConnectionStringAnnotation: expectedZKHost}
+	testPodEnvVariables(t, expectedEnvVars, statefulSet.Spec.Template.Spec.Containers[0].Env)
+	testMapsEqual(t, "statefulSet annotations", expectedStatefulSetAnnotations, statefulSet.Annotations)
+	assert.Nil(t, statefulSet.Spec.Template.Spec.Containers[0].Lifecycle.PostStart, "chroot is empty, so there should be no postStart command")
+
+	// Check the update strategy
+	assert.EqualValues(t, appsv1.OnDeleteStatefulSetStrategyType, statefulSet.Spec.UpdateStrategy.Type, "Incorrect statefulset update strategy")
+	assert.EqualValues(t, appsv1.ParallelPodManagement, statefulSet.Spec.PodManagementPolicy, "Incorrect statefulset pod management policy")
+
+	// Check that the Zookeeper Cluster has been created
+	zkCluster := expectZookeeperCluster(g, requests, expectedCloudRequest, cloudZkKey)
+
+	// Check the settings of the Zookeeper Cluster
+	assert.EqualValues(t, four, zkCluster.Spec.Replicas, "Incorrect zkCluster replicas")
+	assert.EqualValues(t, "persistence", zkCluster.Spec.StorageType, "Incorrect zkCluster storage type")
+	assert.NotNil(t, zkCluster.Spec.Persistence, "ZkCluster.spec.persistence should not be nil")
+	assert.EqualValues(t, zkv1beta1.VolumeReclaimPolicyRetain, zkCluster.Spec.Persistence.VolumeReclaimPolicy, "Incorrect VolumeReclaimPolicy for ZK Cluster persistent storage")
+
+	// Check ZK Pod Options
+	assert.EqualValues(t, "test-repo", zkCluster.Spec.Image.Repository, "Incorrect zkCluster image repo")
+	assert.EqualValues(t, "test-tag", zkCluster.Spec.Image.Tag, "Incorrect zkCluster image tag")
+	assert.EqualValues(t, corev1.PullNever, zkCluster.Spec.Image.PullPolicy, "Incorrect zkCluster image pull policy")
+}
+
 func TestZKACLsCloudReconcile(t *testing.T) {
 	UseZkCRD(false)
 	g := gomega.NewGomegaWithT(t)
diff --git a/controllers/util/zk_util.go b/controllers/util/zk_util.go
index 5612c6e..343c71e 100644
--- a/controllers/util/zk_util.go
+++ b/controllers/util/zk_util.go
@@ -48,9 +48,8 @@
 				Tag:        zkSpec.Image.Tag,
 				PullPolicy: zkSpec.Image.PullPolicy,
 			},
-			Labels:      labels,
-			Replicas:    *zkSpec.Replicas,
-			Persistence: zkSpec.Persistence,
+			Labels:   labels,
+			Replicas: *zkSpec.Replicas,
 			Ports: []corev1.ContainerPort{
 				{
 					Name:          "client",
@@ -68,6 +67,29 @@
 		},
 	}
 
+	// Add storage information for the ZK Cluster
+	if zkSpec.Persistence != nil {
+		// If persistence is provided, then chose it.
+		zkCluster.Spec.StorageType = "persistence"
+	} else if zkSpec.Ephemeral != nil {
+		// If ephemeral is provided, then chose it.
+		zkCluster.Spec.StorageType = "ephemeral"
+	} else {
+		// If neither option is provided, default to the option used for solr (which defaults to ephemeral)
+		if solrCloud.Spec.StorageOptions.PersistentStorage != nil {
+			zkCluster.Spec.StorageType = "persistence"
+		} else {
+			zkCluster.Spec.StorageType = "ephemeral"
+		}
+	}
+
+	// Set the persistence/ephemeral options if necessary
+	if zkSpec.Persistence != nil && zkCluster.Spec.StorageType == "persistence" {
+		zkCluster.Spec.Persistence = zkSpec.Persistence
+	} else if zkSpec.Ephemeral != nil && zkCluster.Spec.StorageType == "ephemeral" {
+		zkCluster.Spec.Ephemeral = zkSpec.Ephemeral
+	}
+
 	// Append Pod Policies if provided by user
 	if zkSpec.ZookeeperPod.Affinity != nil {
 		zkCluster.Spec.Pod.Affinity = zkSpec.ZookeeperPod.Affinity
diff --git a/controllers/util/zk_util_test.go b/controllers/util/zk_util_test.go
new file mode 100644
index 0000000..6f42373
--- /dev/null
+++ b/controllers/util/zk_util_test.go
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package util
+
+import (
+	solr "github.com/apache/solr-operator/api/v1beta1"
+	zkv1beta1 "github.com/pravega/zookeeper-operator/pkg/apis/zookeeper/v1beta1"
+	"github.com/stretchr/testify/assert"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"testing"
+)
+
+func TestDefaultStorageOptions(t *testing.T) {
+	solrCloud := &solr.SolrCloud{
+		ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
+		Spec:       solr.SolrCloudSpec{},
+	}
+	zkSpec := &solr.ZookeeperSpec{
+		Persistence: nil,
+		Ephemeral:   nil,
+	}
+	zkSpec.WithDefaults()
+
+	var zkCluster *zkv1beta1.ZookeeperCluster
+
+	// Solr uses nothing (defaults to ephemeral)
+	zkCluster = GenerateZookeeperCluster(solrCloud, zkSpec)
+	assert.Equal(t, "ephemeral", zkCluster.Spec.StorageType, "By default when no storage is specified for Solr or ZK, the storage should be ephemeral. Wrong storageType")
+	assert.Nil(t, zkCluster.Spec.Persistence, "By default when no storage is specified for Solr or ZK, the storage should be ephemeral. Therefore 'persistence' should be nil")
+
+	// Solr uses Persistent
+	solrCloud.Spec.StorageOptions.PersistentStorage = &solr.SolrPersistentDataStorageOptions{}
+	solrCloud.Spec.StorageOptions.EphemeralStorage = nil
+	zkCluster = GenerateZookeeperCluster(solrCloud, zkSpec)
+	assert.Equal(t, "persistence", zkCluster.Spec.StorageType, "By default when Solr is using persistent storage, zk should as well. Wrong storageType")
+	assert.Nil(t, zkCluster.Spec.Ephemeral, "By default when Solr is using persistent storage, zk should as well. Therefore 'ephemeral' should be nil")
+
+	// Solr uses Ephemeral
+	solrCloud.Spec.StorageOptions.PersistentStorage = nil
+	solrCloud.Spec.StorageOptions.EphemeralStorage = &solr.SolrEphemeralDataStorageOptions{}
+	zkCluster = GenerateZookeeperCluster(solrCloud, zkSpec)
+	assert.Equal(t, "ephemeral", zkCluster.Spec.StorageType, "By default when Solr is using ephemeral storage, zk should as well. Wrong storageType")
+	assert.Nil(t, zkCluster.Spec.Persistence, "By default when Solr is using ephemeral storage, zk should as well. Therefore 'persistence' should be nil")
+}
diff --git a/docs/solr-cloud/solr-cloud-crd.md b/docs/solr-cloud/solr-cloud-crd.md
index 06c6453..512b2ba 100644
--- a/docs/solr-cloud/solr-cloud-crd.md
+++ b/docs/solr-cloud/solr-cloud-crd.md
@@ -148,6 +148,27 @@
 
 The startup parameter `zookeeper-operator` must be provided on startup of the solr-operator for this parameter to be available.
 
+#### Zookeeper Storage Options
+_Since v0.4.0_
+
+The Zookeeper Operator allows for both ephemeral and persistent storage, and the Solr Operator supports both as of `v0.4.0`.
+
+```yaml
+spec:
+  zookeeperRef:
+    provided:
+      ephemeral:
+        emptydirvolumesource: {}
+      persistence:
+        reclaimPolicy: "Retain" # Either Retain or Delete
+        spec: {} # PVC Spec for the Zookeeper volumes
+```
+
+By default, if you do not provide either `ephemeral` or `persistence`, the Solr Operator will default to the type of storage you are using for your Solr pods.
+
+However, if you provide either object above, even if the object is empty, that storage type will be used for the created Zookeeper pods.
+If both `ephemeral` and `persistence` is provided, then `persistence` is preferred.
+
 #### ACLs for Provided Ensembles
 _Since v0.3.0_
 
diff --git a/docs/upgrade-notes.md b/docs/upgrade-notes.md
index 7211569..b744040 100644
--- a/docs/upgrade-notes.md
+++ b/docs/upgrade-notes.md
@@ -60,6 +60,13 @@
 - The default Solr version for `SolrCloud` and `SolrPrometheusExporter` resources has been upgraded from `7.7.0` to `8.9`.
   This will not effect any existing resources, as default versions are hard-written to the resources immediately.
   Only new resources created after the Solr Operator is upgraded to `v0.4.0` will be affected.
+  
+- In previous versions of the Solr Operator, the provided Zookeeper instances could only use Persistent Storage.
+  Now ephemeral storage is enabled, and used by default if Solr is using ephemeral storage.
+  The ZK storage type can be explicitly set via `Spec.zookeeperRef.provided.ephemeral` or `Spec.zookeeperRef.provided.persistence`,
+  however if neither is set, the Solr Operator will default to use the type of storage (persistent or ephemeral) that Solr is using.  
+  **This means that the default Zookeeper Storage type can change for users using ephemeral storage for Solr.
+  If you require ephemeral Solr storage and persistent Zookeeper Storage, be sure to explicitly set that starting in `v0.4.0`.**
 
 ### v0.3.0
 - All deprecated CRD fields and Solr Operator options from `v0.2.*` have been removed.
diff --git a/go.sum b/go.sum
index de0e5eb..3bf04cc 100644
--- a/go.sum
+++ b/go.sum
@@ -262,6 +262,7 @@
 github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
 github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -783,6 +784,7 @@
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da h1:p3Vo3i64TCLY7gIfzeQaUJ+kppEO5WQG3cL8iE8tGHU=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
 github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
 github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
diff --git a/helm/solr-operator/Chart.yaml b/helm/solr-operator/Chart.yaml
index 81529a3..2129523 100644
--- a/helm/solr-operator/Chart.yaml
+++ b/helm/solr-operator/Chart.yaml
@@ -84,6 +84,13 @@
           url: https://github.com/apache/solr-operator/issues/264
         - name: Github PR
           url: https://github.com/apache/solr-operator/pull/283
+    - kind: added
+      description: Introduced ephemeral option for Zookeeper storage
+      links:
+        - name: Github Issue
+          url: https://github.com/apache/solr-operator/issues/259
+        - name: Github PR
+          url: https://github.com/apache/solr-operator/pull/284
   artifacthub.io/images: |
     - name: solr-operator
       image: apache/solr-operator:v0.4.0-prerelease
diff --git a/helm/solr-operator/crds/crds.yaml b/helm/solr-operator/crds/crds.yaml
index 5656a1c..3e53943 100644
--- a/helm/solr-operator/crds/crds.yaml
+++ b/helm/solr-operator/crds/crds.yaml
@@ -5875,6 +5875,24 @@
                       chroot:
                         description: The ChRoot to connect solr at
                         type: string
+                      ephemeral:
+                        description: Ephemeral is the configuration which helps create ephemeral storage At anypoint only one of Persistence or Ephemeral should be present in the manifest
+                        properties:
+                          emptydirvolumesource:
+                            description: EmptyDirVolumeSource is optional and this will create the emptydir volume It has two parameters Medium and SizeLimit which are optional as well Medium specifies What type of storage medium should back this directory. SizeLimit specifies Total amount of local storage required for this EmptyDir volume.
+                            properties:
+                              medium:
+                                description: 'What type of storage medium should back this directory. The default is "" which means to use the node''s default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+                                type: string
+                              sizeLimit:
+                                anyOf:
+                                - type: integer
+                                - type: string
+                                description: 'Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+                                pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+                                x-kubernetes-int-or-string: true
+                            type: object
+                        type: object
                       image:
                         description: Image of Zookeeper to run
                         properties:
@@ -5889,7 +5907,7 @@
                             type: string
                         type: object
                       persistence:
-                        description: Persistence is the configuration for zookeeper persistent layer. PersistentVolumeClaimSpec and VolumeReclaimPolicy can be specified in here.
+                        description: Persistence is the configuration for zookeeper persistent layer. PersistentVolumeClaimSpec and VolumeReclaimPolicy can be specified in here. At anypoint only one of Persistence or Ephemeral should be present in the manifest
                         properties:
                           reclaimPolicy:
                             description: VolumeReclaimPolicy is a zookeeper operator configuration. If it's set to Delete, the corresponding PVCs will be deleted by the operator when zookeeper cluster is deleted. The default value is Retain.
diff --git a/helm/solr/README.md b/helm/solr/README.md
index bf205e0..e111984 100644
--- a/helm/solr/README.md
+++ b/helm/solr/README.md
@@ -157,8 +157,10 @@
 | zk.provided.image.tag | string | | The tag/version of Zookeeper to run. Generally leave this blank, so that the Zookeeper Operator can manage it. |
 | zk.provided.image.pullPolicy | string | `"IfNotPresent"` | PullPolicy for the ZooKeeper image |
 | zk.provided.image.imagePullSecret | string |  | PullSecret for the ZooKeeper image |
+| zk.provided.storageType | string |  | Explicitly set the Zookeeper storage type, not necessary if providing a "persistence" or "ephemeral" option below, or if you want to use same option that you use for Solr. |
 | zk.provided.persistence.reclaimPolicy | string | `"Retain"` | Determines whether to delete or keep the PVCs when ZooKeeper is deleted or scaled down. Either `Retain` or `Delete`. |
 | zk.provided.persistence.spec | object | | A PVC Spec for the ZooKeeper PVC(s) |
+| zk.provided.ephemeral.emptydirvolumesource | object | | An emptyDir volume source for the ZooKeeper Storage on each pod. |
 | zk.provided.zookeeperPodPolicy.serviceAccountName | string |  | Optional serviceAccount to run the ZK Pod under |
 | zk.provided.zookeeperPodPolicy.affinity | string |  | PullSecret for the ZooKeeper image |
 | zk.provided.zookeeperPodPolicy.resources.limits | map[string]string |  | Provide Resource limits for the ZooKeeper containers |
diff --git a/helm/solr/templates/solrcloud.yaml b/helm/solr/templates/solrcloud.yaml
index 8c2160e..83984a5 100644
--- a/helm/solr/templates/solrcloud.yaml
+++ b/helm/solr/templates/solrcloud.yaml
@@ -182,9 +182,12 @@
       image:
         {{- toYaml .Values.zk.provided.image | nindent 8 }}
       {{- end }}
-      {{- if .Values.zk.provided.persistence }}
+      {{- if (or .Values.zk.provided.persistence (lower .Values.zk.provided.storageType | hasPrefix "persist")) }}
       persistence:
         {{- toYaml .Values.zk.provided.persistence | nindent 8 }}
+      {{- else if (or .Values.zk.provided.ephemeral (lower .Values.zk.provided.storageType | eq "ephemeral")) }}
+      ephemeral:
+        {{- toYaml .Values.zk.provided.ephemeral | nindent 8 }}
       {{- end }}
       {{- if (include "solr.zk.zookeeperPodPolicy" .) }}
       zookeeperPodPolicy:
diff --git a/helm/solr/values.yaml b/helm/solr/values.yaml
index 582e18b..9a5f017 100644
--- a/helm/solr/values.yaml
+++ b/helm/solr/values.yaml
@@ -149,9 +149,6 @@
       # tag: ""
       # pullPolicy: IfNotPresent
       # imagePullSecret: ""
-    persistence: {}
-      # reclaimPolicy: "Retain"
-      # spec: {}
     zookeeperPodPolicy: {}
       # affinity: {}
       # tolerations: []
@@ -161,6 +158,15 @@
       # # Set ZK service account individually instead of the global "serviceAccount.name"
       # serviceAccountName: ""
 
+    # Storage defaults to the type of storage you use for Solr, which is ephemeral by default.
+    # Explicitly set the storage type, only necessary when wishing to use an empty persistence or ephemeral object.
+    storageType: ""
+    persistence: {}
+      # reclaimPolicy: "Retain"
+      # spec: {}
+    ephemeral: {}
+      # emptydirvolumesource: {}
+
   # Use this section to inject ACL information for your zookeeper from a Kube secret in the same namespace as your SolrCloud
   acl: {}
     # secret: zk-acls