Skip to content

Commit 9cb2ae1

Browse files
authored
SSH connections are left dangling after use (#668)
1 parent 95bf342 commit 9cb2ae1

File tree

2 files changed

+22
-11
lines changed

2 files changed

+22
-11
lines changed

cmd/backup/script.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,20 @@ func (s *script) init() error {
177177
IdentityPassphrase: s.c.SSHIdentityPassphrase,
178178
RemotePath: s.c.SSHRemotePath,
179179
}
180-
sshBackend, err := ssh.NewStorageBackend(sshConfig, logFunc)
180+
181+
sshBackend, closeSSHConnection, err := ssh.NewStorageBackend(sshConfig, logFunc)
182+
183+
s.registerHook(hookLevelPlumbing, func(err error) error {
184+
if err := closeSSHConnection(); err != nil {
185+
return errwrap.Wrap(err, "failed to close ssh connection")
186+
}
187+
return nil
188+
})
189+
181190
if err != nil {
182191
return errwrap.Wrap(err, "error creating ssh storage backend")
183192
}
193+
184194
s.storages = append(s.storages, sshBackend)
185195
}
186196

internal/storage/ssh/ssh.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ type Config struct {
3636
RemotePath string
3737
}
3838

39+
var noop = func() error { return nil }
40+
3941
// NewStorageBackend creates and initializes a new SSH storage backend.
40-
func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error) {
42+
func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, func() error, error) {
4143
var authMethods []ssh.AuthMethod
4244

4345
if opts.Password != "" {
@@ -47,20 +49,20 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
4749
if _, err := os.Stat(opts.IdentityFile); err == nil {
4850
key, err := os.ReadFile(opts.IdentityFile)
4951
if err != nil {
50-
return nil, errwrap.Wrap(nil, "error reading the private key")
52+
return nil, noop, errwrap.Wrap(nil, "error reading the private key")
5153
}
5254

5355
var signer ssh.Signer
5456
if opts.IdentityPassphrase != "" {
5557
signer, err = ssh.ParsePrivateKeyWithPassphrase(key, []byte(opts.IdentityPassphrase))
5658
if err != nil {
57-
return nil, errwrap.Wrap(nil, "error parsing the encrypted private key")
59+
return nil, noop, errwrap.Wrap(nil, "error parsing the encrypted private key")
5860
}
5961
authMethods = append(authMethods, ssh.PublicKeys(signer))
6062
} else {
6163
signer, err = ssh.ParsePrivateKey(key)
6264
if err != nil {
63-
return nil, errwrap.Wrap(nil, "error parsing the private key")
65+
return nil, noop, errwrap.Wrap(nil, "error parsing the private key")
6466
}
6567
authMethods = append(authMethods, ssh.PublicKeys(signer))
6668
}
@@ -72,13 +74,12 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
7274
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
7375
}
7476
sshClient, err := ssh.Dial("tcp", fmt.Sprintf("%s:%s", opts.HostName, opts.Port), sshClientConfig)
75-
76-
if err != nil {
77-
return nil, errwrap.Wrap(err, "error creating ssh client")
77+
if err != nil || sshClient == nil {
78+
return nil, noop, errwrap.Wrap(err, "error creating ssh client")
7879
}
7980
_, _, err = sshClient.SendRequest("keepalive", false, nil)
8081
if err != nil {
81-
return nil, err
82+
return nil, sshClient.Close, err
8283
}
8384

8485
sftpClient, err := sftp.NewClient(sshClient,
@@ -87,7 +88,7 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
8788
sftp.MaxConcurrentRequestsPerFile(64),
8889
)
8990
if err != nil {
90-
return nil, errwrap.Wrap(err, "error creating sftp client")
91+
return nil, sshClient.Close, errwrap.Wrap(err, "error creating sftp client")
9192
}
9293

9394
return &sshStorage{
@@ -98,7 +99,7 @@ func NewStorageBackend(opts Config, logFunc storage.Log) (storage.Backend, error
9899
client: sshClient,
99100
sftpClient: sftpClient,
100101
hostName: opts.HostName,
101-
}, nil
102+
}, sshClient.Close, nil
102103
}
103104

104105
// Name returns the name of the storage backend

0 commit comments

Comments
 (0)