/
tunnel_driver.go
51 lines (43 loc) · 1.33 KB
/
tunnel_driver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// +build !windows
package googlecompute
import (
"context"
"log"
"os/exec"
"syscall"
)
func NewTunnelDriver() TunnelDriver {
return &TunnelDriverLinux{}
}
type TunnelDriverLinux struct {
cmd *exec.Cmd
}
func (t *TunnelDriverLinux) StartTunnel(cancelCtx context.Context, tempScriptFileName string, timeout int) error {
cmd := exec.CommandContext(cancelCtx, tempScriptFileName)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
err := RunTunnelCommand(cmd, timeout)
if err != nil {
return err
}
// Store successful command on step so we can access it to cancel it
// later.
t.cmd = cmd
return nil
}
func (t *TunnelDriverLinux) StopTunnel() {
if t.cmd != nil && t.cmd.Process != nil {
log.Printf("Cleaning up the IAP tunnel...")
// Why not just cmd.Process.Kill()? I'm glad you asked. The gcloud
// call spawns a python subprocess that listens on the port, and you
// need to use the process _group_ id to halt this process and its
// daemon child. We create the group ID with the syscall.SysProcAttr
// call inside the retry loop above, and then store that ID on the
// command so we can halt it here.
err := syscall.Kill(-t.cmd.Process.Pid, syscall.SIGINT)
if err != nil {
log.Printf("Issue stopping IAP tunnel: %s", err)
}
} else {
log.Printf("Couldn't find IAP tunnel process to kill. Continuing.")
}
}