Skip to content

Commit

Permalink
Merge pull request #5642 from khermano/WFCORE-6255_from_main
Browse files Browse the repository at this point in the history
[WFCORE-6255] Deployment scanner did not undeploy failed archives
  • Loading branch information
bstansberry authored Nov 14, 2023
2 parents 06936c7 + 9418b98 commit 775319f
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -152,6 +153,12 @@ class FileSystemDeploymentService implements DeploymentScanner, NotificationHand
@SuppressWarnings("deprecation")
private final DeploymentTransformer deploymentTransformer;

/**
* Property have to be guarded by scanLock.
* Reads or writes of this field can be done only in code executing
* between a call to {@link #acquireScanLock()} and {@link #releaseScanLock()}
*/
private ScanContext scanContext;

@Override
public void handleNotification(Notification notification) {
Expand Down Expand Up @@ -504,6 +511,23 @@ void scan() {
}
}

/**
* This method exists only for testing purposes
*
* @return unmodifiable collection of registered deployments, null otherwise
*/
Map<String,Boolean> getScanContextRegisteredDeployments() {
if (acquireScanLock()) {
try {
assert scanContext != null;
return Collections.unmodifiableMap(scanContext.registeredDeployments);
} finally {
releaseScanLock();
}
}
return null;
}

/**
* Perform a post-boot scan to remove any deployments added during boot that failed to deploy properly.
* This method isn't private solely to allow a unit test in the same package to call it.
Expand All @@ -513,7 +537,7 @@ void forcedUndeployScan() {
if (acquireScanLock()) {
try {
ROOT_LOGGER.tracef("Performing a post-boot forced undeploy scan for scan directory %s", deploymentDir.getAbsolutePath());
ScanContext scanContext = new ScanContext(deploymentOperations);
scanContext = new ScanContext(deploymentOperations);

// Add remove actions to the plan for anything we count as
// deployed that we didn't find on the scan
Expand All @@ -540,6 +564,7 @@ void forcedUndeployScan() {
} catch (Exception e) {
ROOT_LOGGER.scanException(e, deploymentDir.getAbsolutePath());
} finally {
scanContext = null;
releaseScanLock();
}
}
Expand Down Expand Up @@ -581,7 +606,7 @@ private boolean scan(boolean oneOffScan, final DeploymentOperations deploymentOp
deployedContentEstablished = true;
}

ScanContext scanContext = null;
scanContext = null;
try {
scanContext = new ScanContext(deploymentOperations);
} catch (RuntimeException ex) {
Expand All @@ -592,7 +617,7 @@ private boolean scan(boolean oneOffScan, final DeploymentOperations deploymentOp
throw ex;
}

scanDirectory(deploymentDir, relativePath, scanContext);
scanDirectory(deploymentDir, relativePath);

// WARN about markers with no associated content. Do this first in case any auto-deploy issue
// is due to a file that wasn't meant to be auto-deployed, but has a misspelled marker
Expand Down Expand Up @@ -628,7 +653,7 @@ private boolean scan(boolean oneOffScan, final DeploymentOperations deploymentOp
}

// Deal with any incomplete or non-scannable auto-deploy content
ScanStatus status = handleAutoDeployFailures(scanContext);
ScanStatus status = handleAutoDeployFailures();
if (status != ScanStatus.PROCEED) {
if (status == ScanStatus.RETRY && scanInterval > 1000) {
// schedule a non-repeating task to try again more quickly
Expand Down Expand Up @@ -837,9 +862,8 @@ else if (!directory.canWrite()) {
* Scan the given directory for content changes.
*
* @param directory the directory to scan
* @param scanContext context of the scan
*/
private void scanDirectory(final File directory, final String relativePath, final ScanContext scanContext) {
private void scanDirectory(final File directory, final String relativePath) {
final List<File> children = listDirectoryChildren(directory, filter);
for (File child : children) {
final String fileName = child.getName();
Expand Down Expand Up @@ -909,20 +933,30 @@ private void scanDirectory(final File directory, final String relativePath, fina
// the
// deploymentDir
final boolean archive = deploymentFile.isFile();
addContentAddingTask(path, archive, deploymentName, deploymentFile, timestamp, scanContext);
addContentAddingTask(path, archive, deploymentName, deploymentFile, timestamp);
} else if (fileName.endsWith(FAILED_DEPLOY)) {
final String deploymentName = fileName.substring(0, fileName.length() - FAILED_DEPLOY.length());
scanContext.toRemove.remove(deploymentName);
if (!deployed.containsKey(deploymentName) && !(new File(child.getParent(), deploymentName).exists())) {
removeExtraneousMarker(child, fileName);
if (acquireScanLock()) {
try {
assert scanContext != null;
scanContext.toRemove.remove(deploymentName);
if (!deployed.containsKey(deploymentName) && !(new File(child.getParent(), deploymentName).exists())) {
if (scanContext.registeredDeployments.containsKey(deploymentName)) {
scanContext.scannerTasks.add(new UndeployTask(deploymentName, deploymentDir, scanContext.scanStartTime, true));
}
removeExtraneousMarker(child, fileName);
}
} finally {
releaseScanLock();
}
}
} else if (isEEArchive(fileName)) {
boolean autoDeployable = child.isDirectory() ? autoDeployExploded : autoDeployZip;
if (autoDeployable) {
if (!isAutoDeployDisabled(child)) {
long timestamp = getDeploymentTimestamp(child);
synchronizeScannerStatus(scanContext, directory, fileName, timestamp);
if (isFailedOrUndeployed(scanContext, directory, fileName, timestamp) || scanContext.firstScanDeployments.contains(fileName)) {
synchronizeScannerStatus(directory, fileName, timestamp);
if (isFailedOrUndeployed(directory, fileName, timestamp) || scanContext.firstScanDeployments.contains(fileName)) {
continue;
}

Expand All @@ -935,7 +969,7 @@ private void scanDirectory(final File directory, final String relativePath, fina
if(firstScan){
scanContext.firstScanDeployments.add(fileName);
}
addContentAddingTask(path, archive, fileName, child, timestamp, scanContext);
addContentAddingTask(path, archive, fileName, child, timestamp);
} else {
//we need to make sure that the file was not deleted while
//the scanner was running
Expand All @@ -958,7 +992,7 @@ private void scanDirectory(final File directory, final String relativePath, fina
if (autoDeployXml) {
if (!isAutoDeployDisabled(child)) {
long timestamp = getDeploymentTimestamp(child);
if (isFailedOrUndeployed(scanContext, directory, fileName, timestamp) || scanContext.firstScanDeployments.contains(fileName)) {
if (isFailedOrUndeployed(directory, fileName, timestamp) || scanContext.firstScanDeployments.contains(fileName)) {
continue;
}

Expand All @@ -969,7 +1003,7 @@ private void scanDirectory(final File directory, final String relativePath, fina
if(firstScan){
scanContext.firstScanDeployments.add(fileName);
}
addContentAddingTask(path, true, fileName, child, timestamp, scanContext);
addContentAddingTask(path, true, fileName, child, timestamp);
} else {
//we need to make sure that the file was not deleted while
//the scanner was running
Expand Down Expand Up @@ -1001,7 +1035,7 @@ private void scanDirectory(final File directory, final String relativePath, fina
// Track for possible ERROR logging
scanContext.illegalDir.add(fileName);
} else {
scanDirectory(child, relativePath + child.getName() + File.separator, scanContext);
scanDirectory(child, relativePath + child.getName() + File.separator);
}
}
}
Expand All @@ -1016,20 +1050,20 @@ private boolean isXmlComplete(final File xmlFile) {
}
}

private boolean isFailedOrUndeployed(final ScanContext scanContext, final File directory, final String fileName, final long timestamp) {
private boolean isFailedOrUndeployed(final File directory, final String fileName, final long timestamp) {
final File failedMarker = new File(directory, fileName + FAILED_DEPLOY);
if (failedMarker.exists() && timestamp <= failedMarker.lastModified()) {
return true;
}
final File undeployedMarker = new File(directory, fileName + UNDEPLOYED);
if (isMarkedUndeployed(undeployedMarker, timestamp) && !isRegisteredDeployment(scanContext, fileName)) {
if (isMarkedUndeployed(undeployedMarker, timestamp) && !isRegisteredDeployment(fileName)) {
return true;
}
return false;
}

private void synchronizeScannerStatus(ScanContext scanContext, File directory, String fileName, long timestamp) {
if (isRegisteredDeployment(scanContext, fileName)) {
private void synchronizeScannerStatus(File directory, String fileName, long timestamp) {
if (isRegisteredDeployment(fileName)) {
final File undeployedMarker = new File(directory, fileName + UNDEPLOYED);
if (isMarkedUndeployed(undeployedMarker, timestamp) && !scanContext.persistentDeployments.contains(fileName)) {
try {
Expand Down Expand Up @@ -1058,7 +1092,7 @@ private void synchronizeScannerStatus(ScanContext scanContext, File directory, S
}

private long addContentAddingTask(final String path, final boolean archive, final String deploymentName,
final File deploymentFile, final long timestamp, final ScanContext scanContext) {
final File deploymentFile, final long timestamp) {
if (deploymentTransformer != null) {
try {
deploymentTransformer.transform(deploymentFile.toPath(), deploymentFile.toPath());
Expand All @@ -1076,7 +1110,7 @@ private long addContentAddingTask(final String path, final boolean archive, fina
return timestamp;
}

private boolean isRegisteredDeployment(final ScanContext scanContext, final String fileName) {
private boolean isRegisteredDeployment(final String fileName) {
if(!scanContext.persistentDeployments.contains(fileName)) {//check that we are talking about the deployment in the scanned folder
return scanContext.registeredDeployments.get(fileName) == null ? false : scanContext.registeredDeployments.get(fileName);
}
Expand Down Expand Up @@ -1149,7 +1183,7 @@ private void removeExtraneousMarker(File child, final String fileName) {
*
* @return true if the scan should be aborted
*/
private ScanStatus handleAutoDeployFailures(ScanContext scanContext) {
private ScanStatus handleAutoDeployFailures() {

ScanStatus result = ScanStatus.PROCEED;
boolean warnLogged = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ public void testCleanSpuriousMarkers() throws Exception {
f1 = createFile("spurious" + FileSystemDeploymentService.DEPLOYED);
f2 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.DEPLOYED);

// WFCORE-6255 added UndeployTask, so here needs to be added mocked response which serves as counter of requests in the processOp()
ts.controller.addCompositeSuccessResponse(1);
ts.testee.scan();

// Failed deployments should be cleaned on subsequent scans.
Expand Down Expand Up @@ -688,6 +690,66 @@ public void testFailedRedeployNoMarker() throws Exception {

}

/**
* Test for WFCORE-6255
* It tests that the failed archives are undeployed
*/
@Test
public void testRemoveFailedDeployment() throws Exception {
File war = createFile("foo.war");
File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY);
File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED);
File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY);
TesteeSet ts = createTestee();
ts.testee.setAutoDeployZippedContent(true);

// failure of deploying the foo.war (must be ready before scan)
ts.controller.addCompositeFailureResponse(1, 1);
ts.testee.scan();
assertTrue(war.exists());
assertFalse(dodeploy.exists());
assertFalse(deployed.exists());
assertTrue(failed.exists());

assertTrue(war.delete());
// success of undeploying failed foo.war from the server (must be ready before scan)
ts.controller.addCompositeSuccessResponse(1);
ts.testee.scan();
assertFalse(war.exists());
assertFalse(dodeploy.exists());
assertFalse(deployed.exists());
assertFalse(failed.exists());
assertEquals(0, ts.controller.added.size());
assertEquals(0, ts.controller.deployed.size());
assertTrue(ts.testee.getScanContextRegisteredDeployments().containsKey("foo.war"));

// failed deployment is released from registeredDeployments at the beginning of the next scan (schedule rescan)
ts.testee.scan();
assertEquals(0, ts.testee.getScanContextRegisteredDeployments().size());
}

/**
* After WFCORE-6255 we need a test that validates that the deployment not associated with the scanner being tested isn't undeployed because
* a FAILED_DEPLOY marker file is left in the scanner's directory
*/
@Test
public void testIgnoreExternalScannerFailedDeployment() throws Exception {
MockServerController sc = new MockServerController("foo.war");
TesteeSet ts = createTestee(sc);
ts.controller.externallyDeployed.put("foo.war", null);
assertThat(ts.controller.deployed.size(), is(1));
ts.testee.bootTimeScan(sc.create());
File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY);

// there is no need for mocked method addCompositeSuccessResponse associated with UndeployTask that means
// that there is no undeployment attempt
ts.testee.scan();

assertFalse(failed.exists());
assertThat(ts.controller.deployed.size(), is(1));
assertThat(ts.controller.deployed.keySet(), hasItems("foo.war"));
}

@Test
public void testSuccessfulRetryRedeploy() throws Exception {
File war1 = createFile("bar.war");
Expand Down

0 comments on commit 775319f

Please sign in to comment.