This is an automated email from the ASF dual-hosted git repository.

rzo1 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/storm.git


The following commit(s) were added to refs/heads/master by this push:
     new 2f0a63a2a Fix worker launch: add lib-common to the supervisor's worker 
classpath and restore the lib-worker drop-in directory (#8905)
2f0a63a2a is described below

commit 2f0a63a2ac0cb5934901e485bfcf9256362181c4
Author: reiabreu <[email protected]>
AuthorDate: Sun Jul 19 11:26:38 2026 +0100

    Fix worker launch: add lib-common to the supervisor's worker classpath and 
restore the lib-worker drop-in directory (#8905)
    
    * Fix supervisor-launched workers: add lib-common to the worker framework 
classpath
    
    Since the lib de-duplication (#8819) the distribution ships the worker jars
    in lib-common instead of lib-worker. bin/storm.py was updated, but
    BasicContainer.frameworkClasspath() still built the worker launch classpath
    from lib-worker only, so supervisor-launched workers crashed with
    ClassNotFoundException: org.apache.storm.LogWriter.
    
    Add lib-common to the framework classpath, keeping lib-worker as the
    drop-in location for worker-only jars.
    
    * test: cover the real frameworkClasspath() in BasicContainerTest
    
    The existing launch tests mock frameworkClasspath() away (FRAMEWORK_CP),
    which is how the lib-common regression slipped through. Exercise the real
    implementation via a hook in MockBasicContainer and assert that both
    lib-common/* and lib-worker/* are on the worker classpath.
    
    * build: ship an empty lib-worker drop-in directory in the distribution
    
    The lib de-duplication removed lib-worker entirely, but both bin/storm.py
    and BasicContainer keep lib-worker/* on the worker classpath, and operators
    use the directory as the drop-in point for worker-only jars. Restore it as
    an empty directory holding only a README that documents the new
    lib / lib-common / lib-worker layout, in both the full and lite
    distributions.
    
    ---------
    
    Co-authored-by: Richard Zowalla <[email protected]>
---
 .../final-package/src/main/assembly/common.xml     |  6 +++
 .../src/main/dist/lib-worker/README.md             | 15 +++++++
 .../storm/daemon/supervisor/BasicContainer.java    |  5 +++
 .../daemon/supervisor/BasicContainerTest.java      | 47 ++++++++++++++++++++++
 4 files changed, 73 insertions(+)

diff --git a/storm-dist/binary/final-package/src/main/assembly/common.xml 
b/storm-dist/binary/final-package/src/main/assembly/common.xml
index 6b50cc8ad..402fd3837 100644
--- a/storm-dist/binary/final-package/src/main/assembly/common.xml
+++ b/storm-dist/binary/final-package/src/main/assembly/common.xml
@@ -38,6 +38,12 @@
                 <include>*.jar</include>
             </includes>
         </fileSet>
+        <!-- lib-worker ships empty (README only): it stays on the worker 
classpath as the
+             drop-in point for worker-only jars, matching the pre-dedup 2.x 
layout. -->
+        <fileSet>
+            <directory>${project.basedir}/src/main/dist/lib-worker</directory>
+            <outputDirectory>lib-worker</outputDirectory>
+        </fileSet>
         <fileSet>
             
<directory>${project.basedir}/../storm-webapp-bin/target/webapp/webapp/</directory>
             <outputDirectory>.</outputDirectory>
diff --git a/storm-dist/binary/final-package/src/main/dist/lib-worker/README.md 
b/storm-dist/binary/final-package/src/main/dist/lib-worker/README.md
new file mode 100644
index 000000000..65f2d6a5a
--- /dev/null
+++ b/storm-dist/binary/final-package/src/main/dist/lib-worker/README.md
@@ -0,0 +1,15 @@
+# lib-worker
+
+Drop-in directory for worker-only jars.
+
+Jars placed here are added to the classpath of every worker JVM launched by
+the supervisor, but not to the daemon (nimbus / supervisor / ui) classpath.
+
+The distribution itself ships no worker-only jars: the jars shared by the
+daemons and the workers live in `lib-common/`, daemon-only jars in `lib/`.
+The classpaths are composed as:
+
+    daemon classpath = lib-common + lib
+    worker classpath = lib-common + lib-worker
+
+See also `extlib/`, which is added to both the daemon and worker classpaths.
diff --git 
a/storm-server/src/main/java/org/apache/storm/daemon/supervisor/BasicContainer.java
 
b/storm-server/src/main/java/org/apache/storm/daemon/supervisor/BasicContainer.java
index 7583a96db..35ce6c56f 100644
--- 
a/storm-server/src/main/java/org/apache/storm/daemon/supervisor/BasicContainer.java
+++ 
b/storm-server/src/main/java/org/apache/storm/daemon/supervisor/BasicContainer.java
@@ -372,6 +372,10 @@ public class BasicContainer extends Container {
     }
 
     protected List<String> frameworkClasspath(SimpleVersion topoVersion) {
+        // Jars shared by the daemon and worker classpaths are de-duplicated 
into lib-common
+        // (see storm-dist dedup-libs.py); storm-client and its dependencies 
live there, so the
+        // worker classpath needs lib-common in addition to lib-worker.
+        File stormCommonLibDir = new File(stormHome, "lib-common");
         File stormWorkerLibDir = new File(stormHome, "lib-worker");
         String topoConfDir = System.getenv("STORM_CONF_DIR") != null
                 ? System.getenv("STORM_CONF_DIR")
@@ -379,6 +383,7 @@ public class BasicContainer extends Container {
         File stormExtlibDir = new File(stormHome, "extlib");
         String extcp = System.getenv("STORM_EXT_CLASSPATH");
         List<String> pathElements = new LinkedList<>();
+        pathElements.add(getWildcardDir(stormCommonLibDir));
         pathElements.add(getWildcardDir(stormWorkerLibDir));
         pathElements.add(getWildcardDir(stormExtlibDir));
         pathElements.add(extcp);
diff --git 
a/storm-server/src/test/java/org/apache/storm/daemon/supervisor/BasicContainerTest.java
 
b/storm-server/src/test/java/org/apache/storm/daemon/supervisor/BasicContainerTest.java
index a4f6ec93a..4f941d42e 100644
--- 
a/storm-server/src/test/java/org/apache/storm/daemon/supervisor/BasicContainerTest.java
+++ 
b/storm-server/src/test/java/org/apache/storm/daemon/supervisor/BasicContainerTest.java
@@ -31,11 +31,13 @@ import org.apache.storm.generated.StormTopology;
 import org.apache.storm.utils.LocalState;
 import org.apache.storm.utils.SimpleVersion;
 import org.apache.storm.utils.Utils;
+import org.apache.storm.utils.VersionInfo;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -402,6 +404,47 @@ public class BasicContainerTest {
                    "storm.log.dir", stormLogDir);
     }
 
+    @Test
+    public void testFrameworkClasspathIncludesSharedAndWorkerLibs() throws 
Exception {
+        final String topoId = "test_topology_classpath";
+        final int supervisorPort = 6628;
+        final int port = 8080;
+        final String stormHome = ContainerTest.asAbsPath("tmp", "storm-home");
+        final String stormLogDir = ContainerTest.asFile(".", 
"target").getCanonicalPath();
+        final String stormLocal = ContainerTest.asAbsPath("tmp", 
"storm-local");
+
+        final Map<String, Object> superConf = new HashMap<>();
+        superConf.put(Config.STORM_LOCAL_DIR, stormLocal);
+        superConf.put(Config.STORM_WORKERS_ARTIFACTS_DIR, stormLocal);
+
+        LocalAssignment la = new LocalAssignment();
+        la.set_topology_id(topoId);
+
+        AdvancedFSOps ops = mock(AdvancedFSOps.class);
+        when(ops.doRequiredTopoFilesExist(superConf, topoId)).thenReturn(true);
+
+        LocalState ls = mock(LocalState.class);
+        MockResourceIsolationManager iso = new MockResourceIsolationManager();
+
+        checkpoint(() -> {
+                       MockBasicContainer mc = new 
MockBasicContainer(ContainerType.LAUNCH, superConf,
+                           "SUPERVISOR", supervisorPort, port, la, iso, ls, 
"worker-id", new StormMetricsRegistry(),
+                           new HashMap<>(), ops, "profile");
+
+                       List<String> cp = 
mc.realFrameworkClasspath(VersionInfo.OUR_VERSION);
+
+                       // The distribution de-duplicates the jars shared by 
the daemon and worker
+                       // classpaths into lib-common; storm-client (LogWriter, 
Worker) ships there,
+                       // so a worker launched without lib-common on the 
classpath cannot start.
+                       String libCommon = stormHome + File.separator + 
"lib-common" + File.separator + "*";
+                       String libWorker = stormHome + File.separator + 
"lib-worker" + File.separator + "*";
+                       assertTrue(cp.contains(libCommon), "worker classpath 
must include lib-common/*, got: " + cp);
+                       assertTrue(cp.contains(libWorker), "worker classpath 
must include lib-worker/*, got: " + cp);
+                   },
+                   ConfigUtils.STORM_HOME, stormHome,
+                   "storm.log.dir", stormLogDir);
+    }
+
     @Test
     public void testLaunchStorm1version() throws Exception {
         final String topoId = "test_topology_storm_1.x";
@@ -712,6 +755,10 @@ public class BasicContainerTest {
             return Collections.singletonList("FRAMEWORK_CP");
         }
 
+        public List<String> realFrameworkClasspath(SimpleVersion version) {
+            return super.frameworkClasspath(version);
+        }
+
         @Override
         protected String javaLibraryPath(String stormRoot, Map<String, Object> 
conf) {
             return "JLP";

Reply via email to