On Tue, Jul 14, 2015 at 05:59:20PM +0200, 'Klaus Aehlig' via ganeti-devel wrote:
As per our design, the maintenance daemons stores its state
in the configuration; also, various of its aspects are
configurable. So add a corresponding configuration object.

Signed-off-by: Klaus Aehlig <[email protected]>
---
Makefile.am                       |  1 +
lib/bootstrap.py                  |  2 ++
lib/objects.py                    | 21 +++++++++++++-
lib/tools/cfgupgrade.py           | 13 ++++++++-
src/Ganeti/Objects.hs             |  3 ++
src/Ganeti/Objects/Lens.hs        |  8 ++++++
src/Ganeti/Objects/Maintenance.hs | 59 +++++++++++++++++++++++++++++++++++++++
test/hs/Test/Ganeti/Objects.hs    | 10 ++++++-
test/py/cfgupgrade_unittest.py    |  1 +
9 files changed, 115 insertions(+), 3 deletions(-)
create mode 100644 src/Ganeti/Objects/Maintenance.hs

diff --git a/Makefile.am b/Makefile.am
index 57760c3..bd5b64b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -983,6 +983,7 @@ HS_LIB_SRCS = \
        src/Ganeti/Objects/Disk.hs \
        src/Ganeti/Objects/Instance.hs \
        src/Ganeti/Objects/Lens.hs \
+       src/Ganeti/Objects/Maintenance.hs \
        src/Ganeti/Objects/Nic.hs \
        src/Ganeti/OpCodes.hs \
        src/Ganeti/OpCodes/Lens.hs \
diff --git a/lib/bootstrap.py b/lib/bootstrap.py
index 1164e5e..9fc0231 100644
--- a/lib/bootstrap.py
+++ b/lib/bootstrap.py
@@ -863,6 +863,7 @@ def InitConfig(version, cluster_config, master_node_config,
    default_nodegroup.uuid: default_nodegroup,
    }
  now = time.time()
+  maintenance = objects.Maintenance(serial_no=1, ctime=now, mtime=now)
  config_data = objects.ConfigData(version=version,
                                   cluster=cluster_config,
                                   nodegroups=nodegroups,
@@ -871,6 +872,7 @@ def InitConfig(version, cluster_config, master_node_config,
                                   networks={},
                                   disks={},
                                   filters={},
+                                   maintenance=maintenance,
                                   serial_no=1,
                                   ctime=now, mtime=now)
  utils.WriteFile(cfg_file,
diff --git a/lib/objects.py b/lib/objects.py
index 0ce3c0f..806fe75 100644
--- a/lib/objects.py
+++ b/lib/objects.py
@@ -63,7 +63,7 @@ from socket import AF_INET

__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
           "OS", "Node", "NodeGroup", "Cluster", "FillDict", "Network",
-           "Filter"]
+           "Filter", "Maintenance"]

_TIMESTAMPS = ["ctime", "mtime"]
_UUID = ["uuid"]
@@ -416,6 +416,7 @@ class ConfigData(ConfigObject):
    "networks",
    "disks",
    "filters",
+    "maintenance",
    "serial_no",
    ] + _TIMESTAMPS

@@ -428,6 +429,7 @@ class ConfigData(ConfigObject):
    """
    mydict = super(ConfigData, self).ToDict(_with_private=_with_private)
    mydict["cluster"] = mydict["cluster"].ToDict()
+    mydict["maintenance"] = mydict["maintenance"].ToDict()
    for key in ("nodes", "instances", "nodegroups", "networks", "disks",
                "filters"):
      mydict[key] = outils.ContainerToDicts(mydict[key])
@@ -449,6 +451,7 @@ class ConfigData(ConfigObject):
    obj.networks = outils.ContainerFromDicts(obj.networks, dict, Network)
    obj.disks = outils.ContainerFromDicts(obj.disks, dict, Disk)
    obj.filters = outils.ContainerFromDicts(obj.filters, dict, Filter)
+    obj.maintenance = Maintenance.FromDict(obj.maintenance)
    return obj

  def DisksOfType(self, dev_type):
@@ -491,6 +494,9 @@ class ConfigData(ConfigObject):
      disk.UpgradeConfig()
    if self.filters is None:
      self.filters = {}
+    if self.maintenance is None:
+      self.maintenance = Maintenance.FromDict({})
+    self.maintenance.UpgradeConfig()

  def _UpgradeEnabledDiskTemplates(self):
    """Upgrade the cluster's enabled disk templates by inspecting the currently
@@ -549,6 +555,19 @@ class Filter(ConfigObject):
               "predicates", "action", "reason_trail"] + _UUID


+class Maintenance(ConfigObject):
+  """Config object representing the state of the maintenance daemon"""
+  __slots__ = ["roundDelay", "jobs", "serial_no"] + _TIMESTAMPS
+
+  def UpgradeConfig(self):
+    if self.serial_no is None:
+      self.serial_no = 1
+    if self.mtime is None:
+      self.mtime = time.time()
+    if self.ctime is None:
+      self.ctime = time.time()
+
+
class Disk(ConfigObject):
  """Config object representing a block device."""
  __slots__ = [
diff --git a/lib/tools/cfgupgrade.py b/lib/tools/cfgupgrade.py
index d64c7f9..90fe2c9 100644
--- a/lib/tools/cfgupgrade.py
+++ b/lib/tools/cfgupgrade.py
@@ -677,6 +677,14 @@ class CfgUpgrade(object):
        else:
          disk["nodes"] = []

+  @OrFail("Upgrading maintenance data")
+  def UpgradeMaintenance(self):
+    # pylint can't infer config_data type
+    # pylint: disable=E1103
+    maintenance = self.config_data.get("maintenance", None)
+    if maintenance is None:
+      self.config_data["maintenance"] = {}
+
  def UpgradeAll(self):
    self.config_data["version"] = version.BuildVersion(TARGET_MAJOR,
                                                       TARGET_MINOR, 0)
@@ -692,7 +700,8 @@ class CfgUpgrade(object):
             self.UpgradeInstanceIndices,
             self.UpgradeFilters,
             self.UpgradeDiskNodes,
-             self.UpgradeDiskTemplate]
+             self.UpgradeDiskTemplate,
+             self.UpgradeMaintenance]
    for s in steps:
      s()
    return not self.errors
@@ -700,6 +709,8 @@ class CfgUpgrade(object):
  # DOWNGRADE ------------------------------------------------------------

  def DowngradeAll(self):
+    if "maintenance" in self.config_data:
+      del self.config_data["maintenance"]
    self.config_data["version"] = version.BuildVersion(DOWNGRADE_MAJOR,
                                                       DOWNGRADE_MINOR, 0)
    return True
diff --git a/src/Ganeti/Objects.hs b/src/Ganeti/Objects.hs
index 2bf734f..ee4fd70 100644
--- a/src/Ganeti/Objects.hs
+++ b/src/Ganeti/Objects.hs
@@ -103,6 +103,7 @@ module Ganeti.Objects
  , module Ganeti.PartialParams
  , module Ganeti.Objects.Disk
  , module Ganeti.Objects.Instance
+  , module Ganeti.Objects.Maintenance
  ) where

import Control.Applicative
@@ -126,6 +127,7 @@ import qualified Ganeti.ConstantUtils as ConstantUtils
import Ganeti.JSON
import Ganeti.Objects.BitArray (BitArray)
import Ganeti.Objects.Disk
+import Ganeti.Objects.Maintenance
import Ganeti.Objects.Nic
import Ganeti.Objects.Instance
import Ganeti.Query.Language
@@ -701,6 +703,7 @@ $(buildObject "ConfigData" "config" $
  , simpleField "networks"   [t| Container Network   |]
  , simpleField "disks"      [t| Container Disk      |]
  , simpleField "filters"    [t| Container FilterRule |]
+  , simpleField "maintenance" [t| MaintenanceData    |]
  ]
  ++ timeStampFields
  ++ serialFields)
diff --git a/src/Ganeti/Objects/Lens.hs b/src/Ganeti/Objects/Lens.hs
index 05bb5f2..8850dc9 100644
--- a/src/Ganeti/Objects/Lens.hs
+++ b/src/Ganeti/Objects/Lens.hs
@@ -149,6 +149,14 @@ instance SerialNoObjectL Cluster where
instance TagsObjectL Cluster where
  tagsL = clusterTagsL

+$(makeCustomLenses ''MaintenanceData)
+
+instance TimeStampObjectL MaintenanceData where
+  mTimeL = maintMtimeL
+
+instance SerialNoObjectL MaintenanceData where
+  serialL = maintSerialL
+
$(makeCustomLenses ''ConfigData)

instance SerialNoObjectL ConfigData where
diff --git a/src/Ganeti/Objects/Maintenance.hs 
b/src/Ganeti/Objects/Maintenance.hs
new file mode 100644
index 0000000..8587f81
--- /dev/null
+++ b/src/Ganeti/Objects/Maintenance.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+{-| Implementation of the Ganeti configuration for the maintenance daemon.
+
+-}
+
+{-
+
+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.Maintenance
+  ( MaintenanceData(..)
+  ) where
+
+import qualified Ganeti.Constants as C
+import Ganeti.THH
+import Ganeti.THH.Field
+import Ganeti.Types
+
+$(buildObject "MaintenanceData" "maint" $
+  [ defaultField [| C.maintdDefaultRoundDelay |]
+    $ simpleField "roundDelay" [t| Int |]
+  , defaultField [| [] |] $ simpleField "jobs" [t| [ JobId ] |]
+  ]
+  ++ timeStampFields
+  ++ serialFields)
+
+instance SerialNoObject MaintenanceData where
+  serialOf = maintSerial
+
+instance TimeStampObject MaintenanceData where
+  cTimeOf = maintCtime
+  mTimeOf = maintMtime
diff --git a/test/hs/Test/Ganeti/Objects.hs b/test/hs/Test/Ganeti/Objects.hs
index 319e7ee..4b116e1 100644
--- a/test/hs/Test/Ganeti/Objects.hs
+++ b/test/hs/Test/Ganeti/Objects.hs
@@ -375,6 +375,13 @@ instance Arbitrary FilterRule where
                         <*> arbitrary
                         <*> genUUID

+instance Arbitrary MaintenanceData where
+  arbitrary = MaintenanceData <$> (fromPositive <$> arbitrary)
+                              <*> arbitrary
+                              <*> arbitrary
+                              <*> arbitrary
+                              <*> arbitrary
+
-- | Generates a network instance with minimum netmasks of /24. Generating
-- bigger networks slows down the tests, because long bit strings are generated
-- for the reservations.
@@ -431,6 +438,7 @@ genEmptyCluster ncount = do
      networks = GenericContainer Map.empty
      disks = GenericContainer Map.empty
      filters = GenericContainer Map.empty
+  maintenance <- arbitrary
  let contgroups = GenericContainer $ Map.singleton guuid grp
  serial <- arbitrary
  -- timestamp fields
@@ -438,7 +446,7 @@ genEmptyCluster ncount = do
  mtime <- arbitrary
  cluster <- resize 8 arbitrary
  let c = ConfigData version cluster contnodes contgroups continsts networks
-            disks filters ctime mtime serial
+            disks filters ctime maintenance mtime serial
  return c

-- | FIXME: make an even simpler base version of creating a cluster.
diff --git a/test/py/cfgupgrade_unittest.py b/test/py/cfgupgrade_unittest.py
index eb4a396..a436351 100755
--- a/test/py/cfgupgrade_unittest.py
+++ b/test/py/cfgupgrade_unittest.py
@@ -79,6 +79,7 @@ def GetMinimalConfig():
    "disks": {},
    "networks": {},
    "filters": {},
+    "maintenance": {},
    "nodegroups": {},
    "nodes": {
      "node1-uuid": {
--
2.4.3.573.g4eafbef


LGTM

Reply via email to