This is an automated email from the ASF dual-hosted git repository.

houston pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 7701225  Add ephemeral option for zk storage. (#284)
7701225 is described below

commit 7701225fea9388a2b9f21e4ae0bcb1115d3b9e6f
Author: Houston Putman <hous...@apache.org>
AuthorDate: Tue Jul 20 12:41:00 2021 -0400

    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).
---
 Makefile                                         |   1 +
 api/v1beta1/solrcloud_types.go                   |  10 +-
 api/v1beta1/zz_generated.deepcopy.go             |   5 +
 config/crd/bases/solr.apache.org_solrclouds.yaml |  20 +-
 controllers/controller_utils_test.go             |   6 +
 controllers/solrcloud_controller_test.go         |  86 +-------
 controllers/solrcloud_controller_zk_test.go      | 244 +++++++++++++++++++++++
 controllers/util/zk_util.go                      |  28 ++-
 controllers/util/zk_util_test.go                 |  59 ++++++
 docs/solr-cloud/solr-cloud-crd.md                |  21 ++
 docs/upgrade-notes.md                            |   7 +
 go.sum                                           |   2 +
 helm/solr-operator/Chart.yaml                    |   7 +
 helm/solr-operator/crds/crds.yaml                |  20 +-
 helm/solr/README.md                              |   2 +
 helm/solr/templates/solrcloud.yaml               |   5 +-
 helm/solr/values.yaml                            |  12 +-
 17 files changed, 440 insertions(+), 95 deletions(-)

diff --git a/Makefile b/Makefile
index d306a8b..debdf03 100644
--- a/Makefile
+++ b/Makefile
@@ -102,6 +102,7 @@ generate:
 
 # 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 @@ func (ref *ZookeeperRef) withDefaults() (changed bool) {
                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 @@ type ZookeeperSpec struct {
 
        // 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 @@ type ZookeeperSpec struct {
        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 @@ func (in *ZookeeperSpec) DeepCopyInto(out 
*ZookeeperSpec) {
                *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 @@ spec:
                       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 @@ spec:
                             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 @@ import (
        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 @@ func cleanupTest(g *gomega.GomegaWithT, namespace string) {
                // 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 @@ var (
        }
        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 @@ var (
        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 @@ func TestCustomKubeOptionsCloudReconcile(t *testing.T) {
        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 @@ func TestCloudWithExternalZookeeperChroot(t *testing.T) {
        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 @@ package controllers
 
 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 @@ import (
 
 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 @@ func GenerateZookeeperCluster(solrCloud *solr.SolrCloud, 
zkSpec *solr.ZookeeperS
                                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 @@ func GenerateZookeeperCluster(solrCloud *solr.SolrCloud, 
zkSpec *solr.ZookeeperS
                },
        }
 
+       // 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 @@ each solrCloud that has this option specified.
 
 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 @@ _Note that the Helm chart version does not contain a `v` 
prefix, which the downl
 - 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/fsouza/fake-gcs-server v1.7.0/go.mod 
h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7R
 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/russross/blackfriday/v2 v2.0.1/go.mod 
h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
 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 @@ annotations:
           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 @@ spec:
                       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 @@ spec:
                             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 @@ Currently the Zookeeper Operator does not support ACLs, so 
do not use the provid
 | 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 @@ spec:
       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 @@ zk:
       # tag: ""
       # pullPolicy: IfNotPresent
       # imagePullSecret: ""
-    persistence: {}
-      # reclaimPolicy: "Retain"
-      # spec: {}
     zookeeperPodPolicy: {}
       # affinity: {}
       # tolerations: []
@@ -161,6 +158,15 @@ zk:
       # # 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

Reply via email to