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

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 7c89a6bae8 [#7816] feat(filesystem-hadoop3): Support custom client 
config (#7819)
7c89a6bae8 is described below

commit 7c89a6bae89263dad5b223f242caf74df2df3e98
Author: qbhan <[email protected]>
AuthorDate: Tue Aug 12 18:19:38 2025 +0800

    [#7816] feat(filesystem-hadoop3): Support custom client config (#7819)
    
    ### What changes were proposed in this pull request?
    Support custom client config when use `GVFS`
    
    ### Why are the changes needed?
    Fix: #7816
    
    ### Does this PR introduce _any_ user-facing change?
    - add config `fs.gravitino.client.` which is the configuration key
    prefix for the Gravitino client config.
    
    ### How was this patch tested?
    local tests
---
 .../GravitinoVirtualFileSystemConfiguration.java   | 14 ++++++
 .../hadoop/GravitinoVirtualFileSystemUtils.java    | 32 +++++++++++++
 .../gravitino/filesystem/hadoop/TestGvfsBase.java  | 56 ++++++++++++++++++++++
 docs/how-to-use-gvfs.md                            |  7 +++
 4 files changed, 109 insertions(+)

diff --git 
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
 
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
index ef84b39014..4ffb8d3731 100644
--- 
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
+++ 
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemConfiguration.java
@@ -18,6 +18,9 @@
  */
 package org.apache.gravitino.filesystem.hadoop;
 
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+
 /** Configuration class for Gravitino Virtual File System. */
 public class GravitinoVirtualFileSystemConfiguration {
 
@@ -50,6 +53,8 @@ public class GravitinoVirtualFileSystemConfiguration {
   /** The authentication type for kerberos authentication. */
   public static final String KERBEROS_AUTH_TYPE = "kerberos";
   // oauth2
+  /** The configuration key prefix for oauth2 */
+  public static final String FS_GRAVITINO_CLIENT_OAUTH2_PREFIX = 
"fs.gravitino.client.oauth2.";
   /** The configuration key for the URI of the default OAuth server. */
   public static final String FS_GRAVITINO_CLIENT_OAUTH2_SERVER_URI_KEY =
       "fs.gravitino.client.oauth2.serverUri";
@@ -66,6 +71,8 @@ public class GravitinoVirtualFileSystemConfiguration {
   public static final String FS_GRAVITINO_CLIENT_OAUTH2_SCOPE_KEY =
       "fs.gravitino.client.oauth2.scope";
 
+  /** The configuration key prefix for kerberos */
+  public static final String FS_GRAVITINO_CLIENT_KERBEROS_PREFIX = 
"fs.gravitino.client.kerberos.";
   /** The configuration key for the principal. */
   public static final String FS_GRAVITINO_CLIENT_KERBEROS_PRINCIPAL_KEY =
       "fs.gravitino.client.kerberos.principal";
@@ -143,8 +150,15 @@ public class GravitinoVirtualFileSystemConfiguration {
   public static final String FS_GRAVITINO_ENABLE_CREDENTIAL_VENDING =
       "fs.gravitino.enableCredentialVending";
 
+  /** The configuration key prefix for the Gravitino client config. */
+  public static final String FS_GRAVITINO_CLIENT_CONFIG_PREFIX = 
"fs.gravitino.client.";
+
   /** The default value for whether to enable credential vending. */
   public static final boolean FS_GRAVITINO_ENABLE_CREDENTIAL_VENDING_DEFAULT = 
false;
 
+  /** The configuration key list which not a Gravitino client config */
+  public static final List<String> NOT_GRAVITINO_CLIENT_CONFIG_LIST =
+      ImmutableList.of(FS_GRAVITINO_CLIENT_METALAKE_KEY, 
FS_GRAVITINO_CLIENT_AUTH_TYPE_KEY);
+
   private GravitinoVirtualFileSystemConfiguration() {}
 }
diff --git 
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
 
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
index 926637072b..3a28fd6ac0 100644
--- 
a/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
+++ 
b/clients/filesystem-hadoop3/src/main/java/org/apache/gravitino/filesystem/hadoop/GravitinoVirtualFileSystemUtils.java
@@ -19,8 +19,14 @@
 
 package org.apache.gravitino.filesystem.hadoop;
 
+import static 
org.apache.gravitino.client.GravitinoClientConfiguration.GRAVITINO_CLIENT_CONFIG_PREFIX;
+import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_CONFIG_PREFIX;
+import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_KERBEROS_PREFIX;
+import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_OAUTH2_PREFIX;
 import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_REQUEST_HEADER_PREFIX;
+import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.NOT_GRAVITINO_CLIENT_CONFIG_LIST;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import java.io.File;
@@ -94,6 +100,8 @@ public class GravitinoVirtualFileSystemUtils {
                     e -> 
e.getKey().substring(FS_GRAVITINO_CLIENT_REQUEST_HEADER_PREFIX.length()),
                     Map.Entry::getValue));
 
+    Map<String, String> clientConfig = extractClientConfig(configuration);
+
     String authType =
         configuration.getOrDefault(
             
GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_AUTH_TYPE_KEY,
@@ -103,6 +111,7 @@ public class GravitinoVirtualFileSystemUtils {
           .withMetalake(metalakeValue)
           .withSimpleAuth()
           .withHeaders(requestHeaders)
+          .withClientConfig(clientConfig)
           .build();
     } else if (authType.equalsIgnoreCase(
         GravitinoVirtualFileSystemConfiguration.OAUTH2_AUTH_TYPE)) {
@@ -150,6 +159,7 @@ public class GravitinoVirtualFileSystemUtils {
           .withMetalake(metalakeValue)
           .withOAuth(authDataProvider)
           .withHeaders(requestHeaders)
+          .withClientConfig(clientConfig)
           .build();
     } else if (authType.equalsIgnoreCase(
         GravitinoVirtualFileSystemConfiguration.KERBEROS_AUTH_TYPE)) {
@@ -181,6 +191,7 @@ public class GravitinoVirtualFileSystemUtils {
           .withMetalake(metalakeValue)
           .withKerberosAuth(authDataProvider)
           .withHeaders(requestHeaders)
+          .withClientConfig(clientConfig)
           .build();
     } else {
       throw new IllegalArgumentException(
@@ -190,6 +201,27 @@ public class GravitinoVirtualFileSystemUtils {
     }
   }
 
+  @VisibleForTesting
+  static Map<String, String> extractClientConfig(Map<String, String> 
configuration) {
+    return configuration.entrySet().stream()
+        .filter(e -> isClientConfigKey(e.getKey()))
+        .collect(
+            Collectors.toMap(
+                e ->
+                    e.getKey()
+                        .replace(FS_GRAVITINO_CLIENT_CONFIG_PREFIX, 
GRAVITINO_CLIENT_CONFIG_PREFIX),
+                Map.Entry::getValue,
+                (oldVal, newVal) -> newVal));
+  }
+
+  private static boolean isClientConfigKey(String key) {
+    return key.startsWith(FS_GRAVITINO_CLIENT_CONFIG_PREFIX)
+        && !key.startsWith(FS_GRAVITINO_CLIENT_OAUTH2_PREFIX)
+        && !key.startsWith(FS_GRAVITINO_CLIENT_KERBEROS_PREFIX)
+        && !key.startsWith(FS_GRAVITINO_CLIENT_REQUEST_HEADER_PREFIX)
+        && !NOT_GRAVITINO_CLIENT_CONFIG_LIST.contains(key);
+  }
+
   /**
    * Extract the full identifier of the fileset from the virtual path.
    *
diff --git 
a/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/TestGvfsBase.java
 
b/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/TestGvfsBase.java
index d9084f90f3..7d266341bc 100644
--- 
a/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/TestGvfsBase.java
+++ 
b/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/TestGvfsBase.java
@@ -18,11 +18,15 @@
  */
 package org.apache.gravitino.filesystem.hadoop;
 
+import static 
org.apache.gravitino.client.GravitinoClientConfiguration.CLIENT_CONNECTION_TIMEOUT_MS;
+import static 
org.apache.gravitino.client.GravitinoClientConfiguration.CLIENT_SOCKET_TIMEOUT_MS;
 import static org.apache.gravitino.file.Fileset.LOCATION_NAME_UNKNOWN;
 import static org.apache.gravitino.file.Fileset.PROPERTY_DEFAULT_LOCATION_NAME;
 import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_BLOCK_SIZE_DEFAULT;
+import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_CONFIG_PREFIX;
 import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemConfiguration.FS_GRAVITINO_CLIENT_REQUEST_HEADER_PREFIX;
 import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemUtils.extractIdentifier;
+import static 
org.apache.gravitino.filesystem.hadoop.GravitinoVirtualFileSystemUtils.getConfigMap;
 import static org.apache.hc.core5.http.HttpStatus.SC_NOT_FOUND;
 import static org.apache.hc.core5.http.HttpStatus.SC_OK;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -43,6 +47,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
 import java.lang.reflect.Field;
+import java.net.SocketTimeoutException;
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -67,6 +72,7 @@ import org.apache.gravitino.dto.responses.VersionResponse;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
 import org.apache.gravitino.exceptions.NoSuchFilesetException;
 import org.apache.gravitino.exceptions.NoSuchLocationNameException;
+import org.apache.gravitino.exceptions.RESTException;
 import org.apache.gravitino.file.Fileset;
 import org.apache.gravitino.rest.RESTUtils;
 import org.apache.hadoop.conf.Configuration;
@@ -76,6 +82,7 @@ import org.apache.hadoop.fs.Path;
 import org.apache.hc.core5.http.Method;
 import org.awaitility.Awaitility;
 import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Assumptions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
@@ -985,6 +992,55 @@ public class TestGvfsBase extends GravitinoMockServerBase {
     }
   }
 
+  @Test
+  public void testGravitinoClientConfig() {
+    Configuration configuration = new Configuration(conf);
+    // test valid client property
+    configuration.set(FS_GRAVITINO_CLIENT_CONFIG_PREFIX + 
"connectionTimeoutMs", "8000");
+    configuration.set(FS_GRAVITINO_CLIENT_CONFIG_PREFIX + "socketTimeoutMs", 
"4000");
+    Map<String, String> clientConfig =
+        
GravitinoVirtualFileSystemUtils.extractClientConfig(getConfigMap(configuration));
+    Assertions.assertEquals(clientConfig.get(CLIENT_CONNECTION_TIMEOUT_MS), 
"8000");
+    Assertions.assertEquals(clientConfig.get(CLIENT_SOCKET_TIMEOUT_MS), 
"4000");
+
+    // test invalid client property
+    configuration.set(FS_GRAVITINO_CLIENT_CONFIG_PREFIX + "xxxx", "2000");
+    Throwable throwable =
+        Assertions.assertThrows(
+            IllegalArgumentException.class,
+            () -> {
+              try (FileSystem fs = new 
Path("gvfs://fileset/").getFileSystem(configuration)) {}
+            });
+    Assertions.assertEquals(
+        "Invalid property for client: gravitino.client.xxxx", 
throwable.getMessage());
+  }
+
+  @Test
+  public void testSocketTimeout() throws IOException {
+
+    Configuration configuration = new Configuration(conf);
+    configuration.set(FS_GRAVITINO_CLIENT_CONFIG_PREFIX + "socketTimeoutMs", 
"2000");
+
+    mockServer().clear(request().withPath("/api/version"));
+    HttpRequest req = request().withPath("/api/version");
+    mockServer()
+        .when(req, Times.once())
+        .respond(
+            response()
+                .withStatusCode(SC_OK)
+                .withBody(getJsonString(new 
VersionResponse(Version.getCurrentVersionDTO())))
+                .withDelay(TimeUnit.MILLISECONDS, 5000));
+
+    Throwable throwable =
+        Assertions.assertThrows(
+            RESTException.class,
+            () -> {
+              try (FileSystem fs = new 
Path("gvfs://fileset/").getFileSystem(configuration)) {}
+            });
+    Assertions.assertInstanceOf(SocketTimeoutException.class, 
throwable.getCause());
+    Assertions.assertEquals("Read timed out", 
throwable.getCause().getMessage());
+  }
+
   private void buildMockResourceForCredential(String filesetName, String 
filesetLocation)
       throws JsonProcessingException {
     String filesetPath =
diff --git a/docs/how-to-use-gvfs.md b/docs/how-to-use-gvfs.md
index 4a197862ef..468930778c 100644
--- a/docs/how-to-use-gvfs.md
+++ b/docs/how-to-use-gvfs.md
@@ -71,6 +71,13 @@ the path mapping and convert automatically.
 | `fs.gravitino.hook.class`                             | The hook class to 
inject into the <br/>Gravitino Virtual File System. Users can implement their 
own `GravitinoVirtualFileSystemHook` and configure the class name in this conf 
to inject custom code.                                                          
                                                      | 
`org.apache.gravitino.filesystem.hadoop.NoOpHook`              | No             
                     | 0.9.0-incubating |
 | `fs.gravitino.client.request.header.`                 | The configuration 
key prefix for the Gravitino client request header. You can set the request 
header for the Gravitino client.                                                
                                                                                
                                                       | (none)                 
                                        | No                                  | 
0.9.0-incubating |
 | `fs.gravitino.enableCredentialVending`                | Whether to enable 
credential vending for the Gravitino Virtual File System.                       
                                                                                
                                                                                
                                                   | `false`                    
                                    | No                                  | 
0.9.0-incubating |
+| `fs.gravitino.client.`                                | The configuration 
key prefix for the Gravitino client config.                                     
                                                                                
                                                                                
                                                   | (none)                     
                                    | No                                  | 
1.0.0            |
+
+To configure the Gravitino client, use properties prefixed with 
`fs.gravitino.client.`. These properties undergo automatic transformation: the 
prefix is replaced with `gravitino.client.` and passed to the `GravitinoClient`.
+
+**Example:** Setting `fs.gravitino.client.socketTimeoutMs` is equivalent to 
setting `gravitino.client.socketTimeoutMs` for the `GravitinoClient`.
+
+**Note:** Invalid configuration properties will result in exceptions. Please 
see [Gravitino Java client 
configurations](./how-to-use-gravitino-client.md#gravitino-java-client-configuration)
 for more support client configuration.
 
 Apart from the above properties, to access fileset like S3, GCS, OSS and 
custom fileset, extra properties are needed, please see 
 [S3 GVFS Java client 
configurations](./fileset-catalog-with-s3.md#using-the-gvfs-java-client-to-access-the-fileset),

Reply via email to