From 79829d237326e31c9b768c558acd6443c74ae318 Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Sat, 16 Jun 2012 09:07:00 +0100
Subject: [PATCH] Allow single-homed <-> multi-homed transitions

To change the cluster from single homed to multi homed or vice versa one
must target the master node first, and pass the --force option. All
other nodes then will work as long as they are reachable by the master.

Note that this will also prevent a node to be set to single-homed if the
master is multi-homed, which wasn't disallowed before, and warn if a
single-homed <-> multi-homed transition happens.

Also note that it's still theoretically possible to flip a cluster
inadvertently by changing the master node this way, and then doing a
master failover before fixing the other nodes.

Signed-off-by: Guido Trotter <ultrotter@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 doc/admin.rst    | 31 +++++++++++++++++++++++++++++++
 lib/cmdlib.py    | 26 +++++++++++++++++++++++---
 man/gnt-node.rst |  7 ++++++-
 3 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/doc/admin.rst b/doc/admin.rst
index 8850187e0..80028e6ec 100644
--- a/doc/admin.rst
+++ b/doc/admin.rst
@@ -912,6 +912,37 @@ it's easy to remove it from the cluster::
 This will deconfigure the node, stop the ganeti daemons on it and leave
 it hopefully like before it joined to the cluster.
 
+Replication network changes
++++++++++++++++++++++++++++
+
+The :command:`gnt-node modify -s` command can be used to change the
+secondary IP of a node. This operation can only be performed if:
+
+- No instance is active on the target node
+- The new target IP is reachable from the master's secondary IP
+
+Also this operation will not allow to change a node from single-homed
+(same primary and secondary ip) to multi-homed (separate replication
+network) or vice versa, unless:
+
+- The target node is the master node and `--force` is passed.
+- The target cluster is single-homed and the new primary ip is a change
+  to single homed for a particular node.
+- The target cluster is multi-homed and the new primary ip is a change
+  to multi homed for a particular node.
+
+For example to do a single-homed to multi-homed conversion::
+
+  $ gnt-node modify --force -s %SECONDARY_IP% %MASTER_NAME%
+  $ gnt-node modify -s %SECONDARY_IP% %NODE1_NAME%
+  $ gnt-node modify -s %SECONDARY_IP% %NODE2_NAME%
+  $ gnt-node modify -s %SECONDARY_IP% %NODE3_NAME%
+  ...
+
+The same commands can be used for multi-homed to single-homed except the
+secondary IPs should be the same as the primaries for each node, for
+that case.
+
 Storage handling
 ++++++++++++++++
 
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index ba6661c38..3a22ef53a 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -5996,13 +5996,33 @@ class LUNodeSetParams(LogicalUnit):
                         " without using re-add. Please make sure the node"
                         " is healthy!")
 
+    # When changing the secondary ip, verify if this is a single-homed to
+    # multi-homed transition or vice versa, and apply the relevant
+    # restrictions.
     if self.op.secondary_ip:
       # Ok even without locking, because this can't be changed by any LU
       master = self.cfg.GetNodeInfo(self.cfg.GetMasterNode())
       master_singlehomed = master.secondary_ip == master.primary_ip
-      if master_singlehomed and self.op.secondary_ip:
-        raise errors.OpPrereqError("Cannot change the secondary ip on a single"
-                                   " homed cluster", errors.ECODE_INVAL)
+      if master_singlehomed and self.op.secondary_ip != node.primary_ip:
+        if self.op.force and node.name == master.name:
+          self.LogWarning("Transitioning from single-homed to multi-homed"
+                          " cluster. All nodes will require a secondary ip.")
+        else:
+          raise errors.OpPrereqError("Changing the secondary ip on a"
+                                     " single-homed cluster requires the"
+                                     " --force option to be passed, and the"
+                                     " target node to be the master",
+                                     errors.ECODE_INVAL)
+      elif not master_singlehomed and self.op.secondary_ip == node.primary_ip:
+        if self.op.force and node.name == master.name:
+          self.LogWarning("Transitioning from multi-homed to single-homed"
+                          " cluster. Secondary IPs will have to be removed.")
+        else:
+          raise errors.OpPrereqError("Cannot set the secondary IP to be the"
+                                     " same as the primary IP on a multi-homed"
+                                     " cluster, unless the --force option is"
+                                     " passed, and the target node is the"
+                                     " master", errors.ECODE_INVAL)
 
       assert not (frozenset(affected_instances) -
                   self.owned_locks(locking.LEVEL_INSTANCE))
diff --git a/man/gnt-node.rst b/man/gnt-node.rst
index 35683c8cd..5dabe5c69 100644
--- a/man/gnt-node.rst
+++ b/man/gnt-node.rst
@@ -313,7 +313,12 @@ candidate role if is in that role)::
 
 The ``-s (--secondary-ip)`` option can be used to change the node's
 secondary ip. No drbd instances can be running on the node, while this
-operation is taking place.
+operation is taking place. Remember that the secondary ip must be
+reachable from the master secondary ip, when being changed, so be sure
+that the node has the new IP already configured and active. In order to
+convert a cluster from single homed to multi-homed or vice versa
+``--force`` is needed as well, and the target node for the first change
+must be the master.
 
 See **ganeti(7)** for a description of ``--submit`` and other common
 options.
-- 
GitLab