diff --git a/weed/command/mini.go b/weed/command/mini.go index a7a0ba01a..a02d40e7d 100644 --- a/weed/command/mini.go +++ b/weed/command/mini.go @@ -1344,6 +1344,10 @@ func runMini(cmd *Command, args []string) bool { tableBucketSpec := *miniTableBucket if tableBucketSpec == "" { tableBucketSpec = os.Getenv("S3_TABLE_BUCKET") + } else if os.Getenv("S3_TABLE_BUCKET") == "" { + // The catalog routes unprefixed requests to the first S3_TABLE_BUCKET + // entry; let the -tableBucket flag mean the same thing. + os.Setenv("S3_TABLE_BUCKET", tableBucketSpec) } if err := ensureMiniTableBuckets(tableBucketSpec); err != nil { glog.Warningf("failed to ensure table buckets %q: %v", tableBucketSpec, err) diff --git a/weed/s3api/iceberg/iceberg_issue_9103_test.go b/weed/s3api/iceberg/iceberg_issue_9103_test.go index 555d09c9e..760dd4871 100644 --- a/weed/s3api/iceberg/iceberg_issue_9103_test.go +++ b/weed/s3api/iceberg/iceberg_issue_9103_test.go @@ -81,3 +81,25 @@ func TestBuildFileIOConfig(t *testing.T) { } }) } + +func TestGetBucketFromPrefix_TableBucketEnvFallback(t *testing.T) { + r := httptest.NewRequest("GET", "/v1/namespaces", nil) + + t.Setenv("S3_TABLE_BUCKET", " ,analytics, other") + if got := getBucketFromPrefix(r); got != "analytics" { + t.Fatalf("first S3_TABLE_BUCKET entry: got %q, want analytics", got) + } + + // The explicit default still wins over the table bucket list. + t.Setenv("S3TABLES_DEFAULT_BUCKET", "explicit") + if got := getBucketFromPrefix(r); got != "explicit" { + t.Fatalf("S3TABLES_DEFAULT_BUCKET override: got %q, want explicit", got) + } + + // A prefixless value with neither env set falls through to the default. + t.Setenv("S3TABLES_DEFAULT_BUCKET", "") + t.Setenv("S3_TABLE_BUCKET", " , ") + if got := getBucketFromPrefix(r); got != "warehouse" { + t.Fatalf("empty specs: got %q, want warehouse", got) + } +} diff --git a/weed/s3api/iceberg/utils.go b/weed/s3api/iceberg/utils.go index 84f02c47a..266d975e3 100644 --- a/weed/s3api/iceberg/utils.go +++ b/weed/s3api/iceberg/utils.go @@ -236,6 +236,14 @@ func getBucketFromPrefix(r *http.Request) string { if bucket := os.Getenv("S3TABLES_DEFAULT_BUCKET"); bucket != "" { return bucket } + // Some writers commit to the unprefixed path even though their reads + // honor the /v1/config prefix; the deployment's first table bucket is + // where those commits belong. + for _, name := range strings.Split(os.Getenv("S3_TABLE_BUCKET"), ",") { + if name = strings.TrimSpace(name); name != "" { + return name + } + } // Default bucket if no prefix - use "warehouse" for Iceberg return "warehouse" }