Compare commits

...
46 Commits
Author SHA1 Message Date
ssongliu cf230ca6e7 fix: Fix the problem of the failure of 1pctl update port (#9199) 2025-06-20 06:45:13 +00:00
蘭 bb99853000 fix: File content support GBK encoding (#9198) 2025-06-20 06:43:13 +00:00
ssongliu 0c64c8ff52 fix: Fix the problem of incomplete printing of the cronjob (#9197) 2025-06-20 14:25:35 +08:00
ssongliu e3e2006c19 fix: Solve the problem of failed binding and synchronization of Ali Pan (#9195) 2025-06-20 11:12:49 +08:00
蘭 eddc1b6a8d fix: Fix hidden file flipping issue (#9189) 2025-06-19 11:51:00 +00:00
ssongliu 83e1db723e fix: Optimize the synchronization log information of the script library (#9188) 2025-06-19 10:42:59 +00:00
ssongliu 76c608c703 style: Adjust the style of the cronjob status button (#9185) 2025-06-19 09:49:01 +00:00
CityFun d61a77bec7 feat: add core debug cmd for cpu/mem analysis (#9186) 2025-06-19 17:48:51 +08:00
ssongliu a6a2d9991c fix: Remove the redis password restriction (#9184) 2025-06-19 08:36:59 +00:00
CityFun 060dd08167 fix: fix issue with http3 config not work in proxy website (#9183) 2025-06-19 15:12:29 +08:00
CityFun dd1d93e096 fix: fix issue with docker cmd not close (#9182) 2025-06-19 07:06:59 +00:00
蘭 e4b24f51fc feat: Add cache to query SMS records (#9180) 2025-06-19 07:01:00 +00:00
CityFun e472269a4e feat: add agent debug cmd for cpu/mem analysis (#9181) 2025-06-19 14:59:51 +08:00
CityFun 4032276556 feat: update demo handle (#9175) 2025-06-18 09:58:56 +00:00
ssongliu 420537f092 fix: Fix the problem of abnormal addition of remote connections to th… (#9174)
Refs #9151
2025-06-18 09:20:57 +00:00
蘭 3867e536b2 fix: Fix menu sorting (#9172) 2025-06-18 09:18:57 +00:00
CityFun 4bc7b96ae4 style: change button style (#9171) 2025-06-18 08:48:58 +00:00
ssongliu 9f0338382f feat: Script within the container support the selection of users (#9170)
Refs #8766
2025-06-18 08:46:58 +00:00
蘭 692c77eb1a fix: Service status acquisition compatible with snap (#9169) 2025-06-18 16:45:22 +08:00
CityFun 0778e3e81d feat: add baidu and rynu dns provider for ssl (#9167)
Refs https://github.com/1Panel-dev/1Panel/issues/9160
2025-06-18 07:20:57 +00:00
CityFun 80e217e839 feat: Adopt temporary container adaptation for app store status verification (#9165)
Refs https://github.com/1Panel-dev/1Panel/issues/8973
2025-06-18 07:18:57 +00:00
蘭 47547ad4e1 fix: Fix image loading issue (#9164) 2025-06-18 07:16:57 +00:00
CityFun 8b22acce27 fix: fix issue with open container log failed (#9163) 2025-06-18 07:14:56 +00:00
ssongliu 754ac64bf6 fix: Increase the timeout period of the swap setting (#9162)
Refs #9142
2025-06-18 03:50:56 +00:00
ssongliu 3b37d5ae72 fix: Upgrade the element version to 2.9.9 (#9158) 2025-06-18 03:48:57 +00:00
ssongliu 4e2f24a8f0 fix: Fix the problem of failed Google drive backup (#9156)
Refs #9129
2025-06-17 10:48:55 +00:00
蘭 23a1fbdd4b fix: Clear cache by specifying default values (#9154)
#8933
2025-06-17 10:42:54 +00:00
蘭 795223e7fa fix: Fix the issue of interface image loss caused by clearing cache (#9149)
Refs: #9050
2025-06-17 09:00:54 +00:00
ssongliu 10039c6173 fix: Optimize the script library to synchronize the task log (#9148) 2025-06-17 16:59:34 +08:00
CityFun 146b628cc1 feat: Restrict the size of log files to read. (#9147) 2025-06-17 16:59:23 +08:00
CityFun 0c31fcc8a3 fix: fix issue with local app can not open port (#9145) 2025-06-17 08:36:53 +00:00
蘭 2c290dbbf7 fix: hide menu and sorting (#9141) 2025-06-17 16:14:28 +08:00
ssongliu 0df8a33b9e fix: Fix the problem of failed start of swap in the toolbox (#9143)
Refs #9142
2025-06-17 08:08:53 +00:00
ssongliu 1278e910f5 fix: Fix the issue of abnormal login log recording (#9139)
Refs #9054
2025-06-17 08:06:55 +00:00
ssongliu 429e2c6cbe feat: Optimize the node to add inspection items (#9138) 2025-06-17 08:04:54 +00:00
CityFun 00a5cc654a fix: fix issue with run script with no return (#9137) 2025-06-17 16:04:02 +08:00
蘭 d68a0b076b feat: transfer some code (#9124)
refs #9067
2025-06-17 03:56:53 +00:00
CityFun 99ef8e9310 fix: fix issue with edit dotnet environment failed (#9121)
Refs https://github.com/1Panel-dev/1Panel/issues/9083
2025-06-16 08:50:51 +00:00
Process Xie 5e549fdb71 fix: terminate Docker logs process when client disconnects (#9091)
* Update container.go

* Update container.go
2025-06-16 16:07:13 +08:00
CityFun 8f7b026f0e feat: Add quick installation for PHP extension pcntl (#9119) 2025-06-16 07:38:51 +00:00
CityFun fabf33a83b feat: Ensure compatibility with docker-compose commands. (#9117) 2025-06-16 07:14:51 +00:00
CityFun 211c956c4b fix: Fix input field validation error when editing installed application (#9115) 2025-06-16 06:44:51 +00:00
CityFun 55d966a52e fix: fix issue with php install swoole failed (#9113)
Refs https://github.com/1Panel-dev/1Panel/issues/9080
2025-06-16 06:42:51 +00:00
ssongliu a0d5319cd9 fix: Modify the license binding node filtering (#9111) 2025-06-16 06:40:52 +00:00
ssongliu d9358b87c4 style: Optimize the closing method of the right drawer (#9108) 2025-06-16 06:38:51 +00:00
CityFun 89526d9075 feat: add docker status for appstore (#9058) 2025-06-13 10:00:42 +00:00
138 changed files with 1966 additions and 674 deletions
+23
View File
@@ -35,6 +35,29 @@ func (b *BaseApi) SearchContainer(c *gin.Context) {
}) })
} }
// @Tags Container
// @Summary Load container users
// @Accept json
// @Param request body dto.OperationWithName true "request"
// @Produce json
// @Success 200 {array} string
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /containers/users [post]
func (b *BaseApi) LoadContainerUsers(c *gin.Context) {
var req dto.OperationWithName
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
list, err := containerService.LoadUsers(req)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Container // @Tags Container
// @Summary List containers // @Summary List containers
// @Accept json // @Accept json
+8 -8
View File
@@ -13,7 +13,7 @@ import (
// @Success 200 {object} response.HostToolRes // @Success 200 {object} response.HostToolRes
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool [post] // @Router /hosts/tool [post]
func (b *BaseApi) GetToolStatus(c *gin.Context) { func (b *BaseApi) GetToolStatus(c *gin.Context) {
var req request.HostToolReq var req request.HostToolReq
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -35,7 +35,7 @@ func (b *BaseApi) GetToolStatus(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool/create [post] // @Router /hosts/tool/create [post]
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"} // @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建 [type] 配置","formatEN":"create [type] config"}
func (b *BaseApi) InitToolConfig(c *gin.Context) { func (b *BaseApi) InitToolConfig(c *gin.Context) {
var req request.HostToolCreate var req request.HostToolCreate
@@ -57,7 +57,7 @@ func (b *BaseApi) InitToolConfig(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool/operate [post] // @Router /hosts/tool/operate [post]
// @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"} // @x-panel-log {"bodyKeys":["operate","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] [type] ","formatEN":"[operate] [type]"}
func (b *BaseApi) OperateTool(c *gin.Context) { func (b *BaseApi) OperateTool(c *gin.Context) {
var req request.HostToolReq var req request.HostToolReq
@@ -79,7 +79,7 @@ func (b *BaseApi) OperateTool(c *gin.Context) {
// @Success 200 {object} response.HostToolConfig // @Success 200 {object} response.HostToolConfig
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool/config [post] // @Router /hosts/tool/config [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"} // @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 主机工具配置文件 ","formatEN":"[operate] tool config"}
func (b *BaseApi) OperateToolConfig(c *gin.Context) { func (b *BaseApi) OperateToolConfig(c *gin.Context) {
var req request.HostToolConfig var req request.HostToolConfig
@@ -102,7 +102,7 @@ func (b *BaseApi) OperateToolConfig(c *gin.Context) {
// @Success 200 {string} logContent // @Success 200 {string} logContent
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool/log [post] // @Router /hosts/tool/log [post]
func (b *BaseApi) GetToolLog(c *gin.Context) { func (b *BaseApi) GetToolLog(c *gin.Context) {
var req request.HostToolLogReq var req request.HostToolLogReq
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -124,7 +124,7 @@ func (b *BaseApi) GetToolLog(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool/supervisor/process [post] // @Router /hosts/tool/supervisor/process [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"} // @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] 守护进程 ","formatEN":"[operate] process"}
func (b *BaseApi) OperateProcess(c *gin.Context) { func (b *BaseApi) OperateProcess(c *gin.Context) {
var req request.SupervisorProcessConfig var req request.SupervisorProcessConfig
@@ -146,7 +146,7 @@ func (b *BaseApi) OperateProcess(c *gin.Context) {
// @Success 200 {object} response.SupervisorProcessConfig // @Success 200 {object} response.SupervisorProcessConfig
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool/supervisor/process [get] // @Router /hosts/tool/supervisor/process [get]
func (b *BaseApi) GetProcess(c *gin.Context) { func (b *BaseApi) GetProcess(c *gin.Context) {
configs, err := hostToolService.GetSupervisorProcessConfig() configs, err := hostToolService.GetSupervisorProcessConfig()
if err != nil { if err != nil {
@@ -163,7 +163,7 @@ func (b *BaseApi) GetProcess(c *gin.Context) {
// @Success 200 {string} content // @Success 200 {string} content
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/tool/supervisor/process/file [post] // @Router /hosts/tool/supervisor/process/file [post]
// @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] Supervisor 进程文件 ","formatEN":"[operate] Supervisor Process Config file"} // @x-panel-log {"bodyKeys":["operate"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operate] Supervisor 进程文件 ","formatEN":"[operate] Supervisor Process Config file"}
func (b *BaseApi) GetProcessFile(c *gin.Context) { func (b *BaseApi) GetProcessFile(c *gin.Context) {
var req request.SupervisorProcessFileReq var req request.SupervisorProcessFileReq
+8 -8
View File
@@ -11,7 +11,7 @@ import (
// @Success 200 {object} dto.SSHInfo // @Success 200 {object} dto.SSHInfo
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/ssh/search [post] // @Router /hosts/ssh/search [post]
func (b *BaseApi) GetSSHInfo(c *gin.Context) { func (b *BaseApi) GetSSHInfo(c *gin.Context) {
info, err := sshService.GetSSHInfo() info, err := sshService.GetSSHInfo()
if err != nil { if err != nil {
@@ -28,7 +28,7 @@ func (b *BaseApi) GetSSHInfo(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/ssh/operate [post] // @Router /hosts/ssh/operate [post]
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"} // @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"}
func (b *BaseApi) OperateSSH(c *gin.Context) { func (b *BaseApi) OperateSSH(c *gin.Context) {
var req dto.Operate var req dto.Operate
@@ -50,7 +50,7 @@ func (b *BaseApi) OperateSSH(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/ssh/update [post] // @Router /hosts/ssh/update [post]
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"} // @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"}
func (b *BaseApi) UpdateSSH(c *gin.Context) { func (b *BaseApi) UpdateSSH(c *gin.Context) {
var req dto.SSHUpdate var req dto.SSHUpdate
@@ -72,7 +72,7 @@ func (b *BaseApi) UpdateSSH(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/conffile/update [post] // @Router /hosts/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"} // @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
func (b *BaseApi) UpdateSSHByfile(c *gin.Context) { func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
var req dto.SSHConf var req dto.SSHConf
@@ -94,7 +94,7 @@ func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/ssh/generate [post] // @Router /hosts/ssh/generate [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"} // @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
func (b *BaseApi) GenerateSSH(c *gin.Context) { func (b *BaseApi) GenerateSSH(c *gin.Context) {
var req dto.GenerateSSH var req dto.GenerateSSH
@@ -116,7 +116,7 @@ func (b *BaseApi) GenerateSSH(c *gin.Context) {
// @Success 200 {string} secret // @Success 200 {string} secret
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/ssh/secret [post] // @Router /hosts/ssh/secret [post]
func (b *BaseApi) LoadSSHSecret(c *gin.Context) { func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
var req dto.GenerateLoad var req dto.GenerateLoad
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -138,7 +138,7 @@ func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
// @Success 200 {object} dto.SSHLog // @Success 200 {object} dto.SSHLog
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/ssh/log [post] // @Router /hosts/ssh/log [post]
func (b *BaseApi) LoadSSHLogs(c *gin.Context) { func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
var req dto.SearchSSHLog var req dto.SearchSSHLog
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -158,7 +158,7 @@ func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
// @Success 200 {string} conf // @Success 200 {string} conf
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /host/ssh/conf [get] // @Router /hosts/ssh/conf [get]
func (b *BaseApi) LoadSSHConf(c *gin.Context) { func (b *BaseApi) LoadSSHConf(c *gin.Context) {
data, err := sshService.LoadSSHConf() data, err := sshService.LoadSSHConf()
if err != nil { if err != nil {
+6 -4
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/docker/docker/api/types/container"
"math" "math"
"net/http" "net/http"
"os" "os"
@@ -16,7 +17,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/files" "github.com/1Panel-dev/1Panel/agent/utils/files"
"github.com/1Panel-dev/1Panel/agent/utils/req_helper" "github.com/1Panel-dev/1Panel/agent/utils/req_helper"
"github.com/docker/docker/api/types"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"github.com/1Panel-dev/1Panel/agent/utils/env" "github.com/1Panel-dev/1Panel/agent/utils/env"
@@ -703,6 +703,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
Rule: form.Rule, Rule: form.Rule,
Type: form.Type, Type: form.Type,
Multiple: form.Multiple, Multiple: form.Multiple,
Required: form.Required,
} }
if form.Edit { if form.Edit {
appParam.Edit = true appParam.Edit = true
@@ -761,6 +762,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
Value: form.Default, Value: form.Default,
Values: form.Values, Values: form.Values,
Multiple: form.Multiple, Multiple: form.Multiple,
Required: form.Required,
}) })
} }
} }
@@ -789,15 +791,15 @@ func syncAppInstallStatus(appInstall *model.AppInstall, force bool) error {
defer cli.Close() defer cli.Close()
var ( var (
containers []types.Container containers []container.Summary
containersMap map[string]types.Container containersMap map[string]container.Summary
containerNames = strings.Split(appInstall.ContainerName, ",") containerNames = strings.Split(appInstall.ContainerName, ",")
) )
containers, err = cli.ListContainersByName(containerNames) containers, err = cli.ListContainersByName(containerNames)
if err != nil { if err != nil {
return err return err
} }
containersMap = make(map[string]types.Container) containersMap = make(map[string]container.Summary)
for _, con := range containers { for _, con := range containers {
containersMap[con.Names[0]] = con containersMap[con.Names[0]] = con
} }
+14 -6
View File
@@ -5,6 +5,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/compose-spec/compose-go/v2/types"
"log" "log"
"math" "math"
"net/http" "net/http"
@@ -25,8 +26,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/task" "github.com/1Panel-dev/1Panel/agent/app/task"
"github.com/docker/docker/api/types"
"github.com/1Panel-dev/1Panel/agent/utils/req_helper" "github.com/1Panel-dev/1Panel/agent/utils/req_helper"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
@@ -786,6 +785,15 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
return appInstallRepo.Save(context.Background(), &install) return appInstallRepo.Save(context.Background(), &install)
} }
func skipCheckStatus(service types.ServiceConfig) bool {
for key := range service.Labels {
if key == "skipStatusCheck" {
return true
}
}
return false
}
func getContainerNames(install model.AppInstall) ([]string, error) { func getContainerNames(install model.AppInstall) ([]string, error) {
envStr, err := coverEnvJsonToStr(install.Env) envStr, err := coverEnvJsonToStr(install.Env)
if err != nil { if err != nil {
@@ -797,7 +805,7 @@ func getContainerNames(install model.AppInstall) ([]string, error) {
} }
containerMap := make(map[string]struct{}) containerMap := make(map[string]struct{})
for _, service := range project.AllServices() { for _, service := range project.AllServices() {
if service.ContainerName == "${CONTAINER_NAME}" || service.ContainerName == "" { if service.ContainerName == "${CONTAINER_NAME}" || service.ContainerName == "" || skipCheckStatus(service) {
continue continue
} }
containerMap[service.ContainerName] = struct{}{} containerMap[service.ContainerName] = struct{}{}
@@ -1363,7 +1371,7 @@ func doNotNeedSync(installed model.AppInstall) bool {
installed.Status == constant.StatusSyncing || installed.Status == constant.StatusUninstalling || installed.Status == constant.StatusInstallErr installed.Status == constant.StatusSyncing || installed.Status == constant.StatusUninstalling || installed.Status == constant.StatusInstallErr
} }
func synAppInstall(containers map[string]types.Container, appInstall *model.AppInstall, force bool) { func synAppInstall(containers map[string]container.Summary, appInstall *model.AppInstall, force bool) {
oldStatus := appInstall.Status oldStatus := appInstall.Status
containerNames := strings.Split(appInstall.ContainerName, ",") containerNames := strings.Split(appInstall.ContainerName, ",")
if len(containers) == 0 { if len(containers) == 0 {
@@ -1437,7 +1445,7 @@ func synAppInstall(containers map[string]types.Container, appInstall *model.AppI
func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool) ([]response.AppInstallDTO, error) { func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool) ([]response.AppInstallDTO, error) {
var ( var (
res []response.AppInstallDTO res []response.AppInstallDTO
containersMap map[string]types.Container containersMap map[string]container.Summary
) )
if sync { if sync {
cli, err := docker.NewClient() cli, err := docker.NewClient()
@@ -1445,7 +1453,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
defer cli.Close() defer cli.Close()
containers, err := cli.ListAllContainers() containers, err := cli.ListAllContainers()
if err == nil { if err == nil {
containersMap = make(map[string]types.Container, len(containers)) containersMap = make(map[string]container.Summary, len(containers))
for _, contain := range containers { for _, contain := range containers {
containersMap[contain.Names[0]] = contain containersMap[contain.Names[0]] = contain
} }
+60 -17
View File
@@ -83,6 +83,8 @@ type IContainerService interface {
ComposeUpdate(req dto.ComposeUpdate) error ComposeUpdate(req dto.ComposeUpdate) error
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error) Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
LoadUsers(req dto.OperationWithName) ([]string, error)
StreamLogs(ctx *gin.Context, params dto.StreamLog) StreamLogs(ctx *gin.Context, params dto.StreamLog)
} }
@@ -882,16 +884,20 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
func (u *ContainerService) StreamLogs(ctx *gin.Context, params dto.StreamLog) { func (u *ContainerService) StreamLogs(ctx *gin.Context, params dto.StreamLog) {
messageChan := make(chan string, 1024) messageChan := make(chan string, 1024)
errorChan := make(chan error, 1) errorChan := make(chan error, 1)
doneChan := make(chan struct{})
go collectLogs(params, messageChan, errorChan) go func() {
<-ctx.Request.Context().Done()
close(doneChan)
}()
go collectLogs(doneChan, params, messageChan, errorChan)
ctx.Stream(func(w io.Writer) bool { ctx.Stream(func(w io.Writer) bool {
select { select {
case msg, ok := <-messageChan: case msg, ok := <-messageChan:
if !ok { if !ok {
return msg == "" return false
} }
_, err := fmt.Fprintf(w, "data: %v\n\n", msg) _, err := fmt.Fprintf(w, "data: %s\n\n", msg)
if err != nil { if err != nil {
return false return false
} }
@@ -900,17 +906,14 @@ func (u *ContainerService) StreamLogs(ctx *gin.Context, params dto.StreamLog) {
if err != nil { if err != nil {
_, _ = fmt.Fprintf(w, "event: error\ndata: %v\n\n", err.Error()) _, _ = fmt.Fprintf(w, "event: error\ndata: %v\n\n", err.Error())
} }
return true
case <-ctx.Request.Context().Done():
return false return false
} }
}) })
} }
func collectLogs(params dto.StreamLog, messageChan chan<- string, errorChan chan<- error) { func collectLogs(done <-chan struct{}, params dto.StreamLog, messageChan chan<- string, errorChan chan<- error) {
defer close(messageChan) defer close(messageChan)
defer close(errorChan) defer close(errorChan)
var cmdArgs []string var cmdArgs []string
if params.Type == "compose" { if params.Type == "compose" {
cmdArgs = []string{"compose", "-f", params.Compose} cmdArgs = []string{"compose", "-f", params.Compose}
@@ -928,36 +931,61 @@ func collectLogs(params dto.StreamLog, messageChan chan<- string, errorChan chan
if params.Container != "" { if params.Container != "" {
cmdArgs = append(cmdArgs, params.Container) cmdArgs = append(cmdArgs, params.Container)
} }
dockerCmd := exec.Command("docker", cmdArgs...) dockerCmd := exec.Command("docker", cmdArgs...)
dockerCmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
stdout, err := dockerCmd.StdoutPipe() stdout, err := dockerCmd.StdoutPipe()
if err != nil { if err != nil {
errorChan <- fmt.Errorf("failed to get stdout pipe: %v", err) errorChan <- fmt.Errorf("failed to get stdout pipe: %v", err)
return return
} }
dockerCmd.Stderr = dockerCmd.Stdout dockerCmd.Stderr = dockerCmd.Stdout
if err = dockerCmd.Start(); err != nil { if err = dockerCmd.Start(); err != nil {
errorChan <- fmt.Errorf("failed to start command: %v", err) errorChan <- fmt.Errorf("failed to start docker logs command: %v", err)
return return
} }
defer func() {
if dockerCmd.Process != nil {
if pgid, err := syscall.Getpgid(dockerCmd.Process.Pid); err == nil {
_ = syscall.Kill(-pgid, syscall.SIGKILL)
}
_ = dockerCmd.Process.Kill()
_ = dockerCmd.Wait()
}
}()
scanner := bufio.NewScanner(stdout) scanner := bufio.NewScanner(stdout)
processKilled := false
go func() {
<-done
if !processKilled && dockerCmd.Process != nil {
processKilled = true
if pgid, err := syscall.Getpgid(dockerCmd.Process.Pid); err == nil {
_ = syscall.Kill(-pgid, syscall.SIGKILL)
}
_ = dockerCmd.Process.Kill()
}
}()
for scanner.Scan() { for scanner.Scan() {
message := scanner.Text() message := scanner.Text()
select { select {
case messageChan <- message: case messageChan <- message:
case <-time.After(5 * time.Second): case <-done:
errorChan <- fmt.Errorf("message channel blocked")
return return
} }
} }
if err = scanner.Err(); err != nil {
if err = scanner.Err(); err != nil && err != io.EOF {
errorChan <- fmt.Errorf("scanner error: %v", err) errorChan <- fmt.Errorf("scanner error: %v", err)
return
}
if err = dockerCmd.Wait(); err != nil {
errorChan <- fmt.Errorf("%v", err)
return
} }
_ = dockerCmd.Wait()
} }
func (u *ContainerService) DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error { func (u *ContainerService) DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error {
@@ -1065,6 +1093,21 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
return &data, nil return &data, nil
} }
func (u *ContainerService) LoadUsers(req dto.OperationWithName) ([]string, error) {
std, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s cat /etc/passwd", req.Name)
if err != nil {
return nil, err
}
var users []string
lines := strings.Split(string(std), "\n")
for _, line := range lines {
if strings.Contains(line, ":") {
users = append(users, strings.Split(line, ":")[0])
}
}
return users, nil
}
func stringsToMap(list []string) map[string]string { func stringsToMap(list []string) map[string]string {
var labelMap = make(map[string]string) var labelMap = make(map[string]string)
for _, label := range list { for _, label := range list {
+5 -5
View File
@@ -60,7 +60,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t
if err := doAppBackup(&app, task, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil { if err := doAppBackup(&app, task, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
return err return err
} }
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName)) downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(backupDir, record.FileName))
if err != nil { if err != nil {
return err return err
} }
@@ -101,7 +101,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
return err return err
} }
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName)) downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(backupDir, record.FileName))
if err != nil { if err != nil {
return err return err
} }
@@ -149,7 +149,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
} }
} }
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName)) downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(backupDir, record.FileName))
if err != nil { if err != nil {
return err return err
} }
@@ -193,7 +193,7 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
record.CronjobID = cronjob.ID record.CronjobID = cronjob.ID
record.Name = cronjob.Name record.Name = cronjob.Name
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, fileName)) downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(backupDir, fileName))
if err != nil { if err != nil {
taskItem.LogFailedWithErr("Upload backup file", err) taskItem.LogFailedWithErr("Upload backup file", err)
return err return err
@@ -228,7 +228,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
record.CronjobID = cronjob.ID record.CronjobID = cronjob.ID
record.Name = cronjob.Name record.Name = cronjob.Name
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(path.Dir(backupDir), fileName)) downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(path.Dir(backupDir), fileName))
if err != nil { if err != nil {
taskItem.LogFailedWithErr("Upload backup file", err) taskItem.LogFailedWithErr("Upload backup file", err)
return err return err
+22 -7
View File
@@ -118,11 +118,21 @@ func (u *CronjobService) handleShell(cronjob model.Cronjob, taskItem *task.Task)
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem)) cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem))
taskItem.AddSubTaskWithOps(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error { taskItem.AddSubTaskWithOps(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error {
if len(cronjob.ContainerName) != 0 { if len(cronjob.ContainerName) != 0 {
scriptItem := cronjob.Script
if cronjob.ScriptMode == "select" {
scriptItem = path.Join("/tmp", path.Base(cronjob.Script))
if err := cmdMgr.Run("docker", "cp", cronjob.Script, cronjob.ContainerName+":"+scriptItem); err != nil {
return err
}
}
command := "sh" command := "sh"
if len(cronjob.Command) != 0 { if len(cronjob.Command) != 0 {
command = cronjob.Command command = cronjob.Command
} }
return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(cronjob.Script, "\"", "\\\"")) if len(cronjob.User) != 0 {
return cmdMgr.Run("docker", "exec", "-u", cronjob.User, cronjob.ContainerName, command, "-c", strings.ReplaceAll(scriptItem, "\"", "\\\""))
}
return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(scriptItem, "\"", "\\\""))
} }
if len(cronjob.Executor) == 0 { if len(cronjob.Executor) == 0 {
cronjob.Executor = "bash" cronjob.Executor = "bash"
@@ -252,23 +262,28 @@ func (u *CronjobService) handleSystemClean(cronjob model.Cronjob, taskItem *task
taskItem.AddSubTaskWithOps(i18n.GetMsgByKey("HandleSystemClean"), cleanTask, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second) taskItem.AddSubTaskWithOps(i18n.GetMsgByKey("HandleSystemClean"), cleanTask, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
} }
func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, accountMap map[string]backupClientHelper, file string) (string, error) { func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, task *task.Task, accountMap map[string]backupClientHelper, file string) (string, error) {
defer func() { defer func() {
_ = os.Remove(file) _ = os.Remove(file)
}() }()
var errItem error
accounts := strings.Split(cronjob.SourceAccountIDs, ",") accounts := strings.Split(cronjob.SourceAccountIDs, ",")
cloudSrc := strings.TrimPrefix(file, global.Dir.TmpDir+"/") cloudSrc := strings.TrimPrefix(file, global.Dir.TmpDir+"/")
for _, account := range accounts { for _, account := range accounts {
if len(account) != 0 { if len(account) != 0 {
global.LOG.Debugf("start upload file to %s, dir: %s", accountMap[account].name, pathUtils.Join(accountMap[account].backupPath, cloudSrc)) _, err := accountMap[account].client.Upload(file, pathUtils.Join(accountMap[account].backupPath, cloudSrc))
if _, err := accountMap[account].client.Upload(file, pathUtils.Join(accountMap[account].backupPath, cloudSrc)); err != nil { task.LogWithStatus(
global.LOG.Errorf("upload file to %s failed, err: %v", accountMap[account].name, err) i18n.GetMsgWithMap("UploadFile", map[string]interface{}{
"file": pathUtils.Join(accountMap[account].backupPath, cloudSrc),
"backup": accountMap[account].name,
}), err)
if err != nil {
errItem = err
continue continue
} }
global.LOG.Debugf("upload successful!")
} }
} }
return cloudSrc, nil return cloudSrc, errItem
} }
func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap map[string]backupClientHelper, record model.BackupRecord) { func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap map[string]backupClientHelper, record model.BackupRecord) {
+11 -6
View File
@@ -246,18 +246,23 @@ func (u *DeviceService) UpdateSwap(req dto.SwapHelper) error {
} }
return operateSwapWithFile(true, req) return operateSwapWithFile(true, req)
} }
std1, err := cmd.RunDefaultWithStdoutBashCf("%s dd if=/dev/zero of=%s bs=1024 count=%d", cmd.SudoHandleCmd(), req.Path, req.Size) stdDD, err := cmd.RunDefaultWithStdoutBashCf("%s dd if=/dev/zero of=%s bs=1024 count=%d", cmd.SudoHandleCmd(), req.Path, req.Size)
if err != nil { if err != nil {
return fmt.Errorf("handle dd path %s failed, err: %s", req.Path, std1) return fmt.Errorf("handle dd %s failed, std: %s, err: %s", req.Path, stdDD, err)
} }
std2, err := cmd.RunDefaultWithStdoutBashCf("%s mkswap -f %s", cmd.SudoHandleCmd(), req.Path) stdChmod, err := cmd.RunDefaultWithStdoutBashCf("%s chmod 0600 %s", cmd.SudoHandleCmd(), req.Path)
if err != nil { if err != nil {
return fmt.Errorf("handle dd path %s failed, err: %s", req.Path, std2) return fmt.Errorf("handle chmod 0600 %s failed,std: %s, err: %s", req.Path, stdChmod, err)
} }
std3, err := cmd.RunDefaultWithStdoutBashCf("%s swapon %s", cmd.SudoHandleCmd(), req.Path) stdMkswap, err := cmd.RunDefaultWithStdoutBashCf("%s mkswap -f %s", cmd.SudoHandleCmd(), req.Path)
if err != nil {
return fmt.Errorf("handle mkswap -f %s failed, std: %s, err: %s", req.Path, stdMkswap, err)
}
stdSwapon, err := cmd.RunDefaultWithStdoutBashCf("%s swapon %s", cmd.SudoHandleCmd(), req.Path)
if err != nil { if err != nil {
_, _ = cmd.RunDefaultWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path) _, _ = cmd.RunDefaultWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path)
return fmt.Errorf("handle dd path %s failed, err: %s", req.Path, std3) return fmt.Errorf("handle swapoff %s failed,std: %s, err: %s", req.Path, stdSwapon, err)
} }
return operateSwapWithFile(false, req) return operateSwapWithFile(false, req)
} }
+30 -5
View File
@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"path" "path"
"path/filepath"
"sort" "sort"
"strings" "strings"
"time" "time"
@@ -50,7 +51,7 @@ func (u *DeviceService) Scan() dto.CleanData {
ID: uuid.NewString(), ID: uuid.NewString(),
Label: "1panel_original", Label: "1panel_original",
Size: uint64(originalSize), Size: uint64(originalSize),
IsCheck: true, IsCheck: originalSize > 0,
IsRecommend: true, IsRecommend: true,
Type: "1panel_original", Type: "1panel_original",
Children: loadTreeWithDir(true, "1panel_original", originalPath, fileOp), Children: loadTreeWithDir(true, "1panel_original", originalPath, fileOp),
@@ -85,7 +86,7 @@ func (u *DeviceService) Scan() dto.CleanData {
ID: uuid.NewString(), ID: uuid.NewString(),
Label: "snapshot", Label: "snapshot",
Size: snapSize, Size: snapSize,
IsCheck: true, IsCheck: snapSize > 0,
IsRecommend: true, IsRecommend: true,
Type: "snapshot", Type: "snapshot",
Children: snapTree, Children: snapTree,
@@ -100,7 +101,7 @@ func (u *DeviceService) Scan() dto.CleanData {
ID: uuid.NewString(), ID: uuid.NewString(),
Label: "rollback", Label: "rollback",
Size: rollbackSize, Size: rollbackSize,
IsCheck: true, IsCheck: rollbackSize > 0,
IsRecommend: true, IsRecommend: true,
Type: "rollback", Type: "rollback",
Children: rollBackTree, Children: rollBackTree,
@@ -126,7 +127,7 @@ func (u *DeviceService) Scan() dto.CleanData {
ID: uuid.NewString(), ID: uuid.NewString(),
Label: "unused", Label: "unused",
Size: unusedSize, Size: unusedSize,
IsCheck: true, IsCheck: unusedSize > 0,
IsRecommend: true, IsRecommend: true,
Type: "unused", Type: "unused",
Children: unusedTree, Children: unusedTree,
@@ -338,7 +339,7 @@ func doSystemClean(taskItem *task.Task) func(t *task.Task) error {
} }
dropWithTask(path.Join(global.Dir.BaseDir, tmpUploadPath), taskItem, &size, &fileCount) dropWithTask(path.Join(global.Dir.BaseDir, tmpUploadPath), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, uploadPath), taskItem, &size, &fileCount) dropWithExclude(path.Join(global.Dir.BaseDir, uploadPath), []string{"theme"}, taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, downloadPath), taskItem, &size, &fileCount) dropWithTask(path.Join(global.Dir.BaseDir, downloadPath), taskItem, &size, &fileCount)
logFiles, _ := os.ReadDir(global.Dir.LogDir) logFiles, _ := os.ReadDir(global.Dir.LogDir)
@@ -714,6 +715,30 @@ func dropVolumes() {
} }
} }
func dropWithExclude(pathToDelete string, excludeSubDirs []string, taskItem *task.Task, size *int64, count *int) {
entries, err := os.ReadDir(pathToDelete)
if err != nil {
taskItem.LogFailed(fmt.Sprintf("read dir %s failed: %v", pathToDelete, err))
return
}
for _, entry := range entries {
name := entry.Name()
fullPath := filepath.Join(pathToDelete, name)
excluded := false
for _, ex := range excludeSubDirs {
if name == ex {
excluded = true
break
}
}
if excluded {
continue
}
dropWithTask(fullPath, taskItem, size, count)
}
}
func dropWithTask(itemPath string, taskItem *task.Task, size *int64, count *int) { func dropWithTask(itemPath string, taskItem *task.Task, size *int64, count *int) {
itemSize := int64(0) itemSize := int64(0)
itemCount := 0 itemCount := 0
+1 -1
View File
@@ -337,7 +337,7 @@ func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo,
} }
if !utf8.Valid(content) { if !utf8.Valid(content) {
_, decodeName, _ := charset.DetermineEncoding(content, "") _, decodeName, _ := charset.DetermineEncoding(content, "")
if decodeName == "windows-1252" { if decodeName == "windows-1252" || strings.ToLower(decodeName) == "gbk" {
reader := strings.NewReader(info.Content) reader := strings.NewReader(info.Content)
item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder()) item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder())
contents, err := io.ReadAll(item) contents, err := io.ReadAll(item)
+12 -7
View File
@@ -182,6 +182,7 @@ func (u *FirewallService) OperateFirewall(operation string) error {
if err != nil { if err != nil {
return err return err
} }
needRestartDocker := false
switch operation { switch operation {
case "start": case "start":
if err := client.Start(); err != nil { if err := client.Start(); err != nil {
@@ -191,26 +192,30 @@ func (u *FirewallService) OperateFirewall(operation string) error {
_ = client.Stop() _ = client.Stop()
return err return err
} }
_, _ = cmd.RunDefaultWithStdoutBashC("systemctl restart docker") needRestartDocker = true
return nil
case "stop": case "stop":
if err := client.Stop(); err != nil { if err := client.Stop(); err != nil {
return err return err
} }
_, _ = cmd.RunDefaultWithStdoutBashC("systemctl restart docker") needRestartDocker = true
return nil
case "restart": case "restart":
if err := client.Restart(); err != nil { if err := client.Restart(); err != nil {
return err return err
} }
_, _ = cmd.RunDefaultWithStdoutBashC("systemctl restart docker") needRestartDocker = true
return nil
case "disablePing": case "disablePing":
return u.updatePingStatus("0") return u.updatePingStatus("0")
case "enablePing": case "enablePing":
return u.updatePingStatus("1") return u.updatePingStatus("1")
default:
return fmt.Errorf("not supported operation: %s", operation)
} }
return fmt.Errorf("not support such operation: %s", operation) if needRestartDocker {
if err := restartDocker(); err != nil {
return err
}
}
return nil
} }
func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool) error { func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool) error {
+13 -11
View File
@@ -105,21 +105,23 @@ func (f *FtpService) Sync() error {
if err != nil { if err != nil {
return err return err
} }
currentData := make(map[string]model.Ftp)
for _, item := range listsInDB {
currentData[item.User] = item
}
sameData := make(map[string]struct{}) sameData := make(map[string]struct{})
for _, item := range lists { for _, item := range lists {
for _, itemInDB := range listsInDB { if itemInDB, ok := currentData[item.User]; ok {
if item.User == itemInDB.User { sameData[item.User] = struct{}{}
sameData[item.User] = struct{}{} if item.Path != itemInDB.Path || item.Status != itemInDB.Status {
if item.Path != itemInDB.Path || item.Status != itemInDB.Status { if err := ftpRepo.Update(itemInDB.ID, map[string]interface{}{"path": item.Path, "status": item.Status}); err != nil {
_ = ftpRepo.Update(itemInDB.ID, map[string]interface{}{"path": item.Path, "status": item.Status}) return err
} }
break
} }
} } else {
} if err := ftpRepo.Create(&model.Ftp{User: item.User, Path: item.Path, Status: item.Status}); err != nil {
for _, item := range lists { return err
if _, ok := sameData[item.User]; !ok { }
_ = ftpRepo.Create(&model.Ftp{User: item.User, Path: item.Path, Status: item.Status})
} }
} }
for _, item := range listsInDB { for _, item := range listsInDB {
+2 -3
View File
@@ -91,9 +91,8 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil { if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err) return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
} }
stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl restart docker") if err := restartDocker(); err != nil {
if err != nil { return err
return errors.New(string(stdout))
} }
ticker := time.NewTicker(3 * time.Second) ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop() defer ticker.Stop()
+1 -1
View File
@@ -682,7 +682,7 @@ func (r *RuntimeService) GetPHPExtensions(runtimeID uint) (response.PHPExtension
} }
} }
var phpExtensions []response.SupportExtension var phpExtensions []response.SupportExtension
if err = json.Unmarshal(nginx_conf.PHPExtensionsJson, &phpExtensions); err != nil { if err = json.Unmarshal(nginx_conf.GetWebsiteFile("php_extensions.json"), &phpExtensions); err != nil {
return res, err return res, err
} }
for _, ext := range phpExtensions { for _, ext := range phpExtensions {
+1 -1
View File
@@ -657,7 +657,7 @@ func unInstallPHPExtension(runtime *model.Runtime, delExtensions []string) error
dir := runtime.GetPath() dir := runtime.GetPath()
fileOP := files.NewFileOp() fileOP := files.NewFileOp()
var phpExtensions []response.SupportExtension var phpExtensions []response.SupportExtension
if err := json.Unmarshal(nginx_conf.PHPExtensionsJson, &phpExtensions); err != nil { if err := json.Unmarshal(nginx_conf.GetWebsiteFile("php_extensions.json"), &phpExtensions); err != nil {
return err return err
} }
phpVersion := getRuntimeEnv(runtime.Env, "PHP_VERSION") phpVersion := getRuntimeEnv(runtime.Env, "PHP_VERSION")
+3 -1
View File
@@ -371,7 +371,9 @@ func recoverBaseData(src string, itemHelper *snapRecoverHelper) error {
} }
} }
_, _ = cmd.RunDefaultWithStdoutBashC("systemctl restart docker") if err := restartDocker(); err != nil {
return err
}
return nil return nil
} }
+1 -1
View File
@@ -985,7 +985,7 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = ChangeHSTSConfig(req.Hsts, website); err != nil { if err = ChangeHSTSConfig(req.Hsts, req.Http3, website); err != nil {
return nil, err return nil, err
} }
res.Enable = req.Enable res.Enable = req.Enable
+3 -3
View File
@@ -436,14 +436,14 @@ func (w WebsiteCAService) DownloadFile(id uint) (*os.File, error) {
if err = fileOp.CreateDir(dir, constant.DirPerm); err != nil { if err = fileOp.CreateDir(dir, constant.DirPerm); err != nil {
return nil, err return nil, err
} }
if err = fileOp.WriteFile(path.Join(dir, "ca.csr"), strings.NewReader(ca.CSR), constant.DirPerm); err != nil { if err = fileOp.WriteFile(path.Join(dir, "ca.crt"), strings.NewReader(ca.CSR), constant.DirPerm); err != nil {
return nil, err return nil, err
} }
if err = fileOp.WriteFile(path.Join(dir, "private.key"), strings.NewReader(ca.PrivateKey), constant.DirPerm); err != nil { if err = fileOp.WriteFile(path.Join(dir, "ca.key"), strings.NewReader(ca.PrivateKey), constant.DirPerm); err != nil {
return nil, err return nil, err
} }
fileName := ca.Name + ".zip" fileName := ca.Name + ".zip"
if err = fileOp.Compress([]string{path.Join(dir, "ca.csr"), path.Join(dir, "private.key")}, dir, fileName, files.SdkZip, ""); err != nil { if err = fileOp.Compress([]string{path.Join(dir, "ca.crt"), path.Join(dir, "ca.key")}, dir, fileName, files.SdkZip, ""); err != nil {
return nil, err return nil, err
} }
return os.Open(path.Join(dir, fileName)) return os.Open(path.Join(dir, fileName))
+6 -1
View File
@@ -1162,7 +1162,7 @@ func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
return nil return nil
} }
func ChangeHSTSConfig(enable bool, website model.Website) error { func ChangeHSTSConfig(enable bool, http3Enable bool, website model.Website) error {
includeDir := GetSitePath(website, SiteProxyDir) includeDir := GetSitePath(website, SiteProxyDir)
fileOp := files.NewFileOp() fileOp := files.NewFileOp()
if !fileOp.Stat(includeDir) { if !fileOp.Stat(includeDir) {
@@ -1193,6 +1193,11 @@ func ChangeHSTSConfig(enable bool, website model.Website) error {
} else { } else {
location.RemoveDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""}) location.RemoveDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""})
} }
if http3Enable {
location.UpdateDirective("add_header", []string{"Alt-Svc", "'h3=\":443\"; ma=2592000'"})
} else {
location.RemoveDirective("add_header", []string{"Alt-Svc", "'h3=\":443\"; ma=2592000'"})
}
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil { if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return buserr.WithErr("ErrUpdateBuWebsite", err) return buserr.WithErr("ErrUpdateBuWebsite", err)
} }
+169
View File
@@ -0,0 +1,169 @@
package cmd
import (
"fmt"
"os"
"runtime"
"runtime/pprof"
"time"
"github.com/spf13/cobra"
)
var (
cpuProfile string
memProfile string
duration time.Duration
showMemStats bool
showGoroutine bool
)
func init() {
RootCmd.AddCommand(debugCmd)
debugCmd.Flags().StringVar(&cpuProfile, "cpuprofile", "", "write cpu profile to file")
debugCmd.Flags().StringVar(&memProfile, "memprofile", "", "write memory profile to file")
debugCmd.Flags().DurationVar(&duration, "duration", 30*time.Second, "duration for cpu profiling")
debugCmd.Flags().BoolVar(&showMemStats, "memstats", false, "show memory statistics")
debugCmd.Flags().BoolVar(&showGoroutine, "goroutine", false, "show goroutine profile")
}
var debugCmd = &cobra.Command{
Use: "debug",
Short: "Performance debugging with pprof",
Long: `Debug command provides CPU and memory profiling capabilities using pprof.
Examples:
# CPU profiling for 30 seconds
1panel-agent debug --cpuprofile=cpu.prof --duration=30s
# Memory profiling
1panel-agent debug --memprofile=mem.prof
# Show memory statistics
1panel-agent debug --memstats
# Show goroutine information
1panel-agent debug --goroutine
# Combined profiling
1panel-agent debug --cpuprofile=cpu.prof --memprofile=mem.prof --memstats`,
RunE: func(cmd *cobra.Command, args []string) error {
if cpuProfile != "" {
if err := startCPUProfile(cpuProfile); err != nil {
return fmt.Errorf("failed to start CPU profile: %v", err)
}
defer stopCPUProfile()
time.Sleep(duration)
fmt.Printf("CPU profile saved to: %s\n", cpuProfile)
}
if memProfile != "" {
if err := writeMemProfile(memProfile); err != nil {
return fmt.Errorf("failed to write memory profile: %v", err)
}
fmt.Printf("Memory profile saved to: %s\n", memProfile)
}
if showMemStats {
printMemStats()
}
if showGoroutine {
printGoroutineInfo()
}
if cpuProfile == "" && memProfile == "" && !showMemStats && !showGoroutine {
printBasicInfo()
}
return nil
},
}
func startCPUProfile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
if err := pprof.StartCPUProfile(f); err != nil {
f.Close()
return err
}
return nil
}
func stopCPUProfile() {
pprof.StopCPUProfile()
}
func writeMemProfile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
runtime.GC()
if err := pprof.WriteHeapProfile(f); err != nil {
return err
}
return nil
}
func printMemStats() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Println("\n=== Memory Statistics ===")
fmt.Printf("Allocated memory: %d KB (%d MB)\n", m.Alloc/1024, m.Alloc/1024/1024)
fmt.Printf("Total allocated: %d KB (%d MB)\n", m.TotalAlloc/1024, m.TotalAlloc/1024/1024)
fmt.Printf("System memory: %d KB (%d MB)\n", m.Sys/1024, m.Sys/1024/1024)
fmt.Printf("Heap allocated: %d KB (%d MB)\n", m.HeapAlloc/1024, m.HeapAlloc/1024/1024)
fmt.Printf("Heap system: %d KB (%d MB)\n", m.HeapSys/1024, m.HeapSys/1024/1024)
fmt.Printf("Heap idle: %d KB (%d MB)\n", m.HeapIdle/1024, m.HeapIdle/1024/1024)
fmt.Printf("Heap in use: %d KB (%d MB)\n", m.HeapInuse/1024, m.HeapInuse/1024/1024)
fmt.Printf("Heap released: %d KB (%d MB)\n", m.HeapReleased/1024, m.HeapReleased/1024/1024)
fmt.Printf("Heap objects: %d\n", m.HeapObjects)
fmt.Printf("GC runs: %d\n", m.NumGC)
fmt.Printf("GC pause total: %d ns\n", m.PauseTotalNs)
fmt.Printf("Next GC: %d KB (%d MB)\n", m.NextGC/1024, m.NextGC/1024/1024)
fmt.Printf("Last GC: %s\n", time.Unix(0, int64(m.LastGC)).Format("2006-01-02 15:04:05"))
}
func printGoroutineInfo() {
fmt.Println("\n=== Goroutine Information ===")
fmt.Printf("Number of goroutines: %d\n", runtime.NumGoroutine())
fmt.Printf("Number of CPUs: %d\n", runtime.NumCPU())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
buf := make([]byte, 1024*1024)
stackSize := runtime.Stack(buf, true)
fmt.Printf("\nGoroutine stack trace (first 2048 bytes):\n")
if stackSize > 2048 {
fmt.Printf("%s...\n", buf[:2048])
fmt.Printf("(truncated, total size: %d bytes)\n", stackSize)
} else {
fmt.Printf("%s\n", buf[:stackSize])
}
}
func printBasicInfo() {
fmt.Println("=== Performance Debug Info ===")
fmt.Printf("Go version: %s\n", runtime.Version())
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
fmt.Printf("CPUs: %d\n", runtime.NumCPU())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine())
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Memory allocated: %d KB\n", m.Alloc/1024)
fmt.Printf("Total allocations: %d KB\n", m.TotalAlloc/1024)
fmt.Printf("GC runs: %d\n", m.NumGC)
fmt.Println("\nUse --help to see available profiling options.")
}
+14
View File
@@ -0,0 +1,14 @@
package cmd
import (
"github.com/1Panel-dev/1Panel/agent/server"
"github.com/spf13/cobra"
)
var RootCmd = &cobra.Command{
Use: "1panel-agent",
RunE: func(cmd *cobra.Command, args []string) error {
server.Start()
return nil
},
}
+7 -4
View File
@@ -1,9 +1,9 @@
package main package main
import ( import (
_ "net/http/pprof" "fmt"
"github.com/1Panel-dev/1Panel/agent/cmd/server/cmd"
"github.com/1Panel-dev/1Panel/agent/server" "os"
) )
// @title 1Panel // @title 1Panel
@@ -15,5 +15,8 @@ import (
// @host localhost // @host localhost
// @BasePath /api/v2 // @BasePath /api/v2
func main() { func main() {
server.Start() if err := cmd.RootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
} }
+14 -3
View File
@@ -3,6 +3,7 @@ package nginx_conf
import ( import (
"embed" "embed"
_ "embed" _ "embed"
"io"
) )
//go:embed ssl.conf //go:embed ssl.conf
@@ -44,8 +45,18 @@ var PathAuth []byte
//go:embed upstream.conf //go:embed upstream.conf
var Upstream []byte var Upstream []byte
//go:embed php_extensions.json
var PHPExtensionsJson []byte
//go:embed sse.conf //go:embed sse.conf
var SSE []byte var SSE []byte
//go:embed *.json
var websitesFiles embed.FS
func GetWebsiteFile(filename string) []byte {
file, err := websitesFiles.Open(filename)
if err != nil {
return nil
}
defer file.Close()
res, _ := io.ReadAll(file)
return res
}
@@ -91,7 +91,7 @@
"installed": false "installed": false
}, },
{ {
"name": "Swoole", "name": "swoole",
"check": "swoole", "check": "swoole",
"file": "swoole.so", "file": "swoole.so",
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"], "versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
@@ -369,5 +369,12 @@
"file": "bcmath.so", "file": "bcmath.so",
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"], "versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
"installed": false "installed": false
},
{
"name": "pcntl",
"check": "pcntl",
"file": "pcntl.so",
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
"installed": false
} }
] ]
+8 -3
View File
@@ -1,9 +1,10 @@
package global package global
type ServerConfig struct { type ServerConfig struct {
Base Base `mapstructure:"base"` Base Base `mapstructure:"base"`
RemoteURL RemoteURL `mapstructure:"remote_url"` RemoteURL RemoteURL `mapstructure:"remote_url"`
Log LogConfig `mapstructure:"log"` Log LogConfig `mapstructure:"log"`
DockerConfig DockerConfig
} }
type Base struct { type Base struct {
@@ -51,3 +52,7 @@ type LogConfig struct {
LogSuffix string `mapstructure:"log_suffix"` LogSuffix string `mapstructure:"log_suffix"`
MaxBackup int `mapstructure:"max_backup"` MaxBackup int `mapstructure:"max_backup"`
} }
type DockerConfig struct {
Command string
}
+1
View File
@@ -64,6 +64,7 @@ require (
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 // indirect github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.63.100 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect github.com/andybalholm/brotli v1.0.4 // indirect
github.com/baidubce/bce-sdk-go v0.9.223 // indirect
github.com/bodgit/plumbing v1.2.0 // indirect github.com/bodgit/plumbing v1.2.0 // indirect
github.com/bodgit/sevenzip v1.3.0 // indirect github.com/bodgit/sevenzip v1.3.0 // indirect
github.com/bodgit/windows v1.0.0 // indirect github.com/bodgit/windows v1.0.0 // indirect
+2
View File
@@ -90,6 +90,8 @@ github.com/aws/aws-sdk-go v1.55.0/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQ
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/baidubce/bce-sdk-go v0.9.223 h1:vvDeIemf7ePPP59nLHCntQ/vS++ok2HKbRPgmz1VZKU=
github.com/baidubce/bce-sdk-go v0.9.223/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+3
View File
@@ -92,6 +92,7 @@ ErrCustomApps: 'There is an installed application, please uninstall it first'
ErrCustomRuntimes: 'There is an installed runtime environment, please delete it first' ErrCustomRuntimes: 'There is an installed runtime environment, please delete it first'
ErrAppVersionDeprecated: "The {{ .name }} application is not compatible with the current 1Panel version, skipped" ErrAppVersionDeprecated: "The {{ .name }} application is not compatible with the current 1Panel version, skipped"
ErrDockerFailed: "The state of Docker is abnormal, please check the service status" ErrDockerFailed: "The state of Docker is abnormal, please check the service status"
ErrDockerComposeCmdNotFound: "The Docker Compose command does not exist, please install this command on the host machine first"
#file #file
ErrFileCanNotRead: 'This file does not support preview' ErrFileCanNotRead: 'This file does not support preview'
@@ -107,6 +108,7 @@ ErrSourcePathNotFound: 'Source directory does not exist'
ErrFavoriteExist: 'This path has already been favorited' ErrFavoriteExist: 'This path has already been favorited'
ErrInvalidChar: 'Illegal characters are not allowed' ErrInvalidChar: 'Illegal characters are not allowed'
ErrPathNotDelete: 'The selected directory cannot be deleted' ErrPathNotDelete: 'The selected directory cannot be deleted'
ErrLogFileToLarge: "The log file exceeds 500MB and cannot be opened"
#website #website
ErrAliasIsExist: 'Alias already exists' ErrAliasIsExist: 'Alias already exists'
@@ -202,6 +204,7 @@ HandleSystemClean: 'System cache cleanup'
SystemLog: 'System Log' SystemLog: 'System Log'
CutWebsiteLog: 'Rotate Website Log' CutWebsiteLog: 'Rotate Website Log'
FileOrDir: 'Directory / File' FileOrDir: 'Directory / File'
UploadFile: 'Uploading backup file {{ .file }} to {{ .backup }}'
#toolbox #toolbox
ErrNotExistUser: 'The current user does not exist, please modify and try again!' ErrNotExistUser: 'The current user does not exist, please modify and try again!'
+3
View File
@@ -92,6 +92,7 @@ ErrCustomApps: 'インストールされているアプリケーションがあ
ErrCustomRuntimes: 'ランタイム環境がインストールされています。まずそれを削除してください' ErrCustomRuntimes: 'ランタイム環境がインストールされています。まずそれを削除してください'
ErrAppVersionDeprecated: "{{ .name }} アプリケーションは現在の 1Panel バージョンと互換性がありません、スキップしました" ErrAppVersionDeprecated: "{{ .name }} アプリケーションは現在の 1Panel バージョンと互換性がありません、スキップしました"
ErrDockerFailed: "Docker の状態が異常です。サービス状態を確認してください" ErrDockerFailed: "Docker の状態が異常です。サービス状態を確認してください"
ErrDockerComposeCmdNotFound: "Docker Compose コマンドは存在しません。ホストマシンにこのコマンドを先にインストールしてください"
#file #file
ErrFileCanNotRead: 'このファイルはプレビューをサポートしていません' ErrFileCanNotRead: 'このファイルはプレビューをサポートしていません'
@@ -107,6 +108,7 @@ ErrSourcePathNotFound: 'ソース ディレクトリが存在しません'
ErrFavoriteExist: 'このパスはすでにお気に入りに登録されています' ErrFavoriteExist: 'このパスはすでにお気に入りに登録されています'
ErrInvalidChar: '不正な文字は許可されません' ErrInvalidChar: '不正な文字は許可されません'
ErrPathNotDelete: '選択されたディレクトリは削除できません' ErrPathNotDelete: '選択されたディレクトリは削除できません'
ErrLogFileToLarge: "ログファイルが500MBを超えており、開くことができません"
#website #website
ErrAliasIsExist: 'エイリアスがすでに存在します' ErrAliasIsExist: 'エイリアスがすでに存在します'
@@ -202,6 +204,7 @@ HandleSystemClean: 'システム キャッシュのクリーンアップ'
SystemLog: 'システムログ' SystemLog: 'システムログ'
CutWebsiteLog: 'ウェブサイトログのローテーション' CutWebsiteLog: 'ウェブサイトログのローテーション'
FileOrDir: 'ディレクトリ / ファイル' FileOrDir: 'ディレクトリ / ファイル'
UploadFile: 'バックアップファイル {{ .file }} を {{ .backup }} にアップロード中'
#toolbox #toolbox
ErrNotExistUser: '現在のユーザーは存在しません。変更してもう一度お試しください。' ErrNotExistUser: '現在のユーザーは存在しません。変更してもう一度お試しください。'
+3
View File
@@ -92,6 +92,7 @@ ErrCustomApps: '설치된 애플리케이션이 있습니다. 먼저 제거해
ErrCustomRuntimes: '설치된 런타임 환경이 있습니다. 먼저 삭제해 주세요' ErrCustomRuntimes: '설치된 런타임 환경이 있습니다. 먼저 삭제해 주세요'
ErrAppVersionDeprecated: "{{ .name }} 응용 프로그램은 현재 1Panel 버전과 호환되지 않아 건너뛰었습니다" ErrAppVersionDeprecated: "{{ .name }} 응용 프로그램은 현재 1Panel 버전과 호환되지 않아 건너뛰었습니다"
ErrDockerFailed: "Docker의 상태가 비정상입니다. 서비스 상태를 확인하세요" ErrDockerFailed: "Docker의 상태가 비정상입니다. 서비스 상태를 확인하세요"
ErrDockerComposeCmdNotFound: "Docker Compose 명령이 없습니다. 호스트 머신에 먼저 이 명령을 설치하세요"
#파일 #파일
ErrFileCanNotRead: '이 파일은 미리보기를 지원하지 않습니다' ErrFileCanNotRead: '이 파일은 미리보기를 지원하지 않습니다'
@@ -107,6 +108,7 @@ ErrSourcePathNotFound: '소스 디렉토리가 존재하지 않습니다'
ErrFavoriteExist: '이 경로는 이미 즐겨찾기되었습니다' ErrFavoriteExist: '이 경로는 이미 즐겨찾기되었습니다'
ErrInvalidChar: '불법 문자는 허용되지 않습니다' ErrInvalidChar: '불법 문자는 허용되지 않습니다'
ErrPathNotDelete: '선택한 디렉토리를 삭제할 수 없습니다' ErrPathNotDelete: '선택한 디렉토리를 삭제할 수 없습니다'
ErrLogFileToLarge: "로그 파일이 500MB를 초과하여 열 수 없습니다"
#웹사이트 #웹사이트
ErrAliasIsExist: '별칭이 이미 존재합니다' ErrAliasIsExist: '별칭이 이미 존재합니다'
@@ -202,6 +204,7 @@ HandleSystemClean: '시스템 캐시 정리'
SystemLog: '시스템 로그' SystemLog: '시스템 로그'
CutWebsiteLog: '웹사이트 로그 회전' CutWebsiteLog: '웹사이트 로그 회전'
FileOrDir: '디렉터리 / 파일' FileOrDir: '디렉터리 / 파일'
UploadFile: '백업 파일 {{ .file }} 을(를) {{ .backup }}(으)로 업로드 중'
#도구상자 #도구상자
ErrNotExistUser: '현재 사용자가 존재하지 않습니다. 수정한 후 다시 시도하세요!' ErrNotExistUser: '현재 사용자가 존재하지 않습니다. 수정한 후 다시 시도하세요!'
+2
View File
@@ -92,6 +92,7 @@ ErrCustomApps: 'Ada aplikasi yang dipasang, sila nyahpasangnya dahulu'
ErrCustomRuntimes: 'Terdapat persekitaran masa jalan yang dipasang, sila padamkannya dahulu' ErrCustomRuntimes: 'Terdapat persekitaran masa jalan yang dipasang, sila padamkannya dahulu'
ErrAppVersionDeprecated: "Aplikasi {{ .name }} tidak sesuai dengan versi 1Panel saat ini, dilewati" ErrAppVersionDeprecated: "Aplikasi {{ .name }} tidak sesuai dengan versi 1Panel saat ini, dilewati"
ErrDockerFailed: "Keadaan Docker tidak normal, sila periksa status perkhidmatan" ErrDockerFailed: "Keadaan Docker tidak normal, sila periksa status perkhidmatan"
ErrDockerComposeCmdNotFound: "Perintah Docker Compose tidak wujud, sila pasang perintah ini di mesin tuan terlebih dahulu"
#fail #fail
ErrFileCanNotRead: 'Fail ini tidak menyokong pratonton' ErrFileCanNotRead: 'Fail ini tidak menyokong pratonton'
@@ -202,6 +203,7 @@ HandleSystemClean: 'Pembersihan cache sistem'
SystemLog: 'Log Sistem' SystemLog: 'Log Sistem'
CutWebsiteLog: 'Putar Log Laman Web' CutWebsiteLog: 'Putar Log Laman Web'
FileOrDir: 'Direktori / Fail' FileOrDir: 'Direktori / Fail'
UploadFile: 'Muat naik fail sandaran {{ .file }} ke {{ .backup }}'
#kotak alat #kotak alat
ErrNotExistUser: 'Pengguna semasa tidak wujud, sila ubah suai dan cuba lagi!' ErrNotExistUser: 'Pengguna semasa tidak wujud, sila ubah suai dan cuba lagi!'
+3
View File
@@ -92,6 +92,7 @@ ErrCustomApps: 'Há um aplicativo instalado, desinstale-o primeiro'
ErrCustomRuntimes: 'Há um ambiente de execução instalado, exclua-o primeiro' ErrCustomRuntimes: 'Há um ambiente de execução instalado, exclua-o primeiro'
ErrAppVersionDeprecated: "O aplicativo {{ .name }} não é compatível com a versão atual do 1Panel, ignorado" ErrAppVersionDeprecated: "O aplicativo {{ .name }} não é compatível com a versão atual do 1Panel, ignorado"
ErrDockerFailed: "O estado do Docker está anormal, verifique o status do serviço" ErrDockerFailed: "O estado do Docker está anormal, verifique o status do serviço"
ErrDockerComposeCmdNotFound: "O comando Docker Compose não existe, por favor, instale este comando na máquina host primeiro"
#arquivo #arquivo
ErrFileCanNotRead: 'Este arquivo não suporta visualização' ErrFileCanNotRead: 'Este arquivo não suporta visualização'
@@ -107,6 +108,7 @@ ErrSourcePathNotFound: 'O diretório de origem não existe'
ErrFavoriteExist: 'Este caminho já foi favorito' ErrFavoriteExist: 'Este caminho já foi favorito'
ErrInvalidChar: 'Caracteres ilegais não são permitidos' ErrInvalidChar: 'Caracteres ilegais não são permitidos'
ErrPathNotDelete: 'O diretório selecionado não pode ser excluído' ErrPathNotDelete: 'O diretório selecionado não pode ser excluído'
ErrLogFileToLarge: "Fail log melebihi 500MB, tidak boleh dibuka"
#site #site
ErrAliasIsExist: 'Alias já existe' ErrAliasIsExist: 'Alias já existe'
@@ -202,6 +204,7 @@ HandleSystemClean: 'Limpeza de cache do sistema'
SystemLog: 'Log do Sistema' SystemLog: 'Log do Sistema'
CutWebsiteLog: 'Rotacionar Log do Website' CutWebsiteLog: 'Rotacionar Log do Website'
FileOrDir: 'Diretório / Arquivo' FileOrDir: 'Diretório / Arquivo'
UploadFile: 'Enviando arquivo de backup {{ .file }} para {{ .backup }}'
#caixa de ferramentas #caixa de ferramentas
ErrNotExistUser: 'O usuário atual não existe, modifique e tente novamente!' ErrNotExistUser: 'O usuário atual não existe, modifique e tente novamente!'
+3
View File
@@ -92,6 +92,7 @@ ErrCustomApps: 'Установлено приложение. Сначала уд
ErrCustomRuntimes: 'Установлена среда выполнения. Сначала удалите ее' ErrCustomRuntimes: 'Установлена среда выполнения. Сначала удалите ее'
ErrAppVersionDeprecated: "Приложение {{ .name }} несовместимо с текущей версией 1Panel, пропущено" ErrAppVersionDeprecated: "Приложение {{ .name }} несовместимо с текущей версией 1Panel, пропущено"
ErrDockerFailed: "Состояние Docker аномально, проверьте состояние сервиса" ErrDockerFailed: "Состояние Docker аномально, проверьте состояние сервиса"
ErrDockerComposeCmdNotFound: "Команда Docker Compose отсутствует, пожалуйста, установите эту команду на хост-машине сначала"
#файл #файл
ErrFileCanNotRead: 'Этот файл не поддерживает предварительный просмотр' ErrFileCanNotRead: 'Этот файл не поддерживает предварительный просмотр'
@@ -107,6 +108,7 @@ ErrSourcePathNotFound: 'Исходный каталог не существуе
ErrFavoriteExist: 'Этот путь уже добавлен в избранное' ErrFavoriteExist: 'Этот путь уже добавлен в избранное'
ErrInvalidChar: 'Недопустимые символы не допускаются' ErrInvalidChar: 'Недопустимые символы не допускаются'
ErrPathNotDelete: 'Выбранный каталог не может быть удален' ErrPathNotDelete: 'Выбранный каталог не может быть удален'
ErrLogFileToLarge: "Файл журнала превышает 500MB и не может быть открыт"
#веб-сайт #веб-сайт
ErrAliasIsExist: 'Псевдоним уже существует' ErrAliasIsExist: 'Псевдоним уже существует'
@@ -202,6 +204,7 @@ HandleSystemClean: 'Очистка системного кэша'
SystemLog: 'Системный лог' SystemLog: 'Системный лог'
CutWebsiteLog: 'Ротация логов сайта' CutWebsiteLog: 'Ротация логов сайта'
FileOrDir: 'Каталог / Файл' FileOrDir: 'Каталог / Файл'
UploadFile: 'Загрузка файла резервной копии {{ .file }} в {{ .backup }}'
#ящик для инструментов #ящик для инструментов
ErrNotExistUser: 'Текущий пользователь не существует, измените его и повторите попытку!' ErrNotExistUser: 'Текущий пользователь не существует, измените его и повторите попытку!'
+3
View File
@@ -91,6 +91,7 @@ ErrCustomApps: '存在已安裝的應用程式,請先解除安裝'
ErrCustomRuntimes: '存在已安裝的運作環境,請先刪除' ErrCustomRuntimes: '存在已安裝的運作環境,請先刪除'
ErrAppVersionDeprecated: "{{ .name }} 應用不適配目前 1Panel 版本,跳過" ErrAppVersionDeprecated: "{{ .name }} 應用不適配目前 1Panel 版本,跳過"
ErrDockerFailed: "Docker 狀態異常,請檢查服務狀態" ErrDockerFailed: "Docker 狀態異常,請檢查服務狀態"
ErrDockerComposeCmdNotFound: "Docker Compose 命令不存在,請先在宿主機安裝此命令"
#file #file
ErrFileCanNotRead: '此檔案不支援預覽' ErrFileCanNotRead: '此檔案不支援預覽'
@@ -106,6 +107,7 @@ ErrSourcePathNotFound: '來源目錄不存在'
ErrFavoriteExist: '已收藏此路徑' ErrFavoriteExist: '已收藏此路徑'
ErrInvalidChar: '禁止使用非法字元' ErrInvalidChar: '禁止使用非法字元'
ErrPathNotDelete: '所選目錄不可刪除' ErrPathNotDelete: '所選目錄不可刪除'
ErrLogFileToLarge: "日志文件超过 500M,無法打開"
#website #website
ErrAliasIsExist: '代號已存在' ErrAliasIsExist: '代號已存在'
@@ -201,6 +203,7 @@ HandleSystemClean: '系統快取清理'
SystemLog: '系統日誌' SystemLog: '系統日誌'
CutWebsiteLog: '切割網站日誌' CutWebsiteLog: '切割網站日誌'
FileOrDir: '目錄 / 檔案' FileOrDir: '目錄 / 檔案'
UploadFile: '上傳備份文件 {{ .file }} 到 {{ .backup }}'
#toolbox #toolbox
ErrNotExistUser: '目前使用者不存在,請修改後重試!' ErrNotExistUser: '目前使用者不存在,請修改後重試!'
+3
View File
@@ -91,6 +91,7 @@ ErrCustomApps: "存在已经安装的应用,请先卸载"
ErrCustomRuntimes: "存在已经安装的运行环境,请先删除" ErrCustomRuntimes: "存在已经安装的运行环境,请先删除"
ErrAppVersionDeprecated: " {{ .name }} 应用不适配当前 1Panel 版本,跳过" ErrAppVersionDeprecated: " {{ .name }} 应用不适配当前 1Panel 版本,跳过"
ErrDockerFailed: "Docker 状态异常,请检查服务状态" ErrDockerFailed: "Docker 状态异常,请检查服务状态"
ErrDockerComposeCmdNotFound: "Docker Compose 命令不存在,请先在宿主机安装此命令"
#file #file
ErrFileCanNotRead: "此文件不支持预览" ErrFileCanNotRead: "此文件不支持预览"
@@ -106,6 +107,7 @@ ErrSourcePathNotFound: "源目录不存在"
ErrFavoriteExist: "已收藏此路径" ErrFavoriteExist: "已收藏此路径"
ErrInvalidChar: "禁止使用非法字符" ErrInvalidChar: "禁止使用非法字符"
ErrPathNotDelete: "所选目录不可删除" ErrPathNotDelete: "所选目录不可删除"
ErrLogFileToLarge: "日志文件超过 500M,无法打开"
#website #website
ErrAliasIsExist: "代号已存在" ErrAliasIsExist: "代号已存在"
@@ -201,6 +203,7 @@ HandleSystemClean: "系统缓存清理"
SystemLog: "系统日志" SystemLog: "系统日志"
CutWebsiteLog: "切割网站日志" CutWebsiteLog: "切割网站日志"
FileOrDir: "目录 / 文件" FileOrDir: "目录 / 文件"
UploadFile: "上传备份文件 {{ .file }} 到 {{ .backup }}"
#toolbox #toolbox
ErrNotExistUser: "当前用户不存在,请修改后重试!" ErrNotExistUser: "当前用户不存在,请修改后重试!"
+15
View File
@@ -6,6 +6,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/service" "github.com/1Panel-dev/1Panel/agent/app/service"
"github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/common"
) )
func Init() { func Init() {
@@ -15,6 +16,7 @@ func Init() {
go syncSSL() go syncSSL()
go syncTask() go syncTask()
go initAcmeAccount() go initAcmeAccount()
go checkDockerCompose()
} }
func syncApp() { func syncApp() {
@@ -71,3 +73,16 @@ func initAcmeAccount() {
} }
} }
} }
func checkDockerCompose() {
dockerComposCmd := common.GetDockerComposeCommand()
if dockerComposCmd == "" {
global.LOG.Errorf("Docker Compose command not found, please install Docker Compose Plugin")
return
}
global.CONF.DockerConfig.Command = dockerComposCmd
if err := service.NewISettingService().Update("DockerComposeCommand", dockerComposCmd); err != nil {
global.LOG.Errorf("update docker compose command error: %s", err.Error())
return
}
}
-57
View File
@@ -1,57 +0,0 @@
package middleware
import (
"net/http"
"strings"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/gin-gonic/gin"
)
var whiteUrlList = map[string]struct{}{
"/api/v2/auth/login": {},
"/api/v2/websites/config": {},
"/api/v2/websites/waf/config": {},
"/api/v2/files/loadfile": {},
"/api/v2/files/size": {},
"/api/v2/logs/operation": {},
"/api/v2/logs/login": {},
"/api/v2/auth/logout": {},
"/api/v1/dashboard/current": {},
"/api/v2/apps/installed/loadport": {},
"/api/v2/apps/installed/check": {},
"/api/v2/apps/installed/conninfo": {},
"/api/v2/databases/load/file": {},
"/api/v2/databases/variables": {},
"/api/v2/databases/status": {},
"/api/v2/databases/baseinfo": {},
"/api/v2/waf/attack/stat": {},
"/api/v2/waf/config/website": {},
"/api/v2/monitor/stat": {},
"/api/v2/monitor/visitors": {},
"/api/v2/monitor/visitors/loc": {},
"/api/v2/monitor/qps": {},
}
func DemoHandle() gin.HandlerFunc {
return func(c *gin.Context) {
if strings.Contains(c.Request.URL.Path, "search") || c.Request.Method == http.MethodGet {
c.Next()
return
}
if _, ok := whiteUrlList[c.Request.URL.Path]; ok {
c.Next()
return
}
c.JSON(http.StatusInternalServerError, dto.Response{
Code: http.StatusInternalServerError,
Message: buserr.New("ErrDemoEnvironment").Error(),
})
c.Abort()
}
}
+2
View File
@@ -33,6 +33,8 @@ func (s *ContainerRouter) InitRouter(Router *gin.RouterGroup) {
baRouter.POST("/operate", baseApi.ContainerOperation) baRouter.POST("/operate", baseApi.ContainerOperation)
baRouter.POST("/prune", baseApi.ContainerPrune) baRouter.POST("/prune", baseApi.ContainerPrune)
baRouter.POST("/users", baseApi.LoadContainerUsers)
baRouter.GET("/repo", baseApi.ListRepo) baRouter.GET("/repo", baseApi.ListRepo)
baRouter.POST("/repo/status", baseApi.CheckRepoStatus) baRouter.POST("/repo/status", baseApi.CheckRepoStatus)
baRouter.POST("/repo/search", baseApi.SearchRepo) baRouter.POST("/repo/search", baseApi.SearchRepo)
+2 -1
View File
@@ -497,6 +497,7 @@ func (a *aliClient) completeUpload(uploadID, fileID string) error {
type tokenResp struct { type tokenResp struct {
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
AccessToken string `json:"access_token"`
} }
func loadToken(refresh_token string) (string, error) { func loadToken(refresh_token string) (string, error) {
@@ -524,7 +525,7 @@ func loadToken(refresh_token string) (string, error) {
if err := json.Unmarshal(resp.Body(), &respItem); err != nil { if err := json.Unmarshal(resp.Body(), &respItem); err != nil {
return "", err return "", err
} }
return respItem.RefreshToken, nil return respItem.AccessToken, nil
} }
func RefreshALIToken(varMap map[string]interface{}) (string, error) { func RefreshALIToken(varMap map[string]interface{}) (string, error) {
+12 -2
View File
@@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"regexp"
cosSDK "github.com/tencentyun/cos-go-sdk-v5" cosSDK "github.com/tencentyun/cos-go-sdk-v5"
) )
@@ -18,6 +19,7 @@ type cosClient struct {
func NewCosClient(vars map[string]interface{}) (*cosClient, error) { func NewCosClient(vars map[string]interface{}) (*cosClient, error) {
region := loadParamFromVars("region", vars) region := loadParamFromVars("region", vars)
endpoint := loadParamFromVars("endpoint", vars)
accessKey := loadParamFromVars("accessKey", vars) accessKey := loadParamFromVars("accessKey", vars)
secretKey := loadParamFromVars("secretKey", vars) secretKey := loadParamFromVars("secretKey", vars)
bucket := loadParamFromVars("bucket", vars) bucket := loadParamFromVars("bucket", vars)
@@ -26,7 +28,15 @@ func NewCosClient(vars map[string]interface{}) (*cosClient, error) {
scType = "Standard" scType = "Standard"
} }
u, _ := url.Parse(fmt.Sprintf("https://cos.%s.myqcloud.com", region)) endpointType := "cos"
if len(endpoint) != 0 {
re := regexp.MustCompile(`.*cos-dualstack\..*`)
if re.MatchString(endpoint) {
endpointType = "cos-dualstack"
}
}
u, _ := url.Parse(fmt.Sprintf("https://%s.%s.myqcloud.com", endpointType, region))
b := &cosSDK.BaseURL{BucketURL: u} b := &cosSDK.BaseURL{BucketURL: u}
client := cosSDK.NewClient(b, &http.Client{ client := cosSDK.NewClient(b, &http.Client{
Transport: &cosSDK.AuthorizationTransport{ Transport: &cosSDK.AuthorizationTransport{
@@ -36,7 +46,7 @@ func NewCosClient(vars map[string]interface{}) (*cosClient, error) {
}) })
if len(bucket) != 0 { if len(bucket) != 0 {
u2, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", bucket, region)) u2, _ := url.Parse(fmt.Sprintf("https://%s.%s.%s.myqcloud.com", bucket, endpointType, region))
b2 := &cosSDK.BaseURL{BucketURL: u2} b2 := &cosSDK.BaseURL{BucketURL: u2}
clientWithBucket := cosSDK.NewClient(b2, &http.Client{ clientWithBucket := cosSDK.NewClient(b2, &http.Client{
Transport: &cosSDK.AuthorizationTransport{ Transport: &cosSDK.AuthorizationTransport{
@@ -393,7 +393,6 @@ func RefreshGoogleToken(grantType string, tokenType string, varMap map[string]in
if err := json.Unmarshal(resp.Body(), &respItem); err != nil { if err := json.Unmarshal(resp.Body(), &respItem); err != nil {
return "", err return "", err
} }
fmt.Println(respItem)
if tokenType == "accessToken" { if tokenType == "accessToken" {
return respItem.AccessToken, nil return respItem.AccessToken, nil
} }
@@ -41,6 +41,8 @@ func NewCloudStorageClient(backupType string, vars map[string]interface{}) (Clou
return client.NewUpClient(vars) return client.NewUpClient(vars)
case constant.ALIYUN: case constant.ALIYUN:
return client.NewALIClient(vars) return client.NewALIClient(vars)
case constant.GoogleDrive:
return client.NewGoogleDriveClient(vars)
default: default:
return nil, buserr.WithName("ErrNotSupportType", backupType) return nil, buserr.WithName("ErrNotSupportType", backupType)
} }
+1 -1
View File
@@ -120,9 +120,9 @@ func (c *CommandHelper) run(name string, arg ...string) (string, error) {
cmd.Stdout = file cmd.Stdout = file
cmd.Stderr = file cmd.Stderr = file
} else if len(c.scriptPath) != 0 { } else if len(c.scriptPath) != 0 {
cmd = exec.Command("bash", c.scriptPath)
cmd.Stdout = &stdout cmd.Stdout = &stdout
cmd.Stderr = &stderr cmd.Stderr = &stderr
cmd = exec.Command("bash", c.scriptPath)
} else { } else {
cmd.Stdout = &stdout cmd.Stdout = &stdout
cmd.Stderr = &stderr cmd.Stderr = &stderr
+17
View File
@@ -6,6 +6,7 @@ import (
"io" "io"
mathRand "math/rand" mathRand "math/rand"
"net" "net"
"os/exec"
"reflect" "reflect"
"regexp" "regexp"
"sort" "sort"
@@ -409,3 +410,19 @@ func GetSystemVersion(versionString string) string {
} }
return "" return ""
} }
func isCommandAvailable(name string, args ...string) bool {
execCmd := exec.Command(name, args...)
err := execCmd.Run()
return err == nil
}
func GetDockerComposeCommand() string {
if isCommandAvailable("docker", "compose", "version") {
return "docker compose"
}
if isCommandAvailable("docker-compose", "version") {
return "docker-compose"
}
return ""
}
+39 -7
View File
@@ -1,40 +1,72 @@
package compose package compose
import ( import (
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/cmd"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"time" "time"
) )
func checkCmd() error {
if global.CONF.DockerConfig.Command == "" {
dockerComposCmd := common.GetDockerComposeCommand()
if dockerComposCmd == "" {
return buserr.New("ErrDockerComposeCmdNotFound")
}
global.CONF.DockerConfig.Command = dockerComposCmd
}
return nil
}
func Up(filePath string) (string, error) { func Up(filePath string) (string, error) {
stdout, err := cmd.RunDefaultWithStdoutBashCfAndTimeOut("docker compose -f %s up -d", 20*time.Minute, filePath) if err := checkCmd(); err != nil {
return "", err
}
stdout, err := cmd.RunDefaultWithStdoutBashCfAndTimeOut(global.CONF.DockerConfig.Command+" -f %s up -d", 20*time.Minute, filePath)
return stdout, err return stdout, err
} }
func Down(filePath string) (string, error) { func Down(filePath string) (string, error) {
stdout, err := cmd.RunDefaultWithStdoutBashCf("docker compose -f %s down --remove-orphans", filePath) if err := checkCmd(); err != nil {
return "", err
}
stdout, err := cmd.RunDefaultWithStdoutBashCf(global.CONF.DockerConfig.Command+" -f %s down --remove-orphans", filePath)
return stdout, err return stdout, err
} }
func Stop(filePath string) (string, error) { func Stop(filePath string) (string, error) {
stdout, err := cmd.RunDefaultWithStdoutBashCf("docker compose -f %s stop", filePath) if err := checkCmd(); err != nil {
return "", err
}
stdout, err := cmd.RunDefaultWithStdoutBashCf(global.CONF.DockerConfig.Command+" -f %s stop", filePath)
return stdout, err return stdout, err
} }
func Restart(filePath string) (string, error) { func Restart(filePath string) (string, error) {
stdout, err := cmd.RunDefaultWithStdoutBashCf("docker compose -f %s restart", filePath) if err := checkCmd(); err != nil {
return "", err
}
stdout, err := cmd.RunDefaultWithStdoutBashCf(global.CONF.DockerConfig.Command+" -f %s restart", filePath)
return stdout, err return stdout, err
} }
func Operate(filePath, operation string) (string, error) { func Operate(filePath, operation string) (string, error) {
stdout, err := cmd.RunDefaultWithStdoutBashCf("docker compose -f %s %s", filePath, operation) if err := checkCmd(); err != nil {
return "", err
}
stdout, err := cmd.RunDefaultWithStdoutBashCf(global.CONF.DockerConfig.Command+" -f %s %s", filePath, operation)
return stdout, err return stdout, err
} }
func DownAndUp(filePath string) (string, error) { func DownAndUp(filePath string) (string, error) {
stdout, err := cmd.RunDefaultWithStdoutBashCf("docker compose -f %s down", filePath) if err := checkCmd(); err != nil {
return "", err
}
stdout, err := cmd.RunDefaultWithStdoutBashCf(global.CONF.DockerConfig.Command+" -f %s down", filePath)
if err != nil { if err != nil {
return stdout, err return stdout, err
} }
stdout, err = cmd.RunDefaultWithStdoutBashCf("docker compose -f %s up -d", filePath) stdout, err = cmd.RunDefaultWithStdoutBashCf(global.CONF.DockerConfig.Command+" -f %s up -d", filePath)
return stdout, err return stdout, err
} }
+2 -2
View File
@@ -144,14 +144,14 @@ func (c Client) NetworkExist(name string) bool {
func CreateDefaultDockerNetwork() error { func CreateDefaultDockerNetwork() error {
cli, err := NewClient() cli, err := NewClient()
if err != nil { if err != nil {
global.LOG.Errorf("init docker client error %s", err.Error()) global.LOG.Warnf("init docker client error %s", err.Error())
return err return err
} }
defer cli.Close() defer cli.Close()
if !cli.NetworkExist("1panel-network") { if !cli.NetworkExist("1panel-network") {
if err := cli.CreateNetwork("1panel-network"); err != nil { if err := cli.CreateNetwork("1panel-network"); err != nil {
global.LOG.Errorf("create default docker network error %s", err.Error()) global.LOG.Warnf("create default docker network error %s", err.Error())
return err return err
} }
} }
+11
View File
@@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/utils/req_helper" "github.com/1Panel-dev/1Panel/agent/utils/req_helper"
"io" "io"
@@ -103,6 +104,16 @@ func ReadFileByLine(filename string, page, pageSize int, latest bool) (lines []s
} }
defer file.Close() defer file.Close()
fi, err := file.Stat()
if err != nil {
return
}
if fi.Size() > 500*1024*1024 {
err = buserr.New("ErrLogFileToLarge")
return
}
totalLines, err := countLines(filename) totalLines, err := countLines(filename)
if err != nil { if err != nil {
return return
+9
View File
@@ -33,3 +33,12 @@ type IptablesNatInfo struct {
SrcPort string `json:"srcPort"` SrcPort string `json:"srcPort"`
DestPort string `json:"destPort"` DestPort string `json:"destPort"`
} }
type IptablesFilterInfo struct {
Num string `json:"num"`
Target string `json:"target"`
Protocol string `json:"protocol"`
Opt string `json:"opt"`
Source string `json:"source"`
Destination string `json:"destination"`
}
+144 -28
View File
@@ -10,9 +10,22 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/cmd"
) )
const (
PreRoutingChain = "1PANEL_PREROUTING"
PostRoutingChain = "1PANEL_POSTROUTING"
ForwardChain = "1PANEL_FORWARD"
)
const (
FilterTab = "filter"
NatTab = "nat"
)
const NatChain = "1PANEL" const NatChain = "1PANEL"
var NatListRegex = regexp.MustCompile(`^(\d+)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)(?:\s+(.+?) .+?:(\d{1,5}(?::\d+)?).+?[ :](.+-.+|(?:.+:)?\d{1,5}(?:-\d{1,5})?))?$`) var (
natListRegex = regexp.MustCompile(`^(\d+)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)(?:\s+(.+?) .+?:(\d{1,5}(?::\d+)?).+?[ :](.+-.+|(?:.+:)?\d{1,5}(?:-\d{1,5})?))?$`)
)
type Iptables struct { type Iptables struct {
CmdStr string CmdStr string
@@ -37,8 +50,24 @@ func (iptables *Iptables) run(rule string) error {
return nil return nil
} }
func (iptables *Iptables) runf(rule string, a ...any) error { func (iptables *Iptables) outf(tab, rule string, a ...any) (stdout string, err error) {
return iptables.run(fmt.Sprintf(rule, a...)) stdout, err = cmd.RunDefaultWithStdoutBashCf("%s iptables -t %s %s", iptables.CmdStr, tab, fmt.Sprintf(rule, a...))
if err != nil && stdout != "" {
global.LOG.Errorf("iptables failed, err: %s", stdout)
}
return
}
func (iptables *Iptables) runf(tab, rule string, a ...any) error {
stdout, err := iptables.outf(tab, rule, a...)
if err != nil {
return fmt.Errorf("%s, %s", err, stdout)
}
if stdout != "" {
return fmt.Errorf("iptables error: %s", stdout)
}
return nil
} }
func (iptables *Iptables) Check() error { func (iptables *Iptables) Check() error {
@@ -47,26 +76,30 @@ func (iptables *Iptables) Check() error {
return fmt.Errorf("%s, %s", err, stdout) return fmt.Errorf("%s, %s", err, stdout)
} }
if stdout == "0" { if stdout == "0" {
return fmt.Errorf("disable") return fmt.Errorf("ipv4 forward disable")
}
chain, _ := iptables.outf(NatTab, "-L -n | grep 'Chain %s'", PreRoutingChain)
if len(strings.ReplaceAll(chain, "\n", "")) != 0 {
return fmt.Errorf("chain enabled")
} }
return nil return nil
} }
func (iptables *Iptables) NatNewChain() error { func (iptables *Iptables) NewChain(tab, chain string) error {
return iptables.runf("-N %s", NatChain) return iptables.runf(tab, "-N %s", chain)
} }
func (iptables *Iptables) NatAppendChain() error { func (iptables *Iptables) AppendChain(tab string, chain, chain1 string) error {
return iptables.runf("-A PREROUTING -j %s", NatChain) return iptables.runf(tab, "-A %s -j %s", chain, chain1)
} }
func (iptables *Iptables) NatList(chain ...string) ([]IptablesNatInfo, error) { func (iptables *Iptables) NatList(chain ...string) ([]IptablesNatInfo, error) {
rule := fmt.Sprintf("%s iptables -t nat -nL %s --line", iptables.CmdStr, NatChain) if len(chain) == 0 {
if len(chain) == 1 { chain = append(chain, PreRoutingChain)
rule = fmt.Sprintf("%s iptables -t nat -nL %s --line", iptables.CmdStr, chain[0])
} }
stdout, err := cmd.RunDefaultWithStdoutBashC(rule) stdout, err := iptables.outf(NatTab, "-nL %s --line", chain[0])
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -76,8 +109,8 @@ func (iptables *Iptables) NatList(chain ...string) ([]IptablesNatInfo, error) {
line = strings.TrimFunc(line, func(r rune) bool { line = strings.TrimFunc(line, func(r rune) bool {
return r <= 32 return r <= 32
}) })
if NatListRegex.MatchString(line) { if natListRegex.MatchString(line) {
match := NatListRegex.FindStringSubmatch(line) match := natListRegex.FindStringSubmatch(line)
if !strings.Contains(match[9], ":") { if !strings.Contains(match[9], ":") {
match[9] = fmt.Sprintf(":%s", match[9]) match[9] = fmt.Sprintf(":%s", match[9])
} }
@@ -97,43 +130,126 @@ func (iptables *Iptables) NatList(chain ...string) ([]IptablesNatInfo, error) {
return forwardList, nil return forwardList, nil
} }
func (iptables *Iptables) NatAdd(protocol, src, destIp, destPort string, save bool) error { func (iptables *Iptables) NatAdd(protocol, srcPort, dest, destPort string, save bool) error {
rule := fmt.Sprintf("-A %s -p %s --dport %s -j REDIRECT --to-port %s", NatChain, protocol, src, destPort) if dest != "" && dest != "127.0.0.1" && dest != "localhost" {
if destIp != "" && destIp != "127.0.0.1" && destIp != "localhost" { if err := iptables.runf(NatTab, fmt.Sprintf(
rule = fmt.Sprintf("-A %s -p %s --dport %s -j DNAT --to-destination %s:%s", NatChain, protocol, src, destIp, destPort) "-A %s -p %s --dport %s -j DNAT --to-destination %s:%s",
} PreRoutingChain,
if err := iptables.run(rule); err != nil { protocol,
return err srcPort,
dest,
destPort,
)); err != nil {
return err
}
if err := iptables.runf(NatTab, fmt.Sprintf(
"-A %s -d %s -p %s --dport %s -j MASQUERADE",
PostRoutingChain,
dest,
protocol,
destPort,
)); err != nil {
return err
}
if err := iptables.runf(FilterTab, fmt.Sprintf(
"-A %s -d %s -p %s --dport %s -j ACCEPT",
ForwardChain,
dest,
protocol,
destPort,
)); err != nil {
return err
}
if err := iptables.runf(FilterTab, fmt.Sprintf(
"-A %s -s %s -p %s --sport %s -j ACCEPT",
ForwardChain,
dest,
protocol,
destPort,
)); err != nil {
return err
}
} else {
if err := iptables.runf(NatTab, fmt.Sprintf(
"-A %s -p %s --dport %s -j REDIRECT --to-port %s",
PreRoutingChain,
protocol,
srcPort,
destPort,
)); err != nil {
return err
}
} }
if save { if save {
return global.DB.Save(&model.Forward{ return global.DB.Save(&model.Forward{
Protocol: protocol, Protocol: protocol,
Port: src, Port: srcPort,
TargetIP: destIp, TargetIP: dest,
TargetPort: destPort, TargetPort: destPort,
}).Error }).Error
} }
return nil return nil
} }
func (iptables *Iptables) NatRemove(num string, protocol, src, destIp, destPort string) error { func (iptables *Iptables) NatRemove(num string, protocol, srcPort, dest, destPort string) error {
if err := iptables.runf("-D %s %s", NatChain, num); err != nil { if err := iptables.runf(NatTab, "-D %s %s", PreRoutingChain, num); err != nil {
return err return err
} }
if dest != "" && dest != "127.0.0.1" && dest != "localhost" {
if err := iptables.runf(NatTab, fmt.Sprintf(
"-D %s -d %s -p %s --dport %s -j MASQUERADE",
PostRoutingChain,
dest,
protocol,
destPort,
)); err != nil {
return err
}
if err := iptables.runf(FilterTab, fmt.Sprintf(
"-D %s -d %s -p %s --dport %s -j ACCEPT",
ForwardChain,
dest,
protocol,
destPort,
)); err != nil {
return err
}
if err := iptables.runf(FilterTab, fmt.Sprintf(
"-D %s -s %s -p %s --sport %s -j ACCEPT",
ForwardChain,
dest,
protocol,
destPort,
)); err != nil {
return err
}
}
global.DB.Where( global.DB.Where(
"protocol = ? AND port = ? AND target_ip = ? AND target_port = ?", "protocol = ? AND port = ? AND target_ip = ? AND target_port = ?",
protocol, protocol,
src, srcPort,
destIp, dest,
destPort, destPort,
).Delete(&model.Forward{}) ).Delete(&model.Forward{})
return nil return nil
} }
func (iptables *Iptables) Reload() error { func (iptables *Iptables) Reload() error {
if err := iptables.runf("-F %s", NatChain); err != nil { if err := iptables.runf(NatTab, "-F %s", PreRoutingChain); err != nil {
return err
}
if err := iptables.runf(NatTab, "-F %s", PostRoutingChain); err != nil {
return err
}
if err := iptables.runf(FilterTab, "-F %s", ForwardChain); err != nil {
return err return err
} }
+21 -15
View File
@@ -5,7 +5,6 @@ import (
"strings" "strings"
"github.com/1Panel-dev/1Panel/agent/buserr" "github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/cmd"
) )
@@ -100,16 +99,11 @@ func (f *Ufw) ListPort() ([]FireInfo, error) {
} }
func (f *Ufw) ListForward() ([]FireInfo, error) { func (f *Ufw) ListForward() ([]FireInfo, error) {
_ = f.EnableForward()
iptables, err := NewIptables() iptables, err := NewIptables()
if err != nil { if err != nil {
return nil, err return nil, err
} }
panelChian, _ := cmd.RunDefaultWithStdoutBashCf("%s iptables -t nat -L -n | grep 'Chain 1PANEL'", iptables.CmdStr)
if len(strings.ReplaceAll(panelChian, "\n", "")) == 0 {
if err := f.EnableForward(); err != nil {
global.LOG.Errorf("init port forward failed, err: %v", err)
}
}
rules, err := iptables.NatList() rules, err := iptables.NatList()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -304,21 +298,33 @@ func (f *Ufw) EnableForward() error {
if err != nil { if err != nil {
return err return err
} }
_ = iptables.NatNewChain() if err = iptables.Check(); err != nil {
return err
}
_ = iptables.NewChain(NatTab, PreRoutingChain)
_ = iptables.NewChain(NatTab, PostRoutingChain)
_ = iptables.NewChain(FilterTab, ForwardChain)
if err = f.enableChain(iptables); err != nil {
return err
}
return iptables.Reload()
}
func (f *Ufw) enableChain(iptables *Iptables) error {
rules, err := iptables.NatList("PREROUTING") rules, err := iptables.NatList("PREROUTING")
if err != nil { if err != nil {
return err return err
} }
for _, rule := range rules { for _, rule := range rules {
if rule.Target == NatChain { if rule.Target == PreRoutingChain {
goto reload return nil
} }
} }
if err = iptables.NatAppendChain(); err != nil { _ = iptables.AppendChain(NatTab, "PREROUTING", PreRoutingChain)
return err _ = iptables.AppendChain(NatTab, "POSTROUTING", PostRoutingChain)
} _ = iptables.AppendChain(FilterTab, "FORWARD", ForwardChain)
reload: return nil
return iptables.Reload()
} }
+1 -1
View File
@@ -33,7 +33,7 @@ func NewPostgresqlClient(conn client.DBInfo) (PostgresqlClient, error) {
} }
escapedUsername := url.QueryEscape(conn.Username) escapedUsername := url.QueryEscape(conn.Username)
escapedPassword := url.QueryEscape(conn.Password) escapedPassword := url.QueryEscape(conn.Password)
connArgs := fmt.Sprintf("postgres://%s:%s@%s:%d/?sslmode=disable", escapedUsername, escapedPassword, conn.Address, conn.Port) connArgs := fmt.Sprintf("postgres://%s:%s@%s:%d/postgres?sslmode=disable", escapedUsername, escapedPassword, conn.Address, conn.Port)
db, err := sql.Open("pgx", connArgs) db, err := sql.Open("pgx", connArgs)
if err != nil { if err != nil {
return nil, err return nil, err
+144 -123
View File
@@ -4,10 +4,12 @@ import (
"encoding/json" "encoding/json"
"github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/providers/dns/alidns" "github.com/go-acme/lego/v4/providers/dns/alidns"
"github.com/go-acme/lego/v4/providers/dns/baiducloud"
"github.com/go-acme/lego/v4/providers/dns/clouddns" "github.com/go-acme/lego/v4/providers/dns/clouddns"
"github.com/go-acme/lego/v4/providers/dns/cloudflare" "github.com/go-acme/lego/v4/providers/dns/cloudflare"
"github.com/go-acme/lego/v4/providers/dns/cloudns" "github.com/go-acme/lego/v4/providers/dns/cloudns"
"github.com/go-acme/lego/v4/providers/dns/dnspod" "github.com/go-acme/lego/v4/providers/dns/dnspod"
"github.com/go-acme/lego/v4/providers/dns/dynu"
"github.com/go-acme/lego/v4/providers/dns/freemyip" "github.com/go-acme/lego/v4/providers/dns/freemyip"
"github.com/go-acme/lego/v4/providers/dns/godaddy" "github.com/go-acme/lego/v4/providers/dns/godaddy"
"github.com/go-acme/lego/v4/providers/dns/huaweicloud" "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
@@ -45,6 +47,8 @@ const (
WestCN DnsType = "WestCN" WestCN DnsType = "WestCN"
ClouDNS DnsType = "ClouDNS" ClouDNS DnsType = "ClouDNS"
RegRu DnsType = "RegRu" RegRu DnsType = "RegRu"
Dynu DnsType = "Dynu"
BaiduCloud DnsType = "BaiduCloud"
) )
type DNSParam struct { type DNSParam struct {
@@ -85,146 +89,163 @@ func getDNSProviderConfig(dnsType DnsType, params string) (challenge.Provider, e
} }
switch dnsType { switch dnsType {
case DnsPod: case DnsPod:
dnsPodConfig := dnspod.NewDefaultConfig() config := dnspod.NewDefaultConfig()
dnsPodConfig.LoginToken = param.ID + "," + param.Token config.LoginToken = param.ID + "," + param.Token
dnsPodConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
dnsPodConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
dnsPodConfig.TTL = ttl config.TTL = ttl
p, err = dnspod.NewDNSProviderConfig(dnsPodConfig) p, err = dnspod.NewDNSProviderConfig(config)
case AliYun: case AliYun:
alidnsConfig := alidns.NewDefaultConfig() config := alidns.NewDefaultConfig()
alidnsConfig.SecretKey = param.SecretKey config.SecretKey = param.SecretKey
alidnsConfig.APIKey = param.AccessKey config.APIKey = param.AccessKey
alidnsConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
alidnsConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
alidnsConfig.TTL = ttl config.TTL = ttl
p, err = alidns.NewDNSProviderConfig(alidnsConfig) p, err = alidns.NewDNSProviderConfig(config)
case CloudFlare: case CloudFlare:
cloudflareConfig := cloudflare.NewDefaultConfig() config := cloudflare.NewDefaultConfig()
cloudflareConfig.AuthEmail = param.Email config.AuthEmail = param.Email
cloudflareConfig.AuthToken = param.APIkey config.AuthToken = param.APIkey
cloudflareConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
cloudflareConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
cloudflareConfig.TTL = ttl config.TTL = ttl
p, err = cloudflare.NewDNSProviderConfig(cloudflareConfig) p, err = cloudflare.NewDNSProviderConfig(config)
case CloudDns: case CloudDns:
clouddnsConfig := clouddns.NewDefaultConfig() config := clouddns.NewDefaultConfig()
clouddnsConfig.ClientID = param.ClientID config.ClientID = param.ClientID
clouddnsConfig.Email = param.Email config.Email = param.Email
clouddnsConfig.Password = param.Password config.Password = param.Password
clouddnsConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
clouddnsConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
clouddnsConfig.TTL = ttl config.TTL = ttl
p, err = clouddns.NewDNSProviderConfig(clouddnsConfig) p, err = clouddns.NewDNSProviderConfig(config)
case NameCheap: case NameCheap:
namecheapConfig := namecheap.NewDefaultConfig() config := namecheap.NewDefaultConfig()
namecheapConfig.APIKey = param.APIkey config.APIKey = param.APIkey
namecheapConfig.APIUser = param.APIUser config.APIUser = param.APIUser
namecheapConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
namecheapConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
namecheapConfig.TTL = ttl config.TTL = ttl
p, err = namecheap.NewDNSProviderConfig(namecheapConfig) p, err = namecheap.NewDNSProviderConfig(config)
case NameSilo: case NameSilo:
nameSiloConfig := namesilo.NewDefaultConfig() config := namesilo.NewDefaultConfig()
nameSiloConfig.APIKey = param.APIkey config.APIKey = param.APIkey
nameSiloConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
nameSiloConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
nameSiloConfig.TTL = ttl config.TTL = ttl
p, err = namesilo.NewDNSProviderConfig(nameSiloConfig) p, err = namesilo.NewDNSProviderConfig(config)
case Godaddy: case Godaddy:
godaddyConfig := godaddy.NewDefaultConfig() config := godaddy.NewDefaultConfig()
godaddyConfig.APIKey = param.APIkey config.APIKey = param.APIkey
godaddyConfig.APISecret = param.APISecret config.APISecret = param.APISecret
godaddyConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
godaddyConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
godaddyConfig.TTL = ttl config.TTL = ttl
p, err = godaddy.NewDNSProviderConfig(godaddyConfig) p, err = godaddy.NewDNSProviderConfig(config)
case NameCom: case NameCom:
nameComConfig := namedotcom.NewDefaultConfig() config := namedotcom.NewDefaultConfig()
nameComConfig.APIToken = param.Token config.APIToken = param.Token
nameComConfig.Username = param.APIUser config.Username = param.APIUser
nameComConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
nameComConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
nameComConfig.TTL = ttl config.TTL = ttl
p, err = namedotcom.NewDNSProviderConfig(nameComConfig) p, err = namedotcom.NewDNSProviderConfig(config)
case TencentCloud: case TencentCloud:
tencentCloudConfig := tencentcloud.NewDefaultConfig() config := tencentcloud.NewDefaultConfig()
tencentCloudConfig.SecretID = param.SecretID config.SecretID = param.SecretID
tencentCloudConfig.SecretKey = param.SecretKey config.SecretKey = param.SecretKey
tencentCloudConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
tencentCloudConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
tencentCloudConfig.TTL = ttl config.TTL = ttl
p, err = tencentcloud.NewDNSProviderConfig(tencentCloudConfig) p, err = tencentcloud.NewDNSProviderConfig(config)
case RainYun: case RainYun:
rainyunConfig := rainyun.NewDefaultConfig() config := rainyun.NewDefaultConfig()
rainyunConfig.APIKey = param.APIkey config.APIKey = param.APIkey
rainyunConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
rainyunConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
rainyunConfig.TTL = ttl config.TTL = ttl
p, err = rainyun.NewDNSProviderConfig(rainyunConfig) p, err = rainyun.NewDNSProviderConfig(config)
case Volcengine: case Volcengine:
volcConfig := volcengine.NewDefaultConfig() config := volcengine.NewDefaultConfig()
volcConfig.SecretKey = param.SecretKey config.SecretKey = param.SecretKey
volcConfig.AccessKey = param.AccessKey config.AccessKey = param.AccessKey
volcConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
volcConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
volcConfig.TTL = ttl config.TTL = ttl
p, err = volcengine.NewDNSProviderConfig(volcConfig) p, err = volcengine.NewDNSProviderConfig(config)
case HuaweiCloud: case HuaweiCloud:
huaweiCloudConfig := huaweicloud.NewDefaultConfig() config := huaweicloud.NewDefaultConfig()
huaweiCloudConfig.AccessKeyID = param.AccessKey config.AccessKeyID = param.AccessKey
huaweiCloudConfig.SecretAccessKey = param.SecretKey config.SecretAccessKey = param.SecretKey
huaweiCloudConfig.Region = param.Region config.Region = param.Region
huaweiCloudConfig.PropagationTimeout = propagationTimeout if config.Region == "" {
huaweiCloudConfig.PollingInterval = pollingInterval config.Region = "cn-north-1"
huaweiCloudConfig.TTL = int32(ttl) }
p, err = huaweicloud.NewDNSProviderConfig(huaweiCloudConfig) config.PropagationTimeout = propagationTimeout
config.PollingInterval = pollingInterval
config.TTL = int32(ttl)
p, err = huaweicloud.NewDNSProviderConfig(config)
case FreeMyIP: case FreeMyIP:
freeMyIpConfig := freemyip.NewDefaultConfig() config := freemyip.NewDefaultConfig()
freeMyIpConfig.Token = param.Token config.Token = param.Token
freeMyIpConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
freeMyIpConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
p, err = freemyip.NewDNSProviderConfig(freeMyIpConfig) p, err = freemyip.NewDNSProviderConfig(config)
case Vercel: case Vercel:
vercelConfig := vercel.NewDefaultConfig() config := vercel.NewDefaultConfig()
vercelConfig.AuthToken = param.Token config.AuthToken = param.Token
vercelConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
vercelConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
p, err = vercel.NewDNSProviderConfig(vercelConfig) p, err = vercel.NewDNSProviderConfig(config)
case Spaceship: case Spaceship:
spaceshipConfig := spaceship.NewDefaultConfig() config := spaceship.NewDefaultConfig()
spaceshipConfig.APIKey = param.APIkey config.APIKey = param.APIkey
spaceshipConfig.APISecret = param.APISecret config.APISecret = param.APISecret
spaceshipConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
spaceshipConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
spaceshipConfig.TTL = ttl config.TTL = ttl
p, err = spaceship.NewDNSProviderConfig(spaceshipConfig) p, err = spaceship.NewDNSProviderConfig(config)
case WestCN: case WestCN:
westcnConfig := westcn.NewDefaultConfig() config := westcn.NewDefaultConfig()
westcnConfig.Username = param.Username config.Username = param.Username
westcnConfig.Password = param.Password config.Password = param.Password
westcnConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
westcnConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
westcnConfig.TTL = ttl config.TTL = ttl
p, err = westcn.NewDNSProviderConfig(westcnConfig) p, err = westcn.NewDNSProviderConfig(config)
case ClouDNS: case ClouDNS:
cloudnsConfig := cloudns.NewDefaultConfig() config := cloudns.NewDefaultConfig()
cloudnsConfig.AuthID = param.AuthID config.AuthID = param.AuthID
cloudnsConfig.SubAuthID = param.SubAuthID config.SubAuthID = param.SubAuthID
cloudnsConfig.AuthPassword = param.AuthPassword config.AuthPassword = param.AuthPassword
cloudnsConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
cloudnsConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
cloudnsConfig.TTL = ttl config.TTL = ttl
p, err = cloudns.NewDNSProviderConfig(cloudnsConfig) p, err = cloudns.NewDNSProviderConfig(config)
case RegRu: case RegRu:
regRuConfig := regru.NewDefaultConfig() config := regru.NewDefaultConfig()
regRuConfig.Username = param.Username config.Username = param.Username
regRuConfig.Password = param.Password config.Password = param.Password
regRuConfig.PropagationTimeout = propagationTimeout config.PropagationTimeout = propagationTimeout
regRuConfig.PollingInterval = pollingInterval config.PollingInterval = pollingInterval
regRuConfig.TTL = ttl config.TTL = ttl
p, err = regru.NewDNSProviderConfig(regRuConfig) p, err = regru.NewDNSProviderConfig(config)
case Dynu:
config := dynu.NewDefaultConfig()
config.APIKey = param.APIkey
config.PropagationTimeout = propagationTimeout
config.PollingInterval = pollingInterval
config.TTL = ttl
p, err = dynu.NewDNSProviderConfig(config)
case BaiduCloud:
config := baiducloud.NewDefaultConfig()
config.AccessKeyID = param.AccessKey
config.SecretAccessKey = param.SecretKey
config.PropagationTimeout = propagationTimeout
config.PollingInterval = pollingInterval
config.TTL = ttl
p, err = baiducloud.NewDNSProviderConfig(config)
} }
if err != nil { if err != nil {
+64 -12
View File
@@ -1,6 +1,7 @@
package systemctl package systemctl
import ( import (
"bytes"
"fmt" "fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"os/exec" "os/exec"
@@ -16,31 +17,65 @@ func RunSystemCtl(args ...string) (string, error) {
return string(output), nil return string(output), nil
} }
func isSnapService(serviceName string) bool {
cmd := exec.Command("snap", "services")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return false
}
return strings.Contains(out.String(), serviceName)
}
func isSnapServiceActive(serviceName string) bool {
cmd := exec.Command("snap", "services")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return false
}
lines := strings.Split(out.String(), "\n")
for _, line := range lines {
if strings.Contains(line, serviceName) && strings.Contains(line, "active") {
return true
}
}
return false
}
func IsActive(serviceName string) (bool, error) { func IsActive(serviceName string) (bool, error) {
out, err := RunSystemCtl("is-active", serviceName) out, err := RunSystemCtl("is-active", serviceName)
if err != nil { if err == nil {
return false, err return strings.TrimSpace(out) == "active", nil
} }
return out == "active\n", nil
if isSnapServiceActive(serviceName) {
return true, nil
}
return false, fmt.Errorf("service %s is not active: %v", serviceName, err)
} }
func IsEnable(serviceName string) (bool, error) { func IsEnable(serviceName string) (bool, error) {
out, err := RunSystemCtl("is-enabled", serviceName) out, err := RunSystemCtl("is-enabled", serviceName)
if err != nil { if err == nil {
return false, err return strings.TrimSpace(out) == "enabled", nil
} }
return out == "enabled\n", nil
if isSnapServiceActive(serviceName) {
return true, nil
}
return false, fmt.Errorf("failed to determine if service %s is enabled: %v", serviceName, err)
} }
func IsExist(serviceName string) (bool, error) { func IsExist(serviceName string) (bool, error) {
out, err := RunSystemCtl("is-enabled", serviceName) out, err := RunSystemCtl("is-enabled", serviceName)
if err != nil { if err == nil || strings.Contains(out, "disabled") {
if strings.Contains(out, "disabled") { return true, nil
return true, nil
}
return false, nil
} }
return true, nil if isSnapService(serviceName) {
return true, nil
}
return false, nil
} }
func handlerErr(out string, err error) error { func handlerErr(out string, err error) error {
@@ -55,10 +90,27 @@ func handlerErr(out string, err error) error {
func Restart(serviceName string) error { func Restart(serviceName string) error {
out, err := RunSystemCtl("restart", serviceName) out, err := RunSystemCtl("restart", serviceName)
if err == nil {
return nil
}
if isSnapService(serviceName) {
cmd := exec.Command("snap", "restart", serviceName)
output, snapErr := cmd.CombinedOutput()
return handlerErr(string(output), snapErr)
}
return handlerErr(out, err) return handlerErr(out, err)
} }
func Operate(operate, serviceName string) error { func Operate(operate, serviceName string) error {
out, err := RunSystemCtl(operate, serviceName) out, err := RunSystemCtl(operate, serviceName)
if err == nil {
return nil
}
if isSnapService(serviceName) && (operate == "start" || operate == "stop" || operate == "restart") {
cmd := exec.Command("snap", operate, serviceName)
output, snapErr := cmd.CombinedOutput()
return handlerErr(string(output), snapErr)
}
return handlerErr(out, err) return handlerErr(out, err)
} }
+10 -1
View File
@@ -6,6 +6,7 @@ import (
"github.com/1Panel-dev/1Panel/core/app/dto" "github.com/1Panel-dev/1Panel/core/app/dto"
"github.com/1Panel-dev/1Panel/core/app/model" "github.com/1Panel-dev/1Panel/core/app/model"
"github.com/1Panel-dev/1Panel/core/constant" "github.com/1Panel-dev/1Panel/core/constant"
"github.com/1Panel-dev/1Panel/core/global"
"github.com/1Panel-dev/1Panel/core/utils/captcha" "github.com/1Panel-dev/1Panel/core/utils/captcha"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@@ -133,7 +134,15 @@ func (b *BaseApi) GetLoginSetting(c *gin.Context) {
helper.InternalServer(c, err) helper.InternalServer(c, err)
return return
} }
helper.SuccessWithData(c, settingInfo) res := &dto.LoginSetting{
IsDemo: global.CONF.Base.IsDemo,
IsIntl: global.CONF.Base.IsIntl,
Language: settingInfo.Language,
MenuTabs: settingInfo.MenuTabs,
PanelName: settingInfo.PanelName,
Theme: settingInfo.Theme,
}
helper.SuccessWithData(c, res)
} }
func saveLoginLogs(c *gin.Context, err error) { func saveLoginLogs(c *gin.Context, err error) {
+9
View File
@@ -219,3 +219,12 @@ type AppstoreConfig struct {
UpgradeBackup string `json:"upgradeBackup"` UpgradeBackup string `json:"upgradeBackup"`
UninstallDeleteBackup string `json:"uninstallDeleteBackup"` UninstallDeleteBackup string `json:"uninstallDeleteBackup"`
} }
type LoginSetting struct {
IsDemo bool `json:"isDemo"`
IsIntl bool `json:"isIntl"`
Language string `json:"language"`
MenuTabs string `json:"menuTabs"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
}
+2 -2
View File
@@ -37,7 +37,7 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
return nil, "", buserr.New("ErrRecordNotFound") return nil, "", buserr.New("ErrRecordNotFound")
} }
if nameSetting.Value != info.Name { if nameSetting.Value != info.Name {
return nil, "ErrAuth", nil return nil, "ErrAuth", buserr.New("ErrAuth")
} }
if err = checkPassword(info.Password); err != nil { if err = checkPassword(info.Password); err != nil {
return nil, "ErrAuth", err return nil, "ErrAuth", err
@@ -47,7 +47,7 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
return nil, "", err return nil, "", err
} }
if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance { if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance {
return nil, "ErrEntrance", nil return nil, "ErrEntrance", buserr.New("ErrEntrance")
} }
mfa, err := settingRepo.Get(repo.WithByKey("MFAStatus")) mfa, err := settingRepo.Get(repo.WithByKey("MFAStatus"))
if err != nil { if err != nil {
+9 -1
View File
@@ -284,7 +284,15 @@ func (u *BackupService) RefreshToken(req dto.OperateByName) error {
varsItem, _ := json.Marshal(varMap) varsItem, _ := json.Marshal(varMap)
backup.Vars = string(varsItem) backup.Vars = string(varsItem)
return backupRepo.Save(&backup) if err := backupRepo.Save(&backup); err != nil {
return err
}
go func() {
if err := xpack.Sync(constant.SyncBackupAccounts); err != nil {
global.LOG.Errorf("sync backup account to node failed, err: %v", err)
}
}()
return nil
} }
func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) { func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) {
-1
View File
@@ -11,7 +11,6 @@ var (
groupRepo = repo.NewIGroupRepo() groupRepo = repo.NewIGroupRepo()
upgradeLogRepo = repo.NewIUpgradeLogRepo() upgradeLogRepo = repo.NewIUpgradeLogRepo()
taskRepo = repo.NewITaskRepo()
agentRepo = repo.NewIAgentRepo() agentRepo = repo.NewIAgentRepo()
scriptRepo = repo.NewIScriptRepo() scriptRepo = repo.NewIScriptRepo()
) )
+11 -8
View File
@@ -188,34 +188,37 @@ func (u *ScriptService) Sync(req dto.OperateByTaskID) error {
} }
var scriptSetting model.Setting var scriptSetting model.Setting
_ = global.DB.Where("key = ?", "ScriptVersion").First(&scriptSetting).Error _ = global.DB.Where("key = ?", "ScriptVersion").First(&scriptSetting).Error
if scriptSetting.Value == string(versionRes) { localVersion := strings.ReplaceAll(string(versionRes), "\n", "")
syncTask.Logf("The local-%s and remote-%s versions are detected to be consistent. Skip...", scriptSetting.Value, versionRes) remoteVersion := strings.ReplaceAll(scriptSetting.Value, "\n", "")
if localVersion == remoteVersion {
syncTask.Log(i18n.GetMsgByKey("ScriptSyncSkip"))
return nil return nil
} }
syncTask.Log("start to download data.yaml")
dataUrl := fmt.Sprintf("%s/scripts/data.yaml", global.CONF.RemoteURL.ResourceURL) dataUrl := fmt.Sprintf("%s/scripts/data.yaml", global.CONF.RemoteURL.ResourceURL)
_, dataRes, err := req_helper.HandleRequestWithProxy(dataUrl, http.MethodGet, constant.TimeOut20s) _, dataRes, err := req_helper.HandleRequestWithProxy(dataUrl, http.MethodGet, constant.TimeOut20s)
syncTask.LogWithStatus(i18n.GetMsgByKey("DownloadData"), err)
if err != nil { if err != nil {
return fmt.Errorf("load scripts data.yaml from remote failed, err: %v", err) return fmt.Errorf("load scripts data.yaml from remote failed, err: %v", err)
} }
syncTask.Log("download successful!")
var scripts Scripts var scripts Scripts
if err = yaml.Unmarshal(dataRes, &scripts); err != nil { if err = yaml.Unmarshal(dataRes, &scripts); err != nil {
return fmt.Errorf("the format of data.yaml is err: %v", err) return fmt.Errorf("the format of data.yaml is err: %v", err)
} }
syncTask.Log("start to download scripts.tar.gz")
tmpDir := path.Join(global.CONF.Base.InstallDir, "1panel/tmp/script") tmpDir := path.Join(global.CONF.Base.InstallDir, "1panel/tmp/script")
if _, err := os.Stat(tmpDir); err != nil { if _, err := os.Stat(tmpDir); err != nil {
_ = os.MkdirAll(tmpDir, 0755) _ = os.MkdirAll(tmpDir, 0755)
} }
scriptsUrl := fmt.Sprintf("%s/scripts/scripts.tar.gz", global.CONF.RemoteURL.ResourceURL) scriptsUrl := fmt.Sprintf("%s/scripts/scripts.tar.gz", global.CONF.RemoteURL.ResourceURL)
if err := files.DownloadFileWithProxy(scriptsUrl, tmpDir+"/scripts.tar.gz"); err != nil { err = files.DownloadFileWithProxy(scriptsUrl, tmpDir+"/scripts.tar.gz")
syncTask.LogWithStatus(i18n.GetMsgByKey("DownloadPackage"), err)
if err != nil {
return fmt.Errorf("download scripts.tar.gz failed, err: %v", err) return fmt.Errorf("download scripts.tar.gz failed, err: %v", err)
} }
syncTask.Log("download successful! now start to decompress...")
if err := files.HandleUnTar(tmpDir+"/scripts.tar.gz", tmpDir, ""); err != nil { if err := files.HandleUnTar(tmpDir+"/scripts.tar.gz", tmpDir, ""); err != nil {
return fmt.Errorf("handle decompress scripts.tar.gz failed, err: %v", err) return fmt.Errorf("handle decompress scripts.tar.gz failed, err: %v", err)
} }
@@ -234,7 +237,7 @@ func (u *ScriptService) Sync(req dto.OperateByTaskID) error {
scriptsForDB = append(scriptsForDB, scriptItem) scriptsForDB = append(scriptsForDB, scriptItem)
} }
syncTask.Log("analytic completion! now start to refresh database...") syncTask.Log(i18n.GetMsgByKey("AnalyticCompletion"))
if err := scriptRepo.SyncAll(scriptsForDB); err != nil { if err := scriptRepo.SyncAll(scriptsForDB); err != nil {
return fmt.Errorf("sync script with db failed, err: %v", err) return fmt.Errorf("sync script with db failed, err: %v", err)
} }
+169
View File
@@ -0,0 +1,169 @@
package cmd
import (
"fmt"
"os"
"runtime"
"runtime/pprof"
"time"
"github.com/spf13/cobra"
)
var (
cpuProfile string
memProfile string
duration time.Duration
showMemStats bool
showGoroutine bool
)
func init() {
RootCmd.AddCommand(debugCmd)
debugCmd.Flags().StringVar(&cpuProfile, "cpuprofile", "", "write cpu profile to file")
debugCmd.Flags().StringVar(&memProfile, "memprofile", "", "write memory profile to file")
debugCmd.Flags().DurationVar(&duration, "duration", 30*time.Second, "duration for cpu profiling")
debugCmd.Flags().BoolVar(&showMemStats, "memstats", false, "show memory statistics")
debugCmd.Flags().BoolVar(&showGoroutine, "goroutine", false, "show goroutine profile")
}
var debugCmd = &cobra.Command{
Use: "debug",
Short: "Performance debugging with pprof",
Long: `Debug command provides CPU and memory profiling capabilities using pprof.
Examples:
# CPU profiling for 30 seconds
1panel-core debug --cpuprofile=cpu.prof --duration=30s
# Memory profiling
1panel-core debug --memprofile=mem.prof
# Show memory statistics
1panel-core debug --memstats
# Show goroutine information
1panel-core debug --goroutine
# Combined profiling
1panel-core debug --cpuprofile=cpu.prof --memprofile=mem.prof --memstats`,
RunE: func(cmd *cobra.Command, args []string) error {
if cpuProfile != "" {
if err := startCPUProfile(cpuProfile); err != nil {
return fmt.Errorf("failed to start CPU profile: %v", err)
}
defer stopCPUProfile()
time.Sleep(duration)
fmt.Printf("CPU profile saved to: %s\n", cpuProfile)
}
if memProfile != "" {
if err := writeMemProfile(memProfile); err != nil {
return fmt.Errorf("failed to write memory profile: %v", err)
}
fmt.Printf("Memory profile saved to: %s\n", memProfile)
}
if showMemStats {
printMemStats()
}
if showGoroutine {
printGoroutineInfo()
}
if cpuProfile == "" && memProfile == "" && !showMemStats && !showGoroutine {
printBasicInfo()
}
return nil
},
}
func startCPUProfile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
if err := pprof.StartCPUProfile(f); err != nil {
f.Close()
return err
}
return nil
}
func stopCPUProfile() {
pprof.StopCPUProfile()
}
func writeMemProfile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
runtime.GC()
if err := pprof.WriteHeapProfile(f); err != nil {
return err
}
return nil
}
func printMemStats() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Println("\n=== Memory Statistics ===")
fmt.Printf("Allocated memory: %d KB (%d MB)\n", m.Alloc/1024, m.Alloc/1024/1024)
fmt.Printf("Total allocated: %d KB (%d MB)\n", m.TotalAlloc/1024, m.TotalAlloc/1024/1024)
fmt.Printf("System memory: %d KB (%d MB)\n", m.Sys/1024, m.Sys/1024/1024)
fmt.Printf("Heap allocated: %d KB (%d MB)\n", m.HeapAlloc/1024, m.HeapAlloc/1024/1024)
fmt.Printf("Heap system: %d KB (%d MB)\n", m.HeapSys/1024, m.HeapSys/1024/1024)
fmt.Printf("Heap idle: %d KB (%d MB)\n", m.HeapIdle/1024, m.HeapIdle/1024/1024)
fmt.Printf("Heap in use: %d KB (%d MB)\n", m.HeapInuse/1024, m.HeapInuse/1024/1024)
fmt.Printf("Heap released: %d KB (%d MB)\n", m.HeapReleased/1024, m.HeapReleased/1024/1024)
fmt.Printf("Heap objects: %d\n", m.HeapObjects)
fmt.Printf("GC runs: %d\n", m.NumGC)
fmt.Printf("GC pause total: %d ns\n", m.PauseTotalNs)
fmt.Printf("Next GC: %d KB (%d MB)\n", m.NextGC/1024, m.NextGC/1024/1024)
fmt.Printf("Last GC: %s\n", time.Unix(0, int64(m.LastGC)).Format("2006-01-02 15:04:05"))
}
func printGoroutineInfo() {
fmt.Println("\n=== Goroutine Information ===")
fmt.Printf("Number of goroutines: %d\n", runtime.NumGoroutine())
fmt.Printf("Number of CPUs: %d\n", runtime.NumCPU())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
buf := make([]byte, 1024*1024)
stackSize := runtime.Stack(buf, true)
fmt.Printf("\nGoroutine stack trace (first 2048 bytes):\n")
if stackSize > 2048 {
fmt.Printf("%s...\n", buf[:2048])
fmt.Printf("(truncated, total size: %d bytes)\n", stackSize)
} else {
fmt.Printf("%s\n", buf[:stackSize])
}
}
func printBasicInfo() {
fmt.Println("=== Performance Debug Info ===")
fmt.Printf("Go version: %s\n", runtime.Version())
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
fmt.Printf("CPUs: %d\n", runtime.NumCPU())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine())
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Memory allocated: %d KB\n", m.Alloc/1024)
fmt.Printf("Total allocations: %d KB\n", m.TotalAlloc/1024)
fmt.Printf("GC runs: %d\n", m.NumGC)
fmt.Println("\nUse --help to see available profiling options.")
}
+1 -1
View File
@@ -209,7 +209,7 @@ func port() {
fmt.Println("\n" + i18n.GetMsgByKeyForCmd("UpdateSuccessful")) fmt.Println("\n" + i18n.GetMsgByKeyForCmd("UpdateSuccessful"))
fmt.Println(i18n.GetMsgWithMapForCmd("UpdatePortResult", map[string]interface{}{"name": newPortStr})) fmt.Println(i18n.GetMsgWithMapForCmd("UpdatePortResult", map[string]interface{}{"name": newPortStr}))
std, err := cmd.RunDefaultWithStdoutBashC("1pctl restart") std, err := cmd.RunDefaultWithStdoutBashC("1pctl restart core")
if err != nil { if err != nil {
fmt.Println(std) fmt.Println(std)
} }
+1 -1
View File
@@ -32,7 +32,7 @@ const (
GoogleDrive = "GoogleDrive" GoogleDrive = "GoogleDrive"
OneDriveRedirectURI = "http://localhost/login/authorized" OneDriveRedirectURI = "http://localhost/login/authorized"
GoogleRedirectURI = "http://localhost:8080" GoogleRedirectURI = "https://localhost:8080"
DaemonJsonPath = "/etc/docker/daemon.json" DaemonJsonPath = "/etc/docker/daemon.json"
) )
+1
View File
@@ -23,6 +23,7 @@ require (
github.com/mojocn/base64Captcha v1.3.6 github.com/mojocn/base64Captcha v1.3.6
github.com/nicksnyder/go-i18n/v2 v2.4.0 github.com/nicksnyder/go-i18n/v2 v2.4.0
github.com/oschwald/maxminddb-golang v1.13.1 github.com/oschwald/maxminddb-golang v1.13.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.6 github.com/pkg/sftp v1.13.6
github.com/qiniu/go-sdk/v7 v7.21.1 github.com/qiniu/go-sdk/v7 v7.21.1
+2
View File
@@ -362,6 +362,8 @@ github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7g
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE= github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8= github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+4
View File
@@ -93,6 +93,10 @@ SubTask: "Subtask"
#script #script
ScriptLibrary: "Script Library" ScriptLibrary: "Script Library"
ScriptSyncSkip: "Current script library is already the latest version!"
DownloadData: "Downloading script library file data.yaml"
DownloadPackage: "Downloading script library package"
AnalyticCompletion: "Analysis completed, now syncing to database..."
Node: "Node" Node: "Node"
SyncNode: "Sync node data" SyncNode: "Sync node data"
+4
View File
@@ -94,6 +94,10 @@ SubTask: "サブタスク"
#script #script
ScriptLibrary: "スクリプトライブラリ" ScriptLibrary: "スクリプトライブラリ"
ScriptSyncSkip: "現在のスクリプトライブラリは最新バージョンです!"
DownloadData: "スクリプトライブラリファイル data.yaml をダウンロード中"
DownloadPackage: "スクリプトライブラリパッケージをダウンロード中"
AnalyticCompletion: "解析が完了しました、データベースに同期しています..."
Node: "ノード" Node: "ノード"
SyncNode: "ノードデータ同期" SyncNode: "ノードデータ同期"
+4
View File
@@ -93,6 +93,10 @@ SubTask: "서브 작업"
#script #script
ScriptLibrary: "스크립트 라이브러리" ScriptLibrary: "스크립트 라이브러리"
ScriptSyncSkip: "현재 스크립트 라이브러리가 이미 최신 버전입니다!"
DownloadData: "스크립트 라이브러리 파일 data.yaml 다운로드 중"
DownloadPackage: "스크립트 라이브러리 패키지 다운로드 중"
AnalyticCompletion: "분석 완료, 데이터베이스에 동기화 중..."
Node: "노드" Node: "노드"
SyncNode: "노드 데이터 동기화" SyncNode: "노드 데이터 동기화"
+4
View File
@@ -93,6 +93,10 @@ SubTask: "Tugas Sub"
#script #script
ScriptLibrary: "Pustaka Skrip" ScriptLibrary: "Pustaka Skrip"
ScriptSyncSkip: "Pustaka skrip semasa sudah versi terkini!"
DownloadData: "Muat turun fail pustaka skrip data.yaml"
DownloadPackage: "Muat turun pakej pustaka skrip"
AnalyticCompletion: "Analisis selesai, sedang menyegerakkan ke pangkalan data..."
Node: "Nod" Node: "Nod"
SyncNode: "Segerakkan data nod" SyncNode: "Segerakkan data nod"
+4
View File
@@ -93,6 +93,10 @@ SubTask: "Subtarefa"
#script #script
ScriptLibrary: "Biblioteca de Scripts" ScriptLibrary: "Biblioteca de Scripts"
ScriptSyncSkip: "A biblioteca de scripts atual já é a versão mais recente!"
DownloadData: "Baixando arquivo data.yaml da biblioteca de scripts"
DownloadPackage: "Baixando pacote da biblioteca de scripts"
AnalyticCompletion: "Análise concluída, agora sincronizando com o banco de dados..."
Node: "Nó" Node: "Nó"
SyncNode: "Sincronizar dados do nó" SyncNode: "Sincronizar dados do nó"
+4
View File
@@ -93,6 +93,10 @@ SubTask: "Подзадача"
#script #script
ScriptLibrary: "Библиотека скриптов" ScriptLibrary: "Библиотека скриптов"
ScriptSyncSkip: "Текущая библиотека скриптов уже является последней версией!"
DownloadData: "Загрузка файла библиотеки скриптов data.yaml"
DownloadPackage: "Загрузка архива библиотеки скриптов"
AnalyticCompletion: "Анализ завершён, начинается синхронизация с базой данных..."
Node: "Узел" Node: "Узел"
SyncNode: "Синхронизация данных узла" SyncNode: "Синхронизация данных узла"
+4
View File
@@ -93,6 +93,10 @@ SubTask: "子任務"
#script #script
ScriptLibrary: "腳本庫" ScriptLibrary: "腳本庫"
ScriptSyncSkip: "當前腳本庫已是最新版本!"
DownloadData: "下載腳本庫文件 data.yaml"
DownloadPackage: "下載腳本庫壓縮包"
AnalyticCompletion: "解析成功,現在開始同步到資料庫..."
#sync node #sync node
Node: "節點" Node: "節點"
+4
View File
@@ -93,6 +93,10 @@ SubTask: "子任务"
#script #script
ScriptLibrary: "脚本库" ScriptLibrary: "脚本库"
ScriptSyncSkip: "检查到当前脚本库已是最新版本!"
DownloadData: "下载脚本库文件 data.yaml"
DownloadPackage: "下载脚本库压缩包"
AnalyticCompletion: "解析成功,现在开始同步到数据库..."
#sync node #sync node
Node: "节点" Node: "节点"
+3 -2
View File
@@ -29,17 +29,18 @@ func LoadMenus() string {
{ID: "71", Disabled: false, Title: "menu.files", IsShow: true, Label: "File", Path: "/hosts/files"}, {ID: "71", Disabled: false, Title: "menu.files", IsShow: true, Label: "File", Path: "/hosts/files"},
{ID: "72", Disabled: false, Title: "menu.monitor", IsShow: true, Label: "Monitorx", Path: "/hosts/monitor/monitor"}, {ID: "72", Disabled: false, Title: "menu.monitor", IsShow: true, Label: "Monitorx", Path: "/hosts/monitor/monitor"},
{ID: "74", Disabled: false, Title: "menu.firewall", IsShow: true, Label: "FirewallPort", Path: "/hosts/firewall/port"}, {ID: "74", Disabled: false, Title: "menu.firewall", IsShow: true, Label: "FirewallPort", Path: "/hosts/firewall/port"},
{ID: "75", Disabled: false, Title: "menu.supervisor", IsShow: true, Label: "Process", Path: "/hosts/process/process"}, {ID: "75", Disabled: false, Title: "menu.processManage", IsShow: true, Label: "Process", Path: "/hosts/process/process"},
{ID: "76", Disabled: false, Title: "menu.ssh", IsShow: true, Label: "SSH", Path: "/hosts/ssh/ssh"}, {ID: "76", Disabled: false, Title: "menu.ssh", IsShow: true, Label: "SSH", Path: "/hosts/ssh/ssh"},
}}, }},
{ID: "8", Disabled: false, Title: "menu.terminal", IsShow: true, Label: "Terminal-Menu", Path: "/hosts/terminal"}, {ID: "8", Disabled: false, Title: "menu.terminal", IsShow: true, Label: "Terminal-Menu", Path: "/hosts/terminal"},
{ID: "9", Disabled: false, Title: "menu.toolbox", IsShow: true, Label: "Toolbox-Menu", Path: "/toolbox"},
{ID: "10", Disabled: false, Title: "menu.cronjob", IsShow: true, Label: "Cronjob-Menu", Path: "/cronjobs"}, {ID: "10", Disabled: false, Title: "menu.cronjob", IsShow: true, Label: "Cronjob-Menu", Path: "/cronjobs"},
{ID: "9", Disabled: false, Title: "menu.toolbox", IsShow: true, Label: "Toolbox-Menu", Path: "/toolbox"},
{ID: "11", Disabled: false, Title: "xpack.menu", IsShow: true, Label: "Xpack-Menu", {ID: "11", Disabled: false, Title: "xpack.menu", IsShow: true, Label: "Xpack-Menu",
Children: []dto.ShowMenu{ Children: []dto.ShowMenu{
{ID: "118", Disabled: false, Title: "xpack.app.app", IsShow: true, Label: "XApp", Path: "/xpack/app"}, {ID: "118", Disabled: false, Title: "xpack.app.app", IsShow: true, Label: "XApp", Path: "/xpack/app"},
{ID: "112", Disabled: false, Title: "xpack.waf.name", IsShow: true, Label: "Dashboard", Path: "/xpack/waf/dashboard"}, {ID: "112", Disabled: false, Title: "xpack.waf.name", IsShow: true, Label: "Dashboard", Path: "/xpack/waf/dashboard"},
{ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "Node", Path: "/xpack/node"}, {ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "Node", Path: "/xpack/node"},
{ID: "119", Disabled: false, Title: "xpack.upage", IsShow: true, Label: "Upage", Path: "/xpack/upage"},
{ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard"}, {ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard"},
{ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper"}, {ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper"},
{ID: "115", Disabled: false, Title: "xpack.exchange.exchange", IsShow: true, Label: "FileExange", Path: "/xpack/exchange/file"}, {ID: "115", Disabled: false, Title: "xpack.exchange.exchange", IsShow: true, Label: "FileExange", Path: "/xpack/exchange/file"},
+2
View File
@@ -17,6 +17,8 @@ func Init() {
migrations.InitGoogle, migrations.InitGoogle,
migrations.AddTaskDB, migrations.AddTaskDB,
migrations.AddXpackHideMenu, migrations.AddXpackHideMenu,
migrations.UpdateGoogle,
migrations.UpdateXpackHideMenu,
}) })
if err := m.Migrate(); err != nil { if err := m.Migrate(); err != nil {
global.LOG.Error(err) global.LOG.Error(err)
+143 -1
View File
@@ -312,7 +312,7 @@ var AddXpackHideMenu = &gormigrate.Migration{
} }
} }
if !exists { if !exists {
menus[i].Children = append(menus[i].Children, newItem) menus[i].Children = append([]dto.ShowMenu{newItem}, menus[i].Children...)
} }
break break
} }
@@ -328,3 +328,145 @@ var AddXpackHideMenu = &gormigrate.Migration{
return tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Update("value", string(updatedJSON)).Error return tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Update("value", string(updatedJSON)).Error
}, },
} }
var UpdateXpackHideMenu = &gormigrate.Migration{
ID: "20250617-update-xpack-hide-menu",
Migrate: func(tx *gorm.DB) error {
var menuJSON string
if err := tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Pluck("value", &menuJSON).Error; err != nil {
return err
}
var menus []dto.ShowMenu
if err := json.Unmarshal([]byte(menuJSON), &menus); err != nil {
return tx.Model(&model.Setting{}).
Where("key = ?", "HideMenu").
Update("value", helper.LoadMenus()).Error
}
newItem := dto.ShowMenu{
ID: "119",
Disabled: false,
Title: "xpack.upage",
IsShow: true,
Label: "Upage",
Path: "/xpack/upage",
}
for i, menu := range menus {
if menu.ID == "11" {
exists := false
for _, child := range menu.Children {
if child.ID == newItem.ID {
exists = true
break
}
}
if exists {
break
}
insertIndex := -1
for j, child := range menu.Children {
if child.ID == "111" {
insertIndex = j
break
}
}
if insertIndex != -1 {
children := menu.Children
menus[i].Children = append(children[:insertIndex+1], append([]dto.ShowMenu{newItem}, children[insertIndex+1:]...)...)
} else {
menus[i].Children = append([]dto.ShowMenu{newItem}, menus[i].Children...)
}
break
}
}
for i, menu := range menus {
if menu.ID == "11" {
existsIndex := -1
for j, child := range menu.Children {
if child.ID == "118" {
existsIndex = j
break
}
}
if existsIndex == 0 {
break
}
var item118 dto.ShowMenu
if existsIndex != -1 {
item118 = menu.Children[existsIndex]
menus[i].Children = append(menu.Children[:existsIndex], menu.Children[existsIndex+1:]...)
} else {
item118 = dto.ShowMenu{
ID: "118",
Disabled: false,
Title: "xpack.app.app",
IsShow: true,
Label: "XApp",
Path: "/xpack/app",
}
}
menus[i].Children = append([]dto.ShowMenu{item118}, menus[i].Children...)
break
}
}
var idx9, idx10 = -1, -1
for i, menu := range menus {
if menu.ID == "9" && menu.Path == "/toolbox" {
idx9 = i
}
if menu.ID == "10" && menu.Path == "/cronjobs" {
idx10 = i
}
}
if idx9 != -1 && idx10 != -1 && idx10 > idx9 {
menus[idx9], menus[idx10] = menus[idx10], menus[idx9]
}
for i, menu := range menus {
if menu.ID == "7" {
for j, child := range menu.Children {
if child.ID == "75" {
if child.Title != "menu.processManage" {
menus[i].Children[j].Title = "menu.processManage"
}
break
}
}
break
}
}
updatedJSON, err := json.Marshal(menus)
if err != nil {
return tx.Model(&model.Setting{}).
Where("key = ?", "HideMenu").
Update("value", helper.LoadMenus()).Error
}
return tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Update("value", string(updatedJSON)).Error
},
}
var UpdateGoogle = &gormigrate.Migration{
ID: "20250616-update-google",
Migrate: func(tx *gorm.DB) error {
if err := tx.Model(&model.Setting{}).
Where("key = ?", "GoogleID").
Update("value", "NTU2NTQ3NDYwMTQtY2Q0bGR0dDk2aGNsNWcxYWtwdmJhZTFmcjJlZ2Y0MXAuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20=").Error; err != nil {
return err
}
if err := tx.Model(&model.Setting{}).
Where("key = ?", "GoogleSc").
Update("value", "R09DU1BYLXRibXg0QVdVZ3d3Ykc2QW1XTHQ3YUdaZElVeE4=").Error; err != nil {
return err
}
return nil
},
}
+10 -1
View File
@@ -17,6 +17,12 @@ var whiteUrlList = map[string]struct{}{
"/api/v2/files/size": {}, "/api/v2/files/size": {},
"/api/v2/runtimes/sync": {}, "/api/v2/runtimes/sync": {},
"/api/v2/toolbox/device/base": {}, "/api/v2/toolbox/device/base": {},
"/api/v2/files/user/group": {},
"/api/v2/files/mount": {},
"/api/v2/hosts/ssh/log": {},
"/api/v2/toolbox/clam/base": {},
"/api/v2/hosts/too": {},
"/api/v2/backups/record/size": {},
"/api/v2/core/auth/login": {}, "/api/v2/core/auth/login": {},
"/api/v2/core/logs/login": {}, "/api/v2/core/logs/login": {},
@@ -43,11 +49,14 @@ var whiteUrlList = map[string]struct{}{
"/api/v2/xpack/monitor/websites": {}, "/api/v2/xpack/monitor/websites": {},
"/api/v2/xpack/monitor/trend": {}, "/api/v2/xpack/monitor/trend": {},
"/api/v2/xpack/monitor/rank": {}, "/api/v2/xpack/monitor/rank": {},
"/api/v2/xpack/waf/cdn": {},
"/api/v2/core/nodes/list": {},
} }
func DemoHandle() gin.HandlerFunc { func DemoHandle() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
if strings.Contains(c.Request.URL.Path, "search") || c.Request.Method == http.MethodGet { if strings.Contains(c.Request.URL.Path, "search") || (c.Request.Method == http.MethodGet && c.Request.URL.Path != "/api/v2/containers/exec") {
c.Next() c.Next()
return return
} }
+31 -1
View File
@@ -20,9 +20,10 @@ type aliClient struct {
} }
func NewALIClient(vars map[string]interface{}) (*aliClient, error) { func NewALIClient(vars map[string]interface{}) (*aliClient, error) {
refresh_token := loadParamFromVars("refresh_token", vars)
drive_id := loadParamFromVars("drive_id", vars) drive_id := loadParamFromVars("drive_id", vars)
token, err := RefreshALIToken(vars) token, err := loadToken(refresh_token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -355,6 +356,35 @@ func (a *aliClient) completeUpload(uploadID, fileID string) error {
type tokenResp struct { type tokenResp struct {
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
AccessToken string `json:"access_token"`
}
func loadToken(refresh_token string) (string, error) {
client := resty.New()
client.SetTLSClientConfig(&tls.Config{
InsecureSkipVerify: true,
})
data := map[string]interface{}{
"grant_type": "refresh_token",
"refresh_token": refresh_token,
}
url := "https://api.aliyundrive.com/token/refresh"
resp, err := client.R().
SetBody(data).
Post(url)
if err != nil {
return "", fmt.Errorf("load account token failed, err: %v", err)
}
if resp.StatusCode() != 200 {
return "", fmt.Errorf("load account token failed, code: %v", resp.StatusCode())
}
var respItem tokenResp
if err := json.Unmarshal(resp.Body(), &respItem); err != nil {
return "", err
}
return respItem.AccessToken, nil
} }
func RefreshALIToken(varMap map[string]interface{}) (string, error) { func RefreshALIToken(varMap map[string]interface{}) (string, error) {
+12 -2
View File
@@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"regexp"
cosSDK "github.com/tencentyun/cos-go-sdk-v5" cosSDK "github.com/tencentyun/cos-go-sdk-v5"
) )
@@ -18,6 +19,7 @@ type cosClient struct {
func NewCosClient(vars map[string]interface{}) (*cosClient, error) { func NewCosClient(vars map[string]interface{}) (*cosClient, error) {
region := loadParamFromVars("region", vars) region := loadParamFromVars("region", vars)
endpoint := loadParamFromVars("endpoint", vars)
accessKey := loadParamFromVars("accessKey", vars) accessKey := loadParamFromVars("accessKey", vars)
secretKey := loadParamFromVars("secretKey", vars) secretKey := loadParamFromVars("secretKey", vars)
bucket := loadParamFromVars("bucket", vars) bucket := loadParamFromVars("bucket", vars)
@@ -26,7 +28,15 @@ func NewCosClient(vars map[string]interface{}) (*cosClient, error) {
scType = "Standard" scType = "Standard"
} }
u, _ := url.Parse(fmt.Sprintf("https://cos.%s.myqcloud.com", region)) endpointType := "cos"
if len(endpoint) != 0 {
re := regexp.MustCompile(`.*cos-dualstack\..*`)
if re.MatchString(endpoint) {
endpointType = "cos-dualstack"
}
}
u, _ := url.Parse(fmt.Sprintf("https://%s.%s.myqcloud.com", endpointType, region))
b := &cosSDK.BaseURL{BucketURL: u} b := &cosSDK.BaseURL{BucketURL: u}
client := cosSDK.NewClient(b, &http.Client{ client := cosSDK.NewClient(b, &http.Client{
Transport: &cosSDK.AuthorizationTransport{ Transport: &cosSDK.AuthorizationTransport{
@@ -36,7 +46,7 @@ func NewCosClient(vars map[string]interface{}) (*cosClient, error) {
}) })
if len(bucket) != 0 { if len(bucket) != 0 {
u2, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", bucket, region)) u2, _ := url.Parse(fmt.Sprintf("https://%s.%s.%s.myqcloud.com", bucket, endpointType, region))
b2 := &cosSDK.BaseURL{BucketURL: u2} b2 := &cosSDK.BaseURL{BucketURL: u2}
clientWithBucket := cosSDK.NewClient(b2, &http.Client{ clientWithBucket := cosSDK.NewClient(b2, &http.Client{
Transport: &cosSDK.AuthorizationTransport{ Transport: &cosSDK.AuthorizationTransport{
+13
View File
@@ -66,6 +66,19 @@ func ScanPort(port int) bool {
return false return false
} }
func CheckPort(host string, port string, timeout time.Duration) bool {
target := net.JoinHostPort(host, port)
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
return false
}
return strings.Contains(err.Error(), "connection refused")
}
defer conn.Close()
return true
}
func ComparePanelVersion(version1, version2 string) bool { func ComparePanelVersion(version1, version2 string) bool {
if version1 == version2 { if version1 == version2 {
return false return false
+1 -1
View File
@@ -38,7 +38,7 @@
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"element-plus": "^2.9.7", "element-plus": "^2.9.9",
"fit2cloud-ui-plus": "^1.2.2", "fit2cloud-ui-plus": "^1.2.2",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"js-base64": "^3.7.7", "js-base64": "^3.7.7",
+3
View File
@@ -9,6 +9,9 @@ export const searchContainer = (params: Container.ContainerSearch) => {
export const listContainer = () => { export const listContainer = () => {
return http.post<Array<string>>(`/containers/list`, {}); return http.post<Array<string>>(`/containers/list`, {});
}; };
export const loadContainerUsers = (name: string) => {
return http.post<Array<string>>(`/containers/users`, { name: name });
};
export const loadContainerStatus = () => { export const loadContainerStatus = () => {
return http.get<Container.ContainerStatus>(`/containers/status`); return http.get<Container.ContainerStatus>(`/containers/status`);
}; };
+2 -2
View File
@@ -40,8 +40,8 @@ export const changeBind = (id: number, nodeIDs: Array<number>) => {
export const loadLicenseOptions = () => { export const loadLicenseOptions = () => {
return http.get<Array<Setting.LicenseOptions>>(`/core/licenses/options`); return http.get<Array<Setting.LicenseOptions>>(`/core/licenses/options`);
}; };
export const listNodeOptions = () => { export const listNodeOptions = (type: string) => {
return http.get<Array<Setting.NodeItem>>(`/core/nodes/list`); return http.post<Array<Setting.NodeItem>>(`/core/nodes/list`, { type: type });
}; };
export const listAllNodes = () => { export const listAllNodes = () => {
+1 -1
View File
@@ -25,7 +25,7 @@ export const updateDevicePasswd = (user: string, passwd: string) => {
return http.post(`/toolbox/device/update/passwd`, { user: user, passwd: Base64.encode(passwd) }, TimeoutEnum.T_60S); return http.post(`/toolbox/device/update/passwd`, { user: user, passwd: Base64.encode(passwd) }, TimeoutEnum.T_60S);
}; };
export const updateDeviceSwap = (params: Toolbox.SwapHelper) => { export const updateDeviceSwap = (params: Toolbox.SwapHelper) => {
return http.post(`/toolbox/device/update/swap`, params, TimeoutEnum.T_60S); return http.post(`/toolbox/device/update/swap`, params, TimeoutEnum.T_10M);
}; };
export const updateDeviceByConf = (name: string, file: string) => { export const updateDeviceByConf = (name: string, file: string) => {
return http.post(`/toolbox/device/update/byconf`, { name: name, file: file }, TimeoutEnum.T_5M); return http.post(`/toolbox/device/update/byconf`, { name: name, file: file }, TimeoutEnum.T_5M);
+12 -4
View File
@@ -1,9 +1,9 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 4776196 */ font-family: "iconfont"; /* Project id 4776196 */
src: url('iconfont.woff2?t=1745909790481') format('woff2'), src: url('iconfont.woff2?t=1750234328196') format('woff2'),
url('iconfont.woff?t=1745909790481') format('woff'), url('iconfont.woff?t=1750234328196') format('woff'),
url('iconfont.ttf?t=1745909790481') format('truetype'), url('iconfont.ttf?t=1750234328196') format('truetype'),
url('iconfont.svg?t=1745909790481#iconfont') format('svg'); url('iconfont.svg?t=1750234328196#iconfont') format('svg');
} }
.iconfont { .iconfont {
@@ -14,6 +14,14 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.p-start:before {
content: "\e688";
}
.p-stop:before {
content: "\e750";
}
.p-node-4:before { .p-node-4:before {
content: "\e73c"; content: "\e73c";
} }
File diff suppressed because one or more lines are too long
@@ -5,6 +5,20 @@
"css_prefix_text": "p-", "css_prefix_text": "p-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "15838584",
"name": "arrow-right-filling",
"font_class": "start",
"unicode": "e688",
"unicode_decimal": 59016
},
{
"icon_id": "212329",
"name": "stop",
"font_class": "stop",
"unicode": "e750",
"unicode_decimal": 59216
},
{ {
"icon_id": "7712749", "icon_id": "7712749",
"name": "node-4", "name": "node-4",
@@ -14,6 +14,10 @@
/> />
<missing-glyph /> <missing-glyph />
<glyph glyph-name="start" unicode="&#59016;" d="M755.2 352L390.4 21.333333c-17.066667-14.933333-44.8-14.933333-59.733333 2.133334-6.4 8.533333-10.666667 19.2-10.666667 29.866666v661.333334c0 23.466667 19.2 42.666667 42.666667 42.666666 10.666667 0 21.333333-4.266667 27.733333-10.666666l362.666667-330.666667c17.066667-14.933333 19.2-42.666667 2.133333-59.733333 2.133333-2.133333 0-2.133333 0-4.266667z" horiz-adv-x="1024" />
<glyph glyph-name="stop" unicode="&#59216;" d="M291.065468 30.504749c-24.391172 0-44.186906 19.751547-44.186906 44.186907L246.878562 693.308344c0 24.391172 19.795734 44.186906 44.186906 44.186907s44.186906-19.795734 44.186907-44.186907l0-618.616688C335.252375 50.256296 315.456641 30.504749 291.065468 30.504749zM732.934532 30.504749c-24.435359 0-44.186906 19.751547-44.186907 44.186907L688.747625 693.308344c0 24.391172 19.751547 44.186906 44.186907 44.186907s44.186906-19.795734 44.186906-44.186907l0-618.616688C777.121438 50.256296 757.369891 30.504749 732.934532 30.504749z" horiz-adv-x="1024" />
<glyph glyph-name="node-4" unicode="&#59196;" d="M607.934 478.143c-6.18 6.178-12.766 11.747-19.554 16.91l-0.012-0.011c-6.986 6.72-16.472 10.857-26.93 10.857-21.465 0-38.865-17.4-38.865-38.864a38.697 38.697 0 0 1 9.072-24.947h-0.001a39.02 39.02 0 0 1 9.59-8.256c3.665-3.022 7.262-5.998 10.625-9.361l3.204-3.205c40.28-40.23 28.255-109.54-12.025-149.82l-171.88-171.83c-40.279-40.23-105.762-40.23-146.042 0l-3.23 3.232c-40.281 40.278-40.281 105.81 0 145.99l75.936 75.91c9.742 7.734 15.997 19.67 15.997 33.073 0 23.313-18.899 42.211-42.212 42.211a42.01 42.01 0 0 1-23.725-7.297c-0.021 0.045-0.044 0.088-0.066 0.134l-0.81-0.757a42.455 42.455 0 0 1-8.026-7.51l-78.913-73.842c-74.178-74.23-74.178-195.633 0-269.759l3.204-3.203c74.179-74.127 195.53-74.127 269.708 0l171.83 171.88c74.075 74.175 80.356 191.185 6.281 265.312l-3.156 3.153zM855.62 730.196l-3.204 3.204c-74.178 74.178-195.529 74.178-269.707 0l-171.83-171.88c-74.178-74.178-78.263-181.296-4.085-255.523l3.153-3.104c3.369-3.368 6.866-6.543 10.435-9.589a36.872 36.872 0 0 1 8.993-7.31l0.077-0.062 0.012 0.01a36.508 36.508 0 0 1 18.258-4.87c20.263 0 36.69 16.428 36.69 36.69 0 5.719-1.31 11.132-3.646 15.958-4.85 10.89-13.93 17.52-20.21 23.802l-3.154 3.103c-40.278 40.278-24.983 98.796 15.295 139.074l171.931 171.83c40.18 40.281 105.685 40.281 145.966 0l3.206-3.152c40.279-40.282 40.279-105.839 0-146.068l-75.687-75.738c-10.297-7.629-16.974-19.865-16.974-33.663 0-23.123 18.746-41.87 41.87-41.87a41.668 41.668 0 0 1 21.946 6.211c0.048-0.082 0.093-0.157 0.14-0.24l1.175 1.083a42.09 42.09 0 0 1 9.529 8.793l79.766 73.603c74.233 74.177 74.233 195.53 0.055 269.708z" horiz-adv-x="1024" /> <glyph glyph-name="node-4" unicode="&#59196;" d="M607.934 478.143c-6.18 6.178-12.766 11.747-19.554 16.91l-0.012-0.011c-6.986 6.72-16.472 10.857-26.93 10.857-21.465 0-38.865-17.4-38.865-38.864a38.697 38.697 0 0 1 9.072-24.947h-0.001a39.02 39.02 0 0 1 9.59-8.256c3.665-3.022 7.262-5.998 10.625-9.361l3.204-3.205c40.28-40.23 28.255-109.54-12.025-149.82l-171.88-171.83c-40.279-40.23-105.762-40.23-146.042 0l-3.23 3.232c-40.281 40.278-40.281 105.81 0 145.99l75.936 75.91c9.742 7.734 15.997 19.67 15.997 33.073 0 23.313-18.899 42.211-42.212 42.211a42.01 42.01 0 0 1-23.725-7.297c-0.021 0.045-0.044 0.088-0.066 0.134l-0.81-0.757a42.455 42.455 0 0 1-8.026-7.51l-78.913-73.842c-74.178-74.23-74.178-195.633 0-269.759l3.204-3.203c74.179-74.127 195.53-74.127 269.708 0l171.83 171.88c74.075 74.175 80.356 191.185 6.281 265.312l-3.156 3.153zM855.62 730.196l-3.204 3.204c-74.178 74.178-195.529 74.178-269.707 0l-171.83-171.88c-74.178-74.178-78.263-181.296-4.085-255.523l3.153-3.104c3.369-3.368 6.866-6.543 10.435-9.589a36.872 36.872 0 0 1 8.993-7.31l0.077-0.062 0.012 0.01a36.508 36.508 0 0 1 18.258-4.87c20.263 0 36.69 16.428 36.69 36.69 0 5.719-1.31 11.132-3.646 15.958-4.85 10.89-13.93 17.52-20.21 23.802l-3.154 3.103c-40.278 40.278-24.983 98.796 15.295 139.074l171.931 171.83c40.18 40.281 105.685 40.281 145.966 0l3.206-3.152c40.279-40.282 40.279-105.839 0-146.068l-75.687-75.738c-10.297-7.629-16.974-19.865-16.974-33.663 0-23.123 18.746-41.87 41.87-41.87a41.668 41.668 0 0 1 21.946 6.211c0.048-0.082 0.093-0.157 0.14-0.24l1.175 1.083a42.09 42.09 0 0 1 9.529 8.793l79.766 73.603c74.233 74.177 74.233 195.53 0.055 269.708z" horiz-adv-x="1024" />
<glyph glyph-name="node-3" unicode="&#59351;" d="M900.144 799.76H123.84a66.896 66.896 0 0 1-66.816-66.832v-541.152a66.896 66.896 0 0 1 66.816-66.832h467.744a24 24 0 0 1 0 48H123.84a18.848 18.848 0 0 0-18.816 18.832V732.96A18.864 18.864 0 0 0 123.84 751.792h776.304a18.848 18.848 0 0 0 18.816-18.832v-541.152a18.832 18.832 0 0 0-18.816-18.832H753.76a24 24 0 0 1 0-48h146.384a66.896 66.896 0 0 1 66.816 66.832V732.96a66.896 66.896 0 0 1-66.816 66.8zM795.808 16.24H213.168a24 24 0 0 1 0-48h582.64a24 24 0 0 1 0 48zM204.192 502.16v-192.608a24 24 0 0 1 48 0V502.16a24 24 0 0 1-48 0zM478.096 443.36v-133.856a24 24 0 0 1 48 0V443.36a24 24 0 0 1-48 0zM819.808 309.552V443.36a24 24 0 0 1-48 0v-133.856a24 24 0 0 1 48 0zM342.336 622.96v-313.408a24 24 0 0 1 48 0V622.96a24 24 0 0 1-48 0zM648.64 646.96a24 24 0 0 1-24-24v-313.408a24 24 0 0 1 48 0V622.96a24 24 0 0 1-24 24zM655.152 162.192a32.24 32.24 0 0 1-2.24-4c-0.48-1.44-0.96-3.04-1.28-4.48a24.416 24.416 0 0 1-0.48-4.8 25.008 25.008 0 0 1 1.76-9.12 26.048 26.048 0 0 1 5.28-7.84 22.288 22.288 0 0 1 7.68-5.12 23.504 23.504 0 0 1 9.28-1.92 22.192 22.192 0 0 1 9.12 1.92 22.912 22.912 0 0 1 7.84 5.12 26.048 26.048 0 0 1 5.28 7.84 25.008 25.008 0 0 1 1.76 9.12 24 24 0 0 1-7.04 16.96 24.752 24.752 0 0 1-33.92 0 23.264 23.264 0 0 1-3.04-3.68z" horiz-adv-x="1024" /> <glyph glyph-name="node-3" unicode="&#59351;" d="M900.144 799.76H123.84a66.896 66.896 0 0 1-66.816-66.832v-541.152a66.896 66.896 0 0 1 66.816-66.832h467.744a24 24 0 0 1 0 48H123.84a18.848 18.848 0 0 0-18.816 18.832V732.96A18.864 18.864 0 0 0 123.84 751.792h776.304a18.848 18.848 0 0 0 18.816-18.832v-541.152a18.832 18.832 0 0 0-18.816-18.832H753.76a24 24 0 0 1 0-48h146.384a66.896 66.896 0 0 1 66.816 66.832V732.96a66.896 66.896 0 0 1-66.816 66.8zM795.808 16.24H213.168a24 24 0 0 1 0-48h582.64a24 24 0 0 1 0 48zM204.192 502.16v-192.608a24 24 0 0 1 48 0V502.16a24 24 0 0 1-48 0zM478.096 443.36v-133.856a24 24 0 0 1 48 0V443.36a24 24 0 0 1-48 0zM819.808 309.552V443.36a24 24 0 0 1-48 0v-133.856a24 24 0 0 1 48 0zM342.336 622.96v-313.408a24 24 0 0 1 48 0V622.96a24 24 0 0 1-48 0zM648.64 646.96a24 24 0 0 1-24-24v-313.408a24 24 0 0 1 48 0V622.96a24 24 0 0 1-24 24zM655.152 162.192a32.24 32.24 0 0 1-2.24-4c-0.48-1.44-0.96-3.04-1.28-4.48a24.416 24.416 0 0 1-0.48-4.8 25.008 25.008 0 0 1 1.76-9.12 26.048 26.048 0 0 1 5.28-7.84 22.288 22.288 0 0 1 7.68-5.12 23.504 23.504 0 0 1 9.28-1.92 22.192 22.192 0 0 1 9.12 1.92 22.912 22.912 0 0 1 7.84 5.12 26.048 26.048 0 0 1 5.28 7.84 25.008 25.008 0 0 1 1.76 9.12 24 24 0 0 1-7.04 16.96 24.752 24.752 0 0 1-33.92 0 23.264 23.264 0 0 1-3.04-3.68z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+6 -1
View File
@@ -4,7 +4,8 @@
@close="handleClose" @close="handleClose"
:destroy-on-close="true" :destroy-on-close="true"
:size="size" :size="size"
:close-on-press-escape="true" :close-on-press-escape="autoClose"
:close-on-click-modal="autoClose"
> >
<template #header> <template #header>
<el-page-header @back="handleBack"> <el-page-header @back="handleBack">
@@ -73,6 +74,10 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
autoClose: {
type: Boolean,
default: true,
},
}); });
const slots = useSlots(); const slots = useSlots();
@@ -153,7 +153,9 @@ const searchLogs = async () => {
}; };
eventSource.onerror = (event: MessageEvent) => { eventSource.onerror = (event: MessageEvent) => {
stopListening(); stopListening();
MsgError(event.data); if (event.data && event.data != '') {
MsgError(event.data);
}
}; };
}; };
+8 -1
View File
@@ -205,7 +205,14 @@ const getContent = async (pre: boolean) => {
isLoading.value = true; isLoading.value = true;
emit('update:isReading', true); emit('update:isReading', true);
const res = await readByLine(readReq, props.config.operateNode || ''); let res;
try {
res = await readByLine(readReq, props.config.operateNode || '');
} catch (error) {
isLoading.value = false;
firstLoading.value = false;
}
logPath.value = res.data.path; logPath.value = res.data.path;
firstLoading.value = false; firstLoading.value = false;
+31 -11
View File
@@ -1,5 +1,5 @@
<template> <template>
<el-tooltip v-if="msg" effect="dark" placement="bottom"> <el-tooltip v-if="msg && msg != ''" effect="dark" placement="bottom">
<template #content> <template #content>
<div class="content">{{ msg }}</div> <div class="content">{{ msg }}</div>
</template> </template>
@@ -12,19 +12,24 @@
</span> </span>
</el-tag> </el-tag>
</el-tooltip> </el-tooltip>
<span v-else>
<el-tag size="small" v-else :type="getType(statusItem)" round effect="light"> <el-tag size="small" :type="getType(statusItem)" round effect="light" v-if="!operate">
<span class="flx-align-center"> <span class="flx-align-center">
{{ $t('commons.status.' + statusItem) }}
<el-icon v-if="loadingIcon(statusItem)" class="is-loading">
<Loading />
</el-icon>
</span>
</el-tag>
<el-button size="small" v-else :type="getType(statusItem)" plain round>
{{ $t('commons.status.' + statusItem) }} {{ $t('commons.status.' + statusItem) }}
<el-icon v-if="loadingIcon(statusItem)" class="is-loading"> <el-icon v-if="loadingIcon(statusItem)" class="is-loading">
<Loading /> <Loading />
</el-icon> </el-icon>
<el-icon size="15" v-if="operate"> <svg-icon iconName="p-stop" className="status-icon" v-if="stopIcon(statusItem)"></svg-icon>
<CaretRight v-if="statusItem == 'running'" /> <svg-icon iconName="p-start" className="status-icon" v-if="runningIcon(statusItem)"></svg-icon>
<CaretBottom v-if="statusItem == 'stopped'" /> </el-button>
</el-icon> </span>
</span>
</el-tag>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@@ -33,6 +38,7 @@ import { computed } from 'vue';
const props = defineProps({ const props = defineProps({
status: String, status: String,
msg: String, msg: String,
hasIcon: Boolean,
operate: { operate: {
type: Boolean, type: Boolean,
default: false, default: false,
@@ -64,9 +70,9 @@ const getType = (status: string) => {
case 'unhealthy': case 'unhealthy':
case 'failed': case 'failed':
case 'lost': case 'lost':
case 'exited':
return 'danger'; return 'danger';
case 'paused': case 'paused':
case 'exited':
case 'dead': case 'dead':
case 'removing': case 'removing':
case 'deleted': case 'deleted':
@@ -95,9 +101,18 @@ const loadingStatus = [
'executing', 'executing',
]; ];
const stopStatus = ['stopped', 'exited', 'disable'];
const runningStatus = ['running', 'enable'];
const loadingIcon = (status: string): boolean => { const loadingIcon = (status: string): boolean => {
return loadingStatus.indexOf(status) > -1; return loadingStatus.indexOf(status) > -1;
}; };
const stopIcon = (status: string): boolean => {
return stopStatus.indexOf(status.toLocaleLowerCase()) > -1;
};
const runningIcon = (status: string): boolean => {
return runningStatus.indexOf(status.toLocaleLowerCase()) > -1;
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -105,4 +120,9 @@ const loadingIcon = (status: string): boolean => {
width: 300px; width: 300px;
word-break: break-all; word-break: break-all;
} }
.status-icon {
width: 1em;
height: 1em;
}
</style> </style>
+1 -1
View File
@@ -52,7 +52,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { dateFormat } from '@/utils/util'; import { dateFormat } from '@/utils/util';
import { searchTasks } from '@/api/modules/log'; import { searchTasks } from '@/api/modules/log';
import { reactive, ref } from '@vue/runtime-core'; import { reactive, ref } from 'vue';
import { Log } from '@/api/interface/log'; import { Log } from '@/api/interface/log';
import TaskLog from '@/components/log/task/index.vue'; import TaskLog from '@/components/log/task/index.vue';
import bus from '@/global/bus'; import bus from '@/global/bus';
+8
View File
@@ -211,6 +211,10 @@ export const DNSTypes = [
label: 'Name.com', label: 'Name.com',
value: 'NameCom', value: 'NameCom',
}, },
{
label: 'Dynu',
value: 'Dynu',
},
{ {
label: 'reg.ru', label: 'reg.ru',
value: 'RegRu', value: 'RegRu',
@@ -219,6 +223,10 @@ export const DNSTypes = [
label: 'FreeMyIP', label: 'FreeMyIP',
value: 'FreeMyIP', value: 'FreeMyIP',
}, },
{
label: i18n.global.t('ssl.baiduCloud'),
value: 'BaiduCloud',
},
{ {
label: i18n.global.t('website.rainyun'), label: i18n.global.t('website.rainyun'),
value: 'RainYun', value: 'RainYun',
+14 -4
View File
@@ -2616,6 +2616,7 @@ const message = {
'The default execution directory of the script is the 1Panel installation directory. If a certificate is pushed into local directory, the execution directory will be the certificate push directory. The default execution timeout is 30 minutes.', 'The default execution directory of the script is the 1Panel installation directory. If a certificate is pushed into local directory, the execution directory will be the certificate push directory. The default execution timeout is 30 minutes.',
customAcme: 'Custom ACME Service', customAcme: 'Custom ACME Service',
customAcmeURL: 'ACME Service URL', customAcmeURL: 'ACME Service URL',
baiduCloud: 'Baidu Cloud',
}, },
firewall: { firewall: {
create: 'Create rule', create: 'Create rule',
@@ -3378,13 +3379,22 @@ const message = {
nodeSyncHelper1: '1. Public backup account information', nodeSyncHelper1: '1. Public backup account information',
nodeSyncHelper2: '2. Connection information between the main node and sub-nodes', nodeSyncHelper2: '2. Connection information between the main node and sub-nodes',
nodeCheck: 'Availability check',
checkSSH: 'Check node SSH connection',
checkLicense: 'Check node license status',
checkService: 'Check existing service information on node',
checkPort: 'Check node port reachability',
panelExist: panelExist:
'1Panel V1 service is running on this node. Please upgrade to V2 using the migration script before adding.', 'Detected that this node is running 1Panel V1 service. Please upgrade to V2 using the migration script before adding.',
coreExist: 'This node has already been enabled as the main node and cannot be added as a slave node.', coreExist: 'This node is already enabled as a master node and cannot be added as a slave node.',
agentExist: agentExist:
'1panel-agent is already installed on this node. Continuing will preserve existing data and only replace the 1panel-agent service. Proceed?', 'Detected that 1panel-agent is already installed on this node. Continuing will retain existing data and only replace the 1panel-agent service.',
dataExist: '1Panel historical data exists on this node. Confirm to continue adding?', oldDataExist:
'Detected historical 1Panel V2 data on this node. The following information will be used to overwrite current settings:',
errLicense: 'The license bound to this node is unavailable. Please check and try again!', errLicense: 'The license bound to this node is unavailable. Please check and try again!',
errNodePort:
'Node port [ {0} ] is detected as inaccessible. Please check if the firewall or security group has allowed this port.',
reinstallHelper: 'Reinstall node {0}, do you want to continue?', reinstallHelper: 'Reinstall node {0}, do you want to continue?',
unhealthyCheck: 'Abnormal Check', unhealthyCheck: 'Abnormal Check',
fixOperation: 'Fix Operation', fixOperation: 'Fix Operation',
+14 -5
View File
@@ -2513,6 +2513,7 @@ const message = {
'スクリプトのデフォルトの実行ディレクトリは、1Panelインストールディレクトリです。証明書がローカルディレクトリにプッシュされた場合、実行ディレクトリは証明書プッシュディレクトリになります。デフォルトの実行タイムアウトは30分です。', 'スクリプトのデフォルトの実行ディレクトリは、1Panelインストールディレクトリです。証明書がローカルディレクトリにプッシュされた場合、実行ディレクトリは証明書プッシュディレクトリになります。デフォルトの実行タイムアウトは30分です。',
customAcme: 'カスタム ACME サービス', customAcme: 'カスタム ACME サービス',
customAcmeURL: 'ACME サービス URL', customAcmeURL: 'ACME サービス URL',
baiduCloud: '百度クラウド',
}, },
firewall: { firewall: {
create: 'ルールを作成します', create: 'ルールを作成します',
@@ -3246,13 +3247,21 @@ const message = {
nodeSyncHelper1: '1. 公共のバックアップアカウント情報', nodeSyncHelper1: '1. 公共のバックアップアカウント情報',
nodeSyncHelper2: '2. 主ノードとサブノードの接続情報', nodeSyncHelper2: '2. 主ノードとサブノードの接続情報',
nodeCheck: '可用性チェック',
checkSSH: 'ノードSSH接続を確認',
checkLicense: 'ノードライセンス状態を確認',
checkService: 'ノードの既存サービス情報を確認',
checkPort: 'ノードポート到達性を確認',
panelExist: panelExist:
'このノードで1Panel V1サービスが実行中です。追加する前に移行スクリプトでV2にアップグレードしてください。', 'このノードで1Panel V1サービスが実行中です。追加前に移行スクリプトでV2へアップグレードしてください。',
coreExist: 'このノードは既にメインノードとして有効になっており、スレーブノードとして追加できません。', coreExist: 'このノードはマスターノードとして有効化済みのため、スレーブノードとして追加できません。',
agentExist: agentExist:
'このノードには1panel-agentがインストール済みです。続行すると既存データは保持され、1panel-agentサービスのみ置き換えられます。続行しますか?', 'このノードに1panel-agentが既にインストールされています。続行すると既存データを保持し、1panel-agentサービスのみを置換します。',
dataExist: 'このノードに1Panelの過去データが存在します。追加を続行しますか?', oldDataExist: 'このノードに1Panel V2の過去データが検出されました。以下の情報で現在の設定を上書きします:',
errLicense: 'このノードにバインドされたライセンスが利用できません。確認して再試行してください!', errLicense: 'このノードに紐づけられたライセンスが利用できません。確認して再試行してください!',
errNodePort:
'ノードポート[ {0} ]にアクセスできないことが検出されました。ファイアウォールまたはセキュリティグループでこのポートが開放されているか確認してください。',
reinstallHelper: 'ノード{0}を再インストールします。続行しますか?', reinstallHelper: 'ノード{0}を再インストールします。続行しますか?',
unhealthyCheck: '異常チェック', unhealthyCheck: '異常チェック',
fixOperation: '修正操作', fixOperation: '修正操作',
+15 -5
View File
@@ -2470,6 +2470,7 @@ const message = {
'스크립트의 기본 실행 디렉토리는 1Panel 설치 디렉토리입니다. 인증서가 로컬 디렉토리에 푸시되는 경우 실행 디렉토리는 인증서 푸시 디렉토리가 됩니다. 기본 실행 제한 시간은 30분입니다.', '스크립트의 기본 실행 디렉토리는 1Panel 설치 디렉토리입니다. 인증서가 로컬 디렉토리에 푸시되는 경우 실행 디렉토리는 인증서 푸시 디렉토리가 됩니다. 기본 실행 제한 시간은 30분입니다.',
customAcme: '사용자 정의 ACME 서비스', customAcme: '사용자 정의 ACME 서비스',
customAcmeURL: 'ACME 서비스 URL', customAcmeURL: 'ACME 서비스 URL',
baiduCloud: '바이두 클라우드',
}, },
firewall: { firewall: {
create: '규칙 만들기', create: '규칙 만들기',
@@ -3189,13 +3190,22 @@ const message = {
nodeSyncHelper1: '1. 공용 백업 계정 정보', nodeSyncHelper1: '1. 공용 백업 계정 정보',
nodeSyncHelper2: '2. 주 노드와 하위 노드 간의 연결 정보', nodeSyncHelper2: '2. 주 노드와 하위 노드 간의 연결 정보',
nodeCheck: '가용성 확인',
checkSSH: '노드 SSH 연결 확인',
checkLicense: '노드 라이선스 상태 확인',
checkService: '노드의 기존 서비스 정보 확인',
checkPort: '노드 포트 접근 가능 여부 확인',
panelExist: panelExist:
'이 노드에서 1Panel V1 서비스가 실행 중입니다. 추가하기 전에 마이그레이션 스크립트로 V2로 업그레이드하세요.', '이 노드에서 1Panel V1 서비스가 실행 중인 것으로 감지되었습니다. 추가 전에 마이그레이션 스크립트로 V2로 업그레이드하십시오.',
coreExist: '이 노드는 이미 메인 노드로 활성화되어 있어 슬레이브 노드로 추가할 수 없습니다.', coreExist: '이 노드는 이미 마스터 노드로 활성화되어 있어 슬레이브 노드로 추가할 수 없습니다.',
agentExist: agentExist:
'이 노드에 1panel-agent가 이미 설치되어 있습니다. 계속하면 기존 데이터는 유지되고 1panel-agent 서비스만 교체됩니다. 계속하시겠습니까?', '이 노드에 1panel-agent가 이미 설치되어 있는 것으로 감지되었습니다. 계속하면 기존 데이터를 유지하고 1panel-agent 서비스만 교체됩니다.',
dataExist: '이 노드에 1Panel 이전 데이터가 존재합니다. 추가를 계속하시겠습니까?', oldDataExist:
errLicense: '이 노드에 연결된 라이선스를 사용할 수 없습니다. 확인 후 다시 시도하세요!', '이 노드에서 1Panel V2 기록 데이터가 감지되었습니다. 다음 정보를 사용하여 현재 설정을 덮어씁니다:',
errLicense: '이 노드에 바인딩된 라이선스를 사용할 수 없습니다. 확인 후 다시 시도하십시오!',
errNodePort:
'노드 포트 [ {0} ]에 접근할 수 없는 것으로 감지되었습니다. 방화벽 또는 보안 그룹에서 해당 포트가 허용되었는지 확인하십시오.',
reinstallHelper: '노드 {0}를 재설치합니다. 계속하시겠습니까?', reinstallHelper: '노드 {0}를 재설치합니다. 계속하시겠습니까?',
unhealthyCheck: '비정상 체크', unhealthyCheck: '비정상 체크',
fixOperation: '수정 작업', fixOperation: '수정 작업',

Some files were not shown because too many files have changed in this diff Show More