Revision b2245847 hbal.hs

b/hbal.hs
25 25

  
26 26
module Main (main) where
27 27

  
28
import Control.Concurrent (threadDelay)
29
import Control.Exception (bracket)
28 30
import Data.List
29 31
import Data.Function
30 32
import Data.Maybe (isJust, fromJust)
......
34 36
import qualified System
35 37

  
36 38
import Text.Printf (printf, hPrintf)
39
import Text.JSON (showJSON)
37 40

  
38 41
import qualified Ganeti.HTools.Container as Container
39 42
import qualified Ganeti.HTools.Cluster as Cluster
40 43
import qualified Ganeti.HTools.Node as Node
44
import qualified Ganeti.HTools.Instance as Instance
41 45

  
42 46
import Ganeti.HTools.CLI
43 47
import Ganeti.HTools.ExtLoader
44 48
import Ganeti.HTools.Utils
45 49
import Ganeti.HTools.Types
46 50

  
51
import qualified Ganeti.Luxi as L
52
import qualified Ganeti.OpCodes as OpCodes
53
import Ganeti.Jobs
54

  
47 55
-- | Options list and functions
48 56
options :: [OptType]
49 57
options =
......
54 62
    , oInstFile
55 63
    , oRapiMaster
56 64
    , oLuxiSocket
65
    , oExecJobs
57 66
    , oMaxSolLength
58 67
    , oVerbose
59 68
    , oQuiet
......
109 118
    printf "%.8f %d %.8f %8.3f" ini_cv plc_len fin_cv
110 119
               (if fin_cv == 0 then 1 else ini_cv / fin_cv)
111 120

  
121
-- | Submits a list of jobs and waits for all to finish execution
122
execJobs :: L.Client -> [[OpCodes.OpCode]] -> IO (Result [String])
123
execJobs client = L.submitManyJobs client . showJSON
124

  
125
-- | Polls a set of jobs at a fixed interval until all are finished
126
-- one way or another
127
waitForJobs :: L.Client -> [String] -> IO (Result [JobStatus])
128
waitForJobs client jids = do
129
  sts <- L.queryJobsStatus client jids
130
  case sts of
131
    Bad x -> return $ Bad x
132
    Ok s -> if any (<= JobRunning) s
133
            then do
134
              -- TODO: replace hardcoded value with a better thing
135
              threadDelay (1000000 * 15)
136
              waitForJobs client jids
137
            else return $ Ok s
138

  
139
-- | Check that a set of job statuses is all success
140
checkJobsStatus :: [JobStatus] -> Bool
141
checkJobsStatus = all (== JobSuccess)
142

  
143
-- | Execute an entire jobset
144
execJobSet :: String -> String -> Node.List
145
           -> Instance.List -> [JobSet] -> IO ()
146
execJobSet _      _   _  _  [] = return ()
147
execJobSet master csf nl il (js:jss) = do
148
  -- map from jobset (htools list of positions) to [[opcodes]]
149
  let jobs = map (\(_, idx, move, _) ->
150
                      Cluster.iMoveToJob csf nl il idx move) js
151
  let descr = map (\(_, idx, _, _) -> Container.nameOf il idx) js
152
  putStrLn $ "Executing jobset for instances " ++ commaJoin descr
153
  jrs <- bracket (L.getClient master) L.closeClient
154
         (\client -> do
155
            jids <- execJobs client jobs
156
            case jids of
157
              Bad x -> return $ Bad x
158
              Ok x -> do
159
                putStrLn $ "Got job IDs " ++ commaJoin x
160
                waitForJobs client x
161
         )
162
  (case jrs of
163
     Bad x -> do
164
       hPutStrLn stderr $ "Cannot compute job status, aborting: " ++ show x
165
       return ()
166
     Ok x -> if checkJobsStatus x
167
             then execJobSet master csf nl il jss
168
             else do
169
               hPutStrLn stderr $ "Not all jobs completed successfully: " ++
170
                         show x
171
               hPutStrLn stderr "Aborting.")
172

  
112 173
-- | Main function.
113 174
main :: IO ()
114 175
main = do
......
212 273
  unless (oneline || verbose == 0) $
213 274
         printf "Solution length=%d\n" (length ord_plc)
214 275

  
215
  let cmd_data = Cluster.formatCmds . Cluster.splitJobs $ cmd_strs
276
  let cmd_jobs = Cluster.splitJobs cmd_strs
277
      cmd_data = Cluster.formatCmds cmd_jobs
216 278

  
217 279
  when (isJust $ optShowCmds opts) $
218 280
       do
......
227 289
            writeFile out_path (shTemplate ++ cmd_data)
228 290
            printf "The commands have been written to file '%s'\n" out_path)
229 291

  
292
  when (optExecJobs opts && not (null ord_plc))
293
           (case optLuxi opts of
294
              Nothing -> do
295
                hPutStrLn stderr "Execution of commands possible only on LUXI"
296
                exitWith $ ExitFailure 1
297
              Just master -> execJobSet master csf fin_nl il cmd_jobs)
298

  
230 299
  when (optShowNodes opts) $
231 300
       do
232 301
         let ini_cs = Cluster.totalResources nl

Also available in: Unified diff