diff --git a/cmd/ctrld/cli.go b/cmd/cli/cli.go similarity index 99% rename from cmd/ctrld/cli.go rename to cmd/cli/cli.go index 8913b0f..894efc0 100644 --- a/cmd/ctrld/cli.go +++ b/cmd/cli/cli.go @@ -1,4 +1,4 @@ -package main +package cli import ( "bytes" diff --git a/cmd/ctrld/cli_test.go b/cmd/cli/cli_test.go similarity index 97% rename from cmd/ctrld/cli_test.go rename to cmd/cli/cli_test.go index 23746b7..01f2586 100644 --- a/cmd/ctrld/cli_test.go +++ b/cmd/cli/cli_test.go @@ -1,4 +1,4 @@ -package main +package cli import ( "os" diff --git a/cmd/ctrld/conn.go b/cmd/cli/conn.go similarity index 99% rename from cmd/ctrld/conn.go rename to cmd/cli/conn.go index a627935..82e6468 100644 --- a/cmd/ctrld/conn.go +++ b/cmd/cli/conn.go @@ -1,4 +1,4 @@ -package main +package cli import ( "net" diff --git a/cmd/ctrld/control_client.go b/cmd/cli/control_client.go similarity index 97% rename from cmd/ctrld/control_client.go rename to cmd/cli/control_client.go index 8a41193..c626602 100644 --- a/cmd/ctrld/control_client.go +++ b/cmd/cli/control_client.go @@ -1,4 +1,4 @@ -package main +package cli import ( "context" diff --git a/cmd/ctrld/control_server.go b/cmd/cli/control_server.go similarity index 99% rename from cmd/ctrld/control_server.go rename to cmd/cli/control_server.go index 5118113..5f5ac51 100644 --- a/cmd/ctrld/control_server.go +++ b/cmd/cli/control_server.go @@ -1,4 +1,4 @@ -package main +package cli import ( "context" diff --git a/cmd/ctrld/control_server_test.go b/cmd/cli/control_server_test.go similarity index 98% rename from cmd/ctrld/control_server_test.go rename to cmd/cli/control_server_test.go index 2bcd64a..297b37d 100644 --- a/cmd/ctrld/control_server_test.go +++ b/cmd/cli/control_server_test.go @@ -1,4 +1,4 @@ -package main +package cli import ( "bytes" diff --git a/cmd/ctrld/dns.go b/cmd/cli/dns.go similarity index 86% rename from cmd/ctrld/dns.go rename to cmd/cli/dns.go index 770a630..cf9d779 100644 --- a/cmd/ctrld/dns.go +++ b/cmd/cli/dns.go @@ -1,4 +1,4 @@ -package main +package cli //lint:ignore U1000 use in os_linux.go type getDNS func(iface string) []string diff --git a/cmd/ctrld/dns_proxy.go b/cmd/cli/dns_proxy.go similarity index 99% rename from cmd/ctrld/dns_proxy.go rename to cmd/cli/dns_proxy.go index 81a373e..23ae03e 100644 --- a/cmd/ctrld/dns_proxy.go +++ b/cmd/cli/dns_proxy.go @@ -1,4 +1,4 @@ -package main +package cli import ( "context" diff --git a/cmd/ctrld/dns_proxy_test.go b/cmd/cli/dns_proxy_test.go similarity index 99% rename from cmd/ctrld/dns_proxy_test.go rename to cmd/cli/dns_proxy_test.go index 3245875..b7b0dbd 100644 --- a/cmd/ctrld/dns_proxy_test.go +++ b/cmd/cli/dns_proxy_test.go @@ -1,4 +1,4 @@ -package main +package cli import ( "context" diff --git a/cmd/cli/main.go b/cmd/cli/main.go new file mode 100644 index 0000000..e7376be --- /dev/null +++ b/cmd/cli/main.go @@ -0,0 +1,161 @@ +package cli + +import ( + "io" + "os" + "path/filepath" + "sync/atomic" + "time" + + "github.com/kardianos/service" + "github.com/rs/zerolog" + + "github.com/Control-D-Inc/ctrld" +) + +var ( + configPath string + configBase64 string + daemon bool + listenAddress string + primaryUpstream string + secondaryUpstream string + domains []string + logPath string + homedir string + cacheSize int + cfg ctrld.Config + verbose int + silent bool + cdUID string + cdOrg string + cdDev bool + iface string + ifaceStartStop string + + mainLog atomic.Pointer[zerolog.Logger] + consoleWriter zerolog.ConsoleWriter +) + +func init() { + l := zerolog.New(io.Discard) + mainLog.Store(&l) +} + +func Main() { + ctrld.InitConfig(v, "ctrld") + initCLI() + if err := rootCmd.Execute(); err != nil { + mainLog.Load().Error().Msg(err.Error()) + os.Exit(1) + } +} + +func normalizeLogFilePath(logFilePath string) string { + if logFilePath == "" || filepath.IsAbs(logFilePath) || service.Interactive() { + return logFilePath + } + if homedir != "" { + return filepath.Join(homedir, logFilePath) + } + dir, _ := userHomeDir() + if dir == "" { + return logFilePath + } + return filepath.Join(dir, logFilePath) +} + +func initConsoleLogging() { + consoleWriter = zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) { + w.TimeFormat = time.StampMilli + }) + multi := zerolog.MultiLevelWriter(consoleWriter) + l := mainLog.Load().Output(multi).With().Timestamp().Logger() + mainLog.Store(&l) + switch { + case silent: + zerolog.SetGlobalLevel(zerolog.NoLevel) + case verbose == 1: + zerolog.SetGlobalLevel(zerolog.InfoLevel) + case verbose > 1: + zerolog.SetGlobalLevel(zerolog.DebugLevel) + default: + zerolog.SetGlobalLevel(zerolog.NoticeLevel) + } +} + +// initLogging initializes global logging setup. +func initLogging() { + initLoggingWithBackup(true) +} + +// initLoggingWithBackup initializes log setup base on current config. +// If doBackup is true, backup old log file with ".1" suffix. +// +// This is only used in runCmd for special handling in case of logging config +// change in cd mode. Without special reason, the caller should use initLogging +// wrapper instead of calling this function directly. +func initLoggingWithBackup(doBackup bool) { + writers := []io.Writer{io.Discard} + if logFilePath := normalizeLogFilePath(cfg.Service.LogPath); logFilePath != "" { + // Create parent directory if necessary. + if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil { + mainLog.Load().Error().Msgf("failed to create log path: %v", err) + os.Exit(1) + } + + // Default open log file in append mode. + flags := os.O_CREATE | os.O_RDWR | os.O_APPEND + if doBackup { + // Backup old log file with .1 suffix. + if err := os.Rename(logFilePath, logFilePath+".1"); err != nil && !os.IsNotExist(err) { + mainLog.Load().Error().Msgf("could not backup old log file: %v", err) + } else { + // Backup was created, set flags for truncating old log file. + flags = os.O_CREATE | os.O_RDWR + } + } + logFile, err := os.OpenFile(logFilePath, flags, os.FileMode(0o600)) + if err != nil { + mainLog.Load().Error().Msgf("failed to create log file: %v", err) + os.Exit(1) + } + writers = append(writers, logFile) + } + writers = append(writers, consoleWriter) + multi := zerolog.MultiLevelWriter(writers...) + l := mainLog.Load().Output(multi).With().Timestamp().Logger() + mainLog.Store(&l) + // TODO: find a better way. + ctrld.ProxyLogger.Store(&l) + + zerolog.SetGlobalLevel(zerolog.NoticeLevel) + logLevel := cfg.Service.LogLevel + switch { + case silent: + zerolog.SetGlobalLevel(zerolog.NoLevel) + return + case verbose == 1: + logLevel = "info" + case verbose > 1: + logLevel = "debug" + } + if logLevel == "" { + return + } + level, err := zerolog.ParseLevel(logLevel) + if err != nil { + mainLog.Load().Warn().Err(err).Msg("could not set log level") + return + } + zerolog.SetGlobalLevel(level) +} + +func initCache() { + if !cfg.Service.CacheEnable { + return + } + if cfg.Service.CacheSize == 0 { + cfg.Service.CacheSize = 4096 + } +} diff --git a/cmd/ctrld/main_test.go b/cmd/cli/main_test.go similarity index 93% rename from cmd/ctrld/main_test.go rename to cmd/cli/main_test.go index 9654fb6..6ed26c7 100644 --- a/cmd/ctrld/main_test.go +++ b/cmd/cli/main_test.go @@ -1,4 +1,4 @@ -package main +package cli import ( "os" diff --git a/cmd/ctrld/net_darwin.go b/cmd/cli/net_darwin.go similarity index 98% rename from cmd/ctrld/net_darwin.go rename to cmd/cli/net_darwin.go index f0f7e5a..f456327 100644 --- a/cmd/ctrld/net_darwin.go +++ b/cmd/cli/net_darwin.go @@ -1,4 +1,4 @@ -package main +package cli import ( "bufio" diff --git a/cmd/ctrld/net_darwin_test.go b/cmd/cli/net_darwin_test.go similarity index 98% rename from cmd/ctrld/net_darwin_test.go rename to cmd/cli/net_darwin_test.go index 7110d15..443a9d1 100644 --- a/cmd/ctrld/net_darwin_test.go +++ b/cmd/cli/net_darwin_test.go @@ -1,4 +1,4 @@ -package main +package cli import ( "strings" diff --git a/cmd/ctrld/net_others.go b/cmd/cli/net_others.go similarity index 88% rename from cmd/ctrld/net_others.go rename to cmd/cli/net_others.go index 9093395..2f7aec8 100644 --- a/cmd/ctrld/net_others.go +++ b/cmd/cli/net_others.go @@ -1,6 +1,6 @@ //go:build !darwin -package main +package cli import "net" diff --git a/cmd/ctrld/netlink_linux.go b/cmd/cli/netlink_linux.go similarity index 97% rename from cmd/ctrld/netlink_linux.go rename to cmd/cli/netlink_linux.go index 7657fc3..0faae84 100644 --- a/cmd/ctrld/netlink_linux.go +++ b/cmd/cli/netlink_linux.go @@ -1,4 +1,4 @@ -package main +package cli import ( "github.com/vishvananda/netlink" diff --git a/cmd/ctrld/netlink_others.go b/cmd/cli/netlink_others.go similarity index 80% rename from cmd/ctrld/netlink_others.go rename to cmd/cli/netlink_others.go index d069661..f0afd21 100644 --- a/cmd/ctrld/netlink_others.go +++ b/cmd/cli/netlink_others.go @@ -1,5 +1,5 @@ //go:build !linux -package main +package cli func (p *prog) watchLinkState() {} diff --git a/cmd/ctrld/network_manager_linux.go b/cmd/cli/network_manager_linux.go similarity index 99% rename from cmd/ctrld/network_manager_linux.go rename to cmd/cli/network_manager_linux.go index 799c2dc..5e7b540 100644 --- a/cmd/ctrld/network_manager_linux.go +++ b/cmd/cli/network_manager_linux.go @@ -1,4 +1,4 @@ -package main +package cli import ( "context" diff --git a/cmd/ctrld/network_manager_others.go b/cmd/cli/network_manager_others.go similarity index 93% rename from cmd/ctrld/network_manager_others.go rename to cmd/cli/network_manager_others.go index cd43bbc..323d2f2 100644 --- a/cmd/ctrld/network_manager_others.go +++ b/cmd/cli/network_manager_others.go @@ -1,6 +1,6 @@ //go:build !linux -package main +package cli func setupNetworkManager() error { reloadNetworkManager() diff --git a/cmd/ctrld/os_darwin.go b/cmd/cli/os_darwin.go similarity index 99% rename from cmd/ctrld/os_darwin.go rename to cmd/cli/os_darwin.go index ac872d8..5931819 100644 --- a/cmd/ctrld/os_darwin.go +++ b/cmd/cli/os_darwin.go @@ -1,4 +1,4 @@ -package main +package cli import ( "net" diff --git a/cmd/ctrld/os_freebsd.go b/cmd/cli/os_freebsd.go similarity index 99% rename from cmd/ctrld/os_freebsd.go rename to cmd/cli/os_freebsd.go index 5a1fa36..a6d6dde 100644 --- a/cmd/ctrld/os_freebsd.go +++ b/cmd/cli/os_freebsd.go @@ -1,4 +1,4 @@ -package main +package cli import ( "net" diff --git a/cmd/ctrld/os_linux.go b/cmd/cli/os_linux.go similarity index 99% rename from cmd/ctrld/os_linux.go rename to cmd/cli/os_linux.go index 7a4efae..004e863 100644 --- a/cmd/ctrld/os_linux.go +++ b/cmd/cli/os_linux.go @@ -1,4 +1,4 @@ -package main +package cli import ( "bufio" diff --git a/cmd/ctrld/os_linux_test.go b/cmd/cli/os_linux_test.go similarity index 97% rename from cmd/ctrld/os_linux_test.go rename to cmd/cli/os_linux_test.go index 671f1b4..694fb18 100644 --- a/cmd/ctrld/os_linux_test.go +++ b/cmd/cli/os_linux_test.go @@ -1,4 +1,4 @@ -package main +package cli import ( "reflect" diff --git a/cmd/ctrld/os_others.go b/cmd/cli/os_others.go similarity index 93% rename from cmd/ctrld/os_others.go rename to cmd/cli/os_others.go index 3807bcc..45edf0a 100644 --- a/cmd/ctrld/os_others.go +++ b/cmd/cli/os_others.go @@ -1,6 +1,6 @@ //go:build !linux && !darwin && !freebsd -package main +package cli // TODO(cuonglm): implement. func allocateIP(ip string) error { diff --git a/cmd/ctrld/os_windows.go b/cmd/cli/os_windows.go similarity index 99% rename from cmd/ctrld/os_windows.go rename to cmd/cli/os_windows.go index f96e224..a58411e 100644 --- a/cmd/ctrld/os_windows.go +++ b/cmd/cli/os_windows.go @@ -1,4 +1,4 @@ -package main +package cli import ( "errors" diff --git a/cmd/ctrld/prog.go b/cmd/cli/prog.go similarity index 99% rename from cmd/ctrld/prog.go rename to cmd/cli/prog.go index fab10cc..c3006ec 100644 --- a/cmd/ctrld/prog.go +++ b/cmd/cli/prog.go @@ -1,4 +1,4 @@ -package main +package cli import ( "errors" diff --git a/cmd/ctrld/prog_darwin.go b/cmd/cli/prog_darwin.go similarity index 93% rename from cmd/ctrld/prog_darwin.go rename to cmd/cli/prog_darwin.go index 1a6656d..9cd5786 100644 --- a/cmd/ctrld/prog_darwin.go +++ b/cmd/cli/prog_darwin.go @@ -1,4 +1,4 @@ -package main +package cli import ( "github.com/kardianos/service" diff --git a/cmd/ctrld/prog_freebsd.go b/cmd/cli/prog_freebsd.go similarity index 95% rename from cmd/ctrld/prog_freebsd.go rename to cmd/cli/prog_freebsd.go index 283e03c..93d737f 100644 --- a/cmd/ctrld/prog_freebsd.go +++ b/cmd/cli/prog_freebsd.go @@ -1,4 +1,4 @@ -package main +package cli import ( "os" diff --git a/cmd/ctrld/prog_linux.go b/cmd/cli/prog_linux.go similarity index 98% rename from cmd/ctrld/prog_linux.go rename to cmd/cli/prog_linux.go index f14a054..6f28083 100644 --- a/cmd/ctrld/prog_linux.go +++ b/cmd/cli/prog_linux.go @@ -1,4 +1,4 @@ -package main +package cli import ( "github.com/kardianos/service" diff --git a/cmd/ctrld/prog_others.go b/cmd/cli/prog_others.go similarity index 95% rename from cmd/ctrld/prog_others.go rename to cmd/cli/prog_others.go index 7d70825..92f3a9f 100644 --- a/cmd/ctrld/prog_others.go +++ b/cmd/cli/prog_others.go @@ -1,6 +1,6 @@ //go:build !linux && !freebsd && !darwin -package main +package cli import "github.com/kardianos/service" diff --git a/cmd/ctrld/sema.go b/cmd/cli/sema.go similarity index 96% rename from cmd/ctrld/sema.go rename to cmd/cli/sema.go index 8faa9d2..92b6ce0 100644 --- a/cmd/ctrld/sema.go +++ b/cmd/cli/sema.go @@ -1,4 +1,4 @@ -package main +package cli type semaphore interface { acquire() diff --git a/cmd/ctrld/service.go b/cmd/cli/service.go similarity index 99% rename from cmd/ctrld/service.go rename to cmd/cli/service.go index 263dfd8..c6ed68c 100644 --- a/cmd/ctrld/service.go +++ b/cmd/cli/service.go @@ -1,4 +1,4 @@ -package main +package cli import ( "bytes" diff --git a/cmd/ctrld/service_others.go b/cmd/cli/service_others.go similarity index 90% rename from cmd/ctrld/service_others.go rename to cmd/cli/service_others.go index 82a6ea3..e9522f4 100644 --- a/cmd/ctrld/service_others.go +++ b/cmd/cli/service_others.go @@ -1,6 +1,6 @@ //go:build !windows -package main +package cli import ( "os" diff --git a/cmd/ctrld/service_windows.go b/cmd/cli/service_windows.go similarity index 96% rename from cmd/ctrld/service_windows.go rename to cmd/cli/service_windows.go index 0ce8d3a..a1010a8 100644 --- a/cmd/ctrld/service_windows.go +++ b/cmd/cli/service_windows.go @@ -1,4 +1,4 @@ -package main +package cli import "golang.org/x/sys/windows" diff --git a/cmd/ctrld/main.go b/cmd/ctrld/main.go index 80160ec..af204ad 100644 --- a/cmd/ctrld/main.go +++ b/cmd/ctrld/main.go @@ -1,161 +1,7 @@ package main -import ( - "io" - "os" - "path/filepath" - "sync/atomic" - "time" - - "github.com/kardianos/service" - "github.com/rs/zerolog" - - "github.com/Control-D-Inc/ctrld" -) - -var ( - configPath string - configBase64 string - daemon bool - listenAddress string - primaryUpstream string - secondaryUpstream string - domains []string - logPath string - homedir string - cacheSize int - cfg ctrld.Config - verbose int - silent bool - cdUID string - cdOrg string - cdDev bool - iface string - ifaceStartStop string - - mainLog atomic.Pointer[zerolog.Logger] - consoleWriter zerolog.ConsoleWriter -) - -func init() { - l := zerolog.New(io.Discard) - mainLog.Store(&l) -} +import "github.com/Control-D-Inc/ctrld/cmd/cli" func main() { - ctrld.InitConfig(v, "ctrld") - initCLI() - if err := rootCmd.Execute(); err != nil { - mainLog.Load().Error().Msg(err.Error()) - os.Exit(1) - } -} - -func normalizeLogFilePath(logFilePath string) string { - if logFilePath == "" || filepath.IsAbs(logFilePath) || service.Interactive() { - return logFilePath - } - if homedir != "" { - return filepath.Join(homedir, logFilePath) - } - dir, _ := userHomeDir() - if dir == "" { - return logFilePath - } - return filepath.Join(dir, logFilePath) -} - -func initConsoleLogging() { - consoleWriter = zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) { - w.TimeFormat = time.StampMilli - }) - multi := zerolog.MultiLevelWriter(consoleWriter) - l := mainLog.Load().Output(multi).With().Timestamp().Logger() - mainLog.Store(&l) - switch { - case silent: - zerolog.SetGlobalLevel(zerolog.NoLevel) - case verbose == 1: - zerolog.SetGlobalLevel(zerolog.InfoLevel) - case verbose > 1: - zerolog.SetGlobalLevel(zerolog.DebugLevel) - default: - zerolog.SetGlobalLevel(zerolog.NoticeLevel) - } -} - -// initLogging initializes global logging setup. -func initLogging() { - initLoggingWithBackup(true) -} - -// initLoggingWithBackup initializes log setup base on current config. -// If doBackup is true, backup old log file with ".1" suffix. -// -// This is only used in runCmd for special handling in case of logging config -// change in cd mode. Without special reason, the caller should use initLogging -// wrapper instead of calling this function directly. -func initLoggingWithBackup(doBackup bool) { - writers := []io.Writer{io.Discard} - if logFilePath := normalizeLogFilePath(cfg.Service.LogPath); logFilePath != "" { - // Create parent directory if necessary. - if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil { - mainLog.Load().Error().Msgf("failed to create log path: %v", err) - os.Exit(1) - } - - // Default open log file in append mode. - flags := os.O_CREATE | os.O_RDWR | os.O_APPEND - if doBackup { - // Backup old log file with .1 suffix. - if err := os.Rename(logFilePath, logFilePath+".1"); err != nil && !os.IsNotExist(err) { - mainLog.Load().Error().Msgf("could not backup old log file: %v", err) - } else { - // Backup was created, set flags for truncating old log file. - flags = os.O_CREATE | os.O_RDWR - } - } - logFile, err := os.OpenFile(logFilePath, flags, os.FileMode(0o600)) - if err != nil { - mainLog.Load().Error().Msgf("failed to create log file: %v", err) - os.Exit(1) - } - writers = append(writers, logFile) - } - writers = append(writers, consoleWriter) - multi := zerolog.MultiLevelWriter(writers...) - l := mainLog.Load().Output(multi).With().Timestamp().Logger() - mainLog.Store(&l) - // TODO: find a better way. - ctrld.ProxyLogger.Store(&l) - - zerolog.SetGlobalLevel(zerolog.NoticeLevel) - logLevel := cfg.Service.LogLevel - switch { - case silent: - zerolog.SetGlobalLevel(zerolog.NoLevel) - return - case verbose == 1: - logLevel = "info" - case verbose > 1: - logLevel = "debug" - } - if logLevel == "" { - return - } - level, err := zerolog.ParseLevel(logLevel) - if err != nil { - mainLog.Load().Warn().Err(err).Msg("could not set log level") - return - } - zerolog.SetGlobalLevel(level) -} - -func initCache() { - if !cfg.Service.CacheEnable { - return - } - if cfg.Service.CacheSize == 0 { - cfg.Service.CacheSize = 4096 - } + cli.Main() }