@@ -29,6 +29,7 @@ import (
2929
3030 "cdr.dev/slog"
3131
32+ "github.com/coder/coder/v2/agent/agentcontainers"
3233 "github.com/coder/coder/v2/agent/agentexec"
3334 "github.com/coder/coder/v2/agent/agentrsa"
3435 "github.com/coder/coder/v2/agent/usershell"
@@ -100,6 +101,8 @@ type Config struct {
100101 X11DisplayOffset * int
101102 // BlockFileTransfer restricts use of file transfer applications.
102103 BlockFileTransfer bool
104+
105+ ExperimentalContainersEnabled bool
103106}
104107
105108type Server struct {
@@ -288,6 +291,22 @@ func extractMagicSessionType(env []string) (magicType MagicSessionType, rawType
288291 })
289292}
290293
294+ func extractContainerInfo (env []string ) (container , containerUser string , filteredEnv []string ) {
295+ for _ , kv := range env {
296+ if strings .HasPrefix (kv , "CODER_CONTAINER=" ) {
297+ container = strings .TrimPrefix (kv , "CODER_CONTAINER=" )
298+ }
299+
300+ if strings .HasPrefix (kv , "CODER_CONTAINER_USER=" ) {
301+ containerUser = strings .TrimPrefix (kv , "CODER_CONTAINER_USER=" )
302+ }
303+ }
304+
305+ return container , containerUser , slices .DeleteFunc (env , func (kv string ) bool {
306+ return strings .HasPrefix (kv , "CODER_CONTAINER=" ) || strings .HasPrefix (kv , "CODER_CONTAINER_USER=" )
307+ })
308+ }
309+
291310func (s * Server ) sessionHandler (session ssh.Session ) {
292311 ctx := session .Context ()
293312 id := uuid .New ()
@@ -310,6 +329,11 @@ func (s *Server) sessionHandler(session ssh.Session) {
310329
311330 env := session .Environ ()
312331 magicType , magicTypeRaw , env := extractMagicSessionType (env )
332+ container , containerUser , env := extractContainerInfo (env )
333+ s .logger .Debug (ctx , "container info" ,
334+ slog .F ("container" , container ),
335+ slog .F ("container_user" , containerUser ),
336+ )
313337
314338 switch magicType {
315339 case MagicSessionTypeVSCode :
@@ -340,6 +364,11 @@ func (s *Server) sessionHandler(session ssh.Session) {
340364 switch ss := session .Subsystem (); ss {
341365 case "" :
342366 case "sftp" :
367+ if s .config .ExperimentalContainersEnabled && container != "" {
368+ logger .Warn (ctx , "sftp not yet supported with containers" )
369+ _ = session .Exit (1 )
370+ return
371+ }
343372 s .sftpHandler (logger , session )
344373 return
345374 default :
@@ -359,7 +388,7 @@ func (s *Server) sessionHandler(session ssh.Session) {
359388 env = append (env , fmt .Sprintf ("DISPLAY=localhost:%d.%d" , display , x11 .ScreenNumber ))
360389 }
361390
362- err := s .sessionStart (logger , session , env , magicType )
391+ err := s .sessionStart (logger , session , env , magicType , container , containerUser )
363392 var exitError * exec.ExitError
364393 if xerrors .As (err , & exitError ) {
365394 code := exitError .ExitCode ()
@@ -429,30 +458,43 @@ func (s *Server) fileTransferBlocked(session ssh.Session) bool {
429458 return false
430459}
431460
432- func (s * Server ) sessionStart (logger slog.Logger , session ssh.Session , env []string , magicType MagicSessionType ) (retErr error ) {
461+ func (s * Server ) sessionStart (logger slog.Logger , session ssh.Session , env []string , magicType MagicSessionType , container , containerUser string ) (retErr error ) {
433462 ctx := session .Context ()
434463
435464 magicTypeLabel := magicTypeMetricLabel (magicType )
436465 sshPty , windowSize , isPty := session .Pty ()
466+ ptyLabel := "no"
467+ if isPty {
468+ ptyLabel = "yes"
469+ }
437470
471+ // plumb in envinfoer here to modify command for container exec?
438472 cmd , err := s .CreateCommand (ctx , session .RawCommand (), env , nil )
439473 if err != nil {
440- ptyLabel := "no"
441- if isPty {
442- ptyLabel = "yes"
443- }
444474 s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "create_command" ).Add (1 )
445475 return err
446476 }
447477
478+ if s .config .ExperimentalContainersEnabled && container != "" {
479+ ei , err := agentcontainers .EnvInfo (ctx , s .Execer , container , containerUser )
480+ if err != nil {
481+ s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "container_env_info" ).Add (1 )
482+ return err
483+ }
484+ modifiedCmd , modifiedArgs := ei .ModifyCommand (cmd .Path , cmd .Args ... )
485+ if modifiedCmd != cmd .Path || slices .Compare (modifiedArgs , cmd .Args ) != 0 {
486+ logger .Debug (ctx , "modified command for container" ,
487+ slog .F ("before" , append ([]string {cmd .Path }, cmd .Args ... )),
488+ slog .F ("after" , append ([]string {modifiedCmd }, modifiedArgs ... )),
489+ )
490+ cmd .Path = modifiedCmd
491+ cmd .Args = modifiedArgs
492+ }
493+ }
494+
448495 if ssh .AgentRequested (session ) {
449496 l , err := ssh .NewAgentListener ()
450497 if err != nil {
451- ptyLabel := "no"
452- if isPty {
453- ptyLabel = "yes"
454- }
455-
456498 s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "listener" ).Add (1 )
457499 return xerrors .Errorf ("new agent listener: %w" , err )
458500 }
0 commit comments