@@ -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"
@@ -104,6 +105,9 @@ type Config struct {
104105 BlockFileTransfer bool
105106 // ReportConnection.
106107 ReportConnection reportConnectionFunc
108+ // Experimental: allow connecting to running containers if
109+ // CODER_AGENT_DEVCONTAINERS_ENABLE=true.
110+ ExperimentalContainersEnabled bool
107111}
108112
109113type Server struct {
@@ -324,6 +328,22 @@ func (s *sessionCloseTracker) Close() error {
324328 return s .Session .Close ()
325329}
326330
331+ func extractContainerInfo (env []string ) (container , containerUser string , filteredEnv []string ) {
332+ for _ , kv := range env {
333+ if strings .HasPrefix (kv , "CODER_CONTAINER=" ) {
334+ container = strings .TrimPrefix (kv , "CODER_CONTAINER=" )
335+ }
336+
337+ if strings .HasPrefix (kv , "CODER_CONTAINER_USER=" ) {
338+ containerUser = strings .TrimPrefix (kv , "CODER_CONTAINER_USER=" )
339+ }
340+ }
341+
342+ return container , containerUser , slices .DeleteFunc (env , func (kv string ) bool {
343+ return strings .HasPrefix (kv , "CODER_CONTAINER=" ) || strings .HasPrefix (kv , "CODER_CONTAINER_USER=" )
344+ })
345+ }
346+
327347func (s * Server ) sessionHandler (session ssh.Session ) {
328348 ctx := session .Context ()
329349 id := uuid .New ()
@@ -353,6 +373,7 @@ func (s *Server) sessionHandler(session ssh.Session) {
353373 defer s .trackSession (session , false )
354374
355375 reportSession := true
376+
356377 switch magicType {
357378 case MagicSessionTypeVSCode :
358379 s .connCountVSCode .Add (1 )
@@ -395,9 +416,19 @@ func (s *Server) sessionHandler(session ssh.Session) {
395416 return
396417 }
397418
419+ container , containerUser , env := extractContainerInfo (env )
420+ s .logger .Debug (ctx , "container info" ,
421+ slog .F ("container" , container ),
422+ slog .F ("container_user" , containerUser ),
423+ )
424+
398425 switch ss := session .Subsystem (); ss {
399426 case "" :
400427 case "sftp" :
428+ if s .config .ExperimentalContainersEnabled && container != "" {
429+ closeCause ("sftp not yet supported with containers" )
430+ return
431+ }
401432 err := s .sftpHandler (logger , session )
402433 if err != nil {
403434 closeCause (err .Error ())
@@ -422,7 +453,7 @@ func (s *Server) sessionHandler(session ssh.Session) {
422453 env = append (env , fmt .Sprintf ("DISPLAY=localhost:%d.%d" , display , x11 .ScreenNumber ))
423454 }
424455
425- err := s .sessionStart (logger , session , env , magicType )
456+ err := s .sessionStart (logger , session , env , magicType , container , containerUser )
426457 var exitError * exec.ExitError
427458 if xerrors .As (err , & exitError ) {
428459 code := exitError .ExitCode ()
@@ -495,30 +526,35 @@ func (s *Server) fileTransferBlocked(session ssh.Session) bool {
495526 return false
496527}
497528
498- func (s * Server ) sessionStart (logger slog.Logger , session ssh.Session , env []string , magicType MagicSessionType ) (retErr error ) {
529+ func (s * Server ) sessionStart (logger slog.Logger , session ssh.Session , env []string , magicType MagicSessionType , container , containerUser string ) (retErr error ) {
499530 ctx := session .Context ()
500531
501532 magicTypeLabel := magicTypeMetricLabel (magicType )
502533 sshPty , windowSize , isPty := session .Pty ()
534+ ptyLabel := "no"
535+ if isPty {
536+ ptyLabel = "yes"
537+ }
503538
504- cmd , err := s .CreateCommand (ctx , session .RawCommand (), env , nil )
505- if err != nil {
506- ptyLabel := "no"
507- if isPty {
508- ptyLabel = "yes"
539+ // plumb in envinfoer here to modify command for container exec?
540+ var ei usershell.EnvInfoer
541+ var err error
542+ if s .config .ExperimentalContainersEnabled && container != "" {
543+ ei , err = agentcontainers .EnvInfo (ctx , s .Execer , container , containerUser )
544+ if err != nil {
545+ s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "container_env_info" ).Add (1 )
546+ return err
509547 }
548+ }
549+ cmd , err := s .CreateCommand (ctx , session .RawCommand (), env , ei )
550+ if err != nil {
510551 s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "create_command" ).Add (1 )
511552 return err
512553 }
513554
514555 if ssh .AgentRequested (session ) {
515556 l , err := ssh .NewAgentListener ()
516557 if err != nil {
517- ptyLabel := "no"
518- if isPty {
519- ptyLabel = "yes"
520- }
521-
522558 s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "listener" ).Add (1 )
523559 return xerrors .Errorf ("new agent listener: %w" , err )
524560 }
0 commit comments