Browse Source

Merge branch 'v0.3.7' of https://github.com/IceWhaleTech/CasaOS into v0.3.7

LinkLeong 2 years ago
parent
commit
be80d0cd95

+ 30 - 34
build/scripts/migration/script.d/03-migrate-casaos.sh

@@ -60,8 +60,6 @@ BUILD_PATH=$(dirname "${BASH_SOURCE[0]}")/../../..
 SOURCE_ROOT=${BUILD_PATH}/sysroot
 
 APP_NAME="casaos"
-APP_NAME_FORMAL="CasaOS"
-#APP_NAME_FORMAL="casaos-alpha"
 
 # check if migration is needed
 SOURCE_BIN_PATH=${SOURCE_ROOT}/usr/bin
@@ -85,6 +83,25 @@ if [ "${NEED_MIGRATION}" = "false" ]; then
     exit 0
 fi
 
+ARCH="unknown"
+
+case $(uname -m) in
+    x86_64)
+        ARCH="amd64"
+        ;;
+    aarch64)
+        ARCH="arm64"
+        ;;
+    armv7l)
+        ARCH="arm-7"
+        ;;
+    *)
+        __error "Unsupported architecture"
+        ;;
+esac
+
+__info "ARCH: ${ARCH}"
+
 MIGRATION_SERVICE_DIR=${1}
 
 if [ -z "${MIGRATION_SERVICE_DIR}" ]; then
@@ -95,10 +112,10 @@ MIGRATION_PATH=()
 
 CURRENT_VERSION_FOUND="false"
 
-# a VERSION_PAIR looks like "v0.3.5 v0.3.6-alpha2"
+# a VERSION_PAIR looks like "v0.3.5 <url>"
 #
 # - "v0.3.5" is the current version installed on this host
-# - "v0.3.6-alpha2" is the version of the migration tool from GitHub
+# - "<url>" is the url of the migration tool
 while read -r VERSION_PAIR; do
     if [ -z "${VERSION_PAIR}" ]; then
         continue
@@ -107,15 +124,15 @@ while read -r VERSION_PAIR; do
     # obtain "v0.3.5" from "v0.3.5 v0.3.6-alpha2"
     VER1=$(echo "${VERSION_PAIR}" | cut -d' ' -f1)
 
-    # obtain "v0.3.6-alpha2" from "v0.3.5 v0.3.6-alpha2"
-    VER2=$(echo "${VERSION_PAIR}" | cut -d' ' -f2)
+    # obtain "<url>" from "v0.3.5 <url>"
+    URL=$(eval echo "${VERSION_PAIR}" | cut -d' ' -f2)
 
     if [ "${CURRENT_VERSION}" = "${VER1// /}" ] || [ "${CURRENT_VERSION}" = "LEGACY_WITHOUT_VERSION" ]; then
         CURRENT_VERSION_FOUND="true"
     fi
 
     if [ "${CURRENT_VERSION_FOUND}" = "true" ]; then
-        MIGRATION_PATH+=("${VER2// /}")
+        MIGRATION_PATH+=("${URL// /}")
     fi
 done < "${MIGRATION_LIST_FILE}"
 
@@ -124,39 +141,18 @@ if [ ${#MIGRATION_PATH[@]} -eq 0 ]; then
     exit 0
 fi
 
-ARCH="unknown"
-
-case $(uname -m) in
-    x86_64)
-        ARCH="amd64"
-        ;;
-    aarch64)
-        ARCH="arm64"
-        ;;
-    armv7l)
-        ARCH="arm-7"
-        ;;
-    *)
-        __error "Unsupported architecture"
-        ;;
-esac
-
 pushd "${MIGRATION_SERVICE_DIR}"
 
-{ for VER2 in "${MIGRATION_PATH[@]}"; do
-
-
-        MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
+{ for URL in "${MIGRATION_PATH[@]}"; do
+        MIGRATION_TOOL_FILE=$(basename "${URL}")
 
         if [ -f "${MIGRATION_TOOL_FILE}" ]; then
             __info "Migration tool ${MIGRATION_TOOL_FILE} exists. Skip downloading."
             continue
         fi
 
-       # MIGRATION_TOOL_URL=http://192.168.2.197:8000/v1/package/migration?type=release&name="${APP_NAME_FORMAL}"&version=${VER2}&arch=${ARCH}
-        MIGRATION_TOOL_URL=https://github.com/IceWhaleTech/"${APP_NAME_FORMAL}"/releases/download/"${VER2}"/linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
-        echo "Dowloading ${MIGRATION_TOOL_URL}..."
-        curl -sL -O "${MIGRATION_TOOL_URL}"
+        __info "Dowloading ${URL}..."
+        curl -fsSL -o "${MIGRATION_TOOL_FILE}" -O "${URL}"
     done
 } || {
     popd
@@ -164,8 +160,8 @@ pushd "${MIGRATION_SERVICE_DIR}"
 }
 
 {
-    for VER2 in "${MIGRATION_PATH[@]}"; do
-        MIGRATION_TOOL_FILE=linux-"${ARCH}"-"${APP_NAME}"-migration-tool-"${VER2}".tar.gz
+    for URL in "${MIGRATION_PATH[@]}"; do
+        MIGRATION_TOOL_FILE=$(basename "${URL}")
         __info "Extracting ${MIGRATION_TOOL_FILE}..."
         tar zxvf "${MIGRATION_TOOL_FILE}" || __error "Failed to extract ${MIGRATION_TOOL_FILE}"
 

+ 3 - 4
build/scripts/migration/service.d/casaos/migration.list

@@ -1,4 +1,3 @@
-LEGACY_WITHOUT_VERSION v0.3.6
-v0.3.5 v0.3.6
-v0.3.5.1 v0.3.6
-v0.3.6 v0.3.7
+LEGACY_WITHOUT_VERSION https://github.com/IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
+v0.3.5 https://github.com/IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz
+v0.3.5.1 https://github.com/IceWhaleTech/CasaOS/releases/download/v0.3.6/linux-${ARCH}-casaos-migration-tool-v0.3.6.tar.gz

+ 7 - 12
build/scripts/setup/service.d/casaos/debian/setup-casaos.sh

@@ -31,15 +31,10 @@ if [ ! -f "${CONF_FILE}" ]; then
     cp -v "${CONF_FILE_SAMPLE}" "${CONF_FILE}"
 fi
 
-if systemctl is-active "${APP_NAME}.service" &>/dev/null ;then
-    echo "server started"
-else
-    # enable and start service
-    systemctl daemon-reload
-
-    echo "Enabling service..."
-    systemctl enable --force --no-ask-password "${APP_NAME}.service"
-
-    #echo "Starting service..."
-    #systemctl start --force --no-ask-password "${APP_NAME}.service"
-fi
+rm -rf /etc/systemd/system/casaos.service # remove old service file
+
+systemctl daemon-reload
+
+# enable service (without starting)
+echo "Enabling service..."
+systemctl enable --force --no-ask-password "${APP_NAME}.service"

+ 1 - 1
build/sysroot/usr/share/casaos/shell/update.sh

@@ -9,4 +9,4 @@
 ### 
 
 
-curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/new.update.sh | bash
+curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | bash

+ 4 - 6
cmd/migration-tool/main.go

@@ -83,8 +83,7 @@ func main() {
 	}
 
 	migrationTools := []interfaces.MigrationTool{
-		NewMigrationToolFor_035(),
-		NewMigrationToolFor_036(),
+		// nothing to migrate from last version
 	}
 
 	var selectedMigrationTool interfaces.MigrationTool
@@ -115,8 +114,7 @@ func main() {
 		panic(err)
 	}
 
-	selectedMigrationTool.PostMigrate()
-	_logger.Info("casaos migration ok")
-	// panic(err)
-
+	if err := selectedMigrationTool.PostMigrate(); err != nil {
+		_logger.Error("Migration succeeded, but post-migration failed: %s", err)
+	}
 }

+ 0 - 182
cmd/migration-tool/migration-034-035.go

@@ -1,182 +0,0 @@
-/*
- * @Author: LinkLeong link@icewhale.org
- * @Date: 2022-08-24 17:36:00
- * @LastEditors: LinkLeong
- * @LastEditTime: 2022-09-05 11:24:27
- * @FilePath: /CasaOS/cmd/migration-tool/migration-034-035.go
- * @Description:
- * @Website: https://www.casaos.io
- * Copyright (c) 2022 by icewhale, All Rights Reserved.
- */
-package main
-
-import (
-	"io"
-	"io/ioutil"
-	"os"
-	"path"
-	"strings"
-
-	interfaces "github.com/IceWhaleTech/CasaOS-Common"
-	"github.com/IceWhaleTech/CasaOS-Common/utils/version"
-	"github.com/IceWhaleTech/CasaOS/pkg/config"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
-	"github.com/IceWhaleTech/CasaOS/service"
-)
-
-type migrationTool036 struct{}
-
-func (u *migrationTool036) IsMigrationNeeded() (bool, error) {
-
-	majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
-	if err != nil {
-		if err == version.ErrLegacyVersionNotFound {
-			return false, nil
-		}
-
-		return false, err
-	}
-
-	if majorVersion > 0 {
-		return false, nil
-	}
-
-	if minorVersion > 3 {
-		return false, nil
-	}
-
-	if minorVersion == 3 && patchVersion > 5 {
-		return false, nil
-	}
-
-	_logger.Info("Migration is needed for a CasaOS version 0.3.5 and older...")
-	return true, nil
-
-}
-
-func (u *migrationTool036) PreMigrate() error {
-
-	return nil
-}
-
-func (u *migrationTool036) Migrate() error {
-
-	if service.MyService.System().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.System().GetDeviceTree(), "Raspberry Pi") {
-		service.MyService.System().UpdateUSBAutoMount("False")
-		service.MyService.System().ExecUSBAutoMountShell("False")
-	}
-	newAPIUrl := "https://api.casaos.io/casaos-api"
-	if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
-		config.ServerInfo.ServerApi = newAPIUrl
-		config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
-		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
-	}
-	command.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/assist.sh | bash")
-	if !file.CheckNotExist("/casaOS") {
-		command.OnlyExec("source /casaOS/server/shell/update.sh ;")
-		command.OnlyExec("source " + config.AppInfo.ShellPath + "/delete-old-service.sh ;")
-	}
-
-	service.MyService.App().ImportApplications(true)
-
-	src := "/casaOS/server/conf/conf.ini"
-	if file.Exists(src) {
-		dst := "/etc/casaos/casaos.conf"
-		source, err := os.Open(src)
-		if err != nil {
-			return err
-		}
-		defer source.Close()
-
-		destination, err := os.Create(dst)
-		if err != nil {
-			return err
-		}
-		defer destination.Close()
-		_, err = io.Copy(destination, source)
-		if err != nil {
-			return err
-		}
-
-	}
-
-	if file.Exists("/casaOS/server/db") {
-		var fds []os.FileInfo
-		var err error
-		to := "/var/lib/casaos/db"
-		file.IsNotExistMkDir(to)
-		from := "/casaOS/server/db"
-		if fds, err = ioutil.ReadDir(from); err != nil {
-			return err
-		}
-
-		for _, fd := range fds {
-			srcfp := path.Join(from, fd.Name())
-			dstfp := path.Join(to, fd.Name())
-			source, err := os.Open(srcfp)
-			if err != nil {
-				return err
-			}
-			defer source.Close()
-
-			destination, err := os.Create(dstfp)
-			if err != nil {
-				return err
-			}
-			defer destination.Close()
-			_, err = io.Copy(destination, source)
-			if err != nil {
-				return err
-			}
-		}
-
-	}
-
-	if file.Exists("/casaOS/server/conf") {
-		var fds []os.FileInfo
-		var err error
-		to := "/var/lib/casaos/conf"
-		file.IsNotExistMkDir(to)
-		from := "/casaOS/server/conf"
-		if fds, err = ioutil.ReadDir(from); err != nil {
-			return err
-		}
-
-		for _, fd := range fds {
-			fExt := path.Ext(fd.Name())
-			if fExt != ".json" {
-				continue
-			}
-			srcfp := path.Join(from, fd.Name())
-			dstfp := path.Join(to, fd.Name())
-			source, err := os.Open(srcfp)
-			if err != nil {
-				return err
-			}
-			defer source.Close()
-
-			destination, err := os.Create(dstfp)
-			if err != nil {
-				return err
-			}
-			defer destination.Close()
-			_, err = io.Copy(destination, source)
-			if err != nil {
-				return err
-			}
-		}
-
-	}
-
-	_logger.Info("update done")
-	return nil
-}
-
-func (u *migrationTool036) PostMigrate() error {
-	return nil
-}
-
-func NewMigrationToolFor_035() interfaces.MigrationTool {
-	return &migrationTool{}
-}

+ 0 - 64
middleware/gin.go

@@ -1,64 +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"
-	"runtime/debug"
-	"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)
-				debug.PrintStack()
-			}
-		}()
-
-		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()
-		}
-	}
-}

+ 9 - 3
pkg/utils/file/file.go

@@ -362,21 +362,27 @@ func WriteToFullPath(data []byte, fullPath string, perm fs.FileMode) error {
 func SpliceFiles(dir, path string, length int, startPoint int) error {
 	fullPath := path
 
-	IsNotExistCreateFile(fullPath)
+	if err := IsNotExistCreateFile(fullPath); err != nil {
+		return err
+	}
 
 	file, _ := os.OpenFile(fullPath,
 		os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
 		0o666,
 	)
+
 	defer file.Close()
+
 	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++ {
 		data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
 		if err != nil {
 			return err
 		}
-		_, err = bufferedWriter.Write(data)
-		if err != nil {
+		if _, err := bufferedWriter.Write(data); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster write
 			return err
 		}
 	}

+ 16 - 4
route/route.go

@@ -1,8 +1,10 @@
 package route
 
 import (
+	"os"
+
+	"github.com/IceWhaleTech/CasaOS-Common/middleware"
 	"github.com/IceWhaleTech/CasaOS-Common/utils/jwt"
-	"github.com/IceWhaleTech/CasaOS/middleware"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	v1 "github.com/IceWhaleTech/CasaOS/route/v1"
 
@@ -11,12 +13,22 @@ import (
 )
 
 func InitRouter() *gin.Engine {
-	r := gin.Default()
+	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.New()
+	r.Use(gin.Recovery())
 	r.Use(middleware.Cors())
-	r.Use(middleware.WriteLog())
 	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.GET("/", WebUIHome)

+ 27 - 28
route/v1/app.go

@@ -18,6 +18,7 @@ import (
 )
 
 const (
+	dockerRootDirFilePath             = "/var/lib/casaos/docker_root"
 	dockerDaemonConfigurationFilePath = "/etc/docker/daemon.json"
 )
 
@@ -274,36 +275,27 @@ func GetDockerDaemonConfiguration(c *gin.Context) {
 	// 	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
 	// }
-	dockerConfig := model.DockerDaemonConfigurationModel{}
-	data := make(map[string]interface{}, 1)
-	data["docker_root_dir"] = ""
+	data := make(map[string]interface{})
 
-	// TODO read dockerRootDir from /etc/casaos/casaos.conf
-	if file.Exists(dockerDaemonConfigurationFilePath) {
-		byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath)
-		err := json.Unmarshal(byteResult, &dockerConfig)
+	if file.Exists(dockerRootDirFilePath) {
+		buf := file.ReadFullFile(dockerRootDirFilePath)
+		err := json.Unmarshal(buf, &data)
 		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
 		}
-
-		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 PutDockerDaemonConfiguration(c *gin.Context) {
-	js := make(map[string]interface{})
-	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()})
+	request := make(map[string]interface{})
+	if err := c.BindJSON(&request); err != nil {
+		c.JSON(http.StatusBadRequest, &model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: err})
 		return
 	}
 
-	value, ok := js["docker_root_dir"]
+	value, ok := request["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
@@ -314,7 +306,7 @@ func PutDockerDaemonConfiguration(c *gin.Context) {
 		byteResult := file.ReadFullFile(dockerDaemonConfigurationFilePath)
 		err := json.Unmarshal(byteResult, &dockerConfig)
 		if err != nil {
-			c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err.Error()})
+			c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to deserialize " + dockerDaemonConfigurationFilePath, Data: err})
 			return
 		}
 	}
@@ -331,26 +323,33 @@ func PutDockerDaemonConfiguration(c *gin.Context) {
 		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()})
+			c.JSON(http.StatusInternalServerError, &model.Result{Success: common_err.SERVICE_ERROR, Message: "error when trying to create " + dockerConfig.Root, Data: err})
 			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})
+	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 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()})
+	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
+		}
 	}
 
-	// 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})
+	c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: request})
 }

+ 1 - 1
route/v1/docker.go

@@ -1126,7 +1126,7 @@ func ContainerUpdateInfo(c *gin.Context) {
 		}
 	}
 	for _, v := range info.Config.Env {
-		if len(showENVList) > 0 {
+		if len(showENVList) > 0 && info.Config.Labels["origin"] != "local" {
 			if _, ok := showENVMap[strings.Split(v, "=")[0]]; ok {
 				temp := model.Env{
 					Name:  strings.Split(v, "=")[0],

+ 68 - 37
route/v1/file.go

@@ -18,9 +18,11 @@ import (
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
+	"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/gin-gonic/gin"
 	uuid "github.com/satori/go.uuid"
+	"go.uber.org/zap"
 )
 
 // @Summary 读取文件
@@ -47,7 +49,7 @@ func GetFilerContent(c *gin.Context) {
 		})
 		return
 	}
-	//文件读取任务是将文件内容读取到内存中。
+	// 文件读取任务是将文件内容读取到内存中。
 	info, err := ioutil.ReadFile(filePath)
 	if err != nil {
 		c.JSON(common_err.SERVICE_ERROR, model.Result{
@@ -83,7 +85,6 @@ func GetLocalFile(c *gin.Context) {
 		return
 	}
 	c.File(path)
-	return
 }
 
 // @Summary download
@@ -96,7 +97,6 @@ func GetLocalFile(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/download [get]
 func GetDownloadFile(c *gin.Context) {
-
 	t := c.Query("format")
 
 	files := c.Query("files")
@@ -135,11 +135,11 @@ func GetDownloadFile(c *gin.Context) {
 		}
 		if !info.IsDir() {
 
-			//打开文件
+			// 打开文件
 			fileTmp, _ := os.Open(filePath)
 			defer fileTmp.Close()
 
-			//获取文件的名称
+			// 获取文件的名称
 			fileName := path.Base(filePath)
 			c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
 			c.File(filePath)
@@ -179,7 +179,6 @@ func GetDownloadFile(c *gin.Context) {
 			log.Printf("Failed to archive %s: %v", fname, err)
 		}
 	}
-
 }
 
 func GetDownloadSingleFile(c *gin.Context) {
@@ -202,7 +201,7 @@ func GetDownloadSingleFile(c *gin.Context) {
 	defer fileTmp.Close()
 
 	fileName := path.Base(filePath)
-	//c.Header("Content-Disposition", "inline")
+	// c.Header("Content-Disposition", "inline")
 	c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
 	c.File(filePath)
 }
@@ -248,7 +247,7 @@ func DirPath(c *gin.Context) {
 			info[i].Extensions = ex
 		}
 	}
-	//Hide the files or folders in operation
+	// Hide the files or folders in operation
 	fileQueue := make(map[string]string)
 	if len(service.OpStrArr) > 0 {
 		for _, v := range service.OpStrArr {
@@ -361,7 +360,6 @@ func PostCreateFile(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/upload [get]
 func GetFileUpload(c *gin.Context) {
-
 	relative := c.Query("relativePath")
 	fileName := c.Query("filename")
 	chunkNumber := c.Query("chunkNumber")
@@ -405,7 +403,8 @@ func PostFileUpload(c *gin.Context) {
 	hash := file.GetHashByContent([]byte(fileName))
 
 	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
 	}
 	tempDir := filepath.Join(path, ".temp", hash+strconv.Itoa(totalChunks)) + "/"
@@ -413,47 +412,82 @@ func PostFileUpload(c *gin.Context) {
 	if fileName != relative {
 		dirPath = strings.TrimSuffix(relative, fileName)
 		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
 
 	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 {
-		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, err := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0o644)
+		if err != nil {
+			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
+		}
 
-		out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644)
 		defer out.Close()
-		_, err := io.Copy(out, f)
+
+		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 `"+tempDir+chunkNumber+"`", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
+			return
+		}
+
+		fileNum, err := ioutil.ReadDir(tempDir)
 		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
 		}
+
+		if totalChunks == len(fileNum) {
+			if err := file.SpliceFiles(tempDir, path, totalChunks, 1); err != nil {
+				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
+			}
+
+			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, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
-		defer out.Close()
-		_, err := io.Copy(out, f)
+		out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o644)
 		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 `"+path+"` for creation", zap.Error(err))
+			c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()})
 			return
 		}
-		c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
-		return
-	}
-	fileNum, err := ioutil.ReadDir(tempDir)
-	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
-	}
-	if totalChunks == len(fileNum) {
-		file.SpliceFiles(tempDir, path, totalChunks, 1)
-		file.RMDir(tempDir)
-	}
 
-	c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
+		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
@@ -465,7 +499,6 @@ func PostFileUpload(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/operate [post]
 func PostOperateFileOrDir(c *gin.Context) {
-
 	list := model.FileOperate{}
 	c.ShouldBind(&list)
 
@@ -515,7 +548,6 @@ func PostOperateFileOrDir(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/delete [delete]
 func DeleteFile(c *gin.Context) {
-
 	paths := []string{}
 	c.ShouldBind(&paths)
 	if len(paths) == 0 {
@@ -547,7 +579,6 @@ func DeleteFile(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /file/update [put]
 func PutFileContent(c *gin.Context) {
-
 	fi := model.FileUpdate{}
 	c.ShouldBind(&fi)
 
@@ -557,7 +588,7 @@ func PutFileContent(c *gin.Context) {
 		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
 		return
 	}
-	//err := os.Remove(path)
+	// err := os.Remove(path)
 	err := os.RemoveAll(fi.FilePath)
 	if err != nil {
 		c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})

+ 1 - 1
service/system.go

@@ -221,7 +221,7 @@ func (s *systemService) UpdateSystemVersion(version string) {
 	}
 	file.CreateFile(config.AppInfo.LogPath + "/upgrade.log")
 	//go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash")
-	go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | sudo bash")
+	go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/IceWhaleTech/get/main/update.sh | bash")
 	//s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
 	//s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
 }