From c1c9881f678926e4727690ee943ddb270340f658 Mon Sep 17 00:00:00 2001 From: hancockks Date: Thu, 21 Jul 2016 08:20:29 -0400 Subject: [PATCH 01/14] Add support for Windows --- .../java/io/teknek/farsandra/Farsandra.java | 336 ++++++++++++------ .../src/main/resources/farsandra.properties | 4 +- 2 files changed, 235 insertions(+), 105 deletions(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java index 1b53cf7..f986783 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java @@ -41,7 +41,7 @@ public class Farsandra { private List seeds; private CForgroundManager manager; private String javaHome; - private Integer jmxPort; + private Integer jmxPort = 7199; private String maxHeapSize = "256M"; private String heapNewSize = "100M"; private List yamlLinesToAppend; @@ -290,7 +290,7 @@ public void start(){ //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. //String yarn = " -Dcassandra-foreground=yes org.apache.cassandra.service.CassandraDaemon"; - File instanceBase = new File(instanceName); + File instanceBase = new File(cRoot,instanceName); if (cleanInstanceOnStart){ if (instanceBase.exists()){ delete(instanceBase); @@ -302,6 +302,8 @@ public void start(){ File instanceConf; File instanceLog; File instanceData; + File instanceBin; + if (configHolder == null){ instanceConf = new File(instanceBase, "conf"); } else { @@ -319,104 +321,30 @@ public void start(){ } else { instanceData = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.data.dir")); } - instanceData.mkdir(); + instanceData.mkdir(); + if (configHolder == null){ + instanceBin = new File(instanceBase, "bin"); + } else { + instanceBin = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); + } + instanceBin.mkdir(); + copyConfToInstanceDir(cRoot, instanceConf, configHolder); File binaryConf; - File cassandraYaml; + File binaryBin; if (configHolder == null){ binaryConf = new File(cRoot, "conf"); - cassandraYaml = new File(binaryConf, "cassandra.yaml"); + binaryBin = new File(cRoot, "bin"); } else { binaryConf = new File(cRoot, this.getConfigHolder().getProperties().getProperty("farsandra.conf.dir")); - cassandraYaml = new File(binaryConf, this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); + binaryBin = new File(cRoot, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); } setUpLoggingConf(instanceConf, instanceLog); makeCassandraEnv(binaryConf, instanceConf); - - List lines; - try { - lines = Files.readAllLines(cassandraYaml.toPath(), Charset.defaultCharset()); - } catch (IOException e) { - throw new RuntimeException(e); - } - lines = replaceHost(lines); - try { - lines = replaceThisWithThatExpectNMatch(lines, - " - /var/lib/cassandra/data", - " - " + this.instanceName + "/data/data" , 1); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, - "# data_file_directories:", - "data_file_directories:" , 1); - lines = replaceThisWithThatExpectNMatch(lines, - "# - /var/lib/cassandra/data", - " - " + this.instanceName + "/data/data" , 1); - } - lines = replaceThisWithThatExpectNMatch(lines, - "listen_address: localhost", - "listen_address: " +host , 1); - try { - lines = replaceThisWithThatExpectNMatch(lines, - "commitlog_directory: /var/lib/cassandra/commitlog", - "commitlog_directory: " + this.instanceName + "/data/commitlog" , 1 ); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, - "# commitlog_directory: /var/lib/cassandra/commitlog", - "commitlog_directory: " + this.instanceName + "/data/commitlog" , 1 ); - } - try { - lines = replaceThisWithThatExpectNMatch(lines, - "saved_caches_directory: /var/lib/cassandra/saved_caches", - "saved_caches_directory: " + this.instanceName + "/data/saved_caches", 1); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, - "# saved_caches_directory: /var/lib/cassandra/saved_caches", - "saved_caches_directory: " + this.instanceName + "/data/saved_caches", 1); - } - try { - lines = replaceThisWithThatExpectNMatch(lines, - "start_rpc: false", - "start_rpc: true", 1); - } catch (RuntimeException ex) { - // Only needed for C* 2.2+ - } - if (storagePort != null){ - lines = replaceThisWithThatExpectNMatch(lines, "storage_port: 7000", "storage_port: "+storagePort, 1 ); - } - if (rpcPort != null){ - lines = replaceThisWithThatExpectNMatch(lines, "rpc_port: 9160", "rpc_port: " + rpcPort, 1); - } - if (nativeTransportPort != null){ - lines = replaceThisWithThatExpectNMatch(lines, "native_transport_port: 9042", "native_transport_port: "+nativeTransportPort, 1 ); - } - if (seeds != null) { - lines = replaceThisWithThatExpectNMatch(lines, " - seeds: \"127.0.0.1\"", - " - seeds: \"" + seeds.get(0) + "\"", 1); - } - for (Map.Entry entry: yamlReplacements.entrySet()){ - lines = replaceThisWithThatExpectNMatch(lines, entry.getKey(), entry.getValue(), 1); - } - lines = yamlLinesToAppend(lines); - File instanceConfToWrite; - if (configHolder == null){ - instanceConfToWrite = new File(instanceConf, "cassandra.yaml"); - } else { - instanceConfToWrite = new File(instanceConf, this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); - } - try (BufferedWriter bw = new BufferedWriter(new FileWriter(instanceConfToWrite))){ - for (String s: lines){ - bw.write(s); - bw.newLine(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } + makeCassandraBat(binaryBin, instanceBin, instanceConf); + makeCassandraYaml(cRoot, binaryConf, instanceConf); } - // /bin/bash -c "env - X=5 y=2 sh xandy.sh" - //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc - //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. - File cstart = new File(new File( cRoot, "bin"),"cassandra"); /*String launch = "/bin/bash -c \"/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath() +" JAVA_HOME="+ "/usr/java/jdk1.7.0_45 " @@ -427,19 +355,52 @@ public void start(){ } else { instanceConf = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.conf.dir")); } - String command = "/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath(); - //command = command + " JAVA_HOME=" + "/usr/java/jdk1.7.0_45 "; - command = command + buildJavaHome() + " "; - command = command + " /bin/bash " + cstart.getAbsolutePath().toString() + " -f "; - String [] launchArray = new String [] { - "/bin/bash" , - "-c" , - command }; - manager.setLaunchArray(launchArray); - manager.go(); + + if (isWindows()) + { + File instanceBin; + if (configHolder == null){ + instanceBin = new File(instanceBase, "bin"); + } else { + instanceBin = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); + } + + File cstart = new File(instanceBin, "cassandra.bat"); + String[] envArray = new String[] {"CASSANDRA_CONF="+instanceConf.getAbsolutePath(), + buildJavaHome(), + "PATH=" + instanceBin.getAbsolutePath(), + "CASSANDRA_HOME="+cRoot.getAbsolutePath()}; +// String[] commandArray = new String[] { "cmd", "/C", "set"}; + String[] commandArray = new String[] { "cmd", "/C", cstart.getAbsolutePath(), "-f"}; + manager.setEvnArray(envArray); + manager.setLaunchArray(commandArray); + } + else + { + // /bin/bash -c "env - X=5 y=2 sh xandy.sh" + //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc + //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. + File cstart = new File(new File( cRoot, "bin"),"cassandra"); + + String command = "/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath(); + //command = command + " JAVA_HOME=" + "/usr/java/jdk1.7.0_45 "; + command = command + " " + buildJavaHome(); + command = command + " /bin/bash " + cstart.getAbsolutePath().toString() + " -f "; + String [] launchArray = new String [] { + "/bin/bash" , + "-c" , + command }; + manager.setLaunchArray(launchArray); + } + manager.go(); } + private boolean isWindows() { + String os = System.getProperty("os.name"); + return os.contains("Windows"); + } + /** * Replaces the default file path of the system log. * Cassandra comes with a log4j configuration that assumes, by default, there's a /var/log/cassandra directory @@ -466,13 +427,21 @@ private void setUpLoggingConf(final File instanceConfDirectory, log4ServerProperties.toPath(), Charset.defaultCharset()); writer = new BufferedWriter(new FileWriter(log4ServerProperties)); for (final String line : lines) { - writer.write( - (line.startsWith(log4jAppenderConfLine) ? log4jAppenderConfLine - .concat("=").concat(systemLog.getAbsolutePath()) : line)); + if (line.startsWith(log4jAppenderConfLine)) { + if (isWindows()) { + writer.write(log4jAppenderConfLine + "=" + systemLog.getAbsolutePath().replace("\\", "/")); + } else { + writer.write(log4jAppenderConfLine + "=" + systemLog.getAbsolutePath()); + } + } else { + writer.write(line); + } writer.newLine(); } } catch (final IOException exception) { throw new RuntimeException(exception); + } catch (final Exception e) { + LOGGER.error("Exception writing log4j-server.properties: " + e.getMessage()); } finally { if (writer != null) { try { @@ -574,12 +543,153 @@ private void makeCassandraEnv(File binaryConf, File instanceConf) { throw new RuntimeException(e); } } + + /** + * Builds the cassandra.yaml replacing stuff along the way + * @param binaryConf directory of downloaded conf + * @param instanceConf directory for conf to be generated + */ + private void makeCassandraYaml(File root, File binaryConf, File instanceConf) { + List lines; + File cassandraYaml; + String fullPath = root.getAbsolutePath() + "\\" + this.instanceName; + + if (configHolder == null) { + cassandraYaml = new File(binaryConf, "cassandra.yaml"); + } else { + cassandraYaml = new File(binaryConf, + this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); + } + try { + lines = Files.readAllLines(cassandraYaml.toPath(), Charset.defaultCharset()); + } catch (IOException e) { + throw new RuntimeException(e); + } + lines = replaceHost(lines); + try { + lines = replaceThisWithThatExpectNMatch(lines, " - /var/lib/cassandra/data", + " - " + fullPath + "/data/data", 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, "# data_file_directories:", "data_file_directories:", 1); + lines = replaceThisWithThatExpectNMatch(lines, "# - /var/lib/cassandra/data", + " - " + fullPath + "/data/data", 1); + } + lines = replaceThisWithThatExpectNMatch(lines, "listen_address: localhost", "listen_address: " + host, 1); + try { + lines = replaceThisWithThatExpectNMatch(lines, "commitlog_directory: /var/lib/cassandra/commitlog", + "commitlog_directory: " + fullPath + "/data/commitlog", 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, "# commitlog_directory: /var/lib/cassandra/commitlog", + "commitlog_directory: " + fullPath + "/data/commitlog", 1); + } + try { + lines = replaceThisWithThatExpectNMatch(lines, "saved_caches_directory: /var/lib/cassandra/saved_caches", + "saved_caches_directory: " + fullPath + "/data/saved_caches", 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, "# saved_caches_directory: /var/lib/cassandra/saved_caches", + "saved_caches_directory: " + fullPath + "/data/saved_caches", 1); + } + try { + lines = replaceThisWithThatExpectNMatch(lines, "start_rpc: false", "start_rpc: true", 1); + } catch (RuntimeException ex) { + // Only needed for C* 2.2+ + } + if (storagePort != null) { + lines = replaceThisWithThatExpectNMatch(lines, "storage_port: 7000", "storage_port: " + storagePort, 1); + } + if (rpcPort != null) { + lines = replaceThisWithThatExpectNMatch(lines, "rpc_port: 9160", "rpc_port: " + rpcPort, 1); + } + if (nativeTransportPort != null) { + lines = replaceThisWithThatExpectNMatch(lines, "native_transport_port: 9042", + "native_transport_port: " + nativeTransportPort, 1); + } + if (seeds != null) { + lines = replaceThisWithThatExpectNMatch(lines, " - seeds: \"127.0.0.1\"", + " - seeds: \"" + seeds.get(0) + "\"", 1); + } + for (Map.Entry entry : yamlReplacements.entrySet()) { + lines = replaceThisWithThatExpectNMatch(lines, entry.getKey(), entry.getValue(), 1); + } + lines = yamlLinesToAppend(lines); + File instanceConfToWrite; + if (configHolder == null) { + instanceConfToWrite = new File(instanceConf, "cassandra.yaml"); + } else { + instanceConfToWrite = new File(instanceConf, + this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); + } + try (BufferedWriter bw = new BufferedWriter(new FileWriter(instanceConfToWrite))) { + for (String s : lines) { + bw.write(s); + bw.newLine(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Builds the cassandra.bat replacing stuff along the way + * @param binaryBin directory of downloaded bin + * @param instanceBin directory for bin to be generated + */ + private void makeCassandraBat(File binaryBin, File instanceBin, File instanceConf) { + String fileName; + if (configHolder == null) { + fileName = "cassandra.bat"; + } else { + fileName = this.getConfigHolder().getProperties().getProperty("cassandra.batch.file.name"); + } + File batchFile = new File(binaryBin, fileName); + List lines; + try { + lines = Files.readAllLines(batchFile.toPath(), Charset.defaultCharset()); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (jmxPort != null) { + lines = replaceSubstringThisWithThatExpectNMatch(lines, "jmxremote.port=7199", "jmxremote.port=" + this.jmxPort, + 1); + } + + lines = replaceSubstringThisWithThatExpectNMatch(lines, "%JAVA_OPTS% %CASSANDRA_PARAMS% -cp", + "%JAVA_OPTS% " + "-Dorg.xerial.snappy.tempdir=\"" + instanceBin.getAbsolutePath() + "\"" + " %CASSANDRA_PARAMS% -cp", 1); + + // Cassandra 1.2.x + if (maxHeapSize != null) { + lines = replaceSubstringThisWithThatExpectNMatch(lines, "-Xms1G", "-Xms" + this.maxHeapSize, 1); + } + + // NEW HEAP SIZE not supported by Windows // TODO + + // if (heapNewSize != null) { + // lines = replaceSubstringThisWithThatExpectNMatch(lines, "-Xmx1G", "-Xmx" + // + heapNewSize, 1); + // } + + // Windows doesn't support the CASSANDRA_CONF environment variable, so put + // our instance configuration + // directory first in the classpath. + + lines = replaceSubstringThisWithThatExpectNMatch(lines, "-cp %CASSANDRA_CLASSPATH%", + "-cp " + instanceConf.getAbsolutePath() + ";%CASSANDRA_CLASSPATH%", 1); + + try (BufferedWriter bw = new BufferedWriter(new FileWriter(new File(instanceBin, fileName)))) { + for (String s : lines) { + bw.write(s); + bw.newLine(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } public String buildJavaHome() { if (this.javaHome != null) { - return " JAVA_HOME=" + this.javaHome; + return "JAVA_HOME=" + this.javaHome; } else if (System.getenv("JAVA_HOME") != null) { - return " JAVA_HOME=" + System.getenv("JAVA_HOME"); + return "JAVA_HOME=" + System.getenv("JAVA_HOME"); } else { return ""; } @@ -594,6 +704,24 @@ void delete(File f) { throw new RuntimeException("Failed to delete file: " + f); } + public List replaceSubstringThisWithThatExpectNMatch(List lines, String match, String replace, int expectedMatches){ + List result = new ArrayList(); + int replaced = 0; + for (String line: lines){ + if (!line.contains(match)){ + result.add(line); + } else{ + replaced++; + result.add(line.replace(match, replace)); + } + } + if (replaced != expectedMatches){ + throw new RuntimeException("looking to make " + expectedMatches +" of ('" + match + "')->'(" + replace + "') but made "+replaced + +" . Likely that farsandra does not understand this version of configuration file. "); + } + return result; + } + public List replaceThisWithThatExpectNMatch(List lines, String match, String replace, int expectedMatches){ List result = new ArrayList(); int replaced = 0; diff --git a/farsandra-core/src/main/resources/farsandra.properties b/farsandra-core/src/main/resources/farsandra.properties index c5bbde1..adcf0f8 100644 --- a/farsandra-core/src/main/resources/farsandra.properties +++ b/farsandra-core/src/main/resources/farsandra.properties @@ -4,7 +4,9 @@ cassandra.package.name.suffix=-bin.tar.gz cassandra.package.dist.site=http://archive.apache.org/dist/cassandra/ cassandra.config.file.name=cassandra.yaml cassandra.environment.file.name=cassandra-env.sh +cassandra.batch.file.name=cassandra.bat farsandra.home.folder=.farsandra farsandra.conf.dir=conf farsandra.log.dir=log -farsandra.data.dir=data \ No newline at end of file +farsandra.data.dir=data +farsandra.bin.dir=bin \ No newline at end of file From e51af739de64229d747b91be6fc00aa165d76143 Mon Sep 17 00:00:00 2001 From: hancockks Date: Thu, 21 Jul 2016 08:21:23 -0400 Subject: [PATCH 02/14] Revert "Add support for Windows" This reverts commit c1c9881f678926e4727690ee943ddb270340f658. --- .../java/io/teknek/farsandra/Farsandra.java | 336 ++++++------------ .../src/main/resources/farsandra.properties | 4 +- 2 files changed, 105 insertions(+), 235 deletions(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java index f986783..1b53cf7 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java @@ -41,7 +41,7 @@ public class Farsandra { private List seeds; private CForgroundManager manager; private String javaHome; - private Integer jmxPort = 7199; + private Integer jmxPort; private String maxHeapSize = "256M"; private String heapNewSize = "100M"; private List yamlLinesToAppend; @@ -290,7 +290,7 @@ public void start(){ //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. //String yarn = " -Dcassandra-foreground=yes org.apache.cassandra.service.CassandraDaemon"; - File instanceBase = new File(cRoot,instanceName); + File instanceBase = new File(instanceName); if (cleanInstanceOnStart){ if (instanceBase.exists()){ delete(instanceBase); @@ -302,8 +302,6 @@ public void start(){ File instanceConf; File instanceLog; File instanceData; - File instanceBin; - if (configHolder == null){ instanceConf = new File(instanceBase, "conf"); } else { @@ -321,30 +319,104 @@ public void start(){ } else { instanceData = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.data.dir")); } - instanceData.mkdir(); - if (configHolder == null){ - instanceBin = new File(instanceBase, "bin"); - } else { - instanceBin = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); - } - instanceBin.mkdir(); - + instanceData.mkdir(); copyConfToInstanceDir(cRoot, instanceConf, configHolder); File binaryConf; - File binaryBin; + File cassandraYaml; if (configHolder == null){ binaryConf = new File(cRoot, "conf"); - binaryBin = new File(cRoot, "bin"); + cassandraYaml = new File(binaryConf, "cassandra.yaml"); } else { binaryConf = new File(cRoot, this.getConfigHolder().getProperties().getProperty("farsandra.conf.dir")); - binaryBin = new File(cRoot, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); + cassandraYaml = new File(binaryConf, this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); } setUpLoggingConf(instanceConf, instanceLog); makeCassandraEnv(binaryConf, instanceConf); - makeCassandraBat(binaryBin, instanceBin, instanceConf); - makeCassandraYaml(cRoot, binaryConf, instanceConf); + + List lines; + try { + lines = Files.readAllLines(cassandraYaml.toPath(), Charset.defaultCharset()); + } catch (IOException e) { + throw new RuntimeException(e); + } + lines = replaceHost(lines); + try { + lines = replaceThisWithThatExpectNMatch(lines, + " - /var/lib/cassandra/data", + " - " + this.instanceName + "/data/data" , 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, + "# data_file_directories:", + "data_file_directories:" , 1); + lines = replaceThisWithThatExpectNMatch(lines, + "# - /var/lib/cassandra/data", + " - " + this.instanceName + "/data/data" , 1); + } + lines = replaceThisWithThatExpectNMatch(lines, + "listen_address: localhost", + "listen_address: " +host , 1); + try { + lines = replaceThisWithThatExpectNMatch(lines, + "commitlog_directory: /var/lib/cassandra/commitlog", + "commitlog_directory: " + this.instanceName + "/data/commitlog" , 1 ); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, + "# commitlog_directory: /var/lib/cassandra/commitlog", + "commitlog_directory: " + this.instanceName + "/data/commitlog" , 1 ); + } + try { + lines = replaceThisWithThatExpectNMatch(lines, + "saved_caches_directory: /var/lib/cassandra/saved_caches", + "saved_caches_directory: " + this.instanceName + "/data/saved_caches", 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, + "# saved_caches_directory: /var/lib/cassandra/saved_caches", + "saved_caches_directory: " + this.instanceName + "/data/saved_caches", 1); + } + try { + lines = replaceThisWithThatExpectNMatch(lines, + "start_rpc: false", + "start_rpc: true", 1); + } catch (RuntimeException ex) { + // Only needed for C* 2.2+ + } + if (storagePort != null){ + lines = replaceThisWithThatExpectNMatch(lines, "storage_port: 7000", "storage_port: "+storagePort, 1 ); + } + if (rpcPort != null){ + lines = replaceThisWithThatExpectNMatch(lines, "rpc_port: 9160", "rpc_port: " + rpcPort, 1); + } + if (nativeTransportPort != null){ + lines = replaceThisWithThatExpectNMatch(lines, "native_transport_port: 9042", "native_transport_port: "+nativeTransportPort, 1 ); + } + if (seeds != null) { + lines = replaceThisWithThatExpectNMatch(lines, " - seeds: \"127.0.0.1\"", + " - seeds: \"" + seeds.get(0) + "\"", 1); + } + for (Map.Entry entry: yamlReplacements.entrySet()){ + lines = replaceThisWithThatExpectNMatch(lines, entry.getKey(), entry.getValue(), 1); + } + lines = yamlLinesToAppend(lines); + File instanceConfToWrite; + if (configHolder == null){ + instanceConfToWrite = new File(instanceConf, "cassandra.yaml"); + } else { + instanceConfToWrite = new File(instanceConf, this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); + } + try (BufferedWriter bw = new BufferedWriter(new FileWriter(instanceConfToWrite))){ + for (String s: lines){ + bw.write(s); + bw.newLine(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } } + // /bin/bash -c "env - X=5 y=2 sh xandy.sh" + //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc + //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. + File cstart = new File(new File( cRoot, "bin"),"cassandra"); /*String launch = "/bin/bash -c \"/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath() +" JAVA_HOME="+ "/usr/java/jdk1.7.0_45 " @@ -355,52 +427,19 @@ public void start(){ } else { instanceConf = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.conf.dir")); } - - if (isWindows()) - { - File instanceBin; - if (configHolder == null){ - instanceBin = new File(instanceBase, "bin"); - } else { - instanceBin = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); - } - - File cstart = new File(instanceBin, "cassandra.bat"); - String[] envArray = new String[] {"CASSANDRA_CONF="+instanceConf.getAbsolutePath(), - buildJavaHome(), - "PATH=" + instanceBin.getAbsolutePath(), - "CASSANDRA_HOME="+cRoot.getAbsolutePath()}; -// String[] commandArray = new String[] { "cmd", "/C", "set"}; - String[] commandArray = new String[] { "cmd", "/C", cstart.getAbsolutePath(), "-f"}; - manager.setEvnArray(envArray); - manager.setLaunchArray(commandArray); - } - else - { - // /bin/bash -c "env - X=5 y=2 sh xandy.sh" - //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc - //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. - File cstart = new File(new File( cRoot, "bin"),"cassandra"); - - String command = "/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath(); - //command = command + " JAVA_HOME=" + "/usr/java/jdk1.7.0_45 "; - command = command + " " + buildJavaHome(); - command = command + " /bin/bash " + cstart.getAbsolutePath().toString() + " -f "; - String [] launchArray = new String [] { - "/bin/bash" , - "-c" , - command }; - manager.setLaunchArray(launchArray); - } - manager.go(); + String command = "/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath(); + //command = command + " JAVA_HOME=" + "/usr/java/jdk1.7.0_45 "; + command = command + buildJavaHome() + " "; + command = command + " /bin/bash " + cstart.getAbsolutePath().toString() + " -f "; + String [] launchArray = new String [] { + "/bin/bash" , + "-c" , + command }; + manager.setLaunchArray(launchArray); + manager.go(); } - private boolean isWindows() { - String os = System.getProperty("os.name"); - return os.contains("Windows"); - } - /** * Replaces the default file path of the system log. * Cassandra comes with a log4j configuration that assumes, by default, there's a /var/log/cassandra directory @@ -427,21 +466,13 @@ private void setUpLoggingConf(final File instanceConfDirectory, log4ServerProperties.toPath(), Charset.defaultCharset()); writer = new BufferedWriter(new FileWriter(log4ServerProperties)); for (final String line : lines) { - if (line.startsWith(log4jAppenderConfLine)) { - if (isWindows()) { - writer.write(log4jAppenderConfLine + "=" + systemLog.getAbsolutePath().replace("\\", "/")); - } else { - writer.write(log4jAppenderConfLine + "=" + systemLog.getAbsolutePath()); - } - } else { - writer.write(line); - } + writer.write( + (line.startsWith(log4jAppenderConfLine) ? log4jAppenderConfLine + .concat("=").concat(systemLog.getAbsolutePath()) : line)); writer.newLine(); } } catch (final IOException exception) { throw new RuntimeException(exception); - } catch (final Exception e) { - LOGGER.error("Exception writing log4j-server.properties: " + e.getMessage()); } finally { if (writer != null) { try { @@ -543,153 +574,12 @@ private void makeCassandraEnv(File binaryConf, File instanceConf) { throw new RuntimeException(e); } } - - /** - * Builds the cassandra.yaml replacing stuff along the way - * @param binaryConf directory of downloaded conf - * @param instanceConf directory for conf to be generated - */ - private void makeCassandraYaml(File root, File binaryConf, File instanceConf) { - List lines; - File cassandraYaml; - String fullPath = root.getAbsolutePath() + "\\" + this.instanceName; - - if (configHolder == null) { - cassandraYaml = new File(binaryConf, "cassandra.yaml"); - } else { - cassandraYaml = new File(binaryConf, - this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); - } - try { - lines = Files.readAllLines(cassandraYaml.toPath(), Charset.defaultCharset()); - } catch (IOException e) { - throw new RuntimeException(e); - } - lines = replaceHost(lines); - try { - lines = replaceThisWithThatExpectNMatch(lines, " - /var/lib/cassandra/data", - " - " + fullPath + "/data/data", 1); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, "# data_file_directories:", "data_file_directories:", 1); - lines = replaceThisWithThatExpectNMatch(lines, "# - /var/lib/cassandra/data", - " - " + fullPath + "/data/data", 1); - } - lines = replaceThisWithThatExpectNMatch(lines, "listen_address: localhost", "listen_address: " + host, 1); - try { - lines = replaceThisWithThatExpectNMatch(lines, "commitlog_directory: /var/lib/cassandra/commitlog", - "commitlog_directory: " + fullPath + "/data/commitlog", 1); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, "# commitlog_directory: /var/lib/cassandra/commitlog", - "commitlog_directory: " + fullPath + "/data/commitlog", 1); - } - try { - lines = replaceThisWithThatExpectNMatch(lines, "saved_caches_directory: /var/lib/cassandra/saved_caches", - "saved_caches_directory: " + fullPath + "/data/saved_caches", 1); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, "# saved_caches_directory: /var/lib/cassandra/saved_caches", - "saved_caches_directory: " + fullPath + "/data/saved_caches", 1); - } - try { - lines = replaceThisWithThatExpectNMatch(lines, "start_rpc: false", "start_rpc: true", 1); - } catch (RuntimeException ex) { - // Only needed for C* 2.2+ - } - if (storagePort != null) { - lines = replaceThisWithThatExpectNMatch(lines, "storage_port: 7000", "storage_port: " + storagePort, 1); - } - if (rpcPort != null) { - lines = replaceThisWithThatExpectNMatch(lines, "rpc_port: 9160", "rpc_port: " + rpcPort, 1); - } - if (nativeTransportPort != null) { - lines = replaceThisWithThatExpectNMatch(lines, "native_transport_port: 9042", - "native_transport_port: " + nativeTransportPort, 1); - } - if (seeds != null) { - lines = replaceThisWithThatExpectNMatch(lines, " - seeds: \"127.0.0.1\"", - " - seeds: \"" + seeds.get(0) + "\"", 1); - } - for (Map.Entry entry : yamlReplacements.entrySet()) { - lines = replaceThisWithThatExpectNMatch(lines, entry.getKey(), entry.getValue(), 1); - } - lines = yamlLinesToAppend(lines); - File instanceConfToWrite; - if (configHolder == null) { - instanceConfToWrite = new File(instanceConf, "cassandra.yaml"); - } else { - instanceConfToWrite = new File(instanceConf, - this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); - } - try (BufferedWriter bw = new BufferedWriter(new FileWriter(instanceConfToWrite))) { - for (String s : lines) { - bw.write(s); - bw.newLine(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /** - * Builds the cassandra.bat replacing stuff along the way - * @param binaryBin directory of downloaded bin - * @param instanceBin directory for bin to be generated - */ - private void makeCassandraBat(File binaryBin, File instanceBin, File instanceConf) { - String fileName; - if (configHolder == null) { - fileName = "cassandra.bat"; - } else { - fileName = this.getConfigHolder().getProperties().getProperty("cassandra.batch.file.name"); - } - File batchFile = new File(binaryBin, fileName); - List lines; - try { - lines = Files.readAllLines(batchFile.toPath(), Charset.defaultCharset()); - } catch (IOException e) { - throw new RuntimeException(e); - } - if (jmxPort != null) { - lines = replaceSubstringThisWithThatExpectNMatch(lines, "jmxremote.port=7199", "jmxremote.port=" + this.jmxPort, - 1); - } - - lines = replaceSubstringThisWithThatExpectNMatch(lines, "%JAVA_OPTS% %CASSANDRA_PARAMS% -cp", - "%JAVA_OPTS% " + "-Dorg.xerial.snappy.tempdir=\"" + instanceBin.getAbsolutePath() + "\"" + " %CASSANDRA_PARAMS% -cp", 1); - - // Cassandra 1.2.x - if (maxHeapSize != null) { - lines = replaceSubstringThisWithThatExpectNMatch(lines, "-Xms1G", "-Xms" + this.maxHeapSize, 1); - } - - // NEW HEAP SIZE not supported by Windows // TODO - - // if (heapNewSize != null) { - // lines = replaceSubstringThisWithThatExpectNMatch(lines, "-Xmx1G", "-Xmx" - // + heapNewSize, 1); - // } - - // Windows doesn't support the CASSANDRA_CONF environment variable, so put - // our instance configuration - // directory first in the classpath. - - lines = replaceSubstringThisWithThatExpectNMatch(lines, "-cp %CASSANDRA_CLASSPATH%", - "-cp " + instanceConf.getAbsolutePath() + ";%CASSANDRA_CLASSPATH%", 1); - - try (BufferedWriter bw = new BufferedWriter(new FileWriter(new File(instanceBin, fileName)))) { - for (String s : lines) { - bw.write(s); - bw.newLine(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } public String buildJavaHome() { if (this.javaHome != null) { - return "JAVA_HOME=" + this.javaHome; + return " JAVA_HOME=" + this.javaHome; } else if (System.getenv("JAVA_HOME") != null) { - return "JAVA_HOME=" + System.getenv("JAVA_HOME"); + return " JAVA_HOME=" + System.getenv("JAVA_HOME"); } else { return ""; } @@ -704,24 +594,6 @@ void delete(File f) { throw new RuntimeException("Failed to delete file: " + f); } - public List replaceSubstringThisWithThatExpectNMatch(List lines, String match, String replace, int expectedMatches){ - List result = new ArrayList(); - int replaced = 0; - for (String line: lines){ - if (!line.contains(match)){ - result.add(line); - } else{ - replaced++; - result.add(line.replace(match, replace)); - } - } - if (replaced != expectedMatches){ - throw new RuntimeException("looking to make " + expectedMatches +" of ('" + match + "')->'(" + replace + "') but made "+replaced - +" . Likely that farsandra does not understand this version of configuration file. "); - } - return result; - } - public List replaceThisWithThatExpectNMatch(List lines, String match, String replace, int expectedMatches){ List result = new ArrayList(); int replaced = 0; diff --git a/farsandra-core/src/main/resources/farsandra.properties b/farsandra-core/src/main/resources/farsandra.properties index adcf0f8..c5bbde1 100644 --- a/farsandra-core/src/main/resources/farsandra.properties +++ b/farsandra-core/src/main/resources/farsandra.properties @@ -4,9 +4,7 @@ cassandra.package.name.suffix=-bin.tar.gz cassandra.package.dist.site=http://archive.apache.org/dist/cassandra/ cassandra.config.file.name=cassandra.yaml cassandra.environment.file.name=cassandra-env.sh -cassandra.batch.file.name=cassandra.bat farsandra.home.folder=.farsandra farsandra.conf.dir=conf farsandra.log.dir=log -farsandra.data.dir=data -farsandra.bin.dir=bin \ No newline at end of file +farsandra.data.dir=data \ No newline at end of file From c81910b32b1a56e76772175518118de85cf3d5d9 Mon Sep 17 00:00:00 2001 From: hancockks Date: Thu, 21 Jul 2016 08:27:31 -0400 Subject: [PATCH 03/14] Revert "Revert "Add support for Windows"" This reverts commit e51af739de64229d747b91be6fc00aa165d76143. --- .../java/io/teknek/farsandra/Farsandra.java | 336 ++++++++++++------ .../src/main/resources/farsandra.properties | 4 +- 2 files changed, 235 insertions(+), 105 deletions(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java index 1b53cf7..f986783 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java @@ -41,7 +41,7 @@ public class Farsandra { private List seeds; private CForgroundManager manager; private String javaHome; - private Integer jmxPort; + private Integer jmxPort = 7199; private String maxHeapSize = "256M"; private String heapNewSize = "100M"; private List yamlLinesToAppend; @@ -290,7 +290,7 @@ public void start(){ //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. //String yarn = " -Dcassandra-foreground=yes org.apache.cassandra.service.CassandraDaemon"; - File instanceBase = new File(instanceName); + File instanceBase = new File(cRoot,instanceName); if (cleanInstanceOnStart){ if (instanceBase.exists()){ delete(instanceBase); @@ -302,6 +302,8 @@ public void start(){ File instanceConf; File instanceLog; File instanceData; + File instanceBin; + if (configHolder == null){ instanceConf = new File(instanceBase, "conf"); } else { @@ -319,104 +321,30 @@ public void start(){ } else { instanceData = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.data.dir")); } - instanceData.mkdir(); + instanceData.mkdir(); + if (configHolder == null){ + instanceBin = new File(instanceBase, "bin"); + } else { + instanceBin = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); + } + instanceBin.mkdir(); + copyConfToInstanceDir(cRoot, instanceConf, configHolder); File binaryConf; - File cassandraYaml; + File binaryBin; if (configHolder == null){ binaryConf = new File(cRoot, "conf"); - cassandraYaml = new File(binaryConf, "cassandra.yaml"); + binaryBin = new File(cRoot, "bin"); } else { binaryConf = new File(cRoot, this.getConfigHolder().getProperties().getProperty("farsandra.conf.dir")); - cassandraYaml = new File(binaryConf, this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); + binaryBin = new File(cRoot, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); } setUpLoggingConf(instanceConf, instanceLog); makeCassandraEnv(binaryConf, instanceConf); - - List lines; - try { - lines = Files.readAllLines(cassandraYaml.toPath(), Charset.defaultCharset()); - } catch (IOException e) { - throw new RuntimeException(e); - } - lines = replaceHost(lines); - try { - lines = replaceThisWithThatExpectNMatch(lines, - " - /var/lib/cassandra/data", - " - " + this.instanceName + "/data/data" , 1); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, - "# data_file_directories:", - "data_file_directories:" , 1); - lines = replaceThisWithThatExpectNMatch(lines, - "# - /var/lib/cassandra/data", - " - " + this.instanceName + "/data/data" , 1); - } - lines = replaceThisWithThatExpectNMatch(lines, - "listen_address: localhost", - "listen_address: " +host , 1); - try { - lines = replaceThisWithThatExpectNMatch(lines, - "commitlog_directory: /var/lib/cassandra/commitlog", - "commitlog_directory: " + this.instanceName + "/data/commitlog" , 1 ); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, - "# commitlog_directory: /var/lib/cassandra/commitlog", - "commitlog_directory: " + this.instanceName + "/data/commitlog" , 1 ); - } - try { - lines = replaceThisWithThatExpectNMatch(lines, - "saved_caches_directory: /var/lib/cassandra/saved_caches", - "saved_caches_directory: " + this.instanceName + "/data/saved_caches", 1); - } catch (RuntimeException ex) { - lines = replaceThisWithThatExpectNMatch(lines, - "# saved_caches_directory: /var/lib/cassandra/saved_caches", - "saved_caches_directory: " + this.instanceName + "/data/saved_caches", 1); - } - try { - lines = replaceThisWithThatExpectNMatch(lines, - "start_rpc: false", - "start_rpc: true", 1); - } catch (RuntimeException ex) { - // Only needed for C* 2.2+ - } - if (storagePort != null){ - lines = replaceThisWithThatExpectNMatch(lines, "storage_port: 7000", "storage_port: "+storagePort, 1 ); - } - if (rpcPort != null){ - lines = replaceThisWithThatExpectNMatch(lines, "rpc_port: 9160", "rpc_port: " + rpcPort, 1); - } - if (nativeTransportPort != null){ - lines = replaceThisWithThatExpectNMatch(lines, "native_transport_port: 9042", "native_transport_port: "+nativeTransportPort, 1 ); - } - if (seeds != null) { - lines = replaceThisWithThatExpectNMatch(lines, " - seeds: \"127.0.0.1\"", - " - seeds: \"" + seeds.get(0) + "\"", 1); - } - for (Map.Entry entry: yamlReplacements.entrySet()){ - lines = replaceThisWithThatExpectNMatch(lines, entry.getKey(), entry.getValue(), 1); - } - lines = yamlLinesToAppend(lines); - File instanceConfToWrite; - if (configHolder == null){ - instanceConfToWrite = new File(instanceConf, "cassandra.yaml"); - } else { - instanceConfToWrite = new File(instanceConf, this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); - } - try (BufferedWriter bw = new BufferedWriter(new FileWriter(instanceConfToWrite))){ - for (String s: lines){ - bw.write(s); - bw.newLine(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } + makeCassandraBat(binaryBin, instanceBin, instanceConf); + makeCassandraYaml(cRoot, binaryConf, instanceConf); } - // /bin/bash -c "env - X=5 y=2 sh xandy.sh" - //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc - //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. - File cstart = new File(new File( cRoot, "bin"),"cassandra"); /*String launch = "/bin/bash -c \"/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath() +" JAVA_HOME="+ "/usr/java/jdk1.7.0_45 " @@ -427,19 +355,52 @@ public void start(){ } else { instanceConf = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.conf.dir")); } - String command = "/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath(); - //command = command + " JAVA_HOME=" + "/usr/java/jdk1.7.0_45 "; - command = command + buildJavaHome() + " "; - command = command + " /bin/bash " + cstart.getAbsolutePath().toString() + " -f "; - String [] launchArray = new String [] { - "/bin/bash" , - "-c" , - command }; - manager.setLaunchArray(launchArray); - manager.go(); + + if (isWindows()) + { + File instanceBin; + if (configHolder == null){ + instanceBin = new File(instanceBase, "bin"); + } else { + instanceBin = new File(instanceBase, this.getConfigHolder().getProperties().getProperty("farsandra.bin.dir")); + } + + File cstart = new File(instanceBin, "cassandra.bat"); + String[] envArray = new String[] {"CASSANDRA_CONF="+instanceConf.getAbsolutePath(), + buildJavaHome(), + "PATH=" + instanceBin.getAbsolutePath(), + "CASSANDRA_HOME="+cRoot.getAbsolutePath()}; +// String[] commandArray = new String[] { "cmd", "/C", "set"}; + String[] commandArray = new String[] { "cmd", "/C", cstart.getAbsolutePath(), "-f"}; + manager.setEvnArray(envArray); + manager.setLaunchArray(commandArray); + } + else + { + // /bin/bash -c "env - X=5 y=2 sh xandy.sh" + //# JVM_OPTS -- Additional arguments to the JVM for heap size, etc + //# CASSANDRA_CONF -- Directory containing Cassandra configuration files. + File cstart = new File(new File( cRoot, "bin"),"cassandra"); + + String command = "/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath(); + //command = command + " JAVA_HOME=" + "/usr/java/jdk1.7.0_45 "; + command = command + " " + buildJavaHome(); + command = command + " /bin/bash " + cstart.getAbsolutePath().toString() + " -f "; + String [] launchArray = new String [] { + "/bin/bash" , + "-c" , + command }; + manager.setLaunchArray(launchArray); + } + manager.go(); } + private boolean isWindows() { + String os = System.getProperty("os.name"); + return os.contains("Windows"); + } + /** * Replaces the default file path of the system log. * Cassandra comes with a log4j configuration that assumes, by default, there's a /var/log/cassandra directory @@ -466,13 +427,21 @@ private void setUpLoggingConf(final File instanceConfDirectory, log4ServerProperties.toPath(), Charset.defaultCharset()); writer = new BufferedWriter(new FileWriter(log4ServerProperties)); for (final String line : lines) { - writer.write( - (line.startsWith(log4jAppenderConfLine) ? log4jAppenderConfLine - .concat("=").concat(systemLog.getAbsolutePath()) : line)); + if (line.startsWith(log4jAppenderConfLine)) { + if (isWindows()) { + writer.write(log4jAppenderConfLine + "=" + systemLog.getAbsolutePath().replace("\\", "/")); + } else { + writer.write(log4jAppenderConfLine + "=" + systemLog.getAbsolutePath()); + } + } else { + writer.write(line); + } writer.newLine(); } } catch (final IOException exception) { throw new RuntimeException(exception); + } catch (final Exception e) { + LOGGER.error("Exception writing log4j-server.properties: " + e.getMessage()); } finally { if (writer != null) { try { @@ -574,12 +543,153 @@ private void makeCassandraEnv(File binaryConf, File instanceConf) { throw new RuntimeException(e); } } + + /** + * Builds the cassandra.yaml replacing stuff along the way + * @param binaryConf directory of downloaded conf + * @param instanceConf directory for conf to be generated + */ + private void makeCassandraYaml(File root, File binaryConf, File instanceConf) { + List lines; + File cassandraYaml; + String fullPath = root.getAbsolutePath() + "\\" + this.instanceName; + + if (configHolder == null) { + cassandraYaml = new File(binaryConf, "cassandra.yaml"); + } else { + cassandraYaml = new File(binaryConf, + this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); + } + try { + lines = Files.readAllLines(cassandraYaml.toPath(), Charset.defaultCharset()); + } catch (IOException e) { + throw new RuntimeException(e); + } + lines = replaceHost(lines); + try { + lines = replaceThisWithThatExpectNMatch(lines, " - /var/lib/cassandra/data", + " - " + fullPath + "/data/data", 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, "# data_file_directories:", "data_file_directories:", 1); + lines = replaceThisWithThatExpectNMatch(lines, "# - /var/lib/cassandra/data", + " - " + fullPath + "/data/data", 1); + } + lines = replaceThisWithThatExpectNMatch(lines, "listen_address: localhost", "listen_address: " + host, 1); + try { + lines = replaceThisWithThatExpectNMatch(lines, "commitlog_directory: /var/lib/cassandra/commitlog", + "commitlog_directory: " + fullPath + "/data/commitlog", 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, "# commitlog_directory: /var/lib/cassandra/commitlog", + "commitlog_directory: " + fullPath + "/data/commitlog", 1); + } + try { + lines = replaceThisWithThatExpectNMatch(lines, "saved_caches_directory: /var/lib/cassandra/saved_caches", + "saved_caches_directory: " + fullPath + "/data/saved_caches", 1); + } catch (RuntimeException ex) { + lines = replaceThisWithThatExpectNMatch(lines, "# saved_caches_directory: /var/lib/cassandra/saved_caches", + "saved_caches_directory: " + fullPath + "/data/saved_caches", 1); + } + try { + lines = replaceThisWithThatExpectNMatch(lines, "start_rpc: false", "start_rpc: true", 1); + } catch (RuntimeException ex) { + // Only needed for C* 2.2+ + } + if (storagePort != null) { + lines = replaceThisWithThatExpectNMatch(lines, "storage_port: 7000", "storage_port: " + storagePort, 1); + } + if (rpcPort != null) { + lines = replaceThisWithThatExpectNMatch(lines, "rpc_port: 9160", "rpc_port: " + rpcPort, 1); + } + if (nativeTransportPort != null) { + lines = replaceThisWithThatExpectNMatch(lines, "native_transport_port: 9042", + "native_transport_port: " + nativeTransportPort, 1); + } + if (seeds != null) { + lines = replaceThisWithThatExpectNMatch(lines, " - seeds: \"127.0.0.1\"", + " - seeds: \"" + seeds.get(0) + "\"", 1); + } + for (Map.Entry entry : yamlReplacements.entrySet()) { + lines = replaceThisWithThatExpectNMatch(lines, entry.getKey(), entry.getValue(), 1); + } + lines = yamlLinesToAppend(lines); + File instanceConfToWrite; + if (configHolder == null) { + instanceConfToWrite = new File(instanceConf, "cassandra.yaml"); + } else { + instanceConfToWrite = new File(instanceConf, + this.getConfigHolder().getProperties().getProperty("cassandra.config.file.name")); + } + try (BufferedWriter bw = new BufferedWriter(new FileWriter(instanceConfToWrite))) { + for (String s : lines) { + bw.write(s); + bw.newLine(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Builds the cassandra.bat replacing stuff along the way + * @param binaryBin directory of downloaded bin + * @param instanceBin directory for bin to be generated + */ + private void makeCassandraBat(File binaryBin, File instanceBin, File instanceConf) { + String fileName; + if (configHolder == null) { + fileName = "cassandra.bat"; + } else { + fileName = this.getConfigHolder().getProperties().getProperty("cassandra.batch.file.name"); + } + File batchFile = new File(binaryBin, fileName); + List lines; + try { + lines = Files.readAllLines(batchFile.toPath(), Charset.defaultCharset()); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (jmxPort != null) { + lines = replaceSubstringThisWithThatExpectNMatch(lines, "jmxremote.port=7199", "jmxremote.port=" + this.jmxPort, + 1); + } + + lines = replaceSubstringThisWithThatExpectNMatch(lines, "%JAVA_OPTS% %CASSANDRA_PARAMS% -cp", + "%JAVA_OPTS% " + "-Dorg.xerial.snappy.tempdir=\"" + instanceBin.getAbsolutePath() + "\"" + " %CASSANDRA_PARAMS% -cp", 1); + + // Cassandra 1.2.x + if (maxHeapSize != null) { + lines = replaceSubstringThisWithThatExpectNMatch(lines, "-Xms1G", "-Xms" + this.maxHeapSize, 1); + } + + // NEW HEAP SIZE not supported by Windows // TODO + + // if (heapNewSize != null) { + // lines = replaceSubstringThisWithThatExpectNMatch(lines, "-Xmx1G", "-Xmx" + // + heapNewSize, 1); + // } + + // Windows doesn't support the CASSANDRA_CONF environment variable, so put + // our instance configuration + // directory first in the classpath. + + lines = replaceSubstringThisWithThatExpectNMatch(lines, "-cp %CASSANDRA_CLASSPATH%", + "-cp " + instanceConf.getAbsolutePath() + ";%CASSANDRA_CLASSPATH%", 1); + + try (BufferedWriter bw = new BufferedWriter(new FileWriter(new File(instanceBin, fileName)))) { + for (String s : lines) { + bw.write(s); + bw.newLine(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } public String buildJavaHome() { if (this.javaHome != null) { - return " JAVA_HOME=" + this.javaHome; + return "JAVA_HOME=" + this.javaHome; } else if (System.getenv("JAVA_HOME") != null) { - return " JAVA_HOME=" + System.getenv("JAVA_HOME"); + return "JAVA_HOME=" + System.getenv("JAVA_HOME"); } else { return ""; } @@ -594,6 +704,24 @@ void delete(File f) { throw new RuntimeException("Failed to delete file: " + f); } + public List replaceSubstringThisWithThatExpectNMatch(List lines, String match, String replace, int expectedMatches){ + List result = new ArrayList(); + int replaced = 0; + for (String line: lines){ + if (!line.contains(match)){ + result.add(line); + } else{ + replaced++; + result.add(line.replace(match, replace)); + } + } + if (replaced != expectedMatches){ + throw new RuntimeException("looking to make " + expectedMatches +" of ('" + match + "')->'(" + replace + "') but made "+replaced + +" . Likely that farsandra does not understand this version of configuration file. "); + } + return result; + } + public List replaceThisWithThatExpectNMatch(List lines, String match, String replace, int expectedMatches){ List result = new ArrayList(); int replaced = 0; diff --git a/farsandra-core/src/main/resources/farsandra.properties b/farsandra-core/src/main/resources/farsandra.properties index c5bbde1..adcf0f8 100644 --- a/farsandra-core/src/main/resources/farsandra.properties +++ b/farsandra-core/src/main/resources/farsandra.properties @@ -4,7 +4,9 @@ cassandra.package.name.suffix=-bin.tar.gz cassandra.package.dist.site=http://archive.apache.org/dist/cassandra/ cassandra.config.file.name=cassandra.yaml cassandra.environment.file.name=cassandra-env.sh +cassandra.batch.file.name=cassandra.bat farsandra.home.folder=.farsandra farsandra.conf.dir=conf farsandra.log.dir=log -farsandra.data.dir=data \ No newline at end of file +farsandra.data.dir=data +farsandra.bin.dir=bin \ No newline at end of file From 98a9a177e9ad91735443a9822b6646350b9efed3 Mon Sep 17 00:00:00 2001 From: hancockks Date: Thu, 21 Jul 2016 08:29:26 -0400 Subject: [PATCH 04/14] Add support for Windows Need to kill Cassandra process manually as Process.destroy() does not kill child processes in Windows. --- .../teknek/farsandra/CForgroundManager.java | 83 ++++++++++++++++++- .../java/io/teknek/farsandra/Farsandra.java | 2 +- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java index 20f736c..c3f770c 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java @@ -1,7 +1,10 @@ package io.teknek.farsandra; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -19,6 +22,7 @@ public class CForgroundManager { private static Logger LOGGER = Logger.getLogger(CForgroundManager.class); private String [] launchArray; + private String [] envArray = null; private Process process; /** * The exit value of the forked process. Initialized to 9999. @@ -51,6 +55,16 @@ public void setLaunchArray(String[] launchArray) { } + /** + * Set the fork command environment variables + + * @param envArray + */ + public void setEvnArray(String[] envArray) { + this.envArray = envArray; + } + + /** * Add a handler for system out events @@ -86,10 +100,18 @@ public void go() { * String launch = "/bin/bash -c \"env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath() * +" JAVA_HOME="+ "/usr/java/jdk1.7.0_45 " + cstart.getAbsolutePath().toString() + " -f \""; */ - LOGGER.debug(Arrays.asList(this.launchArray)); + LOGGER.debug("ENVIRONMENT: " + Arrays.asList(this.envArray)); + LOGGER.debug("LAUNCH COMANDS: " + Arrays.asList(this.launchArray)); Runtime rt = Runtime.getRuntime(); try { - process = rt.exec(launchArray); + if (envArray != null) + { + process = rt.exec(launchArray,envArray); + } + else + { + process = rt.exec(launchArray); + } } catch (IOException e1) { LOGGER.error(e1.getMessage()); throw new RuntimeException(e1); @@ -129,7 +151,62 @@ public void run() { * End the process but do not wait for shutdown latch. Non blocking */ public void destroy(){ - process.destroy(); + if (isWindows()) { + + // Unlike in unix killing a process does not kill any child processes. + // In order to destroy our Cassandra java process, we'll use wimc to query + // for a java process with our instance name in the classpath. + String confPath = null; + for (String s : envArray) + { + if (s.contains("CASSANDRA_CONF")) { + confPath = s.split("=")[1]; + + // wimc requires paths to be double-quoted backslashes. + String wmicKill = "wmic PROCESS where " + + "\"" + "name like '%java%' and CommandLine like " + + "'%" + confPath.replace("\\", "\\\\") + "%' and " + + "CommandLine like '%CassandraDaemon%'" + "\"" + + " call Terminate"; + try { + Process p = Runtime.getRuntime().exec(wmicKill); + p.getOutputStream().close(); + int exitCode = p.exitValue(); + if (exitCode == 0) { + LOGGER.info("Cassandra process destroyed."); + }else { + LOGGER.error("Non-zero exit code from killing the cassandra process."); + } + + } catch (IOException e) { + LOGGER.error("Could not kill the Cassandra java child process"); + } + break; + } + } + if (confPath == null) { + LOGGER.error("Could not locate and kill java child process"); + } + + process.destroy(); + try { + process.waitFor(); + } catch (InterruptedException e) { + ; // nothing to do + } + } else { + process.destroy(); + } + } + /** + * Determines if the operating system is Windows + * + * @return a boolean value indicating if we're on Windows OS + */ + + private boolean isWindows() { + String os = System.getProperty("os.name"); + return os.contains("Windows"); } /** diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java index f986783..17ddc6f 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java @@ -41,7 +41,7 @@ public class Farsandra { private List seeds; private CForgroundManager manager; private String javaHome; - private Integer jmxPort = 7199; + private Integer jmxPort; private String maxHeapSize = "256M"; private String heapNewSize = "100M"; private List yamlLinesToAppend; From 1a34a3a63883d52ec29d6d63e9cb211c69ab1291 Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 08:07:16 -0400 Subject: [PATCH 05/14] Fix properties in farsandra-test --- .../src/main/java/io/teknek/farsandra/CForgroundManager.java | 3 --- farsandra-core/src/test/resources/farsandra.properties | 3 ++- farsandra-core/src/test/resources/farsandra_custom.properties | 3 ++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java index c3f770c..44c4b4d 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java @@ -1,10 +1,7 @@ package io.teknek.farsandra; -import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/farsandra-core/src/test/resources/farsandra.properties b/farsandra-core/src/test/resources/farsandra.properties index c5bbde1..9496606 100644 --- a/farsandra-core/src/test/resources/farsandra.properties +++ b/farsandra-core/src/test/resources/farsandra.properties @@ -7,4 +7,5 @@ cassandra.environment.file.name=cassandra-env.sh farsandra.home.folder=.farsandra farsandra.conf.dir=conf farsandra.log.dir=log -farsandra.data.dir=data \ No newline at end of file +farsandra.data.dir=data +farsandra.bin.dir=bin \ No newline at end of file diff --git a/farsandra-core/src/test/resources/farsandra_custom.properties b/farsandra-core/src/test/resources/farsandra_custom.properties index c5bbde1..9496606 100644 --- a/farsandra-core/src/test/resources/farsandra_custom.properties +++ b/farsandra-core/src/test/resources/farsandra_custom.properties @@ -7,4 +7,5 @@ cassandra.environment.file.name=cassandra-env.sh farsandra.home.folder=.farsandra farsandra.conf.dir=conf farsandra.log.dir=log -farsandra.data.dir=data \ No newline at end of file +farsandra.data.dir=data +farsandra.bin.dir=bin \ No newline at end of file From a3da7b9074f0097b691a8c7faec1885ca0ff4e18 Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 10:33:49 -0400 Subject: [PATCH 06/14] Add unit test for Cassandra 1.2.19 --- .../TestFarsandraWithDefaultConfig.java | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/farsandra-core/src/test/java/io/teknek/farsandra/TestFarsandraWithDefaultConfig.java b/farsandra-core/src/test/java/io/teknek/farsandra/TestFarsandraWithDefaultConfig.java index 46acc89..b9f2888 100644 --- a/farsandra-core/src/test/java/io/teknek/farsandra/TestFarsandraWithDefaultConfig.java +++ b/farsandra-core/src/test/java/io/teknek/farsandra/TestFarsandraWithDefaultConfig.java @@ -78,7 +78,7 @@ public void handleTermination(int exitValue) { } @Test - public void simpleTest() throws InterruptedException { + public void simpleTestWith224() throws InterruptedException { fs.withVersion("2.2.4"); fs.withCleanInstanceOnStart(true); fs.withInstanceName("target/1"); @@ -118,4 +118,46 @@ public void handleTermination(int exitValue) { System.out.println("Thrift open. Party time!"); fs.getManager().destroyAndWaitForShutdown(10); } + + @Test + public void simpleTestWith1219() throws InterruptedException { + fs.withVersion("1.2.19"); + fs.withCleanInstanceOnStart(true); + fs.withInstanceName("target/1"); + fs.withCreateConfigurationFiles(true); + fs.withHost("localhost"); + fs.withSeeds(Arrays.asList("localhost")); + final CountDownLatch started = new CountDownLatch(1); + final AtomicBoolean thriftOpen = new AtomicBoolean(false); + fs.getManager().addOutLineHandler( new LineHandler(){ + @Override + public void handleLine(String line) { + System.out.println("out "+line); + if (line.contains("Listening for thrift clients...")){ + started.countDown(); + thriftOpen.set(true); + } + } + } + ); + fs.getManager().addErrLineHandler( new LineHandler(){ + @Override + public void handleLine(String line) { + System.out.println("err "+line); + } + }); + fs.getManager().addProcessHandler(new ProcessHandler() { + @Override + public void handleTermination(int exitValue) { + System.out.println("Cassandra terminated with exit value: " + exitValue); + started.countDown(); + } + }); + fs.start(); + started.await(); + assertTrue("Thrift didn't started", thriftOpen.get()); + assertTrue("Cassandra is not running", fs.getManager().isRunning()); + System.out.println("Thrift open. Party time!"); + fs.getManager().destroyAndWaitForShutdown(10); + } } From ee42fac042847ceb6c510b28e3e53f4de87642e0 Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 10:34:21 -0400 Subject: [PATCH 07/14] Fix Windows wimc shutdown -- wait for process termination before getting exit code --- .../src/main/java/io/teknek/farsandra/CForgroundManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java index 44c4b4d..4fb28af 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java @@ -168,6 +168,7 @@ public void destroy(){ try { Process p = Runtime.getRuntime().exec(wmicKill); p.getOutputStream().close(); + p.waitFor(10, TimeUnit.SECONDS); int exitCode = p.exitValue(); if (exitCode == 0) { LOGGER.info("Cassandra process destroyed."); @@ -175,7 +176,7 @@ public void destroy(){ LOGGER.error("Non-zero exit code from killing the cassandra process."); } - } catch (IOException e) { + } catch (IOException | InterruptedException e) { LOGGER.error("Could not kill the Cassandra java child process"); } break; From 2f33f15df654e661acb2c8881778fbaaa2c15e10 Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 10:35:14 -0400 Subject: [PATCH 08/14] Fix missing properties for cassandra batch file name --- farsandra-core/src/test/resources/farsandra.properties | 1 + farsandra-core/src/test/resources/farsandra_custom.properties | 1 + 2 files changed, 2 insertions(+) diff --git a/farsandra-core/src/test/resources/farsandra.properties b/farsandra-core/src/test/resources/farsandra.properties index 9496606..adcf0f8 100644 --- a/farsandra-core/src/test/resources/farsandra.properties +++ b/farsandra-core/src/test/resources/farsandra.properties @@ -4,6 +4,7 @@ cassandra.package.name.suffix=-bin.tar.gz cassandra.package.dist.site=http://archive.apache.org/dist/cassandra/ cassandra.config.file.name=cassandra.yaml cassandra.environment.file.name=cassandra-env.sh +cassandra.batch.file.name=cassandra.bat farsandra.home.folder=.farsandra farsandra.conf.dir=conf farsandra.log.dir=log diff --git a/farsandra-core/src/test/resources/farsandra_custom.properties b/farsandra-core/src/test/resources/farsandra_custom.properties index 9496606..adcf0f8 100644 --- a/farsandra-core/src/test/resources/farsandra_custom.properties +++ b/farsandra-core/src/test/resources/farsandra_custom.properties @@ -4,6 +4,7 @@ cassandra.package.name.suffix=-bin.tar.gz cassandra.package.dist.site=http://archive.apache.org/dist/cassandra/ cassandra.config.file.name=cassandra.yaml cassandra.environment.file.name=cassandra-env.sh +cassandra.batch.file.name=cassandra.bat farsandra.home.folder=.farsandra farsandra.conf.dir=conf farsandra.log.dir=log From 1c88e69f3b2c2191237b6a63996b2ec5cb2c7028 Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 10:36:23 -0400 Subject: [PATCH 09/14] Remove default JVM sizes; fix windows maxHeapSize for Cassandra 2.2.x; refactor adding JvmOptions for Windows; add temp dir for jni --- .../java/io/teknek/farsandra/Farsandra.java | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java index 17ddc6f..d7703b6 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java @@ -42,8 +42,8 @@ public class Farsandra { private CForgroundManager manager; private String javaHome; private Integer jmxPort; - private String maxHeapSize = "256M"; - private String heapNewSize = "100M"; + private String maxHeapSize; + private String heapNewSize; private List yamlLinesToAppend; private List envLinesToAppend; private Map envReplacements; @@ -298,7 +298,10 @@ public void start(){ } if (createConfigurationFiles){ - instanceBase.mkdir(); + boolean created = instanceBase.mkdirs(); + if (!created) { + LOGGER.error("Could not create base directory for instance " + instanceBase.getAbsolutePath()); + } File instanceConf; File instanceLog; File instanceData; @@ -653,14 +656,27 @@ private void makeCassandraBat(File binaryBin, File instanceBin, File instanceCon 1); } - lines = replaceSubstringThisWithThatExpectNMatch(lines, "%JAVA_OPTS% %CASSANDRA_PARAMS% -cp", - "%JAVA_OPTS% " + "-Dorg.xerial.snappy.tempdir=\"" + instanceBin.getAbsolutePath() + "\"" + " %CASSANDRA_PARAMS% -cp", 1); + + lines = addJvmOpt(lines, "-Dorg.xerial.snappy.tempdir=" + "\"" + instanceBin.getAbsolutePath() + "\""); + lines = addJvmOpt(lines, "-Djava.io.tmpdir=" + "\"" + instanceBin.getAbsolutePath() + "\""); - // Cassandra 1.2.x if (maxHeapSize != null) { - lines = replaceSubstringThisWithThatExpectNMatch(lines, "-Xms1G", "-Xms" + this.maxHeapSize, 1); + String[] batchFileXms = {"-Xmx1G", "-Xmx2G" }; + boolean replaced = false; + for (int i = 0; i < batchFileXms.length; i++) { + try { + lines = replaceSubstringThisWithThatExpectNMatch(lines, batchFileXms[i], "-Xmx" + this.maxHeapSize, 1); + replaced = true; + break; + } + catch (Exception e) { + if (i == batchFileXms.length - 1) { + throw e; + } + } + } } - + // NEW HEAP SIZE not supported by Windows // TODO // if (heapNewSize != null) { @@ -740,6 +756,19 @@ public List replaceThisWithThatExpectNMatch(List lines, String m return result; } + // For Windows only + protected List addJvmOpt(List lines, String opt) { + List result = new ArrayList(); + for (String line : lines) { + if (!line.equals("echo Starting Cassandra Server")) { + result.add(line); + } else { + result.add("set JAVA_OPTS=%JAVA_OPTS% " + opt); + result.add(line); + } + } + return result; + } public List replaceHost(List lines){ List result = new ArrayList(); From 50e832e18924fbe32ddaf5c85bbe25b987b3f0ba Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 10:40:21 -0400 Subject: [PATCH 10/14] Fix compiler warnings --- .../src/main/java/io/teknek/farsandra/Farsandra.java | 4 +--- .../main/java/io/teknek/farsandra/config/ConfigHolder.java | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java index d7703b6..20bdcd0 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java @@ -388,7 +388,7 @@ public void start(){ String command = "/usr/bin/env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath(); //command = command + " JAVA_HOME=" + "/usr/java/jdk1.7.0_45 "; command = command + " " + buildJavaHome(); - command = command + " /bin/bash " + cstart.getAbsolutePath().toString() + " -f "; + command = command + " /bin/bash " + cstart.getAbsolutePath() + " -f "; String [] launchArray = new String [] { "/bin/bash" , "-c" , @@ -662,11 +662,9 @@ private void makeCassandraBat(File binaryBin, File instanceBin, File instanceCon if (maxHeapSize != null) { String[] batchFileXms = {"-Xmx1G", "-Xmx2G" }; - boolean replaced = false; for (int i = 0; i < batchFileXms.length; i++) { try { lines = replaceSubstringThisWithThatExpectNMatch(lines, batchFileXms[i], "-Xmx" + this.maxHeapSize, 1); - replaced = true; break; } catch (Exception e) { diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/config/ConfigHolder.java b/farsandra-core/src/main/java/io/teknek/farsandra/config/ConfigHolder.java index 1e21dc9..6618a62 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/config/ConfigHolder.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/config/ConfigHolder.java @@ -1,6 +1,5 @@ package io.teknek.farsandra.config; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Properties; From 3f4ecd05757e3bcf552a8cb7d6cf0c0dc1613484 Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 11:38:46 -0400 Subject: [PATCH 11/14] Fix for JRE 7 --- .../src/main/java/io/teknek/farsandra/CForgroundManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java index 4fb28af..9f823f9 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java @@ -168,7 +168,7 @@ public void destroy(){ try { Process p = Runtime.getRuntime().exec(wmicKill); p.getOutputStream().close(); - p.waitFor(10, TimeUnit.SECONDS); + p.waitFor(); int exitCode = p.exitValue(); if (exitCode == 0) { LOGGER.info("Cassandra process destroyed."); From ed5ca0d8e512bda491651baaf6ab6dce3e054a1b Mon Sep 17 00:00:00 2001 From: hancockks Date: Mon, 25 Jul 2016 13:21:17 -0400 Subject: [PATCH 12/14] Fix NPE on debug logging --- .../src/main/java/io/teknek/farsandra/CForgroundManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java index 9f823f9..abbcc89 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java @@ -97,8 +97,10 @@ public void go() { * String launch = "/bin/bash -c \"env - CASSANDRA_CONF=" + instanceConf.getAbsolutePath() * +" JAVA_HOME="+ "/usr/java/jdk1.7.0_45 " + cstart.getAbsolutePath().toString() + " -f \""; */ - LOGGER.debug("ENVIRONMENT: " + Arrays.asList(this.envArray)); LOGGER.debug("LAUNCH COMANDS: " + Arrays.asList(this.launchArray)); + if (this.envArray != null) { + LOGGER.debug("ENVIRONMENT: " + Arrays.asList(this.envArray)); + } Runtime rt = Runtime.getRuntime(); try { if (envArray != null) From c2a982fae94207f8ad6c46577d98cdfc506de2fa Mon Sep 17 00:00:00 2001 From: hancockks Date: Wed, 3 Aug 2016 11:22:56 -0400 Subject: [PATCH 13/14] Move Windows equivalent of process.destroy() into its own method --- .gitignore | 9 +- .../teknek/farsandra/CForgroundManager.java | 90 ++++++++++--------- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/.gitignore b/.gitignore index 842d14a..febba60 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,11 @@ hs_err_pid* cachefile # PMD -.pmd \ No newline at end of file +.pmd +*.bak +farsandra-core/ivy.xml +farsandra-core/src/test/ivy.xml +farsandra-core/src/test/bin/farsandra.properties +farsandra-core/src/test/bin/farsandra_custom.properties +farsandra-core/src/test/bin/log4j.xml +farsandra-core/src/test/resources/log4j.xml \ No newline at end of file diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java index abbcc89..9faadec 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/CForgroundManager.java @@ -146,58 +146,62 @@ public void run() { errstreamThread.start(); } + public void windowsDestroy() { + + // Unlike in unix killing a process does not kill any child processes. + // In order to destroy our Cassandra java process, we'll use wimc to query + // for a java process with our instance name in the classpath. + String confPath = null; + for (String s : envArray) + { + if (s.contains("CASSANDRA_CONF")) { + confPath = s.split("=")[1]; + + // wimc requires paths to be double-quoted backslashes. + String wmicKill = "wmic PROCESS where " + + "\"" + "name like '%java%' and CommandLine like " + + "'%" + confPath.replace("\\", "\\\\") + "%' and " + + "CommandLine like '%CassandraDaemon%'" + "\"" + + " delete"; + try { + Process p = Runtime.getRuntime().exec(wmicKill); + p.getOutputStream().close(); + p.waitFor(); + int exitCode = p.exitValue(); + if (exitCode == 0) { + LOGGER.info("Cassandra process destroyed."); + }else { + LOGGER.error("Non-zero exit code from killing the cassandra process."); + } + + } catch (IOException | InterruptedException e) { + LOGGER.error("Could not kill the Cassandra java child process"); + } + break; + } + } + if (confPath == null) { + LOGGER.error("Could not locate and kill java child process"); + } + process.destroy(); + try { + process.waitFor(); + } catch (InterruptedException e) { + ; // nothing to do + } + } + /** * End the process but do not wait for shutdown latch. Non blocking */ public void destroy(){ if (isWindows()) { - - // Unlike in unix killing a process does not kill any child processes. - // In order to destroy our Cassandra java process, we'll use wimc to query - // for a java process with our instance name in the classpath. - String confPath = null; - for (String s : envArray) - { - if (s.contains("CASSANDRA_CONF")) { - confPath = s.split("=")[1]; - - // wimc requires paths to be double-quoted backslashes. - String wmicKill = "wmic PROCESS where " + - "\"" + "name like '%java%' and CommandLine like " + - "'%" + confPath.replace("\\", "\\\\") + "%' and " + - "CommandLine like '%CassandraDaemon%'" + "\"" + - " call Terminate"; - try { - Process p = Runtime.getRuntime().exec(wmicKill); - p.getOutputStream().close(); - p.waitFor(); - int exitCode = p.exitValue(); - if (exitCode == 0) { - LOGGER.info("Cassandra process destroyed."); - }else { - LOGGER.error("Non-zero exit code from killing the cassandra process."); - } - - } catch (IOException | InterruptedException e) { - LOGGER.error("Could not kill the Cassandra java child process"); - } - break; - } - } - if (confPath == null) { - LOGGER.error("Could not locate and kill java child process"); - } - - process.destroy(); - try { - process.waitFor(); - } catch (InterruptedException e) { - ; // nothing to do - } + windowsDestroy(); } else { process.destroy(); } } + /** * Determines if the operating system is Windows * From a786cf25d740fe9096868a23b85b52725a738d95 Mon Sep 17 00:00:00 2001 From: hancockks Date: Wed, 3 Aug 2016 11:23:18 -0400 Subject: [PATCH 14/14] Retry instance deletion on Windows as locks may take time to be released. --- .../java/io/teknek/farsandra/Farsandra.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java index 20bdcd0..1947e56 100644 --- a/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java +++ b/farsandra-core/src/main/java/io/teknek/farsandra/Farsandra.java @@ -293,7 +293,28 @@ public void start(){ File instanceBase = new File(cRoot,instanceName); if (cleanInstanceOnStart){ if (instanceBase.exists()){ - delete(instanceBase); + boolean retried = false; + while (true) { + // We retry if an instanceBase is reused, there may be some + // latency from killing the process (in Windows) to when the + // file locks are released. + try { + delete(instanceBase); + break; + } + catch (Exception e) { + if (retried == false) { + retried = true; + try { + Thread.sleep(2000); + } catch (InterruptedException e1) { + ; + } + } else { + throw e; + } + } + } } }