Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions pkg/store/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ func Inspect(ctx context.Context, instName string) (*limatype.Instance, error) {
}
}
}
if inst.SSHLocalPort == 0 {
sshConfigPath := filepath.Join(instDir, filenames.SSHConfig)
if port, err := sshPortFromConfig(sshConfigPath); err == nil {
inst.SSHLocalPort = port
} else if !errors.Is(err, os.ErrNotExist) {
inst.Errors = append(inst.Errors, fmt.Errorf("failed to extract SSH local port from %q: %w", sshConfigPath, err))
}
}

inst.CPUs = *y.CPUs
memory, err := units.RAMInBytes(*y.Memory)
Expand Down Expand Up @@ -226,6 +234,21 @@ func ReadPIDFile(path string) (int, error) {
return pid, nil
}

// sshPortFromConfig extracts the SSH port from an ssh config file.
func sshPortFromConfig(configPath string) (int, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This function is not robust to cover a config with multiple host entries, but we do not need to care about it for Lima-generated config files, at least with the current version)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This could be easier for unit testing

Suggested change
func sshPortFromConfig(configPath string) (int, error) {
func sshPortFromConfig(config []byte) (int, error) {

b, err := os.ReadFile(configPath)
if err != nil {
return 0, err
}
for line := range strings.SplitSeq(string(b), "\n") {
line = strings.TrimSpace(line)
if port, ok := strings.CutPrefix(line, "Port "); ok {
return strconv.Atoi(port)
}
}
return 0, fmt.Errorf("port not found in %q", configPath)
}

type FormatData struct {
limatype.Instance `yaml:",inline"`

Expand Down
27 changes: 27 additions & 0 deletions pkg/store/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,33 @@ var tableTwo = "NAME STATUS SSH VMTYPE ARCH CPUS M
"foo Stopped 127.0.0.1:0 qemu x86_64 0 0B 0B\n" +
"bar Stopped 127.0.0.1:0 vz aarch64 0 0B 0B\n"

func TestSSHPortFromConfig(t *testing.T) {
t.Run("valid", func(t *testing.T) {
f := filepath.Join(t.TempDir(), "ssh.config")
content := "Host lima-default\n Hostname 127.0.0.1\n Port 58786\n User foo\n"
assert.NilError(t, os.WriteFile(f, []byte(content), 0o644))
port, err := sshPortFromConfig(f)
assert.NilError(t, err)
assert.Equal(t, 58786, port)
})
t.Run("missing file", func(t *testing.T) {
_, err := sshPortFromConfig(filepath.Join(t.TempDir(), "nonexistent"))
assert.ErrorIs(t, err, os.ErrNotExist)
})
t.Run("no port line", func(t *testing.T) {
f := filepath.Join(t.TempDir(), "ssh.config")
assert.NilError(t, os.WriteFile(f, []byte("Host lima-default\n Hostname 127.0.0.1\n"), 0o644))
_, err := sshPortFromConfig(f)
assert.ErrorContains(t, err, "port not found")
})
t.Run("invalid port", func(t *testing.T) {
f := filepath.Join(t.TempDir(), "ssh.config")
assert.NilError(t, os.WriteFile(f, []byte("Host lima-default\n Port abc\n"), 0o644))
_, err := sshPortFromConfig(f)
assert.ErrorContains(t, err, "invalid syntax")
})
}

func TestPrintInstanceTable(t *testing.T) {
var buf bytes.Buffer
instances := []*limatype.Instance{&instance}
Expand Down