Repository: redhat-developer/service-binding-operator
Pull request #444 (2020-04-29 13:42:39)

Separate SetSBRAnnotations/RemoveSBRAnnotations functions
### Motivation
Part of https://github.com/redhat-developer/service-binding-operator/pull/442 as requested by @isutton  

### Changes
Seperate `SetSBRAnnotations`/`RemoveSBRAnnotations` functions.
After this change `SetSBRAnnotations`/`RemoveSBRAnnotations` is only used to modify the object without updating it using clientset. The original behaviour is changed to `SetAndUpdateSBRAnnotations`/`RemoveAndUpdateSBRAnnotations`.

This is helpful for functions which want to combine set/remove SBRAnnotations with other modifications as a single updating request.

### Testing
Test cases included.

openshift-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **otaviof**
You can assign the PR to them by writing `/assign @otaviof` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=redhat-developer%2Fservice-binding-operator).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/redhat-developer/service-binding-operator/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["otaviof"]} -->
openshift-ci-robot: Hi @int8dev. Thanks for your PR.

I'm waiting for a [redhat-developer](https://github.com/orgs/redhat-developer/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://github.com/orgs/redhat-developer/people) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=redhat-developer%2Fservice-binding-operator).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

DhritiShikhar: /ok-to-test
codecov[bot]: # [Codecov](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444?src=pr&el=h1) Report
> Merging [#444](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444?src=pr&el=desc) into [master](https://codecov.io/gh/redhat-developer/service-binding-operator/commit/95599038d78a069c62a8069a3edc3eb23d8425c2&el=desc) will **increase** coverage by `0.34%`.
> The diff coverage is `77.14%`.

[![Impacted file tree graph](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444/graphs/tree.svg?width=650&height=150&src=pr&token=CICBeVWlrC)](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #444      +/-   ##
==========================================
+ Coverage   65.89%   66.23%   +0.34%     
==========================================
  Files          21       21              
  Lines        1463     1478      +15     
==========================================
+ Hits          964      979      +15     
  Misses        377      377              
  Partials      122      122              
```


| [Impacted Files](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pkg/controller/servicebindingrequest/binding.go](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444/diff?src=pr&el=tree#diff-cGtnL2NvbnRyb2xsZXIvc2VydmljZWJpbmRpbmdyZXF1ZXN0L2JpbmRpbmcuZ28=) | `71.42% <0.00%> (ø)` | |
| [...kg/controller/servicebindingrequest/annotations.go](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444/diff?src=pr&el=tree#diff-cGtnL2NvbnRyb2xsZXIvc2VydmljZWJpbmRpbmdyZXF1ZXN0L2Fubm90YXRpb25zLmdv) | `88.76% <81.81%> (+2.27%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444?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/redhat-developer/service-binding-operator/pull/444?src=pr&el=footer). Last update [c3b49ba...e822e23](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/444?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/examples/commons.mk b/examples/commons.mk
index a1e1ac66..fc753afd 100644
--- a/examples/commons.mk
+++ b/examples/commons.mk
@@ -82,23 +82,55 @@ help: ## Credit: https://gist.github.com/prwhite/8168133#gistcomment-2749866
 
 ## --- Service Binding Operator ---
 
-.PHONY: install-service-binding-operator-subscription
+## ---- Community version ----
+
+.PHONY: install-service-binding-operator-subscription-community
 ## Install the Service Binding Operator Subscription
-install-service-binding-operator-subscription:
-	${Q}${EC} install_service_binding_operator_subscription
+install-service-binding-operator-subscription-community:
+	${Q}${EC} install_service_binding_operator_subscription_community
 
-.PHONY: install-service-binding-operator
+.PHONY: install-service-binding-operator-community
 ## Install the Service Binding Operator
-install-service-binding-operator: install-service-binding-operator-subscription
+install-service-binding-operator-community: install-service-binding-operator-subscription-community
 
-.PHONY: uninstall-service-binding-operator-subscription
+.PHONY: uninstall-service-binding-operator-subscription-community
 ## Uninstall the Service Binding Operator Subscription
-uninstall-service-binding-operator-subscription:
-	${Q}${EC} uninstall_service_binding_operator_subscription
+uninstall-service-binding-operator-subscription-community:
+	${Q}${EC} uninstall_service_binding_operator_subscription_community
 
-.PHONY: uninstall-service-binding-operator
+.PHONY: uninstall-service-binding-operator-community
 ## Uninstall the Service Binding Operator
-uninstall-service-binding-operator: uninstall-service-binding-operator-subscription
+uninstall-service-binding-operator-community: uninstall-service-binding-operator-subscription-community
+
+## ---- Latest master ----
+
+.PHONY: install-service-binding-operator-source-master
+## Install the Service Binding Operator Source for latest master
+install-service-binding-operator-source-master:
+	${Q}${EC} install_service_binding_operator_source_master
+
+.PHONY: uninstall-service-binding-operator-source-master
+## Uninstall the Service Binding Operator Source for latest master
+uninstall-service-binding-operator-source-master:
+	${Q}${EC} uninstall_service_binding_operator_source_master
+
+.PHONY: install-service-binding-operator-subscription-master
+## Install the Service Binding Operator Subscription for latest master
+install-service-binding-operator-subscription-master:
+	${Q}${EC} install_service_binding_operator_subscription_master
+
+.PHONY: install-service-binding-operator-master
+## Install the Service Binding Operator for latest master
+install-service-binding-operator-master: install-service-binding-operator-source-master install-service-binding-operator-subscription-master
+
+.PHONY: uninstall-service-binding-operator-subscription-master
+## Uninstall the Service Binding Operator Subscription for latest master
+uninstall-service-binding-operator-subscription-master:
+	${Q}${EC} uninstall_service_binding_operator_subscription_master
+
+.PHONY: uninstall-service-binding-operator-master
+## Uninstall the Service Binding Operator for latest master
+uninstall-service-binding-operator-master: uninstall-service-binding-operator-subscription-master uninstall-service-binding-operator-source-master
 
 ## --- Backing Service DB (PostgreSQL) Operator ---
 
diff --git a/examples/java_postgresql_customvar/README.md b/examples/java_postgresql_customvar/README.md
index d41e92b9..2284c5cd 100644
--- a/examples/java_postgresql_customvar/README.md
+++ b/examples/java_postgresql_customvar/README.md
@@ -33,16 +33,47 @@ Navigate to the `Operators`->`OperatorHub` in the OpenShift console and in the `
 
 ![Service Binding Operator as shown in OperatorHub](../../assets/operator-hub-sbo-screenshot.png)
 
-and install a `alpha` version.
+and install the `alpha` version.
 
-Alternatively, you can perform the same task with this make command:
+Alternatively, you can perform the same task manually using the following command:
 
 ``` shell
-make install-service-binding-operator
+make install-service-binding-operator-community
 ```
 
 This makes the `ServiceBindingRequest` custom resource available, that the application developer will use later.
 
+##### :bulb: Latest `master` version of the operator
+
+It is also possible to install the latest `master` version of the operator instead of the one from `community-operators`. To enable that an `OperatorSource` has to be installed with the latest `master` version:
+
+``` shell
+cat <<EOS | kubectl apply -f -
+---
+apiVersion: operators.coreos.com/v1
+kind: OperatorSource
+metadata:
+  name: redhat-developer-operators
+  namespace: openshift-marketplace
+spec:
+  type: appregistry
+  endpoint: https://quay.io/cnr
+  registryNamespace: redhat-developer
+EOS
+```
+
+Alternatively, you can perform the same task manually using the following command before going to the Operator Hub:
+
+``` shell
+make install-service-binding-operator-source-master
+```
+
+or running the following command to install the operator completely:
+
+``` shell
+make install-service-binding-operator-master
+```
+
 #### Install the DB operator using an `OperatorSource`
 
 Apply the following `OperatorSource`:
diff --git a/examples/knative_postgresql_customvar/README.md b/examples/knative_postgresql_customvar/README.md
index 7d7d5b67..d88e4d02 100644
--- a/examples/knative_postgresql_customvar/README.md
+++ b/examples/knative_postgresql_customvar/README.md
@@ -36,16 +36,47 @@ Navigate to the `Operators`->`OperatorHub` in the OpenShift console and in the `
 
 ![Service Binding Operator as shown in OperatorHub](../../assets/operator-hub-sbo-screenshot.png)
 
-and install a `alpha` version.
+and install the `alpha` version.
 
-Alternatively, you can perform the same task with this make command:
+Alternatively, you can perform the same task manually using the following command:
 
 ``` shell
-make install-service-binding-operator
+make install-service-binding-operator-community
 ```
 
 This makes the `ServiceBindingRequest` custom resource available, that the application developer will use later.
 
+##### :bulb: Latest `master` version of the operator
+
+It is also possible to install the latest `master` version of the operator instead of the one from `community-operators`. To enable that an `OperatorSource` has to be installed with the latest `master` version:
+
+``` shell
+cat <<EOS | kubectl apply -f -
+---
+apiVersion: operators.coreos.com/v1
+kind: OperatorSource
+metadata:
+  name: redhat-developer-operators
+  namespace: openshift-marketplace
+spec:
+  type: appregistry
+  endpoint: https://quay.io/cnr
+  registryNamespace: redhat-developer
+EOS
+```
+
+Alternatively, you can perform the same task manually using the following command before going to the Operator Hub:
+
+``` shell
+make install-service-binding-operator-source-master
+```
+
+or running the following command to install the operator completely:
+
+``` shell
+make install-service-binding-operator-master
+```
+
 #### Install the backing DB (PostgreSQL) operator
 
 ```shell
diff --git a/examples/nodejs_awsrds_varprefix/README.md b/examples/nodejs_awsrds_varprefix/README.md
index b9f8ce49..98fe4d04 100644
--- a/examples/nodejs_awsrds_varprefix/README.md
+++ b/examples/nodejs_awsrds_varprefix/README.md
@@ -28,16 +28,47 @@ Navigate to the `Operators`->`OperatorHub` in the OpenShift console and in the `
 
 ![Service Binding Operator as shown in OperatorHub](../../assets/operator-hub-sbo-screenshot.png)
 
-and install a `alpha` version.
+and install the `alpha` version.
 
-Alternatively, you can perform the same task with this make command:
+Alternatively, you can perform the same task manually using the following command:
 
 ``` shell
-make install-service-binding-operator
+make install-service-binding-operator-community
 ```
 
 This makes the `ServiceBindingRequest` custom resource available, that the application developer will use later.
 
+##### :bulb: Latest `master` version of the operator
+
+It is also possible to install the latest `master` version of the operator instead of the one from `community-operators`. To enable that an `OperatorSource` has to be installed with the latest `master` version:
+
+``` shell
+cat <<EOS | kubectl apply -f -
+---
+apiVersion: operators.coreos.com/v1
+kind: OperatorSource
+metadata:
+  name: redhat-developer-operators
+  namespace: openshift-marketplace
+spec:
+  type: appregistry
+  endpoint: https://quay.io/cnr
+  registryNamespace: redhat-developer
+EOS
+```
+
+Alternatively, you can perform the same task manually using the following command before going to the Operator Hub:
+
+``` shell
+make install-service-binding-operator-source-master
+```
+
+or running the following command to install the operator completely:
+
+``` shell
+make install-service-binding-operator-master
+```
+
 #### Install the DB operator using an `OperatorSource`
 
 ##### Setup AWS Credentials
diff --git a/examples/nodejs_ibmcloud_operator/README.md b/examples/nodejs_ibmcloud_operator/README.md
index c8f8cdf5..d72b220a 100644
--- a/examples/nodejs_ibmcloud_operator/README.md
+++ b/examples/nodejs_ibmcloud_operator/README.md
@@ -24,13 +24,51 @@ but we can use the same operator to create any other service on the IBM Cloud.
 manage off-cluster service instances on IBM Cloud.
 
 #### Install the Service Binding Operator
-Navigate to `Operators`->`OperatorHub` in the OpenShift console; in the `Developer Tools` category select `Service Binding Operator`
+
+Navigate to the `Operators`->`OperatorHub` in the OpenShift console and in the `Developer Tools` category select the `Service Binding Operator` operator
 
 ![Service Binding Operator as shown in OperatorHub](../../assets/operator-hub-sbo-screenshot.png)
 
-and install an `alpha` version.
+and install the `alpha` version.
+
+Alternatively, you can perform the same task manually using the following command:
+
+``` shell
+make install-service-binding-operator-community
+```
 
-This makes the `ServiceBindingRequest` custom resource available for the application developer.
+This makes the `ServiceBindingRequest` custom resource available, that the application developer will use later.
+
+##### :bulb: Latest `master` version of the operator
+
+It is also possible to install the latest `master` version of the operator instead of the one from `community-operators`. To enable that an `OperatorSource` has to be installed with the latest `master` version:
+
+``` shell
+cat <<EOS | kubectl apply -f -
+---
+apiVersion: operators.coreos.com/v1
+kind: OperatorSource
+metadata:
+  name: redhat-developer-operators
+  namespace: openshift-marketplace
+spec:
+  type: appregistry
+  endpoint: https://quay.io/cnr
+  registryNamespace: redhat-developer
+EOS
+```
+
+Alternatively, you can perform the same task manually using the following command before going to the Operator Hub:
+
+``` shell
+make install-service-binding-operator-source-master
+```
+
+or running the following command to install the operator completely:
+
+``` shell
+make install-service-binding-operator-master
+```
 
 #### Install the IBM Cloud operator
 
diff --git a/examples/nodejs_postgresql/README.md b/examples/nodejs_postgresql/README.md
index 09d9dcc9..0631347e 100644
--- a/examples/nodejs_postgresql/README.md
+++ b/examples/nodejs_postgresql/README.md
@@ -33,16 +33,47 @@ Navigate to the `Operators`->`OperatorHub` in the OpenShift console and in the `
 
 ![Service Binding Operator as shown in OperatorHub](../../assets/operator-hub-sbo-screenshot.png)
 
-and install a `alpha` version.
+and install the `alpha` version.
 
-Alternatively, you can perform the same task with this make command:
+Alternatively, you can perform the same task manually using the following command:
 
 ``` shell
-make install-service-binding-operator
+make install-service-binding-operator-community
 ```
 
 This makes the `ServiceBindingRequest` custom resource available, that the application developer will use later.
 
+##### :bulb: Latest `master` version of the operator
+
+It is also possible to install the latest `master` version of the operator instead of the one from `community-operators`. To enable that an `OperatorSource` has to be installed with the latest `master` version:
+
+``` shell
+cat <<EOS | kubectl apply -f -
+---
+apiVersion: operators.coreos.com/v1
+kind: OperatorSource
+metadata:
+  name: redhat-developer-operators
+  namespace: openshift-marketplace
+spec:
+  type: appregistry
+  endpoint: https://quay.io/cnr
+  registryNamespace: redhat-developer
+EOS
+```
+
+Alternatively, you can perform the same task manually using the following command before going to the Operator Hub:
+
+``` shell
+make install-service-binding-operator-source-master
+```
+
+or running the following command to install the operator completely:
+
+``` shell
+make install-service-binding-operator-master
+```
+
 #### Install the DB operator using an `OperatorSource`
 
 Apply the following `OperatorSource`:
diff --git a/examples/route_k8s_resource/README.md b/examples/route_k8s_resource/README.md
new file mode 100644
index 00000000..90a3ee4b
--- /dev/null
+++ b/examples/route_k8s_resource/README.md
@@ -0,0 +1,126 @@
+# Binding an Imported app to a Route/Ingress
+
+## Introduction
+
+Binding information can be present in standalone k8s objects like routes/ingress, services, deployments too. This scenario illustrates using any resource ( CR / non-CR ) which has a spec and a status as a backing service.
+
+Binding metadata is being read from annotations on the backing service ( like CR, Route, Service, basically any kubernetes object with a spec and status, along with associated CRD or CSV.
+
+Here's how the operator resolves the binding metadata:
+
+1) Look up annotations in the CR or kubernetes resource,
+2) Look up annotations in CRD
+3) Look up descriptors in CSV ( overrides the CRD annotations ..)
+Provide cumulative annotations : (1) and (2 & 3).
+
+
+## Actions to Perform by Users in 2 Roles
+
+In this example there are 2 roles:
+
+* Cluster Admin - Installs the operator into the cluster
+* Application Developer - Imports Node.js applications, creates a Route
+
+### Cluster Admin
+
+First, let's be the cluster admin. We need to install the service binding operator in the cluster:
+
+Navigate to `Operators`->`OperatorHub` in the OpenShift console; in the `Developer Tools` category select `Service Binding Operator`
+
+![Service Binding Operator as shown in OperatorHub](../../assets/operator-hub-sbo-screenshot.png)
+
+and install an `alpha` version.
+
+This makes the `ServiceBindingRequest` custom resource available for the application developer.
+
+
+### Application Developer
+
+Now, let's play the role of an application developer. The application needs a namespace to live in so let's create one:
+
+``` shell
+cat <<EOS |kubectl apply -f -
+---
+kind: Namespace
+apiVersion: v1
+metadata:
+  name: service-binding-demo
+EOS
+```
+
+#### Import an application
+
+In this example we will import an arbitrary [Node.js application](https://github.com/pmacik/nodejs-rest-http-crud).
+
+In the OpenShift Console switch to the Developer perspective. (Make sure you have selected the `service-binding-demo` project). Navigate to the `+ADD` page from the menu and then click on the `[Import from Git]` button. Fill in the form with the following:
+
+* `Git Repo URL` = `https://github.com/pmacik/nodejs-rest-http-crud`
+* `Project` = `service-binding-demo`
+* `Application`->`Create New Application` = `NodeJSApp`
+* `Name` = `nodejs-rest-http-crud-git`
+* `Builder Image` = `Node.js`
+* `Create a route to the application` = checked
+
+and click on the `[Create]` button.
+
+#### Create a Route and annotate it:
+
+Now let's create a kubernetes resource - `Route` (for our case) and annotate it with the value that we would like to be injected for binding. For this case it is the spec.host
+
+``` shell
+cat <<EOS |kubectl apply -f -
+---
+kind: Route
+apiVersion: route.openshift.io/v1
+metadata:
+  name: example
+  namespace: service-binding-demo
+  annotations:
+    openshift.io/host.generated: 'true'
+    servicebindingoperator.redhat.io/spec.host: 'binding:env:attribute' #annotate here.
+spec:
+  host: example-sbo.apps.ci-ln-smyggvb-d5d6b.origin-ci-int-aws.dev.rhcloud.com
+  path: /
+  to:
+    kind: Service
+    name: example
+    weight: 100
+  port:
+    targetPort: 80
+  wildcardPolicy: None
+EOS
+```
+
+Now create a ServiceBindingRequest as below:
+
+``` shell
+cat <<EOS |kubectl apply -f -
+---
+apiVersion: apps.openshift.io/v1alpha1
+kind: ServiceBindingRequest
+
+metadata: 
+  name: binding-request
+  namespace: service-binding-demo
+
+spec: 
+  applicationSelector: 
+    group: ""
+    resource: deployments
+    resourceRef: nodejs-rest-http-crud-git
+    version: v1
+
+  backingServiceSelectors:                                                                                                        
+   - group: route.openshift.io
+      version: v1
+      kind: Route # <--- not NECESSARILY a CR
+      resourceRef: example 
+EOS
+```
+
+When the `ServiceBindingRequest` was created the Service Binding Operator's controller injected the Route information that was annotated to be injected into the application's `Deployment` as environment variables via an intermediate `Secret` called `binding-request`.
+
+Check the contents of `Secret` - `binding-request` by executing `oc get secrets binding-request -o yaml` for the following result:
+
+`ROUTE_HOST: example-sbo.apps.ci-ln-smyggvb-d5d6b.origin-ci-int-aws.dev.rhcloud.com`
+
diff --git a/hack/examples-commons.sh b/hack/examples-commons.sh
index e3060f4a..2f917435 100755
--- a/hack/examples-commons.sh
+++ b/hack/examples-commons.sh
@@ -36,8 +36,11 @@ function uninstall_operator_source {
 
 function get_current_csv {
     PACKAGE_NAME=$1
-    CHANNEL=$2
-    oc get packagemanifest $PACKAGE_NAME -o jsonpath='{.status.channels[?(@.name == "'$CHANNEL'")].currentCSV}'
+    CATALOG=$2
+    CHANNEL=$3
+
+    #oc get packagemanifest $PACKAGE_NAME -o jsonpath='{.status.channels[?(@.name == "'$CHANNEL'")].currentCSV}'
+    oc get packagemanifests -o json | jq -r '.items[] | select(.metadata.name=="'$PACKAGE_NAME'") | select(.status.catalogSource=="'$CATALOG'").status.channels[] | select(.name=="'$CHANNEL'").currentCSV'
 }
 
 function print_operator_subscription {
@@ -45,7 +48,7 @@ function print_operator_subscription {
     OPSRC_NAME=$2
     CHANNEL=$3
 
-    CSV_VERSION=$(get_current_csv $PACKAGE_NAME $CHANNEL)
+    CSV_VERSION=$(get_current_csv $PACKAGE_NAME $OPSRC_NAME $CHANNEL)
     sed -e 's,REPLACE_CSV_VERSION,'$CSV_VERSION',g' $HACK_YAMLS/subscription.template.yaml \
     | sed -e 's,REPLACE_CHANNEL,'$CHANNEL',g' \
     | sed -e 's,REPLACE_OPSRC_NAME,'$OPSRC_NAME',g' \
@@ -53,7 +56,7 @@ function print_operator_subscription {
 }
 
 function install_operator_subscription {
-    if [[ ! -z $(oc get packagemanifest | grep $1) ]]; then
+    if [[ ! -z $(get_current_csv $1 $2 $3) ]]; then
         print_operator_subscription $1 $2 $3 | oc apply --wait -f -
     else
         echo "ERROR: packagemanifest $1 not found";
@@ -67,8 +70,10 @@ function uninstall_operator_subscription {
 
 function wait_for_packagemanifest {
     PACKAGE_NAME=$1
+    OPSRC_NAME=$2
+    CHANNEL=$3
     i=1
-    while [[ -z "$(oc get packagemanifest | grep $PACKAGE_NAME)" ]] && [ $i -le 5 ]; do
+    while [[ -z "$(get_current_csv $1 $2 $3)" ]] && [ $i -le 10 ]; do
         echo "Waiting for package install to complete..."
         sleep 5
         i=$(($i+1))
@@ -77,9 +82,10 @@ function wait_for_packagemanifest {
 
 function uninstall_current_csv {
     PACKAGE_NAME=$1
-    CHANNEL=$2
+    OPSRC_NAME=$2
+    CHANNEL=$3
 
-    oc delete csv $(get_current_csv $PACKAGE_NAME $CHANNEL) -n openshift-operators --ignore-not-found=true
+    oc delete csv $(get_current_csv $PACKAGE_NAME $OPSRC_NAME $CHANNEL) -n openshift-operators --ignore-not-found=true
 }
 
 ## Backing DB (PostgreSQL) Operator
@@ -88,9 +94,10 @@ function install_postgresql_operator_source {
     OPSRC_NAMESPACE=pmacik
     OPSRC_NAME=db-operators
     PACKAGE_NAME=db-operators
+    CHANNEL=stable
 
     install_operator_source $OPSRC_NAMESPACE $OPSRC_NAME
-    wait_for_packagemanifest $PACKAGE_NAME
+    wait_for_packagemanifest $PACKAGE_NAME $OPSRC_NAME $CHANNEL
 }
 
 function uninstall_postgresql_operator_source {
@@ -114,7 +121,7 @@ function uninstall_postgresql_operator_subscription {
     CHANNEL=stable
 
     uninstall_operator_subscription $NAME $OPSRC_NAME $CHANNEL
-    uninstall_current_csv $NAME $CHANNEL
+    uninstall_current_csv $NAME $OPSRC_NAME $CHANNEL
 }
 
 function install_postgresql_db_instance {
@@ -127,7 +134,8 @@ function uninstall_postgresql_db_instance {
 
 ## Service Binding Operator
 
-function install_service_binding_operator_subscription {
+### Community operators
+function install_service_binding_operator_subscription_community {
     NAME=service-binding-operator
     OPSRC_NAME=community-operators
     CHANNEL=alpha
@@ -135,15 +143,52 @@ function install_service_binding_operator_subscription {
     install_operator_subscription $NAME $OPSRC_NAME $CHANNEL
 }
 
-function uninstall_service_binding_operator_subscription {
+function uninstall_service_binding_operator_subscription_community {
     NAME=service-binding-operator
     OPSRC_NAME=community-operators
     CHANNEL=alpha
 
     uninstall_operator_subscription $NAME $OPSRC_NAME $CHANNEL
-    uninstall_current_csv $NAME $CHANNEL
+    uninstall_current_csv $NAME $OPSRC_NAME $CHANNEL
+}
+
+### Latest master
+function install_service_binding_operator_source_master {
+    OPSRC_NAMESPACE=redhat-developer
+    OPSRC_NAME=redhat-developer-operators
+    PACKAGE_NAME=service-binding-operator
+    CHANNEL=alpha
+
+    install_operator_source $OPSRC_NAMESPACE $OPSRC_NAME
+    wait_for_packagemanifest $PACKAGE_NAME $OPSRC_NAME $CHANNEL
+}
+
+function uninstall_service_binding_operator_source_master {
+    OPSRC_NAMESPACE=redhat-developer
+    OPSRC_NAME=redhat-developer-operators
+
+    uninstall_operator_source $OPSRC_NAMESPACE $OPSRC_NAME
+}
+
+function install_service_binding_operator_subscription_master {
+    NAME=service-binding-operator
+    OPSRC_NAME=redhat-developer-operators
+    CHANNEL=alpha
+
+    install_operator_subscription $NAME $OPSRC_NAME $CHANNEL
+}
+
+function uninstall_service_binding_operator_subscription_master {
+    NAME=service-binding-operator
+    OPSRC_NAME=redhat-developer-operators
+    CHANNEL=alpha
+
+    uninstall_operator_subscription $NAME $OPSRC_NAME $CHANNEL
+    uninstall_current_csv $NAME $OPSRC_NAME $CHANNEL
 }
 
+
+
 ## Serverless Operator
 
 function install_serverless_operator_subscription {
@@ -160,7 +205,7 @@ function uninstall_serverless_operator_subscription {
     CHANNEL=techpreview
 
     uninstall_operator_subscription $NAME $OPSRC_NAME $CHANNEL
-    uninstall_current_csv $NAME $CHANNEL
+    uninstall_current_csv $NAME $OPSRC_NAME $CHANNEL
 }
 
 ## Service Mesh Operator
@@ -179,7 +224,7 @@ function uninstall_service_mesh_operator_subscription {
     CHANNEL=1.0
 
     uninstall_operator_subscription $NAME $OPSRC_NAME $CHANNEL
-    uninstall_current_csv $NAME $CHANNEL
+    uninstall_current_csv $NAME $OPSRC_NAME $CHANNEL
 }
 
 ## Knative Serving
diff --git a/pkg/controller/servicebindingrequest/annotations.go b/pkg/controller/servicebindingrequest/annotations.go
index 62d110dc..08e92aee 100644
--- a/pkg/controller/servicebindingrequest/annotations.go
+++ b/pkg/controller/servicebindingrequest/annotations.go
@@ -100,46 +100,69 @@ func updateUnstructuredObj(client dynamic.Interface, obj *unstructured.Unstructu
 	return err
 }
 
-// SetSBRAnnotations update existing annotations to include operator's. The annotations added are
+// SetSBRAnnotations set annotations to include SBR information and return a new object.
+func SetSBRAnnotations(namespacedName types.NamespacedName,
+	obj *unstructured.Unstructured) *unstructured.Unstructured {
+	newObj := obj.DeepCopy()
+	annotations := newObj.GetAnnotations()
+	if annotations == nil {
+		annotations = make(map[string]string)
+	}
+	annotations[sbrNamespaceAnnotation] = namespacedName.Namespace
+	annotations[sbrNameAnnotation] = namespacedName.Name
+	newObj.SetAnnotations(annotations)
+	return newObj
+}
+
+// SetAndUpdateSBRAnnotations update existing annotations to include operator's. The annotations added are
 // referring to a existing SBR namespaced name.
-func SetSBRAnnotations(
+func SetAndUpdateSBRAnnotations(
 	client dynamic.Interface,
 	namespacedName types.NamespacedName,
 	objs []*unstructured.Unstructured,
 ) error {
 	for _, obj := range objs {
-		annotations := obj.GetAnnotations()
-		if annotations == nil {
-			annotations = make(map[string]string)
-		}
-
-		annotations[sbrNamespaceAnnotation] = namespacedName.Namespace
-		annotations[sbrNameAnnotation] = namespacedName.Name
-		obj.SetAnnotations(annotations)
-
-		if err := updateUnstructuredObj(client, obj); err != nil {
+		newObj := SetSBRAnnotations(namespacedName, obj)
+		equal, err := nestedMapComparison(obj, newObj, []string{"metadata", "annotations"}...)
+		if err != nil {
 			return err
 		}
+		if !equal {
+			if err := updateUnstructuredObj(client, newObj); err != nil {
+				return err
+			}
+		}
 	}
 	return nil
 }
 
-// RemoveSBRAnnotations removes SBR related annotations from all the objects and updates them using
+// RemoveSBRAnnotations removes SBR related annotations and return a new object.
+func RemoveSBRAnnotations(obj *unstructured.Unstructured) *unstructured.Unstructured {
+	newObj := obj.DeepCopy()
+	annotations := newObj.GetAnnotations()
+	if annotations == nil {
+		annotations = make(map[string]string)
+	}
+	delete(annotations, sbrNameAnnotation)
+	delete(annotations, sbrNamespaceAnnotation)
+	newObj.SetAnnotations(annotations)
+	return newObj
+}
+
+// RemoveAndUpdateSBRAnnotations removes SBR related annotations from all the objects and updates them using
 // the given client.
-func RemoveSBRAnnotations(client dynamic.Interface, objs []*unstructured.Unstructured) error {
+func RemoveAndUpdateSBRAnnotations(client dynamic.Interface, objs []*unstructured.Unstructured) error {
 	for _, obj := range objs {
-		annotations := obj.GetAnnotations()
-		if annotations == nil {
-			annotations = make(map[string]string)
-		}
-
-		delete(annotations, sbrNameAnnotation)
-		delete(annotations, sbrNamespaceAnnotation)
-		obj.SetAnnotations(annotations)
-
-		if err := updateUnstructuredObj(client, obj); err != nil {
+		newObj := RemoveSBRAnnotations(obj)
+		equal, err := nestedMapComparison(obj, newObj, []string{"metadata", "annotations"}...)
+		if err != nil {
 			return err
 		}
+		if !equal {
+			if err := updateUnstructuredObj(client, newObj); err != nil {
+				return err
+			}
+		}
 	}
 	return nil
 }
diff --git a/pkg/controller/servicebindingrequest/binding.go b/pkg/controller/servicebindingrequest/binding.go
index 760db507..5f7f3b21 100644
--- a/pkg/controller/servicebindingrequest/binding.go
+++ b/pkg/controller/servicebindingrequest/binding.go
@@ -115,7 +115,7 @@ func (b *ServiceBinder) Unbind() (reconcile.Result, error) {
 	logger := b.Logger.WithName("Unbind")
 
 	logger.Info("Cleaning related objects from operator's annotations...")
-	if err := RemoveSBRAnnotations(b.DynClient, b.Objects); err != nil {
+	if err := RemoveAndUpdateSBRAnnotations(b.DynClient, b.Objects); err != nil {
 		logger.Error(err, "On removing annotations from related objects.")
 		return RequeueError(err)
 	}
@@ -236,7 +236,7 @@ func (b *ServiceBinder) Bind() (reconcile.Result, error) {
 
 	// annotating objects related to binding
 	namespacedName := types.NamespacedName{Namespace: b.SBR.GetNamespace(), Name: b.SBR.GetName()}
-	if err = SetSBRAnnotations(b.DynClient, namespacedName, append(b.Objects, secretObj)); err != nil {
+	if err = SetAndUpdateSBRAnnotations(b.DynClient, namespacedName, append(b.Objects, secretObj)); err != nil {
 		b.Logger.Error(err, "On setting annotations in related objects.")
 		return b.onError(err, b.SBR, sbrStatus, updatedObjects)
 	}


Test patch:
diff --git a/pkg/controller/servicebindingrequest/annotations_test.go b/pkg/controller/servicebindingrequest/annotations_test.go
index 0e3668fa..857ee7db 100644
--- a/pkg/controller/servicebindingrequest/annotations_test.go
+++ b/pkg/controller/servicebindingrequest/annotations_test.go
@@ -105,7 +105,55 @@ func TestAnnotationsSetAndRemoveSBRAnnotations(t *testing.T) {
 	objs = append(objs, u)
 
 	t.Run("SetSBRAnnotations", func(t *testing.T) {
-		err := SetSBRAnnotations(client, namespacedName, objs)
+		originCopy := u.DeepCopy()
+		newObj := SetSBRAnnotations(namespacedName, u)
+
+		// we are not modifying the origin object
+		equal, err := nestedMapComparison(u, originCopy)
+		require.NoError(t, err)
+		require.True(t, equal)
+
+		equal, err = nestedMapComparison(u, newObj, []string{"metadata", "annotations"}...)
+		require.NoError(t, err)
+		require.False(t, equal)
+
+		objNamespacedName, err := GetSBRNamespacedNameFromObject(newObj)
+		require.NoError(t, err)
+		require.Equal(t, namespacedName, objNamespacedName)
+
+		// assert nothing else is changed
+		newObj.SetAnnotations(nil)
+		equal, err = nestedMapComparison(u, newObj)
+		require.NoError(t, err)
+		require.True(t, equal)
+	})
+
+	t.Run("RemoveSBRAnnotations", func(t *testing.T) {
+		originCopy := u.DeepCopy()
+		newObj := RemoveSBRAnnotations(u)
+
+		// we are not modifying the origin object
+		equal, err := nestedMapComparison(u, originCopy)
+		require.NoError(t, err)
+		require.True(t, equal)
+
+		equal, err = nestedMapComparison(u, newObj, []string{"metadata", "annotations"}...)
+		require.NoError(t, err)
+		require.False(t, equal)
+
+		objNamespacedName, err := GetSBRNamespacedNameFromObject(newObj)
+		require.NoError(t, err)
+		require.Equal(t, types.NamespacedName{}, objNamespacedName)
+
+		// assert nothing else is changed
+		newObj.SetAnnotations(u.GetAnnotations())
+		equal, err = nestedMapComparison(u, newObj)
+		require.NoError(t, err)
+		require.True(t, equal)
+	})
+
+	t.Run("SetAndUpdateSBRAnnotations", func(t *testing.T) {
+		err := SetAndUpdateSBRAnnotations(client, namespacedName, objs)
 		require.NoError(t, err)
 
 		u, err := deploymentResource.Get(ns, metav1.GetOptions{})
@@ -116,8 +164,8 @@ func TestAnnotationsSetAndRemoveSBRAnnotations(t *testing.T) {
 		require.Equal(t, namespacedName, objNamespacedName)
 	})
 
-	t.Run("RemoveSBRAnnotations", func(t *testing.T) {
-		err := RemoveSBRAnnotations(client, objs)
+	t.Run("RemoveAndUpdateSBRAnnotations", func(t *testing.T) {
+		err := RemoveAndUpdateSBRAnnotations(client, objs)
 		require.NoError(t, err)
 
 		u, err := deploymentResource.Get(ns, metav1.GetOptions{})