From f44e25b422c4739b9bee4878d0efd76488e91356 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 13 Feb 2026 20:28:41 -0800 Subject: [PATCH] fix(iam): ensure access key status is persisted and defaulted to Active (#8341) * Fix master leader election startup issue Fixes #error-log-leader-not-selected-yet * not useful test * fix(iam): ensure access key status is persisted and defaulted to Active * make pb * update tests * using constants --- test/volume_server/grpc/scrub_query_test.go | 18 ++-- weed/admin/dash/admin_data.go | 5 +- weed/admin/dash/service_account_management.go | 5 +- weed/admin/view/app/service_accounts.templ | 4 +- weed/admin/view/app/service_accounts_templ.go | 4 +- weed/pb/volume_server_pb/volume_server.pb.go | 4 +- .../volume_server_pb/volume_server_grpc.pb.go | 102 +++++++++--------- weed/s3api/auth_signature_v4.go | 3 +- weed/shell/command_s3_configure.go | 2 + 9 files changed, 77 insertions(+), 70 deletions(-) diff --git a/test/volume_server/grpc/scrub_query_test.go b/test/volume_server/grpc/scrub_query_test.go index 66766f79d..46b67e0ca 100644 --- a/test/volume_server/grpc/scrub_query_test.go +++ b/test/volume_server/grpc/scrub_query_test.go @@ -144,7 +144,7 @@ func TestQueryInvalidAndMissingFileIDPaths(t *testing.T) { } } -func TestScrubVolumeAutoSelectAndNotImplementedModes(t *testing.T) { +func TestScrubVolumeAutoSelectAndAllModes(t *testing.T) { if testing.Short() { t.Skip("skipping integration test in short mode") } @@ -158,6 +158,11 @@ func TestScrubVolumeAutoSelectAndNotImplementedModes(t *testing.T) { framework.AllocateVolume(t, grpcClient, volumeIDA, "") framework.AllocateVolume(t, grpcClient, volumeIDB, "") + // upload some data so index files are not zero-sized + httpClient := framework.NewHTTPClient() + framework.UploadBytes(t, httpClient, clusterHarness.VolumeAdminURL(), framework.NewFileID(volumeIDA, 1, 1), []byte("test data A")) + framework.UploadBytes(t, httpClient, clusterHarness.VolumeAdminURL(), framework.NewFileID(volumeIDB, 2, 2), []byte("test data B")) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -181,11 +186,8 @@ func TestScrubVolumeAutoSelectAndNotImplementedModes(t *testing.T) { if localResp.GetTotalVolumes() != 1 { t.Fatalf("ScrubVolume local mode expected total_volumes=1, got %d", localResp.GetTotalVolumes()) } - if len(localResp.GetBrokenVolumeIds()) != 1 || localResp.GetBrokenVolumeIds()[0] != volumeIDA { - t.Fatalf("ScrubVolume local mode expected broken volume %d, got %v", volumeIDA, localResp.GetBrokenVolumeIds()) - } - if len(localResp.GetDetails()) == 0 || !strings.Contains(strings.Join(localResp.GetDetails(), " "), "not implemented") { - t.Fatalf("ScrubVolume local mode expected not-implemented details, got %v", localResp.GetDetails()) + if len(localResp.GetBrokenVolumeIds()) != 0 { + t.Fatalf("ScrubVolume local mode expected no broken volumes, got %v: %v", localResp.GetBrokenVolumeIds(), localResp.GetDetails()) } fullResp, err := grpcClient.ScrubVolume(ctx, &volume_server_pb.ScrubVolumeRequest{ @@ -198,8 +200,8 @@ func TestScrubVolumeAutoSelectAndNotImplementedModes(t *testing.T) { if fullResp.GetTotalVolumes() != 1 { t.Fatalf("ScrubVolume full mode expected total_volumes=1, got %d", fullResp.GetTotalVolumes()) } - if len(fullResp.GetDetails()) == 0 || !strings.Contains(strings.Join(fullResp.GetDetails(), " "), "not implemented") { - t.Fatalf("ScrubVolume full mode expected not-implemented details, got %v", fullResp.GetDetails()) + if len(fullResp.GetBrokenVolumeIds()) != 0 { + t.Fatalf("ScrubVolume full mode expected no broken volumes, got %v: %v", fullResp.GetBrokenVolumeIds(), fullResp.GetDetails()) } } diff --git a/weed/admin/dash/admin_data.go b/weed/admin/dash/admin_data.go index 9d33ee158..f7ea81338 100644 --- a/weed/admin/dash/admin_data.go +++ b/weed/admin/dash/admin_data.go @@ -9,13 +9,14 @@ import ( "github.com/gin-gonic/gin" "github.com/seaweedfs/seaweedfs/weed/cluster" "github.com/seaweedfs/seaweedfs/weed/glog" + "github.com/seaweedfs/seaweedfs/weed/iam" "github.com/seaweedfs/seaweedfs/weed/pb/master_pb" ) // Access key status constants const ( - AccessKeyStatusActive = "Active" - AccessKeyStatusInactive = "Inactive" + AccessKeyStatusActive = iam.AccessKeyStatusActive + AccessKeyStatusInactive = iam.AccessKeyStatusInactive ) type AdminData struct { diff --git a/weed/admin/dash/service_account_management.go b/weed/admin/dash/service_account_management.go index c83ce868f..d8a6c7033 100644 --- a/weed/admin/dash/service_account_management.go +++ b/weed/admin/dash/service_account_management.go @@ -8,6 +8,7 @@ import ( "time" "github.com/seaweedfs/seaweedfs/weed/glog" + "github.com/seaweedfs/seaweedfs/weed/iam" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" ) @@ -21,8 +22,8 @@ const ( accessKeyPrefix = "ABIA" // Service account access keys use ABIA prefix // Status constants - StatusActive = "Active" - StatusInactive = "Inactive" + StatusActive = iam.AccessKeyStatusActive + StatusInactive = iam.AccessKeyStatusInactive ) // GetServiceAccounts returns all service accounts, optionally filtered by parent user diff --git a/weed/admin/view/app/service_accounts.templ b/weed/admin/view/app/service_accounts.templ index d057278f5..4696c63b9 100644 --- a/weed/admin/view/app/service_accounts.templ +++ b/weed/admin/view/app/service_accounts.templ @@ -126,7 +126,7 @@ templ ServiceAccounts(data dash.ServiceAccountsData) { {sa.AccessKeyId} - if sa.Status == "Active" { + if sa.Status == dash.StatusActive { Active } else { Inactive @@ -141,7 +141,7 @@ templ ServiceAccounts(data dash.ServiceAccountsData) {