From d7e9323b920ead6f65d565d2ba47588a5a11932f Mon Sep 17 00:00:00 2001
From: Michele Tartara <mtartara@google.com>
Date: Thu, 25 Apr 2013 14:28:58 +0000
Subject: [PATCH] Add the core of the instance status collector

Add the Xen instance status data collector with only its core features.
The next commits will add more reporting functionalities.

The access to the collector is made possible through the mon-collector
tool.

Signed-off-by: Michele Tartara <mtartara@google.com>
Reviewed-by: Klaus Aehlig <aehlig@google.com>
---
 Makefile.am                                  |   2 +
 src/Ganeti/DataCollectors/InstStatus.hs      | 111 +++++++++++++++++++
 src/Ganeti/DataCollectors/InstStatusTypes.hs |  43 +++++++
 src/Ganeti/DataCollectors/Program.hs         |   9 +-
 4 files changed, 163 insertions(+), 2 deletions(-)
 create mode 100644 src/Ganeti/DataCollectors/InstStatus.hs
 create mode 100644 src/Ganeti/DataCollectors/InstStatusTypes.hs

diff --git a/Makefile.am b/Makefile.am
index 10092278b..023b8cb05 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -520,6 +520,8 @@ HS_LIB_SRCS = \
 	src/Ganeti/Daemon.hs \
 	src/Ganeti/DataCollectors/CLI.hs \
 	src/Ganeti/DataCollectors/Drbd.hs \
+	src/Ganeti/DataCollectors/InstStatus.hs \
+	src/Ganeti/DataCollectors/InstStatusTypes.hs \
 	src/Ganeti/DataCollectors/Program.hs \
 	src/Ganeti/DataCollectors/Types.hs \
 	src/Ganeti/Errors.hs \
diff --git a/src/Ganeti/DataCollectors/InstStatus.hs b/src/Ganeti/DataCollectors/InstStatus.hs
new file mode 100644
index 000000000..3209f750c
--- /dev/null
+++ b/src/Ganeti/DataCollectors/InstStatus.hs
@@ -0,0 +1,111 @@
+{-| Instance status data collector.
+
+-}
+
+{-
+
+Copyright (C) 2013 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.InstStatus
+  ( main
+  , options
+  , arguments
+  ) where
+
+
+import Data.Maybe
+import qualified Data.Map as Map
+import Network.BSD (getHostName)
+import qualified Text.JSON as J
+
+import qualified Ganeti.BasicTypes as BT
+import Ganeti.Confd.Client
+import Ganeti.Confd.Types
+import Ganeti.Common
+import Ganeti.DataCollectors.CLI
+import Ganeti.DataCollectors.InstStatusTypes
+import Ganeti.Hypervisor.Xen
+import Ganeti.Objects
+import Ganeti.Utils
+
+-- * Command line options
+
+options :: IO [OptType]
+options = return
+  [ oConfdAddr
+  , oConfdPort
+  ]
+
+-- | The list of arguments supported by the program.
+arguments :: [ArgCompletion]
+arguments = []
+
+-- | Get the list of instances ([primary], [secondary]) on the given node.
+-- Implemented as a function, even if used a single time, to specify in a
+-- convenient and elegant way the return data type, required in order to
+-- prevent incurring in the monomorphism restriction.
+-- The server address and the server port parameters are mainly intended
+-- for testing purposes. If they are Nothing, the default values will be used.
+getInstances
+  :: String
+  -> Maybe String
+  -> Maybe Int
+  -> IO (BT.Result ([Ganeti.Objects.Instance], [Ganeti.Objects.Instance]))
+getInstances node srvAddr srvPort = do
+  client <- getConfdClient srvAddr srvPort
+  reply <- query client ReqNodeInstances $ PlainQuery node
+  return $
+    case fmap (J.readJSON . confdReplyAnswer) reply of
+      Just (J.Ok instances) -> BT.Ok instances
+      Just (J.Error msg) -> BT.Bad msg
+      Nothing -> BT.Bad "No answer from the Confd server"
+
+-- Builds the status of an instance using runtime information about the Xen
+-- Domains, their uptime information and the static information provided by
+-- the ConfD server.
+buildStatus :: Map.Map String Domain -> Map.Map Int UptimeInfo -> Instance
+  -> IO InstStatus
+buildStatus domains uptimes inst = do
+  let name = instName inst
+      currDomain = Map.lookup name domains
+      idNum = fmap domId currDomain
+      currUInfo = idNum >>= (`Map.lookup` uptimes)
+      uptime = fmap uInfoUptime currUInfo
+      adminState = instAdminState inst
+  return $
+    InstStatus
+      name
+      (instUuid inst)
+      adminState
+      uptime
+      (instMtime inst)
+
+-- | Main function.
+main :: Options -> [String] -> IO ()
+main opts _ = do
+  curNode <- getHostName
+  let node = fromMaybe curNode $ optNode opts
+  answer <- getInstances node (optConfdAddr opts) (optConfdPort opts)
+  inst <- exitIfBad "Can't get instance info from ConfD" answer
+  domains <- getInferredDomInfo
+  uptimes <- getUptimeInfo
+  let primaryInst =  fst inst
+  iStatus <- mapM (buildStatus domains uptimes) primaryInst
+  putStrLn $ J.encode iStatus
diff --git a/src/Ganeti/DataCollectors/InstStatusTypes.hs b/src/Ganeti/DataCollectors/InstStatusTypes.hs
new file mode 100644
index 000000000..5eabd3c30
--- /dev/null
+++ b/src/Ganeti/DataCollectors/InstStatusTypes.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-| Type declarations specific for the instance status data collector.
+
+-}
+
+{-
+
+Copyright (C) 2013 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.InstStatusTypes
+  ( InstStatus(..)
+  ) where
+
+
+import Ganeti.Objects
+import Ganeti.THH
+
+-- | Data type representing the status of an instance to be returned.
+$(buildObject "InstStatus" "iStat"
+  [ simpleField "name"         [t| String |]
+  , simpleField "uuid"         [t| String |]
+  , simpleField "adminState"   [t| AdminState |]
+  , optionalNullSerField $
+    simpleField "uptime"       [t| String |]
+  , simpleField "mtime"        [t| Double |]
+  ])
diff --git a/src/Ganeti/DataCollectors/Program.hs b/src/Ganeti/DataCollectors/Program.hs
index 4e5ce133d..b96a7d8f5 100644
--- a/src/Ganeti/DataCollectors/Program.hs
+++ b/src/Ganeti/DataCollectors/Program.hs
@@ -29,10 +29,15 @@ import Ganeti.Common (PersonalityList)
 import Ganeti.DataCollectors.CLI (Options)
 
 import qualified Ganeti.DataCollectors.Drbd as Drbd
+import qualified Ganeti.DataCollectors.InstStatus as InstStatus
 
 -- | Supported binaries.
 personalities :: PersonalityList Options
 personalities = [ ("drbd",   (Drbd.main, Drbd.options, Drbd.arguments,
-                             "gathers and displays DRBD statistics in JSON\
-                             \ format"))
+                              "gathers and displays DRBD statistics in JSON\
+                              \ format"))
+                , ("inst-status-xen", (InstStatus.main, InstStatus.options,
+                                       InstStatus.arguments,
+                                       "gathers and displays the status of the\
+                                       \ instances in JSON format"))
                 ]
-- 
GitLab