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