Export the actual instance state
[ganeti-local] / src / Ganeti / DataCollectors / InstStatus.hs
1 {-| Instance status data collector.
2
3 -}
4
5 {-
6
7 Copyright (C) 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.InstStatus
27   ( main
28   , options
29   , arguments
30   ) where
31
32
33 import Data.Maybe
34 import qualified Data.Map as Map
35 import Network.BSD (getHostName)
36 import qualified Text.JSON as J
37
38 import qualified Ganeti.BasicTypes as BT
39 import Ganeti.Confd.Client
40 import Ganeti.Confd.Types
41 import Ganeti.Common
42 import Ganeti.DataCollectors.CLI
43 import Ganeti.DataCollectors.InstStatusTypes
44 import Ganeti.Hypervisor.Xen
45 import Ganeti.Hypervisor.Xen.Types
46 import Ganeti.Objects
47 import Ganeti.Utils
48
49 -- * Command line options
50
51 options :: IO [OptType]
52 options = return
53   [ oConfdAddr
54   , oConfdPort
55   ]
56
57 -- | The list of arguments supported by the program.
58 arguments :: [ArgCompletion]
59 arguments = []
60
61 -- | Get the list of instances ([primary], [secondary]) on the given node.
62 -- Implemented as a function, even if used a single time, to specify in a
63 -- convenient and elegant way the return data type, required in order to
64 -- prevent incurring in the monomorphism restriction.
65 -- The server address and the server port parameters are mainly intended
66 -- for testing purposes. If they are Nothing, the default values will be used.
67 getInstances
68   :: String
69   -> Maybe String
70   -> Maybe Int
71   -> IO (BT.Result ([Ganeti.Objects.Instance], [Ganeti.Objects.Instance]))
72 getInstances node srvAddr srvPort = do
73   client <- getConfdClient srvAddr srvPort
74   reply <- query client ReqNodeInstances $ PlainQuery node
75   return $
76     case fmap (J.readJSON . confdReplyAnswer) reply of
77       Just (J.Ok instances) -> BT.Ok instances
78       Just (J.Error msg) -> BT.Bad msg
79       Nothing -> BT.Bad "No answer from the Confd server"
80
81 -- Builds the status of an instance using runtime information about the Xen
82 -- Domains, their uptime information and the static information provided by
83 -- the ConfD server.
84 buildStatus :: Map.Map String Domain -> Map.Map Int UptimeInfo -> Instance
85   -> IO InstStatus
86 buildStatus domains uptimes inst = do
87   let name = instName inst
88       currDomain = Map.lookup name domains
89       idNum = fmap domId currDomain
90       currUInfo = idNum >>= (`Map.lookup` uptimes)
91       uptime = fmap uInfoUptime currUInfo
92       adminState = instAdminState inst
93       actualState =
94         if adminState == AdminDown && isNothing currDomain
95           then ActualShutdown
96           else case currDomain of
97             (Just dom@(Domain _ _ _ _ (Just isHung))) ->
98               if isHung
99                 then ActualHung
100                 else domState dom
101             _ -> ActualUnknown
102   return $
103     InstStatus
104       name
105       (instUuid inst)
106       adminState
107       actualState
108       uptime
109       (instMtime inst)
110
111 -- | Main function.
112 main :: Options -> [String] -> IO ()
113 main opts _ = do
114   curNode <- getHostName
115   let node = fromMaybe curNode $ optNode opts
116   answer <- getInstances node (optConfdAddr opts) (optConfdPort opts)
117   inst <- exitIfBad "Can't get instance info from ConfD" answer
118   domains <- getInferredDomInfo
119   uptimes <- getUptimeInfo
120   let primaryInst =  fst inst
121   iStatus <- mapM (buildStatus domains uptimes) primaryInst
122   putStrLn $ J.encode iStatus