Loader.hs: rewrite extractExTags to use chompPrefix
[ganeti-local] / src / Ganeti / Objects.hs
1 {-# LANGUAGE TemplateHaskell #-}
2
3 {-| Implementation of the Ganeti config objects.
4
5 Some object fields are not implemented yet, and as such they are
6 commented out below.
7
8 -}
9
10 {-
11
12 Copyright (C) 2011, 2012 Google Inc.
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.
28
29 -}
30
31 module Ganeti.Objects
32   ( VType(..)
33   , vTypeFromRaw
34   , HvParams
35   , OsParams
36   , PartialNicParams(..)
37   , FilledNicParams(..)
38   , fillNicParams
39   , allNicParamFields
40   , PartialNic(..)
41   , FileDriver(..)
42   , BlockDriver(..)
43   , DiskMode(..)
44   , DiskType(..)
45   , DiskLogicalId(..)
46   , Disk(..)
47   , DiskTemplate(..)
48   , PartialBeParams(..)
49   , FilledBeParams(..)
50   , fillBeParams
51   , allBeParamFields
52   , AdminState(..)
53   , adminStateFromRaw
54   , Instance(..)
55   , toDictInstance
56   , PartialNDParams(..)
57   , FilledNDParams(..)
58   , fillNDParams
59   , allNDParamFields
60   , Node(..)
61   , NodeRole(..)
62   , nodeRoleToRaw
63   , roleDescription
64   , AllocPolicy(..)
65   , FilledISpecParams(..)
66   , PartialISpecParams(..)
67   , fillISpecParams
68   , allISpecParamFields
69   , FilledIPolicy(..)
70   , PartialIPolicy(..)
71   , fillIPolicy
72   , DiskParams
73   , NodeGroup(..)
74   , IpFamily(..)
75   , ipFamilyToVersion
76   , fillDict
77   , ClusterHvParams
78   , OsHvParams
79   , ClusterBeParams
80   , ClusterOsParams
81   , ClusterNicParams
82   , Cluster(..)
83   , ConfigData(..)
84   , TimeStampObject(..)
85   , UuidObject(..)
86   , SerialNoObject(..)
87   , TagsObject(..)
88   , DictObject(..) -- re-exported from THH
89   , TagSet -- re-exported from THH
90   , Network(..)
91   ) where
92
93 import Data.List (foldl')
94 import Data.Maybe
95 import qualified Data.Map as Map
96 import qualified Data.Set as Set
97 import Text.JSON (showJSON, readJSON, JSON, JSValue(..))
98 import qualified Text.JSON as J
99
100 import qualified Ganeti.Constants as C
101 import Ganeti.JSON
102 import Ganeti.Types
103 import Ganeti.THH
104
105 -- * Generic definitions
106
107 -- | Fills one map with keys from the other map, if not already
108 -- existing. Mirrors objects.py:FillDict.
109 fillDict :: (Ord k) => Map.Map k v -> Map.Map k v -> [k] -> Map.Map k v
110 fillDict defaults custom skip_keys =
111   let updated = Map.union custom defaults
112   in foldl' (flip Map.delete) updated skip_keys
113
114 -- | The VTYPES, a mini-type system in Python.
115 $(declareSADT "VType"
116   [ ("VTypeString",      'C.vtypeString)
117   , ("VTypeMaybeString", 'C.vtypeMaybeString)
118   , ("VTypeBool",        'C.vtypeBool)
119   , ("VTypeSize",        'C.vtypeSize)
120   , ("VTypeInt",         'C.vtypeInt)
121   ])
122 $(makeJSONInstance ''VType)
123
124 -- | The hypervisor parameter type. This is currently a simple map,
125 -- without type checking on key/value pairs.
126 type HvParams = Container JSValue
127
128 -- | The OS parameters type. This is, and will remain, a string
129 -- container, since the keys are dynamically declared by the OSes, and
130 -- the values are always strings.
131 type OsParams = Container String
132
133 -- | Class of objects that have timestamps.
134 class TimeStampObject a where
135   cTimeOf :: a -> Double
136   mTimeOf :: a -> Double
137
138 -- | Class of objects that have an UUID.
139 class UuidObject a where
140   uuidOf :: a -> String
141
142 -- | Class of object that have a serial number.
143 class SerialNoObject a where
144   serialOf :: a -> Int
145
146 -- | Class of objects that have tags.
147 class TagsObject a where
148   tagsOf :: a -> Set.Set String
149
150 -- * Node role object
151
152 $(declareSADT "NodeRole"
153   [ ("NROffline",   'C.nrOffline)
154   , ("NRDrained",   'C.nrDrained)
155   , ("NRRegular",   'C.nrRegular)
156   , ("NRCandidate", 'C.nrMcandidate)
157   , ("NRMaster",    'C.nrMaster)
158   ])
159 $(makeJSONInstance ''NodeRole)
160
161 -- | The description of the node role.
162 roleDescription :: NodeRole -> String
163 roleDescription NROffline   = "offline"
164 roleDescription NRDrained   = "drained"
165 roleDescription NRRegular   = "regular"
166 roleDescription NRCandidate = "master candidate"
167 roleDescription NRMaster    = "master"
168
169 -- * Network definitions
170
171 -- FIXME: Not all types might be correct here, since they
172 -- haven't been exhaustively deduced from the python code yet.
173 $(buildObject "Network" "network" $
174   [ simpleField "name"             [t| NonEmptyString |]
175   , optionalField $
176     simpleField "network_type"     [t| NetworkType |]
177   , optionalField $
178     simpleField "mac_prefix"       [t| String |]
179   , optionalField $
180     simpleField "family"           [t| Int |]
181   , simpleField "network"          [t| NonEmptyString |]
182   , optionalField $
183     simpleField "network6"         [t| String |]
184   , optionalField $
185     simpleField "gateway"          [t| String |]
186   , optionalField $
187     simpleField "gateway6"         [t| String |]
188   , optionalField $
189     simpleField "size"             [t| J.JSValue |]
190   , optionalField $
191     simpleField "reservations"     [t| String |]
192   , optionalField $
193     simpleField "ext_reservations" [t| String |]
194   ]
195   ++ serialFields
196   ++ tagsFields)
197
198 instance SerialNoObject Network where
199   serialOf = networkSerial
200
201 instance TagsObject Network where
202   tagsOf = networkTags
203
204 -- * NIC definitions
205
206 $(buildParam "Nic" "nicp"
207   [ simpleField "mode" [t| NICMode |]
208   , simpleField "link" [t| String  |]
209   ])
210
211 $(buildObject "PartialNic" "nic"
212   [ simpleField "mac" [t| String |]
213   , optionalField $ simpleField "ip" [t| String |]
214   , simpleField "nicparams" [t| PartialNicParams |]
215   , optionalField $ simpleField "network" [t| Network |]
216   ])
217
218 -- * Disk definitions
219
220 $(declareSADT "DiskMode"
221   [ ("DiskRdOnly", 'C.diskRdonly)
222   , ("DiskRdWr",   'C.diskRdwr)
223   ])
224 $(makeJSONInstance ''DiskMode)
225
226 $(declareSADT "DiskType"
227   [ ("LD_LV",       'C.ldLv)
228   , ("LD_DRBD8",    'C.ldDrbd8)
229   , ("LD_FILE",     'C.ldFile)
230   , ("LD_BLOCKDEV", 'C.ldBlockdev)
231   , ("LD_RADOS",    'C.ldRbd)
232   , ("LD_EXT",      'C.ldExt)
233   ])
234 $(makeJSONInstance ''DiskType)
235
236 -- | The persistent block driver type. Currently only one type is allowed.
237 $(declareSADT "BlockDriver"
238   [ ("BlockDrvManual", 'C.blockdevDriverManual)
239   ])
240 $(makeJSONInstance ''BlockDriver)
241
242 -- | Constant for the dev_type key entry in the disk config.
243 devType :: String
244 devType = "dev_type"
245
246 -- | The disk configuration type. This includes the disk type itself,
247 -- for a more complete consistency. Note that since in the Python
248 -- code-base there's no authoritative place where we document the
249 -- logical id, this is probably a good reference point.
250 data DiskLogicalId
251   = LIDPlain String String  -- ^ Volume group, logical volume
252   | LIDDrbd8 String String Int Int Int String
253   -- ^ NodeA, NodeB, Port, MinorA, MinorB, Secret
254   | LIDFile FileDriver String -- ^ Driver, path
255   | LIDBlockDev BlockDriver String -- ^ Driver, path (must be under /dev)
256   | LIDRados String String -- ^ Unused, path
257   | LIDExt String String -- ^ ExtProvider, unique name
258     deriving (Show, Eq)
259
260 -- | Mapping from a logical id to a disk type.
261 lidDiskType :: DiskLogicalId -> DiskType
262 lidDiskType (LIDPlain {}) = LD_LV
263 lidDiskType (LIDDrbd8 {}) = LD_DRBD8
264 lidDiskType (LIDFile  {}) = LD_FILE
265 lidDiskType (LIDBlockDev {}) = LD_BLOCKDEV
266 lidDiskType (LIDRados {}) = LD_RADOS
267 lidDiskType (LIDExt {}) = LD_EXT
268
269 -- | Builds the extra disk_type field for a given logical id.
270 lidEncodeType :: DiskLogicalId -> [(String, JSValue)]
271 lidEncodeType v = [(devType, showJSON . lidDiskType $ v)]
272
273 -- | Custom encoder for DiskLogicalId (logical id only).
274 encodeDLId :: DiskLogicalId -> JSValue
275 encodeDLId (LIDPlain vg lv) = JSArray [showJSON vg, showJSON lv]
276 encodeDLId (LIDDrbd8 nodeA nodeB port minorA minorB key) =
277   JSArray [ showJSON nodeA, showJSON nodeB, showJSON port
278           , showJSON minorA, showJSON minorB, showJSON key ]
279 encodeDLId (LIDRados pool name) = JSArray [showJSON pool, showJSON name]
280 encodeDLId (LIDFile driver name) = JSArray [showJSON driver, showJSON name]
281 encodeDLId (LIDBlockDev driver name) = JSArray [showJSON driver, showJSON name]
282 encodeDLId (LIDExt extprovider name) =
283   JSArray [showJSON extprovider, showJSON name]
284
285 -- | Custom encoder for DiskLogicalId, composing both the logical id
286 -- and the extra disk_type field.
287 encodeFullDLId :: DiskLogicalId -> (JSValue, [(String, JSValue)])
288 encodeFullDLId v = (encodeDLId v, lidEncodeType v)
289
290 -- | Custom decoder for DiskLogicalId. This is manual for now, since
291 -- we don't have yet automation for separate-key style fields.
292 decodeDLId :: [(String, JSValue)] -> JSValue -> J.Result DiskLogicalId
293 decodeDLId obj lid = do
294   dtype <- fromObj obj devType
295   case dtype of
296     LD_DRBD8 ->
297       case lid of
298         JSArray [nA, nB, p, mA, mB, k] -> do
299           nA' <- readJSON nA
300           nB' <- readJSON nB
301           p'  <- readJSON p
302           mA' <- readJSON mA
303           mB' <- readJSON mB
304           k'  <- readJSON k
305           return $ LIDDrbd8 nA' nB' p' mA' mB' k'
306         _ -> fail "Can't read logical_id for DRBD8 type"
307     LD_LV ->
308       case lid of
309         JSArray [vg, lv] -> do
310           vg' <- readJSON vg
311           lv' <- readJSON lv
312           return $ LIDPlain vg' lv'
313         _ -> fail "Can't read logical_id for plain type"
314     LD_FILE ->
315       case lid of
316         JSArray [driver, path] -> do
317           driver' <- readJSON driver
318           path'   <- readJSON path
319           return $ LIDFile driver' path'
320         _ -> fail "Can't read logical_id for file type"
321     LD_BLOCKDEV ->
322       case lid of
323         JSArray [driver, path] -> do
324           driver' <- readJSON driver
325           path'   <- readJSON path
326           return $ LIDBlockDev driver' path'
327         _ -> fail "Can't read logical_id for blockdev type"
328     LD_RADOS ->
329       case lid of
330         JSArray [driver, path] -> do
331           driver' <- readJSON driver
332           path'   <- readJSON path
333           return $ LIDRados driver' path'
334         _ -> fail "Can't read logical_id for rdb type"
335     LD_EXT ->
336       case lid of
337         JSArray [extprovider, name] -> do
338           extprovider' <- readJSON extprovider
339           name'   <- readJSON name
340           return $ LIDExt extprovider' name'
341         _ -> fail "Can't read logical_id for extstorage type"
342
343 -- | Disk data structure.
344 --
345 -- This is declared manually as it's a recursive structure, and our TH
346 -- code currently can't build it.
347 data Disk = Disk
348   { diskLogicalId  :: DiskLogicalId
349 --  , diskPhysicalId :: String
350   , diskChildren   :: [Disk]
351   , diskIvName     :: String
352   , diskSize       :: Int
353   , diskMode       :: DiskMode
354   } deriving (Show, Eq)
355
356 $(buildObjectSerialisation "Disk"
357   [ customField 'decodeDLId 'encodeFullDLId ["dev_type"] $
358       simpleField "logical_id"    [t| DiskLogicalId   |]
359 --  , simpleField "physical_id" [t| String   |]
360   , defaultField  [| [] |] $ simpleField "children" [t| [Disk] |]
361   , defaultField [| "" |] $ simpleField "iv_name" [t| String |]
362   , simpleField "size" [t| Int |]
363   , defaultField [| DiskRdWr |] $ simpleField "mode" [t| DiskMode |]
364   ])
365
366 -- * Instance definitions
367
368 $(declareSADT "AdminState"
369   [ ("AdminOffline", 'C.adminstOffline)
370   , ("AdminDown",    'C.adminstDown)
371   , ("AdminUp",      'C.adminstUp)
372   ])
373 $(makeJSONInstance ''AdminState)
374
375 $(buildParam "Be" "bep"
376   [ simpleField "minmem"       [t| Int  |]
377   , simpleField "maxmem"       [t| Int  |]
378   , simpleField "vcpus"        [t| Int  |]
379   , simpleField "auto_balance" [t| Bool |]
380   ])
381
382 $(buildObject "Instance" "inst" $
383   [ simpleField "name"           [t| String             |]
384   , simpleField "primary_node"   [t| String             |]
385   , simpleField "os"             [t| String             |]
386   , simpleField "hypervisor"     [t| Hypervisor         |]
387   , simpleField "hvparams"       [t| HvParams           |]
388   , simpleField "beparams"       [t| PartialBeParams    |]
389   , simpleField "osparams"       [t| OsParams           |]
390   , simpleField "admin_state"    [t| AdminState         |]
391   , simpleField "nics"           [t| [PartialNic]       |]
392   , simpleField "disks"          [t| [Disk]             |]
393   , simpleField "disk_template"  [t| DiskTemplate       |]
394   , optionalField $ simpleField "network_port" [t| Int  |]
395   ]
396   ++ timeStampFields
397   ++ uuidFields
398   ++ serialFields
399   ++ tagsFields)
400
401 instance TimeStampObject Instance where
402   cTimeOf = instCtime
403   mTimeOf = instMtime
404
405 instance UuidObject Instance where
406   uuidOf = instUuid
407
408 instance SerialNoObject Instance where
409   serialOf = instSerial
410
411 instance TagsObject Instance where
412   tagsOf = instTags
413
414 -- * IPolicy definitions
415
416 $(buildParam "ISpec" "ispec"
417   [ simpleField C.ispecMemSize     [t| Int |]
418   , simpleField C.ispecDiskSize    [t| Int |]
419   , simpleField C.ispecDiskCount   [t| Int |]
420   , simpleField C.ispecCpuCount    [t| Int |]
421   , simpleField C.ispecNicCount    [t| Int |]
422   , simpleField C.ispecSpindleUse  [t| Int |]
423   ])
424
425 -- | Custom partial ipolicy. This is not built via buildParam since it
426 -- has a special 2-level inheritance mode.
427 $(buildObject "PartialIPolicy" "ipolicy"
428   [ renameField "MinSpecP" $ simpleField "min" [t| PartialISpecParams |]
429   , renameField "MaxSpecP" $ simpleField "max" [t| PartialISpecParams |]
430   , renameField "StdSpecP" $ simpleField "std" [t| PartialISpecParams |]
431   , optionalField . renameField "SpindleRatioP"
432                     $ simpleField "spindle-ratio"  [t| Double |]
433   , optionalField . renameField "VcpuRatioP"
434                     $ simpleField "vcpu-ratio"     [t| Double |]
435   , optionalField . renameField "DiskTemplatesP"
436                     $ simpleField "disk-templates" [t| [DiskTemplate] |]
437   ])
438
439 -- | Custom filled ipolicy. This is not built via buildParam since it
440 -- has a special 2-level inheritance mode.
441 $(buildObject "FilledIPolicy" "ipolicy"
442   [ renameField "MinSpec" $ simpleField "min" [t| FilledISpecParams |]
443   , renameField "MaxSpec" $ simpleField "max" [t| FilledISpecParams |]
444   , renameField "StdSpec" $ simpleField "std" [t| FilledISpecParams |]
445   , simpleField "spindle-ratio"  [t| Double |]
446   , simpleField "vcpu-ratio"     [t| Double |]
447   , simpleField "disk-templates" [t| [DiskTemplate] |]
448   ])
449
450 -- | Custom filler for the ipolicy types.
451 fillIPolicy :: FilledIPolicy -> PartialIPolicy -> FilledIPolicy
452 fillIPolicy (FilledIPolicy { ipolicyMinSpec       = fmin
453                            , ipolicyMaxSpec       = fmax
454                            , ipolicyStdSpec       = fstd
455                            , ipolicySpindleRatio  = fspindleRatio
456                            , ipolicyVcpuRatio     = fvcpuRatio
457                            , ipolicyDiskTemplates = fdiskTemplates})
458             (PartialIPolicy { ipolicyMinSpecP       = pmin
459                             , ipolicyMaxSpecP       = pmax
460                             , ipolicyStdSpecP       = pstd
461                             , ipolicySpindleRatioP  = pspindleRatio
462                             , ipolicyVcpuRatioP     = pvcpuRatio
463                             , ipolicyDiskTemplatesP = pdiskTemplates}) =
464   FilledIPolicy { ipolicyMinSpec       = fillISpecParams fmin pmin
465                 , ipolicyMaxSpec       = fillISpecParams fmax pmax
466                 , ipolicyStdSpec       = fillISpecParams fstd pstd
467                 , ipolicySpindleRatio  = fromMaybe fspindleRatio pspindleRatio
468                 , ipolicyVcpuRatio     = fromMaybe fvcpuRatio pvcpuRatio
469                 , ipolicyDiskTemplates = fromMaybe fdiskTemplates
470                                          pdiskTemplates
471                 }
472 -- * Node definitions
473
474 $(buildParam "ND" "ndp"
475   [ simpleField "oob_program"   [t| String |]
476   , simpleField "spindle_count" [t| Int    |]
477   , simpleField "exclusive_storage" [t| Bool |]
478   ])
479
480 $(buildObject "Node" "node" $
481   [ simpleField "name"             [t| String |]
482   , simpleField "primary_ip"       [t| String |]
483   , simpleField "secondary_ip"     [t| String |]
484   , simpleField "master_candidate" [t| Bool   |]
485   , simpleField "offline"          [t| Bool   |]
486   , simpleField "drained"          [t| Bool   |]
487   , simpleField "group"            [t| String |]
488   , simpleField "master_capable"   [t| Bool   |]
489   , simpleField "vm_capable"       [t| Bool   |]
490   , simpleField "ndparams"         [t| PartialNDParams |]
491   , simpleField "powered"          [t| Bool   |]
492   ]
493   ++ timeStampFields
494   ++ uuidFields
495   ++ serialFields
496   ++ tagsFields)
497
498 instance TimeStampObject Node where
499   cTimeOf = nodeCtime
500   mTimeOf = nodeMtime
501
502 instance UuidObject Node where
503   uuidOf = nodeUuid
504
505 instance SerialNoObject Node where
506   serialOf = nodeSerial
507
508 instance TagsObject Node where
509   tagsOf = nodeTags
510
511 -- * NodeGroup definitions
512
513 -- | The disk parameters type.
514 type DiskParams = Container (Container JSValue)
515
516 -- | A mapping from network UUIDs to nic params of the networks.
517 type Networks = Container PartialNic
518
519 $(buildObject "NodeGroup" "group" $
520   [ simpleField "name"         [t| String |]
521   , defaultField [| [] |] $ simpleField "members" [t| [String] |]
522   , simpleField "ndparams"     [t| PartialNDParams |]
523   , simpleField "alloc_policy" [t| AllocPolicy     |]
524   , simpleField "ipolicy"      [t| PartialIPolicy  |]
525   , simpleField "diskparams"   [t| DiskParams      |]
526   , simpleField "networks"     [t| Networks        |]
527   ]
528   ++ timeStampFields
529   ++ uuidFields
530   ++ serialFields
531   ++ tagsFields)
532
533 instance TimeStampObject NodeGroup where
534   cTimeOf = groupCtime
535   mTimeOf = groupMtime
536
537 instance UuidObject NodeGroup where
538   uuidOf = groupUuid
539
540 instance SerialNoObject NodeGroup where
541   serialOf = groupSerial
542
543 instance TagsObject NodeGroup where
544   tagsOf = groupTags
545
546 -- | IP family type
547 $(declareIADT "IpFamily"
548   [ ("IpFamilyV4", 'C.ip4Family)
549   , ("IpFamilyV6", 'C.ip6Family)
550   ])
551 $(makeJSONInstance ''IpFamily)
552
553 -- | Conversion from IP family to IP version. This is needed because
554 -- Python uses both, depending on context.
555 ipFamilyToVersion :: IpFamily -> Int
556 ipFamilyToVersion IpFamilyV4 = C.ip4Version
557 ipFamilyToVersion IpFamilyV6 = C.ip6Version
558
559 -- | Cluster HvParams (hvtype to hvparams mapping).
560 type ClusterHvParams = Container HvParams
561
562 -- | Cluster Os-HvParams (os to hvparams mapping).
563 type OsHvParams = Container ClusterHvParams
564
565 -- | Cluser BeParams.
566 type ClusterBeParams = Container FilledBeParams
567
568 -- | Cluster OsParams.
569 type ClusterOsParams = Container OsParams
570
571 -- | Cluster NicParams.
572 type ClusterNicParams = Container FilledNicParams
573
574 -- | Cluster UID Pool, list (low, high) UID ranges.
575 type UidPool = [(Int, Int)]
576
577 -- * Cluster definitions
578 $(buildObject "Cluster" "cluster" $
579   [ simpleField "rsahostkeypub"           [t| String           |]
580   , simpleField "highest_used_port"       [t| Int              |]
581   , simpleField "tcpudp_port_pool"        [t| [Int]            |]
582   , simpleField "mac_prefix"              [t| String           |]
583   , simpleField "volume_group_name"       [t| String           |]
584   , simpleField "reserved_lvs"            [t| [String]         |]
585   , optionalField $
586     simpleField "drbd_usermode_helper"    [t| String           |]
587   , simpleField "master_node"             [t| String           |]
588   , simpleField "master_ip"               [t| String           |]
589   , simpleField "master_netdev"           [t| String           |]
590   , simpleField "master_netmask"          [t| Int              |]
591   , simpleField "use_external_mip_script" [t| Bool             |]
592   , simpleField "cluster_name"            [t| String           |]
593   , simpleField "file_storage_dir"        [t| String           |]
594   , simpleField "shared_file_storage_dir" [t| String           |]
595   , simpleField "enabled_hypervisors"     [t| [Hypervisor]     |]
596   , simpleField "hvparams"                [t| ClusterHvParams  |]
597   , simpleField "os_hvp"                  [t| OsHvParams       |]
598   , simpleField "beparams"                [t| ClusterBeParams  |]
599   , simpleField "osparams"                [t| ClusterOsParams  |]
600   , simpleField "nicparams"               [t| ClusterNicParams |]
601   , simpleField "ndparams"                [t| FilledNDParams   |]
602   , simpleField "diskparams"              [t| DiskParams       |]
603   , simpleField "candidate_pool_size"     [t| Int              |]
604   , simpleField "modify_etc_hosts"        [t| Bool             |]
605   , simpleField "modify_ssh_setup"        [t| Bool             |]
606   , simpleField "maintain_node_health"    [t| Bool             |]
607   , simpleField "uid_pool"                [t| UidPool          |]
608   , simpleField "default_iallocator"      [t| String           |]
609   , simpleField "hidden_os"               [t| [String]         |]
610   , simpleField "blacklisted_os"          [t| [String]         |]
611   , simpleField "primary_ip_family"       [t| IpFamily         |]
612   , simpleField "prealloc_wipe_disks"     [t| Bool             |]
613   , simpleField "ipolicy"                 [t| FilledIPolicy    |]
614  ]
615  ++ timeStampFields
616  ++ uuidFields
617  ++ serialFields
618  ++ tagsFields)
619
620 instance TimeStampObject Cluster where
621   cTimeOf = clusterCtime
622   mTimeOf = clusterMtime
623
624 instance UuidObject Cluster where
625   uuidOf = clusterUuid
626
627 instance SerialNoObject Cluster where
628   serialOf = clusterSerial
629
630 instance TagsObject Cluster where
631   tagsOf = clusterTags
632
633 -- * ConfigData definitions
634
635 $(buildObject "ConfigData" "config" $
636 --  timeStampFields ++
637   [ simpleField "version"    [t| Int                 |]
638   , simpleField "cluster"    [t| Cluster             |]
639   , simpleField "nodes"      [t| Container Node      |]
640   , simpleField "nodegroups" [t| Container NodeGroup |]
641   , simpleField "instances"  [t| Container Instance  |]
642   ]
643   ++ serialFields)
644
645 instance SerialNoObject ConfigData where
646   serialOf = configSerial