Skip to Content

Introducing

In this blog we will cover how we can use the “Node JS” wrapper to get the possibility to access SAP Cloud Platform IoT Application Enablement OData services with SAP Analytics Cloud (SAC).

Please have also a look at the other blogs in the series about SAP Cloud Platform IoT Application Enablement:

Why?

Currently SAP Analytics Cloud cannot handle OAuth based authentication, which is provided by SAP CP IoT AE.

Therefore we need a little “magic” or simple a wrapper to allow this.

Please also refer, to this blog by Lukas Brinkmann to get a deeper knowledge about this here. This blogs describedes how u can run the wrapper locally.

But anyway our target is to run this “SAP Cloud Platform Cloud Foundry Environment” with the “node js buildback”.

 

Sceanrio

In detail we will cover in this blog how to setup and develop and deploy our proxy application on the SAP Cloud Platform Cloud Foundry Environment:

 

Prerequisite please ensure that “node.js” is probably installed on your device.

If not u can get your version here: https://nodejs.org/en/

Start and Fork !

The first task were we start now is to fork the SAP provided repository:

Otherwise you got some nice errors like this.

-----> Building dependencies
          Installing node modules (package.json)
   npm ERR! fetch failed http://nexus.wdf.sap.corp:8081/nexus/repository/build.milestones.npm/brace-expansion/-/brace-expansion-1.1.8.tgz
   npm ERR! fetch failed http://nexus.wdf.sap.corp:8081/nexus/repository/build.milestones.npm/boom/-/boom-2.10.1.tgz

The reason, is based on the “npm-shrinkwrap.json” file in the repository, this files reference to an “internal” SAP server which is not accessible during the cloud foundry build. We create later our own “npm-shrinkwrap.json” file which will reference to the “npm” sources which are accessible from the SAP CP Cloud Foundry Environment.

npm-shrinkwrap.json:

{
  "name": "@sap/sap-iot-ae-node-wrapper",
  "version": "1.3.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "acorn": {
      "version": "5.1.2",
      "resolved": "http://nexus.wdf.sap.corp:8081/nexus/repository/build.milestones.npm/acorn/-/acorn-5.1.2.tgz",
      "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==",
      "dev": true
    },
    "acorn-jsx": {
      "version": "3.0.1",
      "resolved": "http://nexus.wdf.sap.corp:8081/nexus/repository/build.milestones.npm/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
    
.......

After you have successfully forked the repository:

Delete the already mentioned “npm-shrinkwrap.json” file from your newly forked repository.

 

Step 1 – Create your “proxy” application locally

To create our proxy “node js” application we start to execute the following “npm” command.

npm init

Afterwards we specify our setup in detail:

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

Press ^C at any time to quit.
name: (sap_proxy)
version: (1.0.0)
description:
entry point: (index.js) app.js
test command:
git repository:
keywords: 
author: 
license: (ISC)
About to write to \sap_proxy\package.json:

{
  "name": "sap_proxy",
  "version": "1.0.0",
  "description": "sap cp iot ae proxy app",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this ok? (yes)

 

In the next step we adjust the created “package”.json” file to load the required dependencies in this way.

{
  "name": "sap_proxy",
  "version": "1.0.12",
  "description": "",
  "main": "iot-application-services-sdk-nodejs.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
  	"basic-auth": "^1.1.0",
    "express": "^4.15.4",
    "morgan": "^1.8.2",
    "winston": "^2.3.1",
    "sap-iot-ae-node-wrapper": "https://github.com/fableh/iot-application-services-sdk-nodejs"
  },
  "author": "",
  "license": "ISC"
}

 

Execute now:

npm install

and

npm shrinkrwrap

 

Create and modify the deployment descriptor “manifest.yaml” for the application:

---
applications:
- name: sap_proxy
  buildpack: nodejs_buildpack
  command: node app.js
  memory: 128M
  disk_quota: 128M
  host: sap_proxy

Finally we create a application “app.js”.

The complete app can be found on GitHub: https://github.com/fableh/sap_cp_cf_iot_ae_proxy/blob/master/app.js

Some interesting things of the app are described in the following lines.

OAuth settings:

var nodeAE = new NodeAE({
	clientId: '<SAP CP IoT AE Client ID>',
	clientSecret: '<SAP CP Client Secret>',
	tenant: '<your sap cp cf tenant>',
	landscape: 'eu10',
	host: 'hana.ondemand.com'})

Update:

Instead of using the OAuth credentials “hard coded” in the node js application

We can use Cloud Foundry Environment Variables

In this case we need to do some simple steps.

  • Create a “user provided service”:
cf create-user-provided-service my-usp-sap-proxy -p "{\"clientId\":\"sb-iotas_consumer!t5\",\"clientSecret\":\"7tfVLqJDzsLEnpy5gwJhWXZlOXMFXb\", \"tenant\":\"sycor-cf-subaccount\", \"landscape\":\"eu10\", \"host\":\"hana.ondemand.com\"}"
  • Adapt the deployment descriptor an add the “services” definition:
---
applications:
- name: sap-proxy
  buildpack: nodejs_buildpack
  command: node app.js
  memory: 128M
  disk_quota: 128M
  host: sap-proxy
  services:
    - my-usp-sap-proxy
  • Finally change the coding of your “app.js” in this way to acces the newly provided variables:

 

....
var cfenv = require('cfenv')

var appEnv = cfenv.getAppEnv()

var nodeAE = new NodeAE({
    clientId: appEnv.getService('my-usp-sap-proxy').credentials.clientId,
    clientSecret: appEnv.getService('my-usp-sap-proxy').credentials.clientSecret,
    tenant: appEnv.getService('my-usp-sap-proxy').credentials.tenant,
    landscape: appEnv.getService('my-usp-sap-proxy').credentials.landscape,
    host: appEnv.getService('my-usp-sap-proxy').credentials.host

}) 

.....

 

Please check also my updated Github repository here: https://github.com/fableh/sap_cp_cf_iot_ae_proxy


The user and password for our “Basic” authentication:

    if (user.name === 'sap' && user.pass === 'communityrockz') {
        return next();
    } else {
        return unauthorized(res);
    };
};

Finally this part of the application handle how we can access our “OData” service from SAP Analytics Cloud:

const propertySet = 'iotae.sycor.syc.sap.blogs.notebooks:CPU';

app.get('/app.svc/*', auth, function (req, res) {
    const url = req.originalUrl.slice(9, req.originalUrl.length).replace('$inlinecount=allpages&', '');
    console.log(url);

    const response = nodeAE.openGetStream('https://analytics-thing-sap.cfapps.eu10.hana.ondemand.com/' + propertySet + '/' + url);
    response.then(
        function success(stream) {
            stream.pipe(res)
        },
        function error(err) {
            logger.error(err)
        }
    )
})

 

Push the app to “Cloud Foundry”

After we’ve successfully logged in:

>cf login
API endpoint: https://api.cf.eu10.hana.ondemand.com

Email> fabian.lehmann@sycor.de

Password>
Authenticating...
OK

And select our organization and space:

Select an org (or press enter to skip):
1. <cf trial org>
2. <cf prod org>

Org> 2
Targeted org <cf prod org>

Select a space (or press enter to skip):
1. iot
2. ml

Space> 1
Targeted space iot

API endpoint:   https://api.cf.eu10.hana.ondemand.com (API version: 2.100.0)
User:           fabian.lehmann@sycor.de
Org:            <cf prod org>
Space:          iot

Now we push the application to “Cloud Foundry”:

cf push sap_proxy

We can detect that our app is successfully started and running:

Exit status 0
Successfully destroyed container
1 of 1 instances running
App started
OK
App sap_proxy was started using this command `node app.js`

Showing health and status for app sap_proxy in org <cf prod org> / space iot as fabian.lehmann@sycor.de...
OK

requested state: started
instances: 1/1
usage: 128M x 1 instances
urls: sap-proxy.cfapps.eu10.hana.ondemand.com
last uploaded: Wed Jan 24 12:23:13 UTC 2018
stack: cflinuxfs2
buildpack: nodejs_buildpack

     state     since                    cpu    memory        disk            details
#0   running   2018-01-24 01:23:48 PM   0.0%   30M of 128M   43.7M of 128M

And yes of course also on the SCP CF cockpit.

If we now enter the “base” url plus the correct path to the time series OData service, we got now a popup to authenticate:

And finally we got the metadata information about our calles service:

 

Conclusion

First of all big kudos to Christian for the support !

I think this is a nice example how we can benefit from the node js buildback which we´ve in place at the “Cloud Foundry Environment”.

And yes of course we´ve here only a simple app, but this works as expected!

Hopefully SAP Analytics Cloud will provide us in one of the next versions with the capability to use  OAuth based authentification!

 

In the next blog, we will see how we can load the data into SAP Analytics Cloud and start to build up a little story (dashboard).

 

Please feel free to ask me if something is not well explained.

 

Helpful links

SAP Cloud Platform IoT Application Enablement Services

Node js

NPM

Cloud Foudry developer guide

SAP IoT Application Enablement SDK for Node.js on GitHub

Node js application used in the blog on GitHub

SAP Cloud Platform Cloud Foundry Environment

Cloud Foundry Environment Variables

Cf env on Github

 

cheers,

fabian

 

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Christian Schuerings

    Hi Fabian,

    excellent summary of how to connect IoT Application Enablement to SAP Analytics Cloud via a custom proxy application.
    Always happy to help you!

    Regards
    Christian

     

    (2) 
  2. Former Member

     

     

    HI Fabian,

    I thoroughly enjoyed reading your blog series. Excellent summarization and collection for the component, SAP IoT Application Enablement (IoT AE).

    Also please share for what use cases (or scenarios) you are using IoT AE.

    Regards,
    Smitha

    (0) 

Leave a Reply