This is an automated email from the ASF dual-hosted git repository.
janhoy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 6315d3fe2ca SOLR-17717 Use Powershell instead of WMIC to get cmdline
on Windows (#3291)
6315d3fe2ca is described below
commit 6315d3fe2ca46fe7a30a33f4b8deea906d7090c0
Author: Jan Høydahl <[email protected]>
AuthorDate: Thu Apr 17 23:28:50 2025 +0200
SOLR-17717 Use Powershell instead of WMIC to get cmdline on Windows (#3291)
---
solr/CHANGES.txt | 2 +
.../org/apache/solr/cli/SolrProcessManager.java | 93 ++++++++++++++--------
.../apache/solr/cli/SolrProcessManagerTest.java | 11 +++
3 files changed, 72 insertions(+), 34 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 5a8522e5ba9..28a44d546aa 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -261,6 +261,8 @@ Bug Fixes
* SOLR-12831: Clean up shard metadata in ZooKeeper nodes after shard deletion
is invoked. This makes sure Zookeeper
nodes for leader election and terms are not left behind (Andy Vuong, Pierre
Salagnac).
+* SOLR-17717: Starting solr on newer Windows 11 Home complained about missing
wmic (Jan Høydahl)
+
Dependency Upgrades
---------------------
* SOLR-17471: Upgrade Lucene to 9.12.1. (Pierre Salagnac, Christine Poerschke)
diff --git a/solr/core/src/java/org/apache/solr/cli/SolrProcessManager.java
b/solr/core/src/java/org/apache/solr/cli/SolrProcessManager.java
index b36575ae27d..f45bc5dbd66 100644
--- a/solr/core/src/java/org/apache/solr/cli/SolrProcessManager.java
+++ b/solr/core/src/java/org/apache/solr/cli/SolrProcessManager.java
@@ -18,9 +18,10 @@ package org.apache.solr.cli;
import static
org.apache.solr.servlet.SolrDispatchFilter.SOLR_INSTALL_DIR_ATTRIBUTE;
-import java.io.BufferedReader;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -28,6 +29,7 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -35,6 +37,7 @@ import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.apache.commons.io.IOUtils;
import org.apache.lucene.util.Constants;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.EnvUtils;
@@ -52,8 +55,12 @@ public class SolrProcessManager {
// Set this to true during testing to allow the SolrProcessManager to find
only mock Solr
// processes
public static boolean enableTestingMode = false;
+ private static final Map<Long, String> pidToWindowsCommandLineMap = new
HashMap<>();
public SolrProcessManager() {
+ if (Constants.WINDOWS) {
+ pidToWindowsCommandLineMap.putAll(commandLinesWindows());
+ }
pidProcessMap =
ProcessHandle.allProcesses()
.filter(p -> p.info().command().orElse("").contains("java"))
@@ -151,8 +158,8 @@ public class SolrProcessManager {
}
/**
- * Gets the command line of a process as a string. This is a workaround for
the fact that
- * ProcessHandle.info().command() is not (yet) implemented on Windows.
+ * Gets the command line of a process as a string. For Windows we need to
fetch command lines
+ * using a PowerShell command.
*
* @param ph the process handle
* @return the command line of the process
@@ -161,42 +168,60 @@ public class SolrProcessManager {
if (!Constants.WINDOWS) {
return ph.info().commandLine();
} else {
- long desiredProcessid = ph.pid();
- try {
- Process process =
- new ProcessBuilder(
- "wmic",
- "process",
- "where",
- "ProcessID=" + desiredProcessid,
- "get",
- "commandline",
- "/format:list")
- .redirectErrorStream(true)
- .start();
- try (InputStreamReader inputStreamReader =
- new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8);
- BufferedReader reader = new BufferedReader(inputStreamReader)) {
- while (true) {
- String line = reader.readLine();
- if (line == null) {
- return Optional.empty();
- }
- if (!line.startsWith("CommandLine=")) {
- continue;
- }
- return Optional.of(line.substring("CommandLine=".length()));
- }
- }
- } catch (IOException e) {
+ return Optional.ofNullable(pidToWindowsCommandLineMap.get(ph.pid()));
+ }
+ }
+
+ /**
+ * Gets the command lines of all java processes on Windows using PowerShell.
+ *
+ * @return a map of process IDs to command lines
+ */
+ private static Map<Long, String> commandLinesWindows() {
+ try {
+ Process process =
+ new ProcessBuilder(
+ "powershell.exe",
+ "-Command",
+ "Get-CimInstance -ClassName Win32_Process | Where-Object {
$_.Name -like '*java*' } | Select-Object ProcessId, CommandLine |
ConvertTo-Json -Depth 1")
+ .redirectErrorStream(true)
+ .start();
+ String output = IOUtils.toString(process.getInputStream(),
StandardCharsets.UTF_8);
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ String errorText = IOUtils.toString(process.getErrorStream(),
StandardCharsets.UTF_8);
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
- "Error getting command line for process " + desiredProcessid,
- e);
+ "Error getting command lines for Windows: " + errorText);
}
+ return parseWindowsPidToCommandLineJson(output);
+ } catch (IOException e) {
+ throw new SolrException(
+ SolrException.ErrorCode.SERVER_ERROR, "Error getting command lines
for Windows");
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new SolrException(
+ SolrException.ErrorCode.SERVER_ERROR,
+ "Interrupted while getting command lines for Windows");
}
}
+ static Map<Long, String> parseWindowsPidToCommandLineJson(String jsonString)
+ throws JsonProcessingException {
+ // Json format: [{"ProcessId": 1234, "CommandLine": "java foo"}]
+ ObjectMapper mapper = new ObjectMapper();
+ List<WindowsProcessInfo> processInfoList =
+ mapper.readValue(jsonString, new TypeReference<>() {});
+ return processInfoList.stream()
+ .filter(p -> p.CommandLine != null)
+ .collect(Collectors.toMap(p -> p.ProcessId, p -> p.CommandLine));
+ }
+
+ public static class WindowsProcessInfo {
+ public long ProcessId;
+ public String CommandLine;
+ }
+
/**
* Gets the arguments of a process as a list of strings. With workaround for
Windows.
*
diff --git a/solr/core/src/test/org/apache/solr/cli/SolrProcessManagerTest.java
b/solr/core/src/test/org/apache/solr/cli/SolrProcessManagerTest.java
index c715ad676d9..c0bb17f59c7 100644
--- a/solr/core/src/test/org/apache/solr/cli/SolrProcessManagerTest.java
+++ b/solr/core/src/test/org/apache/solr/cli/SolrProcessManagerTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.solr.cli;
+import com.fasterxml.jackson.core.JsonProcessingException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -27,6 +28,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.math3.util.Pair;
import org.apache.solr.SolrTestCase;
@@ -177,6 +179,15 @@ public class SolrProcessManagerTest extends SolrTestCase {
assertEquals("https://localhost:" + processHttps.getKey() + "/solr",
https.getLocalUrl());
}
+ public void testParseWindowsPidToCommandLineJson() throws
JsonProcessingException {
+ String jsonResponseFromPowershell =
+ "[{\"ProcessId\": 9356, \"CommandLine\": \"date\"}, {\"ProcessId\":
4736, \"CommandLine\": null}\n]";
+ Map<Long, String> pidToCommandLine =
+
SolrProcessManager.parseWindowsPidToCommandLineJson(jsonResponseFromPowershell);
+ assertEquals(1, pidToCommandLine.size());
+ assertEquals("date", pidToCommandLine.get(9356L));
+ }
+
/**
* This class is started as new java process by {@link
SolrProcessManagerTest#createProcess}, and
* it listens to a HTTP(s) port to simulate a real Solr process.