-
Notifications
You must be signed in to change notification settings - Fork 223
/
run.go
130 lines (104 loc) · 2.9 KB
/
run.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package agent
import (
"context"
"fmt"
"io"
"log"
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
fly "github.com/superfly/fly-go"
"github.com/superfly/flyctl/agent/server"
"github.com/superfly/flyctl/flyctl"
"github.com/superfly/flyctl/internal/command"
"github.com/superfly/flyctl/internal/config"
"github.com/superfly/flyctl/internal/filemu"
"github.com/superfly/flyctl/internal/flag"
"github.com/superfly/flyctl/internal/state"
)
func newRun() (cmd *cobra.Command) {
const (
short = "Run the Fly agent in the foreground"
long = short + "\n"
)
// Don't use RequireSession preparer. It does its own token monitoring and
// will try to run token discharge flows that would involve opening URLs in
// the user's browser. We don't want to do that in a background agent.
cmd = command.New("run", short, long, run)
cmd.Args = cobra.MaximumNArgs(1)
cmd.Aliases = []string{"daemon-start"}
return
}
func run(ctx context.Context) error {
logPath := flag.FirstArg(ctx)
logger, closeLogger, err := setupLogger(logPath)
if err != nil {
err = fmt.Errorf("failed setting up logger: %w", err)
fmt.Fprintln(os.Stderr, err)
return err
}
defer closeLogger()
if config.Tokens(ctx).GraphQL() == "" {
logger.Println(fly.ErrNoAuthToken)
return fly.ErrNoAuthToken
}
unlock, err := lock(ctx, logger)
if err != nil {
return err
}
defer unlock()
opt := server.Options{
Socket: socketPath(ctx),
Logger: logger,
Background: logPath != "",
ConfigFile: state.ConfigFile(ctx),
ConfigWebsockets: viper.GetBool(flyctl.ConfigWireGuardWebsockets),
}
return server.Run(ctx, opt)
}
func setupLogger(path string) (logger *log.Logger, close func(), err error) {
var out io.Writer
if path != "" {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0o600)
if err != nil {
return nil, nil, err
}
out = io.MultiWriter(os.Stdout, f)
close = func() {
_ = f.Sync()
_ = f.Close()
}
} else {
out = os.Stdout
close = func() {}
}
logger = log.Default()
logger.SetFlags(log.Ldate | log.Lmicroseconds | log.Lmsgprefix)
logger.SetPrefix("srv ")
logger.SetOutput(out)
return
}
type dupInstanceError struct{}
func (*dupInstanceError) Error() string {
return "another instance of the agent is already running"
}
func (*dupInstanceError) Description() string {
return "It looks like another instance of the agent is already running. Please stop it before starting a new one."
}
var errDupInstance = new(dupInstanceError)
func lockPath() string {
return filepath.Join(flyctl.ConfigDir(), "flyctl.agent.lock")
}
func lock(ctx context.Context, logger *log.Logger) (unlock filemu.UnlockFunc, err error) {
switch unlock, err = filemu.Lock(ctx, lockPath()); {
case err == nil:
break // all done
case ctx.Err() != nil:
err = ctx.Err() // parent canceled or deadlined
default:
err = errDupInstance
logger.Print(err)
}
return
}