module Ganeti.HTools.Cluster.Utils
( splitCluster
, iMoveToJob
, instancePriGroup
, availableGroupNodes
) where
import Data.Maybe (fromJust)
import qualified Data.IntSet as IntSet
import Ganeti.BasicTypes
import qualified Ganeti.Constants as C
import qualified Ganeti.HTools.Container as Container
import qualified Ganeti.HTools.Instance as Instance
import qualified Ganeti.HTools.Node as Node
import Ganeti.HTools.Types
import qualified Ganeti.OpCodes as OpCodes
import Ganeti.Types (mkNonEmpty, mkNonNegative)
splitCluster :: Node.List -> Instance.List ->
[(Gdx, (Node.List, Instance.List))]
splitCluster nl il =
let ngroups = Node.computeGroups (Container.elems nl)
in map (\(gdx, nodes) ->
let nidxs = map Node.idx nodes
nodes' = zip nidxs nodes
instances = Container.filter ((`elem` nidxs) . Instance.pNode) il
in (gdx, (Container.fromList nodes', instances))) ngroups
iMoveToJob :: Node.List
-> Instance.List
-> Idx
-> IMove
-> [OpCodes.OpCode]
iMoveToJob nl il idx move =
let inst = Container.find idx il
iname = Instance.name inst
lookNode n = case mkNonEmpty (Container.nameOf nl n) of
Bad msg -> error $ "Empty node name for idx " ++
show n ++ ": " ++ msg ++ "??"
Ok ne -> Just ne
opF' = OpCodes.OpInstanceMigrate
{ OpCodes.opInstanceName = iname
, OpCodes.opInstanceUuid = Nothing
, OpCodes.opMigrationMode = Nothing
, OpCodes.opOldLiveMode = Nothing
, OpCodes.opTargetNode = Nothing
, OpCodes.opTargetNodeUuid = Nothing
, OpCodes.opAllowRuntimeChanges = False
, OpCodes.opIgnoreIpolicy = False
, OpCodes.opMigrationCleanup = False
, OpCodes.opIallocator = Nothing
, OpCodes.opAllowFailover = True
, OpCodes.opIgnoreHvversions = True
}
opFA n = opF { OpCodes.opTargetNode = lookNode n }
opFforced =
OpCodes.OpInstanceFailover
{ OpCodes.opInstanceName = iname
, OpCodes.opInstanceUuid = Nothing
, OpCodes.opShutdownTimeout =
fromJust $ mkNonNegative C.defaultShutdownTimeout
, OpCodes.opIgnoreConsistency = False
, OpCodes.opTargetNode = Nothing
, OpCodes.opTargetNodeUuid = Nothing
, OpCodes.opIgnoreIpolicy = False
, OpCodes.opIallocator = Nothing
, OpCodes.opMigrationCleanup = False
}
opF = if Instance.forthcoming inst then opFforced else opF'
opR n = OpCodes.OpInstanceReplaceDisks
{ OpCodes.opInstanceName = iname
, OpCodes.opInstanceUuid = Nothing
, OpCodes.opEarlyRelease = False
, OpCodes.opIgnoreIpolicy = False
, OpCodes.opReplaceDisksMode = OpCodes.ReplaceNewSecondary
, OpCodes.opReplaceDisksList = []
, OpCodes.opRemoteNode = lookNode n
, OpCodes.opRemoteNodeUuid = Nothing
, OpCodes.opIallocator = Nothing
}
in case move of
Failover -> [ opF ]
FailoverToAny np -> [ opFA np ]
ReplacePrimary np -> [ opF, opR np, opF ]
ReplaceSecondary ns -> [ opR ns ]
ReplaceAndFailover np -> [ opR np, opF ]
FailoverAndReplace ns -> [ opF, opR ns ]
instancePriGroup :: Node.List -> Instance.Instance -> Gdx
instancePriGroup nl i =
let pnode = Container.find (Instance.pNode i) nl
in Node.group pnode
availableGroupNodes :: [(Gdx, [Ndx])]
-> IntSet.IntSet
-> Gdx
-> Result [Ndx]
availableGroupNodes group_nodes excl_ndx gdx = do
local_nodes <- maybe (Bad $ "Can't find group with index " ++ show gdx)
Ok (lookup gdx group_nodes)
let avail_nodes = filter (not . flip IntSet.member excl_ndx) local_nodes
return avail_nodes