root / src / Ganeti / WConfd / Monad.hs @ 13d26b66
History | View | Annotate | Download (6 kB)
1 | 13d26b66 | Petr Pudlak | {-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleContexts #-} |
---|---|---|---|
2 | 9515a7d2 | Petr Pudlak | |
3 | 9515a7d2 | Petr Pudlak | {-| All RPC calls are run within this monad. |
4 | 9515a7d2 | Petr Pudlak | |
5 | 9515a7d2 | Petr Pudlak | It encapsulates: |
6 | 9515a7d2 | Petr Pudlak | |
7 | 9515a7d2 | Petr Pudlak | * IO operations, |
8 | 9515a7d2 | Petr Pudlak | * failures, |
9 | 9515a7d2 | Petr Pudlak | * working with the daemon state, |
10 | 9515a7d2 | Petr Pudlak | * working with the client state. |
11 | 9515a7d2 | Petr Pudlak | |
12 | 9515a7d2 | Petr Pudlak | Code that is specific either to the configuration or the lock management, should |
13 | 9515a7d2 | Petr Pudlak | go into their corresponding dedicated modules. |
14 | 9515a7d2 | Petr Pudlak | -} |
15 | 9515a7d2 | Petr Pudlak | |
16 | 9515a7d2 | Petr Pudlak | {- |
17 | 9515a7d2 | Petr Pudlak | |
18 | 9515a7d2 | Petr Pudlak | Copyright (C) 2014 Google Inc. |
19 | 9515a7d2 | Petr Pudlak | |
20 | 9515a7d2 | Petr Pudlak | This program is free software; you can redistribute it and/or modify |
21 | 9515a7d2 | Petr Pudlak | it under the terms of the GNU General Public License as published by |
22 | 9515a7d2 | Petr Pudlak | the Free Software Foundation; either version 2 of the License, or |
23 | 9515a7d2 | Petr Pudlak | (at your option) any later version. |
24 | 9515a7d2 | Petr Pudlak | |
25 | 9515a7d2 | Petr Pudlak | This program is distributed in the hope that it will be useful, but |
26 | 9515a7d2 | Petr Pudlak | WITHOUT ANY WARRANTY; without even the implied warranty of |
27 | 9515a7d2 | Petr Pudlak | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
28 | 9515a7d2 | Petr Pudlak | General Public License for more details. |
29 | 9515a7d2 | Petr Pudlak | |
30 | 9515a7d2 | Petr Pudlak | You should have received a copy of the GNU General Public License |
31 | 9515a7d2 | Petr Pudlak | along with this program; if not, write to the Free Software |
32 | 9515a7d2 | Petr Pudlak | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
33 | 9515a7d2 | Petr Pudlak | 02110-1301, USA. |
34 | 9515a7d2 | Petr Pudlak | |
35 | 9515a7d2 | Petr Pudlak | -} |
36 | 9515a7d2 | Petr Pudlak | |
37 | 9515a7d2 | Petr Pudlak | module Ganeti.WConfd.Monad |
38 | 9515a7d2 | Petr Pudlak | ( DaemonHandle |
39 | 9515a7d2 | Petr Pudlak | , dhConfigPath |
40 | 13d26b66 | Petr Pudlak | , dhSaveConfigWorker |
41 | 9515a7d2 | Petr Pudlak | , mkDaemonHandle |
42 | 9515a7d2 | Petr Pudlak | , ClientState(..) |
43 | 9515a7d2 | Petr Pudlak | , WConfdMonadInt |
44 | 9515a7d2 | Petr Pudlak | , runWConfdMonadInt |
45 | 9515a7d2 | Petr Pudlak | , WConfdMonad |
46 | 13d26b66 | Petr Pudlak | , daemonHandle |
47 | 9515a7d2 | Petr Pudlak | , modifyConfigState |
48 | 13d26b66 | Petr Pudlak | , readConfigState |
49 | a317d77a | Klaus Aehlig | , modifyLockAllocation |
50 | 9515a7d2 | Petr Pudlak | ) where |
51 | 9515a7d2 | Petr Pudlak | |
52 | 9515a7d2 | Petr Pudlak | import Control.Applicative |
53 | 9515a7d2 | Petr Pudlak | import Control.Monad |
54 | 9515a7d2 | Petr Pudlak | import Control.Monad.Base |
55 | 9515a7d2 | Petr Pudlak | import Control.Monad.Error |
56 | 9515a7d2 | Petr Pudlak | import Control.Monad.Trans.Control |
57 | 9515a7d2 | Petr Pudlak | import Control.Monad.Trans.RWS.Strict |
58 | 13d26b66 | Petr Pudlak | import Data.IORef.Lifted |
59 | 9515a7d2 | Petr Pudlak | |
60 | 9515a7d2 | Petr Pudlak | import Ganeti.BasicTypes |
61 | 9515a7d2 | Petr Pudlak | import Ganeti.Errors |
62 | a317d77a | Klaus Aehlig | import Ganeti.Locking.Locks |
63 | 9515a7d2 | Petr Pudlak | import Ganeti.Logging |
64 | 9515a7d2 | Petr Pudlak | import Ganeti.Types |
65 | 13d26b66 | Petr Pudlak | import Ganeti.Utils.AsyncWorker |
66 | 9515a7d2 | Petr Pudlak | import Ganeti.WConfd.ConfigState |
67 | 9515a7d2 | Petr Pudlak | |
68 | 9515a7d2 | Petr Pudlak | -- * Pure data types used in the monad |
69 | 9515a7d2 | Petr Pudlak | |
70 | 9515a7d2 | Petr Pudlak | -- | The state of the daemon, capturing both the configuration state and the |
71 | 9515a7d2 | Petr Pudlak | -- locking state. |
72 | 9515a7d2 | Petr Pudlak | data DaemonState = DaemonState |
73 | 9515a7d2 | Petr Pudlak | { dsConfigState :: ConfigState |
74 | a317d77a | Klaus Aehlig | , dsLockAllocation :: GanetiLockAllocation |
75 | 9515a7d2 | Petr Pudlak | } |
76 | 9515a7d2 | Petr Pudlak | |
77 | 9515a7d2 | Petr Pudlak | data DaemonHandle = DaemonHandle |
78 | 9515a7d2 | Petr Pudlak | { dhDaemonState :: IORef DaemonState -- ^ The current state of the daemon |
79 | 9515a7d2 | Petr Pudlak | , dhConfigPath :: FilePath -- ^ The configuration file path |
80 | 9515a7d2 | Petr Pudlak | -- all static information that doesn't change during the life-time of the |
81 | 9515a7d2 | Petr Pudlak | -- daemon should go here; |
82 | 9515a7d2 | Petr Pudlak | -- all IDs of threads that do asynchronous work should probably also go here |
83 | 13d26b66 | Petr Pudlak | , dhSaveConfigWorker :: AsyncWorker () |
84 | 9515a7d2 | Petr Pudlak | } |
85 | 9515a7d2 | Petr Pudlak | |
86 | 9515a7d2 | Petr Pudlak | mkDaemonHandle :: FilePath |
87 | 9515a7d2 | Petr Pudlak | -> ConfigState |
88 | a317d77a | Klaus Aehlig | -> GanetiLockAllocation |
89 | 13d26b66 | Petr Pudlak | -> (IO ConfigState -> ResultG (AsyncWorker ())) |
90 | 13d26b66 | Petr Pudlak | -- ^ A function that creates a worker that asynchronously |
91 | 13d26b66 | Petr Pudlak | -- saves the configuration to the master file. |
92 | 13d26b66 | Petr Pudlak | -> ResultG DaemonHandle |
93 | 13d26b66 | Petr Pudlak | mkDaemonHandle cpath cstat lstat saveWorkerFn = do |
94 | 13d26b66 | Petr Pudlak | ds <- newIORef $ DaemonState cstat lstat |
95 | 13d26b66 | Petr Pudlak | saveWorker <- saveWorkerFn $ dsConfigState `liftM` readIORef ds |
96 | 13d26b66 | Petr Pudlak | return $ DaemonHandle ds cpath saveWorker |
97 | 9515a7d2 | Petr Pudlak | |
98 | 9515a7d2 | Petr Pudlak | data ClientState = ClientState |
99 | 9515a7d2 | Petr Pudlak | { clLiveFilePath :: FilePath |
100 | 9515a7d2 | Petr Pudlak | , clJobId :: JobId |
101 | 9515a7d2 | Petr Pudlak | } |
102 | 9515a7d2 | Petr Pudlak | |
103 | 9515a7d2 | Petr Pudlak | -- * The monad and its instances |
104 | 9515a7d2 | Petr Pudlak | |
105 | 9515a7d2 | Petr Pudlak | -- | A type alias for easier referring to the actual content of the monad |
106 | 9515a7d2 | Petr Pudlak | -- when implementing its instances. |
107 | 9515a7d2 | Petr Pudlak | type WConfdMonadIntType = RWST DaemonHandle () (Maybe ClientState) IO |
108 | 9515a7d2 | Petr Pudlak | |
109 | 9515a7d2 | Petr Pudlak | -- | The internal part of the monad without error handling. |
110 | 9515a7d2 | Petr Pudlak | newtype WConfdMonadInt a = WConfdMonadInt |
111 | 9515a7d2 | Petr Pudlak | { getWConfdMonadInt :: WConfdMonadIntType a } |
112 | 9515a7d2 | Petr Pudlak | |
113 | 9515a7d2 | Petr Pudlak | instance Functor WConfdMonadInt where |
114 | 9515a7d2 | Petr Pudlak | fmap f = WConfdMonadInt . fmap f . getWConfdMonadInt |
115 | 9515a7d2 | Petr Pudlak | |
116 | 9515a7d2 | Petr Pudlak | instance Applicative WConfdMonadInt where |
117 | 9515a7d2 | Petr Pudlak | pure = WConfdMonadInt . pure |
118 | 9515a7d2 | Petr Pudlak | WConfdMonadInt f <*> WConfdMonadInt k = WConfdMonadInt $ f <*> k |
119 | 9515a7d2 | Petr Pudlak | |
120 | 9515a7d2 | Petr Pudlak | instance Monad WConfdMonadInt where |
121 | 9515a7d2 | Petr Pudlak | return = WConfdMonadInt . return |
122 | 9515a7d2 | Petr Pudlak | (WConfdMonadInt k) >>= f = WConfdMonadInt $ k >>= getWConfdMonadInt . f |
123 | 9515a7d2 | Petr Pudlak | |
124 | 9515a7d2 | Petr Pudlak | instance MonadIO WConfdMonadInt where |
125 | 9515a7d2 | Petr Pudlak | liftIO = WConfdMonadInt . liftIO |
126 | 9515a7d2 | Petr Pudlak | |
127 | 9515a7d2 | Petr Pudlak | instance MonadBase IO WConfdMonadInt where |
128 | 9515a7d2 | Petr Pudlak | liftBase = WConfdMonadInt . liftBase |
129 | 9515a7d2 | Petr Pudlak | |
130 | 9515a7d2 | Petr Pudlak | instance MonadBaseControl IO WConfdMonadInt where |
131 | 9515a7d2 | Petr Pudlak | newtype StM WConfdMonadInt b = StMWConfdMonadInt |
132 | 9515a7d2 | Petr Pudlak | { runStMWConfdMonadInt :: StM WConfdMonadIntType b } |
133 | 9515a7d2 | Petr Pudlak | liftBaseWith f = WConfdMonadInt . liftBaseWith |
134 | 9515a7d2 | Petr Pudlak | $ \r -> f (liftM StMWConfdMonadInt . r . getWConfdMonadInt) |
135 | 9515a7d2 | Petr Pudlak | restoreM = WConfdMonadInt . restoreM . runStMWConfdMonadInt |
136 | 9515a7d2 | Petr Pudlak | |
137 | 9515a7d2 | Petr Pudlak | instance MonadLog WConfdMonadInt where |
138 | 9515a7d2 | Petr Pudlak | logAt p = WConfdMonadInt . logAt p |
139 | 9515a7d2 | Petr Pudlak | |
140 | 9515a7d2 | Petr Pudlak | -- | Runs the internal part of the WConfdMonad monad on a given daemon |
141 | 9515a7d2 | Petr Pudlak | -- handle. |
142 | 9515a7d2 | Petr Pudlak | runWConfdMonadInt :: WConfdMonadInt a -> DaemonHandle -> IO a |
143 | 9515a7d2 | Petr Pudlak | runWConfdMonadInt (WConfdMonadInt k) dhandle = |
144 | 9515a7d2 | Petr Pudlak | liftM fst $ evalRWST k dhandle Nothing |
145 | 9515a7d2 | Petr Pudlak | |
146 | 9515a7d2 | Petr Pudlak | -- | The complete monad with error handling. |
147 | 9515a7d2 | Petr Pudlak | type WConfdMonad = ResultT GanetiException WConfdMonadInt |
148 | 9515a7d2 | Petr Pudlak | |
149 | 9515a7d2 | Petr Pudlak | -- * Basic functions in the monad |
150 | 9515a7d2 | Petr Pudlak | |
151 | 13d26b66 | Petr Pudlak | -- | Returns the daemon handle. |
152 | 13d26b66 | Petr Pudlak | daemonHandle :: WConfdMonad DaemonHandle |
153 | 13d26b66 | Petr Pudlak | daemonHandle = lift . WConfdMonadInt $ ask |
154 | 13d26b66 | Petr Pudlak | |
155 | 13d26b66 | Petr Pudlak | -- | Returns the current configuration, given a handle |
156 | 13d26b66 | Petr Pudlak | readConfigState :: WConfdMonad ConfigState |
157 | 13d26b66 | Petr Pudlak | readConfigState = liftM dsConfigState . readIORef . dhDaemonState |
158 | 13d26b66 | Petr Pudlak | =<< daemonHandle |
159 | 13d26b66 | Petr Pudlak | |
160 | 9515a7d2 | Petr Pudlak | -- | Atomically modifies the configuration state in the WConfdMonad. |
161 | 9515a7d2 | Petr Pudlak | modifyConfigState :: (ConfigState -> (ConfigState, a)) -> WConfdMonad a |
162 | 9515a7d2 | Petr Pudlak | modifyConfigState f = do |
163 | 13d26b66 | Petr Pudlak | dh <- daemonHandle |
164 | 9515a7d2 | Petr Pudlak | -- TODO: Use lenses to modify the daemons state here |
165 | 9515a7d2 | Petr Pudlak | let mf ds = let (cs', r) = f (dsConfigState ds) |
166 | 9515a7d2 | Petr Pudlak | in (ds { dsConfigState = cs' }, r) |
167 | 13d26b66 | Petr Pudlak | r <- atomicModifyIORef (dhDaemonState dh) mf |
168 | 13d26b66 | Petr Pudlak | -- trigger the config. saving worker and wait for it |
169 | 13d26b66 | Petr Pudlak | logDebug "Triggering config write" |
170 | 13d26b66 | Petr Pudlak | liftBase . triggerAndWait . dhSaveConfigWorker $ dh |
171 | 13d26b66 | Petr Pudlak | logDebug "Config write finished" |
172 | 13d26b66 | Petr Pudlak | -- trigger the config. distribution worker asynchronously |
173 | 13d26b66 | Petr Pudlak | -- TODO |
174 | 13d26b66 | Petr Pudlak | return r |
175 | a317d77a | Klaus Aehlig | |
176 | a317d77a | Klaus Aehlig | -- | Atomically modifies the lock allocation state in WConfdMonad. |
177 | a317d77a | Klaus Aehlig | modifyLockAllocation :: (GanetiLockAllocation -> (GanetiLockAllocation, a)) |
178 | a317d77a | Klaus Aehlig | -> WConfdMonad a |
179 | a317d77a | Klaus Aehlig | modifyLockAllocation f = do |
180 | a317d77a | Klaus Aehlig | dh <- lift . WConfdMonadInt $ ask |
181 | a317d77a | Klaus Aehlig | let mf ds = let (la', r) = f (dsLockAllocation ds) |
182 | a317d77a | Klaus Aehlig | in (ds { dsLockAllocation = la' }, r) |
183 | 13d26b66 | Petr Pudlak | atomicModifyIORef (dhDaemonState dh) mf |
184 | 13d26b66 | Petr Pudlak | -- TODO: Trigger the async. lock saving worker |