diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go index 1c372f7dd7f..ff2aa8c5540 100644 --- a/pkg/driver/driver.go +++ b/pkg/driver/driver.go @@ -88,6 +88,11 @@ type Driver interface { FillConfig(ctx context.Context, cfg *limatype.LimaYAML, filePath string) error SSHAddress(ctx context.Context) (string, error) + + // AdditionalSetupForSSH provides additional setup required for SSH connection. + // It is called after VM is started, before first SSH connection. + // It returns an error if the setup fails. + AdditionalSetupForSSH(ctx context.Context) error } type ConfiguredDriver struct { diff --git a/pkg/driver/external/client/methods.go b/pkg/driver/external/client/methods.go index b26114bed14..536d49b1221 100644 --- a/pkg/driver/external/client/methods.go +++ b/pkg/driver/external/client/methods.go @@ -323,3 +323,16 @@ func (d *DriverClient) BootScripts() (map[string][]byte, error) { d.logger.Debugf("Boot scripts retrieved successfully: %d scripts", len(resp.Scripts)) return resp.Scripts, nil } + +func (d *DriverClient) AdditionalSetupForSSH(ctx context.Context) error { + d.logger.Debug("Performing additional setup for SSH connection") + + _, err := d.DriverSvc.AdditionalSetupForSSH(ctx, &emptypb.Empty{}) + if err != nil { + d.logger.Errorf("Failed to perform additional setup for SSH: %v", err) + return err + } + + d.logger.Debug("Additional setup for SSH completed successfully") + return nil +} diff --git a/pkg/driver/external/driver.pb.desc b/pkg/driver/external/driver.pb.desc index 20d49355704..41cf0db379a 100644 --- a/pkg/driver/external/driver.pb.desc +++ b/pkg/driver/external/driver.pb.desc @@ -1,5 +1,5 @@ -� +� driver.protogoogle/protobuf/empty.proto"� BootScriptsResponse; scripts ( 2!.BootScriptsResponse.ScriptsEntryRscripts: @@ -30,7 +30,7 @@ connection") ListSnapshotsResponse snapshots ( R snapshots"B ForwardGuestAgentResponse% -should_forward (R shouldForward2� +should_forward (R shouldForward2� Driver: Validate.google.protobuf.Empty.google.protobuf.Empty8 Create.google.protobuf.Empty.google.protobuf.Empty< @@ -52,4 +52,5 @@ CreateDisk.google.protobuf.Empty.google.protobuf.Empty1 Configure.SetConfigRequest.google.protobuf.Empty- Info.google.protobuf.Empty .InfoResponse9 -SSHAddress.google.protobuf.Empty.SSHAddressResponseB0Z.github.com/lima-vm/lima/v2/pkg/driver/externalbproto3 \ No newline at end of file +SSHAddress.google.protobuf.Empty.SSHAddressResponseG +AdditionalSetupForSSH.google.protobuf.Empty.google.protobuf.EmptyB0Z.github.com/lima-vm/lima/v2/pkg/driver/externalbproto3 \ No newline at end of file diff --git a/pkg/driver/external/driver.pb.go b/pkg/driver/external/driver.pb.go index 60dc80ad3b7..bcef9b8aa4f 100644 --- a/pkg/driver/external/driver.pb.go +++ b/pkg/driver/external/driver.pb.go @@ -592,7 +592,7 @@ const file_driver_proto_rawDesc = "" + "\x15ListSnapshotsResponse\x12\x1c\n" + "\tsnapshots\x18\x01 \x01(\tR\tsnapshots\"B\n" + "\x19ForwardGuestAgentResponse\x12%\n" + - "\x0eshould_forward\x18\x01 \x01(\bR\rshouldForward2\xa9\t\n" + + "\x0eshould_forward\x18\x01 \x01(\bR\rshouldForward2\xf2\t\n" + "\x06Driver\x12:\n" + "\bValidate\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x128\n" + "\x06Create\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12<\n" + @@ -614,7 +614,8 @@ const file_driver_proto_rawDesc = "" + "\tConfigure\x12\x11.SetConfigRequest\x1a\x16.google.protobuf.Empty\x12-\n" + "\x04Info\x12\x16.google.protobuf.Empty\x1a\r.InfoResponse\x129\n" + "\n" + - "SSHAddress\x12\x16.google.protobuf.Empty\x1a\x13.SSHAddressResponseB0Z.github.com/lima-vm/lima/v2/pkg/driver/externalb\x06proto3" + "SSHAddress\x12\x16.google.protobuf.Empty\x1a\x13.SSHAddressResponse\x12G\n" + + "\x15AdditionalSetupForSSH\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.EmptyB0Z.github.com/lima-vm/lima/v2/pkg/driver/externalb\x06proto3" var ( file_driver_proto_rawDescOnce sync.Once @@ -666,27 +667,29 @@ var file_driver_proto_depIdxs = []int32{ 4, // 17: Driver.Configure:input_type -> SetConfigRequest 13, // 18: Driver.Info:input_type -> google.protobuf.Empty 13, // 19: Driver.SSHAddress:input_type -> google.protobuf.Empty - 13, // 20: Driver.Validate:output_type -> google.protobuf.Empty - 13, // 21: Driver.Create:output_type -> google.protobuf.Empty - 13, // 22: Driver.CreateDisk:output_type -> google.protobuf.Empty - 3, // 23: Driver.Start:output_type -> StartResponse - 13, // 24: Driver.Stop:output_type -> google.protobuf.Empty - 13, // 25: Driver.Delete:output_type -> google.protobuf.Empty - 0, // 26: Driver.BootScripts:output_type -> BootScriptsResponse - 13, // 27: Driver.RunGUI:output_type -> google.protobuf.Empty - 13, // 28: Driver.ChangeDisplayPassword:output_type -> google.protobuf.Empty - 6, // 29: Driver.GetDisplayConnection:output_type -> GetDisplayConnectionResponse - 13, // 30: Driver.CreateSnapshot:output_type -> google.protobuf.Empty - 13, // 31: Driver.ApplySnapshot:output_type -> google.protobuf.Empty - 13, // 32: Driver.DeleteSnapshot:output_type -> google.protobuf.Empty - 10, // 33: Driver.ListSnapshots:output_type -> ListSnapshotsResponse - 11, // 34: Driver.ForwardGuestAgent:output_type -> ForwardGuestAgentResponse - 13, // 35: Driver.GuestAgentConn:output_type -> google.protobuf.Empty - 13, // 36: Driver.Configure:output_type -> google.protobuf.Empty - 2, // 37: Driver.Info:output_type -> InfoResponse - 1, // 38: Driver.SSHAddress:output_type -> SSHAddressResponse - 20, // [20:39] is the sub-list for method output_type - 1, // [1:20] is the sub-list for method input_type + 13, // 20: Driver.AdditionalSetupForSSH:input_type -> google.protobuf.Empty + 13, // 21: Driver.Validate:output_type -> google.protobuf.Empty + 13, // 22: Driver.Create:output_type -> google.protobuf.Empty + 13, // 23: Driver.CreateDisk:output_type -> google.protobuf.Empty + 3, // 24: Driver.Start:output_type -> StartResponse + 13, // 25: Driver.Stop:output_type -> google.protobuf.Empty + 13, // 26: Driver.Delete:output_type -> google.protobuf.Empty + 0, // 27: Driver.BootScripts:output_type -> BootScriptsResponse + 13, // 28: Driver.RunGUI:output_type -> google.protobuf.Empty + 13, // 29: Driver.ChangeDisplayPassword:output_type -> google.protobuf.Empty + 6, // 30: Driver.GetDisplayConnection:output_type -> GetDisplayConnectionResponse + 13, // 31: Driver.CreateSnapshot:output_type -> google.protobuf.Empty + 13, // 32: Driver.ApplySnapshot:output_type -> google.protobuf.Empty + 13, // 33: Driver.DeleteSnapshot:output_type -> google.protobuf.Empty + 10, // 34: Driver.ListSnapshots:output_type -> ListSnapshotsResponse + 11, // 35: Driver.ForwardGuestAgent:output_type -> ForwardGuestAgentResponse + 13, // 36: Driver.GuestAgentConn:output_type -> google.protobuf.Empty + 13, // 37: Driver.Configure:output_type -> google.protobuf.Empty + 2, // 38: Driver.Info:output_type -> InfoResponse + 1, // 39: Driver.SSHAddress:output_type -> SSHAddressResponse + 13, // 40: Driver.AdditionalSetupForSSH:output_type -> google.protobuf.Empty + 21, // [21:41] is the sub-list for method output_type + 1, // [1:21] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name diff --git a/pkg/driver/external/driver.proto b/pkg/driver/external/driver.proto index 743cd491904..9496ae6f945 100644 --- a/pkg/driver/external/driver.proto +++ b/pkg/driver/external/driver.proto @@ -28,6 +28,10 @@ service Driver { rpc Configure(SetConfigRequest) returns (google.protobuf.Empty); rpc Info(google.protobuf.Empty) returns (InfoResponse); rpc SSHAddress(google.protobuf.Empty) returns (SSHAddressResponse); + + // AdditionalSetupForSSH provides additional setup required for SSH connection. + // It is called after VM is started, before first SSH connection. + rpc AdditionalSetupForSSH(google.protobuf.Empty) returns (google.protobuf.Empty); } message BootScriptsResponse { diff --git a/pkg/driver/external/driver_grpc.pb.go b/pkg/driver/external/driver_grpc.pb.go index 01b2a0f1005..c2ed342be5f 100644 --- a/pkg/driver/external/driver_grpc.pb.go +++ b/pkg/driver/external/driver_grpc.pb.go @@ -39,6 +39,7 @@ const ( Driver_Configure_FullMethodName = "/Driver/Configure" Driver_Info_FullMethodName = "/Driver/Info" Driver_SSHAddress_FullMethodName = "/Driver/SSHAddress" + Driver_AdditionalSetupForSSH_FullMethodName = "/Driver/AdditionalSetupForSSH" ) // DriverClient is the client API for Driver service. @@ -64,6 +65,9 @@ type DriverClient interface { Configure(ctx context.Context, in *SetConfigRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) Info(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*InfoResponse, error) SSHAddress(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SSHAddressResponse, error) + // AdditionalSetupForSSH provides additional setup required for SSH connection. + // It is called after VM is started, before first SSH connection. + AdditionalSetupForSSH(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) } type driverClient struct { @@ -273,6 +277,16 @@ func (c *driverClient) SSHAddress(ctx context.Context, in *emptypb.Empty, opts . return out, nil } +func (c *driverClient) AdditionalSetupForSSH(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, Driver_AdditionalSetupForSSH_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // DriverServer is the server API for Driver service. // All implementations must embed UnimplementedDriverServer // for forward compatibility. @@ -296,6 +310,9 @@ type DriverServer interface { Configure(context.Context, *SetConfigRequest) (*emptypb.Empty, error) Info(context.Context, *emptypb.Empty) (*InfoResponse, error) SSHAddress(context.Context, *emptypb.Empty) (*SSHAddressResponse, error) + // AdditionalSetupForSSH provides additional setup required for SSH connection. + // It is called after VM is started, before first SSH connection. + AdditionalSetupForSSH(context.Context, *emptypb.Empty) (*emptypb.Empty, error) mustEmbedUnimplementedDriverServer() } @@ -363,6 +380,9 @@ func (UnimplementedDriverServer) Info(context.Context, *emptypb.Empty) (*InfoRes func (UnimplementedDriverServer) SSHAddress(context.Context, *emptypb.Empty) (*SSHAddressResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SSHAddress not implemented") } +func (UnimplementedDriverServer) AdditionalSetupForSSH(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method AdditionalSetupForSSH not implemented") +} func (UnimplementedDriverServer) mustEmbedUnimplementedDriverServer() {} func (UnimplementedDriverServer) testEmbeddedByValue() {} @@ -719,6 +739,24 @@ func _Driver_SSHAddress_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Driver_AdditionalSetupForSSH_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverServer).AdditionalSetupForSSH(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Driver_AdditionalSetupForSSH_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverServer).AdditionalSetupForSSH(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + // Driver_ServiceDesc is the grpc.ServiceDesc for Driver service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -798,6 +836,10 @@ var Driver_ServiceDesc = grpc.ServiceDesc{ MethodName: "SSHAddress", Handler: _Driver_SSHAddress_Handler, }, + { + MethodName: "AdditionalSetupForSSH", + Handler: _Driver_AdditionalSetupForSSH_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/pkg/driver/external/server/methods.go b/pkg/driver/external/server/methods.go index 44fdcc54fd4..aaa3b33e409 100644 --- a/pkg/driver/external/server/methods.go +++ b/pkg/driver/external/server/methods.go @@ -284,3 +284,14 @@ func (s *DriverServer) ForwardGuestAgent(_ context.Context, _ *emptypb.Empty) (* s.logger.Debug("Received ForwardGuestAgent request") return &pb.ForwardGuestAgentResponse{ShouldForward: s.driver.ForwardGuestAgent()}, nil } + +func (s *DriverServer) AdditionalSetupForSSH(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) { + s.logger.Debug("Received AdditionalSetupForSSH request") + err := s.driver.AdditionalSetupForSSH(ctx) + if err != nil { + s.logger.Errorf("AdditionalSetupForSSH failed: %v", err) + return &emptypb.Empty{}, err + } + s.logger.Debug("AdditionalSetupForSSH succeeded") + return &emptypb.Empty{}, nil +} diff --git a/pkg/driver/krunkit/krunkit_driver_darwin_arm64.go b/pkg/driver/krunkit/krunkit_driver_darwin_arm64.go index 9a712220da2..af457d0a3c0 100644 --- a/pkg/driver/krunkit/krunkit_driver_darwin_arm64.go +++ b/pkg/driver/krunkit/krunkit_driver_darwin_arm64.go @@ -353,3 +353,7 @@ func (l *LimaKrunkitDriver) Unregister(_ context.Context) error { func (l *LimaKrunkitDriver) GuestAgentConn(_ context.Context) (net.Conn, string, error) { return nil, "unix", nil } + +func (l *LimaKrunkitDriver) AdditionalSetupForSSH(_ context.Context) error { + return nil +} diff --git a/pkg/driver/qemu/qemu_driver.go b/pkg/driver/qemu/qemu_driver.go index 339bca2c9b2..5dd4bce6be1 100644 --- a/pkg/driver/qemu/qemu_driver.go +++ b/pkg/driver/qemu/qemu_driver.go @@ -720,3 +720,7 @@ func (l *LimaQemuDriver) ForwardGuestAgent() bool { // if driver is not providing, use host agent return l.vSockPort == 0 && l.virtioPort == "" } + +func (l *LimaQemuDriver) AdditionalSetupForSSH(_ context.Context) error { + return nil +} diff --git a/pkg/driver/vz/vm_darwin.go b/pkg/driver/vz/vm_darwin.go index ec45e39832f..15cff0444e3 100644 --- a/pkg/driver/vz/vm_darwin.go +++ b/pkg/driver/vz/vm_darwin.go @@ -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() { @@ -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() @@ -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) { diff --git a/pkg/driver/vz/vz_driver_darwin.go b/pkg/driver/vz/vz_driver_darwin.go index 927e9b90d26..0cc05dc00f3 100644 --- a/pkg/driver/vz/vz_driver_darwin.go +++ b/pkg/driver/vz/vz_driver_darwin.go @@ -80,7 +80,8 @@ type LimaVzDriver struct { rosettaEnabled bool rosettaBinFmt bool - machine *virtualMachineWrapper + machine *virtualMachineWrapper + waitSSHLocalPortAccessible <-chan any } var _ driver.Driver = (*LimaVzDriver)(nil) @@ -298,7 +299,7 @@ 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) @@ -306,6 +307,7 @@ func (l *LimaVzDriver) Start(ctx context.Context) (chan error, error) { return nil, err } l.machine = vm + l.waitSSHLocalPortAccessible = waitSSHLocalPortAccessible return errCh, nil } @@ -437,3 +439,8 @@ func (l *LimaVzDriver) ForwardGuestAgent() bool { // If driver is not providing, use host agent return l.vSockPort == 0 && l.virtioPort == "" } + +func (l *LimaVzDriver) AdditionalSetupForSSH(_ context.Context) error { + <-l.waitSSHLocalPortAccessible + return nil +} diff --git a/pkg/driver/wsl2/wsl_driver_windows.go b/pkg/driver/wsl2/wsl_driver_windows.go index 4468dbf554e..f19ba49192c 100644 --- a/pkg/driver/wsl2/wsl_driver_windows.go +++ b/pkg/driver/wsl2/wsl_driver_windows.go @@ -357,3 +357,7 @@ func (l *LimaWslDriver) ForwardGuestAgent() bool { // If driver is not providing, use host agent return l.vSockPort == 0 && l.virtioPort == "" } + +func (l *LimaWslDriver) AdditionalSetupForSSH(_ context.Context) error { + return nil +} diff --git a/pkg/hostagent/hostagent.go b/pkg/hostagent/hostagent.go index 5172d0ccb18..66b947b9cd4 100644 --- a/pkg/hostagent/hostagent.go +++ b/pkg/hostagent/hostagent.go @@ -380,6 +380,10 @@ func (a *HostAgent) Run(ctx context.Context) error { return err } + if err := a.driver.AdditionalSetupForSSH(ctx); err != nil { + return err + } + // WSL instance SSH address isn't known until after VM start if a.driver.Info().Features.DynamicSSHAddress { sshAddr, err := a.driver.SSHAddress(ctx) diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 8e783f44994..a4e306a0138 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -52,6 +52,7 @@ func (m *mockDriver) FillConfig(_ context.Context, _ *limatype.LimaYAML, _ strin func (m *mockDriver) InspectStatus(_ context.Context, _ *limatype.Instance) string { return "" } func (m *mockDriver) SSHAddress(_ context.Context) (string, error) { return "", nil } func (m *mockDriver) BootScripts() (map[string][]byte, error) { return nil, nil } +func (m *mockDriver) AdditionalSetupForSSH(_ context.Context) error { return nil } func TestRegister(t *testing.T) { BackupRegistry(t)