Skip to content

Commit 529f082

Browse files
committed
chore: Add sftp reconnections
Signed-off-by: Javier Aliaga <[email protected]>
1 parent 319c986 commit 529f082

File tree

6 files changed

+311
-135
lines changed

6 files changed

+311
-135
lines changed

bindings/sftp/integration/README.md renamed to bindings/sftp/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ curl -X POST -H "Content-Type: application/json" \
3636
-d '{"type":"timeout", "attributes":{"timeout":1000}}'
3737

3838
# Remove all toxics
39-
curl -X DELETE http://localhost:8474/proxies/sftp/toxics
39+
curl -X GET http://localhost:8474/proxies/sftp/toxics
4040
```
4141

4242
See the [Toxiproxy documentation](https://github.com/Shopify/toxiproxy) for more information on available toxics and configuration options.

bindings/sftp/integration/docker-compose.yaml renamed to bindings/sftp/docker-compose.yaml

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
1-
version: '3.8'
2-
31
services:
42
toxiproxy:
53
image: ghcr.io/shopify/toxiproxy:2.5.0
64
ports:
75
- "8474:8474" # Toxiproxy API
8-
- "2222:2222" # Proxied SFTP port
6+
- "2223:2223" # Proxied SFTP port
97
environment:
108
- HOSTNAME=0.0.0.0
119
command: ["-host", "0.0.0.0"]
12-
volumes:
13-
- ./toxiproxy.json:/config/toxiproxy.json
1410
depends_on:
1511
- sftp
1612
networks:
1713
- sftp-network
1814

1915
sftp:
20-
build:
21-
context: .
22-
dockerfile: Dockerfile
16+
image:
17+
atmoz/sftp
2318
environment:
2419
- SFTP_USERS=foo:pass:1001:1001:upload
2520
volumes:
26-
- ./upload:/home/testuser/upload
27-
expose:
21+
- ./upload:/home/foo/upload
22+
ports:
2823
- "2222:22"
2924
networks:
3025
- sftp-network

bindings/sftp/sftp.go

Lines changed: 16 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"io"
99
"reflect"
10-
"sync"
1110

1211
sftpClient "github.com/pkg/sftp"
1312
"golang.org/x/crypto/ssh"
@@ -26,30 +25,9 @@ const (
2625

2726
// Sftp is a binding for file operations on sftp server.
2827
type Sftp struct {
29-
metadata *sftpMetadata
30-
logger logger.Logger
31-
sftpClient *sftpClient.Client
32-
sshClient *ssh.Client
33-
clientConfig *ssh.ClientConfig
34-
lock sync.RWMutex
35-
}
36-
37-
func (sftp *Sftp) Client() (*sftpClient.Client, error) {
38-
sftp.lock.RLock()
39-
current := sftp.sftpClient
40-
sftp.lock.RUnlock()
41-
42-
if current != nil {
43-
if _, err := current.Getwd(); err == nil {
44-
return current, nil
45-
}
46-
}
47-
48-
err := sftp.handleReconnection()
49-
if err != nil {
50-
return nil, err
51-
}
52-
return sftp.sftpClient, nil
28+
metadata *sftpMetadata
29+
logger logger.Logger
30+
c *Client
5331
}
5432

5533
// sftpMetadata defines the sftp metadata.
@@ -137,21 +115,12 @@ func (sftp *Sftp) Init(_ context.Context, metadata bindings.Metadata) error {
137115
HostKeyCallback: hostKeyCallback,
138116
}
139117

140-
sshClient, err := ssh.Dial("tcp", m.Address, config)
141-
if err != nil {
142-
return fmt.Errorf("sftp binding error: error create ssh client: %w", err)
143-
}
144-
145-
newSftpClient, err := sftpClient.NewClient(sshClient)
118+
sftp.metadata = m
119+
sftp.c, err = newClient(m.Address, config)
146120
if err != nil {
147-
_ = sshClient.Close()
148-
return fmt.Errorf("sftp binding error: error create sftp client: %w", err)
121+
return fmt.Errorf("sftp binding error: create sftp client error: %w", err)
149122
}
150123

151-
sftp.clientConfig = config
152-
sftp.metadata = m
153-
sftp.sftpClient = newSftpClient
154-
155124
return nil
156125
}
157126

@@ -185,19 +154,9 @@ func (sftp *Sftp) create(_ context.Context, req *bindings.InvokeRequest) (*bindi
185154
return nil, fmt.Errorf("sftp binding error: %w", err)
186155
}
187156

188-
dir, fileName := sftpClient.Split(path)
189-
190-
c, err := sftp.Client()
191-
if err != nil {
192-
return nil, fmt.Errorf("sftp binding error: error getting sftp client: %w", err)
193-
}
157+
c := sftp.c
194158

195-
err = c.MkdirAll(dir)
196-
if err != nil {
197-
return nil, fmt.Errorf("sftp binding error: error create dir %s: %w", dir, err)
198-
}
199-
200-
file, err := c.Create(path)
159+
file, fileName, err := c.create(path)
201160
if err != nil {
202161
return nil, fmt.Errorf("sftp binding error: error create file %s: %w", path, err)
203162
}
@@ -240,12 +199,9 @@ func (sftp *Sftp) list(_ context.Context, req *bindings.InvokeRequest) (*binding
240199
return nil, fmt.Errorf("sftp binding error: %w", err)
241200
}
242201

243-
c, err := sftp.Client()
244-
if err != nil {
245-
return nil, fmt.Errorf("sftp binding error: error getting sftp client: %w", err)
246-
}
202+
c := sftp.c
247203

248-
files, err := c.ReadDir(path)
204+
files, err := c.list(path)
249205
if err != nil {
250206
return nil, fmt.Errorf("sftp binding error: error read dir %s: %w", path, err)
251207
}
@@ -280,12 +236,9 @@ func (sftp *Sftp) get(_ context.Context, req *bindings.InvokeRequest) (*bindings
280236
return nil, fmt.Errorf("sftp binding error: %w", err)
281237
}
282238

283-
c, err := sftp.Client()
284-
if err != nil {
285-
return nil, fmt.Errorf("sftp binding error: error getting sftp client: %w", err)
286-
}
239+
c := sftp.c
287240

288-
file, err := c.Open(path)
241+
file, err := c.get(path)
289242
if err != nil {
290243
return nil, fmt.Errorf("sftp binding error: error open file %s: %w", path, err)
291244
}
@@ -311,11 +264,9 @@ func (sftp *Sftp) delete(_ context.Context, req *bindings.InvokeRequest) (*bindi
311264
return nil, fmt.Errorf("sftp binding error: %w", err)
312265
}
313266

314-
c, err := sftp.Client()
315-
if err != nil {
316-
return nil, fmt.Errorf("sftp binding error: error getting sftp client: %w", err)
317-
}
318-
err = c.Remove(path)
267+
c := sftp.c
268+
269+
err = c.delete(path)
319270
if err != nil {
320271
return nil, fmt.Errorf("sftp binding error: error remove file %s: %w", path, err)
321272
}
@@ -339,9 +290,7 @@ func (sftp *Sftp) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bin
339290
}
340291

341292
func (sftp *Sftp) Close() error {
342-
sftp.lock.Lock()
343-
defer sftp.lock.Unlock()
344-
return sftp.sftpClient.Close()
293+
return sftp.c.Close()
345294
}
346295

347296
func (metadata sftpMetadata) getPath(requestMetadata map[string]string) (path string, err error) {
@@ -375,41 +324,3 @@ func (sftp *Sftp) GetComponentMetadata() (metadataInfo metadata.MetadataMap) {
375324
metadata.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo, metadata.BindingType)
376325
return
377326
}
378-
379-
func (sftp *Sftp) handleReconnection() error {
380-
sftp.lock.Lock()
381-
defer sftp.lock.Unlock()
382-
383-
// Re-check after acquiring the write lock
384-
if sftp.sftpClient != nil {
385-
if _, err := sftp.sftpClient.Getwd(); err == nil {
386-
return nil
387-
}
388-
_ = sftp.sftpClient.Close()
389-
sftp.sftpClient = nil
390-
}
391-
if sftp.sshClient != nil {
392-
_ = sftp.sshClient.Close()
393-
sftp.sshClient = nil
394-
}
395-
396-
if sftp.metadata == nil || sftp.clientConfig == nil {
397-
return fmt.Errorf("sftp binding error: client not initialized")
398-
}
399-
400-
sshClient, err := ssh.Dial("tcp", sftp.metadata.Address, sftp.clientConfig)
401-
if err != nil {
402-
return fmt.Errorf("sftp binding error: error create ssh client: %w", err)
403-
}
404-
405-
newSftpClient, err := sftpClient.NewClient(sshClient)
406-
if err != nil {
407-
_ = sshClient.Close()
408-
return fmt.Errorf("sftp binding error: error create sftp client: %w", err)
409-
}
410-
411-
sftp.sshClient = sshClient
412-
sftp.sftpClient = newSftpClient
413-
414-
return nil
415-
}

0 commit comments

Comments
 (0)