Add checks for master IP in cluster verify
authorIustin Pop <iustin@google.com>
Mon, 17 May 2010 09:54:34 +0000 (11:54 +0200)
committerIustin Pop <iustin@google.com>
Mon, 17 May 2010 10:33:34 +0000 (12:33 +0200)
This also updates a comment in the unittest for utils.py. We unittest
the new function for two things: correct reporting on real case (for
localhost), and correct reporting with a mocked-out TcpPing that returns
false.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>

Makefile.am
lib/backend.py
lib/cmdlib.py
lib/constants.py
test/ganeti.backend_unittest.py [new file with mode: 0644]
test/ganeti.utils_unittest.py

index 6ffbd78..88c399c 100644 (file)
@@ -320,6 +320,7 @@ TEST_FILES = \
        test/data/proc_drbd83.txt
 
 python_tests = \
+       test/ganeti.backend_unittest.py \
        test/ganeti.bdev_unittest.py \
        test/ganeti.cli_unittest.py \
        test/ganeti.cmdlib_unittest.py \
index 18cf4c4..f1474b7 100644 (file)
@@ -476,6 +476,8 @@ def VerifyNode(what, cluster_name):
 
   """
   result = {}
+  my_name = utils.HostInfo().name
+  port = utils.GetDaemonPort(constants.NODED)
 
   if constants.NV_HYPERVISOR in what:
     result[constants.NV_HYPERVISOR] = tmp = {}
@@ -500,7 +502,6 @@ def VerifyNode(what, cluster_name):
 
   if constants.NV_NODENETTEST in what:
     result[constants.NV_NODENETTEST] = tmp = {}
-    my_name = utils.HostInfo().name
     my_pip = my_sip = None
     for name, pip, sip in what[constants.NV_NODENETTEST]:
       if name == my_name:
@@ -511,7 +512,6 @@ def VerifyNode(what, cluster_name):
       tmp[my_name] = ("Can't find my own primary/secondary IP"
                       " in the node list")
     else:
-      port = utils.GetDaemonPort(constants.NODED)
       for name, pip, sip in what[constants.NV_NODENETTEST]:
         fail = []
         if not utils.TcpPing(pip, port, source=my_pip):
@@ -523,6 +523,17 @@ def VerifyNode(what, cluster_name):
           tmp[name] = ("failure using the %s interface(s)" %
                        " and ".join(fail))
 
+  if constants.NV_MASTERIP in what:
+    # FIXME: add checks on incoming data structures (here and in the
+    # rest of the function)
+    master_name, master_ip = what[constants.NV_MASTERIP]
+    if master_name == my_name:
+      source = constants.LOCALHOST_IP_ADDRESS
+    else:
+      source = None
+    result[constants.NV_MASTERIP] = utils.TcpPing(master_ip, port,
+                                                  source=source)
+
   if constants.NV_LVLIST in what:
     try:
       val = GetVolumeList(what[constants.NV_LVLIST])
index 1647353..8753983 100644 (file)
@@ -1370,6 +1370,18 @@ class LUVerifyCluster(LogicalUnit):
                    "tcp communication with node '%s': %s",
                    anode, nresult[constants.NV_NODENETTEST][anode])
 
+    test = constants.NV_MASTERIP not in nresult
+    _ErrorIf(test, self.ENODENET, node,
+             "node hasn't returned node master IP reachability data")
+    if not test:
+      if not nresult[constants.NV_MASTERIP]:
+        if node == self.master_node:
+          msg = "the master node cannot reach the master IP (not configured?)"
+        else:
+          msg = "cannot reach the master IP"
+        _ErrorIf(True, self.ENODENET, node, msg)
+
+
   def _VerifyInstance(self, instance, instanceconfig, node_image):
     """Verify an instance.
 
@@ -1704,6 +1716,8 @@ class LUVerifyCluster(LogicalUnit):
     # FIXME: verify OS list
     # do local checksums
     master_files = [constants.CLUSTER_CONF_FILE]
+    master_node = self.master_node = self.cfg.GetMasterNode()
+    master_ip = self.cfg.GetMasterIP()
 
     file_names = ssconf.SimpleStore().GetFileList()
     file_names.extend(constants.ALL_CERT_FILES)
@@ -1727,6 +1741,7 @@ class LUVerifyCluster(LogicalUnit):
       constants.NV_HVINFO: self.cfg.GetHypervisorType(),
       constants.NV_NODESETUP: None,
       constants.NV_TIME: None,
+      constants.NV_MASTERIP: (master_node, master_ip),
       }
 
     if vg_name is not None:
@@ -1773,7 +1788,6 @@ class LUVerifyCluster(LogicalUnit):
                                            self.cfg.GetClusterName())
     nvinfo_endtime = time.time()
 
-    master_node = self.cfg.GetMasterNode()
     all_drbd_map = self.cfg.ComputeDRBDMap()
 
     feedback_fn("* Verifying node status")
index e5c9f97..aa84c86 100644 (file)
@@ -599,6 +599,7 @@ NV_PVLIST = "pvlist"
 NV_DRBDLIST = "drbd-list"
 NV_NODESETUP = "nodesetup"
 NV_TIME = "time"
+NV_MASTERIP = "master-ip"
 
 # SSL certificate check constants (in days)
 SSL_CERT_EXPIRATION_WARN = 30
diff --git a/test/ganeti.backend_unittest.py b/test/ganeti.backend_unittest.py
new file mode 100644 (file)
index 0000000..2c94a75
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/python
+#
+
+# Copyright (C) 2010 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 0.0510-1301, USA.
+
+
+"""Script for unittesting the backend module"""
+
+
+import os
+import unittest
+import time
+import tempfile
+import shutil
+
+from ganeti import backend
+from ganeti import constants
+from ganeti import utils
+
+import testutils
+
+
+class TestNodeVerify(testutils.GanetiTestCase):
+  def testMasterIPLocalhost(self):
+    # this a real functional test, but requires localhost to be reachable
+    local_data = (utils.HostInfo().name, constants.LOCALHOST_IP_ADDRESS)
+    result = backend.VerifyNode({constants.NV_MASTERIP: local_data}, None)
+    self.failUnless(constants.NV_MASTERIP in result,
+                    "Master IP data not returned")
+    self.failUnless(result[constants.NV_MASTERIP], "Cannot reach localhost")
+
+  def testMasterIPUnreachable(self):
+    # Network 192.0.2.0/24 is reserved for test/documentation as per
+    # RFC 5735
+    bad_data =  ("master.example.com", "192.0.2.1")
+    # we just test that whatever TcpPing returns, VerifyNode returns too
+    utils.TcpPing = lambda a, b, source=None: False
+    result = backend.VerifyNode({constants.NV_MASTERIP: bad_data}, None)
+    self.failUnless(constants.NV_MASTERIP in result,
+                    "Master IP data not returned")
+    self.failIf(result[constants.NV_MASTERIP],
+                "Result from utils.TcpPing corrupted")
+
+
+if __name__ == "__main__":
+  testutils.GanetiTestProgram()
index b8c00de..863fc79 100755 (executable)
@@ -1007,8 +1007,8 @@ class TestOwnIpAddress(unittest.TestCase):
   def testNowOwnAddress(self):
     """check that I don't own an address"""
 
-    # network 192.0.2.0/24 is reserved for test/documentation as per
-    # rfc 3330, so we *should* not have an address of this range... if
+    # Network 192.0.2.0/24 is reserved for test/documentation as per
+    # RFC 5735, so we *should* not have an address of this range... if
     # this fails, we should extend the test to multiple addresses
     DST_IP = "192.0.2.1"
     self.failIf(OwnIpAddress(DST_IP), "Should not own IP address %s" % DST_IP)