Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Types.hs @ 9ee75f25

History | View | Annotate | Download (22.3 kB)

1
{-# LANGUAGE TemplateHaskell #-}
2

    
3
{-| Some common Ganeti types.
4

    
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'.
9

    
10
-}
11

    
12
{-
13

    
14
Copyright (C) 2012, 2013 Google Inc.
15

    
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.
20

    
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.
25

    
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
29
02110-1301, USA.
30

    
31
-}
32

    
33
module Ganeti.Types
34
  ( AllocPolicy(..)
35
  , allocPolicyFromRaw
36
  , allocPolicyToRaw
37
  , InstanceStatus(..)
38
  , instanceStatusFromRaw
39
  , instanceStatusToRaw
40
  , DiskTemplate(..)
41
  , diskTemplateToRaw
42
  , diskTemplateFromRaw
43
  , TagKind(..)
44
  , tagKindToRaw
45
  , tagKindFromRaw
46
  , NonNegative
47
  , fromNonNegative
48
  , mkNonNegative
49
  , Positive
50
  , fromPositive
51
  , mkPositive
52
  , Negative
53
  , fromNegative
54
  , mkNegative
55
  , NonEmpty
56
  , fromNonEmpty
57
  , mkNonEmpty
58
  , NonEmptyString
59
  , QueryResultCode
60
  , IPv4Address
61
  , mkIPv4Address
62
  , IPv4Network
63
  , mkIPv4Network
64
  , IPv6Address
65
  , mkIPv6Address
66
  , IPv6Network
67
  , mkIPv6Network
68
  , MigrationMode(..)
69
  , migrationModeToRaw
70
  , VerifyOptionalChecks(..)
71
  , verifyOptionalChecksToRaw
72
  , DdmSimple(..)
73
  , DdmFull(..)
74
  , ddmFullToRaw
75
  , CVErrorCode(..)
76
  , cVErrorCodeToRaw
77
  , Hypervisor(..)
78
  , hypervisorToRaw
79
  , OobCommand(..)
80
  , oobCommandToRaw
81
  , StorageType(..)
82
  , storageTypeToRaw
83
  , NodeEvacMode(..)
84
  , nodeEvacModeToRaw
85
  , FileDriver(..)
86
  , fileDriverToRaw
87
  , InstCreateMode(..)
88
  , instCreateModeToRaw
89
  , RebootType(..)
90
  , rebootTypeToRaw
91
  , ExportMode(..)
92
  , exportModeToRaw
93
  , IAllocatorTestDir(..)
94
  , iAllocatorTestDirToRaw
95
  , IAllocatorMode(..)
96
  , iAllocatorModeToRaw
97
  , NICMode(..)
98
  , nICModeToRaw
99
  , JobStatus(..)
100
  , jobStatusToRaw
101
  , jobStatusFromRaw
102
  , FinalizedJobStatus(..)
103
  , finalizedJobStatusToRaw
104
  , JobId
105
  , fromJobId
106
  , makeJobId
107
  , makeJobIdS
108
  , RelativeJobId
109
  , JobIdDep(..)
110
  , JobDependency(..)
111
  , OpSubmitPriority(..)
112
  , opSubmitPriorityToRaw
113
  , parseSubmitPriority
114
  , fmtSubmitPriority
115
  , OpStatus(..)
116
  , opStatusToRaw
117
  , opStatusFromRaw
118
  , ELogType(..)
119
  , eLogTypeToRaw
120
  , ReasonElem
121
  , ReasonTrail
122
  , StorageUnit(..)
123
  , StorageUnitRaw(..)
124
  , StorageKey
125
  , addParamsToStorageUnit
126
  , diskTemplateToStorageType
127
  ) where
128

    
129
import Control.Monad (liftM)
130
import qualified Text.JSON as JSON
131
import Text.JSON (JSON, readJSON, showJSON)
132
import Data.Ratio (numerator, denominator)
133

    
134
import qualified Ganeti.Constants as C
135
import qualified Ganeti.THH as THH
136
import Ganeti.JSON
137
import Ganeti.Utils
138

    
139
-- * Generic types
140

    
141
-- | Type that holds a non-negative value.
142
newtype NonNegative a = NonNegative { fromNonNegative :: a }
143
  deriving (Show, Eq)
144

    
145
-- | Smart constructor for 'NonNegative'.
146
mkNonNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (NonNegative a)
147
mkNonNegative i | i >= 0 = return (NonNegative i)
148
                | otherwise = fail $ "Invalid value for non-negative type '" ++
149
                              show i ++ "'"
150

    
151
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (NonNegative a) where
152
  showJSON = JSON.showJSON . fromNonNegative
153
  readJSON v = JSON.readJSON v >>= mkNonNegative
154

    
155
-- | Type that holds a positive value.
156
newtype Positive a = Positive { fromPositive :: a }
157
  deriving (Show, Eq)
158

    
159
-- | Smart constructor for 'Positive'.
160
mkPositive :: (Monad m, Num a, Ord a, Show a) => a -> m (Positive a)
161
mkPositive i | i > 0 = return (Positive i)
162
             | otherwise = fail $ "Invalid value for positive type '" ++
163
                           show i ++ "'"
164

    
165
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Positive a) where
166
  showJSON = JSON.showJSON . fromPositive
167
  readJSON v = JSON.readJSON v >>= mkPositive
168

    
169
-- | Type that holds a negative value.
170
newtype Negative a = Negative { fromNegative :: a }
171
  deriving (Show, Eq)
172

    
173
-- | Smart constructor for 'Negative'.
174
mkNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (Negative a)
175
mkNegative i | i < 0 = return (Negative i)
176
             | otherwise = fail $ "Invalid value for negative type '" ++
177
                           show i ++ "'"
178

    
179
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Negative a) where
180
  showJSON = JSON.showJSON . fromNegative
181
  readJSON v = JSON.readJSON v >>= mkNegative
182

    
183
-- | Type that holds a non-null list.
184
newtype NonEmpty a = NonEmpty { fromNonEmpty :: [a] }
185
  deriving (Show, Eq)
186

    
187
-- | Smart constructor for 'NonEmpty'.
188
mkNonEmpty :: (Monad m) => [a] -> m (NonEmpty a)
189
mkNonEmpty [] = fail "Received empty value for non-empty list"
190
mkNonEmpty xs = return (NonEmpty xs)
191

    
192
instance (Eq a, Ord a) => Ord (NonEmpty a) where
193
  NonEmpty { fromNonEmpty = x1 } `compare` NonEmpty { fromNonEmpty = x2 } =
194
    x1 `compare` x2
195

    
196
instance (JSON.JSON a) => JSON.JSON (NonEmpty a) where
197
  showJSON = JSON.showJSON . fromNonEmpty
198
  readJSON v = JSON.readJSON v >>= mkNonEmpty
199

    
200
-- | A simple type alias for non-empty strings.
201
type NonEmptyString = NonEmpty Char
202

    
203
type QueryResultCode = Int
204

    
205
newtype IPv4Address = IPv4Address { fromIPv4Address :: String }
206
  deriving (Show, Eq)
207

    
208
-- FIXME: this should check that 'address' is a valid ip
209
mkIPv4Address :: Monad m => String -> m IPv4Address
210
mkIPv4Address address =
211
  return IPv4Address { fromIPv4Address = address }
212

    
213
instance JSON.JSON IPv4Address where
214
  showJSON = JSON.showJSON . fromIPv4Address
215
  readJSON v = JSON.readJSON v >>= mkIPv4Address
216

    
217
newtype IPv4Network = IPv4Network { fromIPv4Network :: String }
218
  deriving (Show, Eq)
219

    
220
-- FIXME: this should check that 'address' is a valid ip
221
mkIPv4Network :: Monad m => String -> m IPv4Network
222
mkIPv4Network address =
223
  return IPv4Network { fromIPv4Network = address }
224

    
225
instance JSON.JSON IPv4Network where
226
  showJSON = JSON.showJSON . fromIPv4Network
227
  readJSON v = JSON.readJSON v >>= mkIPv4Network
228

    
229
newtype IPv6Address = IPv6Address { fromIPv6Address :: String }
230
  deriving (Show, Eq)
231

    
232
-- FIXME: this should check that 'address' is a valid ip
233
mkIPv6Address :: Monad m => String -> m IPv6Address
234
mkIPv6Address address =
235
  return IPv6Address { fromIPv6Address = address }
236

    
237
instance JSON.JSON IPv6Address where
238
  showJSON = JSON.showJSON . fromIPv6Address
239
  readJSON v = JSON.readJSON v >>= mkIPv6Address
240

    
241
newtype IPv6Network = IPv6Network { fromIPv6Network :: String }
242
  deriving (Show, Eq)
243

    
244
-- FIXME: this should check that 'address' is a valid ip
245
mkIPv6Network :: Monad m => String -> m IPv6Network
246
mkIPv6Network address =
247
  return IPv6Network { fromIPv6Network = address }
248

    
249
instance JSON.JSON IPv6Network where
250
  showJSON = JSON.showJSON . fromIPv6Network
251
  readJSON v = JSON.readJSON v >>= mkIPv6Network
252

    
253
-- * Ganeti types
254

    
255
-- | Instance disk template type.
256
$(THH.declareSADT "DiskTemplate"
257
       [ ("DTDiskless",   'C.dtDiskless)
258
       , ("DTFile",       'C.dtFile)
259
       , ("DTSharedFile", 'C.dtSharedFile)
260
       , ("DTPlain",      'C.dtPlain)
261
       , ("DTBlock",      'C.dtBlock)
262
       , ("DTDrbd8",      'C.dtDrbd8)
263
       , ("DTRbd",        'C.dtRbd)
264
       , ("DTExt",        'C.dtExt)
265
       ])
266
$(THH.makeJSONInstance ''DiskTemplate)
267

    
268
instance HasStringRepr DiskTemplate where
269
  fromStringRepr = diskTemplateFromRaw
270
  toStringRepr = diskTemplateToRaw
271

    
272
-- | Data type representing what items the tag operations apply to.
273
$(THH.declareSADT "TagKind"
274
  [ ("TagKindInstance", 'C.tagInstance)
275
  , ("TagKindNode",     'C.tagNode)
276
  , ("TagKindGroup",    'C.tagNodegroup)
277
  , ("TagKindCluster",  'C.tagCluster)
278
  ])
279
$(THH.makeJSONInstance ''TagKind)
280

    
281
-- | The Group allocation policy type.
282
--
283
-- Note that the order of constructors is important as the automatic
284
-- Ord instance will order them in the order they are defined, so when
285
-- changing this data type be careful about the interaction with the
286
-- desired sorting order.
287
$(THH.declareSADT "AllocPolicy"
288
       [ ("AllocPreferred",   'C.allocPolicyPreferred)
289
       , ("AllocLastResort",  'C.allocPolicyLastResort)
290
       , ("AllocUnallocable", 'C.allocPolicyUnallocable)
291
       ])
292
$(THH.makeJSONInstance ''AllocPolicy)
293

    
294
-- | The Instance real state type. FIXME: this could be improved to
295
-- just wrap a /NormalState AdminStatus | ErrorState ErrorCondition/.
296
$(THH.declareSADT "InstanceStatus"
297
       [ ("StatusDown",    'C.inststAdmindown)
298
       , ("StatusOffline", 'C.inststAdminoffline)
299
       , ("ErrorDown",     'C.inststErrordown)
300
       , ("ErrorUp",       'C.inststErrorup)
301
       , ("NodeDown",      'C.inststNodedown)
302
       , ("NodeOffline",   'C.inststNodeoffline)
303
       , ("Running",       'C.inststRunning)
304
       , ("WrongNode",     'C.inststWrongnode)
305
       ])
306
$(THH.makeJSONInstance ''InstanceStatus)
307

    
308
-- | Migration mode.
309
$(THH.declareSADT "MigrationMode"
310
     [ ("MigrationLive",    'C.htMigrationLive)
311
     , ("MigrationNonLive", 'C.htMigrationNonlive)
312
     ])
313
$(THH.makeJSONInstance ''MigrationMode)
314

    
315
-- | Verify optional checks.
316
$(THH.declareSADT "VerifyOptionalChecks"
317
     [ ("VerifyNPlusOneMem", 'C.verifyNplusoneMem)
318
     ])
319
$(THH.makeJSONInstance ''VerifyOptionalChecks)
320

    
321
-- | Cluster verify error codes.
322
$(THH.declareSADT "CVErrorCode"
323
  [ ("CvECLUSTERCFG",                  'C.cvEclustercfgCode)
324
  , ("CvECLUSTERCERT",                 'C.cvEclustercertCode)
325
  , ("CvECLUSTERFILECHECK",            'C.cvEclusterfilecheckCode)
326
  , ("CvECLUSTERDANGLINGNODES",        'C.cvEclusterdanglingnodesCode)
327
  , ("CvECLUSTERDANGLINGINST",         'C.cvEclusterdanglinginstCode)
328
  , ("CvEINSTANCEBADNODE",             'C.cvEinstancebadnodeCode)
329
  , ("CvEINSTANCEDOWN",                'C.cvEinstancedownCode)
330
  , ("CvEINSTANCELAYOUT",              'C.cvEinstancelayoutCode)
331
  , ("CvEINSTANCEMISSINGDISK",         'C.cvEinstancemissingdiskCode)
332
  , ("CvEINSTANCEFAULTYDISK",          'C.cvEinstancefaultydiskCode)
333
  , ("CvEINSTANCEWRONGNODE",           'C.cvEinstancewrongnodeCode)
334
  , ("CvEINSTANCESPLITGROUPS",         'C.cvEinstancesplitgroupsCode)
335
  , ("CvEINSTANCEPOLICY",              'C.cvEinstancepolicyCode)
336
  , ("CvENODEDRBD",                    'C.cvEnodedrbdCode)
337
  , ("CvENODEDRBDHELPER",              'C.cvEnodedrbdhelperCode)
338
  , ("CvENODEFILECHECK",               'C.cvEnodefilecheckCode)
339
  , ("CvENODEHOOKS",                   'C.cvEnodehooksCode)
340
  , ("CvENODEHV",                      'C.cvEnodehvCode)
341
  , ("CvENODELVM",                     'C.cvEnodelvmCode)
342
  , ("CvENODEN1",                      'C.cvEnoden1Code)
343
  , ("CvENODENET",                     'C.cvEnodenetCode)
344
  , ("CvENODEOS",                      'C.cvEnodeosCode)
345
  , ("CvENODEORPHANINSTANCE",          'C.cvEnodeorphaninstanceCode)
346
  , ("CvENODEORPHANLV",                'C.cvEnodeorphanlvCode)
347
  , ("CvENODERPC",                     'C.cvEnoderpcCode)
348
  , ("CvENODESSH",                     'C.cvEnodesshCode)
349
  , ("CvENODEVERSION",                 'C.cvEnodeversionCode)
350
  , ("CvENODESETUP",                   'C.cvEnodesetupCode)
351
  , ("CvENODETIME",                    'C.cvEnodetimeCode)
352
  , ("CvENODEOOBPATH",                 'C.cvEnodeoobpathCode)
353
  , ("CvENODEUSERSCRIPTS",             'C.cvEnodeuserscriptsCode)
354
  , ("CvENODEFILESTORAGEPATHS",        'C.cvEnodefilestoragepathsCode)
355
  , ("CvENODEFILESTORAGEPATHUNUSABLE", 'C.cvEnodefilestoragepathunusableCode)
356
  , ("CvENODESHAREDFILESTORAGEPATHUNUSABLE",
357
     'C.cvEnodesharedfilestoragepathunusableCode)
358
  ])
359
$(THH.makeJSONInstance ''CVErrorCode)
360

    
361
-- | Dynamic device modification, just add\/remove version.
362
$(THH.declareSADT "DdmSimple"
363
     [ ("DdmSimpleAdd",    'C.ddmAdd)
364
     , ("DdmSimpleRemove", 'C.ddmRemove)
365
     ])
366
$(THH.makeJSONInstance ''DdmSimple)
367

    
368
-- | Dynamic device modification, all operations version.
369
$(THH.declareSADT "DdmFull"
370
     [ ("DdmFullAdd",    'C.ddmAdd)
371
     , ("DdmFullRemove", 'C.ddmRemove)
372
     , ("DdmFullModify", 'C.ddmModify)
373
     ])
374
$(THH.makeJSONInstance ''DdmFull)
375

    
376
-- | Hypervisor type definitions.
377
$(THH.declareSADT "Hypervisor"
378
  [ ( "Kvm",    'C.htKvm )
379
  , ( "XenPvm", 'C.htXenPvm )
380
  , ( "Chroot", 'C.htChroot )
381
  , ( "XenHvm", 'C.htXenHvm )
382
  , ( "Lxc",    'C.htLxc )
383
  , ( "Fake",   'C.htFake )
384
  ])
385
$(THH.makeJSONInstance ''Hypervisor)
386

    
387
-- | Oob command type.
388
$(THH.declareSADT "OobCommand"
389
  [ ("OobHealth",      'C.oobHealth)
390
  , ("OobPowerCycle",  'C.oobPowerCycle)
391
  , ("OobPowerOff",    'C.oobPowerOff)
392
  , ("OobPowerOn",     'C.oobPowerOn)
393
  , ("OobPowerStatus", 'C.oobPowerStatus)
394
  ])
395
$(THH.makeJSONInstance ''OobCommand)
396

    
397
-- | Storage type.
398
$(THH.declareSADT "StorageType"
399
  [ ("StorageFile", 'C.stFile)
400
  , ("StorageLvmPv", 'C.stLvmPv)
401
  , ("StorageLvmVg", 'C.stLvmVg)
402
  , ("StorageDiskless", 'C.stDiskless)
403
  , ("StorageBlock", 'C.stBlock)
404
  , ("StorageRados", 'C.stRados)
405
  , ("StorageExt", 'C.stExt)
406
  ])
407
$(THH.makeJSONInstance ''StorageType)
408

    
409
-- | Storage keys are identifiers for storage units. Their content varies
410
-- depending on the storage type, for example a storage key for LVM storage
411
-- is the volume group name.
412
type StorageKey = String
413

    
414
-- | Storage parameters
415
type SPExclusiveStorage = Bool
416

    
417
-- | Storage units without storage-type-specific parameters
418
data StorageUnitRaw = SURaw StorageType StorageKey
419

    
420
-- | Full storage unit with storage-type-specific parameters
421
data StorageUnit = SUFile StorageKey
422
                 | SULvmPv StorageKey SPExclusiveStorage
423
                 | SULvmVg StorageKey SPExclusiveStorage
424
                 | SUDiskless StorageKey
425
                 | SUBlock StorageKey
426
                 | SURados StorageKey
427
                 | SUExt StorageKey
428
                 deriving (Eq)
429

    
430
instance Show StorageUnit where
431
  show (SUFile key) = showSUSimple StorageFile key
432
  show (SULvmPv key es) = showSULvm StorageLvmPv key es
433
  show (SULvmVg key es) = showSULvm StorageLvmVg key es
434
  show (SUDiskless key) = showSUSimple StorageDiskless key
435
  show (SUBlock key) = showSUSimple StorageBlock key
436
  show (SURados key) = showSUSimple StorageRados key
437
  show (SUExt key) = showSUSimple StorageExt key
438

    
439
instance JSON StorageUnit where
440
  showJSON (SUFile key) = showJSON (StorageFile, key, []::[String])
441
  showJSON (SULvmPv key es) = showJSON (StorageLvmPv, key, [es])
442
  showJSON (SULvmVg key es) = showJSON (StorageLvmVg, key, [es])
443
  showJSON (SUDiskless key) = showJSON (StorageDiskless, key, []::[String])
444
  showJSON (SUBlock key) = showJSON (StorageBlock, key, []::[String])
445
  showJSON (SURados key) = showJSON (StorageRados, key, []::[String])
446
  showJSON (SUExt key) = showJSON (StorageExt, key, []::[String])
447
-- FIXME: add readJSON implementation
448
  readJSON = fail "Not implemented"
449

    
450
-- | Composes a string representation of storage types without
451
-- storage parameters
452
showSUSimple :: StorageType -> StorageKey -> String
453
showSUSimple st sk = show (storageTypeToRaw st, sk, []::[String])
454

    
455
-- | Composes a string representation of the LVM storage types
456
showSULvm :: StorageType -> StorageKey -> SPExclusiveStorage -> String
457
showSULvm st sk es = show (storageTypeToRaw st, sk, [es])
458

    
459
-- | Mapping fo disk templates to storage type
460
-- FIXME: This is semantically the same as the constant
461
-- C.diskTemplatesStorageType, remove this when python constants
462
-- are generated from haskell constants
463
diskTemplateToStorageType :: DiskTemplate -> StorageType
464
diskTemplateToStorageType DTExt = StorageExt
465
diskTemplateToStorageType DTFile = StorageFile
466
diskTemplateToStorageType DTSharedFile = StorageFile
467
diskTemplateToStorageType DTDrbd8 = StorageLvmVg
468
diskTemplateToStorageType DTPlain = StorageLvmVg
469
diskTemplateToStorageType DTRbd = StorageRados
470
diskTemplateToStorageType DTDiskless = StorageDiskless
471
diskTemplateToStorageType DTBlock = StorageBlock
472

    
473
-- | Equips a raw storage unit with its parameters
474
addParamsToStorageUnit :: SPExclusiveStorage -> StorageUnitRaw -> StorageUnit
475
addParamsToStorageUnit _ (SURaw StorageBlock key) = SUBlock key
476
addParamsToStorageUnit _ (SURaw StorageDiskless key) = SUDiskless key
477
addParamsToStorageUnit _ (SURaw StorageExt key) = SUExt key
478
addParamsToStorageUnit _ (SURaw StorageFile key) = SUFile key
479
addParamsToStorageUnit es (SURaw StorageLvmPv key) = SULvmPv key es
480
addParamsToStorageUnit es (SURaw StorageLvmVg key) = SULvmVg key es
481
addParamsToStorageUnit _ (SURaw StorageRados key) = SURados key
482

    
483
-- | Node evac modes.
484
$(THH.declareSADT "NodeEvacMode"
485
  [ ("NEvacPrimary",   'C.iallocatorNevacPri)
486
  , ("NEvacSecondary", 'C.iallocatorNevacSec)
487
  , ("NEvacAll",       'C.iallocatorNevacAll)
488
  ])
489
$(THH.makeJSONInstance ''NodeEvacMode)
490

    
491
-- | The file driver type.
492
$(THH.declareSADT "FileDriver"
493
  [ ("FileLoop",   'C.fdLoop)
494
  , ("FileBlktap", 'C.fdBlktap)
495
  ])
496
$(THH.makeJSONInstance ''FileDriver)
497

    
498
-- | The instance create mode.
499
$(THH.declareSADT "InstCreateMode"
500
  [ ("InstCreate",       'C.instanceCreate)
501
  , ("InstImport",       'C.instanceImport)
502
  , ("InstRemoteImport", 'C.instanceRemoteImport)
503
  ])
504
$(THH.makeJSONInstance ''InstCreateMode)
505

    
506
-- | Reboot type.
507
$(THH.declareSADT "RebootType"
508
  [ ("RebootSoft", 'C.instanceRebootSoft)
509
  , ("RebootHard", 'C.instanceRebootHard)
510
  , ("RebootFull", 'C.instanceRebootFull)
511
  ])
512
$(THH.makeJSONInstance ''RebootType)
513

    
514
-- | Export modes.
515
$(THH.declareSADT "ExportMode"
516
  [ ("ExportModeLocal",  'C.exportModeLocal)
517
  , ("ExportModeRemove", 'C.exportModeRemote)
518
  ])
519
$(THH.makeJSONInstance ''ExportMode)
520

    
521
-- | IAllocator run types (OpTestIAllocator).
522
$(THH.declareSADT "IAllocatorTestDir"
523
  [ ("IAllocatorDirIn",  'C.iallocatorDirIn)
524
  , ("IAllocatorDirOut", 'C.iallocatorDirOut)
525
  ])
526
$(THH.makeJSONInstance ''IAllocatorTestDir)
527

    
528
-- | IAllocator mode. FIXME: use this in "HTools.Backend.IAlloc".
529
$(THH.declareSADT "IAllocatorMode"
530
  [ ("IAllocatorAlloc",       'C.iallocatorModeAlloc)
531
  , ("IAllocatorMultiAlloc",  'C.iallocatorModeMultiAlloc)
532
  , ("IAllocatorReloc",       'C.iallocatorModeReloc)
533
  , ("IAllocatorNodeEvac",    'C.iallocatorModeNodeEvac)
534
  , ("IAllocatorChangeGroup", 'C.iallocatorModeChgGroup)
535
  ])
536
$(THH.makeJSONInstance ''IAllocatorMode)
537

    
538
-- | Network mode.
539
$(THH.declareSADT "NICMode"
540
  [ ("NMBridged", 'C.nicModeBridged)
541
  , ("NMRouted",  'C.nicModeRouted)
542
  , ("NMOvs",     'C.nicModeOvs)
543
  ])
544
$(THH.makeJSONInstance ''NICMode)
545

    
546
-- | The JobStatus data type. Note that this is ordered especially
547
-- such that greater\/lesser comparison on values of this type makes
548
-- sense.
549
$(THH.declareSADT "JobStatus"
550
       [ ("JOB_STATUS_QUEUED",    'C.jobStatusQueued)
551
       , ("JOB_STATUS_WAITING",   'C.jobStatusWaiting)
552
       , ("JOB_STATUS_CANCELING", 'C.jobStatusCanceling)
553
       , ("JOB_STATUS_RUNNING",   'C.jobStatusRunning)
554
       , ("JOB_STATUS_CANCELED",  'C.jobStatusCanceled)
555
       , ("JOB_STATUS_SUCCESS",   'C.jobStatusSuccess)
556
       , ("JOB_STATUS_ERROR",     'C.jobStatusError)
557
       ])
558
$(THH.makeJSONInstance ''JobStatus)
559

    
560
-- | Finalized job status.
561
$(THH.declareSADT "FinalizedJobStatus"
562
  [ ("JobStatusCanceled",   'C.jobStatusCanceled)
563
  , ("JobStatusSuccessful", 'C.jobStatusSuccess)
564
  , ("JobStatusFailed",     'C.jobStatusError)
565
  ])
566
$(THH.makeJSONInstance ''FinalizedJobStatus)
567

    
568
-- | The Ganeti job type.
569
newtype JobId = JobId { fromJobId :: Int }
570
  deriving (Show, Eq)
571

    
572
-- | Builds a job ID.
573
makeJobId :: (Monad m) => Int -> m JobId
574
makeJobId i | i >= 0 = return $ JobId i
575
            | otherwise = fail $ "Invalid value for job ID ' " ++ show i ++ "'"
576

    
577
-- | Builds a job ID from a string.
578
makeJobIdS :: (Monad m) => String -> m JobId
579
makeJobIdS s = tryRead "parsing job id" s >>= makeJobId
580

    
581
-- | Parses a job ID.
582
parseJobId :: (Monad m) => JSON.JSValue -> m JobId
583
parseJobId (JSON.JSString x) = makeJobIdS $ JSON.fromJSString x
584
parseJobId (JSON.JSRational _ x) =
585
  if denominator x /= 1
586
    then fail $ "Got fractional job ID from master daemon?! Value:" ++ show x
587
    -- FIXME: potential integer overflow here on 32-bit platforms
588
    else makeJobId . fromIntegral . numerator $ x
589
parseJobId x = fail $ "Wrong type/value for job id: " ++ show x
590

    
591
instance JSON.JSON JobId where
592
  showJSON = JSON.showJSON . fromJobId
593
  readJSON = parseJobId
594

    
595
-- | Relative job ID type alias.
596
type RelativeJobId = Negative Int
597

    
598
-- | Job ID dependency.
599
data JobIdDep = JobDepRelative RelativeJobId
600
              | JobDepAbsolute JobId
601
                deriving (Show, Eq)
602

    
603
instance JSON.JSON JobIdDep where
604
  showJSON (JobDepRelative i) = showJSON i
605
  showJSON (JobDepAbsolute i) = showJSON i
606
  readJSON v =
607
    case JSON.readJSON v::JSON.Result (Negative Int) of
608
      -- first try relative dependency, usually most common
609
      JSON.Ok r -> return $ JobDepRelative r
610
      JSON.Error _ -> liftM JobDepAbsolute (parseJobId v)
611

    
612
-- | Job Dependency type.
613
data JobDependency = JobDependency JobIdDep [FinalizedJobStatus]
614
                     deriving (Show, Eq)
615

    
616
instance JSON JobDependency where
617
  showJSON (JobDependency dep status) = showJSON (dep, status)
618
  readJSON = liftM (uncurry JobDependency) . readJSON
619

    
620
-- | Valid opcode priorities for submit.
621
$(THH.declareIADT "OpSubmitPriority"
622
  [ ("OpPrioLow",    'C.opPrioLow)
623
  , ("OpPrioNormal", 'C.opPrioNormal)
624
  , ("OpPrioHigh",   'C.opPrioHigh)
625
  ])
626
$(THH.makeJSONInstance ''OpSubmitPriority)
627

    
628
-- | Parse submit priorities from a string.
629
parseSubmitPriority :: (Monad m) => String -> m OpSubmitPriority
630
parseSubmitPriority "low"    = return OpPrioLow
631
parseSubmitPriority "normal" = return OpPrioNormal
632
parseSubmitPriority "high"   = return OpPrioHigh
633
parseSubmitPriority str      = fail $ "Unknown priority '" ++ str ++ "'"
634

    
635
-- | Format a submit priority as string.
636
fmtSubmitPriority :: OpSubmitPriority -> String
637
fmtSubmitPriority OpPrioLow    = "low"
638
fmtSubmitPriority OpPrioNormal = "normal"
639
fmtSubmitPriority OpPrioHigh   = "high"
640

    
641
-- | Our ADT for the OpCode status at runtime (while in a job).
642
$(THH.declareSADT "OpStatus"
643
  [ ("OP_STATUS_QUEUED",    'C.opStatusQueued)
644
  , ("OP_STATUS_WAITING",   'C.opStatusWaiting)
645
  , ("OP_STATUS_CANCELING", 'C.opStatusCanceling)
646
  , ("OP_STATUS_RUNNING",   'C.opStatusRunning)
647
  , ("OP_STATUS_CANCELED",  'C.opStatusCanceled)
648
  , ("OP_STATUS_SUCCESS",   'C.opStatusSuccess)
649
  , ("OP_STATUS_ERROR",     'C.opStatusError)
650
  ])
651
$(THH.makeJSONInstance ''OpStatus)
652

    
653
-- | Type for the job message type.
654
$(THH.declareSADT "ELogType"
655
  [ ("ELogMessage",      'C.elogMessage)
656
  , ("ELogRemoteImport", 'C.elogRemoteImport)
657
  , ("ELogJqueueTest",   'C.elogJqueueTest)
658
  ])
659
$(THH.makeJSONInstance ''ELogType)
660

    
661
-- | Type of one element of a reason trail.
662
type ReasonElem = (String, String, Integer)
663

    
664
-- | Type representing a reason trail.
665
type ReasonTrail = [ReasonElem]