diff --git a/.gitignore b/.gitignore index 04708aa9e..11796f5e1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,9 @@ /e2e/bin devpod devpod.exe +devpod-cli # Unit test targets main profile.out package-lock.json -tags +tags \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..eb89ef006 --- /dev/null +++ b/.vscode/launch.json @@ -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", + } + ] +} \ No newline at end of file diff --git a/cmd/agent/container_tunnel.go b/cmd/agent/container_tunnel.go index 139441313..d47eca53f 100644 --- a/cmd/agent/container_tunnel.go +++ b/cmd/agent/container_tunnel.go @@ -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 @@ -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 } @@ -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 } @@ -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 } diff --git a/cmd/agent/workspace/up.go b/cmd/agent/workspace/up.go index cf2845a9f..162f8be9d 100644 --- a/cmd/agent/workspace/up.go +++ b/cmd/agent/workspace/up.go @@ -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 } diff --git a/cmd/build.go b/cmd/build.go index 4a5e1c3fa..2ec27a828 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -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 } @@ -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. diff --git a/cmd/logs.go b/cmd/logs.go index 2252b068c..871ea2c23 100644 --- a/cmd/logs.go +++ b/cmd/logs.go @@ -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 diff --git a/cmd/machine/ssh.go b/cmd/machine/ssh.go index 0e0221a3f..295fdaba6 100644 --- a/cmd/machine/ssh.go +++ b/cmd/machine/ssh.go @@ -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 diff --git a/cmd/ssh.go b/cmd/ssh.go index 71ad685f9..97ede95e8 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -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'") @@ -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) { diff --git a/cmd/up.go b/cmd/up.go index cbd0e9f5e..9bf28c875 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -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 } @@ -497,6 +497,7 @@ func (cmd *UpCmd) devPodUpMachine( sshTunnelStdoutWriter, writer, log.ErrorStreamOnly(), + wInfo.InjectTimeout, ) } diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index c0e11e7fe..9bec10b8e 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -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 } diff --git a/pkg/agent/inject.go b/pkg/agent/inject.go index ca6b12692..ed6a2c01e 100644 --- a/pkg/agent/inject.go +++ b/pkg/agent/inject.go @@ -28,6 +28,7 @@ func InjectAgent( downloadURL string, preferDownload bool, log log.Logger, + timeout time.Duration, ) error { return InjectAgentAndExecute( ctx, @@ -41,6 +42,7 @@ func InjectAgent( nil, nil, log, + timeout, ) } @@ -56,6 +58,7 @@ func InjectAgentAndExecute( stdout io.Writer, stderr io.Writer, log log.Logger, + timeout time.Duration, ) error { // should execute locally? if local { @@ -115,7 +118,7 @@ func InjectAgentAndExecute( stdin, stdout, stderr, - time.Second*20, + timeout, log, ) if err != nil { diff --git a/pkg/client/clientimplementation/workspace_client.go b/pkg/client/clientimplementation/workspace_client.go index b02418791..38bd7fcd5 100644 --- a/pkg/client/clientimplementation/workspace_client.go +++ b/pkg/client/clientimplementation/workspace_client.go @@ -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 { diff --git a/pkg/config/config.go b/pkg/config/config.go index 0078a9662..afcdf0326 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -5,6 +5,8 @@ import ( "fmt" "os" "path/filepath" + "strconv" + "time" "github.com/ghodss/yaml" "github.com/loft-sh/devpod/pkg/telemetry" @@ -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 { @@ -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 +} diff --git a/pkg/config/context.go b/pkg/config/context.go index 8a074f61e..a65e091d5 100644 --- a/pkg/config/context.go +++ b/pkg/config/context.go @@ -13,6 +13,7 @@ const ( ContextOptionDotfilesScript = "DOTFILES_SCRIPT" ContextOptionSSHAgentForwarding = "SSH_AGENT_FORWARDING" ContextOptionSSHConfigPath = "SSH_CONFIG_PATH" + ContextOptionAgentInjectTimeout = "AGENT_INJECT_TIMEOUT" ) var ContextOptions = []ContextOption{ @@ -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", + }, } diff --git a/pkg/devcontainer/compose.go b/pkg/devcontainer/compose.go index b6cb03fcf..9f591b7f3 100644 --- a/pkg/devcontainer/compose.go +++ b/pkg/devcontainer/compose.go @@ -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 { @@ -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) { diff --git a/pkg/devcontainer/run.go b/pkg/devcontainer/run.go index 20fe2f252..73209cc38 100644 --- a/pkg/devcontainer/run.go +++ b/pkg/devcontainer/run.go @@ -10,6 +10,7 @@ import ( "path/filepath" "runtime" "strings" + "time" "github.com/loft-sh/devpod/pkg/devcontainer/config" "github.com/loft-sh/devpod/pkg/driver" @@ -23,7 +24,7 @@ import ( ) type Runner interface { - Up(ctx context.Context, options UpOptions) (*config.Result, error) + Up(ctx context.Context, options UpOptions, timeout time.Duration) (*config.Result, error) Build(ctx context.Context, options provider2.BuildOptions) (string, error) @@ -56,7 +57,6 @@ func NewRunner( } // we use the workspace uid as id to avoid conflicts between container names - return &runner{ Driver: driver, @@ -90,11 +90,11 @@ type UpOptions struct { ForceBuild bool } -func (r *runner) Up(ctx context.Context, options UpOptions) (*config.Result, error) { +func (r *runner) Up(ctx context.Context, options UpOptions, timeout time.Duration) (*config.Result, error) { // download workspace source before recreating container _, isDockerDriver := r.Driver.(driver.DockerDriver) if options.Recreate && !isDockerDriver { - return r.recreateCustomDriver(ctx, options) + return r.recreateCustomDriver(ctx, options, timeout) } // prepare config @@ -123,12 +123,13 @@ func (r *runner) Up(ctx context.Context, options UpOptions) (*config.Result, err substitutedConfig, substitutionContext, options, + timeout, ) if err != nil { return nil, err } } else if isDockerComposeConfig(substitutedConfig.Config) { - result, err = r.runDockerCompose(ctx, substitutedConfig, substitutionContext, options) + result, err = r.runDockerCompose(ctx, substitutedConfig, substitutionContext, options, timeout) if err != nil { return nil, err } @@ -153,7 +154,7 @@ func (r *runner) Up(ctx context.Context, options UpOptions) (*config.Result, err substitutedConfig.Config.ImageContainer = language.MapConfig[lang].ImageContainer } - result, err = r.runSingleContainer(ctx, substitutedConfig, substitutionContext, options) + result, err = r.runSingleContainer(ctx, substitutedConfig, substitutionContext, options, timeout) if err != nil { return nil, err } @@ -296,7 +297,7 @@ func (r *runner) Logs(ctx context.Context, writer io.Writer) error { return r.Driver.GetDevContainerLogs(ctx, r.ID, writer, writer) } -func (r *runner) recreateCustomDriver(ctx context.Context, options UpOptions) (*config.Result, error) { +func (r *runner) recreateCustomDriver(ctx context.Context, options UpOptions, timeout time.Duration) (*config.Result, error) { err := r.Driver.StopDevContainer(ctx, r.ID) if err != nil { return nil, err @@ -305,7 +306,7 @@ func (r *runner) recreateCustomDriver(ctx context.Context, options UpOptions) (* // relaunch Up without recreate now options.Reset = false options.Recreate = false - return r.Up(ctx, options) + return r.Up(ctx, options, timeout) } func isDockerFileConfig(config *config.DevContainerConfig) bool { diff --git a/pkg/devcontainer/setup.go b/pkg/devcontainer/setup.go index f332c3854..f4f8992f1 100644 --- a/pkg/devcontainer/setup.go +++ b/pkg/devcontainer/setup.go @@ -9,6 +9,7 @@ import ( "path/filepath" "runtime" "strings" + "time" "github.com/loft-sh/devpod/pkg/agent" "github.com/loft-sh/devpod/pkg/agent/tunnelserver" @@ -28,11 +29,12 @@ func (r *runner) setupContainer( containerDetails *config.ContainerDetails, mergedConfig *config.MergedDevContainerConfig, substitutionContext *config.SubstitutionContext, + timeout time.Duration, ) (*config.Result, error) { // inject agent err := agent.InjectAgent(ctx, func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { return r.Driver.CommandDevContainer(ctx, r.ID, "root", command, stdin, stdout, stderr) - }, false, agent.ContainerDevPodHelperLocation, agent.DefaultAgentDownloadURL(), false, r.Log) + }, false, agent.ContainerDevPodHelperLocation, agent.DefaultAgentDownloadURL(), false, r.Log, timeout) if err != nil { return nil, errors.Wrap(err, "inject agent") } diff --git a/pkg/devcontainer/single.go b/pkg/devcontainer/single.go index a84f063b8..9355c4866 100644 --- a/pkg/devcontainer/single.go +++ b/pkg/devcontainer/single.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "strings" + "time" "github.com/loft-sh/devpod/pkg/devcontainer/config" "github.com/loft-sh/devpod/pkg/devcontainer/metadata" @@ -22,7 +23,13 @@ const ( WorkspaceUIDExtraEnvVar = "DEVPOD_WORKSPACE_UID" ) -func (r *runner) runSingleContainer(ctx context.Context, parsedConfig *config.SubstitutedConfig, substitutionContext *config.SubstitutionContext, options UpOptions) (*config.Result, error) { +func (r *runner) runSingleContainer( + ctx context.Context, + parsedConfig *config.SubstitutedConfig, + substitutionContext *config.SubstitutionContext, + options UpOptions, + timeout time.Duration, +) (*config.Result, error) { containerDetails, err := r.Driver.FindDevContainer(ctx, r.ID) if err != nil { return nil, fmt.Errorf("find dev container: %w", err) @@ -115,7 +122,7 @@ func (r *runner) runSingleContainer(ctx context.Context, parsedConfig *config.Su } // setup container - return r.setupContainer(ctx, parsedConfig.Raw, containerDetails, mergedConfig, substitutionContext) + return r.setupContainer(ctx, parsedConfig.Raw, containerDetails, mergedConfig, substitutionContext, timeout) } func (r *runner) runContainer( diff --git a/pkg/provider/workspace.go b/pkg/provider/workspace.go index cdd42f0db..a9a5bb71d 100644 --- a/pkg/provider/workspace.go +++ b/pkg/provider/workspace.go @@ -2,6 +2,7 @@ package provider import ( "strings" + "time" "github.com/loft-sh/devpod/pkg/config" devcontainerconfig "github.com/loft-sh/devpod/pkg/devcontainer/config" @@ -160,6 +161,9 @@ type AgentWorkspaceInfo struct { // Origin holds the folder where this config was loaded from Origin string `json:"-"` + + // InjectTimeout specifies how long to wait for the agent to be injected into the dev container + InjectTimeout time.Duration `json:"injectTimeout,omitempty"` } type CLIOptions struct { diff --git a/pkg/tunnel/container.go b/pkg/tunnel/container.go index 11f9a5f3c..d605b4638 100644 --- a/pkg/tunnel/container.go +++ b/pkg/tunnel/container.go @@ -10,6 +10,7 @@ import ( "github.com/loft-sh/devpod/pkg/agent" "github.com/loft-sh/devpod/pkg/client" + "github.com/loft-sh/devpod/pkg/config" "github.com/loft-sh/devpod/pkg/provider" devssh "github.com/loft-sh/devpod/pkg/ssh" "github.com/loft-sh/log" @@ -37,7 +38,7 @@ type ContainerHandler struct { type Handler func(ctx context.Context, containerClient *ssh.Client) error -func (c *ContainerHandler) Run(ctx context.Context, handler Handler) error { +func (c *ContainerHandler) Run(ctx context.Context, handler Handler, cfg *config.Config) error { if handler == nil { return nil } @@ -58,6 +59,9 @@ func (c *ContainerHandler) Run(ctx context.Context, handler Handler) error { defer stdoutWriter.Close() defer stdinWriter.Close() + // Get the timeout from the context options + timeout := config.ParseTimeOption(cfg, config.ContextOptionAgentInjectTimeout) + // tunnel to host tunnelChan := make(chan error, 1) go func() { @@ -69,14 +73,26 @@ func (c *ContainerHandler) Run(ctx context.Context, handler Handler) error { if c.log.GetLevel() == logrus.DebugLevel { command += " --debug" } - tunnelChan <- agent.InjectAgentAndExecute(cancelCtx, func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { - return c.client.Command(ctx, client.CommandOptions{ - Command: command, - Stdin: stdin, - Stdout: stdout, - Stderr: stderr, - }) - }, c.client.AgentLocal(), c.client.AgentPath(), c.client.AgentURL(), true, command, stdinReader, stdoutWriter, writer, c.log.ErrorStreamOnly()) + tunnelChan <- agent.InjectAgentAndExecute( + cancelCtx, + func(ctx context.Context, command string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { + return c.client.Command(ctx, client.CommandOptions{ + Command: command, + Stdin: stdin, + Stdout: stdout, + Stderr: stderr, + }) + }, + c.client.AgentLocal(), + c.client.AgentPath(), + c.client.AgentURL(), + true, + command, + stdinReader, + stdoutWriter, + writer, + c.log.ErrorStreamOnly(), + timeout) }() // connect to container