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

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


The following commit(s) were added to refs/heads/master by this push:
     new 570ab71c9 IMPALA-14287: Resolve environment variables in REST server 
configurations
570ab71c9 is described below

commit 570ab71c9d91f034ad8dc59d48b482a52b28fb50
Author: Peter Rozsa <[email protected]>
AuthorDate: Wed Sep 24 13:42:46 2025 +0200

    IMPALA-14287: Resolve environment variables in REST server configurations
    
    This change adds a step to REST server configuration loading that
    resolves environment variables noted as ${ENV:VARIABLE_NAME} format. If
    the environment variable is not set, then the reference text remains the
    same and Impala logs an error.
    
    Tests:
      - unit tests added
    
    Change-Id: I3faccc15d012c389703c58371a4d38cca82bef60
    Reviewed-on: http://gerrit.cloudera.org:8080/23457
    Reviewed-by: Impala Public Jenkins <[email protected]>
    Tested-by: Impala Public Jenkins <[email protected]>
---
 .../service/catalogmanager/ConfigLoader.java       | 44 ++++++++++
 .../service/catalogmanager/ConfigLoaderTest.java   | 96 +++++++++++++++++++++-
 2 files changed, 139 insertions(+), 1 deletion(-)

diff --git 
a/fe/src/main/java/org/apache/impala/service/catalogmanager/ConfigLoader.java 
b/fe/src/main/java/org/apache/impala/service/catalogmanager/ConfigLoader.java
index 0a7bf1283..bf72e7366 100644
--- 
a/fe/src/main/java/org/apache/impala/service/catalogmanager/ConfigLoader.java
+++ 
b/fe/src/main/java/org/apache/impala/service/catalogmanager/ConfigLoader.java
@@ -25,16 +25,29 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Properties;
+import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import org.apache.impala.common.ImpalaRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ConfigLoader {
 
+  private static final Logger LOG = 
LoggerFactory.getLogger(ConfigLoader.class);
+
   private final File configFolder_;
+  private final UnaryOperator<String> envVarResolver_;
 
   public ConfigLoader(File configFolder) {
+    this(configFolder, System::getenv);
+  }
+
+  public ConfigLoader(File configFolder, UnaryOperator<String> envVarResolver) 
{
     this.configFolder_ = configFolder;
+    this.envVarResolver_ = envVarResolver;
   }
 
   public List<Properties> loadConfigs() throws ImpalaRuntimeException {
@@ -68,9 +81,40 @@ public class ConfigLoader {
     try (InputStream in = Files.newInputStream(file.toPath())) {
       props.load(in);
     }
+    this.resolveEnvVars(props);
     return props;
   }
 
+  private void resolveEnvVars(Properties props) {
+    for (String key : props.stringPropertyNames()) {
+      String value = props.getProperty(key);
+      String resolved = resolveEnvVar(value);
+      props.setProperty(key, resolved);
+    }
+  }
+
+  private String resolveEnvVar(String input) {
+    if (input == null || input.isEmpty()) return input;
+    Pattern pattern = Pattern.compile("\\$\\{ENV:([a-zA-Z][a-zA-Z0-9_-]*)}");
+    Matcher matcher = pattern.matcher(input);
+    StringBuffer sb = new StringBuffer();
+    while (matcher.find()) {
+      String envVarName = matcher.group(1);
+      String envVarValue = this.envVarResolver_.apply(envVarName);
+      String replacement;
+      if (envVarValue == null) {
+        LOG.error("Unable to resolve environment variable: '{}'", envVarName);
+        replacement = matcher.group(0);
+      }
+      else {
+        replacement = envVarValue;
+      }
+      matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
+    }
+    matcher.appendTail(sb);
+    return sb.toString();
+  }
+
   private void checkPropertyValue(String configFile, Properties props, String 
key,
       String expectedValue) {
     if (!props.containsKey(key)) {
diff --git 
a/fe/src/test/java/org/apache/impala/service/catalogmanager/ConfigLoaderTest.java
 
b/fe/src/test/java/org/apache/impala/service/catalogmanager/ConfigLoaderTest.java
index a1ef153b8..326940c98 100644
--- 
a/fe/src/test/java/org/apache/impala/service/catalogmanager/ConfigLoaderTest.java
+++ 
b/fe/src/test/java/org/apache/impala/service/catalogmanager/ConfigLoaderTest.java
@@ -18,6 +18,7 @@ package org.apache.impala.service.catalogmanager;
 
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -124,4 +125,97 @@ public class ConfigLoaderTest {
     List<Properties> configs = loader.loadConfigs();
     assertTrue(configs.isEmpty());
   }
-}
\ No newline at end of file
+
+  @Test
+  public void testEnvVarResolutionResolved() throws Exception {
+    String pathValue = System.getenv("PATH");
+    createConfigFile("resolved.properties",
+        
"path=${ENV:PATH}\nconnector.name=iceberg\niceberg.catalog.type=rest\n");
+    ConfigLoader loader = new ConfigLoader(tempDir);
+    List<Properties> configs = loader.loadConfigs();
+    assertEquals(1, configs.size());
+    assertNotNull(pathValue);
+    assertEquals(pathValue, configs.get(0).getProperty("path"));
+  }
+
+  @Test
+  public void testEnvVarResolutionUnresolved() throws Exception {
+    createConfigFile("unresolved.properties",
+        
"secret=${ENV:FAKE_SECRET}\nconnector.name=iceberg\niceberg.catalog.type=rest\n");
+    ConfigLoader loader = new ConfigLoader(tempDir);
+    List<Properties> configs = loader.loadConfigs();
+    assertEquals(1, configs.size());
+    assertEquals("${ENV:FAKE_SECRET}", configs.get(0).getProperty("secret"));
+  }
+
+  @Test
+  public void testEnvVarInvalidSyntax() throws Exception {
+    createConfigFile("invalid.properties",
+        
"invalid=${SOME_VAR}\nconnector.name=iceberg\niceberg.catalog.type=rest\n");
+    ConfigLoader loader = new ConfigLoader(tempDir);
+    List<Properties> configs = loader.loadConfigs();
+    assertEquals(1, configs.size());
+    assertEquals("${SOME_VAR}", configs.get(0).getProperty("invalid"));
+  }
+
+  @Test
+  public void testMultipleEnvVars() throws Exception {
+    String pathValue = System.getenv("PATH");
+    createConfigFile("multiple.properties",
+        "path=${ENV:PATH}/dir ${ENV:FAKE}\n"
+            + "connector.name=iceberg\niceberg.catalog.type=rest\n");
+    ConfigLoader loader = new ConfigLoader(tempDir);
+    List<Properties> configs = loader.loadConfigs();
+    assertEquals(1, configs.size());
+    String resolvedPath = configs.get(0).getProperty("path");
+    String expected = pathValue + "/dir ${ENV:FAKE}";
+    assertEquals(expected, resolvedPath);
+  }
+
+  @Test
+  public void testMultipleValidEnvVars() throws Exception {
+    String pathValue = System.getenv("PATH");
+    String userValue = System.getenv("USER");
+    String shellValue = System.getenv("SHELL");
+
+    createConfigFile("multiple_env_vars_with_specific_names.properties",
+        "path=${ENV:PATH}\n"
+            + "user=${ENV:USER}\n"
+            + "shell=${ENV:SHELL}\n"
+            + "connector.name=iceberg\niceberg.catalog.type=rest\n");
+
+    ConfigLoader loader = new ConfigLoader(tempDir);
+    List<Properties> configs = loader.loadConfigs();
+
+    assertEquals(1, configs.size());
+    Properties config = configs.get(0);
+
+    assertNotNull(pathValue);
+    assertEquals(pathValue, config.getProperty("path"));
+
+    assertNotNull(userValue);
+    assertEquals(userValue, config.getProperty("user"));
+
+    assertNotNull(shellValue);
+    assertEquals(shellValue, config.getProperty("shell"));
+  }
+
+  @Test
+  public void testEnvVarWithNewLines() throws Exception {
+    createConfigFile("newline.properties",
+        "key=${ENV:CUSTOM_VAR}\n"
+            + "connector.name=iceberg\niceberg.catalog.type=rest\n");
+
+    ConfigLoader loader = new ConfigLoader(tempDir, envVar -> {
+      if (envVar.equals("CUSTOM_VAR")) {
+        return "VALUE\nWITH\nNEWLINE";
+      }
+      return null;
+    });
+
+    List<Properties> configs = loader.loadConfigs();
+    assertEquals(1, configs.size());
+    Properties config = configs.get(0);
+    assertEquals("VALUE\nWITH\nNEWLINE", config.getProperty("key"));
+  }
+}

Reply via email to