commit ffa1c0dc146c9929b7baf7f2d3b18f9e0144fcbf
Author: Iustin Pop <iustin@google.com>
Date:   Mon Sep 22 11:32:16 2008 +0000

    Extend DRBD disks with minors attribute
    
    This patch converts the DRBD disks to contain also a minor (per each
    node) attribute. This minor is not yet used and is always initialized
    with None, so the patch does not have any real-world impact - except for
    automatically upgrading config files (it adds the minors as None, None).
    
    Reviewed-by: imsnah

diff --git a/lib/bdev.py b/lib/bdev.py
index 7ba3470..c3f4a7c 100644
--- a/lib/bdev.py
+++ b/lib/bdev.py
@@ -804,9 +804,15 @@ class DRBD8(BaseDRBD):
 
     if len(children) not in (0, 2):
       raise ValueError("Invalid configuration data %s" % str(children))
-    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 4:
+    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 5:
       raise ValueError("Invalid configuration data %s" % str(unique_id))
-    self._lhost, self._lport, self._rhost, self._rport = unique_id
+    (self._lhost, self._lport,
+     self._rhost, self._rport,
+     self._aminor) = unique_id
+    if (self._lhost is not None and self._lhost == self._rhost and
+        self._lport == self._rport):
+      raise ValueError("Invalid configuration data, same local/remote %s" %
+                       (unique_id,))
     self.Attach()
 
   @classmethod
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 3c86387..224fc16 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -30,6 +30,7 @@ import time
 import tempfile
 import re
 import platform
+import logging
 
 from ganeti import rpc
 from ganeti import ssh
@@ -2909,7 +2910,8 @@ def _GenerateUniqueNames(cfg, exts):
   return results
 
 
-def _GenerateDRBD8Branch(cfg, primary, secondary, size, names, iv_name):
+def _GenerateDRBD8Branch(cfg, primary, secondary, size, names, iv_name,
+                         p_minor, s_minor):
   """Generate a drbd8 device complete with its children.
 
   """
@@ -2920,8 +2922,9 @@ def _GenerateDRBD8Branch(cfg, primary, secondary, size, names, iv_name):
   dev_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
                           logical_id=(vgname, names[1]))
   drbd_dev = objects.Disk(dev_type=constants.LD_DRBD8, size=size,
-                          logical_id = (primary, secondary, port),
-                          children = [dev_data, dev_meta],
+                          logical_id=(primary, secondary, port,
+                                      p_minor, s_minor),
+                          children=[dev_data, dev_meta],
                           iv_name=iv_name)
   return drbd_dev
 
@@ -2954,12 +2957,17 @@ def _GenerateDiskTemplate(cfg, template_name,
     if len(secondary_nodes) != 1:
       raise errors.ProgrammerError("Wrong template configuration")
     remote_node = secondary_nodes[0]
+    (minor_pa, minor_pb,
+     minor_sa, minor_sb) = [None, None, None, None]
+
     names = _GenerateUniqueNames(cfg, [".sda_data", ".sda_meta",
                                        ".sdb_data", ".sdb_meta"])
     drbd_sda_dev = _GenerateDRBD8Branch(cfg, primary_node, remote_node,
-                                         disk_sz, names[0:2], "sda")
+                                        disk_sz, names[0:2], "sda",
+                                        minor_pa, minor_sa)
     drbd_sdb_dev = _GenerateDRBD8Branch(cfg, primary_node, remote_node,
-                                         swap_sz, names[2:4], "sdb")
+                                        swap_sz, names[2:4], "sdb",
+                                        minor_pb, minor_sb)
     disks = [drbd_sda_dev, drbd_sdb_dev]
   elif template_name == constants.DT_FILE:
     if len(secondary_nodes) != 0:
@@ -4003,8 +4011,11 @@ class LUReplaceDisks(LogicalUnit):
                                  pri_node)
 
     # Step: create new storage
+
+    minors = [None for dev in instance.disks]
+    logging.debug("Allocated minors %s" % (minors,))
     self.proc.LogStep(3, steps_total, "allocate new storage")
-    for dev in instance.disks:
+    for idx, dev in enumerate(instance.disks):
       size = dev.size
       info("adding new local storage on %s for %s" % (new_node, dev.iv_name))
       # since we *always* want to create this LV, we use the
@@ -4017,16 +4028,22 @@ class LUReplaceDisks(LogicalUnit):
                                    " node '%s'" %
                                    (new_lv.logical_id[1], new_node))
 
-      iv_names[dev.iv_name] = (dev, dev.children)
+      iv_names[dev.iv_name] = (dev, dev.children, minors[idx])
 
     self.proc.LogStep(4, steps_total, "changing drbd configuration")
     for dev in instance.disks:
       size = dev.size
       info("activating a new drbd on %s for %s" % (new_node, dev.iv_name))
       # create new devices on new_node
+      new_minor = iv_names[dev.iv_name][2]
+      if pri_node == dev.logical_id[0]:
+        new_logical_id = (pri_node, new_node,
+                          dev.logical_id[2], dev.logical_id[3], new_minor)
+      else:
+        new_logical_id = (new_node, pri_node,
+                          dev.logical_id[2], new_minor, dev.logical_id[4])
       new_drbd = objects.Disk(dev_type=constants.LD_DRBD8,
-                              logical_id=(pri_node, new_node,
-                                          dev.logical_id[2]),
+                              logical_id=new_logical_id,
                               children=dev.children)
       if not _CreateBlockDevOnSecondary(cfg, new_node, instance,
                                         new_drbd, False,
@@ -4048,7 +4065,7 @@ class LUReplaceDisks(LogicalUnit):
       cfg.SetDiskID(dev, pri_node)
       # set the physical (unique in bdev terms) id to None, meaning
       # detach from network
-      dev.physical_id = (None,) * len(dev.physical_id)
+      dev.physical_id = (None, None, None, None, dev.physical_id[4])
       # and 'find' the device, which will 'fix' it to match the
       # standalone state
       if rpc.call_blockdev_find(pri_node, dev):
@@ -4078,6 +4095,7 @@ class LUReplaceDisks(LogicalUnit):
       # it will automatically activate the network, if the physical_id
       # is correct
       cfg.SetDiskID(dev, pri_node)
+      logging.debug("Disk to attach: %s", dev)
       if not rpc.call_blockdev_find(pri_node, dev):
         warning("can't attach drbd %s to new secondary!" % dev.iv_name,
                 "please do a gnt-instance info to see the status of disks")
@@ -4089,14 +4107,14 @@ class LUReplaceDisks(LogicalUnit):
     _WaitForSync(cfg, instance, self.proc, unlock=True)
 
     # so check manually all the devices
-    for name, (dev, old_lvs) in iv_names.iteritems():
+    for name, (dev, old_lvs, _) in iv_names.iteritems():
       cfg.SetDiskID(dev, pri_node)
       is_degr = rpc.call_blockdev_find(pri_node, dev)[5]
       if is_degr:
         raise errors.OpExecError("DRBD device %s is degraded!" % name)
 
     self.proc.LogStep(6, steps_total, "removing old storage")
-    for name, (dev, old_lvs) in iv_names.iteritems():
+    for name, (dev, old_lvs, _) in iv_names.iteritems():
       info("remove logical volumes for %s" % name)
       for lv in old_lvs:
         cfg.SetDiskID(lv, old_node)
diff --git a/lib/config.py b/lib/config.py
index efd24d4..87bf557 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -229,8 +229,8 @@ class ConfigWriter:
 
     if disk.logical_id is None and disk.physical_id is not None:
       return
-    if disk.dev_type in constants.LDS_DRBD:
-      pnode, snode, port = disk.logical_id
+    if disk.dev_type == constants.LD_DRBD8:
+      pnode, snode, port, pminor, sminor = disk.logical_id
       if node_name not in (pnode, snode):
         raise errors.ConfigurationError("DRBD device not knowing node %s" %
                                         node_name)
@@ -239,12 +239,12 @@ class ConfigWriter:
       if pnode_info is None or snode_info is None:
         raise errors.ConfigurationError("Can't find primary or secondary node"
                                         " for %s" % str(disk))
+      p_data = (pnode_info.secondary_ip, port)
+      s_data = (snode_info.secondary_ip, port)
       if pnode == node_name:
-        disk.physical_id = (pnode_info.secondary_ip, port,
-                            snode_info.secondary_ip, port)
+        disk.physical_id = p_data + s_data + (pminor,)
       else: # it must be secondary, we tested above
-        disk.physical_id = (snode_info.secondary_ip, port,
-                            pnode_info.secondary_ip, port)
+        disk.physical_id = s_data + p_data + (sminor,)
     else:
       disk.physical_id = disk.logical_id
     return
diff --git a/lib/objects.py b/lib/objects.py
index 5282e9f..a26907d 100644
--- a/lib/objects.py
+++ b/lib/objects.py
@@ -412,7 +412,7 @@ class Disk(ConfigObject):
     if self.logical_id is None and self.physical_id is not None:
       return
     if self.dev_type in constants.LDS_DRBD:
-      pnode, snode, port = self.logical_id
+      pnode, snode, port, pminor, sminor = self.logical_id
       if target_node not in (pnode, snode):
         raise errors.ConfigurationError("DRBD device not knowing node %s" %
                                         target_node)
@@ -421,12 +421,12 @@ class Disk(ConfigObject):
       if pnode_ip is None or snode_ip is None:
         raise errors.ConfigurationError("Can't find primary or secondary node"
                                         " for %s" % str(self))
+      p_data = (pnode_ip, port)
+      s_data = (snode_ip, port)
       if pnode == target_node:
-        self.physical_id = (pnode_ip, port,
-                            snode_ip, port)
+        self.physical_id = p_data + s_data + (pminor,)
       else: # it must be secondary, we tested above
-        self.physical_id = (snode_ip, port,
-                            pnode_ip, port)
+        self.physical_id = s_data + p_data + (sminor,)
     else:
       self.physical_id = self.logical_id
     return
@@ -458,6 +458,9 @@ class Disk(ConfigObject):
       obj.logical_id = tuple(obj.logical_id)
     if obj.physical_id and isinstance(obj.physical_id, list):
       obj.physical_id = tuple(obj.physical_id)
+    if obj.dev_type in constants.LDS_DRBD and len(obj.logical_id) == 3:
+      # old non-minor based disk type
+      obj.logical_id += (None, None)
     return obj
 
   def __str__(self):
@@ -529,7 +532,7 @@ class Instance(TaggableObject):
     def _Helper(primary, sec_nodes, device):
       """Recursively computes secondary nodes given a top device."""
       if device.dev_type in constants.LDS_DRBD:
-        nodea, nodeb, dummy = device.logical_id
+        nodea, nodeb, dummy = device.logical_id[:3]
         if nodea == primary:
           candidate = nodeb
         else:
