Compare commits

..

5 Commits

Author SHA1 Message Date
Tiger Wang
a96f6189ac wip 2022-10-11 19:12:12 -04:00
Tiger Wang
e164a5d4c6 wip 2022-10-11 16:55:20 -04:00
Tiger Wang
42ebd5f325 wip 2022-10-11 00:19:02 -04:00
Tiger Wang
a51bf70b79 update CasaOS-Common to fix runtime error 2022-09-29 00:05:12 -04:00
Tiger Wang
3787c7bf99 change service type to notify for systemd so its status is OK only when service is initialized successfully 2022-09-28 18:19:31 -04:00
12 changed files with 443 additions and 240 deletions

167
.goreleaser.debug.yaml Normal file
View File

@@ -0,0 +1,167 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
project_name: casaos
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
builds:
- id: casaos-amd64
binary: build/sysroot/usr/bin/casaos
env:
- CGO_ENABLED=1
- CC=x86_64-linux-gnu-gcc
gcflags:
- all=-N -l
ldflags:
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- amd64
hooks:
post:
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
- id: casaos-arm64
binary: build/sysroot/usr/bin/casaos
env:
- CGO_ENABLED=1
- CC=aarch64-linux-gnu-gcc
gcflags:
- all=-N -l
ldflags:
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm64
hooks:
post:
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
- id: casaos-arm-7
binary: build/sysroot/usr/bin/casaos
env:
- CGO_ENABLED=1
- CC=arm-linux-gnueabihf-gcc
gcflags:
- all=-N -l
ldflags:
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm
goarm:
- "7"
hooks:
post:
- find build/sysroot -type f | xargs -L 1 realpath --relative-to=build/sysroot > build/sysroot.manifest
- id: casaos-migration-tool-amd64
binary: build/sysroot/usr/bin/casaos-migration-tool
main: ./cmd/migration-tool
env:
- CGO_ENABLED=1
- CC=x86_64-linux-gnu-gcc
gcflags:
- all=-N -l
ldflags:
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- amd64
- id: casaos-migration-tool-arm64
binary: build/sysroot/usr/bin/casaos-migration-tool
main: ./cmd/migration-tool
env:
- CGO_ENABLED=1
- CC=aarch64-linux-gnu-gcc
gcflags:
- all=-N -l
ldflags:
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm64
- id: casaos-migration-tool-arm-7
binary: build/sysroot/usr/bin/casaos-migration-tool
main: ./cmd/migration-tool
env:
- CGO_ENABLED=1
- CC=arm-linux-gnueabihf-gcc
gcflags:
- all=-N -l
ldflags:
- -extldflags "-static"
tags:
- musl
- netgo
goos:
- linux
goarch:
- arm
goarm:
- "7"
archives:
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-v{{ .Version }}"
id: casaos
builds:
- casaos-amd64
- casaos-arm64
- casaos-arm-7
replacements:
arm: arm-7
files:
- build/**/*
- name_template: "{{ .Os }}-{{ .Arch }}-{{ .ProjectName }}-migration-tool-v{{ .Version }}"
id: casaos-migration-tool
builds:
- casaos-migration-tool-amd64
- casaos-migration-tool-arm64
- casaos-migration-tool-arm-7
replacements:
arm: arm-7
files:
- build/sysroot/etc/**/*
checksum:
name_template: "checksums.txt"
snapshot:
name_template: "{{ incpatch .Version }}"
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
# release:
# github:
# owner: IceWhaleTech
# name: CasaOS
# draft: true
# prerelease: auto
# mode: replace
# name_template: "v{{ .Version }}"
release:
github:
owner: IceWhaleTech
name: CasaOS
draft: true
prerelease: auto
mode: replace
name_template: "v{{ .Version }}"

View File

@@ -40,6 +40,6 @@ else
echo "Enabling service..." echo "Enabling service..."
systemctl enable --force --no-ask-password "${APP_NAME}.service" systemctl enable --force --no-ask-password "${APP_NAME}.service"
echo "Starting service..." #echo "Starting service..."
systemctl start --force --no-ask-password "${APP_NAME}.service" #systemctl start --force --no-ask-password "${APP_NAME}.service"
fi fi

2
go.mod
View File

@@ -4,7 +4,7 @@ go 1.16
require ( require (
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9 github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220929035515-b1287110d6d8
github.com/IceWhaleTech/CasaOS-Gateway v0.3.6 github.com/IceWhaleTech/CasaOS-Gateway v0.3.6
github.com/Microsoft/go-winio v0.5.0 // indirect github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/ambelovsky/go-structs v1.1.0 // indirect github.com/ambelovsky/go-structs v1.1.0 // indirect

3
go.sum
View File

@@ -83,8 +83,9 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d h1:62lEBImTxZ83pgzywgDNIrPPuQ+j4ep9QjqrWBn1hrU= github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d h1:62lEBImTxZ83pgzywgDNIrPPuQ+j4ep9QjqrWBn1hrU=
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d/go.mod h1:lW9x+yEjqKdPbE3+cf2fGPJXCw/hChX3Omi9QHTLFsQ= github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d/go.mod h1:lW9x+yEjqKdPbE3+cf2fGPJXCw/hChX3Omi9QHTLFsQ=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9 h1:q4I/lSsCooxdd6LxinGy90y0n6V8EcaPBV1JCfpEnV4=
github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk= github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220901034123-ca130f6b5ce9/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk=
github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220929035515-b1287110d6d8 h1:r8nhgQ6tnrn6ikXN9aLH/K4H4H64Nc0hZ6jyW2B22x0=
github.com/IceWhaleTech/CasaOS-Common v0.0.0-20220929035515-b1287110d6d8/go.mod h1:2MiivEMzvh41codhEKUcn46WK3Ffesop/04qa9jsvQk=
github.com/IceWhaleTech/CasaOS-Gateway v0.3.6 h1:2tQQo85+jzbbjqIsKKn77QlAA73bc7vZsVCFvWnK4mg= github.com/IceWhaleTech/CasaOS-Gateway v0.3.6 h1:2tQQo85+jzbbjqIsKKn77QlAA73bc7vZsVCFvWnK4mg=
github.com/IceWhaleTech/CasaOS-Gateway v0.3.6/go.mod h1:hnZwGUzcOyiufMpVO7l3gu2gAm6Ws4TY4Nlj3kMshXA= github.com/IceWhaleTech/CasaOS-Gateway v0.3.6/go.mod h1:hnZwGUzcOyiufMpVO7l3gu2gAm6Ws4TY4Nlj3kMshXA=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=

View File

@@ -1,62 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-10-08 10:29:08
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-22 11:06:07
* @FilePath: /CasaOS/middleware/gin.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package middleware
import (
"fmt"
"net/http"
"strings"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
//允许跨域设置可以返回其他子段,可以自定义字段
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language,Content-Type,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Access-Control-Allow-Methods,Connection,Host,Origin,Referer,User-Agent,X-Requested-With")
// 允许浏览器(客户端)可以解析的头部 (重要)
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
//c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, Content-Length, X-CSRF-Token, Token, session, Origin, Host, Connection, Accept-Encoding, Accept-Language, X-Requested-With")
//设置缓存时间
c.Header("Access-Control-Max-Age", "172800")
c.Header("Access-Control-Allow-Credentials", "true")
c.Set("Content-Type", "application/json")
//}
//允许类型校验
if method == "OPTIONS" {
c.JSON(http.StatusOK, "ok!")
}
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
c.Next()
}
}
func WriteLog() gin.HandlerFunc {
return func(c *gin.Context) {
if !strings.Contains(c.Request.URL.String(), "password") {
loger.Info("request:", zap.Any("path", c.Request.URL.String()), zap.Any("param", c.Params), zap.Any("query", c.Request.URL.Query()), zap.Any("method", c.Request.Method))
c.Next()
}
}
}

View File

@@ -17,6 +17,8 @@ type DockerStatsModel struct {
Previous interface{} `json:"previous"` Previous interface{} `json:"previous"`
} }
type DeckerDaemonModel struct { // reference - https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file
Graph string `json:"graph"` type DockerDaemonConfigurationModel struct {
// e.g. `/var/lib/docker`
Root string `json:"data-root,omitempty"`
} }

View File

@@ -15,7 +15,6 @@ import (
) )
func NewSshClient(user, password string, port string) (*ssh.Client, error) { func NewSshClient(user, password string, port string) (*ssh.Client, error) {
// connet to ssh // connet to ssh
// addr = fmt.Sprintf("%s:%d", host, port) // addr = fmt.Sprintf("%s:%d", host, port)
@@ -90,11 +89,11 @@ func (w *wsBufferWriter) Write(p []byte) (int, error) {
defer w.mu.Unlock() defer w.mu.Unlock()
return w.buffer.Write(p) return w.buffer.Write(p)
} }
func (s *SshConn) Close() { func (s *SshConn) Close() {
if s.Session != nil { if s.Session != nil {
s.Session.Close() s.Session.Close()
} }
} }
const ( const (
@@ -111,7 +110,6 @@ func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
// read websocket msg // read websocket msg
_, wsData, err := wsConn.ReadMessage() _, wsData, err := wsConn.ReadMessage()
if err != nil { if err != nil {
return "" return ""
} }
@@ -273,6 +271,7 @@ func (ssConn *SshConn) SendComboOutput(wsConn *websocket.Conn, exitCh chan bool)
} }
} }
} }
func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error { func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error {
if w.buffer.Len() != 0 { if w.buffer.Len() != 0 {
err := wsConn.WriteMessage(websocket.TextMessage, w.buffer.Bytes()) err := wsConn.WriteMessage(websocket.TextMessage, w.buffer.Bytes())
@@ -341,6 +340,7 @@ func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exit
} }
} }
} }
func (ssConn *SshConn) SessionWait(quitChan chan bool) { func (ssConn *SshConn) SessionWait(quitChan chan bool) {
if err := ssConn.Session.Wait(); err != nil { if err := ssConn.Session.Wait(); err != nil {
logrus.WithError(err).Error("ssh session wait failed") logrus.WithError(err).Error("ssh session wait failed")

View File

@@ -36,7 +36,7 @@ func ExecResultStrArray(cmdStr string) []string {
return nil return nil
} }
// str, err := ioutil.ReadAll(stdout) // str, err := ioutil.ReadAll(stdout)
var networklist = []string{} networklist := []string{}
outputBuf := bufio.NewReader(stdout) outputBuf := bufio.NewReader(stdout)
for { for {
output, _, err := outputBuf.ReadLine() output, _, err := outputBuf.ReadLine()
@@ -54,6 +54,8 @@ func ExecResultStrArray(cmdStr string) []string {
func ExecResultStr(cmdStr string) string { func ExecResultStr(cmdStr string) string {
cmd := exec.Command("/bin/bash", "-c", cmdStr) cmd := exec.Command("/bin/bash", "-c", cmdStr)
println(cmd.String())
stdout, err := cmd.StdoutPipe() stdout, err := cmd.StdoutPipe()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
@@ -107,6 +109,5 @@ func ExecSmartCTLByPath(path string) []byte {
} }
func ExecEnabledSMART(path string) { func ExecEnabledSMART(path string) {
exec.Command("smartctl", "-s on", path).Output() exec.Command("smartctl", "-s on", path).Output()
} }

View File

@@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"log" "log"
"mime/multipart" "mime/multipart"
@@ -60,7 +61,7 @@ func MkDir(src string) error {
if err != nil { if err != nil {
return err return err
} }
os.Chmod(src, 0777) os.Chmod(src, 0o777)
return nil 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) 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 { if err != nil {
return nil, fmt.Errorf("Fail to OpenFile :%v", err) return nil, fmt.Errorf("Fail to OpenFile :%v", err)
} }
@@ -147,7 +148,7 @@ func CreateFile(path string) error {
} }
func CreateFileAndWriteContent(path string, content 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 { if err != nil {
return err return err
} }
@@ -163,7 +164,7 @@ func CreateFileAndWriteContent(path string, content string) error {
// IsNotExistMkDir create a directory if it does not exist // IsNotExistMkDir create a directory if it does not exist
func IsNotExistCreateFile(src string) error { func IsNotExistCreateFile(src string) error {
if notExist := CheckNotExist(src); notExist == true { if notExist := CheckNotExist(src); notExist {
if err := CreateFile(src); err != nil { if err := CreateFile(src); err != nil {
return err return err
} }
@@ -336,10 +337,17 @@ func WriteToPath(data []byte, path, name string) error {
} else { } else {
fullPath += "/" + name 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, file, err := os.OpenFile(fullPath,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
0666, perm,
) )
if err != nil { if err != nil {
return err return err
@@ -352,24 +360,29 @@ func WriteToPath(data []byte, path, name string) error {
// 最终拼接 // 最终拼接
func SpliceFiles(dir, path string, length int, startPoint int) error { func SpliceFiles(dir, path string, length int, startPoint int) error {
fullPath := path fullPath := path
IsNotExistCreateFile(fullPath) if err := IsNotExistCreateFile(fullPath); err != nil {
return err
}
file, _ := os.OpenFile(fullPath, file, _ := os.OpenFile(fullPath,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
0666, 0o666,
) )
defer file.Close() defer file.Close()
bufferedWriter := bufio.NewWriter(file) bufferedWriter := bufio.NewWriter(file)
// todo: here should have a goroutine to remove each partial file after it is read, to save disk space
for i := 0; i < length+startPoint; i++ { for i := 0; i < length+startPoint; i++ {
data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint)) data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
if err != nil { if err != nil {
return err return err
} }
_, err = bufferedWriter.Write(data) if _, err := bufferedWriter.Write(data); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster write
if err != nil {
return err return err
} }
} }
@@ -380,7 +393,6 @@ func SpliceFiles(dir, path string, length int, startPoint int) error {
} }
func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) { func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) {
switch t { switch t {
case "zip", "": case "zip", "":
return ".zip", archiver.NewZip(), nil return ".zip", archiver.NewZip(), nil
@@ -400,8 +412,8 @@ func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) {
return "", nil, errors.New("format not implemented") 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) info, err := os.Stat(path)
if err != nil { if err != nil {
return err return err
@@ -447,6 +459,7 @@ func AddFile(ar archiver.Writer, path, commonPath string) error {
return nil return nil
} }
func CommonPrefix(sep byte, paths ...string) string { func CommonPrefix(sep byte, paths ...string) string {
// Handle special cases. // Handle special cases.
switch len(paths) { switch len(paths) {

View File

@@ -1,8 +1,10 @@
package route package route
import ( import (
"os"
"github.com/IceWhaleTech/CasaOS-Common/middleware"
"github.com/IceWhaleTech/CasaOS-Common/utils/jwt" "github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
"github.com/IceWhaleTech/CasaOS/middleware"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
v1 "github.com/IceWhaleTech/CasaOS/route/v1" v1 "github.com/IceWhaleTech/CasaOS/route/v1"
@@ -11,13 +13,22 @@ import (
) )
func InitRouter() *gin.Engine { func InitRouter() *gin.Engine {
ginMode := gin.ReleaseMode
if config.ServerInfo.RunMode != "" {
ginMode = config.ServerInfo.RunMode
}
if os.Getenv(gin.EnvGinMode) != "" {
ginMode = os.Getenv(gin.EnvGinMode)
}
gin.SetMode(ginMode)
r := gin.Default() r := gin.New()
r.Use(gin.Recovery())
r.Use(middleware.Cors()) r.Use(middleware.Cors())
r.Use(middleware.WriteLog())
r.Use(gzip.Gzip(gzip.DefaultCompression)) r.Use(gzip.Gzip(gzip.DefaultCompression))
gin.SetMode(config.ServerInfo.RunMode) if ginMode != gin.ReleaseMode {
r.Use(middleware.WriteLog())
}
// r.StaticFS("/ui", http.FS(web.Static)) // r.StaticFS("/ui", http.FS(web.Static))
// r.GET("/", WebUIHome) // r.GET("/", WebUIHome)
@@ -100,8 +111,8 @@ func InitRouter() *gin.Engine {
v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate) v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate)
// Not used // Not used
v1ContainerGroup.POST("/share", v1.ShareAppFile) v1ContainerGroup.POST("/share", v1.ShareAppFile)
v1ContainerGroup.GET("/info", v1.GetcontainerInfo) v1ContainerGroup.GET("/info", v1.GetDockerDaemonConfiguration)
v1ContainerGroup.PUT("/info", v1.PutcontainerInfo) v1ContainerGroup.PUT("/info", v1.PutDockerDaemonConfiguration)
} }
v1AppCategoriesGroup := v1Group.Group("/app-categories") v1AppCategoriesGroup := v1Group.Group("/app-categories")

View File

@@ -2,8 +2,9 @@ package v1
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net/http"
"path/filepath"
"strconv" "strconv"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
@@ -16,6 +17,11 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
const (
dockerRootDirFilePath = "/var/lib/casaos/docker_root"
dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json"
)
// @Summary 获取远程列表 // @Summary 获取远程列表
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -29,7 +35,6 @@ import (
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /app/list [get] // @Router /app/list [get]
func AppList(c *gin.Context) { func AppList(c *gin.Context) {
// service.MyService.Docker().DockerContainerCommit("test2") // service.MyService.Docker().DockerContainerCommit("test2")
index := c.DefaultQuery("index", "1") index := c.DefaultQuery("index", "1")
@@ -151,7 +156,6 @@ func AppUsageList(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /app/appinfo/{id} [get] // @Router /app/appinfo/{id} [get]
func AppInfo(c *gin.Context) { func AppInfo(c *gin.Context) {
id := c.Param("id") id := c.Param("id")
language := c.GetHeader("Language") language := c.GetHeader("Language")
info, err := service.MyService.Casa().GetServerAppInfo(id, "", language) info, err := service.MyService.Casa().GetServerAppInfo(id, "", language)
@@ -265,53 +269,87 @@ func ShareAppFile(c *gin.Context) {
c.JSON(common_err.SUCCESS, json.RawMessage(content)) c.JSON(common_err.SUCCESS, json.RawMessage(content))
} }
func GetcontainerInfo(c *gin.Context) { func GetDockerDaemonConfiguration(c *gin.Context) {
// info, err := service.MyService.Docker().GetDockerInfo() // info, err := service.MyService.Docker().GetDockerInfo()
// if err != nil { // 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()}) // 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 // return
// } // }
daemon := model.DeckerDaemonModel{} data := make(map[string]interface{})
data := make(map[string]interface{}, 1)
data["docker_root_dir"] = "" if file.Exists(dockerRootDirFilePath) {
if file.Exists("/etc/docker/daemon.json") { buf := file.ReadFullFile(dockerRootDirFilePath)
byteResult := file.ReadFullFile("/etc/docker/daemon.json") err := json.Unmarshal(buf, &data)
err := json.Unmarshal(byteResult, &daemon)
if err != nil { 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(common_err.CLIENT_ERROR, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
return return
} }
data["docker_root_dir"] = daemon.Graph
} }
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) 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) {
js := make(map[string]interface{}) func PutDockerDaemonConfiguration(c *gin.Context) {
err := c.BindJSON(&js) request := make(map[string]interface{})
if err != nil { if err := c.BindJSON(&request); 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.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
return return
} }
dockerRootDir := js["docker_root_dir"].(string)
daemon := model.DeckerDaemonModel{} value, ok := request["docker_root_dir"]
if file.Exists("/etc/docker/daemon.json") { if !ok {
byteResult := file.ReadFullFile("/etc/docker/daemon.json") 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"})
err := json.Unmarshal(byteResult, &daemon) return
}
dockerConfig := model.DockerDaemonConfigurationModel{}
if file.Exists(dockerDaemonConfigurationFilePath) {
byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath)
err := json.Unmarshal(byteResult, &dockerConfig)
if err != nil { 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})
return return
} }
} }
dockerRootDir := value.(string)
if dockerRootDir == "/" {
dockerConfig.Root = "" // omitempty - empty string will not be serialized
} else {
if !file.Exists(dockerRootDir) { 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)}) 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 return
} }
daemon.Graph = dockerRootDir
byteMode, _ := json.Marshal(daemon)
file.WriteToPath(byteMode, "/etc/docker", "daemon.json")
fmt.Println(command.ExecResultStr("systemctl daemon-reload")) dockerConfig.Root = filepath.Join(dockerRootDir, "docker")
fmt.Println(command.ExecResultStr("systemctl restart docker"))
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: js}) 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})
return
}
}
if buf, err := json.Marshal(request); err != nil {
c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker root json", Data: err})
return
} else {
if err := file.WriteToFullPath(buf, dockerRootDirFilePath, 0o644); err != nil {
c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to write " + dockerRootDirFilePath, Data: err})
return
}
}
if buf, err := json.Marshal(dockerConfig); err != nil {
c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: "error when trying to serialize docker config", Data: dockerConfig})
return
} else {
if err := file.WriteToFullPath(buf, 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})
return
}
}
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: request})
} }

View File

@@ -18,9 +18,11 @@ import (
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
"go.uber.org/zap"
) )
// @Summary 读取文件 // @Summary 读取文件
@@ -83,7 +85,6 @@ func GetLocalFile(c *gin.Context) {
return return
} }
c.File(path) c.File(path)
return
} }
// @Summary download // @Summary download
@@ -96,7 +97,6 @@ func GetLocalFile(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/download [get] // @Router /file/download [get]
func GetDownloadFile(c *gin.Context) { func GetDownloadFile(c *gin.Context) {
t := c.Query("format") t := c.Query("format")
files := c.Query("files") files := c.Query("files")
@@ -179,7 +179,6 @@ func GetDownloadFile(c *gin.Context) {
log.Printf("Failed to archive %s: %v", fname, err) log.Printf("Failed to archive %s: %v", fname, err)
} }
} }
} }
func GetDownloadSingleFile(c *gin.Context) { func GetDownloadSingleFile(c *gin.Context) {
@@ -361,7 +360,6 @@ func PostCreateFile(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/upload [get] // @Router /file/upload [get]
func GetFileUpload(c *gin.Context) { func GetFileUpload(c *gin.Context) {
relative := c.Query("relativePath") relative := c.Query("relativePath")
fileName := c.Query("filename") fileName := c.Query("filename")
chunkNumber := c.Query("chunkNumber") chunkNumber := c.Query("chunkNumber")
@@ -405,55 +403,92 @@ func PostFileUpload(c *gin.Context) {
hash := file.GetHashByContent([]byte(fileName)) hash := file.GetHashByContent([]byte(fileName))
if len(path) == 0 { if len(path) == 0 {
c.JSON(common_err.INVALID_PARAMS, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) loger.Error("path should not be empty")
c.JSON(http.StatusBadRequest, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return return
} }
tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/" tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
if fileName != relative { if fileName != relative {
dirPath = strings.TrimSuffix(relative, fileName) dirPath = strings.TrimSuffix(relative, fileName)
tempDir += dirPath tempDir += dirPath
file.MkDir(path + "/" + dirPath) if err := file.MkDir(path + "/" + dirPath); err != nil {
loger.Error("error when trying to create `"+path+"/"+dirPath+"`", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
}
} }
path += "/" + relative path += "/" + relative
if !file.CheckNotExist(tempDir + chunkNumber) { if !file.CheckNotExist(tempDir + chunkNumber) {
file.RMDir(tempDir + chunkNumber) if err := file.RMDir(tempDir + chunkNumber); err != nil {
loger.Error("error when trying to remove existing `"+tempDir+chunkNumber+"`", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
}
} }
if totalChunks > 1 { if totalChunks > 1 {
file.IsNotExistMkDir(tempDir) if err := file.IsNotExistMkDir(tempDir); err != nil {
loger.Error("error when trying to create `"+tempDir+"`", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
}
out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644) out, err := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0o644)
defer out.Close()
_, err := io.Copy(out, f)
if err != nil { 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()}) loger.Error("error when trying to open `"+tempDir+chunkNumber+"` for creation", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return return
} }
} else {
out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
defer out.Close() defer out.Close()
_, err := io.Copy(out, f)
if err != nil { if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()}) loger.Error("error when trying to write to `"+tempDir+chunkNumber+"`", zap.Error(err))
return c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
return return
} }
fileNum, err := ioutil.ReadDir(tempDir) fileNum, err := ioutil.ReadDir(tempDir)
if err != nil { 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()}) loger.Error("error when trying to read number of files under `"+tempDir+"`", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return return
} }
if totalChunks == len(fileNum) { if totalChunks == len(fileNum) {
file.SpliceFiles(tempDir, path, totalChunks, 1) if err := file.SpliceFiles(tempDir, path, totalChunks, 1); err != nil {
file.RMDir(tempDir) loger.Error("error when trying to splice files under `"+tempDir+"`", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
} }
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) if err := file.RMDir(tempDir); err != nil {
loger.Error("error when trying to remove `"+tempDir+"`", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
}
}
} else {
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil {
loger.Error("error when trying to open `"+path+"` for creation", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
return
}
defer out.Close()
if _, err := io.Copy(out, f); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster copy
loger.Error("error when trying to write to `"+path+"`", zap.Error(err))
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
} }
// @Summary copy or move file // @Summary copy or move file
@@ -465,7 +500,6 @@ func PostFileUpload(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/operate [post] // @Router /file/operate [post]
func PostOperateFileOrDir(c *gin.Context) { func PostOperateFileOrDir(c *gin.Context) {
list := model.FileOperate{} list := model.FileOperate{}
c.ShouldBind(&list) c.ShouldBind(&list)
@@ -515,7 +549,6 @@ func PostOperateFileOrDir(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/delete [delete] // @Router /file/delete [delete]
func DeleteFile(c *gin.Context) { func DeleteFile(c *gin.Context) {
paths := []string{} paths := []string{}
c.ShouldBind(&paths) c.ShouldBind(&paths)
if len(paths) == 0 { if len(paths) == 0 {
@@ -547,7 +580,6 @@ func DeleteFile(c *gin.Context) {
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/update [put] // @Router /file/update [put]
func PutFileContent(c *gin.Context) { func PutFileContent(c *gin.Context) {
fi := model.FileUpdate{} fi := model.FileUpdate{}
c.ShouldBind(&fi) c.ShouldBind(&fi)