diff --git a/changelog.md b/changelog.md index bc8c45ed..8fb740db 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +## Version 0.17.6 + - Can now chose between plain or formatted logs + - Added "force update" button in service mode + - Fixed issues related to fstab management + +## Version 0.17.5 + - Fixed issue with TCP proxy timeouts + ## Version 0.17.4 - Hide update button in container - Fix issue with allowHTTPLocal and the TCP Proxy diff --git a/client/src/api/index.jsx b/client/src/api/index.jsx index c723d2e2..3b65d88d 100644 --- a/client/src/api/index.jsx +++ b/client/src/api/index.jsx @@ -230,6 +230,15 @@ function terminal(startCmd = "bash") { return new WebSocket(protocol + window.location.host + '/cosmos/api/terminal/'+startCmd) } +function forceAutoUpdate() { + return wrap(fetch('/cosmos/api/force-server-update', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + })); +} + const isDemo = import.meta.env.MODE === 'demo'; let auth = _auth; @@ -281,5 +290,6 @@ export { terminal, cron, rclone, - restartServer + restartServer, + forceAutoUpdate }; \ No newline at end of file diff --git a/client/src/pages/config/users/configman.jsx b/client/src/pages/config/users/configman.jsx index 272698b7..29ccea21 100644 --- a/client/src/pages/config/users/configman.jsx +++ b/client/src/pages/config/users/configman.jsx @@ -50,6 +50,7 @@ const ConfigManagement = () => { const [saveLabel, setSaveLabel] = React.useState(t('global.saveAction')); const {role} = useClientInfos(); const isAdmin = role === "2"; + const [isCheckingUpdate, setIsCheckingUpdate] = React.useState(false); function refresh() { API.config.get().then((res) => { @@ -295,6 +296,15 @@ const ConfigManagement = () => { {status && !status.containerized && <> + + { + setIsCheckingUpdate(true); + API.forceAutoUpdate().then(() => { + setIsCheckingUpdate(false); + }) + }}>{t('mgmt.config.general.forceAutoUpdateButton')} + + Thanks to the sponsors:

null null -Dér Kristóf Gordon null Phobes null Ricardo Escaran null -Carr null

diff --git a/src/httpServer.go b/src/httpServer.go index c0ad49b3..f60b4c4d 100644 --- a/src/httpServer.go +++ b/src/httpServer.go @@ -389,6 +389,7 @@ func InitServer() *mux.Router { srapi.HandleFunc("/api/status", StatusRoute) srapi.HandleFunc("/api/restart-server", restartHostMachineRoute) srapi.HandleFunc("/_logs", LogsRoute) + srapi.HandleFunc("/api/force-server-update", ForceUpdateRoute) srapi.HandleFunc("/api/can-send-email", CanSendEmail) srapi.HandleFunc("/api/newInstall", NewInstallRoute) srapi.HandleFunc("/api/logout", user.UserLogout) diff --git a/src/storage/mergerFS.go b/src/storage/mergerFS.go index e25d37c7..d48cd8fd 100644 --- a/src/storage/mergerFS.go +++ b/src/storage/mergerFS.go @@ -67,7 +67,7 @@ func MountMergerFS(paths []string, mountpoint string, opts string, permanent boo } // Format the fstab entry - fstabEntry := fmt.Sprintf("%s %s mergerfs use_ino,cache.files=partial,dropcacheonclose=true,allow_other,category.create=mfs%s 0 0\n", strings.Join(paths, ":"), mountpoint, opts) + fstabEntry := fmt.Sprintf("\n%s %s mergerfs use_ino,cache.files=partial,dropcacheonclose=true,allow_other,category.create=mfs%s 0 0\n", strings.Join(paths, ":"), mountpoint, opts) // Append to /etc/fstab file, err := os.OpenFile("/etc/fstab", os.O_APPEND|os.O_WRONLY, 0644) diff --git a/src/storage/mounts.go b/src/storage/mounts.go index ba710fad..a1670bff 100644 --- a/src/storage/mounts.go +++ b/src/storage/mounts.go @@ -129,7 +129,7 @@ func Mount(path, mountpoint string, permanent bool, chown string) error { } // Format the fstab entry - fstabEntry := fmt.Sprintf("%s %s auto defaults 0 0\n", path, mountpoint) + fstabEntry := fmt.Sprintf("\n%s %s auto defaults 0 0\n", path, mountpoint) // Append to /etc/fstab file, err := os.OpenFile("/etc/fstab", os.O_APPEND|os.O_WRONLY, 0644) @@ -183,6 +183,8 @@ func Unmount(mountpoint string, permanent bool) error { // isMountPointInFstab checks if the given mountpoint is already in /etc/fstab. func isMountPointInFstab(mountpoint string) (bool, error) { + mountpoint = strings.Replace(mountpoint, "/var/mnt/", "/mnt/", 1) + file, err := os.Open("/etc/fstab") if err != nil { return false, err @@ -191,7 +193,7 @@ func isMountPointInFstab(mountpoint string) (bool, error) { scanner := bufio.NewScanner(file) for scanner.Scan() { - if strings.Contains(scanner.Text(), mountpoint) { + if strings.Contains(scanner.Text(), " " + mountpoint + " ") { return true, nil } } @@ -205,6 +207,8 @@ func isMountPointInFstab(mountpoint string) (bool, error) { // removeFstabEntry removes an entry for the specified mountpoint from /etc/fstab. func removeFstabEntry(mountpoint string) error { + mountpoint = strings.Replace(mountpoint, "/var/mnt/", "/mnt/", 1) + file, err := os.Open("/etc/fstab") if err != nil { return err @@ -215,7 +219,11 @@ func removeFstabEntry(mountpoint string) error { scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() - if !strings.Contains(line, mountpoint) { + + isComment := strings.HasPrefix(line, "#") + isEmpty := len(strings.TrimSpace(line)) == 0 + + if !isEmpty && (!strings.Contains(line, " " + mountpoint + " ") || isComment) { lines = append(lines, line) } } @@ -224,6 +232,8 @@ func removeFstabEntry(mountpoint string) error { return err } + utils.Debug("[STORAGE] Writing new /etc/fstab") + return os.WriteFile("/etc/fstab", []byte(strings.Join(lines, "\n")), 0644) } diff --git a/src/system.go b/src/system.go index 93a045ea..c09558f0 100644 --- a/src/system.go +++ b/src/system.go @@ -144,8 +144,6 @@ func MemStatusRoute(w http.ResponseWriter, req *http.Request) { } if(req.Method == "GET") { - - json.NewEncoder(w).Encode(map[string]interface{}{ "status": "OK", "data": map[string]interface{}{ @@ -175,7 +173,7 @@ func LogsRoute(w http.ResponseWriter, req *http.Request) { if(req.Method == "GET") { // read log file - logFile, err := os.Open(utils.CONFIGFOLDER + "cosmos.log") + logFile, err := os.Open(utils.CONFIGFOLDER + "cosmos.plain.log") if err != nil { utils.Error("Logs: Error reading log file", err) @@ -205,6 +203,21 @@ func LogsRoute(w http.ResponseWriter, req *http.Request) { } } +func ForceUpdateRoute(w http.ResponseWriter, req *http.Request) { + if utils.AdminOnly(w, req) != nil { + return + } + + if(req.Method == "POST") { + utils.Log("API: Force update") + checkUpdatesAvailable() + } else { + utils.Error("Logs: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} + func restartHostMachineRoute(w http.ResponseWriter, req *http.Request) { if utils.AdminOnly(w, req) != nil { return diff --git a/src/utils/log.go b/src/utils/log.go index aaf7d34b..11e2130e 100644 --- a/src/utils/log.go +++ b/src/utils/log.go @@ -37,6 +37,9 @@ type LogLevel int var ( logger *log.Logger errorLogger *log.Logger + + loggerPlain *log.Logger + errorLoggerPlain *log.Logger ) func InitLogs() { @@ -51,6 +54,14 @@ func InitLogs() { Compress: true, } + ljLoggerPlain := &lumberjack.Logger{ + Filename: CONFIGFOLDER + "cosmos.plain.log", + MaxSize: 15, // megabytes + MaxBackups: 2, + MaxAge: 16, // days + Compress: true, + } + // Create a multi-writer to log to both file and stdout // multiWriter := io.MultiWriter(ljLogger, os.Stdout) @@ -60,6 +71,9 @@ func InitLogs() { // Create loggers logger = log.New(ljLogger, "", log.Ldate|log.Ltime) errorLogger = log.New(ljLogger, "", log.Ldate|log.Ltime) + + loggerPlain = log.New(ljLoggerPlain, "", log.Ldate|log.Ltime) + errorLoggerPlain = log.New(ljLoggerPlain, "", log.Ldate|log.Ltime) } func RawLogMessage(level LogLevel, prefix, prefixColor, color, message string) { @@ -69,14 +83,16 @@ func RawLogMessage(level LogLevel, prefix, prefixColor, color, message string) { log.Println(logString) - if logger == nil || errorLogger == nil { + if logger == nil || errorLogger == nil || loggerPlain == nil || errorLoggerPlain == nil { return } if level >= ERROR { errorLogger.Println(logString) + errorLoggerPlain.Println(prefix + " " + message) } else { logger.Println(logString) + loggerPlain.Println(prefix + " " + message) } } }