Skip to content

[#9418] fix(iceberg): inject GCS FileIO token from gcs-service-account-file - #12962

Merged
roryqi merged 12 commits into
apache:mainfrom
lasdf1234:fix/gcs-service-account-file-fileio
Sep 9, 2026
Merged

[#9418] fix(iceberg): inject GCS FileIO token from gcs-service-account-file#12962
roryqi merged 12 commits into
apache:mainfrom
lasdf1234:fix/gcs-service-account-file-fileio

Conversation

@lasdf1234

Copy link
Copy Markdown
Collaborator

What changes were proposed in this pull request?

Iceberg's GCSFileIO does not understand Gravitino's gcs-service-account-file.
When that property is set, load the service account at catalog initialization and
inject Iceberg gcs.oauth2.token / gcs.oauth2.token-expires-at so server-side
FileIO can authenticate (same property-injection style as S3/OSS/ADLS key mapping).
Also update GCS docs that previously required GOOGLE_APPLICATION_CREDENTIALS
even when the catalog property was set.

Why are the changes needed?

gcs-service-account-file reached the credential provider (vending worked) but not
FileIO. Table create wrote metadata with Application Default Credentials and failed
with 401 unless GOOGLE_APPLICATION_CREDENTIALS was set on the process.

Fix: #9418

Does this PR introduce any user-facing change?

  • Configuring gcs-service-account-file is sufficient for Iceberg GCS FileIO;
    GOOGLE_APPLICATION_CREDENTIALS is only a fallback when the property is unset.
  • No new public API or property keys.

How was this patch tested?

./gradlew :iceberg:iceberg-common:test --tests org.apache.gravitino.iceberg.common.utils.TestIcebergCatalogUtil -PskipITs

Made with Cursor

…account-file

Iceberg's GCSFileIO ignores gcs-service-account-file; mint gcs.oauth2.token
at catalog load so server-side FileIO works from catalog properties alone.

Co-authored-by: Cursor <cursoragent@cursor.com>
@lasdf1234 lasdf1234 self-assigned this Sep 7, 2026
@lasdf1234 lasdf1234 added the branch-1.3 Automatically cherry-pick commit to branch-1.3 label Sep 7, 2026
lasdf1234 and others added 2 commits September 7, 2026 19:16
Co-authored-by: Cursor <cursoragent@cursor.com>
…load

Co-authored-by: Cursor <cursoragent@cursor.com>
*/
@VisibleForTesting
static void applyGcsServiceAccountCredentials(Map<String, String> properties) {
String serviceAccountFile = properties.get(GCSProperties.GRAVITINO_GCS_SERVICE_ACCOUNT_FILE);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How to refresh the GCP access token? I will recommend that we add a expire hook for the catalog cache.
You can recreate the catalog before the access token expiration.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — addressed in the latest commit.

IRC catalog wrappers now keep the minted gcs.oauth2.token-expires-at on IcebergConfig, and IcebergCatalogWrapperManager uses a Caffeine Expiry that caps expire-after-access by token expiry minus a 5-minute buffer. When the entry is evicted, the next request recreates the catalog and remints the token.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: we dropped the catalog-cache expiry approach.

IRC catalogWrapperCache is back to plain expireAfterAccess. Token refresh now lives in a separate GcsAccessTokenCache + GravitinoGCSFileIO, which remints from gcs-service-account-file when the cached token is about to expire — independent of catalog-wrapper eviction.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't. Because you can't handle ResolvingFileIO cases.ResolvingFile will use origin GCSFileIO.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got resolved.

lasdf1234 and others added 5 commits September 7, 2026 19:49
…cache expiry

Cap catalog-wrapper cache lifetime by gcs.oauth2.token-expires-at so hot
catalogs recreate and remint OAuth2 tokens before they expire.

Co-authored-by: Cursor <cursoragent@cursor.com>
…d FileIO

Keep IRC catalog expire-after-access unchanged. Remint OAuth2 tokens in
GcsAccessTokenCache and GravitinoGCSFileIO so credential lifetime is
independent of catalog-wrapper eviction.

Co-authored-by: Cursor <cursoragent@cursor.com>
…logUtil

Co-authored-by: Cursor <cursoragent@cursor.com>
Rewrite GravitinoGCSFileIO to the Iceberg GCSFileIO class name via a
string constant so iceberg-rest-server does not need iceberg-gcp at
compile time.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tests

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Code Coverage Report

Overall Project 69.67% -0.16% 🟢
Files changed 56.47% 🔴

Module Coverage
aliyun 19.74% 🔴
api 51.57% 🟢
authorization-common 85.96% 🟢
authorization-ranger 4.38% 🔴
aws 53.54% 🟢
azure 32.1% 🔴
catalog-common 25.76% -0.04% 🔴
catalog-fileset 82.17% 🟢
catalog-glue 69.8% 🟢
catalog-hive 82.96% 🟢
catalog-jdbc-common 45.09% 🟢
catalog-jdbc-doris 82.69% 🟢
catalog-jdbc-mysql 79.33% 🟢
catalog-jdbc-postgresql 83.83% 🟢
catalog-jdbc-starrocks 79.16% 🟢
catalog-kafka 76.99% 🟢
catalog-lakehouse-generic 60.88% 🟢
catalog-lakehouse-hudi 79.1% 🟢
catalog-lakehouse-iceberg 85.9% 🟢
catalog-lakehouse-paimon 84.29% 🟢
catalog-model 77.99% 🟢
cli 44.51% 🟢
client-java 77.5% 🟢
common 57.75% 🟢
core 84.29% -0.77% 🟢
filesystem-hadoop3 76.48% 🟢
flink 0.0% 🔴
flink-common 53.22% 🟢
flink-runtime 0.0% 🔴
gcp 32.2% 🔴
hadoop-auth 68.0% 🟢
hadoop-common 17.84% 🔴
hive-metastore-common 53.5% 🟢
iceberg-aliyun-bundle 0.0% 🔴
iceberg-common 66.21% -0.73% 🟢
iceberg-rest-server 76.77% -1.78% 🟢
idp-basic 86.75% 🟢
integration-test-common 0.0% 🔴
jobs 62.92% 🟢
lance-common 32.52% 🔴
lance-rest-server 68.12% 🟢
lineage 59.39% 🟢
optimizer 83.24% 🟢
optimizer-api 21.95% 🔴
server 89.62% 🟢
server-common 81.35% 🟢
spark 56.27% 🟢
tencent 81.78% 🟢
trino-connector 58.36% 🟢
Files
Module File Coverage
catalog-common IcebergConstants.java 0.0% 🔴
core SchemaHookDispatcher.java 92.31% 🟢
ViewHookDispatcher.java 86.21% 🟢
FilesetHookDispatcher.java 85.29% 🟢
TopicHookDispatcher.java 82.61% 🟢
FunctionHookDispatcher.java 81.48% 🟢
TableHookDispatcher.java 80.49% 🟢
CapabilityHelpers.java 79.24% 🟢
ModelHookDispatcher.java 56.82% 🔴
AccessControlHookDispatcher.java 26.72% 🔴
GravitinoEnv.java 26.61% 🔴
iceberg-common IcebergCatalogUtil.java 61.25% 🟢
iceberg-rest-server IcebergCatalogWrapperManager.java 91.95% 🟢
RESTService.java 5.17% 🔴

lasdf1234 and others added 2 commits September 8, 2026 20:14
Resolve IcebergConstants conflict by keeping both ADLS token-provider
constants from main and GCS OAuth2 token constants from this branch.

Co-authored-by: Cursor <cursoragent@cursor.com>
…expiry

Mint gcs.oauth2.token from gcs-service-account-file and expire IRC catalog
wrappers before token expiry, instead of a dedicated GravitinoGCSFileIO cache.

Co-authored-by: Cursor <cursoragent@cursor.com>
roryqi
roryqi previously approved these changes Sep 8, 2026

@roryqi roryqi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No better solution. If GCS FileIO API provides better solution, we should refactor the code.

…er close

Caffeine may retire a missed cache entry asynchronously after close(), so
asserting pool size immediately can flake with size 1.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@lasdf1234

lasdf1234 commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author
image I deployed irc and used the gravitino.iceberg-rest.gcs-service-account-file configuration for testing. It worked fine. I can see log : Injected gcs.oauth2.token from gcs-service-account-file for Iceberg GCSFileIO. And create table and schema is OK.

@roryqi

roryqi commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Do u test the refresh case?

@lasdf1234

Copy link
Copy Markdown
Collaborator Author

#9418

image As shown in the above figure, after the cache expires, the catalog is removed and the token is re-minted.

@roryqi roryqi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@roryqi
roryqi merged commit 5c8f5bf into apache:main Sep 9, 2026
38 checks passed
@lasdf1234
lasdf1234 deleted the fix/gcs-service-account-file-fileio branch September 9, 2026 09:10
lasdf1234 added a commit to lasdf1234/gravitino that referenced this pull request Sep 10, 2026
…account-file (apache#12962)

Iceberg's `GCSFileIO` does not understand Gravitino's
`gcs-service-account-file`.
When that property is set, load the service account at catalog
initialization and
inject Iceberg `gcs.oauth2.token` / `gcs.oauth2.token-expires-at` so
server-side
FileIO can authenticate (same property-injection style as S3/OSS/ADLS
key mapping).
Also update GCS docs that previously required
`GOOGLE_APPLICATION_CREDENTIALS`
even when the catalog property was set.

`gcs-service-account-file` reached the credential provider (vending
worked) but not
FileIO. Table create wrote metadata with Application Default Credentials
and failed
with 401 unless `GOOGLE_APPLICATION_CREDENTIALS` was set on the process.

Fix: apache#9418

- Configuring `gcs-service-account-file` is sufficient for Iceberg GCS
FileIO;
`GOOGLE_APPLICATION_CREDENTIALS` is only a fallback when the property is
unset.
- No new public API or property keys.

```
./gradlew :iceberg:iceberg-common:test --tests org.apache.gravitino.iceberg.common.utils.TestIcebergCatalogUtil -PskipITs
```

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
lasdf1234 added a commit to lasdf1234/gravitino that referenced this pull request Sep 10, 2026
…account-file (apache#12962)

Iceberg's `GCSFileIO` does not understand Gravitino's
`gcs-service-account-file`.
When that property is set, load the service account at catalog
initialization and
inject Iceberg `gcs.oauth2.token` / `gcs.oauth2.token-expires-at` so
server-side
FileIO can authenticate (same property-injection style as S3/OSS/ADLS
key mapping).
Also update GCS docs that previously required
`GOOGLE_APPLICATION_CREDENTIALS`
even when the catalog property was set.

`gcs-service-account-file` reached the credential provider (vending
worked) but not
FileIO. Table create wrote metadata with Application Default Credentials
and failed
with 401 unless `GOOGLE_APPLICATION_CREDENTIALS` was set on the process.

Fix: apache#9418

- Configuring `gcs-service-account-file` is sufficient for Iceberg GCS
FileIO;
`GOOGLE_APPLICATION_CREDENTIALS` is only a fallback when the property is
unset.
- No new public API or property keys.

```
./gradlew :iceberg:iceberg-common:test --tests org.apache.gravitino.iceberg.common.utils.TestIcebergCatalogUtil -PskipITs
```

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
lasdf1234 added a commit to lasdf1234/gravitino that referenced this pull request Sep 10, 2026
…account-file (apache#12962)

Iceberg's `GCSFileIO` does not understand Gravitino's
`gcs-service-account-file`.
When that property is set, load the service account at catalog
initialization and
inject Iceberg `gcs.oauth2.token` / `gcs.oauth2.token-expires-at` so
server-side
FileIO can authenticate (same property-injection style as S3/OSS/ADLS
key mapping).
Also update GCS docs that previously required
`GOOGLE_APPLICATION_CREDENTIALS`
even when the catalog property was set.

`gcs-service-account-file` reached the credential provider (vending
worked) but not
FileIO. Table create wrote metadata with Application Default Credentials
and failed
with 401 unless `GOOGLE_APPLICATION_CREDENTIALS` was set on the process.

Fix: apache#9418

- Configuring `gcs-service-account-file` is sufficient for Iceberg GCS
FileIO;
`GOOGLE_APPLICATION_CREDENTIALS` is only a fallback when the property is
unset.
- No new public API or property keys.

```
./gradlew :iceberg:iceberg-common:test --tests org.apache.gravitino.iceberg.common.utils.TestIcebergCatalogUtil -PskipITs
```

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
jerryshao pushed a commit that referenced this pull request Sep 10, 2026
…t-file (#12962)

Iceberg's `GCSFileIO` does not understand Gravitino's
`gcs-service-account-file`.
When that property is set, load the service account at catalog
initialization and
inject Iceberg `gcs.oauth2.token` / `gcs.oauth2.token-expires-at` so
server-side
FileIO can authenticate (same property-injection style as S3/OSS/ADLS
key mapping).
Also update GCS docs that previously required
`GOOGLE_APPLICATION_CREDENTIALS`
even when the catalog property was set.

`gcs-service-account-file` reached the credential provider (vending
worked) but not
FileIO. Table create wrote metadata with Application Default Credentials
and failed
with 401 unless `GOOGLE_APPLICATION_CREDENTIALS` was set on the process.

Fix: #9418

- Configuring `gcs-service-account-file` is sufficient for Iceberg GCS
FileIO;
`GOOGLE_APPLICATION_CREDENTIALS` is only a fallback when the property is
unset.
- No new public API or property keys.

```
./gradlew :iceberg:iceberg-common:test --tests org.apache.gravitino.iceberg.common.utils.TestIcebergCatalogUtil -PskipITs
```

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

branch-1.3 Automatically cherry-pick commit to branch-1.3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug report] Iceberg catalog using GCS can't use the property gcs-service-account-file

2 participants