Skip to content

Commit

Permalink
refactor: passing ssh client to docker client methods (#762)
Browse files Browse the repository at this point in the history
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 <toma.puljak@hotmail.com>
  • Loading branch information
Tpuljak authored Jul 12, 2024
1 parent 7177dac commit 1a69d94
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 124 deletions.
1 change: 1 addition & 0 deletions pkg/cmd/workspace/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package workspace

import (
"context"
"errors"
"fmt"
"net/url"
"os"
Expand Down
18 changes: 9 additions & 9 deletions pkg/docker/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ import (
)

type CreateProjectOptions struct {
Project *workspace.Project
ProjectDir string
Cr *containerregistry.ContainerRegistry
LogWriter io.Writer
Gpc *gitprovider.GitProviderConfig
SshSessionConfig *ssh.SessionConfig
Project *workspace.Project
ProjectDir string
Cr *containerregistry.ContainerRegistry
LogWriter io.Writer
Gpc *gitprovider.GitProviderConfig
SshClient *ssh.Client
}

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

DestroyProject(project *workspace.Project) error
DestroyWorkspace(workspace *workspace.Workspace) error
DestroyProject(project *workspace.Project, projectDir string, sshClient *ssh.Client) error
DestroyWorkspace(workspace *workspace.Workspace, workspaceDir string, sshClient *ssh.Client) error

StartProject(opts *CreateProjectOptions, daytonaDownloadUrl string) error
StopProject(project *workspace.Project, logWriter io.Writer) error
Expand Down
45 changes: 28 additions & 17 deletions pkg/docker/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"io"
"os"
"os/user"
"path/filepath"
"strings"
Expand All @@ -23,8 +24,15 @@ import (
log "github.com/sirupsen/logrus"
)

func (d *DockerClient) CreateWorkspace(workspace *workspace.Workspace, logWriter io.Writer) error {
return nil
func (d *DockerClient) CreateWorkspace(workspace *workspace.Workspace, workspaceDir string, logWriter io.Writer, sshClient *ssh.Client) error {
var err error
if sshClient == nil {
err = os.MkdirAll(workspaceDir, 0755)
} else {
err = sshClient.Exec(fmt.Sprintf("mkdir -p %s", workspaceDir), nil)
}

return err
}

func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error {
Expand All @@ -34,28 +42,19 @@ func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error {
return err
}

var sshClient *ssh.Client
if opts.SshSessionConfig != nil {
sshClient, err = ssh.NewClient(opts.SshSessionConfig)
if err != nil {
return err
}
defer sshClient.Close()
}

err = d.cloneProjectRepository(opts, sshClient)
err = d.cloneProjectRepository(opts)
if err != nil {
return err
}

builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, sshClient)
builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, opts.SshClient)
if err != nil {
return err
}

switch builderType {
case detect.BuilderTypeDevcontainer:
_, err := d.createProjectFromDevcontainer(opts, true, sshClient)
_, err := d.createProjectFromDevcontainer(opts, true)
return err
case detect.BuilderTypeImage:
return d.createProjectFromImage(opts)
Expand All @@ -64,9 +63,21 @@ func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error {
}
}

func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions, sshClient *ssh.Client) error {
func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions) error {
ctx := context.Background()

if opts.SshClient != nil {
err := opts.SshClient.Exec(fmt.Sprintf("mkdir -p %s", opts.ProjectDir), nil)
if err != nil {
return err
}
} else {
err := os.MkdirAll(opts.ProjectDir, 0755)
if err != nil {
return err
}
}

var auth *http.BasicAuth
if opts.Gpc != nil {
auth = &http.BasicAuth{
Expand Down Expand Up @@ -128,8 +139,8 @@ func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions, sshCli
newUid := currentUser.Uid
newGid := currentUser.Gid

if sshClient != nil {
newUid, newGid, err = sshClient.GetUserUidGid()
if opts.SshClient != nil {
newUid, newGid, err = opts.SshClient.GetUserUidGid()
if err != nil {
return err
}
Expand Down
28 changes: 14 additions & 14 deletions pkg/docker/create_devcontainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type DevcontainerPaths struct {
TargetConfigFilePath string
}

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

paths := d.getDevcontainerPaths(opts)

if sshClient != nil {
err = sshClient.Exec(fmt.Sprintf("mkdir -p %s", paths.OverridesDir), opts.LogWriter)
if opts.SshClient != nil {
err = opts.SshClient.Exec(fmt.Sprintf("mkdir -p %s", paths.OverridesDir), opts.LogWriter)
if err != nil {
return "", err
}
Expand All @@ -61,7 +61,7 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
}
}

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

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

composeFileContent, err := d.getRemoteComposeContent(opts, paths, socketForwardId, composeFilePath)
Expand Down Expand Up @@ -156,13 +156,13 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
return "", err
}

if sshClient != nil {
if opts.SshClient != nil {
err = os.RemoveAll(composeFilePath)
if err != nil {
opts.LogWriter.Write([]byte(fmt.Sprintf("Error removing override compose file: %v\n", err)))
return "", err
}
res, err := sshClient.WriteFile(string(overrideComposeContent), filepath.Join(paths.OverridesDir, "daytona-compose-override.yml"))
res, err := opts.SshClient.WriteFile(string(overrideComposeContent), filepath.Join(paths.OverridesDir, "daytona-compose-override.yml"))
if err != nil {
opts.LogWriter.Write([]byte(fmt.Sprintf("Error writing override compose file: %s\n", string(res))))
return "", err
Expand All @@ -186,8 +186,8 @@ func (d *DockerClient) createProjectFromDevcontainer(opts *CreateProjectOptions,
return "", err
}

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

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

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

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

env := os.Environ()
if sshClient != nil {
if opts.SshClient != nil {
var err error
env, err = sshClient.GetEnv(nil)
env, err = opts.SshClient.GetEnv(nil)
if err != nil {
return "", nil, err
}
Expand Down Expand Up @@ -544,7 +544,7 @@ func (d *DockerClient) execInContainer(cmd string, opts *CreateProjectOptions, p
}

func (d *DockerClient) getRemoteComposeContent(opts *CreateProjectOptions, paths DevcontainerPaths, socketForwardId, composePath string) (string, error) {
if opts.SshSessionConfig == nil {
if opts.SshClient == nil {
return "", nil
}

Expand Down
19 changes: 12 additions & 7 deletions pkg/docker/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ import (
)

func (s *DockerClientTestSuite) TestCreateWorkspace() {
err := s.dockerClient.CreateWorkspace(workspace1, nil)
workspaceDir := s.T().TempDir()

err := s.dockerClient.CreateWorkspace(workspace1, workspaceDir, nil, nil)
require.Nil(s.T(), err)

_, err = os.Stat(workspaceDir)
require.Nil(s.T(), err)
}

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

err := s.dockerClient.CreateProject(&docker.CreateProjectOptions{
Project: project1,
ProjectDir: projectDir,
Cr: nil,
LogWriter: nil,
Gpc: nil,
SshSessionConfig: nil,
Project: project1,
ProjectDir: projectDir,
Cr: nil,
LogWriter: nil,
Gpc: nil,
SshClient: nil,
})
require.Nil(s.T(), err)
}
24 changes: 20 additions & 4 deletions pkg/docker/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,34 @@ package docker

import (
"context"
"fmt"
"os"

"github.com/daytonaio/daytona/pkg/ssh"
"github.com/daytonaio/daytona/pkg/workspace"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)

func (d *DockerClient) DestroyWorkspace(workspace *workspace.Workspace) error {
return nil
func (d *DockerClient) DestroyWorkspace(workspace *workspace.Workspace, workspaceDir string, sshClient *ssh.Client) error {
if sshClient == nil {
return os.RemoveAll(workspaceDir)
} else {
return sshClient.Exec(fmt.Sprintf("rm -rf %s", workspaceDir), nil)
}
}

func (d *DockerClient) DestroyProject(project *workspace.Project) error {
return d.removeProjectContainer(project)
func (d *DockerClient) DestroyProject(project *workspace.Project, projectDir string, sshClient *ssh.Client) error {
err := d.removeProjectContainer(project)
if err != nil {
return err
}

if sshClient == nil {
return os.RemoveAll(projectDir)
} else {
return sshClient.Exec(fmt.Sprintf("rm -rf %s", projectDir), nil)
}
}

func (d *DockerClient) removeProjectContainer(project *workspace.Project) error {
Expand Down
16 changes: 14 additions & 2 deletions pkg/docker/destroy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@
package docker_test

import (
"os"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

func (s *DockerClientTestSuite) TestDestroyWorkspace() {
err := s.dockerClient.DestroyWorkspace(workspace1)
workspaceDir := s.T().TempDir()

err := s.dockerClient.DestroyWorkspace(workspace1, workspaceDir, nil)
require.Nil(s.T(), err)

_, err = os.Stat(workspaceDir)
require.True(s.T(), os.IsNotExist(err))
}

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

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

err := s.dockerClient.DestroyProject(project1)
projectDir := s.T().TempDir()

err := s.dockerClient.DestroyProject(project1, projectDir, nil)
require.Nil(s.T(), err)

_, err = os.Stat(projectDir)
require.True(s.T(), os.IsNotExist(err))
}
14 changes: 2 additions & 12 deletions pkg/docker/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/daytonaio/daytona/pkg/builder/detect"
"github.com/daytonaio/daytona/pkg/provider/util"
"github.com/daytonaio/daytona/pkg/ssh"
"github.com/daytonaio/daytona/pkg/workspace"
"github.com/docker/docker/api/types"
)
Expand All @@ -20,24 +19,15 @@ func (d *DockerClient) StartProject(opts *CreateProjectOptions, daytonaDownloadU
var err error
containerUser := opts.Project.User

var sshClient *ssh.Client
if opts.SshSessionConfig != nil {
sshClient, err = ssh.NewClient(opts.SshSessionConfig)
if err != nil {
return err
}
defer sshClient.Close()
}

builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, sshClient)
builderType, err := detect.DetectProjectBuilderType(opts.Project, opts.ProjectDir, opts.SshClient)
if err != nil {
return err
}

switch builderType {
case detect.BuilderTypeDevcontainer:
var remoteUser RemoteUser
remoteUser, err = d.startDevcontainerProject(opts, sshClient)
remoteUser, err = d.startDevcontainerProject(opts)
containerUser = string(remoteUser)
case detect.BuilderTypeImage:
err = d.startImageProject(opts)
Expand Down
5 changes: 2 additions & 3 deletions pkg/docker/start_devcontainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@ import (
"path"
"strings"

"github.com/daytonaio/daytona/pkg/ssh"
"github.com/docker/docker/api/types/mount"
)

func (d *DockerClient) startDevcontainerProject(opts *CreateProjectOptions, sshClient *ssh.Client) (RemoteUser, error) {
func (d *DockerClient) startDevcontainerProject(opts *CreateProjectOptions) (RemoteUser, error) {
go func() {
err := d.runDevcontainerUserCommands(opts)
if err != nil {
opts.LogWriter.Write([]byte(fmt.Sprintf("Error running devcontainer user commands: %s\n", err)))
}
}()

return d.createProjectFromDevcontainer(opts, false, sshClient)
return d.createProjectFromDevcontainer(opts, false)
}

func (d *DockerClient) runDevcontainerUserCommands(opts *CreateProjectOptions) error {
Expand Down
Loading

0 comments on commit 1a69d94

Please sign in to comment.