Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Runtime.hs @ 670e954a

History | View | Annotate | Download (6.2 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
  , daemonUser
34
  , daemonGroup
35
  , daemonLogFile
36
  , daemonPidFile
37
  , getEnts
38
  , verifyDaemonUser
39
  ) where
40

    
41
import Control.Exception
42
import Control.Monad
43
import qualified Data.Map as M
44
import System.Exit
45
import System.FilePath
46
import System.IO
47
import System.IO.Error
48
import System.Posix.Types
49
import System.Posix.User
50
import Text.Printf
51

    
52
import qualified Ganeti.Constants as C
53
import qualified Ganeti.Path as Path
54
import Ganeti.BasicTypes
55

    
56
data GanetiDaemon = GanetiMasterd
57
                  | GanetiNoded
58
                  | GanetiRapi
59
                  | GanetiConfd
60
                  | GanetiQueryd
61
                  | GanetiMond
62
                    deriving (Show, Enum, Bounded, Eq, Ord)
63

    
64
data MiscGroup = DaemonsGroup
65
               | AdminGroup
66
                 deriving (Show, Enum, Bounded, Eq, Ord)
67

    
68
data GanetiGroup = DaemonGroup GanetiDaemon
69
                 | ExtraGroup MiscGroup
70
                   deriving (Show, Eq, Ord)
71

    
72
type RuntimeEnts = (M.Map GanetiDaemon UserID, M.Map GanetiGroup GroupID)
73

    
74
-- | Returns the daemon name for a given daemon.
75
daemonName :: GanetiDaemon -> String
76
daemonName GanetiMasterd = C.masterd
77
daemonName GanetiNoded   = C.noded
78
daemonName GanetiRapi    = C.rapi
79
daemonName GanetiConfd   = C.confd
80
daemonName GanetiQueryd  = C.queryd
81
daemonName GanetiMond    = C.mond
82

    
83
-- | Returns whether the daemon only runs on the master node.
84
daemonOnlyOnMaster :: GanetiDaemon -> Bool
85
daemonOnlyOnMaster GanetiMasterd = True
86
daemonOnlyOnMaster GanetiNoded   = False
87
daemonOnlyOnMaster GanetiRapi    = False
88
daemonOnlyOnMaster GanetiConfd   = False
89
daemonOnlyOnMaster GanetiQueryd  = True
90
daemonOnlyOnMaster GanetiMond    = False
91

    
92
-- | Returns the log file base for a daemon.
93
daemonLogBase :: GanetiDaemon -> String
94
daemonLogBase GanetiMasterd = C.daemonsLogbaseGanetiMasterd
95
daemonLogBase GanetiNoded   = C.daemonsLogbaseGanetiNoded
96
daemonLogBase GanetiRapi    = C.daemonsLogbaseGanetiRapi
97
daemonLogBase GanetiConfd   = C.daemonsLogbaseGanetiConfd
98
daemonLogBase GanetiQueryd  = C.daemonsLogbaseGanetiQueryd
99
daemonLogBase GanetiMond    = C.daemonsLogbaseGanetiMond
100

    
101
-- | Returns the configured user name for a daemon.
102
daemonUser :: GanetiDaemon -> String
103
daemonUser GanetiMasterd = C.masterdUser
104
daemonUser GanetiNoded   = C.nodedUser
105
daemonUser GanetiRapi    = C.rapiUser
106
daemonUser GanetiConfd   = C.confdUser
107
daemonUser GanetiQueryd  = C.querydUser
108
daemonUser GanetiMond    = C.mondUser
109

    
110
-- | Returns the configured group for a daemon.
111
daemonGroup :: GanetiGroup -> String
112
daemonGroup (DaemonGroup GanetiMasterd) = C.masterdGroup
113
daemonGroup (DaemonGroup GanetiNoded)   = C.nodedGroup
114
daemonGroup (DaemonGroup GanetiRapi)    = C.rapiGroup
115
daemonGroup (DaemonGroup GanetiConfd)   = C.confdGroup
116
daemonGroup (DaemonGroup GanetiQueryd)  = C.querydGroup
117
daemonGroup (DaemonGroup GanetiMond)    = C.mondGroup
118
daemonGroup (ExtraGroup  DaemonsGroup)  = C.daemonsGroup
119
daemonGroup (ExtraGroup  AdminGroup)    = C.adminGroup
120

    
121
-- | Returns the log file for a daemon.
122
daemonLogFile :: GanetiDaemon -> IO FilePath
123
daemonLogFile daemon = do
124
  logDir <- Path.logDir
125
  return $ logDir </> daemonLogBase daemon <.> "log"
126

    
127
-- | Returns the pid file name for a daemon.
128
daemonPidFile :: GanetiDaemon -> IO FilePath
129
daemonPidFile daemon = do
130
  runDir <- Path.runDir
131
  return $ runDir </> daemonName daemon <.> "pid"
132

    
133
-- | All groups list. A bit hacking, as we can't enforce it's complete
134
-- at compile time.
135
allGroups :: [GanetiGroup]
136
allGroups = map DaemonGroup [minBound..maxBound] ++
137
            map ExtraGroup  [minBound..maxBound]
138

    
139
ignoreDoesNotExistErrors :: IO a -> IO (Result a)
140
ignoreDoesNotExistErrors value = do
141
  result <- tryJust (\e -> if isDoesNotExistError e
142
                             then Just (show e)
143
                             else Nothing) value
144
  return $ eitherToResult result
145

    
146
-- | Computes the group/user maps.
147
getEnts :: IO (Result RuntimeEnts)
148
getEnts = do
149
  users <- mapM (\daemon -> do
150
                   entry <- ignoreDoesNotExistErrors .
151
                            getUserEntryForName .
152
                            daemonUser $ daemon
153
                   return (entry >>= \e -> return (daemon, userID e))
154
                ) [minBound..maxBound]
155
  groups <- mapM (\group -> do
156
                    entry <- ignoreDoesNotExistErrors .
157
                             getGroupEntryForName .
158
                             daemonGroup $ group
159
                    return (entry >>= \e -> return (group, groupID e))
160
                 ) allGroups
161
  return $ do -- 'Result' monad
162
    users'  <- sequence users
163
    groups' <- sequence groups
164
    let usermap = M.fromList users'
165
        groupmap = M.fromList groups'
166
    return (usermap, groupmap)
167

    
168

    
169
-- | Checks whether a daemon runs as the right user.
170
verifyDaemonUser :: GanetiDaemon -> RuntimeEnts -> IO ()
171
verifyDaemonUser daemon ents = do
172
  myuid <- getEffectiveUserID
173
  -- note: we use directly ! as lookup failues shouldn't happen, due
174
  -- to the above map construction
175
  checkUidMatch (daemonName daemon) ((M.!) (fst ents) daemon) myuid
176

    
177
-- | Check that two UIDs are matching or otherwise exit.
178
checkUidMatch :: String -> UserID -> UserID -> IO ()
179
checkUidMatch name expected actual =
180
  when (expected /= actual) $ do
181
    hPrintf stderr "%s started using wrong user ID (%d), \
182
                   \expected %d\n" name
183
              (fromIntegral actual::Int)
184
              (fromIntegral expected::Int) :: IO ()
185
    exitWith $ ExitFailure C.exitFailure