mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-11 08:00:31 +00:00
Compare commits
158
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da23b8e6d9 | ||
|
|
a1799f5b4b | ||
|
|
34496f6a00 | ||
|
|
5d8208a061 | ||
|
|
f94e60c53c | ||
|
|
dd70be51b3 | ||
|
|
12e1a6a855 | ||
|
|
07648367c1 | ||
|
|
5b86ca38e0 | ||
|
|
79d9d9dfc2 | ||
|
|
e667477f4b | ||
|
|
0367149386 | ||
|
|
3d0ce2add4 | ||
|
|
17224b8920 | ||
|
|
05d125c762 | ||
|
|
e1a268b21d | ||
|
|
c486e8a354 | ||
|
|
eba74d91b3 | ||
|
|
613f8c2b57 | ||
|
|
16e2ad64a2 | ||
|
|
3274895dcf | ||
|
|
7367d47d27 | ||
|
|
4ed2a03222 | ||
|
|
586df4627a | ||
|
|
25181b6c27 | ||
|
|
72e6b9b188 | ||
|
|
e2efa20582 | ||
|
|
2cebb1beca | ||
|
|
fb24a699e6 | ||
|
|
1c16a0a69f | ||
|
|
26e480f242 | ||
|
|
fcf864156d | ||
|
|
d773391763 | ||
|
|
b47d63330e | ||
|
|
026ed1eb42 | ||
|
|
fb80724a96 | ||
|
|
a7ab866e95 | ||
|
|
06f636c9aa | ||
|
|
bbc5b8b731 | ||
|
|
cd154b13a9 | ||
|
|
f71a8a1603 | ||
|
|
d2ecae7e97 | ||
|
|
649e7b1912 | ||
|
|
2a97b0a9de | ||
|
|
5ca02a1dcf | ||
|
|
f088cec4d5 | ||
|
|
dde40064d2 | ||
|
|
597000ce52 | ||
|
|
4597cb26a1 | ||
|
|
e16ab09253 | ||
|
|
595be6f470 | ||
|
|
7afe9ac878 | ||
|
|
1f53b64b08 | ||
|
|
49ca336dd6 | ||
|
|
7cabb54c4e | ||
|
|
f55841f41c | ||
|
|
8983cb6186 | ||
|
|
222181baff | ||
|
|
02c002bda6 | ||
|
|
a5fbd01ea5 | ||
|
|
3652e07988 | ||
|
|
6ed000985c | ||
|
|
4a8b524a7c | ||
|
|
39509ad9a8 | ||
|
|
f977a2488d | ||
|
|
e7b1aadb0e | ||
|
|
339b085db7 | ||
|
|
a7c00900d8 | ||
|
|
99023569fc | ||
|
|
e4478da423 | ||
|
|
d0bb9165bf | ||
|
|
72a0e0200e | ||
|
|
5d83f21a26 | ||
|
|
56936aa6cd | ||
|
|
f4a649dc2f | ||
|
|
464ca8d272 | ||
|
|
7897bdabc4 | ||
|
|
3675c2f3f3 | ||
|
|
4eb264bea4 | ||
|
|
129e864975 | ||
|
|
7f05c1ef33 | ||
|
|
97d6d9c69f | ||
|
|
8937acee13 | ||
|
|
7518c5fe95 | ||
|
|
45fbb9f010 | ||
|
|
eff55da020 | ||
|
|
e87bf0b3fc | ||
|
|
3f141346fa | ||
|
|
34b39f6eb8 | ||
|
|
b8fd8ee0d9 | ||
|
|
b8895f215c | ||
|
|
c4b3efeb9d | ||
|
|
8f0c84c2a5 | ||
|
|
90b9c53420 | ||
|
|
46f9f4f561 | ||
|
|
de265a19b2 | ||
|
|
8af6868694 | ||
|
|
b1dde54e38 | ||
|
|
0a6163c89b | ||
|
|
07d0b37692 | ||
|
|
ac9881dd4c | ||
|
|
280c1b4fea | ||
|
|
6b24ee23e6 | ||
|
|
d93f8c5e6e | ||
|
|
384f065040 | ||
|
|
672fedc7e5 | ||
|
|
0433a26a07 | ||
|
|
4ebd4bddee | ||
|
|
030ab743f3 | ||
|
|
d4623a68dd | ||
|
|
a38d1c96d8 | ||
|
|
61ddf89fdd | ||
|
|
5c7d9b4ffe | ||
|
|
563ea985a4 | ||
|
|
657b2ddc8a | ||
|
|
50221c2ace | ||
|
|
b0bf3be707 | ||
|
|
caaf05897a | ||
|
|
0354b11ddb | ||
|
|
bdcf9b075e | ||
|
|
ab77aa2b5b | ||
|
|
1d54dcc95c | ||
|
|
0138d481a6 | ||
|
|
ba6cdc6e10 | ||
|
|
389d9c652f | ||
|
|
4942c6c206 | ||
|
|
40e264e0d4 | ||
|
|
b73b851245 | ||
|
|
49a777e2d8 | ||
|
|
7df43aeb59 | ||
|
|
86047c48e4 | ||
|
|
6000a206a8 | ||
|
|
da75f050e2 | ||
|
|
7ed81996b8 | ||
|
|
2040f8f3b0 | ||
|
|
c216726449 | ||
|
|
a33b17d5da | ||
|
|
58c994a3e2 | ||
|
|
98d01556c2 | ||
|
|
fd21e8de14 | ||
|
|
37ef2059f1 | ||
|
|
41c49ca95f | ||
|
|
1999f102bf | ||
|
|
aa91bb88bc | ||
|
|
7410a41331 | ||
|
|
a987370657 | ||
|
|
1883b05f26 | ||
|
|
c408619042 | ||
|
|
1181b13c83 | ||
|
|
c1aef03f09 | ||
|
|
6609871b1e | ||
|
|
813f1718fb | ||
|
|
49bcc14df7 | ||
|
|
28108a1c02 | ||
|
|
c169dfa395 | ||
|
|
3b26a692b6 | ||
|
|
9a6b51b092 | ||
|
|
c3121fcd38 |
@@ -226,6 +226,28 @@ func (b *BaseApi) CleanRecord(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
// @Summary Handle stop job
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /cronjobs/stop [post]
|
||||
func (b *BaseApi) StopCronJob(c *gin.Context) {
|
||||
var req dto.OperateByID
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := cronjobService.HandleStop(req.ID); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
// @Summary Delete cronjob
|
||||
// @Accept json
|
||||
|
||||
@@ -17,8 +17,9 @@ var (
|
||||
appInstallService = service.NewIAppInstalledService()
|
||||
appIgnoreUpgradeService = service.NewIAppIgnoreUpgradeService()
|
||||
|
||||
aiToolService = service.NewIAIToolService()
|
||||
mcpServerService = service.NewIMcpServerService()
|
||||
aiToolService = service.NewIAIToolService()
|
||||
mcpServerService = service.NewIMcpServerService()
|
||||
tensorrtLLMService = service.NewITensorRTLLMService()
|
||||
|
||||
containerService = service.NewIContainerService()
|
||||
composeTemplateService = service.NewIComposeTemplateService()
|
||||
|
||||
@@ -901,3 +901,44 @@ func (b *BaseApi) GetUsersAndGroups(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Convert file
|
||||
// @Accept json
|
||||
// @Param request body request.FileConvert true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /files/convert [post]
|
||||
func (b *BaseApi) ConvertFile(c *gin.Context) {
|
||||
var req request.FileConvertRequest
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
fileService.Convert(req)
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Convert file
|
||||
// @Accept json
|
||||
// @Param request body dto.PageInfo true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /files/convert/log [post]
|
||||
func (b *BaseApi) ConvertLog(c *gin.Context) {
|
||||
var req dto.PageInfo
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
total, logs, err := fileService.ConvertLog(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: logs,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -95,28 +95,6 @@ func (b *BaseApi) OperateToolConfig(c *gin.Context) {
|
||||
helper.SuccessWithData(c, config)
|
||||
}
|
||||
|
||||
// @Tags Host tool
|
||||
// @Summary Get tool logs
|
||||
// @Accept json
|
||||
// @Param request body request.HostToolLogReq true "request"
|
||||
// @Success 200 {string} logContent
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/tool/log [post]
|
||||
func (b *BaseApi) GetToolLog(c *gin.Context) {
|
||||
var req request.HostToolLogReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logContent, err := hostToolService.GetToolLog(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, logContent)
|
||||
}
|
||||
|
||||
// @Tags Host tool
|
||||
// @Summary Create Supervisor process
|
||||
// @Accept json
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
@@ -77,26 +76,7 @@ func (b *BaseApi) LoadBaseDir(c *gin.Context) {
|
||||
// @Security Timestamp
|
||||
// @Router /settings/ssh/conn [get]
|
||||
func (b *BaseApi) LoadLocalConn(c *gin.Context) {
|
||||
connInfoInDB := settingService.GetSettingByKey("LocalSSHConn")
|
||||
if len(connInfoInDB) == 0 {
|
||||
helper.Success(c)
|
||||
return
|
||||
}
|
||||
var data dto.SSHConnData
|
||||
if err := json.Unmarshal([]byte(connInfoInDB), &data); err != nil {
|
||||
helper.Success(c)
|
||||
return
|
||||
}
|
||||
if len(data.Password) != 0 {
|
||||
data.Password = base64.StdEncoding.EncodeToString([]byte(data.Password))
|
||||
}
|
||||
if len(data.PrivateKey) != 0 {
|
||||
data.PrivateKey = base64.StdEncoding.EncodeToString([]byte(data.PrivateKey))
|
||||
}
|
||||
if len(data.PassPhrase) != 0 {
|
||||
data.PassPhrase = base64.StdEncoding.EncodeToString([]byte(data.PassPhrase))
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
helper.SuccessWithData(c, settingService.GetLocalConn())
|
||||
}
|
||||
|
||||
func (b *BaseApi) CheckLocalConn(c *gin.Context) {
|
||||
|
||||
+75
-41
@@ -68,21 +68,23 @@ func (b *BaseApi) UpdateSSH(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags SSH
|
||||
// @Summary Update host SSH setting by file
|
||||
// @Summary Generate host SSH secret
|
||||
// @Accept json
|
||||
// @Param request body dto.SSHConf true "request"
|
||||
// @Param request body dto.RootCertOperate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/ssh/conffile/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
|
||||
func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
|
||||
var req dto.SSHConf
|
||||
// @Router /hosts/ssh/cert [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
|
||||
func (b *BaseApi) CreateRootCert(c *gin.Context) {
|
||||
var req dto.RootCertOperate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := sshService.UpdateByFile(req.File); err != nil {
|
||||
if err := loadCertAfterDecrypt(&req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
}
|
||||
if err := sshService.CreateRootCert(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
@@ -90,45 +92,23 @@ func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Tags SSH
|
||||
// @Summary Generate host SSH secret
|
||||
// @Summary Update host SSH secret
|
||||
// @Accept json
|
||||
// @Param request body dto.CreateRootCert true "request"
|
||||
// @Param request body dto.RootCertOperate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/ssh/cert [post]
|
||||
// @Router /hosts/ssh/cert/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
|
||||
func (b *BaseApi) CreateRootCert(c *gin.Context) {
|
||||
var req dto.CreateRootCert
|
||||
func (b *BaseApi) EditRootCert(c *gin.Context) {
|
||||
var req dto.RootCertOperate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if len(req.PassPhrase) != 0 {
|
||||
passPhrase, err := base64.StdEncoding.DecodeString(req.PassPhrase)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
req.PassPhrase = string(passPhrase)
|
||||
if err := loadCertAfterDecrypt(&req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
}
|
||||
if len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
if len(req.PublicKey) != 0 {
|
||||
publicKey, err := base64.StdEncoding.DecodeString(req.PublicKey)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
req.PublicKey = string(publicKey)
|
||||
}
|
||||
|
||||
if err := sshService.CreateRootCert(req); err != nil {
|
||||
if err := sshService.EditRootCert(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
@@ -246,15 +226,69 @@ func (b *BaseApi) ExportSSHLogs(c *gin.Context) {
|
||||
|
||||
// @Tags SSH
|
||||
// @Summary Load host SSH conf
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Success 200 {string} conf
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/ssh/conf [get]
|
||||
func (b *BaseApi) LoadSSHConf(c *gin.Context) {
|
||||
data, err := sshService.LoadSSHConf()
|
||||
// @Router /hosts/ssh/file [post]
|
||||
func (b *BaseApi) LoadSSHFile(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := sshService.LoadSSHFile(req.Name)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags SSH
|
||||
// @Summary Update host SSH setting by file
|
||||
// @Accept json
|
||||
// @Param request body dto.SSHConf true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/ssh/file/update [post]
|
||||
// @x-panel-log {"bodyKeys":["key"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改 SSH 配置文件 [key]","formatEN":"update SSH conf [key]"}
|
||||
func (b *BaseApi) UpdateSSHByFile(c *gin.Context) {
|
||||
var req dto.SettingUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := sshService.UpdateByFile(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func loadCertAfterDecrypt(req *dto.RootCertOperate) error {
|
||||
if len(req.PassPhrase) != 0 {
|
||||
passPhrase, err := base64.StdEncoding.DecodeString(req.PassPhrase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.PassPhrase = string(passPhrase)
|
||||
}
|
||||
if len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
if len(req.PublicKey) != 0 {
|
||||
publicKey, err := base64.StdEncoding.DecodeString(req.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.PublicKey = string(publicKey)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (b *BaseApi) PageTensorRTLLMs(c *gin.Context) {
|
||||
var req request.TensorRTLLMSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
list := tensorrtLLMService.Page(req)
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
func (b *BaseApi) CreateTensorRTLLM(c *gin.Context) {
|
||||
var req request.TensorRTLLMCreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := tensorrtLLMService.Create(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UpdateTensorRTLLM(c *gin.Context) {
|
||||
var req request.TensorRTLLMUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := tensorrtLLMService.Update(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteTensorRTLLM(c *gin.Context) {
|
||||
var req request.TensorRTLLMDelete
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := tensorrtLLMService.Delete(req.ID)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) OperateTensorRTLLM(c *gin.Context) {
|
||||
var req request.TensorRTLLMOperate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := tensorrtLLMService.Operate(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
@@ -86,15 +85,16 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
source := c.Query("source")
|
||||
var containerID string
|
||||
var initCmd []string
|
||||
switch source {
|
||||
case "redis", "redis-cluster":
|
||||
containerID, initCmd, err = loadRedisInitCmd(c, source)
|
||||
initCmd, err = loadRedisInitCmd(c, source)
|
||||
case "ollama":
|
||||
containerID, initCmd, err = loadOllamaInitCmd(c)
|
||||
initCmd, err = loadOllamaInitCmd(c)
|
||||
case "container":
|
||||
containerID, initCmd, err = loadContainerInitCmd(c)
|
||||
initCmd, err = loadContainerInitCmd(c)
|
||||
case "database":
|
||||
initCmd, err = loadDatabaseInitCmd(c)
|
||||
default:
|
||||
if wshandleError(wsConn, fmt.Errorf("not support such source %s", source)) {
|
||||
return
|
||||
@@ -103,12 +103,10 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
pidMap := loadMapFromDockerTop(containerID)
|
||||
slave, err := terminal.NewCommand("docker", initCmd...)
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(containerID, strings.ReplaceAll(strings.Join(initCmd, " "), fmt.Sprintf("exec -it %s ", containerID), ""), pidMap)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
|
||||
@@ -127,18 +125,18 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
||||
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||
}
|
||||
|
||||
func loadRedisInitCmd(c *gin.Context, redisType string) (string, []string, error) {
|
||||
func loadRedisInitCmd(c *gin.Context, redisType string) ([]string, error) {
|
||||
name := c.Query("name")
|
||||
from := c.Query("from")
|
||||
commands := []string{"exec", "-it"}
|
||||
database, err := databaseService.Get(name)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("no such database in db, err: %v", err)
|
||||
return nil, fmt.Errorf("no such database in db, err: %v", err)
|
||||
}
|
||||
if from == "local" {
|
||||
redisInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: name, Type: redisType})
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("no such app in db, err: %v", err)
|
||||
return nil, fmt.Errorf("no such app in db, err: %v", err)
|
||||
}
|
||||
name = redisInfo.ContainerName
|
||||
commands = append(commands, []string{name, "redis-cli"}...)
|
||||
@@ -152,38 +150,61 @@ func loadRedisInitCmd(c *gin.Context, redisType string) (string, []string, error
|
||||
commands = append(commands, []string{"-a", database.Password, "--no-auth-warning"}...)
|
||||
}
|
||||
}
|
||||
return name, commands, nil
|
||||
return commands, nil
|
||||
}
|
||||
|
||||
func loadOllamaInitCmd(c *gin.Context) (string, []string, error) {
|
||||
func loadOllamaInitCmd(c *gin.Context) ([]string, error) {
|
||||
name := c.Query("name")
|
||||
if cmd.CheckIllegal(name) {
|
||||
return "", nil, fmt.Errorf("ollama model %s contains illegal characters", name)
|
||||
return nil, fmt.Errorf("ollama model %s contains illegal characters", name)
|
||||
}
|
||||
ollamaInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: "", Type: "ollama"})
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("no such app in db, err: %v", err)
|
||||
return nil, fmt.Errorf("no such app in db, err: %v", err)
|
||||
}
|
||||
containerName := ollamaInfo.ContainerName
|
||||
return containerName, []string{"exec", "-it", containerName, "ollama", "run", name}, nil
|
||||
return []string{"exec", "-it", containerName, "ollama", "run", name}, nil
|
||||
}
|
||||
|
||||
func loadContainerInitCmd(c *gin.Context) (string, []string, error) {
|
||||
func loadContainerInitCmd(c *gin.Context) ([]string, error) {
|
||||
containerID := c.Query("containerid")
|
||||
command := c.Query("command")
|
||||
user := c.Query("user")
|
||||
if cmd.CheckIllegal(user, containerID, command) {
|
||||
return "", nil, fmt.Errorf("the command contains illegal characters. command: %s, user: %s, containerID: %s", command, user, containerID)
|
||||
return nil, fmt.Errorf("the command contains illegal characters. command: %s, user: %s, containerID: %s", command, user, containerID)
|
||||
}
|
||||
if len(command) == 0 || len(containerID) == 0 {
|
||||
return "", nil, fmt.Errorf("error param of command: %s or containerID: %s", command, containerID)
|
||||
return nil, fmt.Errorf("error param of command: %s or containerID: %s", command, containerID)
|
||||
}
|
||||
commands := []string{"exec", "-it", containerID, command}
|
||||
if len(user) != 0 {
|
||||
commands = []string{"exec", "-it", "-u", user, containerID, command}
|
||||
}
|
||||
|
||||
return containerID, commands, nil
|
||||
return commands, nil
|
||||
}
|
||||
|
||||
func loadDatabaseInitCmd(c *gin.Context) ([]string, error) {
|
||||
database := c.Query("database")
|
||||
databaseType := c.Query("databaseType")
|
||||
if len(database) == 0 || len(databaseType) == 0 {
|
||||
return nil, fmt.Errorf("error param of database: %s or database type: %s", database, databaseType)
|
||||
}
|
||||
databaseConn, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Type: databaseType, Name: database})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no such database in db, err: %v", err)
|
||||
}
|
||||
commands := []string{"exec", "-it", databaseConn.ContainerName}
|
||||
switch databaseType {
|
||||
case "mysql", "mysql-cluster":
|
||||
commands = append(commands, []string{"mysql", "-uroot", "-p" + databaseConn.Password}...)
|
||||
case "mariadb":
|
||||
commands = append(commands, []string{"mariadb", "-uroot", "-p" + databaseConn.Password}...)
|
||||
case "postgresql", "postgresql-cluster":
|
||||
commands = []string{"exec", "-e", fmt.Sprintf("PGPASSWORD=%s", databaseConn.Password), "-it", databaseConn.ContainerName, "psql", "-t", "-U", databaseConn.Username}
|
||||
}
|
||||
|
||||
return commands, nil
|
||||
}
|
||||
|
||||
func wshandleError(ws *websocket.Conn, err error) bool {
|
||||
@@ -206,42 +227,6 @@ func wshandleError(ws *websocket.Conn, err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func loadMapFromDockerTop(containerID string) map[string]string {
|
||||
pidMap := make(map[string]string)
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
|
||||
stdout, err := cmd.RunDefaultWithStdoutBashCf("%s docker top %s -eo pid,command ", sudo, containerID)
|
||||
if err != nil {
|
||||
return pidMap
|
||||
}
|
||||
lines := strings.Split(stdout, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
pidMap[parts[0]] = strings.Join(parts[1:], " ")
|
||||
}
|
||||
return pidMap
|
||||
}
|
||||
|
||||
func killBash(containerID, comm string, pidMap map[string]string) {
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
newPidMap := loadMapFromDockerTop(containerID)
|
||||
for pid, command := range newPidMap {
|
||||
isOld := false
|
||||
for pid2 := range pidMap {
|
||||
if pid == pid2 {
|
||||
isOld = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isOld && command == comm {
|
||||
_, _ = cmd.RunDefaultWithStdoutBashCf("%s kill -9 %s", sudo, pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var upGrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024 * 1024 * 10,
|
||||
|
||||
@@ -1141,3 +1141,65 @@ func (b *BaseApi) ExecComposer(c *gin.Context) {
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Batch operate websites
|
||||
// @Accept json
|
||||
// @Param request body request.BatchOpWebsite true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /websites/batch/operate [post]
|
||||
func (b *BaseApi) BatchOpWebsites(c *gin.Context) {
|
||||
var req request.BatchWebsiteOp
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteService.BatchOpWebsite(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get CORS Config
|
||||
// @Accept json
|
||||
// @Param id path int true "id"
|
||||
// @Success 200 {object} request.CorsConfig
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /websites/cors/{id} [get]
|
||||
func (b *BaseApi) GetCORSConfig(c *gin.Context) {
|
||||
id, err := helper.GetParamID(c)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
res, err := websiteService.GetCors(id)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Update CORS Config
|
||||
// @Accept json
|
||||
// @Param request body request.CorsConfigReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /websites/cors/update [post]
|
||||
func (b *BaseApi) UpdateCORSConfig(c *gin.Context) {
|
||||
var req request.CorsConfigReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteService.UpdateCors(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package v2
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
@@ -217,6 +219,79 @@ func (b *BaseApi) UploadWebsiteSSL(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
// @Summary Upload SSL file
|
||||
// @Accept multipart/form-data
|
||||
// @Param type formData string true "type"
|
||||
// @Param description formData string false "description"
|
||||
// @Param sslID formData string false "sslID"
|
||||
// @Param privateKeyFile formData file true "privateKeyFile"
|
||||
// @Param certificateFile formData file true "certificateFile"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /websites/ssl/upload/file [post]
|
||||
// @x-panel-log {"bodyKeys":["type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"上传 ssl 文件 [type]","formatEN":"Upload ssl file [type]"}
|
||||
func (b *BaseApi) UploadSSLFile(c *gin.Context) {
|
||||
var req request.WebsiteSSLFileUpload
|
||||
|
||||
req.Type = c.PostForm("type")
|
||||
req.Description = c.PostForm("description")
|
||||
sslID := c.PostForm("sslID")
|
||||
if sslID != "" {
|
||||
req.SSLID, _ = strconv.ParseUint(sslID, 10, 64)
|
||||
}
|
||||
|
||||
privateKeyFile, err := c.FormFile("privateKeyFile")
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
certificateFile, err := c.FormFile("certificateFile")
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
privateKeyContent, err := readUploadedFile(privateKeyFile)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
certificateContent, err := readUploadedFile(certificateFile)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
uploadReq := request.WebsiteSSLUpload{
|
||||
Type: "paste",
|
||||
PrivateKey: string(privateKeyContent),
|
||||
Certificate: string(certificateContent),
|
||||
Description: req.Description,
|
||||
SSLID: uint(req.SSLID),
|
||||
}
|
||||
|
||||
if err := websiteSSLService.Upload(uploadReq); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func readUploadedFile(fileHeader *multipart.FileHeader) ([]byte, error) {
|
||||
file, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return io.ReadAll(file)
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
// @Summary Download SSL file
|
||||
// @Accept json
|
||||
|
||||
@@ -292,6 +292,7 @@ type AlertConfigTest struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Sender string `json:"sender"`
|
||||
UserName string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Encryption string `json:"encryption"` // "ssl" / "tls" / "none"
|
||||
@@ -323,6 +324,7 @@ type AlertEmailConfig struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Sender string `json:"sender"`
|
||||
UserName string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Encryption string `json:"encryption"` // "ssl" / "tls" / "none"
|
||||
|
||||
@@ -128,6 +128,7 @@ type Locale struct {
|
||||
Zh string `json:"zh"`
|
||||
Ko string `json:"ko"`
|
||||
Tr string `json:"tr"`
|
||||
Es string `json:"es-es" yaml:"es-es"`
|
||||
}
|
||||
|
||||
type AppForm struct {
|
||||
|
||||
@@ -99,6 +99,9 @@ type BackupRecords struct {
|
||||
DownloadAccountID uint `json:"downloadAccountID"`
|
||||
FileDir string `json:"fileDir"`
|
||||
FileName string `json:"fileName"`
|
||||
TaskID string `json:"taskID"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ type ClamInfo struct {
|
||||
LastRecordStatus string `json:"lastRecordStatus"`
|
||||
LastRecordTime string `json:"lastRecordTime"`
|
||||
Spec string `json:"spec"`
|
||||
Timeout uint `json:"timeout"`
|
||||
Description string `json:"description"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
@@ -77,6 +78,7 @@ type ClamCreate struct {
|
||||
InfectedStrategy string `json:"infectedStrategy"`
|
||||
InfectedDir string `json:"infectedDir"`
|
||||
Spec string `json:"spec"`
|
||||
Timeout uint `json:"timeout"`
|
||||
Description string `json:"description"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
@@ -91,6 +93,7 @@ type ClamUpdate struct {
|
||||
InfectedStrategy string `json:"infectedStrategy"`
|
||||
InfectedDir string `json:"infectedDir"`
|
||||
Spec string `json:"spec"`
|
||||
Timeout uint `json:"timeout"`
|
||||
Description string `json:"description"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
|
||||
@@ -71,7 +71,6 @@ type ResourceLimit struct {
|
||||
|
||||
type ContainerOperate struct {
|
||||
TaskID string `json:"taskID"`
|
||||
ContainerID string `json:"containerID"`
|
||||
ForcePull bool `json:"forcePull"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Image string `json:"image" validate:"required"`
|
||||
@@ -144,6 +143,7 @@ type VolumeHelper struct {
|
||||
SourceDir string `json:"sourceDir"`
|
||||
ContainerDir string `json:"containerDir"`
|
||||
Mode string `json:"mode"`
|
||||
Shared string `json:"shared"`
|
||||
}
|
||||
type PortHelper struct {
|
||||
HostIP string `json:"hostIP"`
|
||||
|
||||
@@ -34,6 +34,7 @@ type ChangeQuicks struct {
|
||||
type QuickJump struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
Title string `json:"title"`
|
||||
Detail string `json:"detail"`
|
||||
Recommend int `json:"recommend"`
|
||||
|
||||
@@ -27,7 +27,8 @@ type SwapHelper struct {
|
||||
Size uint64 `json:"size"`
|
||||
Used string `json:"used"`
|
||||
|
||||
IsNew bool `json:"isNew"`
|
||||
IsNew bool `json:"isNew"`
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
||||
type TimeZoneOptions struct {
|
||||
|
||||
@@ -37,6 +37,7 @@ type ForwardRuleOperate struct {
|
||||
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||
Num string `json:"num"`
|
||||
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
|
||||
Interface string `json:"interface"`
|
||||
Port string `json:"port" validate:"required"`
|
||||
TargetIP string `json:"targetIP"`
|
||||
TargetPort string `json:"targetPort" validate:"required"`
|
||||
|
||||
@@ -30,14 +30,14 @@ type ImageBuild struct {
|
||||
}
|
||||
|
||||
type ImagePull struct {
|
||||
TaskID string `json:"taskID"`
|
||||
RepoID uint `json:"repoID"`
|
||||
ImageName string `json:"imageName" validate:"required"`
|
||||
TaskID string `json:"taskID"`
|
||||
RepoID uint `json:"repoID"`
|
||||
ImageName []string `json:"imageName" validate:"required"`
|
||||
}
|
||||
|
||||
type ImageTag struct {
|
||||
SourceID string `json:"sourceID" validate:"required"`
|
||||
TargetName string `json:"targetName" validate:"required"`
|
||||
SourceID string `json:"sourceID" validate:"required"`
|
||||
Tags []string `json:"tags" validate:"required"`
|
||||
}
|
||||
|
||||
type ImagePush struct {
|
||||
|
||||
@@ -148,3 +148,19 @@ type FileExistReq struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Dir string `json:"dir" validate:"required"`
|
||||
}
|
||||
|
||||
type FileConvert struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
InputFile string `json:"inputFile" validate:"required"`
|
||||
Extension string `json:"extension" validate:"required"`
|
||||
OutputFormat string `json:"outputFormat" validate:"required"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type FileConvertRequest struct {
|
||||
Files []FileConvert `json:"files" validate:"required"`
|
||||
OutputPath string `json:"outputPath" validate:"required"`
|
||||
DeleteSource bool `json:"deleteSource"`
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type SupervisorProcessConfig struct {
|
||||
Numprocs string `json:"numprocs"`
|
||||
AutoRestart string `json:"autoRestart"`
|
||||
AutoStart string `json:"autoStart"`
|
||||
Environment string `json:"environment"`
|
||||
}
|
||||
|
||||
type SupervisorProcessFileReq struct {
|
||||
|
||||
@@ -100,6 +100,7 @@ type PHPConfigUpdate struct {
|
||||
Scope string `json:"scope" validate:"required"`
|
||||
DisableFunctions []string `json:"disableFunctions"`
|
||||
UploadMaxSize string `json:"uploadMaxSize"`
|
||||
MaxExecutionTime string `json:"maxExecutionTime"`
|
||||
}
|
||||
|
||||
type PHPFileUpdate struct {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package request
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
|
||||
type TensorRTLLMSearch struct {
|
||||
dto.PageInfo
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type TensorRTLLMCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
ContainerName string `json:"containerName" validate:"required"`
|
||||
Version string `json:"version" validate:"required"`
|
||||
ModelDir string `json:"modelDir" validate:"required"`
|
||||
Image string `json:"image" validate:"required"`
|
||||
Command string `json:"command" validate:"required"`
|
||||
DockerConfig
|
||||
}
|
||||
|
||||
type TensorRTLLMUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
TensorRTLLMCreate
|
||||
}
|
||||
|
||||
type TensorRTLLMDelete struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type TensorRTLLMOperate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required"`
|
||||
}
|
||||
|
||||
type DockerConfig struct {
|
||||
ExposedPorts []ExposedPort `json:"exposedPorts"`
|
||||
Environments []Environment `json:"environments"`
|
||||
Volumes []Volume `json:"volumes"`
|
||||
}
|
||||
@@ -95,6 +95,7 @@ type WebsiteDelete struct {
|
||||
DeleteApp bool `json:"deleteApp"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteDB bool `json:"deleteDB"`
|
||||
}
|
||||
|
||||
type WebsiteOp struct {
|
||||
@@ -102,6 +103,12 @@ type WebsiteOp struct {
|
||||
Operate string `json:"operate"`
|
||||
}
|
||||
|
||||
type BatchWebsiteOp struct {
|
||||
IDs []uint `json:"ids" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required"`
|
||||
TaskID string `json:"taskID" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteRedirectUpdate struct {
|
||||
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||
Key string `json:"key" validate:"required"`
|
||||
@@ -222,6 +229,21 @@ type WebsiteProxyConfig struct {
|
||||
Replaces map[string]string `json:"replaces"`
|
||||
SNI bool `json:"sni"`
|
||||
ProxySSLName string `json:"proxySSLName"`
|
||||
CorsConfig
|
||||
}
|
||||
|
||||
type CorsConfig struct {
|
||||
Cors bool `json:"cors"`
|
||||
AllowOrigins string `json:"allowOrigins"`
|
||||
AllowMethods string `json:"allowMethods"`
|
||||
AllowHeaders string `json:"allowHeaders"`
|
||||
AllowCredentials bool `json:"allowCredentials"`
|
||||
Preflight bool `json:"preflight"`
|
||||
}
|
||||
|
||||
type CorsConfigReq struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
CorsConfig
|
||||
}
|
||||
|
||||
type WebsiteProxyReq struct {
|
||||
|
||||
@@ -157,3 +157,9 @@ type WebsiteCAObtain struct {
|
||||
type WebsiteCARenew struct {
|
||||
SSLID uint `json:"SSLID" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteSSLFileUpload struct {
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description"`
|
||||
SSLID uint64 `json:"sslID"`
|
||||
}
|
||||
|
||||
@@ -73,3 +73,11 @@ type DepthDirSizeRes struct {
|
||||
Path string `json:"path"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
type FileConvertLog struct {
|
||||
Date string `json:"date"`
|
||||
Type string `json:"type"`
|
||||
Log string `json:"log"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ type SupervisorProcessConfig struct {
|
||||
Status []ProcessStatus `json:"status"`
|
||||
AutoRestart string `json:"autoRestart"`
|
||||
AutoStart string `json:"autoStart"`
|
||||
Environment string `json:"environment"`
|
||||
}
|
||||
|
||||
type ProcessStatus struct {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
)
|
||||
|
||||
type TensorRTLLMsRes struct {
|
||||
Items []TensorRTLLMDTO `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
type TensorRTLLMDTO struct {
|
||||
model.TensorRTLLM
|
||||
Version string `json:"version"`
|
||||
Model string `json:"model"`
|
||||
Dir string `json:"dir"`
|
||||
ModelDir string `json:"modelDir"`
|
||||
Image string `json:"image"`
|
||||
Command string `json:"command"`
|
||||
|
||||
ExposedPorts []request.ExposedPort `json:"exposedPorts"`
|
||||
Environments []request.Environment `json:"environments"`
|
||||
Volumes []request.Volume `json:"volumes"`
|
||||
}
|
||||
@@ -59,16 +59,16 @@ type WebsiteNginxConfig struct {
|
||||
}
|
||||
|
||||
type WebsiteHTTPS struct {
|
||||
Enable bool `json:"enable"`
|
||||
HttpConfig string `json:"httpConfig"`
|
||||
SSL model.WebsiteSSL `json:"SSL"`
|
||||
SSLProtocol []string `json:"SSLProtocol"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Hsts bool `json:"hsts"`
|
||||
HstsIncludeSubDomains bool `json:"hstsIncludeSubDomains"`
|
||||
HttpsPorts []int `json:"httpsPorts"`
|
||||
HttpsPort string `json:"httpsPort"`
|
||||
Http3 bool `json:"http3"`
|
||||
Enable bool `json:"enable"`
|
||||
HttpConfig string `json:"httpConfig"`
|
||||
SSL model.WebsiteSSL `json:"SSL"`
|
||||
SSLProtocol []string `json:"SSLProtocol"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Hsts bool `json:"hsts"`
|
||||
HstsIncludeSubDomains bool `json:"hstsIncludeSubDomains"`
|
||||
HttpsPorts []int `json:"httpsPorts"`
|
||||
HttpsPort string `json:"httpsPort"`
|
||||
Http3 bool `json:"http3"`
|
||||
}
|
||||
|
||||
type WebsiteLog struct {
|
||||
@@ -82,6 +82,7 @@ type PHPConfig struct {
|
||||
Params map[string]string `json:"params"`
|
||||
DisableFunctions []string `json:"disableFunctions"`
|
||||
UploadMaxSize string `json:"uploadMaxSize"`
|
||||
MaxExecutionTime string `json:"maxExecutionTime"`
|
||||
}
|
||||
|
||||
type NginxRewriteRes struct {
|
||||
|
||||
@@ -69,6 +69,8 @@ type SSHConnData struct {
|
||||
Password string `json:"password"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
PassPhrase string `json:"passPhrase"`
|
||||
|
||||
LocalSSHConnShow string `json:"localSSHConnShow"`
|
||||
}
|
||||
|
||||
type SystemProxy struct {
|
||||
|
||||
@@ -22,7 +22,8 @@ type SSHInfo struct {
|
||||
CurrentUser string `json:"currentUser"`
|
||||
}
|
||||
|
||||
type CreateRootCert struct {
|
||||
type RootCertOperate struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Mode string `json:"mode"`
|
||||
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
|
||||
|
||||
@@ -43,11 +43,17 @@ type App struct {
|
||||
func (i *App) IsLocalApp() bool {
|
||||
return i.Resource == constant.ResourceLocal
|
||||
}
|
||||
func (i *App) IsCustomApp() bool {
|
||||
return i.Resource == constant.AppResourceCustom
|
||||
}
|
||||
|
||||
func (i *App) GetAppResourcePath() string {
|
||||
if i.IsLocalApp() {
|
||||
//这里要去掉本地应用的local前缀
|
||||
return filepath.Join(global.Dir.LocalAppResourceDir, strings.TrimPrefix(i.Key, "local"))
|
||||
}
|
||||
if i.IsCustomApp() {
|
||||
return filepath.Join(global.Dir.CustomAppResourceDir, i.Key)
|
||||
}
|
||||
return filepath.Join(global.Dir.RemoteAppResourceDir, i.Key)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ type AppLauncher struct {
|
||||
type QuickJump struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
Title string `json:"title"`
|
||||
Detail string `json:"detail"`
|
||||
Recommend int `json:"recommend"`
|
||||
|
||||
@@ -27,5 +27,8 @@ type BackupRecord struct {
|
||||
FileDir string `json:"fileDir"`
|
||||
FileName string `json:"fileName"`
|
||||
|
||||
TaskID string `json:"taskID"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ type Clam struct {
|
||||
InfectedStrategy string `json:"infectedStrategy"`
|
||||
InfectedDir string `json:"infectedDir"`
|
||||
Spec string `json:"spec"`
|
||||
RetryTimes uint `json:"retryTimes"`
|
||||
Timeout uint `json:"timeout"`
|
||||
EntryID int `json:"entryID"`
|
||||
Description string `json:"description"`
|
||||
|
||||
|
||||
@@ -18,4 +18,5 @@ type Forward struct {
|
||||
Port string `gorm:"not null" json:"port"`
|
||||
TargetIP string `gorm:"not null" json:"targetIP"`
|
||||
TargetPort string `gorm:"not null" json:"targetPort"`
|
||||
Interface string `json:"interface"`
|
||||
}
|
||||
|
||||
@@ -49,3 +49,7 @@ func (r *Runtime) GetPHPPath() string {
|
||||
func (r *Runtime) GetLogPath() string {
|
||||
return path.Join(r.GetPath(), "build.log")
|
||||
}
|
||||
|
||||
func (r *Runtime) GetSlowLogPath() string {
|
||||
return path.Join(r.GetPath(), "log", "fpm.slow.log")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package model
|
||||
|
||||
type TensorRTLLM struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
ContainerName string `json:"containerName"`
|
||||
Message string `json:"message"`
|
||||
//Port int `json:"port"`
|
||||
Status string `json:"status"`
|
||||
Env string `json:"env"`
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
@@ -10,35 +10,37 @@ import (
|
||||
|
||||
type WebsiteSSL struct {
|
||||
BaseModel
|
||||
PrimaryDomain string `json:"primaryDomain"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Pem string `json:"pem"`
|
||||
Domains string `json:"domains"`
|
||||
CertURL string `json:"certURL"`
|
||||
Type string `json:"type"`
|
||||
Provider string `json:"provider"`
|
||||
Organization string `json:"organization"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"column:acme_account_id" json:"acmeAccountId" `
|
||||
CaID uint `json:"caId"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
StartDate time.Time `json:"startDate"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
KeyType string `json:"keyType"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
Description string `json:"description"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
ExecShell bool `json:"execShell"`
|
||||
Shell string `json:"shell"`
|
||||
MasterSSLID uint `json:"masterSslId"`
|
||||
Nodes string `json:"nodes"`
|
||||
PushNode bool `json:"pushNode"`
|
||||
PrimaryDomain string `json:"primaryDomain"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Pem string `json:"pem"`
|
||||
Domains string `json:"domains"`
|
||||
CertURL string `json:"certURL"`
|
||||
Type string `json:"type"`
|
||||
Provider string `json:"provider"`
|
||||
Organization string `json:"organization"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"column:acme_account_id" json:"acmeAccountId" `
|
||||
CaID uint `json:"caId"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
StartDate time.Time `json:"startDate"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
KeyType string `json:"keyType"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
Description string `json:"description"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
ExecShell bool `json:"execShell"`
|
||||
Shell string `json:"shell"`
|
||||
MasterSSLID uint `json:"masterSslId"`
|
||||
Nodes string `json:"nodes"`
|
||||
PushNode bool `json:"pushNode"`
|
||||
PrivateKeyPath string `json:"privateKeyPath"`
|
||||
CertPath string `json:"certPath"`
|
||||
|
||||
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
|
||||
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
|
||||
|
||||
@@ -95,6 +95,7 @@ func (u *LauncherRepo) UpdateQuicks(quicks []model.QuickJump) error {
|
||||
if err := tx.Model(&model.QuickJump{}).Where("id = ?", item.ID).Updates(map[string]interface{}{
|
||||
"is_show": item.IsShow,
|
||||
"detail": item.Detail,
|
||||
"alias": item.Alias,
|
||||
}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
|
||||
@@ -19,7 +19,7 @@ type IHostRepo interface {
|
||||
GetCert(opts ...DBOption) (model.RootCert, error)
|
||||
PageCert(limit, offset int, opts ...DBOption) (int64, []model.RootCert, error)
|
||||
ListCert(opts ...DBOption) ([]model.RootCert, error)
|
||||
CreateCert(cert *model.RootCert) error
|
||||
SaveCert(cert *model.RootCert) error
|
||||
UpdateCert(id uint, vars map[string]interface{}) error
|
||||
DeleteCert(opts ...DBOption) error
|
||||
}
|
||||
@@ -107,8 +107,8 @@ func (u *HostRepo) ListCert(opts ...DBOption) ([]model.RootCert, error) {
|
||||
return ops, err
|
||||
}
|
||||
|
||||
func (u *HostRepo) CreateCert(cert *model.RootCert) error {
|
||||
return global.DB.Create(cert).Error
|
||||
func (u *HostRepo) SaveCert(cert *model.RootCert) error {
|
||||
return global.DB.Save(cert).Error
|
||||
}
|
||||
|
||||
func (u *HostRepo) UpdateCert(id uint, vars map[string]interface{}) error {
|
||||
|
||||
@@ -24,6 +24,7 @@ type ITaskRepo interface {
|
||||
DeleteAll() error
|
||||
|
||||
WithByID(id string) DBOption
|
||||
WithByIDNotIn(ids []string) DBOption
|
||||
WithResourceID(id uint) DBOption
|
||||
WithOperate(taskOperate string) DBOption
|
||||
WithByStatus(status string) DBOption
|
||||
@@ -58,6 +59,12 @@ func (t TaskRepo) WithByID(id string) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (t TaskRepo) WithByIDNotIn(ids []string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("id not in (?)", ids)
|
||||
}
|
||||
}
|
||||
|
||||
func (t TaskRepo) WithOperate(taskOperate string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("operate = ?", taskOperate)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package repo
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
|
||||
type TensorRTLLMRepo struct {
|
||||
}
|
||||
|
||||
type ITensorRTLLMRepo interface {
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.TensorRTLLM, error)
|
||||
GetFirst(opts ...DBOption) (*model.TensorRTLLM, error)
|
||||
Create(tensorrtLLM *model.TensorRTLLM) error
|
||||
Save(tensorrtLLM *model.TensorRTLLM) error
|
||||
DeleteBy(opts ...DBOption) error
|
||||
List(opts ...DBOption) ([]model.TensorRTLLM, error)
|
||||
}
|
||||
|
||||
func NewITensorRTLLMRepo() ITensorRTLLMRepo {
|
||||
return &TensorRTLLMRepo{}
|
||||
}
|
||||
|
||||
func (t TensorRTLLMRepo) Page(page, size int, opts ...DBOption) (int64, []model.TensorRTLLM, error) {
|
||||
var servers []model.TensorRTLLM
|
||||
db := getDb(opts...).Model(&model.TensorRTLLM{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&servers).Error
|
||||
return count, servers, err
|
||||
}
|
||||
|
||||
func (t TensorRTLLMRepo) GetFirst(opts ...DBOption) (*model.TensorRTLLM, error) {
|
||||
var tensorrtLLM model.TensorRTLLM
|
||||
if err := getDb(opts...).First(&tensorrtLLM).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tensorrtLLM, nil
|
||||
}
|
||||
|
||||
func (t TensorRTLLMRepo) List(opts ...DBOption) ([]model.TensorRTLLM, error) {
|
||||
var tensorrtLLMs []model.TensorRTLLM
|
||||
if err := getDb(opts...).Find(&tensorrtLLMs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tensorrtLLMs, nil
|
||||
}
|
||||
|
||||
func (t TensorRTLLMRepo) Create(tensorrtLLM *model.TensorRTLLM) error {
|
||||
return getDb().Create(tensorrtLLM).Error
|
||||
}
|
||||
|
||||
func (t TensorRTLLMRepo) Save(tensorrtLLM *model.TensorRTLLM) error {
|
||||
return getDb().Save(tensorrtLLM).Error
|
||||
}
|
||||
|
||||
func (t TensorRTLLMRepo) DeleteBy(opts ...DBOption) error {
|
||||
return getDb(opts...).Delete(&model.TensorRTLLM{}).Error
|
||||
}
|
||||
@@ -479,10 +479,14 @@ func (a AlertService) DeleteAlertConfig(id uint) error {
|
||||
}
|
||||
|
||||
func (a AlertService) TestAlertConfig(req dto.AlertConfigTest) (bool, error) {
|
||||
username := req.UserName
|
||||
if username == "" {
|
||||
username = req.Sender
|
||||
}
|
||||
cfg := email.SMTPConfig{
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
Username: req.Sender,
|
||||
Username: username,
|
||||
Password: req.Password,
|
||||
From: fmt.Sprintf("%s <%s>", req.DisplayName, req.Sender),
|
||||
Encryption: req.Encryption,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -72,7 +73,11 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts = append(opts, appRepo.WithArch(info.KernelArch))
|
||||
kernelArch := info.KernelArch
|
||||
if kernelArch == "aarch64" {
|
||||
kernelArch = "arm64"
|
||||
}
|
||||
opts = append(opts, appRepo.WithArch(kernelArch))
|
||||
}
|
||||
if len(req.Tags) != 0 {
|
||||
tags, err := tagRepo.GetByKeys(req.Tags)
|
||||
@@ -107,7 +112,7 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{
|
||||
lang := strings.ToLower(common.GetLang(ctx))
|
||||
for _, ap := range apps {
|
||||
if req.Type == "php" {
|
||||
if ap.RequiredPanelVersion == 0 || !common.CompareAppVersion(common.GetSystemVersion(info.SystemVersion), fmt.Sprintf("%f", ap.RequiredPanelVersion)) {
|
||||
if !global.CONF.Base.IsOffLine && (ap.RequiredPanelVersion == 0 || !common.CompareAppVersion(common.GetSystemVersion(info.SystemVersion), fmt.Sprintf("%f", ap.RequiredPanelVersion))) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -480,6 +485,15 @@ func (a AppService) Install(req request.AppInstallCreate) (appInstall *model.App
|
||||
req.Params["RESTY_ADD_PACKAGE_BUILDDEPS"] = ""
|
||||
req.Params["RESTY_CONFIG_OPTIONS_MORE"] = ""
|
||||
}
|
||||
if app.Key == "openresty" && (app.Resource == "remote" || app.Resource == "custom") && common.CompareVersion(appDetail.Version, "1.27") {
|
||||
if dir, ok := req.Params["WEBSITE_DIR"]; ok {
|
||||
siteDir := dir.(string)
|
||||
if siteDir == "" || !strings.HasPrefix(siteDir, "/") {
|
||||
siteDir = path.Join(global.Dir.DataDir, dir.(string))
|
||||
}
|
||||
req.Params["WEBSITE_DIR"] = siteDir
|
||||
}
|
||||
}
|
||||
paramByte, err = json.Marshal(req.Params)
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
@@ -677,29 +677,29 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
backupFile string
|
||||
)
|
||||
backUpApp := func(t *task.Task) error {
|
||||
if req.Backup {
|
||||
backupService := NewIBackupService()
|
||||
backupRecordService := NewIBackupRecordService()
|
||||
fileName := fmt.Sprintf("upgrade_backup_%s_%s.tar.gz", install.Name, time.Now().Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
backupRecord, err := backupService.AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name, FileName: fileName})
|
||||
if err == nil {
|
||||
backups, _ := backupRecordService.ListAppRecords(install.App.Key, install.Name, "upgrade_backup")
|
||||
if len(backups) > 3 {
|
||||
backupsToDelete := backups[:len(backups)-3]
|
||||
var deleteIDs []uint
|
||||
for _, backup := range backupsToDelete {
|
||||
deleteIDs = append(deleteIDs, backup.ID)
|
||||
}
|
||||
_ = backupRecordService.BatchDeleteRecord(deleteIDs)
|
||||
backupService := NewIBackupService()
|
||||
backupRecordService := NewIBackupRecordService()
|
||||
fileName := fmt.Sprintf("upgrade_backup_%s_%s.tar.gz", install.Name, time.Now().Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
backupRecord, err := backupService.AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name, FileName: fileName})
|
||||
if err == nil {
|
||||
backups, _ := backupRecordService.ListAppRecords(install.App.Key, install.Name, "upgrade_backup")
|
||||
if len(backups) > 3 {
|
||||
backupsToDelete := backups[:len(backups)-3]
|
||||
var deleteIDs []uint
|
||||
for _, backup := range backupsToDelete {
|
||||
deleteIDs = append(deleteIDs, backup.ID)
|
||||
}
|
||||
backupFile = path.Join(global.Dir.LocalBackupDir, backupRecord.FileDir, backupRecord.FileName)
|
||||
} else {
|
||||
return buserr.WithNameAndErr("ErrAppBackup", install.Name, err)
|
||||
_ = backupRecordService.BatchDeleteRecord(deleteIDs)
|
||||
}
|
||||
backupFile = path.Join(global.Dir.LocalBackupDir, backupRecord.FileDir, backupRecord.FileName)
|
||||
} else {
|
||||
return buserr.WithNameAndErr("ErrAppBackup", install.Name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
upgradeTask.AddSubTask(task.GetTaskName(install.Name, task.TaskBackup, task.TaskScopeApp), backUpApp, nil)
|
||||
if req.Backup {
|
||||
upgradeTask.AddSubTask(task.GetTaskName(install.Name, task.TaskBackup, task.TaskScopeApp), backUpApp, nil)
|
||||
}
|
||||
|
||||
upgradeApp := func(t *task.Task) error {
|
||||
fileOp := files.NewFileOp()
|
||||
@@ -946,7 +946,7 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
|
||||
}
|
||||
|
||||
func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall, logger *log.Logger) (err error) {
|
||||
if app.IsLocalApp() {
|
||||
if app.IsLocalApp() || app.IsCustomApp() {
|
||||
return nil
|
||||
}
|
||||
appResourceDir := path.Join(global.Dir.AppResourceDir, app.Resource)
|
||||
@@ -1163,7 +1163,11 @@ func upApp(task *task.Task, appInstall *model.AppInstall, pullImages bool) error
|
||||
appInstall.Message = errMsg + errOur
|
||||
installErr := errors.New(appInstall.Message)
|
||||
task.LogFailedWithErr(i18n.GetMsgByKey("PullImage"), installErr)
|
||||
return installErr
|
||||
if exist, _ := dockerCLi.ImageExists(image); !exist {
|
||||
return installErr
|
||||
} else {
|
||||
task.Log(i18n.GetMsgByKey("UseExistImage"))
|
||||
}
|
||||
} else {
|
||||
task.Log(i18n.GetMsgByKey("PullImageSuccess"))
|
||||
}
|
||||
@@ -2063,7 +2067,7 @@ func handleSSLConfig(appInstall *model.AppInstall, hasDefaultWebsite bool) error
|
||||
}
|
||||
defaultConfig.FilePath = defaultConfigPath
|
||||
defaultServer := defaultConfig.FindServers()[0]
|
||||
updateDefaultServer(defaultServer, appInstall.HttpPort, appInstall.HttpsPort, !hasDefaultWebsite)
|
||||
updateDefaultServer(defaultServer, appInstall.HttpPort, appInstall.HttpsPort, !hasDefaultWebsite, true)
|
||||
defaultServer.UpdateDirective("include", []string{"/usr/local/openresty/nginx/conf/ssl/root_ssl.conf"})
|
||||
defaultServer.UpdateDirective("http2", []string{"on"})
|
||||
if err = nginx.WriteConfig(defaultConfig, nginx.IndentedStyle); err != nil {
|
||||
|
||||
@@ -45,36 +45,29 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er
|
||||
fileName = fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
}
|
||||
|
||||
backupApp := func() (*model.BackupRecord, error) {
|
||||
if err = handleAppBackup(&install, nil, backupDir, fileName, "", req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("backup app %s failed, err: %v", req.DetailName, err)
|
||||
return nil, err
|
||||
}
|
||||
record := &model.BackupRecord{
|
||||
Type: "app",
|
||||
Name: req.Name,
|
||||
DetailName: req.DetailName,
|
||||
SourceAccountIDs: "1",
|
||||
DownloadAccountID: 1,
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
Description: req.Description,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return record, nil
|
||||
record := &model.BackupRecord{
|
||||
Type: "app",
|
||||
Name: req.Name,
|
||||
DetailName: req.DetailName,
|
||||
SourceAccountIDs: "1",
|
||||
DownloadAccountID: 1,
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
TaskID: req.TaskID,
|
||||
Status: constant.StatusWaiting,
|
||||
Description: req.Description,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.TaskID != "" {
|
||||
go func() {
|
||||
_, _ = backupApp()
|
||||
}()
|
||||
} else {
|
||||
return backupApp()
|
||||
if err = handleAppBackup(&install, nil, record.ID, backupDir, fileName, "", req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("backup app %s failed, err: %v", req.DetailName, err)
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
@@ -94,11 +87,9 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
if _, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if err := handleAppRecover(&install, nil, req.File, false, req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("recover app %s failed, err: %v", req.DetailName, err)
|
||||
}
|
||||
}()
|
||||
if err := handleAppRecover(&install, nil, req.File, false, req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("recover app %s failed, err: %v", req.DetailName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -111,7 +102,7 @@ func backupDatabaseWithTask(parentTask *task.Task, resourceKey, tmpDir, name str
|
||||
}
|
||||
parentTask.LogStart(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase))
|
||||
databaseHelper := DatabaseHelper{Database: db.MysqlName, DBType: resourceKey, Name: db.Name}
|
||||
if err := handleMysqlBackup(databaseHelper, parentTask, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil {
|
||||
if err := handleMysqlBackup(databaseHelper, parentTask, 0, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
parentTask.LogSuccess(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase))
|
||||
@@ -122,7 +113,7 @@ func backupDatabaseWithTask(parentTask *task.Task, resourceKey, tmpDir, name str
|
||||
}
|
||||
parentTask.LogStart(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase))
|
||||
databaseHelper := DatabaseHelper{Database: db.PostgresqlName, DBType: resourceKey, Name: db.Name}
|
||||
if err := handlePostgresqlBackup(databaseHelper, parentTask, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil {
|
||||
if err := handlePostgresqlBackup(databaseHelper, parentTask, 0, tmpDir, fmt.Sprintf("%s.sql.gz", name), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
parentTask.LogSuccess(task.GetTaskName(db.Name, task.TaskBackup, task.TaskScopeDatabase))
|
||||
@@ -130,25 +121,34 @@ func backupDatabaseWithTask(parentTask *task.Task, resourceKey, tmpDir, name str
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleAppBackup(install *model.AppInstall, parentTask *task.Task, backupDir, fileName, excludes, secret, taskID string) error {
|
||||
func handleAppBackup(install *model.AppInstall, parentTask *task.Task, recordID uint, backupDir, fileName, excludes, secret, taskID string) error {
|
||||
var (
|
||||
err error
|
||||
backupTask *task.Task
|
||||
)
|
||||
backupTask = parentTask
|
||||
if parentTask == nil {
|
||||
backupTask, err = task.NewTaskWithOps(install.Name, task.TaskBackup, task.TaskScopeApp, taskID, install.ID)
|
||||
backupTask, err = task.NewTaskWithOps(install.Name, task.TaskBackup, task.TaskScopeBackup, taskID, install.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
itemHandler := func() error { return doAppBackup(install, backupTask, backupDir, fileName, excludes, secret) }
|
||||
backupTask.AddSubTask(task.GetTaskName(install.Name, task.TaskBackup, task.TaskScopeApp), func(t *task.Task) error { return itemHandler() }, nil)
|
||||
if parentTask != nil {
|
||||
return itemHandler()
|
||||
}
|
||||
return backupTask.Execute()
|
||||
|
||||
backupTask.AddSubTaskWithOps(task.GetTaskName(install.Name, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour)
|
||||
go func() {
|
||||
if err := backupTask.Execute(); err != nil {
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverFile string, isRollback bool, secret, taskID string) error {
|
||||
@@ -160,7 +160,7 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
)
|
||||
recoverTask = parentTask
|
||||
if parentTask == nil {
|
||||
recoverTask, err = task.NewTaskWithOps(install.Name, task.TaskRecover, task.TaskScopeApp, taskID, install.ID)
|
||||
recoverTask, err = task.NewTaskWithOps(install.Name, task.TaskRecover, task.TaskScopeBackup, taskID, install.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -170,7 +170,7 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
fileOp := files.NewFileOp()
|
||||
if !isRollback {
|
||||
rollbackFile = path.Join(global.Dir.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format(constant.DateTimeSlimLayout)))
|
||||
if err := handleAppBackup(install, recoverTask, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil {
|
||||
if err := handleAppBackup(install, recoverTask, 0, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil {
|
||||
t.Log(fmt.Sprintf("backup app %s for rollback before recover failed, err: %v", install.Name, err))
|
||||
}
|
||||
}
|
||||
@@ -308,6 +308,10 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
return nil
|
||||
}
|
||||
|
||||
if parentTask != nil {
|
||||
return recoverApp(parentTask)
|
||||
}
|
||||
|
||||
rollBackApp := func(t *task.Task) {
|
||||
if isRollback {
|
||||
return
|
||||
@@ -324,12 +328,11 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
}
|
||||
}
|
||||
|
||||
recoverTask.AddSubTask(task.GetTaskName(install.Name, task.TaskRecover, task.TaskScopeApp), recoverApp, rollBackApp)
|
||||
if parentTask != nil {
|
||||
return recoverApp(parentTask)
|
||||
}
|
||||
return recoverTask.Execute()
|
||||
recoverTask.AddSubTask(task.GetTaskName(install.Name, task.TaskRecover, task.TaskScopeBackup), recoverApp, rollBackApp)
|
||||
go func() {
|
||||
_ = recoverTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func doAppBackup(install *model.AppInstall, parentTask *task.Task, backupDir, fileName, excludes, secret string) error {
|
||||
@@ -351,6 +354,7 @@ func doAppBackup(install *model.AppInstall, parentTask *task.Task, backupDir, fi
|
||||
}
|
||||
|
||||
appPath := install.GetPath()
|
||||
parentTask.LogStart(i18n.GetMsgByKey("TaskBackup"))
|
||||
if err := fileOp.TarGzCompressPro(true, appPath, path.Join(tmpDir, "app.tar.gz"), "", excludes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -30,11 +30,6 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
targetDir := path.Join(global.Dir.LocalBackupDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName}
|
||||
if err := handleMysqlBackup(databaseHelper, nil, targetDir, fileName, req.TaskID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record := &model.BackupRecord{
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
@@ -43,19 +38,25 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
DownloadAccountID: 1,
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
TaskID: req.TaskID,
|
||||
Status: constant.StatusWaiting,
|
||||
Description: req.Description,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName}
|
||||
if err := handleMysqlBackup(databaseHelper, nil, record.ID, targetDir, fileName, req.TaskID); err != nil {
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) MysqlRecover(req dto.CommonRecover) error {
|
||||
if err := handleMysqlRecover(req, nil, false, req.TaskID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return handleMysqlRecover(req, nil, false, req.TaskID)
|
||||
}
|
||||
|
||||
func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
@@ -64,14 +65,14 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
return err
|
||||
}
|
||||
req.File = recoveFile
|
||||
|
||||
if err := handleMysqlRecover(req, nil, false, req.TaskID); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("recover from uploads successful!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir, fileName, taskID string) error {
|
||||
func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint, targetDir, fileName, taskID string) error {
|
||||
var (
|
||||
err error
|
||||
backupTask *task.Task
|
||||
@@ -83,18 +84,25 @@ func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir, file
|
||||
}
|
||||
itemName := fmt.Sprintf("%s[%s] - %s", db.Database, db.DBType, db.Name)
|
||||
if parentTask == nil {
|
||||
backupTask, err = task.NewTaskWithOps(itemName, task.TaskBackup, task.TaskScopeDatabase, taskID, dbInfo.ID)
|
||||
backupTask, err = task.NewTaskWithOps(itemName, task.TaskBackup, task.TaskScopeBackup, taskID, dbInfo.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
itemHandler := func() error { return doMysqlBackup(db, targetDir, fileName) }
|
||||
backupTask.AddSubTask(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeDatabase), func(t *task.Task) error { return itemHandler() }, nil)
|
||||
if parentTask != nil {
|
||||
return itemHandler()
|
||||
}
|
||||
return backupTask.Execute()
|
||||
backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour)
|
||||
go func() {
|
||||
if err := backupTask.Execute(); err != nil {
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback bool, taskID string) error {
|
||||
@@ -109,7 +117,7 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback
|
||||
}
|
||||
itemName := fmt.Sprintf("%s[%s] - %s", req.Name, req.Type, req.DetailName)
|
||||
if parentTask == nil {
|
||||
itemTask, err = task.NewTaskWithOps(itemName, task.TaskRecover, task.TaskScopeDatabase, taskID, dbInfo.ID)
|
||||
itemTask, err = task.NewTaskWithOps(itemName, task.TaskRecover, task.TaskScopeBackup, taskID, dbInfo.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -139,8 +147,6 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: path.Dir(rollbackFile),
|
||||
FileName: path.Base(rollbackFile),
|
||||
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("backup mysql db %s for rollback before recover failed, err: %v", req.DetailName, err)
|
||||
}
|
||||
@@ -153,8 +159,6 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback
|
||||
Version: version,
|
||||
Format: dbInfo.Format,
|
||||
SourceFile: rollbackFile,
|
||||
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("rollback mysql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
|
||||
} else {
|
||||
@@ -172,8 +176,6 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback
|
||||
Version: version,
|
||||
Format: dbInfo.Format,
|
||||
SourceFile: req.File,
|
||||
|
||||
Timeout: 300,
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("recover mysql db %s from %s failed, err: %v", req.DetailName, req.File, err)
|
||||
return err
|
||||
@@ -181,12 +183,15 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback
|
||||
isOk = true
|
||||
return nil
|
||||
}
|
||||
itemTask.AddSubTask(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil)
|
||||
if parentTask != nil {
|
||||
return recoverDatabase(parentTask)
|
||||
}
|
||||
|
||||
return itemTask.Execute()
|
||||
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 3, time.Hour)
|
||||
go func() {
|
||||
_ = itemTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func doMysqlBackup(db DatabaseHelper, targetDir, fileName string) error {
|
||||
@@ -205,8 +210,6 @@ func doMysqlBackup(db DatabaseHelper, targetDir, fileName string) error {
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: targetDir,
|
||||
FileName: fileName,
|
||||
|
||||
Timeout: 300,
|
||||
}
|
||||
return cli.Backup(backupInfo)
|
||||
}
|
||||
|
||||
@@ -29,11 +29,6 @@ func (u *BackupService) PostgresqlBackup(req dto.CommonBackup) error {
|
||||
targetDir := path.Join(global.Dir.LocalBackupDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName}
|
||||
if err := handlePostgresqlBackup(databaseHelper, nil, targetDir, fileName, req.TaskID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record := &model.BackupRecord{
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
@@ -42,11 +37,18 @@ func (u *BackupService) PostgresqlBackup(req dto.CommonBackup) error {
|
||||
DownloadAccountID: 1,
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
TaskID: req.TaskID,
|
||||
Status: constant.StatusWaiting,
|
||||
Description: req.Description,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
}
|
||||
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName}
|
||||
if err := handlePostgresqlBackup(databaseHelper, nil, record.ID, targetDir, fileName, req.TaskID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (u *BackupService) PostgresqlRecover(req dto.CommonRecover) error {
|
||||
@@ -69,7 +71,7 @@ func (u *BackupService) PostgresqlRecoverByUpload(req dto.CommonRecover) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir, fileName, taskID string) error {
|
||||
func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint, targetDir, fileName, taskID string) error {
|
||||
var (
|
||||
err error
|
||||
backupTask *task.Task
|
||||
@@ -77,18 +79,25 @@ func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir,
|
||||
backupTask = parentTask
|
||||
itemName := fmt.Sprintf("%s - %s", db.Database, db.Name)
|
||||
if parentTask == nil {
|
||||
backupTask, err = task.NewTaskWithOps(itemName, task.TaskBackup, task.TaskScopeDatabase, taskID, db.ID)
|
||||
backupTask, err = task.NewTaskWithOps(itemName, task.TaskBackup, task.TaskScopeBackup, taskID, db.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
itemHandler := func() error { return doPostgresqlgBackup(db, targetDir, fileName) }
|
||||
backupTask.AddSubTask(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeDatabase), func(task *task.Task) error { return itemHandler() }, nil)
|
||||
if parentTask != nil {
|
||||
return itemHandler()
|
||||
}
|
||||
return backupTask.Execute()
|
||||
backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour)
|
||||
go func() {
|
||||
if err := backupTask.Execute(); err != nil {
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback bool) error {
|
||||
@@ -102,7 +111,7 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
|
||||
}
|
||||
itemTask = parentTask
|
||||
if parentTask == nil {
|
||||
itemTask, err = task.NewTaskWithOps(req.Name, task.TaskRecover, task.TaskScopeDatabase, req.TaskID, dbInfo.ID)
|
||||
itemTask, err = task.NewTaskWithOps(req.Name, task.TaskRecover, task.TaskScopeBackup, req.TaskID, dbInfo.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -163,12 +172,15 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
|
||||
isOk = true
|
||||
return nil
|
||||
}
|
||||
itemTask.AddSubTask(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil)
|
||||
if parentTask != nil {
|
||||
return recoverDatabase(parentTask)
|
||||
}
|
||||
|
||||
return itemTask.Execute()
|
||||
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 3, time.Hour)
|
||||
go func() {
|
||||
_ = itemTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func doPostgresqlgBackup(db DatabaseHelper, targetDir, fileName string) error {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
@@ -239,6 +240,9 @@ func (u *BackupRecordService) LoadRecordSize(req dto.SearchForSize) ([]dto.Recor
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range records {
|
||||
if item.Status == constant.StatusWaiting {
|
||||
continue
|
||||
}
|
||||
list = append(list, backupSizeHelper{ID: item.ID, DownloadID: item.DownloadAccountID, FilePath: path.Join(item.FileDir, item.FileName)})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,22 +44,24 @@ func (u *BackupService) RedisBackup(req dto.CommonBackup) error {
|
||||
}
|
||||
itemDir := fmt.Sprintf("database/redis/%s", redisInfo.Name)
|
||||
backupDir := path.Join(global.Dir.LocalBackupDir, itemDir)
|
||||
if err := handleRedisBackup(redisInfo, nil, backupDir, fileName, req.Secret, req.TaskID); err != nil {
|
||||
return err
|
||||
}
|
||||
record := &model.BackupRecord{
|
||||
Type: "redis",
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
SourceAccountIDs: "1",
|
||||
DownloadAccountID: 1,
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
TaskID: req.TaskID,
|
||||
Status: constant.StatusWaiting,
|
||||
Description: req.Description,
|
||||
}
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
}
|
||||
|
||||
if err := handleRedisBackup(redisInfo, nil, record.ID, backupDir, fileName, req.Secret, req.TaskID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -75,15 +77,14 @@ func (u *BackupService) RedisRecover(req dto.CommonRecover) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDir, fileName, secret, taskID string) error {
|
||||
|
||||
func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, recordID uint, backupDir, fileName, secret, taskID string) error {
|
||||
var (
|
||||
err error
|
||||
itemTask *task.Task
|
||||
)
|
||||
itemTask = parentTask
|
||||
if parentTask == nil {
|
||||
itemTask, err = task.NewTaskWithOps("Redis", task.TaskBackup, task.TaskScopeDatabase, taskID, redisInfo.ID)
|
||||
itemTask, err = task.NewTaskWithOps("Redis", task.TaskBackup, task.TaskScopeBackup, taskID, redisInfo.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -128,6 +129,14 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi
|
||||
return backupDatabase(parentTask)
|
||||
}
|
||||
|
||||
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskBackup"), backupDatabase, nil, 3, time.Hour)
|
||||
go func() {
|
||||
if err := itemTask.Execute(); err != nil {
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||
}()
|
||||
return itemTask.Execute()
|
||||
}
|
||||
|
||||
@@ -138,7 +147,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, parentTask *task.Task, recover
|
||||
)
|
||||
itemTask = parentTask
|
||||
if parentTask == nil {
|
||||
itemTask, err = task.NewTaskWithOps("Redis", task.TaskRecover, task.TaskScopeDatabase, taskID, redisInfo.ID)
|
||||
itemTask, err = task.NewTaskWithOps("Redis", task.TaskRecover, task.TaskScopeBackup, taskID, redisInfo.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -180,7 +189,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, parentTask *task.Task, recover
|
||||
}
|
||||
}
|
||||
rollbackFile := path.Join(global.Dir.TmpDir, fmt.Sprintf("database/redis/%s_%s.%s", redisInfo.Name, time.Now().Format(constant.DateTimeSlimLayout), suffix))
|
||||
if err := handleRedisBackup(redisInfo, nil, path.Dir(rollbackFile), path.Base(rollbackFile), secret, ""); err != nil {
|
||||
if err := handleRedisBackup(redisInfo, nil, 0, path.Dir(rollbackFile), path.Base(rollbackFile), secret, ""); err != nil {
|
||||
return fmt.Errorf("backup database %s for rollback before recover failed, err: %v", redisInfo.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
@@ -230,5 +239,8 @@ func handleRedisRecover(redisInfo *repo.RootInfo, parentTask *task.Task, recover
|
||||
return recoverDatabase(parentTask)
|
||||
}
|
||||
|
||||
return itemTask.Execute()
|
||||
go func() {
|
||||
_ = itemTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,26 +38,26 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
backupDir := path.Join(global.Dir.LocalBackupDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", website.Alias, timeNow+common.RandStrAndNum(5))
|
||||
|
||||
go func() {
|
||||
if err = handleWebsiteBackup(&website, nil, backupDir, fileName, "", req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("backup website %s failed, err: %v", website.Alias, err)
|
||||
return
|
||||
}
|
||||
record := &model.BackupRecord{
|
||||
Type: "website",
|
||||
Name: website.Alias,
|
||||
DetailName: website.Alias,
|
||||
SourceAccountIDs: "1",
|
||||
DownloadAccountID: 1,
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
Description: req.Description,
|
||||
}
|
||||
if err = backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
record := &model.BackupRecord{
|
||||
Type: "website",
|
||||
Name: website.Alias,
|
||||
DetailName: website.Alias,
|
||||
SourceAccountIDs: "1",
|
||||
DownloadAccountID: 1,
|
||||
FileDir: itemDir,
|
||||
FileName: fileName,
|
||||
TaskID: req.TaskID,
|
||||
Status: constant.StatusWaiting,
|
||||
Description: req.Description,
|
||||
}
|
||||
if err = backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
if err = handleWebsiteBackup(&website, nil, record.ID, backupDir, fileName, "", req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("backup website %s failed, err: %v", website.Alias, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -66,40 +66,34 @@ func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if err := handleWebsiteRecover(&website, req.File, false, req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("recover website %s failed, err: %v", website.Alias, err)
|
||||
}
|
||||
}()
|
||||
if err := handleWebsiteRecover(&website, nil, req.File, false, req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("recover website %s failed, err: %v", website.Alias, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback bool, secret, taskID string) error {
|
||||
recoverTask, err := task.NewTaskWithOps(website.PrimaryDomain, task.TaskRecover, task.TaskScopeWebsite, taskID, website.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
func handleWebsiteRecover(website *model.Website, parentTask *task.Task, recoverFile string, isRollback bool, secret, taskID string) error {
|
||||
var (
|
||||
err error
|
||||
recoverTask *task.Task
|
||||
isOk = false
|
||||
rollbackFile string
|
||||
)
|
||||
recoverTask = parentTask
|
||||
if parentTask == nil {
|
||||
recoverTask, err = task.NewTaskWithOps(website.PrimaryDomain, task.TaskRecover, task.TaskScopeBackup, taskID, website.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
recoverTask.AddSubTask(task.GetTaskName(website.PrimaryDomain, task.TaskRecover, task.TaskScopeWebsite), func(t *task.Task) error {
|
||||
isOk := false
|
||||
recoverWebsite := func(t *task.Task) error {
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.Dir.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format(constant.DateTimeSlimLayout)))
|
||||
if err := handleWebsiteBackup(website, recoverTask, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil {
|
||||
rollbackFile = path.Join(global.Dir.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format(constant.DateTimeSlimLayout)))
|
||||
if err := handleWebsiteBackup(website, recoverTask, 0, path.Dir(rollbackFile), path.Base(rollbackFile), "", "", taskID); err != nil {
|
||||
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
|
||||
}
|
||||
defer func() {
|
||||
if !isOk {
|
||||
t.LogStart(i18n.GetMsgByKey("Rollback"))
|
||||
if err := handleWebsiteRecover(website, rollbackFile, true, "", taskID); err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("Rollback"), err)
|
||||
return
|
||||
}
|
||||
t.LogSuccess(i18n.GetMsgByKey("Rollback"))
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
} else {
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
t.Log(i18n.GetWithName("DeCompressFile", recoverFile))
|
||||
@@ -151,12 +145,10 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
taskName := task.GetTaskName(app.Name, task.TaskRecover, task.TaskScopeApp)
|
||||
t.LogStart(taskName)
|
||||
if err := handleAppRecover(&app, recoverTask, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true, "", ""); err != nil {
|
||||
t.LogFailedWithErr(taskName, err)
|
||||
return err
|
||||
}
|
||||
t.LogSuccess(taskName)
|
||||
if _, err = compose.DownAndUp(fmt.Sprintf("%s/%s/%s/docker-compose.yml", global.Dir.AppInstallDir, app.App.Key, app.Name)); err != nil {
|
||||
t.LogFailedWithErr("Run", err)
|
||||
return err
|
||||
}
|
||||
case constant.Runtime:
|
||||
@@ -167,7 +159,6 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
taskName := task.GetTaskName(runtime.Name, task.TaskRecover, task.TaskScopeRuntime)
|
||||
t.LogStart(taskName)
|
||||
if err := handleRuntimeRecover(runtime, fmt.Sprintf("%s/%s.runtime.tar.gz", tmpPath, website.Alias), true, ""); err != nil {
|
||||
t.LogFailedWithErr(taskName, err)
|
||||
return err
|
||||
}
|
||||
t.LogSuccess(taskName)
|
||||
@@ -186,7 +177,6 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
taskName := i18n.GetMsgByKey("TaskRecover") + i18n.GetMsgByKey("websiteDir")
|
||||
t.Log(taskName)
|
||||
if err = fileOp.TarGzExtractPro(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), GetOpenrestyDir(SitesRootDir), ""); err != nil {
|
||||
t.LogFailedWithErr(taskName, err)
|
||||
return err
|
||||
}
|
||||
stdout, err := cmd.RunDefaultWithStdoutBashCf("docker exec -i %s nginx -s reload", nginxInfo.ContainerName)
|
||||
@@ -199,28 +189,60 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
}
|
||||
isOk = true
|
||||
return nil
|
||||
}, nil)
|
||||
return recoverTask.Execute()
|
||||
}
|
||||
|
||||
if parentTask != nil {
|
||||
return recoverWebsite(parentTask)
|
||||
}
|
||||
|
||||
rollBackWebsite := func(t *task.Task) {
|
||||
if isRollback {
|
||||
return
|
||||
}
|
||||
if !isOk {
|
||||
t.Log(i18n.GetMsgByKey("RecoverFailedStartRollBack"))
|
||||
if err := handleWebsiteRecover(website, t, rollbackFile, true, "", ""); err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("Rollback"), err)
|
||||
return
|
||||
}
|
||||
t.LogSuccess(i18n.GetMsgByKey("Rollback"))
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
} else {
|
||||
_ = os.RemoveAll(rollbackFile)
|
||||
}
|
||||
}
|
||||
recoverTask.AddSubTask(task.GetTaskName(website.PrimaryDomain, task.TaskRecover, task.TaskScopeBackup), recoverWebsite, rollBackWebsite)
|
||||
go func() {
|
||||
_ = recoverTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleWebsiteBackup(website *model.Website, parentTask *task.Task, backupDir, fileName, excludes, secret, taskID string) error {
|
||||
func handleWebsiteBackup(website *model.Website, parentTask *task.Task, recordID uint, backupDir, fileName, excludes, secret, taskID string) error {
|
||||
var (
|
||||
err error
|
||||
backupTask *task.Task
|
||||
)
|
||||
backupTask = parentTask
|
||||
if parentTask == nil {
|
||||
backupTask, err = task.NewTaskWithOps(website.Alias, task.TaskBackup, task.TaskScopeWebsite, taskID, website.ID)
|
||||
backupTask, err = task.NewTaskWithOps(website.Alias, task.TaskBackup, task.TaskScopeBackup, taskID, website.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
itemHandler := func() error { return doWebsiteBackup(website, backupTask, backupDir, fileName, excludes, secret) }
|
||||
backupTask.AddSubTask(task.GetTaskName(website.Alias, task.TaskBackup, task.TaskScopeWebsite), func(t *task.Task) error { return itemHandler() }, nil)
|
||||
if parentTask != nil {
|
||||
return itemHandler()
|
||||
}
|
||||
return backupTask.Execute()
|
||||
backupTask.AddSubTaskWithOps(task.GetTaskName(website.Alias, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour)
|
||||
go func() {
|
||||
if err := backupTask.Execute(); err != nil {
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func doWebsiteBackup(website *model.Website, parentTask *task.Task, backupDir, fileName, excludes, secret string) error {
|
||||
@@ -252,7 +274,7 @@ func doWebsiteBackup(website *model.Website, parentTask *task.Task, backupDir, f
|
||||
return err
|
||||
}
|
||||
parentTask.LogStart(task.GetTaskName(app.Name, task.TaskBackup, task.TaskScopeApp))
|
||||
if err = handleAppBackup(&app, parentTask, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes, "", ""); err != nil {
|
||||
if err = handleAppBackup(&app, parentTask, 0, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes, "", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
parentTask.LogSuccess(task.GetTaskName(app.Name, task.TaskBackup, task.TaskScopeApp))
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/alert_push"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/clam"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/systemctl"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
"github.com/jinzhu/copier"
|
||||
@@ -238,6 +240,7 @@ func (c *ClamService) Update(req dto.ClamUpdate) error {
|
||||
upMap["infected_dir"] = req.InfectedDir
|
||||
upMap["infected_strategy"] = req.InfectedStrategy
|
||||
upMap["spec"] = req.Spec
|
||||
upMap["timeout"] = req.Timeout
|
||||
upMap["description"] = req.Description
|
||||
if err := clamRepo.Update(req.ID, upMap); err != nil {
|
||||
return err
|
||||
@@ -339,6 +342,9 @@ func (c *ClamService) SearchRecords(req dto.ClamLogSearch) (int64, interface{},
|
||||
if clam.ID == 0 {
|
||||
return 0, nil, buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
loc, _ := time.LoadLocation(common.LoadTimeZoneByCmd())
|
||||
req.StartTime = req.StartTime.In(loc)
|
||||
req.EndTime = req.EndTime.In(loc)
|
||||
|
||||
total, records, err := clamRepo.PageRecords(req.Page, req.PageSize, clamRepo.WithByClamID(req.ClamID), repo.WithByStatus(req.Status), repo.WithByCreatedAt(req.StartTime, req.EndTime))
|
||||
if err != nil {
|
||||
|
||||
@@ -640,7 +640,6 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
|
||||
}
|
||||
|
||||
var data dto.ContainerOperate
|
||||
data.ContainerID = oldContainer.ID
|
||||
data.Name = strings.ReplaceAll(oldContainer.Name, "/", "")
|
||||
data.Image = oldContainer.Config.Image
|
||||
if oldContainer.NetworkSettings != nil {
|
||||
@@ -702,11 +701,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
newContainer, _ := client.ContainerInspect(ctx, req.Name)
|
||||
if newContainer.ContainerJSONBase != nil && newContainer.ID != req.ContainerID {
|
||||
return buserr.New("ErrContainerName")
|
||||
}
|
||||
oldContainer, err := client.ContainerInspect(ctx, req.ContainerID)
|
||||
oldContainer, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -730,7 +725,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
||||
}, nil)
|
||||
|
||||
taskItem.AddSubTask(i18n.GetWithName("ContainerCreate", req.Name), func(t *task.Task) error {
|
||||
err := client.ContainerRemove(ctx, req.ContainerID, container.RemoveOptions{Force: true})
|
||||
err := client.ContainerRemove(ctx, req.Name, container.RemoveOptions{Force: true})
|
||||
taskItem.LogWithStatus(i18n.GetWithName("ContainerRemoveOld", req.Name), err)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1503,17 +1498,19 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *conta
|
||||
hostConf.DNS = req.DNS
|
||||
config.Volumes = make(map[string]struct{})
|
||||
for _, volume := range req.Volumes {
|
||||
if volume.Type == "volume" {
|
||||
hostConf.Mounts = append(hostConf.Mounts, mount.Mount{
|
||||
Type: mount.Type(volume.Type),
|
||||
Source: volume.SourceDir,
|
||||
Target: volume.ContainerDir,
|
||||
ReadOnly: volume.Mode == "ro",
|
||||
})
|
||||
config.Volumes[volume.ContainerDir] = struct{}{}
|
||||
} else {
|
||||
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
|
||||
item := mount.Mount{
|
||||
Type: mount.Type(volume.Type),
|
||||
Source: volume.SourceDir,
|
||||
Target: volume.ContainerDir,
|
||||
ReadOnly: volume.Mode == "ro",
|
||||
}
|
||||
if volume.Type == "bind" {
|
||||
item.BindOptions = &mount.BindOptions{
|
||||
Propagation: mount.Propagation(volume.Shared),
|
||||
}
|
||||
}
|
||||
hostConf.Mounts = append(hostConf.Mounts, item)
|
||||
config.Volumes[volume.ContainerDir] = struct{}{}
|
||||
}
|
||||
return &config, &hostConf, &networkConf, nil
|
||||
}
|
||||
@@ -1555,6 +1552,7 @@ func loadVolumeBinds(binds []container.MountPoint) []dto.VolumeHelper {
|
||||
if bind.RW {
|
||||
volumeItem.Mode = "rw"
|
||||
}
|
||||
volumeItem.Shared = string(bind.Propagation)
|
||||
datas = append(datas, volumeItem)
|
||||
}
|
||||
return datas
|
||||
|
||||
@@ -36,6 +36,7 @@ type ICronjobService interface {
|
||||
Delete(req dto.CronjobBatchDelete) error
|
||||
StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error)
|
||||
CleanRecord(req dto.CronjobClean) error
|
||||
HandleStop(id uint) error
|
||||
|
||||
Export(req dto.OperateByIDs) (string, error)
|
||||
Import(req []dto.CronjobTrans) error
|
||||
@@ -499,8 +500,8 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
||||
if hasBackup(cronjob.Type) {
|
||||
accountMap := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
|
||||
if !req.CleanRemoteData {
|
||||
for key := range accountMap {
|
||||
if key != constant.Local {
|
||||
for key, val := range accountMap {
|
||||
if val.accountType != constant.Local {
|
||||
delete(accountMap, key)
|
||||
}
|
||||
}
|
||||
@@ -604,7 +605,7 @@ func (u *CronjobService) StartJob(cronjob *model.Cronjob, isUpdate bool) (string
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
}
|
||||
specs := strings.Split(cronjob.Spec, ",")
|
||||
specs := strings.Split(cronjob.Spec, "&&")
|
||||
var ids []string
|
||||
for _, spec := range specs {
|
||||
cronjob.Spec = spec
|
||||
@@ -617,6 +618,20 @@ func (u *CronjobService) StartJob(cronjob *model.Cronjob, isUpdate bool) (string
|
||||
return strings.Join(ids, ","), nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) HandleStop(id uint) error {
|
||||
record, _ := cronjobRepo.GetRecord(repo.WithByID(id))
|
||||
if record.ID == 0 {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
if len(record.TaskID) == 0 {
|
||||
return nil
|
||||
}
|
||||
if cancle, ok := global.TaskCtxMap[record.TaskID]; ok {
|
||||
cancle()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||
for _, id := range req.IDs {
|
||||
cronjob, _ := cronjobRepo.Get(repo.WithByID(id))
|
||||
|
||||
@@ -38,6 +38,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t
|
||||
retry := 0
|
||||
taskItem.AddSubTaskWithOps(task.GetTaskName(app.Name, task.TaskBackup, task.TaskScopeCronjob), func(task *task.Task) error {
|
||||
var record model.BackupRecord
|
||||
record.Status = constant.StatusSuccess
|
||||
record.From = "cronjob"
|
||||
record.Type = "app"
|
||||
record.CronjobID = cronjob.ID
|
||||
@@ -95,6 +96,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||
retry := 0
|
||||
taskItem.AddSubTaskWithOps(task.GetTaskName(web.Alias, task.TaskBackup, task.TaskScopeCronjob), func(task *task.Task) error {
|
||||
var record model.BackupRecord
|
||||
record.Status = constant.StatusSuccess
|
||||
record.From = "cronjob"
|
||||
record.Type = "website"
|
||||
record.CronjobID = cronjob.ID
|
||||
@@ -154,6 +156,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
|
||||
itemName := fmt.Sprintf("%s[%s] - %s", dbInfo.Database, dbInfo.DBType, dbInfo.Name)
|
||||
taskItem.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeCronjob), func(task *task.Task) error {
|
||||
var record model.BackupRecord
|
||||
record.Status = constant.StatusSuccess
|
||||
record.From = "cronjob"
|
||||
record.Type = dbInfo.DBType
|
||||
record.CronjobID = cronjob.ID
|
||||
@@ -238,6 +241,7 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
|
||||
}
|
||||
}
|
||||
var record model.BackupRecord
|
||||
record.Status = constant.StatusSuccess
|
||||
record.From = "cronjob"
|
||||
record.Type = "directory"
|
||||
record.CronjobID = cronjob.ID
|
||||
@@ -273,6 +277,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
|
||||
return err
|
||||
}
|
||||
var record model.BackupRecord
|
||||
record.Status = constant.StatusSuccess
|
||||
record.From = "cronjob"
|
||||
record.Type = "log"
|
||||
record.CronjobID = cronjob.ID
|
||||
@@ -301,6 +306,7 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, jobRecord model.J
|
||||
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
|
||||
}
|
||||
var record model.BackupRecord
|
||||
record.Status = constant.StatusSuccess
|
||||
record.From = "cronjob"
|
||||
record.Type = "snapshot"
|
||||
record.CronjobID = cronjob.ID
|
||||
|
||||
@@ -132,7 +132,8 @@ func (u *CronjobService) loadTask(cronjob *model.Cronjob, record *model.JobRecor
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleShell(cronjob model.Cronjob, taskItem *task.Task) {
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem))
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem), cmd.WithContext(taskItem.TaskCtx))
|
||||
|
||||
taskItem.AddSubTaskWithOps(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error {
|
||||
if len(cronjob.ContainerName) != 0 {
|
||||
scriptItem := cronjob.Script
|
||||
@@ -147,17 +148,21 @@ func (u *CronjobService) handleShell(cronjob model.Cronjob, taskItem *task.Task)
|
||||
command = cronjob.Command
|
||||
}
|
||||
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", "-u", cronjob.User, cronjob.ContainerName, command, "-c", scriptItem)
|
||||
}
|
||||
return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(scriptItem, "\"", "\\\""))
|
||||
return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", scriptItem)
|
||||
}
|
||||
if len(cronjob.Executor) == 0 {
|
||||
cronjob.Executor = "bash"
|
||||
}
|
||||
if cronjob.ScriptMode == "input" {
|
||||
fileItem := pathUtils.Join(global.Dir.DataDir, "task", "shell", cronjob.Name, cronjob.Name+".sh")
|
||||
suffix := ".sh"
|
||||
if strings.HasPrefix(cronjob.Executor, "python") {
|
||||
suffix = ".py"
|
||||
}
|
||||
fileItem := pathUtils.Join(global.Dir.DataDir, "task", "shell", cronjob.Name, cronjob.Name+suffix)
|
||||
_ = os.MkdirAll(pathUtils.Dir(fileItem), os.ModePerm)
|
||||
shellFile, err := os.OpenFile(fileItem, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
||||
shellFile, err := os.OpenFile(fileItem, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, constant.DirPerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -217,6 +222,7 @@ func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime t
|
||||
for _, website := range websites {
|
||||
taskItem.Log(website.Alias)
|
||||
var record model.BackupRecord
|
||||
record.Status = constant.StatusSuccess
|
||||
record.From = "cronjob"
|
||||
record.Type = "cut-website-log"
|
||||
record.CronjobID = cronjob.ID
|
||||
|
||||
+51
-31
@@ -12,9 +12,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ntp"
|
||||
@@ -231,40 +233,58 @@ func (u *DeviceService) UpdatePasswd(req dto.ChangePasswd) error {
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdateSwap(req dto.SwapHelper) error {
|
||||
if cmd.CheckIllegal(req.Path) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
if !req.IsNew {
|
||||
std, err := cmd.RunDefaultWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle swapoff %s failed, err: %s", req.Path, std)
|
||||
}
|
||||
}
|
||||
if req.Size == 0 {
|
||||
if req.Path == path.Join(global.Dir.BaseDir, ".1panel_swap") {
|
||||
_ = os.Remove(path.Join(global.Dir.BaseDir, ".1panel_swap"))
|
||||
}
|
||||
return operateSwapWithFile(true, req)
|
||||
}
|
||||
stdDD, err := cmd.RunDefaultWithStdoutBashCf("%s dd if=/dev/zero of=%s bs=1024 count=%d", cmd.SudoHandleCmd(), req.Path, req.Size)
|
||||
taskItem, err := task.NewTaskWithOps(req.Path, task.TaskSwapSet, task.TaskScopeSystem, req.TaskID, 1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle dd %s failed, std: %s, err: %s", req.Path, stdDD, err)
|
||||
}
|
||||
stdChmod, err := cmd.RunDefaultWithStdoutBashCf("%s chmod 0600 %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle chmod 0600 %s failed,std: %s, err: %s", req.Path, stdChmod, err)
|
||||
}
|
||||
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)
|
||||
global.LOG.Errorf("new task for create container failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
stdSwapon, err := cmd.RunDefaultWithStdoutBashCf("%s swapon %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
_, _ = cmd.RunDefaultWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path)
|
||||
return fmt.Errorf("handle swapoff %s failed,std: %s, err: %s", req.Path, stdSwapon, err)
|
||||
}
|
||||
return operateSwapWithFile(false, req)
|
||||
taskItem.AddSubTask(i18n.GetMsgWithMap("SetSwap", map[string]interface{}{"path": req.Path, "size": common.LoadSizeUnit2F(float64(req.Size * 1024))}), func(t *task.Task) error {
|
||||
if cmd.CheckIllegal(req.Path) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem))
|
||||
if !req.IsNew {
|
||||
std, err := cmdMgr.RunWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle swapoff %s failed, err: %s", req.Path, std)
|
||||
}
|
||||
}
|
||||
if req.Size == 0 {
|
||||
if req.Path == path.Join(global.Dir.BaseDir, ".1panel_swap") {
|
||||
_ = os.Remove(path.Join(global.Dir.BaseDir, ".1panel_swap"))
|
||||
}
|
||||
return operateSwapWithFile(true, req)
|
||||
}
|
||||
taskItem.LogStart(i18n.GetMsgByKey("CreateSwap"))
|
||||
stdDD, err := cmdMgr.RunWithStdoutBashCf("%s dd if=/dev/zero of=%s bs=1024 count=%d", cmd.SudoHandleCmd(), req.Path, req.Size)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle dd %s failed, std: %s, err: %s", req.Path, stdDD, err)
|
||||
}
|
||||
|
||||
taskItem.Log("chmod 0600 " + req.Path)
|
||||
stdChmod, err := cmdMgr.RunWithStdoutBashCf("%s chmod 0600 %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle chmod 0600 %s failed,std: %s, err: %s", req.Path, stdChmod, err)
|
||||
}
|
||||
taskItem.LogStart(i18n.GetMsgByKey("FormatSwap"))
|
||||
stdMkswap, err := cmdMgr.RunWithStdoutBashCf("%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)
|
||||
}
|
||||
|
||||
taskItem.LogStart(i18n.GetMsgByKey("EnableSwap"))
|
||||
stdSwapon, err := cmdMgr.RunWithStdoutBashCf("%s swapon %s", cmd.SudoHandleCmd(), req.Path)
|
||||
if err != nil {
|
||||
_, _ = cmdMgr.RunWithStdoutBashCf("%s swapoff %s", cmd.SudoHandleCmd(), req.Path)
|
||||
return fmt.Errorf("handle swapoff %s failed,std: %s, err: %s", req.Path, stdSwapon, err)
|
||||
}
|
||||
return operateSwapWithFile(false, req)
|
||||
}, nil)
|
||||
go func() {
|
||||
_ = taskItem.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) LoadConf(name string) (string, error) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
@@ -74,8 +76,21 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
sort.Slice(upgradeTree.Children, func(i, j int) bool {
|
||||
return common.CompareVersion(upgradeTree.Children[i].Label, upgradeTree.Children[j].Label)
|
||||
})
|
||||
upgradeTree.Children[0].IsCheck = false
|
||||
upgradeTree.Children[0].IsRecommend = false
|
||||
if global.IsMaster {
|
||||
var copiesSeeting model.Setting
|
||||
_ = global.CoreDB.Where("key = ?", "UpgradeBackupCopies").First(&copiesSeeting).Error
|
||||
copies, _ := strconv.Atoi(copiesSeeting.Value)
|
||||
if copies == 0 || copies > len(upgradeTree.Children) {
|
||||
copies = len(upgradeTree.Children)
|
||||
}
|
||||
for i := 0; i < copies; i++ {
|
||||
upgradeTree.Children[i].IsCheck = false
|
||||
upgradeTree.Children[i].IsRecommend = false
|
||||
}
|
||||
} else {
|
||||
upgradeTree.Children[0].IsCheck = false
|
||||
upgradeTree.Children[0].IsRecommend = false
|
||||
}
|
||||
}
|
||||
treeData = append(treeData, upgradeTree)
|
||||
|
||||
@@ -214,7 +229,7 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
}
|
||||
case "task_log":
|
||||
if len(item.Name) == 0 {
|
||||
files, _ := os.ReadDir(path.Join(global.Dir.TaskDir))
|
||||
files, _ := os.ReadDir(global.Dir.TaskDir)
|
||||
if len(files) == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -222,15 +237,10 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
if file.Name() == "ssl" || !file.IsDir() {
|
||||
continue
|
||||
}
|
||||
dropFileOrDir(path.Join(global.Dir.TaskDir, file.Name()))
|
||||
dropTaskLog(path.Join(global.Dir.TaskDir, file.Name()))
|
||||
}
|
||||
_ = taskRepo.DeleteAll()
|
||||
} else {
|
||||
pathItem := path.Join(global.Dir.TaskDir, item.Name)
|
||||
dropFileOrDir(pathItem)
|
||||
if len(item.Name) != 0 {
|
||||
_ = taskRepo.Delete(repo.WithByType(item.Name))
|
||||
}
|
||||
dropTaskLog(path.Join(global.Dir.TaskDir, item.Name))
|
||||
}
|
||||
case "script":
|
||||
dropFileOrDir(path.Join(global.Dir.TmpDir, "script", item.Name))
|
||||
@@ -530,7 +540,6 @@ func loadTreeWithAllFile(isCheck bool, originalPath, treeType, pathItem string,
|
||||
}
|
||||
|
||||
func dropFileOrDir(itemPath string) {
|
||||
global.LOG.Debugf("drop file %s", itemPath)
|
||||
if err := os.RemoveAll(itemPath); err != nil {
|
||||
global.LOG.Errorf("drop file %s failed, err %v", itemPath, err)
|
||||
}
|
||||
@@ -606,6 +615,62 @@ func dropVolumes() (int, int) {
|
||||
return len(res.VolumesDeleted), int(res.SpaceReclaimed)
|
||||
}
|
||||
|
||||
func dropTaskLog(logDir string) {
|
||||
files, err := os.ReadDir(logDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
taskType := path.Base(logDir)
|
||||
var usedTasks []string
|
||||
switch taskType {
|
||||
case "Cronjob":
|
||||
_ = global.DB.Model(&model.JobRecords{}).Where("task_id != ?", "").Select("task_id").Find(&usedTasks).Error
|
||||
case "Snapshot":
|
||||
var (
|
||||
snapIDs []string
|
||||
recoverIDs []string
|
||||
rollbackIDs []string
|
||||
)
|
||||
_ = global.DB.Model(&model.Snapshot{}).Where("task_id != ?", "").Select("task_id").Find(&snapIDs).Error
|
||||
_ = global.DB.Model(&model.Snapshot{}).Where("task_recover_id != ", "").Select("task_id").Find(&recoverIDs).Error
|
||||
_ = global.DB.Model(&model.Snapshot{}).Where("task_rollback_id != ?", "").Select("task_id").Find(&rollbackIDs).Error
|
||||
usedTasks = append(usedTasks, snapIDs...)
|
||||
usedTasks = append(usedTasks, recoverIDs...)
|
||||
usedTasks = append(usedTasks, rollbackIDs...)
|
||||
case "Backup":
|
||||
_ = global.DB.Model(&model.BackupRecord{}).Where("task_id != ?", "").Select("task_id").Find(&usedTasks).Error
|
||||
case "Clam":
|
||||
_ = global.DB.Model(&model.ClamRecord{}).Where("task_id != ?", "").Select("task_id").Find(&usedTasks).Error
|
||||
case "Tamper":
|
||||
xpackDB, err := common.LoadDBConnByPathWithErr(path.Join(global.CONF.Base.InstallDir, "1panel/db/xpack.db"), "xpack.db")
|
||||
if err == nil {
|
||||
_ = xpackDB.Table("tampers").Where("task_id != ?", "").Select("task_id").Find(&usedTasks).Error
|
||||
}
|
||||
case "System":
|
||||
xpackDB, err := common.LoadDBConnByPathWithErr(path.Join(global.CONF.Base.InstallDir, "1panel/db/xpack.db"), "xpack.db")
|
||||
if err == nil {
|
||||
_ = xpackDB.Model("nodes").Where("task_id != ?", "").Select("task_id").Find(&usedTasks).Error
|
||||
}
|
||||
default:
|
||||
dropFileOrDir(logDir)
|
||||
_ = taskRepo.Delete(repo.WithByType(taskType))
|
||||
return
|
||||
}
|
||||
usedMap := make(map[string]struct{})
|
||||
for _, item := range usedTasks {
|
||||
if _, ok := usedMap[item]; !ok {
|
||||
usedMap[item] = struct{}{}
|
||||
}
|
||||
}
|
||||
for _, item := range files {
|
||||
if _, ok := usedMap[strings.TrimSuffix(item.Name(), ".log")]; ok {
|
||||
continue
|
||||
}
|
||||
_ = os.Remove(logDir + "/" + item.Name())
|
||||
}
|
||||
_ = taskRepo.Delete(repo.WithByType(taskType), taskRepo.WithByIDNotIn(usedTasks))
|
||||
}
|
||||
|
||||
func dropWithExclude(pathToDelete string, excludeSubDirs []string, taskItem *task.Task, size *int64, count *int) {
|
||||
entries, err := os.ReadDir(pathToDelete)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
@@ -457,7 +458,7 @@ func restartDocker() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stdout, err := cmd.RunDefaultWithStdoutBashCf("%s restart docker", restartCmd)
|
||||
stdout, err := cmd.NewCommandMgr(cmd.WithTimeout(3*time.Minute)).RunWithStdoutBashCf("%s restart docker", restartCmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to restart Docker: %s", stdout)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ var (
|
||||
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
|
||||
appIgnoreUpgradeRepo = repo.NewIAppIgnoreUpgradeRepo()
|
||||
|
||||
aiRepo = repo.NewIAiRepo()
|
||||
mcpServerRepo = repo.NewIMcpServerRepo()
|
||||
aiRepo = repo.NewIAiRepo()
|
||||
mcpServerRepo = repo.NewIMcpServerRepo()
|
||||
tensorrtLLMRepo = repo.NewITensorRTLLMRepo()
|
||||
|
||||
mysqlRepo = repo.NewIMysqlRepo()
|
||||
postgresqlRepo = repo.NewIPostgresqlRepo()
|
||||
|
||||
@@ -3,7 +3,12 @@ package service
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/convert"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ini_conf"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -66,6 +71,8 @@ type IFileService interface {
|
||||
BatchCheckFiles(req request.FilePathsCheck) []response.ExistFileInfo
|
||||
GetHostMount() []dto.DiskInfo
|
||||
GetUsersAndGroups() (*response.UserGroupResponse, error)
|
||||
Convert(req request.FileConvertRequest)
|
||||
ConvertLog(req dto.PageInfo) (int64, []response.FileConvertLog, error)
|
||||
}
|
||||
|
||||
var filteredPaths = []string{
|
||||
@@ -554,6 +561,19 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||
logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
||||
case "mariadb-slow-logs":
|
||||
logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
|
||||
case "php-fpm-slow-logs":
|
||||
php, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logFilePath = php.GetSlowLogPath()
|
||||
case constant.Supervisord:
|
||||
configPath := "/etc/supervisord.conf"
|
||||
pathSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorConfigPath))
|
||||
if pathSet.ID != 0 || pathSet.Value != "" {
|
||||
configPath = pathSet.Value
|
||||
}
|
||||
logFilePath, _ = ini_conf.GetIniValue(configPath, "supervisord", "logfile")
|
||||
}
|
||||
|
||||
file, err := os.Open(logFilePath)
|
||||
@@ -723,3 +743,103 @@ func getValidUsers(validGroups map[string]bool) ([]response.UserInfo, map[string
|
||||
}
|
||||
return users, groupSet, nil
|
||||
}
|
||||
|
||||
func (f *FileService) Convert(req request.FileConvertRequest) {
|
||||
convertTask, err := task.NewTaskWithOps(i18n.GetMsgByKey("FileConvert"), task.TaskExec, task.TaskScopeFileConvert, req.TaskID, 1)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("Create convert task failed %v", err)
|
||||
return
|
||||
}
|
||||
convertTask.AddSubTask(task.GetTaskName(i18n.GetMsgByKey("FileConvert"), task.TaskExec, task.TaskScopeFileConvert), func(t *task.Task) (err error) {
|
||||
for _, file := range req.Files {
|
||||
input := filepath.Join(file.Path, file.InputFile)
|
||||
nameOnly := file.InputFile[0 : len(file.InputFile)-len(file.Extension)]
|
||||
output := filepath.Join(req.OutputPath, nameOnly+"."+file.OutputFormat)
|
||||
status, errMsg := convert.MediaFile(input, output, file.OutputFormat, req.DeleteSource)
|
||||
if status == "FAILED" {
|
||||
convertTask.Log(fmt.Sprintf("%s -> %s [%s]: %s\n",
|
||||
input, output, status, errMsg))
|
||||
} else {
|
||||
convertTask.Log(fmt.Sprintf("%s -> %s [%s]: %s\n",
|
||||
input, output, status, "SUCCESS"))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
go func() {
|
||||
_ = convertTask.Execute()
|
||||
}()
|
||||
}
|
||||
|
||||
func (f *FileService) ConvertLog(req dto.PageInfo) (total int64, data []response.FileConvertLog, err error) {
|
||||
logFilePath := filepath.Join(global.Dir.ConvertLogDir, "convert.log")
|
||||
file, err := os.Open(logFilePath)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
const chunkSize = 64 * 1024
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
fileSize := stat.Size()
|
||||
|
||||
var (
|
||||
buf []byte
|
||||
remainder []byte
|
||||
offset = fileSize
|
||||
lines []string
|
||||
)
|
||||
|
||||
pageStart := int64((req.Page - 1) * req.PageSize)
|
||||
pageEnd := pageStart + int64(req.PageSize)
|
||||
|
||||
for offset > 0 {
|
||||
readSize := chunkSize
|
||||
if offset < int64(readSize) {
|
||||
readSize = int(offset)
|
||||
}
|
||||
offset -= int64(readSize)
|
||||
|
||||
tmp := make([]byte, readSize)
|
||||
if _, err := file.ReadAt(tmp, offset); err != nil && err != io.EOF {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
buf = append(tmp, remainder...)
|
||||
linesSplit := strings.Split(string(buf), "\n")
|
||||
|
||||
if offset > 0 {
|
||||
remainder = []byte(linesSplit[0])
|
||||
linesSplit = linesSplit[1:]
|
||||
}
|
||||
|
||||
for i := len(linesSplit) - 1; i >= 0; i-- {
|
||||
line := strings.TrimSpace(linesSplit[i])
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
total++
|
||||
if total > pageStart && total <= pageEnd {
|
||||
lines = append(lines, line)
|
||||
}
|
||||
if total >= pageEnd {
|
||||
break
|
||||
}
|
||||
}
|
||||
if total >= pageEnd {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
var entry response.FileConvertLog
|
||||
if err := json.Unmarshal([]byte(line), &entry); err == nil {
|
||||
data = append(data, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return total, data, nil
|
||||
}
|
||||
|
||||
@@ -329,7 +329,8 @@ func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error {
|
||||
if reqRule.Port == rule.Port &&
|
||||
reqRule.TargetPort == rule.TargetPort &&
|
||||
reqRule.TargetIP == rule.TargetIP &&
|
||||
proto == rule.Protocol {
|
||||
proto == rule.Protocol &&
|
||||
reqRule.Interface == rule.Interface {
|
||||
shouldKeep = false
|
||||
break
|
||||
}
|
||||
@@ -353,7 +354,8 @@ func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error {
|
||||
if reqRule.Port == rule.Port &&
|
||||
reqRule.TargetPort == rule.TargetPort &&
|
||||
reqRule.TargetIP == rule.TargetIP &&
|
||||
proto == rule.Protocol {
|
||||
proto == rule.Protocol &&
|
||||
reqRule.Interface == rule.Interface {
|
||||
return buserr.New("ErrRecordExist")
|
||||
}
|
||||
}
|
||||
@@ -383,6 +385,7 @@ func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error {
|
||||
Port: r.Port,
|
||||
TargetIP: r.TargetIP,
|
||||
TargetPort: r.TargetPort,
|
||||
Interface: r.Interface,
|
||||
}, r.Operation); err != nil {
|
||||
if req.ForceDelete {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -31,7 +31,6 @@ type IHostToolService interface {
|
||||
CreateToolConfig(req request.HostToolCreate) error
|
||||
OperateTool(req request.HostToolReq) error
|
||||
OperateToolConfig(req request.HostToolConfig) (*response.HostToolConfig, error)
|
||||
GetToolLog(req request.HostToolLogReq) (string, error)
|
||||
OperateSupervisorProcess(req request.SupervisorProcessConfig) error
|
||||
GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error)
|
||||
OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error)
|
||||
@@ -261,25 +260,6 @@ func (h *HostToolService) OperateToolConfig(req request.HostToolConfig) (*respon
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (h *HostToolService) GetToolLog(req request.HostToolLogReq) (string, error) {
|
||||
fileOp := files.NewFileOp()
|
||||
logfilePath := ""
|
||||
switch req.Type {
|
||||
case constant.Supervisord:
|
||||
configPath := "/etc/supervisord.conf"
|
||||
pathSet, _ := settingRepo.Get(settingRepo.WithByKey(constant.SupervisorConfigPath))
|
||||
if pathSet.ID != 0 || pathSet.Value != "" {
|
||||
configPath = pathSet.Value
|
||||
}
|
||||
logfilePath, _ = ini_conf.GetIniValue(configPath, "supervisord", "logfile")
|
||||
}
|
||||
oldContent, err := fileOp.GetContent(logfilePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(oldContent), nil
|
||||
}
|
||||
|
||||
func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcessConfig) error {
|
||||
var (
|
||||
supervisordDir = path.Join(global.Dir.DataDir, "tools", "supervisord")
|
||||
@@ -333,6 +313,9 @@ func handleProcess(supervisordDir string, req request.SupervisorProcessConfig, c
|
||||
_, _ = section.NewKey("priority", "999")
|
||||
_, _ = section.NewKey("numprocs", req.Numprocs)
|
||||
_, _ = section.NewKey("process_name", "%(program_name)s_%(process_num)02d")
|
||||
if req.Environment != "" {
|
||||
_, _ = section.NewKey("environment", req.Environment)
|
||||
}
|
||||
|
||||
if err = configFile.SaveTo(iniPath); err != nil {
|
||||
return err
|
||||
@@ -363,6 +346,8 @@ func handleProcess(supervisordDir string, req request.SupervisorProcessConfig, c
|
||||
autoRestart.SetValue(req.AutoRestart)
|
||||
autoStart := section.Key("autostart")
|
||||
autoStart.SetValue(req.AutoStart)
|
||||
environment := section.Key("environment")
|
||||
environment.SetValue(req.Environment)
|
||||
|
||||
if err = configFile.SaveTo(iniPath); err != nil {
|
||||
return err
|
||||
@@ -435,6 +420,9 @@ func handleProcessConfig(configDir, containerName string) ([]response.Supervisor
|
||||
if autoStart, _ := section.GetKey("autostart"); autoStart != nil {
|
||||
config.AutoStart = autoStart.Value()
|
||||
}
|
||||
if environment, _ := section.GetKey("environment"); environment != nil {
|
||||
config.Environment = environment.Value()
|
||||
}
|
||||
_ = getProcessStatus(&config, containerName)
|
||||
result = append(result, config)
|
||||
}
|
||||
|
||||
@@ -256,17 +256,19 @@ func (u *ImageService) ImagePull(req dto.ImagePull) error {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
imageItemName := strings.ReplaceAll(path.Base(req.ImageName), ":", "_")
|
||||
taskItem, err := task.NewTaskWithOps(imageItemName, task.TaskPull, task.TaskScopeImage, req.TaskID, 1)
|
||||
taskItem, err := task.NewTaskWithOps(strings.Join(req.ImageName, ","), task.TaskPull, task.TaskScopeImage, req.TaskID, 1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("new task for image pull failed, err: %v", err)
|
||||
}
|
||||
go func() {
|
||||
taskItem.AddSubTask(i18n.GetWithName("ImagePull", req.ImageName), func(t *task.Task) error {
|
||||
|
||||
for _, item := range req.ImageName {
|
||||
itemName := strings.ReplaceAll(path.Base(item), ":", "_")
|
||||
taskItem.AddSubTask(i18n.GetWithName("ImagePull", itemName), func(t *task.Task) error {
|
||||
taskItem.Logf("----------------- %s -----------------", itemName)
|
||||
options := image.PullOptions{}
|
||||
imageName := req.ImageName
|
||||
imageName := item
|
||||
if req.RepoID == 0 {
|
||||
hasAuth, authStr := loadAuthInfo(req.ImageName)
|
||||
hasAuth, authStr := loadAuthInfo(item)
|
||||
if hasAuth {
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
@@ -288,7 +290,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) error {
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
imageName = repo.DownloadUrl + "/" + req.ImageName
|
||||
imageName = repo.DownloadUrl + "/" + item
|
||||
}
|
||||
dockerCli := docker.NewClientWithExist(client)
|
||||
err = dockerCli.PullImageWithProcessAndOptions(taskItem, imageName, options)
|
||||
@@ -298,6 +300,8 @@ func (u *ImageService) ImagePull(req dto.ImagePull) error {
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
}
|
||||
go func() {
|
||||
_ = taskItem.Execute()
|
||||
}()
|
||||
return nil
|
||||
@@ -359,9 +363,39 @@ func (u *ImageService) ImageTag(req dto.ImageTag) error {
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if err := client.ImageTag(context.TODO(), req.SourceID, req.TargetName); err != nil {
|
||||
imageItem, err := client.ImageInspect(context.Background(), req.SourceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tag := range req.Tags {
|
||||
isNew := true
|
||||
for _, tagOld := range imageItem.RepoTags {
|
||||
if tag == tagOld {
|
||||
isNew = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if isNew {
|
||||
if err := client.ImageTag(context.TODO(), req.SourceID, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, tagOld := range imageItem.RepoTags {
|
||||
isDel := true
|
||||
for _, tag := range req.Tags {
|
||||
if tag == tagOld {
|
||||
isDel = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if isDel {
|
||||
if _, err := client.ImageRemove(context.TODO(), tagOld, image.RemoveOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/cmd/server/mcp"
|
||||
"github.com/1Panel-dev/1Panel/agent/cmd/server/ai"
|
||||
"github.com/1Panel-dev/1Panel/agent/cmd/server/nginx_conf"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
@@ -565,7 +565,7 @@ func handleEnv(mcpServer *model.McpServer) gotenv.Env {
|
||||
func handleCreateParams(mcpServer *model.McpServer, environments []request.Environment, volumes []request.Volume) error {
|
||||
var composeContent []byte
|
||||
if mcpServer.ID == 0 {
|
||||
composeContent = mcp.DefaultMcpCompose
|
||||
composeContent = ai.DefaultMcpCompose
|
||||
} else {
|
||||
composeContent = []byte(mcpServer.DockerCompose)
|
||||
}
|
||||
@@ -680,6 +680,9 @@ func GetWebsiteID() uint {
|
||||
}
|
||||
|
||||
func pullImage(imageType string) {
|
||||
if global.CONF.Base.IsOffLine {
|
||||
return
|
||||
}
|
||||
if imageType == "npx" {
|
||||
if err := docker.PullImage("supercorp/supergateway:latest"); err != nil {
|
||||
global.LOG.Errorf("docker pull mcp image error: %s", err.Error())
|
||||
|
||||
@@ -119,7 +119,16 @@ func updateDefaultServerConfig(enable bool) error {
|
||||
}
|
||||
defaultConfig.FilePath = defaultConfigPath
|
||||
defaultServer := defaultConfig.FindServers()[0]
|
||||
updateDefaultServer(defaultServer, nginxInstall.HttpPort, nginxInstall.HttpsPort, enable)
|
||||
|
||||
includeSSL := false
|
||||
for _, dir := range defaultServer.GetDirectives() {
|
||||
if dir.GetName() == "include" && dir.GetParameters()[0] == "/usr/local/openresty/nginx/conf/ssl/root_ssl.conf" {
|
||||
includeSSL = true
|
||||
break
|
||||
}
|
||||
}
|
||||
updateDefaultServer(defaultServer, nginxInstall.HttpPort, nginxInstall.HttpsPort, enable, includeSSL)
|
||||
|
||||
if err = nginx.WriteConfig(defaultConfig, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -262,11 +271,13 @@ func nginxCheckAndReload(oldContent string, filePath string, containerName strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateDefaultServer(server *components.Server, httpPort int, httpsPort int, defaultServer bool) {
|
||||
func updateDefaultServer(server *components.Server, httpPort int, httpsPort int, defaultServer bool, ssl bool) {
|
||||
server.UpdateListen(fmt.Sprintf("%d", httpPort), defaultServer)
|
||||
server.UpdateListen(fmt.Sprintf("[::]:%d", httpPort), defaultServer)
|
||||
server.UpdateListen(fmt.Sprintf("%d", httpsPort), defaultServer, "ssl")
|
||||
server.UpdateListen(fmt.Sprintf("[::]:%d", httpsPort), defaultServer, "ssl")
|
||||
server.UpdateListen(fmt.Sprintf("%d", httpsPort), defaultServer, "quic", "reuseport")
|
||||
server.UpdateListen(fmt.Sprintf("[::]:%d", httpsPort), defaultServer, "quic", "reuseport")
|
||||
if ssl {
|
||||
server.UpdateListen(fmt.Sprintf("%d", httpsPort), defaultServer, "ssl")
|
||||
server.UpdateListen(fmt.Sprintf("[::]:%d", httpsPort), defaultServer, "ssl")
|
||||
server.UpdateListen(fmt.Sprintf("%d", httpsPort), defaultServer, "quic", "reuseport")
|
||||
server.UpdateListen(fmt.Sprintf("[::]:%d", httpsPort), defaultServer, "quic", "reuseport")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
fcgiclient "github.com/tomasen/fcgi_client"
|
||||
"maps"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -231,6 +232,14 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
detail, _ := appDetailRepo.GetFirst(repo.WithByID(runtime.AppDetailID))
|
||||
if detail.AppId == 0 {
|
||||
appID, appDetailID := handleRuntimeDetailID(runtime)
|
||||
runtimeDTO.AppDetailID = appDetailID
|
||||
runtimeDTO.AppID = appID
|
||||
} else {
|
||||
runtimeDTO.AppID = detail.AppId
|
||||
}
|
||||
for k, v := range envs {
|
||||
runtimeDTO.Params[k] = v
|
||||
if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
|
||||
@@ -381,6 +390,9 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
|
||||
appParam.Value = []string{}
|
||||
} else {
|
||||
appParam.Value = strings.Split(v, ",")
|
||||
if strSlice, ok := appParam.Value.([]string); ok && len(strSlice) > 0 && strSlice[0] == "" {
|
||||
appParam.Value = strSlice[1:]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, fv := range form.Values {
|
||||
@@ -584,7 +596,7 @@ func (r *RuntimeService) GetNodeModules(req request.NodeModuleReq) ([]response.N
|
||||
nodeModulesPath := path.Join(runtime.CodeDir, "node_modules")
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(nodeModulesPath) {
|
||||
return nil, buserr.New("ErrNodeModulesNotFound")
|
||||
return res, nil
|
||||
}
|
||||
moduleDirs, err := os.ReadDir(nodeModulesPath)
|
||||
if err != nil {
|
||||
@@ -617,31 +629,17 @@ func (r *RuntimeService) OperateNodeModules(req request.NodeModuleOperateReq) er
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := req.PkgManager
|
||||
switch req.Operate {
|
||||
case constant.RuntimeInstall:
|
||||
if req.PkgManager == constant.RuntimeNpm {
|
||||
cmd += " install"
|
||||
} else {
|
||||
cmd += " add"
|
||||
}
|
||||
case constant.RuntimeUninstall:
|
||||
if req.PkgManager == constant.RuntimeNpm {
|
||||
cmd += " uninstall"
|
||||
} else {
|
||||
cmd += " remove"
|
||||
}
|
||||
case constant.RuntimeUpdate:
|
||||
if req.PkgManager == constant.RuntimeNpm {
|
||||
cmd += " update"
|
||||
} else {
|
||||
cmd += " upgrade"
|
||||
}
|
||||
}
|
||||
cmd += " " + req.Module
|
||||
operation := getOperation(req.Operate, req.PkgManager)
|
||||
execScript := fmt.Sprintf("%s %s %s", req.PkgManager, operation, req.Module)
|
||||
|
||||
cmdMgr := cmd2.NewCommandMgr(cmd2.WithTimeout(5 * time.Minute))
|
||||
return cmdMgr.Run("docker", "exec", "-i", containerName, "bash", "-c", fmt.Sprintf("'%s'", cmd))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Minute)
|
||||
defer cancel()
|
||||
installCmd := exec.CommandContext(ctx, "docker", "exec", "-i", containerName, "bash", "-c", execScript)
|
||||
output, err := installCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute command: %s, error: %w", string(output), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) SyncForRestart() error {
|
||||
@@ -860,6 +858,10 @@ func (r *RuntimeService) GetPHPConfig(id uint) (*response.PHPConfig, error) {
|
||||
if uploadMaxSize != "" {
|
||||
res.UploadMaxSize = uploadMaxSize
|
||||
}
|
||||
timeout := phpConfig.Key("max_execution_time").Value()
|
||||
if timeout != "" {
|
||||
res.MaxExecutionTime = timeout
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -912,6 +914,15 @@ func (r *RuntimeService) UpdatePHPConfig(req request.PHPConfigUpdate) (err error
|
||||
if matched, _ := regexp.MatchString(patternUpload, line); matched {
|
||||
lines[i] = "upload_max_filesize" + " = " + req.UploadMaxSize
|
||||
}
|
||||
case "max_execution_time":
|
||||
pattern := "^" + regexp.QuoteMeta("max_execution_time") + "\\s*=\\s*.*$"
|
||||
if matched, _ := regexp.MatchString(pattern, line); matched {
|
||||
lines[i] = "max_execution_time" + " = " + req.MaxExecutionTime
|
||||
}
|
||||
patternInput := "^" + regexp.QuoteMeta("max_input_time") + "\\s*=\\s*.*$"
|
||||
if matched, _ := regexp.MatchString(patternInput, line); matched {
|
||||
lines[i] = "max_input_time" + " = " + req.MaxExecutionTime
|
||||
}
|
||||
}
|
||||
}
|
||||
updatedContent := strings.Join(lines, "\n")
|
||||
|
||||
@@ -689,9 +689,15 @@ func checkContainerStatus(name string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func delPHPExtensions(dir, phpExtensionDir, fileName, extName string) {
|
||||
fileOp := files.NewFileOp()
|
||||
_ = fileOp.DeleteFile(path.Join(phpExtensionDir, fileName))
|
||||
_ = fileOp.DeleteFile(path.Join(dir, "conf", "conf.d", "docker-php-ext-"+extName+".ini"))
|
||||
_ = removePHPIniExt(path.Join(dir, "conf", "php.ini"), fileName)
|
||||
}
|
||||
|
||||
func unInstallPHPExtension(runtime *model.Runtime, delExtensions []string) error {
|
||||
dir := runtime.GetPath()
|
||||
fileOP := files.NewFileOp()
|
||||
var phpExtensions []response.SupportExtension
|
||||
if err := json.Unmarshal(nginx_conf.GetWebsiteFile("php_extensions.json"), &phpExtensions); err != nil {
|
||||
return err
|
||||
@@ -700,16 +706,20 @@ func unInstallPHPExtension(runtime *model.Runtime, delExtensions []string) error
|
||||
phpExtensionDir := path.Join(dir, "extensions", getExtensionDir(phpVersion))
|
||||
|
||||
delMap := make(map[string]struct{})
|
||||
for _, ext := range phpExtensions {
|
||||
for _, del := range delExtensions {
|
||||
for _, del := range delExtensions {
|
||||
exist := false
|
||||
for _, ext := range phpExtensions {
|
||||
if ext.Name == del {
|
||||
exist = true
|
||||
delMap[ext.Check] = struct{}{}
|
||||
_ = fileOP.DeleteFile(path.Join(phpExtensionDir, ext.File))
|
||||
_ = fileOP.DeleteFile(path.Join(dir, "conf", "conf.d", "docker-php-ext-"+ext.Check+".ini"))
|
||||
_ = removePHPIniExt(path.Join(dir, "conf", "php.ini"), ext.File)
|
||||
delPHPExtensions(dir, phpExtensionDir, ext.Check, ext.Name)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
delMap[del] = struct{}{}
|
||||
delPHPExtensions(dir, phpExtensionDir, del+".so", del)
|
||||
}
|
||||
}
|
||||
extensions := getRuntimeEnv(runtime.Env, "PHP_EXTENSIONS")
|
||||
var (
|
||||
@@ -1035,3 +1045,31 @@ func HandleOldPHPRuntime() {
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func getOperation(operate, pkgManager string) string {
|
||||
operations := map[string][2]string{
|
||||
constant.RuntimeInstall: {"install", "add"},
|
||||
constant.RuntimeUninstall: {"uninstall", "remove"},
|
||||
constant.RuntimeUpdate: {"update", "upgrade"},
|
||||
}
|
||||
|
||||
ops := operations[operate]
|
||||
if pkgManager == constant.RuntimeNpm {
|
||||
return ops[0]
|
||||
}
|
||||
return ops[1]
|
||||
}
|
||||
|
||||
func handleRuntimeDetailID(runtime model.Runtime) (uint, uint) {
|
||||
app, _ := appRepo.GetFirst(appRepo.WithKey(runtime.Type))
|
||||
if app.ID == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
appDetail, _ := appDetailRepo.GetFirst(appDetailRepo.WithVersion(runtime.Version), appDetailRepo.WithAppId(app.ID))
|
||||
if appDetail.ID == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
runtime.AppDetailID = appDetail.ID
|
||||
_ = runtimeRepo.Save(&runtime)
|
||||
return app.ID, appDetail.ID
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ssh"
|
||||
"github.com/jinzhu/copier"
|
||||
@@ -23,6 +22,7 @@ type ISettingService interface {
|
||||
TestConnByInfo(req dto.SSHConnData) bool
|
||||
SaveConnInfo(req dto.SSHConnData) error
|
||||
GetSystemProxy() (*dto.SystemProxy, error)
|
||||
GetLocalConn() dto.SSHConnData
|
||||
GetSettingByKey(key string) string
|
||||
}
|
||||
|
||||
@@ -119,7 +119,6 @@ func (u *SettingService) SaveConnInfo(req dto.SSHConnData) error {
|
||||
localConn, _ := json.Marshal(&connItem)
|
||||
connAfterEncrypt, _ := encrypt.StringEncrypt(string(localConn))
|
||||
_ = settingRepo.Update("LocalSSHConn", connAfterEncrypt)
|
||||
_ = settingRepo.Update("LocalSSHConnShow", constant.StatusEnable)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -134,6 +133,29 @@ func (u *SettingService) GetSystemProxy() (*dto.SystemProxy, error) {
|
||||
return &systemProxy, nil
|
||||
}
|
||||
|
||||
func (u *SettingService) GetLocalConn() dto.SSHConnData {
|
||||
var data dto.SSHConnData
|
||||
connItem, _ := settingRepo.GetValueByKey("LocalSSHConn")
|
||||
if len(connItem) == 0 {
|
||||
return data
|
||||
}
|
||||
connInfoInDB, _ := encrypt.StringDecrypt(connItem)
|
||||
data.LocalSSHConnShow, _ = settingRepo.GetValueByKey("LocalSSHConnShow")
|
||||
if err := json.Unmarshal([]byte(connInfoInDB), &data); err != nil {
|
||||
return data
|
||||
}
|
||||
if len(data.Password) != 0 {
|
||||
data.Password = base64.StdEncoding.EncodeToString([]byte(data.Password))
|
||||
}
|
||||
if len(data.PrivateKey) != 0 {
|
||||
data.PrivateKey = base64.StdEncoding.EncodeToString([]byte(data.PrivateKey))
|
||||
}
|
||||
if len(data.PassPhrase) != 0 {
|
||||
data.PassPhrase = base64.StdEncoding.EncodeToString([]byte(data.PassPhrase))
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (u *SettingService) GetSettingByKey(key string) string {
|
||||
switch key {
|
||||
case "LocalSSHConn":
|
||||
|
||||
+191
-28
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
@@ -37,15 +38,16 @@ type SSHService struct{}
|
||||
type ISSHService interface {
|
||||
GetSSHInfo() (*dto.SSHInfo, error)
|
||||
OperateSSH(operation string) error
|
||||
UpdateByFile(value string) error
|
||||
Update(req dto.SSHUpdate) error
|
||||
LoadSSHConf() (string, error)
|
||||
LoadSSHFile(name string) (string, error)
|
||||
UpdateByFile(req dto.SettingUpdate) error
|
||||
|
||||
LoadLog(ctx *gin.Context, req dto.SearchSSHLog) (int64, []dto.SSHHistory, error)
|
||||
ExportLog(ctx *gin.Context, req dto.SearchSSHLog) (string, error)
|
||||
|
||||
SyncRootCert() error
|
||||
CreateRootCert(req dto.CreateRootCert) error
|
||||
CreateRootCert(req dto.RootCertOperate) error
|
||||
EditRootCert(req dto.RootCertOperate) error
|
||||
SearchRootCerts(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
DeleteRootCerts(req dto.ForceDelete) error
|
||||
}
|
||||
@@ -208,31 +210,20 @@ func (u *SSHService) Update(req dto.SSHUpdate) error {
|
||||
if err := NewIFirewallService().UpdatePortRule(ruleItem); err != nil {
|
||||
global.LOG.Errorf("reset firewall rules %s -> %s failed, err: %v", req.OldValue, req.NewValue, err)
|
||||
}
|
||||
newPort, _ := strconv.Atoi(req.NewValue)
|
||||
if err := updateLocalConn(uint(newPort)); err != nil {
|
||||
global.LOG.Errorf("update local conn for terminal failed, err: %v", err)
|
||||
}
|
||||
|
||||
if err := updateSSHSocketFile(req.NewValue); err != nil {
|
||||
global.LOG.Errorf("update port for ssh.socket failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = cmd.RunDefaultWithStdoutBashCf("%s systemctl restart %s", sudo, serviceName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SSHService) UpdateByFile(value string) error {
|
||||
serviceName, err := loadServiceName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(sshPath, os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err = file.WriteString(value); err != nil {
|
||||
return err
|
||||
}
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
_, _ = cmd.RunDefaultWithStdoutBashCf("%s systemctl restart %s", sudo, serviceName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SSHService) SyncRootCert() error {
|
||||
currentUser, err := user.Current()
|
||||
if err != nil {
|
||||
@@ -270,7 +261,7 @@ func (u *SSHService) SyncRootCert() error {
|
||||
return hostRepo.SyncCert(rootCerts)
|
||||
}
|
||||
|
||||
func (u *SSHService) CreateRootCert(req dto.CreateRootCert) error {
|
||||
func (u *SSHService) CreateRootCert(req dto.RootCertOperate) error {
|
||||
if cmd.CheckIllegal(req.EncryptionMode, req.PassPhrase) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
@@ -290,6 +281,19 @@ func (u *SSHService) CreateRootCert(req dto.CreateRootCert) error {
|
||||
publicPath := fmt.Sprintf("%s/.ssh/%s.pub", currentUser.HomeDir, req.Name)
|
||||
authFilePath := currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||
|
||||
authFileItem, _ := os.ReadFile(authFilePath)
|
||||
authFile := string(authFileItem)
|
||||
if authFile != "" && !strings.HasSuffix(authFile, "\n") {
|
||||
file, err := os.OpenFile(authFilePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := file.WriteString("\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if req.Mode == "input" || req.Mode == "import" {
|
||||
if err := os.WriteFile(privatePath, []byte(req.PrivateKey), constant.FilePerm); err != nil {
|
||||
return err
|
||||
@@ -318,7 +322,58 @@ func (u *SSHService) CreateRootCert(req dto.CreateRootCert) error {
|
||||
if len(cert.PassPhrase) != 0 {
|
||||
cert.PassPhrase, _ = encrypt.StringEncrypt(cert.PassPhrase)
|
||||
}
|
||||
return hostRepo.CreateCert(&cert)
|
||||
return hostRepo.SaveCert(&cert)
|
||||
}
|
||||
|
||||
func (u *SSHService) EditRootCert(req dto.RootCertOperate) error {
|
||||
currentUser, err := user.Current()
|
||||
if err != nil {
|
||||
return fmt.Errorf("load current user failed, err: %v", err)
|
||||
}
|
||||
certItem, _ := hostRepo.GetCert(repo.WithByID(req.ID))
|
||||
if certItem.ID == 0 {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
oldPublicItem, err := os.ReadFile(certItem.PublicKeyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cert model.RootCert
|
||||
if err := copier.Copy(&cert, req); err != nil {
|
||||
return err
|
||||
}
|
||||
cert.PrivateKeyPath = fmt.Sprintf("%s/.ssh/%s", currentUser.HomeDir, req.Name)
|
||||
cert.PublicKeyPath = fmt.Sprintf("%s/.ssh/%s.pub", currentUser.HomeDir, req.Name)
|
||||
if err := os.WriteFile(cert.PrivateKeyPath, []byte(req.PrivateKey), constant.FilePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(cert.PublicKeyPath, []byte(req.PublicKey), constant.FilePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authFilePath := currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||
authItem, err := os.ReadFile(authFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldPublic := strings.ReplaceAll(string(oldPublicItem), "\n", "")
|
||||
newPublic := strings.ReplaceAll(string(req.PublicKey), "\n", "")
|
||||
lines := strings.Split(string(authItem), "\n")
|
||||
var newFiles []string
|
||||
for i := 0; i < len(lines); i++ {
|
||||
if len(lines[i]) != 0 && lines[i] != oldPublic && lines[i] != newPublic {
|
||||
newFiles = append(newFiles, lines[i])
|
||||
}
|
||||
}
|
||||
newFiles = append(newFiles, newPublic)
|
||||
if err := os.WriteFile(authFilePath, []byte(strings.Join(newFiles, "\n")), constant.FilePerm); err != nil {
|
||||
return fmt.Errorf("refresh authorized_keys failed, err: %v", err)
|
||||
}
|
||||
if len(cert.PassPhrase) != 0 {
|
||||
cert.PassPhrase, _ = encrypt.StringEncrypt(cert.PassPhrase)
|
||||
}
|
||||
return hostRepo.SaveCert(&cert)
|
||||
}
|
||||
|
||||
func (u *SSHService) SearchRootCerts(req dto.SearchWithPage) (int64, interface{}, error) {
|
||||
@@ -491,17 +546,64 @@ func (u *SSHService) ExportLog(ctx *gin.Context, req dto.SearchSSHLog) (string,
|
||||
return tmpFileName, nil
|
||||
}
|
||||
|
||||
func (u *SSHService) LoadSSHConf() (string, error) {
|
||||
if _, err := os.Stat("/etc/ssh/sshd_config"); err != nil {
|
||||
return "", buserr.New("ErrHttpReqNotFound")
|
||||
func (u *SSHService) LoadSSHFile(name string) (string, error) {
|
||||
var fileName string
|
||||
switch name {
|
||||
case "authKeys":
|
||||
currentUser, err := user.Current()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load current user failed, err: %v", err)
|
||||
}
|
||||
fileName = currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||
case "sshdConf":
|
||||
fileName = "/etc/ssh/sshd_config"
|
||||
default:
|
||||
return "", buserr.WithName("ErrNotSupportType", name)
|
||||
}
|
||||
content, err := os.ReadFile("/etc/ssh/sshd_config")
|
||||
if _, err := os.Stat(fileName); err != nil {
|
||||
return "", buserr.WithErr("ErrHttpReqNotFound", err)
|
||||
}
|
||||
content, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(content), nil
|
||||
}
|
||||
|
||||
func (u *SSHService) UpdateByFile(req dto.SettingUpdate) error {
|
||||
var fileName string
|
||||
switch req.Key {
|
||||
case "authKeys":
|
||||
currentUser, err := user.Current()
|
||||
if err != nil {
|
||||
return fmt.Errorf("load current user failed, err: %v", err)
|
||||
}
|
||||
fileName = currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||
case "sshdConf":
|
||||
fileName = "/etc/ssh/sshd_config"
|
||||
default:
|
||||
return buserr.WithName("ErrNotSupportType", req.Key)
|
||||
}
|
||||
file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err = file.WriteString(req.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.Key == "authKeys" {
|
||||
return nil
|
||||
}
|
||||
serviceName, err := loadServiceName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
_, _ = cmd.RunDefaultWithStdoutBashCf("%s systemctl restart %s", sudo, serviceName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func sortFileList(fileNames []sshFileItem) []sshFileItem {
|
||||
if len(fileNames) < 2 {
|
||||
return fileNames
|
||||
@@ -738,3 +840,64 @@ func loadEncryptioMode(content string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func updateLocalConn(newPort uint) error {
|
||||
conn, _ := settingRepo.GetValueByKey("LocalSSHConn")
|
||||
if len(conn) == 0 {
|
||||
return nil
|
||||
}
|
||||
connItem, err := encrypt.StringDecrypt(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var data dto.SSHConnData
|
||||
if err := json.Unmarshal([]byte(connItem), &data); err != nil {
|
||||
return err
|
||||
}
|
||||
data.Port = newPort
|
||||
connNew, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
connNewItem, err := encrypt.StringEncrypt(string(connNew))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return settingRepo.Update("LocalSSHConn", connNewItem)
|
||||
}
|
||||
|
||||
func updateSSHSocketFile(newPort string) error {
|
||||
active, _ := systemctl.IsActive("ssh.socket")
|
||||
if !active {
|
||||
return nil
|
||||
}
|
||||
filepath := "/usr/lib/systemd/system/ssh.socket"
|
||||
file, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(string(file), "\n")
|
||||
for i := 0; i < len(lines); i++ {
|
||||
if strings.HasPrefix(lines[i], "ListenStream=") {
|
||||
parts := strings.Split(lines[i], ":")
|
||||
if len(parts) > 1 {
|
||||
lines[i] = strings.ReplaceAll(lines[i], parts[len(parts)-1], newPort)
|
||||
continue
|
||||
}
|
||||
parts = strings.Split(lines[i], "=")
|
||||
if len(parts) > 1 {
|
||||
lines[i] = strings.ReplaceAll(lines[i], parts[len(parts)-1], newPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
fileItem, err := os.OpenFile(filepath, os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fileItem.Close()
|
||||
if _, err = fileItem.WriteString(strings.Join(lines, "\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = cmd.RunDefaultBashC("systemctl daemon-reload && systemctl restart ssh.socket")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/cmd/server/ai"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/subosito/gotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TensorRTLLMService struct{}
|
||||
|
||||
type ITensorRTLLMService interface {
|
||||
Page(req request.TensorRTLLMSearch) response.TensorRTLLMsRes
|
||||
Create(create request.TensorRTLLMCreate) error
|
||||
Update(req request.TensorRTLLMUpdate) error
|
||||
Delete(id uint) error
|
||||
Operate(req request.TensorRTLLMOperate) error
|
||||
}
|
||||
|
||||
func NewITensorRTLLMService() ITensorRTLLMService {
|
||||
return &TensorRTLLMService{}
|
||||
}
|
||||
|
||||
func (t TensorRTLLMService) Page(req request.TensorRTLLMSearch) response.TensorRTLLMsRes {
|
||||
var (
|
||||
res response.TensorRTLLMsRes
|
||||
items []response.TensorRTLLMDTO
|
||||
)
|
||||
|
||||
total, data, _ := tensorrtLLMRepo.Page(req.PageInfo.Page, req.PageInfo.PageSize)
|
||||
for _, item := range data {
|
||||
_ = syncTensorRTLLMContainerStatus(&item)
|
||||
serverDTO := response.TensorRTLLMDTO{
|
||||
TensorRTLLM: item,
|
||||
}
|
||||
envs, _ := gotenv.Unmarshal(item.Env)
|
||||
serverDTO.Version = envs["VERSION"]
|
||||
serverDTO.ModelDir = envs["MODEL_PATH"]
|
||||
serverDTO.Dir = path.Join(global.Dir.TensorRTLLMDir, item.Name)
|
||||
serverDTO.Image = envs["IMAGE"]
|
||||
serverDTO.Command = envs["COMMAND"]
|
||||
|
||||
for k, v := range envs {
|
||||
if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
|
||||
if strings.Contains(k, "CONTAINER_PORT") {
|
||||
r := regexp.MustCompile(`_(\d+)$`)
|
||||
matches := r.FindStringSubmatch(k)
|
||||
containerPort, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
hostPort, err := strconv.Atoi(envs[fmt.Sprintf("HOST_PORT_%s", matches[1])])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
hostIP := envs[fmt.Sprintf("HOST_IP_%s", matches[1])]
|
||||
if hostIP == "" {
|
||||
hostIP = "0.0.0.0"
|
||||
}
|
||||
serverDTO.ExposedPorts = append(serverDTO.ExposedPorts, request.ExposedPort{
|
||||
ContainerPort: containerPort,
|
||||
HostPort: hostPort,
|
||||
HostIP: hostIP,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
composeByte, err := files.NewFileOp().GetContent(path.Join(global.Dir.TensorRTLLMDir, item.Name, "docker-compose.yml"))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
serverDTO.Environments, err = getDockerComposeEnvironments(composeByte)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
volumes, err := getDockerComposeVolumes(composeByte)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var defaultVolumes = map[string]string{
|
||||
"${MODEL_PATH}": "/models",
|
||||
}
|
||||
for _, volume := range volumes {
|
||||
exist := false
|
||||
for key, value := range defaultVolumes {
|
||||
if key == volume.Source && value == volume.Target {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
serverDTO.Volumes = append(serverDTO.Volumes, volume)
|
||||
}
|
||||
}
|
||||
items = append(items, serverDTO)
|
||||
}
|
||||
res.Total = total
|
||||
res.Items = items
|
||||
return res
|
||||
}
|
||||
|
||||
func handleLLMParams(llm *model.TensorRTLLM, create request.TensorRTLLMCreate) error {
|
||||
var composeContent []byte
|
||||
if llm.ID == 0 {
|
||||
composeContent = ai.DefaultTensorrtLLMCompose
|
||||
} else {
|
||||
composeContent = []byte(llm.DockerCompose)
|
||||
}
|
||||
composeMap := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal(composeContent, &composeMap); err != nil {
|
||||
return err
|
||||
}
|
||||
services, serviceValid := composeMap["services"].(map[string]interface{})
|
||||
if !serviceValid {
|
||||
return buserr.New("ErrFileParse")
|
||||
}
|
||||
serviceName := ""
|
||||
serviceValue := make(map[string]interface{})
|
||||
|
||||
if llm.ID > 0 {
|
||||
serviceName = llm.Name
|
||||
serviceValue = services[serviceName].(map[string]interface{})
|
||||
} else {
|
||||
for name, service := range services {
|
||||
serviceName = name
|
||||
serviceValue = service.(map[string]interface{})
|
||||
break
|
||||
}
|
||||
delete(services, serviceName)
|
||||
}
|
||||
|
||||
delete(serviceValue, "ports")
|
||||
if len(create.ExposedPorts) > 0 {
|
||||
var ports []interface{}
|
||||
for i := range create.ExposedPorts {
|
||||
containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i)
|
||||
hostPortStr := fmt.Sprintf("HOST_PORT_%d", i)
|
||||
hostIPStr := fmt.Sprintf("HOST_IP_%d", i)
|
||||
ports = append(ports, fmt.Sprintf("${%s}:${%s}:${%s}", hostIPStr, hostPortStr, containerPortStr))
|
||||
}
|
||||
serviceValue["ports"] = ports
|
||||
}
|
||||
|
||||
delete(serviceValue, "environment")
|
||||
var environments []interface{}
|
||||
for _, e := range create.Environments {
|
||||
environments = append(environments, fmt.Sprintf("%s=%s", e.Key, e.Value))
|
||||
}
|
||||
if len(environments) > 0 {
|
||||
serviceValue["environment"] = environments
|
||||
}
|
||||
|
||||
var volumes []interface{}
|
||||
var defaultVolumes = map[string]string{
|
||||
"${MODEL_PATH}": "/models",
|
||||
}
|
||||
for k, v := range defaultVolumes {
|
||||
volumes = append(volumes, fmt.Sprintf("%s:%s", k, v))
|
||||
}
|
||||
for _, volume := range create.Volumes {
|
||||
volumes = append(volumes, fmt.Sprintf("%s:%s", volume.Source, volume.Target))
|
||||
}
|
||||
serviceValue["volumes"] = volumes
|
||||
|
||||
services[llm.Name] = serviceValue
|
||||
composeByte, err := yaml.Marshal(composeMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llm.DockerCompose = string(composeByte)
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleLLMEnv(llm *model.TensorRTLLM, create request.TensorRTLLMCreate) gotenv.Env {
|
||||
env := make(gotenv.Env)
|
||||
env["CONTAINER_NAME"] = create.ContainerName
|
||||
env["MODEL_PATH"] = create.ModelDir
|
||||
env["VERSION"] = create.Version
|
||||
env["IMAGE"] = create.Image
|
||||
env["COMMAND"] = create.Command
|
||||
for i, port := range create.ExposedPorts {
|
||||
containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i)
|
||||
hostPortStr := fmt.Sprintf("HOST_PORT_%d", i)
|
||||
hostIPStr := fmt.Sprintf("HOST_IP_%d", i)
|
||||
env[containerPortStr] = strconv.Itoa(port.ContainerPort)
|
||||
env[hostPortStr] = strconv.Itoa(port.HostPort)
|
||||
env[hostIPStr] = port.HostIP
|
||||
}
|
||||
envStr, _ := gotenv.Marshal(env)
|
||||
llm.Env = envStr
|
||||
return env
|
||||
}
|
||||
|
||||
func (t TensorRTLLMService) Create(create request.TensorRTLLMCreate) error {
|
||||
servers, _ := tensorrtLLMRepo.List()
|
||||
for _, server := range servers {
|
||||
if server.ContainerName == create.ContainerName {
|
||||
return buserr.New("ErrContainerName")
|
||||
}
|
||||
if server.Name == create.Name {
|
||||
return buserr.New("ErrNameIsExist")
|
||||
}
|
||||
}
|
||||
for _, export := range create.ExposedPorts {
|
||||
if err := checkPortExist(export.HostPort); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := checkContainerName(create.ContainerName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tensorrtLLMDir := path.Join(global.Dir.TensorRTLLMDir, create.Name)
|
||||
filesOP := files.NewFileOp()
|
||||
if !filesOP.Stat(tensorrtLLMDir) {
|
||||
_ = filesOP.CreateDir(tensorrtLLMDir, 0644)
|
||||
}
|
||||
tensorrtLLM := &model.TensorRTLLM{
|
||||
Name: create.Name,
|
||||
ContainerName: create.ContainerName,
|
||||
Status: constant.StatusStarting,
|
||||
}
|
||||
|
||||
if err := handleLLMParams(tensorrtLLM, create); err != nil {
|
||||
return err
|
||||
}
|
||||
env := handleLLMEnv(tensorrtLLM, create)
|
||||
llmDir := path.Join(global.Dir.TensorRTLLMDir, create.Name)
|
||||
envPath := path.Join(llmDir, ".env")
|
||||
if err := gotenv.Write(env, envPath); err != nil {
|
||||
return err
|
||||
}
|
||||
dockerComposePath := path.Join(llmDir, "docker-compose.yml")
|
||||
if err := filesOP.SaveFile(dockerComposePath, tensorrtLLM.DockerCompose, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
tensorrtLLM.Status = constant.StatusStarting
|
||||
|
||||
if err := tensorrtLLMRepo.Create(tensorrtLLM); err != nil {
|
||||
return err
|
||||
}
|
||||
go startTensorRTLLM(tensorrtLLM)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t TensorRTLLMService) Update(req request.TensorRTLLMUpdate) error {
|
||||
tensorrtLLM, err := tensorrtLLMRepo.GetFirst(repo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tensorrtLLM.ContainerName != req.ContainerName {
|
||||
if err := checkContainerName(req.ContainerName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tensorrtLLM.ContainerName = req.ContainerName
|
||||
if err := handleLLMParams(tensorrtLLM, req.TensorRTLLMCreate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
env := handleLLMEnv(tensorrtLLM, req.TensorRTLLMCreate)
|
||||
envStr, _ := gotenv.Marshal(env)
|
||||
tensorrtLLM.Env = envStr
|
||||
llmDir := path.Join(global.Dir.TensorRTLLMDir, tensorrtLLM.Name)
|
||||
envPath := path.Join(llmDir, ".env")
|
||||
if err := gotenv.Write(env, envPath); err != nil {
|
||||
return err
|
||||
}
|
||||
dockerComposePath := path.Join(llmDir, "docker-compose.yml")
|
||||
if err := files.NewFileOp().SaveFile(dockerComposePath, tensorrtLLM.DockerCompose, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
tensorrtLLM.Status = constant.StatusStarting
|
||||
if err := tensorrtLLMRepo.Save(tensorrtLLM); err != nil {
|
||||
return err
|
||||
}
|
||||
go startTensorRTLLM(tensorrtLLM)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t TensorRTLLMService) Delete(id uint) error {
|
||||
tensorrtLLM, err := tensorrtLLMRepo.GetFirst(repo.WithByID(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
composePath := path.Join(global.Dir.TensorRTLLMDir, tensorrtLLM.Name, "docker-compose.yml")
|
||||
_, _ = compose.Down(composePath)
|
||||
_ = files.NewFileOp().DeleteDir(path.Join(global.Dir.TensorRTLLMDir, tensorrtLLM.Name))
|
||||
return tensorrtLLMRepo.DeleteBy(repo.WithByID(id))
|
||||
}
|
||||
|
||||
func (t TensorRTLLMService) Operate(req request.TensorRTLLMOperate) error {
|
||||
tensorrtLLM, err := tensorrtLLMRepo.GetFirst(repo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
composePath := path.Join(global.Dir.TensorRTLLMDir, tensorrtLLM.Name, "docker-compose.yml")
|
||||
var out string
|
||||
switch req.Operate {
|
||||
case "start":
|
||||
out, err = compose.Up(composePath)
|
||||
tensorrtLLM.Status = constant.StatusRunning
|
||||
case "stop":
|
||||
out, err = compose.Down(composePath)
|
||||
tensorrtLLM.Status = constant.StatusStopped
|
||||
case "restart":
|
||||
out, err = compose.Restart(composePath)
|
||||
tensorrtLLM.Status = constant.StatusRunning
|
||||
}
|
||||
if err != nil {
|
||||
tensorrtLLM.Status = constant.StatusError
|
||||
tensorrtLLM.Message = out
|
||||
}
|
||||
return tensorrtLLMRepo.Save(tensorrtLLM)
|
||||
}
|
||||
|
||||
func startTensorRTLLM(tensorrtLLM *model.TensorRTLLM) {
|
||||
composePath := path.Join(global.Dir.TensorRTLLMDir, tensorrtLLM.Name, "docker-compose.yml")
|
||||
if tensorrtLLM.Status != constant.StatusNormal {
|
||||
_, _ = compose.Down(composePath)
|
||||
}
|
||||
if out, err := compose.Up(composePath); err != nil {
|
||||
tensorrtLLM.Status = constant.StatusError
|
||||
tensorrtLLM.Message = out
|
||||
} else {
|
||||
tensorrtLLM.Status = constant.StatusRunning
|
||||
tensorrtLLM.Message = ""
|
||||
}
|
||||
_ = syncTensorRTLLMContainerStatus(tensorrtLLM)
|
||||
}
|
||||
|
||||
func syncTensorRTLLMContainerStatus(tensorrtLLM *model.TensorRTLLM) error {
|
||||
containerNames := []string{tensorrtLLM.ContainerName}
|
||||
cli, err := docker.NewClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err := cli.ListContainersByName(containerNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(containers) == 0 {
|
||||
if tensorrtLLM.Status == constant.StatusStarting {
|
||||
return nil
|
||||
}
|
||||
tensorrtLLM.Status = constant.StatusStopped
|
||||
return tensorrtLLMRepo.Save(tensorrtLLM)
|
||||
}
|
||||
container := containers[0]
|
||||
switch container.State {
|
||||
case "exited":
|
||||
tensorrtLLM.Status = constant.StatusError
|
||||
case "running":
|
||||
tensorrtLLM.Status = constant.StatusRunning
|
||||
case "paused":
|
||||
tensorrtLLM.Status = constant.StatusStopped
|
||||
case "restarting":
|
||||
tensorrtLLM.Status = constant.StatusRestarting
|
||||
default:
|
||||
if tensorrtLLM.Status != constant.StatusStarting {
|
||||
tensorrtLLM.Status = constant.StatusStopped
|
||||
}
|
||||
}
|
||||
return tensorrtLLMRepo.Save(tensorrtLLM)
|
||||
}
|
||||
@@ -60,6 +60,7 @@ type IWebsiteService interface {
|
||||
UpdateWebsite(req request.WebsiteUpdate) error
|
||||
DeleteWebsite(req request.WebsiteDelete) error
|
||||
GetWebsite(id uint) (response.WebsiteDTO, error)
|
||||
BatchOpWebsite(req request.BatchWebsiteOp) error
|
||||
|
||||
CreateWebsiteDomain(create request.WebsiteDomainCreate) ([]model.WebsiteDomain, error)
|
||||
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
|
||||
@@ -95,6 +96,9 @@ type IWebsiteService interface {
|
||||
ClearProxyCache(req request.NginxCommonReq) error
|
||||
DeleteProxy(req request.WebsiteProxyDel) (err error)
|
||||
|
||||
UpdateCors(req request.CorsConfigReq) error
|
||||
GetCors(websiteID uint) (*request.CorsConfig, error)
|
||||
|
||||
GetAntiLeech(id uint) (*response.NginxAntiLeechRes, error)
|
||||
UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err error)
|
||||
|
||||
@@ -517,6 +521,43 @@ func (w WebsiteService) OpWebsite(req request.WebsiteOp) error {
|
||||
return websiteRepo.Save(context.Background(), &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) BatchOpWebsite(req request.BatchWebsiteOp) error {
|
||||
websites, _ := websiteRepo.List(repo.WithByIDs(req.IDs))
|
||||
opTask, err := task.NewTaskWithOps(i18n.GetMsgByKey("Status"), task.TaskBatch, task.TaskScopeWebsite, req.TaskID, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opWebsiteTask := func(t *task.Task) error {
|
||||
for _, web := range websites {
|
||||
msg := fmt.Sprintf("%s %s", i18n.GetMsgByKey(req.Operate), web.PrimaryDomain)
|
||||
switch req.Operate {
|
||||
case constant.StopWeb, constant.StartWeb:
|
||||
if err := opWebsite(&web, req.Operate); err != nil {
|
||||
t.LogFailedWithErr(msg, err)
|
||||
continue
|
||||
}
|
||||
_ = websiteRepo.Save(context.Background(), &web)
|
||||
case "delete":
|
||||
if err := w.DeleteWebsite(request.WebsiteDelete{
|
||||
ID: web.ID,
|
||||
}); err != nil {
|
||||
t.LogFailedWithErr(msg, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
t.LogSuccess(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
opTask.AddSubTask("", opWebsiteTask, nil)
|
||||
|
||||
go func() {
|
||||
_ = opTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetWebsiteOptions(req request.WebsiteOptionReq) ([]response.WebsiteOption, error) {
|
||||
var options []repo.DBOption
|
||||
if len(req.Types) > 0 {
|
||||
@@ -603,6 +644,36 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
|
||||
return buserr.WithName("ErrParentWebsite", strings.Join(names, ","))
|
||||
}
|
||||
}
|
||||
|
||||
if website.Type == constant.Runtime && req.DeleteDB && website.DbID != 0 {
|
||||
switch website.DbType {
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
mysqlDB, _ := mysqlRepo.Get(repo.WithByID(website.DbID))
|
||||
if mysqlDB.ID > 0 {
|
||||
deleteReq := dto.MysqlDBDelete{
|
||||
ID: mysqlDB.ID,
|
||||
Database: mysqlDB.MysqlName,
|
||||
ForceDelete: req.ForceDelete,
|
||||
}
|
||||
if err = NewIMysqlService().Delete(context.TODO(), deleteReq); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case constant.AppPostgresql, constant.AppPostgres:
|
||||
pgDB, _ := postgresqlRepo.Get(repo.WithByID(website.DbID))
|
||||
if pgDB.ID > 0 {
|
||||
deleteReq := dto.PostgresqlDBDelete{
|
||||
ID: pgDB.ID,
|
||||
ForceDelete: req.ForceDelete,
|
||||
Database: pgDB.PostgresqlName,
|
||||
}
|
||||
if err = NewIPostgresqlService().Delete(context.TODO(), deleteReq); err != nil && !req.ForceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = delNginxConfig(website, req.ForceDelete); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1613,7 +1684,7 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
config, err = parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
config, err = parser.NewStringParser(string(nginx_conf.GetWebsiteFile("proxy.conf"))).Parse()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -1680,6 +1751,35 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
} else {
|
||||
location.UpdateDirective("proxy_ssl_server_name", []string{"off"})
|
||||
}
|
||||
if req.Cors {
|
||||
location.UpdateDirective("add_header", []string{"Access-Control-Allow-Origin", req.AllowOrigins, "always"})
|
||||
if req.AllowMethods != "" {
|
||||
location.UpdateDirective("add_header", []string{"Access-Control-Allow-Methods", req.AllowMethods, "always"})
|
||||
} else {
|
||||
location.RemoveDirective("add_header", []string{"Access-Control-Allow-Methods"})
|
||||
}
|
||||
if req.AllowHeaders != "" {
|
||||
location.UpdateDirective("add_header", []string{"Access-Control-Allow-Headers", req.AllowHeaders, "always"})
|
||||
} else {
|
||||
location.RemoveDirective("add_header", []string{"Access-Control-Allow-Headers"})
|
||||
}
|
||||
if req.AllowCredentials {
|
||||
location.UpdateDirective("add_header", []string{"Access-Control-Allow-Credentials", "true", "always"})
|
||||
} else {
|
||||
location.RemoveDirective("add_header", []string{"Access-Control-Allow-Credentials"})
|
||||
}
|
||||
if req.Preflight {
|
||||
location.AddCorsOption()
|
||||
} else {
|
||||
location.RemoveDirective("if", []string{"(", "$request_method", "=", "'OPTIONS'", ")"})
|
||||
}
|
||||
} else {
|
||||
location.RemoveDirective("add_header", []string{"Access-Control-Allow-Origin"})
|
||||
location.RemoveDirective("add_header", []string{"Access-Control-Allow-Methods"})
|
||||
location.RemoveDirective("add_header", []string{"Access-Control-Allow-Headers"})
|
||||
location.RemoveDirective("add_header", []string{"Access-Control-Allow-Credentials"})
|
||||
location.RemoveDirective("if", []string{"(", "$request_method", "=", "'OPTIONS'", ")"})
|
||||
}
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return buserr.WithErr("ErrUpdateBuWebsite", err)
|
||||
}
|
||||
@@ -1839,6 +1939,12 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e
|
||||
proxyConfig.ProxySSLName = directive.GetParameters()[0]
|
||||
}
|
||||
}
|
||||
proxyConfig.Cors = location.Cors
|
||||
proxyConfig.AllowCredentials = location.AllowCredentials
|
||||
proxyConfig.AllowHeaders = location.AllowHeaders
|
||||
proxyConfig.AllowOrigins = location.AllowOrigins
|
||||
proxyConfig.AllowMethods = location.AllowMethods
|
||||
proxyConfig.Preflight = location.Preflight
|
||||
res = append(res, proxyConfig)
|
||||
}
|
||||
return
|
||||
@@ -1915,6 +2021,65 @@ func (w WebsiteService) DeleteProxy(req request.WebsiteProxyDel) (err error) {
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) UpdateCors(req request.CorsConfigReq) error {
|
||||
website, err := websiteRepo.GetFirst(repo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := []dto.NginxParam{
|
||||
{Name: "add_header", Params: []string{"Access-Control-Allow-Origin"}},
|
||||
{Name: "add_header", Params: []string{"Access-Control-Allow-Methods"}},
|
||||
{Name: "add_header", Params: []string{"Access-Control-Allow-Headers"}},
|
||||
{Name: "add_header", Params: []string{"Access-Control-Allow-Credentials"}},
|
||||
{Name: "if", Params: []string{"(", "$request_method", "=", "'OPTIONS'", ")"}},
|
||||
}
|
||||
if err := deleteNginxConfig(constant.NginxScopeServer, params, &website); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.Cors {
|
||||
return updateWebsiteConfig(website, func(server *components.Server) error {
|
||||
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Origin", req.AllowOrigins, "always"})
|
||||
if req.AllowMethods != "" {
|
||||
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Methods", req.AllowMethods, "always"})
|
||||
}
|
||||
if req.AllowHeaders != "" {
|
||||
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Headers", req.AllowHeaders, "always"})
|
||||
}
|
||||
if req.AllowCredentials {
|
||||
server.UpdateDirective("add_header", []string{"Access-Control-Allow-Credentials", "true", "always"})
|
||||
}
|
||||
if req.Preflight {
|
||||
server.AddCorsOption()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetCors(websiteID uint) (*request.CorsConfig, error) {
|
||||
website, err := websiteRepo.GetFirst(repo.WithByID(websiteID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
server, err := getServer(website)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if server == nil {
|
||||
return nil, nil
|
||||
}
|
||||
cors := &request.CorsConfig{
|
||||
Cors: server.Cors,
|
||||
AllowOrigins: server.AllowOrigins,
|
||||
AllowMethods: server.AllowMethods,
|
||||
AllowHeaders: server.AllowHeaders,
|
||||
AllowCredentials: server.AllowCredentials,
|
||||
Preflight: server.Preflight,
|
||||
}
|
||||
return cors, nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error) {
|
||||
var (
|
||||
website model.Website
|
||||
@@ -3036,6 +3201,10 @@ func (w WebsiteService) UpdateLoadBalance(req request.WebsiteLBUpdate) error {
|
||||
if !fileOp.Stat(filePath) {
|
||||
return nil
|
||||
}
|
||||
oldContent, err := fileOp.GetContent(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parser, err := parser.NewParser(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -3087,10 +3256,7 @@ func (w WebsiteService) UpdateLoadBalance(req request.WebsiteLBUpdate) error {
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return buserr.WithErr("ErrUpdateBuWebsite", err)
|
||||
}
|
||||
if err = opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return nginxCheckAndReload(string(oldContent), filePath, nginxInstall.ContainerName)
|
||||
}
|
||||
|
||||
func (w WebsiteService) DeleteLoadBalance(req request.WebsiteLBDelete) error {
|
||||
|
||||
@@ -626,9 +626,13 @@ func (w WebsiteSSLService) Upload(req request.WebsiteSSLUpload) error {
|
||||
} else {
|
||||
websiteSSL.Pem = string(content)
|
||||
}
|
||||
websiteSSL.CertPath = req.CertificatePath
|
||||
websiteSSL.PrivateKeyPath = req.PrivateKeyPath
|
||||
} else {
|
||||
websiteSSL.PrivateKey = req.PrivateKey
|
||||
websiteSSL.Pem = req.Certificate
|
||||
websiteSSL.CertPath = ""
|
||||
websiteSSL.PrivateKeyPath = ""
|
||||
}
|
||||
|
||||
privateKeyCertBlock, _ := pem.Decode([]byte(websiteSSL.PrivateKey))
|
||||
|
||||
@@ -223,7 +223,7 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
server.UpdateDirective("error_page", []string{"404", "/404.html"})
|
||||
if runtime.Resource == constant.ResourceLocal {
|
||||
server.UpdateRoot(rootIndex)
|
||||
localPath := path.Join(GetSitePath(*website, SiteIndexDir), "index.php")
|
||||
localPath := path.Join(rootIndex, "index.php")
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||
} else {
|
||||
server.UpdateRoot(rootIndex)
|
||||
@@ -249,7 +249,7 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
if parentRuntime.Type == constant.RuntimePHP {
|
||||
if parentRuntime.Resource == constant.ResourceLocal {
|
||||
server.UpdateRoot(rootIndex)
|
||||
localPath := path.Join(nginxInstall.GetPath(), rootIndex, "index.php")
|
||||
localPath := path.Join(rootIndex, "index.php")
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||
} else {
|
||||
server.UpdateRoot(rootIndex)
|
||||
@@ -959,7 +959,7 @@ func opWebsite(website *model.Website, operate string) error {
|
||||
}
|
||||
if runtime.Type == constant.RuntimePHP {
|
||||
if website.ProxyType == constant.RuntimeProxyUnix || website.ProxyType == constant.RuntimeProxyTcp {
|
||||
localPath = path.Join(GetSitePath(*website, SiteIndexDir), "index.php")
|
||||
localPath = path.Join(rootIndex, "index.php")
|
||||
}
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||
} else {
|
||||
@@ -1303,6 +1303,7 @@ const (
|
||||
SiteRootAuthBasicPath = "SiteRootAuthBasicPath"
|
||||
SitePathAuthBasicDir = "SitePathAuthBasicDir"
|
||||
SiteUpstreamDir = "SiteUpstreamDir"
|
||||
SiteCorsPath = "SiteCorsPath"
|
||||
)
|
||||
|
||||
func GetSitePath(website model.Website, confType string) string {
|
||||
@@ -1333,6 +1334,8 @@ func GetSitePath(website model.Website, confType string) string {
|
||||
return path.Join(GteSiteDir(website.Alias), "path_auth")
|
||||
case SiteUpstreamDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "upstream")
|
||||
case SiteCorsPath:
|
||||
return path.Join(GteSiteDir(website.Alias), "cors", "cors.conf")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1481,3 +1484,53 @@ func ParseDomain(domain string) (*model.WebsiteDomain, error) {
|
||||
Port: port,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func updateWebsiteConfig(website model.Website, updateFunc func(server *components.Server) error) error {
|
||||
configPath := GetSitePath(website, SiteConf)
|
||||
nginxContent, err := files.NewFileOp().GetContent(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config, err := parser.NewStringParser(string(nginxContent)).Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.FilePath = configPath
|
||||
servers := config.FindServers()
|
||||
if len(servers) == 0 {
|
||||
return errors.New("nginx config is not valid")
|
||||
}
|
||||
server := servers[0]
|
||||
if err := updateFunc(server); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nginxCheckAndReload(string(nginxContent), configPath, nginxInstall.ContainerName)
|
||||
}
|
||||
|
||||
func getServer(website model.Website) (*components.Server, error) {
|
||||
configPath := GetSitePath(website, SiteConf)
|
||||
nginxContent, err := files.NewFileOp().GetContent(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config, err := parser.NewStringParser(string(nginxContent)).Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
servers := config.FindServers()
|
||||
if len(servers) == 0 {
|
||||
return nil, errors.New("nginx config is not valid")
|
||||
}
|
||||
server := servers[0]
|
||||
return server, nil
|
||||
}
|
||||
|
||||
+24
-14
@@ -25,6 +25,8 @@ type ActionFunc func(*Task) error
|
||||
type RollbackFunc func(*Task)
|
||||
|
||||
type Task struct {
|
||||
TaskCtx context.Context
|
||||
|
||||
Name string
|
||||
TaskID string
|
||||
Logger *log.Logger
|
||||
@@ -69,6 +71,10 @@ const (
|
||||
TaskHandle = "TaskHandle"
|
||||
TaskScan = "TaskScan"
|
||||
TaskExec = "TaskExec"
|
||||
TaskBatch = "TaskBatch"
|
||||
TaskProtect = "TaskProtect"
|
||||
TaskConvert = "TaskConvert"
|
||||
TaskSwapSet = "TaskSwapSet"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -85,8 +91,11 @@ const (
|
||||
TaskScopeContainer = "Container"
|
||||
TaskScopeCompose = "Compose"
|
||||
TaskScopeImage = "Image"
|
||||
TaskScopeBackup = "Backup"
|
||||
TaskScopeRuntimeExtension = "RuntimeExtension"
|
||||
TaskScopeCustomAppstore = "CustomAppstore"
|
||||
TaskScopeTamper = "Tamper"
|
||||
TaskScopeFileConvert = "Convert"
|
||||
)
|
||||
|
||||
func GetTaskName(resourceName, operate, scope string) string {
|
||||
@@ -143,7 +152,9 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e
|
||||
Operate: operate,
|
||||
}
|
||||
taskRepo := repo.NewITaskRepo()
|
||||
task := &Task{Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: taskModel, Writer: writer}
|
||||
ctx, cancle := context.WithCancel(context.Background())
|
||||
global.TaskCtxMap[taskID] = cancle
|
||||
task := &Task{TaskCtx: ctx, Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: taskModel, Writer: writer}
|
||||
return task, nil
|
||||
}
|
||||
|
||||
@@ -151,7 +162,9 @@ func ReNewTaskWithOps(resourceName, operate, scope, taskID string, resourceID ui
|
||||
return ReNewTask(GetTaskName(resourceName, operate, scope), operate, scope, taskID, resourceID)
|
||||
}
|
||||
func ReNewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, error) {
|
||||
if taskID == "" {
|
||||
taskRepo := repo.NewITaskRepo()
|
||||
taskItem, _ := taskRepo.GetFirst(taskRepo.WithByID(taskID))
|
||||
if taskItem.ID == "" {
|
||||
return NewTask(name, operate, taskScope, taskID, resourceID)
|
||||
}
|
||||
logDir := path.Join(global.Dir.TaskDir, taskScope)
|
||||
@@ -167,17 +180,10 @@ func ReNewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task,
|
||||
}
|
||||
writer := bufio.NewWriter(file)
|
||||
logger := log.New(file, "", log.LstdFlags)
|
||||
taskModel := &model.Task{
|
||||
ID: taskID,
|
||||
Name: name,
|
||||
Type: taskScope,
|
||||
LogFile: logPath,
|
||||
Status: constant.StatusExecuting,
|
||||
ResourceID: resourceID,
|
||||
Operate: operate,
|
||||
}
|
||||
taskRepo := repo.NewITaskRepo()
|
||||
task := &Task{Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: taskModel, Writer: writer}
|
||||
logger.Print("\n --------------------------------------------------- \n")
|
||||
taskItem.Status = constant.StatusExecuting
|
||||
task := &Task{Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: &taskItem, Writer: writer}
|
||||
task.updateTask(&taskItem)
|
||||
return task, nil
|
||||
}
|
||||
|
||||
@@ -207,6 +213,7 @@ func (t *Task) AddSubTaskWithIgnoreErr(name string, action ActionFunc) {
|
||||
}
|
||||
|
||||
func (s *SubTask) Execute() error {
|
||||
defer delete(global.TaskCtxMap, s.RootTask.TaskID)
|
||||
subTaskName := s.Name
|
||||
if s.Name == "" {
|
||||
subTaskName = i18n.GetMsgByKey("SubTask")
|
||||
@@ -231,6 +238,9 @@ func (s *SubTask) Execute() error {
|
||||
case err = <-done:
|
||||
if err != nil {
|
||||
s.RootTask.Log(i18n.GetWithNameAndErr("SubTaskFailed", subTaskName, err))
|
||||
if err.Error() == i18n.GetMsgByKey("ErrShutDown") {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
s.RootTask.Log(i18n.GetWithName("SubTaskSuccess", subTaskName))
|
||||
return nil
|
||||
@@ -317,7 +327,7 @@ func (t *Task) LogFailedWithErr(msg string, err error) {
|
||||
}
|
||||
|
||||
func (t *Task) LogSuccess(msg string) {
|
||||
t.Logger.Println(msg + i18n.GetMsgByKey("Success"))
|
||||
t.Logger.Println(msg + " " + i18n.GetMsgByKey("Success"))
|
||||
}
|
||||
func (t *Task) LogSuccessF(format string, v ...any) {
|
||||
t.Logger.Println(fmt.Sprintf(format, v...) + i18n.GetMsgByKey("Success"))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package mcp
|
||||
package ai
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
@@ -6,3 +6,6 @@ import (
|
||||
|
||||
//go:embed compose.yml
|
||||
var DefaultMcpCompose []byte
|
||||
|
||||
//go:embed llm-compose.yml
|
||||
var DefaultTensorrtLLMCompose []byte
|
||||
@@ -0,0 +1,30 @@
|
||||
services:
|
||||
tensorrt-llm:
|
||||
image: ${IMAGE}:${VERSION}
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: always
|
||||
runtime: nvidia
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
networks:
|
||||
- 1panel-network
|
||||
volumes:
|
||||
- ${MODEL_PATH}:/models
|
||||
ipc: host
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 65535
|
||||
hard: 65535
|
||||
stack: 67108864
|
||||
command: ${COMMAND}
|
||||
networks:
|
||||
1panel-network:
|
||||
external: true
|
||||
@@ -2,6 +2,7 @@ base:
|
||||
install_dir: /opt
|
||||
mode: dev
|
||||
is_demo: false
|
||||
is_offline: false
|
||||
|
||||
remote_url:
|
||||
app_repo: https://apps-assets.fit2cloud.com
|
||||
|
||||
@@ -1,4 +1,25 @@
|
||||
[
|
||||
{
|
||||
"name": "amqp",
|
||||
"check": "amqp",
|
||||
"file": "amqp.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "apcu",
|
||||
"check": "apcu",
|
||||
"file": "apcu.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "bcmath",
|
||||
"check": "bcmath",
|
||||
"file": "bcmath.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "ionCube",
|
||||
"check": "ionCube Loader",
|
||||
@@ -41,13 +62,7 @@
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "apcu",
|
||||
"check": "apcu",
|
||||
"file": "apcu.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
|
||||
{
|
||||
"name": "imagick",
|
||||
"check": "imagick",
|
||||
@@ -363,13 +378,7 @@
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "bcmath",
|
||||
"check": "bcmath",
|
||||
"file": "bcmath.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
|
||||
{
|
||||
"name": "pcntl",
|
||||
"check": "pcntl",
|
||||
@@ -383,5 +392,40 @@
|
||||
"file": "sodium.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "gettext",
|
||||
"check": "gettext",
|
||||
"file": "gettext.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "soap",
|
||||
"check": "soap",
|
||||
"file": "soap.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "sysvsem",
|
||||
"check": "sysvsem",
|
||||
"file": "sysvsem.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "sockets",
|
||||
"check": "sockets",
|
||||
"file": "sockets.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "xmlrpc",
|
||||
"check": "xmlrpc",
|
||||
"file": "xmlrpc.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
}
|
||||
]
|
||||
|
||||
@@ -10,7 +10,7 @@ server {
|
||||
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md){
|
||||
return 404;
|
||||
}
|
||||
location ^~ /.well-known{
|
||||
location ^~ /.well-known/acme-challenge {
|
||||
allow all;
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ const (
|
||||
TypeImagePush = "image-push"
|
||||
TypeImageBuild = "image-build"
|
||||
TypeComposeCreate = "compose-create"
|
||||
|
||||
InterruptedMsg = "the task was interrupted due to the restart of the 1panel service"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
+16
-12
@@ -14,6 +14,7 @@ type Base struct {
|
||||
Mode string `mapstructure:"mode"` // xpack [ Enable / Disable ]
|
||||
IsDemo bool `mapstructure:"is_demo"`
|
||||
InstallDir string `mapstructure:"install_dir"`
|
||||
IsOffLine bool `mapstructure:"is_offline"`
|
||||
}
|
||||
|
||||
type RemoteURL struct {
|
||||
@@ -31,18 +32,21 @@ type SystemDir struct {
|
||||
TmpDir string
|
||||
LocalBackupDir string
|
||||
|
||||
AppDir string
|
||||
ResourceDir string
|
||||
AppResourceDir string
|
||||
AppInstallDir string
|
||||
LocalAppResourceDir string
|
||||
LocalAppInstallDir string
|
||||
RemoteAppResourceDir string
|
||||
CustomAppResourceDir string
|
||||
RuntimeDir string
|
||||
RecycleBinDir string
|
||||
SSLLogDir string
|
||||
McpDir string
|
||||
AppDir string
|
||||
ResourceDir string
|
||||
AppResourceDir string
|
||||
AppInstallDir string
|
||||
LocalAppResourceDir string
|
||||
LocalAppInstallDir string
|
||||
RemoteAppResourceDir string
|
||||
CustomAppResourceDir string
|
||||
OfflineAppResourceDir string
|
||||
RuntimeDir string
|
||||
RecycleBinDir string
|
||||
SSLLogDir string
|
||||
McpDir string
|
||||
ConvertLogDir string
|
||||
TensorRTLLMDir string
|
||||
}
|
||||
|
||||
type LogConfig struct {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
badger_db "github.com/1Panel-dev/1Panel/agent/init/cache/db"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
@@ -34,4 +36,6 @@ var (
|
||||
|
||||
AlertBaseJobID cron.EntryID
|
||||
AlertResourceJobID cron.EntryID
|
||||
|
||||
TaskCtxMap = make(map[string]context.CancelFunc)
|
||||
)
|
||||
|
||||
+3
-1
@@ -177,10 +177,12 @@ require (
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/nrdcg/dnspod-go v0.4.0 // indirect
|
||||
github.com/nrdcg/freemyip v0.3.0 // indirect
|
||||
github.com/nrdcg/goacmedns v0.2.0 // indirect
|
||||
github.com/nrdcg/mailinabox v0.2.0 // indirect
|
||||
github.com/nrdcg/namesilo v0.2.1 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/ovh/go-ovh v1.9.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
|
||||
@@ -532,6 +532,8 @@ github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
||||
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
@@ -626,6 +628,8 @@ github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lL
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
|
||||
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM=
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@@ -710,12 +714,16 @@ github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U
|
||||
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
||||
github.com/nrdcg/freemyip v0.3.0 h1:0D2rXgvLwe2RRaVIjyUcQ4S26+cIS2iFwnhzDsEuuwc=
|
||||
github.com/nrdcg/freemyip v0.3.0/go.mod h1:c1PscDvA0ukBF0dwelU/IwOakNKnVxetpAQ863RMJoM=
|
||||
github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0=
|
||||
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
|
||||
github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk=
|
||||
github.com/nrdcg/mailinabox v0.2.0/go.mod h1:0yxqeYOiGyxAu7Sb94eMxHPIOsPYXAjTeA9ZhePhGnc=
|
||||
github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
|
||||
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
@@ -742,6 +750,8 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr
|
||||
github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
|
||||
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/ovh/go-ovh v1.9.0 h1:6K8VoL3BYjVV3In9tPJUdT7qMx9h0GExN9EXx1r2kKE=
|
||||
github.com/ovh/go-ovh v1.9.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
|
||||
@@ -134,6 +134,7 @@ func Init() {
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/tr.yaml")
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/es-ES.yaml")
|
||||
lang := GetLanguageFromDB()
|
||||
global.I18n = i18n.NewLocalizer(bundle, lang)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ ErrApiConfigKeyInvalid: 'API interface key error: {{ .detail }}'
|
||||
ErrApiConfigIPInvalid: 'The IP used to call the API interface is not in the whitelist: {{ .detail }}'
|
||||
ErrApiConfigDisable: 'This interface prohibits the use of API interface calls: {{ .detail }}'
|
||||
ErrApiConfigKeyTimeInvalid: 'API interface timestamp error: {{ .detail }}'
|
||||
ErrShutDown: "Command manually terminated!"
|
||||
|
||||
ErrMinQuickJump: "Please set at least one quick jump entry!"
|
||||
ErrMaxQuickJump: "You can set up to four quick jump entries!"
|
||||
@@ -94,6 +95,7 @@ ErrCustomRuntimes: 'There is an installed runtime environment, please delete it
|
||||
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"
|
||||
ErrDockerComposeCmdNotFound: "The Docker Compose command does not exist, please install this command on the host machine first"
|
||||
UseExistImage: 'Failed to pull image, using existing image'
|
||||
|
||||
#ssh
|
||||
ExportIP: "Login IP"
|
||||
@@ -122,6 +124,7 @@ ErrLogFileToLarge: "The log file exceeds 500MB and cannot be opened"
|
||||
FileDropFailed: "Failed to clean up file {{ .name }}: {{ .err }}"
|
||||
FileDropSuccess: "Successfully cleaned up file {{ .name }}, cleaned {{ .count }} files, freed {{ .size }} disk space"
|
||||
FileDropSum: "File cleanup completed successfully, total {{ .count }} files cleaned, total {{ .size }} disk space freed"
|
||||
ErrBadDecrypt: "Compressed package decryption password error, decompression failed, please check and try again!"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: 'Alias already exists'
|
||||
@@ -140,6 +143,10 @@ ErrSSLValid: 'Certificate file is abnormal, please check the certificate status!
|
||||
ErrWebsiteDir: "Please select a directory within the website directory."
|
||||
ErrComposerFileNotFound: "composer.json file does not exist"
|
||||
ErrRuntimeNoPort: "The runtime environment is not set with a port, please edit the runtime environment first."
|
||||
Status: 'Status'
|
||||
start: 'Start'
|
||||
stop: 'Stop'
|
||||
delete: 'Delete'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: 'The {{ .name }} certificate is being used by a website and cannot be deleted'
|
||||
@@ -241,6 +248,18 @@ NoSuchResource: "No backup content found in the database, skipping..."
|
||||
ErrNotExistUser: 'The current user does not exist, please modify and try again!'
|
||||
ErrBanAction: 'Setting failed. The current {{ .name }} service is unavailable. Please check and try again!'
|
||||
ErrClamdscanNotFound: 'The clamdscan command was not detected, please refer to the documentation to install it!'
|
||||
TaskSwapSet: "Set Swap"
|
||||
SetSwap: "Set Swap {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Create Swap File"
|
||||
FormatSwap: "Format Swap File"
|
||||
EnableSwap: "Enable Swap"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "Clean up historical protection settings"
|
||||
SetTamperWithRules: "Start directory protection according to rules"
|
||||
ProtectDir: "Protect directory {{ .name }}"
|
||||
IgnoreFile: "Protect file {{ .name }}"
|
||||
TamperSetSuccessful: "Protection settings completed, start monitoring the following directories:"
|
||||
|
||||
#waf
|
||||
ErrScope: 'Modifying this configuration is not supported'
|
||||
@@ -313,6 +332,7 @@ TaskDelete: 'Delete'
|
||||
TaskUpgrade: 'Upgrade'
|
||||
TaskUpdate: 'Update'
|
||||
TaskRestart: 'Restart'
|
||||
TaskProtect: "Protect"
|
||||
TaskBackup: 'Backup'
|
||||
TaskRecover: 'Recover'
|
||||
TaskRollback: 'Rollback'
|
||||
@@ -353,6 +373,8 @@ RuntimeExtension: 'Runtime Environment Extension'
|
||||
TaskIsExecuting: 'Task is running'
|
||||
CustomAppstore: 'Custom application warehouse'
|
||||
TaskExec: 'Execute'
|
||||
TaskBatch: "Batch Operation"
|
||||
FileConvert: 'File Conversion'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "Scan {{ .name }}"
|
||||
|
||||
@@ -0,0 +1,509 @@
|
||||
ErrInvalidParams: 'Error en los parámetros de la solicitud: {{ .detail }}'
|
||||
ErrTokenParse: 'Error al generar el token: {{ .detail }}'
|
||||
ErrInitialPassword: 'La contraseña original es incorrecta'
|
||||
ErrInternalServer: 'Error interno del servidor: {{ .detail }}'
|
||||
ErrRecordExist: 'El registro ya existe'
|
||||
ErrRecordNotFound: 'Registro no encontrado'
|
||||
ErrStructTransform: 'Error de conversión de tipo: {{ .err }}'
|
||||
ErrNotLogin: 'Usuario no ha iniciado sesión: {{ .detail }}'
|
||||
ErrPasswordExpired: 'La contraseña actual ha expirado: {{ .detail }}'
|
||||
ErrNotSupportType: 'El sistema no admite el tipo actual: {{ .name }}'
|
||||
ErrProxy: 'Error en la solicitud, por favor revise el estado del nodo: {{ .detail }}'
|
||||
ErrApiConfigStatusInvalid: 'Se prohíbe el acceso a la interfaz API: {{ .detail }}'
|
||||
ErrApiConfigKeyInvalid: 'Error en la clave de la interfaz API: {{ .detail }}'
|
||||
ErrApiConfigIPInvalid: 'La IP usada para llamar a la API no está en la lista blanca: {{ .detail }}'
|
||||
ErrApiConfigDisable: 'Esta interfaz prohíbe el uso de llamadas a la API: {{ .detail }}'
|
||||
ErrApiConfigKeyTimeInvalid: 'Error en la marca de tiempo de la interfaz API: {{ .detail }}'
|
||||
ErrShutDown: "¡Comando terminado manualmente!"
|
||||
|
||||
ErrMinQuickJump: "¡Por favor configure al menos una entrada de acceso rápido!"
|
||||
ErrMaxQuickJump: "¡Puede configurar hasta cuatro entradas de acceso rápido!"
|
||||
|
||||
#común
|
||||
ErrUsernameIsExist: 'El nombre de usuario ya existe'
|
||||
ErrNameIsExist: 'El nombre ya existe'
|
||||
ErrDemoEnvironment: '¡Servidor de demostración, esta operación está prohibida!'
|
||||
ErrCmdTimeout: '¡Tiempo de espera excedido en la ejecución del comando!'
|
||||
ErrCmdIllegal: 'Hay caracteres ilegales en el comando, ¡modifíquelo e intente de nuevo!'
|
||||
ErrPortExist: 'El puerto {{ .port }} ya está ocupado por {{ .type }} [{{ .name }}]'
|
||||
TYPE_APP: 'Aplicación'
|
||||
TYPE_RUNTIME: 'Entorno de ejecución'
|
||||
TYPE_DOMAIN: 'Nombre de dominio'
|
||||
ErrTypePort: 'El formato del puerto {{ .name }} es incorrecto'
|
||||
ErrTypePortRange: 'El rango de puertos debe estar entre 1-65535'
|
||||
Success: 'Éxito'
|
||||
Failed: 'Error'
|
||||
SystemRestart: 'La tarea fue interrumpida debido a un reinicio del sistema'
|
||||
ErrGroupIsDefault: 'Grupo predeterminado, no se puede eliminar'
|
||||
ErrGroupIsInWebsiteUse: 'El grupo está siendo usado por otro sitio web y no se puede eliminar.'
|
||||
|
||||
#backup
|
||||
ErrBackupInUsed: 'La cuenta de respaldo está siendo utilizada en una tarea programada y no se puede eliminar.'
|
||||
ErrBackupCheck: 'Error al probar la conexión de la cuenta de respaldo {{ .err }}'
|
||||
ErrBackupLocalDelete: 'No se admite aún la eliminación de la cuenta de respaldo del servidor local'
|
||||
ErrBackupLocalCreate: 'No se admite aún la creación de cuentas de respaldo del servidor local'
|
||||
Localhost: "Máquina local"
|
||||
|
||||
#app
|
||||
ErrPortInUsed: '¡El puerto {{ .detail }} ya está ocupado!'
|
||||
ErrAppLimit: 'El número de aplicaciones instaladas ha superado el límite'
|
||||
ErrNotInstall: 'Aplicación no instalada'
|
||||
ErrPortInOtherApp: '¡El puerto {{ .port }} ya está ocupado por la aplicación {{ .apps }}!'
|
||||
ErrDbUserNotValid: '¡Base de datos existente, usuario y contraseña no coinciden!'
|
||||
ErrUpdateBuWebsite: 'La aplicación se actualizó correctamente, pero falló la modificación del archivo de configuración del sitio web. ¡Por favor revise la configuración!'
|
||||
Err1PanelNetworkFailed: '¡Fallo la creación de la red por defecto del contenedor! {{ .detail }}'
|
||||
ErrFileParse: '¡Fallo al analizar el archivo docker-compose de la aplicación!'
|
||||
ErrInstallDirNotFound: 'El directorio de instalación no existe. Si desea desinstalar, seleccione Desinstalación forzada'
|
||||
AppStoreIsUpToDate: 'La tienda de aplicaciones ya está en la última versión'
|
||||
LocalAppVersionNull: '¡La aplicación {{ .name }} no está sincronizada a la versión! No se puede agregar a la lista de aplicaciones'
|
||||
LocalAppVersionErr: '¡La sincronización de la versión {{ .version }} de {{ .name }} falló! {{ .err }}'
|
||||
ErrFileNotFound: 'El archivo {{ .name }} no existe'
|
||||
ErrFileParseApp: '¡El archivo {{ .name }} falló al analizarse! {{ .err }}'
|
||||
ErrAppDirNull: 'La carpeta de la versión no existe'
|
||||
LocalAppErr: '¡La sincronización de la aplicación {{ .name }} falló! {{ .err }}'
|
||||
ErrContainerName: 'El nombre del contenedor ya existe'
|
||||
ErrCreateHttpClient: 'Fallo al crear la solicitud {{ .err }}'
|
||||
ErrHttpReqTimeOut: 'La solicitud superó el tiempo de espera {{ .err }}'
|
||||
ErrHttpReqFailed: 'La solicitud falló {{ .err }}'
|
||||
ErrNoSuchHost: 'No se pudo encontrar el servidor solicitado {{ .err }}'
|
||||
ErrHttpReqNotFound: 'No se pudo encontrar el recurso solicitado {{ .err }}'
|
||||
ErrContainerNotFound: 'El contenedor {{ .name }} no existe'
|
||||
ErrContainerMsg: 'El contenedor {{ .name }} presenta anomalías. Revise el log en la página de contenedores para más detalles'
|
||||
ErrAppBackup: 'Falló el respaldo de la aplicación {{ .name }} {{ .err }}'
|
||||
ErrVersionTooLow: 'La versión actual de 1Panel es demasiado baja para actualizar la tienda de aplicaciones. Actualice primero.'
|
||||
ErrAppNameExist: 'El nombre de la aplicación ya existe'
|
||||
AppStoreIsSyncing: 'La tienda de aplicaciones está sincronizando, inténtelo más tarde'
|
||||
ErrGetCompose: '¡Fallo al obtener el archivo docker-compose.yml! {{ .detail }}'
|
||||
ErrAppWarn: 'Estado anómalo, revise el log'
|
||||
ErrAppParamKey: 'El campo de parámetro {{ .name }} es anómalo'
|
||||
ErrAppUpgrade: 'La actualización de la aplicación {{ .name }} falló {{ .err }}'
|
||||
AppRecover: 'Revertir la aplicación {{ .name }}'
|
||||
PullImageStart: 'Iniciar descarga de la imagen {{ .name }}'
|
||||
PullImageSuccess: 'Descarga de imagen exitosa'
|
||||
AppStoreIsLastVersion: 'La tienda de aplicaciones ya está en la última versión'
|
||||
AppStoreSyncSuccess: 'Sincronización de la tienda de aplicaciones exitosa'
|
||||
SyncAppDetail: 'Sincronizar configuración de la aplicación'
|
||||
AppVersionNotMatch: 'La aplicación {{ .name }} requiere una versión superior de 1Panel, se omite la sincronización'
|
||||
MoveSiteDir: 'La actualización actual requiere migrar el directorio del sitio web OpenResty'
|
||||
MoveSiteDirSuccess: 'Migración del directorio del sitio exitosa'
|
||||
DeleteRuntimePHP: 'Eliminar entorno de ejecución PHP'
|
||||
CustomAppStoreFileValid: 'Los paquetes de la tienda de aplicaciones deben estar en formato .tar.gz'
|
||||
PullImageTimeout: 'Tiempo de espera al descargar la imagen, intente aumentar la aceleración o use otra'
|
||||
ErrAppIsDown: 'El estado de la aplicación {{ .name }} es anómalo, revise'
|
||||
ErrCustomApps: 'Hay una aplicación instalada, desinstálela primero'
|
||||
ErrCustomRuntimes: 'Hay un entorno de ejecución instalado, elimínelo primero'
|
||||
ErrAppVersionDeprecated: "La aplicación {{ .name }} no es compatible con la versión actual de 1Panel, omitida"
|
||||
ErrDockerFailed: "El estado de Docker es anómalo, revise el servicio"
|
||||
ErrDockerComposeCmdNotFound: "El comando Docker Compose no existe, por favor instálelo primero en el host"
|
||||
UseExistImage: 'Error al extraer la imagen, usando imagen existente'
|
||||
|
||||
#ssh
|
||||
ExportIP: "IP de inicio de sesión"
|
||||
ExportArea: "Ubicación"
|
||||
ExportPort: "Puerto"
|
||||
ExportAuthMode: "Método de inicio de sesión"
|
||||
ExportUser: "Usuario"
|
||||
ExportStatus: "Estado de inicio de sesión"
|
||||
ExportDate: "Fecha y hora"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: 'Este archivo no soporta vista previa'
|
||||
ErrFileToLarge: 'El archivo es mayor a 10M y no puede abrirse'
|
||||
ErrPathNotFound: 'El directorio no existe'
|
||||
ErrMovePathFailed: '¡La ruta de destino no puede contener la ruta original!'
|
||||
ErrLinkPathNotFound: '¡La ruta de destino no existe!'
|
||||
ErrFileIsExist: '¡El archivo o carpeta ya existe!'
|
||||
ErrFileUpload: '{{ .name }} falló al subir archivo {{ .detail }}'
|
||||
ErrFileDownloadDir: 'No se admite la descarga de carpetas'
|
||||
ErrCmdNotFound: 'El comando {{ .name }} no existe, instálelo primero en el host'
|
||||
ErrSourcePathNotFound: 'El directorio fuente no existe'
|
||||
ErrFavoriteExist: 'Esta ruta ya ha sido marcada como favorita'
|
||||
ErrInvalidChar: 'No se permiten caracteres ilegales'
|
||||
ErrPathNotDelete: 'No se puede eliminar el directorio seleccionado'
|
||||
FileDropFailed: "Error al limpiar el archivo {{ .name }}: {{ .err }}"
|
||||
FileDropSuccess: "Archivo {{ .name }} limpiado correctamente, {{ .count }} archivos eliminados, {{ .size }} de espacio liberado"
|
||||
FileDropSum: "Limpieza de archivos completada, total {{ .count }} archivos eliminados, {{ .size }} de espacio liberado"
|
||||
ErrBadDecrypt: "Error de contraseña de descifrado del paquete comprimido, descompresión fallida, ¡compruebe e inténtelo de nuevo!"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: 'El alias ya existe'
|
||||
ErrBackupMatch: 'El archivo de respaldo no coincide con parte de los datos actuales del sitio web {{ .detail }}'
|
||||
ErrBackupExist: 'Parte de los datos fuente del respaldo no existe {{ .detail }}'
|
||||
ErrPHPResource: '¡El entorno local no soporta cambio!'
|
||||
ErrPathPermission: 'Se detectó una carpeta con permisos distintos a 1000:1000 en el directorio index, lo cual puede causar errores de acceso denegado. Haga clic en Guardar arriba'
|
||||
ErrDomainIsUsed: 'El dominio ya está en uso por el sitio web [{{ .name }}]'
|
||||
ErrDomainFormat: 'El formato del dominio {{ .name }} es incorrecto'
|
||||
ErrDefaultAlias: 'default es un código reservado, use otro'
|
||||
ErrParentWebsite: 'Primero debe eliminar el sub-sitio {{ .name }}'
|
||||
ErrBuildDirNotFound: 'El directorio de compilación no existe'
|
||||
ErrImageNotExist: 'La imagen del entorno {{ .name }} no existe, edítela de nuevo'
|
||||
ErrProxyIsUsed: "El balanceo de carga ya está usado por un proxy reverso, no se puede eliminar"
|
||||
ErrSSLValid: 'Archivo de certificado anómalo, ¡revise el estado del certificado!'
|
||||
ErrWebsiteDir: "Por favor seleccione un directorio dentro del directorio del sitio web"
|
||||
ErrComposerFileNotFound: "El archivo composer.json no existe"
|
||||
ErrRuntimeNoPort: "El entorno de ejecución no tiene configurado un puerto, edítelo primero"
|
||||
Status: 'Estado'
|
||||
start: 'Iniciar'
|
||||
stop: 'Detener'
|
||||
delete: 'Eliminar'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: 'El certificado {{ .name }} está siendo utilizado por un sitio web y no puede eliminarse'
|
||||
ErrAccountCannotDelete: 'La cuenta está asociada a un certificado y no puede eliminarse'
|
||||
ErrSSLApply: 'Renovación del certificado exitosa, recarga de openresty fallida, ¡revise la configuración!'
|
||||
ErrEmailIsExist: 'El correo ya existe'
|
||||
ErrSSLKeyNotFound: 'El archivo de clave privada no existe'
|
||||
ErrSSLCertificateNotFound: 'El archivo de certificado no existe'
|
||||
ErrSSLKeyFormat: 'Error en la verificación del archivo de clave privada'
|
||||
ErrSSLCertificateFormat: 'Formato de certificado incorrecto, use formato pem'
|
||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid o EabHmacKey no pueden estar en blanco'
|
||||
ErrOpenrestyNotFound: 'El modo Http requiere tener Openresty instalado primero'
|
||||
ApplySSLStart: 'Iniciando solicitud de certificado, dominio [{{ .domain }}] método de solicitud [{{ .type }}]'
|
||||
dnsAccount: 'DNS Automático'
|
||||
dnsManual: 'DNS Manual'
|
||||
http: 'HTTP'
|
||||
ApplySSLFailed: 'Solicitud de certificado para [{{ .domain }}] fallida, {{ .detail }}'
|
||||
ApplySSLSuccess: '¡Solicitud de certificado para [{{ .domain }}] exitosa!'
|
||||
DNSAccountName: 'Cuenta DNS [{{ .name }}] proveedor [{{ .type }}]'
|
||||
PushDirLog: 'Certificado empujado al directorio [{{ .path }}] {{ .status }}'
|
||||
ErrDeleteWithPanelSSL: 'La configuración SSL del panel utiliza este certificado y no puede eliminarse'
|
||||
ErrDefaultCA: 'La autoridad por defecto no puede eliminarse'
|
||||
ApplyWebSiteSSLLog: 'Iniciando renovación del certificado del sitio web {{ .name }}'
|
||||
ErrUpdateWebsiteSSL: 'Actualización de certificado del sitio web {{ .name }} falló: {{ .err }}'
|
||||
ApplyWebSiteSSLSuccess: 'Certificado del sitio web actualizado exitosamente'
|
||||
ErrExecShell: 'Ejecución del script fallida {{ .err }}'
|
||||
ExecShellStart: 'Iniciando ejecución de script'
|
||||
ExecShellSuccess: 'Ejecución de script exitosa'
|
||||
StartUpdateSystemSSL: 'Iniciando actualización del certificado del sistema'
|
||||
UpdateSystemSSLSuccess: 'Certificado del sistema actualizado correctamente'
|
||||
ErrWildcardDomain: 'No se puede solicitar certificado de dominio wildcard en modo HTTP'
|
||||
ErrDeleteCAWithSSL: "La organización actual tiene un certificado emitido y no puede eliminarse."
|
||||
ErrApplySSLCanNotDelete: "El certificado {{ .name }} en proceso de solicitud no puede eliminarse, inténtelo más tarde"
|
||||
StartPushSSLToNode: "Iniciando envío de certificado al nodo"
|
||||
PushSSLToNodeFailed: "Error al enviar el certificado al nodo: {{ .err }}"
|
||||
PushSSLToNodeSuccess: "Certificado enviado correctamente al nodo"
|
||||
|
||||
#mysql
|
||||
ErrUserIsExist: 'El usuario actual ya existe, intente con otro'
|
||||
ErrDatabaseIsExist: 'La base de datos actual ya existe, intente con otro nombre'
|
||||
ErrExecTimeOut: 'Tiempo de espera en la ejecución SQL, revise la base de datos'
|
||||
ErrRemoteExist: 'La base de datos remota ya existe con ese nombre, modifíquelo e intente de nuevo'
|
||||
ErrLocalExist: 'El nombre ya existe en la base de datos local, modifíquelo e intente de nuevo'
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'El tipo de archivo de recuperación no coincide con el método de persistencia actual, modifíquelo e intente'
|
||||
|
||||
#container
|
||||
ErrInUsed: '{{ .detail }} está en uso y no puede eliminarse'
|
||||
ErrObjectInUsed: 'El objeto está en uso y no puede eliminarse'
|
||||
ErrObjectBeDependent: 'Esta imagen depende de otras imágenes y no puede eliminarse'
|
||||
ErrPortRules: 'El número de puerto no coincide, ingrese de nuevo'
|
||||
ErrPgImagePull: 'Tiempo de espera al descargar la imagen, configure la aceleración o descárguela manualmente ({{ .name }}) e intente de nuevo'
|
||||
PruneHelper: "Esta limpieza eliminó {{ .name }} {{ .count }} elementos, liberando {{ .size }} de espacio en disco"
|
||||
ImageRemoveHelper: "Imagen {{ .name }} eliminada, liberando {{ .size }} de espacio en disco"
|
||||
BuildCache: "Caché de compilación"
|
||||
Volume: "Volumen de almacenamiento"
|
||||
Network: "Red"
|
||||
|
||||
#runtime
|
||||
ErrFileNotExist: 'El archivo {{ .detail }} no existe, ¡verifique la integridad!'
|
||||
ErrImageBuildErr: 'Fallo al construir la imagen'
|
||||
ErrImageExist: "¡La imagen ya existe! Modifique el nombre de la imagen."
|
||||
ErrDelWithWebsite: 'El entorno de ejecución ya está asociado a un sitio web y no puede eliminarse'
|
||||
ErrRuntimeStart: 'Fallo al iniciar'
|
||||
ErrPackageJsonNotFound: 'El archivo package.json no existe'
|
||||
ErrScriptsNotFound: 'No se encontró la configuración de scripts en package.json'
|
||||
ErrContainerNameNotFound: 'No se puede obtener el nombre del contenedor, revise el archivo .env'
|
||||
ErrNodeModulesNotFound: 'La carpeta node_modules no existe, edite o espere a que inicie'
|
||||
ErrContainerNameIsNull: 'El nombre del contenedor no existe'
|
||||
ErrPHPPortIsDefault: "El puerto 9000 es el predeterminado, modifique e intente de nuevo"
|
||||
ErrPHPRuntimePortFailed: "El puerto {{ .name }} ya está en uso por el entorno actual, modifique e intente"
|
||||
|
||||
#tool
|
||||
ErrConfigNotFound: 'El archivo de configuración no existe'
|
||||
ErrConfigParse: 'El formato del archivo de configuración es incorrecto'
|
||||
ErrConfigIsNull: 'El archivo de configuración no puede estar vacío'
|
||||
ErrConfigDirNotFound: 'El directorio de ejecución no existe'
|
||||
ErrConfigAlreadyExist: 'Ya existe un archivo de configuración con ese nombre'
|
||||
ErrUserFindErr: 'Búsqueda del usuario {{ .name }} fallida {{ .err }}'
|
||||
|
||||
#cronjob
|
||||
CutWebsiteLogSuccess: 'Log del sitio web {{ .name }} cortado con éxito, ruta de respaldo {{ .path }}'
|
||||
HandleShell: 'Ejecutar script {{ .name }}'
|
||||
HandleNtpSync: 'Sincronizar hora del sistema'
|
||||
HandleSystemClean: 'Limpiar caché del sistema'
|
||||
SystemLog: 'Log del sistema'
|
||||
CutWebsiteLog: 'Rotar log del sitio web'
|
||||
FileOrDir: 'Directorio / Archivo'
|
||||
UploadFile: 'Subiendo archivo de respaldo {{ .file }} a {{ .backup }}'
|
||||
IgnoreBackupErr: 'Fallo en el respaldo, error: {{ .detail }}, se ignora este error...'
|
||||
IgnoreUploadErr: 'Fallo en la subida, error: {{ .detail }}, se ignora este error...'
|
||||
Upload: "Subir"
|
||||
LoadBackupFailed: "Error al obtener la conexión de la cuenta de respaldo, error: {{ .detail }}"
|
||||
InExecuting: "La tarea actual se está ejecutando, por favor no la repita"
|
||||
NoSuchResource: "No se encontraron contenidos de respaldo en la base de datos, omitiendo..."
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: 'El usuario actual no existe, modifíquelo e intente de nuevo'
|
||||
ErrBanAction: 'Fallo al configurar. El servicio {{ .name }} no está disponible, revise e intente de nuevo'
|
||||
ErrClamdscanNotFound: 'El comando clamdscan no fue detectado, siga la documentación para instalarlo'
|
||||
TaskSwapSet: "Configurar Swap"
|
||||
SetSwap: "Configurar Swap {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Crear Archivo Swap"
|
||||
FormatSwap: "Formatear Archivo Swap"
|
||||
EnableSwap: "Habilitar Swap"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "Limpiar configuraciones de protección históricas"
|
||||
SetTamperWithRules: "Iniciar protección de directorio según reglas"
|
||||
ProtectDir: "Proteger directorio {{ .name }}"
|
||||
IgnoreFile: "Proteger archivo {{ .name }}"
|
||||
TamperSetSuccessful: "Configuración de protección completada, comenzando monitoreo de los siguientes directorios:"
|
||||
|
||||
#waf
|
||||
ErrScope: 'No se admite la modificación de esta configuración'
|
||||
ErrStateChange: 'Fallo al cambiar de estado'
|
||||
ErrRuleExist: 'La regla ya existe'
|
||||
ErrRuleNotExist: 'La regla no existe'
|
||||
ErrParseIP: 'Formato de IP incorrecto'
|
||||
ErrDefaultIP: 'default es un nombre reservado, cámbielo'
|
||||
ErrGroupInUse: 'El grupo IP está en uso por listas negras/blancas y no se puede eliminar'
|
||||
ErrIPGroupAclUse: "El grupo IP está en uso por reglas personalizadas del sitio web {{ .name }}, no puede eliminarse"
|
||||
ErrGroupExist: 'El nombre del grupo IP ya existe'
|
||||
ErrIPRange: 'Rango de IP incorrecto'
|
||||
ErrIPExist: 'La IP ya existe'
|
||||
urlDefense: 'Reglas de URL'
|
||||
urlHelper: 'URL prohibida'
|
||||
dirFilter: 'Filtro de directorio'
|
||||
xss: 'XSS'
|
||||
phpExec: 'Ejecución de scripts PHP'
|
||||
oneWordTrojan: 'Troyano de una sola palabra'
|
||||
appFilter: 'Filtrar directorios peligrosos'
|
||||
webshell: 'Webshell'
|
||||
args: 'Reglas de parámetros'
|
||||
protocolFilter: 'Filtrado de protocolos'
|
||||
javaFileter: 'Filtrado de archivos Java peligrosos'
|
||||
scannerFilter: 'Filtrado de escáneres'
|
||||
escapeFilter: 'Filtro de escape'
|
||||
customRule: 'Regla personalizada'
|
||||
httpMethod: 'Filtrado de métodos HTTP'
|
||||
fileExt: 'Restricciones de carga de archivos'
|
||||
defaultIpBlack: 'Grupo de IPs maliciosas'
|
||||
cookie: 'Reglas de Cookie'
|
||||
urlBlack: 'Lista negra de URLs'
|
||||
uaBlack: 'Lista negra de User-Agent'
|
||||
attackCount: 'Límite de frecuencia de ataques'
|
||||
fileExtCheck: 'Restricción de carga de archivos'
|
||||
geoRestrict: 'Restricciones de acceso regional'
|
||||
unknownWebsite: 'Acceso no autorizado al dominio'
|
||||
notFoundCount: 'Límite de tasa 404'
|
||||
headerDefense: 'Reglas de encabezado'
|
||||
defaultUaBlack: 'Reglas de User-Agent'
|
||||
methodWhite: 'Reglas HTTP'
|
||||
captcha: 'Verificación humano-máquina'
|
||||
fiveSeconds: 'Verificación de 5 segundos'
|
||||
vulnCheck: 'Reglas suplementarias'
|
||||
acl: 'Reglas personalizadas'
|
||||
sql: 'Inyección SQL'
|
||||
cc: 'Límite de frecuencia de acceso'
|
||||
defaultUrlBlack: 'Reglas de URL'
|
||||
sqlInject: 'Inyección SQL'
|
||||
ErrDBNotExist: 'La base de datos no existe'
|
||||
allow: 'permitir'
|
||||
deny: 'denegar'
|
||||
OpenrestyNotFound: 'Openresty no está instalado'
|
||||
remoteIpIsNull: "La lista de IP está vacía"
|
||||
OpenrestyVersionErr: "La versión de Openresty es demasiado baja, actualice a 1.27.1.2-2-2-focal"
|
||||
|
||||
#task
|
||||
TaskStart: 'La tarea {{ .name }} inicia [INICIO]'
|
||||
TaskEnd: 'La tarea {{ .name }} completada [COMPLETADA]'
|
||||
TaskFailed: 'La tarea {{ .name }} falló'
|
||||
TaskTimeout: 'La tarea {{ .name }} excedió el tiempo'
|
||||
TaskSuccess: 'La tarea {{ .name }} se realizó con éxito'
|
||||
TaskRetry: 'Iniciar el {{ .name }} reintento'
|
||||
SubTaskSuccess: '{{ .name }} exitoso'
|
||||
SubTaskFailed: '{{ .name }} falló: {{ .err }}'
|
||||
TaskInstall: 'Instalar'
|
||||
TaskUninstall: 'Desinstalar'
|
||||
TaskCreate: 'Crear'
|
||||
TaskProtect: "Proteger"
|
||||
TaskDelete: 'Eliminar'
|
||||
TaskUpgrade: 'Actualizar'
|
||||
TaskUpdate: 'Actualizar'
|
||||
TaskRestart: 'Reiniciar'
|
||||
TaskBackup: 'Respaldar'
|
||||
TaskRecover: 'Recuperar'
|
||||
TaskRollback: 'Revertir'
|
||||
TaskPull: 'Descargar'
|
||||
TaskCommit: 'Commit'
|
||||
TaskBuild: 'Construir'
|
||||
TaskPush: 'Subir'
|
||||
TaskHandle: 'Ejecutar'
|
||||
Website: 'Sitio web'
|
||||
App: 'Aplicación'
|
||||
Runtime: 'Entorno de ejecución'
|
||||
Database: 'Base de datos'
|
||||
ConfigFTP: 'Crear usuario FTP {{ .name }}'
|
||||
ConfigOpenresty: 'Crear archivo de configuración Openresty'
|
||||
InstallAppSuccess: 'Aplicación {{ .name }} instalada correctamente'
|
||||
ConfigRuntime: 'Configurar entorno de ejecución'
|
||||
ConfigApp: 'Configurar aplicación'
|
||||
SuccessStatus: '{{ .name }} exitoso'
|
||||
FailedStatus: '{{ .name }} falló {{ .err }}'
|
||||
HandleLink: 'Gestionar asociación de aplicación'
|
||||
HandleDatabaseApp: 'Gestionar parámetros de aplicación'
|
||||
ExecShell: 'Ejecutar script {{ .name }}'
|
||||
PullImage: 'Descargar imagen'
|
||||
Start: 'Iniciar'
|
||||
Run: 'Ejecutar'
|
||||
Stop: 'Detener'
|
||||
Image: 'Imagen'
|
||||
Compose: 'Orquestación'
|
||||
Container: 'Contenedor'
|
||||
AppLink: 'Aplicación enlazada'
|
||||
EnableSSL: 'Habilitar HTTPS'
|
||||
AppStore: 'Tienda de aplicaciones'
|
||||
TaskSync: 'Sincronizar'
|
||||
LocalApp: 'Aplicación local'
|
||||
SubTask: 'Subtarea'
|
||||
RuntimeExtension: 'Extensión del entorno de ejecución'
|
||||
TaskIsExecuting: 'Tarea en ejecución'
|
||||
CustomAppstore: 'Almacén de aplicaciones personalizado'
|
||||
TaskClean: "Limpieza"
|
||||
TaskExec: "Ejecutar"
|
||||
TaskBatch: "Operación por Lotes"
|
||||
FileConvert: 'Conversión de Formato de Archivo'
|
||||
|
||||
# task - ai
|
||||
OllamaModelPull: 'Descargar modelo Ollama {{ .name }}'
|
||||
OllamaModelSize: 'Obtener tamaño del modelo Ollama {{ .name }}'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "Escanear {{ .name }}"
|
||||
TaskScan: "Escaneo"
|
||||
|
||||
# task-snapshot
|
||||
Snapshot: 'Instantánea'
|
||||
SnapDBInfo: 'Escribir información de base de datos de 1Panel'
|
||||
SnapCopy: 'Copiar archivos y directorios {{ .name }}'
|
||||
SnapNewDB: 'Inicializar conexión a base de datos {{ .name }}'
|
||||
SnapDeleteOperationLog: 'Eliminar log de operaciones'
|
||||
SnapDeleteLoginLog: 'Eliminar log de accesos'
|
||||
SnapDeleteMonitor: 'Eliminar datos de monitoreo'
|
||||
SnapRemoveSystemIP: 'Eliminar IP del sistema'
|
||||
SnapBaseInfo: 'Escribir información básica de 1Panel'
|
||||
SnapInstallAppImageEmpty: 'No se seleccionaron imágenes de aplicaciones, omitiendo...'
|
||||
SnapInstallApp: 'Respaldar aplicaciones instaladas de 1Panel'
|
||||
SnapDockerSave: 'Comprimir aplicaciones instaladas'
|
||||
SnapLocalBackup: 'Respaldar directorio local de 1Panel'
|
||||
SnapCompressBackup: 'Comprimir directorio local de respaldo'
|
||||
SnapPanelData: 'Respaldar directorio de datos de 1Panel'
|
||||
SnapCompressPanel: 'Directorio de datos comprimido'
|
||||
SnapWebsite: 'Respaldar directorio de sitios web de 1Panel'
|
||||
SnapCloseDBConn: 'Cerrar conexión de base de datos'
|
||||
SnapCompress: 'Crear archivos de instantánea'
|
||||
SnapCompressFile: 'Comprimir archivo de instantánea'
|
||||
SnapCheckCompress: 'Verificar archivo de compresión de instantánea'
|
||||
SnapCompressSize: 'Tamaño del archivo de instantánea {{ .name }}'
|
||||
SnapUpload: 'Subir archivo de instantánea'
|
||||
SnapUploadTo: 'Subir archivo de instantánea a {{ .name }}'
|
||||
|
||||
SnapshotRecover: 'Restaurar instantánea'
|
||||
RecoverDownload: 'Descargar archivo de instantánea'
|
||||
Download: 'Descargar'
|
||||
RecoverDownloadAccount: 'Obtener cuenta de respaldo para descargar instantánea {{ .name }}'
|
||||
RecoverDecompress: 'Descomprimir archivos de instantánea'
|
||||
Decompress: 'Descompresión'
|
||||
BackupBeforeRecover: 'Respaldar datos del sistema antes de restaurar instantánea'
|
||||
Readjson: 'Leer archivo Json de la instantánea'
|
||||
ReadjsonPath: 'Obtener ruta del archivo Json en la instantánea'
|
||||
ReadjsonContent: 'Leer archivo Json'
|
||||
ReadjsonMarshal: 'Procesar escape de Json'
|
||||
RecoverApp: 'Restaurar aplicaciones instaladas'
|
||||
RecoverWebsite: 'Recuperar directorio del sitio web'
|
||||
RecoverAppImage: 'Restaurar imagen de la instantánea'
|
||||
RecoverCompose: 'Restaurar otros contenidos de compose'
|
||||
RecoverComposeList: 'Obtener todos los compose a restaurar'
|
||||
RecoverComposeItem: 'Restaurar compose {{ .name }}'
|
||||
RecoverAppEmpty: 'No se encontraron imágenes de respaldo de aplicaciones en la instantánea'
|
||||
RecoverBaseData: 'Recuperar datos y archivos básicos'
|
||||
RecoverDaemonJsonEmpty: 'El archivo daemon.json no existe ni en la instantánea ni en el equipo actual'
|
||||
RecoverDaemonJson: 'Restaurar archivo daemon.json de configuración de contenedor'
|
||||
RecoverDBData: 'Restaurar datos de base de datos'
|
||||
RecoverBackups: 'Restaurar directorio local de respaldo'
|
||||
RecoverPanelData: 'Recuperar directorio de datos'
|
||||
|
||||
# task - container
|
||||
ContainerNewCliet: 'Inicializar cliente Docker'
|
||||
ContainerImagePull: 'Descargar imagen de contenedor {{ .name }}'
|
||||
ContainerRemoveOld: 'Eliminar el contenedor original {{ .name }}'
|
||||
ContainerImageCheck: 'Comprobar si la imagen se descargó correctamente'
|
||||
ContainerLoadInfo: 'Obtener información básica del contenedor'
|
||||
ContainerRecreate: 'Actualización del contenedor fallida, restaurando el contenedor original'
|
||||
ContainerCreate: 'Crear nuevo contenedor {{ .name }}'
|
||||
ContainerCreateFailed: 'Falló la creación del contenedor, eliminando el contenedor fallido'
|
||||
ContainerStartCheck: 'Verificar si el contenedor ha iniciado'
|
||||
|
||||
# task - image
|
||||
ImageBuild: 'Construcción de imagen'
|
||||
ImageBuildStdoutCheck: 'Analizar salida de la imagen'
|
||||
ImageBuildRes: 'Salida de construcción de imagen: {{ .name }}'
|
||||
ImagePull: 'Descargar imagen'
|
||||
ImagePush: 'Subir imagen'
|
||||
ImageRenameTag: 'Modificar etiqueta de imagen'
|
||||
ImageNewTag: 'Nueva etiqueta de imagen {{ .name }}'
|
||||
ComposeCreate: 'Crear orquestación'
|
||||
ComposeCreateRes: 'Salida de creación de orquestación: {{ .name }}'
|
||||
ImageRepoAuthFromDB: "Obtener información de autenticación del repositorio desde la base de datos"
|
||||
ImaegPullRes: "Salida de descarga de imagen: {{ .name }}"
|
||||
ImaegPushRes: "Salida de subida de imagen: {{ .name }}"
|
||||
|
||||
# task - website
|
||||
BackupNginxConfig: 'Respaldar archivo de configuración OpenResty'
|
||||
CompressFileSuccess: 'Directorio comprimido con éxito, guardado en {{ .name }}'
|
||||
CompressDir: 'Directorio comprimido'
|
||||
DeCompressFile: 'Descomprimir archivo {{ .name }}'
|
||||
ErrCheckValid: 'Verificación de archivo de respaldo fallida, {{ .name }}'
|
||||
Rollback: 'Revertir'
|
||||
websiteDir: 'Directorio del sitio web'
|
||||
RecoverFailedStartRollBack: 'Restauración fallida, iniciando reversión'
|
||||
AppBackupFileIncomplete: 'El archivo de respaldo está incompleto, falta app.json o app.tar.gz'
|
||||
AppAttributesNotMatch: 'El tipo o nombre de la aplicación no coincide'
|
||||
|
||||
#alert
|
||||
ErrAlert: 'El formato del mensaje de alerta es incorrecto, ¡revise e intente de nuevo!'
|
||||
ErrAlertPush: 'Error al enviar la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertSave: 'Error al guardar la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertSync: 'Error en la sincronización de la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertRemote: 'Error remoto de alerta, ¡revise e intente de nuevo!'
|
||||
CommonAlert: "Su 1Panel: {{ .msg }}, por favor inicie sesión en el panel para más detalles."
|
||||
NodeExceptionAlert: "Su 1Panel tiene {{ .num }} nodos anómalos, inicie sesión para más detalles."
|
||||
LicenseExceptionAlert: "Su 1Panel tiene {{ .num }} licencias anómalas, inicie sesión para más detalles."
|
||||
SSHAndPanelLoginAlert: "Su 1Panel detectó un inicio de sesión anómalo en el panel {{ .name }} desde {{ .ip }}, revise en el panel para más detalles."
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "Ya hay una tarea de instalación en curso, espere a que termine"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "Notificación de alerta del panel"
|
||||
TestAlertTitle: "Correo de prueba - Verificar conectividad de correo"
|
||||
TestAlert: "Este es un correo de prueba para verificar que la configuración de envío de correos es correcta."
|
||||
LicenseExpirationAlert: "Su licencia de 1Panel expirará en {{ .day }} días. Inicie sesión para más detalles."
|
||||
CronJobFailedAlert: "Su tarea programada '{{ .name }}' ha fallado. Inicie sesión en el panel para más detalles."
|
||||
ClamAlert: "La tarea de escaneo de virus detectó {{ .num }} archivos infectados. Inicie sesión para detalles."
|
||||
WebSiteAlert: "Hay {{ .num }} sitios web en su 1Panel que expirarán en {{ .day }} días. Inicie sesión para más detalles."
|
||||
SSLAlert: "Hay {{ .num }} certificados SSL en su 1Panel que expirarán en {{ .day }} días. Inicie sesión para detalles."
|
||||
DiskUsedAlert: "El disco '{{ .name }}' de su 1Panel ha utilizado {{ .used }}. Inicie sesión para más detalles."
|
||||
ResourceAlert: "El uso promedio de {{ .name }} en {{ .time }} minutos es de {{ .used }}. Inicie sesión para más detalles."
|
||||
PanelVersionAlert: "Hay una nueva versión de 1Panel disponible. Inicie sesión para actualizar."
|
||||
PanelPwdExpirationAlert: "Su contraseña de 1Panel expirará en {{ .day }} días. Inicie sesión para más detalles."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Dispositivo {{ .name }} no encontrado"
|
||||
DeviceIsMounted: "El dispositivo {{ .name }} está montado, desmóntelo primero"
|
||||
PartitionDiskErr: "Error al particionar, {{ .err }}"
|
||||
FormatDiskErr: "Error al formatear disco, {{ .err }}"
|
||||
MountDiskErr: "Error al montar disco, {{ .err }}"
|
||||
UnMountDiskErr: "Error al desmontar disco, {{ .err }}"
|
||||
XfsNotFound: "No se detectó el sistema de archivos xfs, por favor instale xfsprogs primero"
|
||||
@@ -94,6 +94,7 @@ ErrCustomRuntimes: 'ランタイム環境がインストールされています
|
||||
ErrAppVersionDeprecated: "{{ .name }} アプリケーションは現在の 1Panel バージョンと互換性がありません、スキップしました"
|
||||
ErrDockerFailed: "Docker の状態が異常です。サービス状態を確認してください"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose コマンドは存在しません。ホストマシンにこのコマンドを先にインストールしてください"
|
||||
UseExistImage: 'イメージのプルに失敗しました、既存のイメージを使用します'
|
||||
|
||||
#ssh
|
||||
ExportIP: "ログインIP"
|
||||
@@ -122,6 +123,7 @@ ErrLogFileToLarge: "ログファイルが500MBを超えており、開くこと
|
||||
FileDropFailed: "ファイル {{ .name }} のクリーンアップに失敗しました: {{ .err }}"
|
||||
FileDropSuccess: "ファイル {{ .name }} のクリーンアップに成功しました、{{ .count }} ファイルを削除、{{ .size }} のディスク領域を解放"
|
||||
FileDropSum: "ファイルのクリーンアップが完了しました、合計 {{ .count }} ファイルを削除、合計 {{ .size }} のディスク領域を解放"
|
||||
ErrBadDecrypt: "圧縮パッケージの解凍パスワードが間違っています。解凍に失敗しました。確認して再試行してください!"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: 'エイリアスがすでに存在します'
|
||||
@@ -140,6 +142,10 @@ ErrSSLValid: '証明書ファイルが異常です、証明書の状態を確認
|
||||
ErrWebsiteDir: "ウェブサイトディレクトリ内のディレクトリを選択してください。"
|
||||
ErrComposerFileNotFound: "composer.json ファイルが存在しません"
|
||||
ErrRuntimeNoPort: "ランタイム環境にポートが設定されていません。先にランタイム環境を編集してください。"
|
||||
Status: 'ステータス'
|
||||
start: '開始'
|
||||
stop: '停止'
|
||||
delete: '削除'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: '{{ .name }} 証明書は Web サイトで使用されているため、削除できません'
|
||||
@@ -241,6 +247,18 @@ NoSuchResource: "データベースにバックアップ内容が見つかりま
|
||||
ErrNotExistUser: '現在のユーザーは存在しません。変更してもう一度お試しください。'
|
||||
ErrBanAction: '設定に失敗しました。現在の {{ .name }} サービスは利用できません。確認してもう一度お試しください。'
|
||||
ErrClamdscanNotFound: 'clamdscan コマンドが検出されませんでした。インストールするにはドキュメントを参照してください。'
|
||||
TaskSwapSet: "Swap設定"
|
||||
SetSwap: "Swap設定 {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Swapファイル作成"
|
||||
FormatSwap: "Swapファイルフォーマット"
|
||||
EnableSwap: "Swapファイル有効化"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "履歴保護設定をクリーンアップ"
|
||||
SetTamperWithRules: "ルールに従ってディレクトリ保護を開始"
|
||||
ProtectDir: "ディレクトリを保護 {{ .name }}"
|
||||
IgnoreFile: "ファイルを保護 {{ .name }}"
|
||||
TamperSetSuccessful: "保護設定が完了し、以下のディレクトリの監視を開始します:"
|
||||
|
||||
#waf
|
||||
ErrScope: 'この構成の変更はサポートされていません'
|
||||
@@ -313,6 +331,7 @@ TaskDelete: '削除'
|
||||
TaskUpgrade: 'アップグレード'
|
||||
TaskUpdate: '更新'
|
||||
TaskRestart: '再起動'
|
||||
TaskProtect: "保護"
|
||||
TaskBackup: 'バックアップ'
|
||||
TaskRecover: '回復'
|
||||
TaskRollback: 'ロールバック'
|
||||
@@ -353,6 +372,8 @@ RuntimeExtension: 'ランタイム環境拡張'
|
||||
TaskIsExecuting: 'タスクは実行中です'
|
||||
CustomAppstore: 'カスタム アプリケーション ウェアハウス'
|
||||
TaskExec: '実行'
|
||||
TaskBatch: "一括操作"
|
||||
FileConvert: 'ファイル形式の変換'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "{{ .name }} をスキャン"
|
||||
|
||||
@@ -14,6 +14,7 @@ ErrApiConfigKeyInvalid: 'API 인터페이스 키 오류: {{ .detail }}'
|
||||
ErrApiConfigIPInvalid: 'API 인터페이스를 호출하는 데 사용된 IP가 허용 목록에 없습니다: {{ .detail }}'
|
||||
ErrApiConfigDisable: '이 인터페이스는 API 인터페이스 호출 사용을 금지합니다: {{ .detail }}'
|
||||
ErrApiConfigKeyTimeInvalid: 'API 인터페이스 타임스탬프 오류: {{ .detail }}'
|
||||
ErrShutDown: "명령이 수동으로 종료되었습니다!"
|
||||
|
||||
ErrMinQuickJump: "최소 하나의 빠른 점프 항목을 설정해 주세요!"
|
||||
ErrMaxQuickJump: "최대 네 개의 빠른 점프 항목을 설정할 수 있습니다!"
|
||||
@@ -94,6 +95,7 @@ ErrCustomRuntimes: '설치된 런타임 환경이 있습니다. 먼저 삭제해
|
||||
ErrAppVersionDeprecated: "{{ .name }} 응용 프로그램은 현재 1Panel 버전과 호환되지 않아 건너뛰었습니다"
|
||||
ErrDockerFailed: "Docker의 상태가 비정상입니다. 서비스 상태를 확인하세요"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 명령이 없습니다. 호스트 머신에 먼저 이 명령을 설치하세요"
|
||||
UseExistImage: '이미지 가져오기 실패, 기존 이미지 사용'
|
||||
|
||||
#ssh
|
||||
ExportIP: "로그인 IP"
|
||||
@@ -122,6 +124,7 @@ ErrLogFileToLarge: "로그 파일이 500MB를 초과하여 열 수 없습니다"
|
||||
FileDropFailed: "파일 {{ .name }} 정리 실패: {{ .err }}"
|
||||
FileDropSuccess: "파일 {{ .name }} 정리 성공, {{ .count }}개 파일 삭제, {{ .size }} 디스크 공간 확보"
|
||||
FileDropSum: "파일 정리 완료, 총 {{ .count }}개 파일 삭제, 총 {{ .size }} 디스크 공간 확보"
|
||||
ErrBadDecrypt: "압축 패키지 암호 해제 비밀번호 오류, 압축 해제 실패, 확인 후 다시 시도하세요!"
|
||||
|
||||
#웹사이트
|
||||
ErrAliasIsExist: '별칭이 이미 존재합니다'
|
||||
@@ -140,6 +143,10 @@ ErrSSLValid: '인증서 파일에 문제가 있습니다. 인증서 상태를
|
||||
ErrWebsiteDir: "웹사이트 디렉토리 내의 디렉토리를 선택하세요."
|
||||
ErrComposerFileNotFound: "composer.json 파일이 존재하지 않습니다"
|
||||
ErrRuntimeNoPort: "런타임 환경에 포트가 설정되지 않았습니다. 먼저 런타임 환경을 편집하세요."
|
||||
Status: '상태'
|
||||
start: '시작'
|
||||
stop: '중지'
|
||||
delete: '삭제'
|
||||
|
||||
#SSL인증
|
||||
ErrSSLCannotDelete: '{{ .name }} 인증서는 웹사이트에서 사용 중이므로 삭제할 수 없습니다.'
|
||||
@@ -241,6 +248,18 @@ NoSuchResource: "데이터베이스에서 백업 내용을 찾을 수 없어 건
|
||||
ErrNotExistUser: '현재 사용자가 존재하지 않습니다. 수정한 후 다시 시도하세요!'
|
||||
ErrBanAction: '설정에 실패했습니다. 현재 {{ .name }} 서비스를 사용할 수 없습니다. 확인하고 다시 시도하세요!'
|
||||
ErrClamdscanNotFound: 'clamdscan 명령이 감지되지 않았습니다. 설명서를 참조하여 설치하세요!'
|
||||
TaskSwapSet: "Swap 설정"
|
||||
SetSwap: "Swap 설정 {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Swap 파일 생성"
|
||||
FormatSwap: "Swap 파일 포맷"
|
||||
EnableSwap: "Swap 활성화"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "히스토리 보호 설정 정리"
|
||||
SetTamperWithRules: "규칙에 따라 디렉토리 보호 시작"
|
||||
ProtectDir: "디렉토리 보호 {{ .name }}"
|
||||
IgnoreFile: "파일 보호 {{ .name }}"
|
||||
TamperSetSuccessful: "보호 설정 완료, 다음 디렉토리 모니터링 시작:"
|
||||
|
||||
#와프
|
||||
ErrScope: '이 구성을 수정하는 것은 지원되지 않습니다'
|
||||
@@ -313,6 +332,7 @@ TaskDelete: '삭제'
|
||||
TaskUpgrade: '업그레이드'
|
||||
TaskUpdate: '업데이트'
|
||||
TaskRestart: '다시 시작'
|
||||
TaskProtect: "보호"
|
||||
TaskBackup: '백업'
|
||||
TaskRecover: '복구'
|
||||
TaskRollback: '롤백'
|
||||
@@ -353,6 +373,8 @@ RuntimeExtension: '런타임 환경 확장'
|
||||
TaskIsExecuting: '작업이 실행 중입니다'
|
||||
CustomAppstore: '사용자 정의 애플리케이션 웨어하우스'
|
||||
TaskExec: '실행'
|
||||
TaskBatch: "일괄 작업"
|
||||
FileConvert: '파일 형식 변환'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "{{ .name }} 스캔"
|
||||
|
||||
@@ -17,6 +17,7 @@ ErrApiConfigKeyTimeInvalid: 'Ralat cap masa antara muka API: {{ .detail }}'
|
||||
StartPushSSLToNode: "Mula menolak sijil ke nod"
|
||||
PushSSLToNodeFailed: "Gagal menolak sijil ke nod: {{ .err }}"
|
||||
PushSSLToNodeSuccess: "Berjaya menolak sijil ke nod"
|
||||
ErrShutDown: "Arahan dihentikan secara manual!"
|
||||
|
||||
ErrMinQuickJump: "Sila tetapkan sekurang-kurangnya satu entri lompat pantas!"
|
||||
ErrMaxQuickJump: "Anda boleh menetapkan sehingga empat entri lompat pantas!"
|
||||
@@ -97,6 +98,7 @@ ErrCustomRuntimes: 'Terdapat persekitaran masa jalan yang dipasang, sila padamka
|
||||
ErrAppVersionDeprecated: "Aplikasi {{ .name }} tidak sesuai dengan versi 1Panel saat ini, dilewati"
|
||||
ErrDockerFailed: "Keadaan Docker tidak normal, sila periksa status perkhidmatan"
|
||||
ErrDockerComposeCmdNotFound: "Perintah Docker Compose tidak wujud, sila pasang perintah ini di mesin tuan terlebih dahulu"
|
||||
UseExistImage: 'Gagal menarik imej, menggunakan imej sedia ada'
|
||||
|
||||
#ssh
|
||||
ExportIP: "IP Log Masuk"
|
||||
@@ -125,6 +127,7 @@ ErrLogFileTooLarge: "Fail log melebihi 500MB dan tidak boleh dibuka"
|
||||
FileDropFailed: "Gagal membersihkan fail {{ .name }}: {{ .err }}"
|
||||
FileDropSuccess: "Berjaya membersihkan fail {{ .name }}, {{ .count }} fail dibersihkan, {{ .size }} ruang cakera dibebaskan"
|
||||
FileDropSum: "Pembersihan fail selesai, sejumlah {{ .count }} fail dibersihkan, sejumlah {{ .size }} ruang cakera dibebaskan"
|
||||
ErrBadDecrypt: "Kata laluan penyahsulitan pakej termampat salah, penyahmampatan gagal, sila periksa dan cuba lagi!"
|
||||
|
||||
#laman web
|
||||
ErrAliasIsExist: 'Alias sudah wujud'
|
||||
@@ -143,6 +146,10 @@ ErrSSLValid: 'Fail sijil bermasalah, sila periksa status sijil!'
|
||||
ErrWebsiteDir: "Sila pilih direktori dalam direktori laman web."
|
||||
ErrComposerFileNotFound: "Fail composer.json tidak wujud"
|
||||
ErrRuntimeNoPort: "Persekitaran runtime tidak diset dengan port, sila edit persekitaran runtime terlebih dahulu."
|
||||
Status: 'Status'
|
||||
start: 'Mulakan'
|
||||
stop: 'Berhenti'
|
||||
delete: 'Padam'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: 'Sijil {{ .name }} sedang digunakan oleh tapak web dan tidak boleh dipadamkan'
|
||||
@@ -241,6 +248,18 @@ NoSuchResource: "Tiada kandungan sandaran ditemui dalam pangkalan data, dilangka
|
||||
ErrNotExistUser: 'Pengguna semasa tidak wujud, sila ubah suai dan cuba lagi!'
|
||||
ErrBanAction: 'Tetapan gagal. Perkhidmatan {{ .name }} semasa tidak tersedia. Sila semak dan cuba lagi!'
|
||||
ErrClamdscanNotFound: 'Arahan clamdscan tidak dikesan, sila rujuk dokumentasi untuk memasangnya!'
|
||||
TaskSwapSet: "Tetapkan Swap"
|
||||
SetSwap: "Tetapkan Swap {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Buat Fail Swap"
|
||||
FormatSwap: "Format Fail Swap"
|
||||
EnableSwap: "Dayakan Swap"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "Bersihkan tetapan perlindungan sejarah"
|
||||
SetTamperWithRules: "Mulakan perlindungan direktori mengikut peraturan"
|
||||
ProtectDir: "Lindungi direktori {{ .name }}"
|
||||
IgnoreFile: "Lindungi fail {{ .name }}"
|
||||
TamperSetSuccessful: "Tetapan perlindungan selesai, mula memantau direktori berikut:"
|
||||
|
||||
#waf
|
||||
ErrScope: 'Mengubah suai konfigurasi ini tidak disokong'
|
||||
@@ -313,6 +332,7 @@ TaskDelete: 'Padam'
|
||||
TaskUpgrade: 'Naik taraf'
|
||||
TaskUpdate: 'Kemas kini'
|
||||
TaskRestart: 'Mulakan semula'
|
||||
TaskProtect: "Lindungi"
|
||||
TaskBackup: 'Sandaran'
|
||||
TaskRecover: 'Pulihkan'
|
||||
TaskRollback: 'Rollback'
|
||||
@@ -353,6 +373,8 @@ RuntimeExtension: 'Sambungan Persekitaran Runtime'
|
||||
TaskIsExecuting: 'Tugas sedang berjalan'
|
||||
CustomAppstore: 'Gudang aplikasi tersuai'
|
||||
TaskExec: 'Laksanakan'
|
||||
TaskBatch: "Operasi Batch"
|
||||
FileConvert: 'Penukaran Format Fail'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "Imbas {{ .name }}"
|
||||
|
||||
@@ -17,6 +17,7 @@ ErrApiConfigKeyTimeInvalid: 'Erro de registro de data e hora da interface da API
|
||||
StartPushSSLToNode: "Iniciando o envio do certificado para o nó"
|
||||
PushSSLToNodeFailed: "Falha ao enviar o certificado para o nó: {{ .err }}"
|
||||
PushSSLToNodeSuccess: "Certificado enviado com sucesso para o nó"
|
||||
ErrShutDown: "Comando terminado manualmente!"
|
||||
|
||||
ErrMinQuickJump: "Defina pelo menos uma entrada de salto rápido!"
|
||||
ErrMaxQuickJump: "Você pode definir até quatro entradas de salto rápido!"
|
||||
@@ -97,6 +98,7 @@ 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"
|
||||
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"
|
||||
UseExistImage: 'Falha ao puxar a imagem, usando imagem existente'
|
||||
|
||||
#ssh
|
||||
ExportIP: "IP de Login"
|
||||
@@ -125,6 +127,7 @@ ErrLogFileToLarge: "Fail log melebihi 500MB, tidak boleh dibuka"
|
||||
FileDropFailed: "Falha ao limpar arquivo {{ .name }}: {{ .err }}"
|
||||
FileDropSuccess: "Arquivo {{ .name }} limpo com sucesso, {{ .count }} arquivos removidos, {{ .size }} de espaço em disco liberado"
|
||||
FileDropSum: "Limpeza de arquivos concluída com sucesso, total de {{ .count }} arquivos removidos, total de {{ .size }} de espaço em disco liberado"
|
||||
ErrBadDecrypt: "Erro de senha de descriptografia do pacote compactado, descompactação falhou, verifique e tente novamente!"
|
||||
|
||||
#site
|
||||
ErrAliasIsExist: 'Alias já existe'
|
||||
@@ -143,6 +146,10 @@ ErrSSLValid: 'O arquivo do certificado está anormal, verifique o status do cert
|
||||
ErrWebsiteDir: "Por favor, selecione um diretório dentro do diretório do site."
|
||||
ErrComposerFileNotFound: "O arquivo composer.json não existe"
|
||||
ErrRuntimeNoPort: "O ambiente de tempo de execução não está configurado com uma porta, edite o ambiente de tempo de execução primeiro."
|
||||
Status: 'Status'
|
||||
start: 'Iniciar'
|
||||
stop: 'Parar'
|
||||
delete: 'Excluir'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: 'O certificado {{ .name }} está sendo usado por um site e não pode ser excluído'
|
||||
@@ -241,6 +248,18 @@ NoSuchResource: "Nenhum conteúdo de backup encontrado no banco de dados, ignora
|
||||
ErrNotExistUser: 'O usuário atual não existe, modifique e tente novamente!'
|
||||
ErrBanAction: 'Falha na configuração. O serviço atual {{ .name }} não está disponível. Verifique e tente novamente!'
|
||||
ErrClamdscanNotFound: 'O comando clamdscan não foi detectado, consulte a documentação para instalá-lo!'
|
||||
TaskSwapSet: "Configurar Swap"
|
||||
SetSwap: "Configurar Swap {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Criar Arquivo Swap"
|
||||
FormatSwap: "Formatar Arquivo Swap"
|
||||
EnableSwap: "Ativar Swap"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "Limpar configurações de proteção históricas"
|
||||
SetTamperWithRules: "Iniciar proteção de diretório de acordo com as regras"
|
||||
ProtectDir: "Proteger diretório {{ .name }}"
|
||||
IgnoreFile: "Proteger arquivo {{ .name }}"
|
||||
TamperSetSuccessful: "Configurações de proteção concluídas, iniciando monitoramento dos seguintes diretórios:"
|
||||
|
||||
#waf
|
||||
ErrScope: 'A modificação desta configuração não é suportada'
|
||||
@@ -313,6 +332,7 @@ TaskDelete: 'Excluir'
|
||||
TaskUpgrade: 'Atualizar'
|
||||
TaskUpdate: 'Atualizar'
|
||||
TaskRestart: 'Reiniciar'
|
||||
TaskProtect: "Proteger"
|
||||
Backup de Tarefa: 'Backup'
|
||||
TaskRecover: 'Recuperar'
|
||||
TaskRollback: 'Reverter'
|
||||
@@ -353,6 +373,8 @@ RuntimeExtension: 'Extensão do ambiente de tempo de execução'
|
||||
TaskIsExecuting: 'A tarefa está em execução'
|
||||
CustomAppstore: 'Armazém de aplicativos personalizados'
|
||||
TaskExec: 'Executar'
|
||||
TaskBatch: "Operação em Lote"
|
||||
FileConvert: 'Conversão de Formato de Arquivo'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "Escanear {{ .name }}"
|
||||
|
||||
@@ -17,6 +17,7 @@ ErrApiConfigKeyTimeInvalid: 'Ошибка временной метки инте
|
||||
StartPushSSLToNode: "Начало отправки сертификата на узел"
|
||||
PushSSLToNodeFailed: "Не удалось отправить сертификат на узел: {{ .err }}"
|
||||
PushSSLToNodeSuccess: "Сертификат успешно отправлен на узел"
|
||||
ErrShutDown: "Команда завершена вручную!"
|
||||
|
||||
ErrMinQuickJump: "Пожалуйста, установите хотя бы одну запись быстрого перехода!"
|
||||
ErrMaxQuickJump: "Можно установить до четырех записей быстрого перехода!"
|
||||
@@ -97,6 +98,7 @@ ErrCustomRuntimes: 'Установлена среда выполнения. Сн
|
||||
ErrAppVersionDeprecated: "Приложение {{ .name }} несовместимо с текущей версией 1Panel, пропущено"
|
||||
ErrDockerFailed: "Состояние Docker аномально, проверьте состояние сервиса"
|
||||
ErrDockerComposeCmdNotFound: "Команда Docker Compose отсутствует, пожалуйста, установите эту команду на хост-машине сначала"
|
||||
UseExistImage: 'Не удалось загрузить образ, используется существующий образ'
|
||||
|
||||
#ssh
|
||||
ExportIP: "IP входа"
|
||||
@@ -125,6 +127,7 @@ ErrLogFileToLarge: "Файл журнала превышает 500MB и не м
|
||||
FileDropFailed: "Не удалось очистить файл {{ .name }}: {{ .err }}"
|
||||
FileDropSuccess: "Файл {{ .name }} успешно очищен, удалено {{ .count }} файлов, освобождено {{ .size }} дискового пространства"
|
||||
FileDropSum: "Очистка файлов завершена успешно, всего удалено {{ .count }} файлов, освобождено {{ .size }} дискового пространства"
|
||||
ErrBadDecrypt: "Ошибка пароля расшифровки сжатого пакета, распаковка не удалась, проверьте и повторите попытку!"
|
||||
|
||||
#веб-сайт
|
||||
ErrAliasIsExist: 'Псевдоним уже существует'
|
||||
@@ -143,6 +146,10 @@ ErrSSLValid: 'Файл сертификата аномален, проверьт
|
||||
ErrWebsiteDir: "Пожалуйста, выберите директорию внутри директории сайта."
|
||||
ErrComposerFileNotFound: "Файл composer.json не существует"
|
||||
ErrRuntimeNoPort: "Среда выполнения не настроена с портом, сначала отредактируйте среду выполнения."
|
||||
Status: 'Статус'
|
||||
start: 'Запустить'
|
||||
stop: 'Остановить'
|
||||
delete: 'Удалить'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: 'Сертификат {{ .name }} используется веб-сайтом и не может быть удален'
|
||||
@@ -241,6 +248,18 @@ NoSuchResource: "В базе данных не найдено содержимо
|
||||
ErrNotExistUser: 'Текущий пользователь не существует, измените его и повторите попытку!'
|
||||
ErrBanAction: 'Настройка не удалась. Текущая служба {{ .name }} недоступна. Проверьте и повторите попытку!'
|
||||
ErrClamdscanNotFound: 'Команда clamdscan не обнаружена, обратитесь к документации, чтобы установить ее!'
|
||||
TaskSwapSet: "Настройка Swap"
|
||||
SetSwap: "Настроить Swap {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Создать Файл Swap"
|
||||
FormatSwap: "Форматировать Файл Swap"
|
||||
EnableSwap: "Включить Swap"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "Очистить исторические настройки защиты"
|
||||
SetTamperWithRules: "Запустить защиту каталога согласно правилам"
|
||||
ProtectDir: "Защитить каталог {{ .name }}"
|
||||
IgnoreFile: "Защитить файл {{ .name }}"
|
||||
TamperSetSuccessful: "Настройки защиты завершены, начинаю мониторинг следующих каталогов:"
|
||||
|
||||
#ваф
|
||||
ErrScope: 'Изменение этой конфигурации не поддерживается'
|
||||
@@ -313,6 +332,7 @@ TaskDelete: 'Удалить'
|
||||
TaskUpgrade: 'Обновить'
|
||||
TaskUpdate: 'Обновить'
|
||||
TaskRestart: 'Перезапуск'
|
||||
TaskProtect: "Защита"
|
||||
TaskBackup: 'Резервное копирование'
|
||||
TaskRecover: 'Восстановить'
|
||||
TaskRollback: 'Откат'
|
||||
@@ -353,6 +373,8 @@ RuntimeExtension: 'Расширение среды выполнения'
|
||||
TaskIsExecuting: 'Задача выполняется'
|
||||
CustomAppstore: 'Хранилище пользовательских приложений'
|
||||
TaskExec: 'Выполнить'
|
||||
TaskBatch: "Пакетная операция"
|
||||
FileConvert: 'Преобразование формата файла'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "Сканировать {{ .name }}"
|
||||
|
||||
@@ -17,6 +17,7 @@ ErrApiConfigKeyTimeInvalid: 'API arayüz zaman damgası hatası: {{ .detail }}'
|
||||
StartPushSSLToNode: "Sertifika düğüme gönderilmeye başlandı"
|
||||
PushSSLToNodeFailed: "Sertifika düğüme gönderilemedi: {{ .err }}"
|
||||
PushSSLToNodeSuccess: "Sertifika düğüme başarıyla gönderildi"
|
||||
ErrShutDown: "Komut manuel olarak sonlandırıldı!"
|
||||
|
||||
ErrMinQuickJump: "Lütfen en az bir hızlı atlama girişi ayarlayın!"
|
||||
ErrMaxQuickJump: "En fazla dört hızlı atlama girişi ayarlayabilirsiniz!"
|
||||
@@ -97,6 +98,7 @@ ErrCustomRuntimes: 'Yüklü bir çalışma ortamı var, lütfen önce silin'
|
||||
ErrAppVersionDeprecated: "{{ .name }} uygulaması mevcut 1Panel sürümü ile uyumlu değil, atlandı"
|
||||
ErrDockerFailed: "Docker durumu anormal, lütfen servis durumunu kontrol edin"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose komutu mevcut değil, lütfen önce bu komutu host makinesine yükleyin"
|
||||
UseExistImage: 'Görüntü çekme başarısız, mevcut görüntü kullanılıyor'
|
||||
|
||||
#ssh
|
||||
ExportIP: "Giriş IP"
|
||||
@@ -125,6 +127,7 @@ ErrLogFileToLarge: "Günlük dosyası 500MB'ı aşıyor ve açılamıyor"
|
||||
FileDropFailed: "{{ .name }} dosyası temizlenemedi: {{ .err }}"
|
||||
FileDropSuccess: "{{ .name }} dosyası başarıyla temizlendi, {{ .count }} dosya silindi, {{ .size }} disk alanı boşaltıldı"
|
||||
FileDropSum: "Dosya temizleme tamamlandı, toplam {{ .count }} dosya silindi, toplam {{ .size }} disk alanı boşaltıldı"
|
||||
ErrBadDecrypt: "Sıkıştırılmış paket şifre çözme parolası hatalı, açma başarısız, lütfen kontrol edip tekrar deneyin!"
|
||||
|
||||
|
||||
#website
|
||||
@@ -144,6 +147,10 @@ ErrSSLValid: 'Sertifika dosyası anormal, lütfen sertifika durumunu kontrol edi
|
||||
ErrWebsiteDir: "Lütfen web sitesi dizini içindeki bir dizin seçin."
|
||||
ErrComposerFileNotFound: "composer.json dosyası mevcut değil"
|
||||
ErrRuntimeNoPort: "Çalışma zamanı ortamı bir porta sahip değil, lütfen önce çalışma zamanı ortamını düzenleyin."
|
||||
Status: 'Durum'
|
||||
start: 'Başlat'
|
||||
stop: 'Durdur'
|
||||
delete: 'Sil'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: '{{ .name }} sertifikası bir web sitesi tarafından kullanılıyor ve silinemez'
|
||||
@@ -242,6 +249,18 @@ NoSuchResource: "Veritabanında yedek içeriği bulunamadı, atlanıyor..."
|
||||
ErrNotExistUser: 'Mevcut kullanıcı mevcut değil, lütfen değiştirin ve tekrar deneyin!'
|
||||
ErrBanAction: 'Ayarlama başarısız. Mevcut {{ .name }} servisi kullanılamıyor. Lütfen kontrol edin ve tekrar deneyin!'
|
||||
ErrClamdscanNotFound: 'clamdscan komutu tespit edilmedi, lütfen yüklemek için belgeleri inceleyin!'
|
||||
TaskSwapSet: "Swap Ayarla"
|
||||
SetSwap: "Swap Ayarla {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "Swap Dosyası Oluştur"
|
||||
FormatSwap: "Swap Dosyasını Biçimlendir"
|
||||
EnableSwap: "Swap Etkinleştir"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "Geçmiş koruma ayarlarını temizle"
|
||||
SetTamperWithRules: "Kurallara göre dizin korumasını başlat"
|
||||
ProtectDir: "Dizini koru {{ .name }}"
|
||||
IgnoreFile: "Dosyayı koru {{ .name }}"
|
||||
TamperSetSuccessful: "Koruma ayarları tamamlandı, aşağıdaki dizinler izlenmeye başlanıyor:"
|
||||
|
||||
#waf
|
||||
ErrScope: 'Bu yapılandırmayı değiştirme desteklenmiyor'
|
||||
@@ -314,6 +333,7 @@ TaskDelete: 'Sil'
|
||||
TaskUpgrade: 'Yükselt'
|
||||
TaskUpdate: 'Güncelle'
|
||||
TaskRestart: 'Yeniden Başlat'
|
||||
TaskProtect: "Koru"
|
||||
TaskBackup: 'Yedekle'
|
||||
TaskRecover: 'Kurtar'
|
||||
TaskRollback: 'Geri Al'
|
||||
@@ -354,6 +374,8 @@ RuntimeExtension: 'Çalışma Ortamı Uzantısı'
|
||||
TaskIsExecuting: 'Görev çalışıyor'
|
||||
CustomAppstore: 'Özel uygulama deposu'
|
||||
TaskExec: 'Çalıştır'
|
||||
TaskBatch: "Toplu İşlem"
|
||||
FileConvert: 'Dosya Formatı Dönüştürme'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "{{ .name }} Tara"
|
||||
|
||||
@@ -14,6 +14,7 @@ ErrApiConfigKeyInvalid: 'API 介面金鑰錯誤: {{ .detail }}'
|
||||
ErrApiConfigIPInvalid: '呼叫 API 介面 IP 不在白名單: {{ .detail }}'
|
||||
ErrApiConfigDisable: '此介面禁止使用 API 介面呼叫: {{ .detail }}'
|
||||
ErrApiConfigKeyTimeInvalid: 'API 介面時間戳記錯誤: {{ .detail }}'
|
||||
ErrShutDown: "指令被手動結束!"
|
||||
|
||||
ErrMinQuickJump: "請至少設定一個快速跳轉入口!"
|
||||
ErrMaxQuickJump: "最多可設定四個快速跳轉入口!"
|
||||
@@ -92,12 +93,13 @@ ErrCustomApps: '存在已安裝的應用程式,請先解除安裝'
|
||||
ErrCustomRuntimes: '存在已安裝的運作環境,請先刪除'
|
||||
ErrAppVersionDeprecated: "{{ .name }} 應用不適配目前 1Panel 版本,跳過"
|
||||
ErrDockerFailed: "Docker 狀態異常,請檢查服務狀態"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 命令不存在,請先在宿主機安裝此命令"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 指令不存在,請先在宿主機安裝此指令"
|
||||
UseExistImage: '拉取映像失敗,使用存量映像'
|
||||
|
||||
#ssh
|
||||
ExportIP: "登入IP"
|
||||
ExportArea: "歸屬地"
|
||||
ExportPort: "端口"
|
||||
ExportPort: "埠"
|
||||
ExportAuthMode: "登入方式"
|
||||
ExportUser: "使用者"
|
||||
ExportStatus: "登入狀態"
|
||||
@@ -115,12 +117,13 @@ ErrFileDownloadDir: '不支援下載資料夾'
|
||||
ErrCmdNotFound: '{{ .name}} 指令不存在,請先在宿主機安裝此指令'
|
||||
ErrSourcePathNotFound: '來源目錄不存在'
|
||||
ErrFavoriteExist: '已收藏此路徑'
|
||||
ErrInvalidChar: '禁止使用非法字元'
|
||||
ErrInvalidChar: '禁止使用無效字元'
|
||||
ErrPathNotDelete: '所選目錄不可刪除'
|
||||
ErrLogFileToLarge: "日志文件超过 500M,無法打開"
|
||||
ErrLogFileToLarge: "日誌檔案超過 500M,無法打開"
|
||||
FileDropFailed: "清理文件 {{ .name }} 失敗: {{ .err }}"
|
||||
FileDropSuccess: "清理文件 {{ .name }} 成功,清理 {{ .count }} 個文件,釋放 {{ .size }} 磁碟空間"
|
||||
FileDropSum: "文件清理完成,共清理 {{ .count }} 個文件,共釋放 {{ .size }} 磁碟空間"
|
||||
ErrBadDecrypt: "壓縮檔解壓密碼錯誤,解壓失敗,請檢查後重試!"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: '代號已存在'
|
||||
@@ -138,7 +141,11 @@ ErrProxyIsUsed: "負載均衡已被反向代理使用,無法刪除"
|
||||
ErrSSLValid: '證書文件異常,請檢查證書狀態!'
|
||||
ErrWebsiteDir: "請選擇網站目錄下的目錄"
|
||||
ErrComposerFileNotFound: "composer.json 文件不存在"
|
||||
ErrRuntimeNoPort: "運行環境未設置端口,請先編輯運行環境"
|
||||
ErrRuntimeNoPort: "執行環境未設定埠,請先編輯執行環境"
|
||||
Status: '狀態'
|
||||
start: '開啟'
|
||||
stop: '關閉'
|
||||
delete: '刪除'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: '{{ .name }} 憑證正在被網站使用,無法刪除'
|
||||
@@ -192,11 +199,11 @@ ErrObjectInUsed: '該物件正被使用,無法刪除'
|
||||
ErrObjectBeDependent: '此鏡像依賴其他鏡像,無法刪除'
|
||||
ErrPortRules: '連接埠數目不匹配,請重新輸入!'
|
||||
ErrPgImagePull: '鏡像拉取逾時,請配置鏡像加速或手動拉取{{ .name }} 鏡像後重試'
|
||||
PruneHelper: "本次清理 {{ .name }} {{ .count }} 個,釋放磁盤空間 {{ .size }}"
|
||||
ImageRemoveHelper: "刪除鏡像 {{ .name }} ,釋放磁盤空間 {{ .size }}"
|
||||
BuildCache: "構建緩存"
|
||||
Volume: "存儲卷"
|
||||
Network: "網絡"
|
||||
PruneHelper: "本次清理 {{ .name }} {{ .count }} 個,釋放磁碟空間 {{ .size }}"
|
||||
ImageRemoveHelper: "刪除鏡像 {{ .name }} ,釋放磁碟空間 {{ .size }}"
|
||||
BuildCache: "構建快取"
|
||||
Volume: "磁碟區"
|
||||
Network: "網路"
|
||||
|
||||
#runtime
|
||||
ErrFileNotExist: '{{ .detail }} 檔案不存在!請檢查來源檔案完整性!'
|
||||
@@ -232,14 +239,26 @@ UploadFile: '上傳備份文件 {{ .file }} 到 {{ .backup }}'
|
||||
Upload: "上傳"
|
||||
IgnoreBackupErr: "備份失敗,錯誤:{{ .detail }},忽略本次錯誤..."
|
||||
IgnoreUploadErr: "上傳失敗,錯誤:{{ .detail }},忽略本次錯誤..."
|
||||
LoadBackupFailed: "獲取備份帳號連接失敗,錯誤:{{ .detail }}"
|
||||
InExecuting: "當前任務正在執行中,請勿重複執行!"
|
||||
LoadBackupFailed: "取得備份帳號連線失敗,錯誤:{{ .detail }}"
|
||||
InExecuting: "目前任務正在執行中,請勿重複執行!"
|
||||
NoSuchResource: "資料庫中未能查詢到備份內容,跳過..."
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: '目前使用者不存在,請修改後重試!'
|
||||
ErrBanAction: '設定失敗,目前{{ .name }} 服務不可用,請檢查後再試一次!'
|
||||
ErrClamdscanNotFound: '未偵測到clamdscan 指令,請參考文件安裝!'
|
||||
TaskSwapSet: "設定 Swap"
|
||||
SetSwap: "設定 Swap {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "建立 Swap 檔案"
|
||||
FormatSwap: "格式化 Swap 檔案"
|
||||
EnableSwap: "啟用 Swap"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "清理歷史防護設定"
|
||||
SetTamperWithRules: "根據規則啟動目錄防護"
|
||||
ProtectDir: "防護目錄 {{ .name }}"
|
||||
IgnoreFile: "保護文件 {{ .name }}"
|
||||
TamperSetSuccessful: "防護設定完成,開始監聽以下目錄:"
|
||||
|
||||
#waf
|
||||
ErrScope: '不支援修改此配置'
|
||||
@@ -248,7 +267,7 @@ ErrRuleExist: '規則已存在'
|
||||
ErrRuleNotExist: '規則不存在'
|
||||
ErrParseIP: 'IP 格式錯誤'
|
||||
ErrDefaultIP: 'default 為保留名稱,請更換其他名稱'
|
||||
ErrGroupInUse: 'IP 群組被駭/白名單使用,無法刪除'
|
||||
ErrGroupInUse: 'IP 群組被黑/白名單使用,無法刪除'
|
||||
ErrIPGroupAclUse: "IP 群組被網站 {{ .name }} 自訂規則使用,無法刪除"
|
||||
ErrGroupExist: 'IP 群組名稱已存在'
|
||||
ErrIPRange: 'IP 範圍錯誤'
|
||||
@@ -312,11 +331,12 @@ TaskDelete: '刪除'
|
||||
TaskUpgrade: '升級'
|
||||
TaskUpdate: '更新'
|
||||
TaskRestart: '重啟'
|
||||
TaskProtect: "防護"
|
||||
TaskBackup: '備份'
|
||||
TaskRecover: '復原'
|
||||
TaskRollback: '回滾'
|
||||
TaskPull: '拉取'
|
||||
TaskCommit: '制作'
|
||||
TaskCommit: '製作'
|
||||
TaskBuild: '建置'
|
||||
TaskPush: '推送'
|
||||
TaskClean: "清理"
|
||||
@@ -352,6 +372,8 @@ RuntimeExtension: '執行環境擴充'
|
||||
TaskIsExecuting: '任務正在運作'
|
||||
CustomAppstore: '自訂應用程式倉庫'
|
||||
TaskExec: '執行'
|
||||
TaskBatch: "批次操作"
|
||||
FileConvert: '檔案格式轉換'
|
||||
|
||||
# task - clam
|
||||
Clamscan: "掃描 {{ .name }}"
|
||||
@@ -371,7 +393,7 @@ SnapDeleteLoginLog: '刪除存取日誌'
|
||||
SnapDeleteMonitor: '刪除監控資料'
|
||||
SnapRemoveSystemIP: '移除系統IP'
|
||||
SnapBaseInfo: '寫入1Panel 基本資料'
|
||||
SnapInstallAppImageEmpty: '當前未勾選應用鏡像,跳過...'
|
||||
SnapInstallAppImageEmpty: '目前未勾選應用鏡像,跳過...'
|
||||
SnapInstallApp: '備份 1Panel 已安裝應用'
|
||||
SnapDockerSave: '壓縮已安裝應用'
|
||||
SnapLocalBackup: '備份1Panel 本機備份目錄'
|
||||
@@ -462,7 +484,7 @@ ErrInstallExtension: "已有安裝任務正在進行,請等待任務結束"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "面板警示通知"
|
||||
TestAlertTitle: "測試郵件 - 驗證郵箱連通性"
|
||||
TestAlertTitle: "測試郵件 - 驗證信箱連通性"
|
||||
TestAlert: "這是一封測試郵件,用於確認您的郵件發送設定是否正確。"
|
||||
LicenseExpirationAlert: "您的 1Panel 授權將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CronJobFailedAlert: "您的 1Panel 面板中,計畫任務 '{{ .name }}' 執行失敗,詳情請登入面板查看。"
|
||||
@@ -476,13 +498,13 @@ PanelPwdExpirationAlert: "您的 1Panel 面板密碼將於 {{ .day }} 天後到
|
||||
CommonAlert: "您的 1Panel 面板,{{ .msg }},詳情請登入面板查看。"
|
||||
NodeExceptionAlert: "您的 1Panel 面板,{{ .num }} 個節點存在異常,詳情請登入面板查看。"
|
||||
LicenseExceptionAlert: "您的 1Panel 面板,{{ .num }} 個許可證存在異常,詳情請登入面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 1Panel 面板,面板{{ .name }}從 {{ .ip }} 登錄異常,詳情請登入面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 1Panel 面板,面板{{ .name }}從 {{ .ip }} 登入異常,詳情請登入面板查看。"
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "設備 {{ .name }} 未找到"
|
||||
DeviceIsMounted: "設備 {{ .name }} 已掛載,請先卸載"
|
||||
DeviceNotFound: "裝置 {{ .name }} 未找到"
|
||||
DeviceIsMounted: "裝置 {{ .name }} 已掛載,請先移除"
|
||||
PartitionDiskErr: "分區失敗,{{ .err }}"
|
||||
FormatDiskErr: "格式化磁盤失敗,{{ .err }}"
|
||||
MountDiskErr: "掛載磁盤失敗,{{ .err }}"
|
||||
UnMountDiskErr: "卸載磁盤失敗,{{ .err }}"
|
||||
FormatDiskErr: "格式化磁碟失敗,{{ .err }}"
|
||||
MountDiskErr: "掛載磁碟失敗,{{ .err }}"
|
||||
UnMountDiskErr: "移除磁碟失敗,{{ .err }}"
|
||||
XfsNotFound: "未檢測到 xfs 文件系統,請先安裝 xfsprogs"
|
||||
|
||||
+23
-1
@@ -14,6 +14,7 @@ ErrApiConfigKeyInvalid: "API 接口密钥错误: {{ .detail }}"
|
||||
ErrApiConfigIPInvalid: "调用 API 接口 IP 不在白名单: {{ .detail }}"
|
||||
ErrApiConfigDisable: "此接口禁止使用 API 接口调用: {{ .detail }}"
|
||||
ErrApiConfigKeyTimeInvalid: "API 接口时间戳错误: {{ .detail }}"
|
||||
ErrShutDown: "命令被手动结束!"
|
||||
|
||||
ErrMinQuickJump: "请至少设置一个快速跳转入口!"
|
||||
ErrMaxQuickJump: "最多可设置四个快速跳转入口!"
|
||||
@@ -93,8 +94,9 @@ ErrCustomRuntimes: "存在已经安装的运行环境,请先删除"
|
||||
ErrAppVersionDeprecated: " {{ .name }} 应用不适配当前 1Panel 版本,跳过"
|
||||
ErrDockerFailed: "Docker 状态异常,请检查服务状态"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 命令不存在,请先在宿主机安装此命令"
|
||||
UseExistImage: "拉取镜像失败,使用存量镜像"
|
||||
|
||||
#ssh
|
||||
#ssh
|
||||
ExportIP: "登录 IP"
|
||||
ExportArea: "归属地"
|
||||
ExportPort: "端口"
|
||||
@@ -121,6 +123,7 @@ ErrLogFileToLarge: "日志文件超过 500M,无法打开"
|
||||
FileDropFailed: "清理文件 {{ .name }} 失败 {{ .err }}"
|
||||
FileDropSuccess: "清理文件 {{ .name }} 成功,清理文件 {{ .count }},释放磁盘空间 {{ .size }}"
|
||||
FileDropSum: "文件清理成功,清理文件共计 {{ .count }},释放磁盘空间共计 {{ .size }}"
|
||||
ErrBadDecrypt: "压缩包解压密码错误,解压失败,请检查后重试!"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: "代号已存在"
|
||||
@@ -139,6 +142,10 @@ ErrSSLValid: '证书文件异常,请检查证书状态!'
|
||||
ErrWebsiteDir: '请选择网站目录下的目录'
|
||||
ErrComposerFileNotFound: 'composer.json 文件不存在'
|
||||
ErrRuntimeNoPort: '运行环境未设置端口,请先编辑运行环境'
|
||||
Status: '状态'
|
||||
start: '开启'
|
||||
stop: '关闭'
|
||||
delete: '删除'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
|
||||
@@ -240,6 +247,18 @@ NoSuchResource: "数据库中未能查询到备份内容,跳过..."
|
||||
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
||||
ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!"
|
||||
ErrClamdscanNotFound: "未检测到 clamdscan 命令,请参考文档安装!"
|
||||
TaskSwapSet: "设置 Swap"
|
||||
SetSwap: "设置 Swap {{ .path }} - {{ .size }}"
|
||||
CreateSwap: "创建 Swap 文件"
|
||||
FormatSwap: "格式化 Swap 文件"
|
||||
EnableSwap: "启用 Swap"
|
||||
|
||||
#tamper
|
||||
CleanTamperSetting: "清理历史防护设置"
|
||||
SetTamperWithRules: "根据规则启动目录防护"
|
||||
ProtectDir: "防护目录 {{ .name }}"
|
||||
IgnoreFile: "保护文件 {{ .name }}"
|
||||
TamperSetSuccessful: "防护设置完成,开始监听以下目录:"
|
||||
|
||||
#waf
|
||||
ErrScope: "不支持修改此配置"
|
||||
@@ -313,6 +332,7 @@ TaskDelete: "删除"
|
||||
TaskUpgrade: "升级"
|
||||
TaskUpdate: "更新"
|
||||
TaskRestart: "重启"
|
||||
TaskProtect: "防护"
|
||||
TaskBackup: "备份"
|
||||
TaskRecover: "恢复"
|
||||
TaskRollback: "回滚"
|
||||
@@ -353,6 +373,8 @@ RuntimeExtension: "运行环境扩展"
|
||||
TaskIsExecuting: "任务正在运行"
|
||||
CustomAppstore: "自定义应用仓库"
|
||||
TaskExec: "执行"
|
||||
TaskBatch: "批量操作"
|
||||
FileConvert: "文件格式转换"
|
||||
|
||||
# task - clam
|
||||
Clamscan: "扫描 {{ .name }}"
|
||||
|
||||
@@ -20,6 +20,9 @@ func Init() {
|
||||
}
|
||||
|
||||
func syncApp() {
|
||||
if global.CONF.Base.IsOffLine {
|
||||
return
|
||||
}
|
||||
_ = service.NewISettingService().Update("AppStoreSyncStatus", constant.StatusSyncSuccess)
|
||||
if err := service.NewIAppService().SyncAppListFromRemote(""); err != nil {
|
||||
global.LOG.Errorf("App Store synchronization failed")
|
||||
|
||||
@@ -27,8 +27,11 @@ func Init() {
|
||||
global.Dir.LocalAppInstallDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/apps/local"))
|
||||
global.Dir.RemoteAppResourceDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/resource/apps/remote"))
|
||||
global.Dir.CustomAppResourceDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/resource/apps/custom"))
|
||||
global.Dir.OfflineAppResourceDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/resource/offline"))
|
||||
global.Dir.RuntimeDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/runtime"))
|
||||
global.Dir.RecycleBinDir, _ = fileOp.CreateDirWithPath(true, "/.1panel_clash")
|
||||
global.Dir.SSLLogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log/ssl"))
|
||||
global.Dir.McpDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/mcp"))
|
||||
global.Dir.ConvertLogDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/log/convert"))
|
||||
global.Dir.TensorRTLLMDir, _ = fileOp.CreateDirWithPath(true, path.Join(baseDir, "1panel/ai/tensorrt_llm"))
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user