55 "encoding/json"
66 "fmt"
77 "io"
8+ "net"
89 "os"
910 "path/filepath"
1011 "runtime"
@@ -20,6 +21,9 @@ import (
2021 "github.com/loft-sh/devpod/pkg/driver"
2122 "github.com/loft-sh/devpod/pkg/ide"
2223 provider2 "github.com/loft-sh/devpod/pkg/provider"
24+ devssh "github.com/loft-sh/devpod/pkg/ssh"
25+ "github.com/loft-sh/devpod/pkg/ssh/server"
26+ "github.com/loft-sh/devpod/pkg/ts"
2327 "github.com/loft-sh/log"
2428 "github.com/pkg/errors"
2529 "github.com/sirupsen/logrus"
@@ -96,15 +100,6 @@ func (r *runner) setupContainer(
96100 // check if docker driver
97101 _ , isDockerDriver := r .Driver .(driver.DockerDriver )
98102
99- // ssh tunnel
100- sshTunnelCmd := fmt .Sprintf ("'%s' helper ssh-server --stdio" , agent .ContainerDevPodHelperLocation )
101- if ide .ReusesAuthSock (r .WorkspaceConfig .Workspace .IDE .Name ) {
102- sshTunnelCmd += fmt .Sprintf (" --reuse-ssh-auth-sock=%s" , r .WorkspaceConfig .CLIOptions .SSHAuthSockID )
103- }
104- if r .Log .GetLevel () == logrus .DebugLevel {
105- sshTunnelCmd += " --debug"
106- }
107-
108103 // setup container
109104 r .Log .Infof ("Setup container..." )
110105
@@ -132,10 +127,46 @@ func (r *runner) setupContainer(
132127 setupCommand += " --debug"
133128 }
134129
130+ // run setup server
131+ runSetupServer := func (ctx context.Context , stdin io.WriteCloser , stdout io.Reader ) (* config.Result , error ) {
132+ return tunnelserver .RunSetupServer (
133+ ctx ,
134+ stdout ,
135+ stdin ,
136+ r .WorkspaceConfig .Agent .InjectGitCredentials != "false" ,
137+ r .WorkspaceConfig .Agent .InjectDockerCredentials != "false" ,
138+ config .GetMounts (result ),
139+ r .Log ,
140+ tunnelserver .WithPlatformOptions (& r .WorkspaceConfig .CLIOptions .Platform ),
141+ )
142+ }
143+
144+ // check if we should use the platform workspace socket
145+ shouldUsePlatformWorkspaceSocket := r .WorkspaceConfig .CLIOptions .Platform .Enabled && r .WorkspaceConfig .CLIOptions .Platform .WorkspaceSocket != ""
146+ if shouldUsePlatformWorkspaceSocket {
147+ _ , err := os .Stat (r .WorkspaceConfig .CLIOptions .Platform .WorkspaceSocket )
148+ if err != nil {
149+ shouldUsePlatformWorkspaceSocket = false
150+ }
151+ }
152+
153+ // if we can use the platform workspace socket we connect directly to it
154+ if shouldUsePlatformWorkspaceSocket {
155+ return r .runPlatformSetupServer (ctx , setupCommand , runSetupServer )
156+ }
157+
158+ // ssh tunnel
159+ sshTunnelCmd := fmt .Sprintf ("'%s' helper ssh-server --stdio" , agent .ContainerDevPodHelperLocation )
160+ if ide .ReusesAuthSock (r .WorkspaceConfig .Workspace .IDE .Name ) {
161+ sshTunnelCmd += fmt .Sprintf (" --reuse-ssh-auth-sock=%s" , r .WorkspaceConfig .CLIOptions .SSHAuthSockID )
162+ }
163+ if r .Log .GetLevel () == logrus .DebugLevel {
164+ sshTunnelCmd += " --debug"
165+ }
166+
135167 agentInjectFunc := func (cancelCtx context.Context , sshCmd string , sshTunnelStdinReader , sshTunnelStdoutWriter * os.File , writer io.WriteCloser ) error {
136168 return r .Driver .CommandDevContainer (cancelCtx , r .ID , "root" , sshCmd , sshTunnelStdinReader , sshTunnelStdoutWriter , writer )
137169 }
138-
139170 return sshtunnel .ExecuteCommand (
140171 ctx ,
141172 nil ,
@@ -144,21 +175,68 @@ func (r *runner) setupContainer(
144175 sshTunnelCmd ,
145176 setupCommand ,
146177 r .Log ,
147- func (ctx context.Context , stdin io.WriteCloser , stdout io.Reader ) (* config.Result , error ) {
148- return tunnelserver .RunSetupServer (
149- ctx ,
150- stdout ,
151- stdin ,
152- r .WorkspaceConfig .Agent .InjectGitCredentials != "false" ,
153- r .WorkspaceConfig .Agent .InjectDockerCredentials != "false" ,
154- config .GetMounts (result ),
155- r .Log ,
156- tunnelserver .WithPlatformOptions (& r .WorkspaceConfig .CLIOptions .Platform ),
157- )
158- },
178+ runSetupServer ,
159179 )
160180}
161181
182+ func (r * runner ) runPlatformSetupServer (ctx context.Context , setupCommand string , tunnelServerFunc sshtunnel.TunnelServerFunc ) (* config.Result , error ) {
183+ r .Log .Infof ("Connecting to workspace..." )
184+
185+ // create a dialer that connects to the platform workspace socket
186+ dialer := func (ctx context.Context , network , address string ) (net.Conn , error ) {
187+ dial := & net.Dialer {}
188+ return dial .DialContext (ctx , "unix" , r .WorkspaceConfig .CLIOptions .Platform .WorkspaceSocket )
189+ }
190+
191+ // start machine on stdio
192+ ctx , cancel := context .WithCancel (ctx )
193+ defer cancel ()
194+
195+ // create a new direct ssh client
196+ toolClient , err := ts .WaitForSSHClient (ctx , dialer , "tcp" , fmt .Sprintf ("%s:%d" , r .WorkspaceConfig .CLIOptions .Platform .WorkspaceHost , server .DefaultUserPort ), "root" , time .Second * 30 , r .Log )
197+ if err != nil {
198+ return nil , fmt .Errorf ("create SSH tool client: %w" , err )
199+ }
200+ defer toolClient .Close ()
201+
202+ // create the pipes
203+ stdoutReader , stdoutWriter , err := os .Pipe ()
204+ if err != nil {
205+ return nil , err
206+ }
207+ stdinReader , stdinWriter , err := os .Pipe ()
208+ if err != nil {
209+ return nil , err
210+ }
211+ defer stdoutWriter .Close ()
212+ defer stdinWriter .Close ()
213+
214+ // create the error channel & execute remote command
215+ errChan := make (chan error , 1 )
216+ go func () {
217+ defer cancel ()
218+
219+ writer := r .Log .Writer (logrus .InfoLevel , false )
220+ defer writer .Close ()
221+
222+ err = devssh .Run (ctx , toolClient , setupCommand , stdinReader , stdoutWriter , writer , nil )
223+ if err != nil {
224+ errChan <- errors .Wrap (err , "run agent command" )
225+ } else {
226+ errChan <- nil
227+ }
228+ }()
229+
230+ // start tunnel server locally
231+ result , err := tunnelServerFunc (ctx , stdinWriter , stdoutReader )
232+ if err != nil {
233+ return nil , fmt .Errorf ("start tunnel server: %w" , err )
234+ }
235+
236+ // wait until command finished
237+ return result , <- errChan
238+ }
239+
162240func getRelativeDevContainerJson (origin , localWorkspaceFolder string ) string {
163241 relativePath := strings .TrimPrefix (filepath .ToSlash (origin ), filepath .ToSlash (localWorkspaceFolder ))
164242 return strings .TrimPrefix (relativePath , "/" )
0 commit comments