module Ganeti.Runtime
( GanetiDaemon(..)
, MiscGroup(..)
, GanetiGroup(..)
, RuntimeEnts(..)
, daemonName
, daemonOnlyOnMaster
, daemonLogBase
, daemonUser
, daemonGroup
, ExtraLogReason(..)
, daemonLogFile
, daemonsExtraLogbase
, daemonsExtraLogFile
, daemonPidFile
, getEnts
, verifyDaemonUser
) where
import Control.Monad
import Control.Monad.Error
import qualified Data.Map as M
import System.Exit
import System.FilePath
import System.IO
import System.Posix.Types
import System.Posix.User
import Text.Printf
import qualified Ganeti.ConstantUtils as ConstantUtils
import qualified Ganeti.Path as Path
import Ganeti.BasicTypes
import AutoConf
data GanetiDaemon = GanetiMasterd
| GanetiMetad
| GanetiNoded
| GanetiRapi
| GanetiConfd
| GanetiWConfd
| GanetiKvmd
| GanetiLuxid
| GanetiMond
deriving (Show, Enum, Bounded, Eq, Ord)
data MiscGroup = DaemonsGroup
| AdminGroup
deriving (Show, Enum, Bounded, Eq, Ord)
data GanetiGroup = DaemonGroup GanetiDaemon
| ExtraGroup MiscGroup
deriving (Show, Eq, Ord)
data RuntimeEnts = RuntimeEnts
{ reUserToUid :: M.Map GanetiDaemon UserID
, reUidToUser :: M.Map UserID String
, reGroupToGid :: M.Map GanetiGroup GroupID
, reGidToGroup :: M.Map GroupID String
}
daemonName :: GanetiDaemon -> String
daemonName GanetiMasterd = "ganeti-masterd"
daemonName GanetiMetad = "ganeti-metad"
daemonName GanetiNoded = "ganeti-noded"
daemonName GanetiRapi = "ganeti-rapi"
daemonName GanetiConfd = "ganeti-confd"
daemonName GanetiWConfd = "ganeti-wconfd"
daemonName GanetiKvmd = "ganeti-kvmd"
daemonName GanetiLuxid = "ganeti-luxid"
daemonName GanetiMond = "ganeti-mond"
daemonOnlyOnMaster :: GanetiDaemon -> Bool
daemonOnlyOnMaster GanetiMasterd = True
daemonOnlyOnMaster GanetiMetad = False
daemonOnlyOnMaster GanetiNoded = False
daemonOnlyOnMaster GanetiRapi = False
daemonOnlyOnMaster GanetiConfd = False
daemonOnlyOnMaster GanetiWConfd = True
daemonOnlyOnMaster GanetiKvmd = False
daemonOnlyOnMaster GanetiLuxid = True
daemonOnlyOnMaster GanetiMond = False
daemonLogBase :: GanetiDaemon -> String
daemonLogBase GanetiMasterd = "master-daemon"
daemonLogBase GanetiMetad = "meta-daemon"
daemonLogBase GanetiNoded = "node-daemon"
daemonLogBase GanetiRapi = "rapi-daemon"
daemonLogBase GanetiConfd = "conf-daemon"
daemonLogBase GanetiWConfd = "wconf-daemon"
daemonLogBase GanetiKvmd = "kvm-daemon"
daemonLogBase GanetiLuxid = "luxi-daemon"
daemonLogBase GanetiMond = "monitoring-daemon"
daemonUser :: GanetiDaemon -> String
daemonUser GanetiMasterd = AutoConf.masterdUser
daemonUser GanetiMetad = AutoConf.metadUser
daemonUser GanetiNoded = AutoConf.nodedUser
daemonUser GanetiRapi = AutoConf.rapiUser
daemonUser GanetiConfd = AutoConf.confdUser
daemonUser GanetiWConfd = AutoConf.wconfdUser
daemonUser GanetiKvmd = AutoConf.kvmdUser
daemonUser GanetiLuxid = AutoConf.luxidUser
daemonUser GanetiMond = AutoConf.mondUser
daemonGroup :: GanetiGroup -> String
daemonGroup (DaemonGroup GanetiMasterd) = AutoConf.masterdGroup
daemonGroup (DaemonGroup GanetiMetad) = AutoConf.metadGroup
daemonGroup (DaemonGroup GanetiNoded) = AutoConf.nodedGroup
daemonGroup (DaemonGroup GanetiRapi) = AutoConf.rapiGroup
daemonGroup (DaemonGroup GanetiConfd) = AutoConf.confdGroup
daemonGroup (DaemonGroup GanetiWConfd) = AutoConf.wconfdGroup
daemonGroup (DaemonGroup GanetiLuxid) = AutoConf.luxidGroup
daemonGroup (DaemonGroup GanetiKvmd) = AutoConf.kvmdGroup
daemonGroup (DaemonGroup GanetiMond) = AutoConf.mondGroup
daemonGroup (ExtraGroup DaemonsGroup) = AutoConf.daemonsGroup
daemonGroup (ExtraGroup AdminGroup) = AutoConf.adminGroup
data ExtraLogReason = AccessLog | ErrorLog
daemonsExtraLogbase :: GanetiDaemon -> ExtraLogReason -> String
daemonsExtraLogbase daemon AccessLog = daemonLogBase daemon ++ "-access"
daemonsExtraLogbase daemon ErrorLog = daemonLogBase daemon ++ "-error"
daemonLogFile :: GanetiDaemon -> IO FilePath
daemonLogFile daemon = do
logDir <- Path.logDir
return $ logDir </> daemonLogBase daemon <.> "log"
daemonsExtraLogFile :: GanetiDaemon -> ExtraLogReason -> IO FilePath
daemonsExtraLogFile daemon logreason = do
logDir <- Path.logDir
return $ logDir </> daemonsExtraLogbase daemon logreason <.> "log"
daemonPidFile :: GanetiDaemon -> IO FilePath
daemonPidFile daemon = do
runDir <- Path.runDir
return $ runDir </> daemonName daemon <.> "pid"
allGroups :: [GanetiGroup]
allGroups = map DaemonGroup [minBound..maxBound] ++
map ExtraGroup [minBound..maxBound]
getEnts :: (Error e) => ResultT e IO RuntimeEnts
getEnts = do
let userOf = liftM userID . liftIO . getUserEntryForName . daemonUser
let groupOf = liftM groupID . liftIO . getGroupEntryForName . daemonGroup
let allDaemons = [minBound..maxBound] :: [GanetiDaemon]
users <- mapM userOf allDaemons
groups <- mapM groupOf allGroups
return $ RuntimeEnts
(M.fromList $ zip allDaemons users)
(M.fromList $ zip users (map daemonUser allDaemons))
(M.fromList $ zip allGroups groups)
(M.fromList $ zip groups (map daemonGroup allGroups))
verifyDaemonUser :: GanetiDaemon -> RuntimeEnts -> IO ()
verifyDaemonUser daemon ents = do
myuid <- getEffectiveUserID
checkUidMatch (daemonName daemon) ((M.!) (reUserToUid ents) daemon) myuid
checkUidMatch :: String -> UserID -> UserID -> IO ()
checkUidMatch name expected actual =
when (expected /= actual) $ do
hPrintf stderr "%s started using wrong user ID (%d), \
\expected %d\n" name
(fromIntegral actual::Int)
(fromIntegral expected::Int) :: IO ()
exitWith $ ExitFailure ConstantUtils.exitFailure