Skip to content

Commit 1a69d94

Browse files
authored
refactor: passing ssh client to docker client methods (#762)
This way the caller is responsible for initializing the client. This also opens up possibility to initialize the client with tailscale. BREAKING CHANGE: since the provider interface changed, provider will need to be updated. Signed-off-by: Toma Puljak <[email protected]>
1 parent 7177dac commit 1a69d94

11 files changed

+140
-124
lines changed

pkg/cmd/workspace/create.go

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package workspace
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"net/url"
1011
"os"

pkg/docker/client.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ import (
1919
)
2020

2121
type CreateProjectOptions struct {
22-
Project *workspace.Project
23-
ProjectDir string
24-
Cr *containerregistry.ContainerRegistry
25-
LogWriter io.Writer
26-
Gpc *gitprovider.GitProviderConfig
27-
SshSessionConfig *ssh.SessionConfig
22+
Project *workspace.Project
23+
ProjectDir string
24+
Cr *containerregistry.ContainerRegistry
25+
LogWriter io.Writer
26+
Gpc *gitprovider.GitProviderConfig
27+
SshClient *ssh.Client
2828
}
2929

3030
type IDockerClient interface {
3131
CreateProject(opts *CreateProjectOptions) error
32-
CreateWorkspace(workspace *workspace.Workspace, logWriter io.Writer) error
32+
CreateWorkspace(workspace *workspace.Workspace, workspaceDir string, logWriter io.Writer, sshClient *ssh.Client) error
3333

34-
DestroyProject(project *workspace.Project) error
35-
DestroyWorkspace(workspace *workspace.Workspace) error
34+
DestroyProject(project *workspace.Project, projectDir string, sshClient *ssh.Client) error
35+
DestroyWorkspace(workspace *workspace.Workspace, workspaceDir string, sshClient *ssh.Client) error
3636

3737
StartProject(opts *CreateProjectOptions, daytonaDownloadUrl string) error
3838
StopProject(project *workspace.Project, logWriter io.Writer) error

pkg/docker/create.go

+28-17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"fmt"
99
"io"
10+
"os"
1011
"os/user"
1112
"path/filepath"
1213
"strings"
@@ -23,8 +24,15 @@ import (
2324
log "github.com/sirupsen/logrus"
2425
)
2526

26-
func (d *DockerClient) CreateWorkspace(workspace *workspace.Workspace, logWriter io.Writer) error {
27-
return nil
27+
func (d *DockerClient) CreateWorkspace(workspace *workspace.Workspace, workspaceDir string, logWriter io.Writer, sshClient *ssh.Client) error {
28+
var err error
29+
if sshClient == nil {
30+
err = os.MkdirAll(workspaceDir, 0755)
31+
} else {
32+
err = sshClient.Exec(fmt.Sprintf("mkdir -p %s", workspaceDir), nil)
33+
}
34+
35+
return err
2836
}
2937

3038
func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error {
@@ -34,28 +42,19 @@ func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error {
3442
return err
3543
}
3644

37-
var sshClient *ssh.Client
38-
if opts.SshSessionConfig != nil {
39-
sshClient, err = ssh.NewClient(opts.SshSessionConfig)
40-
if err != nil {
41-
return err
42-
}
43-
defer sshClient.Close()
44-
}
45-
46-
err = d.cloneProjectRepository(opts, sshClient)
45+
err = d.cloneProjectRepository(opts)
4746
if err != nil {
4847
return err
4948
}
5049

51-
builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, sshClient)
50+
builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, opts.SshClient)
5251
if err != nil {
5352
return err
5453
}
5554

5655
switch builderType {
5756
case detect.BuilderTypeDevcontainer:
58-
_, err := d.createProjectFromDevcontainer(opts, true, sshClient)
57+
_, err := d.createProjectFromDevcontainer(opts, true)
5958
return err
6059
case detect.BuilderTypeImage:
6160
return d.createProjectFromImage(opts)
@@ -64,9 +63,21 @@ func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error {
6463
}
6564
}
6665

67-
func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions, sshClient *ssh.Client) error {
66+
func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions) error {
6867
ctx := context.Background()
6968

69+
if opts.SshClient != nil {
70+
err := opts.SshClient.Exec(fmt.Sprintf("mkdir -p %s", opts.ProjectDir), nil)
71+
if err != nil {
72+
return err
73+
}
74+
} else {
75+
err := os.MkdirAll(opts.ProjectDir, 0755)
76+
if err != nil {
77+
return err
78+
}
79+
}
80+
7081
var auth *http.BasicAuth
7182
if opts.Gpc != nil {
7283
auth = &http.BasicAuth{
@@ -128,8 +139,8 @@ func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions, sshCli
128139
newUid := currentUser.Uid
129140
newGid := currentUser.Gid
130141

131-
if sshClient != nil {
132-
newUid, newGid, err = sshClient.GetUserUidGid()
142+
if opts.SshClient != nil {
143+
newUid, newGid, err = opts.SshClient.GetUserUidGid()
133144
if err != nil {
134145
return err
135146
}

pkg/docker/create_devcontainer.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type DevcontainerPaths struct {
3939
TargetConfigFilePath string
4040
}
4141

42-
func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions, prebuild bool, sshClient *ssh.Client) (RemoteUser, error) {
42+
func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions, prebuild bool) (RemoteUser, error) {
4343
socketForwardId, err := d.ensureDockerSockForward(opts.LogWriter)
4444
if err != nil {
4545
return "", err
@@ -49,8 +49,8 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
4949

5050
paths := d.getDevcontainerPaths(opts)
5151

52-
if sshClient != nil {
53-
err = sshClient.Exec(fmt.Sprintf("mkdir -p %s", paths.OverridesDir), opts.LogWriter)
52+
if opts.SshClient != nil {
53+
err = opts.SshClient.Exec(fmt.Sprintf("mkdir -p %s", paths.OverridesDir), opts.LogWriter)
5454
if err != nil {
5555
return "", err
5656
}
@@ -61,7 +61,7 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
6161
}
6262
}
6363

64-
rawConfig, config, err := d.readDevcontainerConfig(opts, paths, socketForwardId, sshClient)
64+
rawConfig, config, err := d.readDevcontainerConfig(opts, paths, socketForwardId)
6565
if err != nil {
6666
return "", err
6767
}
@@ -114,7 +114,7 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
114114
if _, ok := devcontainerConfig["dockerComposeFile"]; ok {
115115
composeFilePath := devcontainerConfig["dockerComposeFile"].(string)
116116

117-
if opts.SshSessionConfig != nil {
117+
if opts.SshClient != nil {
118118
composeFilePath = path.Join(opts.ProjectDir, filepath.Dir(opts.Project.Build.Devcontainer.DevContainerFilePath), composeFilePath)
119119

120120
composeFileContent, err := d.getRemoteComposeContent(opts, paths, socketForwardId, composeFilePath)
@@ -156,13 +156,13 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
156156
return "", err
157157
}
158158

159-
if sshClient != nil {
159+
if opts.SshClient != nil {
160160
err = os.RemoveAll(composeFilePath)
161161
if err != nil {
162162
opts.LogWriter.Write([]byte(fmt.Sprintf("Error removing override compose file: %v\n", err)))
163163
return "", err
164164
}
165-
res, err := sshClient.WriteFile(string(overrideComposeContent), filepath.Join(paths.OverridesDir, "daytona-compose-override.yml"))
165+
res, err := opts.SshClient.WriteFile(string(overrideComposeContent), filepath.Join(paths.OverridesDir, "daytona-compose-override.yml"))
166166
if err != nil {
167167
opts.LogWriter.Write([]byte(fmt.Sprintf("Error writing override compose file: %s\n", string(res))))
168168
return "", err
@@ -186,8 +186,8 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
186186
return "", err
187187
}
188188

189-
if sshClient != nil {
190-
res, err := sshClient.WriteFile(string(configString), path.Join(paths.OverridesDir, "devcontainer.json"))
189+
if opts.SshClient != nil {
190+
res, err := opts.SshClient.WriteFile(string(configString), path.Join(paths.OverridesDir, "devcontainer.json"))
191191
if err != nil {
192192
opts.LogWriter.Write([]byte(fmt.Sprintf("Error writing override compose file: %s\n", string(res))))
193193
return "", err
@@ -216,7 +216,7 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
216216

217217
cmd := []string{"-c", strings.Join(devcontainerCmd, " ")}
218218

219-
err = d.runInitializeCommand(config.MergedConfiguration.InitializeCommand, opts.LogWriter, sshClient)
219+
err = d.runInitializeCommand(config.MergedConfiguration.InitializeCommand, opts.LogWriter, opts.SshClient)
220220
if err != nil {
221221
return "", err
222222
}
@@ -338,13 +338,13 @@ func (d *DockerClient) ensureDockerSockForward(logWriter io.Writer) (string, err
338338
return c.ID, d.apiClient.ContainerStart(ctx, dockerSockForwardContainer, container.StartOptions{})
339339
}
340340

341-
func (d *DockerClient) readDevcontainerConfig(opts *CreateProjectOptions, paths DevcontainerPaths, socketForwardId string, sshClient *ssh.Client) (string, *devcontainer.Root, error) {
341+
func (d *DockerClient) readDevcontainerConfig(opts *CreateProjectOptions, paths DevcontainerPaths, socketForwardId string) (string, *devcontainer.Root, error) {
342342
opts.LogWriter.Write([]byte("Reading devcontainer configuration...\n"))
343343

344344
env := os.Environ()
345-
if sshClient != nil {
345+
if opts.SshClient != nil {
346346
var err error
347-
env, err = sshClient.GetEnv(nil)
347+
env, err = opts.SshClient.GetEnv(nil)
348348
if err != nil {
349349
return "", nil, err
350350
}
@@ -544,7 +544,7 @@ func (d *DockerClient) execInContainer(cmd string, opts *CreateProjectOptions, p
544544
}
545545

546546
func (d *DockerClient) getRemoteComposeContent(opts *CreateProjectOptions, paths DevcontainerPaths, socketForwardId, composePath string) (string, error) {
547-
if opts.SshSessionConfig == nil {
547+
if opts.SshClient == nil {
548548
return "", nil
549549
}
550550

pkg/docker/create_test.go

+12-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import (
2424
)
2525

2626
func (s *DockerClientTestSuite) TestCreateWorkspace() {
27-
err := s.dockerClient.CreateWorkspace(workspace1, nil)
27+
workspaceDir := s.T().TempDir()
28+
29+
err := s.dockerClient.CreateWorkspace(workspace1, workspaceDir, nil, nil)
30+
require.Nil(s.T(), err)
31+
32+
_, err = os.Stat(workspaceDir)
2833
require.Nil(s.T(), err)
2934
}
3035

@@ -94,12 +99,12 @@ func (s *DockerClientTestSuite) TestCreateProject() {
9499
).Return(container.CreateResponse{ID: "123"}, nil)
95100

96101
err := s.dockerClient.CreateProject(&docker.CreateProjectOptions{
97-
Project: project1,
98-
ProjectDir: projectDir,
99-
Cr: nil,
100-
LogWriter: nil,
101-
Gpc: nil,
102-
SshSessionConfig: nil,
102+
Project: project1,
103+
ProjectDir: projectDir,
104+
Cr: nil,
105+
LogWriter: nil,
106+
Gpc: nil,
107+
SshClient: nil,
103108
})
104109
require.Nil(s.T(), err)
105110
}

pkg/docker/destroy.go

+20-4
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,34 @@ package docker
55

66
import (
77
"context"
8+
"fmt"
9+
"os"
810

11+
"github.com/daytonaio/daytona/pkg/ssh"
912
"github.com/daytonaio/daytona/pkg/workspace"
1013
"github.com/docker/docker/api/types/container"
1114
"github.com/docker/docker/client"
1215
)
1316

14-
func (d *DockerClient) DestroyWorkspace(workspace *workspace.Workspace) error {
15-
return nil
17+
func (d *DockerClient) DestroyWorkspace(workspace *workspace.Workspace, workspaceDir string, sshClient *ssh.Client) error {
18+
if sshClient == nil {
19+
return os.RemoveAll(workspaceDir)
20+
} else {
21+
return sshClient.Exec(fmt.Sprintf("rm -rf %s", workspaceDir), nil)
22+
}
1623
}
1724

18-
func (d *DockerClient) DestroyProject(project *workspace.Project) error {
19-
return d.removeProjectContainer(project)
25+
func (d *DockerClient) DestroyProject(project *workspace.Project, projectDir string, sshClient *ssh.Client) error {
26+
err := d.removeProjectContainer(project)
27+
if err != nil {
28+
return err
29+
}
30+
31+
if sshClient == nil {
32+
return os.RemoveAll(projectDir)
33+
} else {
34+
return sshClient.Exec(fmt.Sprintf("rm -rf %s", projectDir), nil)
35+
}
2036
}
2137

2238
func (d *DockerClient) removeProjectContainer(project *workspace.Project) error {

pkg/docker/destroy_test.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@
44
package docker_test
55

66
import (
7+
"os"
8+
79
"github.com/docker/docker/api/types"
810
"github.com/docker/docker/api/types/container"
911
"github.com/stretchr/testify/mock"
1012
"github.com/stretchr/testify/require"
1113
)
1214

1315
func (s *DockerClientTestSuite) TestDestroyWorkspace() {
14-
err := s.dockerClient.DestroyWorkspace(workspace1)
16+
workspaceDir := s.T().TempDir()
17+
18+
err := s.dockerClient.DestroyWorkspace(workspace1, workspaceDir, nil)
1519
require.Nil(s.T(), err)
20+
21+
_, err = os.Stat(workspaceDir)
22+
require.True(s.T(), os.IsNotExist(err))
1623
}
1724

1825
func (s *DockerClientTestSuite) TestDestroyProject() {
@@ -33,6 +40,11 @@ func (s *DockerClientTestSuite) TestDestroyProject() {
3340

3441
s.mockClient.On("VolumeRemove", mock.Anything, s.dockerClient.GetProjectVolumeName(project1), true).Return(nil)
3542

36-
err := s.dockerClient.DestroyProject(project1)
43+
projectDir := s.T().TempDir()
44+
45+
err := s.dockerClient.DestroyProject(project1, projectDir, nil)
3746
require.Nil(s.T(), err)
47+
48+
_, err = os.Stat(projectDir)
49+
require.True(s.T(), os.IsNotExist(err))
3850
}

pkg/docker/start.go

+2-12
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111

1212
"github.com/daytonaio/daytona/pkg/builder/detect"
1313
"github.com/daytonaio/daytona/pkg/provider/util"
14-
"github.com/daytonaio/daytona/pkg/ssh"
1514
"github.com/daytonaio/daytona/pkg/workspace"
1615
"github.com/docker/docker/api/types"
1716
)
@@ -20,24 +19,15 @@ func (d *DockerClient) StartProject(opts *CreateProjectOptions, daytonaDownloadU
2019
var err error
2120
containerUser := opts.Project.User
2221

23-
var sshClient *ssh.Client
24-
if opts.SshSessionConfig != nil {
25-
sshClient, err = ssh.NewClient(opts.SshSessionConfig)
26-
if err != nil {
27-
return err
28-
}
29-
defer sshClient.Close()
30-
}
31-
32-
builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, sshClient)
22+
builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, opts.SshClient)
3323
if err != nil {
3424
return err
3525
}
3626

3727
switch builderType {
3828
case detect.BuilderTypeDevcontainer:
3929
var remoteUser RemoteUser
40-
remoteUser, err = d.startDevcontainerProject(opts, sshClient)
30+
remoteUser, err = d.startDevcontainerProject(opts)
4131
containerUser = string(remoteUser)
4232
case detect.BuilderTypeImage:
4333
err = d.startImageProject(opts)

pkg/docker/start_devcontainer.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,18 @@ import (
88
"path"
99
"strings"
1010

11-
"github.com/daytonaio/daytona/pkg/ssh"
1211
"github.com/docker/docker/api/types/mount"
1312
)
1413

15-
func (d *DockerClient) startDevcontainerProject(opts *CreateProjectOptions, sshClient *ssh.Client) (RemoteUser, error) {
14+
func (d *DockerClient) startDevcontainerProject(opts *CreateProjectOptions) (RemoteUser, error) {
1615
go func() {
1716
err := d.runDevcontainerUserCommands(opts)
1817
if err != nil {
1918
opts.LogWriter.Write([]byte(fmt.Sprintf("Error running devcontainer user commands: %s\n", err)))
2019
}
2120
}()
2221

23-
return d.createProjectFromDevcontainer(opts, false, sshClient)
22+
return d.createProjectFromDevcontainer(opts, false)
2423
}
2524

2625
func (d *DockerClient) runDevcontainerUserCommands(opts *CreateProjectOptions) error {

0 commit comments

Comments
 (0)