From b1e8152024ccdf8049f34508a41e6f90fd16a6f3 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Fri, 18 Nov 2011 10:59:12 +0100
Subject: [PATCH] htools: add partial implementation of lib/objects.py

This is partial since not all object types can be easily converted for
now (will need some changes on the Python side for this).

Most importantly, the *Params types do not have a good solution now:
the Python code, due to its dynamic typing, hides the fact that we
actually have two different types at play: a full type which needs to
have all keys, and the 'partial' type which has slightly different
behaviour. I've implemented these in Haskell as two different types,
Full* and Partial*, which are derived automatically from a single
Parameter type, together with the associated Fill* functions.

Furthermore, HVParams is even more special, as its contents is not
fixed but varies per hypervisor type, plus it has the HV_GLOBALS part
which should not be customisable at instance type (yay for
exceptions). As such, this should be written in Haskell as a
multi-constructor type, but it's the only one so far and thus we don't
have support for it yet.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Guido Trotter <ultrotter@google.com>
---
 Makefile.am              |   1 +
 htools/Ganeti/Objects.hs | 266 +++++++++++++++++++++++++++++++++++++++
 htools/Ganeti/THH.hs     |   6 +-
 3 files changed, 270 insertions(+), 3 deletions(-)
 create mode 100644 htools/Ganeti/Objects.hs

diff --git a/Makefile.am b/Makefile.am
index 8949cd93f..eff92145b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -397,6 +397,7 @@ HS_LIB_SRCS = \
 	htools/Ganeti/BasicTypes.hs \
 	htools/Ganeti/Jobs.hs \
 	htools/Ganeti/Luxi.hs \
+	htools/Ganeti/Objects.hs \
 	htools/Ganeti/OpCodes.hs \
 	htools/Ganeti/THH.hs
 
diff --git a/htools/Ganeti/Objects.hs b/htools/Ganeti/Objects.hs
new file mode 100644
index 000000000..a366546cb
--- /dev/null
+++ b/htools/Ganeti/Objects.hs
@@ -0,0 +1,266 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+{-| Implementation of the Ganeti config objects.
+
+Some object fields are not implemented yet, and as such they are
+commented out below.
+
+-}
+
+{-
+
+Copyright (C) 2011, 2012 Google Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Ganeti.Objects
+  ( NICMode(..)
+  , PartialNICParams(..)
+  , FilledNICParams(..)
+  , fillNICParams
+  , PartialNIC(..)
+  , DiskMode(..)
+  , DiskType(..)
+  , Disk(..)
+  , DiskTemplate(..)
+  , PartialBEParams(..)
+  , FilledBEParams(..)
+  , fillBEParams
+  , Instance(..)
+  , toDictInstance
+  , PartialNDParams(..)
+  , FilledNDParams(..)
+  , fillNDParams
+  , Node(..)
+  , AllocPolicy(..)
+  , NodeGroup(..)
+  , Cluster(..)
+  , ConfigData(..)
+  ) where
+
+import Data.Maybe
+import Text.JSON (makeObj, showJSON, readJSON)
+
+import qualified Ganeti.Constants as C
+import Ganeti.HTools.JSON
+
+import Ganeti.THH
+
+-- * NIC definitions
+
+$(declareSADT "NICMode"
+  [ ("NMBridged", 'C.nicModeBridged)
+  , ("NMRouted",  'C.nicModeRouted)
+  ])
+$(makeJSONInstance ''NICMode)
+
+$(buildParam "NIC" "nicp"
+  [ simpleField "mode" [t| NICMode |]
+  , simpleField "link" [t| String  |]
+  ])
+
+$(buildObject "PartialNIC" "nic"
+  [ simpleField "mac" [t| String |]
+  , optionalField $ simpleField "ip" [t| String |]
+  , simpleField "nicparams" [t| PartialNICParams |]
+  ])
+
+-- * Disk definitions
+
+$(declareSADT "DiskMode"
+  [ ("DiskRdOnly", 'C.diskRdonly)
+  , ("DiskRdWr",   'C.diskRdwr)
+  ])
+$(makeJSONInstance ''DiskMode)
+
+$(declareSADT "DiskType"
+  [ ("LD_LV",       'C.ldLv)
+  , ("LD_DRBD8",    'C.ldDrbd8)
+  , ("LD_FILE",     'C.ldFile)
+  , ("LD_BLOCKDEV", 'C.ldBlockdev)
+  ])
+$(makeJSONInstance ''DiskType)
+
+-- | Disk data structure.
+--
+-- This is declared manually as it's a recursive structure, and our TH
+-- code currently can't build it.
+data Disk = Disk
+  { diskDevType    :: DiskType
+--  , diskLogicalId  :: String
+--  , diskPhysicalId :: String
+  , diskChildren   :: [Disk]
+  , diskIvName     :: String
+  , diskSize       :: Int
+  , diskMode       :: DiskMode
+  } deriving (Read, Show, Eq)
+
+$(buildObjectSerialisation "Disk"
+  [ simpleField "dev_type"      [t| DiskMode |]
+--  , simpleField "logical_id"  [t| String   |]
+--  , simpleField "physical_id" [t| String   |]
+  , defaultField  [| [] |] $ simpleField "children" [t| [Disk] |]
+  , defaultField [| "" |] $ simpleField "iv_name" [t| String |]
+  , simpleField "size" [t| Int |]
+  , defaultField [| DiskRdWr |] $ simpleField "mode" [t| DiskMode |]
+  ])
+
+-- * Instance definitions
+
+-- | Instance disk template type. **Copied from HTools/Types.hs**
+$(declareSADT "DiskTemplate"
+  [ ("DTDiskless",   'C.dtDiskless)
+  , ("DTFile",       'C.dtFile)
+  , ("DTSharedFile", 'C.dtSharedFile)
+  , ("DTPlain",      'C.dtPlain)
+  , ("DTBlock",      'C.dtBlock)
+  , ("DTDrbd8",      'C.dtDrbd8)
+  ])
+$(makeJSONInstance ''DiskTemplate)
+
+$(declareSADT "AdminState"
+  [ ("AdminOffline", 'C.adminstOffline)
+  , ("AdminDown",    'C.adminstDown)
+  , ("AdminUp",      'C.adminstUp)
+  ])
+$(makeJSONInstance ''AdminState)
+
+$(buildParam "BE" "bep" $
+  [ simpleField "minmem"       [t| Int  |]
+  , simpleField "maxmem"       [t| Int  |]
+  , simpleField "vcpus"        [t| Int  |]
+  , simpleField "auto_balance" [t| Bool |]
+  ])
+
+$(buildObject "Instance" "inst" $
+  [ simpleField "name"           [t| String             |]
+  , simpleField "primary_node"   [t| String             |]
+  , simpleField "os"             [t| String             |]
+  , simpleField "hypervisor"     [t| String             |]
+--  , simpleField "hvparams"     [t| [(String, String)] |]
+  , simpleField "beparams"       [t| PartialBEParams |]
+--  , simpleField "osparams"     [t| [(String, String)] |]
+  , simpleField "admin_state"    [t| AdminState         |]
+  , simpleField "nics"           [t| [PartialNIC]              |]
+  , simpleField "disks"          [t| [Disk]             |]
+  , simpleField "disk_template"  [t| DiskTemplate       |]
+  , optionalField $ simpleField "network_port" [t| Int |]
+  ]
+  ++ timeStampFields
+  ++ uuidFields
+  ++ serialFields)
+
+-- * Node definitions
+
+$(buildParam "ND" "ndp" $
+  [ simpleField "oob_program" [t| String |]
+  ])
+
+$(buildObject "Node" "node" $
+  [ simpleField "name"             [t| String |]
+  , simpleField "primary_ip"       [t| String |]
+  , simpleField "secondary_ip"     [t| String |]
+  , simpleField "master_candidate" [t| Bool   |]
+  , simpleField "offline"          [t| Bool   |]
+  , simpleField "drained"          [t| Bool   |]
+  , simpleField "group"            [t| String |]
+  , simpleField "master_capable"   [t| Bool   |]
+  , simpleField "vm_capable"       [t| Bool   |]
+--  , simpleField "ndparams"       [t| PartialNDParams |]
+  , simpleField "powered"          [t| Bool   |]
+  ]
+  ++ timeStampFields
+  ++ uuidFields
+  ++ serialFields)
+
+-- * NodeGroup definitions
+
+-- | The Group allocation policy type.
+--
+-- Note that the order of constructors is important as the automatic
+-- Ord instance will order them in the order they are defined, so when
+-- changing this data type be careful about the interaction with the
+-- desired sorting order.
+--
+-- FIXME: COPIED from Types.hs; we need to eliminate this duplication later
+$(declareSADT "AllocPolicy"
+  [ ("AllocPreferred",   'C.allocPolicyPreferred)
+  , ("AllocLastResort",  'C.allocPolicyLastResort)
+  , ("AllocUnallocable", 'C.allocPolicyUnallocable)
+  ])
+$(makeJSONInstance ''AllocPolicy)
+
+$(buildObject "NodeGroup" "group" $
+  [ simpleField "name"         [t| String |]
+  , defaultField  [| [] |] $ simpleField "members" [t| [String] |]
+--  , simpleField "ndparams"   [t| PartialNDParams |]
+  , simpleField "alloc_policy" [t| AllocPolicy |]
+  ]
+  ++ timeStampFields
+  ++ uuidFields
+  ++ serialFields)
+
+-- * Cluster definitions
+$(buildObject "Cluster" "cluster" $
+  [ simpleField "rsahostkeypub"             [t| String   |]
+  , simpleField "highest_used_port"         [t| Int      |]
+  , simpleField "tcpudp_port_pool"          [t| [Int]    |]
+  , simpleField "mac_prefix"                [t| String   |]
+  , simpleField "volume_group_name"         [t| String   |]
+  , simpleField "reserved_lvs"              [t| [String] |]
+--  , simpleField "drbd_usermode_helper"      [t| String   |]
+-- , simpleField "default_bridge"          [t| String   |]
+-- , simpleField "default_hypervisor"      [t| String   |]
+  , simpleField "master_node"               [t| String   |]
+  , simpleField "master_ip"                 [t| String   |]
+  , simpleField "master_netdev"             [t| String   |]
+-- , simpleField "master_netmask"          [t| String   |]
+  , simpleField "cluster_name"              [t| String   |]
+  , simpleField "file_storage_dir"          [t| String   |]
+-- , simpleField "shared_file_storage_dir" [t| String   |]
+  , simpleField "enabled_hypervisors"       [t| [String] |]
+-- , simpleField "hvparams"                [t| [(String, [(String, String)])] |]
+-- , simpleField "os_hvp"                  [t| [(String, String)] |]
+  , containerField $ simpleField "beparams" [t| FilledBEParams |]
+-- , simpleField "osparams"                [t| [(String, String)] |]
+  , containerField $ simpleField "nicparams" [t| FilledNICParams    |]
+--  , simpleField "ndparams"                  [t| FilledNDParams |]
+  , simpleField "candidate_pool_size"       [t| Int                |]
+  , simpleField "modify_etc_hosts"          [t| Bool               |]
+  , simpleField "modify_ssh_setup"          [t| Bool               |]
+  , simpleField "maintain_node_health"      [t| Bool               |]
+  , simpleField "uid_pool"                  [t| [Int]              |]
+  , simpleField "default_iallocator"        [t| String             |]
+  , simpleField "hidden_os"                 [t| [String]           |]
+  , simpleField "blacklisted_os"            [t| [String]           |]
+  , simpleField "primary_ip_family"         [t| Int                |]
+  , simpleField "prealloc_wipe_disks"       [t| Bool               |]
+ ]
+ ++ serialFields)
+
+-- * ConfigData definitions
+
+$(buildObject "ConfigData" "config" $
+--  timeStampFields ++
+  [ simpleField "version"       [t| Int                |]
+  , simpleField "cluster"       [t| Cluster            |]
+  , containerField $ simpleField "nodes"      [t| Node     |]
+  , containerField $ simpleField "nodegroups" [t| NodeGroup |]
+  , containerField $ simpleField "instances"  [t| Instance |]
+  ]
+  ++ serialFields)
diff --git a/htools/Ganeti/THH.hs b/htools/Ganeti/THH.hs
index 87e6b0aa9..2c036550b 100644
--- a/htools/Ganeti/THH.hs
+++ b/htools/Ganeti/THH.hs
@@ -10,7 +10,7 @@ needs in this module (except the one for unittests).
 
 {-
 
-Copyright (C) 2011 Google Inc.
+Copyright (C) 2011, 2012 Google Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -717,8 +717,8 @@ buildParam sname field_pfx fields = do
   fields_p <- mapM (paramFieldTypeInfo field_pfx) fields
   let decl_f = RecC name_f fields_f
       decl_p = RecC name_p fields_p
-  let declF = DataD [] name_f [] [decl_f] [''Show, ''Read]
-      declP = DataD [] name_p [] [decl_p] [''Show, ''Read]
+  let declF = DataD [] name_f [] [decl_f] [''Show, ''Read, ''Eq]
+      declP = DataD [] name_p [] [decl_p] [''Show, ''Read, ''Eq]
   ser_decls_f <- buildObjectSerialisation sname_f fields
   ser_decls_p <- buildPParamSerialisation sname_p fields
   fill_decls <- fillParam sname field_pfx fields
-- 
GitLab