Skip to content

Commit

Permalink
Merge pull request containers#19516 from baude/stopgvproxy
Browse files Browse the repository at this point in the history
Stop gvproxy on hyperv machine stop
  • Loading branch information
openshift-merge-robot authored Aug 18, 2023
2 parents 884e5f6 + 0772d8d commit 20f28e5
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 55 deletions.
60 changes: 5 additions & 55 deletions pkg/machine/applehv/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"io/fs"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
Expand Down Expand Up @@ -692,34 +691,6 @@ 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 {
Expand All @@ -730,7 +701,11 @@ func (m *MacMachine) Stop(name string, opts machine.StopOptions) error {
return machine.ErrWrongState
}

defer m.cleanupGVProxy()
defer func() {
if err := machine.CleanupGVProxy(m.GvProxyPid); err != nil {
logrus.Error(err)
}
}()

return m.Vfkit.stop(false, true)
}
Expand Down Expand Up @@ -915,31 +890,6 @@ func (m *MacMachine) startHostNetworking(ioEater *os.File) (string, machine.APIF
return forwardSock, state, nil
}

// AppleHVSSH is a temporary function for applehv until we decide how the networking will work
// for certain.
func AppleHVSSH(username, identityPath, name string, sshPort int, inputArgs []string) error {
sshDestination := username + "@192.168.64.2"
port := strconv.Itoa(sshPort)

args := []string{"-i", identityPath, "-p", port, sshDestination,
"-o", "IdentitiesOnly=yes",
"-o", "StrictHostKeyChecking=no", "-o", "LogLevel=ERROR", "-o", "SetEnv=LC_ALL="}
if len(inputArgs) > 0 {
args = append(args, inputArgs...)
} else {
fmt.Printf("Connecting to vm %s. To close connection, use `~.` or `exit`\n", name)
}

cmd := exec.Command("ssh", args...)
logrus.Debugf("Executing: ssh %v\n", args)

cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin

return cmd.Run()
}

func (m *MacMachine) setupAPIForwarding(cmd []string) ([]string, string, machine.APIForwardingState) {
socket, err := m.forwardSocketPath()
if err != nil {
Expand Down
79 changes: 79 additions & 0 deletions pkg/machine/gvproxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package machine

import (
"fmt"
"os"
"strconv"
"syscall"
"time"
)

const (
loops = 5
sleepTime = time.Millisecond * 1
)

// backoffForProcess checks if the process still exists, for something like
// sigterm. If the process still exists after loops and sleep time are exhausted,
// an error is returned
func backoffForProcess(pid int) error {
sleepInterval := sleepTime
for i := 0; i < loops; i++ {
proxyProc, err := os.FindProcess(pid)
if proxyProc == nil && err != nil {
// process is killed, gone
return nil //nolint: nilerr
}
time.Sleep(sleepInterval)
// double the time
sleepInterval += sleepInterval
}
return fmt.Errorf("process %d has not ended", pid)
}

// waitOnProcess takes a pid and sends a sigterm to it. it then waits for the
// process to not exist. if the sigterm does not end the process after an interval,
// then sigkill is sent. it also waits for the process to exit after the sigkill too.
func waitOnProcess(processID int) error {
proxyProc, err := os.FindProcess(processID)
if err != nil {
return err
}

// Try to kill the pid with sigterm
if err := proxyProc.Signal(syscall.SIGTERM); err != nil {
return err
}

if err := backoffForProcess(processID); err == nil {
return nil
}

// sigterm has not killed it yet, lets send a sigkill
proxyProc, err = os.FindProcess(processID)
if proxyProc == nil && err != nil {
// process is killed, gone
return nil //nolint: nilerr
}
if err := proxyProc.Signal(syscall.SIGKILL); err != nil {
// lets assume it is dead in this case
return nil //nolint: nilerr
}
return backoffForProcess(processID)
}

// CleanupGVProxy reads the --pid-file for gvproxy attempts to stop it
func CleanupGVProxy(f VMFile) error {
gvPid, err := f.Read()
if err != nil {
return fmt.Errorf("unable to read gvproxy pid file %s: %v", f.GetPath(), err)
}
proxyPid, err := strconv.Atoi(string(gvPid))
if err != nil {
return fmt.Errorf("unable to convert pid to integer: %v", err)
}
if err := waitOnProcess(proxyPid); err == nil {
return nil
}
return f.Delete()
}
13 changes: 13 additions & 0 deletions pkg/machine/hyperv/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func (v HyperVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM,
if err != nil {
return nil, err
}

m.ConfigPath = *configPath

ignitionPath, err := machine.NewMachineFile(filepath.Join(configDir, m.Name)+".ign", nil)
Expand All @@ -126,6 +127,18 @@ func (v HyperVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM,
// Set creation time
m.Created = time.Now()

dataDir, err := machine.GetDataDir(machine.HyperVVirt)
if err != nil {
return nil, err
}

// Set the proxy pid file
gvProxyPid, err := machine.NewMachineFile(filepath.Join(dataDir, "gvproxy.pid"), nil)
if err != nil {
return nil, err
}
m.GvProxyPid = *gvProxyPid

// Acquire the image
imagePath, imageStream, err := v.acquireVMImage(opts)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions pkg/machine/hyperv/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type HyperVMachine struct {
Created time.Time
// LastUp contains the last recorded uptime
LastUp time.Time
// GVProxy will write its PID here
GvProxyPid machine.VMFile
}

// addNetworkAndReadySocketsToRegistry adds the Network and Ready sockets to the
Expand Down Expand Up @@ -510,7 +512,13 @@ func (m *HyperVMachine) Stop(name string, opts machine.StopOptions) error {
if vm.State() != hypervctl.Enabled {
return hypervctl.ErrMachineStateInvalid
}

if err := machine.CleanupGVProxy(m.GvProxyPid); err != nil {
logrus.Error(err)
}

return vm.Stop()

}

func (m *HyperVMachine) jsonConfigPath() (string, error) {
Expand Down Expand Up @@ -615,6 +623,7 @@ func (m *HyperVMachine) startHostNetworking() (string, machine.APIForwardingStat
// Add the ssh port
cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", m.Port)}...)
cmd = append(cmd, []string{"-listen", fmt.Sprintf("vsock://%s", m.NetworkHVSock.KeyName)}...)
cmd = append(cmd, "-pid-file", m.GvProxyPid.GetPath())

cmd, forwardSock, state = m.setupAPIForwarding(cmd)
if logrus.GetLevel() == logrus.DebugLevel {
Expand Down

0 comments on commit 20f28e5

Please sign in to comment.