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

epugh pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/branch_10x by this push:
     new e3d0064289d SOLR-18118: Add in --prompt-inputs to bin/solr start -e 
cloud to programatically respond to input prompts (#4127)
e3d0064289d is described below

commit e3d0064289dcaf88c5d979dd56d68145ee72a872
Author: Eric Pugh <[email protected]>
AuthorDate: Wed Feb 18 06:05:55 2026 -0500

    SOLR-18118: Add in --prompt-inputs to bin/solr start -e cloud to 
programatically respond to input prompts (#4127)
    
    Adds a non-interactive way to run bin/solr start -e cloud by supplying 
ordered prompt answers on the command line, enabling scripted/automated cluster 
startup while keeping existing interactive behavior available.
    
    (cherry picked from commit b71c872c35b1a12551e3d9b832c1ef9c40a1ea0a)
---
 changelog/unreleased/SOLR-18118.yml                |   9 ++
 solr/bin/solr                                      |  24 +++--
 solr/bin/solr.cmd                                  |  22 +++--
 .../java/org/apache/solr/cli/RunExampleTool.java   |  56 ++++++++++-
 .../org/apache/solr/cli/TestSolrCLIRunExample.java | 110 +++++++++++++++++++++
 .../pages/solr-control-script-reference.adoc       |  89 ++++++++++-------
 6 files changed, 256 insertions(+), 54 deletions(-)

diff --git a/changelog/unreleased/SOLR-18118.yml 
b/changelog/unreleased/SOLR-18118.yml
new file mode 100644
index 00000000000..e3d703091ff
--- /dev/null
+++ b/changelog/unreleased/SOLR-18118.yml
@@ -0,0 +1,9 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: Script creating a cluster using bin/solr start -e cloud with 
--prompt-inputs option.
+type: added # added, changed, fixed, deprecated, removed, dependency_update, 
security, other
+authors:
+  - name: Eric Pugh
+  - name: Rahul Goswami
+links:
+  - name: SOLR-18118
+    url: https://issues.apache.org/jira/browse/SOLR-18118
diff --git a/solr/bin/solr b/solr/bin/solr
index ec7f596144d..eaa417ca90d 100755
--- a/solr/bin/solr
+++ b/solr/bin/solr
@@ -407,12 +407,6 @@ function print_usage() {
     echo "  --data-home <dir>     Sets the solr.data.home system property, 
where Solr will store index data in <instance_dir>/data subdirectories."
     echo "                          If not set, Solr uses solr.solr.home for 
config and data."
     echo ""
-    echo "  -e/--example <name>   Name of the example to run; available 
examples:"
-    echo "      cloud:              SolrCloud example"
-    echo "      techproducts:       Comprehensive example illustrating many of 
Solr's core capabilities"
-    echo "      schemaless:         Schema-less example (schema is inferred 
from data during indexing)"
-    echo "      films:              Example of starting with _default 
configset and adding explicit fields dynamically"
-    echo ""
     echo "  --jvm-opts <jvmParams> Additional parameters to pass to the JVM 
when starting Solr, such as to setup"
     echo "                          Java debug options. For example, to enable 
a Java debugger to attach to the Solr JVM"
     echo "                          you could pass: --jvm-opts 
\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=18983\""
@@ -423,7 +417,15 @@ function print_usage() {
     echo "                          you could pass: -j 
\"--include-jetty-dir=/etc/jetty/custom/server/\""
     echo "                          In most cases, you should wrap the 
additional parameters in double quotes."
     echo ""
-    echo "  -y/--no-prompt        Don't prompt for input; accept all defaults 
when running examples that accept user input"
+    echo "  -e/--example <name>   Name of the example to run; available 
examples:"
+    echo "      cloud:              SolrCloud example"
+    echo "      techproducts:       Comprehensive example illustrating many of 
Solr's core capabilities"
+    echo "      schemaless:         Schema-less example (schema is inferred 
from data during indexing)"
+    echo "      films:              Example of starting with _default 
configset and adding explicit fields dynamically"
+    echo ""
+    echo "  -y/--no-prompt        Don't prompt for input; accept all defaults 
when running examples that accept user input."
+    echo ""
+    echo "  --prompt-inputs <values> Don't prompt for input; comma delimited 
list of inputs read when running examples that accept user input."
     echo ""
     echo "  --force               If attempting to start Solr as the root 
user, the script will exit with a warning that running Solr as \"root\" can 
cause problems."
     echo "                          It is possible to override this warning 
with the '--force' parameter."
@@ -817,6 +819,14 @@ if [ $# -gt 0 ]; then
             PASS_TO_RUN_EXAMPLE+=("--no-prompt")
             shift
         ;;
+        --prompt-inputs)
+        if [[ -z "$2" || "${2:0:1}" == "-" ]]; then
+          print_usage "$SCRIPT_CMD" "Prompt values are required when using the 
$1 option!"
+          exit 1
+        fi
+        PASS_TO_RUN_EXAMPLE+=("--prompt-inputs" "$2")
+        shift 2
+        ;;        
         --verbose)
             verbose=true
             SOLR_LOG_LEVEL=DEBUG
diff --git a/solr/bin/solr.cmd b/solr/bin/solr.cmd
index 52be92ed3de..e30cc4416fa 100755
--- a/solr/bin/solr.cmd
+++ b/solr/bin/solr.cmd
@@ -325,12 +325,6 @@ goto err
 @echo   --data-home dir Sets the solr.data.home system property, where Solr 
will store index data in ^<instance_dir^>/data subdirectories.
 @echo                   If not set, Solr uses solr.solr.home for both config 
and data.
 @echo.
-@echo   -e/--example name Name of the example to run; available examples:
-@echo       cloud:          SolrCloud example
-@echo       techproducts:   Comprehensive example illustrating many of Solr's 
core capabilities
-@echo       schemaless:     Schema-less example (schema is inferred from data 
during indexing)
-@echo       films:          Example of starting with _default configset and 
defining explicit fields dynamically
-@echo.
 @echo   --jvm-opts opts Additional parameters to pass to the JVM when starting 
Solr, such as to setup
 @echo                 Java debug options. For example, to enable a Java 
debugger to attach to the Solr JVM
 @echo                 you could pass: --jvm-opts 
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=18983"
@@ -341,8 +335,16 @@ goto err
 @echo                 you could pass: -j 
"--include-jetty-dir=/etc/jetty/custom/server/"
 @echo                 In most cases, you should wrap the additional parameters 
in double quotes.
 @echo.
+@echo   -e/--example name Name of the example to run; available examples:
+@echo       cloud:          SolrCloud example
+@echo       techproducts:   Comprehensive example illustrating many of Solr's 
core capabilities
+@echo       schemaless:     Schema-less example (schema is inferred from data 
during indexing)
+@echo       films:          Example of starting with _default configset and 
defining explicit fields dynamically
+@echo.
 @echo   -y/--no-prompt Don't prompt for input; accept all defaults when 
running examples that accept user input
 @echo.
+@echo   --prompt-inputs values Don't prompt for input; comma delimited list of 
inputs read when running examples that accept user input.
+@echo.
 @echo   --verbose and -q/--quiet Verbose or quiet logging. Sets default log 
level to DEBUG or WARN instead of INFO
 @echo.
 goto done
@@ -399,6 +401,7 @@ IF "%1"=="-j" goto set_addl_jetty_config
 IF "%1"=="--jettyconfig" goto set_addl_jetty_config
 IF "%1"=="-y" goto set_noprompt
 IF "%1"=="--no-prompt" goto set_noprompt
+IF "%1"=="--prompt-inputs" goto set_prompt_inputs
 
 REM Skip stop arg parsing if not stop command
 IF NOT "%SCRIPT_CMD%"=="stop" goto parse_general_args
@@ -695,6 +698,13 @@ set "PASS_TO_RUN_EXAMPLE=--no-prompt !PASS_TO_RUN_EXAMPLE!"
 SHIFT
 goto parse_args
 
+:set_prompt_inputs
+set "PASS_TO_RUN_EXAMPLE=--prompt-inputs %~2 !PASS_TO_RUN_EXAMPLE!"
+
+SHIFT
+SHIFT
+goto parse_args
+
 REM Handle invalid arguments passed to special commands (start, stop, restart)
 :invalid_cmd_line
 @echo.
diff --git a/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java 
b/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java
index 9fcd71c911d..b5b21f6450f 100644
--- a/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java
@@ -73,6 +73,16 @@ public class RunExampleTool extends ToolBase {
               "Don't prompt for input; accept all defaults when running 
examples that accept user input.")
           .build();
 
+  private static final Option PROMPT_INPUTS_OPTION =
+      Option.builder()
+          .longOpt("prompt-inputs")
+          .hasArg()
+          .argName("VALUES")
+          .desc(
+              "Provide comma-separated values for prompts. Same as --no-prompt 
but uses provided values instead of defaults. "
+                  + "Example: --prompt-inputs 
3,8983,8984,8985,\"gettingstarted\",2,2,_default")
+          .build();
+
   private static final Option EXAMPLE_OPTION =
       Option.builder("e")
           .longOpt("example")
@@ -176,6 +186,7 @@ public class RunExampleTool extends ToolBase {
   protected Path exampleDir;
   protected Path solrHomeDir;
   protected String urlScheme;
+  private boolean usingPromptInputs = false;
 
   /** Default constructor used by the framework when running as a command-line 
application. */
   public RunExampleTool(ToolRuntime runtime) {
@@ -197,6 +208,7 @@ public class RunExampleTool extends ToolBase {
   public Options getOptions() {
     return super.getOptions()
         .addOption(NO_PROMPT_OPTION)
+        .addOption(PROMPT_INPUTS_OPTION)
         .addOption(EXAMPLE_OPTION)
         .addOption(SCRIPT_OPTION)
         .addOption(SERVER_DIR_OPTION)
@@ -214,6 +226,12 @@ public class RunExampleTool extends ToolBase {
 
   @Override
   public void runImpl(CommandLine cli) throws Exception {
+    if (cli.hasOption(NO_PROMPT_OPTION) && 
cli.hasOption(PROMPT_INPUTS_OPTION)) {
+      throw new IllegalArgumentException(
+          "Cannot use both --no-prompt and --prompt-inputs options together. "
+              + "Use --no-prompt to accept defaults, or --prompt-inputs to 
provide specific values.");
+    }
+
     this.urlScheme = cli.getOptionValue(URL_SCHEME_OPTION, "http");
     String exampleType = cli.getOptionValue(EXAMPLE_OPTION);
 
@@ -515,6 +533,7 @@ public class RunExampleTool extends ToolBase {
 
   protected void runCloudExample(CommandLine cli) throws Exception {
 
+    usingPromptInputs = cli.hasOption(PROMPT_INPUTS_OPTION);
     boolean prompt = !cli.hasOption(NO_PROMPT_OPTION);
     int numNodes = 2;
     int[] cloudPorts = new int[] {8983, 7574, 8984, 7575};
@@ -530,10 +549,24 @@ public class RunExampleTool extends ToolBase {
 
     echo("\nWelcome to the SolrCloud example!\n");
 
-    Scanner readInput = prompt ? new Scanner(userInput, 
StandardCharsets.UTF_8) : null;
+    Scanner readInput = null;
+    if (usingPromptInputs) {
+      // Create a scanner from the provided prompts
+      String promptsValue = cli.getOptionValue(PROMPT_INPUTS_OPTION);
+      InputStream promptsStream =
+          new 
java.io.ByteArrayInputStream(promptsValue.getBytes(StandardCharsets.UTF_8));
+      readInput = new Scanner(promptsStream, StandardCharsets.UTF_8);
+      readInput.useDelimiter(",");
+      prompt = true; // Enable prompting code path, but reading from prompts 
instead of user
+    } else if (prompt) {
+      readInput = new Scanner(userInput, StandardCharsets.UTF_8);
+    }
+
     if (prompt) {
-      echo(
-          "This interactive session will help you launch a SolrCloud cluster 
on your local workstation.");
+      if (!usingPromptInputs) {
+        echo(
+            "This interactive session will help you launch a SolrCloud cluster 
on your local workstation.");
+      }
 
       // get the number of nodes to start
       numNodes =
@@ -1121,9 +1154,24 @@ public class RunExampleTool extends ToolBase {
 
   protected String prompt(Scanner s, String prompt, String defaultValue) {
     echo(prompt);
-    String nextInput = s.nextLine();
+    String nextInput;
+    if (usingPromptInputs) {
+      // Reading from prompts option - use next() instead of nextLine()
+      nextInput = s.hasNext() ? s.next() : null;
+      // Echo the value being used from prompts
+      if (nextInput != null) {
+        echo(nextInput);
+      }
+    } else {
+      // Reading from user input - use nextLine()
+      nextInput = s.nextLine();
+    }
     if (nextInput != null) {
       nextInput = nextInput.trim();
+      // Remove quotes if present (for values like "gettingstarted")
+      if (nextInput.startsWith("\"") && nextInput.endsWith("\"")) {
+        nextInput = nextInput.substring(1, nextInput.length() - 1);
+      }
       if (nextInput.isEmpty()) nextInput = null;
     }
     return (nextInput != null) ? nextInput : defaultValue;
diff --git a/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java 
b/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
index db26383eb7f..298bbfb0644 100644
--- a/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
+++ b/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
@@ -525,6 +525,116 @@ public class TestSolrCLIRunExample extends SolrTestCaseJ4 
{
     executor.execute(org.apache.commons.exec.CommandLine.parse("bin/solr stop 
-p " + bindPort));
   }
 
+  /**
+   * Test the --prompt-inputs option that allows providing all prompt values 
as a comma-separated
+   * string without requiring interactive input.
+   */
+  @Test
+  public void testSolrCloudExampleWithPrompts() throws Exception {
+    Path solrHomeDir = ExternalPaths.SERVER_HOME;
+    if (!Files.isDirectory(solrHomeDir))
+      fail(solrHomeDir + " not found and is required to run this test!");
+
+    Path solrExampleDir = createTempDir();
+    Path solrServerDir = solrHomeDir.getParent();
+
+    int bindPort = -1;
+    try (ServerSocket socket = new ServerSocket(0)) {
+      bindPort = socket.getLocalPort();
+    }
+
+    String collectionName = "testCloudExampleWithPrompts";
+
+    // Provide all prompt values via --prompt-inputs option:
+    // numNodes, port1, collectionName, numShards, replicationFactor, 
configName
+    String promptsValue = "1," + bindPort + ",\"" + collectionName + 
"\",2,2,_default";
+
+    String[] toolArgs =
+        new String[] {
+          "--example",
+          "cloud",
+          "--server-dir",
+          solrServerDir.toString(),
+          "--example-dir",
+          solrExampleDir.toString(),
+          "--prompt-inputs",
+          promptsValue
+        };
+
+    // capture tool output to stdout
+    CLITestHelper.TestingRuntime runtime = new 
CLITestHelper.TestingRuntime(true);
+
+    RunExampleExecutor executor = new RunExampleExecutor();
+    closeables.add(executor);
+
+    RunExampleTool tool = new RunExampleTool(executor, System.in, runtime);
+    try {
+      tool.runTool(SolrCLI.processCommandLineArgs(tool, toolArgs));
+    } catch (Exception e) {
+      System.err.println(
+          "RunExampleTool failed due to: "
+              + e
+              + "; stdout from tool prior to failure: "
+              + runtime.getOutput());
+      throw e;
+    }
+
+    String toolOutput = runtime.getOutput();
+
+    // verify Solr is running on the expected port and verify the collection 
exists
+    String solrUrl = "http://localhost:"; + bindPort + "/solr";
+    if (!CLIUtils.safeCheckCollectionExists(solrUrl, collectionName, null)) {
+      fail(
+          "After running Solr cloud example with --prompt-inputs, test 
collection '"
+              + collectionName
+              + "' not found in Solr at: "
+              + solrUrl
+              + "; tool output: "
+              + toolOutput);
+    }
+
+    // verify the collection was created with the specified parameters
+    try (CloudSolrClient cloudClient =
+        new RandomizingCloudSolrClientBuilder(
+                
Collections.singletonList(executor.solrCloudCluster.getZkServer().getZkAddress()),
+                Optional.empty())
+            .withDefaultCollection(collectionName)
+            .build()) {
+
+      // index some test docs to verify the collection works
+      int numDocs = 5;
+      for (int d = 0; d < numDocs; d++) {
+        SolrInputDocument doc = new SolrInputDocument();
+        doc.setField("id", "doc" + d);
+        doc.setField("test_s", "prompts");
+        cloudClient.add(doc);
+      }
+      cloudClient.commit();
+
+      QueryResponse qr = cloudClient.query(new SolrQuery("test_s:prompts"));
+      assertEquals(
+          "Expected "
+              + numDocs
+              + " docs in the "
+              + collectionName
+              + " collection created via --prompts",
+          numDocs,
+          qr.getResults().getNumFound());
+    }
+
+    // Verify output contains the prompts values
+    assertTrue(
+        "Tool output should contain the collection name", 
toolOutput.contains(collectionName));
+
+    // delete the collection
+    DeleteTool deleteTool = new DeleteTool(runtime);
+    String[] deleteArgs = new String[] {"--name", collectionName, 
"--solr-url", solrUrl};
+    deleteTool.runTool(SolrCLI.processCommandLineArgs(deleteTool, deleteArgs));
+
+    // stop the test instance
+    executor.execute(org.apache.commons.exec.CommandLine.parse("bin/solr stop 
-p " + bindPort));
+  }
+
   @Test
   public void testFailExecuteScript() throws Exception {
     Path solrHomeDir = ExternalPaths.SERVER_HOME;
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
 
b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
index 577c566eb4a..a7348059cc2 100644
--- 
a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
+++ 
b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
@@ -106,27 +106,6 @@ When running multiple instances of Solr on the same host, 
it is more common to u
 +
 *Example*: `bin/solr start --server-dir newServerDir`
 
-`-e <name>`::
-+
-[%autowidth,frame=none]
-|===
-|Optional |Default: none
-|===
-+
-Start Solr with an example configuration.
-These examples are provided to help you get started faster with Solr 
generally, or just try a specific feature.
-+
-The available options are:
-
-* `cloud`: SolrCloud example
-* `techproducts`: Comprehensive example illustrating many of Solr's core 
capabilities
-* `schemaless`: Schema-less example (schema is inferred from data during 
indexing)
-* `films`: Example of starting with _default configset and adding explicit 
fields dynamically
-+
-See the section <<Running with Example Configurations>> below for more details 
on the example configurations.
-+
-*Example*: `bin/solr start -e schemaless`
-
 `-f`::
 +
 [%autowidth,frame=none]
@@ -162,20 +141,6 @@ Sets the min (`-Xms`) and max (`-Xmx`) heap size for the 
JVM running Solr.
 +
 *Example*: `bin/solr start -m 4g` results in `-Xms4g -Xmx4g` settings.
 
-`--no-prompt`::
-+
-[%autowidth,frame=none]
-|===
-|Optional |Default: none
-|===
-+
-Don't prompt for input; accept all defaults when running examples that accept 
user input.
-+
-For example, when using the "cloud" example, an interactive session guides you 
through several options for your SolrCloud cluster.
-If you want to accept all of the defaults, you can simply add the 
`--no-prompt` option to your request.
-+
-*Example*: `bin/solr start -e cloud --no-prompt`
-
 `-p <port>`::
 +
 [%autowidth,frame=none]
@@ -277,6 +242,56 @@ To emphasize how the default settings work take a moment 
to understand that the
 
 `bin/solr start --host localhost -p 8983 --server-dir server --solr-home solr 
-m 512m`
 
+`-e <name>` or `--example <name>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: none
+|===
++
+Start Solr with an example configuration.
+These examples are provided to help you get started faster with Solr 
generally, or just try a specific feature.
++
+The available options are:
+
+* `cloud`: SolrCloud example
+* `techproducts`: Comprehensive example illustrating many of Solr's core 
capabilities
+* `schemaless`: Schema-less example (schema is inferred from data during 
indexing)
+* `films`: Example of starting with _default configset and adding explicit 
fields dynamically
++
+See the section <<Running with Example Configurations>> below for more details 
on the example configurations.
++
+*Example*: `bin/solr start -e schemaless`
+
+`--no-prompt`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: none
+|===
++
+Don't prompt for input; accept all defaults when running examples that accept 
input.
++
+For example, when using the "cloud" example, an interactive session guides you 
through several options for your SolrCloud cluster.
+If you want to accept all of the defaults, you can simply add the 
`--no-prompt` option to your request.
++
+*Example*: `bin/solr start -e cloud --no-prompt`
+
+`--prompt-inputs <values>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: none
+|===
++
+Don't prompt for input; instead supply ordered answers in comma delimited 
format when running examples that accept input.
++
+For example, when using the "cloud" example, you can answer the prompts 
non-interactively to start a three node cluster on specific ports:
++
+*Example*: `bin/solr start -e cloud --prompt-inputs 
3,9000,9001,9002,"mycollection",2,2,_default`
+
+On Windows please wrap the prompts value in double quotes to preserve the 
comma delimited format.
+
 It is not necessary to define all of the options when starting if the defaults 
are fine for your needs.
 
 ==== Setting Java System Properties
@@ -676,7 +691,7 @@ This defaults to the same name as the collection or core.
 +
 *Example*: `bin/solr create -n basic`
 
-`-sh <shards>` or `-shards <shards>`::
+`-sh <shards>` or `--shards <shards>`::
 +
 [%autowidth,frame=none]
 |===
@@ -937,7 +952,7 @@ Either `--credentials` or `--prompt` *must* be specified.
 When `true`, this blocks out access to unauthenticated users from accessing 
Solr.
 When `false`, unauthenticated users will still be able to access Solr, but 
only for operations not explicitly requiring a user role in the Authorization 
plugin configuration.
 
-`--solrIncludeFile <includeFilePath>`::
+`--solr-include-file <includeFilePath>`::
 +
 [%autowidth,frame=none]
 |===

Reply via email to