@@ -29,6 +29,7 @@ import (
29
29
30
30
"cdr.dev/slog"
31
31
32
+ "github.com/coder/coder/v2/agent/agentcontainers"
32
33
"github.com/coder/coder/v2/agent/agentexec"
33
34
"github.com/coder/coder/v2/agent/agentrsa"
34
35
"github.com/coder/coder/v2/agent/usershell"
@@ -100,6 +101,8 @@ type Config struct {
100
101
X11DisplayOffset * int
101
102
// BlockFileTransfer restricts use of file transfer applications.
102
103
BlockFileTransfer bool
104
+
105
+ ExperimentalContainersEnabled bool
103
106
}
104
107
105
108
type Server struct {
@@ -288,6 +291,22 @@ func extractMagicSessionType(env []string) (magicType MagicSessionType, rawType
288
291
})
289
292
}
290
293
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
+
291
310
func (s * Server ) sessionHandler (session ssh.Session ) {
292
311
ctx := session .Context ()
293
312
id := uuid .New ()
@@ -310,6 +329,11 @@ func (s *Server) sessionHandler(session ssh.Session) {
310
329
311
330
env := session .Environ ()
312
331
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
+ )
313
337
314
338
switch magicType {
315
339
case MagicSessionTypeVSCode :
@@ -340,6 +364,11 @@ func (s *Server) sessionHandler(session ssh.Session) {
340
364
switch ss := session .Subsystem (); ss {
341
365
case "" :
342
366
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
+ }
343
372
s .sftpHandler (logger , session )
344
373
return
345
374
default :
@@ -359,7 +388,7 @@ func (s *Server) sessionHandler(session ssh.Session) {
359
388
env = append (env , fmt .Sprintf ("DISPLAY=localhost:%d.%d" , display , x11 .ScreenNumber ))
360
389
}
361
390
362
- err := s .sessionStart (logger , session , env , magicType )
391
+ err := s .sessionStart (logger , session , env , magicType , container , containerUser )
363
392
var exitError * exec.ExitError
364
393
if xerrors .As (err , & exitError ) {
365
394
code := exitError .ExitCode ()
@@ -429,30 +458,43 @@ func (s *Server) fileTransferBlocked(session ssh.Session) bool {
429
458
return false
430
459
}
431
460
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 ) {
433
462
ctx := session .Context ()
434
463
435
464
magicTypeLabel := magicTypeMetricLabel (magicType )
436
465
sshPty , windowSize , isPty := session .Pty ()
466
+ ptyLabel := "no"
467
+ if isPty {
468
+ ptyLabel = "yes"
469
+ }
437
470
471
+ // plumb in envinfoer here to modify command for container exec?
438
472
cmd , err := s .CreateCommand (ctx , session .RawCommand (), env , nil )
439
473
if err != nil {
440
- ptyLabel := "no"
441
- if isPty {
442
- ptyLabel = "yes"
443
- }
444
474
s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "create_command" ).Add (1 )
445
475
return err
446
476
}
447
477
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
+
448
495
if ssh .AgentRequested (session ) {
449
496
l , err := ssh .NewAgentListener ()
450
497
if err != nil {
451
- ptyLabel := "no"
452
- if isPty {
453
- ptyLabel = "yes"
454
- }
455
-
456
498
s .metrics .sessionErrors .WithLabelValues (magicTypeLabel , ptyLabel , "listener" ).Add (1 )
457
499
return xerrors .Errorf ("new agent listener: %w" , err )
458
500
}
0 commit comments