fix(accounts): tolerate ambiguous shadow bindings

This commit is contained in:
phamnazage-jpg
2026-05-29 15:58:37 +08:00
parent c982c595b8
commit d8d9e6e170
2 changed files with 98 additions and 0 deletions

View File

@@ -375,3 +375,91 @@ func TestSyncProviderAccountsFromImportBatchInfersRouteFromShadowBinding(t *test
t.Fatalf("provider account view route binding = %+v", view) t.Fatalf("provider account view route binding = %+v", view)
} }
} }
func TestSyncProviderAccountsFromImportBatchLeavesRouteEmptyOnAmbiguousShadowBinding(t *testing.T) {
t.Parallel()
store := openTestDBWithFK(t)
ctx := context.Background()
hostID := createTestHost(t, store)
hostRow, err := store.Hosts().GetByID(ctx, hostID)
if err != nil {
t.Fatalf("Hosts().GetByID() error = %v", err)
}
packID := createTestPack(t, store)
providerID, err := store.Providers().Create(ctx, Provider{
PackID: packID,
ProviderID: "asxs-provider",
DisplayName: "ASXS Provider",
BaseURL: "https://api.asxs.top/v1",
Platform: "openai",
})
if err != nil {
t.Fatalf("Providers().Create() error = %v", err)
}
for _, groupID := range []string{"gpt-shared-a", "gpt-shared-b"} {
if _, err := store.LogicalGroups().Create(ctx, LogicalGroup{
LogicalGroupID: groupID,
DisplayName: groupID,
Status: "active",
}); err != nil {
t.Fatalf("LogicalGroups().Create(%s) error = %v", groupID, err)
}
}
for _, routeID := range []string{"route-a", "route-b"} {
logicalGroupID := "gpt-shared-a"
if routeID == "route-b" {
logicalGroupID = "gpt-shared-b"
}
if _, err := store.LogicalGroupRoutes().Create(ctx, LogicalGroupRoute{
RouteID: routeID,
LogicalGroupID: logicalGroupID,
Name: routeID,
Status: "active",
Priority: 10,
Weight: 100,
ShadowGroupID: "group-1",
ShadowHostID: hostRow.HostID,
}); err != nil {
t.Fatalf("LogicalGroupRoutes().Create(%s) error = %v", routeID, err)
}
}
batchID, err := store.ImportBatches().Create(ctx, ImportBatch{
HostID: hostID,
PackID: packID,
ProviderID: providerID,
Mode: "strict",
BatchStatus: "succeeded",
AccessStatus: "subscription_ready",
})
if err != nil {
t.Fatalf("ImportBatches().Create() error = %v", err)
}
if _, err := store.ImportBatchItems().Create(ctx, ImportBatchItem{
BatchID: batchID,
KeyFingerprint: "sha256:key1",
AccountStatus: "passed",
ProbeSummaryJSON: `{"account_id":"account-1","probe_status":"passed"}`,
}); err != nil {
t.Fatalf("ImportBatchItems().Create() error = %v", err)
}
for _, resource := range []ManagedResource{
{BatchID: batchID, HostID: hostID, ResourceType: "group", HostResourceID: "group-1", ResourceName: "ASXS Group"},
{BatchID: batchID, HostID: hostID, ResourceType: "account", HostResourceID: "account-1", ResourceName: "asxs-01"},
} {
if _, err := store.ManagedResources().Create(ctx, resource); err != nil {
t.Fatalf("ManagedResources().Create(%s) error = %v", resource.ResourceType, err)
}
}
if err := SyncProviderAccountsFromImportBatch(ctx, store, batchID); err != nil {
t.Fatalf("SyncProviderAccountsFromImportBatch() error = %v", err)
}
account, err := store.ProviderAccounts().GetByHostIDAndAccountID(ctx, hostID, "account-1")
if err != nil {
t.Fatalf("ProviderAccounts().GetByHostIDAndAccountID() error = %v", err)
}
if account.RouteID != "" {
t.Fatalf("provider account route binding = %+v, want empty route on ambiguous shadow binding", account)
}
}

View File

@@ -134,6 +134,9 @@ func resolveProviderAccountRouteBinding(ctx context.Context, store *DB, shadowHo
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return LogicalGroupRoute{}, err return LogicalGroupRoute{}, err
} }
if isAmbiguousProviderAccountRouteBinding(err) {
return LogicalGroupRoute{}, sql.ErrNoRows
}
return LogicalGroupRoute{}, fmt.Errorf("resolve logical route for provider account shadow binding %q/%q: %w", shadowHostID, shadowGroupID, err) return LogicalGroupRoute{}, fmt.Errorf("resolve logical route for provider account shadow binding %q/%q: %w", shadowHostID, shadowGroupID, err)
} }
return route, nil return route, nil
@@ -209,3 +212,10 @@ func preserveManagedProviderAccountStatus(row *ProviderAccount, existing Provide
} }
} }
} }
func isAmbiguousProviderAccountRouteBinding(err error) bool {
if err == nil {
return false
}
return strings.Contains(err.Error(), "multiple logical group routes match shadow binding")
}