Skip to content
Closed
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
75 changes: 37 additions & 38 deletions pkg/driver/vz/vm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,28 +52,26 @@ type virtualMachineWrapper struct {
// Hold all *os.File created via socketpair() so that they won't get garbage collected. f.FD() gets invalid if f gets garbage collected.
var vmNetworkFiles = make([]*os.File, 1)

func startVM(ctx context.Context, inst *limatype.Instance, sshLocalPort int) (*virtualMachineWrapper, chan error, error) {
func startVM(ctx context.Context, inst *limatype.Instance, sshLocalPort int) (vm *virtualMachineWrapper, waitSSHLocalPortAccessible <-chan any, errCh chan error, err error) {
usernetClient, stopUsernet, err := startUsernet(ctx, inst)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}

machine, err := createVM(ctx, inst)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}

err = machine.Start()
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}

wrapper := &virtualMachineWrapper{VirtualMachine: machine, stopped: false}
notifySSHLocalPortAccessible := make(chan any)
sendErrCh := make(chan error)

errCh := make(chan error)

waitSSHLocalPortAccessible := make(chan struct{})
defer close(waitSSHLocalPortAccessible)
go func() {
// Handle errors via errCh and handle stop vm during context close
defer func() {
Expand All @@ -95,42 +93,44 @@ func startVM(ctx context.Context, inst *limatype.Instance, sshLocalPort int) (*v
pidFile := filepath.Join(inst.Dir, filenames.PIDFile(*inst.Config.VMType))
if _, err := os.Stat(pidFile); !errors.Is(err, os.ErrNotExist) {
logrus.Errorf("pidfile %q already exists", pidFile)
errCh <- err
sendErrCh <- err
}
if err := os.WriteFile(pidFile, []byte(strconv.Itoa(os.Getpid())+"\n"), 0o644); err != nil {
logrus.Errorf("error writing to pid fil %q", pidFile)
errCh <- err
sendErrCh <- err
}
logrus.Info("[VZ] - vm state change: running")

usernetSSHLocalPort := sshLocalPort
useSSHOverVsock := true
if envVar := os.Getenv("LIMA_SSH_OVER_VSOCK"); envVar != "" {
b, err := strconv.ParseBool(envVar)
if err != nil {
logrus.WithError(err).Warnf("invalid LIMA_SSH_OVER_VSOCK value %q", envVar)
} else {
useSSHOverVsock = b
go func() {
defer close(notifySSHLocalPortAccessible)
usernetSSHLocalPort := sshLocalPort
useSSHOverVsock := true
if envVar := os.Getenv("LIMA_SSH_OVER_VSOCK"); envVar != "" {
b, err := strconv.ParseBool(envVar)
if err != nil {
logrus.WithError(err).Warnf("invalid LIMA_SSH_OVER_VSOCK value %q", envVar)
} else {
useSSHOverVsock = b
}
}
}
if !useSSHOverVsock {
logrus.Info("LIMA_SSH_OVER_VSOCK is false, skipping detection of SSH server on vsock port")
} else if err := usernetClient.WaitOpeningSSHPort(ctx, inst); err == nil {
hostAddress := net.JoinHostPort(inst.SSHAddress, strconv.Itoa(usernetSSHLocalPort))
if err := wrapper.startVsockForwarder(ctx, 22, hostAddress); err == nil {
logrus.Infof("Detected SSH server is listening on the vsock port; changed %s to proxy for the vsock port", hostAddress)
usernetSSHLocalPort = 0 // disable gvisor ssh port forwarding
if !useSSHOverVsock {
logrus.Info("LIMA_SSH_OVER_VSOCK is false, skipping detection of SSH server on vsock port")
} else if err := usernetClient.WaitOpeningSSHPort(ctx, inst); err == nil {
hostAddress := net.JoinHostPort(inst.SSHAddress, strconv.Itoa(usernetSSHLocalPort))
if err := wrapper.startVsockForwarder(ctx, 22, hostAddress); err == nil {
logrus.Infof("Detected SSH server is listening on the vsock port; changed %s to proxy for the vsock port", hostAddress)
usernetSSHLocalPort = 0 // disable gvisor ssh port forwarding
} else {
logrus.WithError(err).Warn("Failed to detect SSH server on vsock port, falling back to usernet forwarder")
}
} else {
logrus.WithError(err).Warn("Failed to detect SSH server on vsock port, falling back to usernet forwarder")
logrus.WithError(err).Warn("Failed to wait for the guest SSH server to become available, falling back to usernet forwarder")
}
} else {
logrus.WithError(err).Warn("Failed to wait for the guest SSH server to become available, falling back to usernet forwarder")
}
err := usernetClient.ConfigureDriver(ctx, inst, usernetSSHLocalPort)
if err != nil {
errCh <- err
}
waitSSHLocalPortAccessible <- struct{}{}
err := usernetClient.ConfigureDriver(ctx, inst, usernetSSHLocalPort)
if err != nil {
sendErrCh <- err
}
}()
case vz.VirtualMachineStateStopped:
logrus.Info("[VZ] - vm state change: stopped")
wrapper.mu.Lock()
Expand All @@ -140,15 +140,14 @@ func startVM(ctx context.Context, inst *limatype.Instance, sshLocalPort int) (*v
if stopUsernet != nil {
stopUsernet()
}
errCh <- errors.New("vz driver state stopped")
sendErrCh <- errors.New("vz driver state stopped")
default:
logrus.Debugf("[VZ] - vm state change: %q", newState)
}
}
}
}()
<-waitSSHLocalPortAccessible
return wrapper, errCh, err
return wrapper, notifySSHLocalPortAccessible, sendErrCh, err
}

func startUsernet(ctx context.Context, inst *limatype.Instance) (*usernet.Client, context.CancelFunc, error) {
Expand Down
9 changes: 6 additions & 3 deletions pkg/driver/vz/vz_driver_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ type LimaVzDriver struct {
rosettaEnabled bool
rosettaBinFmt bool

machine *virtualMachineWrapper
machine *virtualMachineWrapper
waitSSHLocalPortAccessible <-chan any
}

var _ driver.Driver = (*LimaVzDriver)(nil)
Expand Down Expand Up @@ -298,14 +299,15 @@ func (l *LimaVzDriver) CreateDisk(ctx context.Context) error {

func (l *LimaVzDriver) Start(ctx context.Context) (chan error, error) {
logrus.Infof("Starting VZ (hint: to watch the boot progress, see %q)", filepath.Join(l.Instance.Dir, "serial*.log"))
vm, errCh, err := startVM(ctx, l.Instance, l.SSHLocalPort)
vm, waitSSHLocalPortAccessible, errCh, err := startVM(ctx, l.Instance, l.SSHLocalPort)
if err != nil {
if errors.Is(err, vz.ErrUnsupportedOSVersion) {
return nil, fmt.Errorf("vz driver requires macOS 13 or higher to run: %w", err)
}
return nil, err
}
l.machine = vm
l.waitSSHLocalPortAccessible = waitSSHLocalPortAccessible

return errCh, nil
}
Expand Down Expand Up @@ -380,7 +382,7 @@ func (l *LimaVzDriver) Info() driver.Info {
guiFlag = l.canRunGUI()
}
info.Features = driver.DriverFeatures{
DynamicSSHAddress: false,
DynamicSSHAddress: true,
SkipSocketForwarding: false,
CanRunGUI: guiFlag,
RosettaEnabled: l.rosettaEnabled,
Expand All @@ -390,6 +392,7 @@ func (l *LimaVzDriver) Info() driver.Info {
}

func (l *LimaVzDriver) SSHAddress(_ context.Context) (string, error) {
<-l.waitSSHLocalPortAccessible
return "127.0.0.1", nil
}

Expand Down
Loading