Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Runtime.hs @ ec321549

History | View | Annotate | Download (6.9 kB)

1
{-| Implementation of the runtime configuration details.
2

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 2011, 2012, 2013 Google Inc.
8

    
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
13

    
14
This program is distributed in the hope that it will be useful, but
15
WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
General Public License for more details.
18

    
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22
02110-1301, USA.
23

    
24
-}
25

    
26
module Ganeti.Runtime
27
  ( GanetiDaemon(..)
28
  , MiscGroup(..)
29
  , GanetiGroup(..)
30
  , RuntimeEnts
31
  , daemonName
32
  , daemonOnlyOnMaster
33
  , daemonLogBase
34
  , daemonUser
35
  , daemonGroup
36
  , ExtraLogReason(..)
37
  , daemonLogFile
38
  , daemonsExtraLogbase
39
  , daemonsExtraLogFile
40
  , daemonPidFile
41
  , getEnts
42
  , verifyDaemonUser
43
  ) where
44

    
45
import Control.Exception
46
import Control.Monad
47
import qualified Data.Map as M
48
import System.Exit
49
import System.FilePath
50
import System.IO
51
import System.IO.Error
52
import System.Posix.Types
53
import System.Posix.User
54
import Text.Printf
55

    
56
import qualified Ganeti.ConstantUtils as ConstantUtils
57
import qualified Ganeti.Path as Path
58
import Ganeti.BasicTypes
59

    
60
import AutoConf
61

    
62
data GanetiDaemon = GanetiMasterd
63
                  | GanetiNoded
64
                  | GanetiRapi
65
                  | GanetiConfd
66
                  | GanetiLuxid
67
                  | GanetiMond
68
                    deriving (Show, Enum, Bounded, Eq, Ord)
69

    
70
data MiscGroup = DaemonsGroup
71
               | AdminGroup
72
                 deriving (Show, Enum, Bounded, Eq, Ord)
73

    
74
data GanetiGroup = DaemonGroup GanetiDaemon
75
                 | ExtraGroup MiscGroup
76
                   deriving (Show, Eq, Ord)
77

    
78
type RuntimeEnts = (M.Map GanetiDaemon UserID, M.Map GanetiGroup GroupID)
79

    
80
-- | Returns the daemon name for a given daemon.
81
daemonName :: GanetiDaemon -> String
82
daemonName GanetiMasterd = "ganeti-masterd"
83
daemonName GanetiNoded   = "ganeti-noded"
84
daemonName GanetiRapi    = "ganeti-rapi"
85
daemonName GanetiConfd   = "ganeti-confd"
86
daemonName GanetiLuxid   = "ganeti-luxid"
87
daemonName GanetiMond    = "ganeti-mond"
88

    
89
-- | Returns whether the daemon only runs on the master node.
90
daemonOnlyOnMaster :: GanetiDaemon -> Bool
91
daemonOnlyOnMaster GanetiMasterd = True
92
daemonOnlyOnMaster GanetiNoded   = False
93
daemonOnlyOnMaster GanetiRapi    = False
94
daemonOnlyOnMaster GanetiConfd   = False
95
daemonOnlyOnMaster GanetiLuxid   = True
96
daemonOnlyOnMaster GanetiMond    = False
97

    
98
-- | Returns the log file base for a daemon.
99
daemonLogBase :: GanetiDaemon -> String
100
daemonLogBase GanetiMasterd = "master-daemon"
101
daemonLogBase GanetiNoded   = "node-daemon"
102
daemonLogBase GanetiRapi    = "rapi-daemon"
103
daemonLogBase GanetiConfd   = "conf-daemon"
104
daemonLogBase GanetiLuxid   = "luxi-daemon"
105
daemonLogBase GanetiMond    = "monitoring-daemon"
106

    
107
-- | Returns the configured user name for a daemon.
108
daemonUser :: GanetiDaemon -> String
109
daemonUser GanetiMasterd = AutoConf.masterdUser
110
daemonUser GanetiNoded   = AutoConf.nodedUser
111
daemonUser GanetiRapi    = AutoConf.rapiUser
112
daemonUser GanetiConfd   = AutoConf.confdUser
113
daemonUser GanetiLuxid   = AutoConf.luxidUser
114
daemonUser GanetiMond    = AutoConf.mondUser
115

    
116
-- | Returns the configured group for a daemon.
117
daemonGroup :: GanetiGroup -> String
118
daemonGroup (DaemonGroup GanetiMasterd) = AutoConf.masterdGroup
119
daemonGroup (DaemonGroup GanetiNoded)   = AutoConf.nodedGroup
120
daemonGroup (DaemonGroup GanetiRapi)    = AutoConf.rapiGroup
121
daemonGroup (DaemonGroup GanetiConfd)   = AutoConf.confdGroup
122
daemonGroup (DaemonGroup GanetiLuxid)   = AutoConf.luxidGroup
123
daemonGroup (DaemonGroup GanetiMond)    = AutoConf.mondGroup
124
daemonGroup (ExtraGroup  DaemonsGroup)  = AutoConf.daemonsGroup
125
daemonGroup (ExtraGroup  AdminGroup)    = AutoConf.adminGroup
126

    
127
data ExtraLogReason = AccessLog | ErrorLog
128

    
129
daemonsExtraLogbase :: GanetiDaemon -> ExtraLogReason -> String
130
daemonsExtraLogbase daemon AccessLog = daemonLogBase daemon ++ "-access"
131
daemonsExtraLogbase daemon ErrorLog = daemonLogBase daemon ++ "-error"
132

    
133
-- | Returns the log file for a daemon.
134
daemonLogFile :: GanetiDaemon -> IO FilePath
135
daemonLogFile daemon = do
136
  logDir <- Path.logDir
137
  return $ logDir </> daemonLogBase daemon <.> "log"
138

    
139
-- | Returns the extra log files for a daemon.
140
daemonsExtraLogFile :: GanetiDaemon -> ExtraLogReason -> IO FilePath
141
daemonsExtraLogFile daemon logreason = do
142
  logDir <- Path.logDir
143
  return $ logDir </> daemonsExtraLogbase daemon logreason <.> "log"
144

    
145
-- | Returns the pid file name for a daemon.
146
daemonPidFile :: GanetiDaemon -> IO FilePath
147
daemonPidFile daemon = do
148
  runDir <- Path.runDir
149
  return $ runDir </> daemonName daemon <.> "pid"
150

    
151
-- | All groups list. A bit hacking, as we can't enforce it's complete
152
-- at compile time.
153
allGroups :: [GanetiGroup]
154
allGroups = map DaemonGroup [minBound..maxBound] ++
155
            map ExtraGroup  [minBound..maxBound]
156

    
157
ignoreDoesNotExistErrors :: IO a -> IO (Result a)
158
ignoreDoesNotExistErrors value = do
159
  result <- tryJust (\e -> if isDoesNotExistError e
160
                             then Just (show e)
161
                             else Nothing) value
162
  return $ eitherToResult result
163

    
164
-- | Computes the group/user maps.
165
getEnts :: IO (Result RuntimeEnts)
166
getEnts = do
167
  users <- mapM (\daemon -> do
168
                   entry <- ignoreDoesNotExistErrors .
169
                            getUserEntryForName .
170
                            daemonUser $ daemon
171
                   return (entry >>= \e -> return (daemon, userID e))
172
                ) [minBound..maxBound]
173
  groups <- mapM (\group -> do
174
                    entry <- ignoreDoesNotExistErrors .
175
                             getGroupEntryForName .
176
                             daemonGroup $ group
177
                    return (entry >>= \e -> return (group, groupID e))
178
                 ) allGroups
179
  return $ do -- 'Result' monad
180
    users'  <- sequence users
181
    groups' <- sequence groups
182
    let usermap = M.fromList users'
183
        groupmap = M.fromList groups'
184
    return (usermap, groupmap)
185

    
186

    
187
-- | Checks whether a daemon runs as the right user.
188
verifyDaemonUser :: GanetiDaemon -> RuntimeEnts -> IO ()
189
verifyDaemonUser daemon ents = do
190
  myuid <- getEffectiveUserID
191
  -- note: we use directly ! as lookup failues shouldn't happen, due
192
  -- to the above map construction
193
  checkUidMatch (daemonName daemon) ((M.!) (fst ents) daemon) myuid
194

    
195
-- | Check that two UIDs are matching or otherwise exit.
196
checkUidMatch :: String -> UserID -> UserID -> IO ()
197
checkUidMatch name expected actual =
198
  when (expected /= actual) $ do
199
    hPrintf stderr "%s started using wrong user ID (%d), \
200
                   \expected %d\n" name
201
              (fromIntegral actual::Int)
202
              (fromIntegral expected::Int) :: IO ()
203
    exitWith $ ExitFailure ConstantUtils.exitFailure