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
11 changes: 6 additions & 5 deletions cli_config/cli_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ type VmImage struct {
}

type VmConfig struct {
Manager string `yaml:"manager"`
HostsResolver string `yaml:"hosts_resolver"`
Images []VmImage `yaml:"images"`
Ubuntu string `yaml:"ubuntu"`
InstanceName string `yaml:"instance_name"`
Manager string `yaml:"manager"`
HostsResolver string `yaml:"hosts_resolver"`
Images []VmImage `yaml:"images"`
Ubuntu string `yaml:"ubuntu"`
InstanceName string `yaml:"instance_name"`
ForwardHttpPort bool `yaml:"forward_http_port"`
}

type Config struct {
Expand Down
66 changes: 61 additions & 5 deletions pkg/lima/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"net"
"os"
"path/filepath"
"strings"
Expand All @@ -27,10 +28,17 @@ var (
ErrUnsupportedOS = errors.New("unsupported OS or macOS version. The macOS Virtualization Framework requires macOS 13.0 (Ventura) or later.")
)

type PortFinder interface {
Resolve() (int, error)
}

type TCPPortFinder struct{}

type Manager struct {
ConfigPath string
Sites map[string]*trellis.Site
HostsResolver vm.HostsResolver
PortFinder PortFinder
ui cli.Ui
trellis *trellis.Trellis
}
Expand All @@ -55,6 +63,7 @@ func NewManager(trellis *trellis.Trellis, ui cli.Ui) (manager *Manager, err erro
ConfigPath: limaConfigPath,
Sites: trellis.Environments["development"].WordPressSites,
HostsResolver: hostsResolver,
PortFinder: &TCPPortFinder{},
trellis: trellis,
ui: ui,
}
Expand All @@ -78,7 +87,10 @@ func (m *Manager) GetInstance(name string) (Instance, bool) {
}

func (m *Manager) CreateInstance(name string) error {
instance := m.newInstance(name)
instance, err := m.newInstance(name)
if err != nil {
return err
}

cmd := command.WithOptions(
command.WithTermOutput(),
Expand Down Expand Up @@ -172,7 +184,8 @@ func (m *Manager) StartInstance(name string) error {

instance.Username = string(user)

// Hydrate instance with data from limactl that is only available after starting (mainly the forwarded SSH local port)
// Hydrate instance with data from limactl that is only available after
// starting (mainly the forwarded local ports)
err = m.hydrateInstance(&instance)
if err != nil {
return err
Expand Down Expand Up @@ -232,7 +245,7 @@ func (m *Manager) initInstance(instance *Instance) {
instance.Sites = m.Sites
}

func (m *Manager) newInstance(name string) Instance {
func (m *Manager) newInstance(name string) (Instance, error) {
instance := Instance{Name: name}
m.initInstance(&instance)

Expand All @@ -249,9 +262,24 @@ func (m *Manager) newInstance(name string) Instance {
images = imagesFromVersion(m.trellis.CliConfig.Vm.Ubuntu)
}

config := Config{Images: images}
portForwards := []PortForward{}

if m.trellis.CliConfig.Vm.ForwardHttpPort {
httpForwardPort, err := m.PortFinder.Resolve()
if err != nil {
return Instance{}, fmt.Errorf("Could not find a local free port for HTTP forwarding: %v", err)
}

portForwards = append(portForwards, PortForward{
GuestPort: 80,
HostPort: httpForwardPort,
},
)
}

config := Config{Images: images, PortForwards: portForwards}
instance.Config = config
return instance
return instance, nil
}

func (m *Manager) createConfigPath() error {
Expand Down Expand Up @@ -329,3 +357,31 @@ func ensureRequirements() error {
func imagesFromVersion(version string) []Image {
return UbuntuImages[version]
}

func (p *TCPPortFinder) Resolve() (int, error) {
lAddr0, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:0")
if err != nil {
return 0, err
}

l, err := net.ListenTCP("tcp4", lAddr0)
if err != nil {
return 0, err
}

defer func() { _ = l.Close() }()
lAddr := l.Addr()

lTCPAddr, ok := lAddr.(*net.TCPAddr)
if !ok {
return 0, fmt.Errorf("expected *net.TCPAddr, got %v", lAddr)
}

port := lTCPAddr.Port

if port <= 0 {
return 0, fmt.Errorf("unexpected port %d", port)
}

return port, nil
}
23 changes: 22 additions & 1 deletion pkg/lima/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ type MockHostsResolver struct {
Hosts map[string]string
}

type MockPortFinder struct{}

func (p *MockPortFinder) Resolve() (int, error) {
return 60720, nil
}

func TestNewManager(t *testing.T) {
defer trellis.LoadFixtureProject(t)()
trellis := trellis.NewTrellis()
Expand Down Expand Up @@ -120,7 +126,13 @@ func TestNewInstanceUbuntuVersion(t *testing.T) {
t.Fatal(err)
}

instance := manager.newInstance("test")
manager.PortFinder = &MockPortFinder{}

instance, err := manager.newInstance("test")

if err != nil {
t.Fatal(err)
}

if instance.Name != "test" {
t.Errorf("expected instance name to be %q, got %q", "test", instance.Name)
Expand All @@ -133,6 +145,14 @@ func TestNewInstanceUbuntuVersion(t *testing.T) {
if instance.Config.Images[0].Alias != "focal" {
t.Errorf("expected instance config to have focal image, got %q", instance.Config.Images[0].Alias)
}

if len(instance.Config.PortForwards) != 1 {
t.Errorf("expected instance config to have 1 port forwards, got %d", len(instance.Config.PortForwards))
}

if instance.Config.PortForwards[0].GuestPort != 80 || instance.Config.PortForwards[0].HostPort != 60720 {
t.Errorf("expected instance config to have port forward guest 80 to host 60720, got guest %d to host %d", instance.Config.PortForwards[0].GuestPort, instance.Config.PortForwards[0].HostPort)
}
}
func TestInstances(t *testing.T) {
defer trellis.LoadFixtureProject(t)()
Expand Down Expand Up @@ -197,6 +217,7 @@ func TestCreateInstance(t *testing.T) {

hostsStorage := make(map[string]string)
manager.HostsResolver = &MockHostsResolver{Hosts: hostsStorage}
manager.PortFinder = &MockPortFinder{}

instanceName := "test"
sshPort := 60720
Expand Down
9 changes: 5 additions & 4 deletions trellis/trellis.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ var DefaultCliConfig = cli_config.Config{
Open: make(map[string]string),
VirtualenvIntegration: true,
Vm: cli_config.VmConfig{
Manager: "auto",
HostsResolver: "hosts_file",
Ubuntu: "24.04",
InstanceName: "",
Manager: "auto",
HostsResolver: "hosts_file",
Ubuntu: "24.04",
InstanceName: "",
ForwardHttpPort: true,
},
}

Expand Down
Loading