Skip to Content
Technical Articles

Service Instances | SAP Cloud Platform – Cloud Foundry

This blog post series is about developing applications in a multicloud environment.

  1. Cloud Foundry, Neo, and multicloud environments
  2. Cloud Foundry, UAA, and XSUAA
  3. Business Logic App
  4. Service Instance (SAP HANA Cloud)
  5. Application Router
  6. Authentication using XSUAA
  7. Authorization using XSUAA
  8. Application Runtime (appendix)

Questions? Post as comment.

Useful? Give a like and share on social media. Thanks!

/wp-content/uploads/2016/02/sapnwabline_885687.png

Hands-On Tutorials

Developing Secure Applications on the SAP Cloud Platform

In this blog series, we explore developing secure applications in a multi-cloud Cloud Foundry environment. In the previous blog, we covered the Business Logic App with deliberately very basic code samples in Node.js, Python, and Java as to focus on how these apps are deployed and can be configured in the Cloud Foundry environment.

In the this blog we are going to add Service Instances to the app, as common for 12-factor apps and in micro-services architectures. For this, we use the Cloud Foundry marketplace. Here we can find many services that enable the developer to focus on the business issue and not on the supporting infrastructure.

For persistence our app uses two services:

  • SAP HANA Cloud
  • SAP HANA Schema and HDI Containers

We will use the SAP HANA client for Python and Node.js plus some additional packages/modules to parse Cloud Foundry environment variables and build the connection string.

Sample Code

We continue with the (slightly modified) sample code from SAP Cloud Platform documentation for our Python sample:

For Node.js, we switch to the SAP HANA platform XS Advanced environment (powered by Cloud Foundry)

You can download the sample code from repository

Appendix

For more detailed information about the SAP Cloud Platform trial environment, Cloud Foundry buildpacks, dependencies declarations, attributes, Diego cells and more, see the “appendix” blog

/wp-content/uploads/2016/02/sapnwabline_885687.png

Create Service Instance

What’s the Plan?

To discover which services are available, we can query the marketplace with the cf marketplace command. Each Cloud Foundry environment (SAP Cloud Platform, IBM Cloud, Pivotal, etc.) will have a different menu. SAP HANA-related services are specific to the SAP Cloud Platform, for example.

As documented in the Cloud Foundry documentation

cf m
cf m -s hana-cloud-trial
cf m -s hana

Service Plan hana

The following services are available

  • hana-cloud-trial = SAP HANA Cloud
  • hana = schemas and containers for SAP HANA Cloud
  • hanatrial = schemas and containers for SAP HANA Service

The SAP HANA Service (hana-db) itself is no longer available on the trial.

For information about SAP HANA-specific plans, see the SAP HANA documentation. We can bind an application to the SAP HANA Cloud instance or simply to an HDI container. For this we can use the hdi-shared plan.

As the same plans also exist for XS Advanced, see also the platform documentation as this provides a bit more information on the topic.

For some background about how Cloud Foundry and XS Advanced relate, see

Create Service Instance

For this tutorial example, we need to create a service instance for an HDI container on SAP HANA Cloud.

The cf create-service command requires SERVICE, PLAN, and a service instance NAME. You use this name to refer to your service instance with other commands. The name is just a label and can be renamed at any time using the cf rename-service command. To make change to the service use cf update-service and delete the service use cf delete-service.

As documented in the Cloud Foundry documentation

For the Cloud Foundry CLI Reference Guide, see

hana-cloud-trial

We can use the same create-service command to create an SAP HANA Cloud instance.

cf create-service hana-cloud-trial hana hanacloudtrialdb 
-c '{"data":
      {"edition":"cloud",
       "memory":30,
       "systempassword":"Initial1",
       "whitelistIPs":["0.0.0.0/0"]}}'
cf service hanacloudtrialdb 

How to create an SAP HANA Cloud service instance using the cf CLI, see

Note that we first need to create database before we can create a schema (make sense) otherwise the message is returned

FAILED: There is no database available

hdi-shared

cf create-service hana hdi-shared hdicontainer-1

Services

The cf services command lists all available services. To get more information about a specific service use the cf service command with the name of the service.

As documented

cf services
cf service hdicontainer-1

Services in SAP Cloud Platform Cockpit

The Service Instance menu at the Cloud Foundry space level shows the same information with the option to run related service commands (cf update-service, etc.)

/wp-content/uploads/2016/02/sapnwabline_885687.png

Deploy an App – Python

To make use of a service we first need to bind the service to our app. Depending on the service, you can bind service instances to apps and/or routes. For this we can use the cf bind-service command. Alternatively, we can also bind services to app using the app manifest file.

As documented,

App Manifest

We continue with the manifest.yml where we left off in our previous blog post. As discussed, the name and (start) command are required (for Python). Optionally, define buildpack, memory and disk quota.

For the service binding, add a services: entry listing the HDI container service instance.

---
applications:
- name: myapp-hana
  buildpacks:
  - python_buildpack
  random-route: true
  path: myapp-hana
  memory: 128M
  disk_quota: 512M
  command: python server.py
  services:
    - hdicontainer-1

Note that unlike most application attributes (buildpack, memory, etc.) we cannot pass the service binding as command line parameter.

Business Logic

To connect to a database, you need a database client. Here we are using the Python dbapi as provided by the SAP HANA client library hdbcli.

As documented in the Python Package Index (PyPI)

But where do we get the connection information from? From the bound service! For this, we need the AppEnv function from the Cloud Foundry environment library (cfenv).

As documented in the Python Package Index (PyPI)

import os
from flask import Flask
from cfenv import AppEnv
from hdbcli import dbapi

app = Flask(__name__)
env = AppEnv()

hana_service = 'hana'  
hana = env.get_service(label=hana_service)

@app.route('/')
def hello():
    if hana is None:
        return "Can't connect to HANA service '{}' – check service name?".format(hana_service)
    else:
        conn = dbapi.connect(address=hana.credentials['host'],
                             port=int(hana.credentials['port']),
                             user=hana.credentials['user'],
                             password=hana.credentials['password'],
                             encrypt='true',
                             sslTrustStore=hana.credentials['certificate'])

        cursor = conn.cursor()
        cursor.execute("select CURRENT_UTCTIMESTAMP from DUMMY")
        ro = cursor.fetchone()
        cursor.close()
        conn.close()

        return "Current time is: " + str(ro["CURRENT_UTCTIMESTAMP"])

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=int(os.getenv("PORT", 5000)))

Requirements

For our business app to make the required library calls, we need to add them to the requirements.txt file. The exact version numbers are optional in our case.

Flask
cfenv
hdbcli

Push

The three files to deploy are the app manifest, the Python source code file with the business application logic and the requirements file for the Python package manager pip.

Environment

Like the Business Logic App, we can request the environment variables for the bound services using the cf env command.

As documented in the Cloud Foundry documentation and the Cloud Foundry CLI Reference Guide

cf env myapp-hana

SAP Cloud Platform Cockpit

The hdcontainer-1 service instance contains connection information.

The service is bound to myapp.

The connection information is then passed as environment variables to myapp.

Using app binding and environment variables, our business logic app connects to other services.

/wp-content/uploads/2016/02/sapnwabline_885687.png

Build an App – Node.js

Running the App Locally

As before, generate the package descriptor (package.json) and install the dependencies.

mkdir myapp-hana && cd myapp-hana
npm init -y
npm install @sap/hana-client --save

 

To the package descriptor, add the client as dependencies. For Cloud Foundry deployment add the version of the Node engine and the start command.

{
  "name": "myapp-hana"
  ...
  "dependencies": {
    "express": "latest",
    "@sap/hana-client": "latest"
  },
  "engines": {
    "node": "10.x.x"
  },
  "scripts": {
    "start": "node server.js"
  }
}

Business Logic (server.js)

Below the business logic of our app which will query the database and return the contents on a web page (with minimal formatting and error handling).

// hana
var hana = require('@sap/hana-client');
var conn = hana.createConnection();
var conn_params = {
  serverNode: '<UUID>.hana.trial-eu10.hanacloud.ondemand.com:443',
  uid: '<user>',
  pwd: '<password>',
  encrypt: 'true',
  sslValidateCertificate: 'false'
};
var sql = "select * from SYS.M_DATABASE";

const express = require('express');
const app = express();
const port = process.env.PORT || 3000;

app.get('/', function (req, res, next) {
  conn.connect(conn_params, function(err) {
    var rows = conn.exec(sql, function (err, rows) {
      res.send(rows);
    conn.disconnect();
    });
  })
});

app.listen(port, function () {
  console.log('myapp listening on port ' + port);
});

For more information about the Node.js driver for SAP HANA, see

/wp-content/uploads/2016/02/sapnwabline_885687.png

Deploy an App – Node.js

As we put all the configuration in the business logic file, we can deploy the app as before but obviously, hardcoded passwords and connection strings is not ideal, so let’s refactor our app to make use of the service instances.

Application Descriptor (package.json)

As with Python, we need to add the modules to our dependencies:

  • SAP HANA client to make the database connection
  • XS env to parse Cloud Foundry environment variables (an SAP adaption of cfenv)
  • HDB extension to build the connection string

For more information about cfenv, see

To install the packages locally use commands.

npm install --save @sap/hana-client
npm install --save @sap/xsenv
npm install --save @sap/hdbext

This will added the dependencies to the application descriptor (package.json).

  "dependencies": {
    "@sap/hana-client": "latest",
    "@sap/hdbext": "latest",
    "@sap/xsenv": "latest",
    "express": "latest"
  },

Business Logic (server.js)

We need to modify our business logic and

  • Add xsenv and use it to get the environment variables of the service instance hdicontainer-1
  • Add hdbext to act as middleware

Compare this file with our Python implementation above and note

  • the use of xsenv instead of cfenv
  • how hdbext takes care of creating and closing the connection
var express = require('express');
var app = express();
var xsenv = require('@sap/xsenv');
var services = xsenv.getServices({ hana:'hdicontainer-1' });
var hdbext = require('@sap/hdbext');
var sql = "select * from SYS.M_DATABASE";

app.use('/hana', hdbext.middleware(services.hana));

app.get('/hana', function (req, res, next) {
    req.db.exec(sql, function (err, rows) {
    if (err) { return next(err); }
    res.send(rows);
  });
})

app.get('/', function (req, res) {
  res.send('Hello World!');
});

var port = process.env.PORT || 3000;
app.listen(port, function () {
  console.log('myapp listening on port ' + port);
});

Update the manifest to bind our app to the service instance

---
applications:
- name: myapp
  path: myapp
  random-route: true
  services:
    - hdicontainer-1

When we access the root (/), the app returns a message.

When we access /hana, the app queries the database.

/wp-content/uploads/2016/02/sapnwabline_885687.png

Please Proceed

In the next blog we start to connect our business application with Cloud Foundry service instances.

/wp-content/uploads/2016/02/sapnwabline_885687.png

Share and Connect

Enjoyed the blog? Post a comment, share on social media, and/or give a like. Thanks!

If you would like to receive updates, connect with me on

Best,

Denys van Kempen

Be the first to leave a comment
You must be Logged on to comment or reply to a post.