1 {-# LANGUAGE TemplateHaskell #-}
3 {-| Some common Ganeti types.
5 This holds types common to both core work, and to htools. Types that
6 are very core specific (e.g. configuration objects) should go in
7 'Ganeti.Objects', while types that are specific to htools in-memory
8 representation should go into 'Ganeti.HTools.Types'.
14 Copyright (C) 2012, 2013 Google Inc.
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
38 , instanceStatusFromRaw
69 , VerifyOptionalChecks(..)
70 , verifyOptionalChecksToRaw
85 , IAllocatorTestDir(..)
93 , FinalizedJobStatus(..)
94 , finalizedJobStatusToRaw
102 , OpSubmitPriority(..)
103 , opSubmitPriorityToRaw
104 , parseSubmitPriority
115 , addParamsToStorageUnit
116 , diskTemplateToStorageType
119 import Control.Monad (liftM)
120 import qualified Text.JSON as JSON
121 import Text.JSON (JSON, readJSON, showJSON)
122 import Data.Ratio (numerator, denominator)
124 import qualified Ganeti.Constants as C
125 import qualified Ganeti.THH as THH
131 -- | Type that holds a non-negative value.
132 newtype NonNegative a = NonNegative { fromNonNegative :: a }
135 -- | Smart constructor for 'NonNegative'.
136 mkNonNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (NonNegative a)
137 mkNonNegative i | i >= 0 = return (NonNegative i)
138 | otherwise = fail $ "Invalid value for non-negative type '" ++
141 instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (NonNegative a) where
142 showJSON = JSON.showJSON . fromNonNegative
143 readJSON v = JSON.readJSON v >>= mkNonNegative
145 -- | Type that holds a positive value.
146 newtype Positive a = Positive { fromPositive :: a }
149 -- | Smart constructor for 'Positive'.
150 mkPositive :: (Monad m, Num a, Ord a, Show a) => a -> m (Positive a)
151 mkPositive i | i > 0 = return (Positive i)
152 | otherwise = fail $ "Invalid value for positive type '" ++
155 instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Positive a) where
156 showJSON = JSON.showJSON . fromPositive
157 readJSON v = JSON.readJSON v >>= mkPositive
159 -- | Type that holds a negative value.
160 newtype Negative a = Negative { fromNegative :: a }
163 -- | Smart constructor for 'Negative'.
164 mkNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (Negative a)
165 mkNegative i | i < 0 = return (Negative i)
166 | otherwise = fail $ "Invalid value for negative type '" ++
169 instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Negative a) where
170 showJSON = JSON.showJSON . fromNegative
171 readJSON v = JSON.readJSON v >>= mkNegative
173 -- | Type that holds a non-null list.
174 newtype NonEmpty a = NonEmpty { fromNonEmpty :: [a] }
177 -- | Smart constructor for 'NonEmpty'.
178 mkNonEmpty :: (Monad m) => [a] -> m (NonEmpty a)
179 mkNonEmpty [] = fail "Received empty value for non-empty list"
180 mkNonEmpty xs = return (NonEmpty xs)
182 instance (Eq a, Ord a) => Ord (NonEmpty a) where
183 NonEmpty { fromNonEmpty = x1 } `compare` NonEmpty { fromNonEmpty = x2 } =
186 instance (JSON.JSON a) => JSON.JSON (NonEmpty a) where
187 showJSON = JSON.showJSON . fromNonEmpty
188 readJSON v = JSON.readJSON v >>= mkNonEmpty
190 -- | A simple type alias for non-empty strings.
191 type NonEmptyString = NonEmpty Char
193 type QueryResultCode = Int
195 newtype IPv4Address = IPv4Address { fromIPv4Address :: String }
198 -- FIXME: this should check that 'address' is a valid ip
199 mkIPv4Address :: Monad m => String -> m IPv4Address
200 mkIPv4Address address =
201 return IPv4Address { fromIPv4Address = address }
203 instance JSON.JSON IPv4Address where
204 showJSON = JSON.showJSON . fromIPv4Address
205 readJSON v = JSON.readJSON v >>= mkIPv4Address
207 newtype IPv4Network = IPv4Network { fromIPv4Network :: String }
210 -- FIXME: this should check that 'address' is a valid ip
211 mkIPv4Network :: Monad m => String -> m IPv4Network
212 mkIPv4Network address =
213 return IPv4Network { fromIPv4Network = address }
215 instance JSON.JSON IPv4Network where
216 showJSON = JSON.showJSON . fromIPv4Network
217 readJSON v = JSON.readJSON v >>= mkIPv4Network
219 newtype IPv6Address = IPv6Address { fromIPv6Address :: String }
222 -- FIXME: this should check that 'address' is a valid ip
223 mkIPv6Address :: Monad m => String -> m IPv6Address
224 mkIPv6Address address =
225 return IPv6Address { fromIPv6Address = address }
227 instance JSON.JSON IPv6Address where
228 showJSON = JSON.showJSON . fromIPv6Address
229 readJSON v = JSON.readJSON v >>= mkIPv6Address
231 newtype IPv6Network = IPv6Network { fromIPv6Network :: String }
234 -- FIXME: this should check that 'address' is a valid ip
235 mkIPv6Network :: Monad m => String -> m IPv6Network
236 mkIPv6Network address =
237 return IPv6Network { fromIPv6Network = address }
239 instance JSON.JSON IPv6Network where
240 showJSON = JSON.showJSON . fromIPv6Network
241 readJSON v = JSON.readJSON v >>= mkIPv6Network
245 -- | Instance disk template type.
246 $(THH.declareSADT "DiskTemplate"
247 [ ("DTDiskless", 'C.dtDiskless)
248 , ("DTFile", 'C.dtFile)
249 , ("DTSharedFile", 'C.dtSharedFile)
250 , ("DTPlain", 'C.dtPlain)
251 , ("DTBlock", 'C.dtBlock)
252 , ("DTDrbd8", 'C.dtDrbd8)
253 , ("DTRbd", 'C.dtRbd)
254 , ("DTExt", 'C.dtExt)
256 $(THH.makeJSONInstance ''DiskTemplate)
258 instance HasStringRepr DiskTemplate where
259 fromStringRepr = diskTemplateFromRaw
260 toStringRepr = diskTemplateToRaw
262 -- | Data type representing what items the tag operations apply to.
263 $(THH.declareSADT "TagKind"
264 [ ("TagKindInstance", 'C.tagInstance)
265 , ("TagKindNode", 'C.tagNode)
266 , ("TagKindGroup", 'C.tagNodegroup)
267 , ("TagKindCluster", 'C.tagCluster)
269 $(THH.makeJSONInstance ''TagKind)
271 -- | The Group allocation policy type.
273 -- Note that the order of constructors is important as the automatic
274 -- Ord instance will order them in the order they are defined, so when
275 -- changing this data type be careful about the interaction with the
276 -- desired sorting order.
277 $(THH.declareSADT "AllocPolicy"
278 [ ("AllocPreferred", 'C.allocPolicyPreferred)
279 , ("AllocLastResort", 'C.allocPolicyLastResort)
280 , ("AllocUnallocable", 'C.allocPolicyUnallocable)
282 $(THH.makeJSONInstance ''AllocPolicy)
284 -- | The Instance real state type. FIXME: this could be improved to
285 -- just wrap a /NormalState AdminStatus | ErrorState ErrorCondition/.
286 $(THH.declareSADT "InstanceStatus"
287 [ ("StatusDown", 'C.inststAdmindown)
288 , ("StatusOffline", 'C.inststAdminoffline)
289 , ("ErrorDown", 'C.inststErrordown)
290 , ("ErrorUp", 'C.inststErrorup)
291 , ("NodeDown", 'C.inststNodedown)
292 , ("NodeOffline", 'C.inststNodeoffline)
293 , ("Running", 'C.inststRunning)
294 , ("WrongNode", 'C.inststWrongnode)
296 $(THH.makeJSONInstance ''InstanceStatus)
299 $(THH.declareSADT "MigrationMode"
300 [ ("MigrationLive", 'C.htMigrationLive)
301 , ("MigrationNonLive", 'C.htMigrationNonlive)
303 $(THH.makeJSONInstance ''MigrationMode)
305 -- | Verify optional checks.
306 $(THH.declareSADT "VerifyOptionalChecks"
307 [ ("VerifyNPlusOneMem", 'C.verifyNplusoneMem)
309 $(THH.makeJSONInstance ''VerifyOptionalChecks)
311 -- | Cluster verify error codes.
312 $(THH.declareSADT "CVErrorCode"
313 [ ("CvECLUSTERCFG", 'C.cvEclustercfgCode)
314 , ("CvECLUSTERCERT", 'C.cvEclustercertCode)
315 , ("CvECLUSTERFILECHECK", 'C.cvEclusterfilecheckCode)
316 , ("CvECLUSTERDANGLINGNODES", 'C.cvEclusterdanglingnodesCode)
317 , ("CvECLUSTERDANGLINGINST", 'C.cvEclusterdanglinginstCode)
318 , ("CvEINSTANCEBADNODE", 'C.cvEinstancebadnodeCode)
319 , ("CvEINSTANCEDOWN", 'C.cvEinstancedownCode)
320 , ("CvEINSTANCELAYOUT", 'C.cvEinstancelayoutCode)
321 , ("CvEINSTANCEMISSINGDISK", 'C.cvEinstancemissingdiskCode)
322 , ("CvEINSTANCEFAULTYDISK", 'C.cvEinstancefaultydiskCode)
323 , ("CvEINSTANCEWRONGNODE", 'C.cvEinstancewrongnodeCode)
324 , ("CvEINSTANCESPLITGROUPS", 'C.cvEinstancesplitgroupsCode)
325 , ("CvEINSTANCEPOLICY", 'C.cvEinstancepolicyCode)
326 , ("CvENODEDRBD", 'C.cvEnodedrbdCode)
327 , ("CvENODEDRBDHELPER", 'C.cvEnodedrbdhelperCode)
328 , ("CvENODEFILECHECK", 'C.cvEnodefilecheckCode)
329 , ("CvENODEHOOKS", 'C.cvEnodehooksCode)
330 , ("CvENODEHV", 'C.cvEnodehvCode)
331 , ("CvENODELVM", 'C.cvEnodelvmCode)
332 , ("CvENODEN1", 'C.cvEnoden1Code)
333 , ("CvENODENET", 'C.cvEnodenetCode)
334 , ("CvENODEOS", 'C.cvEnodeosCode)
335 , ("CvENODEORPHANINSTANCE", 'C.cvEnodeorphaninstanceCode)
336 , ("CvENODEORPHANLV", 'C.cvEnodeorphanlvCode)
337 , ("CvENODERPC", 'C.cvEnoderpcCode)
338 , ("CvENODESSH", 'C.cvEnodesshCode)
339 , ("CvENODEVERSION", 'C.cvEnodeversionCode)
340 , ("CvENODESETUP", 'C.cvEnodesetupCode)
341 , ("CvENODETIME", 'C.cvEnodetimeCode)
342 , ("CvENODEOOBPATH", 'C.cvEnodeoobpathCode)
343 , ("CvENODEUSERSCRIPTS", 'C.cvEnodeuserscriptsCode)
344 , ("CvENODEFILESTORAGEPATHS", 'C.cvEnodefilestoragepathsCode)
345 , ("CvENODEFILESTORAGEPATHUNUSABLE", 'C.cvEnodefilestoragepathunusableCode)
347 $(THH.makeJSONInstance ''CVErrorCode)
349 -- | Dynamic device modification, just add\/remove version.
350 $(THH.declareSADT "DdmSimple"
351 [ ("DdmSimpleAdd", 'C.ddmAdd)
352 , ("DdmSimpleRemove", 'C.ddmRemove)
354 $(THH.makeJSONInstance ''DdmSimple)
356 -- | Dynamic device modification, all operations version.
357 $(THH.declareSADT "DdmFull"
358 [ ("DdmFullAdd", 'C.ddmAdd)
359 , ("DdmFullRemove", 'C.ddmRemove)
360 , ("DdmFullModify", 'C.ddmModify)
362 $(THH.makeJSONInstance ''DdmFull)
364 -- | Hypervisor type definitions.
365 $(THH.declareSADT "Hypervisor"
366 [ ( "Kvm", 'C.htKvm )
367 , ( "XenPvm", 'C.htXenPvm )
368 , ( "Chroot", 'C.htChroot )
369 , ( "XenHvm", 'C.htXenHvm )
370 , ( "Lxc", 'C.htLxc )
371 , ( "Fake", 'C.htFake )
373 $(THH.makeJSONInstance ''Hypervisor)
375 -- | Oob command type.
376 $(THH.declareSADT "OobCommand"
377 [ ("OobHealth", 'C.oobHealth)
378 , ("OobPowerCycle", 'C.oobPowerCycle)
379 , ("OobPowerOff", 'C.oobPowerOff)
380 , ("OobPowerOn", 'C.oobPowerOn)
381 , ("OobPowerStatus", 'C.oobPowerStatus)
383 $(THH.makeJSONInstance ''OobCommand)
386 $(THH.declareSADT "StorageType"
387 [ ("StorageFile", 'C.stFile)
388 , ("StorageLvmPv", 'C.stLvmPv)
389 , ("StorageLvmVg", 'C.stLvmVg)
390 , ("StorageDiskless", 'C.stDiskless)
391 , ("StorageBlock", 'C.stBlock)
392 , ("StorageRados", 'C.stRados)
393 , ("StorageExt", 'C.stExt)
395 $(THH.makeJSONInstance ''StorageType)
397 -- | Storage keys are identifiers for storage units. Their content varies
398 -- depending on the storage type, for example a storage key for LVM storage
399 -- is the volume group name.
400 type StorageKey = String
402 -- | Storage parameters
403 type SPExclusiveStorage = Bool
405 -- | Storage units without storage-type-specific parameters
406 data StorageUnitRaw = SURaw StorageType StorageKey
408 -- | Full storage unit with storage-type-specific parameters
409 data StorageUnit = SUFile StorageKey
410 | SULvmPv StorageKey SPExclusiveStorage
411 | SULvmVg StorageKey SPExclusiveStorage
412 | SUDiskless StorageKey
418 instance Show StorageUnit where
419 show (SUFile key) = showSUSimple StorageFile key
420 show (SULvmPv key es) = showSULvm StorageLvmPv key es
421 show (SULvmVg key es) = showSULvm StorageLvmVg key es
422 show (SUDiskless key) = showSUSimple StorageDiskless key
423 show (SUBlock key) = showSUSimple StorageBlock key
424 show (SURados key) = showSUSimple StorageRados key
425 show (SUExt key) = showSUSimple StorageExt key
427 instance JSON StorageUnit where
428 showJSON (SUFile key) = showJSON (StorageFile, key, []::[String])
429 showJSON (SULvmPv key es) = showJSON (StorageLvmPv, key, [es])
430 showJSON (SULvmVg key es) = showJSON (StorageLvmVg, key, [es])
431 showJSON (SUDiskless key) = showJSON (StorageDiskless, key, []::[String])
432 showJSON (SUBlock key) = showJSON (StorageBlock, key, []::[String])
433 showJSON (SURados key) = showJSON (StorageRados, key, []::[String])
434 showJSON (SUExt key) = showJSON (StorageExt, key, []::[String])
435 -- FIXME: add readJSON implementation
436 readJSON = fail "Not implemented"
438 -- | Composes a string representation of storage types without
439 -- storage parameters
440 showSUSimple :: StorageType -> StorageKey -> String
441 showSUSimple st sk = show (storageTypeToRaw st, sk, []::[String])
443 -- | Composes a string representation of the LVM storage types
444 showSULvm :: StorageType -> StorageKey -> SPExclusiveStorage -> String
445 showSULvm st sk es = show (storageTypeToRaw st, sk, [es])
447 -- | Mapping fo disk templates to storage type
448 -- FIXME: This is semantically the same as the constant
449 -- C.diskTemplatesStorageType, remove this when python constants
450 -- are generated from haskell constants
451 diskTemplateToStorageType :: DiskTemplate -> StorageType
452 diskTemplateToStorageType DTExt = StorageExt
453 diskTemplateToStorageType DTFile = StorageFile
454 diskTemplateToStorageType DTSharedFile = StorageFile
455 diskTemplateToStorageType DTDrbd8 = StorageLvmVg
456 diskTemplateToStorageType DTPlain = StorageLvmVg
457 diskTemplateToStorageType DTRbd = StorageRados
458 diskTemplateToStorageType DTDiskless = StorageDiskless
459 diskTemplateToStorageType DTBlock = StorageBlock
461 -- | Equips a raw storage unit with its parameters
462 addParamsToStorageUnit :: SPExclusiveStorage -> StorageUnitRaw -> StorageUnit
463 addParamsToStorageUnit _ (SURaw StorageBlock key) = SUBlock key
464 addParamsToStorageUnit _ (SURaw StorageDiskless key) = SUDiskless key
465 addParamsToStorageUnit _ (SURaw StorageExt key) = SUExt key
466 addParamsToStorageUnit _ (SURaw StorageFile key) = SUFile key
467 addParamsToStorageUnit es (SURaw StorageLvmPv key) = SULvmPv key es
468 addParamsToStorageUnit es (SURaw StorageLvmVg key) = SULvmVg key es
469 addParamsToStorageUnit _ (SURaw StorageRados key) = SURados key
471 -- | Node evac modes.
472 $(THH.declareSADT "NodeEvacMode"
473 [ ("NEvacPrimary", 'C.iallocatorNevacPri)
474 , ("NEvacSecondary", 'C.iallocatorNevacSec)
475 , ("NEvacAll", 'C.iallocatorNevacAll)
477 $(THH.makeJSONInstance ''NodeEvacMode)
479 -- | The file driver type.
480 $(THH.declareSADT "FileDriver"
481 [ ("FileLoop", 'C.fdLoop)
482 , ("FileBlktap", 'C.fdBlktap)
484 $(THH.makeJSONInstance ''FileDriver)
486 -- | The instance create mode.
487 $(THH.declareSADT "InstCreateMode"
488 [ ("InstCreate", 'C.instanceCreate)
489 , ("InstImport", 'C.instanceImport)
490 , ("InstRemoteImport", 'C.instanceRemoteImport)
492 $(THH.makeJSONInstance ''InstCreateMode)
495 $(THH.declareSADT "RebootType"
496 [ ("RebootSoft", 'C.instanceRebootSoft)
497 , ("RebootHard", 'C.instanceRebootHard)
498 , ("RebootFull", 'C.instanceRebootFull)
500 $(THH.makeJSONInstance ''RebootType)
503 $(THH.declareSADT "ExportMode"
504 [ ("ExportModeLocal", 'C.exportModeLocal)
505 , ("ExportModeRemove", 'C.exportModeRemote)
507 $(THH.makeJSONInstance ''ExportMode)
509 -- | IAllocator run types (OpTestIAllocator).
510 $(THH.declareSADT "IAllocatorTestDir"
511 [ ("IAllocatorDirIn", 'C.iallocatorDirIn)
512 , ("IAllocatorDirOut", 'C.iallocatorDirOut)
514 $(THH.makeJSONInstance ''IAllocatorTestDir)
516 -- | IAllocator mode. FIXME: use this in "HTools.Backend.IAlloc".
517 $(THH.declareSADT "IAllocatorMode"
518 [ ("IAllocatorAlloc", 'C.iallocatorModeAlloc)
519 , ("IAllocatorMultiAlloc", 'C.iallocatorModeMultiAlloc)
520 , ("IAllocatorReloc", 'C.iallocatorModeReloc)
521 , ("IAllocatorNodeEvac", 'C.iallocatorModeNodeEvac)
522 , ("IAllocatorChangeGroup", 'C.iallocatorModeChgGroup)
524 $(THH.makeJSONInstance ''IAllocatorMode)
527 $(THH.declareSADT "NICMode"
528 [ ("NMBridged", 'C.nicModeBridged)
529 , ("NMRouted", 'C.nicModeRouted)
530 , ("NMOvs", 'C.nicModeOvs)
532 $(THH.makeJSONInstance ''NICMode)
534 -- | The JobStatus data type. Note that this is ordered especially
535 -- such that greater\/lesser comparison on values of this type makes
537 $(THH.declareSADT "JobStatus"
538 [ ("JOB_STATUS_QUEUED", 'C.jobStatusQueued)
539 , ("JOB_STATUS_WAITING", 'C.jobStatusWaiting)
540 , ("JOB_STATUS_CANCELING", 'C.jobStatusCanceling)
541 , ("JOB_STATUS_RUNNING", 'C.jobStatusRunning)
542 , ("JOB_STATUS_CANCELED", 'C.jobStatusCanceled)
543 , ("JOB_STATUS_SUCCESS", 'C.jobStatusSuccess)
544 , ("JOB_STATUS_ERROR", 'C.jobStatusError)
546 $(THH.makeJSONInstance ''JobStatus)
548 -- | Finalized job status.
549 $(THH.declareSADT "FinalizedJobStatus"
550 [ ("JobStatusCanceled", 'C.jobStatusCanceled)
551 , ("JobStatusSuccessful", 'C.jobStatusSuccess)
552 , ("JobStatusFailed", 'C.jobStatusError)
554 $(THH.makeJSONInstance ''FinalizedJobStatus)
556 -- | The Ganeti job type.
557 newtype JobId = JobId { fromJobId :: Int }
560 -- | Builds a job ID.
561 makeJobId :: (Monad m) => Int -> m JobId
562 makeJobId i | i >= 0 = return $ JobId i
563 | otherwise = fail $ "Invalid value for job ID ' " ++ show i ++ "'"
565 -- | Builds a job ID from a string.
566 makeJobIdS :: (Monad m) => String -> m JobId
567 makeJobIdS s = tryRead "parsing job id" s >>= makeJobId
569 -- | Parses a job ID.
570 parseJobId :: (Monad m) => JSON.JSValue -> m JobId
571 parseJobId (JSON.JSString x) = makeJobIdS $ JSON.fromJSString x
572 parseJobId (JSON.JSRational _ x) =
573 if denominator x /= 1
574 then fail $ "Got fractional job ID from master daemon?! Value:" ++ show x
575 -- FIXME: potential integer overflow here on 32-bit platforms
576 else makeJobId . fromIntegral . numerator $ x
577 parseJobId x = fail $ "Wrong type/value for job id: " ++ show x
579 instance JSON.JSON JobId where
580 showJSON = JSON.showJSON . fromJobId
581 readJSON = parseJobId
583 -- | Relative job ID type alias.
584 type RelativeJobId = Negative Int
586 -- | Job ID dependency.
587 data JobIdDep = JobDepRelative RelativeJobId
588 | JobDepAbsolute JobId
591 instance JSON.JSON JobIdDep where
592 showJSON (JobDepRelative i) = showJSON i
593 showJSON (JobDepAbsolute i) = showJSON i
595 case JSON.readJSON v::JSON.Result (Negative Int) of
596 -- first try relative dependency, usually most common
597 JSON.Ok r -> return $ JobDepRelative r
598 JSON.Error _ -> liftM JobDepAbsolute (parseJobId v)
600 -- | Job Dependency type.
601 data JobDependency = JobDependency JobIdDep [FinalizedJobStatus]
604 instance JSON JobDependency where
605 showJSON (JobDependency dep status) = showJSON (dep, status)
606 readJSON = liftM (uncurry JobDependency) . readJSON
608 -- | Valid opcode priorities for submit.
609 $(THH.declareIADT "OpSubmitPriority"
610 [ ("OpPrioLow", 'C.opPrioLow)
611 , ("OpPrioNormal", 'C.opPrioNormal)
612 , ("OpPrioHigh", 'C.opPrioHigh)
614 $(THH.makeJSONInstance ''OpSubmitPriority)
616 -- | Parse submit priorities from a string.
617 parseSubmitPriority :: (Monad m) => String -> m OpSubmitPriority
618 parseSubmitPriority "low" = return OpPrioLow
619 parseSubmitPriority "normal" = return OpPrioNormal
620 parseSubmitPriority "high" = return OpPrioHigh
621 parseSubmitPriority str = fail $ "Unknown priority '" ++ str ++ "'"
623 -- | Format a submit priority as string.
624 fmtSubmitPriority :: OpSubmitPriority -> String
625 fmtSubmitPriority OpPrioLow = "low"
626 fmtSubmitPriority OpPrioNormal = "normal"
627 fmtSubmitPriority OpPrioHigh = "high"
629 -- | Our ADT for the OpCode status at runtime (while in a job).
630 $(THH.declareSADT "OpStatus"
631 [ ("OP_STATUS_QUEUED", 'C.opStatusQueued)
632 , ("OP_STATUS_WAITING", 'C.opStatusWaiting)
633 , ("OP_STATUS_CANCELING", 'C.opStatusCanceling)
634 , ("OP_STATUS_RUNNING", 'C.opStatusRunning)
635 , ("OP_STATUS_CANCELED", 'C.opStatusCanceled)
636 , ("OP_STATUS_SUCCESS", 'C.opStatusSuccess)
637 , ("OP_STATUS_ERROR", 'C.opStatusError)
639 $(THH.makeJSONInstance ''OpStatus)
641 -- | Type for the job message type.
642 $(THH.declareSADT "ELogType"
643 [ ("ELogMessage", 'C.elogMessage)
644 , ("ELogRemoteImport", 'C.elogRemoteImport)
645 , ("ELogJqueueTest", 'C.elogJqueueTest)
647 $(THH.makeJSONInstance ''ELogType)
649 -- | Type of one element of a reason trail.
650 type ReasonElem = (String, String, Integer)
652 -- | Type representing a reason trail.
653 type ReasonTrail = [ReasonElem]