Revision 179c0828
b/htools/Ganeti/HTools/Cluster.hs | ||
---|---|---|
139 | 139 |
data Table = Table Node.List Instance.List Score [Placement] |
140 | 140 |
deriving (Show, Read) |
141 | 141 |
|
142 |
-- | Cluster statistics data type. |
|
142 | 143 |
data CStats = CStats { csFmem :: Integer -- ^ Cluster free mem |
143 | 144 |
, csFdsk :: Integer -- ^ Cluster free disk |
144 | 145 |
, csAmem :: Integer -- ^ Cluster allocatable mem |
... | ... | |
278 | 279 |
, (2, "pri_tags_score") |
279 | 280 |
] |
280 | 281 |
|
282 |
-- | Holds the weights used by 'compCVNodes' for each metric. |
|
281 | 283 |
detailedCVWeights :: [Double] |
282 | 284 |
detailedCVWeights = map fst detailedCVInfo |
283 | 285 |
|
... | ... | |
333 | 335 |
compCV :: Node.List -> Double |
334 | 336 |
compCV = compCVNodes . Container.elems |
335 | 337 |
|
336 |
|
|
337 | 338 |
-- | Compute online nodes from a 'Node.List'. |
338 | 339 |
getOnline :: Node.List -> [Node.Node] |
339 | 340 |
getOnline = filter (not . Node.offline) . Container.elems |
... | ... | |
1314 | 1315 |
in intercalate ", " formatted |
1315 | 1316 |
|
1316 | 1317 |
-- | Convert a placement into a list of OpCodes (basically a job). |
1317 |
iMoveToJob :: Node.List -> Instance.List |
|
1318 |
-> Idx -> IMove -> [OpCodes.OpCode] |
|
1318 |
iMoveToJob :: Node.List -- ^ The node list; only used for node |
|
1319 |
-- names, so any version is good |
|
1320 |
-- (before or after the operation) |
|
1321 |
-> Instance.List -- ^ The instance list; also used for |
|
1322 |
-- names only |
|
1323 |
-> Idx -- ^ The index of the instance being |
|
1324 |
-- moved |
|
1325 |
-> IMove -- ^ The actual move to be described |
|
1326 |
-> [OpCodes.OpCode] -- ^ The list of opcodes equivalent to |
|
1327 |
-- the given move |
|
1319 | 1328 |
iMoveToJob nl il idx move = |
1320 | 1329 |
let inst = Container.find idx il |
1321 | 1330 |
iname = Instance.name inst |
b/htools/Ganeti/HTools/Compat.hs | ||
---|---|---|
34 | 34 |
|
35 | 35 |
import qualified Control.Parallel.Strategies |
36 | 36 |
|
37 |
-- | Wrapper over the function exported from |
|
38 |
-- "Control.Parallel.Strategies". |
|
39 |
-- |
|
40 |
-- This wraps either the old or the new name of the function, |
|
41 |
-- depending on the detected library version. |
|
37 | 42 |
rwhnf :: Control.Parallel.Strategies.Strategy a |
38 | 43 |
#ifdef PARALLEL3 |
39 | 44 |
rwhnf = Control.Parallel.Strategies.rseq |
b/htools/Ganeti/HTools/Container.hs | ||
---|---|---|
59 | 59 |
|
60 | 60 |
import qualified Ganeti.HTools.Types as T |
61 | 61 |
|
62 |
-- | Our key type. |
|
63 |
|
|
62 | 64 |
type Key = IntMap.Key |
65 |
|
|
66 |
-- | Our container type. |
|
63 | 67 |
type Container = IntMap.IntMap |
64 | 68 |
|
65 | 69 |
-- | Locate a key in the map (must exist). |
b/htools/Ganeti/HTools/ExtLoader.hs | ||
---|---|---|
55 | 55 |
wrapIO :: IO (Result a) -> IO (Result a) |
56 | 56 |
wrapIO = flip catch (return . Bad . show) |
57 | 57 |
|
58 |
-- | Parses a user-supplied utilisation string. |
|
58 | 59 |
parseUtilisation :: String -> Result (String, DynUtil) |
59 | 60 |
parseUtilisation line = |
60 | 61 |
case sepSplit ' ' line of |
b/htools/Ganeti/HTools/Group.hs | ||
---|---|---|
73 | 73 |
, idx = -1 |
74 | 74 |
} |
75 | 75 |
|
76 |
-- | Sets the group index. |
|
77 |
-- |
|
76 | 78 |
-- This is used only during the building of the data structures. |
77 | 79 |
setIdx :: Group -> T.Gdx -> Group |
78 | 80 |
setIdx t i = t {idx = i} |
b/htools/Ganeti/HTools/IAlloc.hs | ||
---|---|---|
237 | 237 |
" were moved successfully" |
238 | 238 |
in Ok (info, showJSON (mes, fes, Cluster.esOpCodes es), fin_nl, fin_il) |
239 | 239 |
|
240 |
-- | Process a request and return new node lists |
|
240 |
-- | Process a request and return new node lists.
|
|
241 | 241 |
processRequest :: Request -> Result IAllocResult |
242 | 242 |
processRequest request = |
243 | 243 |
let Request rqtype (ClusterData gl nl il _) = request |
... | ... | |
251 | 251 |
Cluster.tryNodeEvac gl nl il mode xi >>= |
252 | 252 |
formatNodeEvac gl nl il |
253 | 253 |
|
254 |
-- | Reads the request from the data file(s) |
|
254 |
-- | Reads the request from the data file(s).
|
|
255 | 255 |
readRequest :: Options -> [String] -> IO Request |
256 | 256 |
readRequest opts args = do |
257 | 257 |
when (null args) $ do |
b/htools/Ganeti/HTools/Instance.hs | ||
---|---|---|
159 | 159 |
-> Instance -- ^ the modified instance |
160 | 160 |
setBoth t p s = t { pNode = p, sNode = s } |
161 | 161 |
|
162 |
-- | Sets the movable flag on an instance. |
|
162 | 163 |
setMovable :: Instance -- ^ The original instance |
163 | 164 |
-> Bool -- ^ New movable flag |
164 | 165 |
-> Instance -- ^ The modified instance |
... | ... | |
186 | 187 |
specOf Instance { mem = m, dsk = d, vcpus = c } = |
187 | 188 |
T.RSpec { T.rspecCpu = c, T.rspecMem = m, T.rspecDsk = d } |
188 | 189 |
|
189 |
-- | Computed the number of nodes for a given disk template |
|
190 |
-- | Computed the number of nodes for a given disk template.
|
|
190 | 191 |
requiredNodes :: T.DiskTemplate -> Int |
191 | 192 |
requiredNodes T.DTDrbd8 = 2 |
192 | 193 |
requiredNodes _ = 1 |
b/htools/Ganeti/HTools/Luxi.hs | ||
---|---|---|
88 | 88 |
queryGroupsMsg = |
89 | 89 |
L.QueryGroups [] ["uuid", "name", "alloc_policy"] False |
90 | 90 |
|
91 |
-- | Wraper over callMethod doing node query.
|
|
91 |
-- | Wraper over 'callMethod' doing node query.
|
|
92 | 92 |
queryNodes :: L.Client -> IO (Result JSValue) |
93 | 93 |
queryNodes = L.callMethod queryNodesMsg |
94 | 94 |
|
95 |
-- | Wraper over callMethod doing instance query.
|
|
95 |
-- | Wraper over 'callMethod' doing instance query.
|
|
96 | 96 |
queryInstances :: L.Client -> IO (Result JSValue) |
97 | 97 |
queryInstances = L.callMethod queryInstancesMsg |
98 | 98 |
|
99 |
-- | Wrapper over 'callMethod' doing cluster information query. |
|
99 | 100 |
queryClusterInfo :: L.Client -> IO (Result JSValue) |
100 | 101 |
queryClusterInfo = L.callMethod queryClusterInfoMsg |
101 | 102 |
|
... | ... | |
167 | 168 |
|
168 | 169 |
parseNode _ v = fail ("Invalid node query result: " ++ show v) |
169 | 170 |
|
171 |
-- | Parses the cluster tags. |
|
170 | 172 |
getClusterTags :: JSValue -> Result [String] |
171 | 173 |
getClusterTags v = do |
172 | 174 |
let errmsg = "Parsing cluster info" |
173 | 175 |
obj <- annotateResult errmsg $ asJSObject v |
174 | 176 |
tryFromObj errmsg (fromJSObject obj) "tags" |
175 | 177 |
|
178 |
-- | Parses the cluster groups. |
|
176 | 179 |
getGroups :: JSValue -> Result [(String, Group.Group)] |
177 | 180 |
getGroups arr = toArray arr >>= mapM parseGroup |
178 | 181 |
|
182 |
-- | Parses a given group information. |
|
179 | 183 |
parseGroup :: JSValue -> Result (String, Group.Group) |
180 | 184 |
parseGroup (JSArray [ uuid, name, apol ]) = do |
181 | 185 |
xname <- annotateResult "Parsing new group" (fromJVal name) |
b/htools/Ganeti/HTools/Program/Hail.hs | ||
---|---|---|
36 | 36 |
import Ganeti.HTools.Loader (Request(..), ClusterData(..)) |
37 | 37 |
import Ganeti.HTools.ExtLoader (maybeSaveData) |
38 | 38 |
|
39 |
-- | Options list and functions |
|
39 |
-- | Options list and functions.
|
|
40 | 40 |
options :: [OptType] |
41 | 41 |
options = |
42 | 42 |
[ oPrintNodes |
b/htools/Ganeti/HTools/Program/Hbal.hs | ||
---|---|---|
54 | 54 |
import qualified Ganeti.Luxi as L |
55 | 55 |
import Ganeti.Jobs |
56 | 56 |
|
57 |
-- | Options list and functions |
|
57 |
-- | Options list and functions.
|
|
58 | 58 |
options :: [OptType] |
59 | 59 |
options = |
60 | 60 |
[ oPrintNodes |
... | ... | |
133 | 133 |
mg_limit min_gain evac_mode |
134 | 134 |
Nothing -> return (ini_tbl, cmd_strs) |
135 | 135 |
|
136 |
-- | Formats the solution for the oneline display |
|
136 |
-- | Formats the solution for the oneline display.
|
|
137 | 137 |
formatOneline :: Double -> Int -> Double -> String |
138 | 138 |
formatOneline ini_cv plc_len fin_cv = |
139 | 139 |
printf "%.8f %d %.8f %8.3f" ini_cv plc_len fin_cv |
140 | 140 |
(if fin_cv == 0 then 1 else ini_cv / fin_cv) |
141 | 141 |
|
142 | 142 |
-- | Polls a set of jobs at a fixed interval until all are finished |
143 |
-- one way or another |
|
143 |
-- one way or another.
|
|
144 | 144 |
waitForJobs :: L.Client -> [String] -> IO (Result [JobStatus]) |
145 | 145 |
waitForJobs client jids = do |
146 | 146 |
sts <- L.queryJobsStatus client jids |
... | ... | |
153 | 153 |
waitForJobs client jids |
154 | 154 |
else return $ Ok s |
155 | 155 |
|
156 |
-- | Check that a set of job statuses is all success |
|
156 |
-- | Check that a set of job statuses is all success.
|
|
157 | 157 |
checkJobsStatus :: [JobStatus] -> Bool |
158 | 158 |
checkJobsStatus = all (== JOB_STATUS_SUCCESS) |
159 | 159 |
|
160 |
-- | Wrapper over execJobSet checking for early termination |
|
160 |
-- | Wrapper over execJobSet checking for early termination.
|
|
161 | 161 |
execWrapper :: String -> Node.List |
162 | 162 |
-> Instance.List -> IORef Int -> [JobSet] -> IO Bool |
163 | 163 |
execWrapper _ _ _ _ [] = return True |
... | ... | |
170 | 170 |
return False |
171 | 171 |
else execJobSet master nl il cref alljss) |
172 | 172 |
|
173 |
-- | Execute an entire jobset |
|
173 |
-- | Execute an entire jobset.
|
|
174 | 174 |
execJobSet :: String -> Node.List |
175 | 175 |
-> Instance.List -> IORef Int -> [JobSet] -> IO Bool |
176 | 176 |
execJobSet _ _ _ _ [] = return True |
... | ... | |
201 | 201 |
hPutStrLn stderr "Aborting." |
202 | 202 |
return False) |
203 | 203 |
|
204 |
-- | Signal handler for graceful termination |
|
204 |
-- | Signal handler for graceful termination.
|
|
205 | 205 |
hangleSigInt :: IORef Int -> IO () |
206 | 206 |
hangleSigInt cref = do |
207 | 207 |
writeIORef cref 1 |
208 | 208 |
putStrLn ("Cancel request registered, will exit at" ++ |
209 | 209 |
" the end of the current job set...") |
210 | 210 |
|
211 |
-- | Signal handler for immediate termination |
|
211 |
-- | Signal handler for immediate termination.
|
|
212 | 212 |
hangleSigTerm :: IORef Int -> IO () |
213 | 213 |
hangleSigTerm cref = do |
214 | 214 |
-- update the cref to 2, just for consistency |
... | ... | |
216 | 216 |
putStrLn "Double cancel request, exiting now..." |
217 | 217 |
exitImmediately $ ExitFailure 2 |
218 | 218 |
|
219 |
-- | Runs a job set with handling of signals. |
|
219 | 220 |
runJobSet :: String -> Node.List -> Instance.List -> [JobSet] -> IO Bool |
220 | 221 |
runJobSet master fin_nl il cmd_jobs = do |
221 | 222 |
cref <- newIORef 0 |
b/htools/Ganeti/HTools/Program/Hscan.hs | ||
---|---|---|
46 | 46 |
import Ganeti.HTools.CLI |
47 | 47 |
import Ganeti.HTools.Types |
48 | 48 |
|
49 |
-- | Options list and functions |
|
49 |
-- | Options list and functions.
|
|
50 | 50 |
options :: [OptType] |
51 | 51 |
options = |
52 | 52 |
[ oPrintNodes |
... | ... | |
58 | 58 |
, oShowHelp |
59 | 59 |
] |
60 | 60 |
|
61 |
-- | Return a one-line summary of cluster state |
|
61 |
-- | Return a one-line summary of cluster state.
|
|
62 | 62 |
printCluster :: Node.List -> Instance.List |
63 | 63 |
-> String |
64 | 64 |
printCluster nl il = |
... | ... | |
79 | 79 |
ccv |
80 | 80 |
|
81 | 81 |
|
82 |
-- | Replace slashes with underscore for saving to filesystem |
|
82 |
-- | Replace slashes with underscore for saving to filesystem.
|
|
83 | 83 |
fixSlash :: String -> String |
84 | 84 |
fixSlash = map (\x -> if x == '/' then '_' else x) |
85 | 85 |
|
... | ... | |
91 | 91 |
let (_, fix_nl) = checkData nl il |
92 | 92 |
return cdata { cdNodes = fix_nl } |
93 | 93 |
|
94 |
-- | Writes cluster data out |
|
94 |
-- | Writes cluster data out.
|
|
95 | 95 |
writeData :: Int |
96 | 96 |
-> String |
97 | 97 |
-> Options |
... | ... | |
108 | 108 |
name err >> return False |
109 | 109 |
Ok processed -> writeDataInner nlen name opts cdata processed |
110 | 110 |
|
111 |
-- | Inner function for writing cluster data to disk. |
|
111 | 112 |
writeDataInner :: Int |
112 | 113 |
-> String |
113 | 114 |
-> Options |
b/htools/Ganeti/HTools/Program/Hspace.hs | ||
---|---|---|
48 | 48 |
import Ganeti.HTools.ExtLoader |
49 | 49 |
import Ganeti.HTools.Loader |
50 | 50 |
|
51 |
-- | Options list and functions |
|
51 |
-- | Options list and functions.
|
|
52 | 52 |
options :: [OptType] |
53 | 53 |
options = |
54 | 54 |
[ oPrintNodes |
... | ... | |
110 | 110 |
cpuEff :: Cluster.CStats -> Double |
111 | 111 |
cpuEff = effFn Cluster.csIcpu (fromIntegral . Cluster.csVcpu) |
112 | 112 |
|
113 |
-- | Holds data for converting a 'Cluster.CStats' structure into |
|
114 |
-- detailed statictics. |
|
113 | 115 |
statsData :: [(String, Cluster.CStats -> String)] |
114 | 116 |
statsData = [ ("SCORE", printf "%.8f" . Cluster.csScore) |
115 | 117 |
, ("INST_CNT", printf "%d" . Cluster.csNinst) |
... | ... | |
133 | 135 |
, ("MNODE_DSK_AVAIL", printf "%d" . Cluster.csMdsk) |
134 | 136 |
] |
135 | 137 |
|
138 |
-- | List holding 'RSpec' formatting information. |
|
136 | 139 |
specData :: [(String, RSpec -> String)] |
137 | 140 |
specData = [ ("MEM", printf "%d" . rspecMem) |
138 | 141 |
, ("DSK", printf "%d" . rspecDsk) |
139 | 142 |
, ("CPU", printf "%d" . rspecCpu) |
140 | 143 |
] |
141 | 144 |
|
145 |
-- | List holding 'Cluster.CStats' formatting information. |
|
142 | 146 |
clusterData :: [(String, Cluster.CStats -> String)] |
143 | 147 |
clusterData = [ ("MEM", printf "%.0f" . Cluster.csTmem) |
144 | 148 |
, ("DSK", printf "%.0f" . Cluster.csTdsk) |
... | ... | |
146 | 150 |
, ("VCPU", printf "%d" . Cluster.csVcpu) |
147 | 151 |
] |
148 | 152 |
|
149 |
-- | Function to print stats for a given phase |
|
153 |
-- | Function to print stats for a given phase.
|
|
150 | 154 |
printStats :: Phase -> Cluster.CStats -> [(String, String)] |
151 | 155 |
printStats ph cs = |
152 | 156 |
map (\(s, fn) -> (printf "%s_%s" kind s, fn cs)) statsData |
... | ... | |
211 | 215 |
map (\(spec, cnt) -> printf "%d,%d,%d=%d" (rspecMem spec) |
212 | 216 |
(rspecDsk spec) (rspecCpu spec) cnt) |
213 | 217 |
|
218 |
-- | Formats \"key-metrics\" values. |
|
214 | 219 |
formatRSpec :: Double -> String -> RSpec -> [(String, String)] |
215 | 220 |
formatRSpec m_cpu s r = |
216 | 221 |
[ ("KM_" ++ s ++ "_CPU", show $ rspecCpu r) |
... | ... | |
219 | 224 |
, ("KM_" ++ s ++ "_DSK", show $ rspecDsk r) |
220 | 225 |
] |
221 | 226 |
|
227 |
-- | Shows allocations stats. |
|
222 | 228 |
printAllocationStats :: Double -> Node.List -> Node.List -> IO () |
223 | 229 |
printAllocationStats m_cpu ini_nl fin_nl = do |
224 | 230 |
let ini_stats = Cluster.totalResources ini_nl |
... | ... | |
228 | 234 |
printKeys $ formatRSpec m_cpu "POOL"ralo |
229 | 235 |
printKeys $ formatRSpec m_cpu "UNAV" runa |
230 | 236 |
|
231 |
-- | Ensure a value is quoted if needed |
|
237 |
-- | Ensure a value is quoted if needed.
|
|
232 | 238 |
ensureQuoted :: String -> String |
233 | 239 |
ensureQuoted v = if not (all (\c -> isAlphaNum c || c == '.') v) |
234 | 240 |
then '\'':v ++ "'" |
235 | 241 |
else v |
236 | 242 |
|
237 |
-- | Format a list of key\/values as a shell fragment |
|
243 |
-- | Format a list of key\/values as a shell fragment.
|
|
238 | 244 |
printKeys :: [(String, String)] -> IO () |
239 | 245 |
printKeys = mapM_ (\(k, v) -> |
240 | 246 |
printf "HTS_%s=%s\n" (map toUpper k) (ensureQuoted v)) |
241 | 247 |
|
248 |
-- | Converts instance data to a list of strings. |
|
242 | 249 |
printInstance :: Node.List -> Instance.Instance -> [String] |
243 | 250 |
printInstance nl i = [ Instance.name i |
244 | 251 |
, Container.nameOf nl $ Instance.pNode i |
... | ... | |
250 | 257 |
, show (Instance.vcpus i) |
251 | 258 |
] |
252 | 259 |
|
253 |
-- | Optionally print the allocation map |
|
260 |
-- | Optionally print the allocation map.
|
|
254 | 261 |
printAllocationMap :: Int -> String |
255 | 262 |
-> Node.List -> [Instance.Instance] -> IO () |
256 | 263 |
printAllocationMap verbose msg nl ixes = |
... | ... | |
314 | 321 |
printClusterScores ini_nl fin_nl |
315 | 322 |
printClusterEff (Cluster.totalResources fin_nl) |
316 | 323 |
|
324 |
-- | Displays the initial/final cluster scores. |
|
317 | 325 |
printClusterScores :: Node.List -> Node.List -> IO () |
318 | 326 |
printClusterScores ini_nl fin_nl = do |
319 | 327 |
printf " - initial cluster score: %.8f\n" $ Cluster.compCV ini_nl::IO () |
320 | 328 |
printf " - final cluster score: %.8f\n" $ Cluster.compCV fin_nl |
321 | 329 |
|
330 |
-- | Displays the cluster efficiency. |
|
322 | 331 |
printClusterEff :: Cluster.CStats -> IO () |
323 | 332 |
printClusterEff cs = |
324 | 333 |
mapM_ (\(s, fn) -> |
b/htools/Ganeti/HTools/Types.hs | ||
---|---|---|
180 | 180 |
| FailoverAndReplace Ndx -- ^ Failover, replace secondary (f, r:ns) |
181 | 181 |
deriving (Show, Read) |
182 | 182 |
|
183 |
-- | Instance disk template type |
|
183 |
-- | Instance disk template type.
|
|
184 | 184 |
data DiskTemplate = DTDiskless |
185 | 185 |
| DTFile |
186 | 186 |
| DTSharedFile |
... | ... | |
189 | 189 |
| DTDrbd8 |
190 | 190 |
deriving (Show, Read, Eq, Enum, Bounded) |
191 | 191 |
|
192 |
-- | Converts a DiskTemplate to String |
|
192 |
-- | Converts a DiskTemplate to String.
|
|
193 | 193 |
dtToString :: DiskTemplate -> String |
194 | 194 |
dtToString DTDiskless = C.dtDiskless |
195 | 195 |
dtToString DTFile = C.dtFile |
... | ... | |
198 | 198 |
dtToString DTBlock = C.dtBlock |
199 | 199 |
dtToString DTDrbd8 = C.dtDrbd8 |
200 | 200 |
|
201 |
-- | Converts a DiskTemplate from String |
|
201 |
-- | Converts a DiskTemplate from String.
|
|
202 | 202 |
dtFromString :: (Monad m) => String -> m DiskTemplate |
203 | 203 |
dtFromString s = |
204 | 204 |
case () of |
... | ... | |
281 | 281 |
isBad :: Result a -> Bool |
282 | 282 |
isBad = not . isOk |
283 | 283 |
|
284 |
-- | Converter from Either String to 'Result' |
|
284 |
-- | Converter from Either String to 'Result'.
|
|
285 | 285 |
eitherToResult :: Either String a -> Result a |
286 | 286 |
eitherToResult (Left s) = Bad s |
287 | 287 |
eitherToResult (Right v) = Ok v |
b/htools/Ganeti/HTools/Version.hs.in | ||
---|---|---|
1 | 1 |
-- Hey Emacs, this is a -*- haskell -*- file |
2 |
{- | Auto-generated module holding version information. |
|
3 |
-} |
|
2 | 4 |
|
3 | 5 |
module Ganeti.HTools.Version |
4 | 6 |
( |
b/htools/test.hs | ||
---|---|---|
37 | 37 |
import Ganeti.HTools.CLI |
38 | 38 |
import Ganeti.HTools.Utils (sepSplit) |
39 | 39 |
|
40 |
-- | Options list and functions |
|
40 |
-- | Options list and functions.
|
|
41 | 41 |
options :: [OptType] |
42 | 42 |
options = |
43 | 43 |
[ oReplay |
... | ... | |
61 | 61 |
incIORef :: IORef Int -> IO () |
62 | 62 |
incIORef ir = atomicModifyIORef ir (\x -> (x + 1, ())) |
63 | 63 |
|
64 |
-- | Wrapper over a test runner with error counting |
|
64 |
-- | Wrapper over a test runner with error counting.
|
|
65 | 65 |
wrapTest :: IORef Int |
66 | 66 |
-> (Args -> IO Result) |
67 | 67 |
-> Args |
Also available in: Unified diff