Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / DataCollectors / Drbd.hs @ 8c5419ee

History | View | Annotate | Download (4.7 kB)

1
{-| DRBD data collector.
2

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 2012, 2013 Google Inc.
8

    
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.
13

    
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.
18

    
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
22
02110-1301, USA.
23

    
24
-}
25

    
26
module Ganeti.DataCollectors.Drbd
27
  ( main
28
  , options
29
  , arguments
30
  , dcName
31
  , dcVersion
32
  , dcFormatVersion
33
  , dcCategory
34
  , dcKind
35
  , dcData
36
  ) where
37

    
38

    
39
import qualified Control.Exception as E
40
import Control.Monad
41
import Data.Attoparsec.Text.Lazy as A
42
import Data.Maybe
43
import Data.Text.Lazy (pack, unpack)
44
import Network.BSD (getHostName)
45
import qualified Text.JSON as J
46

    
47
import qualified Ganeti.BasicTypes as BT
48
import qualified Ganeti.Constants as C
49
import Ganeti.Block.Drbd.Parser(drbdStatusParser)
50
import Ganeti.Block.Drbd.Types(DrbdInstMinor)
51
import Ganeti.Common
52
import Ganeti.Confd.Client
53
import Ganeti.Confd.Types
54
import Ganeti.DataCollectors.CLI
55
import Ganeti.DataCollectors.Types
56
import Ganeti.Utils
57

    
58

    
59
-- | The default path of the DRBD status file.
60
-- It is hardcoded because it is not likely to change.
61
defaultFile :: FilePath
62
defaultFile = C.drbdStatusFile
63

    
64
-- | The default setting for the maximum amount of not parsed character to
65
-- print in case of error.
66
-- It is set to use most of the screen estate on a standard 80x25 terminal.
67
-- TODO: add the possibility to set this with a command line parameter.
68
defaultCharNum :: Int
69
defaultCharNum = 80*20
70

    
71
-- | The name of this data collector.
72
dcName :: String
73
dcName = "drbd"
74

    
75
-- | The version of this data collector.
76
dcVersion :: DCVersion
77
dcVersion = DCVerBuiltin
78

    
79
-- | The version number for the data format of this data collector.
80
dcFormatVersion :: Int
81
dcFormatVersion = 1
82

    
83
-- | The category of this data collector.
84
dcCategory :: Maybe DCCategory
85
dcCategory = Just DCStorage
86

    
87
-- | The kind of this data collector.
88
dcKind :: DCKind
89
dcKind = DCKStatus
90

    
91
-- | The data exported by the data collector, taken from the default location.
92
dcData :: IO J.JSValue
93
dcData = buildJsonReport defaultFile Nothing
94

    
95
-- * Command line options
96

    
97
options :: IO [OptType]
98
options =
99
  return
100
    [ oDrbdStatus
101
    , oDrbdPairing
102
    ]
103

    
104
-- | The list of arguments supported by the program.
105
arguments :: [ArgCompletion]
106
arguments = [ArgCompletion OptComplFile 0 (Just 0)]
107

    
108
-- | Get information about the pairing of DRBD minors and Ganeti instances
109
-- on the current node. The information is taken from the Confd client
110
-- or, if a filename is specified, from a JSON encoded file (for testing
111
-- purposes).
112
getPairingInfo :: Maybe String -> IO (BT.Result [DrbdInstMinor])
113
getPairingInfo Nothing = do
114
  curNode <- getHostName
115
  client <- getConfdClient Nothing Nothing
116
  reply <- query client ReqNodeDrbd $ PlainQuery curNode
117
  return $
118
    case fmap (J.readJSONs . confdReplyAnswer) reply of
119
      Just (J.Ok instMinor) -> BT.Ok instMinor
120
      Just (J.Error msg) -> BT.Bad msg
121
      Nothing -> BT.Bad "No answer from the Confd server"
122
getPairingInfo (Just filename) = do
123
  content <- readFile filename
124
  return $
125
    case J.decode content of
126
      J.Ok instMinor -> BT.Ok instMinor
127
      J.Error msg -> BT.Bad msg
128

    
129
-- | This function computes the JSON representation of the DRBD status.
130
buildJsonReport :: FilePath -> Maybe FilePath -> IO J.JSValue
131
buildJsonReport statusFile pairingFile = do
132
  contents <-
133
    ((E.try $ readFile statusFile) :: IO (Either IOError String)) >>=
134
      exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok
135
  pairingResult <- getPairingInfo pairingFile
136
  pairing <- exitIfBad "Can't get pairing info" pairingResult
137
  case A.parse (drbdStatusParser pairing) $ pack contents of
138
    A.Fail unparsedText contexts errorMessage -> exitErr $
139
      show (Prelude.take defaultCharNum $ unpack unparsedText) ++ "\n"
140
        ++ show contexts ++ "\n" ++ errorMessage
141
    A.Done _ drbdStatus -> return $ J.showJSON drbdStatus
142

    
143
-- | Main function.
144
main :: Options -> [String] -> IO ()
145
main opts args = do
146
  let statusFile = fromMaybe defaultFile $ optDrbdStatus opts
147
      pairingFile = optDrbdPairing opts
148
  unless (null args) . exitErr $ "This program takes exactly zero" ++
149
                                  " arguments, got '" ++ unwords args ++ "'"
150
  report <- buildJsonReport statusFile pairingFile >>=
151
    buildReport dcName dcVersion dcFormatVersion dcCategory dcKind
152
  putStrLn $ J.encode report