Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / Query / Node.hs @ 5227de56

History | View | Annotate | Download (8.2 kB)

1
{-| Implementation of the Ganeti Query2 node queries.
2

    
3
 -}
4

    
5
{-
6

    
7
Copyright (C) 2012 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.Query.Node
27
  ( NodeRuntime
28
  , nodeFieldsMap
29
  ) where
30

    
31
import Control.Applicative
32
import Data.List
33
import qualified Data.Map as Map
34
import qualified Text.JSON as J
35

    
36
import Ganeti.Config
37
import Ganeti.Objects
38
import Ganeti.JSON
39
import Ganeti.Rpc
40
import Ganeti.Query.Language
41
import Ganeti.Query.Common
42
import Ganeti.Query.Types
43

    
44
-- | NodeRuntime is the resulting type for NodeInfo call.
45
type NodeRuntime = Either RpcError RpcResultNodeInfo
46

    
47
-- | List of node live fields.
48
nodeLiveFieldsDefs :: [(FieldName, FieldTitle, FieldType, String, FieldDoc)]
49
nodeLiveFieldsDefs =
50
  [ ("bootid", "BootID", QFTText, "bootid",
51
     "Random UUID renewed for each system reboot, can be used\
52
     \ for detecting reboots by tracking changes")
53
  , ("cnodes", "CNodes", QFTNumber, "cpu_nodes",
54
     "Number of NUMA domains on node (if exported by hypervisor)")
55
  , ("csockets", "CSockets", QFTNumber, "cpu_sockets",
56
     "Number of physical CPU sockets (if exported by hypervisor)")
57
  , ("ctotal", "CTotal", QFTNumber, "cpu_total",
58
     "Number of logical processors")
59
  , ("dfree", "DFree", QFTUnit, "vg_free",
60
     "Available disk space in volume group")
61
  , ("dtotal", "DTotal", QFTUnit, "vg_size",
62
     "Total disk space in volume group used for instance disk allocation")
63
  , ("mfree", "MFree", QFTUnit, "memory_free",
64
     "Memory available for instance allocations")
65
  , ("mnode", "MNode", QFTUnit, "memory_dom0",
66
     "Amount of memory used by node (dom0 for Xen)")
67
  , ("mtotal", "MTotal", QFTUnit, "memory_total",
68
     "Total amount of memory of physical machine")
69
  ]
70

    
71
-- | Map each name to a function that extracts that value from
72
-- the RPC result.
73
nodeLiveFieldExtract :: FieldName -> RpcResultNodeInfo -> J.JSValue
74
nodeLiveFieldExtract "bootid" res =
75
  J.showJSON $ rpcResNodeInfoBootId res
76
nodeLiveFieldExtract "cnodes" res =
77
  jsonHead (rpcResNodeInfoHvInfo res) hvInfoCpuNodes
78
nodeLiveFieldExtract "csockets" res =
79
  jsonHead (rpcResNodeInfoHvInfo res) hvInfoCpuSockets
80
nodeLiveFieldExtract "ctotal" res =
81
  jsonHead (rpcResNodeInfoHvInfo res) hvInfoCpuTotal
82
nodeLiveFieldExtract "dfree" res =
83
  getMaybeJsonHead (rpcResNodeInfoVgInfo res) vgInfoVgFree
84
nodeLiveFieldExtract "dtotal" res =
85
  getMaybeJsonHead (rpcResNodeInfoVgInfo res) vgInfoVgSize
86
nodeLiveFieldExtract "mfree" res =
87
  jsonHead (rpcResNodeInfoHvInfo res) hvInfoMemoryFree
88
nodeLiveFieldExtract "mnode" res =
89
  jsonHead (rpcResNodeInfoHvInfo res) hvInfoMemoryDom0
90
nodeLiveFieldExtract "mtotal" res =
91
  jsonHead (rpcResNodeInfoHvInfo res) hvInfoMemoryTotal
92
nodeLiveFieldExtract _ _ = J.JSNull
93

    
94
-- | Helper for extracting field from RPC result.
95
nodeLiveRpcCall :: FieldName -> NodeRuntime -> Node -> ResultEntry
96
nodeLiveRpcCall fname (Right res) _ =
97
  case nodeLiveFieldExtract fname res of
98
    J.JSNull -> rsNoData
99
    x -> rsNormal x
100
nodeLiveRpcCall _ (Left err) _ =
101
    ResultEntry (rpcErrorToStatus err) Nothing
102

    
103
-- | Builder for node live fields.
104
nodeLiveFieldBuilder :: (FieldName, FieldTitle, FieldType, String, FieldDoc)
105
                     -> FieldData Node NodeRuntime
106
nodeLiveFieldBuilder (fname, ftitle, ftype, _, fdoc) =
107
  ( FieldDefinition fname ftitle ftype fdoc
108
  , FieldRuntime $ nodeLiveRpcCall fname)
109

    
110
-- | The docstring for the node role. Note that we use 'reverse in
111
-- order to keep the same order as Python.
112
nodeRoleDoc :: String
113
nodeRoleDoc =
114
  "Node role; " ++
115
  intercalate ", "
116
   (map (\role ->
117
          "\"" ++ nodeRoleToRaw role ++ "\" for " ++ roleDescription role)
118
   (reverse [minBound..maxBound]))
119

    
120
-- | Get node powered status.
121
getNodePower :: ConfigData -> Node -> ResultEntry
122
getNodePower cfg node =
123
  case getNodeNdParams cfg node of
124
    Nothing -> rsNoData
125
    Just ndp -> if null (ndpOobProgram ndp)
126
                  then rsUnavail
127
                  else rsNormal (nodePowered node)
128

    
129
-- | List of all node fields.
130
nodeFields :: FieldList Node NodeRuntime
131
nodeFields =
132
  [ (FieldDefinition "drained" "Drained" QFTBool "Whether node is drained",
133
     FieldSimple (rsNormal . nodeDrained))
134
  , (FieldDefinition "master_candidate" "MasterC" QFTBool
135
       "Whether node is a master candidate",
136
     FieldSimple (rsNormal . nodeMasterCandidate))
137
  , (FieldDefinition "master_capable" "MasterCapable" QFTBool
138
       "Whether node can become a master candidate",
139
     FieldSimple (rsNormal . nodeMasterCapable))
140
  , (FieldDefinition "name" "Node" QFTText "Node name",
141
     FieldSimple (rsNormal . nodeName))
142
  , (FieldDefinition "offline" "Offline" QFTBool
143
       "Whether node is marked offline",
144
     FieldSimple (rsNormal . nodeOffline))
145
  , (FieldDefinition "vm_capable" "VMCapable" QFTBool
146
       "Whether node can host instances",
147
     FieldSimple (rsNormal . nodeVmCapable))
148
  , (FieldDefinition "pip" "PrimaryIP" QFTText "Primary IP address",
149
     FieldSimple (rsNormal . nodePrimaryIp))
150
  , (FieldDefinition "sip" "SecondaryIP" QFTText "Secondary IP address",
151
     FieldSimple (rsNormal . nodeSecondaryIp))
152
  , (FieldDefinition "master" "IsMaster" QFTBool "Whether node is master",
153
     FieldConfig (\cfg node ->
154
                    rsNormal (nodeName node ==
155
                              clusterMasterNode (configCluster cfg))))
156
  , (FieldDefinition "group" "Group" QFTText "Node group",
157
     FieldConfig (\cfg node ->
158
                    rsMaybe (groupName <$> getGroupOfNode cfg node)))
159
  , (FieldDefinition "group.uuid" "GroupUUID" QFTText "UUID of node group",
160
     FieldSimple (rsNormal . nodeGroup))
161
  ,  (FieldDefinition "ndparams" "NodeParameters" QFTOther
162
        "Merged node parameters",
163
      FieldConfig ((rsMaybe .) . getNodeNdParams))
164
  , (FieldDefinition "custom_ndparams" "CustomNodeParameters" QFTOther
165
                       "Custom node parameters",
166
     FieldSimple (rsNormal . nodeNdparams))
167
  -- FIXME: the below could be generalised a bit, like in Python
168
  , (FieldDefinition "pinst_cnt" "Pinst" QFTNumber
169
       "Number of instances with this node as primary",
170
     FieldConfig (\cfg ->
171
                    rsNormal . length . fst . getNodeInstances cfg . nodeName))
172
  , (FieldDefinition "sinst_cnt" "Sinst" QFTNumber
173
       "Number of instances with this node as secondary",
174
     FieldConfig (\cfg ->
175
                    rsNormal . length . snd . getNodeInstances cfg . nodeName))
176
  , (FieldDefinition "pinst_list" "PriInstances" QFTOther
177
       "List of instances with this node as primary",
178
     FieldConfig (\cfg -> rsNormal . map instName . fst .
179
                          getNodeInstances cfg . nodeName))
180
  , (FieldDefinition "sinst_list" "SecInstances" QFTOther
181
       "List of instances with this node as secondary",
182
     FieldConfig (\cfg -> rsNormal . map instName . snd .
183
                          getNodeInstances cfg . nodeName))
184
  , (FieldDefinition "role" "Role" QFTText nodeRoleDoc,
185
     FieldConfig ((rsNormal .) . getNodeRole))
186
  , (FieldDefinition "powered" "Powered" QFTBool
187
       "Whether node is thought to be powered on",
188
     FieldConfig getNodePower)
189
  -- FIXME: the two fields below are incomplete in Python, part of the
190
  -- non-implemented node resource model; they are declared just for
191
  -- parity, but are not functional
192
  , (FieldDefinition "hv_state" "HypervisorState" QFTOther "Hypervisor state",
193
     missingRuntime)
194
  , (FieldDefinition "disk_state" "DiskState" QFTOther "Disk state",
195
     missingRuntime)
196
  ] ++
197
  map nodeLiveFieldBuilder nodeLiveFieldsDefs ++
198
  map buildNdParamField allNDParamFields ++
199
  timeStampFields ++
200
  uuidFields "Node" ++
201
  serialFields "Node" ++
202
  tagsFields
203

    
204
-- | The node fields map.
205
nodeFieldsMap :: FieldMap Node NodeRuntime
206
nodeFieldsMap = Map.fromList $ map (\v -> (fdefName (fst v), v)) nodeFields