Move the hooks file mask into constants.py
[ganeti-local] / lib / objects.py
index 26facb6..43cea75 100644 (file)
@@ -50,7 +50,7 @@ class ConfigObject(object):
       as None instead of raising an error
 
   Classes derived from this must always declare __slots__ (we use many
-  config objects and the memory reduction is useful.
+  config objects and the memory reduction is useful)
 
   """
   __slots__ = []
@@ -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.
 
@@ -472,6 +508,7 @@ class Disk(ConfigObject):
     if self.dev_type == constants.LD_LV:
       val =  "<LogicalVolume(/dev/%s/%s" % self.logical_id
     elif self.dev_type in constants.LDS_DRBD:
+      node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
       val = "<DRBD8("
       if self.physical_id is None:
         phy = "unconfigured"
@@ -480,9 +517,8 @@ class Disk(ConfigObject):
                (self.physical_id[0], self.physical_id[1],
                 self.physical_id[2], self.physical_id[3]))
 
-      val += ("hosts=%s-%s, port=%s, %s, " %
-              (self.logical_id[0], self.logical_id[1], self.logical_id[2],
-               phy))
+      val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
+              (node_a, minor_a, node_b, minor_b, port, phy))
       if self.children and self.children.count(None) == 0:
         val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
       else:
@@ -494,9 +530,30 @@ 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.
+
+    """
+    all_errors = []
+    if self.mode not in constants.DISK_ACCESS_SET:
+      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):
   """Config object representing an instance."""
@@ -507,7 +564,7 @@ class Instance(TaggableObject):
     "hypervisor",
     "hvparams",
     "beparams",
-    "status",
+    "admin_up",
     "nics",
     "disks",
     "disk_template",
@@ -548,6 +605,7 @@ class Instance(TaggableObject):
           _Helper(nodes, child)
 
     all_nodes = set()
+    all_nodes.add(self.primary_node)
     for device in self.disks:
       _Helper(all_nodes, device)
     return tuple(all_nodes)
@@ -645,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."""
@@ -688,6 +755,7 @@ class Node(TaggableObject):
     "serial_no",
     "master_candidate",
     "offline",
+    "drained",
     ]
 
 
@@ -711,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.
 
@@ -750,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
@@ -763,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