cancel
Showing results for 
Search instead for 
Did you mean: 

Destination not found in my multitenant CAP app

marcmaurí
Participant
0 Kudos
40,254

Hello,

In my multitenant CAP app, I got an error when accessing an S/4HANA Cloud via Cloud SDK from my consumer subaccount. It works fine when accessing from my provider. My scenario is the following:

Perhaps it may seem a little weird the own s/4hana cloud system vs the provider subaccount, it is here just for test purposes.

When accessing https://provider-myapp-aa.cfapps.eu10.hana.ondemand.com/mobile/getData(cardTemplate=''), the own s4hc is reached successfully and data is retrieved but doing so from the consumer, https://consumer-myapp-aa.cfapps.eu10.hana.ondemand.com/mobile/getData(cardTemplate=''), I got the following error in the provider app:

2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT error calling api Error: Could not find a destination with name "s4n103C1"! Unable to execute request.
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at Object.errorWithCause (/home/vcap/app/node_modules/@sap/cloud-sdk-core/node_modules/@sap/cloud-sdk-util/dist/error.js:14:20)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at /home/vcap/app/node_modules/@sap/cloud-sdk-core/dist/request-builder/request-builder-base.js:125:78
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at process._tickCallback (internal/process/next_tick.js:68:7)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT Caused by:
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT Error: FetchTokenError: Client credentials Grant failed! Request failed with status code 401
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at Object.errorWithCause (/home/vcap/app/node_modules/@sap/cloud-sdk-core/node_modules/@sap/cloud-sdk-util/dist/error.js:14:20)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at accessTokenError (/home/vcap/app/node_modules/@sap/cloud-sdk-core/dist/scp-cf/xsuaa-service.js:166:29)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at /home/vcap/app/node_modules/@sap/cloud-sdk-core/dist/scp-cf/xsuaa-service.js:43:57
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at process._tickCallback (internal/process/next_tick.js:68:7)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT Caused by:
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT Error: Request failed with status code 401
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at createError (/home/vcap/app/node_modules/axios/lib/core/createError.js:16:15)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at settle (/home/vcap/app/node_modules/axios/lib/core/settle.js:17:12)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at IncomingMessage.handleStreamEnd (/home/vcap/app/node_modules/axios/lib/adapters/http.js:237:11)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at IncomingMessage.emit (events.js:203:15)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at endReadableNT (_stream_readable.js:1145:12)
2020-04-15T09:46:27.639+0000 [APP/PROC/WEB/0] OUT     at process._tickCallback (internal/process/next_tick.js:63:19)

The destination s4n103C1 is created in the provider subaccount and I have made sure that the fields are well filled out. I tried creating the destination in the consumer subaccount and I got the same error.

Let me here remark that accessing other CAP services from the consumer subaccount (i.e https://consumer-myapp-aa.cfapps.eu10.hana.ondemand.com/mobile/books) works fine, the error occurs when accessing backend destinations via Cloud SDK.

The source code that raises the error is:

    var cloud_sdk_core_1 = require("@sap/cloud-sdk-core");
    const { serializeEntity } = require("@sap/cloud-sdk-core");
    
    // building the select fields array
    ....
     
    var jwt = retrieveJwt(req._.req)

    // call api
    const salesOrder = await SalesOrder
      .requestBuilder()
      .getAll()
      .select(...selectFields)        
      .filter(filters)
      .top(top)
      .execute({destinationName: destination, jwt: jwt}) 
      .then(result => result.map(so => serializeEntity(so, SalesOrder)))
      .catch(reason => {
          console.log('error calling api ', reason)
      })

This is my mta.yaml file:

_schema-version: 2.0.0
ID: myapp
version: 1.0.0
modules:
  - name: myapp-db
    type: hdb
    path: db
    parameters:
      memory: 256M
      disk-quota: 256M
    requires:
      - name: myapp-db-hdi-container
  - name: myapp-srv
    type: nodejs
    path: srv
    parameters:
      memory: 512M
      disk-quota: 512M
    provides:
      - name: srv_api
        properties:
          url: ${default-url}
    requires:
      - name: myapp-db-hdi-container
      - name: myapp-uaa    
      - name: myapp_destination
      - name: myapp_connectivity   
    properties:
      SAP_JWT_TRUST_ACL:
       - clientid: "*"
         identityzone: "*"     
      DEBUG : "false"     
  - name: myapp-ui
    type: nodejs
    path: app
    parameters:
      memory: 256M
      disk-quota: 256M
    requires:
      - name: myapp-uaa
      - name: srv_api
        group: destinations
        properties:
          forwardAuthToken: true
          strictSSL: true
          name: srv_api
          url: ~{url}
    properties:
      SAP_JWT_TRUST_ACL:
       - clientid: "*"
         identityzone: "*"  
      TENANT_HOST_PATTERN: "^(.*)-myapp-ui.cfapps.eu10.hana.ondemand.com"            
resources:
  - name: myapp-db-hdi-container
    type: com.sap.xs.hdi-container
    properties:
      hdi-container-name: ${service-name}
  - name: myapp-uaa
    type: org.cloudfoundry.managed-service
    parameters:
      service-plan: application
      service: xsuaa
      path: ./xs-security.json
      shared: true
      config:
        xsappname: myapp-${space}
  - name: myapp_destination
    type: org.cloudfoundry.managed-service
    parameters:
      service-plan: lite
      service: destination
  - name: myapp_connectivity
    type: org.cloudfoundry.managed-service
    parameters:
      service-plan: lite
      service: connectivity      

Any clues with this issue?

Thanks in advance.

Best regards,

Marc

Accepted Solutions (1)

Accepted Solutions (1)

former_member194549
Contributor
0 Kudos

Hi Marc

as dhem already described, did you implement the getDependencies endpoint?

Here we had problems in our solution when we had not implemented this endpoint.

You can create an AppRouter module (@sap/approuter) and execute the getDependencies callback against this module. The AppRouter includes a middleware (lib/middleware/subscription-middleware.js) which can answer these requests.
For the AppRouter to answer the request correctly, you must bind the service instance of the destination service (maybe also the service instance of the connectivity service, but I'm not sure if this is necessary) to the AppRouter. The AppRouter reads the bound services and uses them to create the payload that is returned.

When the getDependencies callback is executed against the AppRouter, it returns an array containing information about the bound service instance of the destination service (and the connectivity service instance if it is bound).

Following a screenshot of the response of our getDependencies Callback handled by a AppRouter module.

Regards
Simon

marcmaurí
Participant
0 Kudos

Hi Simon,

if I understood correctly, only with an Approuter module (I already have it) and without coding any additional handler to process the request, I can execute the onboarding and getDependencies callbacks against this module. Did I get it right?

But, how did you configure the route in xs-app.json? What do you set in destination/localDir/service parameters for the route? One of these is mandatory.

        {
            "source": "^/callback/(.*)$",
            "target": "/callback/$1",
            "authenticationType": "xsuaa",
            "destination": ...
        }

I have not found any documentation on how to implement it, just some additional mention that it is possible to do so.

Thanks in advance.

Regards,

Marc

former_member194549
Contributor
0 Kudos

Hi Marc,

you got that right and you don't have to define a route.

All you have to do is create a service instance of the saas-registry service, set the URIs for onSubscription and getDependencies (in many documentation you will find the paths callback/v1.0/tenants/{tenantId} and callback/v1.0/dependencies here, but they can be different) and bind the service instance to your router.

The XSUAA service must be configured correctly and bound to the AppRouter (tenant-mode, grant-as-authority-to-apps, Scope $XSAPPNAME.Callback (Link)) and the AppRouter also needs the TENANT_HOST_PATTERN (Link).

You do not need to configure any routes for the subscription.

Note
The AppRouter does not forward the requests where the path matches the path of the URIs in the saas registry.

Take a look at node_modules/@sap/approuter/lib/middleware/subscription-middleware.js of your AppRouter module. There you will find the middleware.

Regards
Simon

marcmaurí
Participant

Hi Simon,
thanks for sharing such exhaustive details. I guess I forgot to recreate some service in my first try because the configuration was as you explain. Now it works like a charm.

So, in summary, both approaches works fine, but this one based on Approuter doesn't need any coding and is easier to implement.
Thanks for your support sperstorfer and dhem!
Best regards,
Marc

Answers (0)