This brief is to demonstrate how one can leverage selected SAP BTP Kyma runtime serverless features, namely
Previously demonstrated topic was: |
Requirements and Disclaimers:Sample code: |
Putting it all together.
SAP BTP, Kyma runtime is SAP’s fully managed commercial kubernetes offering, part of SAP Business Technology Platform. It is often bundled with SAP Commerce Cloud and nowadays is becoming an extensibility runtime of choice.
Kyma brings additional components on top of a plain gardener cluster. And serverless is one of them.
Serverless Architecture
The previous instalment demonstrated how to override a base function image.
Another cool and strategic feature with Kyma serverless CRD is the ability to mount secrets as volumes.
Secrets mounted as Volumes
Secrets mounted as Volume is a new feature introduced with the latest kyma release.
This is really useful when using the standard SAP libraries of the likes of xsenv, xssec and others with the BTP services provisioned with the btp service operator. and really essential when it comes to implementing portable, multi-environment services with one single code line.
Let’s have a look at a snippet of a template of a function definition with the secretMounts.
The secretMounts allow to map values of the kubernetes secrets into a function’s volume mount paths. The mounts paths are like the base directories in a folder structure and, combined with the secrets keys names, they become the data paths.
Thus, a function code can easily read secrets keys values from these data paths as if they were files.
apiVersion: serverless.kyma-project.io/v1alpha2
kind: Function
metadata:
name: {{ .Values.services.srv.name }}
labels:
{{- include "app.labels" . | nindent 4 }}
app: {{ .Values.services.srv.name }}
spec:
runtime: {{ .Values.services.srv.runtime }}
env:
- name: SERVICE_BINDING_ROOT
value: /bindings
secretMounts:
- secretName: {{ .Values.services.uaa.bindingSecretName }}
mountPath: "/bindings/fun-uaa"
- secretName: {{ .Values.services.dest.bindingSecretNamex509 }}
mountPath: "/bindings/fun-dest-x509"
- secretName: {{ .Values.services.hdi.bindingSecretName }}
mountPath: "/bindings/fun-hdi"
source:
gitRepository:
Eventually, this is how this works with most of the commonly used SAP libraries. We are using the SERVICE_BINDING_ROOT env variable to define the binding directory root folder (here called binding) to expose the mounted SAP BTP services binding secrets to SAP libraries that may be used in the function code.
This way any code relying on SAP libraries to manipulate the secrets can be used across runtime environments without modifications.
Using standard SAP libraries with mounted secrets
Let’s see how to use SAP HANA Cloud with functions using @sap/hana-client and other SAP libraries.
The below code snippet demonstrates the most commonly used SAP libraries:
- xssec: https://www.npmjs.com/package/@sap/xssec
- xsenv: https://www.npmjs.com/package/@sap/xsenv
- hana-client: https://www.npmjs.com/package/@sap/hana-client
const xsenv = require('@sap/xsenv');
const services = xsenv.getServices({
uaa: { label: 'xsuaa' }
,
hana: { label: 'hana' }
});
const util = require('util');
const xssec = require('@sap/xssec');
const createSecurityContext = util.promisify(xssec.createSecurityContext);
const hana = require('@sap/hana-client');
services.hana.sslValidateCertificate = true;
services.hana.ssltruststore = services.hana.certificate;
const hanaConn = hana.createConnection();
async function queryDB(sql, procedure, param) {
try {
await hanaConn.connect(services.hana);
} catch (err) {
debug('queryDB connect', err.message, err.stack);
results = err.message;
}
try {
await hanaConn.exec('SET SCHEMA ' + services.hana.schema);
if (procedure === undefined) {
results = await hanaConn.exec(sql);
}
else {
let hanaStmt = await hanaConn.prepare(procedure);
results = hanaStmt.exec(param);
}
} catch (err) {
debug('queryDB exec', err.message, err.stack);
results = err.message;
}
try {
await hanaConn.disconnect();
} catch (err) {
debug('queryDB disconnect', err.message, err.stack);
results = err.message;
}
return results;
}
and here goes a couple of simple calls against a SAP HANA Cloud database instance:
const session = await queryDB(`SELECT * FROM M_SESSION_CONTEXT`);
const db = await queryDB(`SELECT SYSTEM_ID, DATABASE_NAME, HOST, VERSION, USAGE FROM M_DATABASE`);
const connections = await queryDB(`SELECT TOP 10 USER_NAME, CLIENT_IP, CLIENT_HOST, START_TIME FROM M_CONNECTIONS WHERE OWN='TRUE' ORDER BY START_TIME DESC`);
Conclusion
This concludes a short excursion into the land of kyma serverless. To help you get started please refer to our Power of serverless with SAP BTP, Kyma runtime code samples here.
Good to know:
- If you needed an easy way to create or scaffold your own kyma serverless samples (both with nodejs and python runtimes alike), please refer to SAP HANA Academy code generators, including the latest kyma serverless fass generator.
- SAP Business Technology Platform – Serverless Functions | Hands-On Tutorial Videos | SAP Blogs
Last but not least, I hope you have enjoyed reading the blog post. Feel free to provide feedback in the comments section below.
SAP Community: https://community.sap.com/
SAP Community Topic Page link: https://community.sap.com/topics/kyma
SAP Community Q&A Tags:
Kyma Open Source: https://answers.sap.com/tags/2936b97d-6a90-4cd8-b635-0e51441611eb
SAP BTP, Kyma runtime: https://answers.sap.com/tags/73554900100800003012
Follow me in SAP Community: Piotr Tesny