Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit 7b41515

Browse files
committed
Implement graceful termination
1 parent 625361f commit 7b41515

File tree

3 files changed

+16
-4
lines changed

3 files changed

+16
-4
lines changed

config/ssh.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ type SSHConfig struct {
4343
// allowed to be sent without a response being received. If this number
4444
// is exceeded the connection is considered dead
4545
ClientAliveCountMax int `json:"clientAliveCountMax" yaml:"clientAliveCountMax" default:"3" comment:"Maximum number of failed keepalives"`
46+
// GracefulTerminationDeadline is the amount of time ContainerSSH will
47+
// wait after receiving a SIGTERM for all the clients to disconnect.
48+
// After this duraction all connections are forcefully terminated.
49+
GracefulTerminationDeadline time.Duration `json:"gracefulTerminationDeadline" yaml:"gracefulTerminationDeadline" default:"0"`
4650
}
4751

4852
// GenerateHostKey generates a random host key and adds it to SSHConfig
@@ -120,6 +124,9 @@ func (cfg SSHConfig) Validate() error {
120124
if cfg.ClientAliveCountMax <= 0 {
121125
return fmt.Errorf("clientAliveCountMax should be at least 1")
122126
}
127+
if cfg.GracefulTerminationDeadline < 1 * time.Minute {
128+
return fmt.Errorf("gracefulTerminationDeadline should be at least 1 minute")
129+
}
123130
return nil
124131
}
125132

internal/sshserver/serverImpl.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,13 @@ func (s *serverImpl) RunWithLifecycle(lifecycle service.Lifecycle) error {
8686
s.wg.Add(1)
8787
go s.handleConnection(tcpConn)
8888
}
89+
8990
lifecycle.Stopping()
9091
s.shuttingDown = true
9192
allClientsExited := make(chan struct{})
9293
shutdownHandlerExited := make(chan struct{}, 1)
94+
s.disconnectClients(lifecycle, allClientsExited)
9395
go s.shutdownHandlers.Shutdown(lifecycle.ShutdownContext())
94-
go s.disconnectClients(lifecycle, allClientsExited)
9596
go s.shutdownHandler(lifecycle, shutdownHandlerExited)
9697

9798
s.wg.Wait()
@@ -322,6 +323,7 @@ func (s *serverImpl) createConfiguration(
322323
ServerVersion: s.cfg.ServerVersion.String(),
323324
BannerCallback: func(conn ssh.ConnMetadata) string { return s.cfg.Banner },
324325
}
326+
325327
for _, key := range s.hostKeys {
326328
serverConfig.AddHostKey(key)
327329
}

main.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ func startServices(cfg config.AppConfig, loggerFactory log.LoggerFactory) error
182182
return err
183183
}
184184

185-
return startPool(pool, lifecycle)
185+
return startPool(pool, lifecycle, cfg)
186186
}
187187

188-
func startPool(pool Service, lifecycle service.Lifecycle) error {
188+
func startPool(pool Service, lifecycle service.Lifecycle, cfg config.AppConfig) error {
189189
starting := make(chan struct{})
190190
lifecycle.OnStarting(
191191
func(s service.Service, l service.Lifecycle) {
@@ -204,12 +204,15 @@ func startPool(pool Service, lifecycle service.Lifecycle) error {
204204
rotateSignals := make(chan os.Signal, 1)
205205
signal.Notify(exitSignals, exitSignalList...)
206206
signal.Notify(rotateSignals, rotateSignalList...)
207+
208+
deadline := cfg.SSH.GracefulTerminationDeadline + 5 * time.Second
209+
207210
go func() {
208211
if _, ok := <-exitSignals; ok {
209212
// ok means the channel wasn't closed
210213
shutdownContext, cancelFunc := context.WithTimeout(
211214
context.Background(),
212-
20*time.Second,
215+
deadline,
213216
)
214217
defer cancelFunc()
215218
lifecycle.Stop(

0 commit comments

Comments
 (0)