Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions bindings/sftp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# SFTP with Toxiproxy Setup

This setup includes an SFTP server and Toxiproxy for simulating network conditions during testing.

## Services

- **SFTP**: A simple SFTP server with a test user
- **Toxiproxy**: A TCP proxy that allows simulating network conditions like latency, bandwidth restrictions, and connection failures

## Getting Started

1. Start the services:

```bash
docker-compose up -d
```

2. Connect to SFTP via the Toxiproxy port:

```bash
sftp -P 2222 foo@localhost
# Password: pass
```

3. Control Toxiproxy via its API (port 8474):

```bash
# Add 1000ms latency to SFTP connections
curl -X POST -H "Content-Type: application/json" \
http://localhost:8474/proxies/sftp/toxics \
-d '{"type":"latency", "attributes":{"latency":1000, "jitter":0}}'

# Simulate connection timeout
curl -X POST -H "Content-Type: application/json" \
http://localhost:8474/proxies/sftp/toxics \
-d '{"type":"timeout", "attributes":{"timeout":1000}}'

# Remove all toxics
curl -X GET http://localhost:8474/proxies/sftp/toxics
```

See the [Toxiproxy documentation](https://github.com/Shopify/toxiproxy) for more information on available toxics and configuration options.
29 changes: 29 additions & 0 deletions bindings/sftp/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
services:
toxiproxy:
image: ghcr.io/shopify/toxiproxy:2.5.0
ports:
- "8474:8474" # Toxiproxy API
- "2223:2223" # Proxied SFTP port
environment:
- HOSTNAME=0.0.0.0
command: ["-host", "0.0.0.0"]
depends_on:
- sftp
networks:
- sftp-network

sftp:
image:
atmoz/sftp
environment:
- SFTP_USERS=foo:pass:1001:1001:upload
volumes:
- ./upload:/home/foo/upload
ports:
- "2222:22"
networks:
- sftp-network

networks:
sftp-network:
driver: bridge
42 changes: 18 additions & 24 deletions bindings/sftp/sftp.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ const (

// Sftp is a binding for file operations on sftp server.
type Sftp struct {
metadata *sftpMetadata
logger logger.Logger
sftpClient *sftpClient.Client
metadata *sftpMetadata
logger logger.Logger
c *Client
}

// sftpMetadata defines the sftp metadata.
Expand Down Expand Up @@ -115,19 +115,12 @@ func (sftp *Sftp) Init(_ context.Context, metadata bindings.Metadata) error {
HostKeyCallback: hostKeyCallback,
}

sshClient, err := ssh.Dial("tcp", m.Address, config)
if err != nil {
return fmt.Errorf("sftp binding error: error create ssh client: %w", err)
}

newSftpClient, err := sftpClient.NewClient(sshClient)
sftp.metadata = m
sftp.c, err = newClient(m.Address, config)
if err != nil {
return fmt.Errorf("sftp binding error: error create sftp client: %w", err)
return fmt.Errorf("sftp binding error: create sftp client error: %w", err)
}

sftp.metadata = m
sftp.sftpClient = newSftpClient

return nil
}

Expand Down Expand Up @@ -161,14 +154,9 @@ func (sftp *Sftp) create(_ context.Context, req *bindings.InvokeRequest) (*bindi
return nil, fmt.Errorf("sftp binding error: %w", err)
}

dir, fileName := sftpClient.Split(path)
c := sftp.c

err = sftp.sftpClient.MkdirAll(dir)
if err != nil {
return nil, fmt.Errorf("sftp binding error: error create dir %s: %w", dir, err)
}

file, err := sftp.sftpClient.Create(path)
file, fileName, err := c.create(path)
if err != nil {
return nil, fmt.Errorf("sftp binding error: error create file %s: %w", path, err)
}
Expand Down Expand Up @@ -211,7 +199,9 @@ func (sftp *Sftp) list(_ context.Context, req *bindings.InvokeRequest) (*binding
return nil, fmt.Errorf("sftp binding error: %w", err)
}

files, err := sftp.sftpClient.ReadDir(path)
c := sftp.c

files, err := c.list(path)
if err != nil {
return nil, fmt.Errorf("sftp binding error: error read dir %s: %w", path, err)
}
Expand Down Expand Up @@ -246,7 +236,9 @@ func (sftp *Sftp) get(_ context.Context, req *bindings.InvokeRequest) (*bindings
return nil, fmt.Errorf("sftp binding error: %w", err)
}

file, err := sftp.sftpClient.Open(path)
c := sftp.c

file, err := c.get(path)
if err != nil {
return nil, fmt.Errorf("sftp binding error: error open file %s: %w", path, err)
}
Expand All @@ -272,7 +264,9 @@ func (sftp *Sftp) delete(_ context.Context, req *bindings.InvokeRequest) (*bindi
return nil, fmt.Errorf("sftp binding error: %w", err)
}

err = sftp.sftpClient.Remove(path)
c := sftp.c

err = c.delete(path)
if err != nil {
return nil, fmt.Errorf("sftp binding error: error remove file %s: %w", path, err)
}
Expand All @@ -296,7 +290,7 @@ func (sftp *Sftp) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bin
}

func (sftp *Sftp) Close() error {
return sftp.sftpClient.Close()
return sftp.c.Close()
}

func (metadata sftpMetadata) getPath(requestMetadata map[string]string) (path string, err error) {
Expand Down
Loading