Skip to content

Commit dd3c71c

Browse files
authored
Core: Add Endpoints and resource paths for Generic Table (#1286)
1 parent 7e82f2c commit dd3c71c

File tree

6 files changed

+276
-2
lines changed

6 files changed

+276
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.polaris.core.rest;
20+
21+
import com.google.common.collect.ImmutableSet;
22+
import java.util.Set;
23+
import org.apache.iceberg.rest.Endpoint;
24+
import org.apache.polaris.core.config.FeatureConfiguration;
25+
import org.apache.polaris.core.context.CallContext;
26+
27+
public class PolarisEndpoints {
28+
public static final Endpoint V1_LIST_GENERIC_TABLES =
29+
Endpoint.create("GET", PolarisResourcePaths.V1_GENERIC_TABLES);
30+
public static final Endpoint V1_LOAD_GENERIC_TABLE =
31+
Endpoint.create("GET", PolarisResourcePaths.V1_GENERIC_TABLE);
32+
public static final Endpoint V1_CREATE_GENERIC_TABLE =
33+
Endpoint.create("POST", PolarisResourcePaths.V1_GENERIC_TABLES);
34+
public static final Endpoint V1_DELETE_GENERIC_TABLE =
35+
Endpoint.create("DELETE", PolarisResourcePaths.V1_GENERIC_TABLE);
36+
37+
public static final Set<Endpoint> GENERIC_TABLE_ENDPOINTS =
38+
ImmutableSet.<Endpoint>builder()
39+
.add(V1_LIST_GENERIC_TABLES)
40+
.add(V1_CREATE_GENERIC_TABLE)
41+
.add(V1_DELETE_GENERIC_TABLE)
42+
.add(V1_LOAD_GENERIC_TABLE)
43+
.build();
44+
45+
/**
46+
* Get the generic table endpoints. Returns GENERIC_TABLE_ENDPOINTS if ENABLE_GENERIC_TABLES is
47+
* set to true, otherwise, returns an empty set.
48+
*/
49+
public static Set<Endpoint> getSupportedGenericTableEndpoints(CallContext callContext) {
50+
// add the generic table endpoints as supported endpoints if generic table feature is enabled.
51+
boolean genericTableEnabled =
52+
callContext
53+
.getPolarisCallContext()
54+
.getConfigurationStore()
55+
.getConfiguration(
56+
callContext.getPolarisCallContext(), FeatureConfiguration.ENABLE_GENERIC_TABLES);
57+
58+
return genericTableEnabled ? GENERIC_TABLE_ENDPOINTS : ImmutableSet.of();
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.polaris.core.rest;
20+
21+
import com.google.common.base.Joiner;
22+
import java.util.Map;
23+
import org.apache.iceberg.catalog.Namespace;
24+
import org.apache.iceberg.catalog.TableIdentifier;
25+
import org.apache.iceberg.rest.RESTUtil;
26+
27+
public class PolarisResourcePaths {
28+
private static final Joiner SLASH = Joiner.on("/").skipNulls();
29+
public static final String PREFIX = "prefix";
30+
31+
// Generic Table endpoints
32+
public static final String V1_GENERIC_TABLES =
33+
"polaris/v1/{prefix}/namespaces/{namespace}/generic-tables";
34+
public static final String V1_GENERIC_TABLE =
35+
"polaris/v1/{prefix}/namespaces/{namespace}/generic-tables/{generic-table}";
36+
37+
private final String prefix;
38+
39+
public PolarisResourcePaths(String prefix) {
40+
this.prefix = prefix;
41+
}
42+
43+
public static PolarisResourcePaths forCatalogProperties(Map<String, String> properties) {
44+
return new PolarisResourcePaths(properties.get(PREFIX));
45+
}
46+
47+
public String genericTables(Namespace ns) {
48+
return SLASH.join(
49+
"polaris", "v1", prefix, "namespaces", RESTUtil.encodeNamespace(ns), "generic-tables");
50+
}
51+
52+
public String genericTable(TableIdentifier ident) {
53+
return SLASH.join(
54+
"polaris",
55+
"v1",
56+
prefix,
57+
"namespaces",
58+
RESTUtil.encodeNamespace(ident.namespace()),
59+
"generic-tables",
60+
RESTUtil.encodeString(ident.name()));
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.polaris.core.rest;
20+
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
import org.apache.iceberg.catalog.Namespace;
24+
import org.apache.iceberg.catalog.TableIdentifier;
25+
import org.assertj.core.api.Assertions;
26+
import org.junit.jupiter.api.BeforeEach;
27+
import org.junit.jupiter.api.Test;
28+
29+
public class PolarisResourcePathsTest {
30+
private static final String testPrefix = "polaris-test";
31+
32+
private PolarisResourcePaths paths;
33+
34+
@BeforeEach
35+
public void setUp() {
36+
Map<String, String> properties = new HashMap<>();
37+
properties.put(PolarisResourcePaths.PREFIX, testPrefix);
38+
paths = PolarisResourcePaths.forCatalogProperties(properties);
39+
}
40+
41+
@Test
42+
public void testGenericTablesPath() {
43+
Namespace ns = Namespace.of("ns1", "ns2");
44+
String genericTablesPath = paths.genericTables(ns);
45+
String expectedPath =
46+
String.format("polaris/v1/%s/namespaces/%s/generic-tables", testPrefix, "ns1%1Fns2");
47+
Assertions.assertThat(genericTablesPath).isEqualTo(expectedPath);
48+
}
49+
50+
@Test
51+
public void testGenericTablePath() {
52+
Namespace ns = Namespace.of("ns1");
53+
TableIdentifier ident = TableIdentifier.of(ns, "test-table");
54+
String genericTablePath = paths.genericTable(ident);
55+
String expectedPath =
56+
String.format(
57+
"polaris/v1/%s/namespaces/%s/generic-tables/%s", testPrefix, "ns1", "test-table");
58+
Assertions.assertThat(genericTablePath).isEqualTo(expectedPath);
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.polaris.service.quarkus.catalog;
20+
21+
import static jakarta.ws.rs.core.Response.Status.CREATED;
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
24+
import io.quarkus.test.junit.QuarkusTest;
25+
import jakarta.ws.rs.core.Response;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.UUID;
29+
import org.apache.iceberg.rest.responses.ConfigResponse;
30+
import org.apache.polaris.core.admin.model.*;
31+
import org.apache.polaris.core.rest.PolarisEndpoints;
32+
import org.apache.polaris.service.TestServices;
33+
import org.junit.jupiter.params.ParameterizedTest;
34+
import org.junit.jupiter.params.provider.ValueSource;
35+
36+
@QuarkusTest
37+
public class GetConfigTest {
38+
@ParameterizedTest
39+
@ValueSource(booleans = {true, false})
40+
public void testGetConfig(boolean enableGenericTable) {
41+
TestServices services =
42+
TestServices.builder().config(Map.of("ENABLE_GENERIC_TABLES", enableGenericTable)).build();
43+
44+
FileStorageConfigInfo fileStorage =
45+
FileStorageConfigInfo.builder(StorageConfigInfo.StorageTypeEnum.FILE)
46+
.setAllowedLocations(List.of("file://"))
47+
.build();
48+
String catalogName = "test-catalog-" + UUID.randomUUID();
49+
Catalog catalog =
50+
PolarisCatalog.builder()
51+
.setType(Catalog.TypeEnum.INTERNAL)
52+
.setName(catalogName)
53+
.setProperties(new CatalogProperties("file:///tmp/path/to/data"))
54+
.setStorageConfigInfo(fileStorage)
55+
.build();
56+
57+
Response response =
58+
services
59+
.catalogsApi()
60+
.createCatalog(
61+
new CreateCatalogRequest(catalog),
62+
services.realmContext(),
63+
services.securityContext());
64+
assertThat(response.getStatus()).isEqualTo(CREATED.getStatusCode());
65+
66+
response =
67+
services
68+
.restConfigurationApi()
69+
.getConfig(catalogName, services.realmContext(), services.securityContext());
70+
ConfigResponse configResponse = response.readEntity(ConfigResponse.class);
71+
assertThat(configResponse.overrides()).contains(Map.entry("prefix", catalogName));
72+
if (enableGenericTable) {
73+
assertThat(configResponse.endpoints()).contains(PolarisEndpoints.V1_CREATE_GENERIC_TABLE);
74+
assertThat(configResponse.endpoints()).contains(PolarisEndpoints.V1_DELETE_GENERIC_TABLE);
75+
assertThat(configResponse.endpoints()).contains(PolarisEndpoints.V1_LIST_GENERIC_TABLES);
76+
assertThat(configResponse.endpoints()).contains(PolarisEndpoints.V1_LOAD_GENERIC_TABLE);
77+
} else {
78+
assertThat(configResponse.endpoints())
79+
.doesNotContain(PolarisEndpoints.V1_CREATE_GENERIC_TABLE);
80+
assertThat(configResponse.endpoints())
81+
.doesNotContain(PolarisEndpoints.V1_DELETE_GENERIC_TABLE);
82+
assertThat(configResponse.endpoints())
83+
.doesNotContain(PolarisEndpoints.V1_LIST_GENERIC_TABLES);
84+
assertThat(configResponse.endpoints()).doesNotContain(PolarisEndpoints.V1_LOAD_GENERIC_TABLE);
85+
}
86+
}
87+
}

service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import org.apache.polaris.core.persistence.ResolvedPolarisEntity;
6868
import org.apache.polaris.core.persistence.resolver.Resolver;
6969
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
70+
import org.apache.polaris.core.rest.PolarisEndpoints;
7071
import org.apache.polaris.service.catalog.AccessDelegationMode;
7172
import org.apache.polaris.service.catalog.CatalogPrefixParser;
7273
import org.apache.polaris.service.catalog.api.IcebergRestCatalogApiService;
@@ -723,6 +724,7 @@ public Response getConfig(
723724
.addAll(DEFAULT_ENDPOINTS)
724725
.addAll(VIEW_ENDPOINTS)
725726
.addAll(COMMIT_ENDPOINT)
727+
.addAll(PolarisEndpoints.getSupportedGenericTableEndpoints(callContext))
726728
.build())
727729
.build())
728730
.build();

service/common/src/testFixtures/java/org/apache/polaris/service/TestServices.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
import org.apache.polaris.service.admin.api.PolarisCatalogsApi;
4747
import org.apache.polaris.service.catalog.DefaultCatalogPrefixParser;
4848
import org.apache.polaris.service.catalog.api.IcebergRestCatalogApi;
49-
import org.apache.polaris.service.catalog.api.IcebergRestCatalogApiService;
49+
import org.apache.polaris.service.catalog.api.IcebergRestConfigurationApi;
5050
import org.apache.polaris.service.catalog.iceberg.IcebergCatalogAdapter;
5151
import org.apache.polaris.service.catalog.io.FileIOFactory;
5252
import org.apache.polaris.service.catalog.io.MeasuredFileIOFactory;
@@ -64,6 +64,7 @@
6464
public record TestServices(
6565
PolarisCatalogsApi catalogsApi,
6666
IcebergRestCatalogApi restApi,
67+
IcebergRestConfigurationApi restConfigurationApi,
6768
PolarisConfigurationStore configurationStore,
6869
PolarisDiagnostics polarisDiagnostics,
6970
RealmEntityManagerFactory entityManagerFactory,
@@ -170,7 +171,7 @@ public Map<String, Object> contextVariables() {
170171
new PolarisCallContextCatalogFactory(
171172
realmEntityManagerFactory, metaStoreManagerFactory, taskExecutor, fileIOFactory);
172173

173-
IcebergRestCatalogApiService service =
174+
IcebergCatalogAdapter service =
174175
new IcebergCatalogAdapter(
175176
realmContext,
176177
callContext,
@@ -181,6 +182,7 @@ public Map<String, Object> contextVariables() {
181182
new DefaultCatalogPrefixParser());
182183

183184
IcebergRestCatalogApi restApi = new IcebergRestCatalogApi(service);
185+
IcebergRestConfigurationApi restConfigurationApi = new IcebergRestConfigurationApi(service);
184186

185187
CreatePrincipalResult createdPrincipal =
186188
metaStoreManager.createPrincipal(
@@ -225,6 +227,7 @@ public String getAuthenticationScheme() {
225227
return new TestServices(
226228
catalogsApi,
227229
restApi,
230+
restConfigurationApi,
228231
configurationStore,
229232
polarisDiagnostics,
230233
realmEntityManagerFactory,

0 commit comments

Comments
 (0)