Currently hv/disk_state_static parameters are supported only for cluster
object properly. For node groups and nodes they were introduced in
2da9f556, however only on the python side. Convert hv_state_static from
None to {} in ConfigUpgrade for NodeGroup and Node as well. Haskell
objects are extended with these parameters as well.

Also mock config objects modified to return empty dictionaries for
hv_state_static instead of None.

Signed-off-by: Oleg Ponomarev <[email protected]>
---
 Makefile.am                      |  1 +
 lib/objects.py                   | 10 ++++++
 src/Ganeti/Objects.hs            | 71 ++++++++++++++++++++++------------------
 src/Ganeti/Objects/HvState.hs    | 60 +++++++++++++++++++++++++++++++++
 test/hs/Test/Ganeti/Objects.hs   | 31 ++++++++++++++++--
 test/py/testutils/config_mock.py |  5 +--
 6 files changed, 141 insertions(+), 37 deletions(-)
 create mode 100644 src/Ganeti/Objects/HvState.hs

diff --git a/Makefile.am b/Makefile.am
index 7a0ec87..62027fe 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -996,6 +996,7 @@ HS_LIB_SRCS = \
        src/Ganeti/Objects/BitArray.hs \
        src/Ganeti/Objects/Disk.hs \
        src/Ganeti/Objects/Instance.hs \
+       src/Ganeti/Objects/HvState.hs \
        src/Ganeti/Objects/Lens.hs \
        src/Ganeti/Objects/Maintenance.hs \
        src/Ganeti/Objects/Nic.hs \
diff --git a/lib/objects.py b/lib/objects.py
index 02db0e3..c6648f1 100644
--- a/lib/objects.py
+++ b/lib/objects.py
@@ -1490,6 +1490,11 @@ class Node(TaggableObject):
     if self.powered is None:
       self.powered = True
 
+    if self.hv_state_static is None:
+      self.hv_state_static = {}
+    if self.disk_state_static is None:
+      self.disk_state_static = {}
+
   def ToDict(self, _with_private=False):
     """Custom function for serializing.
 
@@ -1587,6 +1592,11 @@ class NodeGroup(TaggableObject):
     if self.ipolicy is None:
       self.ipolicy = MakeEmptyIPolicy()
 
+    if self.hv_state_static is None:
+      self.hv_state_static = {}
+    if self.disk_state_static is None:
+      self.disk_state_static = {}
+
     if self.networks is None:
       self.networks = {}
 
diff --git a/src/Ganeti/Objects.hs b/src/Ganeti/Objects.hs
index 98f0ac9..9c6a3d5 100644
--- a/src/Ganeti/Objects.hs
+++ b/src/Ganeti/Objects.hs
@@ -104,7 +104,11 @@ module Ganeti.Objects
   , module Ganeti.Objects.Disk
   , module Ganeti.Objects.Instance
   , module Ganeti.Objects.Maintenance
-  ) where
+  , FilledHvStateParams(..)
+  , PartialHvStateParams(..)
+  , allHvStateParamFields
+  , FilledHvState
+  , PartialHvState ) where
 
 import Prelude ()
 import Ganeti.Prelude
@@ -131,6 +135,7 @@ import Ganeti.Objects.Disk
 import Ganeti.Objects.Maintenance
 import Ganeti.Objects.Nic
 import Ganeti.Objects.Instance
+import Ganeti.Objects.HvState
 import Ganeti.Query.Language
 import Ganeti.PartialParams
 import Ganeti.Types
@@ -389,6 +394,12 @@ instance PartialParams FilledIPolicy PartialIPolicy where
     FilledIPolicy <$> pminmax <*> (toFilled =<< pstd) <*> pspindleRatio
                   <*> pmemoryRatio <*> pvcpuRatio <*> pdiskTemplates
 
+-- | Disk state parameters.
+--
+-- As according to the documentation this option is unused by Ganeti,
+-- the content is just a 'JSValue'.
+type DiskState = Container JSValue
+
 -- * Node definitions
 
 $(buildParam "ND" "ndp"
@@ -403,17 +414,21 @@ $(buildParam "ND" "ndp"
   ])
 
 $(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   |]
+  [ 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            |]
+  , defaultField [| emptyContainer |] $
+    simpleField "hv_state_static"   [t| PartialHvState  |]
+  , defaultField [| emptyContainer |] $
+    simpleField "disk_state_static" [t| DiskState       |]
   ]
   ++ timeStampFields
   ++ uuidFields
@@ -442,13 +457,17 @@ type GroupDiskParams = Container DiskParams
 type Networks = Container PartialNicParams
 
 $(buildObject "NodeGroup" "group" $
-  [ simpleField "name"         [t| String |]
+  [ simpleField "name"              [t| String |]
   , defaultField [| [] |] $ simpleField "members" [t| [String] |]
-  , simpleField "ndparams"     [t| PartialNDParams |]
-  , simpleField "alloc_policy" [t| AllocPolicy     |]
-  , simpleField "ipolicy"      [t| PartialIPolicy  |]
-  , simpleField "diskparams"   [t| GroupDiskParams |]
-  , simpleField "networks"     [t| Networks        |]
+  , simpleField "ndparams"          [t| PartialNDParams |]
+  , simpleField "alloc_policy"      [t| AllocPolicy     |]
+  , simpleField "ipolicy"           [t| PartialIPolicy  |]
+  , simpleField "diskparams"        [t| GroupDiskParams |]
+  , simpleField "networks"          [t| Networks        |]
+  , defaultField [| emptyContainer |] $
+    simpleField "hv_state_static"   [t| PartialHvState  |]
+  , defaultField [| emptyContainer |] $
+    simpleField "disk_state_static" [t| DiskState       |]
   ]
   ++ timeStampFields
   ++ uuidFields
@@ -614,18 +633,6 @@ type IAllocatorParams = Container JSValue
 -- | The master candidate client certificate digests
 type CandidateCertificates = Container String
 
--- | Disk state parameters.
---
--- As according to the documentation this option is unused by Ganeti,
--- the content is just a 'JSValue'.
-type DiskState = Container JSValue
-
--- | Hypervisor state parameters.
---
--- As according to the documentation this option is unused by Ganeti,
--- the content is just a 'JSValue'.
-type HypervisorState = Container JSValue
-
 -- * Cluster definitions
 $(buildObject "Cluster" "cluster" $
   [ simpleField "rsahostkeypub"                  [t| String                  |]
@@ -670,9 +677,9 @@ $(buildObject "Cluster" "cluster" $
   , simpleField "prealloc_wipe_disks"            [t| Bool                    |]
   , simpleField "ipolicy"                        [t| FilledIPolicy           |]
   , defaultField [| emptyContainer |] $
-    simpleField "hv_state_static"                [t| HypervisorState        |]
+    simpleField "hv_state_static"                [t| FilledHvState           |]
   , defaultField [| emptyContainer |] $
-    simpleField "disk_state_static"              [t| DiskState              |]
+    simpleField "disk_state_static"              [t| DiskState               |]
   , simpleField "enabled_disk_templates"         [t| [DiskTemplate]          |]
   , simpleField "candidate_certs"                [t| CandidateCertificates   |]
   , simpleField "max_running_jobs"               [t| Int                     |]
diff --git a/src/Ganeti/Objects/HvState.hs b/src/Ganeti/Objects/HvState.hs
new file mode 100644
index 0000000..de2599f
--- /dev/null
+++ b/src/Ganeti/Objects/HvState.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE TemplateHaskell, FunctionalDependencies #-}
+
+{-| Implementation of the Ganeti HvState config object.
+
+-}
+
+{-
+
+Copyright (C) 2015 Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-}
+
+module Ganeti.Objects.HvState
+  ( FilledHvStateParams(..)
+  , PartialHvStateParams(..)
+  , allHvStateParamFields
+  , FilledHvState
+  , PartialHvState ) where
+
+import Ganeti.THH
+import Ganeti.JSON
+import Ganeti.Types
+
+$(buildParam "HvState" "hvstate"
+  [ simpleField "cpu_node"  [t| Int |]
+  , simpleField "cpu_total" [t| Int |]
+  , simpleField "mem_hv"    [t| Int |]
+  , simpleField "mem_node"  [t| Int |]
+  , simpleField "mem_total" [t| Int |]
+  ])
+
+-- | Static filled hypervisor state (hvtype to hvstate mapping)
+type FilledHvState = GenericContainer Hypervisor FilledHvStateParams
+
+-- | Static partial hypervisor state (hvtype to hvstate mapping)
+type PartialHvState = GenericContainer Hypervisor PartialHvStateParams
diff --git a/test/hs/Test/Ganeti/Objects.hs b/test/hs/Test/Ganeti/Objects.hs
index db43835..6d8deef 100644
--- a/test/hs/Test/Ganeti/Objects.hs
+++ b/test/hs/Test/Ganeti/Objects.hs
@@ -91,14 +91,37 @@ instance Arbitrary (Container DataCollectorConfig) where
     return GenericContainer {
       fromContainer = Map.fromList $ zip names configs }
 
+-- FYI: Currently only memory node value is used
+instance Arbitrary PartialHvStateParams where
+  arbitrary = PartialHvStateParams <$> pure Nothing <*> pure Nothing
+              <*> pure Nothing <*> genMaybe (fromPositive <$> arbitrary)
+              <*> pure Nothing
+
+instance Arbitrary PartialHvState where
+  arbitrary = do
+    hv_params <- arbitrary
+    return GenericContainer {
+      fromContainer = Map.fromList [ hv_params ] }
+
+-- FYI: Currently only memory node value is used
+instance Arbitrary FilledHvStateParams where
+  arbitrary = FilledHvStateParams <$> pure 0 <*> pure 0 <*> pure 0
+              <*> (fromPositive <$> arbitrary) <*> pure 0
+
+instance Arbitrary FilledHvState where
+  arbitrary = do
+    hv_params <- arbitrary
+    return GenericContainer {
+      fromContainer = Map.fromList [ hv_params ] }
+
 $(genArbitrary ''PartialNDParams)
 
 instance Arbitrary Node where
   arbitrary = Node <$> genFQDN <*> genFQDN <*> genFQDN
               <*> arbitrary <*> arbitrary <*> arbitrary <*> genFQDN
               <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
-              <*> arbitrary <*> arbitrary <*> genFQDN <*> arbitrary
-              <*> (Set.fromList <$> genTags)
+              <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
+              <*> genFQDN <*> arbitrary <*> (Set.fromList <$> genTags)
 
 $(genArbitrary ''BlockDriver)
 
@@ -662,6 +685,8 @@ genNodeGroup = do
   nic_param_list <- vectorOf num_networks (arbitrary::Gen PartialNicParams)
   net_map <- pure (GenericContainer . Map.fromList $
     zip net_uuid_list nic_param_list)
+  hv_state <- arbitrary
+  disk_state <- arbitrary
   -- timestamp fields
   ctime <- arbitrary
   mtime <- arbitrary
@@ -669,7 +694,7 @@ genNodeGroup = do
   serial <- arbitrary
   tags <- Set.fromList <$> genTags
   let group = NodeGroup name members ndparams alloc_policy ipolicy diskparams
-              net_map ctime mtime uuid serial tags
+              net_map hv_state disk_state ctime mtime uuid serial tags
   return group
 
 instance Arbitrary NodeGroup where
diff --git a/test/py/testutils/config_mock.py b/test/py/testutils/config_mock.py
index 7ae27bc..7e31cf3 100644
--- a/test/py/testutils/config_mock.py
+++ b/test/py/testutils/config_mock.py
@@ -64,6 +64,7 @@ def _UpdateIvNames(base_idx, disks):
 
 
 # pylint: disable=R0904
+# pylint: disable=W0102
 class ConfigMock(config.ConfigWriter):
   """A mocked cluster configuration with added methods for easy customization.
 
@@ -109,7 +110,7 @@ class ConfigMock(config.ConfigWriter):
                       ndparams=None,
                       diskparams=None,
                       ipolicy=None,
-                      hv_state_static=None,
+                      hv_state_static={},
                       disk_state_static=None,
                       alloc_policy=None,
                       networks=None):
@@ -160,7 +161,7 @@ class ConfigMock(config.ConfigWriter):
                  ndparams=None,
                  powered=True,
                  hv_state=None,
-                 hv_state_static=None,
+                 hv_state_static={},
                  disk_state=None,
                  disk_state_static=None):
     """Add a new L{objects.Node} to the cluster configuration
-- 
2.6.0.rc2.230.g3dd15c0

Reply via email to