Repository: redhat-developer/service-binding-operator
Pull request #1040 (2021-10-04 16:24:17)

Add support for Opstree Redis operator-backed services
Provisioned `redis.redis.opstreelabs.in/v1beta1`/`Redis` instances are bindable out of the box, exposing following binding data:
* type (always set to 'redis')
* host
* password

In order to expose `type`, support for binding constant has been added. Namely, if a service binding annotation value does not specify `path`,
then the annotation value is used as the binding value. With that it is possible to state something like this:

```
service.binding/type: redis
```

Unit and acceptance tests have been added to verify the introduced behavior.



Solves indirectly #843

openshift-ci[bot]: [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 ask for approval from **pedjak** after the PR has been reviewed.

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":["pedjak"]} -->
openshift-ci[bot]: @pedjak: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
ci/prow/4.9-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.9-acceptance/1445073025555763200) | true | `/test 4.9-acceptance`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=redhat-developer&repo=service-binding-operator&pr=1040). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:pedjak).

<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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci[bot]: @pedjak: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
ci/prow/4.9-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.9-acceptance/1445073025555763200) | true | `/test 4.9-acceptance`
ci/prow/4.6-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.6-acceptance/1445073017976655872) | true | `/test 4.6-acceptance`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=redhat-developer&repo=service-binding-operator&pr=1040). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:pedjak).

<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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci[bot]: @pedjak: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
ci/prow/4.9-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.9-acceptance/1445073025555763200) | true | `/test 4.9-acceptance`
ci/prow/4.6-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.6-acceptance/1445073017976655872) | true | `/test 4.6-acceptance`
ci/prow/4.7-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.7-acceptance/1445073020493238272) | true | `/test 4.7-acceptance`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=redhat-developer&repo=service-binding-operator&pr=1040). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:pedjak).

<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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci[bot]: @pedjak: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
ci/prow/4.9-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.9-acceptance/1445073025555763200) | true | `/test 4.9-acceptance`
ci/prow/4.6-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.6-acceptance/1445073017976655872) | true | `/test 4.6-acceptance`
ci/prow/4.7-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.7-acceptance/1445073020493238272) | true | `/test 4.7-acceptance`
ci/prow/4.8-acceptance | 9b36e0511efc95b04e399092bbda08e4ec3bc2d5 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/redhat-developer_service-binding-operator/1040/pull-ci-redhat-developer-service-binding-operator-master-4.8-acceptance/1445073023177592832) | true | `/test 4.8-acceptance`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=redhat-developer&repo=service-binding-operator&pr=1040). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:pedjak).

<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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
codecov[bot]: # [Codecov](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer) Report
> Merging [#1040](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer) (b762e6b) into [master](https://codecov.io/gh/redhat-developer/service-binding-operator/commit/fe66266d0b3477d387ca0291b22c80aea4f53055?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer) (fe66266) will **increase** coverage by `0.68%`.
> The diff coverage is `50.00%`.

[![Impacted file tree graph](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040/graphs/tree.svg?width=650&height=150&src=pr&token=CICBeVWlrC&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer)](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer)

```diff
@@            Coverage Diff             @@
##           master    #1040      +/-   ##
==========================================
+ Coverage   56.98%   57.67%   +0.68%     
==========================================
  Files          29       29              
  Lines        1653     1642      -11     
==========================================
+ Hits          942      947       +5     
+ Misses        584      568      -16     
  Partials      127      127              
```


| [Impacted Files](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer) | Coverage Δ | |
|---|---|---|
| [pkg/binding/definition.go](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer#diff-cGtnL2JpbmRpbmcvZGVmaW5pdGlvbi5nbw==) | `45.31% <0.00%> (-2.23%)` | :arrow_down: |
| [pkg/binding/annotationmapper.go](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer#diff-cGtnL2JpbmRpbmcvYW5ub3RhdGlvbm1hcHBlci5nbw==) | `87.50% <100.00%> (+0.15%)` | :arrow_up: |
| [pkg/binding/model.go](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer#diff-cGtnL2JpbmRpbmcvbW9kZWwuZ28=) | `90.19% <100.00%> (+2.69%)` | :arrow_up: |
| [apis/binding/v1alpha1/servicebinding\_webhook.go](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer#diff-YXBpcy9iaW5kaW5nL3YxYWxwaGExL3NlcnZpY2ViaW5kaW5nX3dlYmhvb2suZ28=) | `41.66% <0.00%> (+26.51%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer). Last update [fe66266...b762e6b](https://codecov.io/gh/redhat-developer/service-binding-operator/pull/1040?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=redhat-developer).

openshift-ci[bot]: New changes are detected. LGTM label has been removed.
openshift-ci[bot]: [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 ask for approval from **baijum** after the PR has been reviewed.

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":["baijum"]} -->
sadlerap: /lgtm
/approve
openshift-ci[bot]: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/redhat-developer/service-binding-operator/pull/1040#issuecomment-934717388" title="Approved">sadlerap</a>*

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).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

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

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":[]} -->

Patch:
diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml
index 2d7c4453..cb584674 100644
--- a/config/rbac/kustomization.yaml
+++ b/config/rbac/kustomization.yaml
@@ -10,6 +10,8 @@ resources:
 - bindablekinds_viewer_rolebinding.yaml
 - servicebinding_controller_role.yaml
 - servicebinding_controller_rolebinding.yaml
+# operators supproted out of the box
+- opstree_redis_clusterrole.yaml
 # Comment the following 4 lines if you want to disable
 # the auth proxy (https://github.com/brancz/kube-rbac-proxy)
 # which protects your /metrics endpoint.
diff --git a/config/rbac/opstree_redis_clusterrole.yaml b/config/rbac/opstree_redis_clusterrole.yaml
new file mode 100644
index 00000000..74611d6c
--- /dev/null
+++ b/config/rbac/opstree_redis_clusterrole.yaml
@@ -0,0 +1,14 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: opstree-redis-viewer-role
+  labels:
+    servicebinding.io/controller: "true"
+rules:
+  - apiGroups:
+      - redis.redis.opstreelabs.in
+    resources:
+      - redis
+    verbs:
+      - get
+      - list
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index dcebeec7..e3406fbc 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -38,6 +38,8 @@ rules:
   verbs:
   - get
   - list
+  - patch
+  - update
   - watch
 - apiGroups:
   - apps
diff --git a/controllers/crd/crd_controller.go b/controllers/crd/crd_controller.go
index 17810478..85f4b2be 100644
--- a/controllers/crd/crd_controller.go
+++ b/controllers/crd/crd_controller.go
@@ -24,6 +24,7 @@ import (
 	"github.com/redhat-developer/service-binding-operator/pkg/client/kubernetes"
 	"github.com/redhat-developer/service-binding-operator/pkg/converter"
 	"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/service"
+	"github.com/redhat-developer/service-binding-operator/pkg/util"
 	v1apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -35,6 +36,14 @@ import (
 	"sync"
 )
 
+var bindingAnnotations = map[schema.GroupVersionKind]map[string]string{
+	schema.GroupVersionKind{Group: "redis.redis.opstreelabs.in", Version: "v1beta1", Kind: "Redis"}: {
+		"service.binding/type":     "redis",
+		"service.binding/host":     "path={.metadata.name}",
+		"service.binding/password": "path={.spec.kubernetesConfig.redisSecret.name},objectType=Secret,sourceKey=password",
+	},
+}
+
 // CrdReconciler reconciles a CustomResourceDefinition resources
 type CrdReconciler struct {
 	client.Client
@@ -47,7 +56,7 @@ type CrdReconciler struct {
 // +kubebuilder:rbac:groups=binding.operators.coreos.com,resources=bindablekinds,verbs=get;list;watch;create;update;patch;delete
 // +kubebuilder:rbac:groups=binding.operators.coreos.com,resources=bindablekinds/status,verbs=get;update;patch
 // +kubebuilder:rbac:groups=binding.operators.coreos.com,resources=bindablekinds/finalizers,verbs=update
-// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch
+// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch;update;patch
 
 // Reconcile is part of the main kubernetes reconciliation loop which aims to
 // move the current state of the cluster closer to the desired state.
@@ -75,10 +84,13 @@ func (r *CrdReconciler) Reconcile(req ctrl.Request) (reconcileResult ctrl.Result
 		return ctrl.Result{}, err
 	}
 
+	toPersist := false
+
 	for i := range crd.Spec.Versions {
 		gvk := schema.GroupVersionKind{Group: crd.Spec.Group, Kind: crd.Spec.Names.Kind, Version: crd.Spec.Versions[i].Name}
 		if !crd.GetDeletionTimestamp().IsZero() {
 			r.bindableKinds.Delete(gvk)
+			toPersist = true
 			continue
 		}
 		fakeServiceContent := &unstructured.Unstructured{}
@@ -96,10 +108,27 @@ func (r *CrdReconciler) Reconcile(req ctrl.Request) (reconcileResult ctrl.Result
 		}
 		if bindable {
 			r.bindableKinds.Store(gvk, true)
+			toPersist = true
 			log.Info("bindable", "gvk", gvk)
+		} else {
+			annotations, found := bindingAnnotations[gvk]
+			if found {
+				log.Info("Found bindable annotations", "gvk", gvk, "annotations", annotations)
+				crd.SetAnnotations(util.MergeMaps(crd.GetAnnotations(), annotations))
+				err := r.Update(ctx, crd)
+				if err != nil {
+					log.Error(err, "Error updating CRD")
+					return ctrl.Result{}, err
+				}
+				log.Info("Annotations applied")
+			}
 		}
 	}
 
+	if !toPersist {
+		log.Info("Done")
+		return ctrl.Result{}, nil
+	}
 	bk := &bindingapi.BindableKinds{}
 	err = r.Get(ctx, client.ObjectKey{Name: "bindable-kinds"}, bk)
 	if err != nil {
diff --git a/pkg/binding/annotationmapper.go b/pkg/binding/annotationmapper.go
index 67b31f95..91018f50 100644
--- a/pkg/binding/annotationmapper.go
+++ b/pkg/binding/annotationmapper.go
@@ -34,6 +34,7 @@ const (
 	elementTypeModelKey             modelKey = "elementType"
 	AnnotationPrefix                         = "service.binding"
 	ProvisionedServiceAnnotationKey          = "servicebinding.io/provisioned-service"
+	TypeKey                                  = AnnotationPrefix + "/type"
 )
 
 func NewDefinitionBuilder(annotationName string, annotationValue string, configMapReader UnstructuredResourceReader, secretReader UnstructuredResourceReader) *annotationBackedDefinitionBuilder {
@@ -95,9 +96,10 @@ func (m *annotationBackedDefinitionBuilder) Build() (Definition, error) {
 	}
 
 	switch {
-	case mod.isStringElementType() && mod.isStringObjectType():
+	case (mod.isStringElementType() && mod.isStringObjectType()) || mod.value != "":
 		return &stringDefinition{
 			outputName: outputName,
+			value:      mod.value,
 			definition: definition{
 				path: mod.path,
 			},
diff --git a/pkg/binding/definition.go b/pkg/binding/definition.go
index d0673b3e..986aa4ff 100644
--- a/pkg/binding/definition.go
+++ b/pkg/binding/definition.go
@@ -4,7 +4,6 @@ import (
 	"encoding/base64"
 	"errors"
 	"fmt"
-
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 )
 
@@ -56,6 +55,7 @@ func (d *definition) GetPath() string {
 
 type stringDefinition struct {
 	outputName string
+	value      string
 	definition
 }
 
@@ -65,6 +65,13 @@ func (d *stringDefinition) Apply(u *unstructured.Unstructured) (Value, error) {
 	if d.outputName == "" {
 		return nil, fmt.Errorf("cannot use generic service.binding annotation for string elements, need to specify binding key like service.binding/foo")
 	}
+	if d.value != "" {
+		return &value{
+			v: map[string]interface{}{
+				d.outputName: d.value,
+			},
+		}, nil
+	}
 	val, err := getValuesByJSONPath(u.Object, d.path)
 	if err != nil {
 		return nil, err
diff --git a/pkg/binding/model.go b/pkg/binding/model.go
index 58a0e8f6..c9bad704 100644
--- a/pkg/binding/model.go
+++ b/pkg/binding/model.go
@@ -12,7 +12,7 @@ type model struct {
 	objectType  objectType
 	sourceKey   string
 	sourceValue string
-	bindAs      BindingType
+	value       string
 }
 
 func (m *model) isStringElementType() bool {
@@ -58,6 +58,11 @@ func newModel(annotationValue string) (*model, error) {
 	// assert PathModelKey is present
 	path, found := raw[pathModelKey]
 	if !found {
+		if len(raw) == 0 {
+			return &model{
+				value: annotationValue,
+			}, nil
+		}
 		return nil, fmt.Errorf("path not found: %q", annotationValue)
 	}
 	if !strings.HasPrefix(path, "{") || !strings.HasSuffix(path, "}") {
@@ -120,6 +125,5 @@ func newModel(annotationValue string) (*model, error) {
 		objectType:  objType,
 		sourceValue: sourceValue,
 		sourceKey:   sourceKey,
-		bindAs:      TypeEnvVar,
 	}, nil
 }


Test patch:
diff --git a/hack/get-test-namespace b/hack/get-test-namespace
index ad543134..c8b29ff3 100755
--- a/hack/get-test-namespace
+++ b/hack/get-test-namespace
@@ -33,6 +33,6 @@ uuid()
 
 mkdir -p "$OUTPUT_DIR"
 
-[ -f "$NS_FILE" ] || echo "test-namespace-$(uuid | cut -d '-' -f 5)" > "$NS_FILE"
+[ -f "$NS_FILE" ] || echo "test-ns-$(uuid | cut -d '-' -f 5 | cut -c -4)" > "$NS_FILE"
 
 cat "$NS_FILE"
\ No newline at end of file
diff --git a/pkg/binding/annotationmapper_test.go b/pkg/binding/annotationmapper_test.go
index 8d693444..5f7de695 100644
--- a/pkg/binding/annotationmapper_test.go
+++ b/pkg/binding/annotationmapper_test.go
@@ -85,6 +85,17 @@ func TestAnnotationBackedBuilderValidAnnotations(t *testing.T) {
 				},
 			},
 		},
+		{
+			description: "value definition",
+			builder: &annotationBackedDefinitionBuilder{
+				name:  "service.binding/type",
+				value: "foo",
+			},
+			expectedValue: &stringDefinition{
+				outputName: "type",
+				value:      "foo",
+			},
+		},
 		{
 			description: "Ignore non-service binding annotations",
 			builder: &annotationBackedDefinitionBuilder{
diff --git a/pkg/binding/definition_test.go b/pkg/binding/definition_test.go
index d666eb98..901541c9 100644
--- a/pkg/binding/definition_test.go
+++ b/pkg/binding/definition_test.go
@@ -13,6 +13,7 @@ func TestStringDefinition(t *testing.T) {
 		description   string
 		outputName    string
 		path          string
+		value         string
 		expectedValue interface{}
 	}
 
@@ -33,6 +34,14 @@ func TestStringDefinition(t *testing.T) {
 				"anotherName": "AzureDiamond",
 			},
 		},
+		{
+			description: "raw value",
+			outputName:  "foo",
+			value:       "bar",
+			expectedValue: map[string]interface{}{
+				"foo": "bar",
+			},
+		},
 	}
 
 	u := &unstructured.Unstructured{
@@ -52,6 +61,7 @@ func TestStringDefinition(t *testing.T) {
 				definition: definition{
 					path: tc.path,
 				},
+				value: tc.value,
 			}
 			val, err := d.Apply(u)
 			require.NoError(t, err)
diff --git a/test/acceptance/features/steps/olm.py b/test/acceptance/features/steps/olm.py
index 8edef74f..16e440f3 100644
--- a/test/acceptance/features/steps/olm.py
+++ b/test/acceptance/features/steps/olm.py
@@ -29,10 +29,11 @@ class Operator(object):
             return False
 
     def install_catalog_source(self):
-        install_src_output = self.openshift.create_catalog_source(self.operator_catalog_source_name, self.operator_catalog_image)
-        if re.search(r'.*catalogsource.operators.coreos.com/%s\s(unchanged|created)' % self.operator_catalog_source_name, install_src_output) is None:
-            print("Failed to create {} catalog source".format(self.operator_catalog_source_name))
-            return False
+        if self.operator_catalog_image != "":
+            install_src_output = self.openshift.create_catalog_source(self.operator_catalog_source_name, self.operator_catalog_image)
+            if re.search(r'.*catalogsource.operators.coreos.com/%s\s(unchanged|created)' % self.operator_catalog_source_name, install_src_output) is None:
+                print("Failed to create {} catalog source".format(self.operator_catalog_source_name))
+                return False
         return self.openshift.wait_for_package_manifest(self.package_name, self.operator_catalog_source_name, self.operator_catalog_channel)
 
     def install_operator_subscription(self):
diff --git a/test/acceptance/features/steps/redisoperator.py b/test/acceptance/features/steps/redisoperator.py
new file mode 100644
index 00000000..3a4514b3
--- /dev/null
+++ b/test/acceptance/features/steps/redisoperator.py
@@ -0,0 +1,24 @@
+from olm import Operator
+from environment import ctx
+from behave import given
+
+
+class RedisOperator(Operator):
+
+    def __init__(self, name="redis-operator"):
+        self.name = name
+        if ctx.cli == "oc":
+            self.operator_catalog_source_name = "community-operators"
+        else:
+            self.operator_catalog_source_name = "operatorhubio-catalog"
+        self.operator_catalog_channel = "stable"
+        self.package_name = name
+
+
+@given(u'Opstree Redis operator is running')
+def install_redis_operator(_context):
+    operator = RedisOperator()
+    if not operator.is_running():
+        operator.install_operator_subscription()
+        operator.is_running(wait=True)
+    print("Opstree Redis operator is running")
diff --git a/test/acceptance/features/supportExistingOperatorBackedServices.feature b/test/acceptance/features/supportExistingOperatorBackedServices.feature
new file mode 100644
index 00000000..cd8199e0
--- /dev/null
+++ b/test/acceptance/features/supportExistingOperatorBackedServices.feature
@@ -0,0 +1,89 @@
+@olm
+Feature: Support a number of existing operator-backed services out of the box
+
+  As a user of Service Binding operator
+  I would like to be able to bind my application to a number of existing operator-backed services
+  without a need to tweak their k8s resources
+
+  Background:
+    Given Namespace [TEST_NAMESPACE] is used
+    * Service Binding Operator is running
+
+  Scenario: Bind test application to Redis instance provisioned by Opstree Redis operator
+    Given Opstree Redis operator is running
+    * Generic test application is running
+    * The Secret is present
+            """
+            apiVersion: v1
+            kind: Secret
+            metadata:
+                name: redis-secret
+            stringData:
+                password: redisSecret!
+            """
+
+    * The Custom Resource is present
+          """
+          apiVersion: redis.redis.opstreelabs.in/v1beta1
+          kind: Redis
+          metadata:
+            name: redis-standalone
+          spec:
+            kubernetesConfig:
+              image: quay.io/opstree/redis:v6.2.5
+              imagePullPolicy: IfNotPresent
+              resources:
+                requests:
+                  cpu: 101m
+                  memory: 128Mi
+                limits:
+                  cpu: 101m
+                  memory: 128Mi
+              serviceType: ClusterIP
+              redisSecret:
+                name: redis-secret
+                key: password
+            storage:
+              volumeClaimTemplate:
+                spec:
+                  # storageClassName: standard
+                  accessModes: ["ReadWriteOnce"]
+                  resources:
+                    requests:
+                      storage: 1Gi
+            redisExporter:
+              enabled: false
+              image: quay.io/opstree/redis-exporter:1.0
+          """
+    When Service Binding is applied
+          """
+          apiVersion: binding.operators.coreos.com/v1alpha1
+          kind: ServiceBinding
+          metadata:
+              name: $scenario_id
+          spec:
+              services:
+              - group: redis.redis.opstreelabs.in
+                version: v1beta1
+                kind: Redis
+                name: redis-standalone
+              application:
+                name: $scenario_id
+                group: apps
+                version: v1
+                resource: deployments
+          """
+    Then Service Binding is ready
+    And Kind Redis with apiVersion redis.redis.opstreelabs.in/v1beta1 is listed in bindable kinds
+    And Content of file "/bindings/$scenario_id/type" in application pod is
+           """
+           redis
+           """
+    And Content of file "/bindings/$scenario_id/host" in application pod is
+           """
+           redis-standalone
+           """
+    And Content of file "/bindings/$scenario_id/password" in application pod is
+           """
+           redisSecret!
+           """
\ No newline at end of file