Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
CarlosRoggan
Product and Topic Expert
Product and Topic Expert
With other words:

How to write serverless function
in
SAP Cloud Platform Serverless Runtime
and using
Service Registration
aka
Credential Store
to reference
Platform Services


This blog is part of a series of tutorials explaining how to write serverless functions using the Functions-as-a-Service offering in SAP Cloud Platform Serverless Runtime

Quicklinks:
Local development
Quick Guide
Sample Project


The previous blog was not good
Why?
Too complicated
The same can be achieved more easily using the Service Registration feature offered by FaaS
What's this?
Let's see:

In the previous blog,
we created a service instance and service key
we created a project
we created a file to store the service key
we created a secret pointing to the file

To facilitate using a service instance, FaaS offers a feature to register a service instance in FaaS
This means that we don't need to create a secret anymore
We just reference the registered service
Furthermore, the service is registered globally in FaaS, making it available for all projects

In this tutorial, we're going to learn how to use the service registration feature in the Extension Center but also how to achieve the same with the command line client for local development

As example, we're going to use the platform service Enterprise Messaging, and we'll connect our function to it.
Our scenario is:

Whenever a message is sent to Messaging,
then our function will be triggered
and it will do nothing

Prerequisites



Preparation


In this tutorial, we want to learn how to register a service instance.
As such, the first step is to create such instance
A nice side-effect: we learn how to connect FaaS to Enterprise Messaging

If you aren't familiar at all with messaging, you can have a look in a rough description I wrote here

Command line users see here

1. Create instance of service Enterprise Messaging


We create an instance of the Enterprise Messaging service.
We use the following JSON parameters:
{
"options": {
"management": true,
"messagingrest": true,
"messaging": true
},
"rules": {
"topicRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
},
"queueRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
}
},
"version": "1.1.0",
"emname": "faas_msg_client",
"namespace": "comp/busi/crm"
}

And as name for the service instance, we enter faas_msg_instance

Note:
As you know, I like to use silly names in my tutorials, I believe it makes the learning easier, because the name always tells what it is about and it makes clear that an arbitrary name can be chosen
Of course, it is not recommended to use silly names in productive environment

Note:
If you don't find the Messaging service, you might need to configure Entitlements

2. Create Service Key for the instance


After creating the service instance, we need a Service Key.
It provides credentials which allow to access the service externally, without binding an application

To create a service key, we have to click on the newly created service instance
In our example, we enter the name as faas_service_key
We don’t close the browser page, we will need to view the service key content later on

3. Configure Messaging


After creating the messaging instance, we can open the messaging dashboard.

We go to messaging client created above (property "emname": faas_msg_client)


We create queue with name queue/for/faas
This will result in full queue name comp/busi/crm/queue/for/faas
The queue is used for receiving and queuing messages.


That's it for the preparation.

Small Recap:
We've created messaging instance and service key
We've created a queue in our client

Extension Center


Now we want to use this service in a Function
I've promised that it is easy.
Yes

1. Register Service Instance


FaaS provides built-in support for connecting to Platform services
Prerequisites are: service instance and service key
Fortunately, we just created both in the chapter above
So we’re lucky enough to use them
The FaaS feature to support the Platform services includes a kind of service registration
Independent of any specific function project, we can register a service instance in the FaaS runtime
It will safeguard the service instance credentials against any malicious phishing hooks
No secret required, no tedious copy&pasting of clientids and so on
And whenever we need it, we can just use it

I like to compare it to a dog show in a circus:
If you say "hepp", the dog will jump, etc
If you say “enterprise-messaging”, the function will connect to the registered service instance
(BTW, why I’ve never seen a cat show in a circus…?)


How to register a service instance?

In Extension Center, we don’t click on “Extensions”
We don’t create any project
Instead, on the left menu pane, we expand “Configurations” and click on “Extensions”
Yes, it's quite similar name
The "Extension Credentials" screen is shown


Here we can store credentials of a service instance. As mentioned above, the service key of a service instance is used for external access.
Since we cannot bind a function to a service, it will always be external.
Problem?
No.

In the “Extension Credentials” screen we can register a service instance.
It is clear that changes in this screen are not related to individual projects.
Services are registered globally in FaaS and can be used by multiple projects (extensions)
With other words: using the Extension Center, we can store credentials.

So let's go ahead and press “New Credentials”
In the creation dialog, we have to enter following values:

Type:
This is the service offering of the SAP Cloud Platform, the service names as displayed in the service marketplace. Luckily, we have tool support, such that we don't need to look up the type names.
For our example, we choose "enterprise-messaging"

Service Instance:
Here we enter the name of the instance of the Enterprise Messaging service which we created in the preparation section above.
In our example: faas_msg_instance

Service Key:
Similarly, we enter the name of the service key created above
In our example: faas_service_key

Credentials:
Here we enter the value of the service key.
Remember I told you to not close the browser window...?



2. Use Registered Service


As we’ve seen, the service is registered in the FaaS runtime on global level
With other words, we've stored service credentials in the Extension Center
Now we can use it in a project
So let’s create a new Faas Project, or, with other words, a new Extension

Create Extension

In our example, we create an extension that consumes messages from a message queue and writes any silly statement to the log

In the creation wizard, we choose use the "Blank Template"
And we give a name like "tracker"

Create Function

We create a new Function with the following sample values:















Function Name tracker-func
Module Name trackerimpl.js
Handler Name msgreceiver

The function implementation could be as follows:
module.exports = { 
msgreceiver: function (event, context) {
console.log(event.data)
}
}

As usual, to keep the code simple and readable, the function implementation does:
nothing.
Just log the payload of the received message
In a productive scenario, the function would do anything more interesting, process the message and call any other component of the extension scenario
(Otherwise it would be a shame: wake up the function, just to do nothing...)

Create AMQP Trigger

In Extension Center, press "Add Trigger" and choose type AMQP
Step through the wizard and enter the following values:

Step 1:
Trigger Name: amqp-tracker-tricker

Step 2:
Incoming link name: msg-to-faas-link
Source Address: queue:comp/busi/crm/queue/for/faas
With other words: the full queue name as created in the preparation section, preceded by "queue:"
To add the link, we press the PLUS icon

Step 3: Outgoing Link:
We don't enter anything here
Only press “step 4”

Step 4: Rules
Filter: msg-to-faas-link
Invoke Function: tracker-func
On failure: reject message
And we press the +

Step 5: Credentials
Press “use existing credentials store”
Type: enterprise-messaging
Instance: faas_msg_instance
Key: faas_service_key

Finally confirm and close the wizard

We can check the extension project to verify what the wizard has done for us:

In file system:
Created folders to carry config files
Created config files to carry the configs
Created configs for the messaging trigger, containing the config we entered in the wizard

In faas.json:
Defined a reference to the service which we registered in FaaS (Credentials store)
Defined a config map (generated name)
Defined the trigger which uses the config and the service-reference

Small recap
Connecting a function to messaging involves:
Create and use service registration (alternatively, use secret)
Create AMQP triger and configure it with queue / topic names and rules

3. Run the scenario


Remember the scenario:
A message is sent to the Messaging service, which causes the AMQP-trigger to wake up the function
Fortunately, the dashboard offers a little tool which allows to send messages.

So we go to the Enterprise Messaging dashboard
To send a message to the queue which we defined above:
We select the messaging client created above
We select the Tab “Test”
We choose Action as “Publish Message to a Queue”
Then we select our queue
Obviously, we enter a silly useless message
Finally, we press “Publish”


What's happening now?

The Test tool has sent a message to the queue
We can see in the same tool ui, that the “Number of Messages” has been increased from 0 to 1
The message would wait there in the queue until it is picked up
(That’s why a queue is called queue)
Now, we have somebody who is watching that queue and picks the messages which are dropped there:
Yes.
Us.
OK, but also the AMQP trigger is watching the queue (we configured it)
And whenever an innocent message falls into the queue, the trigger will wake up the function
Before it wakes up the function, the trigger checks the rules, of course
The function then receives the message in the parameter “event”
Like that, the function implementation can access the message payload
That's what we did
And the function can do something with the payload
That's what we didn’t do
Since the trigger has picked the message from the queue, the “Number of Messages” in the dashboard is reduced from 1 to 0
We can check that in the dashboard (Queues tab)

What we need to check as well: the FaaS log
Here we can see the log output which was written by our function.


This makes our little scenario complete:
A message is sent to Enterprise Messaging and the connected FaaS reacts and reads the message

Local Development


The following description is meant for those of you who are used to work locally and interact with FaaS using the command line
Since you're anyways the experts, I'm only giving some useful commands
No explanations

Preparation


Create instance of Enterprise Messaging service:

cf cs enterprise-messaging default faas_msg_instance -c <jsonFileWithParams>

Create service key

cf csk messaginginstance serviceKeyForMessaging

View the created service key

cf service-key faas_msg_instance faas_service_key

It is not required to copy the content
However, we will need to view the ID of the messaging service instance
So don't close this command shell



1. Register Service Instance


Very first step: login to cloud foundry using the CF CLI

cf login

First step: login to the FaaS runtime using the FaaS CLI

xfsrt-cli login

Or we might want to check to which subaccount our FaaS CLI is currently pointing at

xfsrt-cli target

Now, to register an existing instance of Enterprise Messaging in FaaS, we use the following command

xfsrt-cli faas service register -s faas_msg_instance -b faas_service_key

Syntax:

xfsrt-cli faas service register
--service-name <name of instance>
--service-binding <name of service key>

Note:
You need to be logged in Cloud Foundry using the CF CLI
If not, you might get an error message and it might be required to execute the service-registration command twice

Note:
The FaaS CLI is so convenient that it proposes the existing service instances, so we can skip the parameters of the command


I have to repeat that the FaaS CLI is a really great and convenient tool

Few more commands:

To view already registered service instances:

xfsrt-cli faas service list

To unregister a service instance

xfsrt-cli faas service delete

then wait and choose the desired service

2. Use Registered Service


Create a project

On our local file system, we create a project based on the sample code in the appendix

To use the registered service, we define a reference to it
"services": {
"cs1": {
"type": "enterprise-messaging",
"instance": "a1b2c3d4-a1b2-1234-a1b2-a1b2c3d4e5f6",
"key": "faas_service_key"

Then we can use the service reference in our trigger:
"triggers": {
"amqp-tracker-tricker": {
"type": "AMQP",
"service": "cs1",

Note:
In the faas.json, which is the manifest of our project, we define a reference to a registered service. Like that, we can use it in our project. The reference points to the registered service instance. It has to point to the unique name of the service instance. Otherwise there might be name clashes. As such, we have to look for the instance ID. We find it in the service key content

Deploy

Jump into the project root directory (same folder where faas.json is located) and execute

xfsrt-cli faas project deploy

Note:
Even for service references it is possible to provide deploy values, as described here

3. Run the scenario


To run our scenario, send messages from Enterprise Messaging Dashboard and make sure that they are consumed (number of messages in the queue must decrease to 0)

Check the logs to view if our function works as expected
Jump into the project folder (to make the command easier), then execute

xfsrt-cli faas project logs

In the logs we can see the payload of the messages that we send

Summary


In this tutorial we've learned how to register an existing service instance in FaaS
With other words, we've learned how to store credentials in Extension Center
And we've learned how to use them in a FaaS project
To showcase it, we've used an instance of Enterprise Messaging service.
More precisely, we've used the registered service from an AMQP trigger

Troubleshooting


If you have headache because messages aren't arriving in Messaging Queue, you should check this guide

Quick Guide


An existing service instance can be registered globally in FaaS (service key is required)
In Extension Center, it is done via top level menu "Configuration"
With command line: xfsrt-cli faas service register

To use the registered service (credentials) in a faas.json:
Define new service reference under element "services"
Use service reference from trigger definition
Also (not covered in this blog), the stored credentials can be accessed from function code

Appendix: All Sample Project Files


I’ve downloaded the project from Extension Center and for your convenience, pasting the file content here
Note that I would have chosen different names, where it is visible that names were generated by Extension Center

Note:
In the faas.json we have to enter the ID of the instance of the Enterprise Messaging service.
When registering the service instance, we can choose the instance by name
However, when defining the reference in the faas.json, we have to enter the ID
To retrieve the ID, proceed as follows
Go to chapter "Preparation->Create Service Key" and copy the value of property instanceid
If you coincidentally closed the window, proceed as follows
Open the content of the service key with command csk
Then search for the property instanceid (usually at the end of the json )
The value of the instanceid usually looks like this:
a1b2c3d4- a1b2- a1b2- a1b2- a1b2c3d4e5f6
This has to be entered as value for the property instance in the faas.json


package.json
{}

faas.json
{
"project": "tracker",
"version": "0.0.1",
"runtime": "nodejs10",
"library": "./lib",
"configs": {
"amqp-tracker-tricker-config": {
"source": "./data/amqp-tracker-tricker-config"
}
},
"functions": {
"tracker-func": {
"module": "trackerimpl.js",
"handler": "msgreceiver",
"timeout": 180
}
},
"triggers": {
"amqp-tracker-tricker": {
"type": "AMQP",
"service": "cs1",
"config": "amqp-tracker-tricker-config"
}
},
"services": {
"cs1": {
"type": "enterprise-messaging",
"instance": "c2ab778a-0c68-4523-b7df-ce188bc67337",
"key": "faas_service_key"
}
}
}

amqp.json
{
"incoming": {
"msg-to-faas-link": {
"sourceAddress": "queue:comp/busi/crm/queue/for/faas"
}
}
}

bind.json
{
"functions": {
"tracker-func": {}
},
"rules": [
{
"filter": {
"incoming": "msg-to-faas-link"
},
"action": {
"function": "tracker-func",
"failure": "reject",
"content": "application/json"
}
}
]
}

trackerimpl.js
module.exports = { 
msgreceiver: function (event, context) {
console.log(event.data)
}
}

Params for messaging instance:
{
"options": {
"management": true,
"messagingrest": true,
"messaging": true
},
"rules": {
"topicRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
},
"queueRules": {
"publishFilter": [
"${namespace}/*"
],
"subscribeFilter": [
"${namespace}/*"
]
}
},
"version": "1.1.0",
"emname": "faas_msg_client",
"namespace": "comp/busi/crm"
}