Skip to content

Instantly share code, notes, and snippets.

@ptesny
Last active February 9, 2023 21:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ptesny/382b08659eb8952fda35aedd824c0274 to your computer and use it in GitHub Desktop.
Save ptesny/382b08659eb8952fda35aedd824c0274 to your computer and use it in GitHub Desktop.
jdbc-hana-test

Sample code that demonstrates SAP HANA Cloud official nodejs driver calls from a kyma function

Source

  • handler.js
const hana = require("@sap/hana-client");
const { PerformanceObserver, performance } = require('perf_hooks');
const util = require('util');
const StringBuilder = require("string-builder");


async function hanacloud(event) {
    let queryString = event.extensions.request.query;
    console.log('queryString: ', queryString)
    const urlParams = new URLSearchParams(queryString);

    const connOptions_hdi = {
      serverNode: '*************.hana.prod-****.hanacloud.ondemand.com:443',
      encrypt: "true",
      sslValidateCertificate: "false",
      uid: '*****************_RT', 
      pwd: '*************',

    }; 

    const connOptions_hanadb = {
      serverNode: '***************.hana.prod-****.hanacloud.ondemand.com:443',
      encrypt: "true",
      sslValidateCertificate: "false",
      uid: 'DBADMIN',
      pwd: 'pwd', 

    }; 

    const connOptions = urlParams.has('hdi') ? connOptions_hdi : connOptions_hanadb;
    var t0 = performance.now();

    var dbConnection;
    try {
      dbConnection = await hana.createConnection();
    } catch (err) {
      console.error(err);
      return err.toString();
    }
    
    const schema =  '9DD0EC1FFFD24E1D94E742C25A384AED';

    console.log(urlParams.has('sql'));
    
    const sqlStatement1 = "SELECT * FROM TABLES WHERE SCHEMA_NAME = " + "\'" + schema+ "\'" ;
    const sqlStatement2 = "SELECT * FROM SCHEMAS";  
    const sqlStatement3 = "SELECT * FROM SYS.M_DATABASES";
    const sqlStatement4 = "SELECT * FROM SYS.M_SERVICES";
    const sqlStatement5 = "SELECT * FROM EFFECTIVE_PRIVILEGE_GRANTEES WHERE (OBJECT_TYPE = 'SYSTEMPRIVILEGE') AND (PRIVILEGE = 'EXPORT' OR PRIVILEGE='IMPORT')";
    const sqlStatement6 = "SELECT * FROM USERS";
    const sqlStatement7 = "alter user DBADMIN DISABLE PASSWORD LIFETIME";
    const sqlStatement8 = "select * from users where password_change_time is null and user_name not like '_SYS%' and user_name not like 'XSS%' order by PASSWORD_CHANGE_TIME asc";

    var sqlStatement = sqlStatement1;
    if (urlParams.has('sql')) {
      switch(urlParams.get('sql')) {
        case "1" : sqlStatement = sqlStatement1; break;
        case "2" : sqlStatement = sqlStatement2; break;
        case "3" : sqlStatement = sqlStatement3; break;
        case "4" : sqlStatement = sqlStatement4; break;
        case "5" : sqlStatement = sqlStatement5; break;
        case "6" : sqlStatement = sqlStatement6; break;
        case "7" : sqlStatement = sqlStatement7; break;
        case "8" : sqlStatement = sqlStatement8; break;
      }
    }

    var resultset = 0;
    var resultset2 = 0;
    var perfcounter = 0;

    try {
      console.log('dbConnection.connect')
      await dbConnection.connect(connOptions);
    } catch(err) {
      console.error(err);
      return err.toString();
    }
    
    var execError = null;
    try {
      console.log('dbConnection.exec')
      const rows = await dbConnection.exec(sqlStatement)
      resultset = rows; 
      resultset2 = util.inspect(rows, { colors: false });
      
      console.log(resultset);
      var t1 = performance.now();
      
      perfcounter = "number of rows: " + rows.length + " time in msec " +  (t1 - t0);
      
      console.log(resultset);

    } catch (err) {
      console.error(err);
      execError = err;
    }

    try {
      console.log('dbConnection.disconnect')
      await dbConnection.disconnect();
      if (execError !== null) return execError.toString();
    } catch (err) {
      console.error(err);
      return err.toString();
    }

    let sb = new StringBuilder();
    sb.appendFormat("sqlStatement : {0}", sqlStatement);
    sb.appendLine();
    sb.appendFormat("perfcounter : {0}", perfcounter);
    sb.appendLine();
    
    return sb.append(resultset2).toString();
}


module.exports = { 
  main: async function (event, context) {
      const message = `Hello World`
        + ` from the Kyma Function ${context["function-name"]}`
        + ` running on ${context.runtime}!`;
    console.log(message);   
    const endpoint = event.extensions.request.path;

    switch (endpoint) {

      case "/hanacloud":
        return hanacloud(event);

    }    
    console.log(event.endpoint);
    return message;
  }
}


Dependencies

  • package.json
{ 
  "name": "hana-cloud",
  "version": "1.0.0",
   "dependencies": {
    "@sap/hana-client":"latest",
    "util": "^0.12.5",
    "perf_hooks": "^0.0.1",
    "string-builder": "^0.1.8"
  },
  "devDependencies": {
  }  
}

Base image override

In order to be able to run this function you may need to override the function base image as follows:

image

if the image override is not applied the function may simply fail when trying to connect to hana db as follows:

> nodejs16-runtime@0.1.0 start
> node server.js
user code loaded in 1sec 399.877434ms
Hello World from the Kyma Function hana-cloud running on nodejs16!
queryString: { sql: '4' }
true
dbConnection.connect

............... this does not go through ...................

npm notice
npm notice New major version of npm available! 8.19.3 -> 9.4.1
npm notice Changelog: <https://github.com/npm/cli/releases/tag/v9.4.1>
npm notice Run `npm install -g npm@9.4.1` to update!
npm notice
npm ERR! path /usr/src/app
npm ERR! command failed
npm ERR! signal SIGSEGV
npm ERR! command sh -c -- node server.js
npm ERR! A complete log of this run can be found in:
npm ERR! /tmp/_logs/2023-02-03T08_56_49_266Z-debug-0.log

Additionally, the following issue provides more details: kyma-project/kyma#16674

The unsupported nodejs override images are available here:

Dockerfile.custom.nodej16

FROM node:16.19.0-bullseye-slim

ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
ENV npm_config_cache /tmp/

RUN mkdir -p /usr/src/app \
    && mkdir -p /usr/src/app/lib
WORKDIR /usr/src/app

COPY package.json /usr/src/app/
RUN npm install && npm cache clean --force \

    && apt-get update \
    && apt-get install -y openssl python make g++

COPY lib /usr/src/app/lib

COPY server.js /usr/src/app/server.js

CMD ["npm", "start"]

EXPOSE 8888

and the build command:

  • docker build --platform amd64 -t tiosouji/hc:bullseye-slim16 -f ./Dockerfile.custom.nodejs16 .

Dockerfile.custom.nodej14

FROM node:14.21.2-bullseye-slim



COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]

# Serverless
LABEL source = git@github.com:kyma-project/kyma.git

COPY kubeless/ /

WORKDIR /kubeless_rt/

RUN npm install && npm cache clean --force \

    && apt-get update \
    && apt-get install -y openssl python make g++

USER 1000

CMD ["node", "kubeless.js"]

and the build command:

  • docker build --platform amd64 -t tiosouji/hc:bullseye-slim14 -f ./Dockerfile.custom.nodejs14 .

Appendix

Power of serverless with SAP BTP, Kyma runtime. Base image override. | SAP Blogs

Connect Using the SAP HANA Node.js Interface | SAP Developer Tutorials

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment