arjunashok commented on code in PR #277:
URL: https://github.com/apache/cassandra-sidecar/pull/277#discussion_r2570460153
##########
server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java:
##########
@@ -18,38 +18,232 @@
package org.apache.cassandra.sidecar.lifecycle;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.jetbrains.annotations.VisibleForTesting;
/**
- * A {@link LifecycleProvider} that manages Cassandra instances as OS
processes.
- * <p>
- * This implementation is a placeholder and is not yet implemented.
+ * Manage the lifecycle of Cassandra instances running on local processes
*/
public class ProcessLifecycleProvider implements LifecycleProvider
{
+ static final String OPT_CASSANDRA_HOME = "cassandra_home";
+ static final String OPT_CASSANDRA_CONF_DIR = "cassandra_conf_dir";
+ static final String OPT_CASSANDRA_LOG_DIR = "cassandra_log_dir";
+ static final String OPT_STATE_DIR = "state_dir";
+
+ protected static final Logger LOG =
LoggerFactory.getLogger(ProcessLifecycleProvider.class);
+ public static final long CASSANDRA_PROCESS_TIMEOUT_MS =
Long.getLong("cassandra.sidecar.lifecycle.process.timeout.ms", 120_000L);
+
+ private final String lifecycleDir;
+ private final String defaultCassandraHome;
+ private final Map<String, String> defaultJvmProperties = new HashMap<>();
+ private final Map<String, String> defaultEnvVars = new HashMap<>();
+
public ProcessLifecycleProvider(Map<String, String> params)
{
- // Params unused for now
+ // Extract any JVM properties or environment variables from the params
+ for (Map.Entry<String, String> entry : params.entrySet())
+ {
+ if (entry.getKey().startsWith("cassandra."))
+ {
+ defaultJvmProperties.put(entry.getKey(), entry.getValue());
+ }
+ else if (entry.getKey().startsWith("env."))
+ {
+ defaultEnvVars.put(entry.getKey().replaceAll("env.", ""),
entry.getValue());
+ }
+ }
+ this.lifecycleDir = params.get(OPT_STATE_DIR);
+ this.defaultCassandraHome = params.get(OPT_CASSANDRA_HOME);
+ if (lifecycleDir == null || lifecycleDir.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_STATE_DIR + "' must be set for ProcessLifecycleProvider");
+ }
+ if (defaultCassandraHome == null || defaultCassandraHome.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_CASSANDRA_HOME + "' must be set for ProcessLifecycleProvider");
+ }
}
@Override
public void start(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ if (isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already running.",
instance.host());
+ return;
+ }
+ startCassandra(instance);
}
@Override
public void stop(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
-
+ if (!isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already stopped.",
instance.host());
+ return;
+ }
+ stopCassandra(instance);
}
@Override
public boolean isRunning(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ return isCassandraProcessRunning(instance);
+ }
+
+ private void startCassandra(InstanceMetadata instance)
+ {
+ ProcessRuntimeConfiguration runtimeConfig =
getRuntimeConfiguration(instance);
+ try
+ {
+ String stdoutLocation =
getStdoutLocation(runtimeConfig.instanceName());
+ String stderrLocation =
getStderrLocation(runtimeConfig.instanceName());
+ String pidFileLocation =
getPidFileLocation(runtimeConfig.instanceName());
+ ProcessBuilder processBuilder =
runtimeConfig.buildStartCommand(pidFileLocation,
Review Comment:
Seems like the additional files created here - stdout/stderr - are
appended-to without rotation/cleanup and could result in disk space issues.
Also, there is a possibility of stale PID files if the process terminates
abnormally. We would need some cleanup mechanism for such cases.
##########
server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java:
##########
@@ -18,38 +18,232 @@
package org.apache.cassandra.sidecar.lifecycle;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.jetbrains.annotations.VisibleForTesting;
/**
- * A {@link LifecycleProvider} that manages Cassandra instances as OS
processes.
- * <p>
- * This implementation is a placeholder and is not yet implemented.
+ * Manage the lifecycle of Cassandra instances running on local processes
*/
public class ProcessLifecycleProvider implements LifecycleProvider
{
+ static final String OPT_CASSANDRA_HOME = "cassandra_home";
+ static final String OPT_CASSANDRA_CONF_DIR = "cassandra_conf_dir";
+ static final String OPT_CASSANDRA_LOG_DIR = "cassandra_log_dir";
+ static final String OPT_STATE_DIR = "state_dir";
+
+ protected static final Logger LOG =
LoggerFactory.getLogger(ProcessLifecycleProvider.class);
+ public static final long CASSANDRA_PROCESS_TIMEOUT_MS =
Long.getLong("cassandra.sidecar.lifecycle.process.timeout.ms", 120_000L);
+
+ private final String lifecycleDir;
+ private final String defaultCassandraHome;
+ private final Map<String, String> defaultJvmProperties = new HashMap<>();
+ private final Map<String, String> defaultEnvVars = new HashMap<>();
+
public ProcessLifecycleProvider(Map<String, String> params)
{
- // Params unused for now
+ // Extract any JVM properties or environment variables from the params
+ for (Map.Entry<String, String> entry : params.entrySet())
+ {
+ if (entry.getKey().startsWith("cassandra."))
+ {
+ defaultJvmProperties.put(entry.getKey(), entry.getValue());
+ }
+ else if (entry.getKey().startsWith("env."))
+ {
+ defaultEnvVars.put(entry.getKey().replaceAll("env.", ""),
entry.getValue());
+ }
+ }
+ this.lifecycleDir = params.get(OPT_STATE_DIR);
+ this.defaultCassandraHome = params.get(OPT_CASSANDRA_HOME);
Review Comment:
Should we fail-fast if these directories do not exist or do not have
appropriate permissions?
##########
server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java:
##########
@@ -18,38 +18,232 @@
package org.apache.cassandra.sidecar.lifecycle;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.jetbrains.annotations.VisibleForTesting;
/**
- * A {@link LifecycleProvider} that manages Cassandra instances as OS
processes.
- * <p>
- * This implementation is a placeholder and is not yet implemented.
+ * Manage the lifecycle of Cassandra instances running on local processes
*/
public class ProcessLifecycleProvider implements LifecycleProvider
{
+ static final String OPT_CASSANDRA_HOME = "cassandra_home";
+ static final String OPT_CASSANDRA_CONF_DIR = "cassandra_conf_dir";
+ static final String OPT_CASSANDRA_LOG_DIR = "cassandra_log_dir";
+ static final String OPT_STATE_DIR = "state_dir";
+
+ protected static final Logger LOG =
LoggerFactory.getLogger(ProcessLifecycleProvider.class);
+ public static final long CASSANDRA_PROCESS_TIMEOUT_MS =
Long.getLong("cassandra.sidecar.lifecycle.process.timeout.ms", 120_000L);
+
+ private final String lifecycleDir;
+ private final String defaultCassandraHome;
+ private final Map<String, String> defaultJvmProperties = new HashMap<>();
+ private final Map<String, String> defaultEnvVars = new HashMap<>();
+
public ProcessLifecycleProvider(Map<String, String> params)
{
- // Params unused for now
+ // Extract any JVM properties or environment variables from the params
+ for (Map.Entry<String, String> entry : params.entrySet())
+ {
+ if (entry.getKey().startsWith("cassandra."))
+ {
+ defaultJvmProperties.put(entry.getKey(), entry.getValue());
+ }
+ else if (entry.getKey().startsWith("env."))
+ {
+ defaultEnvVars.put(entry.getKey().replaceAll("env.", ""),
entry.getValue());
+ }
+ }
+ this.lifecycleDir = params.get(OPT_STATE_DIR);
+ this.defaultCassandraHome = params.get(OPT_CASSANDRA_HOME);
+ if (lifecycleDir == null || lifecycleDir.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_STATE_DIR + "' must be set for ProcessLifecycleProvider");
+ }
+ if (defaultCassandraHome == null || defaultCassandraHome.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_CASSANDRA_HOME + "' must be set for ProcessLifecycleProvider");
+ }
}
@Override
public void start(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ if (isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already running.",
instance.host());
+ return;
+ }
+ startCassandra(instance);
}
@Override
public void stop(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
-
+ if (!isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already stopped.",
instance.host());
+ return;
+ }
+ stopCassandra(instance);
}
@Override
public boolean isRunning(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ return isCassandraProcessRunning(instance);
+ }
+
+ private void startCassandra(InstanceMetadata instance)
+ {
+ ProcessRuntimeConfiguration runtimeConfig =
getRuntimeConfiguration(instance);
+ try
+ {
+ String stdoutLocation =
getStdoutLocation(runtimeConfig.instanceName());
+ String stderrLocation =
getStderrLocation(runtimeConfig.instanceName());
+ String pidFileLocation =
getPidFileLocation(runtimeConfig.instanceName());
+ ProcessBuilder processBuilder =
runtimeConfig.buildStartCommand(pidFileLocation,
+
stdoutLocation,
+
stderrLocation);
+ LOG.info("Starting Cassandra instance {} with command: {}",
runtimeConfig.instanceName(), processBuilder.command());
+
+ Process process = processBuilder.start();
+ process.waitFor(CASSANDRA_PROCESS_TIMEOUT_MS,
TimeUnit.MILLISECONDS); // blocking call, make async?
+
+ if (isCassandraProcessRunning(instance))
+ {
+ LOG.info("Started Cassandra instance {} with PID {}",
runtimeConfig.instanceName(), readPidFromFile(Path.of(pidFileLocation)));
+ }
+ else
+ {
+ throw new RuntimeException("Failed to start Cassandra instance
" + runtimeConfig.instanceName() +
+ ". Check stdout at " +
stdoutLocation + " and stderr at " + stderrLocation);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new RuntimeException("Failed to start Cassandra instance " +
runtimeConfig.instanceName() + " due to " + t.getMessage(), t);
+ }
+ }
+
+ private void stopCassandra(InstanceMetadata instance)
+ {
+ ProcessRuntimeConfiguration casCfg = getRuntimeConfiguration(instance);
+ try
+ {
+ String pidFileLocation = getPidFileLocation(casCfg.instanceName());
+ Long pid = readPidFromFile(Path.of(pidFileLocation));
+ Optional<ProcessHandle> processHandle = ProcessHandle.of(pid);
+ if (processHandle.isPresent())
+ {
+ LOG.info("Stopping process of Cassandra instance {} with PID
{}.", casCfg.instanceName(), pid);
+ CompletableFuture<ProcessHandle> terminationFuture =
processHandle.get().onExit();
+ processHandle.get().destroy(); // blocking call, make async?
Review Comment:
Consider a force destroy `destroyForcibly()` on timeout with appropriate
logging.
##########
examples/lifecycle/setup.sh:
##########
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+set -eu
+
+SCRIPT_DIR=$(realpath "$(dirname "$0")")
+CASSANDRA_VERSION=4.1.10
+CASSANDRA_DIR="apache-cassandra-${CASSANDRA_VERSION}"
+TARBALL_NAME="${CASSANDRA_DIR}-bin.tar.gz"
+TARBALL_URL="https://dlcdn.apache.org/cassandra/${CASSANDRA_VERSION}/${TARBALL_NAME}"
+NODE_DIR="${SCRIPT_DIR}/nodes/localhost"
+
+SIDECAR_YAML="${SCRIPT_DIR}/conf/sidecar.yaml"
+SIDECAR_YAML_TEMPLATE="${SCRIPT_DIR}/conf/sidecar.yaml.template"
+CASSANDRA_HOME="${NODE_DIR}/opt/${CASSANDRA_DIR}"
+CASSANDRA_LOG_DIR="${NODE_DIR}/var/log/cassandra"
+CASSANDRA_CONF="${NODE_DIR}/etc/cassandra"
+CASSANDRA_STORAGE_DIR="${NODE_DIR}/var/lib/cassandra"
+SIDECAR_LIFECYCLE_DIR="${NODE_DIR}/var/lib/cassandra-sidecar/lifecycle"
+TMP_DIR="${NODE_DIR}/tmp"
+
+echo "Creating directories"
+mkdir -p ${CASSANDRA_HOME} ${CASSANDRA_LOG_DIR} ${CASSANDRA_CONF}
${CASSANDRA_STORAGE_DIR} ${SIDECAR_LIFECYCLE_DIR} ${TMP_DIR}
+
+if [ -f ${CASSANDRA_HOME}/bin/cassandra ]; then
+ echo "Cassandra already installed at ${CASSANDRA_HOME}, skipping install"
+else
+ echo "Installing Cassandra at ${CASSANDRA_HOME}"
+ echo "Downloading ${TARBALL_URL}"
+ wget -P ${TMP_DIR} ${TARBALL_URL}
+
+ echo "Extracting tarball"
+ tar -xvzf ${TMP_DIR}/${TARBALL_NAME} -C $(dirname $CASSANDRA_HOME)
+fi
+
+echo "Creating configuration"
+cp -r ${CASSANDRA_HOME}/conf/* ${CASSANDRA_CONF}
+sed "s#\$cassandraHome#${CASSANDRA_HOME}#g" ${SIDECAR_YAML_TEMPLATE} >
${SIDECAR_YAML}
+sed -i "s#\$baseDir#${NODE_DIR}#g" ${SIDECAR_YAML}
Review Comment:
This was complaining on a Mac. The format that worked was -
```
sed -i '' "s#\$baseDir#${NODE_DIR}#g" ${SIDECAR_YAML}
```
##########
server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java:
##########
@@ -18,38 +18,232 @@
package org.apache.cassandra.sidecar.lifecycle;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.jetbrains.annotations.VisibleForTesting;
/**
- * A {@link LifecycleProvider} that manages Cassandra instances as OS
processes.
- * <p>
- * This implementation is a placeholder and is not yet implemented.
+ * Manage the lifecycle of Cassandra instances running on local processes
*/
public class ProcessLifecycleProvider implements LifecycleProvider
{
+ static final String OPT_CASSANDRA_HOME = "cassandra_home";
+ static final String OPT_CASSANDRA_CONF_DIR = "cassandra_conf_dir";
+ static final String OPT_CASSANDRA_LOG_DIR = "cassandra_log_dir";
+ static final String OPT_STATE_DIR = "state_dir";
+
+ protected static final Logger LOG =
LoggerFactory.getLogger(ProcessLifecycleProvider.class);
+ public static final long CASSANDRA_PROCESS_TIMEOUT_MS =
Long.getLong("cassandra.sidecar.lifecycle.process.timeout.ms", 120_000L);
+
+ private final String lifecycleDir;
+ private final String defaultCassandraHome;
+ private final Map<String, String> defaultJvmProperties = new HashMap<>();
+ private final Map<String, String> defaultEnvVars = new HashMap<>();
+
public ProcessLifecycleProvider(Map<String, String> params)
{
- // Params unused for now
+ // Extract any JVM properties or environment variables from the params
+ for (Map.Entry<String, String> entry : params.entrySet())
+ {
+ if (entry.getKey().startsWith("cassandra."))
+ {
+ defaultJvmProperties.put(entry.getKey(), entry.getValue());
+ }
+ else if (entry.getKey().startsWith("env."))
+ {
+ defaultEnvVars.put(entry.getKey().replaceAll("env.", ""),
entry.getValue());
+ }
+ }
+ this.lifecycleDir = params.get(OPT_STATE_DIR);
+ this.defaultCassandraHome = params.get(OPT_CASSANDRA_HOME);
+ if (lifecycleDir == null || lifecycleDir.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_STATE_DIR + "' must be set for ProcessLifecycleProvider");
+ }
+ if (defaultCassandraHome == null || defaultCassandraHome.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_CASSANDRA_HOME + "' must be set for ProcessLifecycleProvider");
+ }
}
@Override
public void start(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ if (isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already running.",
instance.host());
+ return;
+ }
+ startCassandra(instance);
}
@Override
public void stop(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
-
+ if (!isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already stopped.",
instance.host());
+ return;
+ }
+ stopCassandra(instance);
}
@Override
public boolean isRunning(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ return isCassandraProcessRunning(instance);
+ }
+
+ private void startCassandra(InstanceMetadata instance)
+ {
+ ProcessRuntimeConfiguration runtimeConfig =
getRuntimeConfiguration(instance);
+ try
+ {
+ String stdoutLocation =
getStdoutLocation(runtimeConfig.instanceName());
+ String stderrLocation =
getStderrLocation(runtimeConfig.instanceName());
+ String pidFileLocation =
getPidFileLocation(runtimeConfig.instanceName());
+ ProcessBuilder processBuilder =
runtimeConfig.buildStartCommand(pidFileLocation,
+
stdoutLocation,
+
stderrLocation);
+ LOG.info("Starting Cassandra instance {} with command: {}",
runtimeConfig.instanceName(), processBuilder.command());
+
+ Process process = processBuilder.start();
+ process.waitFor(CASSANDRA_PROCESS_TIMEOUT_MS,
TimeUnit.MILLISECONDS); // blocking call, make async?
Review Comment:
As you have called out, consider using some sort of a periodic check for
process, Instead of blocking the thread. Likewise for the stop process below.
```suggestion
vertx.setPeriodic(1000, timerId -> {
if (isCassandraProcessRunning(instance)) {
vertx.cancelTimer(timerId);
LOG.info("Started Cassandra instance {} with PID {}",
runtimeConfig.instanceName(),
readPidFromFile(Path.of(pidFileLocation)));
} else if (System.currentTimeMillis() > startTime +
CASSANDRA_PROCESS_TIMEOUT_MS) {
vertx.cancelTimer(timerId);
LOG.error("Failed to start Cassandra instance {} within
timeout", runtimeConfig.instanceName());
// Handle timeout error
}
});
```
##########
server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java:
##########
@@ -18,38 +18,232 @@
package org.apache.cassandra.sidecar.lifecycle;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.jetbrains.annotations.VisibleForTesting;
/**
- * A {@link LifecycleProvider} that manages Cassandra instances as OS
processes.
- * <p>
- * This implementation is a placeholder and is not yet implemented.
+ * Manage the lifecycle of Cassandra instances running on local processes
*/
public class ProcessLifecycleProvider implements LifecycleProvider
{
+ static final String OPT_CASSANDRA_HOME = "cassandra_home";
+ static final String OPT_CASSANDRA_CONF_DIR = "cassandra_conf_dir";
+ static final String OPT_CASSANDRA_LOG_DIR = "cassandra_log_dir";
+ static final String OPT_STATE_DIR = "state_dir";
+
+ protected static final Logger LOG =
LoggerFactory.getLogger(ProcessLifecycleProvider.class);
+ public static final long CASSANDRA_PROCESS_TIMEOUT_MS =
Long.getLong("cassandra.sidecar.lifecycle.process.timeout.ms", 120_000L);
+
+ private final String lifecycleDir;
+ private final String defaultCassandraHome;
+ private final Map<String, String> defaultJvmProperties = new HashMap<>();
+ private final Map<String, String> defaultEnvVars = new HashMap<>();
+
public ProcessLifecycleProvider(Map<String, String> params)
{
- // Params unused for now
+ // Extract any JVM properties or environment variables from the params
+ for (Map.Entry<String, String> entry : params.entrySet())
+ {
+ if (entry.getKey().startsWith("cassandra."))
+ {
+ defaultJvmProperties.put(entry.getKey(), entry.getValue());
+ }
+ else if (entry.getKey().startsWith("env."))
+ {
+ defaultEnvVars.put(entry.getKey().replaceAll("env.", ""),
entry.getValue());
+ }
+ }
+ this.lifecycleDir = params.get(OPT_STATE_DIR);
+ this.defaultCassandraHome = params.get(OPT_CASSANDRA_HOME);
+ if (lifecycleDir == null || lifecycleDir.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_STATE_DIR + "' must be set for ProcessLifecycleProvider");
+ }
+ if (defaultCassandraHome == null || defaultCassandraHome.isEmpty())
+ {
+ throw new ConfigurationException("Configuration property '" +
OPT_CASSANDRA_HOME + "' must be set for ProcessLifecycleProvider");
+ }
}
@Override
public void start(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ if (isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already running.",
instance.host());
+ return;
+ }
+ startCassandra(instance);
}
@Override
public void stop(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
-
+ if (!isCassandraProcessRunning(instance))
+ {
+ LOG.info("Cassandra instance {} is already stopped.",
instance.host());
+ return;
+ }
+ stopCassandra(instance);
}
@Override
public boolean isRunning(InstanceMetadata instance)
{
- throw new UnsupportedOperationException("Not implemented yet");
+ return isCassandraProcessRunning(instance);
+ }
+
+ private void startCassandra(InstanceMetadata instance)
+ {
+ ProcessRuntimeConfiguration runtimeConfig =
getRuntimeConfiguration(instance);
+ try
+ {
+ String stdoutLocation =
getStdoutLocation(runtimeConfig.instanceName());
+ String stderrLocation =
getStderrLocation(runtimeConfig.instanceName());
+ String pidFileLocation =
getPidFileLocation(runtimeConfig.instanceName());
+ ProcessBuilder processBuilder =
runtimeConfig.buildStartCommand(pidFileLocation,
+
stdoutLocation,
+
stderrLocation);
+ LOG.info("Starting Cassandra instance {} with command: {}",
runtimeConfig.instanceName(), processBuilder.command());
+
+ Process process = processBuilder.start();
+ process.waitFor(CASSANDRA_PROCESS_TIMEOUT_MS,
TimeUnit.MILLISECONDS); // blocking call, make async?
+
+ if (isCassandraProcessRunning(instance))
+ {
+ LOG.info("Started Cassandra instance {} with PID {}",
runtimeConfig.instanceName(), readPidFromFile(Path.of(pidFileLocation)));
+ }
+ else
+ {
+ throw new RuntimeException("Failed to start Cassandra instance
" + runtimeConfig.instanceName() +
+ ". Check stdout at " +
stdoutLocation + " and stderr at " + stderrLocation);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new RuntimeException("Failed to start Cassandra instance " +
runtimeConfig.instanceName() + " due to " + t.getMessage(), t);
+ }
+ }
+
+ private void stopCassandra(InstanceMetadata instance)
+ {
+ ProcessRuntimeConfiguration casCfg = getRuntimeConfiguration(instance);
+ try
+ {
+ String pidFileLocation = getPidFileLocation(casCfg.instanceName());
+ Long pid = readPidFromFile(Path.of(pidFileLocation));
+ Optional<ProcessHandle> processHandle = ProcessHandle.of(pid);
+ if (processHandle.isPresent())
+ {
+ LOG.info("Stopping process of Cassandra instance {} with PID
{}.", casCfg.instanceName(), pid);
+ CompletableFuture<ProcessHandle> terminationFuture =
processHandle.get().onExit();
+ processHandle.get().destroy(); // blocking call, make async?
+ terminationFuture.get(CASSANDRA_PROCESS_TIMEOUT_MS,
TimeUnit.MILLISECONDS);
+ }
+ else
+ {
+ LOG.warn("No process running for Cassandra instance {} with
PID {}.", casCfg.instanceName, pid);
Review Comment:
Call the method for or consistency.
```suggestion
LOG.warn("No process running for Cassandra instance {} with
PID {}.", casCfg.instanceName(), pid);
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]