Repository: pravega/zookeeper-operator (go)

Issue:
ImagePullSecrets field is not supported
CRD ZookeeperCluster don't support ImagePullSecrets, the mirror image of the private warehouse cannot be pulled up.

```
apiVersion: zookeeper.pravega.io/v1beta1
kind: ZookeeperCluster
metadata:
  name: zookeeper
  namespace: default
spec:
  # Add fields here
  replicas: 3
  image:
    repository: xxxxx:8080/xxxxx/zookeeper
    tag: 3.6.1
  persistence:
    accessModes: [ "ReadWriteOnce" ]
    storageClassName: "cbs"
    reclaimPolicy: Delete
    resources:
      requests:
        storage: 10Gi
```

Pull request description:
Issue 185: support for imagepullsecrets field added
### Change log description
Support for imagepullsecret added for allowing pull of images in a private repository.

### Purpose of the change
Fixes #185 

### What the code does
imagepullsecret is added as part of pod policy and works with any other service account other than default  and allows to do pull for images from a private repository

### How to verify it
Following is tested and works:-
1) zookeeper cluster deployment with the zookeeper image in a private repo works for a non-default service account when correct imagepullsecret is specified.
2) zookeeper cluster deployment with the zookeeper image in public repository works for both default and non-default service account.


Patch:
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 72a780f..d972a48 100644
--- a/charts/zookeeper-operator/templates/zookeeper.pravega.io_zookeeperclusters_crd.yaml
+++ b/charts/zookeeper-operator/templates/zookeeper.pravega.io_zookeeperclusters_crd.yaml
@@ -2339,6 +2339,19 @@ spec:
                 serviceAccountName:
                   description: Service Account to be used in pods
                   type: string
+                imagePullSecrets:
+                  description: ImagePullSecrets is a list of references to secrets
+                      in the same namespace to use for pulling any images.
+                  items:
+                    description: LocalObjectReference contains enough information
+                      to let you locate the referenced object inside the same namespace.
+                    properties:
+                      name:
+                        description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+                          TODO: Add other useful fields. apiVersion, kind, uid?'
+                        type: string
+                    type: object
+                  type: array
                 terminationGracePeriodSeconds:
                   description: TerminationGracePeriodSeconds is the amount of time
                     that kubernetes will give for a pod instance to shutdown normally.
diff --git a/charts/zookeeper/README.md b/charts/zookeeper/README.md
index 19ca494..047bac2 100644
--- a/charts/zookeeper/README.md
+++ b/charts/zookeeper/README.md
@@ -72,6 +72,7 @@ The following table lists the configurable parameters of the zookeeper chart and
 | `pod.securityContext` | Specifies the security context for the entire pod | `{}` |
 | `pod.terminationGracePeriodSeconds` | Amount of time given to the pod to shutdown normally | `30` |
 | `pod.serviceAccountName` | Name for the service account | `zookeeper` |
+| `pod.imagePullSecrets` | ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images. | `[]` |
 | `config.initLimit` | Amount of time (in ticks) to allow followers to connect and sync to a leader | `10` |
 | `config.tickTime` | Length of a single tick which is the basic time unit used by Zookeeper (measured in milliseconds) | `2000` |
 | `config.syncLimit` | Amount of time (in ticks) to allow followers to sync with Zookeeper | `2` |
diff --git a/charts/zookeeper/templates/zookeeper.yaml b/charts/zookeeper/templates/zookeeper.yaml
index d1b4c8c..79babc2 100644
--- a/charts/zookeeper/templates/zookeeper.yaml
+++ b/charts/zookeeper/templates/zookeeper.yaml
@@ -65,6 +65,10 @@ spec:
     terminationGracePeriodSeconds: {{ .Values.pod.terminationGracePeriodSeconds }}
     {{- end }}
     serviceAccountName: {{ default "zookeeper" .Values.pod.serviceAccountName }}
+    {{- if .Values.pod.imagePullSecrets }}
+    imagePullSecrets:
+{{ toYaml .Values.pod.imagePullSecrets | indent 6 }}
+    {{- end }}
   {{- if .Values.config }}
   config:
     {{- if .Values.config.initLimit }}
diff --git a/charts/zookeeper/values.yaml b/charts/zookeeper/values.yaml
index dad1e81..e8cba23 100644
--- a/charts/zookeeper/values.yaml
+++ b/charts/zookeeper/values.yaml
@@ -21,6 +21,7 @@ pod:
   # securityContext: {}
   # terminationGracePeriodSeconds: 30
   serviceAccountName: zookeeper
+  # imagePullSecrets: []
 
 config: {}
   # initLimit: 10
diff --git a/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml b/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml
index e0a1080..65cd6f1 100644
--- a/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml
+++ b/deploy/crds/zookeeper.pravega.io_zookeeperclusters_crd.yaml
@@ -2335,6 +2335,19 @@ spec:
                 serviceAccountName:
                   description: Service Account to be used in pods
                   type: string
+                imagePullSecrets:
+                  description: ImagePullSecrets is a list of references to secrets in
+                      the same namespace to use for pulling any images.
+                  items:
+                    description: LocalObjectReference contains enough information
+                      to let you locate the referenced object inside the same namespace.
+                    properties:
+                      name:
+                        description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+                          TODO: Add other useful fields. apiVersion, kind, uid?'
+                        type: string
+                    type: object
+                  type: array
                 terminationGracePeriodSeconds:
                   description: TerminationGracePeriodSeconds is the amount of time
                     that kubernetes will give for a pod instance to shutdown normally.
diff --git a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
index b73d719..ae053b3 100644
--- a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
+++ b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
@@ -339,6 +339,8 @@ type PodPolicy struct {
 	TerminationGracePeriodSeconds int64 `json:"terminationGracePeriodSeconds,omitempty"`
 	// Service Account to be used in pods
 	ServiceAccountName string `json:"serviceAccountName,omitempty"`
+	// ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images
+	ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
 }
 
 func (p *PodPolicy) withDefaults(z *ZookeeperCluster) (changed bool) {
diff --git a/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go b/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go
index c6b5228..2814d07 100644
--- a/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go
+++ b/pkg/apis/zookeeper/v1beta1/zz_generated.deepcopy.go
@@ -157,6 +157,11 @@ func (in *PodPolicy) DeepCopyInto(out *PodPolicy) {
 		*out = new(v1.PodSecurityContext)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.ImagePullSecrets != nil {
+		in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
+		*out = make([]v1.LocalObjectReference, len(*in))
+		copy(*out, *in)
+	}
 	return
 }
 
diff --git a/pkg/zk/generators.go b/pkg/zk/generators.go
index 3e2dd41..45a9112 100644
--- a/pkg/zk/generators.go
+++ b/pkg/zk/generators.go
@@ -175,7 +175,6 @@ func makeZkPodSpec(z *v1beta1.ZookeeperCluster, volumes []v1.Volume) v1.PodSpec
 	podSpec.Tolerations = z.Spec.Pod.Tolerations
 	podSpec.TerminationGracePeriodSeconds = &z.Spec.Pod.TerminationGracePeriodSeconds
 	podSpec.ServiceAccountName = z.Spec.Pod.ServiceAccountName
-
 	return podSpec
 }
 
@@ -349,6 +348,7 @@ func MakeServiceAccount(z *v1beta1.ZookeeperCluster) *v1.ServiceAccount {
 			Name:      z.Spec.Pod.ServiceAccountName,
 			Namespace: z.Namespace,
 		},
+		ImagePullSecrets: z.Spec.Pod.ImagePullSecrets,
 	}
 }
 


Test patch:
diff --git a/pkg/apis/zookeeper/v1beta1/deepcopy_test.go b/pkg/apis/zookeeper/v1beta1/deepcopy_test.go
index 1b72c87..4051788 100644
--- a/pkg/apis/zookeeper/v1beta1/deepcopy_test.go
+++ b/pkg/apis/zookeeper/v1beta1/deepcopy_test.go
@@ -29,9 +29,9 @@ func TestDeepcopy(t *testing.T) {
 var _ = Describe("ZookeeperCluster DeepCopy", func() {
 	Context("with defaults", func() {
 		var (
-			str1, str2, str3, str4, str5, str6, str7, str8, str9, str10 string
-			checkport                                                   int32
-			z1, z2                                                      *v1beta1.ZookeeperCluster
+			str1, str2, str3, str4, str5, str6, str7, str8, str9, str10, str11 string
+			checkport                                                          int32
+			z1, z2                                                             *v1beta1.ZookeeperCluster
 		)
 		BeforeEach(func() {
 			z1 = &v1beta1.ZookeeperCluster{
@@ -104,7 +104,12 @@ var _ = Describe("ZookeeperCluster DeepCopy", func() {
 			z1.Spec.Pod.Annotations = m
 			podSec := &v1.PodSecurityContext{}
 			z1.Spec.Pod.SecurityContext = podSec
+			pullsecret1 := v1.LocalObjectReference{
+				Name: "testimagepullsecret",
+			}
+			z1.Spec.Pod.ImagePullSecrets = []v1.LocalObjectReference{pullsecret1}
 			z1.Spec.Pod.DeepCopyInto(&z2.Spec.Pod)
+			str11 = z2.Spec.Pod.ImagePullSecrets[0].Name
 			port := z1.ZookeeperPorts()
 			tempPort := port.DeepCopy()
 			checkport = tempPort.Client
@@ -138,7 +143,9 @@ var _ = Describe("ZookeeperCluster DeepCopy", func() {
 		It("value of str10 should be zk-2", func() {
 			Ω(str10).To(Equal("zk-2"))
 		})
-
+		It("value of str11 should be testimagepullsecret", func() {
+			Ω(str11).To(Equal("testimagepullsecret"))
+		})
 		It("value of checkport should be 2181", func() {
 			Ω(checkport).To(Equal(int32(2181)))
 		})