Prevent silent failure in case of connection problems
[ganeti-local] / src / Ganeti / Query / Node.hs
index 5583054..36b5000 100644 (file)
@@ -31,16 +31,19 @@ module Ganeti.Query.Node
 
 import Control.Applicative
 import Data.List
+import Data.Maybe
 import qualified Data.Map as Map
 import qualified Text.JSON as J
 
 import Ganeti.Config
+import Ganeti.Logging
 import Ganeti.Objects
 import Ganeti.JSON
 import Ganeti.Rpc
 import Ganeti.Query.Language
 import Ganeti.Query.Common
 import Ganeti.Query.Types
+import Ganeti.Utils (niceSort)
 
 -- | Runtime is the resulting type for NodeInfo call.
 type Runtime = Either RpcError RpcResultNodeInfo
@@ -109,7 +112,7 @@ nodeLiveFieldBuilder (fname, ftitle, ftype, _, fdoc) =
   , FieldRuntime $ nodeLiveRpcCall fname
   , QffNormal)
 
--- | The docstring for the node role. Note that we use 'reverse in
+-- | The docstring for the node role. Note that we use 'reverse' in
 -- order to keep the same order as Python.
 nodeRoleDoc :: String
 nodeRoleDoc =
@@ -140,7 +143,7 @@ nodeFields =
        "Whether node can become a master candidate",
      FieldSimple (rsNormal . nodeMasterCapable), QffNormal)
   , (FieldDefinition "name" "Node" QFTText "Node name",
-     FieldSimple (rsNormal . nodeName), QffNormal)
+     FieldSimple (rsNormal . nodeName), QffHostname)
   , (FieldDefinition "offline" "Offline" QFTBool
        "Whether node is marked offline",
      FieldSimple (rsNormal . nodeOffline), QffNormal)
@@ -181,11 +184,11 @@ nodeFields =
      QffNormal)
   , (FieldDefinition "pinst_list" "PriInstances" QFTOther
        "List of instances with this node as primary",
-     FieldConfig (\cfg -> rsNormal . map instName . fst .
+     FieldConfig (\cfg -> rsNormal . niceSort . map instName . fst .
                           getNodeInstances cfg . nodeName), QffNormal)
   , (FieldDefinition "sinst_list" "SecInstances" QFTOther
        "List of instances with this node as secondary",
-     FieldConfig (\cfg -> rsNormal . map instName . snd .
+     FieldConfig (\cfg -> rsNormal . niceSort . map instName . snd .
                           getNodeInstances cfg . nodeName), QffNormal)
   , (FieldDefinition "role" "Role" QFTText nodeRoleDoc,
      FieldConfig ((rsNormal .) . getNodeRole), QffNormal)
@@ -196,9 +199,9 @@ nodeFields =
   -- non-implemented node resource model; they are declared just for
   -- parity, but are not functional
   , (FieldDefinition "hv_state" "HypervisorState" QFTOther "Hypervisor state",
-     missingRuntime, QffNormal)
+     FieldSimple (const rsUnavail), QffNormal)
   , (FieldDefinition "disk_state" "DiskState" QFTOther "Disk state",
-     missingRuntime, QffNormal)
+     FieldSimple (const rsUnavail), QffNormal)
   ] ++
   map nodeLiveFieldBuilder nodeLiveFieldsDefs ++
   map buildNdParamField allNDParamFields ++
@@ -212,6 +215,15 @@ fieldsMap :: FieldMap Node Runtime
 fieldsMap =
   Map.fromList $ map (\v@(f, _, _) -> (fdefName f, v)) nodeFields
 
+-- | Scan the list of results produced by executeRpcCall and log all the RPC
+-- errors.
+logRpcErrors :: [(Node, Runtime)] -> IO ()
+logRpcErrors allElems =
+  let logOneRpcErr (_, Right _) = return ()
+      logOneRpcErr (_, Left err) =
+        logError $ "Error in the RPC HTTP reply: " ++ show err
+  in mapM_ logOneRpcErr allElems
+
 -- | Collect live data from RPC query if enabled.
 --
 -- FIXME: Check which fields we actually need and possibly send empty
@@ -221,7 +233,7 @@ collectLiveData:: Bool -> ConfigData -> [Node] -> IO [(Node, Runtime)]
 collectLiveData False _ nodes =
   return $ zip nodes (repeat $ Left (RpcResultError "Live data disabled"))
 collectLiveData True cfg nodes = do
-  let vgs = [clusterVolumeGroupName $ configCluster cfg]
+  let vgs = maybeToList . clusterVolumeGroupName $ configCluster cfg
       hvs = [getDefaultHypervisor cfg]
       step n (bn, gn, em) =
         let ndp' = getNodeNdParams cfg n
@@ -231,6 +243,7 @@ collectLiveData True cfg nodes = do
              Nothing -> (n : bn, gn, em)
       (bnodes, gnodes, emap) = foldr step ([], [], []) nodes
   rpcres <- executeRpcCall gnodes (RpcCallNodeInfo vgs hvs (Map.fromList emap))
+  logRpcErrors rpcres
   -- FIXME: The order of nodes in the result could be different from the input
   return $ zip bnodes (repeat $ Left (RpcResultError "Broken configuration"))
            ++ rpcres