Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Types.hs @ 3f173b09

History | View | Annotate | Download (29.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
  , OobStatus(..)
82
  , oobStatusToRaw
83
  , StorageType(..)
84
  , storageTypeToRaw
85
  , EvacMode(..)
86
  , evacModeToRaw
87
  , FileDriver(..)
88
  , fileDriverToRaw
89
  , InstCreateMode(..)
90
  , instCreateModeToRaw
91
  , RebootType(..)
92
  , rebootTypeToRaw
93
  , ExportMode(..)
94
  , exportModeToRaw
95
  , IAllocatorTestDir(..)
96
  , iAllocatorTestDirToRaw
97
  , IAllocatorMode(..)
98
  , iAllocatorModeToRaw
99
  , NICMode(..)
100
  , nICModeToRaw
101
  , JobStatus(..)
102
  , jobStatusToRaw
103
  , jobStatusFromRaw
104
  , FinalizedJobStatus(..)
105
  , finalizedJobStatusToRaw
106
  , JobId
107
  , fromJobId
108
  , makeJobId
109
  , makeJobIdS
110
  , RelativeJobId
111
  , JobIdDep(..)
112
  , JobDependency(..)
113
  , absoluteJobDependency
114
  , OpSubmitPriority(..)
115
  , opSubmitPriorityToRaw
116
  , parseSubmitPriority
117
  , fmtSubmitPriority
118
  , OpStatus(..)
119
  , opStatusToRaw
120
  , opStatusFromRaw
121
  , ELogType(..)
122
  , eLogTypeToRaw
123
  , ReasonElem
124
  , ReasonTrail
125
  , StorageUnit(..)
126
  , StorageUnitRaw(..)
127
  , StorageKey
128
  , addParamsToStorageUnit
129
  , diskTemplateToStorageType
130
  , VType(..)
131
  , vTypeFromRaw
132
  , vTypeToRaw
133
  , NodeRole(..)
134
  , nodeRoleToRaw
135
  , roleDescription
136
  , DiskMode(..)
137
  , diskModeToRaw
138
  , BlockDriver(..)
139
  , blockDriverToRaw
140
  , AdminState(..)
141
  , adminStateFromRaw
142
  , adminStateToRaw
143
  , StorageField(..)
144
  , storageFieldToRaw
145
  , DiskAccessMode(..)
146
  , diskAccessModeToRaw
147
  , LocalDiskStatus(..)
148
  , localDiskStatusFromRaw
149
  , localDiskStatusToRaw
150
  , localDiskStatusName
151
  , ReplaceDisksMode(..)
152
  , replaceDisksModeToRaw
153
  , RpcTimeout(..)
154
  , rpcTimeoutFromRaw -- FIXME: no used anywhere
155
  , rpcTimeoutToRaw
156
  , ImportExportCompression(..)
157
  , importExportCompressionToRaw
158
  , HotplugTarget(..)
159
  , hotplugTargetToRaw
160
  , HotplugAction(..)
161
  , hotplugActionToRaw
162
  , Private(..)
163
  , showPrivateJSObject
164
  ) where
165

    
166
import Control.Monad (liftM)
167
import qualified Text.JSON as JSON
168
import Text.JSON (JSON, readJSON, showJSON)
169
import Data.Ratio (numerator, denominator)
170

    
171
import qualified Ganeti.ConstantUtils as ConstantUtils
172
import Ganeti.JSON
173
import qualified Ganeti.THH as THH
174
import Ganeti.Utils
175

    
176
-- * Generic types
177

    
178
-- | Type that holds a non-negative value.
179
newtype NonNegative a = NonNegative { fromNonNegative :: a }
180
  deriving (Show, Eq)
181

    
182
-- | Smart constructor for 'NonNegative'.
183
mkNonNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (NonNegative a)
184
mkNonNegative i | i >= 0 = return (NonNegative i)
185
                | otherwise = fail $ "Invalid value for non-negative type '" ++
186
                              show i ++ "'"
187

    
188
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (NonNegative a) where
189
  showJSON = JSON.showJSON . fromNonNegative
190
  readJSON v = JSON.readJSON v >>= mkNonNegative
191

    
192
-- | Type that holds a positive value.
193
newtype Positive a = Positive { fromPositive :: a }
194
  deriving (Show, Eq)
195

    
196
-- | Smart constructor for 'Positive'.
197
mkPositive :: (Monad m, Num a, Ord a, Show a) => a -> m (Positive a)
198
mkPositive i | i > 0 = return (Positive i)
199
             | otherwise = fail $ "Invalid value for positive type '" ++
200
                           show i ++ "'"
201

    
202
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Positive a) where
203
  showJSON = JSON.showJSON . fromPositive
204
  readJSON v = JSON.readJSON v >>= mkPositive
205

    
206
-- | Type that holds a negative value.
207
newtype Negative a = Negative { fromNegative :: a }
208
  deriving (Show, Eq)
209

    
210
-- | Smart constructor for 'Negative'.
211
mkNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (Negative a)
212
mkNegative i | i < 0 = return (Negative i)
213
             | otherwise = fail $ "Invalid value for negative type '" ++
214
                           show i ++ "'"
215

    
216
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Negative a) where
217
  showJSON = JSON.showJSON . fromNegative
218
  readJSON v = JSON.readJSON v >>= mkNegative
219

    
220
-- | Type that holds a non-null list.
221
newtype NonEmpty a = NonEmpty { fromNonEmpty :: [a] }
222
  deriving (Show, Eq)
223

    
224
-- | Smart constructor for 'NonEmpty'.
225
mkNonEmpty :: (Monad m) => [a] -> m (NonEmpty a)
226
mkNonEmpty [] = fail "Received empty value for non-empty list"
227
mkNonEmpty xs = return (NonEmpty xs)
228

    
229
instance (Eq a, Ord a) => Ord (NonEmpty a) where
230
  NonEmpty { fromNonEmpty = x1 } `compare` NonEmpty { fromNonEmpty = x2 } =
231
    x1 `compare` x2
232

    
233
instance (JSON.JSON a) => JSON.JSON (NonEmpty a) where
234
  showJSON = JSON.showJSON . fromNonEmpty
235
  readJSON v = JSON.readJSON v >>= mkNonEmpty
236

    
237
-- | A simple type alias for non-empty strings.
238
type NonEmptyString = NonEmpty Char
239

    
240
type QueryResultCode = Int
241

    
242
newtype IPv4Address = IPv4Address { fromIPv4Address :: String }
243
  deriving (Show, Eq)
244

    
245
-- FIXME: this should check that 'address' is a valid ip
246
mkIPv4Address :: Monad m => String -> m IPv4Address
247
mkIPv4Address address =
248
  return IPv4Address { fromIPv4Address = address }
249

    
250
instance JSON.JSON IPv4Address where
251
  showJSON = JSON.showJSON . fromIPv4Address
252
  readJSON v = JSON.readJSON v >>= mkIPv4Address
253

    
254
newtype IPv4Network = IPv4Network { fromIPv4Network :: String }
255
  deriving (Show, Eq)
256

    
257
-- FIXME: this should check that 'address' is a valid ip
258
mkIPv4Network :: Monad m => String -> m IPv4Network
259
mkIPv4Network address =
260
  return IPv4Network { fromIPv4Network = address }
261

    
262
instance JSON.JSON IPv4Network where
263
  showJSON = JSON.showJSON . fromIPv4Network
264
  readJSON v = JSON.readJSON v >>= mkIPv4Network
265

    
266
newtype IPv6Address = IPv6Address { fromIPv6Address :: String }
267
  deriving (Show, Eq)
268

    
269
-- FIXME: this should check that 'address' is a valid ip
270
mkIPv6Address :: Monad m => String -> m IPv6Address
271
mkIPv6Address address =
272
  return IPv6Address { fromIPv6Address = address }
273

    
274
instance JSON.JSON IPv6Address where
275
  showJSON = JSON.showJSON . fromIPv6Address
276
  readJSON v = JSON.readJSON v >>= mkIPv6Address
277

    
278
newtype IPv6Network = IPv6Network { fromIPv6Network :: String }
279
  deriving (Show, Eq)
280

    
281
-- FIXME: this should check that 'address' is a valid ip
282
mkIPv6Network :: Monad m => String -> m IPv6Network
283
mkIPv6Network address =
284
  return IPv6Network { fromIPv6Network = address }
285

    
286
instance JSON.JSON IPv6Network where
287
  showJSON = JSON.showJSON . fromIPv6Network
288
  readJSON v = JSON.readJSON v >>= mkIPv6Network
289

    
290
-- * Ganeti types
291

    
292
-- | Instance disk template type.
293
$(THH.declareLADT ''String "DiskTemplate"
294
       [ ("DTDiskless",   "diskless")
295
       , ("DTFile",       "file")
296
       , ("DTSharedFile", "sharedfile")
297
       , ("DTPlain",      "plain")
298
       , ("DTBlock",      "blockdev")
299
       , ("DTDrbd8",      "drbd")
300
       , ("DTRbd",        "rbd")
301
       , ("DTExt",        "ext")
302
       , ("DTGluster",    "gluster")
303
       ])
304
$(THH.makeJSONInstance ''DiskTemplate)
305

    
306
instance THH.PyValue DiskTemplate where
307
  showValue = show . diskTemplateToRaw
308

    
309
instance HasStringRepr DiskTemplate where
310
  fromStringRepr = diskTemplateFromRaw
311
  toStringRepr = diskTemplateToRaw
312

    
313
-- | Data type representing what items the tag operations apply to.
314
$(THH.declareLADT ''String "TagKind"
315
  [ ("TagKindInstance", "instance")
316
  , ("TagKindNode",     "node")
317
  , ("TagKindGroup",    "nodegroup")
318
  , ("TagKindCluster",  "cluster")
319
  , ("TagKindNetwork",  "network")
320
  ])
321
$(THH.makeJSONInstance ''TagKind)
322

    
323
-- | The Group allocation policy type.
324
--
325
-- Note that the order of constructors is important as the automatic
326
-- Ord instance will order them in the order they are defined, so when
327
-- changing this data type be careful about the interaction with the
328
-- desired sorting order.
329
$(THH.declareLADT ''String "AllocPolicy"
330
       [ ("AllocPreferred",   "preferred")
331
       , ("AllocLastResort",  "last_resort")
332
       , ("AllocUnallocable", "unallocable")
333
       ])
334
$(THH.makeJSONInstance ''AllocPolicy)
335

    
336
-- | The Instance real state type.
337
$(THH.declareLADT ''String "InstanceStatus"
338
       [ ("StatusDown",    "ADMIN_down")
339
       , ("StatusOffline", "ADMIN_offline")
340
       , ("ErrorDown",     "ERROR_down")
341
       , ("ErrorUp",       "ERROR_up")
342
       , ("NodeDown",      "ERROR_nodedown")
343
       , ("NodeOffline",   "ERROR_nodeoffline")
344
       , ("Running",       "running")
345
       , ("UserDown",      "USER_down")
346
       , ("WrongNode",     "ERROR_wrongnode")
347
       ])
348
$(THH.makeJSONInstance ''InstanceStatus)
349

    
350
-- | Migration mode.
351
$(THH.declareLADT ''String "MigrationMode"
352
     [ ("MigrationLive",    "live")
353
     , ("MigrationNonLive", "non-live")
354
     ])
355
$(THH.makeJSONInstance ''MigrationMode)
356

    
357
-- | Verify optional checks.
358
$(THH.declareLADT ''String "VerifyOptionalChecks"
359
     [ ("VerifyNPlusOneMem", "nplusone_mem")
360
     ])
361
$(THH.makeJSONInstance ''VerifyOptionalChecks)
362

    
363
-- | Cluster verify error codes.
364
$(THH.declareLADT ''String "CVErrorCode"
365
  [ ("CvECLUSTERCFG",                  "ECLUSTERCFG")
366
  , ("CvECLUSTERCERT",                 "ECLUSTERCERT")
367
  , ("CvECLUSTERCLIENTCERT",           "ECLUSTERCLIENTCERT")
368
  , ("CvECLUSTERFILECHECK",            "ECLUSTERFILECHECK")
369
  , ("CvECLUSTERDANGLINGNODES",        "ECLUSTERDANGLINGNODES")
370
  , ("CvECLUSTERDANGLINGINST",         "ECLUSTERDANGLINGINST")
371
  , ("CvEINSTANCEBADNODE",             "EINSTANCEBADNODE")
372
  , ("CvEINSTANCEDOWN",                "EINSTANCEDOWN")
373
  , ("CvEINSTANCELAYOUT",              "EINSTANCELAYOUT")
374
  , ("CvEINSTANCEMISSINGDISK",         "EINSTANCEMISSINGDISK")
375
  , ("CvEINSTANCEFAULTYDISK",          "EINSTANCEFAULTYDISK")
376
  , ("CvEINSTANCEWRONGNODE",           "EINSTANCEWRONGNODE")
377
  , ("CvEINSTANCESPLITGROUPS",         "EINSTANCESPLITGROUPS")
378
  , ("CvEINSTANCEPOLICY",              "EINSTANCEPOLICY")
379
  , ("CvEINSTANCEUNSUITABLENODE",      "EINSTANCEUNSUITABLENODE")
380
  , ("CvEINSTANCEMISSINGCFGPARAMETER", "EINSTANCEMISSINGCFGPARAMETER")
381
  , ("CvENODEDRBD",                    "ENODEDRBD")
382
  , ("CvENODEDRBDVERSION",             "ENODEDRBDVERSION")
383
  , ("CvENODEDRBDHELPER",              "ENODEDRBDHELPER")
384
  , ("CvENODEFILECHECK",               "ENODEFILECHECK")
385
  , ("CvENODEHOOKS",                   "ENODEHOOKS")
386
  , ("CvENODEHV",                      "ENODEHV")
387
  , ("CvENODELVM",                     "ENODELVM")
388
  , ("CvENODEN1",                      "ENODEN1")
389
  , ("CvENODENET",                     "ENODENET")
390
  , ("CvENODEOS",                      "ENODEOS")
391
  , ("CvENODEORPHANINSTANCE",          "ENODEORPHANINSTANCE")
392
  , ("CvENODEORPHANLV",                "ENODEORPHANLV")
393
  , ("CvENODERPC",                     "ENODERPC")
394
  , ("CvENODESSH",                     "ENODESSH")
395
  , ("CvENODEVERSION",                 "ENODEVERSION")
396
  , ("CvENODESETUP",                   "ENODESETUP")
397
  , ("CvENODETIME",                    "ENODETIME")
398
  , ("CvENODEOOBPATH",                 "ENODEOOBPATH")
399
  , ("CvENODEUSERSCRIPTS",             "ENODEUSERSCRIPTS")
400
  , ("CvENODEFILESTORAGEPATHS",        "ENODEFILESTORAGEPATHS")
401
  , ("CvENODEFILESTORAGEPATHUNUSABLE", "ENODEFILESTORAGEPATHUNUSABLE")
402
  , ("CvENODESHAREDFILESTORAGEPATHUNUSABLE",
403
     "ENODESHAREDFILESTORAGEPATHUNUSABLE")
404
  , ("CvEGROUPDIFFERENTPVSIZE",        "EGROUPDIFFERENTPVSIZE")
405
  ])
406
$(THH.makeJSONInstance ''CVErrorCode)
407

    
408
-- | Dynamic device modification, just add\/remove version.
409
$(THH.declareLADT ''String "DdmSimple"
410
     [ ("DdmSimpleAdd",    "add")
411
     , ("DdmSimpleRemove", "remove")
412
     ])
413
$(THH.makeJSONInstance ''DdmSimple)
414

    
415
-- | Dynamic device modification, all operations version.
416
--
417
-- TODO: DDM_SWAP, DDM_MOVE?
418
$(THH.declareLADT ''String "DdmFull"
419
     [ ("DdmFullAdd",    "add")
420
     , ("DdmFullRemove", "remove")
421
     , ("DdmFullModify", "modify")
422
     ])
423
$(THH.makeJSONInstance ''DdmFull)
424

    
425
-- | Hypervisor type definitions.
426
$(THH.declareLADT ''String "Hypervisor"
427
  [ ("Kvm",    "kvm")
428
  , ("XenPvm", "xen-pvm")
429
  , ("Chroot", "chroot")
430
  , ("XenHvm", "xen-hvm")
431
  , ("Lxc",    "lxc")
432
  , ("Fake",   "fake")
433
  ])
434
$(THH.makeJSONInstance ''Hypervisor)
435

    
436
instance THH.PyValue Hypervisor where
437
  showValue = show . hypervisorToRaw
438

    
439
instance HasStringRepr Hypervisor where
440
  fromStringRepr = hypervisorFromRaw
441
  toStringRepr = hypervisorToRaw
442

    
443
-- | Oob command type.
444
$(THH.declareLADT ''String "OobCommand"
445
  [ ("OobHealth",      "health")
446
  , ("OobPowerCycle",  "power-cycle")
447
  , ("OobPowerOff",    "power-off")
448
  , ("OobPowerOn",     "power-on")
449
  , ("OobPowerStatus", "power-status")
450
  ])
451
$(THH.makeJSONInstance ''OobCommand)
452

    
453
-- | Oob command status
454
$(THH.declareLADT ''String "OobStatus"
455
  [ ("OobStatusCritical", "CRITICAL")
456
  , ("OobStatusOk",       "OK")
457
  , ("OobStatusUnknown",  "UNKNOWN")
458
  , ("OobStatusWarning",  "WARNING")
459
  ])
460
$(THH.makeJSONInstance ''OobStatus)
461

    
462
-- | Storage type.
463
$(THH.declareLADT ''String "StorageType"
464
  [ ("StorageFile", "file")
465
  , ("StorageSharedFile", "sharedfile")
466
  , ("StorageLvmPv", "lvm-pv")
467
  , ("StorageLvmVg", "lvm-vg")
468
  , ("StorageDiskless", "diskless")
469
  , ("StorageBlock", "blockdev")
470
  , ("StorageRados", "rados")
471
  , ("StorageExt", "ext")
472
  ])
473
$(THH.makeJSONInstance ''StorageType)
474

    
475
-- | Storage keys are identifiers for storage units. Their content varies
476
-- depending on the storage type, for example a storage key for LVM storage
477
-- is the volume group name.
478
type StorageKey = String
479

    
480
-- | Storage parameters
481
type SPExclusiveStorage = Bool
482

    
483
-- | Storage units without storage-type-specific parameters
484
data StorageUnitRaw = SURaw StorageType StorageKey
485

    
486
-- | Full storage unit with storage-type-specific parameters
487
data StorageUnit = SUFile StorageKey
488
                 | SUSharedFile StorageKey
489
                 | SULvmPv StorageKey SPExclusiveStorage
490
                 | SULvmVg StorageKey SPExclusiveStorage
491
                 | SUDiskless StorageKey
492
                 | SUBlock StorageKey
493
                 | SURados StorageKey
494
                 | SUExt StorageKey
495
                 deriving (Eq)
496

    
497
instance Show StorageUnit where
498
  show (SUFile key) = showSUSimple StorageFile key
499
  show (SUSharedFile key) = showSUSimple StorageSharedFile key
500
  show (SULvmPv key es) = showSULvm StorageLvmPv key es
501
  show (SULvmVg key es) = showSULvm StorageLvmVg key es
502
  show (SUDiskless key) = showSUSimple StorageDiskless key
503
  show (SUBlock key) = showSUSimple StorageBlock key
504
  show (SURados key) = showSUSimple StorageRados key
505
  show (SUExt key) = showSUSimple StorageExt key
506

    
507
instance JSON StorageUnit where
508
  showJSON (SUFile key) = showJSON (StorageFile, key, []::[String])
509
  showJSON (SUSharedFile key) = showJSON (StorageSharedFile, key, []::[String])
510
  showJSON (SULvmPv key es) = showJSON (StorageLvmPv, key, [es])
511
  showJSON (SULvmVg key es) = showJSON (StorageLvmVg, key, [es])
512
  showJSON (SUDiskless key) = showJSON (StorageDiskless, key, []::[String])
513
  showJSON (SUBlock key) = showJSON (StorageBlock, key, []::[String])
514
  showJSON (SURados key) = showJSON (StorageRados, key, []::[String])
515
  showJSON (SUExt key) = showJSON (StorageExt, key, []::[String])
516
-- FIXME: add readJSON implementation
517
  readJSON = fail "Not implemented"
518

    
519
-- | Composes a string representation of storage types without
520
-- storage parameters
521
showSUSimple :: StorageType -> StorageKey -> String
522
showSUSimple st sk = show (storageTypeToRaw st, sk, []::[String])
523

    
524
-- | Composes a string representation of the LVM storage types
525
showSULvm :: StorageType -> StorageKey -> SPExclusiveStorage -> String
526
showSULvm st sk es = show (storageTypeToRaw st, sk, [es])
527

    
528
-- | Mapping from disk templates to storage types
529
-- FIXME: This is semantically the same as the constant
530
-- C.diskTemplatesStorageType, remove this when python constants
531
-- are generated from haskell constants
532
diskTemplateToStorageType :: DiskTemplate -> StorageType
533
diskTemplateToStorageType DTExt = StorageExt
534
diskTemplateToStorageType DTFile = StorageFile
535
diskTemplateToStorageType DTSharedFile = StorageSharedFile
536
diskTemplateToStorageType DTDrbd8 = StorageLvmVg
537
diskTemplateToStorageType DTPlain = StorageLvmVg
538
diskTemplateToStorageType DTRbd = StorageRados
539
diskTemplateToStorageType DTDiskless = StorageDiskless
540
diskTemplateToStorageType DTBlock = StorageBlock
541
diskTemplateToStorageType DTGluster = StorageSharedFile
542

    
543
-- | Equips a raw storage unit with its parameters
544
addParamsToStorageUnit :: SPExclusiveStorage -> StorageUnitRaw -> StorageUnit
545
addParamsToStorageUnit _ (SURaw StorageBlock key) = SUBlock key
546
addParamsToStorageUnit _ (SURaw StorageDiskless key) = SUDiskless key
547
addParamsToStorageUnit _ (SURaw StorageExt key) = SUExt key
548
addParamsToStorageUnit _ (SURaw StorageFile key) = SUFile key
549
addParamsToStorageUnit _ (SURaw StorageSharedFile key) = SUSharedFile key
550
addParamsToStorageUnit es (SURaw StorageLvmPv key) = SULvmPv key es
551
addParamsToStorageUnit es (SURaw StorageLvmVg key) = SULvmVg key es
552
addParamsToStorageUnit _ (SURaw StorageRados key) = SURados key
553

    
554
-- | Node evac modes.
555
--
556
-- This is part of the 'IAllocator' interface and it is used, for
557
-- example, in 'Ganeti.HTools.Loader.RqType'.  However, it must reside
558
-- in this module, and not in 'Ganeti.HTools.Types', because it is
559
-- also used by 'Ganeti.Constants'.
560
$(THH.declareLADT ''String "EvacMode"
561
  [ ("ChangePrimary",   "primary-only")
562
  , ("ChangeSecondary", "secondary-only")
563
  , ("ChangeAll",       "all")
564
  ])
565
$(THH.makeJSONInstance ''EvacMode)
566

    
567
-- | The file driver type.
568
$(THH.declareLADT ''String "FileDriver"
569
  [ ("FileLoop",   "loop")
570
  , ("FileBlktap", "blktap")
571
  , ("FileBlktap2", "blktap2")
572
  ])
573
$(THH.makeJSONInstance ''FileDriver)
574

    
575
-- | The instance create mode.
576
$(THH.declareLADT ''String "InstCreateMode"
577
  [ ("InstCreate",       "create")
578
  , ("InstImport",       "import")
579
  , ("InstRemoteImport", "remote-import")
580
  ])
581
$(THH.makeJSONInstance ''InstCreateMode)
582

    
583
-- | Reboot type.
584
$(THH.declareLADT ''String "RebootType"
585
  [ ("RebootSoft", "soft")
586
  , ("RebootHard", "hard")
587
  , ("RebootFull", "full")
588
  ])
589
$(THH.makeJSONInstance ''RebootType)
590

    
591
-- | Export modes.
592
$(THH.declareLADT ''String "ExportMode"
593
  [ ("ExportModeLocal",  "local")
594
  , ("ExportModeRemote", "remote")
595
  ])
596
$(THH.makeJSONInstance ''ExportMode)
597

    
598
-- | IAllocator run types (OpTestIAllocator).
599
$(THH.declareLADT ''String "IAllocatorTestDir"
600
  [ ("IAllocatorDirIn",  "in")
601
  , ("IAllocatorDirOut", "out")
602
  ])
603
$(THH.makeJSONInstance ''IAllocatorTestDir)
604

    
605
-- | IAllocator mode. FIXME: use this in "HTools.Backend.IAlloc".
606
$(THH.declareLADT ''String "IAllocatorMode"
607
  [ ("IAllocatorAlloc",       "allocate")
608
  , ("IAllocatorMultiAlloc",  "multi-allocate")
609
  , ("IAllocatorReloc",       "relocate")
610
  , ("IAllocatorNodeEvac",    "node-evacuate")
611
  , ("IAllocatorChangeGroup", "change-group")
612
  ])
613
$(THH.makeJSONInstance ''IAllocatorMode)
614

    
615
-- | Network mode.
616
$(THH.declareLADT ''String "NICMode"
617
  [ ("NMBridged", "bridged")
618
  , ("NMRouted",  "routed")
619
  , ("NMOvs",     "openvswitch")
620
  , ("NMPool",    "pool")
621
  ])
622
$(THH.makeJSONInstance ''NICMode)
623

    
624
-- | The JobStatus data type. Note that this is ordered especially
625
-- such that greater\/lesser comparison on values of this type makes
626
-- sense.
627
$(THH.declareLADT ''String "JobStatus"
628
  [ ("JOB_STATUS_QUEUED",    "queued")
629
  , ("JOB_STATUS_WAITING",   "waiting")
630
  , ("JOB_STATUS_CANCELING", "canceling")
631
  , ("JOB_STATUS_RUNNING",   "running")
632
  , ("JOB_STATUS_CANCELED",  "canceled")
633
  , ("JOB_STATUS_SUCCESS",   "success")
634
  , ("JOB_STATUS_ERROR",     "error")
635
  ])
636
$(THH.makeJSONInstance ''JobStatus)
637

    
638
-- | Finalized job status.
639
$(THH.declareLADT ''String "FinalizedJobStatus"
640
  [ ("JobStatusCanceled",   "canceled")
641
  , ("JobStatusSuccessful", "success")
642
  , ("JobStatusFailed",     "error")
643
  ])
644
$(THH.makeJSONInstance ''FinalizedJobStatus)
645

    
646
-- | The Ganeti job type.
647
newtype JobId = JobId { fromJobId :: Int }
648
  deriving (Show, Eq, Ord)
649

    
650
-- | Builds a job ID.
651
makeJobId :: (Monad m) => Int -> m JobId
652
makeJobId i | i >= 0 = return $ JobId i
653
            | otherwise = fail $ "Invalid value for job ID ' " ++ show i ++ "'"
654

    
655
-- | Builds a job ID from a string.
656
makeJobIdS :: (Monad m) => String -> m JobId
657
makeJobIdS s = tryRead "parsing job id" s >>= makeJobId
658

    
659
-- | Parses a job ID.
660
parseJobId :: (Monad m) => JSON.JSValue -> m JobId
661
parseJobId (JSON.JSString x) = makeJobIdS $ JSON.fromJSString x
662
parseJobId (JSON.JSRational _ x) =
663
  if denominator x /= 1
664
    then fail $ "Got fractional job ID from master daemon?! Value:" ++ show x
665
    -- FIXME: potential integer overflow here on 32-bit platforms
666
    else makeJobId . fromIntegral . numerator $ x
667
parseJobId x = fail $ "Wrong type/value for job id: " ++ show x
668

    
669
instance JSON.JSON JobId where
670
  showJSON = JSON.showJSON . fromJobId
671
  readJSON = parseJobId
672

    
673
-- | Relative job ID type alias.
674
type RelativeJobId = Negative Int
675

    
676
-- | Job ID dependency.
677
data JobIdDep = JobDepRelative RelativeJobId
678
              | JobDepAbsolute JobId
679
                deriving (Show, Eq)
680

    
681
instance JSON.JSON JobIdDep where
682
  showJSON (JobDepRelative i) = showJSON i
683
  showJSON (JobDepAbsolute i) = showJSON i
684
  readJSON v =
685
    case JSON.readJSON v::JSON.Result (Negative Int) of
686
      -- first try relative dependency, usually most common
687
      JSON.Ok r -> return $ JobDepRelative r
688
      JSON.Error _ -> liftM JobDepAbsolute (parseJobId v)
689

    
690
-- | From job ID dependency and job ID, compute the absolute dependency.
691
absoluteJobIdDep :: (Monad m) => JobIdDep -> JobId -> m JobIdDep
692
absoluteJobIdDep (JobDepAbsolute jid) _ = return $ JobDepAbsolute jid
693
absoluteJobIdDep (JobDepRelative rjid) jid =
694
  liftM JobDepAbsolute . makeJobId $ fromJobId jid + fromNegative rjid
695

    
696
-- | Job Dependency type.
697
data JobDependency = JobDependency JobIdDep [FinalizedJobStatus]
698
                     deriving (Show, Eq)
699

    
700
instance JSON JobDependency where
701
  showJSON (JobDependency dep status) = showJSON (dep, status)
702
  readJSON = liftM (uncurry JobDependency) . readJSON
703

    
704
-- | From job dependency and job id compute an absolute job dependency.
705
absoluteJobDependency :: (Monad m) => JobDependency -> JobId -> m JobDependency
706
absoluteJobDependency (JobDependency jdep fstats) jid =
707
  liftM (flip JobDependency fstats) $ absoluteJobIdDep jdep jid
708

    
709
-- | Valid opcode priorities for submit.
710
$(THH.declareIADT "OpSubmitPriority"
711
  [ ("OpPrioLow",    'ConstantUtils.priorityLow)
712
  , ("OpPrioNormal", 'ConstantUtils.priorityNormal)
713
  , ("OpPrioHigh",   'ConstantUtils.priorityHigh)
714
  ])
715
$(THH.makeJSONInstance ''OpSubmitPriority)
716

    
717
-- | Parse submit priorities from a string.
718
parseSubmitPriority :: (Monad m) => String -> m OpSubmitPriority
719
parseSubmitPriority "low"    = return OpPrioLow
720
parseSubmitPriority "normal" = return OpPrioNormal
721
parseSubmitPriority "high"   = return OpPrioHigh
722
parseSubmitPriority str      = fail $ "Unknown priority '" ++ str ++ "'"
723

    
724
-- | Format a submit priority as string.
725
fmtSubmitPriority :: OpSubmitPriority -> String
726
fmtSubmitPriority OpPrioLow    = "low"
727
fmtSubmitPriority OpPrioNormal = "normal"
728
fmtSubmitPriority OpPrioHigh   = "high"
729

    
730
-- | Our ADT for the OpCode status at runtime (while in a job).
731
$(THH.declareLADT ''String "OpStatus"
732
  [ ("OP_STATUS_QUEUED",    "queued")
733
  , ("OP_STATUS_WAITING",   "waiting")
734
  , ("OP_STATUS_CANCELING", "canceling")
735
  , ("OP_STATUS_RUNNING",   "running")
736
  , ("OP_STATUS_CANCELED",  "canceled")
737
  , ("OP_STATUS_SUCCESS",   "success")
738
  , ("OP_STATUS_ERROR",     "error")
739
  ])
740
$(THH.makeJSONInstance ''OpStatus)
741

    
742
-- | Type for the job message type.
743
$(THH.declareLADT ''String "ELogType"
744
  [ ("ELogMessage",      "message")
745
  , ("ELogRemoteImport", "remote-import")
746
  , ("ELogJqueueTest",   "jqueue-test")
747
  ])
748
$(THH.makeJSONInstance ''ELogType)
749

    
750
-- | Type of one element of a reason trail.
751
type ReasonElem = (String, String, Integer)
752

    
753
-- | Type representing a reason trail.
754
type ReasonTrail = [ReasonElem]
755

    
756
-- | The VTYPES, a mini-type system in Python.
757
$(THH.declareLADT ''String "VType"
758
  [ ("VTypeString",      "string")
759
  , ("VTypeMaybeString", "maybe-string")
760
  , ("VTypeBool",        "bool")
761
  , ("VTypeSize",        "size")
762
  , ("VTypeInt",         "int")
763
  ])
764
$(THH.makeJSONInstance ''VType)
765

    
766
instance THH.PyValue VType where
767
  showValue = THH.showValue . vTypeToRaw
768

    
769
-- * Node role type
770

    
771
$(THH.declareLADT ''String "NodeRole"
772
  [ ("NROffline",   "O")
773
  , ("NRDrained",   "D")
774
  , ("NRRegular",   "R")
775
  , ("NRCandidate", "C")
776
  , ("NRMaster",    "M")
777
  ])
778
$(THH.makeJSONInstance ''NodeRole)
779

    
780
-- | The description of the node role.
781
roleDescription :: NodeRole -> String
782
roleDescription NROffline   = "offline"
783
roleDescription NRDrained   = "drained"
784
roleDescription NRRegular   = "regular"
785
roleDescription NRCandidate = "master candidate"
786
roleDescription NRMaster    = "master"
787

    
788
-- * Disk types
789

    
790
$(THH.declareLADT ''String "DiskMode"
791
  [ ("DiskRdOnly", "ro")
792
  , ("DiskRdWr",   "rw")
793
  ])
794
$(THH.makeJSONInstance ''DiskMode)
795

    
796
-- | The persistent block driver type. Currently only one type is allowed.
797
$(THH.declareLADT ''String "BlockDriver"
798
  [ ("BlockDrvManual", "manual")
799
  ])
800
$(THH.makeJSONInstance ''BlockDriver)
801

    
802
-- * Instance types
803

    
804
$(THH.declareLADT ''String "AdminState"
805
  [ ("AdminOffline", "offline")
806
  , ("AdminDown",    "down")
807
  , ("AdminUp",      "up")
808
  ])
809
$(THH.makeJSONInstance ''AdminState)
810

    
811
-- * Storage field type
812

    
813
$(THH.declareLADT ''String "StorageField"
814
  [ ( "SFUsed",        "used")
815
  , ( "SFName",        "name")
816
  , ( "SFAllocatable", "allocatable")
817
  , ( "SFFree",        "free")
818
  , ( "SFSize",        "size")
819
  ])
820
$(THH.makeJSONInstance ''StorageField)
821

    
822
-- * Disk access protocol
823

    
824
$(THH.declareLADT ''String "DiskAccessMode"
825
  [ ( "DiskUserspace",   "userspace")
826
  , ( "DiskKernelspace", "kernelspace")
827
  ])
828
$(THH.makeJSONInstance ''DiskAccessMode)
829

    
830
-- | Local disk status
831
--
832
-- Python code depends on:
833
--   DiskStatusOk < DiskStatusUnknown < DiskStatusFaulty
834
$(THH.declareILADT "LocalDiskStatus"
835
  [ ("DiskStatusFaulty",  3)
836
  , ("DiskStatusOk",      1)
837
  , ("DiskStatusUnknown", 2)
838
  ])
839

    
840
localDiskStatusName :: LocalDiskStatus -> String
841
localDiskStatusName DiskStatusFaulty = "faulty"
842
localDiskStatusName DiskStatusOk = "ok"
843
localDiskStatusName DiskStatusUnknown = "unknown"
844

    
845
-- | Replace disks type.
846
$(THH.declareLADT ''String "ReplaceDisksMode"
847
  [ -- Replace disks on primary
848
    ("ReplaceOnPrimary",    "replace_on_primary")
849
    -- Replace disks on secondary
850
  , ("ReplaceOnSecondary",  "replace_on_secondary")
851
    -- Change secondary node
852
  , ("ReplaceNewSecondary", "replace_new_secondary")
853
  , ("ReplaceAuto",         "replace_auto")
854
  ])
855
$(THH.makeJSONInstance ''ReplaceDisksMode)
856

    
857
-- | Basic timeouts for RPC calls.
858
$(THH.declareILADT "RpcTimeout"
859
  [ ("Urgent",    60)       -- 1 minute
860
  , ("Fast",      5 * 60)   -- 5 minutes
861
  , ("Normal",    15 * 60)  -- 15 minutes
862
  , ("Slow",      3600)     -- 1 hour
863
  , ("FourHours", 4 * 3600) -- 4 hours
864
  , ("OneDay",    86400)    -- 1 day
865
  ])
866

    
867
$(THH.declareLADT ''String "ImportExportCompression"
868
  [ -- No compression
869
    ("None", "none")
870
    -- gzip compression
871
  , ("GZip", "gzip")
872
  ])
873
$(THH.makeJSONInstance ''ImportExportCompression)
874

    
875
instance THH.PyValue ImportExportCompression where
876
  showValue = THH.showValue . importExportCompressionToRaw
877

    
878
-- | Hotplug action.
879

    
880
$(THH.declareLADT ''String "HotplugAction"
881
  [ ("HAAdd", "hotadd")
882
  , ("HARemove",  "hotremove")
883
  , ("HAMod",     "hotmod")
884
  ])
885
$(THH.makeJSONInstance ''HotplugAction)
886

    
887
-- | Hotplug Device Target.
888

    
889
$(THH.declareLADT ''String "HotplugTarget"
890
  [ ("HTDisk", "hotdisk")
891
  , ("HTNic",  "hotnic")
892
  ])
893
$(THH.makeJSONInstance ''HotplugTarget)
894

    
895
-- * Private type and instances
896

    
897
-- | A container for values that should be happy to be manipulated yet
898
-- refuses to be shown unless explicitly requested.
899
newtype Private a = Private { getPrivate :: a }
900
  deriving Eq
901

    
902
instance (Show a, JSON.JSON a) => JSON.JSON (Private a) where
903
  readJSON = liftM Private . JSON.readJSON
904
  showJSON (Private x) = JSON.showJSON x
905

    
906
-- | "Show" the value of the field.
907
--
908
-- It would be better not to implement this at all.
909
-- Alas, Show OpCode requires Show Private.
910
instance Show a => Show (Private a) where
911
  show _ = "<redacted>"
912

    
913
instance THH.PyValue a => THH.PyValue (Private a) where
914
  showValue (Private x) = "Private(" ++ THH.showValue x ++ ")"
915

    
916
instance Functor Private where
917
  fmap f (Private x) = Private $ f x
918

    
919
instance Monad Private where
920
  (Private x) >>= f = f x
921
  return = Private
922

    
923
showPrivateJSObject :: (JSON.JSON a) =>
924
                       [(String, a)] -> JSON.JSObject (Private JSON.JSValue)
925
showPrivateJSObject value = JSON.toJSObject $ map f value
926
  where f (k, v) = (k, Private $ JSON.showJSON v)