This is an automated email from the ASF dual-hosted git repository.
roryqi 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 6177bd0550 [#10841] fix(iceberg): Fix the issues of the table plan
endpoint (#10842)
6177bd0550 is described below
commit 6177bd0550e573bd4292a6e159217b1329f28702
Author: roryqi <[email protected]>
AuthorDate: Fri Apr 24 11:52:22 2026 +0800
[#10841] fix(iceberg): Fix the issues of the table plan endpoint (#10842)
### What changes were proposed in this pull request?
Fix the issues of the table plan endpoint
### Why are the changes needed?
Fix: #10841
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Add UT.
---
.../service/rest/IcebergConfigOperations.java | 8 +++++-
.../service/rest/IcebergTableOperations.java | 2 +-
.../iceberg/service/rest/TestIcebergConfig.java | 33 ++++++++++++++++++++++
.../service/rest/TestIcebergTableOperations.java | 2 +-
4 files changed, 42 insertions(+), 3 deletions(-)
diff --git
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergConfigOperations.java
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergConfigOperations.java
index 719d75ce93..f8c0c28036 100644
---
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergConfigOperations.java
+++
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergConfigOperations.java
@@ -57,6 +57,12 @@ public class IcebergConfigOperations {
private final IcebergCatalogWrapperManager catalogWrapperManager;
+ // TODO: Iceberg 1.10.1's Endpoint.V1_SUBMIT_TABLE_SCAN_PLAN uses a broken
path that is missing
+ // the namespaces/{namespace} segment (fixed in apache/iceberg#14120,
targeting 1.11.x).
+ // We override it here with the correct namespace-scoped path until we
upgrade.
+ private static final Endpoint V1_SUBMIT_TABLE_SCAN_PLAN =
+ Endpoint.create("POST",
"/v1/{prefix}/namespaces/{namespace}/tables/{table}/plan");
+
private static final List<Endpoint> DEFAULT_ENDPOINTS =
ImmutableList.<Endpoint>builder()
.add(Endpoint.V1_LIST_NAMESPACES)
@@ -75,7 +81,7 @@ public class IcebergConfigOperations {
.add(Endpoint.V1_REGISTER_TABLE)
.add(Endpoint.V1_REPORT_METRICS)
.add(Endpoint.V1_TABLE_CREDENTIALS)
- .add(Endpoint.V1_SUBMIT_TABLE_SCAN_PLAN)
+ .add(V1_SUBMIT_TABLE_SCAN_PLAN)
.build();
private static final List<Endpoint> DEFAULT_VIEW_ENDPOINTS =
diff --git
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
index 18d5adbdde..ce3fbc8f24 100644
---
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
+++
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
@@ -493,7 +493,7 @@ public class IcebergTableOperations {
* @return Response containing the scan plan with tasks
*/
@POST
- @Path("{table}/scan")
+ @Path("{table}/plan")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Timed(name = "plan-table-scan." + MetricNames.HTTP_PROCESS_DURATION,
absolute = true)
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergConfig.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergConfig.java
index b02d9fa61b..3a33ae5d9e 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergConfig.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergConfig.java
@@ -125,4 +125,37 @@ public class TestIcebergConfig extends IcebergTestBase {
hasViewListEndpoint,
"Config response should contain view list endpoint for catalog that
supports views");
}
+
+ @Test
+ public void testConfigScanPlanEndpointPathIsNamespaceScoped() {
+ // Iceberg 1.10.1's Endpoint.V1_SUBMIT_TABLE_SCAN_PLAN advertises the
wrong path
+ // (missing namespaces/{namespace}) — fixed in apache/iceberg#14120
(targeting 1.11.x).
+ // This test guards against regressing to the broken path after an Iceberg
upgrade.
+ Response resp = getConfigClientBuilder().get();
+ Assertions.assertEquals(Response.Status.OK.getStatusCode(),
resp.getStatus());
+
+ ConfigResponse response = resp.readEntity(ConfigResponse.class);
+
+ boolean hasScanPlanEndpoint =
+ response.endpoints().stream()
+ .anyMatch(
+ endpoint ->
+ "POST".equals(endpoint.httpMethod())
+ &&
endpoint.path().contains("namespaces/{namespace}/tables/{table}/plan"));
+ Assertions.assertTrue(
+ hasScanPlanEndpoint,
+ "Config response must advertise the namespace-scoped scan plan path: "
+ + "POST /v1/{prefix}/namespaces/{namespace}/tables/{table}/plan");
+
+ boolean hasBrokenScanPlanEndpoint =
+ response.endpoints().stream()
+ .anyMatch(
+ endpoint ->
+ "POST".equals(endpoint.httpMethod())
+ && endpoint.path().endsWith("/tables/{table}/plan")
+ &&
!endpoint.path().contains("namespaces/{namespace}"));
+ Assertions.assertFalse(
+ hasBrokenScanPlanEndpoint,
+ "Config response must not advertise the namespace-less scan plan path
from Iceberg 1.10.1");
+ }
}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
index f447d1c492..a90bc5d4f4 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
@@ -494,7 +494,7 @@ public class TestIcebergTableOperations extends
IcebergNamespaceTestBase {
}
private Response doPlanTableScan(Namespace ns, String tableName,
PlanTableScanRequest request) {
- Invocation.Builder builder = getTableClientBuilder(ns,
Optional.of(tableName + "/scan"));
+ Invocation.Builder builder = getTableClientBuilder(ns,
Optional.of(tableName + "/plan"));
return builder.post(Entity.entity(request,
MediaType.APPLICATION_JSON_TYPE));
}