IBM Cloud CLI allows complete management of the Cloud Functions system. You can use the Cloud Functions CLI plugin-in to manage your code snippets in actions, create triggers, and rules to enable your actions to respond to events, and bundle actions into packages.
Setting up the IBM Cloud CLI
Download and install the IBM Cloud CLI. Alternatively, you can use Homebrew.
brew cask install ibm-cloud-cli
Log in to the IBM Cloud CLI.
If you have more than one account, you’ll prompt to select which account to use. Follow the prompts or use the target
command to select your IBM Cloud account.
ibmcloud target -c <account_id>
You must specify a region to deploy. You can use the target
command to target or change regions. Check the document for the regions that you can use.
ibmcloud target -r <region>
You must also specify a resource group. To get a list of your resource groups, run the following command.
Example output:
Retrieving all resource groups under account <account_name> as email@ibm.com...
OK
Name ID Default Group State
default a8a12accd63b437bbd6d58fb8b462ca7 true ACTIVE
test a8a12abbbd63b437cca6d58fb8b462ca7 false ACTIVE
Target a resource group by running the following command.
ibmcloud target -g <resource_group>
Setting up the Cloud Functions CLI plug-in
To work with Cloud Functions, download and install the CLI plug-in.
Install the Cloud Functions plug-in.
ibmcloud plugin install cloud-functions
All Cloud Functions commands begin with ibmcloud fn
.
For more information about Cloud Functions commands, see the Cloud Functions CLI reference.
Managing namespaces
What is a namespace?
Namespaces contain Cloud Functions entities, such as actions and triggers, and belong to a resource group. You can let users access your entities by granting them access to the namespace.
When you create a namespace, the following components are created:
Component | Description |
---|
Service ID | You can use the service ID as a functional ID when you make outbound calls. All of the actions that are created in this namespace can use this service ID for access to other resources. The functional user gets the Reader role by default. Reader access means it can read namespace entities and invoke actions. The Reader role is used by triggers to invoke actions. To control inbound traffic, you might want to grant access to other users such as assigning Reader role to invoke actions. |
API key | An API Key for the service ID that can be used to generate IAM tokens. You can use the tokens to authenticate the namespace with other IBM Cloud services. The API key is provided to actions as the environment variable __OW_IAM_NAMESPACE_API_KEY . |
You can view a list of service IDs by running the following command.
You can also check the API keys that are associated with a specific service ID by running the following command.
ibmcloud iam service-api-keys <ServiceID-12345678-1234-abcd-1234-123456789abc>
Tip: Do not delete IDs or API keys.
You can see a list of your Cloud Functions namespace by running the following command.
ibmcloud fn namespace list
The command output includes all of the namespaces in the currently selected region and also lists whether the namespace is a Cloud Foundry-based or an IAM-based namespace. Note that this command is scoped to the targeted region and resource group that you set.
Creating an IAM-based namespace
Use the following command to create an IAM-managed namespace with the CLI.
ibmcloud fn namespace create <namespace_name> [--description <"description of yur namespace">]
<namespace_name>
: The display name for the IAM-based namespace.
-n <description>
: Optional: Add a description to the namespace, such as which kind of actions or packages you plan to create. If your description is longer than one word, it must be in quotations.
--description <description>
: Optional: Add a description to the namespace, such as which kind of actions or packages you plan to create. If your description is longer than one word, it must be in quotations.
Verify that your new namespace is created.
ibmcloud fn namespace get <namespace_name> --properties
Before you can create entities in the namespace, you must set your CLI context to the namespace by targeting it.
ibmcloud fn property set --namespace <namespace_name>
Note: After you set a property, it is retained until you manually unset it. If you want to switch between IAM namespaces or between cloud Foundry and IAM namespace, you must unset the namespace property and then reset it. For more information, see ibmcloud fn property set
.
Targeting namespaces
Before you can work in Cloud Functions, you must also target a namespace.
ibmcloud fn namespace target <namespace_name>
Accessing other resources from namespace:
Actions typically call other IBM Cloud resources and services that require appropriate authentication. If these services are IAM-enabled and accept IAM tokens, you can leverage the namespace’s functional ID for outbound communication.
For each namespace, a service ID is created that represents the namespace. You can grant access to other services and resources for this service ID by assigning the appropriate roles by using IAM policy management. For more information, see Creating and working with service IDs.
At runtime, Cloud Functions passes an API key of the namespace service ID to the action code as the environment variable _OW_IAM_NAMESPACE_API_KEY
. The actions code can use this API key to generate an IAM token. Most of the supported Cloud Functions SDKs such as Cloudant and IBM Cloud Object Storage authenticate with the IAM key itself. For other IAM-managed services or resources that use a REST API, you can authenticate with the token that is derived from the IAM API key. For more information, see Create an IAM access token for a user or service ID.
Deploying quick start templates in Node runtime
These templates are a combination of actions, triggers, sequences. By using these templates, we can understand how IBM Cloud Functions entities work together and even use these entities as a basis for own project develops.
IBM Cloudant Events template
This IBM Cloudant template creates a sequence of actions and trigger that invokes that sequence. The trigger is fired when a change is made in the connected IBM Cloudant NoSQL database.
Set up IBM Cloudant database
Before we begin, we have to set up an instance of IBM Cloudant before we deploy this quick start template. When you create your IBM Cloudant instance, you must select Use both legacy credentials and IAM
as your available authentication methods.
In your browser, log in to IBM Cloud and go to the Dashboard. Select Create resource.
Search for IBM Cloudant, and select the service.
For Available authentication methods, select Use both legacy credentials and IAM. You can leave the default settings for other fields. Click Create to create the service.
After your IBM Cloudant instance is provisioned, select the instance from the Resource list and then select Launch Cloudant Dashboard.
From the IBM Cloudant Dashboard, click Create Database.
Create a non-partitioned database called cats
for this quick start template.
Back to the IBM Cloudant instance, select Service credentials. If you do not have service credentials set up, click New Credentials to create them. These values are required for deploying this template.
Now that your instance of IBM Cloudant is provisioned and a sample database of cats
set up, you are ready to deploy the IBM Cloudant Events template.
Deploying the IBM Cloudant Events template from the CLI
Create a new folder for this template Cloud Functions.
Create a new JavaScript file inside this folder, you can name it as process-change.js
. Paste the following snippet into it.
function main(params) {
const { name, color } = params;
return new Promise((resolve, reject) => {
if (!name || !color) {
reject({
error: 'Please make sure name and color are passed in as params.'
});
} else {
const message = `A ${color} cat named ${name} was added`;
console.log(message);
resolve({
change: message,
});
}
});
}
exports.main = main;
Create a manifest.yaml
file with following content.
# Wskdeploy manifest for openwhisk-cloudant-trigger
# GitHub repo is located at https://github.com/IBM/openwhisk-cloudant-trigger
# Installing openwhisk actions, triggers, and rules for OpenWhisk building block - Cloudant Trigger
# Deployment using this manifest file creates following OpenWhisk components:
# Package: openwhisk-cloudant
# Package: $PACKAGE_NAME
# Action: $PACKAGE_NAME/process-change.js
# Sequence: $PACKAGE_NAME/process-change-cloudant-sequence
# Trigger: $TRIGGER_NAME
# Rule: $RULE_NAME
# This manifest file reads following env. variables:
# CLOUDANT_HOSTNAME
# CLOUDANT_USERNAME
# CLOUDANT_PASSWORD
# CLOUDANT_DATABASE
# PACKAGE_NAME
# RULE_NAME
# TRIGGER_NAME
project:
namespace: _
packages:
$PACKAGE_NAME:
dependencies:
# binding cloudant package named openwhisk-cloudant
openwhisk-cloudant:
location: /whisk.system/cloudant
inputs:
username: $CLOUDANT_USERNAME
password: $CLOUDANT_PASSWORD
host: $CLOUDANT_HOSTNAME
iamApiKey: $CLOUDANT_IAM_APIKEY
triggers:
# Trigger
# Creating trigger to fire events when data is inserted into database
$TRIGGER_NAME:
feed: openwhisk-cloudant/changes
inputs:
dbname: $CLOUDANT_DATABASE
actions:
# Action named "process-change"
# Creating action that is printing data which is written to the database
process-change:
function: ./process-change.js
runtime: nodejs:12
sequences:
# Sequence named "process-change-cloudant-sequence"
# Creating sequence to connect the cloudant "read" action with the "process-change" action
process-change-cloudant-sequence:
actions: openwhisk-cloudant/read, process-change
rules:
# Rule
# Creating rule that maps database change trigger to sequence
$RULE_NAME:
trigger: $TRIGGER_NAME
action: process-change-cloudant-sequence
Now, deploy the Cloud Functions with the following environment variable.
CLOUDANT_HOSTNAME=<host> CLOUDANT_USERNAME=<username> CLOUDANT_PASSWORD=<password> CLOUDANT_DATABASE=<database> PACKAGE_NAME=<name> RULE_NAME=<name> TRIGGER_NAME=<name> ibmcloud fn deploy -m manifest.yaml
These environment variables are indicated in the manifest.yaml
. We can set these fields in the web console, however, to deploy just using the CLI, we need to feed them in the deploy commands. Find these information in the web console by navigating to your IBM Cloudant instance and then selecting Service Credentials that we created in previous step. Also, you can find service credentials by running the following commands.
a. Find the credentials for your IBM Cloudant instance.
ibmcloud resource service-keys --instance-name <Cloudant-name>
Example output:
Name State Created At
template-test active Sun Oct 25 11:51:44 UTC 2020
b. Retrieve the details of the service key. Replace the template-test
with the credentials that you retrieved in the previous step.
ibmcloud resource service-key template-test
Example output:
Name: template-test
ID: crn:v1:bluemix:public:cloudantnosqldb:us-south:a/5294aaf79314431586303d483bd3f3e0:2e4c6f05-a971-433e-b9c3-f6afcb326b1e:resource-key:6030db27-9f3c-4ca9-9561-7cb813875fbe
Created At: Sun Oct 25 11:51:44 UTC 2020
State: active
Credentials:
apikey: J2axYj49SRfXjfbErzGYWeeG-sgvAzuljt1ojykFRtf3
host: a26bb3a6-e85d-4962-a734-a8d51e30e753-bluemix.cloudantnosqldb.appdomain.cloud
iam_apikey_description: Auto-generated for key 6030db27-9f3c-4ca9-9561-7cb813875fbe
iam_apikey_name: template-test
iam_role_crn: crn:v1:bluemix:public:iam::::serviceRole:Manager
iam_serviceid_crn: crn:v1:bluemix:public:iam-identity::a/5294aaf79314431586303d483bd3f3e0::serviceid:ServiceId-5a737aa4-c1fb-41aa-8952-057cfb2bff18
password: 152577110cc5f237e2862a23e6f4c84579d43c59fd8d9577a252059694d266c9
port: 443
url: https://a26bb3a6-e85d-4962-a734-a8d51e30e753-bluemix:152577110cc5f237e2862a23e6f4c84579d43c59fd8d9577a252059694d266c9@a26bb3a6-e85d-4962-a734-a8d51e30e753-bluemix.cloudantnosqldb.appdomain.cloud
username: a26bb3a6-e85d-4962-a734-a8d51e30e753-bluemix
Using the correct service credential information found the previous output, run the following command to deploy the Cloud Functions:
CLOUDANT_HOSTNAME=a26bb3a6-e85d-4962-a734-a8d51e30e753-bluemix.cloudantnosqldb.appdomain.cloud CLOUDANT_USERNAME=a26bb3a6-e85d-4962-a734-a8d51e30e753-bluemix CLOUDANT_PASSWORD=152577110cc5f237e2862a23e6f4c84579d43c59fd8d9577a252059694d266c9 CLOUDANT_DATABASE=cats PACKAGE_NAME=my-package RULE_NAME=my-rule TRIGGER_NAME=my-trigger ibmcloud fn deploy -m ./manifest.yaml
The CLOUDANT_DATABASE
name with cats
is created in previous step, the following environment variables can be customized, e.g. PACKAGE_NAME=awesome-package
.
Testing your IBM Cloudant Events package
Now that you have your IBM Cloudant database and your IBM Cloudant events (action and trigger) ready, let’s try it out! The expected data item is a cat, with a name and a coloraturas defined. When a new cat is added to the cats
database or a current cat item is edited, the data is logged to the console module in Node.js.
Before you make entries in the IBM Cloudant database, make sure that the process change
action is working properly. Note that this entry does not update IBM Cloudant database, but instead of a method of testing the actions itself (by logging).
Open the Action page from the Cloud Functions web console.
From the events package (called my-package
, if you accepted the default name), click on the process change
action that will redirect you to the detail page.
Click Invoke with parameters and enter a valid JSON entry for name
and color
, similar to the following example:
{
"name": "Tarball",
"color": "Black"
}
Click Apply.
Click Invoke. In the Activation pane, find output similar to the following example:
Activation ID:
6f446242d8804b07846242d880db0742
Results:
{
"change": "A Black cat named Tarball was added"
}
Logs:
[
"2020-10-25T14:37:53.069453Z stdout: A Black cat named Tarball was added"
]
Testing the Cloudant trigger
While you can test the process change
action, you cannot test the trigger without making an entry to the IBM Cloudant database. Try the next.
From the command line, run the following command to view a streaming, live list of activations for you namespace. It’s waiting for any changes in the IBM Cloudant database.
ibmcloud fn activation poll
From the IBM Cloud resource list, select your IBM Cloudant instance, in Manage > Dashboard > Databases, click Launch.
Select your cats
database that created previously.
Click Create Document.
Enter valid JSON and click Create Document (_id
is automatically allocated).
{
"_id": "d10d48872d1b4ae28ec1103610ce97cd",
"name": "Tom",
"color": "Grey"
}
Back to your CLI terminal, check the activation poll to see whether the trigger fired.
Example output:
Activation: 'process-change' (c6c1e389c74049d581e389c74019d527)
[
"2020-10-25T14:56:13.945030Z stdout: A Grey cat named Tom was added"
]
Summary
Now we finish the first quick start template deployment. The trigger comes from the IBM Cloudant database that invokes an action to log the changes in the database. Let’s move on to learn more.
Get HTTP resource template
The Get HTTP resource template creates an action, which takes a location parameter as input. The action is enabled as a web action, allowing it to be invoked with a URL, which is CORS enabled and does not need an authentication key, which is useful for building backend services for web applications.
Note: By default, the get-http-resource
endpoint is publicly available to anyone who calls it.
Deploy the Get HTTP Resource template from the CLI
Create a new folder for this template Cloud Functions.
Also create a new JavaScript file inside the folder, with following snippet.
/**
* main() will be invoked when you Run This Action.
*
* When enabled as a Web Action, use the following URL to invoke this action:
* https://{APIHOST}/api/v1/web/{QUALIFIED ACTION NAME}?location=Austin
*
* For example:
* https://openwhisk.ng.bluemix.net/api/v1/web/myusername@us.ibm.com_myspace/get-http-resource/location?location=Austin
*
* In this case, the params variable will look like:
* { "location": "Austin" }
*
*/
const needle = require('needle');
async function main({
location = 'Austin'
}) {
try {
let response = await needle('get', `https://httpbin.org/anything?location=${location}`, {
headers: {
'accept': 'application/json'
}
});
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json'
},
body: {
location: response.body.args.location
},
};
} catch (err) {
console.log(err)
return Promise.reject({
statusCode: 500,
headers: {
'Content-Type': 'application/json'
},
body: {
message: err.message
},
});
}
}
exports.main = main;
Then create the manifest.yaml
file with following content:
# Wskdeploy manifest for Get External Resource - location
# Deployment using this manifest file creates the following OpenWhisk components:
# Package: get-http-resource
# Action: get-http-resource/location.js
#
# The action can be invoked using:
# curl https://us-south.functions.cloud.ibm.com/api/v1/web/<namespace>/get-http-resource/location.json?location=<location>
project:
namespace: _
packages:
$PACKAGE_NAME:
version: 1.0
license: Apache-2.0
actions:
location:
web-export: true
function: ./location.js
runtime: nodejs:12
Now deploy the template with a custom package name as an environment variable.
PACKAGE_NAME=<name> ibmcloud fn deploy -m ./manifest.yaml
I’m going to set the PACKAGE_NAME
to my-package
just as the previous template example, which will group all the actions under my-package
together. So, the deploy command becomes
PACKAGE_NAME=my-package ibmcloud fn deploy -m ./manifest.yaml
Invoking the Get HTTP Resource action
Test out the Get HTTP Resource action by using one of the following methods:
From the Cloud Functions Actions page, select the action and then click Invoke.
You can change the input parmeter by Invoke with parameters and entering valid JSON in the following format:
{
"location": "Siem Reap"
}
Opening the URL that given in the action’s Endpoints. You can also get the URL for any action using the CLI:
ibmcloud fn action get <package_name>/<action_name> --url
For example, to get the URL of the location action we just deployed:
ibmcloud fn action get my-package/location --url
Example output:
https://us-south.functions.appdomain.cloud/api/v1/web/b0112440-ab69-4fbf-9a2e-bf30151e74dc/my-package/location
Add a parameter for location by appending ?location=<city>
to the end of the URL. For example:
https://us-south.functions.appdomain.cloud/api/v1/web/b0112440-ab69-4fbf-9a2e-bf30151e74dc/my-package/location?location=London
Curling the URL. For example:
curl "https://us-south.functions.appdomain.cloud/api/v1/web/b0112440-ab69-4fbf-9a2e-bf30151e74dc/my-package/location?location=London"
Hello World template
This template is basic IBM Cloud Functions, which create a single action called helloworld
. This action accepts a single parameter in JSON format, { "name": "xxxx" }
.
Deploying the Hello World template from the CLI
Create a folder for this template.
Create a JavaScript file named helloworld.js
with:
/**
*
* main() will be invoked when you Run This Action.
*
* @param Cloud Functions actions accept a single parameter,
* which must be a JSON object.
*
* In this case, the params variable will look like:
* { "name": "xxxx" }
*
* @return which must be a JSON object.
* It will be the output of this action.
*
*/
function main(params) {
if (params.name) {
return {
greeting: `Hello ${params.name}`
};
}
return {
greeting: 'Hello stranger!'
};
}
exports.main = main;
Now, let’s deploy the template without a manifest.yaml
file with CLI.
ibmcloud fn action create my-package/helloworld ./helloworld.js --kind nodejs:12
Example output:
ok: created action my-package/helloworld
Testing the Hello World action
From the Cloud Functions Actions page, select the action and then click Invoke or Invoke with parameters.
Note that this action is just return a JSON object, not web enabled nor return HTTP content.
Conclude
Well, just made my hand wet with IBM CLI to build Cloud Functions and have a rough feeling on how the Cloud Functions work. I’m considering to use IBM cloud to backend my website as the IBM Cloud free tier includes 400,000 GB-s :>.