Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
7 changes: 6 additions & 1 deletion cmd/agent/workspace/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ func (cmd *BuildCmd) Run(ctx context.Context) error {
// initialize the workspace
cancelCtx, cancel := context.WithCancel(ctx)
defer cancel()
_, logger, credentialsDir, err := initWorkspace(cancelCtx, cancel, workspaceInfo, cmd.Debug, false)
_, logger, credentialsDir, err := initWorkspace(initWorkspaceParams{
ctx: cancelCtx,
workspaceInfo: workspaceInfo,
debug: cmd.Debug,
shouldInstallDaemon: false,
})
if err != nil {
return err
} else if credentialsDir != "" {
Expand Down
167 changes: 97 additions & 70 deletions cmd/agent/workspace/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/skevetter/devpod/pkg/agent"
"github.com/skevetter/devpod/pkg/agent/tunnel"
"github.com/skevetter/devpod/pkg/agent/tunnelserver"
"github.com/skevetter/devpod/pkg/binaries"
"github.com/skevetter/devpod/pkg/client/clientimplementation"
"github.com/skevetter/devpod/pkg/command"
"github.com/skevetter/devpod/pkg/credentials"
Expand All @@ -27,7 +26,7 @@ import (
"github.com/skevetter/devpod/pkg/dockercredentials"
"github.com/skevetter/devpod/pkg/dockerinstall"
"github.com/skevetter/devpod/pkg/extract"
provider2 "github.com/skevetter/devpod/pkg/provider"
"github.com/skevetter/devpod/pkg/provider"
"github.com/skevetter/devpod/pkg/util"
"github.com/skevetter/log"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -75,13 +74,12 @@ func (cmd *UpCmd) Run(ctx context.Context) error {
cancelCtx, cancel := context.WithCancel(ctx)
defer cancel()

tunnelClient, logger, credentialsDir, err := initWorkspace(
cancelCtx,
cancel,
workspaceInfo,
cmd.Debug,
cmd.shouldInstallDaemon(workspaceInfo),
)
tunnelClient, logger, credentialsDir, err := initWorkspace(initWorkspaceParams{
ctx: cancelCtx,
workspaceInfo: workspaceInfo,
debug: cmd.Debug,
shouldInstallDaemon: cmd.shouldInstallDaemon(workspaceInfo),
})
defer cmd.cleanupCredentials(credentialsDir)
if err != nil {
return cmd.handleInitError(err, workspaceInfo, logger)
Expand All @@ -94,10 +92,10 @@ func (cmd *UpCmd) Run(ctx context.Context) error {
return nil
}

func (cmd *UpCmd) loadWorkspaceInfo(ctx context.Context) (*provider2.AgentWorkspaceInfo, error) {
func (cmd *UpCmd) loadWorkspaceInfo(ctx context.Context) (*provider.AgentWorkspaceInfo, error) {
shouldExit, workspaceInfo, err := agent.WriteWorkspaceInfoAndDeleteOld(
cmd.WorkspaceInfo,
func(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) error {
func(workspaceInfo *provider.AgentWorkspaceInfo, log log.Logger) error {
return deleteWorkspace(ctx, workspaceInfo, log)
},
log.Default.ErrorStreamOnly(),
Expand All @@ -111,15 +109,15 @@ func (cmd *UpCmd) loadWorkspaceInfo(ctx context.Context) (*provider2.AgentWorksp
return workspaceInfo, nil
}

func (cmd *UpCmd) shouldPreventDaemonShutdown(workspaceInfo *provider2.AgentWorkspaceInfo) bool {
func (cmd *UpCmd) shouldPreventDaemonShutdown(workspaceInfo *provider.AgentWorkspaceInfo) bool {
return !workspaceInfo.CLIOptions.Platform.Enabled
}

func (cmd *UpCmd) shouldInstallDaemon(workspaceInfo *provider2.AgentWorkspaceInfo) bool {
func (cmd *UpCmd) shouldInstallDaemon(workspaceInfo *provider.AgentWorkspaceInfo) bool {
return !workspaceInfo.CLIOptions.Platform.Enabled && !workspaceInfo.CLIOptions.DisableDaemon
}

func (cmd *UpCmd) handleInitError(err error, workspaceInfo *provider2.AgentWorkspaceInfo, logger log.Logger) error {
func (cmd *UpCmd) handleInitError(err error, workspaceInfo *provider.AgentWorkspaceInfo, logger log.Logger) error {
if logger == nil {
logger = log.Discard
}
Expand All @@ -141,7 +139,12 @@ func (cmd *UpCmd) cleanupCredentials(credentialsDir string) {
}
}

func (cmd *UpCmd) up(ctx context.Context, workspaceInfo *provider2.AgentWorkspaceInfo, tunnelClient tunnel.TunnelClient, logger log.Logger) error {
func (cmd *UpCmd) up(
ctx context.Context,
workspaceInfo *provider.AgentWorkspaceInfo,
tunnelClient tunnel.TunnelClient,
logger log.Logger,
) error {
result, err := cmd.devPodUp(ctx, workspaceInfo, logger)
if err != nil {
return err
Expand All @@ -164,7 +167,11 @@ func (cmd *UpCmd) sendResult(ctx context.Context, result *config2.Result, tunnel
return nil
}

func (cmd *UpCmd) devPodUp(ctx context.Context, workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) (*config2.Result, error) {
func (cmd *UpCmd) devPodUp(
ctx context.Context,
workspaceInfo *provider.AgentWorkspaceInfo,
log log.Logger,
) (*config2.Result, error) {
runner, err := CreateRunner(workspaceInfo, log)
if err != nil {
return nil, err
Expand All @@ -176,11 +183,11 @@ func (cmd *UpCmd) devPodUp(ctx context.Context, workspaceInfo *provider2.AgentWo
}, workspaceInfo.InjectTimeout)
}

func CreateRunner(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) (devcontainer.Runner, error) {
func CreateRunner(workspaceInfo *provider.AgentWorkspaceInfo, log log.Logger) (devcontainer.Runner, error) {
return devcontainer.NewRunner(agent.ContainerDevPodHelperLocation, agent.DefaultAgentDownloadURL(), workspaceInfo, log)
}

func InitContentFolder(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) (bool, error) {
func InitContentFolder(workspaceInfo *provider.AgentWorkspaceInfo, log log.Logger) (bool, error) {
exists, err := contentFolderExists(workspaceInfo.ContentFolder, log)
if err != nil {
return false, err
Expand Down Expand Up @@ -228,7 +235,7 @@ func createContentFolder(path string, log log.Logger) error {
return nil
}

func downloadWorkspaceBinaries(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) error {
func downloadWorkspaceBinaries(workspaceInfo *provider.AgentWorkspaceInfo, log log.Logger) error {
binariesDir, err := agent.GetAgentBinariesDir(
workspaceInfo.Agent.DataPath,
workspaceInfo.Workspace.Context,
Expand All @@ -238,7 +245,7 @@ func downloadWorkspaceBinaries(workspaceInfo *provider2.AgentWorkspaceInfo, log
return fmt.Errorf("error getting workspace %s binaries dir: %w", workspaceInfo.Workspace.ID, err)
}

_, err = binaries.DownloadBinaries(workspaceInfo.Agent.Binaries, binariesDir, log)
_, err = provider.DownloadBinaries(workspaceInfo.Agent.Binaries, binariesDir, log)
if err != nil {
return fmt.Errorf("error downloading workspace %s binaries: %w", workspaceInfo.Workspace.ID, err)
}
Expand All @@ -248,8 +255,7 @@ func downloadWorkspaceBinaries(workspaceInfo *provider2.AgentWorkspaceInfo, log

type workspaceInitializer struct {
ctx context.Context
cancel context.CancelFunc
workspaceInfo *provider2.AgentWorkspaceInfo
workspaceInfo *provider.AgentWorkspaceInfo
debug bool
shouldInstallDaemon bool
tunnelClient tunnel.TunnelClient
Expand All @@ -258,49 +264,73 @@ type workspaceInitializer struct {
gitCredentialsHelper string
}

func initWorkspace(ctx context.Context, cancel context.CancelFunc, workspaceInfo *provider2.AgentWorkspaceInfo, debug, shouldInstallDaemon bool) (tunnel.TunnelClient, log.Logger, string, error) {
type initWorkspaceParams struct {
ctx context.Context
workspaceInfo *provider.AgentWorkspaceInfo
debug bool
shouldInstallDaemon bool
}

func initWorkspace(params initWorkspaceParams) (tunnel.TunnelClient, log.Logger, string, error) {
init := &workspaceInitializer{
ctx: ctx,
cancel: cancel,
workspaceInfo: workspaceInfo,
debug: debug,
shouldInstallDaemon: shouldInstallDaemon,
ctx: params.ctx,
workspaceInfo: params.workspaceInfo,
debug: params.debug,
shouldInstallDaemon: params.shouldInstallDaemon,
}

if err := init.initializeTunnel(); err != nil {
return nil, nil, "", err
if err := init.initialize(); err != nil {
return nil, init.logger, init.dockerCredentialsDir, err
}

if err := init.setupCredentials(); err != nil {
init.logger.Errorf("error retrieving docker / git credentials: %v", err)
return init.tunnelClient, init.logger, init.dockerCredentialsDir, nil
}

func (w *workspaceInitializer) initialize() error {
if err := w.initializeTunnel(); err != nil {
return err
}

dockerErrChan := init.installDockerAsync()
if err := w.setupCredentials(); err != nil {
w.logger.Warnf("failed to set up docker/git credentials (continuing without them): %v", err)
}

if err := init.prepareWorkspaceContent(); err != nil {
return nil, init.logger, init.dockerCredentialsDir, err
dockerErrChan := w.installDockerAsync()

if err := w.prepareWorkspaceContent(); err != nil {
return err
}

if init.shouldInstallDaemon {
if err := installDaemon(init.workspaceInfo, init.logger); err != nil {
init.logger.Errorf("install DevPod daemon: %v", err)
}
w.setupDaemonIfNeeded()

if err := w.waitForDocker(dockerErrChan); err != nil {
return err
}

if err := init.waitForDocker(dockerErrChan); err != nil {
return nil, nil, init.dockerCredentialsDir, err
w.configureDockerDaemon()
return nil
}

func (w *workspaceInitializer) setupDaemonIfNeeded() {
if w.shouldInstallDaemon {
if err := installDaemon(w.workspaceInfo, w.logger); err != nil {
w.logger.Errorf("install DevPod daemon: %v", err)
}
}
}

daemonErrChan := init.configureDockerDaemonAsync()
if err := <-daemonErrChan; err != nil {
init.logger.Warn(
func (w *workspaceInitializer) configureDockerDaemon() {
if !w.shouldConfigureDockerDaemon() {
w.logger.Debug("skipping configuring docker daemon")
return
}
if err := configureDockerDaemon(w.ctx, w.logger); err != nil {
w.logger.Warn(
"could not find docker daemon config file, if using the registry cache, " +
"please ensure the daemon is configured with containerd-snapshotter=true, " +
"more info at https://docs.docker.com/engine/storage/containerd/",
)
}

return init.tunnelClient, init.logger, init.dockerCredentialsDir, nil
}

func (w *workspaceInitializer) initializeTunnel() error {
Expand Down Expand Up @@ -414,22 +444,6 @@ func (w *workspaceInitializer) waitForDocker(resultChan <-chan dockerInstallResu
return nil
}

func (w *workspaceInitializer) configureDockerDaemonAsync() <-chan error {
errChan := make(chan error, 1)

if !w.shouldConfigureDockerDaemon() {
w.logger.Debug("skipping configuring docker daemon")
errChan <- nil
return errChan
}

go func() {
errChan <- configureDockerDaemon(w.ctx, w.logger)
}()

return errChan
}

func (w *workspaceInitializer) shouldConfigureDockerDaemon() bool {
if !w.workspaceInfo.Agent.IsDockerDriver() {
return false
Expand All @@ -445,7 +459,7 @@ func (w *workspaceInitializer) shouldConfigureDockerDaemon() bool {

type prepareWorkspaceParams struct {
ctx context.Context
workspaceInfo *provider2.AgentWorkspaceInfo
workspaceInfo *provider.AgentWorkspaceInfo
client tunnel.TunnelClient
gitHelper string
log log.Logger
Expand Down Expand Up @@ -494,7 +508,7 @@ func prepareWorkspace(params prepareWorkspaceParams) error {

type prepareGitWorkspaceParams struct {
ctx context.Context
workspaceInfo *provider2.AgentWorkspaceInfo
workspaceInfo *provider.AgentWorkspaceInfo
gitHelper string
exists bool
log log.Logger
Expand Down Expand Up @@ -530,7 +544,12 @@ func prepareGitWorkspace(params prepareGitWorkspaceParams) error {
)
}

func prepareLocalWorkspace(ctx context.Context, workspaceInfo *provider2.AgentWorkspaceInfo, client tunnel.TunnelClient, log log.Logger) error {
func prepareLocalWorkspace(
ctx context.Context,
workspaceInfo *provider.AgentWorkspaceInfo,
client tunnel.TunnelClient,
log log.Logger,
) error {
if workspaceInfo.ContentFolder == workspaceInfo.Workspace.Source.LocalFolder {
log.Debugf("local folder %s with local provider; skip downloading", workspaceInfo.ContentFolder)
return nil
Expand All @@ -540,7 +559,7 @@ func prepareLocalWorkspace(ctx context.Context, workspaceInfo *provider2.AgentWo
return downloadLocalFolder(ctx, workspaceInfo.ContentFolder, client, log)
}

func ensureLastDevContainerJson(workspaceInfo *provider2.AgentWorkspaceInfo) error {
func ensureLastDevContainerJson(workspaceInfo *provider.AgentWorkspaceInfo) error {
filePath := filepath.Join(workspaceInfo.ContentFolder, filepath.FromSlash(workspaceInfo.LastDevContainerConfig.Path))

if _, err := os.Stat(filePath); err == nil {
Expand All @@ -567,7 +586,7 @@ func ensureLastDevContainerJson(workspaceInfo *provider2.AgentWorkspaceInfo) err

type credentialsConfig struct {
ctx context.Context
workspaceInfo *provider2.AgentWorkspaceInfo
workspaceInfo *provider.AgentWorkspaceInfo
client tunnel.TunnelClient
log log.Logger
}
Expand Down Expand Up @@ -608,7 +627,7 @@ func configureCredentials(cfg credentialsConfig) (string, string, error) {
return dockerCredentials, gitCredentials, nil
}

func installDaemon(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) error {
func installDaemon(workspaceInfo *provider.AgentWorkspaceInfo, log log.Logger) error {
if len(workspaceInfo.Agent.Exec.Shutdown) == 0 {
return nil
}
Expand Down Expand Up @@ -665,11 +684,18 @@ func configureDockerDaemon(ctx context.Context, log log.Logger) error {
}

func writeDockerDaemonConfig(config []byte) error {
if err := tryWriteRootlessDockerConfig(config); err == nil {
rootlessErr := tryWriteRootlessDockerConfig(config)
if rootlessErr == nil {
return nil
}

// #nosec G306 -- daemon.json needs to be readable by docker daemon
rootErr := os.WriteFile("/etc/docker/daemon.json", config, 0644)
if rootErr == nil {
return nil
}

return os.WriteFile("/etc/docker/daemon.json", config, 0644)
return fmt.Errorf("failed to write docker daemon config (rootless: %v, root: %v)", rootlessErr, rootErr)
}

func tryWriteRootlessDockerConfig(config []byte) error {
Expand All @@ -683,6 +709,7 @@ func tryWriteRootlessDockerConfig(config []byte) error {
return err
}

// #nosec G306 -- daemon.json needs to be readable by docker daemon
return os.WriteFile(filepath.Join(dockerConfigDir, "daemon.json"), config, 0644)
}

Expand Down
11 changes: 10 additions & 1 deletion pkg/client/clientimplementation/daemonclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/skevetter/devpod/pkg/config"
daemon "github.com/skevetter/devpod/pkg/daemon/platform"
"github.com/skevetter/devpod/pkg/options"
"github.com/skevetter/devpod/pkg/options/resolver"
"github.com/skevetter/devpod/pkg/platform"
platformclient "github.com/skevetter/devpod/pkg/platform/client"
"github.com/skevetter/devpod/pkg/provider"
Expand Down Expand Up @@ -105,7 +106,15 @@ func (c *client) RefreshOptions(ctx context.Context, userOptionsRaw []string, re
return fmt.Errorf("parse options: %w", err)
}

workspace, err := options.ResolveAndSaveOptionsProxy(ctx, c.devPodConfig, c.config, c.workspace, userOptions, c.log)
workspace, err := options.ResolveAndSaveOptionsWorkspace(
ctx,
c.devPodConfig,
c.config,
c.workspace,
userOptions,
c.log,
resolver.WithResolveSubOptions(),
)
if err != nil {
return err
}
Expand Down
Loading
Loading