Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WFCORE-6255] Deployment scanner did not undeploy failed archives #5642

Merged
merged 1 commit into from
Nov 14, 2023

Conversation

khermano
Copy link
Contributor

@github-actions github-actions bot added the deps-ok Dependencies have been checked, and there are no significant changes label Aug 30, 2023
Copy link
Contributor

@bstansberry bstansberry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @khermano -- the approach seems reasonable, although I mention a scenario that needs to be covered, plus this needs specific testing.

@@ -931,6 +931,7 @@ private void scanDirectory(final File directory, final String relativePath, fina
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())) {
scanContext.scannerTasks.add(new UndeployTask(deploymentName, deploymentDir, child.lastModified(), true));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe child.lastModified() should be scanContext.scanStartTime. If this actually does an undeploy, the undeploy didn't happen when the FAILED_DEPLOY marker was written.

It doesn't really matter because this param ends up unused since you pass 'true' as the forcedUndeploy param, but maybe after some future change it will matter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more substantive problem is there needs to be a check that this isn't going to undeploy something not associated with this scanner; e.g. a scanned deployment failed, and admin removed the file, and then the admin used the CLI to force-deploy.

I believe scanContext.persistentDeployments is meant to contain the set of deployments not associated with this scanner, so that could be how to check.

Tests of this change should cover this scenario in addition to the basic one described in the JIRA.

@@ -495,6 +495,7 @@ public void testCleanSpuriousMarkers() throws Exception {
f1 = createFile("spurious" + FileSystemDeploymentService.DEPLOYED);
f2 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.DEPLOYED);

ts.controller.addCompositeSuccessResponse(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer this test being left as is and one or two next test methods specifically targeting this JIRA be added. It's too hard to reason about how this test change means the fix is being tested.

If you had to do this just to get the existing test to pass, a code comment explaining why it's needed would be good.

Copy link
Contributor Author

@khermano khermano Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @bstansberry. Thank you very much for the review and detailed description of the possible problems.
Yes, I just tried to get the existing test pass.
If I understand it correctly, the test was failing because I added UndeploymentTask in FileSystemDeploymentService which wasn't considered by the mocked controller. I guess the addCompositeSuccessResponse method only adds one success response to MockServerController.responses to use it in the processOp method somehow as a counter of requests.
Should I also try to create some other test?
For now I will force-push my changes.

Copy link
Contributor

@bstansberry bstansberry Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @khermano -- yes, please add another test method or two, e.g. one that specifically covers the bug and another that validates that a deployment not associated with the scanner being tested isn't undeployed just because a cruft FAILED_DEPLOY marker file is left in the scanner's directory. I think the test infrastructure used by FileSystemDeploymentServiceTestCase can handle that scenario, or at least is close to being able to.

It sounds like the line I commented on here needs to remain, which is fine, but preceding it with a brief comment would be good as it's not obvious why it's there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @bstansberry ,
so I added the comment and the test for the bug you recommended, but I am unsure about the other one.
I tried a couple of things to deploy the failing kitchensink.war through CLI and console, but none of them create any content in the scanned standalone/deployments directory, not even deploy ~/../kitchensink.war --force.
And I think that maybe creating markers like ".failed", ".deployed" and others is only a deployment-scanner thing, or am I wrong about that? 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khermano For the 2nd one I was looking for another test method in FileSystemDeploymentServiceUnitTestCase. I can't say precisely how to do it but have a look at the various testIgnoreExternal...Deployment methods and their use of the ExternalDeployment class. The purpose of that class was to represent a deployment not under the control of the scanner being tested. I don't know if the test utilities in FileSystemDeploymentServiceUnitTestCase are sufficient to cover your scenario, but if they are not they can probably be tweaked a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @bstansberry ,
I am sorry for the delay. I got stuck with this and needed to work on something else, but I think I finally have it.
So again, I'm really sorry for the inconvenience. Hopefully, it looks okay.

Copy link
Contributor

@bstansberry bstansberry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @khermano

The tests look good. Converting scanContext to an instance field brings some maintenance risk related to thread safety, so I've requested a few changes related to reducing that risk. But the basic fix looks fine.

@@ -152,6 +153,11 @@ class FileSystemDeploymentService implements DeploymentScanner, NotificationHand
@SuppressWarnings("deprecation")
private final DeploymentTransformer deploymentTransformer;

private ScanContext scanContext;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this an instance variable is a bit dangerous for maintenance, so it needs a good usage comment. Something like

// Guarded by scanLock.
// Reads or writes of this field can only be done in code executing between a call to {@link #acquireScanLock()} and {@link #releaseScanLock()}

@@ -152,6 +153,11 @@ class FileSystemDeploymentService implements DeploymentScanner, NotificationHand
@SuppressWarnings("deprecation")
private final DeploymentTransformer deploymentTransformer;

private ScanContext scanContext;

public Map<String,Boolean> getScanContextRegisteredDeployments() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be package-protected and moved down in the file to a less prominent position. Please add method javadoc stating the method only exists for testing. The test is in the same package, so package-protected works. That kind of thing is why it's in the same package. :)

private ScanContext scanContext;

public Map<String,Boolean> getScanContextRegisteredDeployments() {
return Collections.unmodifiableMap(scanContext.registeredDeployments);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per my comment above about the new scanContext field, please wrap this in acquireScanLock() try { ... } finally { releaseScanLock(); }

an 'assert scanContext != null' would also be good.

Doing all this doesn't really matter for your test but it reduces the risk of future misuse of this method by having the test code follow the concurrency rules that we create for the production code.

@wildfly-ci
Copy link

Core -> Full Integration Build 12991 outcome was FAILURE using a merge of 9418b98
Summary: Tests failed: 3 (3 new), passed: 4120, ignored: 65 Build time: 02:15:18

Failed tests

org.jboss.as.test.integration.hibernate.search.backend.elasticsearch.massindexer.HibernateSearchElasticsearchMassIndexerTestCase:     Caused by: org.jboss.weld.exceptions.DeploymentException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)
    Caused by: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)"}}}}
Cannot deploy HibernateSearchElasticsearchMassIndexerTestCase.war: {"WFLYCTL0062: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-1" => {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"HibernateSearchElasticsearchMassIndexerTestCase.war\".WeldStartService" => "Failed to start service
    Caused by: org.jboss.weld.exceptions.DeploymentException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)
    Caused by: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)"}}}}
	at org.jboss.as.arquillian.container.ArchiveDeployer.deployInternal(ArchiveDeployer.java:185)
	at org.jboss.as.arquillian.container.ArchiveDeployer.deployInternal(ArchiveDeployer.java:163)
	at org.jboss.as.arquillian.container.ArchiveDeployer.deploy(ArchiveDeployer.java:91)
	at org.jboss.as.arquillian.container.CommonDeployableContainer.deploy(CommonDeployableContainer.java:262)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)


org.jboss.as.test.integration.hibernate.search.backend.elasticsearch.projectionconstructor.HibernateSearchElasticsearchProjectionConstructorTestCase:     Caused by: org.jboss.weld.exceptions.DeploymentException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)
    Caused by: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)"}}}}
Cannot deploy HibernateSearchElasticsearchProjectionConstructorTestCase.war: {"WFLYCTL0062: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-1" => {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"HibernateSearchElasticsearchProjectionConstructorTestCase.war\".WeldStartService" => "Failed to start service
    Caused by: org.jboss.weld.exceptions.DeploymentException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)
    Caused by: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)"}}}}
	at org.jboss.as.arquillian.container.ArchiveDeployer.deployInternal(ArchiveDeployer.java:185)
	at org.jboss.as.arquillian.container.ArchiveDeployer.deployInternal(ArchiveDeployer.java:163)
	at org.jboss.as.arquillian.container.ArchiveDeployer.deploy(ArchiveDeployer.java:91)
	at org.jboss.as.arquillian.container.CommonDeployableContainer.deploy(CommonDeployableContainer.java:262)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)


org.jboss.as.test.integration.hibernate.search.backend.elasticsearch.simple.HibernateSearchElasticsearchSimpleTestCase:     Caused by: org.jboss.weld.exceptions.DeploymentException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)
    Caused by: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)"}}}}
Cannot deploy HibernateSearchElasticsearchSimpleTestCase.war: {"WFLYCTL0062: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-1" => {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"HibernateSearchElasticsearchSimpleTestCase.war\".WeldStartService" => "Failed to start service
    Caused by: org.jboss.weld.exceptions.DeploymentException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)
    Caused by: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    default backend: 
        failures: 
          - HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: Connection refused
            Request: GET  with parameters {}
            Response: (no response)"}}}}
	at org.jboss.as.arquillian.container.ArchiveDeployer.deployInternal(ArchiveDeployer.java:185)
	at org.jboss.as.arquillian.container.ArchiveDeployer.deployInternal(ArchiveDeployer.java:163)
	at org.jboss.as.arquillian.container.ArchiveDeployer.deploy(ArchiveDeployer.java:91)
	at org.jboss.as.arquillian.container.CommonDeployableContainer.deploy(CommonDeployableContainer.java:262)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)


@bstansberry bstansberry merged commit 775319f into wildfly:main Nov 14, 2023
12 checks passed
@bstansberry
Copy link
Contributor

Thanks @khermano

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deps-ok Dependencies have been checked, and there are no significant changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants