BUG 2302 : odl-clustering-test-app should not be part of the odl-restconf-all feature set
[controller.git] / opendaylight / clustering / services_implementation / src / main / java / org / opendaylight / controller / clustering / services_implementation / internal / ClusterManager.java
index 65e7720dd3141734951cb7d51e2b69bf8619df7b..e34eb329330d2e1b30ee72aac6950f2084894777 100644 (file)
@@ -13,6 +13,8 @@ import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.net.UnknownHostException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.Enumeration;
@@ -69,7 +71,7 @@ public class ClusterManager implements IClusterServices {
     private ViewChangedListener cacheManagerListener;
 
     private static String loopbackAddress = InetAddress.getLoopbackAddress().getHostAddress();
-
+    private static final int gossipRouterPortDefault = 12001;
     // defaultTransactionTimeout is 60 seconds
     private static int DEFAULT_TRANSACTION_TIMEOUT = 60;
 
@@ -91,14 +93,24 @@ public class ClusterManager implements IClusterServices {
      */
     private GossipRouter startGossiper() {
         boolean amIGossipRouter = false;
-        Integer gossipRouterPortDefault = 12001;
         Integer gossipRouterPort = gossipRouterPortDefault;
         InetAddress gossipRouterAddress = null;
         String supernodes_list = System.getProperty("supernodes",
                 loopbackAddress);
+        /*
+         * Check the environment for the "container" variable, if this is set
+         * and is equal to "lxc", then ODL is running inside an lxc
+         * container, and address resolution of supernodes will be modified
+         * accordingly.
+         */
+        boolean inContainer = "lxc".equals(System.getenv("container"));
         StringBuffer sanitized_supernodes_list = new StringBuffer();
         List<InetAddress> myAddresses = new ArrayList<InetAddress>();
 
+        if (inContainer) {
+            logger.trace("DOCKER: Resolving supernode host names using docker container semantics");
+        }
+
         StringTokenizer supernodes = new StringTokenizer(supernodes_list, ":");
         if (supernodes.hasMoreTokens()) {
             // Populate the list of my addresses
@@ -132,10 +144,38 @@ public class ClusterManager implements IClusterServices {
             }
             host = host_port.nextToken();
             InetAddress hostAddr;
+            /*
+             * If we are in a container and the hostname begins with a '+', this is
+             * an indication that we should resolve this host name in the context
+             * of a docker container.
+             *
+             * Specifically this means:
+             * '+self'   : self reference and the host will be mapped to the value of
+             *             HOSTNAME in the environment
+             * '+<name>' : references another container by its name. The docker established
+             *             environment variables will be used to resolve the host to an
+             *             IP address.
+             */
+            if (inContainer && host != null && host.charAt(0) == '+') {
+                if ("+self".equals(host)) {
+                    host = System.getenv("HOSTNAME");
+                } else {
+                    String link = System.getenv(host.substring(1).toUpperCase() + "_PORT");
+                    if (link != null) {
+                        try {
+                            host = new URI(link).getHost();
+                        } catch (URISyntaxException e) {
+                            logger.error("DOCKER: Unable to translate container reference ({}) to host IP Address, will attempt using normal host name",
+                                host.substring(1));
+                        }
+                    }
+                }
+            }
+
             try {
                 hostAddr = InetAddress.getByName(host);
             } catch (UnknownHostException ue) {
-                logger.error("Host not known");
+                logger.error("Host {} is not known", host);
                 continue;
             }
             if (host_port.hasMoreTokens()) {
@@ -143,13 +183,12 @@ public class ClusterManager implements IClusterServices {
                 try {
                     port_num = Integer.valueOf(port);
                 } catch (NumberFormatException ne) {
-                    logger
-                            .error("Supplied supernode gossiepr port is not recognized, using standard gossipport");
+                    logger.error("Supplied supernode gossip port is not recognized, using default gossip port {}",
+                                 gossipRouterPortDefault);
                     port_num = gossipRouterPortDefault;
                 }
                 if ((port_num > 65535) || (port_num < 0)) {
-                    logger
-                            .error("Supplied supernode gossip port is outside a valid TCP port range");
+                    logger.error("Supplied supernode gossip port is outside a valid TCP port range");
                     port_num = gossipRouterPortDefault;
                 }
             }
@@ -168,8 +207,7 @@ public class ClusterManager implements IClusterServices {
             if (!sanitized_supernodes_list.toString().equals("")) {
                 sanitized_supernodes_list.append(",");
             }
-            sanitized_supernodes_list.append(hostAddr.getHostAddress() + "["
-                    + port_num + "]");
+            sanitized_supernodes_list.append(hostAddr.getHostAddress()).append("[").append(port_num).append("]");
         }
 
         if (amIGossipRouter) {