Repository: pravega/zookeeper-operator
Pull request #221 (2020-07-15 23:31:06)

ZooKeeper Operator API Resource Hook.
### Change log description

* Adds a manifest which defines a post-install/upgrade hook to make sure the `zookeepercluster` resource exists.

### Purpose of the change

* If one is unlucky with the timings when install the `zookeeper-operator` chart, directly followed by the `zookeeper` chart, the api-resource `ZooKeeperCluster` may not exist by the time the zookeeper chart tries to create a `ZooKeeperCluster`.

### What the code does

* See above.

### How to verify it

Run many install/uninstall cycles of the mentioned charts -- see that the zookeeper chart does not start before its resource dependency is registered.


co-jo: Note: I'm not entirely sure if all the resources mentioned in the `yaml` manifest area needed. I referenced the one from the zookeeper chart.
codecov-commenter: # [Codecov](https://codecov.io/gh/pravega/zookeeper-operator/pull/221?src=pr&el=h1) Report
> Merging [#221](https://codecov.io/gh/pravega/zookeeper-operator/pull/221?src=pr&el=desc) into [master](https://codecov.io/gh/pravega/zookeeper-operator/commit/fb3a0ceb93c0ef900d7a309768149ee95cf7a36c&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/pravega/zookeeper-operator/pull/221/graphs/tree.svg?width=650&height=150&src=pr&token=04r424HENM)](https://codecov.io/gh/pravega/zookeeper-operator/pull/221?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master     #221   +/-   ##
=======================================
  Coverage   82.82%   82.82%           
=======================================
  Files          11       11           
  Lines        1223     1223           
=======================================
  Hits         1013     1013           
  Misses        142      142           
  Partials       68       68           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/pravega/zookeeper-operator/pull/221?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pravega/zookeeper-operator/pull/221?src=pr&el=footer). Last update [fb3a0ce...d13bea2](https://codecov.io/gh/pravega/zookeeper-operator/pull/221?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index e6fed56..7ad80d0 100644
--- a/README.md
+++ b/README.md
@@ -25,20 +25,32 @@ The project is currently alpha. While no breaking API changes are currently plan
 
 ### Overview
 
-This operator runs a Zookeeper 3.5 cluster, and uses Zookeeper dynamic reconfiguration to handle node membership.
+This operator runs a Zookeeper 3.6.1 cluster, and uses Zookeeper dynamic reconfiguration to handle node membership.
 
 The operator itself is built with the [Operator framework](https://github.com/operator-framework/operator-sdk).
 
 ## Requirements
 
-- Access to a Kubernetes v1.9.0+ cluster
+- Access to a Kubernetes v1.15.0+ cluster
 
 ## Usage
 
+We recommend using our [helm charts](charts) for all installation and upgrades. However there are manual deployment and upgrade options available as well.
+
 ### Install the operator
 
 > Note: if you are running on Google Kubernetes Engine (GKE), please [check this first](#installation-on-google-kubernetes-engine).
 
+#### Install via helm
+
+Use helm to quickly deploy a zookeeper operator with the release name `zookeeper-operator`.
+
+```
+$ helm install zookeeper-operator charts/zookeeper-operator
+```
+
+#### Manual deployment
+
 Register the `ZookeeperCluster` custom resource definition (CRD).
 
 ```
@@ -77,13 +89,25 @@ zookeeper-operator   1         1         1            1           12m
 
 ### Deploy a sample Zookeeper cluster
 
+#### Install via helm
+
+Helm can be used to install a sample zookeeper cluster with the release name `zookeeper`.
+
+```
+$ helm install zookeeper charts/zookeeper
+```
+
+Check out the [zookeeper helm charts](charts/zookeeper) for the complete list of configurable parameters.
+
+#### Manual deployment
+
 Create a Yaml file called `zk.yaml` with the following content to install a 3-node Zookeeper cluster.
 
 ```yaml
 apiVersion: "zookeeper.pravega.io/v1beta1"
 kind: "ZookeeperCluster"
 metadata:
-  name: "example"
+  name: "zookeeper"
 spec:
   replicas: 3
 ```
@@ -97,8 +121,8 @@ After a couple of minutes, all cluster members should become ready.
 ```
 $ kubectl get zk
 
-NAME      REPLICAS   READY REPLICAS   VERSION   DESIRED VERSION   INTERNAL ENDPOINT    EXTERNAL ENDPOINT   AGE
-example   3          3                 0.2.7     0.2.7             10.100.200.18:2181   N/A                 94s
+NAME        REPLICAS   READY REPLICAS    VERSION   DESIRED VERSION   INTERNAL ENDPOINT    EXTERNAL ENDPOINT   AGE
+zookeeper   3          3                 0.2.8     0.2.8             10.100.200.18:2181   N/A                 94s
 ```
 >Note: when the Version field is set as well as Ready Replicas are equal to Replicas that signifies our cluster is in Ready state
 
@@ -117,18 +141,18 @@ Conditions:
 >Note: User should wait for the Pods Ready condition to be True
 
 ```
-$ kubectl get all -l app=example
-NAME                   DESIRED   CURRENT   AGE
-statefulsets/example   3         3         2m
+$ kubectl get all -l app=zookeeper
+NAME                     DESIRED   CURRENT   AGE
+statefulsets/zookeeper   3         3         2m
 
-NAME           READY     STATUS    RESTARTS   AGE
-po/example-0   1/1       Running   0          2m
-po/example-1   1/1       Running   0          1m
-po/example-2   1/1       Running   0          1m
+NAME             READY     STATUS    RESTARTS   AGE
+po/zookeeper-0   1/1       Running   0          2m
+po/zookeeper-1   1/1       Running   0          1m
+po/zookeeper-2   1/1       Running   0          1m
 
-NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
-svc/example-client     ClusterIP   10.31.243.173   <none>        2181/TCP            2m
-svc/example-headless   ClusterIP   None            <none>        2888/TCP,3888/TCP   2m
+NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
+svc/zookeeper-client     ClusterIP   10.31.243.173   <none>        2181/TCP            2m
+svc/zookeeper-headless   ClusterIP   None            <none>        2888/TCP,3888/TCP   2m
 ```
 
 ### Deploy a sample Zookeeper cluster with Istio
@@ -154,7 +178,17 @@ $ kubectl create -f zk-with-istio.yaml
 
 ### Upgrade a Zookeeper cluster
 
-To initiate an upgrade process, a user has to update the `spec.image.tag` field of the `ZookeeperCluster` custom resource. This can be done in three different ways using the `kubectl` command.
+#### Trigger the upgrade via helm
+
+The upgrade can be triggered via helm using the following command
+```
+$ helm upgrade zookeeper <location of modified charts> --timeout 600s
+```
+Here `zookeeper` is the release name of the zookeeper cluster.
+
+#### Trigger the upgrade manually
+
+To initiate an upgrade process manually, a user has to update the `spec.image.tag` field of the `ZookeeperCluster` custom resource. This can be done in three different ways using the `kubectl` command.
 1. `kubectl edit zk <name>`, modify the `tag` value in the YAML resource, save, and exit.
 2. If you have the custom resource defined in a local YAML file, e.g. `zk.yaml`, you can modify the `tag` value, and reapply the resource with `kubectl apply -f zk.yaml`.
 3. `kubectl patch zk <name> --type='json' -p='[{"op": "replace", "path": "/spec/image/tag", "value": "X.Y.Z"}]'`.
@@ -179,8 +213,8 @@ Additionally, the Desired Version will be set to the version that we are upgradi
 ```
 $ kubectl get zk
 
-NAME         REPLICAS   READY REPLICAS   VERSION   DESIRED VERSION   INTERNAL ENDPOINT     EXTERNAL ENDPOINT   AGE
-example       3          3                0.2.6     0.2.7             10.100.200.126:2181   N/A                 11m
+NAME            REPLICAS   READY REPLICAS   VERSION   DESIRED VERSION   INTERNAL ENDPOINT     EXTERNAL ENDPOINT   AGE
+zookeeper       3          3                0.2.6     0.2.7             10.100.200.126:2181   N/A                 11m
 
 ```
 Once the upgrade completes, the Version field is set to the Desired Version, as shown below
@@ -188,8 +222,8 @@ Once the upgrade completes, the Version field is set to the Desired Version, as
 ```
 $ kubectl get zk
 
-NAME         REPLICAS   READY REPLICAS   VERSION   DESIRED VERSION   INTERNAL ENDPOINT     EXTERNAL ENDPOINT   AGE
-example        3          3               0.2.7     0.2.7            10.100.200.126:2181   N/A                 11m
+NAME            REPLICAS   READY REPLICAS   VERSION   DESIRED VERSION   INTERNAL ENDPOINT     EXTERNAL ENDPOINT   AGE
+zookeeper       3          3                0.2.7     0.2.7             10.100.200.126:2181   N/A                 11m
 
 
 ```
@@ -213,6 +247,15 @@ Status:
 
 ### Uninstall the Zookeeper cluster
 
+#### Uninstall via helm
+
+```
+$ helm uninstall zookeeper
+```
+Here `zookeeper` is the zookeeper cluster release name.
+
+#### Manual uninstall
+
 ```
 $ kubectl delete -f zk.yaml
 ```
@@ -221,6 +264,15 @@ $ kubectl delete -f zk.yaml
 
 > Note that the Zookeeper clusters managed by the Zookeeper operator will NOT be deleted even if the operator is uninstalled.
 
+#### Uninstall via helm
+
+```
+$ helm uninstall zookeeper-operator
+```
+Here `zookeeper-operator` is the operator release name.
+
+#### Manual uninstall
+
 To delete all clusters, delete all cluster CR objects before uninstalling the operator.
 
 ```
@@ -272,10 +324,10 @@ where:
 
 ### Direct access to the cluster
 
-For debugging and development you might want to access the Zookeeper cluster directly. For example, if you created the cluster with name `example` in the `default` namespace you can forward the Zookeeper port from any of the pods (e.g. `example-0`) as follows:
+For debugging and development you might want to access the Zookeeper cluster directly. For example, if you created the cluster with name `zookeeper` in the `default` namespace you can forward the Zookeeper port from any of the pods (e.g. `zookeeper-0`) as follows:
 
 ```
-$ kubectl port-forward -n default example-0 2181:2181
+$ kubectl port-forward -n default zookeeper-0 2181:2181
 ```
 
 ### Run the operator locally
diff --git a/charts/zookeeper-operator/Chart.yaml b/charts/zookeeper-operator/Chart.yaml
index ec4f64c..6a72dc3 100644
--- a/charts/zookeeper-operator/Chart.yaml
+++ b/charts/zookeeper-operator/Chart.yaml
@@ -1,7 +1,8 @@
 apiVersion: v2
 name: zookeeper-operator
-version: 0.1.0
 description: Zookeeper Operator Helm chart for Kubernetes
+version: 0.2.8
+appVersion: 0.2.8
 keywords:
 - zookeeper
 - storage
diff --git a/charts/zookeeper-operator/README.md b/charts/zookeeper-operator/README.md
index 9bab853..2efc451 100644
--- a/charts/zookeeper-operator/README.md
+++ b/charts/zookeeper-operator/README.md
@@ -37,7 +37,7 @@ The following table lists the configurable parameters of the Zookeeper operator
 | Parameter | Description | Default |
 | ----- | ----------- | ------ |
 | `image.repository` | Image repository | `pravega/zookeeper-operator` |
-| `image.tag` | Image tag | `0.2.7` |
+| `image.tag` | Image tag | `0.2.8` |
 | `image.pullPolicy` | Image pull policy | `IfNotPresent` |
 | `crd.create` | Create zookeeper CRD | `true` |
 | `rbac.create` | Create RBAC resources | `true` |
diff --git a/charts/zookeeper-operator/templates/_helpers.tpl b/charts/zookeeper-operator/templates/_helpers.tpl
index e788ffa..a3dff43 100644
--- a/charts/zookeeper-operator/templates/_helpers.tpl
+++ b/charts/zookeeper-operator/templates/_helpers.tpl
@@ -28,18 +28,10 @@ If release name contains chart name it will be used as a full name.
 Common labels
 */}}
 {{- define "zookeeper-operator.commonLabels" -}}
-helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
-{{ include "zookeeper-operator.selectorLabels" . }}
+app.kubernetes.io/name: {{ include "zookeeper-operator.name" . }}
 {{- if .Chart.AppVersion }}
 app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
 {{- end }}
 app.kubernetes.io/managed-by: {{ .Release.Service }}
+helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
 {{- end -}}
-
-{{/*
-Selector labels
-*/}}
-{{- define "zookeeper-operator.selectorLabels" -}}
-app.kubernetes.io/name: {{ include "zookeeper-operator.name" . }}
-app.kubernetes.io/instance: {{ .Release.Name }}
-{{- end }}
diff --git a/charts/zookeeper-operator/templates/operator.yaml b/charts/zookeeper-operator/templates/operator.yaml
index d136438..8462367 100644
--- a/charts/zookeeper-operator/templates/operator.yaml
+++ b/charts/zookeeper-operator/templates/operator.yaml
@@ -9,11 +9,12 @@ spec:
   replicas: 1
   selector:
     matchLabels:
-{{ include "zookeeper-operator.selectorLabels" . | indent 6 }}
+      name: {{ template "zookeeper-operator.fullname" . }}
   template:
     metadata:
       labels:
-{{ include "zookeeper-operator.selectorLabels" . | indent 8 }}
+        name: {{ template "zookeeper-operator.fullname" . }}
+        component: zookeeper-operator
     spec:
       serviceAccountName: {{ .Values.serviceAccount.name }}
       containers:
diff --git a/charts/zookeeper-operator/templates/post-install-upgrade-hooks.yaml b/charts/zookeeper-operator/templates/post-install-upgrade-hooks.yaml
new file mode 100644
index 0000000..13a39c0
--- /dev/null
+++ b/charts/zookeeper-operator/templates/post-install-upgrade-hooks.yaml
@@ -0,0 +1,107 @@
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    "helm.sh/hook": post-install, post-upgrade
+    "helm.sh/hook-weight": "1"
+    "helm.sh/hook-delete-policy": hook-succeeded, before-hook-creation, hook-failed
+rules:
+- apiGroups:
+  - zookeeper.pravega.io
+  resources:
+  - "*"
+  verbs:
+  - get
+- apiGroups:
+  - extensions
+  resources:
+  - "deployments"
+  verbs:
+  - get
+---
+
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    "helm.sh/hook": post-install, post-upgrade
+    "helm.sh/hook-weight": "1"
+    "helm.sh/hook-delete-policy": hook-succeeded, before-hook-creation, hook-failed
+subjects:
+- kind: ServiceAccount
+  name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+  namespace: {{.Release.Namespace}}
+roleRef:
+  kind: Role
+  name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+  apiGroup: rbac.authorization.k8s.io
+
+---
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    "helm.sh/hook": post-install, post-upgrade
+    "helm.sh/hook-weight": "1"
+    "helm.sh/hook-delete-policy": hook-succeeded, before-hook-creation, hook-failed
+
+---
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+  namespace: {{ .Release.Namespace }}
+  annotations:
+      "helm.sh/hook": post-install, post-upgrade
+      "helm.sh/hook-weight": "1"
+      "helm.sh/hook-delete-policy": hook-succeeded, before-hook-creation, hook-failed
+data:
+  validations.sh: |
+    #!/bin/sh
+    set -e
+    sleep 30
+
+    if [ -z "$(kubectl api-resources | grep ZookeeperCluster)" ]; then
+        exit 1
+    fi
+---
+
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+  namespace: {{ .Release.Namespace }}
+  annotations:
+    "helm.sh/hook": post-install, post-upgrade
+    "helm.sh/hook-weight": "2"
+    "helm.sh/hook-delete-policy": hook-succeeded, before-hook-creation, hook-failed
+spec:
+  backoffLimit: {{ .Values.hooks.backoffLimit }}
+  template:
+    metadata:
+      name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+    spec:
+      serviceAccountName: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+      restartPolicy: Never
+      containers:
+      - name: post-install-upgrade-job
+        image: "{{ .Values.hooks.image.repository }}:{{ .Values.hooks.image.tag }}"
+        command:
+          - /scripts/validations.sh
+        volumeMounts:
+          - name: sh
+            mountPath: /scripts
+            readOnly: true
+      volumes:
+        - name: sh
+          configMap:
+            name: {{ template "zookeeper-operator.fullname" . }}-post-install-upgrade
+            defaultMode: 0555
diff --git a/charts/zookeeper-operator/values.yaml b/charts/zookeeper-operator/values.yaml
index 2247064..7474ca7 100644
--- a/charts/zookeeper-operator/values.yaml
+++ b/charts/zookeeper-operator/values.yaml
@@ -9,7 +9,7 @@ global:
 
 image:
   repository: pravega/zookeeper-operator
-  tag: 0.2.7
+  tag: 0.2.8
   pullPolicy: IfNotPresent
 
 ## Install RBAC roles and bindings.
@@ -39,3 +39,10 @@ resources: {}
   # requests:
   #   cpu: 1
   #   memory: 128Mi
+
+hooks:
+  backoffLimit: 10
+  image:
+    repository: lachlanevenson/k8s-kubectl
+    tag: v1.16.10
+
diff --git a/charts/zookeeper/Chart.yaml b/charts/zookeeper/Chart.yaml
index 2cddde9..d4f6906 100644
--- a/charts/zookeeper/Chart.yaml
+++ b/charts/zookeeper/Chart.yaml
@@ -1,7 +1,8 @@
 apiVersion: v2
 name: zookeeper
 description: Zookeeper Helm chart for Kubernetes
-version: 0.1.0
+version: 0.2.8
+appVersion: 0.2.8
 keywords:
 - zookeeper
 - storage
diff --git a/charts/zookeeper/README.md b/charts/zookeeper/README.md
index 9417fa9..681acb5 100644
--- a/charts/zookeeper/README.md
+++ b/charts/zookeeper/README.md
@@ -40,7 +40,7 @@ The following table lists the configurable parameters of the Zookeeper chart and
 | ----- | ----------- | ------ |
 | `replicas` | Expected size of the zookeeper cluster (valid range is from 1 to 7) | `3` |
 | `image.repository` | Image repository | `pravega/zookeeper` |
-| `image.tag` | Image tag | `0.2.7` |
+| `image.tag` | Image tag | `0.2.8` |
 | `image.pullPolicy` | Image pull policy | `IfNotPresent` |
 | `domainName` | Domain name to be used for DNS | |
 | `labels` | Specifies the labels to be attached | `{}` |
diff --git a/charts/zookeeper/templates/_helpers.tpl b/charts/zookeeper/templates/_helpers.tpl
index 7d41a60..5ae8328 100644
--- a/charts/zookeeper/templates/_helpers.tpl
+++ b/charts/zookeeper/templates/_helpers.tpl
@@ -29,7 +29,6 @@ Common labels
 */}}
 {{- define "zookeeper.commonLabels" -}}
 app.kubernetes.io/name: {{ include "zookeeper.name" . }}
-app.kubernetes.io/instance: {{ .Release.Name }}
 {{- if .Chart.AppVersion }}
 app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
 {{- end }}
diff --git a/charts/zookeeper/templates/post-install-upgrade-hooks.yaml b/charts/zookeeper/templates/post-install-upgrade-hooks.yaml
index 3136ae1..9be6ac5 100644
--- a/charts/zookeeper/templates/post-install-upgrade-hooks.yaml
+++ b/charts/zookeeper/templates/post-install-upgrade-hooks.yaml
@@ -61,7 +61,6 @@ data:
   validations.sh: |
     #!/bin/sh
     set -e
-
     sleep 30
 
     replicas=`kubectl get zk -n {{ .Release.Namespace }} {{ template "zookeeper.fullname" . }} -o jsonpath='{.status.replicas}'`
@@ -93,7 +92,7 @@ metadata:
     "helm.sh/hook-weight": "2"
     "helm.sh/hook-delete-policy": hook-succeeded, before-hook-creation, hook-failed
 spec:
-  backoffLimit: 3
+  backoffLimit: {{ .Values.hooks.backoffLimit }}
   template:
     metadata:
       name: {{ template "zookeeper.fullname" . }}-post-install-upgrade
diff --git a/charts/zookeeper/values.yaml b/charts/zookeeper/values.yaml
index 253b44a..2bcca92 100644
--- a/charts/zookeeper/values.yaml
+++ b/charts/zookeeper/values.yaml
@@ -2,7 +2,7 @@ replicas: 3
 
 image:
   repository: pravega/zookeeper
-  tag: 0.2.7
+  tag: 0.2.8
   pullPolicy: IfNotPresent
 
 domainName:
@@ -37,3 +37,4 @@ hooks:
   image:
     repository: lachlanevenson/k8s-kubectl
     tag: v1.16.10
+  backoffLimit: 10
diff --git a/deploy/crds/zookeeper_v1beta1_zookeepercluster_cr.yaml b/deploy/crds/zookeeper_v1beta1_zookeepercluster_cr.yaml
index 659691c..8bde8c3 100644
--- a/deploy/crds/zookeeper_v1beta1_zookeepercluster_cr.yaml
+++ b/deploy/crds/zookeeper_v1beta1_zookeepercluster_cr.yaml
@@ -6,7 +6,7 @@ spec:
   replicas: 3
   image:
     repository: pravega/zookeeper
-    tag: 0.2.7
+    tag: 0.2.8
   persistence:
     reclaimPolicy: Delete
     spec:
diff --git a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
index 09e1d1a..6c71a04 100644
--- a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
+++ b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types.go
@@ -25,7 +25,7 @@ const (
 
 	// DefaultZkContainerVersion is the default tag used for for the zookeeper
 	// container
-	DefaultZkContainerVersion = "0.2.7"
+	DefaultZkContainerVersion = "0.2.8"
 
 	// DefaultZkContainerPolicy is the default container pull policy used
 	DefaultZkContainerPolicy = "Always"


Test patch:
diff --git a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types_test.go b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types_test.go
index cfe58aa..77d9a62 100644
--- a/pkg/apis/zookeeper/v1beta1/zookeepercluster_types_test.go
+++ b/pkg/apis/zookeeper/v1beta1/zookeepercluster_types_test.go
@@ -81,7 +81,7 @@ var _ = Describe("ZookeeperCluster Types", func() {
 			})
 
 			It("Checking tostring() function", func() {
-				Ω(z.Spec.Image.ToString()).To(Equal("pravega/zookeeper:0.2.7"))
+				Ω(z.Spec.Image.ToString()).To(Equal("pravega/zookeeper:0.2.8"))
 			})
 
 		})