diff --git a/backend/app/api/v1/terminal.go b/backend/app/api/v1/terminal.go index 736d1633837b..e3ec524dc5cc 100644 --- a/backend/app/api/v1/terminal.go +++ b/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, diff --git a/backend/utils/terminal/local_cmd.go b/backend/utils/terminal/local_cmd.go index 2d3a775499fb..85c0c75124f8 100644 --- a/backend/utils/terminal/local_cmd.go +++ b/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) -}