In this programming guide, we are going to discuss inputs
section of manifest and
deployment file along with command line options --param
and --param-file
. First some background.
We define a project in manifest/deployment file which is a collection of packages. A package in turn is a collection of OpenWhisk entities such as actions, sequences, triggers, rules, apis, etc. These OpenWhisk entities in manifest/deployment files generally need data from users/environment for its successful deployment. This data includes:
- Default values of action parameters including sensitive information such as credentials.
- Shared package bindings which are created outside of an existing deployment, for example, Cloudant, Slack, etc.
- Service credentials, for example, cloudant credentials, slack token, etc
Inputs can be specified at different levels:
- Action Inputs
- Trigger Inputs
- Package Inputs
- Project Inputs
And can be specified in multiple different ways:
- Manifest file
- Deployment file
- CLI using
--param
and--param-file
Before we dive into details of each level of inputs with all different ways, wskdeploy
follows a particular order in which the values are read:
- Input values specified using
--param
and/or--param-file
takes the highest precedence order. The values specified on CLI are taken to the server. - Next, input values are read from deployment file
- Last, input values are read from manifest file
Let's start with a simple example of a helloworld
action which has two inputs name
and place
.
packages:
helloworldapp:
actions:
hello:
inputs:
name:
type: string
description: "your first name"
required: false
value: Amy
place:
type: string
description: "The city name"
required: false
value: Paris
code: |
function main(params) {
return {payload: 'Hello, ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
Or (Single Line Inputs):
packages:
helloworldapp:
actions:
hello:
inputs:
name: Amy
place: Paris
code: |
function main(params) {
return {payload: 'Hello, ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
Whisk deploy creates bindings at the action level with two parameters name
and place
:
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_1.yaml
Packages:
Name: helloworldapp
bindings:
annotation:
* action: hello
bindings:
- name : "Amy"
- place : "Paris"
annotation:
This is how two inputs name
and place
are stored in hello
action on OpenWhisk server:
"parameters": [
{
"key": "name",
"value": "Amy"
}
{
"key": "place",
"value": "Paris"
},
],
packages:
helloworldapp:
actions:
hello:
inputs:
name:
type: string
description: "your first name"
required: true
value: $FIRST_NAME
place:
type: string
description: "The city name"
required: true
value: $CITY_NAME
code: |
function main(params) {
return {payload: 'Hello, ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
Deployment of this kind of manifest file results in following failure as inputs
name
and place
are marked required
but their values $FIRST_NAME
and $CITY_NAME
could not be determined.
Error: manifestreader.go [92]: [ERROR_YAML_FILE_FORMAT_ERROR]: File: [manifest_validate_package_inputs_2.yaml]:
==> manifest_parser.go [148]: [ERROR_YAML_FILE_FORMAT_ERROR]: File: [manifest_validate_package_inputs_2.yaml]: Required inputs are missing values even after applying interpolation using env. variables. Please set missing env. variables and/or input values in manifest/deployment file or on CLI for following inputs: name, place
On the other side, single line inputs does not support this kind of validation as
they are not marked as required
by default.
packages:
helloworldapp:
actions:
hello:
inputs:
name: $FIRST_NAME
place: $CITY_NAME
code: |
function main(params) {
return {payload: 'Hello, ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
Action is created with two bindings name
and place
set to ""
:
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_2.yaml
Packages:
Name: helloworldapp
bindings:
annotation:
* action: hello
bindings:
- name : ""
- place : ""
annotation:
Now, after setting env. variables, wskdeploy
creates an action with bindings similar to previous example:
export FIRST_NAME=Amy
export CITY_NAME=Paris
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_2.yaml
Packages:
Name: helloworldapp
bindings:
annotation:
* action: hello
bindings:
- name : "Amy"
- place : "Paris"
annotation:
The input values can be overwritten using --param
on CLI. Sample manifest in [Action Inputs](#Action Inputs) can be deployed using:
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_1.yaml --param name Bob
Packages:
Name: helloworldapp
bindings:
annotation:
* action: hello
bindings:
- name : "Bob"
- place : "Paris"
annotation:
This example shows how env. variables FIRST_NAME
and CITY_NAME
are defined under project.
These two variables are needed for deployment and need not be propagated to OpenWhisk server.
This is the best and common practice of specifying inputs at the action level and env.
variables at the project level. Here, both FIRST_NAME
and CITY_NAME
have default
values but reads from environment if they are specified.
project:
name: helloworld
inputs:
FIRST_NAME:
type: string
description: "your first name"
required: true
value: Amy
CITY_NAME:
type: string
description: "The city name"
required: true
value: Paris
packages:
helloworldapp:
actions:
hello:
inputs:
name:
type: string
description: "your first name"
required: true
value: $FIRST_NAME
place:
type: string
description: "The city name"
required: true
value: $CITY_NAME
code: |
function main(params) {
return {payload: 'Hello, ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
This is how bindings are created only under action:
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_3.yaml
Packages:
Name: helloworldapp
bindings:
annotation:
* action: hello
bindings:
- name : "Amy"
- place : "Paris"
annotation:
With env. variables:
export FIRST_NAME=Bob
export CITY_NAME=San Francisco
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_3.yaml
Packages:
Name: helloworldapp
bindings:
annotation:
* action: hello
bindings:
- name : "Bob"
- place : "San Francisco"
annotation:
project:
name: helloworld
inputs:
FIRST_NAME:
type: string
description: "your first name"
required: true
value: Amy
CITY_NAME:
type: string
description: "The city name"
required: true
value: Paris
packages:
helloworldapp:
inputs:
name:
type: string
description: "your first name"
required: true
value: $FIRST_NAME
place:
type: string
description: "The city name"
required: true
value: $CITY_NAME
actions:
hello:
code: |
function main(params) {
return {payload: 'Hello, ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
Now, bindings are created under Package:
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_4.yaml
Packages:
Name: helloworldapp
bindings:
- name : "Amy"
- place : "Paris"
annotation:
* action: hello
bindings:
annotation:
And can be overwritten using env. variables:
export FIRST_NAME=Bob
export CITY_NAME=San Francisco
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_4.yaml
Packages:
Name: helloworldapp
bindings:
- name : "Bob"
- place : "San Francisco"
annotation:
* action: hello
bindings:
annotation:
Here, package helloworldapp
has three inputs defined which are available to all
three actions helloWithMorning
, helloWithEvening
, and helloWithNight
during
invocation. But two of the actions have redefined the same input message
which
is created as an action binding on the server.
project:
name: helloworld
inputs:
FIRST_NAME:
type: string
description: "your first name"
required: true
value: Amy
CITY_NAME:
type: string
description: "The city name"
required: true
value: Paris
packages:
helloworldapp:
inputs:
name:
type: string
description: "your first name"
required: true
value: $FIRST_NAME
place:
type: string
description: "The city name"
required: true
value: $CITY_NAME
message:
type: string
description: "The Message"
required: true
value: "Good Night"
actions:
helloWithMorning:
inputs:
message:
type: string
description: "The Message"
required: true
value: "Good Morning"
code: |
function main(params) {
return {payload: 'Hello, ' + params.message + ' ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
helloWithEvening:
inputs:
message:
type: string
description: "The Message"
required: true
value: "Good Evening"
code: |
function main(params) {
return {payload: 'Hello, ' + params.message + ' ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
helloWithNight:
code: |
function main(params) {
return {payload: 'Hello, ' + params.message + ' ' + params.name + ' from ' + params.place};
}
runtime: nodejs:default
Now, invoking helloWithMorning
returns Good Morning
and invoking helloWithEvening
returns Good Evening
whereas invoking helloWithNight
returns Good Night
which
is stored as the package binding.
./wskdeploy --preview -m tests/dat/manifest_validate_package_inputs_5.yaml
Packages:
Name: helloworldapp
bindings:
- name : "Amy"
- place : "Paris"
- message : "Good Night"
annotation:
* action: helloWithMorning
bindings:
- message : "Good Morning"
annotation:
* action: helloWithEvening
bindings:
- message : "Good Evening"
annotation:
* action: helloWithNight
bindings:
annotation: