From f45b87faa082a853fdb469ce22c2e13c3b8f1890 Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 09:47:29 +0000 Subject: [PATCH] Honor recorded SSH options for exec --- container.go | 4 ++++ linuxkit.go | 14 +++++++++++--- linuxkit_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/container.go b/container.go index 5c3dfae..5905641 100644 --- a/container.go +++ b/container.go @@ -31,6 +31,10 @@ type Container struct { Memory int `json:"memory,omitempty"` // CPUs is the number of CPUs allocated. CPUs int `json:"cpus,omitempty"` + // SSHPort is the host port mapped to guest SSH. + SSHPort int `json:"ssh_port,omitempty"` + // SSHKey is the private key used for SSH exec commands. + SSHKey string `json:"ssh_key,omitempty"` } // Status represents the state of a container. diff --git a/linuxkit.go b/linuxkit.go index c248df1..ef52c2f 100644 --- a/linuxkit.go +++ b/linuxkit.go @@ -142,6 +142,8 @@ func (m *LinuxKitManager) Run(ctx context.Context, image string, opts RunOptions Ports: opts.Ports, Memory: opts.Memory, CPUs: opts.CPUs, + SSHPort: opts.SSHPort, + SSHKey: opts.SSHKey, } if opts.Detach { @@ -421,8 +423,11 @@ func (m *LinuxKitManager) Exec(ctx context.Context, id string, cmd []string) err return coreerr.E("LinuxKitManager.Exec", "container is not running: "+id, nil) } - // Default SSH port - sshPort := 2222 + // Use the container's configured SSH port, falling back to the default. + sshPort := container.SSHPort + if sshPort <= 0 { + sshPort = 2222 + } // Build SSH command sshArgs := []string{ @@ -430,8 +435,11 @@ func (m *LinuxKitManager) Exec(ctx context.Context, id string, cmd []string) err "-o", "StrictHostKeyChecking=yes", "-o", "UserKnownHostsFile=~/.core/known_hosts", "-o", "LogLevel=ERROR", - "root@localhost", } + if container.SSHKey != "" { + sshArgs = append(sshArgs, "-i", container.SSHKey) + } + sshArgs = append(sshArgs, "root@localhost") sshArgs = append(sshArgs, cmd...) sshCmd := proc.NewCommandContext(ctx, "ssh", sshArgs...) diff --git a/linuxkit_test.go b/linuxkit_test.go index 1a89c0d..6e7a8b2 100644 --- a/linuxkit_test.go +++ b/linuxkit_test.go @@ -2,6 +2,8 @@ package container import ( "context" + "os" + "strings" "syscall" "testing" "time" @@ -357,6 +359,51 @@ func TestLinuxKitManager_Exec_NotRunning_Bad(t *testing.T) { assert.Contains(t, err.Error(), "not running") } +func TestLinuxKitManager_Exec_UsesContainerSSHOptions_Good(t *testing.T) { + manager, _, tmpDir := newTestManager(t) + + capturePath := coreutil.JoinPath(tmpDir, "ssh-args.txt") + sshPath := coreutil.JoinPath(tmpDir, "ssh") + script := "#!/bin/sh\nprintf '%s\\n' \"$@\" > \"" + capturePath + "\"\n" + require.NoError(t, io.Local.Write(sshPath, script)) + require.NoError(t, os.Chmod(sshPath, 0o755)) + + oldPath := os.Getenv("PATH") + t.Setenv("PATH", tmpDir+":"+oldPath) + + container := &Container{ + ID: "abc12345", + Status: StatusRunning, + SSHPort: 2200, + SSHKey: "/tmp/test-id_ed25519", + } + _ = manager.State().Add(container) + + ctx := context.Background() + err := manager.Exec(ctx, "abc12345", []string{"ls", "-la"}) + require.NoError(t, err) + + data, err := io.Local.Read(capturePath) + require.NoError(t, err) + args := strings.Split(strings.TrimSpace(data), "\n") + + assert.Equal(t, []string{ + "-p", + "2200", + "-o", + "StrictHostKeyChecking=yes", + "-o", + "UserKnownHostsFile=~/.core/known_hosts", + "-o", + "LogLevel=ERROR", + "-i", + "/tmp/test-id_ed25519", + "root@localhost", + "ls", + "-la", + }, args) +} + func TestLinuxKit_DetectImageFormat_Good(t *testing.T) { tests := []struct { path string