From 0f2d2fd1b71cdc91ca4f82b3efa6cf6a2e4f10ff Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Mon, 12 Feb 2024 11:02:42 -0800 Subject: [PATCH] Fix more tests that launch ClusterStartup --- .../labkey/api/pipeline/PipelineService.java | 3 + .../pipeline/api/PipelineServiceImpl.java | 101 ++++++++++++++++++ .../pipeline/cluster/ClusterStartup.java | 91 +--------------- 3 files changed, 107 insertions(+), 88 deletions(-) diff --git a/api/src/org/labkey/api/pipeline/PipelineService.java b/api/src/org/labkey/api/pipeline/PipelineService.java index a9a849d3b8b..7368e6aafe9 100644 --- a/api/src/org/labkey/api/pipeline/PipelineService.java +++ b/api/src/org/labkey/api/pipeline/PipelineService.java @@ -132,6 +132,9 @@ static void setInstance(PipelineService instance) boolean isEnterprisePipeline(); + /** Generate command-line arguments to launch org.labkey.pipeline.cluster.ClusterStartup. Intended for automated tests */ + List getClusterStartupArguments() throws IOException; + enum JmsType { none, inProcess, external, unknown } @NotNull JmsType getJmsType(); diff --git a/pipeline/src/org/labkey/pipeline/api/PipelineServiceImpl.java b/pipeline/src/org/labkey/pipeline/api/PipelineServiceImpl.java index af9942c80b3..1952a56e680 100644 --- a/pipeline/src/org/labkey/pipeline/api/PipelineServiceImpl.java +++ b/pipeline/src/org/labkey/pipeline/api/PipelineServiceImpl.java @@ -18,7 +18,9 @@ import com.fasterxml.jackson.core.type.TypeReference; import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,6 +41,7 @@ import org.labkey.api.data.TableSelector; import org.labkey.api.exp.api.ExpRun; import org.labkey.api.files.FileContentService; +import org.labkey.api.module.ModuleLoader; import org.labkey.api.pipeline.AnalyzeForm; import org.labkey.api.pipeline.ParamParser; import org.labkey.api.pipeline.PipeRoot; @@ -68,6 +71,7 @@ import org.labkey.api.util.FileUtil; import org.labkey.api.util.JsonUtil; import org.labkey.api.util.NetworkDrive; +import org.labkey.api.util.Pair; import org.labkey.api.util.TestContext; import org.labkey.api.util.logging.LogHelper; import org.labkey.api.view.ActionURL; @@ -77,6 +81,7 @@ import org.labkey.api.view.UnauthorizedException; import org.labkey.api.view.ViewBackgroundInfo; import org.labkey.api.view.ViewContext; +import org.labkey.bootstrap.ClusterBootstrap; import org.labkey.pipeline.PipelineController; import org.labkey.pipeline.analysis.ProtocolManagementAuditProvider; import org.labkey.pipeline.importer.FolderImportJob; @@ -95,7 +100,10 @@ import javax.naming.InitialContext; import javax.naming.NamingException; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; @@ -113,6 +121,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; import static org.labkey.api.pipeline.PipelineJobNotificationProvider.DefaultPipelineJobNotificationProvider.DEFAULT_PIPELINE_JOB_NOTIFICATION_PROVIDER; import static org.labkey.api.pipeline.file.AbstractFileAnalysisJob.ANALYSIS_PARAMETERS_ROLE_NAME; @@ -446,6 +457,96 @@ public boolean isEnterprisePipeline() return (getPipelineQueue() instanceof EPipelineQueueImpl); } + /** @return first is labkeyBootstrap.jar, second is servletApi.jar */ + private Pair extractBootstrapFromEmbedded() throws IOException + { + File bootstrap = null; + File servlet = null; + // Look through the JAR files in the working directory, which is expected to contain the Spring Boot + // entrypoint and the Servlet API + File pwd = new File("."); + File[] jars = pwd.listFiles(f -> f.getName().toLowerCase().endsWith(".jar")); + for (File jar : jars) + { + try (JarFile j = new JarFile(jar)) + { + // Look inside the JAR for a labkeyBootstrap*.jar file + Iterator entries = j.entries().asIterator(); + while (entries.hasNext()) + { + JarEntry entry = entries.next(); + if (entry.getName().contains("labkeyBootstrap") && entry.getName().toLowerCase().endsWith(".jar")) + { + bootstrap = extractEntry(j, entry, "labkeyBootstrap.jar"); + } + if (entry.getName().contains("tomcat-servlet-api") && entry.getName().toLowerCase().endsWith(".jar")) + { + servlet = extractEntry(j, entry, "servletApi.jar"); + } + } + } + } + return Pair.of(bootstrap, servlet); + } + + private File extractEntry(JarFile jar, ZipEntry entry, String name) throws IOException + { + File result = FileUtil.getAbsoluteCaseSensitiveFile(new File(name)); + try (InputStream in = jar.getInputStream(entry); + OutputStream out = new FileOutputStream(result)) + { + IOUtils.copy(in, out); + } + return result; + } + + + @Override + public List getClusterStartupArguments() throws IOException + { + List args = new ArrayList<>(); + args.add(System.getProperty("java.home") + "/bin/java" + (SystemUtils.IS_OS_WINDOWS ? ".exe" : "")); + File labkeyBootstrap = new File(new File(new File(System.getProperty("catalina.home")), "lib"), "labkeyBootstrap.jar"); + File servletApi = null; + + if (!labkeyBootstrap.exists()) + { + Pair extracted = extractBootstrapFromEmbedded(); + labkeyBootstrap = extracted.first; + if (labkeyBootstrap == null || !labkeyBootstrap.exists()) + { + throw new IllegalStateException("Couldn't find labkeyBootstrap.jar"); + } + servletApi = extracted.second; + if (servletApi == null || !servletApi.exists()) + { + throw new IllegalStateException("Couldn't find servletApi.jar"); + } + } + + // Uncomment this line if you want to debug the forked process +// args.add("-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=*:5005"); + args.add("-cp"); + args.add(labkeyBootstrap.getPath()); + args.add(ClusterBootstrap.class.getName()); + + for (String sysProp : new String[]{"labkey.externalModulesDir", "labkey.modulesDir", "cpas.modulesDir"}) + { + String sysPropValue = StringUtils.trimToNull(System.getProperty(sysProp)); + if (sysPropValue != null) + { + args.add("-D" + sysProp +"=" + sysPropValue); + } + } + + args.add("-webappdir=" + ModuleLoader.getServletContext().getRealPath("")); + if (servletApi != null) + { + args.add("-pipelinelibdir=" + servletApi.getParent()); + } + return args; + } + @Override public @NotNull JmsType getJmsType() { diff --git a/pipeline/src/org/labkey/pipeline/cluster/ClusterStartup.java b/pipeline/src/org/labkey/pipeline/cluster/ClusterStartup.java index 0418d4ba2da..70f4a251ea1 100644 --- a/pipeline/src/org/labkey/pipeline/cluster/ClusterStartup.java +++ b/pipeline/src/org/labkey/pipeline/cluster/ClusterStartup.java @@ -16,18 +16,16 @@ package org.labkey.pipeline.cluster; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.SystemUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.labkey.api.module.ModuleLoader; import org.labkey.api.pipeline.PipelineJob; import org.labkey.api.pipeline.PipelineJobException; import org.labkey.api.pipeline.PipelineJobService; +import org.labkey.api.pipeline.PipelineService; import org.labkey.api.reader.Readers; import org.labkey.api.util.ContextListener; import org.labkey.api.util.FileUtil; @@ -35,7 +33,6 @@ import org.labkey.api.util.PageFlowUtil; import org.labkey.api.util.Pair; import org.labkey.api.util.TestContext; -import org.labkey.bootstrap.ClusterBootstrap; import org.labkey.pipeline.AbstractPipelineStartup; import org.labkey.pipeline.mule.test.DummyPipelineJob; import org.mule.umo.manager.UMOManager; @@ -43,22 +40,13 @@ import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.zip.ZipEntry; /** * Entry point for pipeline jobs that are invoked on a cluster node. After completion of the job, the process @@ -273,91 +261,18 @@ protected String executeJobRemote(List args, int expectedExitCode) throw @NotNull private List createArgs(@Nullable PipelineJob job) throws IOException { - List args = new ArrayList<>(); - args.add(System.getProperty("java.home") + "/bin/java" + (SystemUtils.IS_OS_WINDOWS ? ".exe" : "")); - File labkeyBootstrap = new File(new File(new File(System.getProperty("catalina.home")), "lib"), "labkeyBootstrap.jar"); - File servletApi = null; - - if (!labkeyBootstrap.exists()) - { - Pair extracted = extractBootstrapFromEmbedded(); - labkeyBootstrap = extracted.first; - if (labkeyBootstrap == null || !labkeyBootstrap.exists()) - { - throw new IllegalStateException("Couldn't find labkeyBootstrap.jar"); - } - servletApi = extracted.second; - if (servletApi == null || !servletApi.exists()) - { - throw new IllegalStateException("Couldn't find servletApi.jar"); - } - } - - // Uncomment this line if you want to debug the forked process -// args.add("-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=*:5005"); - args.add("-cp"); - args.add(labkeyBootstrap.getPath()); - args.add(ClusterBootstrap.class.getName()); - args.add("-webappdir=" + ModuleLoader.getServletContext().getRealPath("")); - if (servletApi != null) - { - args.add("-pipelinelibdir=" + servletApi.getParent()); - } - + List args = PipelineService.get().getClusterStartupArguments(); if (job != null) { // Serialize to a file File serializedJob = new File(_tempDir, "job.json"); File log = new File(_tempDir, "job.log"); - job.setLogFile(log); + job.setLogFile(log.toPath()); job.writeToFile(serializedJob); args.add(serializedJob.toURI().toString()); } return args; } - - /** @return first is labkeyBootstrap.jar, second is servletApi.jar */ - private Pair extractBootstrapFromEmbedded() throws IOException - { - File bootstrap = null; - File servlet = null; - // Look through the JAR files in the working directory, which is expected to contain the Spring Boot - // entrypoint and the Servlet API - File pwd = new File("."); - File[] jars = pwd.listFiles(f -> f.getName().toLowerCase().endsWith(".jar")); - for (File jar : jars) - { - try (JarFile j = new JarFile(jar)) - { - // Look inside the JAR for a labkeyBootstrap*.jar file - Iterator entries = j.entries().asIterator(); - while (entries.hasNext()) - { - JarEntry entry = entries.next(); - if (entry.getName().contains("labkeyBootstrap") && entry.getName().toLowerCase().endsWith(".jar")) - { - bootstrap = extractEntry(j, entry, "labkeyBootstrap.jar"); - } - if (entry.getName().contains("tomcat-servlet-api") && entry.getName().toLowerCase().endsWith(".jar")) - { - servlet = extractEntry(j, entry, "servletApi.jar"); - } - } - } - } - return Pair.of(bootstrap, servlet); - } - - private File extractEntry(JarFile jar, ZipEntry entry, String name) throws IOException - { - File result = FileUtil.getAbsoluteCaseSensitiveFile(new File(name)); - try (InputStream in = jar.getInputStream(entry); - OutputStream out = new FileOutputStream(result)) - { - IOUtils.copy(in, out); - } - return result; - } } }