-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from tinythings/isbm-handler-bridge
Add handler bridge
- Loading branch information
Showing
5 changed files
with
192 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Event Handlers | |
|
||
console_logger | ||
outcome_logger | ||
pipescript | ||
|
||
Overview | ||
-------- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
Pipe Script | ||
=========== | ||
|
||
.. note:: | ||
|
||
This document explains how to use **pipescript** event handler. | ||
|
||
Synopsis | ||
-------- | ||
|
||
.. code-block:: text | ||
:caption: Initialisation | ||
handler: | ||
- pipescript | ||
*Pipescript* handler is used to pipe action's response through any script, using STDIN. | ||
User can define what to do with this information further. | ||
|
||
.. important:: | ||
|
||
This handler will react only if action contains return code ``0``, i.e. handler has | ||
a proper response data structure. Otherwise handler will skip the process and | ||
will log an error. | ||
|
||
Options | ||
------- | ||
|
||
``program`` | ||
^^^^^^^^^^ | ||
|
||
A full command line what needs to be called in event of writing STDIN to the program. Example: | ||
|
||
.. code-block:: yaml | ||
:caption: Program definition | ||
program: "/path/to/my/script.pl --some=argument --quiet" | ||
``quiet`` | ||
^^^^^^^^^^^ | ||
|
||
**Optional.** Mute logging. Example: | ||
|
||
.. code-block:: yaml | ||
:caption: Mute logging | ||
quiet: true | ||
``format`` | ||
^^^^^^^^^^ | ||
|
||
In what format output needs to be sent to the target program. Options: | ||
|
||
- ``yaml`` | ||
- ``json`` | ||
|
||
Example: | ||
|
||
.. code-block:: yaml | ||
:caption: Format definition | ||
format: json # or "yaml" | ||
Example | ||
------- | ||
|
||
.. code-block:: yaml | ||
:caption: Setup example | ||
events: | ||
# React only on action-wise successful events | ||
$/$/$/0: | ||
handlers: | ||
pipescript | ||
pipescript: | ||
program: /opt/bin/extra-logger.pl | ||
quiet: false | ||
format: json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
Pipescript is a handler that pipes the action output through a script | ||
on certain event outcomes. | ||
*/ | ||
|
||
use super::evthandler::EventHandler; | ||
use crate::intp::{ | ||
actproc::response::ActionResponse, | ||
conf::{EventConfig, EventConfigOption}, | ||
}; | ||
use colored::Colorize; | ||
use core::str; | ||
use serde_json::Value; | ||
use std::{ | ||
io::Write, | ||
process::{Command, Stdio}, | ||
}; | ||
|
||
#[derive(Default, Debug)] | ||
pub struct PipeScriptHandler { | ||
cfg: EventConfig, | ||
} | ||
|
||
impl PipeScriptHandler { | ||
/// Format the output | ||
fn fmt(&self, value: Option<Value>, format: &str) -> String { | ||
let value = match value { | ||
Some(v) => v, | ||
None => return "".to_string(), | ||
}; | ||
|
||
match format.to_lowercase().as_str() { | ||
"yaml" => serde_yaml::to_string(&value).unwrap_or_default(), | ||
_ => serde_json::to_string(&value).unwrap_or_default(), | ||
} | ||
} | ||
|
||
/// Call user-defined script | ||
fn call_script(&self, evt: &ActionResponse) { | ||
// Successfull responses only | ||
if evt.response.retcode() > 0 { | ||
return; | ||
} | ||
|
||
// Config is required | ||
let cfg = match self.config() { | ||
Some(cfg) => cfg, | ||
None => return, | ||
}; | ||
|
||
// Program is required | ||
let cmd = match cfg.as_string("program") { | ||
Some(cmd) => cmd.split_whitespace().map(|s| s.to_string()).collect::<Vec<String>>(), | ||
None => return, | ||
}; | ||
|
||
// Verbosity | ||
let quiet = cfg.as_bool("quiet").unwrap_or(false); | ||
|
||
// Communication format | ||
let format = cfg.as_string("format").unwrap_or("json".to_string()); | ||
|
||
match Command::new(&cmd[0]).args(&cmd[1..]).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() { | ||
Ok(mut p) => { | ||
if let Some(mut stdin) = p.stdin.take() { | ||
if let Err(err) = stdin.write_all(self.fmt(evt.response.data(), &format).as_bytes()) { | ||
log::error!("Unable to pipe data to '{}': {}", cmd.join(" "), err); | ||
} else if !quiet { | ||
log::info!("{} - {}", "Pipescript".cyan(), cmd.join(" ")); | ||
} | ||
} | ||
} | ||
Err(err) => log::error!("{} error: {} for '{}'", PipeScriptHandler::id(), err, cmd.join(" ")), | ||
}; | ||
} | ||
} | ||
|
||
/// Pipescript handler | ||
impl EventHandler for PipeScriptHandler { | ||
fn new(_eid: String, cfg: crate::intp::conf::EventConfig) -> Self | ||
where | ||
Self: Sized, | ||
{ | ||
PipeScriptHandler { cfg } | ||
} | ||
|
||
fn id() -> String | ||
where | ||
Self: Sized, | ||
{ | ||
"pipescript".to_string() | ||
} | ||
|
||
fn handle(&self, evt: &ActionResponse) { | ||
self.call_script(evt); | ||
} | ||
|
||
fn config(&self) -> Option<EventConfigOption> { | ||
self.cfg.cfg(&PipeScriptHandler::id()) | ||
} | ||
} |