From e7323b5e55c623198ecfdb74acaf77a7f0d1ff11 Mon Sep 17 00:00:00 2001
From: Manuel Franceschini <livewire@google.com>
Date: Mon, 2 Aug 2010 19:26:07 +0200
Subject: [PATCH] Support IPv6 cluster init

Signed-off-by: Manuel Franceschini <livewire@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/backend.py      | 23 ++++++++++++++++++-----
 lib/cli.py          |  8 ++++++++
 lib/cmdlib.py       |  9 ++++++++-
 lib/daemon.py       | 13 ++++++++++++-
 scripts/gnt-cluster | 11 +++++++++--
 5 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/lib/backend.py b/lib/backend.py
index b8725912e..a4105dbba 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -287,7 +287,12 @@ def StartMaster(start_daemons, no_voting):
         logging.error(msg)
         err_msgs.append(msg)
     else:
-      result = utils.RunCmd(["ip", "address", "add", "%s/32" % master_ip,
+      netmask = 32
+      if netutils.IP6Address.IsValid(master_ip):
+        netmask = 128
+
+      result = utils.RunCmd(["ip", "address", "add",
+                             "%s/%d" % (master_ip, netmask),
                              "dev", master_netdev, "label",
                              "%s:0" % master_netdev])
       if result.failed:
@@ -295,9 +300,12 @@ def StartMaster(start_daemons, no_voting):
         logging.error(msg)
         err_msgs.append(msg)
 
-      result = utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev,
-                             "-s", master_ip, master_ip])
-      # we'll ignore the exit code of arping
+      # we ignore the exit code of the following cmds
+      if netutils.IP4Address.IsValid(master_ip):
+        utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev, "-s",
+                      master_ip, master_ip])
+      elif netutils.IP6Address.IsValid(master_ip):
+        utils.RunCmd(["ndisc6", "-q", "-r 3", master_ip, master_netdev])
 
   if err_msgs:
     _Fail("; ".join(err_msgs))
@@ -322,7 +330,12 @@ def StopMaster(stop_daemons):
   # GetMasterInfo will raise an exception if not able to return data
   master_netdev, master_ip, _ = GetMasterInfo()
 
-  result = utils.RunCmd(["ip", "address", "del", "%s/32" % master_ip,
+  netmask = 32
+  if netutils.IP6Address.IsValid(master_ip):
+    netmask = 128
+
+  result = utils.RunCmd(["ip", "address", "del",
+                         "%s/%d" % (master_ip, netmask),
                          "dev", master_netdev])
   if result.failed:
     logging.error("Can't remove the master IP, error: %s", result.output)
diff --git a/lib/cli.py b/lib/cli.py
index 9d865555f..a314ce445 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -119,6 +119,7 @@ __all__ = [
   "OSPARAMS_OPT",
   "OS_OPT",
   "OS_SIZE_OPT",
+  "PRIMARY_IP_VERSION_OPT",
   "RAPI_CERT_OPT",
   "READD_OPT",
   "REBOOT_TYPE_OPT",
@@ -1021,6 +1022,13 @@ NODRBD_STORAGE_OPT = cli_option("--no-drbd-storage", dest="drbd_storage",
                                 action="store_false", default=True,
                                 help="Disable support for DRBD")
 
+PRIMARY_IP_VERSION_OPT = \
+    cli_option("--primary-ip-version", default=constants.IP4_VERSION,
+               action="store", dest="primary_ip_version",
+               metavar="%d|%d" % (constants.IP4_VERSION,
+                                  constants.IP6_VERSION),
+               help="Cluster-wide IP version for primary IP")
+
 
 def _ParseArgs(argv, commands, aliases):
   """Parser for the command line arguments.
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index c092cceb1..6870f172f 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -2527,7 +2527,8 @@ class LURenameCluster(LogicalUnit):
     """Verify that the passed name is a valid one.
 
     """
-    hostname = netutils.GetHostname(name=self.op.name)
+    hostname = netutils.GetHostname(name=self.op.name,
+                                    family=self.cfg.GetPrimaryIPFamily())
 
     new_name = hostname.name
     self.ip = new_ip = hostname.ip
@@ -4117,6 +4118,11 @@ class LUQueryClusterInfo(NoHooksLU):
         if hv_name in cluster.enabled_hypervisors:
           os_hvp[os_name][hv_name] = hv_params
 
+    # Convert ip_family to ip_version
+    primary_ip_version = constants.IP4_VERSION
+    if cluster.primary_ip_family == netutils.IP6Address.family:
+      primary_ip_version = constants.IP6_VERSION
+
     result = {
       "software_version": constants.RELEASE_VERSION,
       "protocol_version": constants.PROTOCOL_VERSION,
@@ -4147,6 +4153,7 @@ class LUQueryClusterInfo(NoHooksLU):
       "uid_pool": cluster.uid_pool,
       "default_iallocator": cluster.default_iallocator,
       "reserved_lvs": cluster.reserved_lvs,
+      "primary_ip_version": primary_ip_version,
       }
 
     return result
diff --git a/lib/daemon.py b/lib/daemon.py
index 86e6c02da..5346e47da 100644
--- a/lib/daemon.py
+++ b/lib/daemon.py
@@ -40,6 +40,7 @@ from ganeti import utils
 from ganeti import constants
 from ganeti import errors
 from ganeti import netutils
+from ganeti import ssconf
 
 
 _DEFAULT_RUN_USER = "root"
@@ -542,6 +543,16 @@ def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn,
 
   if daemon_name in constants.DAEMONS_PORTS:
     default_bind_address = constants.IP4_ADDRESS_ANY
+    try:
+      family = ssconf.SimpleStore().GetPrimaryIPFamily()
+      if family == netutils.IP6Address.family:
+        default_bind_address = constants.IP6_ADDRESS_ANY
+    except errors.ConfigurationError:
+      # This case occurs when adding a node, as there is no ssconf available
+      # when noded is first started. In that case, however, the correct
+      # bind_address must be passed
+      pass
+
     default_port = netutils.GetDaemonPort(daemon_name)
 
     # For networked daemons we allow choosing the port and bind address
@@ -549,7 +560,7 @@ def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn,
                             help="Network port (default: %s)" % default_port,
                             default=default_port, type="int")
     optionparser.add_option("-b", "--bind", dest="bind_address",
-                            help=("Bind address (default: %s)" %
+                            help=("Bind address (default: '%s')" %
                                   default_bind_address),
                             default=default_bind_address, metavar="ADDRESS")
 
diff --git a/scripts/gnt-cluster b/scripts/gnt-cluster
index 2da37fdcd..ab505b8ec 100755
--- a/scripts/gnt-cluster
+++ b/scripts/gnt-cluster
@@ -105,6 +105,12 @@ def InitCluster(opts, args):
   if uid_pool is not None:
     uid_pool = uidpool.ParseUidPool(uid_pool)
 
+  try:
+    primary_ip_version = int(opts.primary_ip_version)
+  except (ValueError, TypeError), err:
+    ToStderr("Invalid primary ip version value: %s" % str(err))
+    return 1
+
   bootstrap.InitCluster(cluster_name=args[0],
                         secondary_ip=opts.secondary_ip,
                         vg_name=vg_name,
@@ -122,7 +128,7 @@ def InitCluster(opts, args):
                         drbd_helper=drbd_helper,
                         uid_pool=uid_pool,
                         default_iallocator=opts.default_iallocator,
-                        primary_ip_version=constants.IP4_VERSION,
+                        primary_ip_version=primary_ip_version,
                         )
   op = opcodes.OpPostInitCluster()
   SubmitOpCode(op, opts=opts)
@@ -318,6 +324,7 @@ def ShowClusterConfig(opts, args):
             uidpool.FormatUidPool(result["uid_pool"],
                                   roman=opts.roman_integers))
   ToStdout("  - default instance allocator: %s", result["default_iallocator"])
+  ToStdout("  - primary ip version: %d", result["primary_ip_version"])
 
   ToStdout("Default instance parameters:")
   _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
@@ -849,7 +856,7 @@ commands = {
      NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
      SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
      UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
-     DEFAULT_IALLOCATOR_OPT],
+     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT],
     "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
   'destroy': (
     DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
-- 
GitLab