Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Query / Server.hs @ c92b4671

History | View | Annotate | Download (16.8 kB)

1 d120506c Agata Murawska
{-| Implementation of the Ganeti Query2 server.
2 25b54de0 Iustin Pop
3 25b54de0 Iustin Pop
-}
4 25b54de0 Iustin Pop
5 25b54de0 Iustin Pop
{-
6 25b54de0 Iustin Pop
7 72747d91 Iustin Pop
Copyright (C) 2012, 2013 Google Inc.
8 25b54de0 Iustin Pop
9 25b54de0 Iustin Pop
This program is free software; you can redistribute it and/or modify
10 25b54de0 Iustin Pop
it under the terms of the GNU General Public License as published by
11 25b54de0 Iustin Pop
the Free Software Foundation; either version 2 of the License, or
12 25b54de0 Iustin Pop
(at your option) any later version.
13 25b54de0 Iustin Pop
14 25b54de0 Iustin Pop
This program is distributed in the hope that it will be useful, but
15 25b54de0 Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
16 25b54de0 Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 25b54de0 Iustin Pop
General Public License for more details.
18 25b54de0 Iustin Pop
19 25b54de0 Iustin Pop
You should have received a copy of the GNU General Public License
20 25b54de0 Iustin Pop
along with this program; if not, write to the Free Software
21 25b54de0 Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 25b54de0 Iustin Pop
02110-1301, USA.
23 25b54de0 Iustin Pop
24 25b54de0 Iustin Pop
-}
25 25b54de0 Iustin Pop
26 4cab6703 Iustin Pop
module Ganeti.Query.Server
27 670e954a Thomas Thrainer
  ( main
28 670e954a Thomas Thrainer
  , checkMain
29 670e954a Thomas Thrainer
  , prepMain
30 0d0ac025 Iustin Pop
  ) where
31 25b54de0 Iustin Pop
32 f2374060 Iustin Pop
import Control.Applicative
33 25b54de0 Iustin Pop
import Control.Concurrent
34 25b54de0 Iustin Pop
import Control.Exception
35 c6013594 Klaus Aehlig
import Control.Monad (forever, when, zipWithM, liftM)
36 25b54de0 Iustin Pop
import Data.Bits (bitSize)
37 c87997d2 Jose A. Lopes
import qualified Data.Set as Set (toList)
38 670e954a Thomas Thrainer
import Data.IORef
39 be7531a9 Klaus Aehlig
import Data.Maybe (fromMaybe)
40 25b54de0 Iustin Pop
import qualified Text.JSON as J
41 6222b3a3 Klaus Aehlig
import Text.JSON (encode, showJSON, JSValue(..))
42 25b54de0 Iustin Pop
import System.Info (arch)
43 d5665e10 Klaus Aehlig
import System.Directory
44 25b54de0 Iustin Pop
45 25b54de0 Iustin Pop
import qualified Ganeti.Constants as C
46 c87997d2 Jose A. Lopes
import qualified Ganeti.ConstantUtils as ConstantUtils (unFrozenSet)
47 5183e8be Iustin Pop
import Ganeti.Errors
48 9eeb0aa5 Michael Hanselmann
import qualified Ganeti.Path as Path
49 0d0ac025 Iustin Pop
import Ganeti.Daemon
50 25b54de0 Iustin Pop
import Ganeti.Objects
51 f2374060 Iustin Pop
import qualified Ganeti.Config as Config
52 218e3b0f Thomas Thrainer
import Ganeti.ConfigReader
53 25b54de0 Iustin Pop
import Ganeti.BasicTypes
54 e5fba493 Klaus Aehlig
import Ganeti.JQueue
55 b5fa2700 Klaus Aehlig
import Ganeti.JQScheduler
56 74b3f734 Petr Pudlak
import Ganeti.JSON (TimeAsDoubleJSON(..))
57 25b54de0 Iustin Pop
import Ganeti.Logging
58 25b54de0 Iustin Pop
import Ganeti.Luxi
59 4cab6703 Iustin Pop
import qualified Ganeti.Query.Language as Qlang
60 1c3231aa Thomas Thrainer
import qualified Ganeti.Query.Cluster as QCluster
61 d5665e10 Klaus Aehlig
import Ganeti.Path (queueDir, jobQueueLockFile, jobQueueDrainFile)
62 946f1fb3 Klaus Aehlig
import Ganeti.Rpc
63 4cbe9bda Iustin Pop
import Ganeti.Query.Query
64 c4e0d065 Klaus Aehlig
import Ganeti.Query.Filter (makeSimpleFilter)
65 6e94b75c Jose A. Lopes
import Ganeti.Types
66 c7003a76 Petr Pudlak
import qualified Ganeti.UDSServer as U (Handler(..), listener)
67 6222b3a3 Klaus Aehlig
import Ganeti.Utils (lockFile, exitIfBad, watchFile)
68 3cb9bd38 Jose A. Lopes
import qualified Ganeti.Version as Version
69 25b54de0 Iustin Pop
70 cd67e337 Iustin Pop
-- | Helper for classic queries.
71 cd67e337 Iustin Pop
handleClassicQuery :: ConfigData      -- ^ Cluster config
72 cd67e337 Iustin Pop
                   -> Qlang.ItemType  -- ^ Query type
73 037762a9 Iustin Pop
                   -> [Either String Integer] -- ^ Requested names
74 037762a9 Iustin Pop
                                              -- (empty means all)
75 cd67e337 Iustin Pop
                   -> [String]        -- ^ Requested fields
76 cd67e337 Iustin Pop
                   -> Bool            -- ^ Whether to do sync queries or not
77 5183e8be Iustin Pop
                   -> IO (GenericResult GanetiException JSValue)
78 c4e0d065 Klaus Aehlig
handleClassicQuery _ _ _ _ True =
79 5183e8be Iustin Pop
  return . Bad $ OpPrereqError "Sync queries are not allowed" ECodeInval
80 c4e0d065 Klaus Aehlig
handleClassicQuery cfg qkind names fields _ = do
81 c4e0d065 Klaus Aehlig
  let flt = makeSimpleFilter (nameField qkind) names
82 cd67e337 Iustin Pop
  qr <- query cfg True (Qlang.Query qkind fields flt)
83 cd67e337 Iustin Pop
  return $ showJSON <$> (qr >>= queryCompat)
84 cd67e337 Iustin Pop
85 25b54de0 Iustin Pop
-- | Minimal wrapper to handle the missing config case.
86 9131274c Jose A. Lopes
handleCallWrapper :: MVar () -> JQStatus ->  Result ConfigData
87 e5fba493 Klaus Aehlig
                     -> LuxiOp -> IO (ErrorResult JSValue)
88 b5fa2700 Klaus Aehlig
handleCallWrapper _ _ (Bad msg) _ =
89 5183e8be Iustin Pop
  return . Bad . ConfigurationError $
90 5183e8be Iustin Pop
           "I do not have access to a valid configuration, cannot\
91 5183e8be Iustin Pop
           \ process queries: " ++ msg
92 b5fa2700 Klaus Aehlig
handleCallWrapper qlock qstat (Ok config) op = handleCall qlock qstat config op
93 25b54de0 Iustin Pop
94 25b54de0 Iustin Pop
-- | Actual luxi operation handler.
95 9131274c Jose A. Lopes
handleCall :: MVar () -> JQStatus
96 b5fa2700 Klaus Aehlig
              -> ConfigData -> LuxiOp -> IO (ErrorResult JSValue)
97 b5fa2700 Klaus Aehlig
handleCall _ _ cdata QueryClusterInfo =
98 25b54de0 Iustin Pop
  let cluster = configCluster cdata
99 1c3231aa Thomas Thrainer
      master = QCluster.clusterMasterNodeName cdata
100 25b54de0 Iustin Pop
      hypervisors = clusterEnabledHypervisors cluster
101 966e1580 Helga Velroyen
      diskTemplates = clusterEnabledDiskTemplates cluster
102 72747d91 Iustin Pop
      def_hv = case hypervisors of
103 72747d91 Iustin Pop
                 x:_ -> showJSON x
104 72747d91 Iustin Pop
                 [] -> JSNull
105 25b54de0 Iustin Pop
      bits = show (bitSize (0::Int)) ++ "bits"
106 25b54de0 Iustin Pop
      arch_tuple = [bits, arch]
107 5b11f8db Iustin Pop
      obj = [ ("software_version", showJSON C.releaseVersion)
108 5b11f8db Iustin Pop
            , ("protocol_version", showJSON C.protocolVersion)
109 5b11f8db Iustin Pop
            , ("config_version", showJSON C.configVersion)
110 c87997d2 Jose A. Lopes
            , ("os_api_version", showJSON . maximum .
111 c87997d2 Jose A. Lopes
                                 Set.toList . ConstantUtils.unFrozenSet $
112 c87997d2 Jose A. Lopes
                                 C.osApiVersions)
113 5b11f8db Iustin Pop
            , ("export_version", showJSON C.exportVersion)
114 3cb9bd38 Jose A. Lopes
            , ("vcs_version", showJSON Version.version)
115 5b11f8db Iustin Pop
            , ("architecture", showJSON arch_tuple)
116 25b54de0 Iustin Pop
            , ("name", showJSON $ clusterClusterName cluster)
117 1c3231aa Thomas Thrainer
            , ("master", showJSON (case master of
118 1c3231aa Thomas Thrainer
                                     Ok name -> name
119 1c3231aa Thomas Thrainer
                                     _ -> undefined))
120 72747d91 Iustin Pop
            , ("default_hypervisor", def_hv)
121 5b11f8db Iustin Pop
            , ("enabled_hypervisors", showJSON hypervisors)
122 a2160e57 Iustin Pop
            , ("hvparams", showJSON $ clusterHvparams cluster)
123 a2160e57 Iustin Pop
            , ("os_hvp", showJSON $ clusterOsHvp cluster)
124 25b54de0 Iustin Pop
            , ("beparams", showJSON $ clusterBeparams cluster)
125 25b54de0 Iustin Pop
            , ("osparams", showJSON $ clusterOsparams cluster)
126 25b54de0 Iustin Pop
            , ("ipolicy", showJSON $ clusterIpolicy cluster)
127 25b54de0 Iustin Pop
            , ("nicparams", showJSON $ clusterNicparams cluster)
128 25b54de0 Iustin Pop
            , ("ndparams", showJSON $ clusterNdparams cluster)
129 a2160e57 Iustin Pop
            , ("diskparams", showJSON $ clusterDiskparams cluster)
130 25b54de0 Iustin Pop
            , ("candidate_pool_size",
131 25b54de0 Iustin Pop
               showJSON $ clusterCandidatePoolSize cluster)
132 178ad717 Klaus Aehlig
            , ("max_running_jobs",
133 178ad717 Klaus Aehlig
               showJSON $ clusterMaxRunningJobs cluster)
134 25b54de0 Iustin Pop
            , ("master_netdev",  showJSON $ clusterMasterNetdev cluster)
135 25b54de0 Iustin Pop
            , ("master_netmask", showJSON $ clusterMasterNetmask cluster)
136 25b54de0 Iustin Pop
            , ("use_external_mip_script",
137 25b54de0 Iustin Pop
               showJSON $ clusterUseExternalMipScript cluster)
138 64b0309a Dimitris Aragiorgis
            , ("volume_group_name",
139 64b0309a Dimitris Aragiorgis
               maybe JSNull showJSON (clusterVolumeGroupName cluster))
140 25b54de0 Iustin Pop
            , ("drbd_usermode_helper",
141 25b54de0 Iustin Pop
               maybe JSNull showJSON (clusterDrbdUsermodeHelper cluster))
142 25b54de0 Iustin Pop
            , ("file_storage_dir", showJSON $ clusterFileStorageDir cluster)
143 25b54de0 Iustin Pop
            , ("shared_file_storage_dir",
144 25b54de0 Iustin Pop
               showJSON $ clusterSharedFileStorageDir cluster)
145 d3e6fd0e Santi Raffa
            , ("gluster_storage_dir",
146 d3e6fd0e Santi Raffa
               showJSON $ clusterGlusterStorageDir cluster)
147 25b54de0 Iustin Pop
            , ("maintain_node_health",
148 25b54de0 Iustin Pop
               showJSON $ clusterMaintainNodeHealth cluster)
149 74b3f734 Petr Pudlak
            , ("ctime", showJSON . TimeAsDoubleJSON $ clusterCtime cluster)
150 74b3f734 Petr Pudlak
            , ("mtime", showJSON . TimeAsDoubleJSON $ clusterMtime cluster)
151 25b54de0 Iustin Pop
            , ("uuid", showJSON $ clusterUuid cluster)
152 25b54de0 Iustin Pop
            , ("tags", showJSON $ clusterTags cluster)
153 25b54de0 Iustin Pop
            , ("uid_pool", showJSON $ clusterUidPool cluster)
154 25b54de0 Iustin Pop
            , ("default_iallocator",
155 25b54de0 Iustin Pop
               showJSON $ clusterDefaultIallocator cluster)
156 0359e5d0 Spyros Trigazis
            , ("default_iallocator_params",
157 0359e5d0 Spyros Trigazis
              showJSON $ clusterDefaultIallocatorParams cluster)
158 25b54de0 Iustin Pop
            , ("reserved_lvs", showJSON $ clusterReservedLvs cluster)
159 25b54de0 Iustin Pop
            , ("primary_ip_version",
160 25b54de0 Iustin Pop
               showJSON . ipFamilyToVersion $ clusterPrimaryIpFamily cluster)
161 7b9ceea7 Helga Velroyen
            , ("prealloc_wipe_disks",
162 7b9ceea7 Helga Velroyen
               showJSON $ clusterPreallocWipeDisks cluster)
163 7b9ceea7 Helga Velroyen
            , ("hidden_os", showJSON $ clusterHiddenOs cluster)
164 7b9ceea7 Helga Velroyen
            , ("blacklisted_os", showJSON $ clusterBlacklistedOs cluster)
165 966e1580 Helga Velroyen
            , ("enabled_disk_templates", showJSON diskTemplates)
166 25b54de0 Iustin Pop
            ]
167 25b54de0 Iustin Pop
168 1c3231aa Thomas Thrainer
  in case master of
169 1c3231aa Thomas Thrainer
    Ok _ -> return . Ok . J.makeObj $ obj
170 1c3231aa Thomas Thrainer
    Bad ex -> return $ Bad ex
171 25b54de0 Iustin Pop
172 b5fa2700 Klaus Aehlig
handleCall _ _ cfg (QueryTags kind name) = do
173 f2374060 Iustin Pop
  let tags = case kind of
174 6e94b75c Jose A. Lopes
               TagKindCluster  -> Ok . clusterTags $ configCluster cfg
175 6e94b75c Jose A. Lopes
               TagKindGroup    -> groupTags <$> Config.getGroup    cfg name
176 6e94b75c Jose A. Lopes
               TagKindNode     -> nodeTags  <$> Config.getNode     cfg name
177 6e94b75c Jose A. Lopes
               TagKindInstance -> instTags  <$> Config.getInstance cfg name
178 a8633d70 Jose A. Lopes
               TagKindNetwork  -> Bad $ OpPrereqError
179 a8633d70 Jose A. Lopes
                                        "Network tag is not allowed"
180 a8633d70 Jose A. Lopes
                                        ECodeInval
181 6e94b75c Jose A. Lopes
  return (J.showJSON <$> tags)
182 f2374060 Iustin Pop
183 b5fa2700 Klaus Aehlig
handleCall _ _ cfg (Query qkind qfields qfilter) = do
184 fa2c927c Agata Murawska
  result <- query cfg True (Qlang.Query qkind qfields qfilter)
185 4cbe9bda Iustin Pop
  return $ J.showJSON <$> result
186 4cbe9bda Iustin Pop
187 b5fa2700 Klaus Aehlig
handleCall _ _ _ (QueryFields qkind qfields) = do
188 518023a9 Iustin Pop
  let result = queryFields (Qlang.QueryFields qkind qfields)
189 518023a9 Iustin Pop
  return $ J.showJSON <$> result
190 518023a9 Iustin Pop
191 b5fa2700 Klaus Aehlig
handleCall _ _ cfg (QueryNodes names fields lock) =
192 037762a9 Iustin Pop
  handleClassicQuery cfg (Qlang.ItemTypeOpCode Qlang.QRNode)
193 c4e0d065 Klaus Aehlig
    (map Left names) fields lock
194 cd67e337 Iustin Pop
195 b5fa2700 Klaus Aehlig
handleCall _ _ cfg (QueryInstances names fields lock) =
196 89352544 Helga Velroyen
  handleClassicQuery cfg (Qlang.ItemTypeOpCode Qlang.QRInstance)
197 89352544 Helga Velroyen
    (map Left names) fields lock
198 89352544 Helga Velroyen
199 b5fa2700 Klaus Aehlig
handleCall _ _ cfg (QueryGroups names fields lock) =
200 037762a9 Iustin Pop
  handleClassicQuery cfg (Qlang.ItemTypeOpCode Qlang.QRGroup)
201 c4e0d065 Klaus Aehlig
    (map Left names) fields lock
202 cd67e337 Iustin Pop
203 b5fa2700 Klaus Aehlig
handleCall _ _ cfg (QueryJobs names fields) =
204 a7e484c4 Iustin Pop
  handleClassicQuery cfg (Qlang.ItemTypeLuxi Qlang.QRJob)
205 c4e0d065 Klaus Aehlig
    (map (Right . fromIntegral . fromJobId) names)  fields False
206 a7e484c4 Iustin Pop
207 b5fa2700 Klaus Aehlig
handleCall _ _ cfg (QueryNetworks names fields lock) =
208 795d035d Klaus Aehlig
  handleClassicQuery cfg (Qlang.ItemTypeOpCode Qlang.QRNetwork)
209 795d035d Klaus Aehlig
    (map Left names) fields lock
210 795d035d Klaus Aehlig
211 be7531a9 Klaus Aehlig
handleCall _ _ cfg (QueryConfigValues fields) = do
212 be7531a9 Klaus Aehlig
  let params = [ ("cluster_name", return . showJSON . clusterClusterName
213 be7531a9 Klaus Aehlig
                                    . configCluster $ cfg)
214 be7531a9 Klaus Aehlig
               , ("watcher_pause", liftM (maybe JSNull showJSON)
215 be7531a9 Klaus Aehlig
                                     QCluster.isWatcherPaused)
216 be7531a9 Klaus Aehlig
               , ("master_node", return . genericResult (const JSNull) showJSON
217 be7531a9 Klaus Aehlig
                                   $ QCluster.clusterMasterNodeName cfg)
218 1264bd58 Klaus Aehlig
               , ("drain_flag", liftM (showJSON . not) isQueueOpen)
219 be7531a9 Klaus Aehlig
               ] :: [(String, IO JSValue)]
220 be7531a9 Klaus Aehlig
  let answer = map (fromMaybe (return JSNull) . flip lookup params) fields
221 be7531a9 Klaus Aehlig
  answerEval <- sequence answer
222 be7531a9 Klaus Aehlig
  return . Ok . showJSON $ answerEval
223 be7531a9 Klaus Aehlig
224 b5fa2700 Klaus Aehlig
handleCall qlock qstat cfg (SubmitJobToDrainedQueue ops) =
225 e5fba493 Klaus Aehlig
  do
226 f5b765f0 Klaus Aehlig
    let mcs = Config.getMasterCandidates cfg
227 f5b765f0 Klaus Aehlig
    jobid <- allocateJobId mcs qlock
228 e5fba493 Klaus Aehlig
    case jobid of
229 e5fba493 Klaus Aehlig
      Bad s -> return . Bad . GenericError $ s
230 e5fba493 Klaus Aehlig
      Ok jid -> do
231 c6013594 Klaus Aehlig
        ts <- currentTimestamp
232 c6013594 Klaus Aehlig
        job <- liftM (setReceivedTimestamp ts)
233 c6013594 Klaus Aehlig
                 $ queuedJobFromOpCodes jid ops
234 e5fba493 Klaus Aehlig
        qDir <- queueDir
235 e5fba493 Klaus Aehlig
        write_result <- writeJobToDisk qDir job
236 e5fba493 Klaus Aehlig
        case write_result of
237 e5fba493 Klaus Aehlig
          Bad s -> return . Bad . GenericError $ s
238 e5fba493 Klaus Aehlig
          Ok () -> do
239 f5b765f0 Klaus Aehlig
            _ <- replicateManyJobs qDir mcs [job]
240 b5fa2700 Klaus Aehlig
            _ <- forkIO $ enqueueNewJobs qstat [job]
241 e5fba493 Klaus Aehlig
            return . Ok . showJSON . fromJobId $ jid
242 e5fba493 Klaus Aehlig
243 b5fa2700 Klaus Aehlig
handleCall qlock qstat cfg (SubmitJob ops) =
244 e5fba493 Klaus Aehlig
  do
245 e5fba493 Klaus Aehlig
    open <- isQueueOpen
246 e5fba493 Klaus Aehlig
    if not open
247 e5fba493 Klaus Aehlig
       then return . Bad . GenericError $ "Queue drained"
248 b5fa2700 Klaus Aehlig
       else handleCall qlock qstat cfg (SubmitJobToDrainedQueue ops)
249 e5fba493 Klaus Aehlig
250 b5fa2700 Klaus Aehlig
handleCall qlock qstat cfg (SubmitManyJobs lops) =
251 94d6d0a3 Klaus Aehlig
  do
252 94d6d0a3 Klaus Aehlig
    open <- isQueueOpen
253 94d6d0a3 Klaus Aehlig
    if not open
254 94d6d0a3 Klaus Aehlig
      then return . Bad . GenericError $ "Queue drained"
255 94d6d0a3 Klaus Aehlig
      else do
256 f5b765f0 Klaus Aehlig
        let mcs = Config.getMasterCandidates cfg
257 f5b765f0 Klaus Aehlig
        result_jobids <- allocateJobIds mcs qlock (length lops)
258 94d6d0a3 Klaus Aehlig
        case result_jobids of
259 94d6d0a3 Klaus Aehlig
          Bad s -> return . Bad . GenericError $ s
260 94d6d0a3 Klaus Aehlig
          Ok jids -> do
261 c6013594 Klaus Aehlig
            ts <- currentTimestamp
262 c6013594 Klaus Aehlig
            jobs <- liftM (map $ setReceivedTimestamp ts)
263 c6013594 Klaus Aehlig
                      $ zipWithM queuedJobFromOpCodes jids lops
264 94d6d0a3 Klaus Aehlig
            qDir <- queueDir
265 94d6d0a3 Klaus Aehlig
            write_results <- mapM (writeJobToDisk qDir) jobs
266 f5b765f0 Klaus Aehlig
            let annotated_results = zip write_results jobs
267 94d6d0a3 Klaus Aehlig
                succeeded = map snd $ filter (isOk . fst) annotated_results
268 94d6d0a3 Klaus Aehlig
            when (any isBad write_results) . logWarning
269 94d6d0a3 Klaus Aehlig
              $ "Writing some jobs failed " ++ show annotated_results
270 f5b765f0 Klaus Aehlig
            replicateManyJobs qDir mcs succeeded
271 b5fa2700 Klaus Aehlig
            _ <- forkIO $ enqueueNewJobs qstat succeeded
272 94d6d0a3 Klaus Aehlig
            return . Ok . JSArray
273 f5b765f0 Klaus Aehlig
              . map (\(res, job) ->
274 94d6d0a3 Klaus Aehlig
                      if isOk res
275 f5b765f0 Klaus Aehlig
                        then showJSON (True, fromJobId $ qjId job)
276 94d6d0a3 Klaus Aehlig
                        else showJSON (False, genericResult id (const "") res))
277 94d6d0a3 Klaus Aehlig
              $ annotated_results
278 229da00f Petr Pudlak
279 6222b3a3 Klaus Aehlig
handleCall _ _ cfg (WaitForJobChange jid fields prev_job prev_log tmout) = do
280 9131274c Jose A. Lopes
  let compute_fn = computeJobUpdate cfg jid fields prev_log
281 6222b3a3 Klaus Aehlig
  qDir <- queueDir
282 6222b3a3 Klaus Aehlig
  -- verify if the job is finalized, and return immediately in this case
283 6222b3a3 Klaus Aehlig
  jobresult <- loadJobFromDisk qDir False jid
284 6222b3a3 Klaus Aehlig
  case jobresult of
285 6222b3a3 Klaus Aehlig
    Ok (job, _) | not (jobFinalized job) -> do
286 6222b3a3 Klaus Aehlig
      let jobfile = liveJobFile qDir jid
287 6222b3a3 Klaus Aehlig
      answer <- watchFile jobfile (min tmout C.luxiWfjcTimeout)
288 6222b3a3 Klaus Aehlig
                  (prev_job, JSArray []) compute_fn
289 6222b3a3 Klaus Aehlig
      return . Ok $ showJSON answer
290 6222b3a3 Klaus Aehlig
    _ -> liftM (Ok . showJSON) compute_fn
291 6222b3a3 Klaus Aehlig
292 946f1fb3 Klaus Aehlig
handleCall _ _ cfg (SetWatcherPause time) = do
293 946f1fb3 Klaus Aehlig
  let mcs = Config.getMasterCandidates cfg
294 946f1fb3 Klaus Aehlig
      masters = genericResult (const []) return
295 946f1fb3 Klaus Aehlig
                  . Config.getNode cfg . clusterMasterNode
296 946f1fb3 Klaus Aehlig
                  $ configCluster cfg
297 946f1fb3 Klaus Aehlig
  _ <- executeRpcCall (masters ++ mcs) $ RpcCallSetWatcherPause time
298 ed7f7fd9 Petr Pudlak
  return . Ok . maybe JSNull showJSON $ fmap TimeAsDoubleJSON time
299 946f1fb3 Klaus Aehlig
300 d5665e10 Klaus Aehlig
handleCall _ _ cfg (SetDrainFlag value) = do
301 d5665e10 Klaus Aehlig
  let mcs = Config.getMasterCandidates cfg
302 d5665e10 Klaus Aehlig
  fpath <- jobQueueDrainFile
303 d5665e10 Klaus Aehlig
  if value
304 d5665e10 Klaus Aehlig
     then writeFile fpath ""
305 d5665e10 Klaus Aehlig
     else removeFile fpath
306 d5665e10 Klaus Aehlig
  _ <- executeRpcCall mcs $ RpcCallSetDrainFlag value
307 d5665e10 Klaus Aehlig
  return . Ok . showJSON $ True
308 d5665e10 Klaus Aehlig
309 36cb6837 Klaus Aehlig
handleCall _ qstat  cfg (CancelJob jid) = do
310 36cb6837 Klaus Aehlig
  let jName = (++) "job " . show $ fromJobId jid
311 36cb6837 Klaus Aehlig
  dequeueResult <- dequeueJob qstat jid
312 36cb6837 Klaus Aehlig
  case dequeueResult of
313 36cb6837 Klaus Aehlig
    Ok True -> do
314 36cb6837 Klaus Aehlig
      logDebug $ jName ++ " dequeued, marking as canceled"
315 36cb6837 Klaus Aehlig
      qDir <- queueDir
316 36cb6837 Klaus Aehlig
      readResult <- loadJobFromDisk qDir True jid
317 36cb6837 Klaus Aehlig
      let jobFileFailed = return . Ok . showJSON . (,) False
318 36cb6837 Klaus Aehlig
                            . (++) ("Dequeued " ++ jName
319 36cb6837 Klaus Aehlig
                                    ++ ", but failed to mark as cancelled: ")
320 36cb6837 Klaus Aehlig
                          :: String -> IO (ErrorResult JSValue)
321 36cb6837 Klaus Aehlig
      case readResult of
322 36cb6837 Klaus Aehlig
        Bad s -> jobFileFailed s
323 36cb6837 Klaus Aehlig
        Ok (job, _) -> do
324 36cb6837 Klaus Aehlig
          now <- currentTimestamp
325 36cb6837 Klaus Aehlig
          let job' = cancelQueuedJob now job
326 36cb6837 Klaus Aehlig
              mcs = Config.getMasterCandidates cfg
327 36cb6837 Klaus Aehlig
          write_result <- writeJobToDisk qDir job'
328 36cb6837 Klaus Aehlig
          case write_result of
329 36cb6837 Klaus Aehlig
            Bad s -> jobFileFailed s
330 36cb6837 Klaus Aehlig
            Ok () -> do
331 36cb6837 Klaus Aehlig
              replicateManyJobs qDir mcs [job']
332 36cb6837 Klaus Aehlig
              return . Ok . showJSON $ (True, "Dequeued " ++ jName)
333 36cb6837 Klaus Aehlig
    Ok False -> do
334 36cb6837 Klaus Aehlig
      logDebug $ jName ++ " not queued; trying to cancel directly"
335 36cb6837 Klaus Aehlig
      cancelJob jid
336 36cb6837 Klaus Aehlig
    Bad s -> return . Ok . showJSON $ (False, s)
337 36cb6837 Klaus Aehlig
338 b5fa2700 Klaus Aehlig
handleCall _ _ _ op =
339 5183e8be Iustin Pop
  return . Bad $
340 5183e8be Iustin Pop
    GenericError ("Luxi call '" ++ strOfOp op ++ "' not implemented")
341 25b54de0 Iustin Pop
342 edcad688 Petr Pudlak
{-# ANN handleCall "HLint: ignore Too strict if" #-}
343 edcad688 Petr Pudlak
344 6222b3a3 Klaus Aehlig
-- | Query the status of a job and return the requested fields
345 6222b3a3 Klaus Aehlig
-- and the logs newer than the given log number.
346 9131274c Jose A. Lopes
computeJobUpdate :: ConfigData -> JobId -> [String] -> JSValue
347 6222b3a3 Klaus Aehlig
                    -> IO (JSValue, JSValue)
348 6222b3a3 Klaus Aehlig
computeJobUpdate cfg jid fields prev_log = do
349 6222b3a3 Klaus Aehlig
  let sjid = show $ fromJobId jid
350 6222b3a3 Klaus Aehlig
  logDebug $ "Inspecting fields " ++ show fields ++ " of job " ++ sjid
351 6222b3a3 Klaus Aehlig
  let fromJSArray (JSArray xs) = xs
352 6222b3a3 Klaus Aehlig
      fromJSArray _ = []
353 6222b3a3 Klaus Aehlig
  let logFilter JSNull (JSArray _) = True
354 6222b3a3 Klaus Aehlig
      logFilter (JSRational _ n) (JSArray (JSRational _ m:_)) = n < m
355 6222b3a3 Klaus Aehlig
      logFilter _ _ = False
356 6222b3a3 Klaus Aehlig
  let filterLogs n logs = JSArray (filter (logFilter n) (logs >>= fromJSArray))
357 6222b3a3 Klaus Aehlig
  jobQuery <- handleClassicQuery cfg (Qlang.ItemTypeLuxi Qlang.QRJob)
358 6222b3a3 Klaus Aehlig
                [Right . fromIntegral $ fromJobId jid] ("oplog" : fields) False
359 6222b3a3 Klaus Aehlig
  let (rfields, rlogs) = case jobQuery of
360 6222b3a3 Klaus Aehlig
        Ok (JSArray [JSArray (JSArray logs : answer)]) ->
361 6222b3a3 Klaus Aehlig
          (answer, filterLogs prev_log logs)
362 6222b3a3 Klaus Aehlig
        _ -> (map (const JSNull) fields, JSArray [])
363 6222b3a3 Klaus Aehlig
  logDebug $ "Updates for job " ++ sjid ++ " are " ++ encode (rfields, rlogs)
364 6222b3a3 Klaus Aehlig
  return (JSArray rfields, rlogs)
365 6222b3a3 Klaus Aehlig
366 d79a6502 Petr Pudlak
367 d79a6502 Petr Pudlak
type LuxiConfig = (MVar (), JQStatus, ConfigReader)
368 d79a6502 Petr Pudlak
369 d79a6502 Petr Pudlak
luxiExec
370 d79a6502 Petr Pudlak
    :: LuxiConfig
371 d79a6502 Petr Pudlak
    -> LuxiOp
372 d79a6502 Petr Pudlak
    -> IO (Bool, GenericResult GanetiException JSValue)
373 d79a6502 Petr Pudlak
luxiExec (qlock, qstat, creader) args = do
374 25b54de0 Iustin Pop
  cfg <- creader
375 d79a6502 Petr Pudlak
  result <- handleCallWrapper qlock qstat cfg args
376 d79a6502 Petr Pudlak
  return (True, result)
377 d79a6502 Petr Pudlak
378 d79a6502 Petr Pudlak
luxiHandler :: LuxiConfig -> U.Handler LuxiOp JSValue
379 d79a6502 Petr Pudlak
luxiHandler cfg = U.Handler { U.hParse         = decodeLuxiCall
380 d79a6502 Petr Pudlak
                            , U.hInputLogShort = strOfOp
381 d79a6502 Petr Pudlak
                            , U.hInputLogLong  = show
382 d79a6502 Petr Pudlak
                            , U.hExec          = luxiExec cfg
383 d79a6502 Petr Pudlak
                            }
384 d79a6502 Petr Pudlak
385 670e954a Thomas Thrainer
-- | Type alias for prepMain results
386 5e671e0e Petr Pudlak
type PrepResult = (Server, IORef (Result ConfigData), JQStatus)
387 25b54de0 Iustin Pop
388 3695a4e0 Thomas Thrainer
-- | Check function for luxid.
389 670e954a Thomas Thrainer
checkMain :: CheckFn ()
390 670e954a Thomas Thrainer
checkMain _ = return $ Right ()
391 670e954a Thomas Thrainer
392 3695a4e0 Thomas Thrainer
-- | Prepare function for luxid.
393 670e954a Thomas Thrainer
prepMain :: PrepFn () PrepResult
394 670e954a Thomas Thrainer
prepMain _ _ = do
395 670e954a Thomas Thrainer
  socket_path <- Path.defaultQuerySocket
396 0d0ac025 Iustin Pop
  cleanupSocket socket_path
397 73b16ca1 Iustin Pop
  s <- describeError "binding to the Luxi socket"
398 d605e261 Petr Pudlak
         Nothing (Just socket_path) $ getLuxiServer True socket_path
399 670e954a Thomas Thrainer
  cref <- newIORef (Bad "Configuration not yet loaded")
400 6046dca9 Klaus Aehlig
  jq <- emptyJQStatus cref
401 5e671e0e Petr Pudlak
  return (s, cref, jq)
402 670e954a Thomas Thrainer
403 670e954a Thomas Thrainer
-- | Main function.
404 670e954a Thomas Thrainer
main :: MainFn () PrepResult
405 5e671e0e Petr Pudlak
main _ _ (server, cref, jq) = do
406 670e954a Thomas Thrainer
  initConfigReader id cref
407 670e954a Thomas Thrainer
  let creader = readIORef cref
408 b5fa2700 Klaus Aehlig
  initJQScheduler jq
409 9131274c Jose A. Lopes
410 e5fba493 Klaus Aehlig
  qlockFile <- jobQueueLockFile
411 e5fba493 Klaus Aehlig
  lockFile qlockFile >>= exitIfBad "Failed to obtain the job-queue lock"
412 e5fba493 Klaus Aehlig
  qlock <- newMVar ()
413 4c3f55b8 Iustin Pop
414 4c3f55b8 Iustin Pop
  finally
415 c7003a76 Petr Pudlak
    (forever $ U.listener (luxiHandler (qlock, jq, creader)) server)
416 5e671e0e Petr Pudlak
    (closeServer server)