Skip to content

Commit 340aee1

Browse files
committed
begin config + cli refactoring
1 parent a4d2a97 commit 340aee1

File tree

8 files changed

+133
-179
lines changed

8 files changed

+133
-179
lines changed

cli_entry.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,30 @@
66
package main
77

88
import (
9+
"flag"
910
"fmt"
1011
"os"
1112

1213
"github.com/crimist/trakx/config"
1314
"github.com/crimist/trakx/controller"
14-
"go.uber.org/zap"
1515
)
1616

1717
func printHelp() {
1818
help := "Commands:\n"
19-
help += fmt.Sprintf(" %-12s returns the status of trakx\n", "status")
20-
help += fmt.Sprintf(" %-12s starts trakx daemon\n", "start")
21-
help += fmt.Sprintf(" %-12s stops trakx daemon\n", "stop")
22-
help += fmt.Sprintf(" %-12s restarts trakx daemon\n", "restart")
23-
help += fmt.Sprintf(" %-12s executes trakx, doesn't return\n", "execute")
24-
help += fmt.Sprintf(" %-12s wipes trakx pid file, use if you encounter errors with start/stop/restart commands\n", "reset")
19+
help += fmt.Sprintf(" %-12s returns the status of trakx\n", "status")
20+
help += fmt.Sprintf(" %-12s starts trakx daemon\n", "start")
21+
help += fmt.Sprintf(" %-12s stops trakx daemon\n", "stop")
22+
help += fmt.Sprintf(" %-12s restarts trakx daemon\n", "restart")
23+
help += fmt.Sprintf(" %-12s executes trakx, doesn't return\n", "execute")
24+
help += fmt.Sprintf(" %-12s wipes trakx pid file\n", "reset")
2525

26-
help += "Usage:\n"
27-
help += fmt.Sprintf(" %s <command>\n", os.Args[0])
26+
help += "\nFlags:\n"
27+
fmt.Fprint(os.Stderr, help)
28+
flag.PrintDefaults()
2829

29-
help += "Example:\n"
30-
help += fmt.Sprintf(" %s status\n", os.Args[0])
31-
32-
fmt.Print(help)
30+
help = "\nExample:\n"
31+
help += fmt.Sprintf(" %s -config trakx.yaml status\n", os.Args[0])
32+
fmt.Fprint(os.Stderr, help)
3333
}
3434

3535
func logFatal(err error) {
@@ -38,19 +38,21 @@ func logFatal(err error) {
3838
}
3939

4040
func main() {
41-
if len(os.Args) < 2 {
41+
flag.Parse()
42+
43+
if flag.NArg() == 0 {
4244
printHelp()
4345
return
4446
}
4547

4648
conf, err := config.Load()
4749
if err != nil {
48-
zap.L().Fatal("failed to load configuration", zap.Error(err))
50+
logFatal(err)
4951
}
5052

5153
controller := controller.NewController(conf)
5254

53-
switch os.Args[1] {
55+
switch flag.Arg(0) {
5456
case "status":
5557
pidFileExists, processAlive, heartbeat := controller.Status()
5658

cmd/run.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,6 @@ func Run(conf *config.Configuration) {
3333

3434
zap.L().Debug("Starting Trakx")
3535

36-
warnings := conf.Validate()
37-
if warnings&config.WarningUDPValidation != 0 {
38-
zap.L().Warn("Configuration warning [UDP.ConnDB.Validate]: UDP connection validation is disabled. Do not expose this service to untrusted networks; it could be abused in UDP based amplification attacks.")
39-
}
40-
if warnings&config.WarningPeerExpiry != 0 {
41-
zap.L().Warn("Configuration warning [conf.Announce]: Peer expiry time < announce interval. Peers will expire from the database between announces")
42-
}
43-
4436
if conf.Stats.General {
4537
if conf.Stats.Interval <= 0 {
4638
zap.L().Fatal("Invalid configuration: Stats.Interval must be greater than 0 if Stats.General is enabled")

config/config.go

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package config
22

33
import (
4+
"os"
45
"path/filepath"
56
"time"
67

8+
"github.com/pkg/errors"
79
"go.uber.org/zap"
810
)
911

1012
type Configuration struct {
11-
LogLevel LogLevel
12-
CachePath string
13-
Stats struct {
13+
LogLevel LogLevel
14+
Cache string
15+
Stats struct {
1416
General bool
1517
IP bool
1618
Interval time.Duration
@@ -61,56 +63,38 @@ type Configuration struct {
6163
}
6264
}
6365

64-
type Warnings int
65-
66-
const (
67-
WarningNone Warnings = 1 << iota
68-
WarningUDPValidation
69-
WarningPeerExpiry
70-
)
71-
72-
// Validate ensures that configuration values are sane and returns warnings for potential misconfigurations or security issues
73-
func (conf *Configuration) Validate() Warnings {
74-
warnings := WarningNone
66+
// validate checks that configuration values are sane and returns warnings for potential misconfigurations or security issues
67+
func (conf *Configuration) validate() error {
68+
// check cache directory exists and is a directory
69+
stat, err := os.Stat(conf.Cache)
70+
if os.IsNotExist(err) {
71+
zap.L().Debug("cache directory does not exist, creating it", zap.String("cache", conf.Cache))
72+
if err = os.MkdirAll(conf.Cache, defaultFolderPermission); err != nil {
73+
return errors.Wrapf(err, "failed to create cache directory '%s'", conf.Cache)
74+
}
75+
} else if err != nil {
76+
return errors.Wrapf(err, "failed to stat cache '%s'", conf.Cache)
77+
} else if !stat.IsDir() {
78+
return errors.Errorf("cache '%s' is not a directory", conf.Cache)
79+
}
7580

81+
// potential misconfigurations warnings
7682
if !conf.UDP.ConnDB.Validate {
77-
warnings |= WarningUDPValidation
83+
zap.L().Warn("Configuration warning: UDP connection validation is disabled. Do not expose this service to untrusted networks; it could be abused in UDP based amplification attacks.")
7884
}
7985
if conf.DB.Expiry < conf.Announce.Base+conf.Announce.Fuzz {
80-
warnings |= WarningPeerExpiry
86+
zap.L().Warn("Configuration warning: Peer expiry time < announce base + fuzz. Peers will expire from the database between announces.")
8187
}
8288

83-
return warnings
89+
return nil
8490
}
8591

8692
// LogPath returns the log path as defined by the configuration and current time
8793
func (conf *Configuration) LogPath() string {
88-
return filepath.Join(conf.CachePath, "trakx_"+time.Now().Format("06-01-02-15-04-05")+".log")
94+
return filepath.Join(conf.Cache, "trakx_"+time.Now().Format("06-01-02-15-04-05")+".log")
8995
}
9096

9197
// PIDPath retuirns the pid file path
9298
func (conf *Configuration) PIDPath() string {
93-
return filepath.Join(conf.CachePath, "trakx.pid")
94-
}
95-
96-
// setLogLevel sets the desired loglevel in the in memory configuration and logger
97-
func (conf *Configuration) setLogLevel(level LogLevel) {
98-
conf.LogLevel = level
99-
100-
switch level {
101-
case "debug":
102-
loggerAtom.SetLevel(zap.DebugLevel)
103-
zap.L().Debug("Debug loglevel set, debug panics enabled")
104-
case "info":
105-
loggerAtom.SetLevel(zap.InfoLevel)
106-
case "warn":
107-
loggerAtom.SetLevel(zap.WarnLevel)
108-
case "error":
109-
loggerAtom.SetLevel(zap.ErrorLevel)
110-
case "fatal":
111-
loggerAtom.SetLevel(zap.FatalLevel)
112-
default:
113-
zap.L().Warn("Invalid log level was specified, defaulting to warn")
114-
loggerAtom.SetLevel(zap.WarnLevel)
115-
}
99+
return filepath.Join(conf.Cache, "trakx.pid")
116100
}

config/embed.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package config
22

33
import (
44
"embed"
5+
"fmt"
56
"os"
67
"path/filepath"
78
"syscall"
@@ -13,25 +14,30 @@ import (
1314
//go:embed embedded/*
1415
var embeddedFS embed.FS
1516

16-
func writeEmbeddedConfig(path string) error {
17+
func installDefaultConfig(path string) error {
1718
syscall.Umask(0)
1819

19-
if _, err := os.Stat(path); os.IsNotExist(err) {
20-
configData, err := embeddedFS.ReadFile("embedded/trakx.yaml")
21-
if err != nil {
22-
return errors.Wrap(err, "failed to read embedded FS")
23-
}
20+
_, err := os.Stat(path)
2421

25-
if err = os.MkdirAll(filepath.Dir(path), folderPerm); err != nil {
26-
zap.L().Warn("failed to create config directory", zap.Error(err))
27-
}
28-
29-
if err = os.WriteFile(path, configData, filePerm); err != nil {
30-
return errors.Wrap(err, "failed to write configuration file to "+path)
31-
}
32-
} else if err != nil {
22+
if os.IsExist(err) {
23+
zap.L().Debug("configuration file already exists, skipping installation", zap.String("path", path))
24+
return nil
25+
} else if err != nil && !os.IsNotExist(err) {
3326
return errors.Wrap(err, "failed to stat config file "+path)
3427
}
3528

29+
configurationContents, err := embeddedFS.ReadFile("embedded/trakx.yaml")
30+
if err != nil {
31+
return errors.Wrap(err, "failed to read config from embedded FS")
32+
}
33+
34+
if err = os.MkdirAll(filepath.Dir(path), defaultFolderPermission); err != nil {
35+
zap.L().Warn("failed to create configuration directory", zap.Error(err), zap.String("directory", filepath.Dir(path)))
36+
}
37+
38+
if err = os.WriteFile(path, configurationContents, defaultFilePermission); err != nil {
39+
return errors.Wrap(err, fmt.Sprintf("failed to write configuration file '%s'", path))
40+
}
41+
3642
return nil
3743
}

config/embedded/trakx.yaml

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
# Trakx YAML config
22
# Values can be overridden with env vars
3-
# Example: `TRAKX_LOGLEVEL=debug trakx run`
4-
5-
# TODO: find better names for these, ie conndb.trim should be conncache.expiry
3+
# Example: `TRAKX_LOGLEVEL=debug trakx execute`
64

75
# "debug", "info", "warn", "error", or "fatal"
86
# "debug" will enable debug only panics
97
loglevel: "info"
108

11-
# cachepath is the directory in which trakx will write it's pid, logs, and database
12-
cachepath: ~/.cache/trakx/
9+
# cache is the directory in which trakx will write it's pid, logs, and database persistence files
10+
# leave blank for default of XDG_CACHE_HOME/trakx
11+
cache:
1312

1413
# Trakx can track statistic about itself such as the number of announces, seeds, unique ips, etc.
1514
# they are published via the expvar standard at '/stats'
@@ -24,10 +23,11 @@ stats:
2423
interval: 1s
2524

2625
debug:
27-
# port to serve pprof over, 0 to disable
28-
pprof: 0
26+
# port to serve pprof over, leave blank to disable
27+
pprof:
2928

3029
# --- REFACTOR BELOW ---
30+
# TODO: find better names for these, ie conndb.trim should be conncache.expiry
3131

3232
# announce interval = base + [0, fuzz]
3333
announce:
@@ -107,13 +107,8 @@ db:
107107
# pg - write db to postgres
108108
type: "none"
109109

110-
# backup path:
111-
# use "ENV:VARIABLE" for environment variables
112-
# ex: "ENV:TEST" = os.Getenv("TEST")
113-
# types
114-
# file - filepath
115-
# pg - postgres db addr
116-
path: "ENV:DATABASE_URL"
110+
# backup path
111+
path: ""
117112

118113
# interval for removing expired peers
119114
trim: 10m

0 commit comments

Comments
 (0)