Unify the “--backend-parameters” option
[ganeti-local] / lib / objects.py
index 5ae1bb9..e2154db 100644 (file)
@@ -39,6 +39,8 @@ from ganeti import constants
 __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
            "OS", "Node", "Cluster", "FillDict"]
 
+_TIMESTAMPS = ["ctime", "mtime"]
+
 def FillDict(defaults_dict, custom_dict):
   """Basic function to apply settings on top a default dict.
 
@@ -98,18 +100,6 @@ class ConfigObject(object):
                            (type(self).__name__, name))
     return None
 
-  def __setitem__(self, key, value):
-    if key not in self.__slots__:
-      raise KeyError(key)
-    setattr(self, key, value)
-
-  def __getstate__(self):
-    state = {}
-    for name in self.__slots__:
-      if hasattr(self, name):
-        state[name] = getattr(self, name)
-    return state
-
   def __setstate__(self, state):
     for name in state:
       if name in self.__slots__:
@@ -125,7 +115,14 @@ class ConfigObject(object):
     make sure all objects returned are only standard python types.
 
     """
-    return dict([(k, getattr(self, k, None)) for k in self.__slots__])
+    result = {}
+    for name in self.__slots__:
+      value = getattr(self, name, None)
+      if value is not None:
+        result[name] = value
+    return result
+
+  __getstate__ = ToDict
 
   @classmethod
   def FromDict(cls, val):
@@ -186,6 +183,14 @@ class ConfigObject(object):
                       " _ContainerFromDicts" % c_type)
     return ret
 
+  def Copy(self):
+    """Makes a deep copy of the current object and its children.
+
+    """
+    dict_form = self.ToDict()
+    clone_obj = self.__class__.FromDict(dict_form)
+    return clone_obj
+
   def __repr__(self):
     """Implement __repr__ for ConfigObjects."""
     return repr(self.ToDict())
@@ -280,7 +285,8 @@ class TaggableObject(ConfigObject):
 
 class ConfigData(ConfigObject):
   """Top-level config object."""
-  __slots__ = ["version", "cluster", "nodes", "instances", "serial_no"]
+  __slots__ = (["version", "cluster", "nodes", "instances", "serial_no"] +
+               _TIMESTAMPS)
 
   def ToDict(self):
     """Custom function for top-level config data.
@@ -462,6 +468,15 @@ class Disk(ConfigObject):
       raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
                                    " disk type %s" % self.dev_type)
 
+  def UnsetSize(self):
+    """Sets recursively the size to zero for the disk and its children.
+
+    """
+    if self.children:
+      for child in self.children:
+        child.UnsetSize()
+    self.size = 0
+
   def SetPhysicalID(self, target_node, nodes_ip):
     """Convert the logical ID to the physical ID.
 
@@ -578,10 +593,10 @@ class Disk(ConfigObject):
     """Checks that this disk is correctly configured.
 
     """
-    errs = []
+    all_errors = []
     if self.mode not in constants.DISK_ACCESS_SET:
-      errs.append("Disk access mode '%s' is invalid" % (self.mode, ))
-    return errs
+      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
+    return all_errors
 
 
 class Instance(TaggableObject):
@@ -599,7 +614,7 @@ class Instance(TaggableObject):
     "disk_template",
     "network_port",
     "serial_no",
-    ]
+    ] + _TIMESTAMPS
 
   def _ComputeSecondaryNodes(self):
     """Compute the list of secondary nodes.
@@ -756,7 +771,7 @@ class Node(TaggableObject):
     "master_candidate",
     "offline",
     "drained",
-    ]
+    ] + _TIMESTAMPS
 
 
 class Cluster(TaggableObject):
@@ -781,7 +796,7 @@ class Cluster(TaggableObject):
     "nicparams",
     "candidate_pool_size",
     "modify_etc_hosts",
-    ]
+    ] + _TIMESTAMPS
 
   def UpgradeConfig(self):
     """Fill defaults for missing configuration values.
@@ -811,6 +826,13 @@ class Cluster(TaggableObject):
     if self.default_bridge is not None:
       self.default_bridge = None
 
+    # default_hypervisor is just the first enabled one in 2.1
+    if self.default_hypervisor is not None:
+      self.enabled_hypervisors = ([self.default_hypervisor] +
+        [hvname for hvname in self.enabled_hypervisors
+         if hvname != self.default_hypervisor])
+      self.default_hypervisor = None
+
   def ToDict(self):
     """Custom function for cluster.
 
@@ -856,6 +878,53 @@ class Cluster(TaggableObject):
                           instance.beparams)
 
 
+class BlockDevStatus(ConfigObject):
+  """Config object representing the status of a block device."""
+  __slots__ = [
+    "dev_path",
+    "major",
+    "minor",
+    "sync_percent",
+    "estimated_time",
+    "is_degraded",
+    "ldisk_status",
+    ]
+
+
+class ConfdRequest(ConfigObject):
+  """Object holding a confd request.
+
+  @ivar protocol: confd protocol version
+  @ivar type: confd query type
+  @ivar query: query request
+  @ivar rsalt: requested reply salt
+
+  """
+  __slots__ = [
+    "protocol",
+    "type",
+    "query",
+    "rsalt",
+    ]
+
+
+class ConfdReply(ConfigObject):
+  """Object holding a confd reply.
+
+  @ivar protocol: confd protocol version
+  @ivar status: reply status code (ok, error)
+  @ivar answer: confd query reply
+  @ivar serial: configuration serial number
+
+  """
+  __slots__ = [
+    "protocol",
+    "status",
+    "answer",
+    "serial",
+    ]
+
+
 class SerializableConfigParser(ConfigParser.SafeConfigParser):
   """Simple wrapper over ConfigParse that allows serialization.