packages feed

sensu-run 0.1.0 → 0.1.1

raw patch · 4 files changed

+180/−82 lines, 4 files

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for sensu-run +## 0.1.1 -- 2017-06-09++* Add --version option+ ## 0.1.0 -- 2017-06-07  * Fix a bug that ignores --handle option by accident
+ README.md view
@@ -0,0 +1,78 @@+# sensu-run+[![Hackage](https://img.shields.io/hackage/v/sensu-run.svg)](http://hackage.haskell.org/package/sensu-run)+[![Hackage-Deps](https://img.shields.io/hackage-deps/v/sensu-run.svg)](http://packdeps.haskellers.com/feed?needle=sensu-run)+[![Stackage Nightly](http://stackage.org/package/sensu-run/badge/nightly)](http://stackage.org/nightly/package/sensu-run)+[![Build Status](https://travis-ci.org/maoe/sensu-run.svg?branch=master)](https://travis-ci.org/maoe/sensu-run)+[![Build status](https://ci.appveyor.com/api/projects/status/k9594kkn4tncotqt/branch/master?svg=true)](https://ci.appveyor.com/project/maoe/sensu-run/branch/master)++`sensu-run` runs a command and send its result to Sensu server using the [client socket input](https://sensuapp.org/docs/latest/reference/clients.html#client-socket-input) or via the Sensu API. It is useful to monitor cron jobs for example.++## Installation++Install [stack](https://docs.haskellstack.org/en/stable/README/).++```sh+stack install --resolver=nightly sensu-run+```+will install the `sensu-run` command in `~/.local/bin`.++## Usage++```console+% sensu-run --help+Usage: sensu-run ([-n|--name NAME] [--source SOURCE] [--ttl SECONDS]+                 [--timeout SECONDS] [--handler HANDLER] ([--port PORT] |+                 [--server URL]) [--dry|--dry-run] [-s|--shell] [COMMAND] |+                 [-v|--version])++Available options:+  -h,--help                Show this help text+  -n,--name NAME           The name of the check+  --source SOURCE          The check source, used to create a JIT Sensu client+                           for an external resource+  --ttl SECONDS            The time to live in seconds until check results are+                           considered stale+  --timeout SECONDS        The check executaion duration timeout in seconds+  --handler HANDLER        Sensu event handler(s) to use for events created by+                           the check+  --port PORT              Send results to the local sensu-client listening on+                           the specified port (default: 3030)+  --server URL             Send results to the specified Sensu server+  -s,--shell               Execute the command using the shell+```++`--dry-run` option is useful to check the JSON output:++```console+% sensu-run --name check-home-src-size --handler foo --dry-run -- du -s $HOME/src | jq .+{+  "name": "check-home-src-size",+  "command": "du -s /home/maoe/src",+  "issued": 1496966954,+  "executed": 1496966954,+  "duration": 1.235584,+  "status": 0,+  "output": "44567740\t/home/maoe/src\n",+  "handlers": [+    "foo"+  ]+}+```++Without the `--dry-run` option, `sensu-run` sends the output to localhost:PORT, which is expected to be listened by `sensu-client`.++`sensu-run` sets the status field depending on the command exit code and timeout:++| command exit code | `status` field |+|-------------------|----------------|+| 0                 | 0 (OK)         |+| non-zero          | 2 (CRITICAL)   |+| command timed out | 3 (UNKNOWN)    |++### Sensu API++`sensu-run` supports posting check results via Sensu API as well. Use `--server` option to specify Sensu server addresses. If multiple servers are specified, `sensu-run` tries them one by one until it succeeds.++```sh+sensu-run --name check-true --handler foo --server sensu1.example.com --server sensu2.example.com --dry-run -- du -s $HOME/src+```
sensu-run.cabal view
@@ -1,5 +1,5 @@ name: sensu-run-version: 0.1.0+version: 0.1.1 synopsis: A tool to send command execution results to Sensu description:   @sensu-run@ is a command line tool to send command execution results to Sensu@@ -13,7 +13,9 @@ bug-reports: https://github.com/maoe/sensu-run/issues category: System build-type: Simple-extra-source-files: CHANGELOG.md+extra-source-files:+  CHANGELOG.md+  README.md cabal-version: >= 1.10 tested-with: GHC == 8.0.2 
sensu-run.hs view
@@ -15,9 +15,11 @@ import Data.Foldable import Data.List.NonEmpty (NonEmpty) import Data.Maybe+import Data.Monoid import System.Exit import System.IO import qualified Data.List.NonEmpty as NE+import qualified Data.Version as V import qualified System.Timeout as Timeout  import Control.Lens hiding ((.=))@@ -40,40 +42,46 @@ import qualified Network.Wreq as W import qualified Options.Applicative as O +import qualified Paths_sensu_run as Paths+ main :: IO () main = do   issued <- getCurrentTime-  Options {..} <- O.execParser $ O.info (O.helper <*> options) O.fullDesc-  withSystemTempFile "sensu-run.XXX" $ \path hdl -> do-    executed <- getCurrentTime-    rawStatus <- bracket-      (startProcess cmdspec hdl)-      terminateProcess-      (withTimeout timeout . waitForProcess)-    exited <- getCurrentTime-    rawOutput <- BL.readFile path-    let-      encoded = encode CheckResult-        { command = cmdspec-        , output = TL.decodeUtf8With TE.lenientDecode rawOutput-        , status = case rawStatus of-          Nothing -> UNKNOWN-          Just ExitSuccess -> OK-          Just ExitFailure {} -> CRITICAL-        , duration = diffUTCTime exited executed-        , ..-        }-    if dryRun-      then BL8.putStrLn encoded-      else case endpoint of-        ClientSocketInput port -> sendToClientSocketInput port encoded-        SensuServer urls -> sendToSensuServer urls encoded-    case rawStatus of-      Just ExitSuccess -> exitSuccess-      Nothing -> do-        hPutStrLn stderr $ showCmdSpec cmdspec ++ " timed out"-        exitFailure-      Just ExitFailure {} -> exitFailure+  opts <- O.execParser $ O.info (O.helper <*> options) O.fullDesc+  case opts of+    ShowVersion -> do+      putStrLn $ "sensu-run " ++ V.showVersion Paths.version+      exitSuccess+    RunOptions {..} -> withSystemTempFile "sensu-run.XXX" $ \path hdl -> do+      executed <- getCurrentTime+      rawStatus <- bracket+        (startProcess cmdspec hdl)+        terminateProcess+        (withTimeout timeout . waitForProcess)+      exited <- getCurrentTime+      rawOutput <- BL.readFile path+      let+        encoded = encode CheckResult+          { command = cmdspec+          , output = TL.decodeUtf8With TE.lenientDecode rawOutput+          , status = case rawStatus of+            Nothing -> UNKNOWN+            Just ExitSuccess -> OK+            Just ExitFailure {} -> CRITICAL+          , duration = diffUTCTime exited executed+          , ..+          }+      if dryRun+        then BL8.putStrLn encoded+        else case endpoint of+          ClientSocketInput port -> sendToClientSocketInput port encoded+          SensuServer urls -> sendToSensuServer urls encoded+      case rawStatus of+        Just ExitSuccess -> exitSuccess+        Nothing -> do+          hPutStrLn stderr $ showCmdSpec cmdspec ++ " timed out"+          exitFailure+        Just ExitFailure {} -> exitFailure  sendToClientSocketInput   :: PortNumber -- ^ Listening port of Sensu client socket@@ -140,16 +148,18 @@   Just n -> Timeout.timeout (round $ n * 10^(6 :: Int))  io   Nothing -> Just <$> io -data Options = Options-  { name :: T.Text-  , cmdspec :: CmdSpec-  , source :: Maybe T.Text-  , ttl :: Maybe NominalDiffTime-  , timeout :: Maybe NominalDiffTime-  , handlers :: [T.Text]-  , endpoint :: Endpoint-  , dryRun :: Bool-  }+data Options+  = ShowVersion+  | RunOptions+    { name :: T.Text+    , cmdspec :: CmdSpec+    , source :: Maybe T.Text+    , ttl :: Maybe NominalDiffTime+    , timeout :: Maybe NominalDiffTime+    , handlers :: [T.Text]+    , endpoint :: Endpoint+    , dryRun :: Bool+    }  data Endpoint   = ClientSocketInput PortNumber@@ -162,46 +172,50 @@   -- client HTTP sockets listen on 3031.  options :: O.Parser Options-options = do-  name <- textOption $ mconcat-    [ O.short 'n'-    , O.long "name"-    , O.metavar "NAME"-    , O.help "The name of the check"-    ]-  source <- O.optional $ textOption $ mconcat-    [ O.long "source"-    , O.metavar "SOURCE"-    , O.help $ unlines-      [ "The check source, used to create a JIT Sensu client for an"-      , "external resource" ]-    ]-  ttl <- durationOption $ mconcat-    [ O.long "ttl"-    , O.metavar "SECONDS"-    , O.help "The time to live in seconds until check results are considered stale"-    ]-  timeout <- durationOption $ mconcat-    [ O.long "timeout"-    , O.metavar "SECONDS"-    , O.help "The check executaion duration timeout in seconds"-    ]-  handlers <- O.some $ textOption $ mconcat-    [ O.long "handler"-    , O.metavar "HANDLER"-    , O.help "Sensu event handler(s) to use for events created by the check"-    ]-  endpoint <- asum-    [ ClientSocketInput <$> portOption-    , SensuServer . NE.fromList <$> O.some serverOption-    ]-  dryRun <- O.switch $ mconcat-    [ O.long "dry-run"-    , O.long "dry"-    ]-  cmdspec <- cmdSpecOption-  return Options {..}+options = asum+  [ runOptions+  , ShowVersion <$ O.switch (O.long "version" <> O.short 'v')+  ]   where+    runOptions = do+      name <- textOption $ mconcat+        [ O.short 'n'+        , O.long "name"+        , O.metavar "NAME"+        , O.help "The name of the check"+        ]+      source <- O.optional $ textOption $ mconcat+        [ O.long "source"+        , O.metavar "SOURCE"+        , O.help $ unlines+          [ "The check source, used to create a JIT Sensu client for an"+          , "external resource" ]+        ]+      ttl <- durationOption $ mconcat+        [ O.long "ttl"+        , O.metavar "SECONDS"+        , O.help "The time to live in seconds until check results are considered stale"+        ]+      timeout <- durationOption $ mconcat+        [ O.long "timeout"+        , O.metavar "SECONDS"+        , O.help "The check executaion duration timeout in seconds"+        ]+      handlers <- O.some $ textOption $ mconcat+        [ O.long "handler"+        , O.metavar "HANDLER"+        , O.help "Sensu event handler(s) to use for events created by the check"+        ]+      endpoint <- asum+        [ ClientSocketInput <$> portOption+        , SensuServer . NE.fromList <$> O.some serverOption+        ]+      dryRun <- O.switch $ mconcat+        [ O.long "dry-run"+        , O.long "dry"+        ]+      cmdspec <- cmdSpecOption+      return RunOptions {..}     textOption m = T.pack <$> O.strOption m     durationOption m =       fmap (realToFrac @Double) <$> O.optional (O.option O.auto m)