Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service binding global and service envVarPrefix doesn't behave as expected #475

Closed
qibobo opened this issue May 18, 2020 · 27 comments · Fixed by #515
Closed

Service binding global and service envVarPrefix doesn't behave as expected #475

qibobo opened this issue May 18, 2020 · 27 comments · Fixed by #515
Assignees
Labels
kind/bug Something isn't working v0.3.0

Comments

@qibobo
Copy link
Contributor

qibobo commented May 18, 2020

According to our latest test, there are some features broken after #407 is merged.

Below is the SBR and the environment result.

cat <<EOF | kubectl apply -f -
apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest 
metadata:
  name: sbr5
spec:
  envVarPrefix: globalprefix
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments 
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
      envVarPrefix: prefix1
  customEnvVar:
    - name: ALL_SECRET
      value: '{{json .}}'
EOF

Env var result:

GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_IAM_ROLE_CRN=crn:v1:bluemix:public:iam::::serviceRole:Manager
GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_IAM_APIKEY_DESCRIPTION=Auto-generated for key 0aef56aa-fbb2-4dd7-8bc7-972302e14573
GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_APIKEY=xxxxx
globalprefix_ALL_SECRET={"v1alpha1":{"ibmcloud.ibm.com":{"Binding":{"thetranslator5":{"apiVersion":"ibmcloud.ibm.com/v1alpha1","kind":"Binding","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n","service-binding-operator.apps.openshift.io/binding-name":"sbr5","service-binding-operator.apps.openshift.io/binding-namespace":"default"},"creationTimestamp":"2020-05-14T08:55:22Z","finalizers":["binding.ibmcloud.ibm.com"],"generation":1,"name":"thetranslator5","namespace":"default","ownerReferences":[{"apiVersion":"ibmcloud.ibm.com/v1alpha1","blockOwnerDeletion":true,"controller":true,"kind":"Service","name":"thetranslator5","uid":"a6adaa6b-94ae-421f-8698-1e9ec2b48e64"}],"resourceVersion":"4439896","selfLink":"/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5","uid":"e07c5c19-25d8-4016-add9-213366b4259c"},"spec":{"serviceName":"thetranslator5"},"status":{"instanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::","keyInstanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573","message":"Online","secretName":"thetranslator5","state":"Online"}}}},"ibmcloud_ibm_com":{"Binding":{"thetranslator5":{"apiVersion":"ibmcloud.ibm.com/v1alpha1","kind":"Binding","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n","service-binding-operator.apps.openshift.io/binding-name":"sbr5","service-binding-operator.apps.openshift.io/binding-namespace":"default"},"creationTimestamp":"2020-05-14T08:55:22Z","finalizers":["binding.ibmcloud.ibm.com"],"generation":1,"name":"thetranslator5","namespace":"default","ownerReferences":[{"apiVersion":"ibmcloud.ibm.com/v1alpha1","blockOwnerDeletion":true,"controller":true,"kind":"Service","name":"thetranslator5","uid":"a6adaa6b-94ae-421f-8698-1e9ec2b48e64"}],"resourceVersion":"4439896","selfLink":"/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5","uid":"e07c5c19-25d8-4016-add9-213366b4259c"},"spec":{"serviceName":"thetranslator5"},"status":{"instanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::","keyInstanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573","message":"Online","secretName":"thetranslator5","state":"Online"}}}}}}
GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_IAM_SERVICEID_CRN=crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044
GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_IAM_APIKEY_NAME=thetranslator5
GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973

There are 3 issues I have found:

1 There are prefixes BINDING_SECRET_STATUS for all env vars, but previously we do not have them.
2 With the custom env var ALL_SECRET, there is only secretName in the result content, but previously the content of the secret should be in the content.

@qibobo
Copy link
Contributor Author

qibobo commented May 18, 2020

@isutton I can provide a PR for this issue.

@isutton
Copy link
Contributor

isutton commented May 18, 2020

@qibobo I believe we've implemented all the logic required from #428 (it had to be re-implemented in #407 due to the changes of internals), but I might've been wrong and instead misunderstood this table; so thanks for offering to contribute this one 👍.

Here is the function responsible for deciding how to prefix an environment variable according to the combination of global prefix and service prefix, according to the table found in #428:

https://github.com/isutton/service-binding-operator/blob/179c2fb40bb274eeacace087320b00154a6d0e48/pkg/controller/servicebindingrequest/retriever.go#L35-L48

Here you can find the test cases:

https://github.com/isutton/service-binding-operator/blob/179c2fb40bb274eeacace087320b00154a6d0e48/pkg/controller/servicebindingrequest/retriever_test.go#L66

Thanks a lot!

@qibobo
Copy link
Contributor Author

qibobo commented May 18, 2020

@isutton
I have updated the issue. Do you agree for the left two issues?

@isutton isutton changed the title Some behavior are broken in latest master Service binding global and service envVarPrefix doesn't behave as expected May 18, 2020
@isutton
Copy link
Contributor

isutton commented May 18, 2020

@isutton
I have updated the issue. Do you agree for the left two issues?

I'll reply to each point in a different comment, if you don't mind.

Regarding point 1 I believe we should split an environment variable to find out where does each part come from in the environment variable name
GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_IAM_ROLE_CRN:

  • GLOBALPREFIX is present because the .spec.envVarPrefix is declared;
  • PREFIX1 is present because spec.backingServiceSelectors.0.envVarPrefix is declared;
  • BINDING is present because it is the service's kind;
  • SECRET is present because the value was collected out of a v1.Secret (or a v1.ConfigMap);
  • STATUS_SECRETNAME is the path in the Binding resource where the a secret name can be found; and
  • IAM_ROLE_CRN is a leaf in the secret referred in Binding's .spec.status.secretName.

This, in my point of view, is not really an issue but a side-effect of allowing multiple services to be declared and at the same time using the service kind in the strategy to disambiguate values from similar services.

Let's take a look ath the following example, where different services are disambiguated by the usage of envVarPrefix:

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: sbr5
spec:
  envVarPrefix: globalprefix
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments 
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: binding1
      envVarPrefix: prefix1
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: binding2
      envVarPrefix: prefix2
  customEnvVar:
    - name: ALL_SECRET
      value: '{{json .}}'

The configuration above should yield the following environment variables:

GLOBALPREFIX_PREFIX1_BINDING_SECRET_STATUS_SECRETNAME_IAM_ROLE_CRN
GLOBALPREFIX_PREFIX2_BINDING_SECRET_STATUS_SECRETNAME_IAM_ROLE_CRN

Of course, this scheme can be modified to better serve us, it was used as a start point :)

What do you think?

@isutton
Copy link
Contributor

isutton commented May 18, 2020

@isutton
I have updated the issue. Do you agree for the left two issues?

There are two points I'd like to clarify with you, regarding the ALL_SECRET variable in your example:

  1. What is expected to exist in the . context in {{ json . }}? As a thought experiment, I believe that expression is meant to serialize metadata regarding the services, not regarding the template context

    If this is indeed true, then it should be straightforward to create another "bucket" in the context to hold services metadata, for example in a field called allServices as seen in the following example {{ json .allServices }} by adapting the ServiceContext type and serializing it with the proper format.

  2. Only configuration values declared either by OLM integration, annotations in the service's CRD or CR have been added to the template context.

    I've opted for a white-list approach since changes required to contribute a value requires authorization to either install the OLM's resources, or modify those resources mentioned above.

    I'm good if this is not the right approach, but I believe a discussion regarding how services contribute values to the template engine should be had then, so we are aware of any security implications that might come.

What do you think?

@qibobo
Copy link
Contributor Author

qibobo commented May 18, 2020

@isutton
1 For env_var_prefix, by global_env_var_prefix and service_env_var_prefix, we can distinguish multiple backing services. And with the BINDING_SECRET_STATUS_SECRETNAME, the env_var will be too long. I prefer to not add it.

2 For the custom env var, based on the example below, once we add theidto backing-service, we can use the id in custom env var template. For VCAP_SERVICES, we want the secret content to be injected, rather than just the secret name.

- name: VCAP_SERVICES
  value: '{"language-translator":[{"credentials":{{json .xxx.status.secretName}},"name":"thetranslator5","plan":"standard"}]}'
apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: sbr5
spec:
  envVarPrefix: globalprefix
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments 
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
      id: xxx
      envVarPrefix: prefix1
  customEnvVar:
    - name: VCAP_SERVICES
      value: '{"language-translator":[{"credentials":{{json .xxx.status.secretName}},"name":"thetranslator5","plan":"standard"}]}'
    - name: TRANSLATOR_NAME
      value: "thetranslator5"
    - name: ALL_SECRET
      value: '{{json .}}'

@sbose78
Copy link
Member

sbose78 commented May 18, 2020

Ideally, we should not have the KIND_STATUS substring in env vars at all since typically apps don't have env vars which look like that :) We had initially introduced it, we should gradually deprecate it - and update our sample projects.
#428 was a soft way to do so

My proposed next steps:

  • the behaviour we had in master should definitely be restored, if service level prefix is present, skip KIND_STATUS, else preserve existing behaviour.

As part of the same fix/effort, we could address

  • Either, remove KIND_STATUS completely.
  • Or, postpone it with a wider discussion

@qibobo
Copy link
Contributor Author

qibobo commented May 19, 2020

@isutton @sbose78
I've done a test for behaviors that before and after PR407 is merged.
The SBR:

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: sbr5
spec:
  envVarPrefix: globalprefix
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments 
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
      envVarPrefix: prefix1
  customEnvVar:
    - name: TRANSLATOR_NAME
      value: "thetranslator5"
    - name: ALL_SECRET
      value: '{{json .}}'

The result before PR407:

TRANSLATOR_NAME=thetranslator5
GLOBALPREFIX_PREFIX1_SECRET_APIKEY=XXXX
ALL_SECRET={"status":{"instanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::","keyInstanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573","message":"Online","secretName":{"apikey":"XXXX","iam_apikey_description":"Auto-generated for key 0aef56aa-fbb2-4dd7-8bc7-972302e14573","iam_apikey_name":"thetranslator5","iam_role_crn":"crn:v1:bluemix:public:iam::::serviceRole:Manager","iam_serviceid_crn":"crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044","url":"https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"},"state":"Online","status.secretName":{}}}
GLOBALPREFIX_PREFIX1_SECRET_IAM_SERVICEID_CRN=crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044
GLOBALPREFIX_PREFIX1_SECRET_IAM_APIKEY_DESCRIPTION=Auto-generated for key 0aef56aa-fbb2-4dd7-8bc7-972302e14573
GLOBALPREFIX_PREFIX1_SECRET_URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973
VCAP_SERVICES={"language-translator":[{"credentials":null,"name":"thetranslator5","plan":"standard"}]}
GLOBALPREFIX_PREFIX1_SECRET_IAM_ROLE_CRN=crn:v1:bluemix:public:iam::::serviceRole:Manager
GLOBALPREFIX_PREFIX1_SECRET_IAM_APIKEY_NAME=thetranslator5

The result after PR407:

GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973
globalprefix_VCAP_SERVICES={"language-translator":[{"credentials":null,"name":"thetranslator5","plan":"standard"}]}
GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_APIKEY=XXXX
globalprefix_TRANSLATOR_NAME=thetranslator5
globalprefix_ALL_SECRET={"v1alpha1":{"ibmcloud.ibm.com":{"Binding":{"thetranslator5":{"apiVersion":"ibmcloud.ibm.com/v1alpha1","kind":"Binding","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n","service-binding-operator.apps.openshift.io/binding-name":"sbr5","service-binding-operator.apps.openshift.io/binding-namespace":"default"},"creationTimestamp":"2020-05-14T08:55:22Z","finalizers":["binding.ibmcloud.ibm.com"],"generation":1,"name":"thetranslator5","namespace":"default","ownerReferences":[{"apiVersion":"ibmcloud.ibm.com/v1alpha1","blockOwnerDeletion":true,"controller":true,"kind":"Service","name":"thetranslator5","uid":"a6adaa6b-94ae-421f-8698-1e9ec2b48e64"}],"resourceVersion":"4558623","selfLink":"/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5","uid":"e07c5c19-25d8-4016-add9-213366b4259c"},"spec":{"serviceName":"thetranslator5"},"status":{"instanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::","keyInstanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573","message":"Online","secretName":"thetranslator5","state":"Online"}}}},"ibmcloud_ibm_com":{"Binding":{"thetranslator5":{"apiVersion":"ibmcloud.ibm.com/v1alpha1","kind":"Binding","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n","service-binding-operator.apps.openshift.io/binding-name":"sbr5","service-binding-operator.apps.openshift.io/binding-namespace":"default"},"creationTimestamp":"2020-05-14T08:55:22Z","finalizers":["binding.ibmcloud.ibm.com"],"generation":1,"name":"thetranslator5","namespace":"default","ownerReferences":[{"apiVersion":"ibmcloud.ibm.com/v1alpha1","blockOwnerDeletion":true,"controller":true,"kind":"Service","name":"thetranslator5","uid":"a6adaa6b-94ae-421f-8698-1e9ec2b48e64"}],"resourceVersion":"4558623","selfLink":"/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5","uid":"e07c5c19-25d8-4016-add9-213366b4259c"},"spec":{"serviceName":"thetranslator5"},"status":{"instanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::","keyInstanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573","message":"Online","secretName":"thetranslator5","state":"Online"}}}}}}
GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_IAM_SERVICEID_CRN=crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044
GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_IAM_ROLE_CRN=crn:v1:bluemix:public:iam::::serviceRole:Manager
GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_IAM_APIKEY_NAME=thetranslator5
GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_IAM_APIKEY_DESCRIPTION=Auto-generated for key 0aef56aa-fbb2-4dd7-8bc7-972302e14573

The differences between before and after. I prefer we make current behavior the same as before for the following 3 ones.

1  There is an extra string `SECRET_STATUS_SECRETNAME` behind global and service prefix.
2  For custom env vars, there is no globalprefix in the past.
3  For custom env vars, in the past, we can get the whole secret content, but now the data structure is different, and there is only the secret name.

@isutton
Copy link
Contributor

isutton commented May 19, 2020

@qibobo can you share more information about the scene, such as the Binding CRD definition, or whether there are OLM definitions for it?

@qibobo
Copy link
Contributor Author

qibobo commented May 20, 2020

@isutton
Copy link
Contributor

isutton commented May 20, 2020

@qibobo Thanks for your thorough verification, really appreciated!

The differences between before and after. I prefer we make current behavior the same as before for the following 3 ones.

  1. There is an extra string SECRET_STATUS_SECRETNAME behind global and service prefix.

Given this information and the Binding CRD I believe the binding that's happening is different than the binding you're expecting.

In the app used in the internal examples, a reference to the service kind in environment variables can be seen here and excerpted below:

const serviceHost = process.env.DATABASE_DBCONNECTIONIP || 'localhost';
const servicePort = process.env.DATABASE_DBCONNECTIONPORT || '5432';
const user = process.env.DATABASE_SECRET_USER || 'user';
const password = process.env.DATABASE_SECRET_PASSWORD || 'password';
const dbName = process.env.DATABASE_DBNAME || 'my_data'

In the nodejs_postgresql example, the following Service Binding Request is used:

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: binding-request
  namespace: service-binding-demo
spec:
  applicationSelector:
    resourceRef: nodejs-rest-http-crud
    group: apps
    version: v1
    resource: deployments
  backingServiceSelector:
    group: postgresql.baiju.dev
    version: v1alpha1
    kind: Database
    resourceRef: db-demo

Given that #407 haven't changed that behavior, what has been experienced is correct (according to the examples and tests existing prior #407) otherwise this example should've been changed.

@sbose78 what is your take on this?

  1. For custom env vars, there is no globalprefix in the past.

That was an interpretation that .spec.envVarPrefix would apply to all produced environment variables, but that seems not the case.

Shall we track this on a separate issue?

  1. For custom env vars, in the past, we can get the whole secret content, but now the data structure is different, and there is only the secret name.

To reference a v1.Secret using a path in the service resource (e.g. .status.secretName) requires the binding to be defined either in OLM, an annotation in the resource's CRD or the service CRD itself, as in the following example:

name: "servicebindingoperator.redhat.io/status.dbCredentials-password",
value: "binding:env:object:secret",

As can be seen in the test expected value:

expected: map[string]interface{}{
"secret": map[string]interface{}{
"password": "hunter2",
},
},

Please observe the other existing binding:env:object:secret semantics, expressed in the following test input:

name: "servicebindingoperator.redhat.io/status.dbCredentials",
value: "binding:env:object:secret",

And the expected value:

expected: map[string]interface{}{
"secret": map[string]interface{}{
"status": map[string]interface{}{
"dbCredentials": map[string]interface{}{
"username": "AzureDiamond",
"password": "hunter2",
},
},
},
},

In my opinion, until the Service Binding Spec annotations are implemented, a possibility is to whitelist the fields that should be collected from that secret as CRD annotations:

annotations:
    servicebindingoperator.redhat.io/status.secretName-key1: binding:env:object:secret
    servicebindingoperator.redhat.io/status.secretName-key2: binding:env:object:secret

@qibobo can you live with this until we have the Service Binding Spec annotations implemented?

@qibobo
Copy link
Contributor Author

qibobo commented May 21, 2020

@isutton @sbose78
Not sure whether my description for the problem is not clear enough for further discussion, so I refactored the test result in this post again by adding more details:

I think there are regression issues with PR407.

First of all, I patched the backingService CRD "Bindings.ibmcloud.ibm.com " with required annotations.

After the patch:

annotations:
  servicebindingoperator.redhat.io/status.secretName:binding:env:object:secret

Refer to the last comment of #475 (comment), @isutton, do you mean the annotaion above doesn't work at all with PR #407?

Let me assume the annotation still works, then

#Issue 1, the syntax of custom env showed in https://github.com/redhat-developer/service-binding-operator/tree/master/examples/knative_postgresql_customvar doesn't work at all.

I put a SBR as below

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: sbr5
spec:
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
  customEnvVar:
    - name: LANGUAGE_TRANSLATOR_URL
      value: '{{ index .status.secretName "url" }}'
    - name: LANGUAGE_TRANSLATOR_IAM_APIKEY
      value: '{{ index .status.secretName "apikey" }}'

The result before PR407:

LANGUAGE_TRANSLATOR_IAM_APIKEY=XXXX
LANGUAGE_TRANSLATOR_URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973

Then, when I applied the SBR after PR407, the reconcilation was failed with the error

"error":"template: set:1:3: executing \"set\" at <index .status.secretName \"url\">: error calling index: index of untyped nil"

See full stacktrace below for refernce:

{"level":"error","ts":1590029037.2458332,"logger":"controller-runtime.controller","msg":"Reconciler error","controller":"servicebindingrequest-controller","request":"default/sbr5","error":"template: set:1:3: executing \"set\" at <index .status.secretName \"url\">: error calling index: index of untyped nil","stacktrace":"github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/github.com/go-logr/zapr/zapr.go:128\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:258\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"}

Furthermore, I did a little bit further investigation here by using below customEnvVar

    - name: ALL_SECRET
      value: '{{json .}}'

With above JSON template, before 407, I can get the .status.secretName.apikey entry

ALL_SECRET={
  "status": {
    "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
    "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
    "message": "Online",
    "secretName": {
      "apikey": "XXXX",
      "iam_apikey_description": "Auto-generated for key 0aef56aa-fbb2-4dd7-8bc7-972302e14573",
      "iam_apikey_name": "thetranslator5",
      "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
      "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044",
      "url": "https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"
    },
    "state": "Online",
    "status.secretName": {
    }
  }
}

But after 407, I only got

          "status": {
            "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
            "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
            "message": "Online",
            "secretName": "thetranslator5",
            "state": "Online"
          }

Obviously, the .status.secretName is not an JSON object anymore, so that is why I got nil error.

Given the basic example case https://github.com/redhat-developer/service-binding-operator/tree/master/examples/knative_postgresql_customvar is broken now, I think it is a regression issue, and need to be fixed.

#Issue2: The naming of the envprefix

I rework my SBR with env prefix in different layer:

spec:
  envVarPrefix: globalprefix
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
      envVarPrefix: prefix1
  customEnvVar:
   - name: TRANSLATOR_NAME
     value: "thetranslator5"
   - name: ALL_SECRET
     value: '{{json .}}'

a. For the default envs, besides global-level envVarPrefix and service-level envVarPrefix, there is an extra string STATUS_SECRETNAME in the env name. I prefer to keep the behavior of before 407 below.

before 407 (EXPECTED result)

    GLOBALPREFIX_PREFIX1_SECRET_APIKEY=XXXX

after 407

    GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_APIKEY=XXXX

b. For custom env vars, after 407 applied, an extra global-level envVarPrefix is added. I prefer to respect the specified name in customEnvVar without adding any prefix, as the result before 407 below:

before 407 (EXPECTED result)

    TRANSLATOR_NAME=thetranslator5

after 407

   globalprefix_TRANSLATOR_NAME=thetranslator5

@isutton
Copy link
Contributor

isutton commented May 22, 2020

@qibobo thanks for your extensive description, that's really useful!

@isutton @sbose78
Not sure whether my description for the problem is not clear enough for further discussion, so I refactored the test result in this post again by adding more details:

I think there are regression issues with PR407.

First of all, I patched the backingService CRD "Bindings.ibmcloud.ibm.com " with required annotations.

After the patch:

annotations:
  servicebindingoperator.redhat.io/status.secretName: binding:env:object:secret

Refer to the last comment of #475 (comment), @isutton, do you mean the annotaion above doesn't work at all with PR #407?

It should work, according to the tests mentioned in that comment.

Let me assume the annotation still works, then

#Issue 1, the syntax of custom env showed in https://github.com/redhat-developer/service-binding-operator/tree/master/examples/knative_postgresql_customvar doesn't work at all.

I put a SBR as below

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: sbr5
spec:
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
  customEnvVar:
    - name: LANGUAGE_TRANSLATOR_URL
      value: '{{ index .status.secretName "url" }}'
    - name: LANGUAGE_TRANSLATOR_IAM_APIKEY
      value: '{{ index .status.secretName "apikey" }}'

The result before PR407:

LANGUAGE_TRANSLATOR_IAM_APIKEY=XXXX
LANGUAGE_TRANSLATOR_URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973

Then, when I applied the SBR after PR407, the reconcilation was failed with the error

"error":"template: set:1:3: executing \"set\" at <index .status.secretName \"url\">: error calling index: index of untyped nil"

See full stacktrace below for refernce:

{"level":"error","ts":1590029037.2458332,"logger":"controller-runtime.controller","msg":"Reconciler error","controller":"servicebindingrequest-controller","request":"default/sbr5","error":"template: set:1:3: executing \"set\" at <index .status.secretName \"url\">: error calling index: index of untyped nil","stacktrace":"github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/github.com/go-logr/zapr/zapr.go:128\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:258\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"}

This happens due to the introduction of backingServiceSelectors to support multiple backing services to avoid shadowing values in the case multiple services have exposed status.secretName; the disambiguation happens by prefixing each status.secretName with the information regarding the secret itself.

In the example given above, the full value name to be used in customEnvVar would be .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName:

>     - name: LANGUAGE_TRANSLATOR_URL
>       value: '{{ index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName "url" }}'

Furthermore, I did a little bit further investigation here by using below customEnvVar

    - name: ALL_SECRET
      value: '{{json .}}'

With above JSON template, before 407, I can get the .status.secretName.apikey entry

ALL_SECRET={
  "status": {
    "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
    "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
    "message": "Online",
    "secretName": {
      "apikey": "XXXX",
      "iam_apikey_description": "Auto-generated for key 0aef56aa-fbb2-4dd7-8bc7-972302e14573",
      "iam_apikey_name": "thetranslator5",
      "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
      "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044",
      "url": "https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"
    },
    "state": "Online",
    "status.secretName": {
    }
  }
}

But after 407, I only got

          "status": {
            "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
            "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
            "message": "Online",
            "secretName": "thetranslator5",
            "state": "Online"
          }

Can you confirm ALL_SECRET after 407 contains only the status key, or have you copied only part of its contents? Having it entirely is also helpful.

Obviously, the .status.secretName is not an JSON object anymore, so that is why I got nil error.

Given the basic example case https://github.com/redhat-developer/service-binding-operator/tree/master/examples/knative_postgresql_customvar is broken now, I think it is a regression issue, and need to be fixed.

I understand the problem, but I'm not sure it is a regression since the behavior is transitioning from single to multiple services and the implications should be discussed.

#Issue2: The naming of the envprefix

I rework my SBR with env prefix in different layer:

spec:
  envVarPrefix: globalprefix
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
      envVarPrefix: prefix1
  customEnvVar:
   - name: TRANSLATOR_NAME
     value: "thetranslator5"
   - name: ALL_SECRET
     value: '{{json .}}'

a. For the default envs, besides global-level envVarPrefix and service-level envVarPrefix, there is an extra string STATUS_SECRETNAME in the env name. I prefer to keep the behavior of before 407 below.

before 407 (EXPECTED result)

    GLOBALPREFIX_PREFIX1_SECRET_APIKEY=XXXX

after 407

    GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_APIKEY=XXXX

The annotations and tests have been implemented in 407 according to the annotations present in here:

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: databases.postgresql.baiju.dev
  annotations:
    servicebindingoperator.redhat.io/status.dbConfigMap-db.host: binding:env:object:configmap
    servicebindingoperator.redhat.io/status.dbConfigMap-db.name: binding:env:object:configmap
    servicebindingoperator.redhat.io/status.dbConfigMap-db.password: binding:env:object:configmap
    servicebindingoperator.redhat.io/status.dbConfigMap-db.port: binding:env:object:configmap
    servicebindingoperator.redhat.io/status.dbConfigMap-db.username: binding:env:object:configmap
    servicebindingoperator.redhat.io/status.dbConnectionIP: binding:env:attribute
    servicebindingoperator.redhat.io/status.dbConnectionPort: binding:env:attribute
    servicebindingoperator.redhat.io/status.dbCredentials-password: binding:env:object:secret
    servicebindingoperator.redhat.io/status.dbCredentials-user: binding:env:object:secret
    servicebindingoperator.redhat.io/status.dbName: binding:env:attribute

I've searched in the repository for binding:env:object, and yielded the following:

docs/OperatorBestPractices.md:
  55:     servicebindingoperator.redhat.io/status.dbConfigMap.password: 'binding:env:object:secret'
  56:     servicebindingoperator.redhat.io/status.dbConfigMap.username: 'binding:env:object:configmap'
  83:       - binding:env:object:secret:user
  84:       - binding:env:object:secret:password

pkg/controller/servicebindingrequest/olm_test.go:
  115: 		"servicebindingoperator.redhat.io/status.dbCredentials-db.password": "binding:env:object:secret",
  117: 		"servicebindingoperator.redhat.io/status.dbConfigMap-db.host":       "binding:env:object:configmap",
  148: 			"dbCredentials": "binding:env:object:secret:db.password",
  149: 			"dbConfigMap":   "binding:env:object:configmap:db.host",
  181: 			"servicebindingoperator.redhat.io/status.dbConfigMap-db.host":       "binding:env:object:configmap",
  183: 			"servicebindingoperator.redhat.io/status.dbCredentials-db.password": "binding:env:object:secret",
  194: 			"dbCredentials": "binding:env:object:secret:db.password",
  195: 			"dbConfigMap":   "binding:env:object:configmap:db.host",
  226: 			"dbCredentials": "binding:env:object:secret:db.password",
  227: 			"dbConfigMap":   "binding:env:object:configmap:db.host",

pkg/controller/servicebindingrequest/annotations/configmap_test.go:
  54: 		value: "binding:env:object:configmap",
  87: 		value: "binding:env:object:configmap",

pkg/controller/servicebindingrequest/annotations/configmap.go:
  10: const configMapValue = "binding:env:object:configmap"

pkg/controller/servicebindingrequest/annotations/resource_test.go:
  29: 		value:    "binding:env:object:secret",
  34: 		value:    "binding:env:object:configmap",

pkg/controller/servicebindingrequest/annotations/secret_test.go:
  54: 		value: "binding:env:object:secret",
  86: 		value: "binding:env:object:secret",

pkg/controller/servicebindingrequest/annotations/secret.go:
  13: const secretValue = "binding:env:object:secret"

test/mocks/mocks.go:
   68: 			"binding:env:object:configmap:username",
   69: 			"binding:env:object:configmap:password",
   80: 			"binding:env:object:secret:username",
   81: 			"binding:env:object:secret:password",
  102: 		"servicebindingoperator.redhat.io/status.dbCredentials-password": "binding:env:object:secret",
  103: 		"servicebindingoperator.redhat.io/status.dbCredentials-user":     "binding:env:object:secret",

test/third-party-crds/postgresql_v1alpha1_database_crd.yaml:
   7:     servicebindingoperator.redhat.io/status.dbConfigMap-db.host: binding:env:object:configmap
   8:     servicebindingoperator.redhat.io/status.dbConfigMap-db.name: binding:env:object:configmap
   9:     servicebindingoperator.redhat.io/status.dbConfigMap-db.password: binding:env:object:configmap
  10:     servicebindingoperator.redhat.io/status.dbConfigMap-db.port: binding:env:object:configmap
  11:     servicebindingoperator.redhat.io/status.dbConfigMap-db.username: binding:env:object:configmap
  14:     servicebindingoperator.redhat.io/status.dbCredentials-password: binding:env:object:secret
  15:     servicebindingoperator.redhat.io/status.dbCredentials-user: binding:env:object:secret

As you can see, there isn't a binding:env:object:secretand binding:env:object:configmap without an alias on the left hand side (the password in status.dbCredentials-password). It seems that the aforementioned Knative example was working by accident since it didn't have any test covering that case.

The following test shows the behavior you're describing:

t.Run("secret/map", assertHandler(args{
name: "servicebindingoperator.redhat.io/status.dbCredentials",
value: "binding:env:object:secret",
service: map[string]interface{}{
"metadata": map[string]interface{}{
"namespace": "the-namespace",
},
"status": map[string]interface{}{
"dbCredentials": "the-secret-resource-name",
},
},
resources: []runtime.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: "the-namespace",
Name: "the-secret-resource-name",
},
Data: map[string][]byte{
"password": []byte("hunter2"),
"username": []byte("AzureDiamond"),
},
},
},
expected: map[string]interface{}{
"secret": map[string]interface{}{
"status": map[string]interface{}{
"dbCredentials": map[string]interface{}{
"username": "AzureDiamond",
"password": "hunter2",
},
},
},
},
}))

In other words, to solve this issue the expected value in the test above should be modified to the following and then adjusted accordingly in resourceHandler.Handle:

        expected: map[string]interface{}{
            "secret": map[string]interface{}{
                "username": "AzureDiamond",
                "password": "hunter2",
            },
        },

b. For custom env vars, after 407 applied, an extra global-level envVarPrefix is added. I prefer to respect the specified name in customEnvVar without adding any prefix, as the result before 407 below:

before 407 (EXPECTED result)

    TRANSLATOR_NAME=thetranslator5

after 407

   globalprefix_TRANSLATOR_NAME=thetranslator5

That's indeed a bug, and can be fixed in here:

for k, v := range customEnvVars {
prefix := []string{}
if len(globalEnvVarPrefix) > 0 {
prefix = append(prefix, globalEnvVarPrefix)
}
prefix = append(prefix, k)
k = strings.Join(prefix, "_")
envVars[k] = []byte(v.(string))
}

@qibobo
Copy link
Contributor Author

qibobo commented May 22, 2020

@isutton
For the id in custom env var case, we have an example:
With the following SBR,

apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: sbrsample
spec:
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments 
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
      id: xxx
  customEnvVar:
    - name: VCAP_SERVICES
      value: '{"language-translator":[{"credentials":{{json .xxx.status.secretName}},"name":"thetranslator5","plan":"standard"}]}'

The VCAP_SERVICES is:

VCAP_SERVICES={
  "language-translator": [
    {
      "name": "thetranslator5",
      "credentials": {
        "apikey": "xxxxx",
        "iam_apikey_description": "Auto-generated for key bdcab647-4239-406f-a40c-3a99773354b0",
        "iam_apikey_name": "sbr-test-service-credential",
        "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
        "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/8d63fb1cc5e99e86dd7229dddffc05a5::serviceid:ServiceId-0917e5bc-0e3c-403c-bdbe-1f126b773b5c",
        "url": "https://api.us-south.language-translator.watson.cloud.ibm.com/instances/a119ec9f-3f5e-45da-b84a-a1c4ed49848f"
      },
      "plan": "standard"
    }
  ]
}

@isutton
Copy link
Contributor

isutton commented May 25, 2020

@isutton
For the id in custom env var case, we have an example:
With the following SBR,

snip

@qibobo just to make sure I understood you correctly: this example refers to the id field introduced in #468 and, from the looks of it, when used with your example it behaves the way you expect.

Did I get it right? :)

@sbose78
Copy link
Member

sbose78 commented May 26, 2020

I really appreciate the detailed conversation above.

In @qibobo 's comment, @qibobo mentions that when both global env var prefix and service specific env var prefix is provided, the secret key name looks like this:

GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_IAM_SERVICEID_CRN=crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044

..
..
...

1  There is an extra string `SECRET_STATUS_SECRETNAME` behind global and service prefix.

PR's comment can be used as a reference.

I haven't seen this addressed in @isutton 's comment here. The example in that comment is devoid of global or service level prefixes.

I might be missing something, could you please tell me if the above issue is being address this @qibobo @isutton ?

@qibobo
Copy link
Contributor Author

qibobo commented May 26, 2020

@isutton
The id in the sample is the id in PR468 and the VCAP_SERVICES is what we expect the result should be with the id.

@qibobo
Copy link
Contributor Author

qibobo commented May 26, 2020

@isutton
Still get error from operator by adding annotation

servicebindingoperator.redhat.io/status.secretName-url: binding:env:object:secret

After adding the annotation, the CRD is as the following and we can see that the annotation has beeb added.

kubectl get CustomResourceDefinition bindings.ibmcloud.ibm.com -o yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    servicebindingoperator.redhat.io/status.secretName-url: binding:env:object:secret
  creationTimestamp: "2020-04-09T06:17:12Z"

Then I created the following SBR:

cat <<EOF | kubectl apply -f -
apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: sbrsample
spec:
  applicationSelector:
    resourceRef: mytranslator-web-vcap5
    group: apps
    version: v1
    resource: deployments 
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
  customEnvVar:
    - name: LANGUAGE_TRANSLATOR_URL
      value: '{{ index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName "url" }}'
EOF

Then the operator showed the error log:

set:1:3: executing \"set\" at <index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName \"url\">: error calling index: cannot index slice/array with type string"

The whole error log:

{"level":"error","ts":1590485190.2458026,"logger":"retriever","msg":"Creating envVars","Templates":[{"name":"LANGUAGE_TRANSLATOR_URL","value":"{{ index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName \"url\" }}"}],"TemplateContext":{"v1alpha1":{"ibmcloud.ibm.com":{"Binding":{"thetranslator5":{"apiVersion":"ibmcloud.ibm.com/v1alpha1","kind":"Binding","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n"},"creationTimestamp":"2020-05-14T08:55:22Z","finalizers":["binding.ibmcloud.ibm.com"],"generation":1,"name":"thetranslator5","namespace":"default","ownerReferences":[{"apiVersion":"ibmcloud.ibm.com/v1alpha1","blockOwnerDeletion":true,"controller":true,"kind":"Service","name":"thetranslator5","uid":"a6adaa6b-94ae-421f-8698-1e9ec2b48e64"}],"resourceVersion":"5367784","selfLink":"/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5","uid":"e07c5c19-25d8-4016-add9-213366b4259c"},"spec":{"serviceName":"thetranslator5"},"status":{"instanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::","keyInstanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573","message":"Online","secretName":"thetranslator5","state":"Online"}}}},"ibmcloud_ibm_com":{"Binding":{"thetranslator5":{"apiVersion":"ibmcloud.ibm.com/v1alpha1","kind":"Binding","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n"},"creationTimestamp":"2020-05-14T08:55:22Z","finalizers":["binding.ibmcloud.ibm.com"],"generation":1,"name":"thetranslator5","namespace":"default","ownerReferences":[{"apiVersion":"ibmcloud.ibm.com/v1alpha1","blockOwnerDeletion":true,"controller":true,"kind":"Service","name":"thetranslator5","uid":"a6adaa6b-94ae-421f-8698-1e9ec2b48e64"}],"resourceVersion":"5367784","selfLink":"/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5","uid":"e07c5c19-25d8-4016-add9-213366b4259c"},"spec":{"serviceName":"thetranslator5"},"status":{"instanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::","keyInstanceId":"crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573","message":"Online","secretName":"thetranslator5","state":"Online"}}}}}},"error":"template: set:1:3: executing \"set\" at <index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName \"url\">: error calling index: cannot index slice/array with type string","stacktrace":"github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/redhat-developer/service-binding-operator/pkg/log.(*Log).Error\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/log/log.go:35\ngithub.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest.(*Retriever).ProcessServiceContexts\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest/retriever.go:123\ngithub.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest.buildBinding\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest/servicebinder.go:380\ngithub.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest.(*Reconciler).Reconcile\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest/reconciler.go:163\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:256\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"}
{"level":"error","ts":1590485190.246001,"logger":"controller-runtime.controller","msg":"Reconciler error","controller":"servicebindingrequest-controller","request":"default/sbrsample","error":"template: set:1:3: executing \"set\" at <index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName \"url\">: error calling index: cannot index slice/array with type string","stacktrace":"github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/github.com/go-logr/zapr/zapr.go:128\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:258\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"}

And I confirmed that the url is in the secret:

kubectl get secret thetranslator5 -o yaml
apiVersion: v1
data:
  apikey: xxxx
  iam_apikey_description: QXV0by1nZW5lcmF0ZWQgZm9yIGtleSAwYWVmNTZhYS1mYmIyLTRkZDctOGJjNy05NzIzMDJlMTQ1NzM=
  iam_apikey_name: dGhldHJhbnNsYXRvcjU=
  iam_role_crn: Y3JuOnYxOmJsdWVtaXg6cHVibGljOmlhbTo6OjpzZXJ2aWNlUm9sZTpNYW5hZ2Vy
  iam_serviceid_crn: Y3JuOnYxOmJsdWVtaXg6cHVibGljOmlhbS1pZGVudGl0eTo6YS9lZjZhMzQ4MTBjYmNkODkyNTA3ZDNlYmUwMWUzZDk1YTo6c2VydmljZWlkOlNlcnZpY2VJZC03MWUxOGRjNy0xZDAyLTQ3MDQtYjE2Ny1iZTI5ZjQxNzIwNDQ=
  url: aHR0cHM6Ly9hcGkudXMtc291dGgubGFuZ3VhZ2UtdHJhbnNsYXRvci53YXRzb24uY2xvdWQuaWJtLmNvbS9pbnN0YW5jZXMvNzhhYmUxOTgtZmViOC00MWM5LWIyOTMtMzhiMjFiZWI4OTcz
kind: Secret
metadata:
  annotations:
    bindingFromName: thetranslator5
    service-instance-id: 'crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::'
    service-key-id: crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573
  creationTimestamp: "2020-05-14T08:55:35Z"
  name: thetranslator5
  namespace: default
  ownerReferences:
  - apiVersion: ibmcloud.ibm.com/v1alpha1
    blockOwnerDeletion: true
    controller: true
    kind: Binding
    name: thetranslator5
    uid: e07c5c19-25d8-4016-add9-213366b4259c
  resourceVersion: "4000113"
  selfLink: /api/v1/namespaces/default/secrets/thetranslator5
  uid: 00d81803-1076-4519-a667-68148f764cb0
type: Opaque

@qibobo
Copy link
Contributor Author

qibobo commented May 27, 2020

@isutton
I add more log based the master branch in a personal branch dev_qy_newlog.

And with the SBR above I got the some error log that may help:
In code https://github.com/qibobo/service-binding-operator/blob/47c3e07c8da3459c4120459c3cbfd8f57d128797/pkg/controller/servicebindingrequest/retriever.go#L129
the log print out the template and the TemplateContext, and we can see that in the TemplateContext there is no url in v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName

{
  "level": "error",
  "ts": 1590595352.5621564,
  "logger": "retriever",
  "msg": "Creating envVars",
  "Templates": [
    {
      "name": "LANGUAGE_TRANSLATOR_URL",
      "value": "{{ index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName \"url\" }}"
    }
  ],
  "TemplateContext": {
    "v1alpha1": {
      "ibmcloud.ibm.com": {
        "Binding": {
          "thetranslator5": {
            "apiVersion": "ibmcloud.ibm.com/v1alpha1",
            "kind": "Binding",
            "metadata": {
              "annotations": {
                "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n"
              },
              "creationTimestamp": "2020-05-14T08:55:22Z",
              "finalizers": [
                "binding.ibmcloud.ibm.com"
              ],
              "generation": 1,
              "name": "thetranslator5",
              "namespace": "default",
              "ownerReferences": [
                {
                  "apiVersion": "ibmcloud.ibm.com/v1alpha1",
                  "blockOwnerDeletion": true,
                  "controller": true,
                  "kind": "Service",
                  "name": "thetranslator5",
                  "uid": "a6adaa6b-94ae-421f-8698-1e9ec2b48e64"
                }
              ],
              "resourceVersion": "5367784",
              "selfLink": "/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5",
              "uid": "e07c5c19-25d8-4016-add9-213366b4259c"
            },
            "spec": {
              "serviceName": "thetranslator5"
            },
            "status": {
              "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
              "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
              "message": "Online",
              "secretName": "thetranslator5",
              "state": "Online"
            }
          }
        }
      },
      "ibmcloud_ibm_com": {
        "Binding": {
          "thetranslator5": {
            "apiVersion": "ibmcloud.ibm.com/v1alpha1",
            "kind": "Binding",
            "metadata": {
              "annotations": {
                "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n"
              },
              "creationTimestamp": "2020-05-14T08:55:22Z",
              "finalizers": [
                "binding.ibmcloud.ibm.com"
              ],
              "generation": 1,
              "name": "thetranslator5",
              "namespace": "default",
              "ownerReferences": [
                {
                  "apiVersion": "ibmcloud.ibm.com/v1alpha1",
                  "blockOwnerDeletion": true,
                  "controller": true,
                  "kind": "Service",
                  "name": "thetranslator5",
                  "uid": "a6adaa6b-94ae-421f-8698-1e9ec2b48e64"
                }
              ],
              "resourceVersion": "5367784",
              "selfLink": "/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5",
              "uid": "e07c5c19-25d8-4016-add9-213366b4259c"
            },
            "spec": {
              "serviceName": "thetranslator5"
            },
            "status": {
              "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
              "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
              "message": "Online",
              "secretName": "thetranslator5",
              "state": "Online"
            }
          }
        }
      }
    }
  },
  "error": "template: set:1:3: executing \"set\" at <index .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName \"url\">: error calling index: cannot index slice/array with type string",
  "stacktrace": "github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/redhat-developer/service-binding-operator/pkg/log.(*Log).Error\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/log/log.go:35\ngithub.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest.(*Retriever).ProcessServiceContexts\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest/retriever.go:129\ngithub.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest.buildBinding\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest/servicebinder.go:372\ngithub.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest.(*Reconciler).Reconcile\n\t/go/src/github.com/redhat-developer/service-binding-operator/pkg/controller/servicebindingrequest/reconciler.go:165\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:256\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/redhat-developer/service-binding-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88"
}

And in https://github.com/qibobo/service-binding-operator/blob/47c3e07c8da3459c4120459c3cbfd8f57d128797/pkg/controller/servicebindingrequest/retriever.go#L125
It print the envVars and there is a BINDING_SECRET_URL, but it is not used in custom env var template parsing process.

{
  "level": "info",
  "ts": 1590595352.5619142,
  "logger": "retriever",
  "msg": "-------------ProcessServiceContexts1",
  "envVars": {
    "BINDING_SECRET_URL": "xxx"
  },
  "volumeKeys": [
    
  ],
  "customEnvVarCtx": {
    "v1alpha1": {
      "ibmcloud.ibm.com": {
        "Binding": {
          "thetranslator5": {
            "apiVersion": "ibmcloud.ibm.com/v1alpha1",
            "kind": "Binding",
            "metadata": {
              "annotations": {
                "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n"
              },
              "creationTimestamp": "2020-05-14T08:55:22Z",
              "finalizers": [
                "binding.ibmcloud.ibm.com"
              ],
              "generation": 1,
              "name": "thetranslator5",
              "namespace": "default",
              "ownerReferences": [
                {
                  "apiVersion": "ibmcloud.ibm.com/v1alpha1",
                  "blockOwnerDeletion": true,
                  "controller": true,
                  "kind": "Service",
                  "name": "thetranslator5",
                  "uid": "a6adaa6b-94ae-421f-8698-1e9ec2b48e64"
                }
              ],
              "resourceVersion": "5367784",
              "selfLink": "/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5",
              "uid": "e07c5c19-25d8-4016-add9-213366b4259c"
            },
            "spec": {
              "serviceName": "thetranslator5"
            },
            "status": {
              "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
              "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
              "message": "Online",
              "secretName": "thetranslator5",
              "state": "Online"
            }
          }
        }
      },
      "ibmcloud_ibm_com": {
        "Binding": {
          "thetranslator5": {
            "apiVersion": "ibmcloud.ibm.com/v1alpha1",
            "kind": "Binding",
            "metadata": {
              "annotations": {
                "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n"
              },
              "creationTimestamp": "2020-05-14T08:55:22Z",
              "finalizers": [
                "binding.ibmcloud.ibm.com"
              ],
              "generation": 1,
              "name": "thetranslator5",
              "namespace": "default",
              "ownerReferences": [
                {
                  "apiVersion": "ibmcloud.ibm.com/v1alpha1",
                  "blockOwnerDeletion": true,
                  "controller": true,
                  "kind": "Service",
                  "name": "thetranslator5",
                  "uid": "a6adaa6b-94ae-421f-8698-1e9ec2b48e64"
                }
              ],
              "resourceVersion": "5367784",
              "selfLink": "/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5",
              "uid": "e07c5c19-25d8-4016-add9-213366b4259c"
            },
            "spec": {
              "serviceName": "thetranslator5"
            },
            "status": {
              "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
              "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:0aef56aa-fbb2-4dd7-8bc7-972302e14573",
              "message": "Online",
              "secretName": "thetranslator5",
              "state": "Online"
            }
          }
        }
      }
    }
  }
}

@qibobo
Copy link
Contributor Author

qibobo commented May 28, 2020

@isutton
From my last comment, we can see that the secret data is not in the customEnvVarCtx. Below is a sample I think can fix it by add it into retriever. The hardcode "status" and "secretName" are just for demo, we need to pass them as parameters.

err = unstructured.SetNestedField(
	customEnvVarCtx, svcCtx.EnvVars, gvk.Version, gvk.Group, gvk.Kind,
	svcCtx.Service.GetName(),"status","secretName")
if err != nil {
	return nil, nil, err
}

@cdlliuy
Copy link
Contributor

cdlliuy commented Jun 2, 2020

@isutton , what is the next step to move this forward? Will you raise a new PR to resolve this?

@qibobo
Copy link
Contributor Author

qibobo commented Jun 17, 2020

@isutton
Any update?

@isutton
Copy link
Contributor

isutton commented Jun 17, 2020

@qibobo here it is, right from the oven :)

@isutton
Copy link
Contributor

isutton commented Jun 17, 2020

I really appreciate the detailed conversation above.

In @qibobo 's comment, @qibobo mentions that when both global env var prefix and service specific env var prefix is provided, the secret key name looks like this:

GLOBALPREFIX_PREFIX1_SECRET_STATUS_SECRETNAME_IAM_SERVICEID_CRN=crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-71e18dc7-1d02-4704-b167-be29f4172044

..
..
...

1  There is an extra string `SECRET_STATUS_SECRETNAME` behind global and service prefix.

PR's comment can be used as a reference.

I haven't seen this addressed in @isutton 's comment here. The example in that comment is devoid of global or service level prefixes.

I might be missing something, could you please tell me if the above issue is being address this @qibobo @isutton ?

This has been discussed in #475 (comment):

As you can see, there isn't a binding:env:object:secret and binding:env:object:configmap without an alias on the left hand side (the password in status.dbCredentials-password). It seems that the aforementioned Knative example was working by accident since it didn't have any test covering that case.

And here #475 (comment):

In my opinion, until the Service Binding Spec annotations are implemented, a possibility is to whitelist the fields that should be collected from that secret as CRD annotations:

annotations:
   servicebindingoperator.redhat.io/status.secretName-key1: binding:env:object:secret
   servicebindingoperator.redhat.io/status.secretName-key2: binding:env:object:secret

I'm inclined to use the annotations that has been tested so far, and wait for the finalization of the new Service Binding annotation syntax.

@qibobo
Copy link
Contributor Author

qibobo commented Jun 18, 2020

@isutton
I tested the PR #515.
There is one issue for custom env var. To get the secret content, this is the definition in the past:

- name: VCAP_SERVICES
  value: '{"language-translator":[{"credentials":{{json .xxx.status.secretName}},"name":"thetranslator5","plan":"standard"}]}'

But now we need the definition as below:

- name: VCAP_SERVICES
   value: '{"language-translator":[{"credentials":{{json .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName.status.secretName}},"name":"thetranslator5","plan":"standard"}]}'

We can find the whole content of data to do custom_env_var template parsing as below, I think the status.secretName under v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName isn't needed. We can just put the secret content under v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName.

{
  "v1alpha1": {
    "ibmcloud.ibm.com": {
      "Binding": {
        "thetranslator5": {
          "apiVersion": "ibmcloud.ibm.com/v1alpha1",
          "kind": "Binding",
          "metadata": {
            "annotations": {
              "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n",
              "service-binding-operator.apps.openshift.io/binding-name": "binding-request-vcap",
              "service-binding-operator.apps.openshift.io/binding-namespace": "default"
            },
            "creationTimestamp": "2020-05-14T08:55:22Z",
            "finalizers": [
              "binding.ibmcloud.ibm.com"
            ],
            "generation": 1,
            "name": "thetranslator5",
            "namespace": "default",
            "ownerReferences": [
              {
                "apiVersion": "ibmcloud.ibm.com/v1alpha1",
                "blockOwnerDeletion": true,
                "controller": true,
                "kind": "Service",
                "name": "thetranslator5",
                "uid": "a6adaa6b-94ae-421f-8698-1e9ec2b48e64"
              }
            ],
            "resourceVersion": "8035238",
            "selfLink": "/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5",
            "uid": "e07c5c19-25d8-4016-add9-213366b4259c"
          },
          "spec": {
            "serviceName": "thetranslator5"
          },
          "status": {
            "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
            "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:f7c7662b-bbb5-4918-8a36-8517fdee7370",
            "message": "Online",
            "secretName": {
              "status": {
                "secretName": {
                  "apikey": "XXXX",
                  "iam_apikey_description": "Auto-generated for key f7c7662b-bbb5-4918-8a36-8517fdee7370",
                  "iam_apikey_name": "thetranslator5",
                  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
                  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-1a6e5b46-af86-44b5-8021-4eca0aa3be22",
                  "url": "https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"
                }
              },
              "url": "https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"
            },
            "state": "Online"
          }
        }
      }
    },
    "ibmcloud_ibm_com": {
      "Binding": {
        "thetranslator5": {
          "apiVersion": "ibmcloud.ibm.com/v1alpha1",
          "kind": "Binding",
          "metadata": {
            "annotations": {
              "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"ibmcloud.ibm.com/v1alpha1\",\"kind\":\"Binding\",\"metadata\":{\"annotations\":{},\"name\":\"thetranslator5\",\"namespace\":\"default\"},\"spec\":{\"serviceName\":\"thetranslator5\"}}\n",
              "service-binding-operator.apps.openshift.io/binding-name": "binding-request-vcap",
              "service-binding-operator.apps.openshift.io/binding-namespace": "default"
            },
            "creationTimestamp": "2020-05-14T08:55:22Z",
            "finalizers": [
              "binding.ibmcloud.ibm.com"
            ],
            "generation": 1,
            "name": "thetranslator5",
            "namespace": "default",
            "ownerReferences": [
              {
                "apiVersion": "ibmcloud.ibm.com/v1alpha1",
                "blockOwnerDeletion": true,
                "controller": true,
                "kind": "Service",
                "name": "thetranslator5",
                "uid": "a6adaa6b-94ae-421f-8698-1e9ec2b48e64"
              }
            ],
            "resourceVersion": "8035238",
            "selfLink": "/apis/ibmcloud.ibm.com/v1alpha1/namespaces/default/bindings/thetranslator5",
            "uid": "e07c5c19-25d8-4016-add9-213366b4259c"
          },
          "spec": {
            "serviceName": "thetranslator5"
          },
          "status": {
            "instanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973::",
            "keyInstanceId": "crn:v1:bluemix:public:language-translator:us-south:a/ef6a34810cbcd892507d3ebe01e3d95a:78abe198-feb8-41c9-b293-38b21beb8973:resource-key:f7c7662b-bbb5-4918-8a36-8517fdee7370",
            "message": "Online",
            "secretName": {
              "status": {
                "secretName": {
                  "apikey": "XXXX",
                  "iam_apikey_description": "Auto-generated for key f7c7662b-bbb5-4918-8a36-8517fdee7370",
                  "iam_apikey_name": "thetranslator5",
                  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
                  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-1a6e5b46-af86-44b5-8021-4eca0aa3be22",
                  "url": "https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"
                }
              },
              "url": "https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"
            },
            "state": "Online"
          }
        }
      }
    }
  }
}

And the the test steps:

1 add annotation:

metadata:
  annotations:
    servicebindingoperator.redhat.io/status.secretName: binding:env:object:secret
    servicebindingoperator.redhat.io/status.secretName-url: binding:env:object:secret

2 create the SBR:

cat <<EOF | kubectl apply -f -
apiVersion: apps.openshift.io/v1alpha1
kind: ServiceBindingRequest
metadata:
  name: binding-request-vcap
spec:
  applicationSelector:
    resourceRef: knative-vcap
    group: serving.knative.dev 
    version: v1 
    resource: services 
  backingServiceSelectors:
    - group: ibmcloud.ibm.com
      version: v1alpha1
      kind: Binding
      resourceRef: thetranslator5
      envVarPrefix: serviceprefix
  customEnvVar:
    - name: VCAP_SERVICES
      value: '{"language-translator":[{"credentials":{{json .v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName.status.secretName}},"name":"thetranslator5","plan":"standard"}]}'
    - name: TRANSLATOR_NAME
      value: "thetranslator5"
    - name: URL
      value: '{{.v1alpha1.ibmcloud_ibm_com.Binding.thetranslator5.status.secretName.url}}'
EOF

And the result:

SERVICEPREFIX_SECRET_STATUS_SECRETNAME_IAM_APIKEY_NAME=thetranslator5
SERVICEPREFIX_SECRET_STATUS_SECRETNAME_URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973
SERVICEPREFIX_SECRET_STATUS_SECRETNAME_IAM_APIKEY_DESCRIPTION=Auto-generated for key f7c7662b-bbb5-4918-8a36-8517fdee7370
SERVICEPREFIX_SECRET_STATUS_SECRETNAME_IAM_SERVICEID_CRN=crn:v1:bluemix:public:iam-identity::aef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-1a6e5b4-af86-44b5-8021-4eca0aa3be22
SERVICEPREFIX_SECRET_STATUS_SECRETNAME_IAM_ROLE_CRN=crn:v1:bluemix:public:iam::::serviceRole:Manager
SERVICEPREFIX_SECRET_STATUS_SECRETNAME_APIKEY=XXXX

SERVICEPREFIX_SECRET_URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973

URL=https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973
VCAP_SERVICES={"language-translator":[{"credentials":{"apikey":"XXXX","iam_apikey_description":"Auto-generated for key f7c7662b-bbb5-4918-8a36-8517fdee7370","iam_apikey_name":"thetranslator5","iam_role_crn":"crn:v1:bluemix:public:iam::::serviceRole:Manager","iam_serviceid_crn":"crn:v1:bluemix:public:iam-identity::a/ef6a34810cbcd892507d3ebe01e3d95a::serviceid:ServiceId-1a6e5b46-af86-44b5-8021-4eca0aa3be22","url":"https://api.us-south.language-translator.watson.cloud.ibm.com/instances/78abe198-feb8-41c9-b293-38b21beb8973"},"name":"thetranslator5","plan":"standard"}]}
TRANSLATOR_NAME=thetranslator5

@cdlliuy
Copy link
Contributor

cdlliuy commented Jun 18, 2020

@isutton , as discussed on the call, can you help to move forward with #515, and add some description and hints about how to fix the annotation issue with a smaller PR? maybe we can help to contribute the effort to make status.secretName annotation to work.

@isutton
Copy link
Contributor

isutton commented Jun 18, 2020

@cdlliuy this inference is made in newAttributeHandler (L46-L49 below):

// NewAttributeHandler constructs an AttributeHandler.
func newAttributeHandler(
bi *bindingInfo,
resource unstructured.Unstructured,
) *attributeHandler {
outputPath := bi.SourcePath
if len(bi.ResourceReferencePath) > 0 {
outputPath = bi.ResourceReferencePath
}
// the current implementation removes "status." and "spec." from fields exported through
// annotations.
for _, prefix := range []string{"status.", "spec."} {
if strings.HasPrefix(outputPath, prefix) {
outputPath = strings.Replace(outputPath, prefix, "", 1)
}
}
return &attributeHandler{
inputPath: bi.SourcePath,
outputPath: outputPath,
resource: resource,
}
}

Then it is consumed in attributeHandler.Handle and used as output path in the nested.GetValue call (L26 below):

// Handle returns a unstructured object according to the "binding:env:attribute"
// annotation strategy.
func (h *attributeHandler) Handle() (result, error) {
val, _, err := nested.GetValue(h.resource.Object, h.inputPath, h.outputPath)
if err != nil {
return result{}, err
}
return result{
Data: val,
}, nil
}

The change could be make newAttributeHandler propagate bindingInfo.SourcePath as an empty string, and adjust nested.GetValue accordingly to accept an empty string as output path:

// GetValue attempts to retrieve the value in the given string encoded path.
func GetValue(obj interface{}, p string, o string) (map[string]interface{}, bool, error) {
inputPath := NewPath(p)
outputPath := NewPath(o)
val, found, err := getValue(obj, inputPath)
if err != nil || !found {
return nil, found, err
}
return ComposeValue(val, outputPath), found, nil
}

It is also necessary to adjust ComposeValue as well; perhaps the only change required there is to short-circuit and return val in the case p is empty:

func ComposeValue(val interface{}, p path) map[string]interface{} {
// root is the resulting data-structure to be returned to caller.
root := make(map[string]interface{})
// n is a pointer to the current result node being processed.
n := root
// clean and split the path in `base` and `field`; for example, the path `a.b.*.c` is transformed
// into `a.b.c`, resulting in `a.b` as base and `c` as field.
base, field := p.clean().decompose()
// populate the root structure with the wanted hierarchy; being each node a
// map[string]interface{}.
for _, f := range base {
newVal := make(map[string]interface{})
n[f.Name] = newVal
// move the pointer to the last created value.
n = newVal
}
n[field.Name] = val
return root
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working v0.3.0
Projects
None yet
4 participants