September, 11 2015
by Dmitri Zimine
A StackStorm user with large investment in Java asked us: “Can I turn my Java code into StackStorm actions, and how?”
The answer is “Yes you can, in three basic steps”:
dotted.notation
in workflows.
But before diving into details: how StackStorm can leverages Java assets in StackStorm? They become a part of automation library, with unified API, CLI and UI. You combine them via workflows and rules with other actions and sensors – thousands on StackStorm Exchange and through integration with Chef, Puppet, Git, monitoring, and others. They become part of your auto-remediation, continuous deployment, security responses, or other solutions. Last, but not the least, StackStorm native ChatOps integration makes your Java actions runnable from Slack or HipChat or IRC, with few lines of configuration. And if you are NOT Java, check out Actions of All Flavors – an excellent tutorial on turning “any” script into action.
Now lets get techy and dive into step-by-step details.
I am using default
pack in the example below, adjust accordingly if you are creating your Java action in a new pack.
This is the simplest Java app that fits our bill: uses an extra party java library, takes cli arguments, and spits out JSON:
//opt/stackstorm/packs/default/actions/MyApp.java | |
// Used https://code.google.com/p/json-simple/, download and save as lib/json-simple-1.1.1.jar | |
import org.json.simple.JSONArray; | |
import org.json.simple.JSONObject; | |
class MyApp | |
{ | |
public static void main(String[] args) | |
{ | |
JSONObject obj = new JSONObject(); | |
JSONArray list = new JSONArray(); | |
for (String s: args) { | |
list.add(s); | |
} | |
obj.put("description", "array of arguments"); | |
obj.put("args", list); | |
System.out.print(obj); | |
System.out.println(); | |
} | |
} |
I place MyApp.java into /opt/stackstorm/packs/default/actions/
, and the dependency json-simple-1.1.1.jar under /opt/stackstorm/packs/default/actions/lib
. You can keep them wherever you like, and adjust the paths on the next step, when defining action metadata.
Compile and make sure it runs:
$ javac -cp lib/<em>:. MyApp.java $ java -cp lib/</em>:. MyApp foo bar {"args":["foo","bar"],"description":"array of arguments"}
2. Create action
# /opt/stackstorm/packs/default/actions/jaction.yaml | |
--- | |
name: jaction | |
description: Sample of running Java. | |
runner_type: "local-shell-cmd" | |
parameters: | |
cmd: | |
immutable: true | |
default: "java MyApp {{p1}} {{p2}}" | |
cwd: | |
default: "/opt/stackstorm/packs/default/actions/" | |
immutable: true | |
env: | |
default: | |
CLASSPATH: lib/*:. | |
p1: | |
type: "string" | |
default: "do" | |
p2: | |
type: "string" | |
default: "something" | |
You can see, this action meta data as usual. Few notes on “secret sauce” that makes it all work:
local-shell-cmd
runner. It runs an arbitrary command, specified by cmd
parameter. In our case, it is calling Making the default
parameter `immutable` effectively hardcodes it.p1
and p2
are the parameters I define for the action, they are mapped to the input of MyApp in cmd
parameter.cwd
, “current working directory”, is where the command will be executed.env
lets me add environment variables to the execution context. That’s exactly what I need to pass CLASSPATH
. Given that I already set up the cwd
as the directory where MyApp is located, classpath is relative to it: lib/*:.
.Create the action with the following command:
st2 action create /opt/stackstorm/packs/default/actions/jaction.yaml
[email protected]:/opt/stackstorm/packs/default/actions$ st2 run default.jaction p1=do p2=something | |
. | |
id: 55d3c11b5b64c44adab13f5c | |
status: succeeded | |
result: | |
{ | |
"succeeded": true, | |
"failed": false, | |
"return_code": 0, | |
"stderr": "", | |
"stdout": { | |
"args": [ | |
"do", | |
"something" | |
], | |
"description": "array of arguments" | |
} | |
} |
Yes, that’s it!
And make a note: the output is parsed as JSON – to make sure, do st2 execution --json
.
An arbitrary complex java code will follow this exact pattern: wrap in the console app, pass the parameters, refer the location in the action meta data, supply CLASSPATH
using env
, optionally, spit out JSON to conveniently refer the output in the workflows.
Creating a Java action in StackStorm is not hard once you know how. But let’s admit it, it is not intuitive. The right way to do it is to create Java runner that takes care of all the mechanics for you. And contribute this runner to st2.
If someone in the community got the cycles to do it before we get our hands to this task, please let us know; we will guide, help, review and gladly accept. Check out this PRs where our HP friends contributed a CloudSlang runner, for hints and directions.
Explore the other tutorials. Check out “Actions” documentation, and help improve where we miss out.
Come see us in IRC – #stackstorm on freenode.org, or join the stackstorm-community on Slack for live discussion on this and other topics (register here).
Enjoy using StackStorm!