Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Runtime.hs @ cb44e3db

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

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

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

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

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

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

    
70
type RuntimeEnts = (M.Map GanetiDaemon UserID, M.Map GanetiGroup GroupID)
71

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

    
80
-- | Returns the log file base for a daemon.
81
daemonLogBase :: GanetiDaemon -> String
82
daemonLogBase GanetiMasterd = C.daemonsLogbaseGanetiMasterd
83
daemonLogBase GanetiNoded   = C.daemonsLogbaseGanetiNoded
84
daemonLogBase GanetiRapi    = C.daemonsLogbaseGanetiRapi
85
daemonLogBase GanetiConfd   = C.daemonsLogbaseGanetiConfd
86
daemonLogBase GanetiMond    = C.daemonsLogbaseGanetiMond
87

    
88
-- | Returns the configured user name for a daemon.
89
daemonUser :: GanetiDaemon -> String
90
daemonUser GanetiMasterd = C.masterdUser
91
daemonUser GanetiNoded   = C.nodedUser
92
daemonUser GanetiRapi    = C.rapiUser
93
daemonUser GanetiConfd   = C.confdUser
94
daemonUser GanetiMond    = C.mondUser
95

    
96
-- | Returns the configured group for a daemon.
97
daemonGroup :: GanetiGroup -> String
98
daemonGroup (DaemonGroup GanetiMasterd) = C.masterdGroup
99
daemonGroup (DaemonGroup GanetiNoded)   = C.nodedGroup
100
daemonGroup (DaemonGroup GanetiRapi)    = C.rapiGroup
101
daemonGroup (DaemonGroup GanetiConfd)   = C.confdGroup
102
daemonGroup (DaemonGroup GanetiMond)    = C.mondGroup
103
daemonGroup (ExtraGroup  DaemonsGroup)  = C.daemonsGroup
104
daemonGroup (ExtraGroup  AdminGroup)    = C.adminGroup
105

    
106
-- | Returns the log file for a daemon.
107
daemonLogFile :: GanetiDaemon -> IO FilePath
108
daemonLogFile daemon = do
109
  logDir <- Path.logDir
110
  return $ logDir </> daemonLogBase daemon <.> "log"
111

    
112
-- | Returns the pid file name for a daemon.
113
daemonPidFile :: GanetiDaemon -> IO FilePath
114
daemonPidFile daemon = do
115
  runDir <- Path.runDir
116
  return $ runDir </> daemonName daemon <.> "pid"
117

    
118
-- | All groups list. A bit hacking, as we can't enforce it's complete
119
-- at compile time.
120
allGroups :: [GanetiGroup]
121
allGroups = map DaemonGroup [minBound..maxBound] ++
122
            map ExtraGroup  [minBound..maxBound]
123

    
124
ignoreDoesNotExistErrors :: IO a -> IO (Result a)
125
ignoreDoesNotExistErrors value = do
126
  result <- tryJust (\e -> if isDoesNotExistError e
127
                             then Just (show e)
128
                             else Nothing) value
129
  return $ eitherToResult result
130

    
131
-- | Computes the group/user maps.
132
getEnts :: IO (Result RuntimeEnts)
133
getEnts = do
134
  users <- mapM (\daemon -> do
135
                   entry <- ignoreDoesNotExistErrors .
136
                            getUserEntryForName .
137
                            daemonUser $ daemon
138
                   return (entry >>= \e -> return (daemon, userID e))
139
                ) [minBound..maxBound]
140
  groups <- mapM (\group -> do
141
                    entry <- ignoreDoesNotExistErrors .
142
                             getGroupEntryForName .
143
                             daemonGroup $ group
144
                    return (entry >>= \e -> return (group, groupID e))
145
                 ) allGroups
146
  return $ do -- 'Result' monad
147
    users'  <- sequence users
148
    groups' <- sequence groups
149
    let usermap = M.fromList users'
150
        groupmap = M.fromList groups'
151
    return (usermap, groupmap)
152

    
153

    
154
-- | Checks whether a daemon runs as the right user.
155
verifyDaemonUser :: GanetiDaemon -> RuntimeEnts -> IO ()
156
verifyDaemonUser daemon ents = do
157
  myuid <- getEffectiveUserID
158
  -- note: we use directly ! as lookup failues shouldn't happen, due
159
  -- to the above map construction
160
  checkUidMatch (daemonName daemon) ((M.!) (fst ents) daemon) myuid
161

    
162
-- | Check that two UIDs are matching or otherwise exit.
163
checkUidMatch :: String -> UserID -> UserID -> IO ()
164
checkUidMatch name expected actual =
165
  when (expected /= actual) $ do
166
    hPrintf stderr "%s started using wrong user ID (%d), \
167
                   \expected %d\n" name
168
              (fromIntegral actual::Int)
169
              (fromIntegral expected::Int) :: IO ()
170
    exitWith $ ExitFailure C.exitFailure