DSL Reference¶
CloudSlang is a YAML (version 1.2) based language for describing a workflow. Using CloudSlang you can easily define a workflow in a structured, easy-to-understand format that can be run by the CloudSlang Orchestration Engine (Score). CloudSlang files can be run by the CloudSlang CLI or by an embedded instance of Score using the Slang API.
This reference begins with a brief introduction to CloudSlang files and their structure, an alphabetical listing of CloudSlang keywords and concepts, and several examples, including one from which many of the code snippets below are taken.
CloudSlang Files¶
CloudSlang files are written using YAML. The recommended extension for CloudSlang files is .sl, but .sl.yaml and .sl.yml will work as well.
There are two types of CloudSlang files:
- flow - contains a list of tasks and navigation logic that calls operations or subflows
- operation - contains an action that runs a script or method
The following properties are for all types of CloudSlang files. For properties specific to flows or operations, see their respective sections below.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
namespace |
no | – | string | namespace of the flow | namespace |
imports |
no | – | list of key:value pairs | files to import | imports |
The general structure of CloudSlang files is outlined here. Some of the properties that appear are optional. All CloudSlang keywords, properties and concepts are explained in detail below.
Flow file
Operations file
Keywords (A-Z)¶
action¶
The key action is a property of an operation. It is
mapped to a property that defines the type of action, which can be a
java_action or python_script.
java_action¶
The key java_action is a property of action.
It is mapped to the properties that define the class and method where
the @Action resides.
A java_action is a valid @Action that conforms to the method
signature: public Map<String, String> doSomething(paramaters) and
uses the following annotations from
com.hp.oo.sdk.content.annotations:
- required annotations:
- @Param: action parameter
- optional annotations:
- @Action: specify action information
- @Output: action output
- @Response: action response
Example - CloudSlang call to a Java @Action
name: pull_image
inputs:
- input1
- input2
action:
java_action:
className: org.mypackage.MyClass
methodName: doMyAction
outputs:
- returnResult
results:
- SUCCESS : someActionOutput == '0'
- FAILURE
public Map<String, String> doMyAction(
@Param("input1") String input1,
@Param("input2") String input2) {
//logic here
Map<String, String> returnValues = new HashMap<>();
//prepare return values map
return returnValues;
}
python_script¶
python_script is a property of action.All variables in scope at the conclusion of the Python script must be
serializable. If non-serializable variables are used, remove them from
scope by using the del keyword before the script exits.
Note: CloudSlang uses the Jython implementation of Python 2.7. For information on Jython’s limitations, see the Jython FAQ.
Example - action with Python script that divides two numbers
name: divide
inputs:
- dividend
- divisor
action:
python_script: |
if divisor == '0':
quotient = 'division by zero error'
else:
quotient = float(dividend) / float(divisor)
outputs:
- quotient
results:
- ILLEGAL: quotient == 'division by zero error'
- SUCCESS
Note: Single-line Python scripts can be written inline with the
python_script key. Multi-line Python scripts can use the YAML pipe
(|) indicator as in the example above.
Importing External Python Packages¶
There are three approaches to importing and using external Python modules:
- Installing packages into the python-lib folder
- Editing the executable file
- Adding the package location to
sys.path
Installing packages into the python-lib folder:
Prerequisite: pip - see pip‘s documentation for how to install.
Edit the requirements.txt file in the python-lib folder, which is found at the same level as the bin folder that contains the CLI executable.
- If not using a pre-built CLI, you may have to create the python-lib folder and requirements.txt file.
Enter the Python package and all its dependencies in the requirements file.
- See the pip documentation for information on how to format the requirements file (see example below).
Run the following command from inside the python-lib folder:
pip install -r requirements.txt -t.Note: If your machine is behind a proxy you will need to specify the proxy using pip’s
--proxyflag.Import the package as you normally would in Python from within the action’s
python_script:
action:
python_script: |
from pyfiglet import Figlet
f = Figlet(font='slant')
print f.renderText(text)
Example - requirements file
pyfiglet == 0.7.2
setuptools
Note: If you have defined a JYTHONPATH environment variable, you
will need to add the python-lib folder’s path to its value.
Editing the executable file
- Open the executable found in the bin folder for editing.
- Change the
Dpython.pathkey’s value to the desired path. - Import the package as you normally would in Python from within the
action’s
python_script.
Adding the package location to ``sys.path``:
- In the action’s Pyton script, import the
sysmodule. - Use
sys.path.append()to add the path to the desired module. - Import the module and use it.
Example - takes path as input parameter, adds it to sys.path and imports desired module
inputs:
- path
action:
python_script: |
import sys
sys.path.append(path)
import module_to_import
print module_to_import.something()
Importing Python Scripts¶
To import a Python script in a python_script action:
- Add the Python script to the python-lib folder, which is found at the same level as the bin folder that contains the CLI executable.
- Import the script as you normally would in Python from within the
action’s
python_script.
Note: If you have defined a JYTHONPATH environment variable, you
will need to add the python-lib folder’s path to its value.
aggregate¶
The key aggregate is a property of an asynchronous
task name. It is mapped to key:value pairs where
the key is the variable name to publish to the flow’s scope
and the value is the aggregation expression.
Defines the aggregation logic for an asynchronous task, often making us of the branches_context construct.
Aggregation is performed after all branches of an asynchronous task have completed.
Example - aggregates all of the published names into name_list
aggregate:
- name_list: map(lambda x:str(x['name']), branches_context)
async_loop¶
The key asyc_loop is a property of an asynchronous
task’s name. It is mapped to the asynchronous
task’s properties.
For each value in the loop’s list a branch is created and the do
will run an operation or subflow. When all
the branches have finished, the asynchronous
task’s aggregation and
navigation will run.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
for |
yes | variable in list |
loop values | for | |
do |
yes | operation or subflow call | the operation or subflow this task will run in parallel | do operation flow | |
publish |
no | list of key:value pairs | operation or subflow outputs to aggregate and publish to the flow level | publish aggregate outputs |
Example: loop that breaks on a result of custom
- print_values:
async_loop:
for: value in values
do:
print_branch:
- ID: value
publish:
- name
aggregate:
- name_list: map(lambda x:str(x['name']), branches_context)
navigate:
SUCCESS: print_list
FAILURE: FAILURE
branches_context¶
May appear in the aggregate section of an asynchronous task.
As branches of an async_loop complete, their
published values get placed as a dictionary into the
branches_context list. The list is therefore in the order the
branches have completed.
A specific value can be accessed using the index representing its branch’s place in the finishing order and the name of the variable.
Example - retrieves the published name variable from the first branch to finish
aggregate:
- first_name: branches_context[0]['name']
More commonly, the branches_context is used to aggregate the values
that have been published by all of the branches.
Example - aggregates all of the published name values into a list
aggregate:
- name_list: map(lambda x:str(x['name']), branches_context)
break¶
The key break is a property of a loop. It is mapped to a
list of results on which to break out of the loop or an empty list
([]) to override the default breaking behavior for a list. When the
operation or subflow of the iterative
task returns a result in the break’s list, the
iteration halts and the interative task’s
navigation logic is run.
If the break property is not defined, the loop will break on results
of FAILURE by default. This behavior may be overriden so that
iteration will continue even when a result of FAILURE is returned by
defining alternate break behavior or mapping the break key to an
empty list ([]).
Example - loop that breaks on result of CUSTOM
loop:
for: value in range(1,7)
do:
custom_op:
- text: value
break:
- CUSTOM
navigate:
CUSTOM: print_end
Example - loop that continues even on result of FAILURE
loop:
for: value in range(1,7)
do:
custom_op:
- text: value
break: []
default¶
The key default is a property of an input name. It is
mapped to an expression value.
The expression’s value will be passed to the flow or
operation if no other value for that
input parameter is explicitly passed or if the input’s
overridable parameter is set to false and there
is no system_property parameter defined.
Example - default values
inputs:
- str_literal:
default: "'default value'"
- int_exp:
default: '5 + 6'
- from_variable:
default: variable_name
A default value can also be defined inline by entering it as the value to the input parameter’s key.
Example - inline default values
inputs:
- str_literal: "'default value'"
- int_exp: '5 + 6'
- from_variable: variable_name
do¶
The key do is a property of a task name, a
loop, or an async_loop. It is mapped to a
property that references an operation or
flow.
Calls an operation or flow and passes in relevant input.
The operation or flow may be called in several ways:
- by referencing the operation or flow by name when it is in the default namespace (the same namespace as the calling flow)
- by using a fully qualified name (e.g.
path.to.operation.op_name)- a path is recognized as a fully qualified name if the prefix
(before the first
.) is not a defined alias
- a path is recognized as a fully qualified name if the prefix
(before the first
- by using an alias defined in the flow’s imports
section followed by the operation or
flow name (e.g
alias_name.op_name) - by using an alias defined in the flow’s imports
section followed by a continuation of the path to the
operation or flow and its name (e.g
alias_name.path.cont.op_name)
For more information, see the Operation Paths example.
Arguments may be passed to a task in one of two ways:
- list of argument names and optional mapped expressions
- comma-separated
argument_name = optional_expressionpairs
Expression values will supersede values bound to flow inputs with the same name.
Example - call to a divide operation with list of mapped task arguments
do:
divide:
- dividend: input1
- divisor: input2
Example - call to a divide operation with comma-separated pairs
do:
divide: dividend = input1, divisor = input2
flow¶
The key flow is mapped to the properties which make up the flow
contents.
A flow is the basic executable unit of CloudSlang. A flow can run on its own or it can be used by another flow in the do property of a task.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
name |
yes | string | name of the flow | name | |
inputs |
no | list | inputs for the flow | inputs | |
workflow |
yes | map of tasks | container for set of tasks | workflow | |
outputs |
no | list | list of outputs | outputs | |
results |
no | (SUCCESS / FAILURE ) |
list | possible results of the flow | results |
Example - a flow that performs a division of two numbers
flow:
name: division_flow
inputs:
- input1
- input2
workflow:
- divider:
do:
divide:
- dividend: input1
- divisor: input2
publish:
- answer: quotient
navigate:
ILLEGAL: ILLEGAL
SUCCESS: printer
- printer:
do:
print:
- text: input1 + "/" + input2 + " = " + answer
navigate:
SUCCESS: SUCCESS
outputs:
- quotient: answer
results:
- ILLEGAL
- SUCCESS
for¶
The key for is a property of a loop or an
async_loop.
loop: for¶
A for loop iterates through a list or a map.
The iterative task will run once for each element in the list or key in the map.
Iterating through a list¶
When iterating through a list, the for key is mapped to an iteration
variable followed by in followed by a list, an expression that
evaluates to a list, or a comma delimited string.
Example - loop that iterates through the values in a list
- print_values:
loop:
for: value in [1,2,3]
do:
print:
- text: value
Example - loop that iterates through the values in a comma delimited string
- print_values:
loop:
for: value in "1,2,3"
do:
print:
- text: value
Example - loop that iterates through the values returned from an expression
- print_values:
loop:
for: value in range(1,4)
do:
print:
- text: value
Iterating through a map¶
When iterating through a map, the for key is mapped to iteration
variables for the key and value followed by in followed by a map or
an expression that evaluates to a map.
Example - task that iterates through the values returned from an expression
- print_values:
loop:
for: k, v in map
do:
print2:
- text1: k
- text2: v
async_loop: for¶
An asynchronous for loops in parallel branches over the items in a list.
The asynchronous task will run one branch for each element in the list.
The for key is mapped to an iteration variable followed by in
followed by a list or an expression that evaluates to a list.
Example - task that asynchronously loops through the values in a list
- print_values:
async_loop:
for: value in values_list
do:
print_branch:
- ID: value
get¶
May appear in the value of an input, output, publish, loop expression or result expression.
The function in the form of get('key', 'default_value') returns the
value associated with key if the key is defined and its value is not
None. If the key is undefined or its value is None the function
returns the default_value.
Example - usage of get function in inputs and outputs
inputs:
- input1:
required: false
- input1_safe:
default: get('input1', 'default_input')
overridable: false
workflow:
- task1:
do:
print:
- text: input1_safe
publish:
- some_output: get('output1', 'default_output')
outputs:
- some_output
imports¶
The key imports is mapped to the files to import as follows:
- key - alias
- value - namespace of file to be imported
Specifies the file’s dependencies and the aliases they will be referenced by in the file. Using an alias is one way to reference the operations and subflows used in a flow’s tasks. For all the ways to reference operations and subflows used in a flow’s tasks, see the do keyword.
Example - import operations and sublflow into flow
imports:
ops: examples.utils
sub_flows: examples.subflows
flow:
name: hello_flow
workflow:
- print_hi:
do:
ops.print:
- text: "'Hi'"
inputs¶
The key inputs is a property of a flow or
operation. It is mapped to a list of input names. Each
input name may in turn be mapped to its properties.
Inputs are used to pass parameters to flows or operations.
Input properties may also be used in the input list of a task.
| Property | Required | Default | Value Type | Description | More info |
|---|---|---|---|---|---|
required |
no | true | boolean | is the input required | required |
default |
no | expression | default value of the input | default | |
overridable |
no | true | boolean | if false, the default value always overrides values passed in | overridable |
system_property |
no | string | the name of a system property variable | system_property |
Example - two inputs
inputs:
- input1:
default: "'default value'"
overridable: false
- input2
loop¶
The key loop is a property of an iterative
task’s name. It is mapped to the iterative
task’s properties.
For each value in the loop’s list the do will run an
operation or subflow. If the returned
result is in the break list, or if break does not appear and the
returned result is FAILURE, or if the list has been exhausted, the
task’s navigation will run.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
for |
yes | variable in list or key, value in map |
iteration logic | for | |
do |
yes | operation or subflow call | the operation or subflow this task will run iteratively | do operation flow | |
publish |
no | list of key:value pairs | operation or subflow outputs to aggregate and publish to the flow level | publish outputs | |
break |
no | list of results | operation or subflow results on which to break out of the loop | break |
Example: loop that breaks on a result of custom
- custom3:
loop:
for: value in "1,2,3,4,5"
do:
custom3:
- text: value
break:
- CUSTOM
navigate:
CUSTOM: aggregate
SUCCESS: skip_this
name¶
The key name is a property of flow and
operation. It is mapped to a value that is used as the
name of the flow or operation.
The name of a flow or operation may be used when called from a flow‘s task.
Example - naming the flow *division_flow*
name: division_flow
namespace¶
The key namespace is mapped to a string value that defines the
file’s namespace.
The namespace of a file may be used by a flow to import dependencies.
Example - definition a namespace
namespace: examples.hello_world
Example - using a namespace in an imports definition
imports:
ops: examples.hello_world
Note: If the imported file resides in a folder that is different
from the folder in which the importing file resides, the imported file’s
directory must be added using the --cp flag when running from the
CLI (see Run with
Dependencies).
on_failure¶
The key on_failure is a property of a workflow. It
is mapped to a task.
Defines the task, which when using default
navigation, is the target of a FAILURE
result returned from an operation or
flow. The on_failure task’s
navigation defaults to FAILURE.
Example - failure task which call a print operation to print an error message
- on_failure:
- failure:
do:
print:
- text: error_msg
operation¶
The key operation is mapped to the properties which make up the
operation contents.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
inputs |
no | list | operation inputs | inputs | |
action |
yes | python_script or java_action |
operation logic | action | |
outputs |
no | list | operation outputs | outputs | |
results |
no | SUCCESS |
list | possible operation results | results |
Example - operation that adds two inputs and outputs the answer
name: add
inputs:
- left
- right
action:
python_script: ans = left + right
outputs:
- out: ans
results:
- SUCCESS
outputs¶
The key outputs is a property of a flow or
operation. It is mapped to a list of output variable
names which may also contain expression values. Output expressions must
evaluate to strings.
Defines the parameters a flow or operation exposes to possible publication by a task. The calling task refers to an output by its name.
See also self.
Example - various types of outputs
outputs:
- existing_variable
- output2: some_variable
- output3: 5 + 6
- output4: self['input1']
overridable¶
The key overridable is a property of an input name. It
is mapped to a boolean value.
A value of false will ensure that the input
parameter’s default value will not be overridden by
values passed into the flow or operation.
If overridable is not defined, values passed in will override the
default value.
Example - default value of text input parameter will not be overridden by values passed in
inputs:
- text:
default: "'default text'"
overridable: false
publish¶
The key publish is a property of a task name, a
loop or an async_loop. It is mapped to a
list of key:value pairs where the key is the published variable name and
the value is the name of the output received from an
operation or flow.
Standard publish¶
In a standard task, publish binds the
output from an operation or
flow to a variable whose scope is the current
flow and can therefore be used by other tasks or
as the flow’s own output.
Example - publish the quotient output as ans
- division1:
do:
division:
- input1: dividend1
- input2: divisor1
publish:
- ans: quotient
Iterative publish¶
In an iterative task the publish mechanism is run during each iteration after the operation or subflow has completed, therefore allowing for aggregation.
Example - publishing in an iterative task to aggregate output
- aggregate:
loop:
for: value in range(1,6)
do:
print:
- text: value
publish:
- sum: self['sum'] + out
Asynchronous publish¶
In an asynchronous task the publish mechanism is run during each branch after the operation or subflow has completed. Published variables and their values are added as a dictionary to the branches_context list in the order they are received from finished branches, allowing for aggregation.
Example - publishing in an iterative task to aggregate output
- print_values:
async_loop:
for: value in values_list
do:
print_branch:
- ID: value
publish:
- name
aggregate:
- name_list: map(lambda x:str(x['name']), branches_context)
results¶
The key results is a property of a flow or
operation.
The results of a flow or operation can be used by the calling task for navigation purposes.
Note: the only results of an operation or
subflow called in an async_loop that are
evaluated are SUCCESS and FAILURE. Any other results will be
evaluated as SUCCESS.
Flow results¶
In a flow, the key results is mapped to a list of result
names.
Defines the possible results of the flow. By default a
flow has two results, SUCCESS and FAILURE. The
defaults can be overridden with any number of user-defined results.
When overriding, the defaults are lost and must be redefined if they are to be used.
All result possibilities must be listed. When being used as a subflow all flow results must be handled by the calling task.
Example - a user-defined result
results:
- SUCCESS
- ILLEGAL
- FAILURE
Operation results¶
In an operation the key results is mapped to a list
of key:value pairs of result names and boolean expressions.
Defines the possible results of the operation. By
default, if no results exist, the result is SUCCESS. The first
result in the list whose expression evaluates to true, or does not have
an expression at all, will be passed back to the calling
task to be used for navigation purposes.
All operation results must be handled by the calling task.
Example - three user-defined results
results:
- POSITIVE: polarity == '+'
- NEGATIVE: polarity == '-'
- NEUTRAL
required¶
The key required is a property of an input name. It is
mapped to a boolean value.
A value of false will allow the flow or
operation to be called without passing the
input parameter. If required is not defined, the
input parameter defaults to being required.
Example - input2 is optional
inputs:
- input1
- input2:
required: false
self¶
May appear in the value of an output, publish or result expression.
Special syntax to refer to an input parameter as opposed to another variable with the same name in a narrower scope.
Example - output “input1” as it was passed in
outputs:
- output1: self['input1']
Example - usage in publish to refer to a variable in the flow’s scope
publish:
- total_cost: self['total_cost'] + cost
system_property¶
The key system_property is a property of an input
name. It is mapped to a string of a key from a system properties file.
The value referenced from a system properties file will be passed to the
flow or operation if no other value for
that input parameter is explicitly passed in or if the
input’s overridable parameter is set to false.
Note: If multiple system properties files are being used and they contain a system property with the same fully qualified name, the property in the file that is loaded last will overwrite the others with the same name.
Example - system properties
inputs:
- host:
system_property: examples.sysprops.hostname
- port:
system_property: examples.sysprops.port
To pass a system properties file to the CLI, see Run with System Properties.
task¶
A name of a task which is a property of workflow or on_failure.
There are several types of tasks:
Standard Task¶
A standard task calls an operation or subflow once.
The task name is mapped to the task’s properties.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
do |
yes | operation or subflow call | the operation or subflow this task will run | do operation flow | |
publish |
no | list of key:value pairs | operation outputs to publish to the flow level | publish outputs | |
navigate |
no | FAILURE: on_failure or flow finish; SUCCESS: next task |
key:value pairs | navigation logic from operation or flow results | navigation results |
Example - task that performs a division of two inputs, publishes the answer and navigates accordingly
- divider:
do:
divide:
- dividend: input1
- divisor: input2
publish:
- answer: quotient
navigate:
ILLEGAL: FAILURE
SUCCESS: printer
Iterative Task¶
An iterative task calls an operation or subflow iteratively, for each value in a list.
The task name is mapped to the iterative task’s properties.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
loop |
yes | key | container for loop properties | for | |
navigate |
no | FAILURE: on_failure or flow finish; SUCCESS: next task |
key:value pairs | navigation logic from break or the result of the last iteration of the operation or flow | navigation results |
Example - task prints all the values in value_list and then navigates to a task named “another_task”
- print_values:
loop:
for: value in value_list
do:
print:
- text: value
navigate:
SUCCESS: another_task
FAILURE: FAILURE
Asynchronous Task¶
An asynchronous task calls an operation or subflow asynchronously, in parallel branches, for each value in a list.
The task name is mapped to the asynchronous task’s properties.
| Property | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
async_loop |
yes | key | container for async loop properties | async_loop | |
aggregate |
no | list of key:values | values to aggregate from async branches | aggregate | |
navigate |
no | FAILURE: on_failure or flow finish; SUCCESS: next task |
key:value pairs | navigation logic | navigation results |
Example - task prints all the values in value_list asynchronously and then navigates to a task named “another_task”
- print_values:
async_loop:
for: value in values_list
do:
print_branch:
- ID: value
publish:
- name
aggregate:
- name_list: map(lambda x:str(x['name']), branches_context)
navigate:
SUCCESS: another_task
FAILURE: FAILURE
workflow¶
The key workflow is a property of a flow. It is mapped
to a list of the workflow’s tasks.
Defines a container for the tasks, their published variables and navigation logic.
The first task in the workflow is the starting
task of the flow. From there the flow continues sequentially
by default upon receiving results of SUCCESS, to the
flow finish or to on_failure upon a
result of FAILURE, or following whatever overriding
navigation logic that is present.
| Propery | Required | Default | Value Type | Description | More Info |
|---|---|---|---|---|---|
on_failure |
no | task | default navigation target for FAILURE |
on_failure task |
Example - workflow that divides two numbers and prints them out if the division was legal
workflow:
- divider:
do:
divide:
- dividend: input1
- divisor: input2
publish:
- answer: quotient
navigate:
ILLEGAL: FAILURE
SUCCESS: printer
- printer:
do:
print:
- text: input1 + "/" + input2 + " = " + answer