Browse Source

fix: 解决容器终端断开后未退出进程的问题 (#779)

pull/781/head
ssongliu 2 years ago committed by GitHub
parent
commit
edf07be281
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      backend/app/api/v1/terminal.go
  2. 31
      backend/utils/terminal/local_cmd.go

18
backend/app/api/v1/terminal.go

@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"os/exec"
"strconv"
"time"
@ -107,14 +108,15 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
return
}
defer wsConn.Close()
commands := fmt.Sprintf("docker exec -it %s redis-cli", redisConf.ContainerName)
commands := "redis-cli"
if len(redisConf.Requirepass) != 0 {
commands = fmt.Sprintf("docker exec -it %s redis-cli -a %s --no-auth-warning", redisConf.ContainerName, redisConf.Requirepass)
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass)
}
slave, err := terminal.NewCommand(commands)
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
if wshandleError(wsConn, err) {
return
}
defer killBash(redisConf.ContainerName, commands)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
@ -177,6 +179,7 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
if wshandleError(wsConn, err) {
return
}
defer killBash(containerID, command)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
@ -216,6 +219,15 @@ func wshandleError(ws *websocket.Conn, err error) bool {
return false
}
func killBash(containerID, comm string) {
sudo := ""
if cmd.HasNoPasswordSudo() {
sudo = "sudo"
}
command := exec.Command("sh", "-c", fmt.Sprintf("%s kill -9 $(docker top %s -eo pid,command | grep '%s' | awk '{print $1}')", sudo, containerID, comm))
_, _ = command.CombinedOutput()
}
var upGrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024 * 1024 * 10,

31
backend/utils/terminal/local_cmd.go

@ -21,9 +21,8 @@ type LocalCommand struct {
closeSignal syscall.Signal
closeTimeout time.Duration
cmd *exec.Cmd
pty *os.File
ptyClosed chan struct{}
cmd *exec.Cmd
pty *os.File
}
func NewCommand(commands string) (*LocalCommand, error) {
@ -33,15 +32,13 @@ func NewCommand(commands string) (*LocalCommand, error) {
if err != nil {
return nil, errors.Wrapf(err, "failed to start command")
}
ptyClosed := make(chan struct{})
lcmd := &LocalCommand{
closeSignal: DefaultCloseSignal,
closeTimeout: DefaultCloseTimeout,
cmd: cmd,
pty: pty,
ptyClosed: ptyClosed,
cmd: cmd,
pty: pty,
}
return lcmd, nil
@ -57,16 +54,10 @@ func (lcmd *LocalCommand) Write(p []byte) (n int, err error) {
func (lcmd *LocalCommand) Close() error {
if lcmd.cmd != nil && lcmd.cmd.Process != nil {
_ = lcmd.cmd.Process.Signal(lcmd.closeSignal)
}
for {
select {
case <-lcmd.ptyClosed:
return nil
case <-lcmd.closeTimeoutC():
_ = lcmd.cmd.Process.Signal(syscall.SIGKILL)
}
_ = lcmd.cmd.Process.Kill()
}
_ = lcmd.pty.Close()
return nil
}
func (lcmd *LocalCommand) ResizeTerminal(width int, height int) error {
@ -100,11 +91,3 @@ func (lcmd *LocalCommand) Wait(quitChan chan bool) {
setQuit(quitChan)
}
}
func (lcmd *LocalCommand) closeTimeoutC() <-chan time.Time {
if lcmd.closeTimeout >= 0 {
return time.After(lcmd.closeTimeout)
}
return make(chan time.Time)
}

Loading…
Cancel
Save