sensu-run 0.5.0.3 → 0.6.0
raw patch · 3 files changed
+84/−54 lines, 3 filesdep +directorydep +filelock
Dependencies added: directory, filelock
Files
- CHANGELOG.md +5/−0
- sensu-run.cabal +3/−1
- sensu-run.hs +76/−53
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for sensu-run +## 0.6.0 -- 2018-07-09++* Lock a file to prevent multiple instances of the same name from running+ * Use --no-lock option to disable this behavior+ ## 0.5.0.3 -- 2018-07-07 * Relax upper version bound for lens
sensu-run.cabal view
@@ -1,5 +1,5 @@ name: sensu-run-version: 0.5.0.3+version: 0.6.0 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@@ -29,6 +29,8 @@ , async < 2.3 , base >= 4.9 && < 4.12 , bytestring >= 0.10 && < 0.11+ , directory < 1.4+ , filelock < 0.2 , filepath >= 1.4.1 && < 1.5 , http-client >= 0.5.6 && < 0.6 , http-client-tls < 0.4
sensu-run.hs view
@@ -27,16 +27,18 @@ import Prelude import Control.Concurrent.Async-import Control.Lens hiding ((.=))+import Control.Lens hiding ((.=), (<.>)) import Data.Time import Data.Time.Clock.POSIX import Network.HTTP.Client (HttpException) import Network.HTTP.Client.TLS import Network.Socket-import System.FilePath ((</>))+import System.Directory (removeFile)+import System.FileLock+import System.FilePath ((</>), (<.>)) import System.IO.Temp-import System.Process import System.PosixCompat.User (getEffectiveUserName)+import System.Process import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy.Char8 as BL8@@ -67,57 +69,73 @@ ShowVersion -> do putStrLn $ "sensu-run " ++ V.showVersion Paths.version exitSuccess- RunOptions {..} -> withSystemTempFile "sensu-run.XXX" $ \path hdl -> do- executed <- getCurrentTime- rawStatus <- try $ bracket- (startProcess cmdspec)- (\(_, _, ph) -> do- terminateProcess ph- killProcessTree ph- waitForProcess ph)- $ \(out, err, ph) -> do- aout <- async $ redirectOutput out $ if redirect- then [hdl, stdout] else [hdl]- aerr <- async $ redirectOutput err $ if redirect- then [hdl, stderr] else [hdl]- mapM_ waitCatch [aout, aerr]- withTimeout timeout $ waitForProcess ph- hClose hdl- exited <- getCurrentTime- rawOutput <- BL.readFile path- user <- T.pack <$> getEffectiveUserName- let- encoded = encode CheckResult- { command = cmdspec- , output = TL.toLazyText $ mconcat- [ TL.fromLazyText (TL.decodeUtf8With TE.lenientDecode rawOutput)- , case rawStatus of- Left (ioe :: IOException) -> "\n" <> TL.fromString (show ioe)- Right Nothing -> "\n" <> "sensu-run: timed out"- Right _ -> mempty- ]- , status = case rawStatus of- Right (Just ExitSuccess) -> OK- Right (Just ExitFailure {}) -> CRITICAL- _ -> UNKNOWN- , 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- Left ioe -> do- hPutStrLn stderr $ show ioe- exitFailure- Right (Just ExitSuccess) -> exitSuccess- Right Nothing -> do- hPutStrLn stderr $ showCmdSpec cmdspec ++ " timed out"- exitFailure- Right (Just ExitFailure {}) -> exitFailure+ RunOptions {..} -> exclusivelyIf lock name $+ withSystemTempFile "sensu-run.XXX" $ \path hdl -> do+ executed <- getCurrentTime+ rawStatus <- try $ bracket+ (startProcess cmdspec)+ (\(_, _, ph) -> do+ terminateProcess ph+ killProcessTree ph+ waitForProcess ph)+ $ \(out, err, ph) -> do+ aout <- async $ redirectOutput out $ if redirect+ then [hdl, stdout] else [hdl]+ aerr <- async $ redirectOutput err $ if redirect+ then [hdl, stderr] else [hdl]+ mapM_ waitCatch [aout, aerr]+ withTimeout timeout $ waitForProcess ph+ hClose hdl+ exited <- getCurrentTime+ rawOutput <- BL.readFile path+ user <- T.pack <$> getEffectiveUserName+ let+ encoded = encode CheckResult+ { command = cmdspec+ , output = TL.toLazyText $ mconcat+ [ TL.fromLazyText (TL.decodeUtf8With TE.lenientDecode rawOutput)+ , case rawStatus of+ Left (ioe :: IOException) -> "\n" <> TL.fromString (show ioe)+ Right Nothing -> "\n" <> "sensu-run: timed out"+ Right _ -> mempty+ ]+ , status = case rawStatus of+ Right (Just ExitSuccess) -> OK+ Right (Just ExitFailure {}) -> CRITICAL+ _ -> UNKNOWN+ , 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+ Left ioe -> do+ hPutStrLn stderr $ show ioe+ exitFailure+ Right (Just ExitSuccess) -> exitSuccess+ Right Nothing -> do+ hPutStrLn stderr $ showCmdSpec cmdspec ++ " timed out"+ exitFailure+ Right (Just ExitFailure {}) -> exitFailure +exclusivelyIf :: Bool -> T.Text -> IO a -> IO a+exclusivelyIf exclusive name io+ | exclusive = do+ tmpDir <- getCanonicalTemporaryDirectory+ let path = tmpDir </> "sensu-run" <.> T.unpack name <.> "lock"+ r <- withTryFileLock path Exclusive (const io)+ case r of+ Nothing -> do+ putStrLn $ path ++ " is aquired by other process"+ exitSuccess+ Just a -> do+ removeFile path+ return a+ | otherwise = io+ sendToClientSocketInput :: PortNumber -- ^ Listening port of Sensu client socket -> BL8.ByteString -- ^ Payload@@ -215,6 +233,7 @@ , handlers :: [T.Text] , endpoint :: Endpoint , redirect :: Bool+ , lock :: Bool , dryRun :: Bool } @@ -270,6 +289,10 @@ redirect <- O.switch $ mconcat [ O.long "redirect" , O.help "Redirect command output to sensu-run's output"+ ]+ (not -> lock) <- O.switch $ mconcat+ [ O.long "no-lock"+ , O.help "Do not create a lock file to allow multiple instances to run" ] dryRun <- O.switch $ mconcat [ O.long "dry-run"