From ff7d287fc056eac3265c78665ceae7fce4c5994d Mon Sep 17 00:00:00 2001 From: Jake Correnti Date: Mon, 24 Jul 2023 10:19:04 -0400 Subject: [PATCH] Breakup AppleHV machine funcs The functions for AppleHV's VM interface implementation (machine.go) had quite large functions. Pulls out some code that could be moved to its own function for easier readability and maintainability. [NO NEW TESTS NEEDED] Signed-off-by: Jake Correnti --- pkg/machine/applehv/machine.go | 539 ++++++++++++++++++++------------- 1 file changed, 336 insertions(+), 203 deletions(-) diff --git a/pkg/machine/applehv/machine.go b/pkg/machine/applehv/machine.go index bf0efb8e68..48c76df4fa 100644 --- a/pkg/machine/applehv/machine.go +++ b/pkg/machine/applehv/machine.go @@ -79,32 +79,21 @@ type MacMachine struct { GvProxySock machine.VMFile } -func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { - var ( - key string - mounts []machine.Mount - virtiofsMnts []machine.VirtIoFs - ) - dataDir, err := machine.GetDataDir(machine.AppleHvVirt) - if err != nil { - return false, err - } - cfg, err := config.Default() - if err != nil { - return false, err - } - +// acquireVMImage determines if the image is already in a FCOS stream. If so, +// retrives the image path of the uncompressed file. Otherwise, the user has +// provided an alternative image, so we set the image path and download the image. +func (m *MacMachine) acquireVMImage(opts machine.InitOptions, dataDir string) error { // Acquire the image switch opts.ImagePath { case machine.Testing.String(), machine.Next.String(), machine.Stable.String(), "": - g, err := machine.NewGenericDownloader(machine.HyperVVirt, opts.Name, opts.ImagePath) + g, err := machine.NewGenericDownloader(vmtype, opts.Name, opts.ImagePath) if err != nil { - return false, err + return err } imagePath, err := machine.NewMachineFile(g.Get().GetLocalUncompressedFile(dataDir), nil) if err != nil { - return false, err + return err } m.ImagePath = *imagePath default: @@ -113,87 +102,81 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { m.ImageStream = "custom" g, err := machine.NewGenericDownloader(vmtype, m.Name, opts.ImagePath) if err != nil { - return false, err + return err } imagePath, err := machine.NewMachineFile(g.Get().LocalUncompressedFile, nil) if err != nil { - return false, err + return err } m.ImagePath = *imagePath if err := machine.DownloadImage(g); err != nil { - return false, err + return err } } + return nil +} - logPath, err := machine.NewMachineFile(filepath.Join(dataDir, fmt.Sprintf("%s.log", m.Name)), nil) - if err != nil { - return false, err - } - m.LogPath = *logPath - runtimeDir, err := m.getRuntimeDir() - if err != nil { - return false, err - } - - readySocket, err := machine.NewMachineFile(filepath.Join(runtimeDir, fmt.Sprintf("%s_ready.sock", m.Name)), nil) - if err != nil { - return false, err - } - +// setGVProxyInfo sets the VM's gvproxy pid and socket files +func (m *MacMachine) setGVProxyInfo(runtimeDir string) error { gvProxyPid, err := machine.NewMachineFile(filepath.Join(runtimeDir, "gvproxy.pid"), nil) if err != nil { - return false, err + return err } gvProxySock, err := machine.NewMachineFile(filepath.Join(runtimeDir, "gvproxy.sock"), nil) if err != nil { - return false, err + return err } + m.GvProxyPid = *gvProxyPid + m.GvProxySock = *gvProxySock + + return nil +} + +// setVfkitInfo stores the default devices, sets the vfkit endpoint, and +// locates/stores the path to the binary +func (m *MacMachine) setVfkitInfo(cfg *config.Config, readySocket machine.VMFile) error { defaultDevices, err := getDefaultDevices(m.ImagePath.GetPath(), m.LogPath.GetPath(), readySocket.GetPath()) if err != nil { - return false, err + return err } // Store VFKit stuffs vfkitPath, err := cfg.FindHelperBinary("vfkit", false) if err != nil { - return false, err + return err } vfkitBinaryPath, err := machine.NewMachineFile(vfkitPath, nil) if err != nil { - return false, err + return err } - m.ReadySocket = *readySocket - m.GvProxyPid = *gvProxyPid - m.GvProxySock = *gvProxySock m.Vfkit.VirtualMachine.Devices = defaultDevices m.Vfkit.Endpoint = defaultVFKitEndpoint m.Vfkit.VfkitBinaryPath = vfkitBinaryPath - m.IdentityPath = util.GetIdentityPath(m.Name) - m.Rootful = opts.Rootful - m.RemoteUsername = opts.Username - - m.UID = os.Getuid() - - sshPort, err := utils.GetRandomPort() - if err != nil { - return false, err - } - m.Port = sshPort + return nil +} +// addMountsToVM converts the volumes passed through the CLI to virtio-fs mounts +// and adds them to the machine +func (m *MacMachine) addMountsToVM(opts machine.InitOptions, virtiofsMnts *[]machine.VirtIoFs) error { + mounts := []machine.Mount{} for _, volume := range opts.Volumes { source, target, _, readOnly, err := machine.ParseVolumeFromPath(volume) if err != nil { - return false, err + return err } mnt := machine.NewVirtIoFsMount(source, target, readOnly) - virtiofsMnts = append(virtiofsMnts, mnt) + *virtiofsMnts = append(*virtiofsMnts, mnt) mounts = append(mounts, mnt.ToMount()) } m.Mounts = mounts + return nil +} + +func (m *MacMachine) addSSHConnectionsToPodmanSocket(opts machine.InitOptions) error { if len(opts.IgnitionPath) < 1 { // TODO localhost needs to be restored here uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", fmt.Sprintf("/run/user/%d/podman/podman.sock", m.UID), strconv.Itoa(m.Port), m.RemoteUsername) @@ -211,13 +194,123 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { for i := 0; i < 2; i++ { if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil { - return false, err + return err } } } else { fmt.Println("An ignition path was provided. No SSH connection was added to Podman") } + return nil +} + +// writeIgnitionConfigFile generates the ignition config and writes it to the filesystem +func (m *MacMachine) writeIgnitionConfigFile(opts machine.InitOptions, key string, virtiofsMnts *[]machine.VirtIoFs) error { + // Write the ignition file + ign := machine.DynamicIgnition{ + Name: opts.Username, + Key: key, + VMName: m.Name, + VMType: machine.AppleHvVirt, + TimeZone: opts.TimeZone, + WritePath: m.IgnitionFile.GetPath(), + UID: m.UID, + Rootful: m.Rootful, + } + + if err := ign.GenerateIgnitionConfig(); err != nil { + return err + } + + // ready is a unit file that sets up the virtual serial device + // where when the VM is done configuring, it will send an ack + // so a listening host knows it can being interacting with it + ready := `[Unit] + Requires=dev-virtio\\x2dports-%s.device + After=remove-moby.service sshd.socket sshd.service + OnFailure=emergency.target + OnFailureJobMode=isolate + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStart=/bin/sh -c '/usr/bin/echo Ready | socat - VSOCK-CONNECT:2:1025' + [Install] + RequiredBy=default.target + ` + readyUnit := machine.Unit{ + Enabled: machine.BoolToPtr(true), + Name: "ready.service", + Contents: machine.StrToPtr(fmt.Sprintf(ready, "vsock")), + } + virtiofsUnits := generateSystemDFilesForVirtiofsMounts(*virtiofsMnts) + ign.Cfg.Systemd.Units = append(ign.Cfg.Systemd.Units, readyUnit) + ign.Cfg.Systemd.Units = append(ign.Cfg.Systemd.Units, virtiofsUnits...) + + return ign.Write() +} + +func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { + var ( + key string + virtiofsMnts []machine.VirtIoFs + ) + dataDir, err := machine.GetDataDir(machine.AppleHvVirt) + if err != nil { + return false, err + } + cfg, err := config.Default() + if err != nil { + return false, err + } + + if err := m.acquireVMImage(opts, dataDir); err != nil { + return false, err + } + + logPath, err := machine.NewMachineFile(filepath.Join(dataDir, fmt.Sprintf("%s.log", m.Name)), nil) + if err != nil { + return false, err + } + m.LogPath = *logPath + runtimeDir, err := m.getRuntimeDir() + if err != nil { + return false, err + } + + readySocket, err := machine.NewMachineFile(filepath.Join(runtimeDir, fmt.Sprintf("%s_ready.sock", m.Name)), nil) + if err != nil { + return false, err + } + m.ReadySocket = *readySocket + + if err := m.setGVProxyInfo(runtimeDir); err != nil { + return false, err + } + + if err := m.setVfkitInfo(cfg, m.ReadySocket); err != nil { + return false, err + } + + m.IdentityPath = util.GetIdentityPath(m.Name) + m.Rootful = opts.Rootful + m.RemoteUsername = opts.Username + + m.UID = os.Getuid() + + sshPort, err := utils.GetRandomPort() + if err != nil { + return false, err + } + m.Port = sshPort + + if err := m.addMountsToVM(opts, &virtiofsMnts); err != nil { + return false, err + } + + if err := m.addSSHConnectionsToPodmanSocket(opts); err != nil { + return false, err + } + // Until the disk resize can be fixed, we ignore it if err := m.resizeDisk(opts.DiskSize); err != nil && !errors.Is(err, define.ErrNotImplemented) { return false, err @@ -243,52 +336,8 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { return false, os.WriteFile(m.IgnitionFile.GetPath(), inputIgnition, 0644) } // TODO Ignition stuff goes here - // Write the ignition file - - ign := machine.DynamicIgnition{ - Name: opts.Username, - Key: key, - VMName: m.Name, - VMType: machine.AppleHvVirt, - TimeZone: opts.TimeZone, - WritePath: m.IgnitionFile.GetPath(), - UID: m.UID, - Rootful: m.Rootful, - } - - if err := ign.GenerateIgnitionConfig(); err != nil { - return false, err - } - - // ready is a unit file that sets up the virtual serial device - // where when the VM is done configuring, it will send an ack - // so a listening host knows it can being interacting with it - ready := `[Unit] - Requires=dev-virtio\\x2dports-%s.device - After=remove-moby.service sshd.socket sshd.service - OnFailure=emergency.target - OnFailureJobMode=isolate - [Service] - Type=oneshot - RemainAfterExit=yes - ExecStart=/bin/sh -c '/usr/bin/echo Ready | socat - VSOCK-CONNECT:2:1025' - [Install] - RequiredBy=default.target - ` - readyUnit := machine.Unit{ - Enabled: machine.BoolToPtr(true), - Name: "ready.service", - Contents: machine.StrToPtr(fmt.Sprintf(ready, "vsock")), - } - virtiofsUnits := generateSystemDFilesForVirtiofsMounts(virtiofsMnts) - ign.Cfg.Systemd.Units = append(ign.Cfg.Systemd.Units, readyUnit) - ign.Cfg.Systemd.Units = append(ign.Cfg.Systemd.Units, virtiofsUnits...) - - if err := ign.Write(); err != nil { - return false, err - } - - return true, nil + err = m.writeIgnitionConfigFile(opts, key, &virtiofsMnts) + return err == nil, err } func (m *MacMachine) Inspect() (*machine.InspectInfo, error) { @@ -321,24 +370,9 @@ func (m *MacMachine) Inspect() (*machine.InspectInfo, error) { return &ii, nil } -func (m *MacMachine) Remove(name string, opts machine.RemoveOptions) (string, func() error, error) { - var ( - files []string - ) - - vmState, err := m.Vfkit.state() - if err != nil { - return "", nil, err - } - if vmState == machine.Running { - if !opts.Force { - return "", nil, fmt.Errorf("invalid state: %s is running", m.Name) - } - if err := m.Vfkit.stop(true, true); err != nil { - return "", nil, err - } - } - +// collectFilesToDestroy retrieves the files that will be destroyed by `Remove` +func (m *MacMachine) collectFilesToDestroy(opts machine.RemoveOptions) []string { + files := []string{} if !opts.SaveKeys { files = append(files, m.IdentityPath, m.IdentityPath+".pub") } @@ -351,6 +385,45 @@ func (m *MacMachine) Remove(name string, opts machine.RemoveOptions) (string, fu } files = append(files, m.ConfigPath.GetPath()) + return files +} + +// removeFilesAndConnections removes any files and connections associated with +// the machine during `Remove` +func (m *MacMachine) removeFilesAndConnections(files []string) { + for _, f := range files { + if err := os.Remove(f); err != nil && !errors.Is(err, os.ErrNotExist) { + logrus.Error(err) + } + } + if err := machine.RemoveConnections(m.Name); err != nil { + logrus.Error(err) + } + if err := machine.RemoveConnections(m.Name + "-root"); err != nil { + logrus.Error(err) + } +} + +func (m *MacMachine) Remove(name string, opts machine.RemoveOptions) (string, func() error, error) { + var ( + files []string + ) + + vmState, err := m.Vfkit.state() + if err != nil { + return "", nil, err + } + + if vmState == machine.Running { + if !opts.Force { + return "", nil, fmt.Errorf("invalid state: %s is running", m.Name) + } + if err := m.Vfkit.stop(true, true); err != nil { + return "", nil, err + } + } + + files = m.collectFilesToDestroy(opts) confirmationMessage := "\nThe following files will be deleted:\n\n" for _, msg := range files { @@ -359,18 +432,7 @@ func (m *MacMachine) Remove(name string, opts machine.RemoveOptions) (string, fu confirmationMessage += "\n" return confirmationMessage, func() error { - for _, f := range files { - if err := os.Remove(f); err != nil && !errors.Is(err, os.ErrNotExist) { - logrus.Error(err) - } - } - if err := machine.RemoveConnections(m.Name); err != nil { - logrus.Error(err) - } - if err := machine.RemoveConnections(m.Name + "-root"); err != nil { - logrus.Error(err) - } - + m.removeFilesAndConnections(files) // TODO We will need something like this for applehv too i think /* // Remove the HVSOCK for networking @@ -451,6 +513,73 @@ func (m *MacMachine) SSH(name string, opts machine.SSHOptions) error { return machine.CommonSSH(username, m.IdentityPath, m.Name, m.Port, opts.Args) } +// deleteIgnitionSocket retrieves the ignition socket, deletes it, and returns a +// pointer to the `VMFile` +func (m *MacMachine) deleteIgnitionSocket() (*machine.VMFile, error) { + ignitionSocket, err := m.getIgnitionSock() + if err != nil { + return nil, err + } + if err := ignitionSocket.Delete(); err != nil { + return nil, err + } + return ignitionSocket, nil +} + +// getIgnitionVsockDeviceAsCLI retrieves the ignition vsock device and converts +// it to a cmdline format +func getIgnitionVsockDeviceAsCLI(ignitionSocketPath string) ([]string, error) { + ignitionVsockDevice, err := getIgnitionVsockDevice(ignitionSocketPath) + if err != nil { + return nil, err + } + // Convert the device into cli args + ignitionVsockDeviceCLI, err := ignitionVsockDevice.ToCmdLine() + if err != nil { + return nil, err + } + return ignitionVsockDeviceCLI, nil +} + +// getDebugDevicesCMDArgs retrieves the debug devices and converts them to a +// cmdline format +func getDebugDevicesCMDArgs() ([]string, error) { + args := []string{} + debugDevices, err := getDebugDevices() + if err != nil { + return nil, err + } + for _, debugDevice := range debugDevices { + debugCli, err := debugDevice.ToCmdLine() + if err != nil { + return nil, err + } + args = append(args, debugCli...) + } + return args, nil +} + +// getVfKitEndpointCMDArgs converts the vfkit endpoint to a cmdline format +func getVfKitEndpointCMDArgs(endpoint string) ([]string, error) { + restEndpoint, err := vfRest.NewEndpoint(endpoint) + if err != nil { + return nil, err + } + return restEndpoint.ToCmdLine() +} + +// addVolumesToVfKit adds the VM's mounts to vfkit's devices +func (m *MacMachine) addVolumesToVfKit() error { + for _, vol := range m.Mounts { + virtfsDevice, err := vfConfig.VirtioFsNew(vol.Source, vol.Tag) + if err != nil { + return err + } + m.Vfkit.VirtualMachine.Devices = append(m.Vfkit.VirtualMachine.Devices, virtfsDevice) + } + return nil +} + func (m *MacMachine) Start(name string, opts machine.StartOptions) error { var ignitionSocket *machine.VMFile @@ -458,6 +587,7 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error { if err != nil { return err } + if st == machine.Running { return machine.ErrVMAlreadyRunning } @@ -484,12 +614,8 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error { m.Vfkit.VirtualMachine.Devices = append(m.Vfkit.VirtualMachine.Devices, netDevice) - for _, vol := range m.Mounts { - virtfsDevice, err := vfConfig.VirtioFsNew(vol.Source, vol.Tag) - if err != nil { - return err - } - m.Vfkit.VirtualMachine.Devices = append(m.Vfkit.VirtualMachine.Devices, virtfsDevice) + if err := m.addVolumesToVfKit(); err != nil { + return err } // To start the VM, we need to call vfkit @@ -499,55 +625,41 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error { return err } - restEndpoint, err := vfRest.NewEndpoint(m.Vfkit.Endpoint) + vfkitEndpointArgs, err := getVfKitEndpointCMDArgs(m.Vfkit.Endpoint) if err != nil { return err } - restArgs, err := restEndpoint.ToCmdLine() - if err != nil { - return err - } - cmd.Args = append(cmd.Args, restArgs...) + cmd.Args = append(cmd.Args, vfkitEndpointArgs...) firstBoot, err := m.isFirstBoot() if err != nil { return err } + if firstBoot { // If this is the first boot of the vm, we need to add the vsock // device to vfkit so we can inject the ignition file - ignitionSocket, err = m.getIgnitionSock() + ignitionSocket, err = m.deleteIgnitionSocket() if err != nil { return err } - if err := ignitionSocket.Delete(); err != nil { - return err - } - ignitionVsockDevice, err := getIgnitionVsockDevice(ignitionSocket.GetPath()) + + ignitionVsockDeviceCLI, err := getIgnitionVsockDeviceAsCLI(ignitionSocket.GetPath()) if err != nil { return err } - // Convert the device into cli args - ignitionVsockDeviceCli, err := ignitionVsockDevice.ToCmdLine() - if err != nil { - return err - } - cmd.Args = append(cmd.Args, ignitionVsockDeviceCli...) + cmd.Args = append(cmd.Args, ignitionVsockDeviceCLI...) } + if logrus.IsLevelEnabled(logrus.DebugLevel) { - debugDevices, err := getDebugDevices() + debugDevArgs, err := getDebugDevicesCMDArgs() if err != nil { return err } - for _, debugDevice := range debugDevices { - debugCli, err := debugDevice.ToCmdLine() - if err != nil { - return err - } - cmd.Args = append(cmd.Args, debugCli...) - } + cmd.Args = append(cmd.Args, debugDevArgs...) cmd.Args = append(cmd.Args, "--gui") // add command line switch to pop the gui open } + cmd.ExtraFiles = []*os.File{ioEater, ioEater, ioEater} fmt.Println(cmd.Args) @@ -566,14 +678,17 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error { logrus.Debug("ignition vsock server exited") }() } + if err := m.ReadySocket.Delete(); err != nil { return err } + logrus.Debugf("listening for ready on: %s", m.ReadySocket.GetPath()) readyListen, err := net.Listen("unix", m.ReadySocket.GetPath()) if err != nil { return err } + logrus.Debug("waiting for ready notification") var conn net.Conn readyChan := make(chan error) @@ -585,6 +700,7 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error { _, err = bufio.NewReader(conn).ReadString('\n') readyChan <- err }() + if err := cmd.Start(); err != nil { return err } @@ -598,6 +714,7 @@ func (m *MacMachine) Start(name string, opts machine.StartOptions) error { if err != nil { return err } + logrus.Debug("ready notification received") m.waitAPIAndPrintInfo(forwardState, forwardSock, opts.NoInfo) return nil @@ -611,41 +728,45 @@ func (m *MacMachine) State(_ bool) (machine.Status, error) { return vmStatus, nil } +// cleanupGVProxy finds the gvproxy process, kills it, and deletes the +// pidfile +func (m *MacMachine) cleanupGVProxy() { + gvPid, err := m.GvProxyPid.Read() + if err != nil { + logrus.Error(fmt.Errorf("unable to read gvproxy pid file %s: %v", m.GvProxyPid.GetPath(), err)) + return + } + proxyPid, err := strconv.Atoi(string(gvPid)) + if err != nil { + logrus.Error(fmt.Errorf("unable to convert pid to integer: %v", err)) + return + } + proxyProc, err := os.FindProcess(proxyPid) + if proxyProc == nil && err != nil { + logrus.Error("unable to find process: %v", err) + return + } + if err := proxyProc.Kill(); err != nil { + logrus.Error("unable to kill gvproxy: %v", err) + return + } + // gvproxy does not clean up its pid file on exit + if err := m.GvProxyPid.Delete(); err != nil { + logrus.Error("unable to delete gvproxy pid file: %v", err) + } +} + func (m *MacMachine) Stop(name string, opts machine.StopOptions) error { vmState, err := m.State(false) if err != nil { return err } + if vmState != machine.Running { return machine.ErrWrongState } - defer func() { - // I think "soft" errors here is OK - gvPid, err := m.GvProxyPid.Read() - if err != nil { - logrus.Error(fmt.Errorf("unable to read gvproxy pid file %s: %v", m.GvProxyPid.GetPath(), err)) - return - } - proxyPid, err := strconv.Atoi(string(gvPid)) - if err != nil { - logrus.Error(fmt.Errorf("unable to convert pid to integer: %v", err)) - return - } - proxyProc, err := os.FindProcess(proxyPid) - if proxyProc == nil && err != nil { - logrus.Error("unable to find process: %v", err) - return - } - if err := proxyProc.Kill(); err != nil { - logrus.Error("unable to kill gvproxy: %v", err) - return - } - // gvproxy does not clean up its pid file on exit - if err := m.GvProxyPid.Delete(); err != nil { - logrus.Error("unable to delete gvproxy pid file: %v", err) - } - }() + defer m.cleanupGVProxy() return m.Vfkit.stop(false, true) } @@ -655,6 +776,7 @@ func (m *MacMachine) Stop(name string, opts machine.StopOptions) error { func getVMConfigPath(configDir, vmName string) string { return filepath.Join(configDir, fmt.Sprintf("%s.json", vmName)) } + func (m *MacMachine) loadFromFile() (*MacMachine, error) { if len(m.Name) < 1 { return nil, errors.New("encountered machine with no name") @@ -758,6 +880,26 @@ func getVMInfos() ([]*machine.ListResponse, error) { return listed, err } +// setupStartHostNetworkingCmd generates the cmd that will be used to start the +// host networking. Includes the ssh port, gvproxy pid file, gvproxy socket, and +// a debug flag depending on the logrus log level +func (m *MacMachine) setupStartHostNetworkingCmd(gvProxyBinary, forwardSock string, state machine.APIForwardingState) []string { + cmd := []string{gvProxyBinary} + // Add the ssh port + cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", m.Port)}...) + // Add pid file + cmd = append(cmd, "-pid-file", m.GvProxyPid.GetPath()) + // Add vfkit proxy listen + cmd = append(cmd, "-listen-vfkit", fmt.Sprintf("unixgram://%s", m.GvProxySock.GetPath())) + cmd, forwardSock, state = m.setupAPIForwarding(cmd) + if logrus.GetLevel() == logrus.DebugLevel { + cmd = append(cmd, "--debug") + fmt.Println(cmd) + } + + return cmd +} + func (m *MacMachine) startHostNetworking(ioEater *os.File) (string, machine.APIForwardingState, error) { var ( forwardSock string @@ -792,6 +934,7 @@ func (m *MacMachine) startHostNetworking(ioEater *os.File) (string, machine.APIF if err != nil { return "", machine.NoForwarding, err } + attr := new(os.ProcAttr) gvproxy, err := cfg.FindHelperBinary("gvproxy", false) if err != nil { @@ -799,18 +942,7 @@ func (m *MacMachine) startHostNetworking(ioEater *os.File) (string, machine.APIF } attr.Files = []*os.File{ioEater, ioEater, ioEater} - cmd := []string{gvproxy} - // Add the ssh port - cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", m.Port)}...) - // Add pid file - cmd = append(cmd, "-pid-file", m.GvProxyPid.GetPath()) - // Add vfkit proxy listen - cmd = append(cmd, "-listen-vfkit", fmt.Sprintf("unixgram://%s", m.GvProxySock.GetPath())) - cmd, forwardSock, state = m.setupAPIForwarding(cmd) - if logrus.GetLevel() == logrus.DebugLevel { - cmd = append(cmd, "--debug") - fmt.Println(cmd) - } + cmd := m.setupStartHostNetworkingCmd(gvproxy, forwardSock, state) _, err = os.StartProcess(cmd[0], cmd, attr) if err != nil { @@ -843,6 +975,7 @@ func AppleHVSSH(username, identityPath, name string, sshPort int, inputArgs []st return cmd.Run() } + func (m *MacMachine) setupAPIForwarding(cmd []string) ([]string, string, machine.APIForwardingState) { socket, err := m.forwardSocketPath() if err != nil {