module Ganeti.WConfd.ConfigVerify
( verifyConfig
, verifyConfigErr
) where
import Control.Monad (forM_)
import Control.Monad.Error.Class (MonadError(..))
import qualified Data.ByteString.UTF8 as UTF8
import qualified Data.Foldable as F
import qualified Data.Map as M
import qualified Data.Set as S
import Ganeti.Errors
import Ganeti.JSON (GenericContainer(..), Container)
import Ganeti.Objects
import Ganeti.Types
import Ganeti.Utils
import Ganeti.Utils.Validate
keysSet :: (Ord k) => GenericContainer k v -> S.Set k
keysSet = M.keysSet . fromContainer
checkUUIDKeys :: (UuidObject a, Show a)
=> String -> Container a -> ValidationMonad ()
checkUUIDKeys what = mapM_ check . M.toList . fromContainer
where
check (uuid, x) = reportIf (uuid /= UTF8.fromString (uuidOf x))
$ what ++ " '" ++ show x
++ "' is indexed by wrong UUID '"
++ UTF8.toString uuid ++ "'"
checkUUIDRefs :: (UuidObject a, Show a, F.Foldable f)
=> String -> String
-> (a -> [String]) -> f a -> Container b
-> ValidationMonad ()
checkUUIDRefs whatObj whatTarget linkf xs targets = F.mapM_ check xs
where
uuids = keysSet targets
check x = forM_ (linkf x) $ \uuid ->
reportIf (not $ S.member (UTF8.fromString uuid) uuids)
$ whatObj ++ " '" ++ show x ++ "' references a non-existing "
++ whatTarget ++ " UUID '" ++ uuid ++ "'"
verifyConfig :: ConfigData -> ValidationMonad ()
verifyConfig cd = do
let cluster = configCluster cd
nodes = configNodes cd
nodegroups = configNodegroups cd
instances = configInstances cd
networks = configNetworks cd
disks = configDisks cd
let enabledHvs = clusterEnabledHypervisors cluster
hvParams = clusterHvparams cluster
reportIf (null enabledHvs)
"enabled hypervisors list doesn't have any entries"
let missingHvp = S.fromList enabledHvs S.\\ keysSet hvParams
reportIf (not $ S.null missingHvp)
$ "hypervisor parameters missing for the enabled hypervisor(s) "
++ (commaJoin . map hypervisorToRaw . S.toList $ missingHvp)
let enabledDiskTemplates = clusterEnabledDiskTemplates cluster
reportIf (null enabledDiskTemplates)
"enabled disk templates list doesn't have any entries"
let masterNodeName = clusterMasterNode cluster
reportIf (not $ UTF8.fromString masterNodeName
`S.member` keysSet (configNodes cd))
$ "cluster has invalid primary node " ++ masterNodeName
checkUUIDKeys "node" nodes
checkUUIDKeys "nodegroup" nodegroups
checkUUIDKeys "instances" instances
checkUUIDKeys "network" networks
checkUUIDKeys "disk" disks
checkUUIDRefs "node" "nodegroup" (return . nodeGroup) nodes nodegroups
checkUUIDRefs "instance" "primary node" (maybe [] return . instPrimaryNode)
instances nodes
checkUUIDRefs "instance" "disks" instDisks instances disks
verifyConfigErr :: (MonadError GanetiException m) => ConfigData -> m ()
verifyConfigErr cd =
case runValidate $ verifyConfig cd of
(_, []) -> return ()
(_, es) -> throwError $ ConfigVerifyError "Validation failed" es