Repository: pravega/zookeeper-operator (go)

Issue:
Support customized volumeMounts for zookeeper container
### Description

Need to support customized volumeMounts for zk container so that the customized volumes which user set can be mounted to the zk container.

### Importance

ECS ObjectScale need this feature so that zookeeper component can be intergrated with the rsyslog logging injection. 

### Location

Operator code & related templates


Pull request:
Issue 328: Add support of customized volumeMounts for zookeeper container
### Change log description

Added a new field volumeMounts in ZookeeperClusterSpec so that users can set customized volumeMounts for zookeeper container to mount customized volumes user specified.

### Purpose of the change

Fixes #328 

### What the code does

Added a new field volumeMounts in ZookeeperClusterSpec and the customized volumeMounts specified can be added to the zookeeper container.

### How to verify it

Verified that able to configure customized volumeMounts for zk container and successfully mounted the customized volumes to the zk container.


Patch:
diff --git a/charts/zookeeper-operator/templates/pre-delete-hooks.yaml b/charts/zookeeper-operator/templates/pre-delete-hooks.yaml
index c36aa67..d69393c 100644
--- a/charts/zookeeper-operator/templates/pre-delete-hooks.yaml
+++ b/charts/zookeeper-operator/templates/pre-delete-hooks.yaml
@@ -1,6 +1,6 @@
 {{- if .Values.hooks.delete }}
 kind: ClusterRole
-apiVersion: rbac.authorization.k8s.io/v1beta1
+apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: {{ template "zookeeper-operator.fullname" . }}-pre-delete
   annotations:
@@ -18,7 +18,7 @@ rules:
 ---
 
 kind: ClusterRoleBinding
-apiVersion: rbac.authorization.k8s.io/v1beta1
+apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: {{ template "zookeeper-operator.fullname" . }}-pre-delete
   annotations:
diff --git a/charts/zookeeper-operator/templates/zookeeper.pravega.io_zookeeperclusters_crd.yaml b/charts/zookeeper-operator/templates/zookeeper.pravega.io_zookeeperclusters_crd.yaml
index 5bcef79..e8c5edd 100644
--- a/charts/zookeeper-operator/templates/zookeeper.pravega.io_zookeeperclusters_crd.yaml
+++ b/charts/zookeeper-operator/templates/zookeeper.pravega.io_zookeeperclusters_crd.yaml
@@ -1,5 +1,9 @@
 {{- if .Values.crd.create }}
+{{- if .Capabilities.APIVersions.Has "apiextensions.k8s.io/v1" }}
+apiVersion: apiextensions.k8s.io/v1
+{{- else }}
 apiVersion: apiextensions.k8s.io/v1beta1
+{{- end }}
 kind: CustomResourceDefinition
 metadata:
   name: zookeeperclusters.zookeeper.pravega.io
@@ -3735,6 +3739,47 @@ spec:
                 - name
                 type: object
               type: array
+            volumeMounts:
+              description: Customized volumeMounts for zookeeper container.
+                Cannot be updated.
+              items:
+                description: VolumeMount describes a mounting of a Volume within
+                  a container.
+                properties:
+                  mountPath:
+                    description: Path within the container at which the volume
+                      should be mounted.  Must not contain ':'.
+                    type: string
+                  mountPropagation:
+                    description: mountPropagation determines how mounts are
+                      propagated from the host to container and the other way
+                      around. When not set, MountPropagationNone is used. This
+                      field is beta in 1.10.
+                    type: string
+                  name:
+                    description: This must match the Name of a Volume.
+                    type: string
+                  readOnly:
+                    description: Mounted read-only if true, read-write otherwise
+                      (false or unspecified). Defaults to false.
+                    type: boolean
+                  subPath:
+                    description: Path within the volume from which the container's
+                      volume should be mounted. Defaults to "" (volume's root).
+                    type: string
+                  subPathExpr:
+                    description: Expanded path within the volume from which
+                      the container's volume should be mounted. Behaves similarly
+                      to SubPath but environment variable references $(VAR_NAME)
+                      are expanded using the container's environment. Defaults
+                      to "" (volume's root). SubPathExpr and SubPath are mutually
+                      exclusive.
+                    type: string
+                required:
+                - mountPath
+                - name
+                type: object
+              type: array
           type: object
         status:
           description: ZookeeperClusterStatus defines the observed state of ZookeeperCluster
diff --git a/charts/zookeeper/README.md b/charts/zookeeper/README.md
index 189719c..eb9b3ba 100644
--- a/charts/zookeeper/README.md
+++ b/charts/zookeeper/README.md
@@ -113,3 +113,4 @@ The following table lists the configurable parameters of the zookeeper chart and
 | `ephemeral.emptydirvolumesource.sizeLimit` | Total amount of local storage required for the EmptyDir volume. | `20Gi` |
 | `containers` | Application containers run with the zookeeper pod | `[]` |
 | `volumes` | Named volumes that may be accessed by any container in the pod | `[]` |
+| `volumeMounts` | Customized volumeMounts for zookeeper container that can be configured to mount volumes to zookeeper container | `[]` |
diff --git a/charts/zookeeper/values.yaml b/charts/zookeeper/values.yaml
index 2e90dd9..33f7b46 100644
--- a/charts/zookeeper/values.yaml
+++ b/charts/zookeeper/values.yaml
@@ -95,3 +95,4 @@ hooks:
 
 containers: []
 volumes: []
+volumeMounts: []
diff --git a/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml b/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml
index c37e0a2..b268006 100644
--- a/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml
+++ b/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml
@@ -3731,6 +3731,47 @@ spec:
                 - name
                 type: object
               type: array
+            volumeMounts:
+              description: Customized volumeMounts for zookeeper container.
+                Cannot be updated.
+              items:
+                description: VolumeMount describes a mounting of a Volume within
+                  a container.
+                properties:
+                  mountPath:
+                    description: Path within the container at which the volume
+                      should be mounted.  Must not contain ':'.
+                    type: string
+                  mountPropagation:
+                    description: mountPropagation determines how mounts are
+                      propagated from the host to container and the other way
+                      around. When not set, MountPropagationNone is used. This
+                      field is beta in 1.10.
+                    type: string
+                  name:
+                    description: This must match the Name of a Volume.
+                    type: string
+                  readOnly:
+                    description: Mounted read-only if true, read-write otherwise
+                      (false or unspecified). Defaults to false.
+                    type: boolean
+                  subPath:
+                    description: Path within the volume from which the container's
+                      volume should be mounted. Defaults to "" (volume's root).
+                    type: string
+                  subPathExpr:
+                    description: Expanded path within the volume from which
+                      the container's volume should be mounted. Behaves similarly
+                      to SubPath but environment variable references $(VAR_NAME)
+                      are expanded using the container's environment. Defaults
+                      to "" (volume's root). SubPathExpr and SubPath are mutually
+                      exclusive.
+                    type: string
+                required:
+                - mountPath
+                - name
+                type: object
+              type: array
           type: object
         status:
           description: ZookeeperClusterStatus defines the observed state of ZookeeperCluster
diff --git a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
index 365484b..2520314 100644
--- a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
+++ b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
@@ -136,6 +136,9 @@ type ZookeeperClusterSpec struct {
 	// Volumes defines to support customized volumes
 	Volumes []v1.Volume `json:"volumes,omitempty"`
 
+	// VolumeMounts defines to support customized volumeMounts
+	VolumeMounts []v1.VolumeMount `json:"volumeMounts,omitempty"`
+
 	// Probes specifies the timeout values for the Readiness and Liveness Probes
 	// for the zookeeper pods.
 	// +optional
diff --git a/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go b/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go
index 50f7cc1..ee70ca7 100644
--- a/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go
+++ b/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go
@@ -9,6 +9,52 @@ import (
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AdminServerServicePolicy) DeepCopyInto(out *AdminServerServicePolicy) {
+	*out = *in
+	if in.Annotations != nil {
+		in, out := &in.Annotations, &out.Annotations
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdminServerServicePolicy.
+func (in *AdminServerServicePolicy) DeepCopy() *AdminServerServicePolicy {
+	if in == nil {
+		return nil
+	}
+	out := new(AdminServerServicePolicy)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ClientServicePolicy) DeepCopyInto(out *ClientServicePolicy) {
+	*out = *in
+	if in.Annotations != nil {
+		in, out := &in.Annotations, &out.Annotations
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientServicePolicy.
+func (in *ClientServicePolicy) DeepCopy() *ClientServicePolicy {
+	if in == nil {
+		return nil
+	}
+	out := new(ClientServicePolicy)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ClusterCondition) DeepCopyInto(out *ClusterCondition) {
 	*out = *in
@@ -58,6 +104,29 @@ func (in *Ephemeral) DeepCopy() *Ephemeral {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HeadlessServicePolicy) DeepCopyInto(out *HeadlessServicePolicy) {
+	*out = *in
+	if in.Annotations != nil {
+		in, out := &in.Annotations, &out.Annotations
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HeadlessServicePolicy.
+func (in *HeadlessServicePolicy) DeepCopy() *HeadlessServicePolicy {
+	if in == nil {
+		return nil
+	}
+	out := new(HeadlessServicePolicy)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *MembersStatus) DeepCopyInto(out *MembersStatus) {
 	*out = *in
@@ -311,6 +380,9 @@ func (in *ZookeeperClusterSpec) DeepCopyInto(out *ZookeeperClusterSpec) {
 		copy(*out, *in)
 	}
 	in.Pod.DeepCopyInto(&out.Pod)
+	in.AdminServerService.DeepCopyInto(&out.AdminServerService)
+	in.ClientService.DeepCopyInto(&out.ClientService)
+	in.HeadlessService.DeepCopyInto(&out.HeadlessService)
 	if in.Persistence != nil {
 		in, out := &in.Persistence, &out.Persistence
 		*out = new(Persistence)
@@ -336,6 +408,13 @@ func (in *ZookeeperClusterSpec) DeepCopyInto(out *ZookeeperClusterSpec) {
 			(*in)[i].DeepCopyInto(&(*out)[i])
 		}
 	}
+	if in.VolumeMounts != nil {
+		in, out := &in.VolumeMounts, &out.VolumeMounts
+		*out = make([]v1.VolumeMount, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 	if in.Probes != nil {
 		in, out := &in.Probes, &out.Probes
 		*out = new(Probes)
diff --git a/pkg/zk/generators.go b/pkg/zk/generators.go
index b588be9..a7b5104 100644
--- a/pkg/zk/generators.go
+++ b/pkg/zk/generators.go
@@ -142,10 +142,10 @@ func makeZkPodSpec(z *v1beta1.ZookeeperCluster, volumes []v1.Volume) v1.PodSpec
 				Exec: &v1.ExecAction{Command: []string{"zookeeperLive.sh"}},
 			},
 		},
-		VolumeMounts: []v1.VolumeMount{
+		VolumeMounts: append(z.Spec.VolumeMounts, []v1.VolumeMount{
 			{Name: "data", MountPath: "/data"},
 			{Name: "conf", MountPath: "/conf"},
-		},
+		}...),
 		Lifecycle: &v1.Lifecycle{
 			PreStop: &v1.Handler{
 				Exec: &v1.ExecAction{


Test patch:
diff --git a/pkg/apis/zookeeper/v1beta1/deepcopy_test.go b/pkg/apis/zookeeper/v1beta1/deepcopy_test.go
index 922e438..f58586d 100644
--- a/pkg/apis/zookeeper/v1beta1/deepcopy_test.go
+++ b/pkg/apis/zookeeper/v1beta1/deepcopy_test.go
@@ -51,6 +51,12 @@ var _ = Describe("ZookeeperCluster DeepCopy", func() {
 						Name: "testvolume",
 					},
 				},
+				VolumeMounts: []v1.VolumeMount{
+					{
+						Name:      "testvolume",
+						MountPath: "/test/volume",
+					},
+				},
 			}
 
 			z1.WithDefaults()