2022-08-17 11:02:48 +00:00
|
|
|
package v1
|
|
|
|
|
|
|
|
import (
|
2022-12-29 09:06:04 +00:00
|
|
|
"fmt"
|
2022-08-17 11:02:48 +00:00
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
2022-10-17 08:32:31 +00:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/global"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/ssh"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/terminal"
|
2022-08-17 11:02:48 +00:00
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/gorilla/websocket"
|
2022-08-19 10:12:12 +00:00
|
|
|
"github.com/pkg/errors"
|
2022-08-17 11:02:48 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func (b *BaseApi) WsSsh(c *gin.Context) {
|
2022-08-19 10:12:12 +00:00
|
|
|
id, err := strconv.Atoi(c.Query("id"))
|
2022-08-17 11:02:48 +00:00
|
|
|
if err != nil {
|
2022-08-19 10:12:12 +00:00
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
2022-08-17 11:02:48 +00:00
|
|
|
return
|
|
|
|
}
|
2022-08-19 10:12:12 +00:00
|
|
|
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
|
|
|
|
if err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
|
|
|
|
if err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
2022-08-18 10:54:21 +00:00
|
|
|
return
|
|
|
|
}
|
2022-08-31 15:16:10 +00:00
|
|
|
host, err := hostService.GetHostInfo(uint(id))
|
2022-08-19 10:12:12 +00:00
|
|
|
if err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
2022-08-18 10:54:21 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
var connInfo ssh.ConnInfo
|
2022-08-19 10:12:12 +00:00
|
|
|
if err := copier.Copy(&connInfo, &host); err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, constant.ErrStructTransform)
|
2022-08-18 10:54:21 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-08-19 10:12:12 +00:00
|
|
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
|
|
if err != nil {
|
|
|
|
global.LOG.Errorf("gin context http handler failed, err: %v", err)
|
2022-08-17 11:02:48 +00:00
|
|
|
return
|
|
|
|
}
|
2022-08-19 10:12:12 +00:00
|
|
|
defer wsConn.Close()
|
2022-08-17 11:02:48 +00:00
|
|
|
|
2022-08-18 10:54:21 +00:00
|
|
|
client, err := connInfo.NewClient()
|
2022-09-01 02:25:38 +00:00
|
|
|
if wshandleError(wsConn, errors.WithMessage(err, "failed to set up the connection. Please check the host information")) {
|
2022-08-17 11:02:48 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
defer client.Close()
|
2022-08-18 10:54:21 +00:00
|
|
|
ssConn, err := connInfo.NewSshConn(cols, rows)
|
2022-08-17 11:02:48 +00:00
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer ssConn.Close()
|
|
|
|
|
2022-08-18 10:54:21 +00:00
|
|
|
sws, err := terminal.NewLogicSshWsSession(cols, rows, true, connInfo.Client, wsConn)
|
2022-08-17 11:02:48 +00:00
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer sws.Close()
|
|
|
|
|
|
|
|
quitChan := make(chan bool, 3)
|
|
|
|
sws.Start(quitChan)
|
|
|
|
go sws.Wait(quitChan)
|
|
|
|
|
|
|
|
<-quitChan
|
|
|
|
|
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-29 09:06:04 +00:00
|
|
|
func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
|
|
|
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
|
|
|
|
if err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
|
|
|
|
if err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
|
|
|
return
|
|
|
|
}
|
2023-02-20 07:39:55 +00:00
|
|
|
redisConf, err := redisService.LoadConf()
|
2022-12-29 09:06:04 +00:00
|
|
|
if err != nil {
|
2023-02-20 07:39:55 +00:00
|
|
|
global.LOG.Errorf("load redis container failed, err: %v", err)
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
2022-12-29 09:06:04 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-20 07:39:55 +00:00
|
|
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
2022-12-29 09:06:04 +00:00
|
|
|
if err != nil {
|
2023-02-20 07:39:55 +00:00
|
|
|
global.LOG.Errorf("gin context http handler failed, err: %v", err)
|
2022-12-29 09:06:04 +00:00
|
|
|
return
|
|
|
|
}
|
2023-02-20 07:39:55 +00:00
|
|
|
defer wsConn.Close()
|
2023-02-24 10:49:34 +00:00
|
|
|
commands := fmt.Sprintf("docker exec -it %s redis-cli", redisConf.ContainerName)
|
2022-12-29 09:06:04 +00:00
|
|
|
if len(redisConf.Requirepass) != 0 {
|
2023-02-24 10:49:34 +00:00
|
|
|
commands = fmt.Sprintf("docker exec -it %s redis-cli -a %s --no-auth-warning", redisConf.ContainerName, redisConf.Requirepass)
|
2022-12-29 09:06:04 +00:00
|
|
|
}
|
2023-02-24 10:49:34 +00:00
|
|
|
slave, err := terminal.NewCommand(commands)
|
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer slave.Close()
|
|
|
|
|
|
|
|
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
quitChan := make(chan bool, 3)
|
|
|
|
tty.Start(quitChan)
|
|
|
|
go slave.Wait(quitChan)
|
|
|
|
|
|
|
|
<-quitChan
|
|
|
|
|
|
|
|
global.LOG.Info("websocket finished")
|
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
|
|
|
containerID := c.Query("containerid")
|
|
|
|
command := c.Query("command")
|
|
|
|
user := c.Query("user")
|
|
|
|
if len(command) == 0 || len(containerID) == 0 {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error param of command or containerID"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cols, err := strconv.Atoi(c.DefaultQuery("cols", "80"))
|
|
|
|
if err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
rows, err := strconv.Atoi(c.DefaultQuery("rows", "40"))
|
|
|
|
if err != nil {
|
|
|
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
|
|
if err != nil {
|
|
|
|
global.LOG.Errorf("gin context http handler failed, err: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer wsConn.Close()
|
|
|
|
commands := fmt.Sprintf("docker exec -it %s %s", containerID, command)
|
|
|
|
if len(user) != 0 {
|
|
|
|
commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command)
|
|
|
|
}
|
|
|
|
slave, err := terminal.NewCommand(commands)
|
2022-12-29 09:06:04 +00:00
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer slave.Close()
|
|
|
|
|
|
|
|
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
quitChan := make(chan bool, 3)
|
|
|
|
tty.Start(quitChan)
|
|
|
|
go slave.Wait(quitChan)
|
|
|
|
|
|
|
|
<-quitChan
|
|
|
|
|
|
|
|
global.LOG.Info("websocket finished")
|
|
|
|
if wshandleError(wsConn, err) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-17 11:02:48 +00:00
|
|
|
func wshandleError(ws *websocket.Conn, err error) bool {
|
|
|
|
if err != nil {
|
|
|
|
global.LOG.Errorf("handler ws faled:, err: %v", err)
|
|
|
|
dt := time.Now().Add(time.Second)
|
|
|
|
if err := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); err != nil {
|
|
|
|
global.LOG.Errorf("websocket writes control message failed, err: %v", err)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
var upGrader = websocket.Upgrader{
|
|
|
|
ReadBufferSize: 1024,
|
|
|
|
WriteBufferSize: 1024 * 1024 * 10,
|
|
|
|
CheckOrigin: func(r *http.Request) bool {
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
}
|