From f9518d384bec1a7ec62e53675f8d8e54f6c1f22b Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Mon, 29 Sep 2008 13:15:08 +0000
Subject: [PATCH] Extend DRBD disks with shared secret attribute

This patch, which is similar to r1679 (Extend DRBD disks with minors
attribute), extends the logical and physical id of the DRBD disks with a
shared secret attribute. This is generated at disk creation time and
saved in the config file.

The generation of the secret is done so that we don't have duplicates in
the configuration (otherwise the goal of preventing cross-connection
will not be reached), so we add to config.py more than just a simple
call to utils.GenerateSecret().

The patch does not yet enable the use of the secrets.

Reviewed-by: imsnah
---
 lib/bdev.py    |  4 ++--
 lib/cmdlib.py  | 16 ++++++++++------
 lib/config.py  | 48 +++++++++++++++++++++++++++++++++++++++++++-----
 lib/objects.py | 13 +++++++------
 4 files changed, 62 insertions(+), 19 deletions(-)

diff --git a/lib/bdev.py b/lib/bdev.py
index 4732992ef..3648a2c03 100644
--- a/lib/bdev.py
+++ b/lib/bdev.py
@@ -804,11 +804,11 @@ 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) != 5:
+    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 6:
       raise ValueError("Invalid configuration data %s" % str(unique_id))
     (self._lhost, self._lport,
      self._rhost, self._rport,
-     self._aminor) = unique_id
+     self._aminor, self._secret) = 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" %
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index c9474b0ef..4822f5425 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -2923,13 +2923,15 @@ def _GenerateDRBD8Branch(cfg, primary, secondary, size, names, iv_name,
   """
   port = cfg.AllocatePort()
   vgname = cfg.GetVGName()
+  shared_secret = cfg.GenerateDRBDSecret()
   dev_data = objects.Disk(dev_type=constants.LD_LV, size=size,
                           logical_id=(vgname, names[0]))
   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,
-                                      p_minor, s_minor),
+                                      p_minor, s_minor,
+                                      shared_secret),
                           children=[dev_data, dev_meta],
                           iv_name=iv_name)
   return drbd_dev
@@ -4050,10 +4052,12 @@ class LUReplaceDisks(LogicalUnit):
       # create new devices on new_node
       if pri_node == dev.logical_id[0]:
         new_logical_id = (pri_node, new_node,
-                          dev.logical_id[2], dev.logical_id[3], new_minor)
+                          dev.logical_id[2], dev.logical_id[3], new_minor,
+                          dev.logical_id[5])
       else:
         new_logical_id = (new_node, pri_node,
-                          dev.logical_id[2], new_minor, dev.logical_id[4])
+                          dev.logical_id[2], new_minor, dev.logical_id[4],
+                          dev.logical_id[5])
       iv_names[dev.iv_name] = (dev, dev.children, new_logical_id)
       logging.debug("Allocated new_minor: %s, new_logical_id: %s", new_minor,
                     new_logical_id)
@@ -4079,9 +4083,9 @@ class LUReplaceDisks(LogicalUnit):
     done = 0
     for dev in instance.disks:
       cfg.SetDiskID(dev, pri_node)
-      # set the physical (unique in bdev terms) id to None, meaning
-      # detach from network
-      dev.physical_id = (None, None, None, None, dev.physical_id[4])
+      # set the network part of the physical (unique in bdev terms) id
+      # to None, meaning detach from network
+      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):
diff --git a/lib/config.py b/lib/config.py
index f44340b8d..27f85f561 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -126,6 +126,25 @@ class ConfigWriter:
     all_macs = self._AllMACs()
     return mac in all_macs
 
+  @locking.ssynchronized(_config_lock, shared=1)
+  def GenerateDRBDSecret(self):
+    """Generate a DRBD secret.
+
+    This checks the current disks for duplicates.
+
+    """
+    self._OpenConfig()
+    all_secrets = self._AllDRBDSecrets()
+    retries = 64
+    while retries > 0:
+      secret = utils.GenerateSecret()
+      if secret not in all_secrets:
+        break
+      retries -= 1
+    else:
+      raise errors.ConfigurationError("Can't generate unique DRBD secret")
+    return secret
+
   def _ComputeAllLVs(self):
     """Compute the list of all LVs.
 
@@ -185,6 +204,25 @@ class ConfigWriter:
 
     return result
 
+  def _AllDRBDSecrets(self):
+    """Return all DRBD secrets present in the config.
+
+    """
+    def helper(disk, result):
+      """Recursively gather secrets from this disk."""
+      if disk.dev_type == constants.DT_DRBD8:
+        result.append(disk.logical_id[5])
+      if disk.children:
+        for child in disk.children:
+          helper(child, result)
+
+    result = []
+    for instance in self._config_data.instances.values():
+      for disk in instance.disks:
+        helper(disk, result)
+
+    return result
+
   @locking.ssynchronized(_config_lock, shared=1)
   def VerifyConfig(self):
     """Stub verify function.
@@ -268,7 +306,7 @@ class ConfigWriter:
     if disk.logical_id is None and disk.physical_id is not None:
       return
     if disk.dev_type == constants.LD_DRBD8:
-      pnode, snode, port, pminor, sminor = disk.logical_id
+      pnode, snode, port, pminor, sminor, secret = disk.logical_id
       if node_name not in (pnode, snode):
         raise errors.ConfigurationError("DRBD device not knowing node %s" %
                                         node_name)
@@ -280,9 +318,9 @@ class ConfigWriter:
       p_data = (pnode_info.secondary_ip, port)
       s_data = (snode_info.secondary_ip, port)
       if pnode == node_name:
-        disk.physical_id = p_data + s_data + (pminor,)
+        disk.physical_id = p_data + s_data + (pminor, secret)
       else: # it must be secondary, we tested above
-        disk.physical_id = s_data + p_data + (sminor,)
+        disk.physical_id = s_data + p_data + (sminor, secret)
     else:
       disk.physical_id = disk.logical_id
     return
@@ -354,8 +392,8 @@ class ConfigWriter:
 
     """
     def _AppendUsedPorts(instance_name, disk, used):
-      if disk.dev_type == constants.LD_DRBD8 and len(disk.logical_id) == 5:
-        nodeA, nodeB, dummy, minorA, minorB = disk.logical_id
+      if disk.dev_type == constants.LD_DRBD8 and len(disk.logical_id) >= 5:
+        nodeA, nodeB, dummy, minorA, minorB = disk.logical_id[:5]
         for node, port in ((nodeA, minorA), (nodeB, minorB)):
           assert node in used, "Instance node not found in node list"
           if port in used[node]:
diff --git a/lib/objects.py b/lib/objects.py
index 23ecfc87d..3af15eb50 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, pminor, sminor = self.logical_id
+      pnode, snode, port, pminor, sminor, secret = self.logical_id
       if target_node not in (pnode, snode):
         raise errors.ConfigurationError("DRBD device not knowing node %s" %
                                         target_node)
@@ -424,9 +424,9 @@ class Disk(ConfigObject):
       p_data = (pnode_ip, port)
       s_data = (snode_ip, port)
       if pnode == target_node:
-        self.physical_id = p_data + s_data + (pminor,)
+        self.physical_id = p_data + s_data + (pminor, secret)
       else: # it must be secondary, we tested above
-        self.physical_id = s_data + p_data + (sminor,)
+        self.physical_id = s_data + p_data + (sminor, secret)
     else:
       self.physical_id = self.logical_id
     return
@@ -458,9 +458,10 @@ 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)
+    if obj.dev_type in constants.LDS_DRBD:
+      # we need a tuple of length six here
+      if len(obj.logical_id) < 6:
+        obj.logical_id += (None,) * (6 - len(obj.logical_id))
     return obj
 
   def __str__(self):
-- 
GitLab