This is an automated email from the ASF dual-hosted git repository.
fanng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 73d5ffcfe [#5624] feat(bundles): support ADLS credential provider
(#5737)
73d5ffcfe is described below
commit 73d5ffcfe369f2303277660a27ce1d5b781e9836
Author: JUN <[email protected]>
AuthorDate: Tue Dec 17 14:18:25 2024 +0800
[#5624] feat(bundles): support ADLS credential provider (#5737)
### What changes were proposed in this pull request?
Add ADLS credential provider
### Why are the changes needed?
Fix: #5624
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Added a unit test and verified successful access to the ADLS container.

### Supplementary Information
Chose to use the following versions of Azure libraries:
- `azure-identity` = "1.13.1"
- `azure-storage-file-datalake` = "12.20.0"
- `azure-core-http-okhttp` = "1.12.0"
Instead of the latest versions because, although the official
documentation states support for Java 8 and later, the latest versions
appear to have been compiled with Java 21. This caused compilation
issues in the Gravitino environment. Therefore, downgraded and tested to
find the latest usable versions.
---
.../gravitino/credential/ADLSTokenCredential.java | 116 ++++++++++++
.../gravitino/credential/OSSTokenCredential.java | 16 +-
.../org.apache.gravitino.credential.Credential | 1 +
bundles/azure-bundle/build.gradle.kts | 4 +
.../abs/credential/ADLSLocationUtils.java | 85 +++++++++
.../abs/credential/ADLSTokenProvider.java | 138 ++++++++++++++
.../gravitino/abs/fs/AzureFileSystemProvider.java | 10 +-
....apache.gravitino.credential.CredentialProvider | 7 +-
.../lakehouse/iceberg/IcebergConstants.java | 4 +
.../lakehouse/iceberg/IcebergPropertiesUtils.java | 8 +
.../gravitino/credential/CredentialConstants.java | 3 +
.../apache/gravitino/storage/ABSProperties.java | 29 ---
.../apache/gravitino/storage/AzureProperties.java | 39 ++++
.../integration/test/HadoopABSCatalogIT.java | 10 +-
.../tests/integration/test_gvfs_with_abs.py | 4 +-
.../test/GravitinoVirtualFileSystemABSIT.java | 18 +-
.../credential/CredentialPropertyUtils.java | 12 ++
.../credential/TestCredentialFactory.java | 37 +++-
.../credential/TestCredentialPropertiesUtils.java | 24 ++-
.../credential/config/ADLSCredentialConfig.java | 116 ++++++++++++
.../iceberg-rest-server-dependency.sh | 7 +
dev/docker/iceberg-rest-server/rewrite_config.py | 7 +-
docs/hadoop-catalog.md | 12 +-
docs/how-to-use-gvfs.md | 8 +-
docs/iceberg-rest-service.md | 57 ++++--
gradle/libs.versions.toml | 10 +
iceberg/iceberg-common/build.gradle.kts | 1 +
iceberg/iceberg-rest-server/build.gradle.kts | 8 +
.../integration/test/IcebergRESTADLSIT.java | 205 +++++++++++++++++++++
.../iceberg/integration/test/IcebergRESTGCSIT.java | 11 +-
.../iceberg/integration/test/IcebergRESTOSSIT.java | 21 +--
.../integration/test/IcebergRESTOSSSecretIT.java | 15 +-
.../iceberg/integration/test/IcebergRESTS3IT.java | 19 +-
settings.gradle.kts | 2 +-
34 files changed, 921 insertions(+), 143 deletions(-)
diff --git
a/api/src/main/java/org/apache/gravitino/credential/ADLSTokenCredential.java
b/api/src/main/java/org/apache/gravitino/credential/ADLSTokenCredential.java
new file mode 100644
index 000000000..25c83c2f7
--- /dev/null
+++ b/api/src/main/java/org/apache/gravitino/credential/ADLSTokenCredential.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.credential;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+
+/** ADLS SAS token credential. */
+public class ADLSTokenCredential implements Credential {
+
+ /** ADLS SAS token credential type. */
+ public static final String ADLS_SAS_TOKEN_CREDENTIAL_TYPE = "adls-sas-token";
+ /** ADLS base domain */
+ public static final String ADLS_DOMAIN = "dfs.core.windows.net";
+ /** ADLS storage account name */
+ public static final String GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME =
"azure-storage-account-name";
+ /** ADLS SAS token used to access ADLS data. */
+ public static final String GRAVITINO_ADLS_SAS_TOKEN = "adls-sas-token";
+
+ private String accountName;
+ private String sasToken;
+ private long expireTimeInMS;
+
+ /**
+ * Constructs an instance of {@link ADLSTokenCredential} with SAS token.
+ *
+ * @param accountName The ADLS account name.
+ * @param sasToken The ADLS SAS token.
+ * @param expireTimeInMS The SAS token expire time in ms.
+ */
+ public ADLSTokenCredential(String accountName, String sasToken, long
expireTimeInMS) {
+ validate(accountName, sasToken, expireTimeInMS);
+ this.accountName = accountName;
+ this.sasToken = sasToken;
+ this.expireTimeInMS = expireTimeInMS;
+ }
+
+ /**
+ * This is the constructor that is used by credential factory to create an
instance of credential
+ * according to the credential information.
+ */
+ public ADLSTokenCredential() {}
+
+ @Override
+ public String credentialType() {
+ return ADLS_SAS_TOKEN_CREDENTIAL_TYPE;
+ }
+
+ @Override
+ public long expireTimeInMs() {
+ return expireTimeInMS;
+ }
+
+ @Override
+ public Map<String, String> credentialInfo() {
+ return (new ImmutableMap.Builder<String, String>())
+ .put(GRAVITINO_ADLS_SAS_TOKEN, sasToken)
+ .build();
+ }
+
+ @Override
+ public void initialize(Map<String, String> credentialInfo, long
expireTimeInMS) {
+ String accountName =
credentialInfo.get(GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME);
+ String sasToken = credentialInfo.get(GRAVITINO_ADLS_SAS_TOKEN);
+ validate(accountName, sasToken, expireTimeInMS);
+ this.accountName = accountName;
+ this.sasToken = sasToken;
+ this.expireTimeInMS = expireTimeInMS;
+ }
+
+ /**
+ * Get ADLS account name
+ *
+ * @return The ADLS account name
+ */
+ public String accountName() {
+ return accountName;
+ }
+
+ /**
+ * Get ADLS SAS token.
+ *
+ * @return The ADLS SAS token.
+ */
+ public String sasToken() {
+ return sasToken;
+ }
+
+ private void validate(String accountName, String sasToken, long
expireTimeInMS) {
+ Preconditions.checkArgument(
+ StringUtils.isNotBlank(accountName), "ADLS account name should not be
empty.");
+ Preconditions.checkArgument(
+ StringUtils.isNotBlank(sasToken), "ADLS SAS token should not be
empty.");
+ Preconditions.checkArgument(
+ expireTimeInMS > 0, "The expire time of ADLSTokenCredential should
great than 0");
+ }
+}
diff --git
a/api/src/main/java/org/apache/gravitino/credential/OSSTokenCredential.java
b/api/src/main/java/org/apache/gravitino/credential/OSSTokenCredential.java
index edf23f207..70e883948 100644
--- a/api/src/main/java/org/apache/gravitino/credential/OSSTokenCredential.java
+++ b/api/src/main/java/org/apache/gravitino/credential/OSSTokenCredential.java
@@ -51,13 +51,7 @@ public class OSSTokenCredential implements Credential {
*/
public OSSTokenCredential(
String accessKeyId, String secretAccessKey, String securityToken, long
expireTimeInMS) {
- Preconditions.checkArgument(
- StringUtils.isNotBlank(accessKeyId), "OSS access key Id should not be
empty");
- Preconditions.checkArgument(
- StringUtils.isNotBlank(secretAccessKey), "OSS access key secret should
not be empty");
- Preconditions.checkArgument(
- StringUtils.isNotBlank(securityToken), "OSS security token should not
be empty");
-
+ validate(accessKeyId, secretAccessKey, securityToken, expireTimeInMS);
this.accessKeyId = accessKeyId;
this.secretAccessKey = secretAccessKey;
this.securityToken = securityToken;
@@ -133,12 +127,12 @@ public class OSSTokenCredential implements Credential {
private void validate(
String accessKeyId, String secretAccessKey, String sessionToken, long
expireTimeInMs) {
Preconditions.checkArgument(
- StringUtils.isNotBlank(accessKeyId), "S3 access key Id should not be
empty");
+ StringUtils.isNotBlank(accessKeyId), "OSS access key Id should not be
empty");
Preconditions.checkArgument(
- StringUtils.isNotBlank(secretAccessKey), "S3 secret access key should
not be empty");
+ StringUtils.isNotBlank(secretAccessKey), "OSS secret access key should
not be empty");
Preconditions.checkArgument(
- StringUtils.isNotBlank(sessionToken), "S3 session token should not be
empty");
+ StringUtils.isNotBlank(sessionToken), "OSS session token should not be
empty");
Preconditions.checkArgument(
- expireTimeInMs > 0, "The expire time of S3TokenCredential should great
than 0");
+ expireTimeInMs > 0, "The expire time of OSSTokenCredential should
great than 0");
}
}
diff --git
a/api/src/main/resources/META-INF/services/org.apache.gravitino.credential.Credential
b/api/src/main/resources/META-INF/services/org.apache.gravitino.credential.Credential
index b6d2dd028..f130b4b64 100644
---
a/api/src/main/resources/META-INF/services/org.apache.gravitino.credential.Credential
+++
b/api/src/main/resources/META-INF/services/org.apache.gravitino.credential.Credential
@@ -22,3 +22,4 @@ org.apache.gravitino.credential.S3SecretKeyCredential
org.apache.gravitino.credential.GCSTokenCredential
org.apache.gravitino.credential.OSSTokenCredential
org.apache.gravitino.credential.OSSSecretKeyCredential
+org.apache.gravitino.credential.ADLSTokenCredential
diff --git a/bundles/azure-bundle/build.gradle.kts
b/bundles/azure-bundle/build.gradle.kts
index 8580c672e..9e4a4add5 100644
--- a/bundles/azure-bundle/build.gradle.kts
+++ b/bundles/azure-bundle/build.gradle.kts
@@ -27,6 +27,7 @@ plugins {
dependencies {
compileOnly(project(":api"))
compileOnly(project(":core"))
+ compileOnly(project(":catalogs:catalog-common"))
compileOnly(project(":catalogs:catalog-hadoop"))
compileOnly(project(":catalogs:hadoop-common")) {
exclude("*")
@@ -34,6 +35,9 @@ dependencies {
compileOnly(libs.hadoop3.common)
+ implementation(libs.azure.identity)
+ implementation(libs.azure.storage.file.datalake)
+
implementation(libs.commons.lang3)
// runtime used
implementation(libs.commons.logging)
diff --git
a/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/credential/ADLSLocationUtils.java
b/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/credential/ADLSLocationUtils.java
new file mode 100644
index 000000000..198b00deb
--- /dev/null
+++
b/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/credential/ADLSLocationUtils.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.abs.credential;
+
+import java.net.URI;
+
+public class ADLSLocationUtils {
+ /** Encapsulates parts of an ADLS URI: container, account name, and path. */
+ public static class ADLSLocationParts {
+ private final String container;
+ private final String accountName;
+ private final String path;
+
+ public ADLSLocationParts(String container, String accountName, String
path) {
+ this.container = container;
+ this.accountName = accountName;
+ this.path = path;
+ }
+
+ public String getContainer() {
+ return container;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public String getPath() {
+ return path;
+ }
+ }
+
+ /**
+ * Parses an ADLS URI and extracts its components. Example: Input:
+ * "abfss://[email protected]/path/data". Output:
ADLSLocationParts {
+ * container = "container", accountName = "accountName", path = "/path/data"
}
+ *
+ * @param location The ADLS URI (e.g.,
+ * "abfss://[email protected]/path/data").
+ * @return An ADLSLocationParts object containing the container, account
name, and path.
+ * @throws IllegalArgumentException If the URI format is invalid.
+ */
+ public static ADLSLocationParts parseLocation(String location) {
+ URI locationUri = URI.create(location);
+
+ String[] authorityParts = locationUri.getAuthority().split("@");
+
+ if (authorityParts.length <= 1) {
+ throw new IllegalArgumentException("Invalid location: " + location);
+ }
+
+ return new ADLSLocationParts(
+ authorityParts[0], authorityParts[1].split("\\.")[0],
locationUri.getPath());
+ }
+
+ /**
+ * Trims leading and trailing slashes from a given string.
+ *
+ * @param input The string to process.
+ * @return A string without leading or trailing slashes, or null if the
input is null.
+ */
+ public static String trimSlashes(String input) {
+ if (input == null) {
+ return null;
+ }
+ return input.replaceAll("^/+|/*$", "");
+ }
+}
diff --git
a/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/credential/ADLSTokenProvider.java
b/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/credential/ADLSTokenProvider.java
new file mode 100644
index 000000000..e2ee3ed82
--- /dev/null
+++
b/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/credential/ADLSTokenProvider.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.abs.credential;
+
+import com.azure.core.util.Context;
+import com.azure.identity.ClientSecretCredential;
+import com.azure.identity.ClientSecretCredentialBuilder;
+import com.azure.storage.file.datalake.DataLakeServiceClient;
+import com.azure.storage.file.datalake.DataLakeServiceClientBuilder;
+import com.azure.storage.file.datalake.implementation.util.DataLakeSasImplUtil;
+import com.azure.storage.file.datalake.models.UserDelegationKey;
+import com.azure.storage.file.datalake.sas.DataLakeServiceSasSignatureValues;
+import com.azure.storage.file.datalake.sas.PathSasPermission;
+import java.time.OffsetDateTime;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.gravitino.credential.ADLSTokenCredential;
+import org.apache.gravitino.credential.Credential;
+import org.apache.gravitino.credential.CredentialConstants;
+import org.apache.gravitino.credential.CredentialContext;
+import org.apache.gravitino.credential.CredentialProvider;
+import org.apache.gravitino.credential.PathBasedCredentialContext;
+import org.apache.gravitino.credential.config.ADLSCredentialConfig;
+
+/** Generates ADLS token to access ADLS data. */
+public class ADLSTokenProvider implements CredentialProvider {
+ private String storageAccountName;
+ private String tenantId;
+ private String clientId;
+ private String clientSecret;
+ private String endpoint;
+ private Integer tokenExpireSecs;
+
+ @Override
+ public void initialize(Map<String, String> properties) {
+ ADLSCredentialConfig adlsCredentialConfig = new
ADLSCredentialConfig(properties);
+ this.storageAccountName = adlsCredentialConfig.storageAccountName();
+ this.tenantId = adlsCredentialConfig.tenantId();
+ this.clientId = adlsCredentialConfig.clientId();
+ this.clientSecret = adlsCredentialConfig.clientSecret();
+ this.endpoint =
+ String.format("https://%s.%s", storageAccountName,
ADLSTokenCredential.ADLS_DOMAIN);
+ this.tokenExpireSecs = adlsCredentialConfig.tokenExpireInSecs();
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public String credentialType() {
+ return CredentialConstants.ADLS_TOKEN_CREDENTIAL_PROVIDER_TYPE;
+ }
+
+ @Override
+ public Credential getCredential(CredentialContext context) {
+ if (!(context instanceof PathBasedCredentialContext)) {
+ return null;
+ }
+ PathBasedCredentialContext pathBasedCredentialContext =
(PathBasedCredentialContext) context;
+
+ Set<String> writePaths = pathBasedCredentialContext.getWritePaths();
+ Set<String> readPaths = pathBasedCredentialContext.getReadPaths();
+
+ Set<String> combinedPaths = new HashSet<>(writePaths);
+ combinedPaths.addAll(readPaths);
+
+ if (combinedPaths.size() != 1) {
+ throw new IllegalArgumentException(
+ "ADLS should contain exactly one unique path, but found: "
+ + combinedPaths.size()
+ + " paths: "
+ + combinedPaths);
+ }
+ String uniquePath = combinedPaths.iterator().next();
+
+ ClientSecretCredential clientSecretCredential =
+ new ClientSecretCredentialBuilder()
+ .tenantId(tenantId)
+ .clientId(clientId)
+ .clientSecret(clientSecret)
+ .build();
+
+ DataLakeServiceClient dataLakeServiceClient =
+ new DataLakeServiceClientBuilder()
+ .endpoint(endpoint)
+ .credential(clientSecretCredential)
+ .buildClient();
+
+ OffsetDateTime start = OffsetDateTime.now();
+ OffsetDateTime expiry = OffsetDateTime.now().plusSeconds(tokenExpireSecs);
+ UserDelegationKey userDelegationKey =
dataLakeServiceClient.getUserDelegationKey(start, expiry);
+
+ PathSasPermission pathSasPermission =
+ new
PathSasPermission().setReadPermission(true).setListPermission(true);
+
+ if (!writePaths.isEmpty()) {
+ pathSasPermission
+ .setWritePermission(true)
+ .setDeletePermission(true)
+ .setCreatePermission(true)
+ .setAddPermission(true);
+ }
+
+ DataLakeServiceSasSignatureValues signatureValues =
+ new DataLakeServiceSasSignatureValues(expiry, pathSasPermission);
+
+ ADLSLocationUtils.ADLSLocationParts locationParts =
ADLSLocationUtils.parseLocation(uniquePath);
+ String sasToken =
+ new DataLakeSasImplUtil(
+ signatureValues,
+ locationParts.getContainer(),
+ ADLSLocationUtils.trimSlashes(locationParts.getPath()),
+ true)
+ .generateUserDelegationSas(
+ userDelegationKey, locationParts.getAccountName(),
Context.NONE);
+
+ return new ADLSTokenCredential(
+ locationParts.getAccountName(), sasToken,
expiry.toInstant().toEpochMilli());
+ }
+}
diff --git
a/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/fs/AzureFileSystemProvider.java
b/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/fs/AzureFileSystemProvider.java
index cad38e14c..f89240441 100644
---
a/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/fs/AzureFileSystemProvider.java
+++
b/bundles/azure-bundle/src/main/java/org/apache/gravitino/abs/fs/AzureFileSystemProvider.java
@@ -26,7 +26,7 @@ import java.util.Map;
import javax.annotation.Nonnull;
import org.apache.gravitino.catalog.hadoop.fs.FileSystemProvider;
import org.apache.gravitino.catalog.hadoop.fs.FileSystemUtils;
-import org.apache.gravitino.storage.ABSProperties;
+import org.apache.gravitino.storage.AzureProperties;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
@@ -49,13 +49,13 @@ public class AzureFileSystemProvider implements
FileSystemProvider {
Map<String, String> hadoopConfMap =
FileSystemUtils.toHadoopConfigMap(config, ImmutableMap.of());
- if (config.containsKey(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME)
- && config.containsKey(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY)) {
+ if
(config.containsKey(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME)
+ &&
config.containsKey(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY)) {
hadoopConfMap.put(
String.format(
"fs.azure.account.key.%s.dfs.core.windows.net",
- config.get(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME)),
- config.get(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY));
+
config.get(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME)),
+ config.get(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY));
}
if (!config.containsKey(ABFS_IMPL_KEY)) {
diff --git
a/api/src/main/resources/META-INF/services/org.apache.gravitino.credential.Credential
b/bundles/azure-bundle/src/main/resources/META-INF/services/org.apache.gravitino.credential.CredentialProvider
similarity index 75%
copy from
api/src/main/resources/META-INF/services/org.apache.gravitino.credential.Credential
copy to
bundles/azure-bundle/src/main/resources/META-INF/services/org.apache.gravitino.credential.CredentialProvider
index b6d2dd028..fb53efffa 100644
---
a/api/src/main/resources/META-INF/services/org.apache.gravitino.credential.Credential
+++
b/bundles/azure-bundle/src/main/resources/META-INF/services/org.apache.gravitino.credential.CredentialProvider
@@ -16,9 +16,4 @@
# specific language governing permissions and limitations
# under the License.
#
-
-org.apache.gravitino.credential.S3TokenCredential
-org.apache.gravitino.credential.S3SecretKeyCredential
-org.apache.gravitino.credential.GCSTokenCredential
-org.apache.gravitino.credential.OSSTokenCredential
-org.apache.gravitino.credential.OSSSecretKeyCredential
+org.apache.gravitino.abs.credential.ADLSTokenProvider
\ No newline at end of file
diff --git
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
index 4d9e99eba..214f38113 100644
---
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
+++
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergConstants.java
@@ -47,6 +47,10 @@ public class IcebergConstants {
public static final String ICEBERG_OSS_ACCESS_KEY_ID =
"client.access-key-id";
public static final String ICEBERG_OSS_ACCESS_KEY_SECRET =
"client.access-key-secret";
+ public static final String ICEBERG_ADLS_STORAGE_ACCOUNT_NAME =
+ "adls.auth.shared-key.account.name";
+ public static final String ICEBERG_ADLS_STORAGE_ACCOUNT_KEY =
"adls.auth.shared-key.account.key";
+
// Iceberg Table properties constants
public static final String COMMENT = "comment";
diff --git
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergPropertiesUtils.java
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergPropertiesUtils.java
index abe08c57d..06f017c59 100644
---
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergPropertiesUtils.java
+++
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/IcebergPropertiesUtils.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
+import org.apache.gravitino.storage.AzureProperties;
import org.apache.gravitino.storage.OSSProperties;
import org.apache.gravitino.storage.S3Properties;
@@ -55,6 +56,13 @@ public class IcebergPropertiesUtils {
map.put(
OSSProperties.GRAVITINO_OSS_ACCESS_KEY_SECRET,
IcebergConstants.ICEBERG_OSS_ACCESS_KEY_SECRET);
+ // ADLS
+ map.put(
+ AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME,
+ IcebergConstants.ICEBERG_ADLS_STORAGE_ACCOUNT_NAME);
+ map.put(
+ AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY,
+ IcebergConstants.ICEBERG_ADLS_STORAGE_ACCOUNT_KEY);
GRAVITINO_CONFIG_TO_ICEBERG = Collections.unmodifiableMap(map);
}
diff --git
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/credential/CredentialConstants.java
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/credential/CredentialConstants.java
index 739cd0139..7dd74d084 100644
---
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/credential/CredentialConstants.java
+++
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/credential/CredentialConstants.java
@@ -29,5 +29,8 @@ public class CredentialConstants {
public static final String OSS_TOKEN_CREDENTIAL_PROVIDER = "oss-token";
public static final String OSS_TOKEN_EXPIRE_IN_SECS =
"oss-token-expire-in-secs";
+ public static final String ADLS_TOKEN_CREDENTIAL_PROVIDER_TYPE =
"adls-token";
+ public static final String ADLS_TOKEN_EXPIRE_IN_SECS =
"adls-token-expire-in-secs";
+
private CredentialConstants() {}
}
diff --git
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/ABSProperties.java
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/ABSProperties.java
deleted file mode 100644
index a76ece32b..000000000
---
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/ABSProperties.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.gravitino.storage;
-
-public class ABSProperties {
-
- // The account name of the Azure Blob Storage.
- public static final String GRAVITINO_ABS_ACCOUNT_NAME = "abs-account-name";
-
- // The account key of the Azure Blob Storage.
- public static final String GRAVITINO_ABS_ACCOUNT_KEY = "abs-account-key";
-}
diff --git
a/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/AzureProperties.java
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/AzureProperties.java
new file mode 100644
index 000000000..5da0172c5
--- /dev/null
+++
b/catalogs/catalog-common/src/main/java/org/apache/gravitino/storage/AzureProperties.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.storage;
+
+// Defines unified properties for Azure configurations.
+public class AzureProperties {
+
+ // Configuration key for specifying the name of the storage account.
+ public static final String GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME =
"azure-storage-account-name";
+ // Configuration key for specifying the key of the storage account.
+ public static final String GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY =
"azure-storage-account-key";
+
+ // Configuration key for specifying the Azure Active Directory (AAD) tenant
ID.
+ public static final String GRAVITINO_AZURE_TENANT_ID = "azure-tenant-id";
+ // Configuration key for specifying the Azure Active Directory (AAD) client
ID used for
+ // authentication.
+ public static final String GRAVITINO_AZURE_CLIENT_ID = "azure-client-id";
+ // Configuration key for specifying the Azure Active Directory (AAD) client
secret used for
+ // authentication.
+ public static final String GRAVITINO_AZURE_CLIENT_SECRET =
"azure-client-secret";
+
+ private AzureProperties() {}
+}
diff --git
a/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/integration/test/HadoopABSCatalogIT.java
b/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/integration/test/HadoopABSCatalogIT.java
index 0da915a7d..482daba2e 100644
---
a/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/integration/test/HadoopABSCatalogIT.java
+++
b/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/integration/test/HadoopABSCatalogIT.java
@@ -31,7 +31,7 @@ import org.apache.gravitino.Schema;
import org.apache.gravitino.abs.fs.AzureFileSystemProvider;
import org.apache.gravitino.file.Fileset;
import org.apache.gravitino.integration.test.util.GravitinoITUtils;
-import org.apache.gravitino.storage.ABSProperties;
+import org.apache.gravitino.storage.AzureProperties;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
@@ -113,8 +113,8 @@ public class HadoopABSCatalogIT extends HadoopCatalogIT {
protected void createCatalog() {
Map<String, String> map = Maps.newHashMap();
- map.put(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME, ABS_ACCOUNT_NAME);
- map.put(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY, ABS_ACCOUNT_KEY);
+ map.put(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME,
ABS_ACCOUNT_NAME);
+ map.put(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY,
ABS_ACCOUNT_KEY);
map.put(FILESYSTEM_PROVIDERS, AzureFileSystemProvider.ABS_PROVIDER_NAME);
metalake.createCatalog(catalogName, Catalog.Type.FILESET, provider,
"comment", map);
@@ -138,8 +138,8 @@ public class HadoopABSCatalogIT extends HadoopCatalogIT {
GravitinoITUtils.genRandomName("CatalogCatalogIT"));
Map<String, String> catalogProps = Maps.newHashMap();
catalogProps.put("location", ossLocation);
- catalogProps.put(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME,
ABS_ACCOUNT_NAME);
- catalogProps.put(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY, ABS_ACCOUNT_KEY);
+ catalogProps.put(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME,
ABS_ACCOUNT_NAME);
+ catalogProps.put(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY,
ABS_ACCOUNT_KEY);
catalogProps.put(FILESYSTEM_PROVIDERS,
AzureFileSystemProvider.ABS_PROVIDER_NAME);
Catalog localCatalog =
diff --git a/clients/client-python/tests/integration/test_gvfs_with_abs.py
b/clients/client-python/tests/integration/test_gvfs_with_abs.py
index 3377c07cd..a218efcfd 100644
--- a/clients/client-python/tests/integration/test_gvfs_with_abs.py
+++ b/clients/client-python/tests/integration/test_gvfs_with_abs.py
@@ -123,8 +123,8 @@ class TestGvfsWithABS(TestGvfsWithHDFS):
comment="",
properties={
"filesystem-providers": "abs",
- "abs-account-name": cls.azure_abs_account_name,
- "abs-account-key": cls.azure_abs_account_key,
+ "azure-storage-account-name": cls.azure_abs_account_name,
+ "azure-storage-account-key": cls.azure_abs_account_key,
},
)
catalog.as_schemas().create_schema(
diff --git
a/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/integration/test/GravitinoVirtualFileSystemABSIT.java
b/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/integration/test/GravitinoVirtualFileSystemABSIT.java
index 11557417f..d69c2d946 100644
---
a/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/integration/test/GravitinoVirtualFileSystemABSIT.java
+++
b/clients/filesystem-hadoop3/src/test/java/org/apache/gravitino/filesystem/hadoop/integration/test/GravitinoVirtualFileSystemABSIT.java
@@ -30,7 +30,7 @@ import org.apache.gravitino.Catalog;
import org.apache.gravitino.abs.fs.AzureFileSystemProvider;
import org.apache.gravitino.catalog.hadoop.fs.FileSystemUtils;
import org.apache.gravitino.integration.test.util.GravitinoITUtils;
-import org.apache.gravitino.storage.ABSProperties;
+import org.apache.gravitino.storage.AzureProperties;
import org.apache.hadoop.conf.Configuration;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
@@ -77,8 +77,8 @@ public class GravitinoVirtualFileSystemABSIT extends
GravitinoVirtualFileSystemI
Map<String, String> properties = Maps.newHashMap();
- properties.put(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME, ABS_ACCOUNT_NAME);
- properties.put(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY, ABS_ACCOUNT_KEY);
+ properties.put(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME,
ABS_ACCOUNT_NAME);
+ properties.put(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY,
ABS_ACCOUNT_KEY);
properties.put(FILESYSTEM_PROVIDERS,
AzureFileSystemProvider.ABS_PROVIDER_NAME);
Catalog catalog =
@@ -96,8 +96,8 @@ public class GravitinoVirtualFileSystemABSIT extends
GravitinoVirtualFileSystemI
conf.set("fs.gravitino.client.metalake", metalakeName);
// Pass this configuration to the real file system
- conf.set(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME, ABS_ACCOUNT_NAME);
- conf.set(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY, ABS_ACCOUNT_KEY);
+ conf.set(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME,
ABS_ACCOUNT_NAME);
+ conf.set(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY,
ABS_ACCOUNT_KEY);
conf.set("fs.abfss.impl",
"org.apache.hadoop.fs.azurebfs.SecureAzureBlobFileSystem");
}
@@ -133,13 +133,13 @@ public class GravitinoVirtualFileSystemABSIT extends
GravitinoVirtualFileSystemI
Map<String, String> hadoopConfMap = FileSystemUtils.toHadoopConfigMap(map,
ImmutableMap.of());
- if (gvfsConf.get(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME) != null
- && gvfsConf.get(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY) != null) {
+ if (gvfsConf.get(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME) !=
null
+ && gvfsConf.get(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY)
!= null) {
hadoopConfMap.put(
String.format(
"fs.azure.account.key.%s.dfs.core.windows.net",
- gvfsConf.get(ABSProperties.GRAVITINO_ABS_ACCOUNT_NAME)),
- gvfsConf.get(ABSProperties.GRAVITINO_ABS_ACCOUNT_KEY));
+
gvfsConf.get(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME)),
+ gvfsConf.get(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY));
}
hadoopConfMap.forEach(absConf::set);
diff --git
a/common/src/main/java/org/apache/gravitino/credential/CredentialPropertyUtils.java
b/common/src/main/java/org/apache/gravitino/credential/CredentialPropertyUtils.java
index d9fb74903..e1803a6dd 100644
---
a/common/src/main/java/org/apache/gravitino/credential/CredentialPropertyUtils.java
+++
b/common/src/main/java/org/apache/gravitino/credential/CredentialPropertyUtils.java
@@ -33,6 +33,7 @@ public class CredentialPropertyUtils {
@VisibleForTesting static final String ICEBERG_S3_SECRET_ACCESS_KEY =
"s3.secret-access-key";
@VisibleForTesting static final String ICEBERG_S3_TOKEN = "s3.session-token";
@VisibleForTesting static final String ICEBERG_GCS_TOKEN =
"gcs.oauth2.token";
+ @VisibleForTesting static final String ICEBERG_ADLS_TOKEN = "adls.sas-token";
@VisibleForTesting static final String ICEBERG_OSS_ACCESS_KEY_ID =
"client.access-key-id";
@VisibleForTesting static final String ICEBERG_OSS_ACCESS_KEY_SECRET =
"client.access-key-secret";
@@ -75,6 +76,17 @@ public class CredentialPropertyUtils {
if (credential instanceof OSSTokenCredential || credential instanceof
OSSSecretKeyCredential) {
return transformProperties(credential.credentialInfo(),
icebergCredentialPropertyMap);
}
+ if (credential instanceof ADLSTokenCredential) {
+ ADLSTokenCredential adlsCredential = (ADLSTokenCredential) credential;
+ String sasTokenKey =
+ String.format(
+ "%s.%s.%s",
+ ICEBERG_ADLS_TOKEN, adlsCredential.accountName(),
ADLSTokenCredential.ADLS_DOMAIN);
+
+ Map<String, String> icebergADLSCredentialProperties = new HashMap<>();
+ icebergADLSCredentialProperties.put(sasTokenKey,
adlsCredential.sasToken());
+ return icebergADLSCredentialProperties;
+ }
return credential.toProperties();
}
diff --git
a/common/src/test/java/org/apache/gravitino/credential/TestCredentialFactory.java
b/common/src/test/java/org/apache/gravitino/credential/TestCredentialFactory.java
index b873c0afa..75a669e38 100644
---
a/common/src/test/java/org/apache/gravitino/credential/TestCredentialFactory.java
+++
b/common/src/test/java/org/apache/gravitino/credential/TestCredentialFactory.java
@@ -42,7 +42,7 @@ public class TestCredentialFactory {
S3TokenCredential.S3_TOKEN_CREDENTIAL_TYPE, s3TokenCredentialInfo,
expireTime);
Assertions.assertEquals(
S3TokenCredential.S3_TOKEN_CREDENTIAL_TYPE,
s3TokenCredential.credentialType());
- Assertions.assertTrue(s3TokenCredential instanceof S3TokenCredential);
+ Assertions.assertInstanceOf(S3TokenCredential.class, s3TokenCredential);
S3TokenCredential s3TokenCredential1 = (S3TokenCredential)
s3TokenCredential;
Assertions.assertEquals("accessKeyId", s3TokenCredential1.accessKeyId());
Assertions.assertEquals("secretAccessKey",
s3TokenCredential1.secretAccessKey());
@@ -67,7 +67,7 @@ public class TestCredentialFactory {
Assertions.assertEquals(
S3SecretKeyCredential.S3_SECRET_KEY_CREDENTIAL_TYPE,
s3SecretKeyCredential.credentialType());
- Assertions.assertTrue(s3SecretKeyCredential instanceof
S3SecretKeyCredential);
+ Assertions.assertInstanceOf(S3SecretKeyCredential.class,
s3SecretKeyCredential);
S3SecretKeyCredential s3SecretKeyCredential1 = (S3SecretKeyCredential)
s3SecretKeyCredential;
Assertions.assertEquals("accessKeyId",
s3SecretKeyCredential1.accessKeyId());
Assertions.assertEquals("secretAccessKey",
s3SecretKeyCredential1.secretAccessKey());
@@ -84,7 +84,7 @@ public class TestCredentialFactory {
GCSTokenCredential.GCS_TOKEN_CREDENTIAL_TYPE,
gcsTokenCredentialInfo, expireTime);
Assertions.assertEquals(
GCSTokenCredential.GCS_TOKEN_CREDENTIAL_TYPE,
gcsTokenCredential.credentialType());
- Assertions.assertTrue(gcsTokenCredential instanceof GCSTokenCredential);
+ Assertions.assertInstanceOf(GCSTokenCredential.class, gcsTokenCredential);
GCSTokenCredential gcsTokenCredential1 = (GCSTokenCredential)
gcsTokenCredential;
Assertions.assertEquals("accessToken", gcsTokenCredential1.token());
Assertions.assertEquals(expireTime, gcsTokenCredential1.expireTimeInMs());
@@ -106,7 +106,7 @@ public class TestCredentialFactory {
OSSTokenCredential.OSS_TOKEN_CREDENTIAL_TYPE,
ossTokenCredentialInfo, expireTime);
Assertions.assertEquals(
OSSTokenCredential.OSS_TOKEN_CREDENTIAL_TYPE,
ossTokenCredential.credentialType());
- Assertions.assertTrue(ossTokenCredential instanceof OSSTokenCredential);
+ Assertions.assertInstanceOf(OSSTokenCredential.class, ossTokenCredential);
OSSTokenCredential ossTokenCredential1 = (OSSTokenCredential)
ossTokenCredential;
Assertions.assertEquals("access-id", ossTokenCredential1.accessKeyId());
Assertions.assertEquals("secret-key",
ossTokenCredential1.secretAccessKey());
@@ -131,11 +131,38 @@ public class TestCredentialFactory {
Assertions.assertEquals(
OSSSecretKeyCredential.OSS_SECRET_KEY_CREDENTIAL_TYPE,
ossSecretKeyCredential.credentialType());
- Assertions.assertTrue(ossSecretKeyCredential instanceof
OSSSecretKeyCredential);
+ Assertions.assertInstanceOf(OSSSecretKeyCredential.class,
ossSecretKeyCredential);
OSSSecretKeyCredential ossSecretKeyCredential1 =
(OSSSecretKeyCredential) ossSecretKeyCredential;
Assertions.assertEquals("accessKeyId",
ossSecretKeyCredential1.accessKeyId());
Assertions.assertEquals("secretAccessKey",
ossSecretKeyCredential1.secretAccessKey());
Assertions.assertEquals(expireTime,
ossSecretKeyCredential1.expireTimeInMs());
}
+
+ @Test
+ void testADLSTokenCredential() {
+ String storageAccountName = "storage-account-name";
+ String sasToken = "sas-token";
+
+ Map<String, String> adlsTokenCredentialInfo =
+ ImmutableMap.of(
+ ADLSTokenCredential.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME,
+ storageAccountName,
+ ADLSTokenCredential.GRAVITINO_ADLS_SAS_TOKEN,
+ sasToken);
+ long expireTime = 100;
+ Credential credential =
+ CredentialFactory.create(
+ ADLSTokenCredential.ADLS_SAS_TOKEN_CREDENTIAL_TYPE,
+ adlsTokenCredentialInfo,
+ expireTime);
+ Assertions.assertEquals(
+ ADLSTokenCredential.ADLS_SAS_TOKEN_CREDENTIAL_TYPE,
credential.credentialType());
+ Assertions.assertInstanceOf(ADLSTokenCredential.class, credential);
+
+ ADLSTokenCredential adlsTokenCredential = (ADLSTokenCredential) credential;
+ Assertions.assertEquals(storageAccountName,
adlsTokenCredential.accountName());
+ Assertions.assertEquals(sasToken, adlsTokenCredential.sasToken());
+ Assertions.assertEquals(expireTime, adlsTokenCredential.expireTimeInMs());
+ }
}
diff --git
a/common/src/test/java/org/apache/gravitino/credential/TestCredentialPropertiesUtils.java
b/common/src/test/java/org/apache/gravitino/credential/TestCredentialPropertiesUtils.java
index 8e52b1684..cb5eaabe7 100644
---
a/common/src/test/java/org/apache/gravitino/credential/TestCredentialPropertiesUtils.java
+++
b/common/src/test/java/org/apache/gravitino/credential/TestCredentialPropertiesUtils.java
@@ -55,7 +55,7 @@ public class TestCredentialPropertiesUtils {
@Test
void testToIcebergPropertiesForOSS() {
OSSTokenCredential ossTokenCredential =
- new OSSTokenCredential("key", "secret", "security-token", 0);
+ new OSSTokenCredential("key", "secret", "security-token", 100);
Map<String, String> icebergProperties =
CredentialPropertyUtils.toIcebergProperties(ossTokenCredential);
Map<String, String> expectedProperties =
@@ -68,4 +68,26 @@ public class TestCredentialPropertiesUtils {
"security-token");
Assertions.assertEquals(expectedProperties, icebergProperties);
}
+
+ @Test
+ void testToIcebergPropertiesForADLS() {
+ String storageAccountName = "storage-account-name";
+ String sasToken = "sas-token";
+ long expireTimeInMS = 100;
+
+ ADLSTokenCredential adlsTokenCredential =
+ new ADLSTokenCredential(storageAccountName, sasToken, expireTimeInMS);
+ Map<String, String> icebergProperties =
+ CredentialPropertyUtils.toIcebergProperties(adlsTokenCredential);
+
+ String sasTokenKey =
+ String.format(
+ "%s.%s.%s",
+ CredentialPropertyUtils.ICEBERG_ADLS_TOKEN,
+ storageAccountName,
+ ADLSTokenCredential.ADLS_DOMAIN);
+
+ Map<String, String> expectedProperties = ImmutableMap.of(sasTokenKey,
sasToken);
+ Assertions.assertEquals(expectedProperties, icebergProperties);
+ }
}
diff --git
a/core/src/main/java/org/apache/gravitino/credential/config/ADLSCredentialConfig.java
b/core/src/main/java/org/apache/gravitino/credential/config/ADLSCredentialConfig.java
new file mode 100644
index 000000000..e9d368e67
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/credential/config/ADLSCredentialConfig.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.credential.config;
+
+import java.util.Map;
+import javax.validation.constraints.NotNull;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.gravitino.Config;
+import org.apache.gravitino.config.ConfigBuilder;
+import org.apache.gravitino.config.ConfigConstants;
+import org.apache.gravitino.config.ConfigEntry;
+import org.apache.gravitino.credential.CredentialConstants;
+import org.apache.gravitino.storage.AzureProperties;
+
+public class ADLSCredentialConfig extends Config {
+
+ public static final ConfigEntry<String> AZURE_STORAGE_ACCOUNT_NAME =
+ new ConfigBuilder(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME)
+ .doc("The name of the Azure Data Lake Storage account.")
+ .version(ConfigConstants.VERSION_0_7_0)
+ .stringConf()
+ .checkValue(StringUtils::isNotBlank,
ConfigConstants.NOT_BLANK_ERROR_MSG)
+ .create();
+
+ public static final ConfigEntry<String> AZURE_STORAGE_ACCOUNT_KEY =
+ new ConfigBuilder(AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY)
+ .doc("The key of the Azure Data Lake Storage account.")
+ .version(ConfigConstants.VERSION_0_7_0)
+ .stringConf()
+ .checkValue(StringUtils::isNotBlank,
ConfigConstants.NOT_BLANK_ERROR_MSG)
+ .create();
+
+ public static final ConfigEntry<String> AZURE_TENANT_ID =
+ new ConfigBuilder(AzureProperties.GRAVITINO_AZURE_TENANT_ID)
+ .doc("The Azure Active Directory (AAD) tenant ID used for
authentication.")
+ .version(ConfigConstants.VERSION_0_7_0)
+ .stringConf()
+ .checkValue(StringUtils::isNotBlank,
ConfigConstants.NOT_BLANK_ERROR_MSG)
+ .create();
+
+ public static final ConfigEntry<String> AZURE_CLIENT_ID =
+ new ConfigBuilder(AzureProperties.GRAVITINO_AZURE_CLIENT_ID)
+ .doc("The client ID used for authenticating with Azure Active
Directory (AAD).")
+ .version(ConfigConstants.VERSION_0_7_0)
+ .stringConf()
+ .checkValue(StringUtils::isNotBlank,
ConfigConstants.NOT_BLANK_ERROR_MSG)
+ .create();
+
+ public static final ConfigEntry<String> AZURE_CLIENT_SECRET =
+ new ConfigBuilder(AzureProperties.GRAVITINO_AZURE_CLIENT_SECRET)
+ .doc("The client secret used for authenticating with Azure Active
Directory (AAD).")
+ .version(ConfigConstants.VERSION_0_7_0)
+ .stringConf()
+ .checkValue(StringUtils::isNotBlank,
ConfigConstants.NOT_BLANK_ERROR_MSG)
+ .create();
+
+ public static final ConfigEntry<Integer> ADLS_TOKEN_EXPIRE_IN_SECS =
+ new ConfigBuilder(CredentialConstants.ADLS_TOKEN_EXPIRE_IN_SECS)
+ .doc(
+ "The expiration time (in seconds) for the Azure Active Directory
(AAD) authentication token.")
+ .version(ConfigConstants.VERSION_0_7_0)
+ .intConf()
+ .createWithDefault(3600);
+
+ public ADLSCredentialConfig(Map<String, String> properties) {
+ super(false);
+ loadFromMap(properties, k -> true);
+ }
+
+ @NotNull
+ public String storageAccountName() {
+ return this.get(AZURE_STORAGE_ACCOUNT_NAME);
+ }
+
+ @NotNull
+ public String storageAccountKey() {
+ return this.get(AZURE_STORAGE_ACCOUNT_KEY);
+ }
+
+ @NotNull
+ public String tenantId() {
+ return this.get(AZURE_TENANT_ID);
+ }
+
+ @NotNull
+ public String clientId() {
+ return this.get(AZURE_CLIENT_ID);
+ }
+
+ @NotNull
+ public String clientSecret() {
+ return this.get(AZURE_CLIENT_SECRET);
+ }
+
+ @NotNull
+ public Integer tokenExpireInSecs() {
+ return this.get(ADLS_TOKEN_EXPIRE_IN_SECS);
+ }
+}
diff --git a/dev/docker/iceberg-rest-server/iceberg-rest-server-dependency.sh
b/dev/docker/iceberg-rest-server/iceberg-rest-server-dependency.sh
index 5d0015786..2235313dc 100755
--- a/dev/docker/iceberg-rest-server/iceberg-rest-server-dependency.sh
+++ b/dev/docker/iceberg-rest-server/iceberg-rest-server-dependency.sh
@@ -37,12 +37,14 @@ cp -r gravitino-iceberg-rest-server*-bin
${iceberg_rest_server_dir}/packages/gra
cd ${gravitino_home}
./gradlew :bundles:gcp-bundle:jar
./gradlew :bundles:aws-bundle:jar
+./gradlew :bundles:azure-bundle:jar
# prepare bundle jar
cd ${iceberg_rest_server_dir}
mkdir -p bundles
cp ${gravitino_home}/bundles/gcp-bundle/build/libs/gravitino-gcp-bundle-*.jar
bundles/
cp ${gravitino_home}/bundles/aws-bundle/build/libs/gravitino-aws-bundle-*.jar
bundles/
+cp
${gravitino_home}/bundles/azure-bundle/build/libs/gravitino-azure-bundle-*.jar
bundles/
iceberg_gcp_bundle="iceberg-gcp-bundle-1.5.2.jar"
if [ ! -f "bundles/${iceberg_gcp_bundle}" ]; then
@@ -54,6 +56,11 @@ if [ ! -f "bundles/${iceberg_aws_bundle}" ]; then
curl -L -s -o bundles/${iceberg_aws_bundle}
https://repo1.maven.org/maven2/org/apache/iceberg/iceberg-aws-bundle/1.5.2/${iceberg_aws_bundle}
fi
+iceberg_azure_bundle="iceberg-azure-bundle-1.5.2.jar"
+if [ ! -f "bundles/${iceberg_azure_bundle}" ]; then
+ curl -L -s -o bundles/${iceberg_azure_bundle}
https://repo1.maven.org/maven2/org/apache/iceberg/iceberg-azure-bundle/1.5.2/${iceberg_azure_bundle}
+fi
+
# download jdbc driver
curl -L -s -o bundles/sqlite-jdbc-3.42.0.0.jar
https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.42.0.0/sqlite-jdbc-3.42.0.0.jar
diff --git a/dev/docker/iceberg-rest-server/rewrite_config.py
b/dev/docker/iceberg-rest-server/rewrite_config.py
index 9e3441d25..624c67750 100755
--- a/dev/docker/iceberg-rest-server/rewrite_config.py
+++ b/dev/docker/iceberg-rest-server/rewrite_config.py
@@ -28,7 +28,12 @@ env_map = {
"GRAVITINO_S3_SECRET_KEY" : "s3-secret-access-key",
"GRAVITINO_S3_REGION" : "s3-region",
"GRAVITINO_S3_ROLE_ARN" : "s3-role-arn",
- "GRAVITINO_S3_EXTERNAL_ID" : "s3-external-id"
+ "GRAVITINO_S3_EXTERNAL_ID" : "s3-external-id",
+ "GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME" : "azure-storage-account-name",
+ "GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY" : "azure-storage-account-key",
+ "GRAVITINO_AZURE_TENANT_ID" : "azure-tenant-id",
+ "GRAVITINO_AZURE_CLIENT_ID" : "azure-client-id",
+ "GRAVITINO_AZURE_CLIENT_SECRET" : "azure-client-secret",
}
init_config = {
diff --git a/docs/hadoop-catalog.md b/docs/hadoop-catalog.md
index 26d27dce8..ce58826cb 100644
--- a/docs/hadoop-catalog.md
+++ b/docs/hadoop-catalog.md
@@ -79,12 +79,12 @@ In the meantime, you need to place the corresponding bundle
jar [`gravitino-aliy
#### Azure Blob Storage fileset
-| Configuration item | Description
| Default value | Required
| Since version |
-|-------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|-------------------------------------------|------------------|
-| `filesystem-providers` | The file system providers to add. Set it to
`abs` if it's a Azure Blob Storage fileset, or a comma separated string that
contains `abs` like `oss,abs,s3` to support multiple kinds of fileset including
`abs`. | (none) | Yes
| 0.8.0-incubating |
-| `default-filesystem-provider` | The name default filesystem providers of
this Hadoop catalog if users do not specify the scheme in the URI. Default
value is `builtin-local`, for Azure Blob Storage, if we set this value, we can
omit the prefix 'abfss://' in the location. | `builtin-local` | No
| 0.8.0-incubating |
-| `abs-account-name` | The account name of Azure Blob Storage.
| (none) | Yes if it's a Azure Blob
Storage fileset. | 0.8.0-incubating |
-| `abs-account-key` | The account key of Azure Blob Storage.
| (none) | Yes if it's a Azure Blob
Storage fileset. | 0.8.0-incubating |
+| Configuration item | Description
| Default value | Required
| Since version |
+|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|-------------------------------------------|------------------|
+| `filesystem-providers` | The file system providers to add. Set it
to `abs` if it's a Azure Blob Storage fileset, or a comma separated string that
contains `abs` like `oss,abs,s3` to support multiple kinds of fileset including
`abs`. | (none) | Yes
| 0.8.0-incubating |
+| `default-filesystem-provider` | The name default filesystem providers of
this Hadoop catalog if users do not specify the scheme in the URI. Default
value is `builtin-local`, for Azure Blob Storage, if we set this value, we can
omit the prefix 'abfss://' in the location. | `builtin-local` | No
| 0.8.0-incubating |
+| `azure-storage-account-name ` | The account name of Azure Blob Storage.
| (none) | Yes if it's a Azure
Blob Storage fileset. | 0.8.0-incubating |
+| `azure-storage-account-key` | The account key of Azure Blob Storage.
| (none) | Yes if it's a Azure
Blob Storage fileset. | 0.8.0-incubating |
Similar to the above, you need to place the corresponding bundle jar
[`gravitino-azure-bundle-${version}.jar`](https://repo1.maven.org/maven2/org/apache/gravitino/azure-bundle/)
in the directory `${GRAVITINO_HOME}/catalogs/hadoop/libs`.
diff --git a/docs/how-to-use-gvfs.md b/docs/how-to-use-gvfs.md
index 34835ec8d..162d535be 100644
--- a/docs/how-to-use-gvfs.md
+++ b/docs/how-to-use-gvfs.md
@@ -101,10 +101,10 @@ In the meantime, you need to place the corresponding
bundle jar [`gravitino-aliy
#### Azure Blob Storage fileset
-| Configuration item | Description
| Default value | Required | Since version
|
-|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|-------------------------------------------|------------------|
-| `abs-account-name` | The account name of Azure Blob Storage.
| (none) | Yes if it's a Azure Blob Storage fileset. |
0.8.0-incubating |
-| `abs-account-key` | The account key of Azure Blob Storage.
| (none) | Yes if it's a Azure Blob Storage fileset. |
0.8.0-incubating |
+| Configuration item | Description
| Default value | Required | Since
version |
+|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|-------------------------------------------|------------------|
+| `azure-storage-account-name` | The account name of Azure Blob Storage.
| (none) | Yes if it's a Azure Blob Storage fileset. |
0.8.0-incubating |
+| `azure-storage-account-key` | The account key of Azure Blob Storage.
| (none) | Yes if it's a Azure Blob Storage fileset. |
0.8.0-incubating |
Similar to the above, you need to place the corresponding bundle jar
[`gravitino-azure-bundle-${version}.jar`](https://repo1.maven.org/maven2/org/apache/gravitino/azure-bundle/)
in the Hadoop environment(typically located in
`${HADOOP_HOME}/share/hadoop/common/lib/`).
diff --git a/docs/iceberg-rest-service.md b/docs/iceberg-rest-service.md
index 862bb0486..8d9d49745 100644
--- a/docs/iceberg-rest-service.md
+++ b/docs/iceberg-rest-service.md
@@ -17,8 +17,8 @@ The Apache Gravitino Iceberg REST Server follows the [Apache
Iceberg REST API sp
- multi table transaction
- pagination
- Works as a catalog proxy, supporting `Hive` and `JDBC` as catalog backend.
-- Supports credential vending for `S3`、`GCS` and `OSS`.
-- Supports different storages like `S3`, `HDFS`, `OSS`, `GCS` and provides the
capability to support other storages.
+- Supports credential vending for `S3`、`GCS`、`OSS` and `ADLS`.
+- Supports different storages like `S3`, `HDFS`, `OSS`, `GCS`, `ADLS` and
provides the capability to support other storages.
- Supports event listener.
- Supports Audit log.
- Supports OAuth2 and HTTPS.
@@ -171,6 +171,28 @@ Please make sure the credential file is accessible by
Gravitino, like using `exp
Please set `gravitino.iceberg-rest.warehouse` to
`gs://{bucket_name}/${prefix_name}`, and download [Iceberg gcp
bundle](https://mvnrepository.com/artifact/org.apache.iceberg/iceberg-gcp-bundle)
and place it to the classpath of Gravitino Iceberg REST server,
`iceberg-rest-server/libs` for the auxiliary server, `libs` for the standalone
server.
:::
+#### ADLS
+
+Gravitino Iceberg REST service supports generating SAS token to access ADLS
data.
+
+| Configuration item | Description
| Default value | Required | Since Version |
+|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------------|---------------|----------|------------------|
+| `gravitino.iceberg-rest.io-impl` | The IO implementation
for `FileIO` in Iceberg, use `org.apache.iceberg.azure.adlsv2.ADLSFileIO` for
ADLS. | (none) | Yes | 0.8.0-incubating |
+| `gravitino.iceberg-rest.credential-provider-type` | Supports `adls-token`,
generates a temporary token according to the query data path.
| (none) | Yes | 0.8.0-incubating |
+| `gravitino.iceberg-rest.azure-storage-account-name` | The static storage
account name used to access ADLS data.
| (none) | Yes | 0.8.0-incubating |
+| `gravitino.iceberg-rest.azure-storage-account-key` | The static storage
account key used to access ADLS data.
| (none) | Yes | 0.8.0-incubating |
+| `gravitino.iceberg-rest.azure-tenant-id` | Azure Active Directory
(AAD) tenant ID.
| (none) | Yes | 0.8.0-incubating |
+| `gravitino.iceberg-rest.azure-client-id` | Azure Active Directory
(AAD) client ID used for authentication.
| (none) | Yes | 0.8.0-incubating |
+| `gravitino.iceberg-rest.azure-client-secret` | Azure Active Directory
(AAD) client secret used for authentication.
| (none) | Yes | 0.8.0-incubating |
+
+For other Iceberg ADLS properties not managed by Gravitino like
`adls.read.block-size-bytes`, you could config it directly by
`gravitino.iceberg-rest.adls.read.block-size-bytes`.
+
+If you set `credential-provider-type` explicitly, please downloading
[Gravitino Azure bundle
jar](https://mvnrepository.com/artifact/org.apache.gravitino/azure-bundle), and
place it to the classpath of Iceberg REST server.
+
+:::info
+Please set `gravitino.iceberg-rest.warehouse` to
`abfs[s]://{container-name}@{storage-account-name}.dfs.core.windows.net/{path}`,
and download the [Iceberg Azure
bundle](https://mvnrepository.com/artifact/org.apache.iceberg/iceberg-azure-bundle)
and place it in the classpath of Iceberg REST server.
+:::
+
#### HDFS configuration
You should place HDFS configuration file to the classpath of the Iceberg REST
server, `iceberg-rest-server/conf` for Gravitino server package, `conf` for
standalone Gravitino Iceberg REST server package. When writing to HDFS, the
Gravitino Iceberg REST catalog service can only operate as the specified HDFS
user and doesn't support proxying to other HDFS users. See [How to access
Apache Hadoop](gravitino-server-config.md#how-to-access-apache-hadoop) for more
details.
@@ -418,19 +440,24 @@ docker run -d -p 9001:9001
apache/gravitino-iceberg-rest:0.7.0-incubating
Gravitino Iceberg REST server in docker image could access local storage by
default, you could set the following environment variables if the storage is
cloud/remote storage like S3, please refer to [storage section](#storage) for
more details.
-| Environment variables | Configuration items
| Since version |
-|------------------------------------------------|---------------------------------------------------|-------------------|
-| `GRAVITINO_IO_IMPL` |
`gravitino.iceberg-rest.io-impl` | 0.7.0-incubating |
-| `GRAVITINO_URI` |
`gravitino.iceberg-rest.uri` | 0.7.0-incubating |
-| `GRAVITINO_WAREHOUSE` |
`gravitino.iceberg-rest.warehouse` | 0.7.0-incubating |
-| `GRAVITINO_CREDENTIAL_PROVIDER_TYPE` |
`gravitino.iceberg-rest.credential-provider-type` | 0.7.0-incubating |
-| `GRAVITINO_GCS_CREDENTIAL_FILE_PATH` |
`gravitino.iceberg-rest.gcs-credential-file-path` | 0.7.0-incubating |
-| `GRAVITINO_S3_ACCESS_KEY` |
`gravitino.iceberg-rest.s3-access-key-id` | 0.7.0-incubating |
-| `GRAVITINO_S3_SECRET_KEY` |
`gravitino.iceberg-rest.s3-secret-access-key` | 0.7.0-incubating |
-| `GRAVITINO_S3_REGION` |
`gravitino.iceberg-rest.s3-region` | 0.7.0-incubating |
-| `GRAVITINO_S3_ROLE_ARN` |
`gravitino.iceberg-rest.s3-role-arn` | 0.7.0-incubating |
-| `GRAVITINO_S3_EXTERNAL_ID` |
`gravitino.iceberg-rest.s3-external-id` | 0.7.0-incubating |
-| `GRAVITINO_S3_TOKEN_SERVICE_ENDPOINT` |
`gravitino.iceberg-rest.s3-token-service-endpoint`| 0.8.0-incubating |
+| Environment variables | Configuration items
| Since version |
+|-----------------------------------------|-----------------------------------------------------|-------------------|
+| `GRAVITINO_IO_IMPL` | `gravitino.iceberg-rest.io-impl`
| 0.7.0-incubating |
+| `GRAVITINO_URI` | `gravitino.iceberg-rest.uri`
| 0.7.0-incubating |
+| `GRAVITINO_WAREHOUSE` | `gravitino.iceberg-rest.warehouse`
| 0.7.0-incubating |
+| `GRAVITINO_CREDENTIAL_PROVIDER_TYPE` |
`gravitino.iceberg-rest.credential-provider-type` | 0.7.0-incubating |
+| `GRAVITINO_GCS_CREDENTIAL_FILE_PATH` |
`gravitino.iceberg-rest.gcs-credential-file-path` | 0.7.0-incubating |
+| `GRAVITINO_S3_ACCESS_KEY` |
`gravitino.iceberg-rest.s3-access-key-id` | 0.7.0-incubating |
+| `GRAVITINO_S3_SECRET_KEY` |
`gravitino.iceberg-rest.s3-secret-access-key` | 0.7.0-incubating |
+| `GRAVITINO_S3_REGION` | `gravitino.iceberg-rest.s3-region`
| 0.7.0-incubating |
+| `GRAVITINO_S3_ROLE_ARN` |
`gravitino.iceberg-rest.s3-role-arn` | 0.7.0-incubating |
+| `GRAVITINO_S3_EXTERNAL_ID` |
`gravitino.iceberg-rest.s3-external-id` | 0.7.0-incubating |
+| `GRAVITINO_S3_TOKEN_SERVICE_ENDPOINT` |
`gravitino.iceberg-rest.s3-token-service-endpoint` | 0.8.0-incubating |
+| `GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME` |
`gravitino.iceberg-rest.azure-storage-account-name` | 0.8.0-incubating |
+| `GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY` |
`gravitino.iceberg-rest.azure-storage-account-key` | 0.8.0-incubating |
+| `GRAVITINO_AZURE_TENANT_ID` |
`gravitino.iceberg-rest.azure-tenant-id` | 0.8.0-incubating |
+| `GRAVITINO_AZURE_CLIENT_ID` |
`gravitino.iceberg-rest.azure-client-id` | 0.8.0-incubating |
+| `GRAVITINO_AZURE_CLIENT_SECRET` |
`gravitino.iceberg-rest.azure-client-secret` | 0.8.0-incubating |
Or build it manually to add custom configuration or logics:
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 630550a7e..a33c300ee 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -18,6 +18,10 @@
#
[versions]
awssdk = "2.28.3"
+azure-identity = "1.13.1"
+azure-storage-file-datalake = "12.20.0"
+reactor-netty-http = "1.2.1"
+reactor-netty-core = "1.2.1"
junit = "5.8.1"
protoc = "3.24.4"
jackson = "2.15.2"
@@ -120,6 +124,10 @@ aws-policy = { group = "software.amazon.awssdk", name =
"iam-policy-builder", ve
aws-s3 = { group = "software.amazon.awssdk", name = "s3", version.ref =
"awssdk" }
aws-sts = { group = "software.amazon.awssdk", name = "sts", version.ref =
"awssdk" }
aws-kms = { group = "software.amazon.awssdk", name = "kms", version.ref =
"awssdk" }
+azure-identity = { group = "com.azure", name = "azure-identity", version.ref =
"azure-identity"}
+azure-storage-file-datalake = { group = "com.azure", name =
"azure-storage-file-datalake", version.ref = "azure-storage-file-datalake"}
+reactor-netty-http = {group = "io.projectreactor.netty", name =
"reactor-netty-http", version.ref = "reactor-netty-http"}
+reactor-netty-core = {group = "io.projectreactor.netty", name =
"reactor-netty-core", version.ref = "reactor-netty-core"}
protobuf-java = { group = "com.google.protobuf", name = "protobuf-java",
version.ref = "protoc" }
protobuf-java-util = { group = "com.google.protobuf", name =
"protobuf-java-util", version.ref = "protoc" }
jackson-databind = { group = "com.fasterxml.jackson.core", name =
"jackson-databind", version.ref = "jackson" }
@@ -191,6 +199,8 @@ commons-configuration1 = { group = "commons-configuration",
name = "commons-conf
iceberg-aliyun = { group = "org.apache.iceberg", name = "iceberg-aliyun",
version.ref = "iceberg" }
iceberg-aws = { group = "org.apache.iceberg", name = "iceberg-aws",
version.ref = "iceberg" }
iceberg-aws-bundle = { group = "org.apache.iceberg", name =
"iceberg-aws-bundle", version.ref = "iceberg" }
+iceberg-azure = { group = "org.apache.iceberg", name = "iceberg-azure",
version.ref = "iceberg" }
+iceberg-azure-bundle = { group = "org.apache.iceberg", name =
"iceberg-azure-bundle", version.ref = "iceberg" }
iceberg-core = { group = "org.apache.iceberg", name = "iceberg-core",
version.ref = "iceberg" }
iceberg-api = { group = "org.apache.iceberg", name = "iceberg-api",
version.ref = "iceberg" }
iceberg-hive-metastore = { group = "org.apache.iceberg", name =
"iceberg-hive-metastore", version.ref = "iceberg" }
diff --git a/iceberg/iceberg-common/build.gradle.kts
b/iceberg/iceberg-common/build.gradle.kts
index abc9a05a5..b67e04238 100644
--- a/iceberg/iceberg-common/build.gradle.kts
+++ b/iceberg/iceberg-common/build.gradle.kts
@@ -44,6 +44,7 @@ dependencies {
implementation(libs.guava)
implementation(libs.iceberg.aliyun)
implementation(libs.iceberg.aws)
+ implementation(libs.iceberg.azure)
implementation(libs.iceberg.hive.metastore)
implementation(libs.iceberg.gcp)
implementation(libs.hadoop2.common) {
diff --git a/iceberg/iceberg-rest-server/build.gradle.kts
b/iceberg/iceberg-rest-server/build.gradle.kts
index e46193c97..03fe32c92 100644
--- a/iceberg/iceberg-rest-server/build.gradle.kts
+++ b/iceberg/iceberg-rest-server/build.gradle.kts
@@ -65,6 +65,7 @@ dependencies {
testImplementation(project(":bundles:aliyun-bundle"))
testImplementation(project(":bundles:aws-bundle"))
testImplementation(project(":bundles:gcp-bundle", configuration = "shadow"))
+ testImplementation(project(":bundles:azure-bundle"))
testImplementation(project(":integration-test-common", "testArtifacts"))
testImplementation("org.scala-lang.modules:scala-collection-compat_$scalaVersion:$scalaCollectionCompatVersion")
@@ -79,6 +80,13 @@ dependencies {
testImplementation(libs.iceberg.aws.bundle)
testImplementation(libs.iceberg.gcp.bundle)
+ // Prevent netty conflict
+ testImplementation(libs.reactor.netty.http)
+ testImplementation(libs.reactor.netty.core)
+ testImplementation(libs.iceberg.azure.bundle) {
+ exclude("io.netty")
+ exclude("com.google.guava", "guava")
+ }
testImplementation(libs.jersey.test.framework.core) {
exclude(group = "org.junit.jupiter")
}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTADLSIT.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTADLSIT.java
new file mode 100644
index 000000000..570298d05
--- /dev/null
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTADLSIT.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.iceberg.integration.test;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.gravitino.abs.credential.ADLSLocationUtils;
+import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
+import org.apache.gravitino.credential.CredentialConstants;
+import org.apache.gravitino.iceberg.common.IcebergConfig;
+import org.apache.gravitino.integration.test.util.BaseIT;
+import org.apache.gravitino.integration.test.util.DownloaderUtils;
+import org.apache.gravitino.integration.test.util.ITUtils;
+import org.apache.gravitino.storage.AzureProperties;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+
+@SuppressWarnings("FormatStringAnnotation")
+@EnabledIfEnvironmentVariable(named = "GRAVITINO_TEST_CLOUD_IT", matches =
"true")
+public class IcebergRESTADLSIT extends IcebergRESTJdbcCatalogIT {
+
+ private String storageAccountName;
+ private String storageAccountKey;
+ private String tenantId;
+ private String clientId;
+ private String clientSecret;
+ private String warehousePath;
+
+ @Override
+ void initEnv() {
+ this.storageAccountName =
+ System.getenv()
+ .getOrDefault("GRAVITINO_ADLS_STORAGE_ACCOUNT_NAME",
"{STORAGE_ACCOUNT_NAME}");
+ this.storageAccountKey =
+ System.getenv().getOrDefault("GRAVITINO_ADLS_STORAGE_ACCOUNT_KEY",
"{STORAGE_ACCOUNT_KEY}");
+ this.tenantId = System.getenv().getOrDefault("GRAVITINO_ADLS_TENANT_ID",
"{TENANT_ID}");
+ this.clientId = System.getenv().getOrDefault("GRAVITINO_ADLS_CLIENT_ID",
"{CLIENT_ID}");
+ this.clientSecret =
+ System.getenv().getOrDefault("GRAVITINO_ADLS_CLIENT_SECRET",
"{CLIENT_SECRET}");
+ this.warehousePath =
+ String.format(
+ "abfss://%s@%s.dfs.core.windows.net/data/test",
+ System.getenv().getOrDefault("GRAVITINO_ADLS_CONTAINER",
"{ADLS_CONTAINER}"),
+ storageAccountName);
+
+ if (ITUtils.isEmbedded()) {
+ return;
+ }
+ try {
+ downloadIcebergAzureBundleJar();
+ } catch (IOException e) {
+ LOG.warn("Download Iceberg Azure bundle jar failed,", e);
+ throw new RuntimeException(e);
+ }
+ copyAzureBundleJar();
+ }
+
+ @Override
+ public Map<String, String> getCatalogConfig() {
+ HashMap m = new HashMap<String, String>();
+ m.putAll(getCatalogJdbcConfig());
+ m.putAll(getADLSConfig());
+ return m;
+ }
+
+ public boolean supportsCredentialVending() {
+ return true;
+ }
+
+ private Map<String, String> getADLSConfig() {
+ Map configMap = new HashMap<String, String>();
+
+ configMap.put(
+ IcebergConfig.ICEBERG_CONFIG_PREFIX +
CredentialConstants.CREDENTIAL_PROVIDER_TYPE,
+ CredentialConstants.ADLS_TOKEN_CREDENTIAL_PROVIDER_TYPE);
+ configMap.put(
+ IcebergConfig.ICEBERG_CONFIG_PREFIX +
AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_NAME,
+ storageAccountName);
+ configMap.put(
+ IcebergConfig.ICEBERG_CONFIG_PREFIX +
AzureProperties.GRAVITINO_AZURE_STORAGE_ACCOUNT_KEY,
+ storageAccountKey);
+ configMap.put(
+ IcebergConfig.ICEBERG_CONFIG_PREFIX +
AzureProperties.GRAVITINO_AZURE_TENANT_ID, tenantId);
+ configMap.put(
+ IcebergConfig.ICEBERG_CONFIG_PREFIX +
AzureProperties.GRAVITINO_AZURE_CLIENT_ID, clientId);
+ configMap.put(
+ IcebergConfig.ICEBERG_CONFIG_PREFIX +
AzureProperties.GRAVITINO_AZURE_CLIENT_SECRET,
+ clientSecret);
+
+ configMap.put(
+ IcebergConfig.ICEBERG_CONFIG_PREFIX + IcebergConstants.IO_IMPL,
+ "org.apache.iceberg.azure.adlsv2.ADLSFileIO");
+ configMap.put(IcebergConfig.ICEBERG_CONFIG_PREFIX +
IcebergConstants.WAREHOUSE, warehousePath);
+
+ return configMap;
+ }
+
+ private void downloadIcebergAzureBundleJar() throws IOException {
+ String icebergBundleJarName = "iceberg-azure-bundle-1.5.2.jar";
+ String icebergBundleJarUri =
+ "https://repo1.maven.org/maven2/org/apache/iceberg/"
+ + "iceberg-azure-bundle/1.5.2/"
+ + icebergBundleJarName;
+ String gravitinoHome = System.getenv("GRAVITINO_HOME");
+ String targetDir = String.format("%s/iceberg-rest-server/libs/",
gravitinoHome);
+ DownloaderUtils.downloadFile(icebergBundleJarUri, targetDir);
+ }
+
+ private void copyAzureBundleJar() {
+ String gravitinoHome = System.getenv("GRAVITINO_HOME");
+ String targetDir = String.format("%s/iceberg-rest-server/libs/",
gravitinoHome);
+ BaseIT.copyBundleJarsToDirectory("azure-bundle", targetDir);
+ }
+
+ @Test
+ public void testParseLocationValidInput() {
+ String location =
"abfss://[email protected]/data/test/path";
+
+ ADLSLocationUtils.ADLSLocationParts parts =
ADLSLocationUtils.parseLocation(location);
+
+ Assertions.assertEquals("container", parts.getContainer(), "Container name
should match");
+ Assertions.assertEquals("account", parts.getAccountName(), "Account name
should match");
+ Assertions.assertEquals("/data/test/path", parts.getPath(), "Path should
match");
+ }
+
+ @Test
+ public void testParseLocationInvalidInput() {
+ String location = "abfss://container/invalid/location";
+
+ Exception exception =
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> {
+ ADLSLocationUtils.parseLocation(location);
+ });
+
+ Assertions.assertTrue(
+ exception.getMessage().contains("Invalid location"),
+ "Exception message should indicate invalid location");
+ }
+
+ @Test
+ public void testTrimSlashesNullInput() {
+ Assertions.assertNull(ADLSLocationUtils.trimSlashes(null), "Null input
should return null");
+ }
+
+ @Test
+ public void testTrimSlashesEmptyInput() {
+ Assertions.assertEquals(
+ "", ADLSLocationUtils.trimSlashes(""), "Empty input should return
empty string");
+ }
+
+ @Test
+ public void testTrimSlashesNoSlashes() {
+ String input = "data/test/path";
+ Assertions.assertEquals(
+ "data/test/path",
+ ADLSLocationUtils.trimSlashes(input),
+ "Input without slashes should remain unchanged");
+ }
+
+ @Test
+ public void testTrimSlashesLeadingAndTrailingSlashes() {
+ String input = "/data/test/path/";
+ Assertions.assertEquals(
+ "data/test/path",
+ ADLSLocationUtils.trimSlashes(input),
+ "Leading and trailing slashes should be trimmed");
+ }
+
+ @Test
+ public void testTrimSlashesMultipleLeadingAndTrailingSlashes() {
+ String input = "///data/test/path///";
+ Assertions.assertEquals(
+ "data/test/path",
+ ADLSLocationUtils.trimSlashes(input),
+ "Multiple leading and trailing slashes should be trimmed");
+ }
+
+ @Test
+ public void testTrimSlashesOnlySlashes() {
+ String input = "////";
+ Assertions.assertEquals(
+ "", ADLSLocationUtils.trimSlashes(input), "Only slashes should result
in an empty string");
+ }
+}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTGCSIT.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTGCSIT.java
index 89f56c517..8f7821cb4 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTGCSIT.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTGCSIT.java
@@ -22,7 +22,6 @@ package org.apache.gravitino.iceberg.integration.test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import java.util.Optional;
import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
import org.apache.gravitino.credential.CredentialConstants;
import org.apache.gravitino.credential.config.GCSCredentialConfig;
@@ -41,9 +40,10 @@ public class IcebergRESTGCSIT extends
IcebergRESTJdbcCatalogIT {
@Override
void initEnv() {
this.gcsWarehouse =
- String.format("gs://%s/test",
getFromEnvOrDefault("GRAVITINO_GCS_BUCKET", "bucketName"));
+ String.format(
+ "gs://%s/test",
System.getenv().getOrDefault("GRAVITINO_GCS_BUCKET", "bucketName"));
this.gcsCredentialPath =
- getFromEnvOrDefault("GOOGLE_APPLICATION_CREDENTIALS",
"credential.json");
+ System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS",
"credential.json");
if (ITUtils.isEmbedded()) {
return;
}
@@ -100,9 +100,4 @@ public class IcebergRESTGCSIT extends
IcebergRESTJdbcCatalogIT {
String targetDir = String.format("%s/iceberg-rest-server/libs/",
gravitinoHome);
DownloaderUtils.downloadFile(icebergBundleJarUri, targetDir);
}
-
- private String getFromEnvOrDefault(String envVar, String defaultValue) {
- String envValue = System.getenv(envVar);
- return Optional.ofNullable(envValue).orElse(defaultValue);
- }
}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSIT.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSIT.java
index fb6bac65b..f3aaafabb 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSIT.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSIT.java
@@ -22,7 +22,6 @@ package org.apache.gravitino.iceberg.integration.test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import java.util.Optional;
import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
import org.apache.gravitino.credential.CredentialConstants;
import org.apache.gravitino.iceberg.common.IcebergConfig;
@@ -49,13 +48,14 @@ public class IcebergRESTOSSIT extends
IcebergRESTJdbcCatalogIT {
this.warehouse =
String.format(
"oss://%s/gravitino-test",
- getFromEnvOrDefault("GRAVITINO_OSS_BUCKET", "{BUCKET_NAME}"));
- this.accessKey = getFromEnvOrDefault("GRAVITINO_OSS_ACCESS_KEY",
"{ACCESS_KEY}");
- this.secretKey = getFromEnvOrDefault("GRAVITINO_OSS_SECRET_KEY",
"{SECRET_KEY}");
- this.endpoint = getFromEnvOrDefault("GRAVITINO_OSS_ENDPOINT",
"{GRAVITINO_OSS_ENDPOINT}");
- this.region = getFromEnvOrDefault("GRAVITINO_OSS_REGION",
"oss-cn-hangzhou");
- this.roleArn = getFromEnvOrDefault("GRAVITINO_OSS_ROLE_ARN", "{ROLE_ARN}");
- this.externalId = getFromEnvOrDefault("GRAVITINO_OSS_EXTERNAL_ID", "");
+ System.getenv().getOrDefault("GRAVITINO_OSS_BUCKET",
"{BUCKET_NAME}"));
+ this.accessKey = System.getenv().getOrDefault("GRAVITINO_OSS_ACCESS_KEY",
"{ACCESS_KEY}");
+ this.secretKey = System.getenv().getOrDefault("GRAVITINO_OSS_SECRET_KEY",
"{SECRET_KEY}");
+ this.endpoint =
+ System.getenv().getOrDefault("GRAVITINO_OSS_ENDPOINT",
"{GRAVITINO_OSS_ENDPOINT}");
+ this.region = System.getenv().getOrDefault("GRAVITINO_OSS_REGION",
"oss-cn-hangzhou");
+ this.roleArn = System.getenv().getOrDefault("GRAVITINO_OSS_ROLE_ARN",
"{ROLE_ARN}");
+ this.externalId =
System.getenv().getOrDefault("GRAVITINO_OSS_EXTERNAL_ID", "");
if (ITUtils.isEmbedded()) {
return;
@@ -127,9 +127,4 @@ public class IcebergRESTOSSIT extends
IcebergRESTJdbcCatalogIT {
String targetDir = String.format("%s/iceberg-rest-server/libs/",
gravitinoHome);
BaseIT.copyBundleJarsToDirectory("aliyun-bundle", targetDir);
}
-
- private String getFromEnvOrDefault(String envVar, String defaultValue) {
- String envValue = System.getenv(envVar);
- return Optional.ofNullable(envValue).orElse(defaultValue);
- }
}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSSecretIT.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSSecretIT.java
index 73f6262d1..cd5c99c46 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSSecretIT.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTOSSSecretIT.java
@@ -22,7 +22,6 @@ package org.apache.gravitino.iceberg.integration.test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
-import java.util.Optional;
import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
import org.apache.gravitino.credential.CredentialConstants;
import org.apache.gravitino.credential.OSSSecretKeyCredential;
@@ -46,10 +45,11 @@ public class IcebergRESTOSSSecretIT extends
IcebergRESTJdbcCatalogIT {
this.warehouse =
String.format(
"oss://%s/gravitino-test",
- getFromEnvOrDefault("GRAVITINO_OSS_BUCKET", "{BUCKET_NAME}"));
- this.accessKey = getFromEnvOrDefault("GRAVITINO_OSS_ACCESS_KEY",
"{ACCESS_KEY}");
- this.secretKey = getFromEnvOrDefault("GRAVITINO_OSS_SECRET_KEY",
"{SECRET_KEY}");
- this.endpoint = getFromEnvOrDefault("GRAVITINO_OSS_ENDPOINT",
"{GRAVITINO_OSS_ENDPOINT}");
+ System.getenv().getOrDefault("GRAVITINO_OSS_BUCKET",
"{BUCKET_NAME}"));
+ this.accessKey = System.getenv().getOrDefault("GRAVITINO_OSS_ACCESS_KEY",
"{ACCESS_KEY}");
+ this.secretKey = System.getenv().getOrDefault("GRAVITINO_OSS_SECRET_KEY",
"{SECRET_KEY}");
+ this.endpoint =
+ System.getenv().getOrDefault("GRAVITINO_OSS_ENDPOINT",
"{GRAVITINO_OSS_ENDPOINT}");
if (ITUtils.isEmbedded()) {
return;
@@ -113,9 +113,4 @@ public class IcebergRESTOSSSecretIT extends
IcebergRESTJdbcCatalogIT {
String targetDir = String.format("%s/iceberg-rest-server/libs/",
gravitinoHome);
BaseIT.copyBundleJarsToDirectory("aliyun-bundle", targetDir);
}
-
- private String getFromEnvOrDefault(String envVar, String defaultValue) {
- String envValue = System.getenv(envVar);
- return Optional.ofNullable(envValue).orElse(defaultValue);
- }
}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTS3IT.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTS3IT.java
index ab372f78c..d31278051 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTS3IT.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/integration/test/IcebergRESTS3IT.java
@@ -24,7 +24,6 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import org.apache.gravitino.catalog.lakehouse.iceberg.IcebergConstants;
import org.apache.gravitino.credential.CredentialConstants;
import org.apache.gravitino.iceberg.common.IcebergConfig;
@@ -52,12 +51,13 @@ public class IcebergRESTS3IT extends
IcebergRESTJdbcCatalogIT {
@Override
void initEnv() {
this.s3Warehouse =
- String.format("s3://%s/test1",
getFromEnvOrDefault("GRAVITINO_S3_BUCKET", "{BUCKET_NAME}"));
- this.accessKey = getFromEnvOrDefault("GRAVITINO_S3_ACCESS_KEY",
"{ACCESS_KEY}");
- this.secretKey = getFromEnvOrDefault("GRAVITINO_S3_SECRET_KEY",
"{SECRET_KEY}");
- this.region = getFromEnvOrDefault("GRAVITINO_S3_REGION", "ap-southeast-2");
- this.roleArn = getFromEnvOrDefault("GRAVITINO_S3_ROLE_ARN", "{ROLE_ARN}");
- this.externalId = getFromEnvOrDefault("GRAVITINO_S3_EXTERNAL_ID", "");
+ String.format(
+ "s3://%s/test1",
System.getenv().getOrDefault("GRAVITINO_S3_BUCKET", "{BUCKET_NAME}"));
+ this.accessKey = System.getenv().getOrDefault("GRAVITINO_S3_ACCESS_KEY",
"{ACCESS_KEY}");
+ this.secretKey = System.getenv().getOrDefault("GRAVITINO_S3_SECRET_KEY",
"{SECRET_KEY}");
+ this.region = System.getenv().getOrDefault("GRAVITINO_S3_REGION",
"ap-southeast-2");
+ this.roleArn = System.getenv().getOrDefault("GRAVITINO_S3_ROLE_ARN",
"{ROLE_ARN}");
+ this.externalId = System.getenv().getOrDefault("GRAVITINO_S3_EXTERNAL_ID",
"");
if (ITUtils.isEmbedded()) {
return;
}
@@ -126,11 +126,6 @@ public class IcebergRESTS3IT extends
IcebergRESTJdbcCatalogIT {
BaseIT.copyBundleJarsToDirectory("aws-bundle", targetDir);
}
- private String getFromEnvOrDefault(String envVar, String defaultValue) {
- String envValue = System.getenv(envVar);
- return Optional.ofNullable(envValue).orElse(defaultValue);
- }
-
/**
* Parses a string representing table properties into a map of key-value
pairs.
*
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 5776d34fa..150acdb00 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -80,5 +80,5 @@ include("integration-test-common")
include(":bundles:aws-bundle")
include(":bundles:gcp-bundle")
include(":bundles:aliyun-bundle")
-include("bundles:azure-bundle")
+include(":bundles:azure-bundle")
include("catalogs:hadoop-common")