Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Block / Drbd / Parser.hs @ 3add7574

History | View | Annotate | Download (12.6 kB)

1 3c1915df Michele Tartara
{-# LANGUAGE OverloadedStrings #-}
2 3c1915df Michele Tartara
{-| DRBD proc file parser
3 3c1915df Michele Tartara
4 3c1915df Michele Tartara
This module holds the definition of the parser that extracts status
5 3c1915df Michele Tartara
information from the DRBD proc file.
6 3c1915df Michele Tartara
7 3c1915df Michele Tartara
-}
8 3c1915df Michele Tartara
{-
9 3c1915df Michele Tartara
10 3c1915df Michele Tartara
Copyright (C) 2012 Google Inc.
11 3c1915df Michele Tartara
12 3c1915df Michele Tartara
This program is free software; you can redistribute it and/or modify
13 3c1915df Michele Tartara
it under the terms of the GNU General Public License as published by
14 3c1915df Michele Tartara
the Free Software Foundation; either version 2 of the License, or
15 3c1915df Michele Tartara
(at your option) any later version.
16 3c1915df Michele Tartara
17 3c1915df Michele Tartara
This program is distributed in the hope that it will be useful, but
18 3c1915df Michele Tartara
WITHOUT ANY WARRANTY; without even the implied warranty of
19 3c1915df Michele Tartara
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 3c1915df Michele Tartara
General Public License for more details.
21 3c1915df Michele Tartara
22 3c1915df Michele Tartara
You should have received a copy of the GNU General Public License
23 3c1915df Michele Tartara
along with this program; if not, write to the Free Software
24 3c1915df Michele Tartara
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 3c1915df Michele Tartara
02110-1301, USA.
26 3c1915df Michele Tartara
27 3c1915df Michele Tartara
-}
28 3c1915df Michele Tartara
module Ganeti.Block.Drbd.Parser (drbdStatusParser, commaIntParser) where
29 3c1915df Michele Tartara
30 3c1915df Michele Tartara
import Control.Applicative ((<*>), (*>), (<*), (<$>), (<|>), pure)
31 3c1915df Michele Tartara
import qualified Data.Attoparsec.Text as A
32 3c1915df Michele Tartara
import qualified Data.Attoparsec.Combinator as AC
33 3c1915df Michele Tartara
import Data.Attoparsec.Text (Parser)
34 cefd4a4a Michele Tartara
import Data.Maybe
35 3c1915df Michele Tartara
import Data.Text (Text, unpack)
36 3c1915df Michele Tartara
37 3c1915df Michele Tartara
import Ganeti.Block.Drbd.Types
38 3c1915df Michele Tartara
39 3c1915df Michele Tartara
-- | Our own space-skipping function, because A.skipSpace also skips
40 3c1915df Michele Tartara
-- newline characters. It skips ZERO or more spaces, so it does not
41 3c1915df Michele Tartara
-- fail if there are no spaces.
42 3c1915df Michele Tartara
skipSpaces :: Parser ()
43 3c1915df Michele Tartara
skipSpaces = A.skipWhile A.isHorizontalSpace
44 3c1915df Michele Tartara
45 3c1915df Michele Tartara
-- | Skips spaces and the given string, then executes a parser and
46 3c1915df Michele Tartara
-- returns its result.
47 3c1915df Michele Tartara
skipSpacesAndString :: Text -> Parser a -> Parser a
48 3c1915df Michele Tartara
skipSpacesAndString s parser =
49 3c1915df Michele Tartara
  skipSpaces
50 3c1915df Michele Tartara
  *> A.string s
51 3c1915df Michele Tartara
  *> parser
52 3c1915df Michele Tartara
53 3c1915df Michele Tartara
-- | Predicate verifying (potentially bad) end of lines
54 3c1915df Michele Tartara
isBadEndOfLine :: Char -> Bool
55 3c1915df Michele Tartara
isBadEndOfLine c = (c == '\0') || A.isEndOfLine c
56 3c1915df Michele Tartara
57 3c1915df Michele Tartara
-- | Takes a parser and returns it with the content wrapped in a Maybe
58 3c1915df Michele Tartara
-- object. The resulting parser never fails, but contains Nothing if
59 3c1915df Michele Tartara
-- it couldn't properly parse the string.
60 3c1915df Michele Tartara
optional :: Parser a -> Parser (Maybe a)
61 3c1915df Michele Tartara
optional parser = (Just <$> parser) <|> pure Nothing
62 3c1915df Michele Tartara
63 3c1915df Michele Tartara
-- | The parser for a whole DRBD status file.
64 3c1915df Michele Tartara
drbdStatusParser :: Parser DRBDStatus
65 3c1915df Michele Tartara
drbdStatusParser =
66 3c1915df Michele Tartara
  DRBDStatus <$> versionInfoParser
67 3c1915df Michele Tartara
             <*> deviceParser `AC.manyTill` A.endOfInput
68 fd80be11 Michele Tartara
             <* A.endOfInput
69 3c1915df Michele Tartara
70 3c1915df Michele Tartara
-- | The parser for the version information lines.
71 3c1915df Michele Tartara
versionInfoParser :: Parser VersionInfo
72 cefd4a4a Michele Tartara
versionInfoParser = do
73 cefd4a4a Michele Tartara
  versionF <- optional versionP
74 cefd4a4a Michele Tartara
  apiF <- optional apiP
75 cefd4a4a Michele Tartara
  protoF <- optional protoP
76 cefd4a4a Michele Tartara
  srcVersionF <- optional srcVersion
77 cefd4a4a Michele Tartara
  ghF <- fmap unpack <$> optional gh
78 cefd4a4a Michele Tartara
  builderF <- fmap unpack <$> optional builder
79 cefd4a4a Michele Tartara
  if   isNothing versionF
80 cefd4a4a Michele Tartara
    && isNothing apiF
81 cefd4a4a Michele Tartara
    && isNothing protoF
82 cefd4a4a Michele Tartara
    && isNothing srcVersionF
83 cefd4a4a Michele Tartara
    && isNothing ghF
84 cefd4a4a Michele Tartara
    && isNothing builderF
85 cefd4a4a Michele Tartara
    then fail "versionInfo"
86 cefd4a4a Michele Tartara
    else pure $ VersionInfo versionF apiF protoF srcVersionF ghF builderF
87 cefd4a4a Michele Tartara
88 3c1915df Michele Tartara
    where versionP =
89 3c1915df Michele Tartara
            A.string "version:"
90 3c1915df Michele Tartara
            *> skipSpaces
91 3c1915df Michele Tartara
            *> fmap unpack (A.takeWhile $ not . A.isHorizontalSpace)
92 3c1915df Michele Tartara
          apiP =
93 3c1915df Michele Tartara
            skipSpacesAndString "(api:" . fmap unpack $ A.takeWhile (/= '/')
94 3c1915df Michele Tartara
          protoP =
95 3c1915df Michele Tartara
            A.string "/proto:"
96 3c1915df Michele Tartara
            *> fmap Data.Text.unpack (A.takeWhile (/= ')'))
97 3c1915df Michele Tartara
            <* A.takeTill A.isEndOfLine <* A.endOfLine
98 3c1915df Michele Tartara
          srcVersion =
99 3c1915df Michele Tartara
            A.string "srcversion:"
100 3c1915df Michele Tartara
            *> AC.skipMany1 A.space
101 3c1915df Michele Tartara
            *> fmap unpack (A.takeTill A.isEndOfLine)
102 3c1915df Michele Tartara
            <* A.endOfLine
103 3c1915df Michele Tartara
          gh =
104 3c1915df Michele Tartara
            A.string "GIT-hash:"
105 3c1915df Michele Tartara
            *> skipSpaces
106 3c1915df Michele Tartara
            *> A.takeWhile (not . A.isHorizontalSpace)
107 3c1915df Michele Tartara
          builder =
108 3c1915df Michele Tartara
            skipSpacesAndString "build by" $
109 3c1915df Michele Tartara
              skipSpaces
110 3c1915df Michele Tartara
              *> A.takeTill A.isEndOfLine
111 3c1915df Michele Tartara
              <* A.endOfLine
112 3c1915df Michele Tartara
113 3c1915df Michele Tartara
-- | The parser for a (multi-line) string representing a device.
114 3c1915df Michele Tartara
deviceParser :: Parser DeviceInfo
115 3c1915df Michele Tartara
deviceParser = do
116 3c1915df Michele Tartara
  deviceNum <- skipSpaces *> A.decimal <* A.char ':'
117 2188740e Michele Tartara
  cs <- skipSpacesAndString "cs:" connStateParser
118 3c1915df Michele Tartara
  if cs == Unconfigured
119 3c1915df Michele Tartara
    then do
120 3c1915df Michele Tartara
      _ <- additionalEOL
121 3c1915df Michele Tartara
      return $ UnconfiguredDevice deviceNum
122 3c1915df Michele Tartara
    else do
123 3c1915df Michele Tartara
      ro <- skipSpaces *> skipRoleString *> localRemoteParser roleParser
124 3c1915df Michele Tartara
      ds <- skipSpacesAndString "ds:" $ localRemoteParser diskStateParser
125 3c1915df Michele Tartara
      replicProtocol <- A.space *> A.anyChar
126 3c1915df Michele Tartara
      io <- skipSpaces *> ioFlagsParser <* A.skipWhile isBadEndOfLine
127 2188740e Michele Tartara
      pIndicators <- perfIndicatorsParser
128 3c1915df Michele Tartara
      syncS <- conditionalSyncStatusParser cs
129 3c1915df Michele Tartara
      reS <- optional resyncParser
130 3c1915df Michele Tartara
      act <- optional actLogParser
131 3c1915df Michele Tartara
      _ <- additionalEOL
132 2188740e Michele Tartara
      return $ DeviceInfo deviceNum cs ro ds replicProtocol io pIndicators
133 3c1915df Michele Tartara
                          syncS reS act
134 3c1915df Michele Tartara
135 3c1915df Michele Tartara
    where conditionalSyncStatusParser SyncSource = Just <$> syncStatusParser
136 3c1915df Michele Tartara
          conditionalSyncStatusParser SyncTarget = Just <$> syncStatusParser
137 3c1915df Michele Tartara
          conditionalSyncStatusParser _ = pure Nothing
138 3c1915df Michele Tartara
          skipRoleString = A.string "ro:" <|> A.string "st:"
139 3c1915df Michele Tartara
          resyncParser = skipSpacesAndString "resync:" additionalInfoParser
140 3c1915df Michele Tartara
          actLogParser = skipSpacesAndString "act_log:" additionalInfoParser
141 3c1915df Michele Tartara
          additionalEOL = A.skipWhile A.isEndOfLine
142 3c1915df Michele Tartara
143 3c1915df Michele Tartara
-- | The parser for the connection state.
144 2188740e Michele Tartara
connStateParser :: Parser ConnState
145 2188740e Michele Tartara
connStateParser =
146 3c1915df Michele Tartara
  standAlone
147 3c1915df Michele Tartara
  <|> disconnecting
148 3c1915df Michele Tartara
  <|> unconnected
149 3c1915df Michele Tartara
  <|> timeout
150 3c1915df Michele Tartara
  <|> brokenPipe
151 3c1915df Michele Tartara
  <|> networkFailure
152 3c1915df Michele Tartara
  <|> protocolError
153 3c1915df Michele Tartara
  <|> tearDown
154 3c1915df Michele Tartara
  <|> wfConnection
155 3c1915df Michele Tartara
  <|> wfReportParams
156 3c1915df Michele Tartara
  <|> connected
157 3c1915df Michele Tartara
  <|> startingSyncS
158 3c1915df Michele Tartara
  <|> startingSyncT
159 3c1915df Michele Tartara
  <|> wfBitMapS
160 3c1915df Michele Tartara
  <|> wfBitMapT
161 3c1915df Michele Tartara
  <|> wfSyncUUID
162 3c1915df Michele Tartara
  <|> syncSource
163 3c1915df Michele Tartara
  <|> syncTarget
164 3c1915df Michele Tartara
  <|> pausedSyncS
165 3c1915df Michele Tartara
  <|> pausedSyncT
166 3c1915df Michele Tartara
  <|> verifyS
167 3c1915df Michele Tartara
  <|> verifyT
168 3c1915df Michele Tartara
  <|> unconfigured
169 3c1915df Michele Tartara
    where standAlone     = A.string "StandAlone"     *> pure StandAlone
170 3c1915df Michele Tartara
          disconnecting  = A.string "Disconnectiog"  *> pure Disconnecting
171 3c1915df Michele Tartara
          unconnected    = A.string "Unconnected"    *> pure Unconnected
172 3c1915df Michele Tartara
          timeout        = A.string "Timeout"        *> pure Timeout
173 3c1915df Michele Tartara
          brokenPipe     = A.string "BrokenPipe"     *> pure BrokenPipe
174 3c1915df Michele Tartara
          networkFailure = A.string "NetworkFailure" *> pure NetworkFailure
175 3c1915df Michele Tartara
          protocolError  = A.string "ProtocolError"  *> pure ProtocolError
176 3c1915df Michele Tartara
          tearDown       = A.string "TearDown"       *> pure TearDown
177 3c1915df Michele Tartara
          wfConnection   = A.string "WFConnection"   *> pure WFConnection
178 3c1915df Michele Tartara
          wfReportParams = A.string "WFReportParams" *> pure WFReportParams
179 3c1915df Michele Tartara
          connected      = A.string "Connected"      *> pure Connected
180 3c1915df Michele Tartara
          startingSyncS  = A.string "StartingSyncS"  *> pure StartingSyncS
181 3c1915df Michele Tartara
          startingSyncT  = A.string "StartingSyncT"  *> pure StartingSyncT
182 3c1915df Michele Tartara
          wfBitMapS      = A.string "WFBitMapS"      *> pure WFBitMapS
183 3c1915df Michele Tartara
          wfBitMapT      = A.string "WFBitMapT"      *> pure WFBitMapT
184 3c1915df Michele Tartara
          wfSyncUUID     = A.string "WFSyncUUID"     *> pure WFSyncUUID
185 3c1915df Michele Tartara
          syncSource     = A.string "SyncSource"     *> pure SyncSource
186 3c1915df Michele Tartara
          syncTarget     = A.string "SyncTarget"     *> pure SyncTarget
187 3c1915df Michele Tartara
          pausedSyncS    = A.string "PausedSyncS"    *> pure PausedSyncS
188 3c1915df Michele Tartara
          pausedSyncT    = A.string "PausedSyncT"    *> pure PausedSyncT
189 3c1915df Michele Tartara
          verifyS        = A.string "VerifyS"        *> pure VerifyS
190 3c1915df Michele Tartara
          verifyT        = A.string "VerifyT"        *> pure VerifyT
191 3c1915df Michele Tartara
          unconfigured   = A.string "Unconfigured"   *> pure Unconfigured
192 3c1915df Michele Tartara
193 3c1915df Michele Tartara
-- | Parser for recognizing strings describing two elements of the
194 3c1915df Michele Tartara
-- same type separated by a '/'. The first one is considered local,
195 3c1915df Michele Tartara
-- the second remote.
196 3c1915df Michele Tartara
localRemoteParser :: Parser a -> Parser (LocalRemote a)
197 3c1915df Michele Tartara
localRemoteParser parser = LocalRemote <$> parser <*> (A.char '/' *> parser)
198 3c1915df Michele Tartara
199 3c1915df Michele Tartara
-- | The parser for resource roles.
200 3c1915df Michele Tartara
roleParser :: Parser Role
201 3c1915df Michele Tartara
roleParser =
202 3c1915df Michele Tartara
  primary
203 3c1915df Michele Tartara
  <|> secondary
204 3c1915df Michele Tartara
  <|> unknown
205 3c1915df Michele Tartara
    where primary   = A.string "Primary"   *> pure Primary
206 3c1915df Michele Tartara
          secondary = A.string "Secondary" *> pure Secondary
207 3c1915df Michele Tartara
          unknown   = A.string "Unknown"   *> pure Unknown
208 3c1915df Michele Tartara
209 3c1915df Michele Tartara
-- | The parser for disk states.
210 3c1915df Michele Tartara
diskStateParser :: Parser DiskState
211 3c1915df Michele Tartara
diskStateParser =
212 3c1915df Michele Tartara
  diskless
213 3c1915df Michele Tartara
  <|> attaching
214 3c1915df Michele Tartara
  <|> failed
215 3c1915df Michele Tartara
  <|> negotiating
216 3c1915df Michele Tartara
  <|> inconsistent
217 3c1915df Michele Tartara
  <|> outdated
218 3c1915df Michele Tartara
  <|> dUnknown
219 3c1915df Michele Tartara
  <|> consistent
220 3c1915df Michele Tartara
  <|> upToDate
221 3c1915df Michele Tartara
    where diskless     = A.string "Diskless"     *> pure Diskless
222 3c1915df Michele Tartara
          attaching    = A.string "Attaching"    *> pure Attaching
223 3c1915df Michele Tartara
          failed       = A.string "Failed"       *> pure Failed
224 3c1915df Michele Tartara
          negotiating  = A.string "Negotiating"  *> pure Negotiating
225 3c1915df Michele Tartara
          inconsistent = A.string "Inconsistent" *> pure Inconsistent
226 3c1915df Michele Tartara
          outdated     = A.string "Outdated"     *> pure Outdated
227 3c1915df Michele Tartara
          dUnknown     = A.string "DUnknown"     *> pure DUnknown
228 3c1915df Michele Tartara
          consistent   = A.string "Consistent"   *> pure Consistent
229 3c1915df Michele Tartara
          upToDate     = A.string "UpToDate"     *> pure UpToDate
230 3c1915df Michele Tartara
231 3c1915df Michele Tartara
-- | The parser for I/O flags.
232 3c1915df Michele Tartara
ioFlagsParser :: Parser String
233 3c1915df Michele Tartara
ioFlagsParser = fmap unpack . A.takeWhile $ not . isBadEndOfLine
234 3c1915df Michele Tartara
235 3c1915df Michele Tartara
-- | The parser for performance indicators.
236 2188740e Michele Tartara
perfIndicatorsParser :: Parser PerfIndicators
237 2188740e Michele Tartara
perfIndicatorsParser =
238 2188740e Michele Tartara
  PerfIndicators
239 3c1915df Michele Tartara
    <$> skipSpacesAndString "ns:" A.decimal
240 3c1915df Michele Tartara
    <*> skipSpacesAndString "nr:" A.decimal
241 3c1915df Michele Tartara
    <*> skipSpacesAndString "dw:" A.decimal
242 3c1915df Michele Tartara
    <*> skipSpacesAndString "dr:" A.decimal
243 3c1915df Michele Tartara
    <*> skipSpacesAndString "al:" A.decimal
244 3c1915df Michele Tartara
    <*> skipSpacesAndString "bm:" A.decimal
245 3c1915df Michele Tartara
    <*> skipSpacesAndString "lo:" A.decimal
246 3c1915df Michele Tartara
    <*> skipSpacesAndString "pe:" A.decimal
247 3c1915df Michele Tartara
    <*> skipSpacesAndString "ua:" A.decimal
248 3c1915df Michele Tartara
    <*> skipSpacesAndString "ap:" A.decimal
249 3c1915df Michele Tartara
    <*> optional (skipSpacesAndString "ep:" A.decimal)
250 3c1915df Michele Tartara
    <*> optional (skipSpacesAndString "wo:" A.anyChar)
251 3c1915df Michele Tartara
    <*> optional (skipSpacesAndString "oos:" A.decimal)
252 3c1915df Michele Tartara
    <* skipSpaces <* A.endOfLine
253 3c1915df Michele Tartara
254 3c1915df Michele Tartara
-- | The parser for the syncronization status.
255 3c1915df Michele Tartara
syncStatusParser :: Parser SyncStatus
256 3c1915df Michele Tartara
syncStatusParser = do
257 3c1915df Michele Tartara
  _ <- statusBarParser
258 3c1915df Michele Tartara
  percent <-
259 3c1915df Michele Tartara
    skipSpacesAndString "sync'ed:" $ skipSpaces *> A.double <* A.char '%'
260 3c1915df Michele Tartara
  partSyncSize <- skipSpaces *> A.char '(' *> A.decimal
261 3c1915df Michele Tartara
  totSyncSize <- A.char '/' *> A.decimal <* A.char ')'
262 3c1915df Michele Tartara
  sizeUnit <- sizeUnitParser <* optional A.endOfLine
263 3c1915df Michele Tartara
  timeToEnd <- skipSpacesAndString "finish:" $ skipSpaces *> timeParser
264 3c1915df Michele Tartara
  sp <-
265 3c1915df Michele Tartara
    skipSpacesAndString "speed:" $
266 3c1915df Michele Tartara
      skipSpaces
267 3c1915df Michele Tartara
      *> commaIntParser
268 3c1915df Michele Tartara
      <* skipSpaces
269 3c1915df Michele Tartara
      <* A.char '('
270 3c1915df Michele Tartara
      <* commaIntParser
271 3c1915df Michele Tartara
      <* A.char ')'
272 3c1915df Michele Tartara
  w <- skipSpacesAndString "want:" (
273 3c1915df Michele Tartara
         skipSpaces
274 3c1915df Michele Tartara
         *> (Just <$> commaIntParser)
275 3c1915df Michele Tartara
       )
276 3c1915df Michele Tartara
       <|> pure Nothing
277 3c1915df Michele Tartara
  sSizeUnit <- skipSpaces *> sizeUnitParser
278 3c1915df Michele Tartara
  sTimeUnit <- A.char '/' *> timeUnitParser
279 3c1915df Michele Tartara
  _ <- A.endOfLine
280 3c1915df Michele Tartara
  return $
281 3c1915df Michele Tartara
    SyncStatus percent partSyncSize totSyncSize sizeUnit timeToEnd sp w
282 3c1915df Michele Tartara
      sSizeUnit sTimeUnit
283 3c1915df Michele Tartara
284 3c1915df Michele Tartara
-- | The parser for recognizing (and discarding) the sync status bar.
285 3c1915df Michele Tartara
statusBarParser :: Parser ()
286 3c1915df Michele Tartara
statusBarParser =
287 3c1915df Michele Tartara
  skipSpaces
288 3c1915df Michele Tartara
  *> A.char '['
289 3c1915df Michele Tartara
  *> A.skipWhile (== '=')
290 3c1915df Michele Tartara
  *> A.skipWhile (== '>')
291 3c1915df Michele Tartara
  *> A.skipWhile (== '.')
292 3c1915df Michele Tartara
  *> A.char ']'
293 3c1915df Michele Tartara
  *> pure ()
294 3c1915df Michele Tartara
295 3c1915df Michele Tartara
-- | The parser for recognizing data size units (only the ones
296 3c1915df Michele Tartara
-- actually found in DRBD files are implemented).
297 3c1915df Michele Tartara
sizeUnitParser :: Parser SizeUnit
298 3c1915df Michele Tartara
sizeUnitParser =
299 3c1915df Michele Tartara
  kilobyte
300 3c1915df Michele Tartara
  <|> megabyte
301 3c1915df Michele Tartara
    where kilobyte = A.string "K" *> pure KiloByte
302 3c1915df Michele Tartara
          megabyte = A.string "M" *> pure MegaByte
303 3c1915df Michele Tartara
304 3c1915df Michele Tartara
-- | The parser for recognizing time (hh:mm:ss).
305 3c1915df Michele Tartara
timeParser :: Parser Time
306 3c1915df Michele Tartara
timeParser = Time <$> h <*> m <*> s
307 2188740e Michele Tartara
  where h = A.decimal :: Parser Int
308 2188740e Michele Tartara
        m = A.char ':' *> A.decimal :: Parser Int
309 2188740e Michele Tartara
        s = A.char ':' *> A.decimal :: Parser Int
310 3c1915df Michele Tartara
311 3c1915df Michele Tartara
-- | The parser for recognizing time units (only the ones actually
312 3c1915df Michele Tartara
-- found in DRBD files are implemented).
313 3c1915df Michele Tartara
timeUnitParser :: Parser TimeUnit
314 3c1915df Michele Tartara
timeUnitParser = second
315 3c1915df Michele Tartara
  where second = A.string "sec" *> pure Second
316 3c1915df Michele Tartara
317 b22b93dc Michele Tartara
-- | Haskell does not recognise ',' as the thousands separator every 3
318 b22b93dc Michele Tartara
-- digits but DRBD uses it, so we need an ah-hoc parser.
319 b22b93dc Michele Tartara
-- If a number beginning with more than 3 digits without a comma is
320 b22b93dc Michele Tartara
-- parsed, only the first 3 digits are considered to be valid, the rest
321 b22b93dc Michele Tartara
-- is not consumed, and left for further parsing.
322 3c1915df Michele Tartara
commaIntParser :: Parser Int
323 3c1915df Michele Tartara
commaIntParser = do
324 b22b93dc Michele Tartara
  first <-
325 b22b93dc Michele Tartara
    AC.count 3 A.digit <|> AC.count 2 A.digit <|> AC.count 1 A.digit
326 b22b93dc Michele Tartara
  allDigits <- commaIntHelper (read first)
327 3c1915df Michele Tartara
  pure allDigits
328 3c1915df Michele Tartara
329 3c1915df Michele Tartara
-- | Helper (triplet parser) for the commaIntParser
330 3c1915df Michele Tartara
commaIntHelper :: Int -> Parser Int
331 3c1915df Michele Tartara
commaIntHelper acc = nextTriplet <|> end
332 3c1915df Michele Tartara
  where nextTriplet = do
333 3c1915df Michele Tartara
          _ <- A.char ','
334 3c1915df Michele Tartara
          triplet <- AC.count 3 A.digit
335 3c1915df Michele Tartara
          commaIntHelper $ acc * 1000 + (read triplet :: Int)
336 3c1915df Michele Tartara
        end = pure acc :: Parser Int
337 3c1915df Michele Tartara
338 3c1915df Michele Tartara
-- | Parser for the additional information provided by DRBD <= 8.0.
339 3c1915df Michele Tartara
additionalInfoParser::Parser AdditionalInfo
340 3c1915df Michele Tartara
additionalInfoParser = AdditionalInfo
341 3c1915df Michele Tartara
  <$> skipSpacesAndString "used:" A.decimal
342 3c1915df Michele Tartara
  <*> (A.char '/' *> A.decimal)
343 3c1915df Michele Tartara
  <*> skipSpacesAndString "hits:" A.decimal
344 3c1915df Michele Tartara
  <*> skipSpacesAndString "misses:" A.decimal
345 3c1915df Michele Tartara
  <*> skipSpacesAndString "starving:" A.decimal
346 3c1915df Michele Tartara
  <*> skipSpacesAndString "dirty:" A.decimal
347 3c1915df Michele Tartara
  <*> skipSpacesAndString "changed:" A.decimal
348 3c1915df Michele Tartara
  <* A.endOfLine