packages feed

nagios-check (empty) → 0.1.0.0

raw patch · 6 files changed

+335/−0 lines, 6 filesdep +QuickCheckdep +basedep +bifunctorssetup-changed

Dependencies added: QuickCheck, base, bifunctors, exceptions, hspec, mtl, nagios-check, nagios-perfdata, text

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2014 Sharif Olorin++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,4 @@+nagios-check+============++Write Nagios (or Icinga, Shinken, et cetera) plugins in Haskell.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ lib/System/Nagios/Plugin.hs view
@@ -0,0 +1,223 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE RecordWildCards            #-}+{-# LANGUAGE TupleSections              #-}++module System.Nagios.Plugin+(+    CheckStatus(..),+    CheckResult,+    UOM(..),+    PerfValue(..),+    NagiosPlugin,+    runNagiosPlugin,+    runNagiosPlugin',+    addPerfDatum,+    addResult,+    checkStatus,+    checkInfo,+    worstResult,+    PerfDatum,+    finishState+) where++import           Control.Applicative+import           Control.Monad.Catch+import           Control.Monad.State.Lazy+import           Data.Bifunctor+import           Data.Int+import           Data.Monoid+import           Data.Nagios.Perfdata.Metric (UOM (..))+import           Data.Text                   (Text)+import qualified Data.Text                   as T+import qualified Data.Text.IO                as T+import           System.Exit++-- | Nagios plugin exit statuses. Ordered by priority -+--   OK < Warning < Critical < Unknown, which correspond to plugin exit+--   statuses of 0, 1, 2, and 3 respectively.+data CheckStatus = OK       -- ^ Check executed successfully and+                            --   detected no service problems.+                 | Warning  -- ^ Nothing's actually broken but this+                            --   should be followed up.+                 | Critical -- ^ Check executed successfully and detected+                            --   a service failure.+                 | Unknown  -- ^ Check unable to determine service+                            --   status.+  deriving (Enum, Eq, Ord)++instance Show CheckStatus where+    show OK = "OK"+    show Warning = "WARNING"+    show Critical = "CRITICAL"+    show Unknown = "UNKNOWN"++-- | A CheckResult is the exit status of the plugin combined with the+--   plugin's info text. A `NagiosPlugin` which exits with+--+--   > CheckResult (Critical "entropy decreasing in closed system")+--+--   as its peak-badness CheckResult (and no 'PerfDatum's) will a) exit with+--   status 2 and b) output the text "CRITICAL: entropy decreasing in closed+--   system".+newtype CheckResult = CheckResult+  { unCheckResult :: (CheckStatus, Text) }+    deriving (Eq, Ord, Show)++-- | Extract the return status from a 'CheckResult'+checkStatus :: CheckResult -> CheckStatus+checkStatus = fst . unCheckResult++-- | Extract the infotext from a 'CheckResult'.+checkInfo :: CheckResult -> Text+checkInfo = snd . unCheckResult++-- | Value of a performance metric.+data PerfValue = RealValue Double | IntegralValue Int64+  deriving Eq++instance Show PerfValue where+    show (RealValue x) = show x+    show (IntegralValue x) = show x++-- | One performance metric. A plugin will output zero or more of these,+--   whereupon Nagios generally passes them off to an external system such+--   as <http://oss.oetiker.ch/rrdtool/ RRDTool> or+--   <https://github.com/anchor/vaultaire Vaultaire>.+--   The thresholds are purely informative (designed to be graphed), and+--   do not affect alerting; likewise with `_min` and `_max`.+data PerfDatum = PerfDatum+    { _label :: Text             -- ^ Name of quantity being measured.+    , _value :: PerfValue        -- ^ Measured value, integral or real.+    , _uom   :: UOM              -- ^ Unit of measure; 'NullUOM' is fine here.+    , _min   :: Maybe PerfValue  -- ^ Measured quantity cannot be lower than this.+    , _max   :: Maybe PerfValue  -- ^ Measured quantity cannot be higher than this.+    , _warn  :: Maybe PerfValue  -- ^ Warning threshold for graphing.+    , _crit  :: Maybe PerfValue  -- ^ Critical threshold for graphing.+    }+  deriving (Eq, Show)++-- | Current check results/perfdata. If the check suddenly dies, the+--   'worst' of the CheckResults (and all the PerfDatums) will be used+--   to determine the exit state.+type CheckState = ([CheckResult], [PerfDatum])++newtype NagiosPlugin a = NagiosPlugin+  {+    unNagiosPlugin :: StateT CheckState IO a+  } deriving (Functor, Applicative, Monad, MonadIO, MonadState CheckState, MonadCatch, MonadThrow)++-- | Execute a Nagios check. The program will terminate at the check's+--   completion. A default status will provided if none is given.+runNagiosPlugin :: NagiosPlugin a -> IO ()+runNagiosPlugin check = do+    (_, st) <- runNagiosPlugin' $ catch check panic+    finishWith st+  where+    panic :: SomeException -> NagiosPlugin a+    panic = liftIO . finishWith . panicState++-- | Execute a Nagios check as with 'runNagiosPlugin', but return its+--   final state rather than terminating.+runNagiosPlugin' :: NagiosPlugin a -> IO (a, CheckState)+runNagiosPlugin' a = runStateT (unNagiosPlugin a) mempty++-- | Insert a result. Only the 'CheckStatus' with the most 'badness'+--   will determine the check's exit status.+addResult :: CheckStatus -> Text -> NagiosPlugin ()+addResult s t =+    modify (first (CheckResult (s, t) :))++-- | Insert a performance metric into the list the check will output.+addPerfDatum ::+       Text            -- ^ Name of the quantity being measured.+    -> PerfValue       -- ^ Measured value.+    -> UOM             -- ^ Unit of the measured value.+    -> Maybe PerfValue -- ^ Minimum threshold.+    -> Maybe PerfValue -- ^ Maximum threshold.+    -> Maybe PerfValue -- ^ Warning threshold.+    -> Maybe PerfValue -- ^ Critical threshold.+    -> NagiosPlugin ()+addPerfDatum info val uom min' max' warn crit =+    addPerfDatum' $ PerfDatum info val uom min' max' warn crit+  where+    addPerfDatum' pd = do+        (rs, pds) <- get+        put (rs, pd : pds)++-- | The result which will be used if no other results have been+--   provided.+defaultResult :: CheckResult+defaultResult = CheckResult (Unknown, T.pack "no check result specified")++-- | The state the plugin will exit with if an uncaught exception occurs.+--   within the plugin.+panicState :: SomeException -> CheckState+panicState = (,[]) . return . CheckResult . panicResult+  where+    panicResult e = (Critical,+                    T.pack ("unhandled exception: " ++ show e))++-- | Returns result with greatest badness, or a default UNKNOWN result+--   if no results have been specified.+worstResult :: [CheckResult] -> CheckResult+worstResult rs+    | null rs = defaultResult+    | otherwise = maximum rs++-- | Render a plugin's performance data according to the+--   <https://nagios-plugins.org/doc/guidelines.html Nagios plugin development guidelines>.+fmtPerfData :: [PerfDatum] -> Text+fmtPerfData = T.intercalate " " . map fmtPerfDatum+  where+    fmtPerfDatum PerfDatum{..} = T.concat+        [ _label+        , "="+        , T.pack (show _value)+        , T.pack (show _uom)+        , fmtThreshold _min+        , fmtThreshold _max+        , fmtThreshold _warn+        , fmtThreshold _crit+        ]++    fmtThreshold Nothing = ";"+    fmtThreshold (Just t) = T.pack $ ";" <> show t++-- | Render a plugin's result according to the+--   <https://nagios-plugins.org/doc/guidelines.html Nagios plugin development guidelines>.+--+--   FIXME: not actually true yet, need to implement verbose output.+fmtResults :: [CheckResult] -> Text+fmtResults = fmtResult . worstResult+  where+    fmtResult (CheckResult (s,t)) =+        T.pack (show s) <> ": " <> t++-- | Given a check's final state, return the status and output it would+--   exit with.+finishState :: CheckState -> (CheckStatus, Text)+finishState (rs, pds) =+    let worst  = worstResult rs+        output = fmtResults rs <> perfdataPart pds+    in (checkStatus worst, output)+  where+    perfdataPart [] = ""+    perfdataPart xs = " | " <> fmtPerfData xs++-- | Calculate our final result, print output and then exit with the+--   appropriate status.+finishWith :: MonadIO m => CheckState -> m a+finishWith = liftIO . exitWithStatus . finishState++-- | Output the final check result to stdout and then terminate the+--   check program with the appropriate exit status.+exitWithStatus :: (CheckStatus, Text) -> IO a+exitWithStatus (OK, t) = T.putStrLn t >> exitSuccess+exitWithStatus (r, t) = T.putStrLn t >> exitWith (ExitFailure $ fromEnum r)++-- | A 'Range' is a combination of a lower boundary and an upper boundary (x,y).+--   An 'AcceptableRange' asserts that measured values between x and y+--   imply that nothing is wrong; an UnacceptableRange implies the inverse.+data Range = AcceptableRange PerfValue PerfValue+           | UnacceptableRange PerfValue PerfValue
+ nagios-check.cabal view
@@ -0,0 +1,45 @@+name:                nagios-check+version:             0.1.0.0+synopsis:            Package for writing monitoring plugins+description:         Implements Nagios plugin development guidelines+                     within a Haskell framework for writing Nagios+                     checks.+homepage:            https://github.com/fractalcat/nagios-check+license:             MIT+license-file:        LICENSE+author:              Sharif Olorin+maintainer:          sio@tesser.org+copyright:           2014 Sharif Olorin+category:            System+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++source-repository    head+  type:              git +  location:          git@github.com:fractalcat/nagios-check.git++library+  exposed-modules:     System.Nagios.Plugin+  build-depends:       base >=4.7 && <5,+                       mtl,+                       text,+                       bifunctors,+                       exceptions,+                       nagios-perfdata+  hs-source-dirs:      lib+  default-language:    Haskell2010+  ghc-options:         -Wall+                       -Wwarn+                       -fwarn-tabs++test-suite nagios-check-test+  hs-source-dirs:    tests+  main-is:           NagiosCheckTest.hs+  type:              exitcode-stdio-1.0+  default-language:    Haskell2010+  build-depends:       base >=4.7 && <5,+                       hspec,+                       QuickCheck,+                       text,+                       nagios-check
+ tests/NagiosCheckTest.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import           Data.Monoid+import           Data.Text            (Text)+import           Test.Hspec++import           System.Nagios.Plugin++main :: IO ()+main = hspec suite++suite :: Spec+suite = describe "runNagiosPlugin'" $ do+    it "returns default result if no results are specified" $ do+        (_,s) <- runNagiosPlugin' (return ())+        snd (finishState s) `shouldBe` "UNKNOWN: no check result specified"+        fst (finishState s) `shouldBe` Unknown++    it "returns explicitly added result in favor of default" $ do+        (_,s) <- runNagiosPlugin' (universeCheck pi)+        snd (finishState s) `shouldBe` ("OK: " <> universeGoodResult)+        fst (finishState s) `shouldBe` OK++    it "returns result with greatest badness" $ do+        (_,s) <- runNagiosPlugin' (universeCheck 1.0)+        snd (finishState s) `shouldBe` ("CRITICAL: " <> universeBadResult)+        fst (finishState s) `shouldBe` Critical+++universeCheck :: Double -> NagiosPlugin ()+universeCheck pi' = do+    addResult OK universeGoodResult+    if (pi' < (3.0 :: Double)) then addResult Critical universeBadResult else return ()++universeGoodResult :: Text+universeGoodResult = "universe passes basic consistency tests"++universeBadResult :: Text+universeBadResult = "universe broken, π < 3"