Stackstorm
Stackstorm#
- Platform for integration and automation across services and tools
- Ties together existing infrastructure and application environment
-
Focuses on taking actions in response to events
-
Facilitated troubleshooting
- Automated remediation
- Continuous deployment
Compose these rules and workflows as code. StackStorm integrates with other systems through something called packs
How it Works#
- Events are aggregated (Push/Pull) from various services via sensors
- Events are compared against triggers and generate actions
- Processed actions areplaced on a message queue (rabbit mq)
- Actions reach out to services to perform the actions
- Log/audit history is pushed to the db (mongo)
- Processed results are sent back to the rules engine for further processing
Terms:
- Sensors - python plugins. Inbound or outbound, receive or watch for events. A trigger is generated by sdtackstorm.
- Triggers - stackstorm representations of external events
- Actions - Outbound integrations. Eg. SSH, rest call, openstack, docker, ansible,
- Rules - Map triggers to actions or workflows.
- Workflows - Stitch actions together, define order, transitions and passing data.
- Packs - units of content deployment (plugins) found on stackstorm exchange
- Audit trail - actions are recorded and stored.
ST2 Services#
- Provides the main stackstorm functionality
- Located at
/opt/stackstorm/st2
- Share a virtualenv
- Configured via
/etc/st2/st2.conf
Read more about the reference deployment on stackstorm
Getting Started#
Check the st2 version:
st2 --version
st2 3.0.0, on Python 2.7.12
Login:
st2 login st2admin -p Ch@ngeMe
List actions from the core pack:
st2 action list --pack=core
List all the triggers:
st2 trigger list
List rules:
st2 rule list
Actions#
Run a local shell command:
st2 run core.local -- date -R
See the execution results:
st2 execution list
Run a command on a remote host:
st2 run core.remote hosts='localhost' -- uname -a
All stackstorm operations are also available via the REST Api
List all actions:
st2 action list
Get action metadata:
st2 action get core.http
Get details and parameters for an action:
st2 run core.http --help
To run an action from the cli use:
st2 run <action> key=value positional arguments
Eg. st2 run -j core.http url="https://docs.stackstorm.com" method="GET"
Use core.remote
to run linux commands on multiple hosts via ssh. It assumes passwordless ssh is configured for the host.
For core.local
and core.remote
use --
to seperate the command run on the host or use the cmd
parameter.
st2 run core.local -- ls -al
st2 run core.local cmd="ls -al"
Executions#
Get a list of executions:
st2 execution list
Get a single execution:
st2 execution get 5cc6f3766cb8de088e9dab3c
Get the last 5 executions:
st2 execution list -n 5
Creating a Rule#
- StackStorm uses rules to run actions or workflows when events happen.
- Events are typically monitored by sensors.
- When a sensor catches an event, it fires a trigger.
- Trigger trips the rule, the rule checks the criteria and if it matches, it runs an action.
A rule definition is a yaml
file with 3 sections: trigger, criteria and action.
Define a rule, based on the rule structure:
---
name: "sample_rule_with_webhook"
pack: "examples"
description: "Sample rule dumping webhook payload to a file."
enabled: true
trigger:
type: "core.st2.webhook"
parameters:
url: "sample"
criteria:
trigger.body.name:
pattern: "st2"
type: "equals"
action:
ref: "core.local"
parameters:
cmd: "echo \"{{trigger.body}}\" >> ~/st2.webhook_sample.out ; sync"
- The
trigger
is a webhook…so going tohttps://your-server/api/v1/webhooks/sample
trips the rule. - The
criteria
will check that the body name contains the patternst2
- The
action
will append the payload to that file on the stackstorm local host node
The payload of a trigger is reffered to with {{ trigger }}
, if it is a valid json object it can be accessed with {{trigger.path.to.parameter}}
Remember to check available triggers:
# View a list of triggers
st2 trigger list
# Check details of a trigger
st2 trigger get core.st2.webhook
You can do alot more with criteria comparisons
Deploy a Rule#
Stackstorm can autoload rules, or can be deployed with API or CLI
Create a rule from CLI#
st2 rule create /usr/share/doc/st2/examples/rules/sample_rule_with_webhook.yaml
# List the rules
st2 rule list --pack=examples
# Get the rule you just created
st2 rule get examples.sample_rule_with_webhook
Executing the action that triggers that rule#
Check your apikey
:
st2 apikey list
Make the call to the webhook endpoint:
Install httpie:
sudo apt update
sudo apt install httpie
Make the request to the /sample
endpoint:
I got the auth token using the --debug
command
http --verify=no https://10.10.10.10/api/v1/webhooks/sample foo=bar bill=baz name=st2 X-Auth-Token:cc29ec9adca840eeb44734cdbeaa8a4f
Check if the action was executed:
st2 execution list -n 1
Verify it actually worked:
sudo tail /home/stanley/st2.webhook_sample.out
{u'foo': u'bar', u'bill': u'baz', u'name': u'st2'}
By default st2 runs as the stanley user
You can even run an action from stackstorm:
st2 run core.http method=POST body='{"you": "too", "name": "st2"}' url=https://10.10.10.10/api/v1/webhooks/sample headers='x-auth-token=cc29ec9adca840eeb44734cdbeaa8a4f,content-type=application/json' verify_ssl_cert=False
You will get a 202
accepted response…it did not give me the execution id
It is best to store your custom packs (of custom actions, rules, sensors and triggers) as code in a repo as
.yml
files
To deploy them, copy them to: /opt/stackstorm/packs/
# Copy examples to st2 content directory and set permissions
sudo cp -r /usr/share/doc/st2/examples/ /opt/stackstorm/packs/
sudo chown -R root:st2packs /opt/stackstorm/packs/examples
sudo chmod -R g+w /opt/stackstorm/packs/examples
# Run setup
st2 run packs.setup_virtualenv packs=examples
# Reload stackstorm context
st2ctl reload --register-all
Datastore#
To store and share common variables you can use stackstorm’s datastore, which can be referenced in rules and workflows with: {{st2kv.system.my_parameter}}
Create a key value:
st2 key set user stanley
View a list of key value stores:
st2 key list
StackStorm API Docs#
Actions#
In StackStorm, we can accomplish such things through actions
Eg.
- Push a config change to a network device
- Restart a service on a server
- Retrieve information about a virtual machine
- Bounce a switchport
- Send a message to slack
They accept input, do work, and usually provide some output
Run a hello world on the local machine
st2 run core.local "echo Hello World!"
Get help about an action
st2 run core.local -h
Run an action in the background (sometimes you don’t want to have to wait for an action to complete)
st2 run -a core.local "sleep 300"
Get the result of an action
st2 execution get 5cc81e6e6cb8de0867e220ca
id: 5cc81e6e6cb8de0867e220ca
status: running (27s elapsed)
parameters:
cmd: sleep 300
result: None
The execution describes an instance of a running action
See a list of recent executions
st2 execution list
Using a pack#
View the actions in a pack
st2 action list --pack=napalm
Credentials are stored in pack configurations
cat /opt/stackstorm/configs/napalm.yaml
Stackstorm Help#
CLI for StackStorm event-driven automation platform. https://stackstorm.com
positional arguments:
{run,action,action-alias,auth,login,whoami,apikey,execution,inquiry,key,pack,policy,policy-type,rule,webhook,timer,runner,sensor,trace,trigger,trigger-instance,rule-enforcement,workflow,service-registry,role,role-assignment}
run Invoke an action manually.
action An activity that happens as a response to the external
event.
action-alias Action aliases.
auth Authenticate user and acquire access token.
login Authenticate user, acquire access token, and update
CLI config directory
whoami Display the currently authenticated user
apikey API Keys.
execution An invocation of an action.
inquiry Inquiries provide an opportunity to ask a question and
wait for a response in a workflow.
key Key value pair is used to store commonly used
configuration for reuse in sensors, actions, and
rules.
pack A group of related integration resources: actions,
rules, and sensors.
policy Policy that is enforced on a resource.
policy-type Type of policy that can be applied to resources.
rule A specification to invoke an "action" on a "trigger"
selectively based on some criteria.
webhook Webhooks.
timer Timers.
runner Runner is a type of handler for a specific class of
actions.
sensor An adapter which allows you to integrate StackStorm
with external system.
trace A group of executions, rules and triggerinstances that
are related.
trigger An external event that is mapped to a st2 input. It is
the st2 invocation point.
trigger-instance Actual instances of triggers received by st2.
rule-enforcement Models that represent enforcement of rules.
workflow Commands for workflow authoring related operations.
Only orquesta workflows are supported.
service-registry Service registry group and membership related
commands.
role RBAC roles.
role-assignment RBAC role assignments.
Debugging commands#
Using the --debug
flag you can see all the requests being made to the stackstorm api.
**The --debug
flag must be just after st2
Eg.
st2 --debug run core.local date
Stackstorm packs#
Stackstorm is highly extensible It focuses on the primitives necessary to enable event-driven automation
Anytime you want to integrate with a third party system or upload some custom rules or workflows, you do this through a pack.
Install a pack
st2 pack install napalm
Packs can also be installed directly from a git repo:
st2 pack install https://github.com/emedvedev/chatops_tutorial
Actions#
pieces of code that can perform arbitrary automation or remediation tasks
Examples:
- Restart a service on a server
- Create a cloud server
- Acknowledge a nagios, or pagerduty alert
- Send a notification via email or sms
- Send a message to slack
- Snapshot a vm
- Run a nagios check
Executed when a rule is triggered. Multiple actions can be strung together in a workflow.
CLI#
View all actions
st2 action list
List all actions in linux packs
st2 action list -p linux
Get info of a particular action
st2 action get linux.check_loadavg
To execute an action manually
st2 action execute <action with parameters>
Eg.
st2 action execute core.http url="http://httpbin.org/get"
Action Runners#
An execution environment for user-implemented actions to be run remotely via ssh (or locally).
Available runners:
local-shell-cmd
- Executes linux commands on the host of Stackstormlocal-shell-script
- Executes scipts on the host of Stackstormremote-shell-cmd
- Executes linux command on one or more remote hosts provided by the userremote-shell-script
- Remote runner for scriptspython-script
- Python runner, implemented as arun()
method on python classes.http-request
- HTTP clientaction-chain
- Executes simple linear workflowsmistral-v2
- Executes complex Mistral Openstack workflowscloudslang
- Complex workflows, built on top of CloudSlanginquirer
- Implements core logic ofinquiries
winrm-cmd
- Run CLI on windows hostswinrm-ps-cmd
- Run powershell on windows hostswinrm-ps-script
- Run powershell scripts on hosts
Actions inherit the runner’s parameters.
Writing Custom Actions#
An action is composed of: 1. A Yaml metadata file describing the aciton and inputs 2. A script that implements the logic
Can use any programming language as long as it exits with 0
on success and 1
on error.
All log messages should be printed to stderr
Action Metadata#
Describes the action.
name
- Name of the actionrunner_type
- Type of runnerenabled
entry_point
- Location of the action launch script relative to:/opt/stackstorm/packs/${pack_name}/actions/
parameters
- dictionary of parameters for the actiontags
- Supplemental information
Eg.
---
name: "send_sms"
runner_type: "python-script"
description: "This sends an SMS using twilio."
enabled: true
entry_point: "send_sms.py"
parameters:
from_number:
type: "string"
description: "Your twilio 'from' number in E.164 format. Example +14151234567."
required: true
position: 0
to_number:
type: "string"
description: "Recipient number in E.164 format. Example +14151234567."
required: true
position: 1
secret: true
body:
type: "string"
description: "Body of the message."
required: true
position: 2
default: "Hello {% if system.user %} {{ st2kv.system.user }} {% else %} dude {% endif %}!"
Output Schema#
Disabled by default.
To enable it set: validate_output_schema = True
in /etc/st2/st2.conf [system]
Modelling the output of an action. This aids in workflow development and error handling.
For example a python action outputs a tuple:
---
...
output_schema:
errors:
type: array
items:
type: string
output:
required: true
type: array
items:
type: number
status_code:
required: true
type: integer
If the action does not return the correct fields it will fail validation and the action itself will fail. This prevents propagating corrupt data to other actions in a workflow that could lead to unpredictable results.
Paramters in Action#
You can access variable from the key-value store at st2kv.system
. YOu can get access to action context variable with:
parameters:
user:
type: "string"
description: "User of this action."
required: true
default: "{{action_context.api_user}}"
The prefix action_context
is used.
You can also access config_context
which contains key-value contents of your pack configuration
In actionchains and workflows, every task can access the parent’s execution_id
Action Registration#
To register a new action:
- Place it into the content location
- Tell the system the action is available
Actions are grouped in packs and located at: /opt/stackstorm/packs
For hacking one off actions create you action in /opt/stackstorm/packs/default/actions
, once tested add it to a dedicated pack.
Register an action with:
st2 action create my_action_metadata.yaml
Reload all actions:
st2ctl reload --register-actions
Built-in Parameters#
args
cmd
cwd
env
dir
Overriding Runner Parameters#
The linux.rsync
action overrides the cmd
in the remote-shell-cmd
runner, with rsync
:
---
name: 'rsync'
runner_type: 'remote-shell-cmd'
description: 'Copy file(s) from one place to another w/ rsync'
enabled: true
entry_point: ''
parameters:
source:
type: 'string'
description: 'List of files/directories to to be copied'
required: true
dest_server:
type: 'string'
description: "Destination server for rsync'd files"
required: true
destination:
type: 'string'
description: 'Destination of files/directories on target server'
required: true
cmd:
immutable: true
default: 'rsync {{args}} {{source}} {{dest_server}}:{{destination}}'
connect_timeout:
type: 'integer'
description: 'SSH connect timeout in seconds'
default: 30
args:
description: 'Command line arguments passed to rysnc'
default: '-avz -e "ssh -o ConnectTimeout={{connect_timeout}}"'
Environment variables for actions#
Runners make the following environment variables available:
ST2_ACTION_PACK_NAME
- name of pack the current action belongs toST2_ACTION_EXECUTION_ID
- Execution id of the action being executedST2_ACTION_API_URL
- Full URL to the public API endpointST2_ACTION_AUTH_TOKEN
- Auth token which is available to the action until it completes
You can use these in a shell script:
#!/usr/bin/env bash
# Retrieve a list of actions by hitting the API using cURL and the information provided
# via environment variables
RESULT=$(curl -H "X-Auth-Token: ${ST2_ACTION_AUTH_TOKEN}" ${ST2_ACTION_API_URL}/actions)
echo ${RESULT}
Converting Existing Scripts into Actions#
Converting an existing script
- Make sure script conforms to conventions
Make sure it exits on 0 for success, non-zero for error
- Create a metadata file
You will probably use: remote-shell-script
- Update argument parsing in the script
named
- parameters that do not include the position attribute-
positional
- include a position attributescript.sh –param1=value –param2=value –param3=value
types of arguments:
string
,integer
andfloat
- serialized as a stringboolean
- serialized as a string 1 (true) or 0 (false)array
- serialized as a comma delimited stringobject
- serialized as json
Alot more info in the docs…
Sensors and Triggers#
Sensors#
Python that periodically poll external events or passively wait for inbound events. They inject triggers, which can be matched by rules for potencial action execution.
Triggers#
Identify the incoming events to StackStorm A trigger is a tuple of type (string) and optional parameters (object).
Info on creating sensors and triggers in the docs
Rules#
Capture operational patterns as automations
Rules map triggers to actions (or workflows), apply matching criteria and map trigger payloads to action inputs
Example:
---
name: "rule_name" # required
pack: "examples" # optional
description: "Rule description." # optional
enabled: true # required
trigger: # required
type: "trigger_type_ref"
criteria: # optional
trigger.payload_parameter_name1:
type: "regex"
pattern : "^value$"
trigger.payload_parameter_name2:
type: "iequals"
pattern : "watchevent"
action: # required
ref: "action_ref"
parameters: # optional
foo: "bar"
baz: "{{ trigger.payload_parameter_1 }}"
name
- name of the rulepack
- the pack a rule belongs to,default
is assumeddescription
enabled
trigger
- type of trigger emitted (get withst2 trigger list
)criteria
- optional, type of comparison and a pattern to match against.action
- the action to execute
Each rule can only have a single action, for multiple actions you need to create a workflow
Criteria#
Rules needed to be matched against
Eg.
criteria:
trigger.payload_parameter_name1:
type: "regex"
pattern : "^value$"
trigger.payload_parameter_name2:
type: "iequals"
pattern : "watchevent"
The above criteria are AND
If you want OR
criteria, have multiple criteria
sections
Criteria Types#
equals
- Values are equalnequals
- Values not equallessthan
- trigger value is less than provided valuegreaterthan
matchwildcard
- simple grok style linux matchingregex
- regular expression -re.search('pattern', trigger_value)
iregex
- case insensitive regexiequals
- case insensitve string matchcontains
- contains string case sensitivencontains
- does not contain the provided valueicontains
- contains string case insensitivestartswith
- beginning matches a stringendswith
- ends with a given stringiendswith
- ends with, case insensitivitytimediff_lt
- time difference between trigger time and current time less thantimediff_gt
- time difference between trigger time and current time greater thaninside
- checking if trigger.payload is within provided value (opposite of contains)ninside
- not insidesearch
- way to match json withany
orall
Action#
Sets the action or workflow to be executed on successful match of a trigger and an optional set of criteria. A rule can also specify parameters.
Example
action: # required
ref: "action_ref"
parameters: # optional
foo: "bar"
baz: 1
To pass along the context of a trigger to an action, you can interpolate variable with Jinja templating syntax.
action:
ref: "action_ref"
parameters:
foo: "bar"
baz: "{{ trigger.payload_parameter_1 }}"
Both
null
andNone
can be a trigger variable so use the following filter:{{ trigger.payload_parameter_1 | use_none }}
Managing Rules#
To deploy a rule:
st2 rule create ${PATH_TO_RULE}
Eg.
st2 rule create /usr/share/doc/st2/examples/rules/sample_rule_with_webhook.yaml
You can update a rule with:
st2 rule update /usr/share/doc/st2/examples/rules/sample_rule_with_webhook.yaml
Reload all rules with
st2ctl reload --register-rules
List all rules
st2 rule list
View a single rule
st2 rule get examples.sample_rule_with_webhook
Delete a rule
st2 rule delete ${RULE_NAME_OR_ID}
Rule Location#
Rules are located at: /opt/stackstorm/packs/<pack_name>/rules
Testing Rules#
A st2-rule-tester
is provided to evaluate rules against trigger instances without running any of the stackstorm components.
st2-rule-tester --rule=${RULE_FILE} --trigger-instance=${TRIGGER_INSTANCE_DEFINITION} --config-file=/etc/st2/st2.conf
echo $?
RULE_FILE
- yaml rule fileTRIGGER_INSTANCE_DEFINITION
- specification of the trigger with accompanying payload
Example:
---
trigger: "irc.pubmsg"
payload:
source:
nick: "Kami_"
host: "gateway/web/irccloud.com/x-uvv"
channel: "#stackstorm"
timestamp: 1419166748,
message: "stackstorm is cool!"
Timers#
Allow running a particular action repeatedly based on a defined time interval, or at a specific point in time. Like cron jobs.
Trigger types:
core.st2.IntervalTimer
- run at specific intervalscore.st2.DateTimer
- run an action at the specified date and timecore.st2.CronTimer
- Run an action when current time matches the time constraint defined in UNIX cron format
core.st2.IntervalTimer#
Eg.
trigger:
type: "core.st2.IntervalTimer"
parameters:
unit: "seconds"
delta: 30
core.st2.CronTimer#
trigger:
type: "core.st2.CronTimer"
parameters:
timezone: "UTC"
day_of_week: 6 # or day_of_week: "sun"
hour: 0
minute: 0
second: 0
Workflows#
Multiple actions across various systems. Strings atomic actions into higher level automation, orchestrates their executions and inputs, it maintains state between actions and provides reliability and transparency to the execution.
Workflows can be called by other workflows
Workflow runners#
- Orquesta - New workflow engine, replaces both ActionChains and Mistral
- ActionChain - Legacy no frills workflow runner. No complex logic.
- Mistral - orignated in Openstack: complex, nested, error handling, forks, joins etc.
Orquestra#
Runs natively on stackstorm.
Defined in yaml
, does not require a seperate authentication system and database like Mistral.
- A graph based workflow engine
Getting Started#
Requires an action metadata file: /opt/stackstorm/packs/<mypack>/actions
Basic example: examples.orquesta-basic
Save in /opt/stackstorm/packs/examples/actions/workflows/orquesta-basic.yaml
:
version: 1.0
description: A basic workflow that runs an arbitrary linux command.
input:
- cmd
- timeout
tasks:
task1:
action: core.local cmd=<% ctx(cmd) %> timeout=<% ctx(timeout) %>
next:
- when: <% succeeded() %>
publish:
- stdout: <% result().stdout %>
- stderr: <% result().stderr %>
output:
- stdout: <% ctx(stdout) %>
Define the workflow in /opt/stackstorm/packs/examples/actions/orquesta-basic.yaml
:
---
name: orquesta-basic
pack: examples
description: Run a local linux command
runner_type: orquesta
entry_point: workflows/orquesta-basic.yaml
enabled: true
parameters:
cmd:
required: true
type: string
timeout:
type: integer
default: 60
Then create the action:
st2 action create /opt/stackstorm/packs/examples/actions/orquesta-basic.yaml
Run the workflow:
st2 run examples.orquesta-basic cmd=date -a
Inspection#
The workflow is inspected before execution.
Other Stackstorm stuff#
- It has a powerful workflow engine, where a shell script is linear satackstorm can branch and do various actions.
- You can use
core.ask
for asking a question to a user - continue or abort
Storing secrets#
It is recommended to store encrypted values for passwords and private keys.
To store a secret:
st2 key set api_token SECRET_TOKEN --encrypt
To get the key as plain text use:
st2 key get api_token --decrypt
To use variables stored in jinja use decrypt_kv
:
aws_key: "{{st2kv.system.aws_key | decrypt_kv}}"
To store dictionaries or lists:
```# Pass the result of this expression to the action st2.kv.set {{ {‘complex’: ‘structure’, ‘foo’: [‘x’, True]} | to_json_string }}
Or set it on the CLI#
st2 key set foo ‘{“complex”: “structure”, “foo”: [“x”, True]}’
Read the data back in using the st2kv and from_json_string filters#
{{ st2kv.system.foo | from_json_string }}```
In these cases it is very important to check the examples in the repo: st2/contrib/examples/actions/workflows
From the examples there are various ways to intepolate the key value variable:
With yaql
:
password: <% st2kv('system.my_password', decrypt => true) %>
with yaml
:
cmd: 'echo "{{ st2kv.system.foobar }}"'
or:
cmd: echo "{{ st2kv('system.foobar', decrypt=True) }}"
for some reason this does not work:
password: "{{ st2kv.system.password | decrypt_kv }}"
Troubleshooting a Rule#
Excellent post on troubleshooting a rule with stackstorm
Your don’t need a pack for everything#
why can’t you just install the Packer CLI on your StackStorm box? FYI that’s exactly how we use it. Same with Terraform, we install the Terraform CLI on the StackStorm host - NMaludy (stackstorm slack 2019)
If there is a command line tool you want to use, you can use it simply with using a core.local
action.
If the tool is sitting on another server, then you could also use core.remote
Installing packs from private repos#
Sometimes you will have your own private repo to deploy on a stackstorm instance.
You can view this link on installing packs from private repos
Which comes down to doing:
st2 pack install https://<user>:<token>@github.com/username/repo.git
st2 variable#
Apparently you can use the st2
variable in a workflow: ctx(st2)
vars:
- username: {{ ctx(st2).api_user }}