| 2499 | } |
| 2500 | |
| 2501 | func (dbc *DatabaseContext) InstallPrincipals(ctx context.Context, spec map[string]*auth.PrincipalConfig, what string) error { |
| 2502 | for name, princ := range spec { |
| 2503 | isGuest := name == base.GuestUsername |
| 2504 | if isGuest { |
| 2505 | internalName := "" |
| 2506 | princ.Name = &internalName |
| 2507 | } else { |
| 2508 | n := name |
| 2509 | princ.Name = &n |
| 2510 | } |
| 2511 | |
| 2512 | createdPrincipal := true |
| 2513 | worker := func() (shouldRetry bool, err error, value interface{}) { |
| 2514 | _, _, err = dbc.UpdatePrincipal(ctx, princ, (what == "user"), isGuest) |
| 2515 | if err != nil { |
| 2516 | if status, _ := base.ErrorAsHTTPStatus(err); status == http.StatusConflict { |
| 2517 | // Ignore and absorb this error if it's a conflict error, which just means that updatePrincipal didn't overwrite an existing user. |
| 2518 | // Since if there's an existing user it's "mission accomplished", this can be treated as a success case. |
| 2519 | createdPrincipal = false |
| 2520 | return false, nil, nil |
| 2521 | } |
| 2522 | |
| 2523 | if err == base.ErrViewTimeoutError { |
| 2524 | // Timeout error, possibly due to view re-indexing, so retry |
| 2525 | base.InfofCtx(ctx, base.KeyAuth, "Error calling UpdatePrincipal(): %v. Will retry in case this is a temporary error", err) |
| 2526 | return true, err, nil |
| 2527 | } |
| 2528 | |
| 2529 | // Unexpected error, return error don't retry |
| 2530 | return false, err, nil |
| 2531 | } |
| 2532 | |
| 2533 | // No errors, assume it worked |
| 2534 | return false, nil, nil |
| 2535 | |
| 2536 | } |
| 2537 | |
| 2538 | err, _ := base.RetryLoop(ctx, "installPrincipals", worker, base.CreateDoublingSleeperFunc(16, 10)) |
| 2539 | if err != nil { |
| 2540 | return err |
| 2541 | } |
| 2542 | |
| 2543 | if isGuest { |
| 2544 | base.InfofCtx(ctx, base.KeyAll, "Reset guest user to config") |
| 2545 | } else if createdPrincipal { |
| 2546 | base.InfofCtx(ctx, base.KeyAll, "Created %s %q", what, base.UD(name)) |
| 2547 | } |
| 2548 | |
| 2549 | } |
| 2550 | return nil |
| 2551 | } |
| 2552 | |
| 2553 | // DataStoreNames returns the names of all datastores connected to this database |
| 2554 | func (db *Database) DataStoreNames() base.ScopeAndCollectionNames { |