Defining Workflow
Let’s start by discussing why workflow is introduced and where it can and should be used.
The Cloudsoft AMP Workflow is designed to make it easy to describe behaviour of entities, effectors, sensors, and policies in blueprints. It has the sophistication of a programming language including conditions, loops, and error-handling and variables, but more important are the steps which delegate to other systems, such as containers or SSH or HTTP endpoints. Complex programming logic will typically be done in another system, such as a container; but where effectors and sensors need to interact with AMP, such as reading and setting sensors, or invoking effectors, it is often simplest to do that directly in the blueprint.
Workflow in a blueprint has the benefit of being transparent to users and having the AMP context easily available. It also has the advantage that AMP will retry in certain situations. However it has the disadvantage that, although we’ve tried to make it as easy as we can for people to write, you are still writing code in YAML rather than in a first-class programming language.
The following are places that workflow can be used.
Effectors
An effector can be defined using workflow and added to an entity as follows:
- type: some-entity
brooklyn.initializers:
- type: workflow-effector
brooklyn.config:
name: say-hi-and-publish-sensor
steps:
- log Hi
- set-sensor boolean said_hi = true
This initializer will define the effector say-hi-and-publish-sensor
which uses workflow to do just that. The config to define the effector is:
name
: the name of the effector to define (required)parameters
: an optional map of parameters to advertise for the effector, keyed by the parameter name against the definition as a map including optionallytype
,description
, anddefaultValue
; see nested workflow for more details
To define the workflow, this requires:
steps
: to supply the list of steps defining the workflow (required)
And the following optional common configuration keys are supported, with the same semantics as for individual steps as described under Common Step Properties:
-
condition
: an optional condition on the effector which if set and evaluating to false, prevents the effector workflow from running; this does not support interpolated variables -
input
: a map of keys to values to make accessible in the workflow, in addition to effectorparameters
-
output
: defines the output of the workflow, often referring to workflow variables or the output of the last step in the workflow - other common step properties such as
timeout
,on-error
, andnext
- other workflow settings properties such as
lock
,retention
,replayable
, andidempotent
Sensors
A sensor feed to use a workflow to compute a sensor value based on triggers and/or a schedule can be defined as follows:
- type: some-entity
brooklyn.initializers:
- type: workflow-sensor
brooklyn.config:
sensor: count-how-often-other_sensor-is-published
triggers:
- other_sensor
steps:
- let integer x = ${entity.sensor.x} + 1 ?? 0
- return ${x}
This initializer will add the sensor to the entity’s type signature, then run the indicated workflow, periodically and/or on sensors, and set the return value as the value of the sensor. The config to define the sensor feed is:
sensor
: (required) a string specifying the sensor name or map with keysname
(required) being the sensor name and optionallytype
being a type to record for the sensortriggers
: a list of sensors which should trigger this when published, each entry declared either as the string name if on the local entity, or a map ofsensor
containing the name andentity
containing the entity or entity ID where the sensor should be listened for, or if just a single local sensor, that sensor name supplied as a stringperiod
: whether the feed should run periodicallyskip_initial_run
: by default sensors and policies will run when created (if anycondition
is met); this can be settrue
to prevent that, ensuring it is only run after the initialperiod
or when one of thetriggers
fires
In addition to defining the sensor
name, at least one of triggers
or period
must be supplied.
The steps
must also be defined, as per workflow-effector
above,
and the same common configuration is supported.
Policies
A policy to to run a workflow based on triggers and/or a schedule can be defined as follows:
- type: some-entity
brooklyn.policies:
- type: workflow-policy
brooklyn.config:
name: invoke-effector-other_sensor-is-published
triggers:
- other_sensor
steps:
- invoke-effector some_effector
This initializer will add the policy to the entity’s defined management adjuncts, then run the indicated workflow, periodically and/or on sensors. The config to define the policy feed is:
name
: the name for the policy (recommended)triggers
and/orperiod
: perworkflow-sensor
above (at least one required)
The steps
must also be defined, as per above,
and the same common configuration is supported.
Initializer
A workflow can be made to run when an entity is created using a workflow-initializer
.
This can do any custom entity setup, including the above tasks using add-policy
or apply-initializer
steps,
as follows:
- type: some-entity
brooklyn.initializers:
- type: workflow-initializer
brooklyn.config:
name: initializer-to-say-hi-then-add-effector-and-sensor
steps:
- log Hi this workflow initializer will run at entity creation
- step: add-policy
blueprint:
type: workflow-policy
brooklyn.config:
name: invoke-effector-other_sensor-is-published
triggers:
- other_sensor
steps:
- invoke-effector say-hi-and-publish-sensor
- step: apply-initializer
blueprint:
type: workflow-effector
brooklyn.config:
name: say-hi-and-publish-sensor
steps:
- log Hi
- set-sensor boolean said_hi = true
The workflow-initializer
takes the same config as workflow-effector
with the exception of parameters
.
Workflow Entities
New entities can be written to use workflow for their start and stop behavior by extending the
type workflow-entity
. This requires a start
and stop
configuration to be supplied
defining the workflow for those steps. Optionally restart
can be supplied, which if omitted
will default to stopping then starting.
- type: workflow-entity
brooklyn.config:
start:
steps:
- log Starting up
stop:
steps:
- log Stopping
The workflow-entity
will automatically set the service.isUp
and service.state
sensors
based on invocation of start
and stop
and the success of the workflow.
It will also take into consideration the map sensors service.problems
and service.notUp.indicators
,
where any entry in the former will cause service.state
to show as “on-fire” if it is meant to be running,
and any entry in the latter will cause service.isUp
to become false (which will trigger an
entry in service.problems
if it is meant to be running). Thus liveness and health checks can,
and often should, be added, such as in the following getting the status_code
from the main.uri
,
and setting a service.problems
if it is unavailable:
- type: workflow-entity
brooklyn.config:
start:
steps:
- ... # start the service, e.g. using container or http call
- clear-sensor status_code
- set-sensor main.uri = ... # get the URL from the previous; this will trigger sensor feed
- step: wait ${entity.sensor.status_code}
timeout: 5m
stop:
# omitted
brooklyn.initializers:
- type: workflow-sensor
brooklyn.config:
sensor: status_code
period: 1m
triggers:
- main.uri
steps:
- step: http ${main.uri}
on-error:
- set-sensor service.problems['endpoint-live'] = ${error}
- fail rethrow message Endpoint is not accessible
- clear-sensor service.problems['endpoint-live']
- return ${status_code}
The workflow entity does not automatically start or stop children. If this is required, it should be part of the start/stop workflow, as follows:
- type: workflow-entity
brooklyn.config:
start:
steps:
- ... # start this
# now start children
- type: workflow
target: children
steps:
- invoke-effector start
stop:
steps:
# stop children first
- type: workflow
target: children
steps:
- invoke-effector stop
- ... # then stop this
Workflow Software Process Entities
Entities that run software or another machine-based process can also be defined,
relying on Cloudsoft AMP to provision a machine if required, then
using workflow for the install, customize, launch, check-running, and stop phases.
These entities will provision a machine if if given a cloud or machine provisioning
location, and use the same latches and pre/post phase on-box commands as the ofther SoftwareProcess
entities,
but for the key phases it will take a workflow
object as for workflow-entity
.
The steps
will often run ssh
and possibly set-sensor
, and
they can access the run dir and install dir using Freemarker
${entity.driver.installDir}
and ${entity.driver.runDir}
.
The workflow
object can also define inputs and outputs for use locally,
and on-error
handlers.
The checkRunning.workflow
should return true
or false
to indicate whether
the software is running. Alternatively, by setting the entity config usePidFile: true
and in the launch command writing the process id (PID) to ${entity.driver.pidFile}
,
AMP’s automatic PID detection can be used.
As an example:
- type: workflow-software-process
brooklyn.config:
install.workflow:
steps:
- ssh yum update
- ssh yum install ...
launch.workflow:
steps:
- let PORT = 4321
- 'ssh { echo hello | nc -l ${PORT} & } ; echo $! > /tmp/brooklyn-nc.pid'
- 'set-sensor main.uri = http://localhost:${PORT}/'
checkRunning.workflow:
steps:
- step: ssh ps -p `cat /tmp/brooklyn-nc.pid`
timeout: 10s
on-error:
- return false
- return true
stop.workflow:
steps:
- ssh kill -9 `cat /tmp/brooklyn-nc.pid`