, List
, create
, instanceRunning
+ , instanceOffline
+ , instanceDown
+ , applyIfOnline
, setIdx
, setName
, setAlias
import qualified Ganeti.HTools.Container as Container
import qualified Ganeti.Constants as C
+import Ganeti.HTools.Utils
+
-- * Type declarations
-- | The instance type.
instanceRunning (Instance {runSt = T.ErrorUp}) = True
instanceRunning _ = False
+-- | Check if instance is offline.
+instanceOffline :: Instance -> Bool
+instanceOffline (Instance {runSt = T.AdminOffline}) = True
+instanceOffline _ = False
+
+-- | Check if instance is down.
+instanceDown :: Instance -> Bool
+instanceDown inst | instanceRunning inst = False
+instanceDown inst | instanceOffline inst = False
+instanceDown _ = True
+
+-- | Apply the function if the instance is online. Otherwise use
+-- the initial value
+applyIfOnline :: Instance -> (a -> a) -> a -> a
+applyIfOnline = applyIf . not . instanceOffline
+
-- | Constant holding the local storage templates.
--
-- /Note:/ Currently Ganeti only exports node total/free disk space
(\ msgs node ->
let nname = Node.name node
nilst = map (`Container.find` il) (Node.pList node)
- dilst = filter (not . Instance.instanceRunning) nilst
+ dilst = filter Instance.instanceDown nilst
adj_mem = sum . map Instance.mem $ dilst
delta_mem = truncate (Node.tMem node)
- Node.nMem node
nodeImem :: Node.Node -> Instance.List -> Int
nodeImem node il =
let rfind = flip Container.find il
- in sum . map (Instance.mem . rfind)
- $ Node.pList node
+ il' = map rfind $ Node.pList node
+ oil' = filter (not . Instance.instanceOffline) il'
+ in sum . map Instance.mem $ oil'
+
-- | Compute the amount of disk used by instances on a node (either primary
-- or secondary).
removePri t inst =
let iname = Instance.idx inst
new_plist = delete iname (pList t)
- new_mem = fMem t + Instance.mem inst
+ new_mem = Instance.applyIfOnline inst (+ Instance.mem inst) (fMem t)
new_dsk = fDsk t + Instance.dsk inst
new_mp = fromIntegral new_mem / tMem t
new_dp = fromIntegral new_dsk / tDsk t
new_failn1 = new_mem <= rMem t
- new_ucpu = uCpu t - Instance.vcpus inst
+ new_ucpu = Instance.applyIfOnline inst
+ (\x -> x - Instance.vcpus inst) (uCpu t)
new_rcpu = fromIntegral new_ucpu / tCpu t
new_load = utilLoad t `T.subUtil` Instance.util inst
in t { pList = new_plist, fMem = new_mem, fDsk = new_dsk
let iname = Instance.idx inst
uses_disk = Instance.usesLocalStorage inst
cur_dsk = fDsk t
- new_mem = fMem t - Instance.mem inst
+ new_mem = Instance.applyIfOnline inst
+ (\x -> x - Instance.mem inst) (fMem t)
new_dsk = if uses_disk
then cur_dsk - Instance.dsk inst
else cur_dsk
new_failn1 = new_mem <= rMem t
- new_ucpu = uCpu t + Instance.vcpus inst
+ new_ucpu = Instance.applyIfOnline inst (+ Instance.vcpus inst) (uCpu t)
new_pcpu = fromIntegral new_ucpu / tCpu t
new_dp = fromIntegral new_dsk / tDsk t
l_cpu = mCpu t
old_peers = peers t
old_mem = fMem t
new_dsk = fDsk t - Instance.dsk inst
- secondary_needed_mem = if Instance.autoBalance inst
+ secondary_needed_mem = if Instance.autoBalance inst &&
+ not (Instance.instanceOffline inst)
then Instance.mem inst
else 0
new_peem = P.find pdx old_peers + secondary_needed_mem
-- | Check that an instance add with too high memory or disk will be
-- rejected.
prop_Node_addPriFM node inst = Instance.mem inst >= Node.fMem node &&
- not (Node.failN1 node)
+ not (Node.failN1 node) &&
+ not (Instance.instanceOffline inst)
==>
case Node.addPri node inst'' of
Types.OpFail Types.FailMem -> True
inst'' = inst' { Instance.dsk = Instance.dsk inst }
prop_Node_addPriFC node inst (Positive extra) =
- not (Node.failN1 node) ==>
+ not (Node.failN1 node) &&
+ not (Instance.instanceOffline inst) ==>
case Node.addPri node inst'' of
Types.OpFail Types.FailCPU -> True
_ -> False
-- | Check that an instance add with too high memory or disk will be
-- rejected.
prop_Node_addSec node inst pdx =
- (Instance.mem inst >= (Node.fMem node - Node.rMem node) ||
+ ((Instance.mem inst >= (Node.fMem node - Node.rMem node) &&
+ not (Instance.instanceOffline inst)) ||
Instance.dsk inst >= Node.fDsk node) &&
not (Node.failN1 node)
==> isFailure (Node.addSec node inst pdx)
where _types = (node::Node.Node, inst::Instance.Instance, pdx::Int)
+-- | Check that an offline instance with reasonable disk size can always
+-- be added.
+prop_Node_addPriOffline node =
+ forAll (arbitrary `suchThat`
+ (\ x -> (Instance.dsk x < Node.fDsk node) &&
+ Instance.instanceOffline x)) $ \inst ->
+ case Node.addPri node inst of
+ Types.OpGood _ -> True
+ _ -> False
+
+prop_Node_addSecOffline node pdx =
+ forAll (arbitrary `suchThat`
+ (\ x -> (Instance.dsk x < Node.fDsk node) &&
+ Instance.instanceOffline x)) $ \inst ->
+ case Node.addSec node inst pdx of
+ Types.OpGood _ -> True
+ _ -> False
+
-- | Checks for memory reservation changes.
prop_Node_rMem inst =
+ not (Instance.instanceOffline inst) ==>
forAll (arbitrary `suchThat` ((> Types.unitMem) . Node.fMem)) $ \node ->
-- ab = auto_balance, nb = non-auto_balance
-- we use -1 as the primary node of the instance
, 'prop_Node_addPriFD
, 'prop_Node_addPriFC
, 'prop_Node_addSec
+ , 'prop_Node_addPriOffline
+ , 'prop_Node_addSecOffline
, 'prop_Node_rMem
, 'prop_Node_setMdsk
, 'prop_Node_tagMaps_idempotent
, stdDev
, if'
, select
+ , applyIf
, commaJoin
, readEitherString
, JSRecord
-- * Miscellaneous
+-- | Apply the function if condition holds, otherwise use default value.
+applyIf :: Bool -> (a -> a) -> a -> a
+applyIf b f x = if b then f x else x
+
-- | Comma-join a string list.
commaJoin :: [String] -> String
commaJoin = intercalate ","