package main import ( "context" "fmt" "os" "isle/daemon" "dev.mediocregopher.com/mediocre-go-lib.git/mlog" ) // TODO it would be good to have an `isle daemon config-check` kind of command, // which could be run prior to a systemd service restart to make sure we don't // restart the service into a configuration that will definitely fail. var subCmdDaemon = subCmd{ name: "daemon", descr: "Runs the isle daemon (Default if no sub-command given)", do: func(ctx subCmdCtx) error { flags := ctx.flagSet(false) daemonConfigPath := flags.StringP( "config-path", "c", "", "Optional path to a daemon.yml file to load configuration from.", ) dumpConfig := flags.Bool( "dump-config", false, "Write the default configuration file to stdout and exit.", ) logLevelStr := flags.StringP( "log-level", "l", "info", `Maximum log level which should be output. Values can be "debug", "info", "warn", "error", "fatal". Does not apply to sub-processes`, ) if err := flags.Parse(ctx.args); err != nil { return fmt.Errorf("parsing flags: %w", err) } if *dumpConfig { return daemon.CopyDefaultConfig(os.Stdout, envAppDirPath) } logLevel := mlog.LevelFromString(*logLevelStr) if logLevel == nil { return fmt.Errorf("couldn't parse log level %q", *logLevelStr) } logger := ctx.logger.WithMaxLevel(logLevel.Int()) // TODO check that daemon is either running as root, or that the // required linux capabilities are set. // TODO check that the tun module is loaded (for nebula). daemonConfig, err := daemon.LoadConfig(envAppDirPath, *daemonConfigPath) if err != nil { return fmt.Errorf("loading daemon config: %w", err) } daemonInst, err := daemon.NewDaemon( ctx, logger, daemonConfig, envBinDirPath, nil, ) if err != nil { return fmt.Errorf("starting daemon: %w", err) } defer func() { logger.Info(ctx, "Stopping child processes") if err := daemonInst.Shutdown(); err != nil { logger.Error(ctx, "Shutting down daemon cleanly failed, there may be orphaned child processes", err) } logger.Info(ctx, "Child processes successfully stopped") }() { logger := logger.WithNamespace("http") httpSrv, err := newHTTPServer( ctx, logger, daemonInst, ) if err != nil { return fmt.Errorf("starting HTTP server: %w", err) } defer func() { // see comment in daemonInst shutdown logic regarding background // context. logger.Info(ctx, "Shutting down HTTP socket") if err := httpSrv.Shutdown(context.Background()); err != nil { logger.Error(ctx, "Failed to cleanly shutdown http server", err) } }() } <-ctx.Done() return nil }, }