Add checks for tcp/udp port collisions
authorIustin Pop <iustin@google.com>
Sat, 27 Sep 2008 18:47:46 +0000 (18:47 +0000)
committerIustin Pop <iustin@google.com>
Sat, 27 Sep 2008 18:47:46 +0000 (18:47 +0000)
In case the config file is manually modified, or in case of bugs, the
tcp/udp ports could be reused, which will create various problems
(instances not able to start, or drbd disks not able to communicate).

This patch extends the ConfigWriter.VerifyConfig() method (which is used
in cluster verify) to check for duplicates between:
  - the ports used for DRBD disks
  - the ports used for network console
  - the ports marked as free in the config file

Also, if the cluster parameter â€˜highest_used_port’ is actually lower
than the computed highest used port, this is also flagged as an error.

The output from gnt-cluster verify will show (output manually wrapped):

node1 # gnt-cluster verify
* Verifying global settings
  - ERROR: tcp/udp port 11006 has duplicates: instance3.example.com/network port,
instance2.example.com/drbd disk sda
  - ERROR: tcp/udp port 11017 has duplicates: instance3.example.com/drbd disk sda,
instance3.example.com/drbd disk sdb, cluster/port marked as free
  - ERROR: Highest used port mismatch, saved 11010, computed 11017
* Gathering data (2 nodes)
...

Reviewed-by: ultrotter

lib/config.py

index 48f8fff..0cca001 100644 (file)
@@ -177,6 +177,7 @@ class ConfigWriter:
 
     result = []
     seen_macs = []
+    ports = {}
     data = self._config_data
     for instance_name in data.instances:
       instance = data.instances[instance_name]
@@ -193,6 +194,43 @@ class ConfigWriter:
                         (instance_name, idx, nic.mac))
         else:
           seen_macs.append(nic.mac)
+
+      # gather the drbd ports for duplicate checks
+      for dsk in instance.disks:
+        if dsk.dev_type in constants.LDS_DRBD:
+          tcp_port = dsk.logical_id[2]
+          if tcp_port not in ports:
+            ports[tcp_port] = []
+          ports[tcp_port].append((instance.name, "drbd disk %s" % dsk.iv_name))
+      # gather network port reservation
+      net_port = getattr(instance, "network_port", None)
+      if net_port is not None:
+        if net_port not in ports:
+          ports[net_port] = []
+        ports[net_port].append((instance.name, "network port"))
+
+    # cluster-wide pool of free ports
+    for free_port in self._config_data.cluster.tcpudp_port_pool:
+      if free_port not in ports:
+        ports[free_port] = []
+      ports[free_port].append(("cluster", "port marked as free"))
+
+    # compute tcp/udp duplicate ports
+    keys = ports.keys()
+    keys.sort()
+    for pnum in keys:
+      pdata = ports[pnum]
+      if len(pdata) > 1:
+        txt = ", ".join(["%s/%s" % val for val in pdata])
+        result.append("tcp/udp port %s has duplicates: %s" % (pnum, txt))
+
+    # highest used tcp port check
+    if keys:
+      if keys[-1] > self._config_data.cluster.highest_used_port:
+        result.append("Highest used port mismatch, saved %s, computed %s" %
+                      (self._config_data.cluster.highest_used_port,
+                       keys[-1]))
+
     return result
 
   def SetDiskID(self, disk, node_name):