Revision 9491766c src/Ganeti/Query/Instance.hs

b/src/Ganeti/Query/Instance.hs
39 39
import Ganeti.BasicTypes
40 40
import Ganeti.Common
41 41
import Ganeti.Config
42
import Ganeti.Errors
42 43
import Ganeti.Objects
43 44
import Ganeti.Query.Common
44 45
import Ganeti.Query.Language
......
64 65
instanceFields :: FieldList Instance Runtime
65 66
instanceFields =
66 67
  -- Simple fields
67
  [ (FieldDefinition "disk_template" "Disk_template" QFTText
68
  [ (FieldDefinition "admin_state" "InstanceState" QFTText
69
     "Desired state of instance",
70
     FieldSimple (rsNormal . adminStateToRaw . instAdminState), QffNormal)
71
  , (FieldDefinition "admin_up" "Autostart" QFTBool
72
     "Desired state of instance",
73
     FieldSimple (rsNormal . (== AdminUp) . instAdminState), QffNormal)
74
  , (FieldDefinition "disk_template" "Disk_template" QFTText
68 75
     "Instance disk template",
69 76
     FieldSimple (rsNormal . instDiskTemplate), QffNormal)
77
  , (FieldDefinition "disks_active" "DisksActive" QFTBool
78
     "Desired state of instance disks",
79
     FieldSimple (rsNormal . instDisksActive), QffNormal)
70 80
  , (FieldDefinition "name" "Instance" QFTText
71 81
     "Instance name",
72 82
     FieldSimple (rsNormal . instName), QffHostname)
......
79 89
  , (FieldDefinition "os" "OS" QFTText
80 90
     "Operating system",
81 91
     FieldSimple (rsNormal . instOs), QffNormal)
92
  , (FieldDefinition "pnode" "Primary_node" QFTText
93
     "Primary node",
94
     FieldConfig getPrimaryNodeName, QffHostname)
95
  , (FieldDefinition "pnode.group" "PrimaryNodeGroup" QFTText
96
     "Primary node's group",
97
     FieldConfig getPrimaryNodeGroup, QffNormal)
98
  , (FieldDefinition "snodes" "Secondary_Nodes" QFTOther
99
     "Secondary nodes; usually this will just be one node",
100
     FieldConfig (getSecondaryNodeAttribute nodeName), QffNormal)
101
  , (FieldDefinition "snodes.group" "SecondaryNodesGroups" QFTOther
102
     "Node groups of secondary nodes",
103
     FieldConfig (getSecondaryNodeGroupAttribute groupName), QffNormal)
104
  , (FieldDefinition "snodes.group.uuid" "SecondaryNodesGroupsUUID" QFTOther
105
     "Node group UUIDs of secondary nodes",
106
     FieldConfig (getSecondaryNodeGroupAttribute groupUuid), QffNormal)
82 107
  ] ++
83 108

  
84 109
  -- Live fields using special getters
......
98 123
  uuidFields "Instance" ++
99 124
  tagsFields
100 125

  
126
-- * Helper functions for node property retrieval
127

  
128
-- | Helper function for primary node retrieval
129
getPrimaryNode :: ConfigData -> Instance -> ErrorResult Node
130
getPrimaryNode cfg = getInstPrimaryNode cfg . instName
131

  
132
-- | Get primary node hostname
133
getPrimaryNodeName :: ConfigData -> Instance -> ResultEntry
134
getPrimaryNodeName cfg inst =
135
  rsErrorNoData $ (J.showJSON . nodeName) <$> getPrimaryNode cfg inst
136

  
137
-- | Get primary node hostname
138
getPrimaryNodeGroup :: ConfigData -> Instance -> ResultEntry
139
getPrimaryNodeGroup cfg inst =
140
  rsErrorNoData $ (J.showJSON . groupName) <$>
141
    (getPrimaryNode cfg inst >>=
142
    maybeToError "Configuration missing" . getGroupOfNode cfg)
143

  
144
-- | Get secondary nodes - the configuration objects themselves
145
getSecondaryNodes :: ConfigData -> Instance -> ErrorResult [Node]
146
getSecondaryNodes cfg inst = do
147
  pNode <- getPrimaryNode cfg inst
148
  allNodes <- getInstAllNodes cfg $ instName inst
149
  return $ delete pNode allNodes
150

  
151
-- | Get attributes of the secondary nodes
152
getSecondaryNodeAttribute :: (J.JSON a)
153
                          => (Node -> a)
154
                          -> ConfigData
155
                          -> Instance
156
                          -> ResultEntry
157
getSecondaryNodeAttribute getter cfg inst =
158
  rsErrorNoData $ map (J.showJSON . getter) <$> getSecondaryNodes cfg inst
159

  
160
-- | Get secondary node groups
161
getSecondaryNodeGroups :: ConfigData -> Instance -> ErrorResult [NodeGroup]
162
getSecondaryNodeGroups cfg inst = do
163
  sNodes <- getSecondaryNodes cfg inst
164
  return . catMaybes $ map (getGroupOfNode cfg) sNodes
165

  
166
-- | Get attributes of secondary node groups
167
getSecondaryNodeGroupAttribute :: (J.JSON a)
168
                               => (NodeGroup -> a)
169
                               -> ConfigData
170
                               -> Instance
171
                               -> ResultEntry
172
getSecondaryNodeGroupAttribute getter cfg inst =
173
  rsErrorNoData $ map (J.showJSON . getter) <$> getSecondaryNodeGroups cfg inst
174

  
101 175
-- * Live fields functionality
102 176

  
103 177
-- | List of node live fields.
......
128 202

  
129 203
-- | Builder for node live fields.
130 204
instanceLiveFieldBuilder :: (FieldName, FieldTitle, FieldType, String, FieldDoc)
131
                     -> FieldData Instance Runtime
205
                         -> FieldData Instance Runtime
132 206
instanceLiveFieldBuilder (fname, ftitle, ftype, _, fdoc) =
133 207
  ( FieldDefinition fname ftitle ftype fdoc
134 208
  , FieldRuntime $ instanceLiveRpcCall fname
135 209
  , QffNormal)
136 210

  
137

  
138
-- Functionality related to status and operational status extraction
211
-- * Functionality related to status and operational status extraction
139 212

  
140 213
-- | The documentation text for the instance status field
141 214
statusDocText :: String
142 215
statusDocText =
143 216
  let si = show . instanceStatusToRaw :: InstanceStatus -> String
144
  in "Instance status; " ++
145
     si Running ++
146
     " if instance is set to be running and actually is, " ++
147
     si StatusDown ++
148
     " if instance is stopped and is not running, " ++
149
     si WrongNode ++
150
     " if instance running, but not on its designated primary node, " ++
151
     si ErrorUp ++
152
     " if instance should be stopped, but is actually running, " ++
153
     si ErrorDown ++
154
     " if instance should run, but doesn't, " ++
155
     si NodeDown ++
156
     " if instance's primary node is down, " ++
157
     si NodeOffline ++
158
     " if instance's primary node is marked offline, " ++
159
     si StatusOffline ++
160
     " if instance is offline and does not use dynamic resources"
217
  in  "Instance status; " ++
218
      si Running ++
219
      " if instance is set to be running and actually is, " ++
220
      si StatusDown ++
221
      " if instance is stopped and is not running, " ++
222
      si WrongNode ++
223
      " if instance running, but not on its designated primary node, " ++
224
      si ErrorUp ++
225
      " if instance should be stopped, but is actually running, " ++
226
      si ErrorDown ++
227
      " if instance should run, but doesn't, " ++
228
      si NodeDown ++
229
      " if instance's primary node is down, " ++
230
      si NodeOffline ++
231
      " if instance's primary node is marked offline, " ++
232
      si StatusOffline ++
233
      " if instance is offline and does not use dynamic resources"
161 234

  
162 235
-- | Checks if the primary node of an instance is offline
163 236
isPrimaryOffline :: ConfigData -> Instance -> Bool
164 237
isPrimaryOffline cfg inst =
165
  let pNode = optimisticUnwrapper . getNode cfg $ instPrimaryNode inst
166
  in nodeOffline pNode
238
  let pNodeResult = getNode cfg $ instPrimaryNode inst
239
  in case pNodeResult of
240
     Ok pNode -> nodeOffline pNode
241
     Bad    _ -> error "Programmer error - result assumed to be OK is Bad!"
167 242

  
168 243
-- | Determines the status of a live instance
169 244
liveInstanceStatus :: LiveInfo -> Instance -> InstanceStatus
......
182 257
    AdminOffline -> StatusOffline
183 258

  
184 259
-- | Determines the status of the instance, depending on whether it is possible
185
-- | to communicate with its primary node, on which node it is, and its
186
-- | configuration.
187
determineInstanceStatus :: ConfigData -- ^ The configuration data
188
                        -> Runtime    -- ^ All the data from the live call
189
                        -> Instance   -- ^ The static instance configuration
190
                        -> InstanceStatus -- ^ Result
191
determineInstanceStatus cfg res inst =
192
  if isPrimaryOffline cfg inst
193
    then NodeOffline
194
    else case res of
195
      Left _                -> NodeDown
196
      Right (Just liveData) -> liveInstanceStatus liveData inst
197
      Right Nothing         -> deadInstanceStatus inst
198

  
199
-- | Extracts the status, doing necessary transformations but once
260
-- to communicate with its primary node, on which node it is, and its
261
-- configuration.
262
determineInstanceStatus :: ConfigData      -- ^ The configuration data
263
                        -> Runtime         -- ^ All the data from the live call
264
                        -> Instance        -- ^ Static instance configuration
265
                        -> InstanceStatus  -- ^ Result
266
determineInstanceStatus cfg res inst
267
  | isPrimaryOffline cfg inst = NodeOffline
268
  | otherwise = case res of
269
                  Left _                -> NodeDown
270
                  Right (Just liveData) -> liveInstanceStatus liveData inst
271
                  Right Nothing         -> deadInstanceStatus inst
272

  
273
-- | Extracts the instance status, retrieving it using the functions above and
274
-- transforming it into a 'ResultEntry'.
200 275
statusExtract :: ConfigData -> Runtime -> Instance -> ResultEntry
201 276
statusExtract cfg res inst =
202 277
  rsNormal . J.showJSON . instanceStatusToRaw $
203 278
    determineInstanceStatus cfg res inst
204 279

  
205
-- | Extracts the operational status
280
-- | Extracts the operational status of the instance.
206 281
operStatusExtract :: Runtime -> Instance -> ResultEntry
207 282
operStatusExtract res _ =
208
  rsMaybeNoData $ J.showJSON <$> case res of
209
    Left _  -> Nothing
210
    Right x -> Just $ isJust x
211

  
283
  rsMaybeNoData $ J.showJSON <$>
284
    case res of
285
      Left  _ -> Nothing
286
      Right x -> Just $ isJust x
212 287

  
213
-- Helper functions extracting information as necessary for the generic query
288
-- * Helper functions extracting information as necessary for the generic query
214 289
-- interfaces
215 290

  
216
-- | A function removing the GenericResult wrapper from assuredly OK values
217
optimisticUnwrapper :: GenericResult a b -> b
218
optimisticUnwrapper (Ok x) = x
219
optimisticUnwrapper (Bad _) = error "Programmer error: assumptions are wrong!"
220

  
221
-- | Simple filter of OK results only
222
okNodesOnly :: [GenericResult a Node] -> [Node]
223
okNodesOnly = map optimisticUnwrapper . filter isOk
224

  
225 291
-- | Finds information about the instance in the info delivered by a node
226 292
findInstanceInfo :: Instance
227 293
                 -> ERpcError RpcResultAllInstancesInfo
......
286 352
                            RpcResultError $ "Live data disabled"
287 353
  | otherwise = do
288 354
      let hvSpec = getDefaultHypervisorSpec cfg
289
          instance_nodes = nub . okNodesOnly $
355
          instance_nodes = nub . justOk $
290 356
                             map (getNode cfg . instPrimaryNode) instances
291 357
          good_nodes = nodesWithValidConfig cfg instance_nodes
292 358
      rpcres <- executeRpcCall good_nodes $ RpcCallAllInstancesInfo [hvSpec]

Also available in: Unified diff