diff --git a/model/docker.go b/model/docker.go index 20b68cc..34412cd 100644 --- a/model/docker.go +++ b/model/docker.go @@ -17,6 +17,8 @@ type DockerStatsModel struct { Previous interface{} `json:"previous"` } -type DeckerDaemonModel struct { - Graph string `json:"graph"` +// reference - https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file +type DockerDaemonConfigurationModel struct { + // e.g. `/var/lib/docker` + Root string `json:"data-root,omitempty"` } diff --git a/pkg/docker/helper.go b/pkg/docker/helper.go index be76b7d..0aef117 100644 --- a/pkg/docker/helper.go +++ b/pkg/docker/helper.go @@ -15,7 +15,6 @@ import ( ) func NewSshClient(user, password string, port string) (*ssh.Client, error) { - // connet to ssh // addr = fmt.Sprintf("%s:%d", host, port) @@ -23,10 +22,10 @@ func NewSshClient(user, password string, port string) (*ssh.Client, error) { Timeout: time.Second * 5, User: user, HostKeyCallback: ssh.InsecureIgnoreHostKey(), - //HostKeyCallback: , - //HostKeyCallback: hostKeyCallBackFunc(h.Host), + // HostKeyCallback: , + // HostKeyCallback: hostKeyCallBackFunc(h.Host), } - //if h.Type == "password" { + // if h.Type == "password" { config.Auth = []ssh.AuthMethod{ssh.Password(password)} //} else { // config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)} @@ -90,11 +89,11 @@ func (w *wsBufferWriter) Write(p []byte) (int, error) { defer w.mu.Unlock() return w.buffer.Write(p) } + func (s *SshConn) Close() { if s.Session != nil { s.Session.Close() } - } const ( @@ -102,16 +101,15 @@ const ( wsMsgResize = "resize" ) -//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin +// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string { - //tells other go routine quit + // tells other go routine quit username := "" for { - //read websocket msg + // read websocket msg _, wsData, err := wsConn.ReadMessage() if err != nil { - return "" } @@ -125,8 +123,8 @@ func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string { //} switch msgObj.Type { case wsMsgCmd: - //handle xterm.js stdin - //decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) + // handle xterm.js stdin + // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) decodeBytes := []byte(msgObj.Cmd) if msgObj.Cmd == "\u007f" { if len(username) == 0 { @@ -144,7 +142,7 @@ func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string { if err := wsConn.WriteMessage(websocket.TextMessage, decodeBytes); err != nil { logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed") } - //write input cmd to log buffer + // write input cmd to log buffer if _, err := logBuff.Write(decodeBytes); err != nil { logrus.WithError(err).Error("write received cmd into log buffer failed") } @@ -154,11 +152,11 @@ func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string { } func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string { - //tells other go routine quit + // tells other go routine quit password := "" for { - //read websocket msg + // read websocket msg _, wsData, err := wsConn.ReadMessage() if err != nil { logrus.WithError(err).Error("reading webSocket message failed") @@ -175,8 +173,8 @@ func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string //} switch msgObj.Type { case wsMsgCmd: - //handle xterm.js stdin - //decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) + // handle xterm.js stdin + // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) if msgObj.Cmd == "\r" { return password } @@ -194,16 +192,16 @@ func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string } } -//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin +// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) { - //tells other go routine quit + // tells other go routine quit defer setQuit(exitCh) for { select { case <-exitCh: return default: - //read websocket msg + // read websocket msg _, wsData, err := wsConn.ReadMessage() if err != nil { logrus.WithError(err).Error("reading webSocket message failed") @@ -227,15 +225,15 @@ func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffe switch msgObj.Type { case wsMsgResize: - //handle xterm.js size change + // handle xterm.js size change if msgObj.Cols > 0 && msgObj.Rows > 0 { if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil { logrus.WithError(err).Error("ssh pty change windows size failed") } } case wsMsgCmd: - //handle xterm.js stdin - //decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) + // handle xterm.js stdin + // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) decodeBytes := []byte(msgObj.Cmd) if err != nil { logrus.WithError(err).Error("websock cmd string base64 decoding failed") @@ -243,7 +241,7 @@ func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffe if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil { logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed") } - //write input cmd to log buffer + // write input cmd to log buffer if _, err := logBuff.Write(decodeBytes); err != nil { logrus.WithError(err).Error("write received cmd into log buffer failed") } @@ -253,17 +251,17 @@ func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffe } func (ssConn *SshConn) SendComboOutput(wsConn *websocket.Conn, exitCh chan bool) { - //tells other go routine quit - //defer setQuit(exitCh) + // tells other go routine quit + // defer setQuit(exitCh) - //every 120ms write combine output bytes into websocket response + // every 120ms write combine output bytes into websocket response tick := time.NewTicker(time.Millisecond * time.Duration(120)) - //for range time.Tick(120 * time.Millisecond){} + // for range time.Tick(120 * time.Millisecond){} defer tick.Stop() for { select { case <-tick.C: - //write combine output bytes into websocket response + // write combine output bytes into websocket response if err := flushComboOutput(ssConn.ComboOutput, wsConn); err != nil { logrus.WithError(err).Error("ssh sending combo output to webSocket failed") return @@ -273,6 +271,7 @@ func (ssConn *SshConn) SendComboOutput(wsConn *websocket.Conn, exitCh chan bool) } } } + func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error { if w.buffer.Len() != 0 { err := wsConn.WriteMessage(websocket.TextMessage, w.buffer.Bytes()) @@ -284,16 +283,16 @@ func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error { return nil } -//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin +// ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) { - //tells other go routine quit + // tells other go routine quit defer setQuit(exitCh) for { select { case <-exitCh: return default: - //read websocket msg + // read websocket msg _, wsData, err := wsConn.ReadMessage() if err != nil { logrus.WithError(err).Error("reading webSocket message failed") @@ -317,15 +316,15 @@ func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exit switch msgObj.Type { case wsMsgResize: - //handle xterm.js size change + // handle xterm.js size change if msgObj.Cols > 0 && msgObj.Rows > 0 { if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil { logrus.WithError(err).Error("ssh pty change windows size failed") } } case wsMsgCmd: - //handle xterm.js stdin - //decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) + // handle xterm.js stdin + // decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd) decodeBytes := []byte(msgObj.Cmd) if err != nil { logrus.WithError(err).Error("websock cmd string base64 decoding failed") @@ -333,7 +332,7 @@ func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exit if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil { logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed") } - //write input cmd to log buffer + // write input cmd to log buffer if _, err := logBuff.Write(decodeBytes); err != nil { logrus.WithError(err).Error("write received cmd into log buffer failed") } @@ -341,6 +340,7 @@ func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exit } } } + func (ssConn *SshConn) SessionWait(quitChan chan bool) { if err := ssConn.Session.Wait(); err != nil { logrus.WithError(err).Error("ssh session wait failed") @@ -395,7 +395,7 @@ func WsReaderCopy(reader *websocket.Conn, writer io.Writer) { if err = json2.Unmarshal(p, &msgObj); err != nil { writer.Write(p) } else if msgObj.Type == wsMsgResize { - //writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r")) + // writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r")) } } } diff --git a/pkg/utils/command/command_helper.go b/pkg/utils/command/command_helper.go index 9a2fded..a47b288 100644 --- a/pkg/utils/command/command_helper.go +++ b/pkg/utils/command/command_helper.go @@ -35,8 +35,8 @@ func ExecResultStrArray(cmdStr string) []string { fmt.Println(err) return nil } - //str, err := ioutil.ReadAll(stdout) - var networklist = []string{} + // str, err := ioutil.ReadAll(stdout) + networklist := []string{} outputBuf := bufio.NewReader(stdout) for { output, _, err := outputBuf.ReadLine() @@ -54,6 +54,8 @@ func ExecResultStrArray(cmdStr string) []string { func ExecResultStr(cmdStr string) string { cmd := exec.Command("/bin/bash", "-c", cmdStr) + println(cmd.String()) + stdout, err := cmd.StdoutPipe() if err != nil { fmt.Println(err) @@ -73,7 +75,7 @@ func ExecResultStr(cmdStr string) string { return string(str) } -//执行 lsblk 命令 +// 执行 lsblk 命令 func ExecLSBLK() []byte { output, err := exec.Command("lsblk", "-O", "-J", "-b").Output() if err != nil { @@ -83,7 +85,7 @@ func ExecLSBLK() []byte { return output } -//执行 lsblk 命令 +// 执行 lsblk 命令 func ExecLSBLKByPath(path string) []byte { output, err := exec.Command("lsblk", path, "-O", "-J", "-b").Output() if err != nil { @@ -93,7 +95,7 @@ func ExecLSBLKByPath(path string) []byte { return output } -//exec smart +// exec smart func ExecSmartCTLByPath(path string) []byte { timeout := 3 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) @@ -107,6 +109,5 @@ func ExecSmartCTLByPath(path string) []byte { } func ExecEnabledSMART(path string) { - exec.Command("smartctl", "-s on", path).Output() } diff --git a/pkg/utils/file/file.go b/pkg/utils/file/file.go index b08dcda..e7fed65 100644 --- a/pkg/utils/file/file.go +++ b/pkg/utils/file/file.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "log" "mime/multipart" @@ -60,7 +61,7 @@ func MkDir(src string) error { if err != nil { return err } - os.Chmod(src, 0777) + os.Chmod(src, 0o777) return nil } @@ -103,7 +104,7 @@ func MustOpen(fileName, filePath string) (*os.File, error) { return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err) } - f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) + f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o644) if err != nil { return nil, fmt.Errorf("Fail to OpenFile :%v", err) } @@ -113,7 +114,7 @@ func MustOpen(fileName, filePath string) (*os.File, error) { // 判断所给路径文件/文件夹是否存在 func Exists(path string) bool { - _, err := os.Stat(path) //os.Stat获取文件信息 + _, err := os.Stat(path) // os.Stat获取文件信息 if err != nil { if os.IsExist(err) { return true @@ -147,7 +148,7 @@ func CreateFile(path string) error { } func CreateFileAndWriteContent(path string, content string) error { - file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666) + file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o666) if err != nil { return err } @@ -163,7 +164,7 @@ func CreateFileAndWriteContent(path string, content string) error { // IsNotExistMkDir create a directory if it does not exist func IsNotExistCreateFile(src string) error { - if notExist := CheckNotExist(src); notExist == true { + if notExist := CheckNotExist(src); notExist { if err := CreateFile(src); err != nil { return err } @@ -267,7 +268,7 @@ func CopySingleFile(src, dst, style string) error { return os.Chmod(dst, srcinfo.Mode()) } -//Check for duplicate file names +// Check for duplicate file names func GetNoDuplicateFileName(fullPath string) string { path, fileName := filepath.Split(fullPath) fileSuffix := path2.Ext(fileName) @@ -293,7 +294,7 @@ func CopyDir(src string, dst string, style string) error { } return nil } - //dstPath := dst + // dstPath := dst lastPath := src[strings.LastIndex(src, "/")+1:] dst += "/" + lastPath // for i := 0; Exists(dst); i++ { @@ -314,7 +315,7 @@ func CopyDir(src string, dst string, style string) error { } for _, fd := range fds { srcfp := path.Join(src, fd.Name()) - dstfp := dst //path.Join(dst, fd.Name()) + dstfp := dst // path.Join(dst, fd.Name()) if fd.IsDir() { if err = CopyDir(srcfp, dstfp, style); err != nil { @@ -336,10 +337,17 @@ func WriteToPath(data []byte, path, name string) error { } else { fullPath += "/" + name } - IsNotExistCreateFile(fullPath) + return WriteToFullPath(data, fullPath, 0o666) +} + +func WriteToFullPath(data []byte, fullPath string, perm fs.FileMode) error { + if err := IsNotExistCreateFile(fullPath); err != nil { + return err + } + file, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, - 0666, + perm, ) if err != nil { return err @@ -350,16 +358,15 @@ func WriteToPath(data []byte, path, name string) error { return err } -//最终拼接 +// 最终拼接 func SpliceFiles(dir, path string, length int, startPoint int) error { - fullPath := path IsNotExistCreateFile(fullPath) file, _ := os.OpenFile(fullPath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, - 0666, + 0o666, ) defer file.Close() bufferedWriter := bufio.NewWriter(file) @@ -380,7 +387,6 @@ func SpliceFiles(dir, path string, length int, startPoint int) error { } func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) { - switch t { case "zip", "": return ".zip", archiver.NewZip(), nil @@ -400,8 +406,8 @@ func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) { return "", nil, errors.New("format not implemented") } } -func AddFile(ar archiver.Writer, path, commonPath string) error { +func AddFile(ar archiver.Writer, path, commonPath string) error { info, err := os.Stat(path) if err != nil { return err @@ -447,6 +453,7 @@ func AddFile(ar archiver.Writer, path, commonPath string) error { return nil } + func CommonPrefix(sep byte, paths ...string) string { // Handle special cases. switch len(paths) { @@ -513,7 +520,7 @@ func GetFileOrDirSize(path string) (int64, error) { return fileInfo.Size(), nil } -//getFileSize get file size by path(B) +// getFileSize get file size by path(B) func DirSizeB(path string) (int64, error) { var size int64 err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { diff --git a/route/route.go b/route/route.go index 110fd69..8b254f8 100644 --- a/route/route.go +++ b/route/route.go @@ -11,7 +11,6 @@ import ( ) func InitRouter() *gin.Engine { - r := gin.Default() r.Use(middleware.Cors()) @@ -35,7 +34,7 @@ func InitRouter() *gin.Engine { // r.GET("/v1/users/image", v1.GetUserImage) // r.GET("/v1/users/status", v1.GetUserStatus) //init/check - //r.GET("/v1/guide/check", v1.GetGuideCheck) // /v1/sys/guide_check + // r.GET("/v1/guide/check", v1.GetGuideCheck) // /v1/sys/guide_check r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug r.GET("/v1/sys/socket-port", v1.GetSystemSocketPort) //sys/socket_port @@ -73,7 +72,7 @@ func InitRouter() *gin.Engine { v1AppsGroup := v1Group.Group("/apps") v1AppsGroup.Use() { - v1AppsGroup.GET("", v1.AppList) //list + v1AppsGroup.GET("", v1.AppList) // list v1AppsGroup.GET("/:id", v1.AppInfo) } v1ContainerGroup := v1Group.Group("/container") @@ -84,24 +83,24 @@ func InitRouter() *gin.Engine { v1ContainerGroup.GET("/usage", v1.AppUsageList) v1ContainerGroup.GET("/:id", v1.ContainerUpdateInfo) ///update/:id/info v1ContainerGroup.GET("/:id/logs", v1.ContainerLog) // /app/logs/:id - v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) //app/install/config + v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) // app/install/config - v1ContainerGroup.GET("/:id/state", v1.GetContainerState) //app/state/:id ?state=install_progress + v1ContainerGroup.GET("/:id/state", v1.GetContainerState) // app/state/:id ?state=install_progress // there are problems, temporarily do not deal with - v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) //app/terminal/:id - v1ContainerGroup.POST("", v1.InstallApp) //app/install - //v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id + v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) // app/terminal/:id + v1ContainerGroup.POST("", v1.InstallApp) // app/install + // v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id v1ContainerGroup.PUT("/:id", v1.UpdateSetting) ///update/:id/setting v1ContainerGroup.PUT("/:id/state", v1.ChangAppState) // /app/state/:id - v1ContainerGroup.DELETE("/:id", v1.UnInstallApp) //app/uninstall/:id - //Not used + v1ContainerGroup.DELETE("/:id", v1.UnInstallApp) // app/uninstall/:id + // Not used v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate) - //Not used + // Not used v1ContainerGroup.POST("/share", v1.ShareAppFile) - v1ContainerGroup.GET("/info", v1.GetcontainerInfo) - v1ContainerGroup.PUT("/info", v1.PutcontainerInfo) + v1ContainerGroup.GET("/info", v1.GetDockerDaemonConfiguration) + v1ContainerGroup.PUT("/info", v1.PutDockerDaemonConfiguration) } v1AppCategoriesGroup := v1Group.Group("/app-categories") @@ -113,19 +112,19 @@ func InitRouter() *gin.Engine { v1SysGroup := v1Group.Group("/sys") v1SysGroup.Use() { - v1SysGroup.GET("/version", v1.GetSystemCheckVersion) //version/check + v1SysGroup.GET("/version", v1.GetSystemCheckVersion) // version/check v1SysGroup.POST("/update", v1.SystemUpdate) - v1SysGroup.GET("/hardware", v1.GetSystemHardwareInfo) //hardware/info + v1SysGroup.GET("/hardware", v1.GetSystemHardwareInfo) // hardware/info v1SysGroup.GET("/wsssh", v1.WsSsh) v1SysGroup.POST("/ssh-login", v1.PostSshLogin) - //v1SysGroup.GET("/config", v1.GetSystemConfig) //delete - //v1SysGroup.POST("/config", v1.PostSetSystemConfig) - v1SysGroup.GET("/logs", v1.GetCasaOSErrorLogs) //error/logs - //v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)//delete - //v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)//delete + // v1SysGroup.GET("/config", v1.GetSystemConfig) //delete + // v1SysGroup.POST("/config", v1.PostSetSystemConfig) + v1SysGroup.GET("/logs", v1.GetCasaOSErrorLogs) // error/logs + // v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)//delete + // v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)//delete v1SysGroup.POST("/stop", v1.PostKillCasaOS) @@ -141,31 +140,31 @@ func InitRouter() *gin.Engine { v1SysGroup.GET("/server-info", nil) v1SysGroup.PUT("/server-info", nil) v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus) - //v1SysGroup.GET("/port", v1.GetCasaOSPort) - //v1SysGroup.PUT("/port", v1.PutCasaOSPort) + // v1SysGroup.GET("/port", v1.GetCasaOSPort) + // v1SysGroup.PUT("/port", v1.PutCasaOSPort) v1SysGroup.GET("/proxy", v1.GetSystemProxy) } v1PortGroup := v1Group.Group("/port") v1PortGroup.Use() { - v1PortGroup.GET("/", v1.GetPort) //app/port - v1PortGroup.GET("/state/:port", v1.PortCheck) //app/check/:port + v1PortGroup.GET("/", v1.GetPort) // app/port + v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port } v1FileGroup := v1Group.Group("/file") v1FileGroup.Use() { - v1FileGroup.GET("", v1.GetDownloadSingleFile) //download/:path + v1FileGroup.GET("", v1.GetDownloadSingleFile) // download/:path v1FileGroup.POST("", v1.PostCreateFile) v1FileGroup.PUT("", v1.PutFileContent) v1FileGroup.PUT("/name", v1.RenamePath) - //file/rename - v1FileGroup.GET("/content", v1.GetFilerContent) //file/read + // file/rename + v1FileGroup.GET("/content", v1.GetFilerContent) // file/read - //File uploads need to be handled separately, and will not be modified here + // File uploads need to be handled separately, and will not be modified here v1FileGroup.POST("/upload", v1.PostFileUpload) v1FileGroup.GET("/upload", v1.GetFileUpload) - //v1FileGroup.GET("/download", v1.UserFileDownloadCommonService) + // v1FileGroup.GET("/download", v1.UserFileDownloadCommonService) } v1FolderGroup := v1Group.Group("/folder") v1FolderGroup.Use() @@ -178,9 +177,9 @@ func InitRouter() *gin.Engine { v1BatchGroup.Use() { - v1BatchGroup.DELETE("", v1.DeleteFile) //file/delete + v1BatchGroup.DELETE("", v1.DeleteFile) // file/delete v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir) - v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) //file/operate + v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) // file/operate v1BatchGroup.GET("", v1.GetDownloadFile) } v1ImageGroup := v1Group.Group("/image") @@ -211,7 +210,7 @@ func InitRouter() *gin.Engine { v1NotifyGroup.Use() { v1NotifyGroup.POST("/:path", v1.PostNotifyMessage) - //merge to system + // merge to system v1NotifyGroup.POST("/system_status", v1.PostSystemStatusNotify) } } diff --git a/route/v1/app.go b/route/v1/app.go index cc2ee00..dec60ef 100644 --- a/route/v1/app.go +++ b/route/v1/app.go @@ -2,8 +2,9 @@ package v1 import ( "encoding/json" - "fmt" "io/ioutil" + "net/http" + "path/filepath" "strconv" "github.com/IceWhaleTech/CasaOS/model" @@ -16,6 +17,10 @@ import ( "github.com/gin-gonic/gin" ) +const ( + dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json" +) + // @Summary 获取远程列表 // @Produce application/json // @Accept application/json @@ -29,8 +34,7 @@ import ( // @Success 200 {string} string "ok" // @Router /app/list [get] func AppList(c *gin.Context) { - - //service.MyService.Docker().DockerContainerCommit("test2") + // service.MyService.Docker().DockerContainerCommit("test2") index := c.DefaultQuery("index", "1") size := c.DefaultQuery("size", "10000") @@ -139,7 +143,7 @@ func MyAppList(c *gin.Context) { func AppUsageList(c *gin.Context) { list := service.MyService.App().GetHardwareUsage() c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list}) - //c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: nil}) + // c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: nil}) } // @Summary 应用详情 @@ -151,7 +155,6 @@ func AppUsageList(c *gin.Context) { // @Success 200 {string} string "ok" // @Router /app/appinfo/{id} [get] func AppInfo(c *gin.Context) { - id := c.Param("id") language := c.GetHeader("Language") info, err := service.MyService.Casa().GetServerAppInfo(id, "", language) @@ -213,7 +216,7 @@ func AppInfo(c *gin.Context) { // return c1.Type < c2.Type // } - //sort + // sort // if info.NetworkModel != "host" { // sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts) // sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts) @@ -265,53 +268,89 @@ func ShareAppFile(c *gin.Context) { c.JSON(common_err.SUCCESS, json.RawMessage(content)) } -func GetcontainerInfo(c *gin.Context) { +func GetDockerDaemonConfiguration(c *gin.Context) { // info, err := service.MyService.Docker().GetDockerInfo() // if err != nil { // c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) // return // } - daemon := model.DeckerDaemonModel{} + dockerConfig := model.DockerDaemonConfigurationModel{} data := make(map[string]interface{}, 1) data["docker_root_dir"] = "" - if file.Exists("/etc/docker/daemon.json") { - byteResult := file.ReadFullFile("/etc/docker/daemon.json") - err := json.Unmarshal(byteResult, &daemon) + + // TODO read dockerRootDir from /etc/casaos/casaos.conf + if file.Exists(dockerDaemonConfigurationFilePath) { + byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath) + err := json.Unmarshal(byteResult, &dockerConfig) if err != nil { c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()}) return } - data["docker_root_dir"] = daemon.Graph + + if dockerConfig.Root != "" { + data["docker_root_dir"] = dockerConfig.Root + } else { + data["docker_root_dir"] = "/var/lib/docker" + } } c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) } -func PutcontainerInfo(c *gin.Context) { + +func PutDockerDaemonConfiguration(c *gin.Context) { js := make(map[string]interface{}) - err := c.BindJSON(&js) - if err != nil { - c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()}) + if err := c.BindJSON(&js); err != nil { + c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()}) return } - dockerRootDir := js["docker_root_dir"].(string) - daemon := model.DeckerDaemonModel{} - if file.Exists("/etc/docker/daemon.json") { - byteResult := file.ReadFullFile("/etc/docker/daemon.json") - err := json.Unmarshal(byteResult, &daemon) + + value, ok := js["docker_root_dir"] + if !ok { + c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "`docker_root_dir` should not empty"}) + return + } + + dockerConfig := model.DockerDaemonConfigurationModel{} + if file.Exists(dockerDaemonConfigurationFilePath) { + byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath) + err := json.Unmarshal(byteResult, &dockerConfig) if err != nil { - c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err.Error()}) + c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err.Error()}) return } } - if !file.Exists(dockerRootDir) { - c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS), Data: common_err.GetMsg(common_err.DIR_NOT_EXISTS)}) + + dockerRootDir := value.(string) + if dockerRootDir == "/" { + dockerConfig.Root = "" // omitempty - empty string will not be serialized + } else { + if !file.Exists(dockerRootDir) { + c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS), Data: common_err.GetMsg(common_err.DIR_NOT_EXISTS)}) + return + } + + dockerConfig.Root = filepath.Join(dockerRootDir, "docker") + + if err := file.IsNotExistMkDir(dockerConfig.Root); err != nil { + c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to create " + dockerConfig.Root, Data: err.Error()}) + return + } + } + + byteMode, err := json.Marshal(dockerConfig) + if err != nil { + c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker config", Data: dockerConfig}) return } - daemon.Graph = dockerRootDir - byteMode, _ := json.Marshal(daemon) - file.WriteToPath(byteMode, "/etc/docker", "daemon.json") - fmt.Println(command.ExecResultStr("systemctl daemon-reload")) - fmt.Println(command.ExecResultStr("systemctl restart docker")) + if err := file.WriteToFullPath(byteMode, dockerDaemonConfigurationFilePath, 0o644); err != nil { + c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write to " + dockerDaemonConfigurationFilePath, Data: err.Error()}) + return + } - c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: js}) + // TODO also write dockerRootDir to /etc/casaos/casaos.conf + + println(command.ExecResultStr("systemctl daemon-reload")) + println(command.ExecResultStr("systemctl restart docker")) + + c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: js}) }