blob: c9ac93576f16f368cab985bc4bbee670b5da53a0 [file] [log] [blame]
{-| Generic code to work with jobs, e.g. submit jobs and check their status.
-}
{-
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
-}
module Ganeti.Jobs
( submitJobs
, execJobsWait
, execJobsWaitOk
, waitForJobs
) where
import Control.Concurrent (threadDelay)
import Data.List
import Ganeti.BasicTypes
import Ganeti.Errors
import qualified Ganeti.Luxi as L
import Ganeti.OpCodes
import Ganeti.Types
-- | Submits a set of jobs and returns their job IDs without waiting for
-- completion.
submitJobs :: [[MetaOpCode]] -> L.Client -> IO (Result [L.JobId])
submitJobs opcodes client = do
jids <- L.submitManyJobs client opcodes
return (case jids of
Bad e -> Bad $ "Job submission error: " ++ formatError e
Ok jids' -> Ok jids')
-- | Executes a set of jobs and waits for their completion, returning their
-- status.
execJobsWait :: [[MetaOpCode]] -- ^ The list of jobs
-> ([L.JobId] -> IO ()) -- ^ Post-submission callback
-> L.Client -- ^ The Luxi client
-> IO (Result [(L.JobId, JobStatus)])
execJobsWait opcodes callback client = do
jids <- submitJobs opcodes client
case jids of
Bad e -> return $ Bad e
Ok jids' -> do
callback jids'
waitForJobs jids' client
-- | Polls a set of jobs at an increasing interval until all are finished one
-- way or another.
waitForJobs :: [L.JobId] -> L.Client -> IO (Result [(L.JobId, JobStatus)])
waitForJobs jids client = waitForJobs' 500000 15000000
where
waitForJobs' delay maxdelay = do
-- TODO: this should use WaitForJobChange once it's available in Haskell
-- land, instead of a fixed schedule of sleeping intervals.
threadDelay delay
sts <- L.queryJobsStatus client jids
case sts of
Bad e -> return . Bad $ "Checking job status: " ++ formatError e
Ok sts' -> if any (<= JOB_STATUS_RUNNING) sts' then
waitForJobs' (min (delay * 2) maxdelay) maxdelay
else
return . Ok $ zip jids sts'
-- | Execute jobs and return @Ok@ only if all of them succeeded.
execJobsWaitOk :: [[MetaOpCode]] -> L.Client -> IO (Result ())
execJobsWaitOk opcodes client = do
let nullog = const (return () :: IO ())
failed = filter ((/=) JOB_STATUS_SUCCESS . snd)
fmtfail (i, s) = show (fromJobId i) ++ "=>" ++ jobStatusToRaw s
sts <- execJobsWait opcodes nullog client
case sts of
Bad e -> return $ Bad e
Ok sts' -> return (if null $ failed sts' then
Ok ()
else
Bad ("The following jobs failed: " ++
(intercalate ", " . map fmtfail $ failed sts')))