Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Runtime.hs @ 3af1359f

History | View | Annotate | Download (7.6 kB)

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

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 2011, 2012, 2013, 2014 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
                  | GanetiMetad
64
                  | GanetiNoded
65
                  | GanetiRapi
66
                  | GanetiConfd
67
                  | GanetiKvmd
68
                  | GanetiLuxid
69
                  | GanetiMond
70
                    deriving (Show, Enum, Bounded, Eq, Ord)
71

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

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

    
80
type RuntimeEnts = (M.Map GanetiDaemon UserID, M.Map GanetiGroup GroupID)
81

    
82
-- | Returns the daemon name for a given daemon.
83
daemonName :: GanetiDaemon -> String
84
daemonName GanetiMasterd = "ganeti-masterd"
85
daemonName GanetiMetad   = "ganeti-metad"
86
daemonName GanetiNoded   = "ganeti-noded"
87
daemonName GanetiRapi    = "ganeti-rapi"
88
daemonName GanetiConfd   = "ganeti-confd"
89
daemonName GanetiKvmd    = "ganeti-kvmd"
90
daemonName GanetiLuxid   = "ganeti-luxid"
91
daemonName GanetiMond    = "ganeti-mond"
92

    
93
-- | Returns whether the daemon only runs on the master node.
94
daemonOnlyOnMaster :: GanetiDaemon -> Bool
95
daemonOnlyOnMaster GanetiMasterd = True
96
daemonOnlyOnMaster GanetiMetad   = False
97
daemonOnlyOnMaster GanetiNoded   = False
98
daemonOnlyOnMaster GanetiRapi    = False
99
daemonOnlyOnMaster GanetiConfd   = False
100
daemonOnlyOnMaster GanetiKvmd    = False
101
daemonOnlyOnMaster GanetiLuxid   = True
102
daemonOnlyOnMaster GanetiMond    = False
103

    
104
-- | Returns the log file base for a daemon.
105
daemonLogBase :: GanetiDaemon -> String
106
daemonLogBase GanetiMasterd = "master-daemon"
107
daemonLogBase GanetiMetad   = "meta-daemon"
108
daemonLogBase GanetiNoded   = "node-daemon"
109
daemonLogBase GanetiRapi    = "rapi-daemon"
110
daemonLogBase GanetiConfd   = "conf-daemon"
111
daemonLogBase GanetiKvmd    = "kvm-daemon"
112
daemonLogBase GanetiLuxid   = "luxi-daemon"
113
daemonLogBase GanetiMond    = "monitoring-daemon"
114

    
115
-- | Returns the configured user name for a daemon.
116
daemonUser :: GanetiDaemon -> String
117
daemonUser GanetiMasterd = AutoConf.masterdUser
118
daemonUser GanetiMetad   = AutoConf.metadUser
119
daemonUser GanetiNoded   = AutoConf.nodedUser
120
daemonUser GanetiRapi    = AutoConf.rapiUser
121
daemonUser GanetiConfd   = AutoConf.confdUser
122
daemonUser GanetiKvmd    = AutoConf.kvmdUser
123
daemonUser GanetiLuxid   = AutoConf.luxidUser
124
daemonUser GanetiMond    = AutoConf.mondUser
125

    
126
-- | Returns the configured group for a daemon.
127
daemonGroup :: GanetiGroup -> String
128
daemonGroup (DaemonGroup GanetiMasterd) = AutoConf.masterdGroup
129
daemonGroup (DaemonGroup GanetiMetad)   = AutoConf.metadGroup
130
daemonGroup (DaemonGroup GanetiNoded)   = AutoConf.nodedGroup
131
daemonGroup (DaemonGroup GanetiRapi)    = AutoConf.rapiGroup
132
daemonGroup (DaemonGroup GanetiConfd)   = AutoConf.confdGroup
133
daemonGroup (DaemonGroup GanetiLuxid)   = AutoConf.luxidGroup
134
daemonGroup (DaemonGroup GanetiKvmd)    = AutoConf.kvmdGroup
135
daemonGroup (DaemonGroup GanetiMond)    = AutoConf.mondGroup
136
daemonGroup (ExtraGroup  DaemonsGroup)  = AutoConf.daemonsGroup
137
daemonGroup (ExtraGroup  AdminGroup)    = AutoConf.adminGroup
138

    
139
data ExtraLogReason = AccessLog | ErrorLog
140

    
141
-- | Some daemons might require more than one logfile.  Specifically,
142
-- right now only the Haskell http library "snap", used by the
143
-- monitoring daemon, requires multiple log files.
144
daemonsExtraLogbase :: GanetiDaemon -> ExtraLogReason -> String
145
daemonsExtraLogbase daemon AccessLog = daemonLogBase daemon ++ "-access"
146
daemonsExtraLogbase daemon ErrorLog = daemonLogBase daemon ++ "-error"
147

    
148
-- | Returns the log file for a daemon.
149
daemonLogFile :: GanetiDaemon -> IO FilePath
150
daemonLogFile daemon = do
151
  logDir <- Path.logDir
152
  return $ logDir </> daemonLogBase daemon <.> "log"
153

    
154
-- | Returns the extra log files for a daemon.
155
daemonsExtraLogFile :: GanetiDaemon -> ExtraLogReason -> IO FilePath
156
daemonsExtraLogFile daemon logreason = do
157
  logDir <- Path.logDir
158
  return $ logDir </> daemonsExtraLogbase daemon logreason <.> "log"
159

    
160
-- | Returns the pid file name for a daemon.
161
daemonPidFile :: GanetiDaemon -> IO FilePath
162
daemonPidFile daemon = do
163
  runDir <- Path.runDir
164
  return $ runDir </> daemonName daemon <.> "pid"
165

    
166
-- | All groups list. A bit hacking, as we can't enforce it's complete
167
-- at compile time.
168
allGroups :: [GanetiGroup]
169
allGroups = map DaemonGroup [minBound..maxBound] ++
170
            map ExtraGroup  [minBound..maxBound]
171

    
172
ignoreDoesNotExistErrors :: IO a -> IO (Result a)
173
ignoreDoesNotExistErrors value = do
174
  result <- tryJust (\e -> if isDoesNotExistError e
175
                             then Just (show e)
176
                             else Nothing) value
177
  return $ eitherToResult result
178

    
179
-- | Computes the group/user maps.
180
getEnts :: IO (Result RuntimeEnts)
181
getEnts = do
182
  users <- mapM (\daemon -> do
183
                   entry <- ignoreDoesNotExistErrors .
184
                            getUserEntryForName .
185
                            daemonUser $ daemon
186
                   return (entry >>= \e -> return (daemon, userID e))
187
                ) [minBound..maxBound]
188
  groups <- mapM (\group -> do
189
                    entry <- ignoreDoesNotExistErrors .
190
                             getGroupEntryForName .
191
                             daemonGroup $ group
192
                    return (entry >>= \e -> return (group, groupID e))
193
                 ) allGroups
194
  return $ do -- 'Result' monad
195
    users'  <- sequence users
196
    groups' <- sequence groups
197
    let usermap = M.fromList users'
198
        groupmap = M.fromList groups'
199
    return (usermap, groupmap)
200

    
201

    
202
-- | Checks whether a daemon runs as the right user.
203
verifyDaemonUser :: GanetiDaemon -> RuntimeEnts -> IO ()
204
verifyDaemonUser daemon ents = do
205
  myuid <- getEffectiveUserID
206
  -- note: we use directly ! as lookup failues shouldn't happen, due
207
  -- to the above map construction
208
  checkUidMatch (daemonName daemon) ((M.!) (fst ents) daemon) myuid
209

    
210
-- | Check that two UIDs are matching or otherwise exit.
211
checkUidMatch :: String -> UserID -> UserID -> IO ()
212
checkUidMatch name expected actual =
213
  when (expected /= actual) $ do
214
    hPrintf stderr "%s started using wrong user ID (%d), \
215
                   \expected %d\n" name
216
              (fromIntegral actual::Int)
217
              (fromIntegral expected::Int) :: IO ()
218
    exitWith $ ExitFailure ConstantUtils.exitFailure