Initial commit of case znodes cleanup admin action

This commit is contained in:
Richard Cordovano 2019-04-05 19:22:38 -04:00
parent 6ac9b96f1b
commit b52d15e437
3 changed files with 232 additions and 0 deletions

View File

@ -0,0 +1,57 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed 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.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.awt.event.ActionEvent;
import java.util.concurrent.FutureTask;
import javax.swing.AbstractAction;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.progress.AppFrameProgressBar;
import org.sleuthkit.autopsy.progress.TaskCancellable;
/**
* An action class that kicks off a cancellable case nodes cleanup task that
* runs in a background thread and reports progress using an application frame
* progress bar.
*/
final class CaseNodesCleanupAction extends AbstractAction {
private static final long serialVersionUID = 1L;
@Override
@NbBundle.Messages({
"CaseNodesCleanupAction.progressDisplayName=Cleanup Case Znodes"
})
public void actionPerformed(ActionEvent event) {
final AppFrameProgressBar progress = new AppFrameProgressBar(Bundle.CaseNodesCleanupAction_progressDisplayName());
final TaskCancellable taskCanceller = new TaskCancellable(progress);
progress.setCancellationBehavior(taskCanceller);
final Runnable task = new CaseNodesCleanupTask(progress);
final FutureTask<Void> future = new FutureTask<>(task, null);
taskCanceller.setFuture(future);
new Thread(future).start();
}
@Override
public CaseNodesCleanupAction clone() throws CloneNotSupportedException {
super.clone();
throw new CloneNotSupportedException();
}
}

View File

@ -0,0 +1,120 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed 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.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeData;
import org.sleuthkit.autopsy.casemodule.multiusercases.CaseNodeDataCollector;
import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.progress.ProgressIndicator;
/**
* Task for cleaning up case coordination service nodes for which there is no
* longer a corresponding case.
*/
final class CaseNodesCleanupTask implements Runnable {
private static final Logger logger = AutoIngestDashboardLogger.getLogger();
private final ProgressIndicator progress;
/**
* Constucts an instance of a task for cleaning up case coordination service
* nodes for which there is no longer a corresponding case.
*
* @param progress
*/
CaseNodesCleanupTask(ProgressIndicator progress) {
this.progress = progress;
}
@Override
public void run() {
CoordinationService coordinationService;
try {
coordinationService = CoordinationService.getInstance();
} catch (CoordinationService.CoordinationServiceException ex) {
logger.log(Level.WARNING, "Error connecting to the coordination service", ex); // NON-NLS
return;
}
List<CaseNodeData> nodeDataList;
try {
nodeDataList = CaseNodeDataCollector.getNodeData();
} catch (CoordinationService.CoordinationServiceException ex) {
logger.log(Level.WARNING, "Error collecting case node data", ex); // NON-NLS
return;
} catch (InterruptedException ex) {
logger.log(Level.WARNING, "Unexpected interrupt while collecting case node data", ex); // NON-NLS
return;
}
for (CaseNodeData nodeData : nodeDataList) {
final Path caseDirectoryPath = nodeData.getDirectory();
final File caseDirectory = caseDirectoryPath.toFile();
if (!caseDirectory.exists()) {
String caseName = nodeData.getDisplayName();
String nodePath = ""; // NON-NLS
try {
nodePath = CoordinationServiceUtils.getCaseNameNodePath(caseDirectoryPath);
deleteNode(coordinationService, caseName, nodePath);
nodePath = CoordinationServiceUtils.getCaseResourcesNodePath(caseDirectoryPath);
deleteNode(coordinationService, caseName, nodePath);
nodePath = CoordinationServiceUtils.getCaseAutoIngestLogNodePath(caseDirectoryPath);
deleteNode(coordinationService, caseName, nodePath);
nodePath = CoordinationServiceUtils.getCaseDirectoryNodePath(caseDirectoryPath);
deleteNode(coordinationService, caseName, nodePath);
} catch (InterruptedException ex) {
logger.log(Level.WARNING, String.format("Unexpected interrupt while deleting znode %s for %s", nodePath, caseName), ex); // NON-NLS
return;
}
}
}
}
/**
* Attempts to delete a case coordination service node.
*
* @param coordinationService The ccordination service.
* @param caseName The case name.
* @param nodePath The path of the node to delete.
*
* @throws InterruptedException If the thread executing this task is
* interrupted during the delete operation.
*/
private static void deleteNode(CoordinationService coordinationService, String caseName, String nodePath) throws InterruptedException {
try {
coordinationService.deleteNode(CoordinationService.CategoryNode.CASES, nodePath);
} catch (CoordinationService.CoordinationServiceException ex) {
if (!DeleteCaseUtils.isNoNodeException(ex)) {
logger.log(Level.SEVERE, String.format("Error deleting %s znode for %s", nodePath, caseName), ex); // NON-NLS
}
}
}
}

View File

@ -0,0 +1,55 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed 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.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
/**
* A utility class supplying helper methods for case deletion.
*/
final class DeleteCaseUtils {
private static final String NO_NODE_ERROR_MSG_FRAGMENT = "KeeperErrorCode = NoNode";
/**
* Examines a coordination service exception to try to determine if it is a
* no node exception.
*
* @param ex A coordination service exception.
*
* @return True or false.
*/
static boolean isNoNodeException(CoordinationService.CoordinationServiceException ex) {
boolean isNodeNodeEx = false;
Throwable cause = ex.getCause();
if (cause != null) {
String causeMessage = cause.getMessage();
isNodeNodeEx = causeMessage.contains(NO_NODE_ERROR_MSG_FRAGMENT);
}
return isNodeNodeEx;
}
/**
* A private constructor to prevent instantiation.
*/
private DeleteCaseUtils() {
}
}