Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / Types.hs @ 57fb6fcb

History | View | Annotate | Download (15 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 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
  , NonNegative
44
  , fromNonNegative
45
  , mkNonNegative
46
  , Positive
47
  , fromPositive
48
  , mkPositive
49
  , Negative
50
  , fromNegative
51
  , mkNegative
52
  , NonEmpty
53
  , fromNonEmpty
54
  , mkNonEmpty
55
  , NonEmptyString
56
  , MigrationMode(..)
57
  , VerifyOptionalChecks(..)
58
  , DdmSimple(..)
59
  , DdmFull(..)
60
  , CVErrorCode(..)
61
  , cVErrorCodeToRaw
62
  , Hypervisor(..)
63
  , OobCommand(..)
64
  , StorageType(..)
65
  , NodeEvacMode(..)
66
  , FileDriver(..)
67
  , InstCreateMode(..)
68
  , RebootType(..)
69
  , ExportMode(..)
70
  , IAllocatorTestDir(..)
71
  , IAllocatorMode(..)
72
  , iAllocatorModeToRaw
73
  , NetworkType(..)
74
  , networkTypeToRaw
75
  , NICMode(..)
76
  , nICModeToRaw
77
  , JobStatus(..)
78
  , jobStatusToRaw
79
  , jobStatusFromRaw
80
  , FinalizedJobStatus(..)
81
  , finalizedJobStatusToRaw
82
  , JobId
83
  , fromJobId
84
  , makeJobId
85
  , RelativeJobId
86
  , JobIdDep(..)
87
  , JobDependency(..)
88
  , OpSubmitPriority(..)
89
  , OpStatus(..)
90
  , opStatusToRaw
91
  , opStatusFromRaw
92
  ) where
93

    
94
import Control.Monad (liftM)
95
import qualified Text.JSON as JSON
96
import Text.JSON (JSON, readJSON, showJSON)
97
import Data.Ratio (numerator, denominator)
98

    
99
import qualified Ganeti.Constants as C
100
import qualified Ganeti.THH as THH
101
import Ganeti.JSON
102
import Ganeti.Utils
103

    
104
-- * Generic types
105

    
106
-- | Type that holds a non-negative value.
107
newtype NonNegative a = NonNegative { fromNonNegative :: a }
108
  deriving (Show, Eq)
109

    
110
-- | Smart constructor for 'NonNegative'.
111
mkNonNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (NonNegative a)
112
mkNonNegative i | i >= 0 = return (NonNegative i)
113
                | otherwise = fail $ "Invalid value for non-negative type '" ++
114
                              show i ++ "'"
115

    
116
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (NonNegative a) where
117
  showJSON = JSON.showJSON . fromNonNegative
118
  readJSON v = JSON.readJSON v >>= mkNonNegative
119

    
120
-- | Type that holds a positive value.
121
newtype Positive a = Positive { fromPositive :: a }
122
  deriving (Show, Eq)
123

    
124
-- | Smart constructor for 'Positive'.
125
mkPositive :: (Monad m, Num a, Ord a, Show a) => a -> m (Positive a)
126
mkPositive i | i > 0 = return (Positive i)
127
             | otherwise = fail $ "Invalid value for positive type '" ++
128
                           show i ++ "'"
129

    
130
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Positive a) where
131
  showJSON = JSON.showJSON . fromPositive
132
  readJSON v = JSON.readJSON v >>= mkPositive
133

    
134
-- | Type that holds a negative value.
135
newtype Negative a = Negative { fromNegative :: a }
136
  deriving (Show, Eq)
137

    
138
-- | Smart constructor for 'Negative'.
139
mkNegative :: (Monad m, Num a, Ord a, Show a) => a -> m (Negative a)
140
mkNegative i | i < 0 = return (Negative i)
141
             | otherwise = fail $ "Invalid value for negative type '" ++
142
                           show i ++ "'"
143

    
144
instance (JSON.JSON a, Num a, Ord a, Show a) => JSON.JSON (Negative a) where
145
  showJSON = JSON.showJSON . fromNegative
146
  readJSON v = JSON.readJSON v >>= mkNegative
147

    
148
-- | Type that holds a non-null list.
149
newtype NonEmpty a = NonEmpty { fromNonEmpty :: [a] }
150
  deriving (Show, Eq)
151

    
152
-- | Smart constructor for 'NonEmpty'.
153
mkNonEmpty :: (Monad m) => [a] -> m (NonEmpty a)
154
mkNonEmpty [] = fail "Received empty value for non-empty list"
155
mkNonEmpty xs = return (NonEmpty xs)
156

    
157
instance (JSON.JSON a) => JSON.JSON (NonEmpty a) where
158
  showJSON = JSON.showJSON . fromNonEmpty
159
  readJSON v = JSON.readJSON v >>= mkNonEmpty
160

    
161
-- | A simple type alias for non-empty strings.
162
type NonEmptyString = NonEmpty Char
163

    
164
-- * Ganeti types
165

    
166
-- | Instance disk template type.
167
$(THH.declareSADT "DiskTemplate"
168
       [ ("DTDiskless",   'C.dtDiskless)
169
       , ("DTFile",       'C.dtFile)
170
       , ("DTSharedFile", 'C.dtSharedFile)
171
       , ("DTPlain",      'C.dtPlain)
172
       , ("DTBlock",      'C.dtBlock)
173
       , ("DTDrbd8",      'C.dtDrbd8)
174
       , ("DTRbd",        'C.dtRbd)
175
       ])
176
$(THH.makeJSONInstance ''DiskTemplate)
177

    
178
instance HasStringRepr DiskTemplate where
179
  fromStringRepr = diskTemplateFromRaw
180
  toStringRepr = diskTemplateToRaw
181

    
182
-- | The Group allocation policy type.
183
--
184
-- Note that the order of constructors is important as the automatic
185
-- Ord instance will order them in the order they are defined, so when
186
-- changing this data type be careful about the interaction with the
187
-- desired sorting order.
188
$(THH.declareSADT "AllocPolicy"
189
       [ ("AllocPreferred",   'C.allocPolicyPreferred)
190
       , ("AllocLastResort",  'C.allocPolicyLastResort)
191
       , ("AllocUnallocable", 'C.allocPolicyUnallocable)
192
       ])
193
$(THH.makeJSONInstance ''AllocPolicy)
194

    
195
-- | The Instance real state type. FIXME: this could be improved to
196
-- just wrap a /NormalState AdminStatus | ErrorState ErrorCondition/.
197
$(THH.declareSADT "InstanceStatus"
198
       [ ("StatusDown",    'C.inststAdmindown)
199
       , ("StatusOffline", 'C.inststAdminoffline)
200
       , ("ErrorDown",     'C.inststErrordown)
201
       , ("ErrorUp",       'C.inststErrorup)
202
       , ("NodeDown",      'C.inststNodedown)
203
       , ("NodeOffline",   'C.inststNodeoffline)
204
       , ("Running",       'C.inststRunning)
205
       , ("WrongNode",     'C.inststWrongnode)
206
       ])
207
$(THH.makeJSONInstance ''InstanceStatus)
208

    
209
-- | Migration mode.
210
$(THH.declareSADT "MigrationMode"
211
     [ ("MigrationLive",    'C.htMigrationLive)
212
     , ("MigrationNonLive", 'C.htMigrationNonlive)
213
     ])
214
$(THH.makeJSONInstance ''MigrationMode)
215

    
216
-- | Verify optional checks.
217
$(THH.declareSADT "VerifyOptionalChecks"
218
     [ ("VerifyNPlusOneMem", 'C.verifyNplusoneMem)
219
     ])
220
$(THH.makeJSONInstance ''VerifyOptionalChecks)
221

    
222
-- | Cluster verify error codes.
223
$(THH.declareSADT "CVErrorCode"
224
  [ ("CvECLUSTERCFG",           'C.cvEclustercfgCode)
225
  , ("CvECLUSTERCERT",          'C.cvEclustercertCode)
226
  , ("CvECLUSTERFILECHECK",     'C.cvEclusterfilecheckCode)
227
  , ("CvECLUSTERDANGLINGNODES", 'C.cvEclusterdanglingnodesCode)
228
  , ("CvECLUSTERDANGLINGINST",  'C.cvEclusterdanglinginstCode)
229
  , ("CvEINSTANCEBADNODE",      'C.cvEinstancebadnodeCode)
230
  , ("CvEINSTANCEDOWN",         'C.cvEinstancedownCode)
231
  , ("CvEINSTANCELAYOUT",       'C.cvEinstancelayoutCode)
232
  , ("CvEINSTANCEMISSINGDISK",  'C.cvEinstancemissingdiskCode)
233
  , ("CvEINSTANCEFAULTYDISK",   'C.cvEinstancefaultydiskCode)
234
  , ("CvEINSTANCEWRONGNODE",    'C.cvEinstancewrongnodeCode)
235
  , ("CvEINSTANCESPLITGROUPS",  'C.cvEinstancesplitgroupsCode)
236
  , ("CvEINSTANCEPOLICY",       'C.cvEinstancepolicyCode)
237
  , ("CvENODEDRBD",             'C.cvEnodedrbdCode)
238
  , ("CvENODEDRBDHELPER",       'C.cvEnodedrbdhelperCode)
239
  , ("CvENODEFILECHECK",        'C.cvEnodefilecheckCode)
240
  , ("CvENODEHOOKS",            'C.cvEnodehooksCode)
241
  , ("CvENODEHV",               'C.cvEnodehvCode)
242
  , ("CvENODELVM",              'C.cvEnodelvmCode)
243
  , ("CvENODEN1",               'C.cvEnoden1Code)
244
  , ("CvENODENET",              'C.cvEnodenetCode)
245
  , ("CvENODEOS",               'C.cvEnodeosCode)
246
  , ("CvENODEORPHANINSTANCE",   'C.cvEnodeorphaninstanceCode)
247
  , ("CvENODEORPHANLV",         'C.cvEnodeorphanlvCode)
248
  , ("CvENODERPC",              'C.cvEnoderpcCode)
249
  , ("CvENODESSH",              'C.cvEnodesshCode)
250
  , ("CvENODEVERSION",          'C.cvEnodeversionCode)
251
  , ("CvENODESETUP",            'C.cvEnodesetupCode)
252
  , ("CvENODETIME",             'C.cvEnodetimeCode)
253
  , ("CvENODEOOBPATH",          'C.cvEnodeoobpathCode)
254
  , ("CvENODEUSERSCRIPTS",      'C.cvEnodeuserscriptsCode)
255
  , ("CvENODEFILESTORAGEPATHS", 'C.cvEnodefilestoragepathsCode)
256
  ])
257
$(THH.makeJSONInstance ''CVErrorCode)
258

    
259
-- | Dynamic device modification, just add\/remove version.
260
$(THH.declareSADT "DdmSimple"
261
     [ ("DdmSimpleAdd",    'C.ddmAdd)
262
     , ("DdmSimpleRemove", 'C.ddmRemove)
263
     ])
264
$(THH.makeJSONInstance ''DdmSimple)
265

    
266
-- | Dynamic device modification, all operations version.
267
$(THH.declareSADT "DdmFull"
268
     [ ("DdmFullAdd",    'C.ddmAdd)
269
     , ("DdmFullRemove", 'C.ddmRemove)
270
     , ("DdmFullModify", 'C.ddmModify)
271
     ])
272
$(THH.makeJSONInstance ''DdmFull)
273

    
274
-- | Hypervisor type definitions.
275
$(THH.declareSADT "Hypervisor"
276
  [ ( "Kvm",    'C.htKvm )
277
  , ( "XenPvm", 'C.htXenPvm )
278
  , ( "Chroot", 'C.htChroot )
279
  , ( "XenHvm", 'C.htXenHvm )
280
  , ( "Lxc",    'C.htLxc )
281
  , ( "Fake",   'C.htFake )
282
  ])
283
$(THH.makeJSONInstance ''Hypervisor)
284

    
285
-- | Oob command type.
286
$(THH.declareSADT "OobCommand"
287
  [ ("OobHealth",      'C.oobHealth)
288
  , ("OobPowerCycle",  'C.oobPowerCycle)
289
  , ("OobPowerOff",    'C.oobPowerOff)
290
  , ("OobPowerOn",     'C.oobPowerOn)
291
  , ("OobPowerStatus", 'C.oobPowerStatus)
292
  ])
293
$(THH.makeJSONInstance ''OobCommand)
294

    
295
-- | Storage type.
296
$(THH.declareSADT "StorageType"
297
  [ ("StorageFile", 'C.stFile)
298
  , ("StorageLvmPv", 'C.stLvmPv)
299
  , ("StorageLvmVg", 'C.stLvmVg)
300
  ])
301
$(THH.makeJSONInstance ''StorageType)
302

    
303
-- | Node evac modes.
304
$(THH.declareSADT "NodeEvacMode"
305
  [ ("NEvacPrimary",   'C.iallocatorNevacPri)
306
  , ("NEvacSecondary", 'C.iallocatorNevacSec)
307
  , ("NEvacAll",       'C.iallocatorNevacAll)
308
  ])
309
$(THH.makeJSONInstance ''NodeEvacMode)
310

    
311
-- | The file driver type.
312
$(THH.declareSADT "FileDriver"
313
  [ ("FileLoop",   'C.fdLoop)
314
  , ("FileBlktap", 'C.fdBlktap)
315
  ])
316
$(THH.makeJSONInstance ''FileDriver)
317

    
318
-- | The instance create mode.
319
$(THH.declareSADT "InstCreateMode"
320
  [ ("InstCreate",       'C.instanceCreate)
321
  , ("InstImport",       'C.instanceImport)
322
  , ("InstRemoteImport", 'C.instanceRemoteImport)
323
  ])
324
$(THH.makeJSONInstance ''InstCreateMode)
325

    
326
-- | Reboot type.
327
$(THH.declareSADT "RebootType"
328
  [ ("RebootSoft", 'C.instanceRebootSoft)
329
  , ("RebootHard", 'C.instanceRebootHard)
330
  , ("RebootFull", 'C.instanceRebootFull)
331
  ])
332
$(THH.makeJSONInstance ''RebootType)
333

    
334
-- | Export modes.
335
$(THH.declareSADT "ExportMode"
336
  [ ("ExportModeLocal",  'C.exportModeLocal)
337
  , ("ExportModeRemove", 'C.exportModeRemote)
338
  ])
339
$(THH.makeJSONInstance ''ExportMode)
340

    
341
-- | IAllocator run types (OpTestIAllocator).
342
$(THH.declareSADT "IAllocatorTestDir"
343
  [ ("IAllocatorDirIn",  'C.iallocatorDirIn)
344
  , ("IAllocatorDirOut", 'C.iallocatorDirOut)
345
  ])
346
$(THH.makeJSONInstance ''IAllocatorTestDir)
347

    
348
-- | IAllocator mode. FIXME: use this in "HTools.Backend.IAlloc".
349
$(THH.declareSADT "IAllocatorMode"
350
  [ ("IAllocatorAlloc",       'C.iallocatorModeAlloc)
351
  , ("IAllocatorMultiAlloc",  'C.iallocatorModeMultiAlloc)
352
  , ("IAllocatorReloc",       'C.iallocatorModeReloc)
353
  , ("IAllocatorNodeEvac",    'C.iallocatorModeNodeEvac)
354
  , ("IAllocatorChangeGroup", 'C.iallocatorModeChgGroup)
355
  ])
356
$(THH.makeJSONInstance ''IAllocatorMode)
357

    
358
-- | Network type.
359
$(THH.declareSADT "NetworkType"
360
  [ ("PrivateNetwork", 'C.networkTypePrivate)
361
  , ("PublicNetwork",  'C.networkTypePublic)
362
  ])
363
$(THH.makeJSONInstance ''NetworkType)
364

    
365
-- | Netork mode.
366
$(THH.declareSADT "NICMode"
367
  [ ("NMBridged", 'C.nicModeBridged)
368
  , ("NMRouted",  'C.nicModeRouted)
369
  , ("NMOvs",     'C.nicModeOvs)
370
  ])
371
$(THH.makeJSONInstance ''NICMode)
372

    
373
-- | The JobStatus data type. Note that this is ordered especially
374
-- such that greater\/lesser comparison on values of this type makes
375
-- sense.
376
$(THH.declareSADT "JobStatus"
377
       [ ("JOB_STATUS_QUEUED",    'C.jobStatusQueued)
378
       , ("JOB_STATUS_WAITING",   'C.jobStatusWaiting)
379
       , ("JOB_STATUS_CANCELING", 'C.jobStatusCanceling)
380
       , ("JOB_STATUS_RUNNING",   'C.jobStatusRunning)
381
       , ("JOB_STATUS_CANCELED",  'C.jobStatusCanceled)
382
       , ("JOB_STATUS_SUCCESS",   'C.jobStatusSuccess)
383
       , ("JOB_STATUS_ERROR",     'C.jobStatusError)
384
       ])
385
$(THH.makeJSONInstance ''JobStatus)
386

    
387
-- | Finalized job status.
388
$(THH.declareSADT "FinalizedJobStatus"
389
  [ ("JobStatusCanceled",   'C.jobStatusCanceled)
390
  , ("JobStatusSuccessful", 'C.jobStatusSuccess)
391
  , ("JobStatusFailed",     'C.jobStatusError)
392
  ])
393
$(THH.makeJSONInstance ''FinalizedJobStatus)
394

    
395
-- | The Ganeti job type.
396
newtype JobId = JobId { fromJobId :: Int }
397
  deriving (Show, Eq)
398

    
399
-- | Builds a job ID.
400
makeJobId :: (Monad m) => Int -> m JobId
401
makeJobId i | i >= 0 = return $ JobId i
402
            | otherwise = fail $ "Invalid value for job ID ' " ++ show i ++ "'"
403

    
404
-- | Parses a job ID.
405
parseJobId :: (Monad m) => JSON.JSValue -> m JobId
406
parseJobId (JSON.JSString x) =
407
  tryRead "parsing job id" (JSON.fromJSString x) >>= makeJobId
408
parseJobId (JSON.JSRational _ x) =
409
  if denominator x /= 1
410
    then fail $ "Got fractional job ID from master daemon?! Value:" ++ show x
411
    -- FIXME: potential integer overflow here on 32-bit platforms
412
    else makeJobId . fromIntegral . numerator $ x
413
parseJobId x = fail $ "Wrong type/value for job id: " ++ show x
414

    
415
instance JSON.JSON JobId where
416
  showJSON = JSON.showJSON . fromJobId
417
  readJSON = parseJobId
418

    
419
-- | Relative job ID type alias.
420
type RelativeJobId = Negative Int
421

    
422
-- | Job ID dependency.
423
data JobIdDep = JobDepRelative RelativeJobId
424
              | JobDepAbsolute JobId
425
                deriving (Show, Eq)
426

    
427
instance JSON.JSON JobIdDep where
428
  showJSON (JobDepRelative i) = showJSON i
429
  showJSON (JobDepAbsolute i) = showJSON i
430
  readJSON v =
431
    case JSON.readJSON v::JSON.Result (Negative Int) of
432
      -- first try relative dependency, usually most common
433
      JSON.Ok r -> return $ JobDepRelative r
434
      JSON.Error _ -> liftM JobDepAbsolute
435
                      (fromJResult "parsing absolute job id" (readJSON v) >>=
436
                       makeJobId)
437

    
438
-- | Job Dependency type.
439
data JobDependency = JobDependency JobIdDep [FinalizedJobStatus]
440
                     deriving (Show, Eq)
441

    
442
instance JSON JobDependency where
443
  showJSON (JobDependency dep status) = showJSON (dep, status)
444
  readJSON = liftM (uncurry JobDependency) . readJSON
445

    
446
-- | Valid opcode priorities for submit.
447
$(THH.declareIADT "OpSubmitPriority"
448
  [ ("OpPrioLow",    'C.opPrioLow)
449
  , ("OpPrioNormal", 'C.opPrioNormal)
450
  , ("OpPrioHigh",   'C.opPrioHigh)
451
  ])
452
$(THH.makeJSONInstance ''OpSubmitPriority)
453

    
454
-- | Our ADT for the OpCode status at runtime (while in a job).
455
$(THH.declareSADT "OpStatus"
456
       [ ("OP_STATUS_QUEUED",    'C.opStatusQueued)
457
       , ("OP_STATUS_WAITING",   'C.opStatusWaiting)
458
       , ("OP_STATUS_CANCELING", 'C.opStatusCanceling)
459
       , ("OP_STATUS_RUNNING",   'C.opStatusRunning)
460
       , ("OP_STATUS_CANCELED",  'C.opStatusCanceled)
461
       , ("OP_STATUS_SUCCESS",   'C.opStatusSuccess)
462
       , ("OP_STATUS_ERROR",     'C.opStatusError)
463
       ])
464
$(THH.makeJSONInstance ''OpStatus)