Change config upgrade to be explicit
[ganeti-local] / lib / objects.py
index 0feefbe..43cea75 100644 (file)
@@ -153,10 +153,27 @@ 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())
 
+  def UpgradeConfig(self):
+    """Fill defaults for missing configuration values.
+
+    This method will be called at configuration load time, and its
+    implementation will be object dependent.
+
+    """
+    pass
+
 
 class TaggableObject(ConfigObject):
   """An generic class supporting tags.
@@ -179,7 +196,7 @@ class TaggableObject(ConfigObject):
                             constants.MAX_TAG_LEN)
     if not tag:
       raise errors.TagError("Tags cannot be empty")
-    if not re.match("^[ \w.+*/:-]+$", tag):
+    if not re.match("^[\w.+*/:-]+$", tag):
       raise errors.TagError("Tag contains invalid characters")
 
   def GetTags(self):
@@ -265,6 +282,16 @@ class ConfigData(ConfigObject):
     obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
     return obj
 
+  def UpgradeConfig(self):
+    """Fill defaults for missing configuration values.
+
+    """
+    self.cluster.UpgradeConfig()
+    for node in self.nodes.values():
+      node.UpgradeConfig()
+    for instance in self.instances.values():
+      instance.UpgradeConfig()
+
 
 class NIC(ConfigObject):
   """Config object representing a network card."""
@@ -388,6 +415,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.
 
@@ -494,17 +530,29 @@ class Disk(ConfigObject):
       val += ", not visible"
     else:
       val += ", visible as /dev/%s" % self.iv_name
-    val += ", size=%dm)>" % self.size
+    if isinstance(self.size, int):
+      val += ", size=%dm)>" % self.size
+    else:
+      val += ", size='%s')>" % (self.size,)
     return val
 
   def Verify(self):
     """Checks that this disk is correctly configured.
 
     """
-    errors = []
+    all_errors = []
     if self.mode not in constants.DISK_ACCESS_SET:
-      errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
-    return errors
+      all_errors.append("Disk access mode '%s' is invalid" % (self.mode, ))
+    return all_errors
+
+  def UpgradeConfig(self):
+    """Fill defaults for missing configuration values.
+
+    """
+    if self.children:
+      for child in self.children:
+        child.UpgradeConfig()
+    # add here config upgrade for this disk
 
 
 class Instance(TaggableObject):
@@ -655,6 +703,15 @@ class Instance(TaggableObject):
     obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
     return obj
 
+  def UpgradeConfig(self):
+    """Fill defaults for missing configuration values.
+
+    """
+    for nic in self.nics:
+      nic.UpgradeConfig()
+    for disk in self.disks:
+      disk.UpgradeConfig()
+
 
 class OS(ConfigObject):
   """Config object representing an operating system."""
@@ -698,6 +755,7 @@ class Node(TaggableObject):
     "serial_no",
     "master_candidate",
     "offline",
+    "drained",
     ]
 
 
@@ -721,8 +779,30 @@ class Cluster(TaggableObject):
     "hvparams",
     "beparams",
     "candidate_pool_size",
+    "modify_etc_hosts",
     ]
 
+  def UpgradeConfig(self):
+    """Fill defaults for missing configuration values.
+
+    """
+    if self.hvparams is None:
+      self.hvparams = constants.HVC_DEFAULTS
+    else:
+      for hypervisor in self.hvparams:
+        self.hvparams[hypervisor] = self.FillDict(
+            constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
+
+    if self.beparams is None:
+      self.beparams = {constants.BEGR_DEFAULT: constants.BEC_DEFAULTS}
+    else:
+      for begroup in self.beparams:
+        self.beparams[begroup] = self.FillDict(constants.BEC_DEFAULTS,
+                                               self.beparams[begroup])
+
+    if self.modify_etc_hosts is None:
+      self.modify_etc_hosts = True
+
   def ToDict(self):
     """Custom function for cluster.
 
@@ -760,7 +840,7 @@ class Cluster(TaggableObject):
   def FillHV(self, instance):
     """Fill an instance's hvparams dict.
 
-    @type instance: object
+    @type instance: L{objects.Instance}
     @param instance: the instance parameter to fill
     @rtype: dict
     @return: a copy of the instance's hvparams with missing keys filled from
@@ -773,7 +853,7 @@ class Cluster(TaggableObject):
   def FillBE(self, instance):
     """Fill an instance's beparams dict.
 
-    @type instance: object
+    @type instance: L{objects.Instance}
     @param instance: the instance parameter to fill
     @rtype: dict
     @return: a copy of the instance's beparams with missing keys filled from