Repository: pravega/zookeeper-operator (go)

Issue:
ZK Operator should be able to watch a configurable set of namespaces
Controller-runtime added support in newer version to configure controllers to watch a certain set of namespaces.
As it is now the operator can be configured to `watch` either _ALL_ or a single _Namespace_
In environments where multiple instances of ZK clusters are required, having a single operator overseeing multiple instances across many NS, simplifies the deployment.



Pull request:
Operator can watch a configurable set of namespaces
### Change log description

This patch extends the watch mechanism in operator so the ZookeeperCluster resources can be deployed in different namespaces than where the operator runs.

### Purpose of the change

Fixes #142 


### How to verify it

_(Steps to verify that the changes are effective)_


Patch:
diff --git a/README.md b/README.md
index 0fb272b..7ad80d0 100644
--- a/README.md
+++ b/README.md
@@ -20,25 +20,37 @@ The project is currently alpha. While no breaking API changes are currently plan
     * [Direct Access to Cluster](#direct-access-to-the-cluster)
     * [Run the Operator Locally](#run-the-operator-locally)
     * [Installation on GKE](#installation-on-google-kubernetes-engine)
-
+    * [Installation on Minikube](#installation-on-minikube)
 
 
 ### 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
@@ -306,6 +358,21 @@ On GKE, the following command must be run before installing the operator, replac
 $ kubectl create clusterrolebinding your-user-cluster-admin-binding --clusterrole=cluster-admin --user=your.google.cloud.email@example.org
 ```
 
+### Installation on Minikube
+
+#### Minikube Setup
+To setup minikube locally you can follow the steps mentioned [here](https://github.com/pravega/pravega/wiki/Kubernetes-Based-System-Test-Framework#minikube-setup).
+
+Once minikube setup is complete, `minikube start` will create a minikube VM.
+
+#### Cluster Deployment
+First install the zookeeper operator in either of the ways mentioned [here](#install-the-operator).
+Since minikube provides a single node Kubernetes cluster which has a low resource provisioning, we provide a simple way to install a small zookeeper cluster on a minikube environment using the following command.
+
+```
+helm install zookeeper charts/zookeeper --values charts/zookeeper/values/minikube.yaml
+```
+
 #### Zookeeper YAML  Exporter
 
 Zookeeper Exporter is a binary which is used to generate YAML file for all the secondary resources which Zookeeper Operator deploys to the Kubernetes Cluster. It takes ZookeeperCluster resource YAML file as input and generates bunch of secondary resources YAML files. The generated output look like the following:
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..5cddfdc 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.
@@ -27,8 +27,9 @@ serviceAccount:
 crd:
   create: true
 
-## Specifies which namespace the Operator should watch over.
-## An empty string means all namespaces.
+## Specifies which namespace(s) the Operator should watch over.
+## Default: An empty string means all namespaces.
+## Multiple namespaces can be configured using a comma separated list of namespaces
 watchNamespace: ""
 
 ## Operator pod resources
@@ -39,3 +40,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/charts/zookeeper/values/minikube.yaml b/charts/zookeeper/values/minikube.yaml
new file mode 100644
index 0000000..244fc71
--- /dev/null
+++ b/charts/zookeeper/values/minikube.yaml
@@ -0,0 +1,8 @@
+replicas: 1
+
+persistence:
+  storageClassName: standard
+  ## specifying reclaim policy for PersistentVolumes
+  ## accepted values - Delete / Retain
+  reclaimPolicy: Delete
+  volumeSize: 10Gi
diff --git a/cmd/manager/main.go b/cmd/manager/main.go
index 6a0d390..8aa70de 100644
--- a/cmd/manager/main.go
+++ b/cmd/manager/main.go
@@ -16,6 +16,7 @@ import (
 	"fmt"
 	"os"
 	"runtime"
+	"strings"
 
 	"github.com/operator-framework/operator-sdk/pkg/k8sutil"
 	"github.com/operator-framework/operator-sdk/pkg/leader"
@@ -25,6 +26,7 @@ import (
 	"github.com/pravega/zookeeper-operator/pkg/version"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
+	"sigs.k8s.io/controller-runtime/pkg/cache"
 	"sigs.k8s.io/controller-runtime/pkg/client/config"
 	"sigs.k8s.io/controller-runtime/pkg/manager"
 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
@@ -63,11 +65,24 @@ func main() {
 		os.Exit(0)
 	}
 
-	namespace, err := k8sutil.GetWatchNamespace()
+	namespaces, err := k8sutil.GetWatchNamespace()
 	if err != nil {
 		log.Error(err, "failed to get watch namespace")
 		os.Exit(1)
 	}
+	//When operator is started to watch resources in a specific set of namespaces, we use the MultiNamespacedCacheBuilder cache.
+	//In this scenario, it is also suggested to restrict the provided authorization to this namespace by replacing the default
+	//ClusterRole and ClusterRoleBinding to Role and RoleBinding respectively
+	//For further information see the kubernetes documentation about
+	//Using [RBAC Authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/).
+	managerWatchCache := (cache.NewCacheFunc)(nil)
+	if namespaces != "" {
+		ns := strings.Split(namespaces, ",")
+		for i := range ns {
+			ns[i] = strings.TrimSpace(ns[i])
+		}
+		managerWatchCache = cache.MultiNamespacedCacheBuilder(ns)
+	}
 
 	// Get a config to talk to the apiserver
 	cfg, err := config.GetConfig()
@@ -80,7 +95,7 @@ func main() {
 	leader.Become(context.TODO(), "zookeeper-operator-lock")
 
 	// Create a new Cmd to provide shared dependencies and start components
-	mgr, err := manager.New(cfg, manager.Options{Namespace: namespace})
+	mgr, err := manager.New(cfg, manager.Options{NewCache: managerWatchCache})
 	if err != nil {
 		log.Error(err, "")
 		os.Exit(1)
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"
diff --git a/pkg/controller/zookeepercluster/zookeepercluster_controller.go b/pkg/controller/zookeepercluster/zookeepercluster_controller.go
index bfb6505..2d6f7ba 100644
--- a/pkg/controller/zookeepercluster/zookeepercluster_controller.go
+++ b/pkg/controller/zookeepercluster/zookeepercluster_controller.go
@@ -560,20 +560,16 @@ func (r *ReconcileZookeeperCluster) GenerateYAML(inst *zookeeperv1beta1.Zookeepe
 // yamlStatefulSet will generates YAML file for StatefulSet
 func (r *ReconcileZookeeperCluster) yamlStatefulSet(instance *zookeeperv1beta1.ZookeeperCluster) (err error) {
 	sts := zk.MakeStatefulSet(instance)
-	if err = controllerutil.SetControllerReference(instance, sts, r.scheme); err != nil {
-		return err
-	}
-	subdir, err := yamlexporter.CreateOutputSubDir(sts.OwnerReferences[0].Kind, sts.Labels["component"])
+
+	subdir, err := yamlexporter.CreateOutputSubDir("ZookeeperCluster", sts.Labels["component"])
 	return yamlexporter.GenerateOutputYAMLFile(subdir, sts.Kind, sts)
 }
 
 // yamlClientService will generates YAML file for zookeeper client service
 func (r *ReconcileZookeeperCluster) yamlClientService(instance *zookeeperv1beta1.ZookeeperCluster) (err error) {
 	svc := zk.MakeClientService(instance)
-	if err = controllerutil.SetControllerReference(instance, svc, r.scheme); err != nil {
-		return err
-	}
-	subdir, err := yamlexporter.CreateOutputSubDir(svc.OwnerReferences[0].Kind, "client")
+
+	subdir, err := yamlexporter.CreateOutputSubDir("ZookeeperCluster", "client")
 	if err != nil {
 		return err
 	}
@@ -583,10 +579,8 @@ func (r *ReconcileZookeeperCluster) yamlClientService(instance *zookeeperv1beta1
 // yamlHeadlessService will generates YAML file for zookeeper headless service
 func (r *ReconcileZookeeperCluster) yamlHeadlessService(instance *zookeeperv1beta1.ZookeeperCluster) (err error) {
 	svc := zk.MakeHeadlessService(instance)
-	if err = controllerutil.SetControllerReference(instance, svc, r.scheme); err != nil {
-		return err
-	}
-	subdir, err := yamlexporter.CreateOutputSubDir(svc.OwnerReferences[0].Kind, "headless")
+
+	subdir, err := yamlexporter.CreateOutputSubDir("ZookeeperCluster", "headless")
 	if err != nil {
 		return err
 	}
@@ -596,10 +590,8 @@ func (r *ReconcileZookeeperCluster) yamlHeadlessService(instance *zookeeperv1bet
 // yamlPodDisruptionBudget will generates YAML file for zookeeper PDB
 func (r *ReconcileZookeeperCluster) yamlPodDisruptionBudget(instance *zookeeperv1beta1.ZookeeperCluster) (err error) {
 	pdb := zk.MakePodDisruptionBudget(instance)
-	if err = controllerutil.SetControllerReference(instance, pdb, r.scheme); err != nil {
-		return err
-	}
-	subdir, err := yamlexporter.CreateOutputSubDir(pdb.OwnerReferences[0].Kind, "pdb")
+
+	subdir, err := yamlexporter.CreateOutputSubDir("ZookeeperCluster", "pdb")
 	if err != nil {
 		return err
 	}
@@ -609,10 +601,8 @@ func (r *ReconcileZookeeperCluster) yamlPodDisruptionBudget(instance *zookeeperv
 // yamlConfigMap will generates YAML file for Zookeeper configmap
 func (r *ReconcileZookeeperCluster) yamlConfigMap(instance *zookeeperv1beta1.ZookeeperCluster) (err error) {
 	cm := zk.MakeConfigMap(instance)
-	if err = controllerutil.SetControllerReference(instance, cm, r.scheme); err != nil {
-		return err
-	}
-	subdir, err := yamlexporter.CreateOutputSubDir(cm.OwnerReferences[0].Kind, "config")
+
+	subdir, err := yamlexporter.CreateOutputSubDir("ZookeeperCluster", "config")
 	if err != nil {
 		return err
 	}
diff --git a/pkg/zk/generators.go b/pkg/zk/generators.go
index 5083b85..434833b 100644
--- a/pkg/zk/generators.go
+++ b/pkg/zk/generators.go
@@ -21,7 +21,6 @@ import (
 	v1 "k8s.io/api/core/v1"
 	policyv1beta1 "k8s.io/api/policy/v1beta1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
@@ -269,13 +268,7 @@ func makeService(name string, ports []v1.ServicePort, clusterIP bool, z *v1beta1
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
 			Namespace: z.Namespace,
-			OwnerReferences: []metav1.OwnerReference{
-				*metav1.NewControllerRef(z, schema.GroupVersionKind{
-					Group:   v1beta1.SchemeGroupVersion.Group,
-					Version: v1beta1.SchemeGroupVersion.Version,
-					Kind:    "ZookeeperCluster",
-				}),
-			},
+
 			Labels:      map[string]string{"app": z.GetName(), "headless": strconv.FormatBool(!clusterIP)},
 			Annotations: annotationMap,
 		},
@@ -301,13 +294,6 @@ func MakePodDisruptionBudget(z *v1beta1.ZookeeperCluster) *policyv1beta1.PodDisr
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      z.GetName(),
 			Namespace: z.Namespace,
-			OwnerReferences: []metav1.OwnerReference{
-				*metav1.NewControllerRef(z, schema.GroupVersionKind{
-					Group:   v1beta1.SchemeGroupVersion.Group,
-					Version: v1beta1.SchemeGroupVersion.Version,
-					Kind:    "ZookeeperCluster",
-				}),
-			},
 		},
 		Spec: policyv1beta1.PodDisruptionBudgetSpec{
 			MaxUnavailable: &pdbCount,


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"))
 			})
 
 		})