From 702eff2126607843e9993b6be1d19b174344844f Mon Sep 17 00:00:00 2001
From: Andrea Spadaccini <spadaccio@google.com>
Date: Tue, 25 Oct 2011 10:54:10 +0100
Subject: [PATCH] Use master IP address setup script in backend

Replace the code in backend.ActivateMasterIp and
backend.DeactivateMasterIp with the master IP address setup script,
either the default one or the one provided by the user.

- Convert to string the netmask parameter in _BuildMasterIpEnv
- Add the _RunMasterSetupScript function and let ActivateMasterIp and
  DeactivateMasterIp become wrappers for it;
- Change the failure model of DeactivateMasterIp, raising errors if the
  script fails instead of silently ignoring the failure

Signed-off-by: Andrea Spadaccini <spadaccio@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/backend.py | 86 +++++++++++++++++++++++---------------------------
 1 file changed, 40 insertions(+), 46 deletions(-)

diff --git a/lib/backend.py b/lib/backend.py
index ed60340c0..e9539a4d2 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -81,6 +81,10 @@ _IES_CA_FILE = "ca"
 #: Valid LVS output line regex
 _LVSLINE_REGEX = re.compile("^ *([^|]+)\|([^|]+)\|([0-9.]+)\|([^|]{6})\|?$")
 
+# Actions for the master setup script
+_MASTER_START = "start"
+_MASTER_STOP = "stop"
+
 
 class RPCFail(Exception):
   """Class denoting RPC failure.
@@ -303,60 +307,57 @@ def _BuildMasterIpEnv(master_params, use_external_mip_script=None):
   env = {
     "MASTER_NETDEV": master_params.netdev,
     "MASTER_IP": master_params.ip,
-    "MASTER_NETMASK": master_params.netmask,
+    "MASTER_NETMASK": str(master_params.netmask),
     "CLUSTER_IP_VERSION": str(ver),
   }
 
   return env
 
 
-@RunLocalHooks(constants.FAKE_OP_MASTER_TURNUP, "master-ip-turnup",
-               _BuildMasterIpEnv)
-def ActivateMasterIp(master_params, use_external_mip_script):
-  """Activate the IP address of the master daemon.
+def _RunMasterSetupScript(master_params, action, use_external_mip_script):
+  """Execute the master IP address setup script.
 
   @type master_params: L{objects.MasterNetworkParameters}
   @param master_params: network parameters of the master
+  @type action: string
+  @param action: action to pass to the script. Must be one of
+    L{backend._MASTER_START} or L{backend._MASTER_STOP}
   @type use_external_mip_script: boolean
   @param use_external_mip_script: whether to use an external master IP
     address setup script
+  @raise backend.RPCFail: if there are errors during the execution of the
+    script
 
   """
-  # pylint: disable=W0613
-  err_msg = None
-  if netutils.TcpPing(master_params.ip, constants.DEFAULT_NODED_PORT):
-    if netutils.IPAddress.Own(master_params.ip):
-      # we already have the ip:
-      logging.debug("Master IP already configured, doing nothing")
-    else:
-      err_msg = "Someone else has the master ip, not activating"
-      logging.error(err_msg)
+  env = _BuildMasterIpEnv(master_params)
+
+  if use_external_mip_script:
+    setup_script = constants.EXTERNAL_MASTER_SETUP_SCRIPT
   else:
-    ipcls = netutils.IPAddress.GetClassFromIpFamily(master_params.ip_family)
+    setup_script = constants.DEFAULT_MASTER_SETUP_SCRIPT
 
-    result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
-                           "%s/%s" % (master_params.ip, master_params.netmask),
-                           "dev", master_params.netdev, "label",
-                           "%s:0" % master_params.netdev])
-    if result.failed:
-      err_msg = "Can't activate master IP: %s" % result.output
-      logging.error(err_msg)
+  result = utils.RunCmd([setup_script, action], env=env, reset_env=True)
 
-    else:
-      # we ignore the exit code of the following cmds
-      if ipcls == netutils.IP4Address:
-        utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_params.netdev,
-                      "-s", master_params.ip, master_params.ip])
-      elif ipcls == netutils.IP6Address:
-        try:
-          utils.RunCmd(["ndisc6", "-q", "-r 3", master_params.ip,
-                        master_params.netdev])
-        except errors.OpExecError:
-          # TODO: Better error reporting
-          logging.warning("Can't execute ndisc6, please install if missing")
+  if result.failed:
+    _Fail("Failed to %s the master IP. Script return value: %s" %
+          (action, result.exit_code), log=True)
+
+
+@RunLocalHooks(constants.FAKE_OP_MASTER_TURNUP, "master-ip-turnup",
+               _BuildMasterIpEnv)
+def ActivateMasterIp(master_params, use_external_mip_script):
+  """Activate the IP address of the master daemon.
 
-  if err_msg:
-    _Fail(err_msg)
+  @type master_params: L{objects.MasterNetworkParameters}
+  @param master_params: network parameters of the master
+  @type use_external_mip_script: boolean
+  @param use_external_mip_script: whether to use an external master IP
+    address setup script
+  @raise RPCFail: in case of errors during the IP startup
+
+  """
+  _RunMasterSetupScript(master_params, _MASTER_START,
+                        use_external_mip_script)
 
 
 def StartMasterDaemons(no_voting):
@@ -397,18 +398,11 @@ def DeactivateMasterIp(master_params, use_external_mip_script):
   @type use_external_mip_script: boolean
   @param use_external_mip_script: whether to use an external master IP
     address setup script
+  @raise RPCFail: in case of errors during the IP turndown
 
   """
-  # pylint: disable=W0613
-  # TODO: log and report back to the caller the error failures; we
-  # need to decide in which case we fail the RPC for this
-
-  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
-                         "%s/%s" % (master_params.ip, master_params.netmask),
-                         "dev", master_params.netdev])
-  if result.failed:
-    logging.error("Can't remove the master IP, error: %s", result.output)
-    # but otherwise ignore the failure
+  _RunMasterSetupScript(master_params, _MASTER_STOP,
+                        use_external_mip_script)
 
 
 def StopMasterDaemons():
-- 
GitLab