Note

The documentation you're currently reading is for version 2.3.2. Click here to view documentation for the latest stable version.

Rules

BWC uses rules and worfklows to capture operational patterns as automations. Rules map triggers to actions (or workflows), apply matching criteria and map trigger payload to action inputs.

Rule Structure

Rules are defined in YAML. Rule definition structure, as well as required and optional elements are listed below:

---
    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}}"

The generic form of a rule is:

  • The name of the rule.
  • The pack that the rule belongs to. default is assumed if a pack is not specified.
  • The description of the rule.
  • The enabled state of a rule (true or false).
  • The type of trigger emitted from sensors to monitor, which may consist of:
    • parameters associated with a sensor/trigger.
  • An optional set of criteria, consisting of:
    • An attribute of the trigger payload.
    • The type of criteria comparison.
    • The pattern to match against.
  • The action to execute when a rule is matched, consisting of:
    • The ref (action/workflow) to execute.
    • An optional set of parameters to pass to the action execution.

Trigger

The trigger in a rule specifies which incoming events should be inspected for potential match against this rule. View all the triggers configured on a system via the command line with the st2 trigger list command:

vagrant@st2vagrant:~$ st2 trigger list
+--------------------------------+-----------+---------------------------+---------------------------------------------------------------------------------+
| ref                            | pack      | name                      | description                                                                     |
+--------------------------------+-----------+---------------------------+---------------------------------------------------------------------------------+
| core.st2.webhook               | core      | st2.webhook               | Trigger type for registering webhooks that can consume arbitrary payload.       |
| core.st2.generic.actiontrigger | core      | st2.generic.actiontrigger | Trigger encapsulating the completion of an action execution.                    |
| core.st2.IntervalTimer         | core      | st2.IntervalTimer         | Triggers on specified intervals. e.g. every 30s, 1week etc.                     |
| core.st2.DateTimer             | core      | st2.DateTimer             | Triggers exactly once when the current time matches the specified time. e.g.    |
|                                |           |                           | timezone:UTC date:2014-12-31 23:59:59.                                          |
| core.st2.CronTimer             | core      | st2.CronTimer             | Triggers whenever current time matches the specified time constaints like a     |
|                                |           |                           | UNIX cron scheduler.                                                            |
| core.st2.sensor.process_spawn  | core      | st2.sensor.process_spawn  | Trigger encapsulating spawning of a sensor process.                             |
| autoscale.ScaleDownPulse       | autoscale | ScaleDownPulse            | Pulse trigger emitted when an ASG is eligible for deflation                     |
| autoscale.ScaleUpPulse         | autoscale | ScaleUpPulse              | Pulse trigger emitted when an ASG is eligible for expansion                     |
| slack.message                  | slack     | message                   | Trigger which indicates a new message has been posted to a channel              |
| linux.file_watch.line          | linux     | file_watch.line           | Trigger which indicates a new line has been detected                            |
| core.st2.sensor.process_exit   | core      | st2.sensor.process_exit   | Trigger encapsulating exit of a sensor process.                                 |
| newrelic.WebAppAlertTrigger    | newrelic  | WebAppAlertTrigger        |                                                                                 |
| newrelic.WebAppNormalTrigger   | newrelic  | WebAppNormalTrigger       |                                                                                 |
| newrelic.ServerAlertTrigger    | newrelic  | ServerAlertTrigger        |                                                                                 |
| newrelic.ServerNormalTrigger   | newrelic  | ServerNormalTrigger       |                                                                                 |
| dripstat.alert                 | dripstat  | alert                     | Trigger representing an active alert                                            |
+--------------------------------+-----------+---------------------------+---------------------------------------------------------------------------------+

To learn more about Sensors/Triggers, take a look at the Sensors and Triggers page.

Criteria

Rule criteria are the rule(s) needed to be matched against (logical AND). Criteria in the rule is expressed as:

# more variables
criteria:
    trigger.payload_parameter_name1:
        type: "regex"
        pattern : "^value$"
    trigger.payload_parameter_name2:
        type: "iequals"
        pattern : "watchevent"

Note

You can achieve logical OR behavior (either one of multiple criteria expressions needs to match for the action execution to be triggered) by creating multiple independent rules (one per criteria expression).

type specifies which criteria comparison operator to use and pattern specifies a pattern which gets passed to the operator function.

In the regex case, pattern is a regular expression pattern which the trigger value needs to match.

A list of all the available criteria operators is described below. If you are missing some operator, you are welcome to code it up and submit a patch :)

If the criteria key contains an special characters (like -) then use the dictionary lookup format for specifying the criteria key. In case of a webhook based rule it is typical for the header of the posted event to contain such values e.g.:

criteria:
    trigger.headers['X-Custom-Header']:
        type: "eq"
        pattern : "customvalue"

The pattern value can also reference a datastore value using a Jinja variable access syntax as shown below:

criteria:
    trigger.payload.build_number:
        type: "equals"
        pattern : "{{ system.current_build_number }}"

In this example we are referencing a value of a datastore item with the name current_build_number.

Critera Comparison

This section describes all the available operators which can be used in the criteria.

Note

For Developers: The criteria comparison functions are defined in st2/st2common/st2common/operators.py.

Operator Description
equals Values are equal (for values of arbitrary type).
nequals Values are not equal (for values of arbitrary type).
lessthan Trigger value is less than the provided value.
greaterthan Trigger value is greater than the provided value.
matchwildcard Trigger value matches the provided wildcard-like string. This operator provides support for Unix shell-style wildcards which means you can use characters such as * and ?. This operator is preferred over regex for simple string matches.
regex Trigger value matches the provided regular expression pattern. This operator behaves like re.search('pattern', trigger_value).
iregex Trigger value matches the provided regular expression pattern case insensitively. This operator behaves like re.search('pattern', trigger_value, re.IGNORECASE).
matchregex Trigger value matches the provided regular expression pattern. This operator is deprecated in favor of regex and iregex
iequals String trigger value equals the provided value case insensitively.
contains Trigger value contains the provided value. Keep in mind that the trigger value can be either a string or an array (list).
ncontains Trigger value does not contain the provided value. Keep in mind that the trigger value can be either a string or an array (list).
icontains String trigger value contains the provided value case insensitively.
incontains String trigger value does not contain the provided string value case insensitively.
startswith Beginning of the string trigger value matches the provided string value.
istartswith Beginning of the string trigger value matches the provided string value case insensitively.
endswith End of the string trigger value matches the provided string value.
iendswith End of the string trigger value matches the provided string value case insensitively.
timediff_lt Time difference between trigger value and current time is less than the provided value.
timediff_gt Time difference between trigger value and current time is greater than the provided value.
exists Key exists in payload.
nexists Key doesn’t exist in payload.

Action

This section describes the subsequent action/workflow to be executed on a successful match of a trigger and an optional set of criteria. At a minimum, a rule should specify the action to execute. Additionally, a rule can also specify parameters that will be supplied to an action upon execution.

action:                                # required
    ref: "action_ref"
    parameters:                        # optional
        foo: "bar"
        baz: 1

Variable Interpolation

Occasionally, it will be necessary to pass along context of a trigger to an action when a rule is matched. The rules engine is able to interpolate variables by leveraging Jinja templating syntax.

action:
    ref: "action_ref"
    parameters:
        foo: "bar"
        baz: "{{trigger.payload_parameter_1}}"

Note

Value of trigger attribute can be null and None. It is also a valid value of the action parameter in question. You need to use the use_none Jinja template filter to make sure that null / None values are correctly serialized when invoking an action.

action:
    ref: "action_ref"
    parameters:
        foo: "bar"
        baz: "{{trigger.payload_parameter_1|use_none}}"

This workaround is required because of the limitation of our current templating system Jinja which doesn’t support non-string types. We are forced to perform type casting based on the action parameters definition before invoking an action.

Managing Rules

To deploy a rule, use CLI st2 rule create ${PATH_TO_RULE} command, To reload all the rules, use st2ctl reload --register-rules for example: ======= To deploy a rule, use the CLI command: st2 rule create ${PATH_TO_RULE}, for example:

st2 rule create /usr/share/doc/st2/examples/rules/sample_rule_with_webhook.yaml

If a rule with the same name already exists, the above command will return an error:

ERROR: 409 Client Error: Conflict
MESSAGE: Tried to save duplicate unique keys (E11000 duplicate key error index: st2.rule_d_b.$uid_1  dup key: { : "rule:examples:sample_rule_with_webhook" })

To update the rule, edit the rule definition file and run the command: st2 rule update, as in the following example:

st2 rule update examples.sample_rule_with_webhook /usr/share/doc/st2/examples/rules/sample_rule_with_webhook.yaml

Note

Hint: It is a good practice to always edit the original rule file, so that keep your infrastructure in code. You still can get the rule definition from the system by st2 rule get <rule name> -j, update it, and load it back.

To see all the rules, or to get an individual rule, use commands below:

st2 rule list
st2 rule get examples.sample_rule_with_webhook

To undeploy a rule, run st2 rule delete ${RULE_NAME_OR_ID}. For example, to undeploy the examples.sample_rule_with_webhook rule we deployed previously, run:

st2 rule delete examples.sample_rule_with_webhook

Rule Location

Custom rules can be placed in any accessible folder on local system. By convention, custom rules are placed in the /opt/stackstorm/packs/default/rules directory. By default, BWC doesn’t load the rules deployed under /opt/stackstorm/packs/${pack_name}/rules/. However you can force load them with st2 run packs.load register=rules or st2 run packs.load register=all.

Testing Rules

To make testing the rules easier we provide a st2-rule-tester tool which allows evaluating rules against trigger instances without running any of the BWC components.

The tool works by taking a path to the file which contains rule definition and a file which contains trigger instance definition:

st2-rule-tester --rule=${RULE_FILE} --trigger-instance=${TRIGGER_INSTANCE_DEFINITION}
echo $?

Both files need to contain definitions in YAML or JSON format. For the rule, you can use the same file you are planning to deploy.

For the trigger instance, the definition file needs contain the following keys:

  • trigger - Full reference to the trigger (e.g. core.st2.IntervalTimer, slack.message, irc.pubmsg, twitter.matched_tweet, etc.).
  • payload - Trigger payload. The payload itself is specific to the trigger in question. To figure out the trigger structure you can look at the pack README or look for the trigger_types section in the sensor metadata file which is located in the packs/<pack name>/sensors/ directory.

If the trigger instance matches, === RULE MATCHES === will be printed and the tool will exit with 0 status code. On the other hand, if the rule doesn’t match, === RULE DOES NOT MATCH === will be printed and the tool will exit with 1 status code.

Here are some examples of how to use the tool:

my_rule.yaml:

---
  name: "relayed_matched_irc_message"
  pack: "irc"
  description: "Relay IRC message to Slack if the message contains word StackStorm"
  enabled: true

  trigger:
    type: "irc.pubmsg"
    parameters: {}

  criteria:
      trigger.message:
          type: "icontains"
          pattern: "StackStorm"

  action:
    ref: "slack.post_message"
    parameters:
        message: "{{trigger.source.nick}} on {{trigger.channel}}: {{trigger.message}}"
        channel: "#irc-relay"

trigger_instance_1.yaml:

---
    trigger: "irc.pubmsg"
    payload:
      source:
          nick: "Kami_"
          host: "gateway/web/irccloud.com/x-uvv"
      channel: "#stackstorm"
      timestamp: 1419166748,
      message: "stackstorm is cool!"

trigger_instance_2.yaml:

---
    trigger: "irc.pubmsg"
    payload:
      source:
          nick: "Kami_"
          host: "gateway/web/irccloud.com/x-uvv"
      channel: "#stackstorm"
      timestamp: 1419166748,
      message: "blah blah"
st2-rule-tester --rule=./my_rule.yaml --trigger-instance=./trigger_instance_1.yaml
echo $?

Output:

2015-12-11 14:35:03,249 INFO [-] Connecting to database "st2" @ "0.0.0.0:27017" as user "None".
2015-12-11 14:35:03,318 INFO [-] Validating rule irc.relayed_matched_irc_message for pubmsg.
2015-12-11 14:35:03,331 INFO [-] 1 rule(s) found to enforce for pubmsg.
2015-12-11 14:35:03,333 INFO [-] === RULE MATCHES ===
0
st2-rule-tester --rule=./my_rule.yaml --trigger-instance=./trigger_instance_2.yaml
echo $?

Output:

2015-12-11 14:35:57,380 INFO [-] Connecting to database "st2" @ "0.0.0.0:27017" as user "None".
2015-12-11 14:35:57,444 INFO [-] Validating rule irc.relayed_matched_irc_message for pubmsg.
2015-12-11 14:35:57,459 INFO [-] Validation for rule irc.relayed_matched_irc_message failed on -
  key: trigger.message
  pattern: StackStorm
  type: icontains
  payload: blah blah
2015-12-11 14:35:57,461 INFO [-] 0 rule(s) found to enforce for pubmsg.
2015-12-11 14:35:57,462 INFO [-] === RULE DOES NOT MATCH ===
1

st2-rule-tester further allows a kind of post-mortem debugging where you can answer the question Why did my rule not match the trigger that just fired?. This means there is known Rule identifiable by its reference loaded in BWC and similarly a TriggerInstance with a known id.

Lets say we have rule reference my_pack.fire_on_execution and a trigger instance 566b4be632ed352a09cd347d

st2-rule-tester --rule-ref=my_pack.fire_on_execution --trigger-instance-id=566b4be632ed352a09cd347d --config-file=/etc/st2/st2.conf
echo $?

Output:

2015-12-11 15:24:16,459 INFO [-] Connecting to database "st2" @ "0.0.0.0:27017" as user "None".
2015-12-11 15:24:16,527 INFO [-] Validating rule my_pack.fire_on_execution for st2.generic.actiontrigger.
2015-12-11 15:24:16,542 INFO [-] Validation for rule my_pack.fire_on_execution failed on -
  key: trigger.status
  pattern: succeeded
  type: iequals
  payload: failed
2015-12-11 15:24:16,545 INFO [-] 0 rule(s) found to enforce for st2.generic.actiontrigger.
2015-12-11 15:24:16,546 INFO [-] === RULE DOES NOT MATCH ===

The output also identifies the source of the mismatch i.e. whether it was the trigger type that did not match or one of the criteria.

If you are debugging and would like to see the list of trigger instances sent to BWC, you can use the CLI to do so:

st2 trigger-instance list

You can also filter trigger instances by trigger:

st2 trigger-instance list --trigger=core.f9e09284-b2b1-4127-aedd-dcde7a752819

Also, you can get trigger instances within a time range by using timestamp_gt and timestamp_lt filter options:

st2 trigger-instance list --trigger="core.f9e09284-b2b1-4127-aedd-dcde7a752819" -timestamp_gt=2015-06-01T12:00:00Z -timestamp_lt=2015-06-02T12:00:00Z

Note that you can also specify one of timestamp_lt or timestamp_gt too. You can get details about a trigger instance by using get.

st2 trigger-instance get 556e135232ed35569ff23238

Something that might be useful in debugging a rule is to re-send a trigger instance into BWC. You can use the re-emit command for that.

st2 trigger-instance re-emit 556e135232ed35569ff23238

Timers

Timers allow running a particular action repeatedly based on a defined time interval or one time at a particular date and time. You can think of them as cron jobs, but with additional flexibility, e.g. ability to run actions only once, at the provided date and time.

Currently, we support the following timer trigger types:

  • core.st2.IntervalTimer - Run an action at predefined time intervals (e.g. every 30 seconds, every 24 hours, every week, etc.).
  • core.st2.DateTimer - Run an action at the specified date and time.
  • core.st2.CronTimer - Run an action when current time matches the time constraint defined in UNIX cron format.

Timers are implemented as triggers, which means you can use them inside the rules. In the section below, you can find some examples on how to use timers in the rule definitions.

core.st2.IntervalTimer

Available parameters:unit, delta. Supported values for unit parameter: seconds, minutes, hours, days, weeks.

Run action every 30 seconds

---
...

trigger:
  type: "core.st2.IntervalTimer"
  parameters:
      unit: "seconds"
      delta: 30

action:
  ...

Run action every 24 hours

---
...

trigger:
  type: "core.st2.IntervalTimer"
  parameters:
      unit: "hours"
      delta: 24

action:
  ...

Run action every 2 weeks

---
...

trigger:
  type: "core.st2.IntervalTimer"
  parameters:
      unit: "weeks"
      delta: 2

action:
  ...

core.st2.DateTimer

Available parameters: timezone, date.

Run action on a specific date

---
...

trigger:
  type: "core.st2.IntervalTimer"
  parameters:
      timezone: "UTC"
      date: "2014-12-31 23:59:59"

action:
  ...

core.st2.CronTimer

This timer supports cron-like expressions. For a full list of supported expressions, please see http://apscheduler.readthedocs.org/en/3.0/modules/triggers/cron.html#api.

By default, if no value is provided for a particular parameter, * is assumed, which means fire on every value.

Note

Unlike with cron where first day (0) in day_of_week is a Sunday, in BWC CronTimer first day of the week is always Monday. To make it more explicit and avoid confusion, you are encouraged to use name of the weekdays instead (e.g. mon-fri instead of 0-4, or in cron case, 1-5).

Available parameter timezone, year, month, day, week, day_of_week, hour, minute, second.

Run action every Sunday at midnight

---
...

trigger:
  type: "core.st2.CronTimer"
  parameters:
      timezone: "UTC"
      day_of_week: 6 # or day_of_week: "sun"
      hour: 0
      minute: 0
      second: 0

action:
  ...

Run action every day at midnight

---
...

trigger:
  type: "core.st2.CronTimer"
  parameters:
      timezone: "UTC"
      day_of_week: "*"
      hour: 0
      minute: 0
      second: 0

action:
  ...

As noted above, * is assumed if no value is provided for a particular parameter, which means the following is equivalent to the above.

---
...

trigger:
  type: "core.st2.CronTimer"
  parameters:
      timezone: "UTC"
      hour: 0
      minute: 0
      second: 0

action:
  ...

Run action Monday through Friday (every day except weekends) at midnight

---
...

trigger:
  type: "core.st2.CronTimer"
  parameters:
      timezone: "UTC"
      day_of_week: "mon-fri"
      hour: 0
      minute: 0
      second: 0

action:
  ...

Run action every full hour every day of the week

---
...

trigger:
  type: "core.st2.CronTimer"
  parameters:
      timezone: "UTC"
      hour: "*"
      minute: 0
      second: 0

action:
  ...

What’s Next?

Questions? Problems? Suggestions? Engage!