This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new f5519f6ffbf branch-3.1: [fix](params-refactor)Enhance Object Storage
Parameter Validation and Exception Handling #55014 (#55086)
f5519f6ffbf is described below
commit f5519f6ffbf3e33477e7f351659ca7c72d4b1e0d
Author: Calvin Kirs <[email protected]>
AuthorDate: Thu Aug 21 16:45:38 2025 +0800
branch-3.1: [fix](params-refactor)Enhance Object Storage Parameter
Validation and Exception Handling #55014 (#55086)
picked from #55014
---
.../apache/doris/datasource/CatalogProperty.java | 22 +++++++--
.../apache/doris/datasource/ExternalCatalog.java | 28 +----------
.../doris/datasource/iceberg/dlf/DLFCatalog.java | 27 +++++------
.../datasource/property/PropertyConverter.java | 3 --
.../IcebergFileSystemMetaStoreProperties.java | 9 +---
.../storage/AbstractS3CompatibleProperties.java | 5 ++
.../datasource/property/storage/COSProperties.java | 17 -------
.../property/storage/MinioProperties.java | 17 -------
.../datasource/property/storage/OBSProperties.java | 17 -------
.../datasource/property/storage/OSSProperties.java | 14 +-----
.../datasource/property/storage/S3Properties.java | 42 ++++++----------
.../datasource/property/PropertyConverterTest.java | 56 +---------------------
.../property/storage/COSPropertiesTest.java | 8 ++--
.../property/storage/MinioPropertiesTest.java | 13 +++--
.../property/storage/OBSPropertyTest.java | 17 ++++---
.../property/storage/OSSPropertiesTest.java | 37 ++++++++++++--
.../property/storage/S3PropertiesTest.java | 10 ++--
17 files changed, 116 insertions(+), 226 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogProperty.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogProperty.java
index 8ad534ff86b..0fff877ef36 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogProperty.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogProperty.java
@@ -20,7 +20,6 @@ package org.apache.doris.datasource;
import org.apache.doris.common.UserException;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
-import org.apache.doris.datasource.property.PropertyConverter;
import org.apache.doris.datasource.property.metastore.MetastoreProperties;
import org.apache.doris.datasource.property.storage.StorageProperties;
import org.apache.doris.persist.gson.GsonUtils;
@@ -28,6 +27,7 @@ import org.apache.doris.persist.gson.GsonUtils;
import com.google.common.collect.Maps;
import com.google.gson.annotations.SerializedName;
import org.apache.commons.collections.MapUtils;
+import org.apache.hadoop.conf.Configuration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -84,7 +84,7 @@ public class CatalogProperty implements Writable {
public void modifyCatalogProps(Map<String, String> props) {
synchronized (this) {
-
properties.putAll(PropertyConverter.convertToMetaProperties(props));
+ properties.putAll(props);
resetAllCaches();
}
}
@@ -206,9 +206,21 @@ public class CatalogProperty implements Writable {
if (hadoopProperties == null) {
synchronized (this) {
if (hadoopProperties == null) {
- Map<String, String> result = getProperties();
-
result.putAll(PropertyConverter.convertToHadoopFSProperties(getProperties()));
- this.hadoopProperties = result;
+ hadoopProperties = new HashMap<>();
+ Map<StorageProperties.Type, StorageProperties> storageMap
= getStoragePropertiesMap();
+
+ for (StorageProperties sp : storageMap.values()) {
+ Configuration configuration =
sp.getHadoopStorageConfig();
+ if (configuration != null) {
+ configuration.forEach(entry -> {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (value != null) {
+ hadoopProperties.put(key, value);
+ }
+ });
+ }
+ }
}
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
index d5312fe5e3f..083d3d20565 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
@@ -53,7 +53,6 @@ import
org.apache.doris.datasource.maxcompute.MaxComputeExternalDatabase;
import org.apache.doris.datasource.metacache.MetaCache;
import org.apache.doris.datasource.operations.ExternalMetadataOps;
import org.apache.doris.datasource.paimon.PaimonExternalDatabase;
-import org.apache.doris.datasource.property.PropertyConverter;
import org.apache.doris.datasource.test.TestExternalCatalog;
import org.apache.doris.datasource.test.TestExternalDatabase;
import
org.apache.doris.datasource.trinoconnector.TrinoConnectorExternalDatabase;
@@ -167,13 +166,6 @@ public abstract class ExternalCatalog
private boolean objectCreated = false;
protected ExternalMetadataOps metadataOps;
protected TransactionManager transactionManager;
-
- private ExternalSchemaCache schemaCache;
- // A cached and being converted properties for external catalog.
- // generated from catalog properties.
- private byte[] propLock = new byte[0];
- private Map<String, String> convertedProperties = null;
-
protected Optional<Boolean> useMetaCache = Optional.empty();
protected MetaCache<ExternalDatabase<? extends ExternalTable>> metaCache;
protected ExecutionAuthenticator executionAuthenticator;
@@ -315,7 +307,6 @@ public abstract class ExternalCatalog
}
return;
}
- isInitializing = true;
try {
initLocalObjects();
if (!initialized) {
@@ -575,10 +566,6 @@ public abstract class ExternalCatalog
public synchronized void resetToUninitialized(boolean invalidCache) {
this.objectCreated = false;
this.initialized = false;
- synchronized (this.propLock) {
- this.convertedProperties = null;
- }
-
synchronized (this.confLock) {
this.cachedConf = null;
}
@@ -743,17 +730,7 @@ public abstract class ExternalCatalog
@Override
public Map<String, String> getProperties() {
- // convert properties may be a heavy operation, so we cache the result.
- if (convertedProperties != null) {
- return convertedProperties;
- }
- synchronized (propLock) {
- if (convertedProperties != null) {
- return convertedProperties;
- }
- convertedProperties =
PropertyConverter.convertToMetaProperties(catalogProperty.getProperties());
- return convertedProperties;
- }
+ return catalogProperty.getProperties();
}
@Override
@@ -1041,7 +1018,6 @@ public abstract class ExternalCatalog
}
}
}
- this.propLock = new byte[0];
this.confLock = new byte[0];
this.initialized = false;
setDefaultPropsIfMissing(true);
@@ -1165,7 +1141,7 @@ public abstract class ExternalCatalog
@Override
public void dropTable(String dbName, String tableName, boolean isView,
boolean isMtmv, boolean ifExists,
- boolean force) throws DdlException {
+ boolean force) throws DdlException {
makeSureInitialized();
if (metadataOps == null) {
throw new DdlException("Drop table is not supported for catalog: "
+ getName());
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/dlf/DLFCatalog.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/dlf/DLFCatalog.java
index e51292feff2..fb90260f09a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/dlf/DLFCatalog.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/dlf/DLFCatalog.java
@@ -21,11 +21,10 @@ import org.apache.doris.common.credentials.CloudCredential;
import org.apache.doris.common.util.S3Util;
import org.apache.doris.datasource.iceberg.HiveCompatibleCatalog;
import org.apache.doris.datasource.iceberg.dlf.client.DLFCachedClientPool;
-import org.apache.doris.datasource.property.constants.OssProperties;
-import org.apache.doris.datasource.property.constants.S3Properties;
+import org.apache.doris.datasource.property.storage.OSSProperties;
+import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.aliyun.oss.Constants;
import org.apache.iceberg.TableOperations;
import org.apache.iceberg.aws.s3.S3FileIO;
import org.apache.iceberg.catalog.TableIdentifier;
@@ -50,22 +49,18 @@ public class DLFCatalog extends HiveCompatibleCatalog {
protected FileIO initializeFileIO(Map<String, String> properties,
Configuration hadoopConf) {
// read from converted properties or default by old s3 aws properties
- String endpoint = properties.getOrDefault(Constants.ENDPOINT_KEY,
properties.get(S3Properties.Env.ENDPOINT));
+ OSSProperties ossProperties = OSSProperties.of(properties);
+ String endpoint = ossProperties.getEndpoint();
CloudCredential credential = new CloudCredential();
-
credential.setAccessKey(properties.getOrDefault(OssProperties.ACCESS_KEY,
- properties.get(S3Properties.Env.ACCESS_KEY)));
-
credential.setSecretKey(properties.getOrDefault(OssProperties.SECRET_KEY,
- properties.get(S3Properties.Env.SECRET_KEY)));
- if (properties.containsKey(OssProperties.SESSION_TOKEN)
- || properties.containsKey(S3Properties.Env.TOKEN)) {
-
credential.setSessionToken(properties.getOrDefault(OssProperties.SESSION_TOKEN,
- properties.get(S3Properties.Env.TOKEN)));
+ credential.setAccessKey(ossProperties.getAccessKey());
+ credential.setSecretKey(ossProperties.getSecretKey());
+ if (StringUtils.isNotBlank(ossProperties.getSessionToken())) {
+ credential.setSessionToken(ossProperties.getSessionToken());
}
- String region = properties.getOrDefault(OssProperties.REGION,
properties.get(S3Properties.Env.REGION));
- boolean isUsePathStyle = properties.getOrDefault("use_path_style",
"false")
- .equalsIgnoreCase("true");
+ String region = ossProperties.getRegion();
+ boolean isUsePathStyle =
Boolean.parseBoolean(ossProperties.getUsePathStyle());
// s3 file io just supports s3-like endpoint
- String s3Endpoint = endpoint.replace(region, "s3." + region);
+ String s3Endpoint = endpoint.replace("oss-" + region, "s3.oss-" +
region);
if (!s3Endpoint.contains("://")) {
s3Endpoint = "http://" + s3Endpoint;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/PropertyConverter.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/PropertyConverter.java
index aa22a83e1b0..4e26a80de5a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/PropertyConverter.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/PropertyConverter.java
@@ -61,9 +61,6 @@ public class PropertyConverter {
private static final Logger LOG =
LogManager.getLogger(PropertyConverter.class);
public static final String USE_PATH_STYLE = "use_path_style";
- public static final String USE_PATH_STYLE_DEFAULT_VALUE = "false";
- public static final String FORCE_PARSING_BY_STANDARD_URI =
"force_parsing_by_standard_uri";
- public static final String FORCE_PARSING_BY_STANDARD_URI_DEFAULT_VALUE =
"false";
/**
* Convert properties defined at doris to metadata properties on Cloud
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergFileSystemMetaStoreProperties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergFileSystemMetaStoreProperties.java
index fa94f79df77..7dd97b028b2 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergFileSystemMetaStoreProperties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergFileSystemMetaStoreProperties.java
@@ -28,7 +28,6 @@ import org.apache.iceberg.CatalogProperties;
import org.apache.iceberg.catalog.Catalog;
import org.apache.iceberg.hadoop.HadoopCatalog;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -48,6 +47,7 @@ public class IcebergFileSystemMetaStoreProperties extends
AbstractIcebergPropert
List<StorageProperties> storagePropertiesList) {
Configuration configuration =
buildConfiguration(storagePropertiesList);
HadoopCatalog catalog = new HadoopCatalog();
+ buildCatalogProps(catalogProps, storagePropertiesList);
catalog.setConf(configuration);
try {
this.executionAuthenticator.execute(() -> {
@@ -72,9 +72,7 @@ public class IcebergFileSystemMetaStoreProperties extends
AbstractIcebergPropert
return configuration;
}
- private Map<String, String> buildCatalogProps(List<StorageProperties>
storagePropertiesList) {
- Map<String, String> props = new HashMap<>(origProps);
-
+ private void buildCatalogProps(Map<String, String> props,
List<StorageProperties> storagePropertiesList) {
if (storagePropertiesList.size() == 1 && storagePropertiesList.get(0)
instanceof HdfsProperties) {
HdfsProperties hdfsProps = (HdfsProperties)
storagePropertiesList.get(0);
if (hdfsProps.isKerberos()) {
@@ -83,9 +81,6 @@ public class IcebergFileSystemMetaStoreProperties extends
AbstractIcebergPropert
this.executionAuthenticator = new
HadoopExecutionAuthenticator(hdfsProps.getHadoopAuthenticator());
}
}
-
- props.put(CatalogProperties.WAREHOUSE_LOCATION, warehouse);
- return props;
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/AbstractS3CompatibleProperties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/AbstractS3CompatibleProperties.java
index bd5a4a0824c..3b0bca28365 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/AbstractS3CompatibleProperties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/AbstractS3CompatibleProperties.java
@@ -135,6 +135,11 @@ public abstract class AbstractS3CompatibleProperties
extends StorageProperties i
throw new IllegalArgumentException("Invalid endpoint: " +
getEndpoint());
}
setRegionIfPossible();
+ //Allow anonymous access if both access_key and secret_key are empty
+ //But not recommended for production use.
+ if (StringUtils.isBlank(getAccessKey()) !=
StringUtils.isBlank(getSecretKey())) {
+ throw new IllegalArgumentException("Both the access key and the
secret key must be set.");
+ }
}
/**
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/COSProperties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/COSProperties.java
index 8e09576891e..b284ba5666e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/COSProperties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/COSProperties.java
@@ -18,7 +18,6 @@
package org.apache.doris.datasource.property.storage;
import org.apache.doris.datasource.property.ConnectorProperty;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
@@ -126,22 +125,6 @@ public class COSProperties extends
AbstractS3CompatibleProperties {
super(Type.COS, origProps);
}
- @Override
- public void initNormalizeAndCheckProps() {
- super.initNormalizeAndCheckProps();
- // Check if credentials are provided properly - either both or neither
- if (StringUtils.isNotBlank(accessKey) &&
StringUtils.isNotBlank(secretKey)) {
- return;
- }
- // Allow anonymous access if both access_key and secret_key are empty
- if (StringUtils.isBlank(accessKey) && StringUtils.isBlank(secretKey)) {
- return;
- }
- // If only one is provided, it's an error
- throw new StoragePropertiesException(
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.");
- }
-
protected static boolean guessIsMe(Map<String, String> origProps) {
String value = Stream.of("cos.endpoint", "s3.endpoint",
"AWS_ENDPOINT", "endpoint", "ENDPOINT")
.map(origProps::get)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/MinioProperties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/MinioProperties.java
index 6f0496ae5ff..dd8d2735324 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/MinioProperties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/MinioProperties.java
@@ -18,7 +18,6 @@
package org.apache.doris.datasource.property.storage;
import org.apache.doris.datasource.property.ConnectorProperty;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
@@ -113,22 +112,6 @@ public class MinioProperties extends
AbstractS3CompatibleProperties {
super(Type.MINIO, origProps);
}
- @Override
- public void initNormalizeAndCheckProps() {
- super.initNormalizeAndCheckProps();
- // Check if credentials are provided properly - either both or neither
- if (StringUtils.isNotBlank(accessKey) &&
StringUtils.isNotBlank(secretKey)) {
- return;
- }
- // Allow anonymous access if both access_key and secret_key are empty
- if (StringUtils.isBlank(accessKey) && StringUtils.isBlank(secretKey)) {
- return;
- }
- // If only one is provided, it's an error
- throw new StoragePropertiesException(
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.");
- }
-
public static boolean guessIsMe(Map<String, String> origProps) {
//ugly, but we need to check if the user has set any of the identifiers
if (AzureProperties.guessIsMe(origProps) ||
COSProperties.guessIsMe(origProps)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OBSProperties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OBSProperties.java
index 5e9c513d67e..eea6c24ddc4 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OBSProperties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OBSProperties.java
@@ -18,7 +18,6 @@
package org.apache.doris.datasource.property.storage;
import org.apache.doris.datasource.property.ConnectorProperty;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
@@ -130,22 +129,6 @@ public class OBSProperties extends
AbstractS3CompatibleProperties {
// Initialize fields from origProps
}
- @Override
- public void initNormalizeAndCheckProps() {
- super.initNormalizeAndCheckProps();
- // Check if credentials are provided properly - either both or neither
- if (StringUtils.isNotBlank(accessKey) &&
StringUtils.isNotBlank(secretKey)) {
- return;
- }
- // Allow anonymous access if both access_key and secret_key are empty
- if (StringUtils.isBlank(accessKey) && StringUtils.isBlank(secretKey)) {
- return;
- }
- // If only one is provided, it's an error
- throw new StoragePropertiesException(
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.");
- }
-
protected static boolean guessIsMe(Map<String, String> origProps) {
String value = Stream.of("obs.endpoint", "s3.endpoint",
"AWS_ENDPOINT", "endpoint", "ENDPOINT")
.map(origProps::get)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
index 4cb43b3155a..0d7d41f2cc1 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
@@ -19,7 +19,6 @@ package org.apache.doris.datasource.property.storage;
import org.apache.doris.datasource.property.ConnectorPropertiesUtils;
import org.apache.doris.datasource.property.ConnectorProperty;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
@@ -203,7 +202,7 @@ public class OSSProperties extends
AbstractS3CompatibleProperties {
if (!value.contains("aliyuncs.com")) {
return false;
}
- boolean isAliyunOss = (value.contains("oss-") ||
value.contains("dlf."));
+ boolean isAliyunOss = (value.contains("oss-"));
boolean isAmazonS3 = value.contains("s3.");
boolean isDls = value.contains("dls");
return isAliyunOss || isAmazonS3 || isDls;
@@ -247,17 +246,6 @@ public class OSSProperties extends
AbstractS3CompatibleProperties {
if (endpoint.contains("dlf") || endpoint.contains("oss-dls")) {
this.endpoint = getOssEndpoint(region,
BooleanUtils.toBoolean(dlfAccessPublic));
}
- // Check if credentials are provided properly - either both or neither
- if (StringUtils.isNotBlank(accessKey) &&
StringUtils.isNotBlank(secretKey)) {
- return;
- }
- // Allow anonymous access if both access_key and secret_key are empty
- if (StringUtils.isBlank(accessKey) && StringUtils.isBlank(secretKey)) {
- return;
- }
- // If only one is provided, it's an error
- throw new StoragePropertiesException(
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.");
}
private static String getOssEndpoint(String region, boolean publicAccess) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/S3Properties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/S3Properties.java
index bd05f39d4ab..e4a15fb5a8e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/S3Properties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/S3Properties.java
@@ -19,9 +19,7 @@ package org.apache.doris.datasource.property.storage;
import org.apache.doris.datasource.property.ConnectorPropertiesUtils;
import org.apache.doris.datasource.property.ConnectorProperty;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
-import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
import lombok.Setter;
@@ -34,6 +32,7 @@ import
software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvide
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import
software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider;
import
software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sts.StsClient;
import
software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider;
@@ -187,25 +186,10 @@ public class S3Properties extends
AbstractS3CompatibleProperties {
@Override
public void initNormalizeAndCheckProps() {
super.initNormalizeAndCheckProps();
- convertGlueToS3EndpointIfNeeded();
- if (StringUtils.isNotBlank(accessKey) &&
StringUtils.isNotBlank(secretKey)) {
- return;
- }
- if (StringUtils.isNotBlank(s3ExternalId) &&
StringUtils.isNotBlank(s3IAMRole)) {
- return;
- }
- // When using vended credentials with a REST catalog, AK/SK are not
provided directly.
- // The credentials will be fetched from the REST service later.
- // So we skip the credential check in this case.
- if
(Boolean.parseBoolean(origProps.getOrDefault("iceberg.rest.vended-credentials-enabled",
"false"))) {
- return;
- }
- // Allow anonymous access if both access_key and secret_key are empty
- if (StringUtils.isBlank(accessKey) && StringUtils.isBlank(secretKey)) {
- return;
+ if (StringUtils.isNotBlank(s3ExternalId) &&
StringUtils.isBlank(s3IAMRole)) {
+ throw new IllegalArgumentException("s3.external_id must be used
with s3.role_arn");
}
- throw new StoragePropertiesException("Please set s3.access_key and
s3.secret_key or s3.role_arn and "
- + "s3.external_id or omit all for anonymous access to public
bucket.");
+ convertGlueToS3EndpointIfNeeded();
}
/**
@@ -226,7 +210,7 @@ public class S3Properties extends
AbstractS3CompatibleProperties {
* cause the type detection to fail, leading to missed recognition of
valid S3 properties.
* A more robust approach would allow further validation downstream
rather than failing early here.
*/
- if (!Strings.isNullOrEmpty(endpoint)) {
+ if (StringUtils.isNotBlank(endpoint)) {
return endpoint.contains("amazonaws.com");
}
@@ -245,7 +229,7 @@ public class S3Properties extends
AbstractS3CompatibleProperties {
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
- if (!Strings.isNullOrEmpty(region)) {
+ if (StringUtils.isNotBlank(region)) {
return true;
}
return false;
@@ -260,9 +244,10 @@ public class S3Properties extends
AbstractS3CompatibleProperties {
public Map<String, String> getBackendConfigProperties() {
Map<String, String> backendProperties =
generateBackendS3Configuration();
- if (StringUtils.isNotBlank(s3ExternalId)
- && StringUtils.isNotBlank(s3IAMRole)) {
+ if (StringUtils.isNotBlank(s3IAMRole)) {
backendProperties.put("AWS_ROLE_ARN", s3IAMRole);
+ }
+ if (StringUtils.isNotBlank(s3ExternalId)) {
backendProperties.put("AWS_EXTERNAL_ID", s3ExternalId);
}
return backendProperties;
@@ -282,6 +267,7 @@ public class S3Properties extends
AbstractS3CompatibleProperties {
}
if (StringUtils.isNotBlank(s3IAMRole)) {
StsClient stsClient = StsClient.builder()
+ .region(Region.of(region))
.credentialsProvider(InstanceProfileCredentialsProvider.create())
.build();
@@ -289,7 +275,7 @@ public class S3Properties extends
AbstractS3CompatibleProperties {
.stsClient(stsClient)
.refreshRequest(builder -> {
builder.roleArn(s3IAMRole).roleSessionName("aws-sdk-java-v2-fe");
- if (!Strings.isNullOrEmpty(s3ExternalId)) {
+ if (StringUtils.isNotBlank(s3ExternalId)) {
builder.externalId(s3ExternalId);
}
}).build();
@@ -310,12 +296,14 @@ public class S3Properties extends
AbstractS3CompatibleProperties {
super.initializeHadoopStorageConfig();
//Set assumed_roles
//@See
https://hadoop.apache.org/docs/r3.4.1/hadoop-aws/tools/hadoop-aws/assumed_roles.html
- if (StringUtils.isNotBlank(s3ExternalId) &&
StringUtils.isNotBlank(s3IAMRole)) {
+ if (StringUtils.isNotBlank(s3IAMRole)) {
//@See org.apache.hadoop.fs.s3a.auth.AssumedRoleCredentialProvider
- hadoopStorageConfig.set("fs.s3a.assumed.role.external.id",
s3ExternalId);
hadoopStorageConfig.set("fs.s3a.assumed.role.arn", s3IAMRole);
hadoopStorageConfig.set("fs.s3a.aws.credentials.provider",
"org.apache.hadoop.fs.s3a.auth.AssumedRoleCredentialProvider");
+ if (StringUtils.isNotBlank(s3ExternalId)) {
+ hadoopStorageConfig.set("fs.s3a.assumed.role.external.id",
s3ExternalId);
+ }
}
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/PropertyConverterTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/PropertyConverterTest.java
index 36e78d80c6b..6e9686481d0 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/PropertyConverterTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/PropertyConverterTest.java
@@ -23,8 +23,6 @@ import org.apache.doris.analysis.CreateResourceStmt;
import org.apache.doris.analysis.DropCatalogStmt;
import org.apache.doris.analysis.OutFileClause;
import org.apache.doris.analysis.QueryStmt;
-import org.apache.doris.analysis.SelectStmt;
-import org.apache.doris.analysis.TableValuedFunctionRef;
import org.apache.doris.backup.Repository;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.Resource;
@@ -50,7 +48,6 @@ import
org.apache.doris.datasource.property.constants.ObsProperties;
import org.apache.doris.datasource.property.constants.OssProperties;
import org.apache.doris.datasource.property.constants.S3Properties;
import org.apache.doris.meta.MetaContext;
-import org.apache.doris.tablefunction.S3TableValuedFunction;
import org.apache.doris.thrift.TFileFormatType;
import org.apache.doris.utframe.TestWithFeService;
@@ -228,56 +225,6 @@ public class PropertyConverterTest extends
TestWithFeService {
Assertions.assertEquals(repositoryNew.getRemoteFileSystem().getProperties().size(),
4);
}
- @Test
- public void testS3TVFPropertiesConverter() throws Exception {
- FeConstants.runningUnitTest = true;
- String queryOld = "select * from s3(\n"
- + " 'uri' =
'http://s3.us-east-1.amazonaws.com/my-bucket/test.parquet',\n"
- + " 'access_key' = 'akk',\n"
- + " 'secret_key' = 'skk',\n"
- + " 'region' = 'us-east-1',\n"
- + " 'format' = 'parquet',\n"
- + " 'use_path_style' = 'true'\n"
- + ") limit 10;";
- SelectStmt analyzedStmt = createStmt(queryOld);
- Assertions.assertEquals(analyzedStmt.getTableRefs().size(), 1);
- TableValuedFunctionRef oldFuncTable = (TableValuedFunctionRef)
analyzedStmt.getTableRefs().get(0);
- S3TableValuedFunction s3Tvf = (S3TableValuedFunction)
oldFuncTable.getTableFunction();
- Assertions.assertEquals(5,
s3Tvf.getBrokerDesc().getProperties().size());
-
- String queryNew = "select * from s3(\n"
- + " 'uri' =
'http://s3.us-east-1.amazonaws.com/my-bucket/test.parquet',\n"
- + " 's3.access_key' = 'akk',\n"
- + " 's3.secret_key' = 'skk',\n"
- + " 'format' = 'parquet',\n"
- + " 'use_path_style' = 'true'\n"
- + ") limit 10;";
- SelectStmt analyzedStmtNew = createStmt(queryNew);
- Assertions.assertEquals(analyzedStmtNew.getTableRefs().size(), 1);
- TableValuedFunctionRef newFuncTable = (TableValuedFunctionRef)
analyzedStmt.getTableRefs().get(0);
- S3TableValuedFunction newS3Tvf = (S3TableValuedFunction)
newFuncTable.getTableFunction();
- Assertions.assertEquals(5,
newS3Tvf.getBrokerDesc().getProperties().size());
- }
-
- @Test
- public void testAWSOldCatalogPropertiesConverter() throws Exception {
- String queryOld = "create catalog hms_s3_old properties (\n"
- + " 'type'='hms',\n"
- + " 'hive.metastore.uris' = 'thrift://172.21.0.44:7004',\n"
- + " 'AWS_ENDPOINT' = 's3.us-east-1.amazonaws.com',\n"
- + " 'AWS_REGION' = 'us-east-1',\n"
- + " 'AWS_ACCESS_KEY' = 'akk',\n"
- + " 'AWS_SECRET_KEY' = 'skk'\n"
- + ");";
- CreateCatalogStmt analyzedStmt = createStmt(queryOld);
- HMSExternalCatalog catalog = createAndGetCatalog(analyzedStmt,
"hms_s3_old");
- Map<String, String> properties =
catalog.getCatalogProperty().getProperties();
- Assertions.assertEquals(9, properties.size());
-
- Map<String, String> hdProps =
catalog.getCatalogProperty().getHadoopProperties();
- Assertions.assertEquals(17, hdProps.size());
- }
-
@Disabled
@Test
public void testS3CatalogPropertiesConverter() throws Exception {
@@ -304,7 +251,7 @@ public class PropertyConverterTest extends
TestWithFeService {
String query1 = "create catalog " + catalogName1 + " properties (\n"
+ " 'type'='hms',\n"
+ " 'hive.metastore.uris' = 'thrift://172.21.0.1:7004',\n"
- + " 'oss.endpoint' = 'oss-cn-beijing.aliyuncs.com',\n"
+ + " 'oss.endpoint' = 'cn-beijing.oss-dls.aliyuncs.com',\n"
+ " 'oss.hdfs.enabled' = 'true',\n"
+ " 'oss.access_key' = 'akk',\n"
+ " 'oss.secret_key' = 'skk'\n"
@@ -313,7 +260,6 @@ public class PropertyConverterTest extends
TestWithFeService {
CreateCatalogStmt analyzedStmt = createStmt(query1);
HMSExternalCatalog catalog = createAndGetCatalog(analyzedStmt,
catalogName);
Map<String, String> hdProps =
catalog.getCatalogProperty().getHadoopProperties();
- Assertions.assertEquals("com.aliyun.jindodata.oss.JindoOssFileSystem",
hdProps.get("fs.oss.impl"));
Assertions.assertEquals("cn-beijing.oss-dls.aliyuncs.com",
hdProps.get("fs.oss.endpoint"));
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/COSPropertiesTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/COSPropertiesTest.java
index 5d718e0cbf2..0cf30e49c04 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/COSPropertiesTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/COSPropertiesTest.java
@@ -148,7 +148,7 @@ public class COSPropertiesTest {
public void testMissingAccessKey() {
origProps.put("cos.endpoint", "cos.ap-beijing.myqcloud.com");
origProps.put("cos.secret_key", "myCOSSecretKey");
- Assertions.assertThrows(StoragePropertiesException.class, () ->
StorageProperties.createPrimary(origProps),
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
StorageProperties.createPrimary(origProps),
"Please set access_key and secret_key or omit both for
anonymous access to public bucket.");
}
@@ -156,7 +156,9 @@ public class COSPropertiesTest {
public void testMissingSecretKey() {
origProps.put("cos.endpoint", "cos.ap-beijing.myqcloud.com");
origProps.put("cos.access_key", "myCOSAccessKey");
- Assertions.assertThrows(StoragePropertiesException.class, () ->
StorageProperties.createPrimary(origProps),
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.");
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
StorageProperties.createPrimary(origProps),
+ "Both the access key and the secret key must be set.");
+ origProps.remove("cos.access_key");
+ Assertions.assertDoesNotThrow(() ->
StorageProperties.createPrimary(origProps));
}
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/MinioPropertiesTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/MinioPropertiesTest.java
index fe6d8c5e859..bd6fbf2239a 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/MinioPropertiesTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/MinioPropertiesTest.java
@@ -19,7 +19,6 @@ package org.apache.doris.datasource.property.storage;
import org.apache.doris.common.ExceptionChecker;
import org.apache.doris.common.UserException;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@@ -67,18 +66,22 @@ public class MinioPropertiesTest {
public void testMissingAccessKey() {
origProps.put("s3.endpoint", "http://localhost:9000");
origProps.put("s3.secret_key", "minioSecretKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.",
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.",
() -> StorageProperties.createPrimary(origProps));
+ origProps.remove("s3.secret_key");
+ Assertions.assertDoesNotThrow(() ->
StorageProperties.createPrimary(origProps));
}
@Test
public void testMissingSecretKey() {
origProps.put("s3.endpoint", "http://localhost:9000");
origProps.put("s3.access_key", "minioAccessKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.",
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.",
() -> StorageProperties.createPrimary(origProps));
+ origProps.remove("s3.access_key");
+ Assertions.assertDoesNotThrow(() ->
StorageProperties.createPrimary(origProps));
}
@Test
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OBSPropertyTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OBSPropertyTest.java
index e700ede2de3..2c6f5ffab21 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OBSPropertyTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OBSPropertyTest.java
@@ -19,7 +19,6 @@ package org.apache.doris.datasource.property.storage;
import org.apache.doris.common.ExceptionChecker;
import org.apache.doris.common.UserException;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -47,8 +46,8 @@ public class OBSPropertyTest {
// allow both access_key and secret_key to be empty for anonymous
access
ExceptionChecker.expectThrowsNoException(() ->
StorageProperties.createAll(origProps));
origProps.put("obs.access_key", "myOBSAccessKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.",
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.",
() -> StorageProperties.createAll(origProps));
origProps.put("obs.secret_key", "myOBSSecretKey");
origProps.put("obs.endpoint", "obs.cn-north-4.myhuaweicloud.com");
@@ -131,18 +130,22 @@ public class OBSPropertyTest {
public void testmissingAccessKey() {
origProps.put("obs.endpoint", "obs.cn-north-4.myhuaweicloud.com");
origProps.put("obs.secret_key", "myOBSSecretKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.",
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.",
() -> StorageProperties.createPrimary(origProps));
+ origProps.remove("obs.secret_key");
+ Assertions.assertDoesNotThrow(() ->
StorageProperties.createPrimary(origProps));
}
@Test
public void testMissingSecretKey() {
origProps.put("obs.endpoint", "obs.cn-north-4.myhuaweicloud.com");
origProps.put("obs.access_key", "myOBSAccessKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.",
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.",
() -> StorageProperties.createPrimary(origProps));
+ origProps.remove("obs.access_key");
+ Assertions.assertDoesNotThrow(() ->
StorageProperties.createPrimary(origProps));
}
private static String obsAccessKey = "";
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
index 20efe3ebe97..31b56a2bd9b 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
@@ -19,7 +19,6 @@ package org.apache.doris.datasource.property.storage;
import org.apache.doris.common.ExceptionChecker;
import org.apache.doris.common.UserException;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -146,9 +145,21 @@ public class OSSPropertiesTest {
Map<String, String> origProps = new HashMap<>();
origProps.put("oss.endpoint", "oss-cn-hangzhou.aliyuncs.com");
origProps.put("oss.secret_key", "myOSSSecretKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.",
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.",
() -> StorageProperties.createPrimary(origProps));
+ origProps.remove("oss.secret_key");
+ Assertions.assertDoesNotThrow(() ->
StorageProperties.createPrimary(origProps));
+ }
+
+ @Test
+ public void testDlfProperties() {
+ Map<String, String> origProps = new HashMap<>();
+ origProps.put("iceberg.catalog.type", "dlf");
+ origProps.put("dlf.region", "cn-beijing");
+ origProps.put("dlf.access.public", "true");
+ OSSProperties ossProperties = OSSProperties.of(origProps);
+ Assertions.assertEquals("oss-cn-beijing.aliyuncs.com",
ossProperties.getEndpoint());
}
@Test
@@ -156,9 +167,11 @@ public class OSSPropertiesTest {
Map<String, String> origProps = new HashMap<>();
origProps.put("oss.endpoint", "oss-cn-hangzhou.aliyuncs.com");
origProps.put("oss.access_key", "myOSSAccessKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set access_key and secret_key or omit both for
anonymous access to public bucket.",
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.",
() -> StorageProperties.createPrimary(origProps));
+ origProps.remove("oss.access_key");
+ Assertions.assertDoesNotThrow(() ->
StorageProperties.createPrimary(origProps));
}
@Test
@@ -176,4 +189,18 @@ public class OSSPropertiesTest {
origProps.put("uri",
"https://doris-regression-hk.oss-cn-hangzhou-internal.aliyuncs.com/regression/datalake/pipeline_data/data_page_v2_gzip.parquet");
Assertions.assertEquals("oss-cn-hangzhou-internal.aliyuncs.com",
((OSSProperties) StorageProperties.createPrimary(origProps)).getEndpoint());
}
+
+ @Test
+ public void testOSSProperties() throws UserException {
+ Map<String, String> origProps = new HashMap<>();
+ origProps.put("warehouse", "new_dlf_paimon_catalog");
+ origProps.put("uri", "http://cn-beijing-vpc.dlf.aliyuncs.com");
+ origProps.put("type", "paimon");
+ origProps.put("paimon.rest.token.provider", "dlf");
+ origProps.put("paimon.rest.dlf.access-key-secret", "XXXXX");
+ origProps.put("paimon.rest.dlf.access-key-id", "XXXXXX");
+ origProps.put("paimon.catalog.type", "rest");
+ Assertions.assertEquals(1,
StorageProperties.createAll(origProps).size());
+ }
+
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/S3PropertiesTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/S3PropertiesTest.java
index a766be98f15..4852eff9032 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/S3PropertiesTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/S3PropertiesTest.java
@@ -19,7 +19,6 @@ package org.apache.doris.datasource.property.storage;
import org.apache.doris.common.ExceptionChecker;
import org.apache.doris.common.UserException;
-import
org.apache.doris.datasource.property.storage.exception.StoragePropertiesException;
import com.google.common.collect.Maps;
import mockit.Expectations;
@@ -71,8 +70,8 @@ public class S3PropertiesTest {
origProps = new HashMap<>();
origProps.put("s3.endpoint",
"s3-fips.dualstack.us-east-2.amazonaws.com");
origProps.put("s3.access_key", "myS3AccessKey");
- ExceptionChecker.expectThrowsWithMsg(StoragePropertiesException.class,
- "Please set s3.access_key and s3.secret_key", () ->
StorageProperties.createAll(origProps));
+ ExceptionChecker.expectThrowsWithMsg(IllegalArgumentException.class,
+ "Both the access key and the secret key must be set.", () ->
StorageProperties.createAll(origProps));
origProps.put("s3.secret_key", "myS3SecretKey");
ExceptionChecker.expectThrowsNoException(() ->
StorageProperties.createAll(origProps));
}
@@ -221,6 +220,11 @@ public class S3PropertiesTest {
Assertions.assertEquals("arn:aws:iam::123456789012:role/MyTestRole",
backendProperties.get("AWS_ROLE_ARN"));
Assertions.assertEquals("external-123",
backendProperties.get("AWS_EXTERNAL_ID"));
+ origProps.remove("s3.external_id");
+ s3Props = (S3Properties) StorageProperties.createPrimary(origProps);
+ backendProperties = s3Props.getBackendConfigProperties();
+ Assertions.assertNull(backendProperties.get("AWS_EXTERNAL_ID"));
+ Assertions.assertEquals("arn:aws:iam::123456789012:role/MyTestRole",
backendProperties.get("AWS_ROLE_ARN"));
}
@Test
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]