System property awareness in DockerOvs 61/39461/5
authorJosh <jhershbe@redhat.com>
Thu, 26 May 2016 09:14:30 +0000 (11:14 +0200)
committerAnil Vishnoi <vishnoianil@gmail.com>
Sun, 29 May 2016 20:25:32 +0000 (20:25 +0000)
Change-Id: If039cd49c18f9ba55181918c66fce1eaf973df82
Signed-off-by: Josh <jhershbe@redhat.com>
utils/ovsdb-it-utils/pom.xml
utils/ovsdb-it-utils/src/main/java/org/opendaylight/ovsdb/utils/ovsdb/it/utils/DockerOvs.java
utils/ovsdb-it-utils/src/main/java/org/opendaylight/ovsdb/utils/ovsdb/it/utils/ItConstants.java
utils/ovsdb-it-utils/src/main/resources/docker-compose-files/two_dockers-ovs-2.5.1.yml [new file with mode: 0644]

index 161d87b9fabec9ef5e597f77de7f8d7b16b85215..e075889b4280151e0e67145113123b9b6e2f5e56 100644 (file)
@@ -68,6 +68,46 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
           <artifactId>yamlbeans</artifactId>
           <version>1.09</version>
       </dependency>
+
+
+    <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam-container-karaf</artifactId>
+        <scope>compile</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam-junit4</artifactId>
+        <scope>compile</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam</artifactId>
+        <scope>compile</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.ops4j.pax.url</groupId>
+        <artifactId>pax-url-aether</artifactId>
+        <scope>compile</scope>
+    </dependency>
+    <dependency>
+        <groupId>javax.inject</groupId>
+        <artifactId>javax.inject</artifactId>
+        <version>1</version>
+        <scope>compile</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.karaf.features</groupId>
+        <artifactId>org.apache.karaf.features.core</artifactId>
+        <version>${karaf.version}</version>
+        <scope>compile</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.osgi</groupId>
+        <artifactId>org.osgi.core</artifactId>
+        <scope>compile</scope>
+    </dependency>
+
   </dependencies>
 
     <!--
index 4cd3fa2513a33b56a970800db6b44cd49b4b28be..ad8e6841d74e537655fbcfd664df3b0ab11450ad 100644 (file)
@@ -27,16 +27,20 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.esotericsoftware.yamlbeans.YamlException;
 import com.esotericsoftware.yamlbeans.YamlReader;
 import org.junit.Assert;
+import org.ops4j.pax.exam.Option;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.FrameworkUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
+
 /**
  * Run OVS(s) using docker-compose for use in integration tests.
  * For example,
@@ -45,8 +49,8 @@ import org.slf4j.LoggerFactory;
  *      ConnectionInfo connectionInfo = SouthboundUtils.getConnectionInfo(
  *                               ovs.getOvsdbAddress(0), ovs.getOvsdbPort(0));
  *      ...
-        nodeInfo.disconnect();
-
*       nodeInfo.disconnect();
+ *
  * } catch (Exception e) {
  * ...
  * </pre>
@@ -59,13 +63,48 @@ import org.slf4j.LoggerFactory;
  * at the path META-INF/docker-compose-files/. Currently, a single yaml file is used,
  * "docker-ovs-2.5.1.yml." DockerOvs does support docker-compose files that
  * launch more than one docker image, more on this later. DockerOvs will wait for OVS
- * to accept OVSDB connections. In order for this to work, the docker-compose file *must*
- * have a port mapping.
- * Currently, DockerOvs does not support docker images with OVS instances that connect actively.
+ * to accept OVSDB connections.
+ * Any docker-compose file must have a port mapping.
+ *
+ * The following explains how system properties are used to configure DockerOvs
+ * <pre>
+ *  private static String ENV_USAGE =
+ *  "-Ddocker.run - explicitly configure whether or not DockerOvs should run docker-compose\n" +
+ *  "-Dovsdbserver.ipaddress - specify IP address of ovsdb server - implies -Ddocker.run=false\n" +
+ *  "-Dovsdbserver.port - specify the port of the ovsdb server - required with -Dovsdbserver.ipaddress\n" +
+ *  "-Ddocker.compose.file - docker compose file in META-INF/docker-compose-files/. If not specified, default file is used\n" +
+ *  "-Dovsdb.userspace.enabled - true when Ovs is running in user space (usually the case with docker)\n" +
+ *  "-Dovsdb.controller.address - IP address of the controller (usually the docker0 interface with docker)\n" +
+ *  "To auto-run Ovs and connect actively:\n" +
+ *  " -Dovsdb.controller.address=x.x.x.x -Dovsdb.userspace.enabled=yes [-Ddocker.compose.file=ffff]\n" +
+ *  "To auto-run Ovs and connect passively:\n" +
+ *  " -Dovsdbserver.connection=passive -Dovsdb.controller.address=x.x.x.x -Dovsdb.userspace.enabled=yes [-Ddocker.compose.file=ffff]\n" +
+ *  "To actively connect to a running Ovs:\n" +
+ *  " -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=6641 -Dovsdb.controller.address=y.y.y.y\n" +
+ *  "To passively connect to a running Ovs:\n" +
+ *  " -Dovsdbserver.connection=passive -Ddocker.run=false\n";
+ * </pre>
+ * When DockerOvs does not run docker-compose getOvsdbAddress and getOvsdbPort return the address and port specified in
+ * the system properties.
  */
 public class DockerOvs implements AutoCloseable {
+    private static String ENV_USAGE = "Usage:\n" +
+            "-Ddocker.run - explicitly configure whether or not DockerOvs should run docker-compose\n" +
+                    "-Dovsdbserver.ipaddress - specify IP address of ovsdb server - implies -Ddocker.run=false\n" +
+                    "-Dovsdbserver.port - specify the port of the ovsdb server - required with -Dovsdbserver.ipaddress\n" +
+                    "-Ddocker.compose.file - docker compose file in META-INF/docker-compose-files/. If not specified, default file is used\n" +
+                    "-Dovsdb.userspace.enabled - true when Ovs is running in user space (usually the case with docker)\n" +
+                    "-Dovsdb.controller.address - IP address of the controller (usually the docker0 interface with docker)\n" +
+                    "To auto-run Ovs and connect actively:\n" +
+                    " -Dovsdb.controller.address=x.x.x.x -Dovsdb.userspace.enabled=yes <-Ddocker.compose.file=ffff>\n" +
+                    "To auto-run Ovs and connect passively:\n" +
+                    " -Dovsdbserver.connection=passive -Dovsdb.controller.address=x.x.x.x -Dovsdb.userspace.enabled=yes <-Ddocker.compose.file=ffff>\n" +
+                    "To actively connect to a running Ovs:\n" +
+                    " -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=6641 -Dovsdb.controller.address=y.y.y.y\n" +
+                    "To passively connect to a running Ovs:\n" +
+                    " -Dovsdbserver.connection=passive -Ddocker.run=false\n";
+
     private static final Logger LOG = LoggerFactory.getLogger(DockerOvs.class);
-    public static final String DOCKER_SUDO = "docker.sudo";
     private static final String DEFAULT_DOCKER_FILE = "docker-ovs-2.5.1.yml";
     private static final String DOCKER_FILE_PATH = "META-INF/docker-compose-files/";
     //private static final String[] HELP_CMD = {"docker-compose", "--help"};
@@ -80,6 +119,27 @@ public class DockerOvs implements AutoCloseable {
     private File tmpDockerComposeFile;
     private List<String> ovsdbPorts;
     boolean isRunning;
+    private String envServerAddress;
+    private String envServerPort;
+    private String envDockerComposeFile;
+    private boolean runDocker;
+
+    /**
+     * Get the array of system properties as pax exam Option objects for use in pax exam
+     * unit tests with Configuration annotation.
+     * @return List of Option objects
+     */
+    public static Option[] getSysPropOptions() {
+        return new Option[] {
+                propagateSystemProperties(ItConstants.SERVER_IPADDRESS,
+                                            ItConstants.SERVER_PORT,
+                                            ItConstants.CONNECTION_TYPE,
+                                            ItConstants.CONTROLLER_IPADDRESS,
+                                            ItConstants.USERSPACE_ENABLED,
+                                            ItConstants.DOCKER_COMPOSE_FILE_NAME,
+                                            ItConstants.DOCKER_RUN)
+        };
+    }
 
     /**
      * Bring up all docker images in the default docker-compose file.
@@ -97,6 +157,13 @@ public class DockerOvs implements AutoCloseable {
      * @throws InterruptedException If this thread is interrupted
      */
     public DockerOvs(String yamlFileName) throws IOException, InterruptedException {
+        configureFromEnv();
+
+        if (!runDocker) {
+            LOG.info("DockerOvs.DockerOvs: Not running docker, -D{} specified", ItConstants.SERVER_IPADDRESS);
+            return;
+        }
+
         tmpDockerComposeFile = createTempDockerComposeFile(yamlFileName);
         buildDockerComposeCommands();
         ovsdbPorts = extractPortsFromYaml();
@@ -111,6 +178,42 @@ public class DockerOvs implements AutoCloseable {
         waitForOvsdbServers(10 * 1000);
     }
 
+    /**
+     * Pull required configuration from System.getProperties() and validate we have what we need.
+     * Note: Note that there is some minor complexity in how this class is configured using System
+     * properties. This stems from the fact that we want to preserve the meaning of these properties
+     * prior to the introduction of this class. See the ENV_USAGE variable for details.
+     */
+    private void configureFromEnv() {
+        Properties env = System.getProperties();
+        envServerAddress = env.getProperty(ItConstants.SERVER_IPADDRESS);
+        envServerPort = env.getProperty(ItConstants.SERVER_PORT);
+        String envRunDocker = env.getProperty(ItConstants.DOCKER_RUN);
+        String connType = env.getProperty(ItConstants.CONNECTION_TYPE, ItConstants.CONNECTION_TYPE_ACTIVE);
+        String dockerFile = env.getProperty(ItConstants.DOCKER_COMPOSE_FILE_NAME);
+        envDockerComposeFile = DOCKER_FILE_PATH + (null == dockerFile ? DEFAULT_DOCKER_FILE : dockerFile);
+
+        //Are we running docker? If we specified docker.run, that's the answer. Otherwise, if there is a server
+        //address we assume docker is already running
+        runDocker = (envRunDocker != null) ? Boolean.parseBoolean(envRunDocker) : envServerAddress == null;
+
+        if(runDocker) {
+            return;
+        }
+
+        if (connType.equals(ItConstants.CONNECTION_TYPE_PASSIVE)) {
+            return;
+        }
+
+        //At this point we know we're not running docker and the conn type is active - make sure we have what we need
+        //If we have a server address than we require a port too as those
+        //are returned in getOvsdbPort() and getOvsdbAddress()
+        Assert.assertNotNull("Attempt to connect to previous running ovs but missing -Dovsdbserver.ipaddress\n"
+                                                                                    + ENV_USAGE, envServerAddress);
+        Assert.assertNotNull("Attempt to connect to previous running ovs but missing -Dovsdbserver.port\n"
+                + ENV_USAGE, envServerPort);
+    }
+
     /**
      * Verify and build the docker-compose commands we will be running. This function adds the docker-compose file
      * to the command lines and also checks (and adjusts the command line) as to whether sudo is required. This is
@@ -141,6 +244,9 @@ public class DockerOvs implements AutoCloseable {
      * @return IP string
      */
     public String getOvsdbAddress(int ovsNumber) {
+        if (!runDocker) {
+            return envServerAddress;
+        }
         return DEFAULT_OVSDB_HOST;
     }
 
@@ -150,6 +256,9 @@ public class DockerOvs implements AutoCloseable {
      * @return Port as a string
      */
     public String getOvsdbPort(int ovsNumber) {
+        if (!runDocker) {
+            return envServerPort;
+        }
         return ovsdbPorts.get(ovsNumber);
     }
 
@@ -468,7 +577,7 @@ public class DockerOvs implements AutoCloseable {
     private File createTempDockerComposeFile(String yamlFileName) {
         Bundle bundle = FrameworkUtil.getBundle(this.getClass());
         Assert.assertNotNull("DockerOvs: bundle is null", bundle);
-        URL url = bundle.getResource(DOCKER_FILE_PATH + yamlFileName);
+        URL url = bundle.getResource(envDockerComposeFile);
         Assert.assertNotNull("DockerOvs: URL is null", url);
 
         File tmpFile = null;
index c4aaf373db3466f3700379d09d1b6b04373d3aaf..7e9c700fc138a4d06be26a45a9581e1e7c1c0391 100644 (file)
@@ -36,4 +36,6 @@ public final class ItConstants {
     public static final String INTEGRATION_BRIDGE_NAME = "br-int";
     public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
     public static final String NETVIRT_TOPOLOGY_ID = "netvirt:1";
+    public static final String DOCKER_COMPOSE_FILE_NAME="docker.compose.file";
+    public static final String DOCKER_RUN="docker.run";
 }
diff --git a/utils/ovsdb-it-utils/src/main/resources/docker-compose-files/two_dockers-ovs-2.5.1.yml b/utils/ovsdb-it-utils/src/main/resources/docker-compose-files/two_dockers-ovs-2.5.1.yml
new file mode 100644 (file)
index 0000000..0ab364c
--- /dev/null
@@ -0,0 +1,12 @@
+ovs1:
+ image: jhershbe/centos7-ovs:latest
+ ports:
+   - "6641:6640"
+ command: "/usr/bin/supervisord -n"
+ privileged: true
+ovs2:
+ image: jhershbe/centos7-ovs:latest
+ ports:
+   - "6642:6640"
+ command: "/usr/bin/supervisord -n"
+ privileged: true