This is an automated email from the ASF dual-hosted git repository.
takidau pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new cfe7841 Fix register_table to properly initialize FileIO and refactor
overall FileIO initialization to better reveal bugs (#208)
cfe7841 is described below
commit cfe7841fed866071f932b9d1285cb680fc3e77e9
Author: Dennis Huo <[email protected]>
AuthorDate: Mon Aug 26 10:29:07 2024 -0700
Fix register_table to properly initialize FileIO and refactor overall
FileIO initialization to better reveal bugs (#208)
* Instead of injecting a mock STS for integration tests that seek to skip
the credential-subscoping flow, add a feature configuration
"SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION" to skip the flow. This also
allows running the server in a mode where "application default" storage
credentials are directly used for file access.
* Refactor the callsites of refreshIOWithCredentials and refreshCredentials
for
consistency and eliminate most of the dependency on the catalogFileIO; in
all non-test
scenarios, it's a bug to actually depend on the catalogFileIO at all, since
all storage
actions need to be done in the context of a Table or View, and such FileIOs
need to
be initialized with properly scoped credentials for those entities.
Make the FileIO refresh correctly inherit table properties. For cases where
we don't
have a concrete table metadata available, use defaultTableProperties
derived from
the standard convention of catalog properties that have the
TABLE_DEFAULT_PREFIX.
* No longer instantiate any catalogFileIO by default; provide a config
switch
so that it's only populated in targeted test scenarios where it's difficult
to restructure callsites to better separate the responsibilities of the
"client-side" vs "server-side"; for now only BasePolarisCatalogTest relies
on the default catalogFileIO. This change also reveals the broken
registerTable across serveral different test classes.
* Override registerTable to explicitly initialize its own FileIO to read
the existing
metadata file so that it no longer relies on the test-only catalogFileIO
which won't
work in isolated server deployments.
---
.../service/catalog/BasePolarisCatalog.java | 232 +++++++++++++--------
.../service/catalog/BasePolarisCatalogTest.java | 1 +
.../PolarisCatalogHandlerWrapperAuthzTest.java | 10 +-
.../catalog/PolarisSparkIntegrationTest.java | 8 +
.../service/test/PolarisConnectionExtension.java | 64 ------
.../resources/polaris-server-integrationtest.yml | 1 +
6 files changed, 165 insertions(+), 151 deletions(-)
diff --git
a/polaris-service/src/main/java/org/apache/polaris/service/catalog/BasePolarisCatalog.java
b/polaris-service/src/main/java/org/apache/polaris/service/catalog/BasePolarisCatalog.java
index 8d8d1e9..be0d5e3 100644
---
a/polaris-service/src/main/java/org/apache/polaris/service/catalog/BasePolarisCatalog.java
+++
b/polaris-service/src/main/java/org/apache/polaris/service/catalog/BasePolarisCatalog.java
@@ -44,9 +44,11 @@ import java.util.stream.Stream;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.iceberg.BaseMetastoreTableOperations;
+import org.apache.iceberg.BaseTable;
import org.apache.iceberg.CatalogProperties;
import org.apache.iceberg.CatalogUtil;
import org.apache.iceberg.Schema;
+import org.apache.iceberg.Table;
import org.apache.iceberg.TableMetadata;
import org.apache.iceberg.TableMetadataParser;
import org.apache.iceberg.TableOperations;
@@ -66,6 +68,8 @@ import
org.apache.iceberg.exceptions.UnprocessableEntityException;
import org.apache.iceberg.exceptions.ValidationException;
import org.apache.iceberg.io.CloseableGroup;
import org.apache.iceberg.io.FileIO;
+import org.apache.iceberg.io.InputFile;
+import org.apache.iceberg.util.PropertyUtil;
import org.apache.iceberg.view.BaseMetastoreViewCatalog;
import org.apache.iceberg.view.BaseViewOperations;
import org.apache.iceberg.view.ViewBuilder;
@@ -117,6 +121,30 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
// Config key for whether to allow setting the FILE_IO_IMPL using catalog
properties. Should
// only be allowed in dev/test environments.
static final String ALLOW_SPECIFYING_FILE_IO_IMPL =
"ALLOW_SPECIFYING_FILE_IO_IMPL";
+ static final boolean ALLOW_SPECIFYING_FILE_IO_IMPL_DEFAULT = false;
+
+ // Config key for whether to skip credential-subscoping indirection entirely
whenever trying
+ // to obtain storage credentials for instantiating a FileIO. If 'true', no
attempt is made
+ // to use StorageConfigs to generate table-specific storage credentials, but
instead the default
+ // fallthrough of table-level credential properties or else
provider-specific APPLICATION_DEFAULT
+ // credential-loading will be used for the FileIO.
+ // Typically this setting is used in single-tenant server deployments that
don't rely on
+ // "credential-vending" and can use server-default environment variables or
credential config
+ // files for all storage access, or in test/dev scenarios.
+ static final String SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION =
+ "SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION";
+ static final boolean SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION_DEFAULT = false;
+
+ // Config key for initializing a default "catalogFileIO" that is available
either via getIo()
+ // or for any TableOperations/ViewOperations instantiated, via ops.io()
before entity-specific
+ // FileIO initialization is triggered for any such operations.
+ // Typically this should only be used in test scenarios where a
BasePolarisCatalog instance
+ // is used for both the "client-side" and "server-side" logic instead of
being access through
+ // a REST layer.
+ static final String INITIALIZE_DEFAULT_CATALOG_FILEIO_FOR_TEST =
+ "INITIALIZE_DEFAULT_CATALOG_FILEIO_FOR_TEST";
+ static final boolean INITIALIZE_DEFAULT_CATALOG_FILEIO_FOR_TEST_DEFAULT =
false;
+
private static final int MAX_RETRIES = 12;
static final Predicate<Exception> SHOULD_RETRY_REFRESH_PREDICATE =
@@ -146,6 +174,7 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
private String defaultBaseLocation;
private CloseableGroup closeableGroup;
private Map<String, String> catalogProperties;
+ private Map<String, String> tableDefaultProperties;
/**
* @param entityManager provides handle to underlying
PolarisMetaStoreManager with which to
@@ -201,11 +230,8 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
this.defaultBaseLocation = baseLocation.replaceAll("/*$", "");
Boolean allowSpecifyingFileIoImpl =
- callContext
- .getPolarisCallContext()
- .getConfigurationStore()
- .getConfiguration(
- callContext.getPolarisCallContext(),
ALLOW_SPECIFYING_FILE_IO_IMPL, false);
+ getBooleanContextConfiguration(
+ ALLOW_SPECIFYING_FILE_IO_IMPL,
ALLOW_SPECIFYING_FILE_IO_IMPL_DEFAULT);
PolarisStorageConfigurationInfo storageConfigurationInfo =
catalogEntity.getStorageConfigurationInfo();
@@ -228,15 +254,27 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
ioImplClassName,
storageConfigurationInfo);
}
- this.catalogFileIO = loadFileIO(ioImplClassName, properties);
-
this.closeableGroup = CallContext.getCurrentContext().closeables();
closeableGroup.addCloseable(metricsReporter());
- // TODO: FileIO initialization should should happen later depending on the
operation so
- // we'd also add it to the closeableGroup later.
- closeableGroup.addCloseable(this.catalogFileIO);
closeableGroup.setSuppressCloseFailure(true);
+
catalogProperties = properties;
+ tableDefaultProperties =
+ PropertyUtil.propertiesWithPrefix(properties,
CatalogProperties.TABLE_DEFAULT_PREFIX);
+
+ Boolean initializeDefaultCatalogFileioForTest =
+ getBooleanContextConfiguration(
+ INITIALIZE_DEFAULT_CATALOG_FILEIO_FOR_TEST,
+ INITIALIZE_DEFAULT_CATALOG_FILEIO_FOR_TEST_DEFAULT);
+ if (Boolean.TRUE.equals(initializeDefaultCatalogFileioForTest)) {
+ LOGGER.debug(
+ "Initializing a default catalogFileIO with properties {}",
tableDefaultProperties);
+ this.catalogFileIO = loadFileIO(ioImplClassName, tableDefaultProperties);
+ closeableGroup.addCloseable(this.catalogFileIO);
+ } else {
+ LOGGER.debug("Not initializing default catalogFileIO");
+ this.catalogFileIO = null;
+ }
}
@Override
@@ -244,6 +282,45 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
return catalogProperties == null ? ImmutableMap.of() : catalogProperties;
}
+ @Override
+ public Table registerTable(TableIdentifier identifier, String
metadataFileLocation) {
+ Preconditions.checkArgument(
+ identifier != null && isValidIdentifier(identifier), "Invalid
identifier: %s", identifier);
+ Preconditions.checkArgument(
+ metadataFileLocation != null && !metadataFileLocation.isEmpty(),
+ "Cannot register an empty metadata file location as a table");
+
+ // Throw an exception if this table already exists in the catalog.
+ if (tableExists(identifier)) {
+ throw new AlreadyExistsException("Table already exists: %s", identifier);
+ }
+
+ String locationDir = metadataFileLocation.substring(0,
metadataFileLocation.lastIndexOf("/"));
+
+ TableOperations ops = newTableOps(identifier);
+
+ PolarisResolvedPathWrapper resolvedParent =
+ resolvedEntityView.getResolvedPath(identifier.namespace());
+ if (resolvedParent == null) {
+ // Illegal state because the namespace should've already been in the
static resolution set.
+ throw new IllegalStateException(
+ String.format("Failed to fetch resolved parent for TableIdentifier
'%s'", identifier));
+ }
+ FileIO fileIO =
+ refreshIOWithCredentials(
+ identifier,
+ Set.of(locationDir),
+ resolvedParent,
+ new HashMap<>(tableDefaultProperties),
+ Set.of(PolarisStorageActions.READ));
+
+ InputFile metadataFile = fileIO.newInputFile(metadataFileLocation);
+ TableMetadata metadata = TableMetadataParser.read(fileIO, metadataFile);
+ ops.commit(null, metadata);
+
+ return new BaseTable(ops, fullTableName(name(), identifier),
metricsReporter());
+ }
+
@Override
public TableBuilder buildTable(TableIdentifier identifier, Schema schema) {
return new BasePolarisCatalogTableBuilder(identifier, schema);
@@ -312,25 +389,11 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
}
Optional<PolarisEntity> storageInfoEntity =
findStorageInfo(tableIdentifier);
- if (purge && lastMetadata != null) {
- Map<String, String> credentialsMap =
- storageInfoEntity
- .map(
- entity ->
- refreshCredentials(
- tableIdentifier,
- Set.of(PolarisStorageActions.READ,
PolarisStorageActions.WRITE),
- getLocationsAllowedToBeAccessed(lastMetadata),
- entity))
- .orElse(Map.of());
- Map<String, String> tableProperties = new
HashMap<>(lastMetadata.properties());
- tableProperties.putAll(credentialsMap);
- if (!tableProperties.isEmpty()) {
- catalogFileIO = loadFileIO(ioImplClassName, tableProperties);
- // ensure the new fileIO is closed when the catalog is closed
- closeableGroup.addCloseable(catalogFileIO);
- }
- }
+
+ // The storageProperties we stash away in the Task should be the superset
of the
+ // internalProperties of the StorageInfoEntity to be able to use its
StorageIntegration
+ // combined with other miscellaneous FileIO-related initialization
properties defined
+ // by the Table.
Map<String, String> storageProperties =
storageInfoEntity
.map(PolarisEntity::getInternalPropertiesAsMap)
@@ -339,13 +402,14 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
if (lastMetadata == null) {
return Map.<String, String>of();
}
- Map<String, String> clone = new HashMap<>(properties);
+ Map<String, String> clone = new HashMap<>();
+
+ // The user-configurable table properties are the baseline,
but then override
+ // with our restricted properties so that table properties
can't clobber the
+ // more restricted ones.
+ clone.putAll(lastMetadata.properties());
clone.put(CatalogProperties.FILE_IO_IMPL, ioImplClassName);
- try {
- clone.putAll(catalogFileIO.properties());
- } catch (UnsupportedOperationException e) {
- LOGGER.warn("FileIO doesn't implement properties()");
- }
+ clone.putAll(properties);
clone.put(PolarisTaskConstants.STORAGE_LOCATION,
lastMetadata.location());
return clone;
})
@@ -794,6 +858,17 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
// prior to requested subscoped credentials.
tableLocations.forEach(tl -> validateLocationForTableLike(tableIdentifier,
tl));
+ Boolean skipCredentialSubscopingIndirection =
+ getBooleanContextConfiguration(
+ SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION,
SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION_DEFAULT);
+ if (Boolean.TRUE.equals(skipCredentialSubscopingIndirection)) {
+ LOGGER
+ .atInfo()
+ .addKeyValue("tableIdentifier", tableIdentifier)
+ .log("Skipping generation of subscoped creds for table");
+ return Map.of();
+ }
+
boolean allowList =
storageActions.contains(PolarisStorageActions.LIST)
|| storageActions.contains(PolarisStorageActions.ALL);
@@ -1119,16 +1194,18 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
SHOULD_RETRY_REFRESH_PREDICATE,
MAX_RETRIES,
metadataLocation -> {
- FileIO fileIO = this.tableFileIO;
String latestLocationDir =
latestLocation.substring(0, latestLocation.lastIndexOf('/'));
- fileIO =
+ // TODO: Once we have the "current" table properties pulled into
the resolvedEntity
+ // then we should use the actual current table properties for IO
refresh here
+ // instead of the general tableDefaultProperties.
+ FileIO fileIO =
refreshIOWithCredentials(
tableIdentifier,
Set.of(latestLocationDir),
resolvedEntities,
- new HashMap<>(),
- fileIO);
+ new HashMap<>(tableDefaultProperties),
+ Set.of(PolarisStorageActions.READ));
return TableMetadataParser.read(fileIO, metadataLocation);
});
}
@@ -1164,7 +1241,7 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
getLocationsAllowedToBeAccessed(metadata),
resolvedStorageEntity,
new HashMap<>(metadata.properties()),
- tableFileIO);
+ Set.of(PolarisStorageActions.READ, PolarisStorageActions.WRITE));
List<PolarisEntity> resolvedNamespace =
resolvedTableEntities == null
@@ -1303,8 +1380,8 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
private final String fullViewName;
private FileIO viewFileIO;
- BasePolarisViewOperations(FileIO io, TableIdentifier identifier) {
- this.viewFileIO = io;
+ BasePolarisViewOperations(FileIO defaultFileIO, TableIdentifier
identifier) {
+ this.viewFileIO = defaultFileIO;
this.identifier = identifier;
this.fullViewName = ViewUtil.fullViewName(catalogName, identifier);
}
@@ -1336,34 +1413,21 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
SHOULD_RETRY_REFRESH_PREDICATE,
MAX_RETRIES,
metadataLocation -> {
- FileIO fileIO = this.viewFileIO;
- boolean closeFileIO = false;
String latestLocationDir =
latestLocation.substring(0, latestLocation.lastIndexOf('/'));
- Optional<PolarisEntity> storageInfoEntity =
- findStorageInfoFromHierarchy(resolvedEntities);
- Map<String, String> credentialsMap =
- storageInfoEntity
- .map(
- storageInfo ->
- refreshCredentials(
- identifier,
- Set.of(PolarisStorageActions.READ),
- latestLocationDir,
- storageInfo))
- .orElse(Map.of());
- if (!credentialsMap.isEmpty()) {
- String ioImpl = fileIO.getClass().getName();
- fileIO = loadFileIO(ioImpl, credentialsMap);
- closeFileIO = true;
- }
- try {
- return
ViewMetadataParser.read(fileIO.newInputFile(metadataLocation));
- } finally {
- if (closeFileIO) {
- fileIO.close();
- }
- }
+
+ // TODO: Once we have the "current" table properties pulled into
the resolvedEntity
+ // then we should use the actual current table properties for IO
refresh here
+ // instead of the general tableDefaultProperties.
+ FileIO fileIO =
+ refreshIOWithCredentials(
+ identifier,
+ Set.of(latestLocationDir),
+ resolvedEntities,
+ new HashMap<>(tableDefaultProperties),
+ Set.of(PolarisStorageActions.READ));
+
+ return
ViewMetadataParser.read(fileIO.newInputFile(metadataLocation));
});
}
}
@@ -1414,7 +1478,7 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
getLocationsAllowedToBeAccessed(metadata),
resolvedStorageEntity,
tableProperties,
- viewFileIO);
+ Set.of(PolarisStorageActions.READ, PolarisStorageActions.WRITE));
String newLocation = writeNewMetadataIfRequired(metadata);
String oldLocation = base == null ? null : currentMetadataLocation();
@@ -1475,17 +1539,13 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
Set<String> readLocations,
PolarisResolvedPathWrapper resolvedStorageEntity,
Map<String, String> tableProperties,
- FileIO fileIO) {
+ Set<PolarisStorageActions> storageActions) {
Optional<PolarisEntity> storageInfoEntity =
findStorageInfoFromHierarchy(resolvedStorageEntity);
Map<String, String> credentialsMap =
storageInfoEntity
.map(
storageInfo ->
- refreshCredentials(
- identifier,
- Set.of(PolarisStorageActions.READ,
PolarisStorageActions.WRITE),
- readLocations,
- storageInfo))
+ refreshCredentials(identifier, storageActions,
readLocations, storageInfo))
.orElse(Map.of());
// Update the FileIO before we write the new metadata file
@@ -1493,11 +1553,10 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
// the credentials should always override table-level properties, since
// storage configuration will be found at whatever entity defines it
tableProperties.putAll(credentialsMap);
- if (!tableProperties.isEmpty()) {
- fileIO = loadFileIO(ioImplClassName, tableProperties);
- // ensure the new fileIO is closed when the catalog is closed
- closeableGroup.addCloseable(fileIO);
- }
+ FileIO fileIO = null;
+ fileIO = loadFileIO(ioImplClassName, tableProperties);
+ // ensure the new fileIO is closed when the catalog is closed
+ closeableGroup.addCloseable(fileIO);
return fileIO;
}
@@ -1777,7 +1836,6 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
// first validate we can read the metadata file
validateLocationForTableLike(tableIdentifier, newLocation);
- TableOperations tableOperations = newTableOps(tableIdentifier);
String locationDir = newLocation.substring(0,
newLocation.lastIndexOf("/"));
FileIO fileIO =
@@ -1785,8 +1843,8 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
tableIdentifier,
Set.of(locationDir),
resolvedParent,
- new HashMap<>(),
- tableOperations.io());
+ new HashMap<>(tableDefaultProperties),
+ Set.of(PolarisStorageActions.READ, PolarisStorageActions.WRITE));
TableMetadata tableMetadata = TableMetadataParser.read(fileIO,
newLocation);
// then validate that it points to a valid location for this table
@@ -1879,6 +1937,14 @@ public class BasePolarisCatalog extends
BaseMetastoreViewCatalog
}
}
+ /** Helper to retrieve dynamic context-based configuration that has a
boolean value. */
+ private Boolean getBooleanContextConfiguration(String configKey, boolean
defaultValue) {
+ return callContext
+ .getPolarisCallContext()
+ .getConfigurationStore()
+ .getConfiguration(callContext.getPolarisCallContext(), configKey,
defaultValue);
+ }
+
/**
* Check if the exception is retryable for the storage provider
*
diff --git
a/polaris-service/src/test/java/org/apache/polaris/service/catalog/BasePolarisCatalogTest.java
b/polaris-service/src/test/java/org/apache/polaris/service/catalog/BasePolarisCatalogTest.java
index 12caecb..1652c4c 100644
---
a/polaris-service/src/test/java/org/apache/polaris/service/catalog/BasePolarisCatalogTest.java
+++
b/polaris-service/src/test/java/org/apache/polaris/service/catalog/BasePolarisCatalogTest.java
@@ -136,6 +136,7 @@ public class BasePolarisCatalogTest extends
CatalogTests<BasePolarisCatalog> {
metaStoreManager =
managerFactory.getOrCreateMetaStoreManager(realmContext);
Map<String, Object> configMap = new HashMap<>();
configMap.put("ALLOW_SPECIFYING_FILE_IO_IMPL", true);
+ configMap.put("INITIALIZE_DEFAULT_CATALOG_FILEIO_FOR_TEST", true);
polarisContext =
new PolarisCallContext(
managerFactory.getOrCreateSessionSupplier(realmContext).get(),
diff --git
a/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisCatalogHandlerWrapperAuthzTest.java
b/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisCatalogHandlerWrapperAuthzTest.java
index 4f64554..93e8ba3 100644
---
a/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisCatalogHandlerWrapperAuthzTest.java
+++
b/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisCatalogHandlerWrapperAuthzTest.java
@@ -21,9 +21,12 @@ package org.apache.polaris.service.catalog;
import com.google.common.collect.ImmutableMap;
import java.time.Instant;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import org.apache.hadoop.conf.Configuration;
import org.apache.iceberg.CatalogProperties;
+import org.apache.iceberg.CatalogUtil;
import org.apache.iceberg.PartitionSpec;
import org.apache.iceberg.SortOrder;
import org.apache.iceberg.TableMetadata;
@@ -1682,12 +1685,11 @@ public class PolarisCatalogHandlerWrapperAuthzTest
extends PolarisAuthzTestBase
Catalog catalog =
super.createCallContextCatalog(
context, authenticatedPolarisPrincipal, resolvedManifest);
+ String fileIoImpl = "org.apache.iceberg.inmemory.InMemoryFileIO";
catalog.initialize(
- externalCatalog,
- ImmutableMap.of(
- CatalogProperties.FILE_IO_IMPL,
"org.apache.iceberg.inmemory.InMemoryFileIO"));
+ externalCatalog,
ImmutableMap.of(CatalogProperties.FILE_IO_IMPL, fileIoImpl));
- FileIO fileIO = ((BasePolarisCatalog)
catalog).newTableOps(table).io();
+ FileIO fileIO = CatalogUtil.loadFileIO(fileIoImpl, Map.of(), new
Configuration());
TableMetadata tableMetadata =
TableMetadata.buildFromEmpty()
.addSchema(SCHEMA, SCHEMA.highestFieldId())
diff --git
a/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisSparkIntegrationTest.java
b/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisSparkIntegrationTest.java
index b948820..c25f884 100644
---
a/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisSparkIntegrationTest.java
+++
b/polaris-service/src/test/java/org/apache/polaris/service/catalog/PolarisSparkIntegrationTest.java
@@ -141,6 +141,14 @@ public class PolarisSparkIntegrationTest {
CatalogProperties externalProps = new
CatalogProperties("s3://my-bucket/path/to/data");
externalProps.putAll(
Map.of(
+ "table-default.s3.endpoint",
+ s3Container.getHttpEndpoint(),
+ "table-default.s3.path-style-access",
+ "true",
+ "table-default.s3.access-key-id",
+ "foo",
+ "table-default.s3.secret-access-key",
+ "bar",
"s3.endpoint",
s3Container.getHttpEndpoint(),
"s3.path-style-access",
diff --git
a/polaris-service/src/test/java/org/apache/polaris/service/test/PolarisConnectionExtension.java
b/polaris-service/src/test/java/org/apache/polaris/service/test/PolarisConnectionExtension.java
index 30f0a9a..bc267c7 100644
---
a/polaris-service/src/test/java/org/apache/polaris/service/test/PolarisConnectionExtension.java
+++
b/polaris-service/src/test/java/org/apache/polaris/service/test/PolarisConnectionExtension.java
@@ -27,11 +27,8 @@ import io.dropwizard.testing.junit5.DropwizardAppExtension;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
-import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
-import org.apache.polaris.core.PolarisDiagnostics;
import org.apache.polaris.core.context.CallContext;
import org.apache.polaris.core.context.RealmContext;
import org.apache.polaris.core.entity.PolarisEntityConstants;
@@ -39,17 +36,10 @@ import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.entity.PolarisGrantRecord;
import org.apache.polaris.core.entity.PolarisPrincipalSecrets;
-import org.apache.polaris.core.persistence.LocalPolarisMetaStoreManagerFactory;
import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.storage.PolarisCredentialProperty;
-import org.apache.polaris.core.storage.PolarisStorageActions;
-import org.apache.polaris.core.storage.PolarisStorageConfigurationInfo;
-import org.apache.polaris.core.storage.PolarisStorageIntegration;
-import org.apache.polaris.core.storage.PolarisStorageIntegrationProvider;
import org.apache.polaris.service.auth.TokenUtils;
import org.apache.polaris.service.config.PolarisApplicationConfig;
-import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
@@ -58,12 +48,7 @@ import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.platform.commons.util.ReflectionUtils;
-import org.mockito.Mockito;
import org.slf4j.LoggerFactory;
-import software.amazon.awssdk.services.sts.StsClient;
-import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
-import software.amazon.awssdk.services.sts.model.AssumeRoleResponse;
-import software.amazon.awssdk.services.sts.model.Credentials;
public class PolarisConnectionExtension implements BeforeAllCallback,
ParameterResolver {
@@ -94,55 +79,6 @@ public class PolarisConnectionExtension implements
BeforeAllCallback, ParameterR
(PolarisApplicationConfig) dropwizardAppExtension.getConfiguration();
metaStoreManagerFactory = config.getMetaStoreManagerFactory();
- if (metaStoreManagerFactory instanceof
LocalPolarisMetaStoreManagerFactory msmf) {
- StsClient mockSts = Mockito.mock(StsClient.class);
- Mockito.when(mockSts.assumeRole(Mockito.isA(AssumeRoleRequest.class)))
- .thenReturn(
- AssumeRoleResponse.builder()
- .credentials(
- Credentials.builder()
- .accessKeyId("theaccesskey")
- .secretAccessKey("thesecretkey")
- .sessionToken("thesessiontoken")
- .build())
- .build());
- msmf.setStorageIntegrationProvider(
- new PolarisStorageIntegrationProvider() {
- @Override
- public @Nullable <T extends PolarisStorageConfigurationInfo>
- PolarisStorageIntegration<T> getStorageIntegrationForConfig(
- PolarisStorageConfigurationInfo
polarisStorageConfigurationInfo) {
- return new PolarisStorageIntegration<T>("testIntegration") {
- @Override
- public EnumMap<PolarisCredentialProperty, String>
getSubscopedCreds(
- @NotNull PolarisDiagnostics diagnostics,
- @NotNull T storageConfig,
- boolean allowListOperation,
- @NotNull Set<String> allowedReadLocations,
- @NotNull Set<String> allowedWriteLocations) {
- return new EnumMap<>(PolarisCredentialProperty.class);
- }
-
- @Override
- public
EnumMap<PolarisStorageConfigurationInfo.DescribeProperty, String>
- descPolarisStorageConfiguration(
- @NotNull PolarisStorageConfigurationInfo
storageConfigInfo) {
- return new
EnumMap<>(PolarisStorageConfigurationInfo.DescribeProperty.class);
- }
-
- @Override
- public @NotNull Map<String, Map<PolarisStorageActions,
ValidationResult>>
- validateAccessToLocations(
- @NotNull T storageConfig,
- @NotNull Set<PolarisStorageActions> actions,
- @NotNull Set<String> locations) {
- return Map.of();
- }
- };
- }
- });
- }
-
RealmContext realmContext =
config
.getRealmContextResolver()
diff --git
a/polaris-service/src/test/resources/polaris-server-integrationtest.yml
b/polaris-service/src/test/resources/polaris-server-integrationtest.yml
index ebeaf9c..104e59d 100644
--- a/polaris-service/src/test/resources/polaris-server-integrationtest.yml
+++ b/polaris-service/src/test/resources/polaris-server-integrationtest.yml
@@ -71,6 +71,7 @@ featureConfiguration:
DISABLE_TOKEN_GENERATION_FOR_USER_PRINCIPALS: true
ALLOW_WILDCARD_LOCATION: true
ALLOW_SPECIFYING_FILE_IO_IMPL: true
+ SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION: true
ALLOW_OVERLAPPING_CATALOG_URLS: true
SUPPORTED_CATALOG_STORAGE_TYPES:
- FILE