Skip to content

Commit e5b12fc

Browse files
Address review comments
1 parent 1eaec70 commit e5b12fc

File tree

3 files changed

+199
-32
lines changed

3 files changed

+199
-32
lines changed

polaris-core/src/main/java/org/apache/polaris/core/config/FeatureConfiguration.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ public static void enforceFeatureEnabledOrThrow(
253253
.defaultValue(false)
254254
.buildFeatureConfiguration();
255255

256+
public static final FeatureConfiguration<Boolean> ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS =
257+
PolarisConfiguration.<Boolean>builder()
258+
.key("ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS")
259+
.description(
260+
"When enabled, allows RBAC operations to create synthetic entities for"
261+
+ " entities in federated catalogs that don't exist in the local metastore.")
262+
.defaultValue(false)
263+
.buildFeatureConfiguration();
264+
256265
public static final FeatureConfiguration<Boolean> ENABLE_POLICY_STORE =
257266
PolarisConfiguration.<Boolean>builder()
258267
.key("ENABLE_POLICY_STORE")

runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,11 @@ private void authorizeGrantOnTableLikeOperationOrThrow(
526526
PolarisResolvedPathWrapper tableLikeWrapper =
527527
resolutionManifest.getResolvedPath(
528528
identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE, true);
529-
if (!resolutionManifest.getIsPassthroughFacade()
529+
boolean rbacForFederatedCatalogsEnabled =
530+
getCurrentPolarisContext()
531+
.getRealmConfig()
532+
.getConfig(FeatureConfiguration.ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS);
533+
if (!(resolutionManifest.getIsPassthroughFacade() && rbacForFederatedCatalogsEnabled)
530534
&& !subTypes.contains(tableLikeWrapper.getRawLeafEntity().getSubType())) {
531535
CatalogHandler.throwNotFoundExceptionForTableLikeEntity(identifier, subTypes);
532536
}
@@ -1697,7 +1701,11 @@ public boolean grantPrivilegeOnNamespaceToRole(
16971701
PolarisResolvedPathWrapper resolvedPathWrapper = resolutionManifest.getResolvedPath(namespace);
16981702
if (resolvedPathWrapper == null
16991703
|| !resolvedPathWrapper.isFullyResolvedNamespace(catalogName, namespace)) {
1700-
if (resolutionManifest.getIsPassthroughFacade()) {
1704+
boolean rbacForFederatedCatalogsEnabled =
1705+
getCurrentPolarisContext()
1706+
.getRealmConfig()
1707+
.getConfig(FeatureConfiguration.ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS);
1708+
if (resolutionManifest.getIsPassthroughFacade() && rbacForFederatedCatalogsEnabled) {
17011709
resolvedPathWrapper =
17021710
createSyntheticNamespaceEntities(catalogEntity, namespace, resolvedPathWrapper);
17031711
if (resolvedPathWrapper == null
@@ -1773,26 +1781,25 @@ private PolarisResolvedPathWrapper createSyntheticNamespaceEntities(
17731781
PolarisEntity currentParent = existingPath.getRawLeafEntity();
17741782

17751783
String[] allNamespaceLevels = namespace.levels();
1776-
int matchingLevel = -1;
1784+
int numMatchingLevels = 0;
17771785
for (PolarisEntity entity : completePath.subList(1, completePath.size())) {
1778-
if (entity.getName().equals(allNamespaceLevels[matchingLevel + 1])) {
1779-
matchingLevel++;
1780-
} else {
1786+
if (!entity.getName().equals(allNamespaceLevels[numMatchingLevels])) {
17811787
break;
17821788
}
1789+
numMatchingLevels++;
17831790
}
17841791

1785-
for (int i = matchingLevel + 1; i < allNamespaceLevels.length; i++) {
1786-
String namespacePart = allNamespaceLevels[i];
1792+
for (int i = numMatchingLevels; i < allNamespaceLevels.length; i++) {
1793+
String[] namespacePart = Arrays.copyOfRange(allNamespaceLevels, 0, i + 1);
1794+
String leafNamespace = namespacePart[namespacePart.length - 1];
1795+
Namespace currentNamespace = Namespace.of(namespacePart);
17871796

17881797
// TODO: Instead of creating synthetic entitties, rely on external catalog mediated backfill.
17891798
PolarisEntity syntheticNamespace =
1790-
new PolarisEntity.Builder()
1799+
new NamespaceEntity.Builder(currentNamespace)
17911800
.setId(metaStoreManager.generateNewEntityId(getCurrentPolarisContext()).getId())
17921801
.setCatalogId(catalogEntity.getId())
17931802
.setParentId(currentParent.getId())
1794-
.setType(PolarisEntityType.NAMESPACE)
1795-
.setName(namespacePart)
17961803
.setCreateTimestamp(System.currentTimeMillis())
17971804
.build();
17981805

@@ -1810,12 +1817,12 @@ private PolarisResolvedPathWrapper createSyntheticNamespaceEntities(
18101817
resolutionManifest.getResolvedPath(partialNamespace);
18111818
PolarisEntity partialLeafEntity = partialPath.getRawLeafEntity();
18121819
if (partialLeafEntity == null
1813-
|| !(partialLeafEntity.getName().equals(namespacePart)
1820+
|| !(partialLeafEntity.getName().equals(leafNamespace)
18141821
&& partialLeafEntity.getType() == PolarisEntityType.NAMESPACE)) {
18151822
throw new RuntimeException(
18161823
String.format(
18171824
"Failed to create or find namespace entity '%s' in federated catalog '%s'",
1818-
namespacePart, catalogEntity.getName()));
1825+
leafNamespace, catalogEntity.getName()));
18191826
}
18201827
syntheticNamespace = partialLeafEntity;
18211828
}
@@ -2115,7 +2122,11 @@ private boolean grantPrivilegeOnTableLikeToRole(
21152122
identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE);
21162123
if (resolvedPathWrapper == null
21172124
|| !subTypes.contains(resolvedPathWrapper.getRawLeafEntity().getSubType())) {
2118-
if (resolutionManifest.getIsPassthroughFacade()) {
2125+
boolean rbacForFederatedCatalogsEnabled =
2126+
getCurrentPolarisContext()
2127+
.getRealmConfig()
2128+
.getConfig(FeatureConfiguration.ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS);
2129+
if (resolutionManifest.getIsPassthroughFacade() && rbacForFederatedCatalogsEnabled) {
21192130
resolvedPathWrapper =
21202131
createSyntheticTableLikeEntities(
21212132
catalogEntity, identifier, subTypes, resolvedPathWrapper);
@@ -2175,17 +2186,20 @@ private PolarisResolvedPathWrapper createSyntheticTableLikeEntities(
21752186
namespace.toString(), catalogEntity.getName()));
21762187
}
21772188

2178-
// TODO: Instead of creating a synthetic table-like entity, rely on external catalog mediated
2179-
// backfill.
21802189
PolarisEntity parentNamespaceEntity = resolvedNamespacePathWrapper.getRawLeafEntity();
2190+
2191+
// TODO: Once we support GENERIC_TABLE federation, select the intended type depending on the
2192+
// callsite; if it is instantiated via an Iceberg RESTCatalog factory or a different factory
2193+
// for GenericCatalogs.
2194+
PolarisEntitySubType syntheticEntitySubType = selectEntitySubType(subTypes);
2195+
2196+
// TODO: Instead of creating a synthetic table-like entity, rely on external catalog mediated
2197+
// backfill and use the metadata location from the external catalog.
21812198
PolarisEntity syntheticTableEntity =
2182-
new PolarisEntity.Builder()
2199+
new IcebergTableLikeEntity.Builder(identifier, "")
21832200
.setId(metaStoreManager.generateNewEntityId(getCurrentPolarisContext()).getId())
21842201
.setCatalogId(parentNamespaceEntity.getCatalogId())
2185-
.setParentId(parentNamespaceEntity.getId())
2186-
.setType(PolarisEntityType.TABLE_LIKE)
2187-
.setSubType(subTypes.get(0))
2188-
.setName(identifier.name())
2202+
.setSubType(syntheticEntitySubType)
21892203
.setCreateTimestamp(System.currentTimeMillis())
21902204
.build();
21912205

@@ -2306,4 +2320,25 @@ private boolean revokePrivilegeOnPolicyEntityFromRole(
23062320
privilege)
23072321
.isSuccess();
23082322
}
2323+
2324+
/**
2325+
* Selects the appropriate entity subtype for synthetic entities in external catalogs.
2326+
*
2327+
* @param subTypes list of candidate subtypes
2328+
* @return the selected subtype for the synthetic entity
2329+
* @throws IllegalStateException if no supported subtype is found
2330+
*/
2331+
private static PolarisEntitySubType selectEntitySubType(List<PolarisEntitySubType> subTypes) {
2332+
if (subTypes.contains(PolarisEntitySubType.ICEBERG_TABLE)) {
2333+
return PolarisEntitySubType.ICEBERG_TABLE;
2334+
} else if (subTypes.contains(PolarisEntitySubType.ICEBERG_VIEW)) {
2335+
return PolarisEntitySubType.ICEBERG_VIEW;
2336+
} else {
2337+
throw new IllegalStateException(
2338+
String.format(
2339+
"No supported subtype found in %s. Only ICEBERG_TABLE and ICEBERG_VIEW are"
2340+
+ " supported for synthetic entities in external catalogs.",
2341+
subTypes));
2342+
}
2343+
}
23092344
}

0 commit comments

Comments
 (0)