changeset 162:8a351ae62467

Small changes for Windows compatibility This patch adds some Keycloak notes for running on Windows, and updates some of the integration tests to run properly, although there is still a failure near the end. Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/023312.html
author Simon Tooke <stooke@redhat.com>
date Tue, 30 May 2017 11:29:22 -0400
parents 16c078be30b4
children 5c0df0f4ea4a
files common/core/src/main/java/com/redhat/thermostat/gateway/common/util/OS.java distribution/src/windows/bin/thermostat-mongodb.cmd docker/thermostat-keycloak/README.md docker/thermostat-keycloak/setup-keycloak.cmd server/src/test/java/com/redhat/thermostat/gateway/server/services/WebArchiveServiceBuilderTest.java tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/integration/IntegrationTest.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/MongodTestUtil.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/ProcessTestUtil.java
diffstat 8 files changed, 207 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/util/OS.java	Tue May 30 11:29:22 2017 -0400
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.common.util;
+
+/**
+ * Utility class for OS-specific behaviour
+ */
+public class OS {
+
+    /**
+     * The current OS is Linux, BSD, Darwin, AIX, Solaris (etc.)
+     */
+    public static final boolean IS_UNIX;
+
+    /**
+     * The current OS is Windows of any flavour (implies IS_UNIX is false)
+     */
+
+    public static final boolean IS_WINDOWS;
+
+    /**
+     * The current OS is Linux (implies IS_UNIX is also true)
+     */
+    public static final boolean IS_LINUX;
+
+    /**
+     * The current OS is MacOS (implies IS_UNIX is also true)
+     */
+    public static final boolean IS_MACOS;
+
+    /*
+     * the standard line ending for this OS
+     */
+    public static final String EOL = System.getProperty("line.separator");
+
+    static {
+        final String osname = System.getProperty("os.name").toLowerCase();
+
+        IS_UNIX = !osname.contains("win");
+        IS_WINDOWS = !IS_UNIX;
+
+        IS_MACOS = osname.contains("os x") || osname.contains("mac") || osname.contains("darwin");
+        IS_LINUX = osname.contains("linux");
+
+
+    }
+}
--- a/distribution/src/windows/bin/thermostat-mongodb.cmd	Tue May 30 09:16:06 2017 -0400
+++ b/distribution/src/windows/bin/thermostat-mongodb.cmd	Tue May 30 11:29:22 2017 -0400
@@ -61,10 +61,10 @@
     if not exist %DB_PATH% mkdir %DB_PATH%
     if not exist %DATA_PATH% mkdir %DATA_PATH%
 
-    mongod --quiet --nohttpinterface --bind_ip %IP% --nojournal --dbpath %DATA_PATH% --logpath %LOG_PATH% --pidfilepath %PID_PATH% --port %PORT%
+    start /MIN mongod --quiet --nohttpinterface --bind_ip %IP% --nojournal --dbpath %DATA_PATH% --logpath %LOG_PATH% --pidfilepath %PID_PATH% --port %PORT%
 
     if not exist %SETUP_PATH% (
-        rem sleep 3
+        ping -n 5 localhost >nul
         echo setup-complete >%SETUP_PATH%
         mongo %IP%:%PORT% %JS_PATH%
     )
--- a/docker/thermostat-keycloak/README.md	Tue May 30 09:16:06 2017 -0400
+++ b/docker/thermostat-keycloak/README.md	Tue May 30 11:29:22 2017 -0400
@@ -87,3 +87,24 @@
 $ curl -H "Authorization: bearer $TOKEN" "http://localhost:30000/jvm-gc/0.0.1"
 ```
 
+### Windows notes for Keycloak
+
+Docker and VirtualBox do not play well together (you can only run one or the other); you need to use Docker Toolbox to avoid a Hyper-V conflict.
+The Keycloak image must be built from the Docker Quickstart terminal (MingW), not from a Windows command shell.
+
+An alternative is to run Keycloak natively in Windows.  A Keycloak configuration script is provided for that purpose.
+
+(tested with keycloak-3.1.0.Final.zip from  http://www.keycloak.org/downloads.html)
+
+1) Download Keycloak, and unzip the installation file.
+2) set KEYCLOAK_HOME to the root of the unzipped Keycloak installation
+3) set JAVA_HOME to the root of a valid Java runtime installation
+4) while Keycloak is not running, run (web-gateway)\docker\thermostat-keycloak\setup-keycloak.cmd
+   (this will create an admin user, temporarily bring up Keycloak in another window, and set up the Thermostat realm)
+4a) optionally, change the server port from the default of 8080.
+    When running Keycloak in standalone mode, this is configured near the bottom of (keycloak)\standalone\configuration\standalone.xml.
+    (Search for socket-binding-group)
+5) start Keycloak normally: %KEYCLOAK_HOME%\bin\standalone.bat
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docker/thermostat-keycloak/setup-keycloak.cmd	Tue May 30 11:29:22 2017 -0400
@@ -0,0 +1,79 @@
+@echo off
+rem
+rem Copyright 2012-2017 Red Hat, Inc.
+rem
+rem This file is part of Thermostat.
+rem
+rem Thermostat is free software; you can redistribute it and/or modify
+rem it under the terms of the GNU General Public License as published
+rem by the Free Software Foundation; either version 2, or (at your
+rem option) any later version.
+rem
+rem Thermostat is distributed in the hope that it will be useful, but
+rem WITHOUT ANY WARRANTY; without even the implied warranty of
+rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+rem General Public License for more details.
+rem
+rem You should have received a copy of the GNU General Public License
+rem along with Thermostat; see the file COPYING.  If not see
+rem <http://www.gnu.org/licenses/>.
+rem
+rem Linking this code with other modules is making a combined work
+rem based on this code.  Thus, the terms and conditions of the GNU
+rem General Public License cover the whole combination.
+rem
+rem As a special exception, the copyright holders of this code give
+rem you permission to link this code with independent modules to
+rem produce an executable, regardless of the license terms of these
+rem independent modules, and to copy and distribute the resulting
+rem executable under terms of your choice, provided that you also
+rem meet, for each linked independent module, the terms and conditions
+rem of the license of that module.  An independent module is a module
+rem which is not derived from or based on this code.  If you modify
+rem this code, you may extend this exception to your version of the
+rem library, but you are not obligated to do so.  If you do not wish
+rem to do so, delete this exception statement from your version.
+rem
+
+rem Be polite, tell the user everything that's missing before exitting.
+if not defined KEYCLOAK_HOME (
+	echo KEYCLOAK_HOME is not set
+)
+if not defined JAVA_HOME (
+	echo JAVA_HOME is not set
+)
+
+rem now, exit if something is not set
+if not defined KEYCLOAK_HOME (
+	exit /b 1
+)
+if not defined JAVA_HOME (
+	exit /b 1
+)
+
+set KEYCLOAK_ADMIN=tms-admin
+set KEYCLOAK_PASSWD=tms-admin
+set THERMOSTAT_USER=tms-user
+set THERMOSTAT_PASSWORD=tms-pass
+set REALM=thermostat
+set SERVER=http://localhost:8080/auth
+set CLI=%KEYCLOAK_HOME%\bin\kcadm.bat
+
+call %KEYCLOAK_HOME%\bin\add-user.bat  --user %KEYCLOAK_ADMIN% --password %KEYCLOAK_PASSWD%
+call %KEYCLOAK_HOME%\bin\add-user-keycloak.bat  --user %KEYCLOAK_ADMIN% --password %KEYCLOAK_PASSWD%
+
+start %KEYCLOAK_HOME%\bin\standalone.bat
+rem Wait for keycloak to startup
+rem (use ping because there's no 'sleep' command)
+ping 127.0.0.1 -n 30 >nul
+
+call %CLI% config credentials --server %SERVER% --realm master --user %KEYCLOAK_ADMIN% --password %KEYCLOAK_PASSWD%
+call %CLI% create realms -s realm=%REALM% -s enabled=true
+call %CLI% create roles -r %REALM% -s name=thermostat
+call %CLI% create clients -r %REALM% -s clientId=thermostat-bearer -s enabled=true -s bearerOnly=true
+call %CLI% create clients -r %REALM% -s clientId=thermostat-web-client -s enabled=true -s publicClient=true -s 'redirectUris=["http://localhost:8080/*"]' -s 'webOrigins=["+"]' -s directAccessGrantsEnabled=true
+call %CLI% create users -r %REALM% -s enabled=true -s username=%THERMOSTAT_USER%
+call %CLI% add-roles -r %REALM% --uusername %THERMOSTAT_USER% --rolename thermostat
+call %CLI% set-password -r %REALM% --username %THERMOSTAT_USER% --new-password %THERMOSTAT_PASSWORD%
+
+%KEYCLOAK_HOME%\bin\jboss-cli.bat --connect command=:shutdown
--- a/server/src/test/java/com/redhat/thermostat/gateway/server/services/WebArchiveServiceBuilderTest.java	Tue May 30 09:16:06 2017 -0400
+++ b/server/src/test/java/com/redhat/thermostat/gateway/server/services/WebArchiveServiceBuilderTest.java	Tue May 30 11:29:22 2017 -0400
@@ -48,6 +48,7 @@
 import java.util.List;
 import java.util.Map;
 
+import com.redhat.thermostat.gateway.common.util.OS;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -106,7 +107,7 @@
     public void keepsAbsoluteServiceWarFile() {
         EnvHelper env = mock(EnvHelper.class);
         WebArchiveServiceBuilder serviceBuilder = new WebArchiveServiceBuilder(configFactory, env, new PathHelper());
-        String orig = "/abs/path";
+        String orig = OS.IS_UNIX ? "/abs/path" : "C:\\abs\\path";
         String result = serviceBuilder.getAbsolutePathForService(orig);
         assertEquals(orig, result);
     }
--- a/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/integration/IntegrationTest.java	Tue May 30 09:16:06 2017 -0400
+++ b/tests/integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/integration/IntegrationTest.java	Tue May 30 11:29:22 2017 -0400
@@ -50,6 +50,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import com.redhat.thermostat.gateway.common.util.OS;
 import org.eclipse.jetty.client.HttpClient;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -63,7 +64,8 @@
 
     protected static final MongodTestUtil mongodTestUtil = new MongodTestUtil();
     private static final Path distributionImage = Paths.get("../../distribution/target/image");
-    private static final String WEB_GATEWAY_SCRIPT = "thermostat-web-gateway.sh";
+    private static final String POSIX_WEB_GATEWAY_SCRIPT = "thermostat-web-gateway.sh";
+    private static final String WINDOWS_WEB_GATEWAY_SCRIPT = "thermostat-web-gateway.cmd";
 
     private static Process serverProcess;
 
@@ -87,9 +89,11 @@
     }
 
     private static void startServer() throws IOException, InterruptedException {
-        String command = distributionImage.resolve("bin").resolve(WEB_GATEWAY_SCRIPT).toAbsolutePath().toString();
+        String commandStr = OS.IS_UNIX ? distributionImage.resolve("bin").resolve(POSIX_WEB_GATEWAY_SCRIPT).toAbsolutePath().toString()
+                : distributionImage.resolve("bin").resolve(WINDOWS_WEB_GATEWAY_SCRIPT).toAbsolutePath().toString();
 
-        ProcessBuilder processBuilder = new ProcessBuilder().command(command).inheritIO().redirectError(ProcessBuilder.Redirect.PIPE);
+        ProcessBuilder processBuilder = OS.IS_UNIX ? new ProcessBuilder().command(commandStr).inheritIO().redirectError(ProcessBuilder.Redirect.PIPE)
+                : new ProcessBuilder().command("cmd", "/c", commandStr).inheritIO().redirectError(ProcessBuilder.Redirect.PIPE);
 
         serverProcess = processBuilder.start();
         final BufferedReader reader = new BufferedReader(new InputStreamReader(serverProcess.getErrorStream()));
@@ -115,10 +119,13 @@
         }
     }
 
-
-
     private static void stopServer() throws Exception {
-        ProcessTestUtil.killRecursively(serverProcess);
+        if (OS.IS_UNIX) {
+            ProcessTestUtil.killRecursively(serverProcess);
+        } else {
+            // TODO: kill children on Windows
+            serverProcess.destroy();
+        }
     }
 
     @AfterClass
--- a/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/MongodTestUtil.java	Tue May 30 09:16:06 2017 -0400
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/MongodTestUtil.java	Tue May 30 11:29:22 2017 -0400
@@ -43,6 +43,7 @@
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 
+import com.redhat.thermostat.gateway.common.util.OS;
 import org.bson.Document;
 
 import com.mongodb.MongoClient;
@@ -68,10 +69,10 @@
         tempLogFile = tempDbDir.resolve("mongod.log");
         tempLogFile.toFile().deleteOnExit();
 
-        String[] command = {"mongod", "--dbpath", tempDbDir.resolve("data/db").toAbsolutePath().toString(), "--port", String.valueOf(port), "--fork", "--logpath", tempLogFile.toAbsolutePath().toString()};
-        ProcessBuilder builder = new ProcessBuilder(command);
+        String[] posixCommand = {"mongod", "--dbpath", tempDbDir.resolve("data/db").toAbsolutePath().toString(), "--port", String.valueOf(port), "--fork", "--logpath", tempLogFile.toAbsolutePath().toString()};
+        String[] windowsCommand = {"cmd", "/c", "mongod", "--dbpath", tempDbDir.resolve("data/db").toAbsolutePath().toString(), "--port", String.valueOf(port), "--logpath", tempLogFile.toAbsolutePath().toString()};
+        ProcessBuilder builder = new ProcessBuilder(OS.IS_UNIX ? posixCommand : windowsCommand);
         process = builder.start();
-
         mongoClient = new MongoClient(new ServerAddress(host, port));
 
         waitForMongodStart();
--- a/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/ProcessTestUtil.java	Tue May 30 09:16:06 2017 -0400
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/ProcessTestUtil.java	Tue May 30 11:29:22 2017 -0400
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.gateway.tests.utils;
 
+import com.redhat.thermostat.gateway.common.util.OS;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -48,6 +50,9 @@
      * Kill the process and all its children, recursively. Sends SIGTERM.
      */
     public static void killRecursively(Process process) throws Exception {
+        if (OS.IS_WINDOWS) {
+            throw new UnsupportedOperationException("killRecursively() not supported on Windows");
+        }
         killRecursively(getPid(process));
     }