Turning Java App Into StackStorm Action

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”:

java-st2

  1. Wrap the Java code in a Java console application;
  2. Take the input as command line arguments
  3. For the best results, output formatted JSON to stdout/stderr – this way StackStorm will auto-parse it so that you reference them with 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.

1. Sample Java app

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:

  1. I use 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.
  2. p1 and p2 are the parameters I define for the action, they are mapped to the input of MyApp in cmd parameter.
  3. cwd, “current working directory”, is where the command will be executed.
  4. 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

3. Run action

[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.

Dev note

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.

What’s next

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!