Technical Articles
Writing Function-as-a-Service [8]: How to (easily) use Platform Services
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
- Access to FaaS which is currently only available in productive landscape
- Basic knowledge about Node.js
- Access to Extension Center is not required, everything can be done with local dev environment
- To follow this tutorial, it is necessary to be able to use SAP Cloud Platform Enterprise Messaging
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:
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"
}