From 332b1340479fd50ed39f6d9cd84c646e229ae9a9 Mon Sep 17 00:00:00 2001
From: Michele Tartara <mtartara@google.com>
Date: Tue, 27 Nov 2012 10:16:45 +0100
Subject: [PATCH] Add the stand-alone data collector for DRBD

It is implemented as a single binary receiving, as its first parameter,
the name of the actual data collector to be run.
This way, its structure can be used for all the future data collectors.

Also, factored out of bdev.py into constants.py the location of the DRBD
status file.

Signed-off-by: Michele Tartara <mtartara@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 .gitignore                              |  1 +
 Makefile.am                             | 12 +++-
 htools/Ganeti/DataCollectors/Drbd.hs    | 84 +++++++++++++++++++++++++
 htools/Ganeti/DataCollectors/Program.hs | 38 +++++++++++
 htools/mon-collector.hs                 | 61 ++++++++++++++++++
 man/footer.rst                          |  3 +-
 man/mon-collector.rst                   | 42 +++++++++++++
 7 files changed, 237 insertions(+), 4 deletions(-)
 create mode 100644 htools/Ganeti/DataCollectors/Drbd.hs
 create mode 100644 htools/Ganeti/DataCollectors/Program.hs
 create mode 100644 htools/mon-collector.hs
 create mode 100644 man/mon-collector.rst

diff --git a/.gitignore b/.gitignore
index e9b940489..21b59fa27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -115,6 +115,7 @@
 /htools/.hpc
 /htools/coverage
 
+/htools/mon-collector
 /htools/htools
 /htools/hconfd
 /htools/ganeti-confd
diff --git a/Makefile.am b/Makefile.am
index 3255e2a91..5558ccaba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -60,6 +60,7 @@ HTOOLS_DIRS = \
 	htools/Ganeti/Block \
 	htools/Ganeti/Block/Drbd \
 	htools/Ganeti/Confd \
+	htools/Ganeti/DataCollectors \
 	htools/Ganeti/HTools \
 	htools/Ganeti/HTools/Backend \
 	htools/Ganeti/HTools/Program \
@@ -113,6 +114,7 @@ ALL_APIDOC_HS_DIRS = \
 	$(APIDOC_HS_DIR)/Ganeti/Block \
 	$(APIDOC_HS_DIR)/Ganeti/Block/Drbd \
 	$(APIDOC_HS_DIR)/Ganeti/Confd \
+	$(APIDOC_HS_DIR)/Ganeti/DataCollectors \
 	$(APIDOC_HS_DIR)/Ganeti/HTools \
 	$(APIDOC_HS_DIR)/Ganeti/HTools/Backend \
 	$(APIDOC_HS_DIR)/Ganeti/HTools/Program \
@@ -404,7 +406,7 @@ docrst = \
 	doc/virtual-cluster.rst \
 	doc/walkthrough.rst
 
-HS_PROGS = htools/htools
+HS_PROGS = htools/htools htools/mon-collector
 HS_BIN_ROLES = hbal hscan hspace hinfo hcheck
 HS_HTOOLS_PROGS = $(HS_BIN_ROLES) hail
 
@@ -452,6 +454,8 @@ HS_LIB_SRCS = \
 	htools/Ganeti/Confd/Utils.hs \
 	htools/Ganeti/Config.hs \
 	htools/Ganeti/Daemon.hs \
+	htools/Ganeti/DataCollectors/Drbd.hs \
+	htools/Ganeti/DataCollectors/Program.hs \
 	htools/Ganeti/Errors.hs \
 	htools/Ganeti/HTools/Backend/IAlloc.hs \
 	htools/Ganeti/HTools/Backend/Luxi.hs \
@@ -743,7 +747,8 @@ nodist_pkglib_python_scripts = \
 myexeclib_SCRIPTS = \
 	daemons/daemon-util \
 	tools/kvm-ifup \
-	$(pkglib_python_scripts)
+	$(pkglib_python_scripts) \
+	htools/mon-collector
 
 nodist_myexeclib_SCRIPTS = \
 	$(nodist_pkglib_python_scripts)
@@ -829,7 +834,8 @@ man_MANS = \
 	man/hinfo.1 \
 	man/hscan.1 \
 	man/hspace.1 \
-	man/htools.1
+	man/htools.1 \
+	man/mon-collector.7
 
 manrst = $(patsubst %.1,%.rst,$(patsubst %.7,%.rst,$(patsubst %.8,%.rst,$(man_MANS))))
 manhtml = $(patsubst %.rst,%.html,$(manrst))
diff --git a/htools/Ganeti/DataCollectors/Drbd.hs b/htools/Ganeti/DataCollectors/Drbd.hs
new file mode 100644
index 000000000..7d3f893e8
--- /dev/null
+++ b/htools/Ganeti/DataCollectors/Drbd.hs
@@ -0,0 +1,84 @@
+{-| DRBD data collector.
+
+-}
+
+{-
+
+Copyright (C) 2012 Google Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Ganeti.DataCollectors.Drbd
+  ( main
+  , options
+  , arguments
+  ) where
+
+
+import qualified Control.Exception as E
+import Data.Attoparsec.Text.Lazy as A
+import Data.Text.Lazy (pack, unpack)
+import Text.JSON
+
+import qualified Ganeti.BasicTypes as BT
+import qualified Ganeti.Constants as C
+import Ganeti.Block.Drbd.Parser(drbdStatusParser)
+import Ganeti.Common
+import Ganeti.HTools.CLI
+import Ganeti.Utils
+
+
+-- | The default path of the DRBD status file.
+-- It is hardcoded because it is not likely to change.
+defaultFile :: FilePath
+defaultFile = C.drbdStatusFile
+
+-- | The default setting for the maximum amount of not parsed character to
+-- print in case of error.
+-- It is set to use most of the screen estate on a standard 80x25 terminal.
+-- TODO: add the possibility to set this with a command line parameter.
+defaultCharNum :: Int
+defaultCharNum = 80*20
+
+options :: IO [OptType]
+options = return []
+
+-- | The list of arguments supported by the program.
+arguments :: [ArgCompletion]
+arguments = [ArgCompletion OptComplFile 0 (Just 1)]
+
+
+-- * Command line options
+
+-- | Main function.
+main :: Options -> [String] -> IO ()
+main _ args = do
+  contents <-
+    ((E.try . readFile $ getInputPath args) :: IO (Either IOError String)) >>=
+      exitIfBad "Error reading from file" . either (BT.Bad . show) BT.Ok
+  output <-
+    case A.parse drbdStatusParser $ pack contents of
+      A.Fail unparsedText contexts errorMessage -> exitErr $
+        show (Prelude.take defaultCharNum $ unpack unparsedText) ++ "\n"
+          ++ show contexts ++ "\n" ++ errorMessage
+      A.Done _ drbdStatus -> return $ encode drbdStatus
+  putStrLn output
+  where getInputPath a =
+          if null a
+            then defaultFile
+            else head a
diff --git a/htools/Ganeti/DataCollectors/Program.hs b/htools/Ganeti/DataCollectors/Program.hs
new file mode 100644
index 000000000..7498be895
--- /dev/null
+++ b/htools/Ganeti/DataCollectors/Program.hs
@@ -0,0 +1,38 @@
+{-| Small module holding program definitions for data collectors.
+
+-}
+
+{-
+
+Copyright (C) 2012 Google Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Ganeti.DataCollectors.Program (personalities) where
+
+import Ganeti.Common (ArgCompletion)
+import Ganeti.HTools.CLI (OptType, Options)
+
+import qualified Ganeti.DataCollectors.Drbd as Drbd
+
+-- | Supported binaries.
+personalities :: [(String,
+                   (Options -> [String] -> IO (), IO [OptType],
+                    [ArgCompletion]))]
+personalities = [ ("drbd",   (Drbd.main, Drbd.options, Drbd.arguments))
+                ]
diff --git a/htools/mon-collector.hs b/htools/mon-collector.hs
new file mode 100644
index 000000000..06ff282b1
--- /dev/null
+++ b/htools/mon-collector.hs
@@ -0,0 +1,61 @@
+{-| Main binary for all stand-alone data collectors
+
+-}
+
+{-
+
+Copyright (C) 2012 Google Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Main (main) where
+
+import Data.Char (toLower)
+import System.Environment
+import System.IO
+
+import Ganeti.Utils
+import Ganeti.HTools.CLI (parseOpts, genericOpts)
+import Ganeti.DataCollectors.Program (personalities)
+
+-- | Display usage and exit.
+usage :: String -> IO ()
+usage name = do
+  hPutStrLn stderr $ "Unrecognised personality '" ++ name ++ "'."
+  hPutStrLn stderr "This program must be executed specifying one of the \
+                    \following names as the first parameter:"
+  mapM_ (hPutStrLn stderr . ("  - " ++) . fst) personalities
+  exitErr "Please specify the desired role."
+
+main :: IO ()
+main = do
+  cmd_args <- getArgs
+  let binary =
+        if null cmd_args
+          then ""
+          else head cmd_args
+      name = map toLower binary
+      boolnames = map (\(x, y) -> (x == name, Just y)) personalities
+  case select Nothing boolnames of
+    Nothing -> usage name
+    Just (fn, options, arguments) -> do
+         let actual_args = tail cmd_args
+         real_options <- options
+         (opts, args) <- parseOpts actual_args name (real_options ++
+                           genericOpts) arguments
+         fn opts args
diff --git a/man/footer.rst b/man/footer.rst
index a774f057e..7617054c6 100644
--- a/man/footer.rst
+++ b/man/footer.rst
@@ -26,7 +26,8 @@ daemon), **ganeti-masterd**(8) (master daemon), **ganeti-rapi**(8)
 Ganeti htools: **htools**(1) (generic binary), **hbal**(1) (cluster
 balancer), **hspace**(1) (capacity calculation), **hail**(1) (IAllocator
 plugin), **hscan**(1) (data gatherer from remote clusters), **hinfo**(1)
-(cluster information printer).
+(cluster information printer), **mon-collector**(7) (data collectors
+interface).
 
 COPYRIGHT
 ---------
diff --git a/man/mon-collector.rst b/man/mon-collector.rst
new file mode 100644
index 000000000..6260e2ea6
--- /dev/null
+++ b/man/mon-collector.rst
@@ -0,0 +1,42 @@
+mon-collector(7) Ganeti | Version @GANETI_VERSION@
+==================================================
+
+NAME
+----
+
+mon-collector - Command line interface for the data collectors of the
+monitoring system
+
+SYNOPSIS
+--------
+
+**mon-collector** {collector}
+
+DESCRIPTION
+-----------
+
+``mon-collector`` is a suite of tools designed to provide a command line
+interface to the data collectors implemented by the ganeti monitoring system.
+``mon-collector`` is also the generic binary that must be invoked specifying,
+as the first command line parameter, the name of the actual desired data
+collector to be run.
+
+When executed, ``mon-collector`` will run the specified collector and will
+print its output to stdout, in JSON format.
+
+
+
+
+COLLECTORS
+----------
+
+DRBD
+~~~~
+
+| drbd [*status-file*]
+
+Collects the information about the version and status of the DRBD kernel
+module, and of the disks it is managing.
+
+If *status-file* is specified, the status will be read from that file.
+Otherwise, the collector will read it from /proc/drbd.
-- 
GitLab