Create and Contribute a Pack

Think you’d like to create a StackStorm pack? Great! Here’s how to do it, and contribute it to the community.

Packs have a defined structure. You must follow this structure when creating your own pack. It is also helpful to know while debugging issues with packs.

Anatomy of a Pack

The canonical pack filesystem layout looks like this:

# contents of a pack folder
actions/                 #
rules/                   #
sensors/                 #
aliases/                 #
policies/                #
tests/                   #
etc/                     # any additional things (e.g code generators, scripts...)
config.schema.yaml       # configuration schema
packname.yaml.example    # example of config, used in CI
pack.yaml                # pack definition file
requirements.txt         # requirements for Python packs
requirements-tests.txt   # requirements for python tests
icon.png                 # 64x64 .png icon

At the topmost level are the main folders actions, rules, sensors, aliases and policies, as well as some shared files:

  • pack.yaml - Metadata file that describes and identifies the folder as a pack.

  • config.schema.yaml - Schema that defines configuration elements used by a pack.

  • requirements.txt - File containing a list of Python dependencies. Each pack has its own Python virtualenv. If you need any specific Python libraries, specify them here, and they will be automatically installed at pack install time.

    Note

    You should write all dependent libraries of your pack in this requirements.txt to prevent a runtime error because of unexpected dependencies problem.

    When an action of python-script in your pack is going to load a module which is not in the pack’s virtualenv, that will try to load it from the StackStorm’s library path that has these libraries impliedly. If these libraries are used from your pack’s dependent libraries without concern for the dependencies, a runtime error might be happen when these are incompatible with your pack’s libraries.

    The libraries which are specified in the requirements.txt are prioritized to be loaded over StackStorm’s ones. Therefore it’s better to write every libraries, with specifying version, that are called directly or indirectly in your pack’s requirements.txt.

Site-specific pack configuration files are stored at /opt/stackstorm/configs/. See configuration schema for more information.

Actions:

# contents of actions/
actions/
   lib/
   action1.yaml
   action1.py
   action2.yaml
   action1.sh
   workflow1.yaml
   workflow2.yaml
   workflows/
     workflow1.yaml
     workflow2.yaml

The actions folder contains action script files and action metadata files. See Actions and Workflows for specifics on writing actions. Since metadata files and workflow definitions can both be written as YAML, it’s good practice to put the workflow definitions in a separate directory. Note that the lib sub-folder is often used for storing common Python code used by pack actions.

Rules:

# contents of rules/
rules/
   rule1.yaml
   rule2.yaml

The rules folder contains rules. See Rules for specifics on writing rules.

Sensors:

# contents of sensors/
sensors/
   common/
   sensor1.py
   sensor1.yaml
   sensor2.py
   sensor2.yaml

The sensors folder contains sensors. See Sensors for specifics on writing sensors and registering TriggerTypes.

Aliases:

# contents of aliases/
aliases/
   alias1.yaml
   alias2.yaml

The aliases folder contains Action Aliases. See Action Aliases for specifics on writing Action Aliases.

Policies:

# contents of policies/
policies/
   policy1.yaml
   policy2.yaml

The policies folder contains Policies. See Policies for specifics on writing Policies.

Creating Your First Pack

In the example below, we will create a simple pack named hello_st2. The full example is also available at st2/contrib/hello_st2.

  1. Create the pack folder structure and related files. Let’s keep the metadata files such as pack.yaml, config.schema.yaml, and requirements.txt empty for now:

# Use the name of the pack for the folder name.
mkdir hello_st2
cd hello_st2
mkdir actions
mkdir rules
mkdir sensors
mkdir aliases
mkdir policies
touch pack.yaml
touch requirements.txt

Note: All folders are optional. It is safe to skip a folder or keep it empty. Only create the config.schema.yaml file if it is required. An empty schema file is not valid.

  1. Create the pack definition file, pack.yaml:

---
# Pack reference. It can only contain lowercase letters, digits and underscores.
# This attribute is only needed if "name" attribute contains special characters.
ref: hello_st2
# User-friendly pack name. If this attribute contains spaces or any other special characters, then
# the "ref" attribute must also be specified (see above).
name: Hello StackStorm
# User-friendly pack description.
description: Simple pack containing examples of sensor, rule, and action.
# Keywords which are used when searching for packs.
keywords:
    - example
    - test
# Pack version which must follow semver format (<major>.<minor>.<patch> e.g. 1.0.0)
version: 3.8.0
# A list of major Python versions pack is tested with and works with.
python_versions:
  - "2"
  - "3"
# New in StackStorm 3.2
# Specify a list of dependency packs to install. If the pack is in StackStorm Exchange you can use
# the pack name, or you can specify a full Git repository URL. Optionally, you can specify the
# exact version, tag, or branch.
dependencies:
  - core
# Name of the pack author.
author: StackStorm, Inc.
# Email of the pack author.
email: [email protected]
# Optional list of additional contributors to the pack.
contributors:
  - "John Doe1 <[email protected]>"
  - "John Doe2 <[email protected]>"

Note

A note on metadata: StackStorm enforces certain rules about metadata. The version value in pack.yaml must conform to semver:0.2.5, not 0.2. The name value in pack.yaml must only contain lowercase letters, digits, and underscores, unless you set the ref value explicitly in pack.yaml. Finally the email attribute in pack.yaml must contain a properly formatted email address.

From StackStorm 3.7.0, the name _global is reserved, and cannot be used as a pack name.

The python_versions field declares which Python versions this pack supports. As StackStorm only supports Python 3 from version 3.4.0 onwards, packs submitted to the StackStorm Exchange will run CI checks for Python version 3 only. StackStorm will check this field when installing packs, and not allow installation with unsupported major Python versions. If this field is missing, StackStorm assumes both Python 2 and 3 are supported.

  1. Create the action. An action consists of meta data, and entrypoint. The following example simply echoes a greeting.

Copy the following content to actions/greet.yaml:

---
name: greet
pack: hello_st2
runner_type: "local-shell-script"
description: Greet StackStorm!
enabled: true
entry_point: greet.sh
parameters:
    greeting:
        type: string
        description: Greeting you want to say to StackStorm (i.e. Hello, Hi, Yo, etc.)
        required: true
        position: 1

Copy the following content to actions/greet.sh:

#!/bin/bash
echo "$1, StackStorm!"
  1. Create a sensor. The sample sensor below publishes an event to StackStorm every 60 seconds.

Copy the following content to sensors/sensor1.yaml:

---
class_name: "HelloSensor"
entry_point: "sensor1.py"
description: "Test sensor that emits triggers."
trigger_types:
  -
    name: "event1"
    description: "An example trigger."
    payload_schema:
      type: "object"

Copy the following content to sensors/sensor1.py:

# Copyright 2020 The StackStorm Authors.
# Copyright 2019 Extreme Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import eventlet

from st2reactor.sensor.base import Sensor


class HelloSensor(Sensor):
    def __init__(self, sensor_service, config):
        super(HelloSensor, self).__init__(sensor_service=sensor_service, config=config)
        self._logger = self.sensor_service.get_logger(name=self.__class__.__name__)
        self._stop = False

    def setup(self):
        pass

    def run(self):
        while not self._stop:
            self._logger.debug("HelloSensor dispatching trigger...")
            count = self.sensor_service.get_value("hello_st2.count") or 0
            payload = {"greeting": "Yo, StackStorm!", "count": int(count) + 1}
            self.sensor_service.dispatch(trigger="hello_st2.event1", payload=payload)
            self.sensor_service.set_value("hello_st2.count", payload["count"])
            eventlet.sleep(60)

    def cleanup(self):
        self._stop = True

    # Methods required for programmable sensors.
    def add_trigger(self, trigger):
        pass

    def update_trigger(self, trigger):
        pass

    def remove_trigger(self, trigger):
        pass
  1. Create a rule. The sample rule below is triggered by an event from the sensor and invokes the action from the samples above.

Copy the following content to rules/rule1.yaml:

---
name: on_hello_event1
pack: hello_st2
description: Sample rule firing on hello_st2.event1.
enabled: true
trigger:
    type: hello_st2.event1
action:
    ref: hello_st2.greet
    parameters:
        greeting: Yo
  1. Create an action alias. The sample action alias below aliases the greet action and makes it accessible from ChatOps.

Copy the following content to aliases/alias1.yaml:

---
name: greet
pack: hello_st2
description: "Greet StackStorm"
action_ref: "hello_st2.greet"
formats:
  - "greet {{greeting}}"
  1. Create a policy. The sample policy below limits concurrent operation of the greet action.

Copy the following content to policies/policy1.yaml:

---
name: greet.concurrency
pack: hello_st2
description: Limits the concurrent executions of the greet action.
enabled: true
resource_ref: hello_st2.greet
policy_type: action.concurrency
parameters:
    threshold: 10
  1. Install the pack. We encourage using git. If you do so, st2 pack will greatly simplify your pack management. Of course, you can define your own tools and workflow for editing and versioning packs. You’ll need to place the files in /opt/stackstorm/packs and [re-]load the content.

8.1 Use git and pack install (recommended):

# Get the code under git
cd hello_st2
git init && git add ./* && git commit -m "Initial commit"
# Install from local git repo
st2 pack install file://$PWD

When you make code changes, run st2 pack install again: it will do the upgrade. Once you push it to GitHub, you will install and update it right from there:

st2 pack install https://github.com/MY/PACK

8.2 Copy over and register (if you have special needs and know what you’re doing).

mv ./hello_st2 /opt/stackstorm/packs
st2ctl reload

Congratulate yourself: you have created your first pack. Commands like st2 pack list, st2 action list, st2 rule list and st2 trigger list will show you the loaded content. To check if the sensor triggering action is working, run st2 execution list, there should be an entry for executing hello_st2.greet every minute.

Take it from there. Write an awesome automation, or an inspiring integration pack with your favorite tool. Happy hacking!

Submitting a Pack to the Community

Now that you forged this awesome pack in StackStorm it’s time, and good form, to share your awesomeness with the community. StackStorm Exchange is the place for you and everyone else to share and pull integration packs.

To feature your pack on the StackStorm Exchange, submit a GitHub pull request to the StackStorm Exchange Incubator repository. Our team will review the PR, accept it to the incubator, graduate it to the main “Exchange”, and help you promote it.

Contributors License Agreement

By contributing you agree that these contributions are your own (or approved by your employer) and you grant a full, complete, irrevocable copyright license to all users and developers of the project, present and future, pursuant to the license of the project.