modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java
| 4
modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
| 75 +++++++++-
modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeComponentITest.java
| 21 ++
3 files changed, 95 insertions(+), 5 deletions(-)
New commits:
commit d01c43b697ef67f598016824d6cd47b5de2ac83e
Author: John Sanda <jsanda(a)redhat.com>
Date: Fri Jul 26 15:42:46 2013 -0400
add storage node shutdown operation that uses pid file
There can be problems with getting the actual, current pid from Sigar, so the
storage node plugin will first attempt to get the pid from the pid file which
should exist on disk. If that fails, then we will attempt to get the pid from
Sigar.
This implementation for shutdown does not work for Windows so need to revist it
to add in Windows support. We may even consider delegating to rhqtcl.
diff --git
a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java
b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java
index 3e55a93..d648ad8 100644
---
a/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java
+++
b/modules/plugins/cassandra/src/main/java/org/rhq/plugins/cassandra/CassandraNodeComponent.java
@@ -246,8 +246,6 @@ public class CassandraNodeComponent extends
JMXServerComponent<ResourceComponent
long pid = process.getPid();
try {
- getEmsConnection().close();
-
process.kill("KILL");
Configuration pluginConfig = getResourceContext().getPluginConfiguration();
@@ -266,7 +264,7 @@ public class CassandraNodeComponent extends
JMXServerComponent<ResourceComponent
}
}
- private void waitForNodeToGoDown() throws InterruptedException {
+ protected void waitForNodeToGoDown() throws InterruptedException {
if (OperatingSystem.getInstance().getName().equals(OperatingSystem.NAME_MACOSX))
{
// See this thread on VMWare forum:
http://communities.vmware.com/message/2187972#2187972
// Unfortunately there is no work around for this failure on Mac OSX so the
method will silently return on
diff --git
a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
index 125f4d2..5933093 100644
---
a/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
+++
b/modules/plugins/rhq-storage/src/main/java/org/rhq/plugins/storage/StorageNodeComponent.java
@@ -28,6 +28,7 @@ package org.rhq.plugins.storage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
@@ -39,6 +40,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.hyperic.sigar.SigarException;
import org.mc4j.ems.connection.EmsConnection;
import org.mc4j.ems.connection.bean.EmsBean;
import org.mc4j.ems.connection.bean.attribute.EmsAttribute;
@@ -54,9 +56,11 @@ import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.configuration.ConfigurationFacet;
import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
+import org.rhq.core.pluginapi.inventory.ProcessScanResult;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
+import org.rhq.core.system.ProcessInfo;
import org.rhq.core.util.StringUtil;
import org.rhq.core.util.exception.ThrowableUtil;
import org.rhq.core.util.file.FileUtil;
@@ -105,11 +109,80 @@ public class StorageNodeComponent extends CassandraNodeComponent
implements Oper
return updateKnownNodes(parameters);
} else if (name.equals("prepareForBootstrap")) {
return prepareForBootstrap(parameters);
+ } else if (name.equals("shutdown")) {
+ return shutdownStorageNode();
} else {
return super.invokeOperation(name, parameters);
}
}
+ private OperationResult shutdownStorageNode() {
+ OperationResult result = new OperationResult();
+ File binDir = new File(getBasedir(), "bin");
+ File pidFile = new File(binDir, "cassandra.pid");
+
+ try {
+ if (pidFile.exists()) {
+ long pid = readPidFile(pidFile);
+ log.info("Shutting down storage node with pid " + pid);
+ ProcessInfo process = findProcessInfo(pid);
+ if (process != null) {
+ try {
+ process.kill("KILL");
+ waitForNodeToGoDown();
+ pidFile.delete();
+ result.setSimpleResult("Successfully storage node with pid
" + pid);
+ } catch (SigarException e) {
+ log.error("Failed to delete storage node with pid " +
process.getPid(), e);
+ result.setErrorMessage("Failed to delete storage node with
pid " + pid + ": " +
+ ThrowableUtil.getAllMessages(e));
+ }
+ } else {
+ log.warn("Could not find process info for pid " + pid);
+ result = shutdownUsingNativeProcessInfo();
+ }
+
+ } else {
+ log.warn("Did not find pid file " + pidFile + ". It should
not be modified, deleted, or moved.");
+ result = shutdownUsingNativeProcessInfo();
+ }
+ } catch (FileNotFoundException e) {
+ log.error("Could not read pid file " + pidFile, e);
+ result.setErrorMessage("Could not read pid file " + pidFile +
": " + ThrowableUtil.getAllMessages(e));
+ } catch (InterruptedException e) {
+ log.warn("The shutdown operation was cancelled or interrupted. This
interruption occurred while trying " +
+ "to verify that the storage node process has exited.");
+ result.setErrorMessage("The operation was cancelled or interrupted while
trying to verify that the " +
+ "storage node process has exited.");
+ }
+ return result;
+ }
+
+ private long readPidFile(File pidFile) throws FileNotFoundException {
+ return Long.parseLong(StreamUtil.slurp(new FileReader(pidFile)));
+ }
+
+ private ProcessInfo findProcessInfo(long pid) {
+ List<ProcessScanResult> scanResults =
getResourceContext().getNativeProcessesForType();
+
+ for (ProcessScanResult scanResult : scanResults) {
+ if (scanResult.getProcessInfo().getPid() == pid) {
+ return scanResult.getProcessInfo();
+ }
+ }
+ return null;
+ }
+
+ private OperationResult shutdownUsingNativeProcessInfo() throws InterruptedException
{
+ log.warn("Could not obtain process info from pid file");
+ log.info("Obtaining process info from the system to perform the
shutdown");
+
+ OperationResult result = shutdownNode();
+ waitForNodeToGoDown();
+
+ return result;
+ }
+
private OperationResult updateConfiguration(Configuration params) {
boolean restartIsRequired = false;
@@ -237,7 +310,7 @@ public class StorageNodeComponent extends CassandraNodeComponent
implements Oper
OperationResult result = new OperationResult();
log.info("Stopping storage node");
- OperationResult stopNodeResult = stopNode();
+ OperationResult stopNodeResult = shutdownStorageNode();
if (stopNodeResult.getErrorMessage() != null) {
log.error("Failed to stop storage node " + this + " Cannot
prepare the node for bootstrap which means " +
"that the storage node cannot join the cluster. Make sure the
storage node is not running and retry " +
diff --git
a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeComponentITest.java
b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeComponentITest.java
index f0744a4..eb4d545 100644
---
a/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeComponentITest.java
+++
b/modules/plugins/rhq-storage/src/test/java/org/rhq/plugins/storage/StorageNodeComponentITest.java
@@ -231,6 +231,26 @@ public class StorageNodeComponentITest {
assertNodeIsUp("Expected " + storageNode + " to be up after
restarting it.");
}
+ @Test(dependsOnMethods = "restartStorageNode")
+ public void prepareForBootstrap() {
+ Configuration params = Configuration.builder().addSimple("cqlPort",
9242).addSimple("gossipPort", 7200)
+ .openList("storageNodeIPAddresses",
"storageNodeIPAddresse").addSimples("127.0.0.1",
"127.0.0.2")
+ .closeList().build();
+
+ OperationManager operationManager =
PluginContainer.getInstance().getOperationManager();
+ OperationServicesAdapter operationsService = new
OperationServicesAdapter(operationManager);
+
+ long timeout = 1000 * 60;
+ OperationContextImpl operationContext = new
OperationContextImpl(storageNode.getId());
+ OperationServicesResult result =
operationsService.invokeOperation(operationContext, "prepareForBootstrap",
+ params, timeout);
+
+ assertEquals(result.getResultCode(), OperationServicesResultCode.SUCCESS,
"The operation failed: " +
+ result.getErrorStackTrace());
+
+ assertNodeIsUp("Expected " + storageNode + " to be up after the
prepareForBootstrap operation completes.");
+ }
+
private void assertNodeIsUp(String msg) {
executeAvailabilityScan();
@@ -251,7 +271,6 @@ public class StorageNodeComponentITest {
private Availability getAvailability() {
InventoryManager inventoryManager =
PluginContainer.getInstance().getInventoryManager();
-// return inventoryManager.getAvailabilityIfKnown(storageNode);
return inventoryManager.getCurrentAvailability(storageNode);
}