diff --git a/command/agent/command.go b/command/agent/command.go index 77054b324..a1acc374d 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -978,60 +978,8 @@ func (c *Command) handleRetryJoin(config *Config) error { return nil } -// handleSignals blocks until we get an exit-causing signal -func (c *Command) handleSignals() int { - signalCh := make(chan os.Signal, 4) - signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE) - - // Signal readiness only once signal handlers are setup - sdSock, err := openNotify() - if err != nil { - c.agent.logger.Debug("notify socket could not be accessed", "error", err) - } - if sdSock != nil { - defer sdSock.Close() - } - sdNotify(sdSock, sdReady) - - // Wait for a signal -WAIT: - var sig os.Signal - select { - case s := <-signalCh: - sig = s - case <-winsvc.ShutdownChannel(): - sig = os.Interrupt - case <-c.ShutdownCh: - sig = os.Interrupt - case <-c.retryJoinErrCh: - return 1 - } - - // Skip any SIGPIPE signal and don't try to log it (See issues #1798, #3554) - if sig == syscall.SIGPIPE { - goto WAIT - } - - c.Ui.Output(fmt.Sprintf("Caught signal: %v", sig)) - - // Check if this is a SIGHUP - if sig == syscall.SIGHUP { - sdNotifyReloading(sdSock) - c.handleReload() - sdNotify(sdSock, sdReady) - goto WAIT - } - - // Check if we should do a graceful leave - graceful := false - if sig == os.Interrupt && c.agent.GetConfig().LeaveOnInt { - graceful = true - } else if sig == syscall.SIGTERM && c.agent.GetConfig().LeaveOnTerm { - graceful = true - } - - // Bail fast if not doing a graceful leave - if !graceful { +func (c *Command) terminate(signalCh chan os.Signal, sdSock io.Writer) int { + if !c.agent.GetConfig().LeaveOnInt { return 1 } @@ -1058,6 +1006,55 @@ WAIT: } } +// handleSignals blocks until we get an exit-causing signal +func (c *Command) handleSignals() int { + signalCh := make(chan os.Signal, 4) + signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE) + + // Signal readiness only once signal handlers are setup + sdSock, err := openNotify() + if err != nil { + c.agent.logger.Debug("notify socket could not be accessed", "error", err) + } + + if sdSock != nil { + defer sdSock.Close() + } + sdNotify(sdSock, sdReady) + + for { + select { + case sig := <-signalCh: + c.Ui.Output(fmt.Sprintf("Caught signal: %v", sig)) + + switch sig { + case syscall.SIGPIPE: + // Skip any SIGPIPE signal and don't try to log it (See issues #1798, #3554) + continue + case syscall.SIGHUP: + sdNotifyReloading(sdSock) + err := c.handleReload() + if err != nil { + c.Ui.Output("Terminal error found while reloading") + return 1 + } + sdNotify(sdSock, sdReady) + case os.Interrupt, syscall.SIGTERM: + return c.terminate(signalCh, sdSock) + } + + case <-winsvc.ShutdownChannel(): + return c.terminate(signalCh, sdSock) + + case <-c.ShutdownCh: + return c.terminate(signalCh, sdSock) + + case <-c.retryJoinErrCh: + return 1 + } + } +} + // reloadHTTPServer shuts down the existing HTTP server and restarts it. This // is helpful when reloading the agent configuration. func (c *Command) reloadHTTPServer() error { @@ -1077,12 +1074,14 @@ func (c *Command) reloadHTTPServer() error { } // handleReload is invoked when we should reload our configs, e.g. SIGHUP -func (c *Command) handleReload() { +// It will only return an error if the reload encountered a fatal error that must +// cause an agent termination. +func (c *Command) handleReload() error { c.Ui.Output("Reloading configuration...") newConf := c.readConfig() if newConf == nil { c.Ui.Error("Failed to reload configs") - return + return nil } // Change the log level @@ -1103,7 +1102,7 @@ func (c *Command) handleReload() { err := c.agent.Reload(newConf) if err != nil { c.agent.logger.Error("failed to reload the config", "error", err) - return + return nil } } @@ -1112,7 +1111,7 @@ func (c *Command) handleReload() { sconf, err := convertServerConfig(newConf) if err != nil { c.agent.logger.Error("failed to convert server config", "error", err) - return + return nil } // Finalize the config to get the agent objects injected in @@ -1121,7 +1120,7 @@ func (c *Command) handleReload() { // Reload the config if err := s.Reload(sconf); err != nil { c.agent.logger.Error("reloading server config failed", "error", err) - return + return fmt.Errorf("reloading server config failed: %w", err) } } @@ -1130,18 +1129,18 @@ func (c *Command) handleReload() { clientConfig, err := convertClientConfig(newConf) if err != nil { c.agent.logger.Error("failed to convert client config", "error", err) - return + return nil } // Finalize the config to get the agent objects injected in if err := c.agent.finalizeClientConfig(clientConfig); err != nil { c.agent.logger.Error("failed to finalize client config", "error", err) - return + return nil } if err := client.Reload(clientConfig); err != nil { c.agent.logger.Error("reloading client config failed", "error", err) - return + return nil } } @@ -1153,9 +1152,10 @@ func (c *Command) handleReload() { err := c.reloadHTTPServer() if err != nil { c.agent.httpLogger.Error("reloading config failed", "error", err) - return + return nil } } + return nil } // setupTelemetry is used to set up the telemetry sub-systems.