module Ganeti.HTools.Instance
( Instance(..)
, AssocList
, List
, create
, isRunning
, isOffline
, notOffline
, instanceDown
, usesSecMem
, applyIfOnline
, setIdx
, setName
, setAlias
, setPri
, setSec
, setBoth
, setMovable
, specOf
, instBelowISpec
, instAboveISpec
, instMatchesPolicy
, shrinkByType
, localStorageTemplates
, hasSecondary
, requiredNodes
, allNodes
, usesLocalStorage
, mirrorType
) where
import Ganeti.BasicTypes
import qualified Ganeti.HTools.Types as T
import qualified Ganeti.HTools.Container as Container
import Ganeti.HTools.Nic (Nic)
import Ganeti.Utils
data Instance = Instance
{ name :: String
, alias :: String
, mem :: Int
, dsk :: Int
, disks :: [Int]
, vcpus :: Int
, runSt :: T.InstanceStatus
, pNode :: T.Ndx
, sNode :: T.Ndx
, idx :: T.Idx
, util :: T.DynUtil
, movable :: Bool
, autoBalance :: Bool
, diskTemplate :: T.DiskTemplate
, spindleUse :: Int
, allTags :: [String]
, exclTags :: [String]
, arPolicy :: T.AutoRepairPolicy
, nics :: [Nic]
} deriving (Show, Eq)
instance T.Element Instance where
nameOf = name
idxOf = idx
setAlias = setAlias
setIdx = setIdx
allNames n = [name n, alias n]
isRunning :: Instance -> Bool
isRunning (Instance {runSt = T.Running}) = True
isRunning (Instance {runSt = T.ErrorUp}) = True
isRunning _ = False
isOffline :: Instance -> Bool
isOffline (Instance {runSt = T.StatusOffline}) = True
isOffline _ = False
notOffline :: Instance -> Bool
notOffline = not . isOffline
instanceDown :: Instance -> Bool
instanceDown inst | isRunning inst = False
instanceDown inst | isOffline inst = False
instanceDown _ = True
applyIfOnline :: Instance -> (a -> a) -> a -> a
applyIfOnline = applyIf . notOffline
usesSecMem :: Instance -> Bool
usesSecMem inst = notOffline inst && autoBalance inst
localStorageTemplates :: [T.DiskTemplate]
localStorageTemplates = [ T.DTDrbd8, T.DTPlain ]
movableDiskTemplates :: [T.DiskTemplate]
movableDiskTemplates =
[ T.DTDrbd8
, T.DTBlock
, T.DTSharedFile
, T.DTRbd
, T.DTExt
]
type AssocList = [(T.Idx, Instance)]
type List = Container.Container Instance
create :: String -> Int -> Int -> [Int] -> Int -> T.InstanceStatus
-> [String] -> Bool -> T.Ndx -> T.Ndx -> T.DiskTemplate -> Int
-> [Nic] -> Instance
create name_init mem_init dsk_init disks_init vcpus_init run_init tags_init
auto_balance_init pn sn dt su nics_init =
Instance { name = name_init
, alias = name_init
, mem = mem_init
, dsk = dsk_init
, disks = disks_init
, vcpus = vcpus_init
, runSt = run_init
, pNode = pn
, sNode = sn
, idx = 1
, util = T.baseUtil
, movable = supportsMoves dt
, autoBalance = auto_balance_init
, diskTemplate = dt
, spindleUse = su
, allTags = tags_init
, exclTags = []
, arPolicy = T.ArNotEnabled
, nics = nics_init
}
setIdx :: Instance
-> T.Idx
-> Instance
setIdx t i = t { idx = i }
setName :: Instance
-> String
-> Instance
setName t s = t { name = s, alias = s }
setAlias :: Instance
-> String
-> Instance
setAlias t s = t { alias = s }
setPri :: Instance
-> T.Ndx
-> Instance
setPri t p = t { pNode = p }
setSec :: Instance
-> T.Ndx
-> Instance
setSec t s = t { sNode = s }
setBoth :: Instance
-> T.Ndx
-> T.Ndx
-> Instance
setBoth t p s = t { pNode = p, sNode = s }
setMovable :: Instance
-> Bool
-> Instance
setMovable t m = t { movable = m }
shrinkByType :: Instance -> T.FailMode -> Result Instance
shrinkByType inst T.FailMem = let v = mem inst T.unitMem
in if v < T.unitMem
then Bad "out of memory"
else Ok inst { mem = v }
shrinkByType inst T.FailDisk =
let newdisks = map (flip () T.unitDsk) $ disks inst
v = dsk inst (length . disks $ inst) * T.unitDsk
in if any (< T.unitDsk) newdisks
then Bad "out of disk"
else Ok inst { dsk = v, disks = newdisks }
shrinkByType inst T.FailCPU = let v = vcpus inst T.unitCpu
in if v < T.unitCpu
then Bad "out of vcpus"
else Ok inst { vcpus = v }
shrinkByType _ f = Bad $ "Unhandled failure mode " ++ show f
specOf :: Instance -> T.RSpec
specOf Instance { mem = m, dsk = d, vcpus = c } =
T.RSpec { T.rspecCpu = c, T.rspecMem = m, T.rspecDsk = d }
instBelowISpec :: Instance -> T.ISpec -> T.OpResult ()
instBelowISpec inst ispec
| mem inst > T.iSpecMemorySize ispec = Bad T.FailMem
| any (> T.iSpecDiskSize ispec) (disks inst) = Bad T.FailDisk
| vcpus inst > T.iSpecCpuCount ispec = Bad T.FailCPU
| otherwise = Ok ()
instAboveISpec :: Instance -> T.ISpec -> T.OpResult ()
instAboveISpec inst ispec
| mem inst < T.iSpecMemorySize ispec = Bad T.FailMem
| any (< T.iSpecDiskSize ispec) (disks inst) = Bad T.FailDisk
| vcpus inst < T.iSpecCpuCount ispec = Bad T.FailCPU
| otherwise = Ok ()
instMatchesMinMaxSpecs :: Instance -> T.MinMaxISpecs -> T.OpResult ()
instMatchesMinMaxSpecs inst minmax = do
instAboveISpec inst (T.minMaxISpecsMinSpec minmax)
instBelowISpec inst (T.minMaxISpecsMaxSpec minmax)
instMatchesSpecs :: Instance -> [T.MinMaxISpecs] -> T.OpResult ()
instMatchesSpecs _ [] = Ok ()
instMatchesSpecs inst (minmax:minmaxes) =
foldr eithermatch (instMatchesMinMaxSpecs inst minmax) minmaxes
where eithermatch mm (Bad _) = instMatchesMinMaxSpecs inst mm
eithermatch _ y@(Ok ()) = y
instMatchesPolicy :: Instance -> T.IPolicy -> T.OpResult ()
instMatchesPolicy inst ipol = do
instMatchesSpecs inst $ T.iPolicyMinMaxISpecs ipol
if diskTemplate inst `elem` T.iPolicyDiskTemplates ipol
then Ok ()
else Bad T.FailDisk
hasSecondary :: Instance -> Bool
hasSecondary = (== T.DTDrbd8) . diskTemplate
requiredNodes :: T.DiskTemplate -> Int
requiredNodes T.DTDrbd8 = 2
requiredNodes _ = 1
allNodes :: Instance -> [T.Ndx]
allNodes inst = case diskTemplate inst of
T.DTDrbd8 -> [pNode inst, sNode inst]
_ -> [pNode inst]
usesLocalStorage :: Instance -> Bool
usesLocalStorage = (`elem` localStorageTemplates) . diskTemplate
supportsMoves :: T.DiskTemplate -> Bool
supportsMoves = (`elem` movableDiskTemplates)
mirrorType :: Instance -> T.MirrorType
mirrorType = T.templateMirrorType . diskTemplate