1 {-| DRBD data collector.
7 Copyright (C) 2012, 2013 Google Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 module Ganeti.DataCollectors.Drbd
34 import qualified Control.Exception as E
36 import Data.Attoparsec.Text.Lazy as A
38 import Data.Text.Lazy (pack, unpack)
39 import Network.BSD (getHostName)
40 import qualified Text.JSON as J
42 import qualified Ganeti.BasicTypes as BT
43 import qualified Ganeti.Constants as C
44 import Ganeti.Block.Drbd.Parser(drbdStatusParser)
45 import Ganeti.Block.Drbd.Types(DrbdInstMinor)
47 import Ganeti.Confd.Client
48 import Ganeti.Confd.Types
49 import Ganeti.DataCollectors.CLI
50 import Ganeti.DataCollectors.Types
54 -- | The default path of the DRBD status file.
55 -- It is hardcoded because it is not likely to change.
56 defaultFile :: FilePath
57 defaultFile = C.drbdStatusFile
59 -- | The default setting for the maximum amount of not parsed character to
60 -- print in case of error.
61 -- It is set to use most of the screen estate on a standard 80x25 terminal.
62 -- TODO: add the possibility to set this with a command line parameter.
64 defaultCharNum = 80*20
66 -- | The name of this data collector.
70 -- | The version number for the data format of this data collector.
71 dcFormatVersion :: Int
74 -- * Command line options
76 options :: IO [OptType]
83 -- | The list of arguments supported by the program.
84 arguments :: [ArgCompletion]
85 arguments = [ArgCompletion OptComplFile 0 (Just 0)]
87 -- | Get information about the pairing of DRBD minors and Ganeti instances
88 -- on the current node. The information is taken from the Confd client
89 -- or, if a filename is specified, from a JSON encoded file (for testing
91 getPairingInfo :: Maybe String -> IO (BT.Result [DrbdInstMinor])
92 getPairingInfo Nothing = do
93 curNode <- getHostName
94 client <- getConfdClient Nothing Nothing
95 reply <- query client ReqNodeDrbd $ PlainQuery curNode
97 case fmap (J.readJSONs . confdReplyAnswer) reply of
98 Just (J.Ok instMinor) -> BT.Ok instMinor
99 Just (J.Error msg) -> BT.Bad msg
100 Nothing -> BT.Bad "No answer from the Confd server"
101 getPairingInfo (Just filename) = do
102 content <- readFile filename
104 case J.decode content of
105 J.Ok instMinor -> BT.Ok instMinor
106 J.Error msg -> BT.Bad msg
108 -- | This function builds a report with the DRBD status.
109 buildDRBDReport :: FilePath -> Maybe FilePath -> IO DCReport
110 buildDRBDReport statusFile pairingFile = do
112 ((E.try $ readFile statusFile) :: IO (Either IOError String)) >>=
113 exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok
114 pairingResult <- getPairingInfo pairingFile
115 pairing <- exitIfBad "Can't get pairing info" pairingResult
117 case A.parse (drbdStatusParser pairing) $ pack contents of
118 A.Fail unparsedText contexts errorMessage -> exitErr $
119 show (Prelude.take defaultCharNum $ unpack unparsedText) ++ "\n"
120 ++ show contexts ++ "\n" ++ errorMessage
121 A.Done _ drbdStatus -> return $ J.showJSON drbdStatus
122 buildReport dcName Nothing dcFormatVersion jsonData
125 main :: Options -> [String] -> IO ()
127 let statusFile = fromMaybe defaultFile $ optDrbdStatus opts
128 pairingFile = optDrbdPairing opts
129 unless (null args) . exitErr $ "This program takes exactly zero" ++
130 " arguments, got '" ++ unwords args ++ "'"
131 report <- buildDRBDReport statusFile pairingFile
132 putStrLn $ J.encode report