Skip to content

Commit

Permalink
Merge pull request loft-sh#1217 from bkneis/POD-763/expose-timeout-as…
Browse files Browse the repository at this point in the history
…-agent-config

POD-763: Expose inject timeout as contect config and add to agent workspace info
  • Loading branch information
bkneis authored Aug 21, 2024
2 parents b48f066 + c15dd46 commit fbffe09
Show file tree
Hide file tree
Showing 20 changed files with 190 additions and 65 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
/e2e/bin
devpod
devpod.exe
devpod-cli
# Unit test targets
main
profile.out
package-lock.json
tags
tags
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceRoot}",
"args": "up examples/simple",
}
]
}
9 changes: 5 additions & 4 deletions cmd/agent/container_tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func (cmd *ContainerTunnelCmd) Run(ctx context.Context, log log.Logger) error {
os.Stdout,
os.Stderr,
log,
workspaceInfo.InjectTimeout,
)
if err != nil {
return err
Expand All @@ -112,7 +113,7 @@ func startDevContainer(ctx context.Context, workspaceConfig *provider2.AgentWork
// start container if necessary
if containerDetails == nil || containerDetails.State.Status != "running" {
// start container
_, err = StartContainer(ctx, runner, log)
_, err = StartContainer(ctx, runner, log, workspaceConfig)
if err != nil {
return err
}
Expand All @@ -122,7 +123,7 @@ func startDevContainer(ctx context.Context, workspaceConfig *provider2.AgentWork
err = runner.Command(ctx, "root", "cat "+setup.ResultLocation, nil, buf, buf)
if err != nil {
// start container
_, err = StartContainer(ctx, runner, log)
_, err = StartContainer(ctx, runner, log, workspaceConfig)
if err != nil {
return err
}
Expand All @@ -132,9 +133,9 @@ func startDevContainer(ctx context.Context, workspaceConfig *provider2.AgentWork
return nil
}

func StartContainer(ctx context.Context, runner devcontainer.Runner, log log.Logger) (*config.Result, error) {
func StartContainer(ctx context.Context, runner devcontainer.Runner, log log.Logger, workspaceConfig *provider2.AgentWorkspaceInfo) (*config.Result, error) {
log.Debugf("Starting DevPod container...")
result, err := runner.Up(ctx, devcontainer.UpOptions{NoBuild: true})
result, err := runner.Up(ctx, devcontainer.UpOptions{NoBuild: true}, workspaceConfig.InjectTimeout)
if err != nil {
return result, err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/agent/workspace/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ func (cmd *UpCmd) devPodUp(ctx context.Context, workspaceInfo *provider2.AgentWo
// start the devcontainer
result, err := runner.Up(ctx, devcontainer.UpOptions{
CLIOptions: workspaceInfo.CLIOptions,
})
}, workspaceInfo.InjectTimeout)
if err != nil {
return nil, err
}
Expand Down
30 changes: 21 additions & 9 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func (cmd *BuildCmd) build(ctx context.Context, workspaceClient client.Workspace

func (cmd *BuildCmd) buildAgentClient(ctx context.Context, workspaceClient client.WorkspaceClient, log log.Logger) error {
// compress info
workspaceInfo, _, err := workspaceClient.AgentInfo(cmd.CLIOptions)
workspaceInfo, wInfo, err := workspaceClient.AgentInfo(cmd.CLIOptions)
if err != nil {
return err
}
Expand Down Expand Up @@ -191,14 +191,26 @@ func (cmd *BuildCmd) buildAgentClient(ctx context.Context, workspaceClient clien
writer := log.ErrorStreamOnly().Writer(logrus.InfoLevel, false)
defer writer.Close()

errChan <- agent.InjectAgentAndExecute(cancelCtx, func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
return workspaceClient.Command(ctx, client.CommandOptions{
Command: command,
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
})
}, workspaceClient.AgentLocal(), workspaceClient.AgentPath(), workspaceClient.AgentURL(), true, command, stdinReader, stdoutWriter, writer, log.ErrorStreamOnly())
errChan <- agent.InjectAgentAndExecute(
cancelCtx,
func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
return workspaceClient.Command(ctx, client.CommandOptions{
Command: command,
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
})
},
workspaceClient.AgentLocal(),
workspaceClient.AgentPath(),
workspaceClient.AgentURL(),
true,
command,
stdinReader,
stdoutWriter,
writer,
log.ErrorStreamOnly(),
wInfo.InjectTimeout)
}()

// create container etc.
Expand Down
30 changes: 22 additions & 8 deletions cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,34 @@ func (cmd *LogsCmd) Run(ctx context.Context, args []string) error {
sshServerCmd += " --debug"
}

// Get the timeout from the context options
timeout := config.ParseTimeOption(devPodConfig, config.ContextOptionAgentInjectTimeout)

// start ssh server in background
errChan := make(chan error, 1)
go func() {
stderr := log.ErrorStreamOnly().Writer(logrus.DebugLevel, false)
defer stderr.Close()

errChan <- agent.InjectAgentAndExecute(ctx, func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
return client.Command(ctx, clientpkg.CommandOptions{
Command: command,
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
})
}, client.AgentLocal(), client.AgentPath(), client.AgentURL(), true, sshServerCmd, stdinReader, stdoutWriter, stderr, log.ErrorStreamOnly())
errChan <- agent.InjectAgentAndExecute(
ctx,
func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
return client.Command(ctx, clientpkg.CommandOptions{
Command: command,
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
})
},
client.AgentLocal(),
client.AgentPath(),
client.AgentURL(),
true,
sshServerCmd,
stdinReader,
stdoutWriter,
stderr,
log.ErrorStreamOnly(), timeout)
}()

// create agent command
Expand Down
46 changes: 32 additions & 14 deletions cmd/machine/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,39 @@ func (cmd *SSHCmd) Run(ctx context.Context, args []string) error {
writer := log.Default.ErrorStreamOnly().Writer(logrus.InfoLevel, false)
defer writer.Close()

// Get the timeout from the context options
timeout := config.ParseTimeOption(devPodConfig, config.ContextOptionAgentInjectTimeout)

// start the ssh session
return StartSSHSession(ctx, "", cmd.Command, cmd.AgentForwarding, func(ctx context.Context, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
command := fmt.Sprintf("'%s' helper ssh-server --stdio", machineClient.AgentPath())
if cmd.Debug {
command += " --debug"
}
return devagent.InjectAgentAndExecute(ctx, func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
return machineClient.Command(ctx, client.CommandOptions{
Command: command,
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
})
}, machineClient.AgentLocal(), machineClient.AgentPath(), machineClient.AgentURL(), true, command, stdin, stdout, stderr, log.Default.ErrorStreamOnly())
}, writer)
return StartSSHSession(
ctx,
"",
cmd.Command,
cmd.AgentForwarding,
func(ctx context.Context, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
command := fmt.Sprintf("'%s' helper ssh-server --stdio", machineClient.AgentPath())
if cmd.Debug {
command += " --debug"
}
return devagent.InjectAgentAndExecute(ctx, func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
return machineClient.Command(ctx, client.CommandOptions{
Command: command,
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
})
},
machineClient.AgentLocal(),
machineClient.AgentPath(),
machineClient.AgentURL(),
true,
command,
stdin,
stdout,
stderr,
log.Default.ErrorStreamOnly(),
timeout)
}, writer)
}

type ExecFunc func(ctx context.Context, stdin io.Reader, stdout io.Writer, stderr io.Writer) error
Expand Down
8 changes: 6 additions & 2 deletions cmd/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ func NewSSHCmd(flags *flags.GlobalFlags) *cobra.Command {
}

// Run runs the command logic
func (cmd *SSHCmd) Run(ctx context.Context, devPodConfig *config.Config, client client2.BaseWorkspaceClient, log log.Logger) error {
func (cmd *SSHCmd) Run(
ctx context.Context,
devPodConfig *config.Config,
client client2.BaseWorkspaceClient,
log log.Logger) error {
// add ssh keys to agent
if !cmd.Proxy && devPodConfig.ContextOption(config.ContextOptionSSHAgentForwarding) == "true" && devPodConfig.ContextOption(config.ContextOptionSSHAddPrivateKeys) == "true" {
log.Debug("Adding ssh keys to agent, disable via 'devpod context set-options -o SSH_ADD_PRIVATE_KEYS=false'")
Expand Down Expand Up @@ -234,7 +238,7 @@ func (cmd *SSHCmd) jumpContainer(

// start ssh tunnel
return cmd.startTunnel(ctx, devPodConfig, containerClient, client.Workspace(), log)
})
}, devPodConfig)
}

func (cmd *SSHCmd) forwardTimeout(log log.Logger) (time.Duration, error) {
Expand Down
3 changes: 2 additions & 1 deletion cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ func (cmd *UpCmd) devPodUpMachine(
}

// compress info
workspaceInfo, _, err := client.AgentInfo(cmd.CLIOptions)
workspaceInfo, wInfo, err := client.AgentInfo(cmd.CLIOptions)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -497,6 +497,7 @@ func (cmd *UpCmd) devPodUpMachine(
sshTunnelStdoutWriter,
writer,
log.ErrorStreamOnly(),
wInfo.InjectTimeout,
)
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,11 +313,12 @@ func Tunnel(
stdout io.Writer,
stderr io.Writer,
log log.Logger,
timeout time.Duration,
) error {
// inject agent
err := InjectAgent(ctx, func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
return exec(ctx, "root", command, stdin, stdout, stderr)
}, false, ContainerDevPodHelperLocation, DefaultAgentDownloadURL(), false, log)
}, false, ContainerDevPodHelperLocation, DefaultAgentDownloadURL(), false, log, timeout)
if err != nil {
return err
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/agent/inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func InjectAgent(
downloadURL string,
preferDownload bool,
log log.Logger,
timeout time.Duration,
) error {
return InjectAgentAndExecute(
ctx,
Expand All @@ -41,6 +42,7 @@ func InjectAgent(
nil,
nil,
log,
timeout,
)
}

Expand All @@ -56,6 +58,7 @@ func InjectAgentAndExecute(
stdout io.Writer,
stderr io.Writer,
log log.Logger,
timeout time.Duration,
) error {
// should execute locally?
if local {
Expand Down Expand Up @@ -115,7 +118,7 @@ func InjectAgentAndExecute(
stdin,
stdout,
stderr,
time.Second*20,
timeout,
log,
)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions pkg/client/clientimplementation/workspace_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ func (s *workspaceClient) agentInfo(cliOptions provider.CLIOptions) (string, *pr
}
}

// Get the timeout from the context options
agentInfo.InjectTimeout = config.ParseTimeOption(s.devPodConfig, config.ContextOptionAgentInjectTimeout)

// marshal config
out, err := json.Marshal(agentInfo)
if err != nil {
Expand Down
18 changes: 16 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"time"

"github.com/ghodss/yaml"
"github.com/loft-sh/devpod/pkg/telemetry"
Expand Down Expand Up @@ -116,8 +118,12 @@ func (c *Config) IDEOptions(ide string) map[string]OptionValue {
}

func (c *Config) ContextOption(option string) string {
if c.Current().Options != nil && c.Current().Options[option].Value != "" {
return c.Current().Options[option].Value
if c.Contexts != nil {
if _, ok := c.Contexts[c.DefaultContext]; ok && c.Current().Options != nil {
if _, ok := c.Current().Options[option]; ok && c.Current().Options[option].Value != "" {
return c.Current().Options[option].Value
}
}
}

for _, contextOption := range ContextOptions {
Expand Down Expand Up @@ -306,3 +312,11 @@ func SaveConfig(config *Config) error {

return nil
}

func ParseTimeOption(cfg *Config, opt string) time.Duration {
timeout, err := strconv.ParseInt(cfg.ContextOption(opt), 10, 64)
if err != nil {
timeout = 20
}
return time.Duration(timeout) * time.Second
}
6 changes: 6 additions & 0 deletions pkg/config/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (
ContextOptionDotfilesScript = "DOTFILES_SCRIPT"
ContextOptionSSHAgentForwarding = "SSH_AGENT_FORWARDING"
ContextOptionSSHConfigPath = "SSH_CONFIG_PATH"
ContextOptionAgentInjectTimeout = "AGENT_INJECT_TIMEOUT"
)

var ContextOptions = []ContextOption{
Expand Down Expand Up @@ -80,4 +81,9 @@ var ContextOptions = []ContextOption{
Name: ContextOptionSSHConfigPath,
Description: "Specifies the path where the ssh config should be written to",
},
{
Name: ContextOptionAgentInjectTimeout,
Description: "Specifies the timeout to inject the agent",
Default: "20",
},
}
3 changes: 2 additions & 1 deletion pkg/devcontainer/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func (r *runner) runDockerCompose(
parsedConfig *config.SubstitutedConfig,
substitutionContext *config.SubstitutionContext,
options UpOptions,
timeout time.Duration,
) (*config.Result, error) {
composeHelper, err := r.composeHelper()
if err != nil {
Expand Down Expand Up @@ -202,7 +203,7 @@ func (r *runner) runDockerCompose(
}

// setup container
return r.setupContainer(ctx, parsedConfig.Raw, containerDetails, mergedConfig, substitutionContext)
return r.setupContainer(ctx, parsedConfig.Raw, containerDetails, mergedConfig, substitutionContext, timeout)
}

func (r *runner) getDockerComposeFilePaths(parsedConfig *config.SubstitutedConfig, envFiles []string) ([]string, error) {
Expand Down
Loading

0 comments on commit fbffe09

Please sign in to comment.