|
36 | 36 | import java.util.Optional; |
37 | 37 | import java.util.Set; |
38 | 38 | import java.util.function.Function; |
| 39 | +import java.util.stream.Stream; |
39 | 40 | import org.apache.commons.lang3.StringUtils; |
40 | 41 | import org.apache.iceberg.catalog.Namespace; |
41 | 42 | import org.apache.iceberg.catalog.TableIdentifier; |
|
51 | 52 | import org.apache.polaris.core.admin.model.Catalog; |
52 | 53 | import org.apache.polaris.core.admin.model.CatalogGrant; |
53 | 54 | import org.apache.polaris.core.admin.model.CatalogPrivilege; |
| 55 | +import org.apache.polaris.core.admin.model.CatalogRole; |
54 | 56 | import org.apache.polaris.core.admin.model.ConnectionConfigInfo; |
55 | 57 | import org.apache.polaris.core.admin.model.CreateCatalogRequest; |
56 | 58 | import org.apache.polaris.core.admin.model.ExternalCatalog; |
|
60 | 62 | import org.apache.polaris.core.admin.model.OAuthClientCredentialsParameters; |
61 | 63 | import org.apache.polaris.core.admin.model.PolicyGrant; |
62 | 64 | import org.apache.polaris.core.admin.model.PolicyPrivilege; |
| 65 | +import org.apache.polaris.core.admin.model.Principal; |
| 66 | +import org.apache.polaris.core.admin.model.PrincipalRole; |
63 | 67 | import org.apache.polaris.core.admin.model.PrincipalWithCredentials; |
64 | 68 | import org.apache.polaris.core.admin.model.PrincipalWithCredentialsCredentials; |
65 | 69 | import org.apache.polaris.core.admin.model.TableGrant; |
|
82 | 86 | import org.apache.polaris.core.entity.NamespaceEntity; |
83 | 87 | import org.apache.polaris.core.entity.PolarisBaseEntity; |
84 | 88 | import org.apache.polaris.core.entity.PolarisEntity; |
| 89 | +import org.apache.polaris.core.entity.PolarisEntityCore; |
85 | 90 | import org.apache.polaris.core.entity.PolarisEntitySubType; |
86 | 91 | import org.apache.polaris.core.entity.PolarisEntityType; |
87 | 92 | import org.apache.polaris.core.entity.PolarisGrantRecord; |
@@ -200,6 +205,43 @@ private Optional<CatalogRoleEntity> findCatalogRoleByName(String catalogName, St |
200 | 205 | .map(path -> CatalogRoleEntity.of(path.getRawLeafEntity())); |
201 | 206 | } |
202 | 207 |
|
| 208 | + private <T> Stream<T> loadEntities( |
| 209 | + @Nonnull PolarisEntityType entityType, |
| 210 | + @Nonnull PolarisEntitySubType entitySubType, |
| 211 | + @Nullable PolarisEntity catalogEntity, |
| 212 | + @Nonnull Function<PolarisBaseEntity, T> transformer) { |
| 213 | + List<PolarisEntityCore> catalogPath; |
| 214 | + long catalogId; |
| 215 | + if (catalogEntity == null) { |
| 216 | + catalogPath = null; |
| 217 | + catalogId = 0; |
| 218 | + } else { |
| 219 | + catalogPath = PolarisEntity.toCoreList(List.of(catalogEntity)); |
| 220 | + catalogId = catalogEntity.getId(); |
| 221 | + } |
| 222 | + // TODO: add loadEntities method to PolarisMetaStoreManager |
| 223 | + // loadEntity may return null due to multiple non-atomic API calls to the persistence layer. |
| 224 | + // Specifically, this can happen when a PolarisEntity is returned by listEntities, but cannot be |
| 225 | + // loaded afterward because it was purged by another process before it could be loaded. |
| 226 | + return metaStoreManager |
| 227 | + .listEntities( |
| 228 | + getCurrentPolarisContext(), |
| 229 | + catalogPath, |
| 230 | + entityType, |
| 231 | + entitySubType, |
| 232 | + PageToken.readEverything()) |
| 233 | + .getEntities() |
| 234 | + .stream() |
| 235 | + .map( |
| 236 | + nameAndId -> |
| 237 | + metaStoreManager.loadEntity( |
| 238 | + getCurrentPolarisContext(), catalogId, nameAndId.getId(), nameAndId.getType())) |
| 239 | + .map(PolarisEntity::of) |
| 240 | + .filter(Objects::nonNull) |
| 241 | + .map(transformer) |
| 242 | + .filter(Objects::nonNull); |
| 243 | + } |
| 244 | + |
203 | 245 | private void authorizeBasicRootOperationOrThrow(PolarisAuthorizableOperation op) { |
204 | 246 | resolutionManifest = |
205 | 247 | resolutionManifestFactory.createResolutionManifest( |
@@ -618,8 +660,7 @@ private boolean catalogOverlapsWithExistingCatalog(CatalogEntity catalogEntity) |
618 | 660 | } |
619 | 661 |
|
620 | 662 | Set<String> newCatalogLocations = getCatalogLocations(catalogEntity); |
621 | | - return listCatalogsUnsafe().stream() |
622 | | - .map(CatalogEntity::new) |
| 663 | + return listCatalogsUnsafe() |
623 | 664 | .anyMatch( |
624 | 665 | existingCatalog -> { |
625 | 666 | if (existingCatalog.getName().equals(catalogEntity.getName())) { |
@@ -944,40 +985,16 @@ private void validateUpdateCatalogDiffOrThrow( |
944 | 985 | return returnedEntity; |
945 | 986 | } |
946 | 987 |
|
947 | | - /** |
948 | | - * List all catalogs after checking for permission. Nulls due to non-atomic list-then-get are |
949 | | - * filtered out. |
950 | | - */ |
951 | | - public List<PolarisEntity> listCatalogs() { |
| 988 | + /** List all catalogs after checking for permission. */ |
| 989 | + public List<Catalog> listCatalogs() { |
952 | 990 | authorizeBasicRootOperationOrThrow(PolarisAuthorizableOperation.LIST_CATALOGS); |
953 | | - return listCatalogsUnsafe(); |
| 991 | + return listCatalogsUnsafe().map(CatalogEntity::asCatalog).toList(); |
954 | 992 | } |
955 | 993 |
|
956 | | - /** |
957 | | - * List all catalogs without checking for permission. Nulls due to non-atomic list-then-get are |
958 | | - * filtered out. |
959 | | - */ |
960 | | - private List<PolarisEntity> listCatalogsUnsafe() { |
961 | | - // loadEntity may return null due to multiple non-atomic |
962 | | - // API calls to the persistence layer. Specifically, this can happen when a PolarisEntity is |
963 | | - // returned by listCatalogs, but cannot be loaded afterward because it was purged by another |
964 | | - // process before it could be loaded. |
965 | | - return metaStoreManager |
966 | | - .listEntities( |
967 | | - getCurrentPolarisContext(), |
968 | | - null, |
969 | | - PolarisEntityType.CATALOG, |
970 | | - PolarisEntitySubType.ANY_SUBTYPE, |
971 | | - PageToken.readEverything()) |
972 | | - .getEntities() |
973 | | - .stream() |
974 | | - .map( |
975 | | - nameAndId -> |
976 | | - PolarisEntity.of( |
977 | | - metaStoreManager.loadEntity( |
978 | | - getCurrentPolarisContext(), 0, nameAndId.getId(), nameAndId.getType()))) |
979 | | - .filter(Objects::nonNull) |
980 | | - .toList(); |
| 994 | + /** List all catalogs without checking for permission. */ |
| 995 | + private Stream<CatalogEntity> listCatalogsUnsafe() { |
| 996 | + return loadEntities( |
| 997 | + PolarisEntityType.CATALOG, PolarisEntitySubType.ANY_SUBTYPE, null, CatalogEntity::of); |
981 | 998 | } |
982 | 999 |
|
983 | 1000 | public PrincipalWithCredentials createPrincipal(PolarisEntity entity) { |
@@ -1141,24 +1158,16 @@ public void deletePrincipal(String name) { |
1141 | 1158 | return rotateOrResetCredentialsHelper(principalName, true); |
1142 | 1159 | } |
1143 | 1160 |
|
1144 | | - public List<PolarisEntity> listPrincipals() { |
| 1161 | + public List<Principal> listPrincipals() { |
1145 | 1162 | PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LIST_PRINCIPALS; |
1146 | 1163 | authorizeBasicRootOperationOrThrow(op); |
1147 | 1164 |
|
1148 | | - return metaStoreManager |
1149 | | - .listEntities( |
1150 | | - getCurrentPolarisContext(), |
1151 | | - null, |
| 1165 | + return loadEntities( |
1152 | 1166 | PolarisEntityType.PRINCIPAL, |
1153 | 1167 | PolarisEntitySubType.NULL_SUBTYPE, |
1154 | | - PageToken.readEverything()) |
1155 | | - .getEntities() |
1156 | | - .stream() |
1157 | | - .map( |
1158 | | - nameAndId -> |
1159 | | - PolarisEntity.of( |
1160 | | - metaStoreManager.loadEntity( |
1161 | | - getCurrentPolarisContext(), 0, nameAndId.getId(), nameAndId.getType()))) |
| 1168 | + null, |
| 1169 | + PrincipalEntity::of) |
| 1170 | + .map(PrincipalEntity::asPrincipal) |
1162 | 1171 | .toList(); |
1163 | 1172 | } |
1164 | 1173 |
|
@@ -1254,24 +1263,16 @@ public void deletePrincipalRole(String name) { |
1254 | 1263 | return returnedEntity; |
1255 | 1264 | } |
1256 | 1265 |
|
1257 | | - public List<PolarisEntity> listPrincipalRoles() { |
| 1266 | + public List<PrincipalRole> listPrincipalRoles() { |
1258 | 1267 | PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LIST_PRINCIPAL_ROLES; |
1259 | 1268 | authorizeBasicRootOperationOrThrow(op); |
1260 | 1269 |
|
1261 | | - return metaStoreManager |
1262 | | - .listEntities( |
1263 | | - getCurrentPolarisContext(), |
1264 | | - null, |
| 1270 | + return loadEntities( |
1265 | 1271 | PolarisEntityType.PRINCIPAL_ROLE, |
1266 | 1272 | PolarisEntitySubType.NULL_SUBTYPE, |
1267 | | - PageToken.readEverything()) |
1268 | | - .getEntities() |
1269 | | - .stream() |
1270 | | - .map( |
1271 | | - nameAndId -> |
1272 | | - PolarisEntity.of( |
1273 | | - metaStoreManager.loadEntity( |
1274 | | - getCurrentPolarisContext(), 0, nameAndId.getId(), nameAndId.getType()))) |
| 1273 | + null, |
| 1274 | + PrincipalRoleEntity::of) |
| 1275 | + .map(PrincipalRoleEntity::asPrincipalRole) |
1275 | 1276 | .toList(); |
1276 | 1277 | } |
1277 | 1278 |
|
@@ -1383,30 +1384,19 @@ public void deleteCatalogRole(String catalogName, String name) { |
1383 | 1384 | return returnedEntity; |
1384 | 1385 | } |
1385 | 1386 |
|
1386 | | - public List<PolarisEntity> listCatalogRoles(String catalogName) { |
| 1387 | + public List<CatalogRole> listCatalogRoles(String catalogName) { |
1387 | 1388 | PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LIST_CATALOG_ROLES; |
1388 | 1389 | authorizeBasicTopLevelEntityOperationOrThrow(op, catalogName, PolarisEntityType.CATALOG); |
1389 | 1390 |
|
1390 | 1391 | PolarisEntity catalogEntity = |
1391 | 1392 | findCatalogByName(catalogName) |
1392 | 1393 | .orElseThrow(() -> new NotFoundException("Parent catalog %s not found", catalogName)); |
1393 | | - return metaStoreManager |
1394 | | - .listEntities( |
1395 | | - getCurrentPolarisContext(), |
1396 | | - PolarisEntity.toCoreList(List.of(catalogEntity)), |
| 1394 | + return loadEntities( |
1397 | 1395 | PolarisEntityType.CATALOG_ROLE, |
1398 | 1396 | PolarisEntitySubType.NULL_SUBTYPE, |
1399 | | - PageToken.readEverything()) |
1400 | | - .getEntities() |
1401 | | - .stream() |
1402 | | - .map( |
1403 | | - nameAndId -> |
1404 | | - PolarisEntity.of( |
1405 | | - metaStoreManager.loadEntity( |
1406 | | - getCurrentPolarisContext(), |
1407 | | - catalogEntity.getId(), |
1408 | | - nameAndId.getId(), |
1409 | | - nameAndId.getType()))) |
| 1397 | + catalogEntity, |
| 1398 | + CatalogRoleEntity::of) |
| 1399 | + .map(CatalogRoleEntity::asCatalogRole) |
1410 | 1400 | .toList(); |
1411 | 1401 | } |
1412 | 1402 |
|
|
0 commit comments