diff --git a/internal/clientcache/internal/cache/refresh.go b/internal/clientcache/internal/cache/refresh.go index e19f087a9a..93da9fcfd3 100644 --- a/internal/clientcache/internal/cache/refresh.go +++ b/internal/clientcache/internal/cache/refresh.go @@ -79,6 +79,7 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m if err := r.repo.deleteKeyringToken(ctx, *kt); err != nil { return nil, errors.Wrap(ctx, err, op) } + event.WriteSysEvent(ctx, op, "Removed auth token from cache because it was not found to be valid in boundary", "auth token id", at.Id) continue case err != nil && !errors.Is(err, apiErr): event.WriteError(ctx, op, err, event.WithInfoMsg("validating keyring stored token against boundary", "auth token id", at.Id)) @@ -94,6 +95,7 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m switch { case err != nil && (api.ErrUnauthorized.Is(err) || api.ErrNotFound.Is(err)): r.repo.idToKeyringlessAuthToken.Delete(t.Id) + event.WriteSysEvent(ctx, op, "Removed auth token from cache because it was not found to be valid in boundary", "auth token id", at.Id) continue case err != nil && !errors.Is(err, apiErr): event.WriteError(ctx, op, err, event.WithInfoMsg("validating in memory stored token against boundary", "auth token id", at.Id)) @@ -107,12 +109,12 @@ func (r *RefreshService) cleanAndPickAuthTokens(ctx context.Context, u *user) (m return ret, nil } -// refreshableUsers filters the provided users down to the set of users who can -// have their resources refreshed using refresh tokens. A user is returned by -// this method if it has no resources in storage at all or it has a refresh -// token for any resource. -func (r *RefreshService) refreshableUsers(ctx context.Context, in []*user) ([]*user, error) { - const op = "cache.(RefreshService).refreshableUsers" +// cacheSupportedUsers filters the provided users down to the set of users who +// can have their resources refreshed using refresh tokens. A user is returned +// by this method if it does not have a sentinel value refresh token marking it +// as unsupported for caching. +func (r *RefreshService) cacheSupportedUsers(ctx context.Context, in []*user) ([]*user, error) { + const op = "cache.(RefreshService).cacheSupportedUsers" var ret []*user for _, u := range in { cs, err := r.repo.cacheSupportState(ctx, u) @@ -162,7 +164,7 @@ func (r *RefreshService) RefreshForSearch(ctx context.Context, authTokenid strin if u == nil { return errors.New(ctx, errors.NotFound, op, "user not found") } - us, err := r.refreshableUsers(ctx, []*user{u}) + us, err := r.cacheSupportedUsers(ctx, []*user{u}) if err != nil { return errors.Wrap(ctx, err, op) } @@ -235,7 +237,7 @@ func (r *RefreshService) Refresh(ctx context.Context, opt ...Option) error { return errors.Wrap(ctx, err, op) } - us, err = r.refreshableUsers(ctx, us) + us, err = r.cacheSupportedUsers(ctx, us) if err != nil { return errors.Wrap(ctx, err, op) } @@ -279,7 +281,7 @@ func (r *RefreshService) RecheckCachingSupport(ctx context.Context, opt ...Optio return errors.Wrap(ctx, err, op) } - removeUsers, err := r.refreshableUsers(ctx, us) + removeUsers, err := r.cacheSupportedUsers(ctx, us) if err != nil { return errors.Wrap(ctx, err, op) } diff --git a/internal/clientcache/internal/cache/repository_sessions.go b/internal/clientcache/internal/cache/repository_sessions.go index 04fbb411d5..a591c15a05 100644 --- a/internal/clientcache/internal/cache/repository_sessions.go +++ b/internal/clientcache/internal/cache/repository_sessions.go @@ -87,6 +87,7 @@ func (r *Repository) refreshSessions(ctx context.Context, u *user, tokens map[Au for at, t := range tokens { resp, removedIds, newRefreshToken, err = opts.withSessionRetrievalFunc(ctx, u.Address, t, oldRefreshTokenVal) if api.ErrInvalidListToken.Is(err) { + event.WriteSysEvent(ctx, op, "old list token is no longer valid, starting new initial fetch", "user_id", u.Id) if err := r.deleteRefreshToken(ctx, u, resourceType); err != nil { return errors.Wrap(ctx, err, op) } @@ -115,16 +116,17 @@ func (r *Repository) refreshSessions(ctx context.Context, u *user, tokens map[Au return retErr } - event.WriteSysEvent(ctx, op, fmt.Sprintf("updating %d sessions for user %v", len(resp), u)) + var numDeleted int _, err = r.rw.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(_ db.Reader, w db.Writer) error { + var err error switch { case oldRefreshToken == nil: - if _, err := w.Exec(ctx, "delete from session where fk_user_id = @fk_user_id", + if numDeleted, err = w.Exec(ctx, "delete from session where fk_user_id = @fk_user_id", []any{sql.Named("fk_user_id", u.Id)}); err != nil { return err } case len(removedIds) > 0: - if _, err := w.Exec(ctx, "delete from session where id in @ids", + if numDeleted, err = w.Exec(ctx, "delete from session where id in @ids", []any{sql.Named("ids", removedIds)}); err != nil { return err } @@ -152,6 +154,7 @@ func (r *Repository) refreshSessions(ctx context.Context, u *user, tokens map[Au if unsupportedCacheRequest { return ErrRefreshNotSupported } + event.WriteSysEvent(ctx, op, "sessions updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) return nil } @@ -207,6 +210,7 @@ func (r *Repository) checkCachingSessions(ctx context.Context, u *user, tokens m return retErr } + var numDeleted int _, err = r.rw.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(reader db.Reader, w db.Writer) error { switch { case unsupportedCacheRequest: @@ -214,7 +218,8 @@ func (r *Repository) checkCachingSessions(ctx context.Context, u *user, tokens m return err } case newRefreshToken != "": - if _, err := w.Exec(ctx, "delete from session where fk_user_id = @fk_user_id", + var err error + if numDeleted, err = w.Exec(ctx, "delete from session where fk_user_id = @fk_user_id", []any{sql.Named("fk_user_id", u.Id)}); err != nil { return err } @@ -239,6 +244,7 @@ func (r *Repository) checkCachingSessions(ctx context.Context, u *user, tokens m if unsupportedCacheRequest { return ErrRefreshNotSupported } + event.WriteSysEvent(ctx, op, "sessions updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) return nil } diff --git a/internal/clientcache/internal/cache/repository_targets.go b/internal/clientcache/internal/cache/repository_targets.go index e042f5d532..39c7aa6fb1 100644 --- a/internal/clientcache/internal/cache/repository_targets.go +++ b/internal/clientcache/internal/cache/repository_targets.go @@ -86,6 +86,7 @@ func (r *Repository) refreshTargets(ctx context.Context, u *user, tokens map[Aut for at, t := range tokens { resp, removedIds, newRefreshToken, err = opts.withTargetRetrievalFunc(ctx, u.Address, t, oldRefreshTokenVal) if api.ErrInvalidListToken.Is(err) { + event.WriteSysEvent(ctx, op, "old list token is no longer valid, starting new initial fetch", "user_id", u.Id) if err := r.deleteRefreshToken(ctx, u, resourceType); err != nil { return errors.Wrap(ctx, err, op) } @@ -113,16 +114,17 @@ func (r *Repository) refreshTargets(ctx context.Context, u *user, tokens map[Aut return retErr } - event.WriteSysEvent(ctx, op, fmt.Sprintf("updating %d targets for user %v", len(resp), u)) + var numDeleted int _, err = r.rw.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(_ db.Reader, w db.Writer) error { + var err error switch { case oldRefreshToken == nil || unsupportedCacheRequest: - if _, err := w.Exec(ctx, "delete from target where fk_user_id = @fk_user_id", + if numDeleted, err = w.Exec(ctx, "delete from target where fk_user_id = @fk_user_id", []any{sql.Named("fk_user_id", u.Id)}); err != nil { return err } case len(removedIds) > 0: - if _, err := w.Exec(ctx, "delete from target where id in @ids", + if numDeleted, err = w.Exec(ctx, "delete from target where id in @ids", []any{sql.Named("ids", removedIds)}); err != nil { return err } @@ -150,6 +152,7 @@ func (r *Repository) refreshTargets(ctx context.Context, u *user, tokens map[Aut if unsupportedCacheRequest { return ErrRefreshNotSupported } + event.WriteSysEvent(ctx, op, "targets updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) return nil } @@ -205,6 +208,7 @@ func (r *Repository) checkCachingTargets(ctx context.Context, u *user, tokens ma return retErr } + var numDeleted int _, err = r.rw.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(reader db.Reader, w db.Writer) error { switch { case unsupportedCacheRequest: @@ -214,9 +218,10 @@ func (r *Repository) checkCachingTargets(ctx context.Context, u *user, tokens ma return err } case newRefreshToken != "": + var err error // Now that there is a refresh token, the data can be cached, so // cache it and store the refresh token for future refreshes. - if _, err := w.Exec(ctx, "delete from target where fk_user_id = @fk_user_id", + if numDeleted, err = w.Exec(ctx, "delete from target where fk_user_id = @fk_user_id", []any{sql.Named("fk_user_id", u.Id)}); err != nil { return err } @@ -241,6 +246,7 @@ func (r *Repository) checkCachingTargets(ctx context.Context, u *user, tokens ma if unsupportedCacheRequest { return ErrRefreshNotSupported } + event.WriteSysEvent(ctx, op, "targets updated", "deleted", numDeleted, "upserted", len(resp), "user_id", u.Id) return nil } diff --git a/internal/clientcache/internal/daemon/token_handler.go b/internal/clientcache/internal/daemon/token_handler.go index 79e49874e8..8106b66e47 100644 --- a/internal/clientcache/internal/daemon/token_handler.go +++ b/internal/clientcache/internal/daemon/token_handler.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/boundary/internal/clientcache/internal/cache" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/boundary/internal/event" "github.com/hashicorp/boundary/internal/util" ) @@ -114,12 +115,16 @@ func newTokenHandlerFunc(ctx context.Context, repo *cache.Repository, refresher AuthTokenId: perReq.AuthTokenId, } if err = repo.AddKeyringToken(ctx, perReq.BoundaryAddr, kt); err != nil { - writeError(w, fmt.Sprintf("Failed to add a keyring stored token: %v", err), http.StatusInternalServerError) + err := fmt.Errorf("Failed to add a keyring stored token with id %q: %w", perReq.AuthTokenId, err) + event.WriteError(ctx, op, err) + writeError(w, err.Error(), http.StatusInternalServerError) return } case perReq.AuthToken != "": if err = repo.AddRawToken(ctx, perReq.BoundaryAddr, perReq.AuthToken); err != nil { - writeError(w, "Failed to add a raw token", http.StatusInternalServerError) + err := fmt.Errorf("Failed to add a raw token with id %q: %w", perReq.AuthTokenId, err) + event.WriteError(ctx, op, err) + writeError(w, fmt.Sprintf("Failed to add a raw token: %v", err), http.StatusInternalServerError) return } }