Skip to content

Commit 8ba3af5

Browse files
authored
Watch config file for token changes (#3418)
* clean up go.mod formatting * allow config struct to be watched for changes on disk * cordination between agent and foreground cmd to keep tokens updated in both * use current tokens when reconnecting to NATS This required forking NATS. I'm trying to get the changes upstreamed in nats-io/nats.go#1599 * debounce config change notifications
1 parent 0ad5d41 commit 8ba3af5

9 files changed

Lines changed: 471 additions & 180 deletions

File tree

agent/server/server.go

Lines changed: 35 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -137,17 +137,19 @@ func (s *server) serve(parent context.Context, l net.Listener) (err error) {
137137
return nil
138138
})
139139

140-
eg.Go(func() error {
141-
if f := config.Tokens(ctx).FromConfigFile; f == "" {
142-
s.print("monitoring for token expiration")
143-
s.updateMacaroonsInMemory(ctx)
144-
} else {
145-
s.print("monitoring for token changes and expiration")
146-
s.updateMacaroonsInFile(ctx, f)
147-
}
140+
if toks := config.Tokens(ctx); len(toks.MacaroonTokens) != 0 {
141+
eg.Go(func() error {
142+
if f := toks.FromConfigFile; f == "" {
143+
s.print("monitoring for token expiration")
144+
s.updateMacaroonsInMemory(ctx)
145+
} else {
146+
s.print("monitoring for token changes and expiration")
147+
s.updateMacaroonsInFile(ctx, f)
148+
}
148149

149-
return nil
150-
})
150+
return nil
151+
})
152+
}
151153

152154
eg.Go(func() (err error) {
153155
s.printf("OK %d", os.Getpid())
@@ -399,75 +401,49 @@ func (s *server) updateMacaroonsInMemory(ctx context.Context) {
399401
}
400402
}
401403

402-
// updateMacaroons updates the agent's tokens as the config file changes. It
403-
// also prunes expired tokens and fetches discharge tokens as necessary. Those
404-
// updates are written back to the config file.
404+
// updateMacaroons prunes expired tokens and fetches discharge tokens as
405+
// necessary. Those updates are written back to the config file.
405406
func (s *server) updateMacaroonsInFile(ctx context.Context, path string) {
406-
toks := config.Tokens(ctx)
407+
configToks := config.Tokens(ctx)
407408

408409
ticker := time.NewTicker(time.Minute)
409410
defer ticker.Stop()
410411

411412
var lastErr error
412413

413-
fiBefore, err := os.Stat(path)
414-
if err != nil {
415-
s.print("failed stating config file:", err)
416-
s.updateMacaroonsInMemory(ctx)
417-
return
418-
}
419-
420414
for {
421-
updated, err := toks.Update(ctx, tokens.WithDebugger(s))
415+
select {
416+
case <-ctx.Done():
417+
return
418+
case <-ticker.C:
419+
}
420+
421+
// the tokens in the config are continually updated as the config file
422+
// changes. We do our updates on a copy of the tokens so we can still
423+
// tell if the tokens in the config changed out from under us.
424+
configToksBefore := configToks.All()
425+
localToks := tokens.Parse(configToksBefore)
426+
427+
updated, err := localToks.Update(ctx, tokens.WithDebugger(s))
422428
if err != nil && err != lastErr {
423429
s.print("failed upgrading authentication tokens:", err)
424430
lastErr = err
425431

426432
// Don't continue loop here! It might only be partial failure
427433
}
428434

429-
if updated {
430-
fiAfter, err := os.Stat(path)
431-
if err != nil {
432-
s.print("failed stating config file:", err)
435+
// the consequences of a race here (agent and foreground command both
436+
// fetching updates simultaneously) are low, so don't bother with a lock
437+
// file.
438+
if updated && configToks.All() == configToksBefore {
439+
if err := config.SetAccessToken(path, localToks.All()); err != nil {
440+
s.print("Failed to persist authentication token:", err)
433441
s.updateMacaroonsInMemory(ctx)
434442
return
435443
}
436444

437-
// Don't write updates if the file changed out from under us. This
438-
// isn't as strong of an assurance as a lockfile would be, but a
439-
// race isn't that consequential.
440-
if fiBefore.ModTime() == fiAfter.ModTime() {
441-
if err := config.SetAccessToken(path, toks.All()); err != nil {
442-
s.print("Failed to persist authentication token:", err)
443-
s.updateMacaroonsInMemory(ctx)
444-
return
445-
}
446-
447-
s.print("Authentication tokens upgraded")
448-
}
449-
}
450-
451-
select {
452-
case <-ctx.Done():
453-
return
454-
case <-ticker.C:
445+
s.print("Authentication tokens upgraded")
455446
}
456-
457-
if fiBefore, err = os.Stat(path); err != nil {
458-
s.print("failed stating config file:", err)
459-
s.updateMacaroonsInMemory(ctx)
460-
return
461-
}
462-
463-
tok, err := config.ReadAccessToken(path)
464-
if err != nil {
465-
s.print("failed reading config file:", err)
466-
s.updateMacaroonsInMemory(ctx)
467-
return
468-
}
469-
470-
toks.Replace(tokens.Parse(tok))
471447
}
472448
}
473449

0 commit comments

Comments
 (0)