Practice 8 - Cloud Functions
In this lab we will use the IBM Bluemix cloud and take a look at the Cloud Function service, which can be considered a Function as a Service (FaaS) or Serverless platform and is based on the Apache OpenWhisk open source project.
In FaaS Coud Computing model your application consists of a set of functions or microservices. Cloud Functions are not constantly running in the background. They are executed only when specific user specified events are triggered (e.g. when new file is uploaded, new entry is added to the database, new message arrives, etc. ).
You will make an account in IBM Bluemix cloud and set up multiple Python Cloud Functions which are automatically triggered on either web requests or database events. You will also use the Cloudant NoSQL service as the database for your Cloud Functions. Cloudant is based on the CouchDB open source NoSQL JSON document database.
Additional materials, tutorials and references
- IBM bluemix - https://www.ibm.com/cloud-computing/bluemix/open-source
- IBM Cloudant documentation - https://console.bluemix.net/docs/services/Cloudant/index.html
- Cloudant Python tutorial - http://python-cloudant.readthedocs.io/en/latest/getting_started.html
- IBM Cloud Functions - https://console.bluemix.net/docs/openwhisk/index.html
- Introduction to JSON - https://www.digitalocean.com/community/tutorials/an-introduction-to-json
Exercise 8.1. Creating an IBM Bluemix Account
- Sign up for a free IBM Bluemix account at https://www.ibm.com/cloud-computing/bluemix/open-source
- Activate the account using the link sent by email and log in.
- Familiarize yourself with the available Cloud services.
Exercise 8.2. Creating your first Cloud Function
- Go to the IBM Cloud Functions console at https://console.bluemix.net/openwhisk/
- Create a new Python Cloud Function
- Click on Create Action
- Assign a freely chosen name to the new action
- Leave the package as (Default Package)
- Choose Python 3 as the Runtime
- As a result, a simple Hello World function will be generated for you.
- Click Invoke to execute your function to test it.
- This will execute your script in the server without any arguments. You can specify default arguments (JSON document) by using Change Input link, which can be useful for testing your Cloud Functions.
- You should notice that the result of your function is in JSON format.
- Input and output of IBM Cloud Functions is JSON by default
- JSON can be described as a dictionary data structure in JavaScript notation.
- If you have never used JSON before, then read the JSON tutorial here: https://www.digitalocean.com/community/tutorials/an-introduction-to-json
- Modify the function output message so it returns custom message for you instead of default "Hello World"
Exercise 8.3. Setting up Cloudant Database
We are going to use Cloudant NoSQL database in the following exercises, but first we need to set up a new database.
- Go to https://console.bluemix.net/catalog/services/cloudant-nosql-db and create a new (free) Lite Cloudant NoSQL database.
- Assign
labdb1
as the database name
- Assign
- The database will be accessible from your Bluemix Dashboard: https://console.bluemix.net/dashboard/apps
- Create new database credentials
- Go to
Cloudant -> Service Credentials -> New credential
and assign names for your database credentials. - You can view the content of your credentials using the View credentials
- NB! You will need these database credentials in the next exercise.
- Go to
- Cloudant is a NoSQL document database. Entries in the database are JSON documents.
- Create a new JSON document in your database:
- Add two new fields user and message to the document.
- The document should look something like this (don't modify your
"_id"
field):{ "_id": "887b9a497ecacdbae7302f882e0b58a7", "user": "Martin", "message": "Hello World!" }
- Check the content of the created document.
"_id"
and"_rev"
fields will be automatically generated for each JSON document.
Exercise 8.4. Creating Cloud Function for posting documents to Cloudant
In this exercise, we will use a Cloud Function to create a simple web service for submitting data into the Cloudant database.
It is important to note that input to the Cloud Function will be the content of the event it was triggered on. In case of web requests, input will be the HTML request parameters (e.g. headers, body, html form fields). In case of Cloudent, it is a database JSON document. When you execute the script directly in the browser, input is usually empty JSON document.
8.4.1 Create another Cloud Function
We will modify the function to create a new document in labdb1
database every time the Function is executed.
- Add a new method for putting documents into your database:
- First import Cloudant API
from cloudant.client import Cloudant
- Then add a new
addDocToDB(doc)
method to your Cloud Function code def addDocToDB(param, new_doc): db_username = param['username'] db_password = param['password'] db_host = param['url'] databaseName = "labdb1" client = Cloudant(db_username, db_password, url=db_host, connect = True) myDatabaseDemo = client[databaseName] return myDatabaseDemo.create_document(new_doc)
- Specify database url and credentials as additional Cloud Function parameters:
- Go to the Parameters page under your Function.
- Add 3 new parameters with correct values based on your own database URL and credentials.
username
- Your Cloudant credentials usernameurl
- url of your Cloudant databasepassword
Your Cloudant credentials password
- Example of how parameters should look like is provided here: parameters.png
- Now these parameters will be added to the input (document) of your Cloud Function and these values can be accessed from inside the function code.
- This allows us to specify database credentials without hardcoding them into our function code.
- First import Cloudant API
8.4.2 Add a web endpoint to your cloud function.
This will make your function publicly accessible from the internet.
- Create a new Web action endpoint
- Go to
Endpoints -> Enable as Web Action
- This will generate a public web URL for your function that can be accessed from anywhere in the web.
- NB! You will need this URL in the next step.
- Go to
8.4.3 Submitting data to the Cloud Function
Lets now create a local html page for submitting data to your Cloud Function
- Create a new html file in your computer:
- It should contain the following content:
<html> <body> <form id="form_1" method="post" action="https://CLOUD_FUNCTION_ENDPOINT"> User: <input id="user" name="user" type="text" value=""/> <br /> Message: <input id="message" name="message" type="text" value=""/> <br /> <input id="saveForm" type="submit" name="submit" value="Send message" /> </form> </body> </html>
- Replace
https://CLOUD_FUNCTION_ENDPOINT
with the real endpoint URL you previously created.
- As a result, you will have a HTML form which submits user and message fields through a HTML POST request to your web endpoint.
- Save the html file in your computer and open it with a browser.
8.4.4 Modify the Cloud Function to create new documents and save them to the database
Modify Your Cloud Function to read the user and message fields sent from the HTML form and submit a new JSON document containing the values of these fields into the Cloudent database.
- Read the user and message field values from the input document:
def main(param): user = "" if 'user' in param: user = param['user'] message = "" if 'message' in param: message = param['message']
- Create a new JSON document that contains these two fields
doc = {'message': message, 'user': user}
- Use the
addDocToDB(doc)
method inside your functionsmain(dict)
method to add a new document to the database:modified_doc = addDocToDB(param, doc)
- Return the document object at the end of
main
method for ease of debugging:return modified_doc
- Save your Cloud Function
- Verify that a new document is created in a database every time a new value is submitted through the form.
Exercise 8.5. Creating a Cloud Function for automatically modifying new documents in the database
Cloud Functions can also be used to automate tasks. We will now create a Cloud Function that is automatically executed for every new document added to the database and which adds a new field to the document to record when the document was created.
- Create a new Python Cloud Function.
- Go to
Actions -> Create -> Create Action
- Assign a freely chosen name to your function
- Go to
- Add a Cloudant trigger to your Function.
- Go to
Connected Triggers -> Add Trigger -> Cloudant
- Assign a freely chosen name
- Choose your database instance under Cloudant Instance
- Make sure the database is
labdb1
- Click Create & Connect
- Now your Function will be automatically executed every time there is a new entry added to the
labdb1
database and it gets the content of the document as an input argumentdict
.
- Go to
- Modify the Python function to add
time
column to the database document, which notes when the document was created.- Add import statements for Cloudant and time:
from datetime import datetime from cloudant.client import Cloudant
- Add a new method to fetch the database object
def getDBdoc(dict): db_username = dict['username'] db_password = dict['password'] db_host = dict['url'] databaseName = "labdb1" client = Cloudant(db_username, db_password, url=db_host, connect = True) myDatabaseDemo = client[databaseName] db_doc = myDatabaseDemo[dict['id']] return db_doc
- Modify the Cloud Function parameters to specify Cloudant
url
,username
andpassword
(Just like in the Exercise 8.4) - Modify the
main
method to fetch the database object (required for modifying the document in the database).doc = getDBdoc(dict)
- modify the document by adding a new attribute time
doc['time'] = ...
- The value of this field should be the current System time and must be cast into string type.
- Save the modified document:
doc.save()
- Save your Cloud Function
- Test that the function works by creating new documents in
labdb1
database and verifying that time attributes are automatically generated for each of them.
- Add import statements for Cloudant and time:
Deliverables
- Source code of your Cloud Functions from Exercise 8.4 and Exercise 8.5.
- NB! Do not leave your IBM Cloudant database credentials inside your function code or screenshots!!
- Provide the URL to the Cloud Function web endpoint, which you created in Exercise 8.4.
- Screenshot of your Cloudant
labdb1
database view, which should display one of the open documents.