Revision 94c7e022
b/src/Ganeti/WConfd/ConfigWriter.hs | ||
---|---|---|
2 | 2 |
|
3 | 3 |
{-| Implementation of functions specific to configuration management. |
4 | 4 |
|
5 |
TODO: distribute the configuration to master candidates (and not the master) |
|
6 | 5 |
TODO: Detect changes in SSConf and distribute only if it changes |
7 | 6 |
TODO: distribute ssconf configuration, if it has changed |
8 | 7 |
|
... | ... | |
31 | 30 |
|
32 | 31 |
module Ganeti.WConfd.ConfigWriter |
33 | 32 |
( loadConfigFromFile |
34 |
, saveConfigAsyncTask |
|
35 | 33 |
, readConfig |
36 | 34 |
, writeConfig |
35 |
, saveConfigAsyncTask |
|
36 |
, distMCsAsyncTask |
|
37 | 37 |
) where |
38 | 38 |
|
39 | 39 |
import Control.Applicative |
... | ... | |
45 | 45 |
import Ganeti.BasicTypes |
46 | 46 |
import Ganeti.Errors |
47 | 47 |
import Ganeti.Config |
48 |
import Ganeti.Logging.Lifted
|
|
48 |
import Ganeti.Logging |
|
49 | 49 |
import Ganeti.Objects |
50 |
import Ganeti.Rpc |
|
50 | 51 |
import Ganeti.Runtime |
51 | 52 |
import Ganeti.Utils |
52 | 53 |
import Ganeti.Utils.Atomic |
... | ... | |
91 | 92 |
|
92 | 93 |
-- * Asynchronous tasks |
93 | 94 |
|
95 |
-- | Runs the given action on success, or logs an error on failure. |
|
96 |
finishOrLog :: (Show e, MonadLog m) |
|
97 |
=> Priority |
|
98 |
-> String |
|
99 |
-> (a -> m ()) |
|
100 |
-> GenericResult e a |
|
101 |
-> m () |
|
102 |
finishOrLog logPrio logPrefix = |
|
103 |
genericResult (logAt logPrio . (++) (logPrefix ++ ": ") . show) |
|
104 |
|
|
105 |
-- | Creates a stateless asynchronous task that handles errors in its actions. |
|
106 |
mkStatelessAsyncTask :: (MonadBaseControl IO m, MonadLog m, Show e) |
|
107 |
=> Priority |
|
108 |
-> String |
|
109 |
-> ResultT e m () |
|
110 |
-> m (AsyncWorker ()) |
|
111 |
mkStatelessAsyncTask logPrio logPrefix action = |
|
112 |
mkAsyncWorker $ runResultT action >>= finishOrLog logPrio logPrefix return |
|
113 |
|
|
94 | 114 |
-- | Creates an asynchronous task that handles errors in its actions. |
95 | 115 |
-- If an error occurs, it's logged and the internal state remains unchanged. |
96 |
mkStatefulAsyncTask :: (MonadBaseControl IO m, Show e) |
|
116 |
mkStatefulAsyncTask :: (MonadBaseControl IO m, MonadLog m, Show e)
|
|
97 | 117 |
=> Priority |
98 | 118 |
-> String |
99 |
-> (s -> ResultT e m s) |
|
100 | 119 |
-> s |
120 |
-> (s -> ResultT e m s) |
|
101 | 121 |
-> m (AsyncWorker ()) |
102 |
mkStatefulAsyncTask logPrio logPrefix action start =
|
|
122 |
mkStatefulAsyncTask logPrio logPrefix start action =
|
|
103 | 123 |
flip S.evalStateT start . mkAsyncWorker $ |
104 | 124 |
S.get >>= lift . runResultT . action |
105 |
>>= genericResult |
|
106 |
(logAt logPrio . (++) (logPrefix ++ ": ") . show) |
|
107 |
S.put -- on success save the state |
|
125 |
>>= finishOrLog logPrio logPrefix S.put -- put on success |
|
108 | 126 |
|
109 | 127 |
-- | Construct an asynchronous worker whose action is to save the |
110 | 128 |
-- configuration to the master file. |
... | ... | |
116 | 134 |
-> IO ConfigState -- ^ An action to read the current config |
117 | 135 |
-> ResultG (AsyncWorker ()) |
118 | 136 |
saveConfigAsyncTask fpath fstat cdRef = |
119 |
let action oldstat = do |
|
120 |
cd <- liftBase (csConfigData `liftM` cdRef) |
|
121 |
writeConfigToFile cd fpath oldstat |
|
122 |
in lift $ mkStatefulAsyncTask |
|
123 |
EMERGENCY "Can't write the master configuration file" |
|
124 |
action fstat |
|
137 |
lift . mkStatefulAsyncTask |
|
138 |
EMERGENCY "Can't write the master configuration file" fstat |
|
139 |
$ \oldstat -> do |
|
140 |
cd <- liftBase (csConfigData `liftM` cdRef) |
|
141 |
writeConfigToFile cd fpath oldstat |
|
142 |
|
|
143 |
-- | Performs a RPC call on the given list of nodes and logs any failures. |
|
144 |
-- If any of the calls fails, fail the computation with 'failError'. |
|
145 |
execRpcCallAndLog :: (Rpc a b) => [Node] -> a -> ResultG () |
|
146 |
execRpcCallAndLog nodes req = do |
|
147 |
rs <- liftIO $ executeRpcCall nodes req |
|
148 |
es <- logRpcErrors rs |
|
149 |
unless (null es) $ failError "At least one of the RPC calls failed" |
|
150 |
|
|
151 |
-- | Construct an asynchronous worker whose action is to distribute the |
|
152 |
-- configuration to master candidates. |
|
153 |
distMCsAsyncTask :: RuntimeEnts |
|
154 |
-> FilePath -- ^ Path to the config file |
|
155 |
-> IO ConfigState -- ^ An action to read the current config |
|
156 |
-> ResultG (AsyncWorker ()) |
|
157 |
distMCsAsyncTask ents cpath cdRef = |
|
158 |
lift . mkStatelessAsyncTask ERROR "Can't distribute the configuration\ |
|
159 |
\ to master candidates" |
|
160 |
$ do |
|
161 |
cd <- liftBase (csConfigData <$> cdRef) :: ResultG ConfigData |
|
162 |
fupload <- prepareRpcCallUploadFile ents cpath |
|
163 |
execRpcCallAndLog (getMasterCandidates cd) fupload |
Also available in: Unified diff