Skip to content

Commit d0f22ee

Browse files
committed
cordination between agent and foreground cmd to keep tokens updated in both
1 parent 7bb4ca8 commit d0f22ee

File tree

3 files changed

+65
-73
lines changed

3 files changed

+65
-73
lines changed

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

internal/command/agent/run.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ func newRun() (cmd *cobra.Command) {
2727
long = short + "\n"
2828
)
2929

30-
cmd = command.New("run", short, long, run)
30+
cmd = command.New("run", short, long, run,
31+
command.RequireSession,
32+
)
3133

3234
cmd.Args = cobra.MaximumNArgs(1)
3335
cmd.Aliases = []string{"daemon-start"}
@@ -46,12 +48,6 @@ func run(ctx context.Context) error {
4648
}
4749
defer closeLogger()
4850

49-
apiClient := fly.ClientFromContext(ctx)
50-
if !apiClient.Authenticated() {
51-
logger.Println(fly.ErrNoAuthToken)
52-
return fly.ErrNoAuthToken
53-
}
54-
5551
unlock, err := lock(ctx, logger)
5652
if err != nil {
5753
return err
@@ -61,7 +57,7 @@ func run(ctx context.Context) error {
6157
opt := server.Options{
6258
Socket: socketPath(ctx),
6359
Logger: logger,
64-
Client: apiClient,
60+
Client: fly.ClientFromContext(ctx),
6561
Background: logPath != "",
6662
ConfigFile: state.ConfigFile(ctx),
6763
ConfigWebsockets: viper.GetBool(flyctl.ConfigWireGuardWebsockets),

internal/command/command.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -557,9 +557,11 @@ func RequireSession(ctx context.Context) (context.Context, error) {
557557
// updateMacaroons prune any invalid/expired macaroons and fetch needed third
558558
// party discharges
559559
func updateMacaroons(ctx context.Context) (context.Context, error) {
560-
log := logger.FromContext(ctx)
561-
562-
toks := config.Tokens(ctx)
560+
var (
561+
log = logger.FromContext(ctx)
562+
cfg = config.FromContext(ctx)
563+
toks = cfg.Tokens
564+
)
563565

564566
updated, err := toks.Update(ctx,
565567
tokens.WithUserURLCallback(tryOpenUserURL),
@@ -570,15 +572,33 @@ func updateMacaroons(ctx context.Context) (context.Context, error) {
570572
log.Debug(err)
571573
}
572574

573-
if !updated || toks.FromConfigFile == "" {
575+
if toks.FromConfigFile == "" {
574576
return ctx, nil
575577
}
576578

577-
if err := config.SetAccessToken(toks.FromConfigFile, toks.All()); err != nil {
578-
log.Warn("Failed to persist authentication token.")
579+
if updated {
580+
if err := config.SetAccessToken(toks.FromConfigFile, toks.All()); err != nil {
581+
log.Warn("Failed to persist authentication token.")
582+
log.Debug(err)
583+
}
584+
}
585+
586+
sub, err := cfg.Watch(ctx)
587+
if err != nil {
588+
log.Warn("Failed to watch config file for changes.")
579589
log.Debug(err)
590+
return ctx, nil
580591
}
581592

593+
go func() {
594+
for newCfg := range sub {
595+
if cfg.Tokens.All() != newCfg.Tokens.All() {
596+
log.Debug("Authentication tokens updated from config file.")
597+
cfg.Tokens.Replace(newCfg.Tokens)
598+
}
599+
}
600+
}()
601+
582602
return ctx, nil
583603
}
584604

0 commit comments

Comments
 (0)