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’srequirements.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.
Create the pack folder structure and related files. Let’s keep the metadata files such as
pack.yaml
,config.schema.yaml
, andrequirements.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.txtNote: 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.
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 inpack.yaml
must conform to semver:0.2.5
, not0.2
. Thename
value inpack.yaml
must only contain lowercase letters, digits, and underscores, unless you set theref
value explicitly inpack.yaml
. Finally the email attribute inpack.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.
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: 1Copy the following content to
actions/greet.sh
:#!/bin/bash echo "$1, StackStorm!"
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
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
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}}"
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
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://$PWDWhen 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/PACK8.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.
Hint
If you are new to git/GitHub, check this excellent interactive learning resource, a guide for submitting a GitHub pull request and a more detailed Fork-Branch-PullRequest workflow tutorial.
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.