mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-10 00:00:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04b9cbd87a | ||
|
|
4565c5b300 | ||
|
|
bf9a9bf17a | ||
|
|
70df4dc6c4 | ||
|
|
ed3e738fff | ||
|
|
bc376ec495 | ||
|
|
40314e9079 | ||
|
|
82f978c683 | ||
|
|
ed288368ea | ||
|
|
db8fa144eb | ||
|
|
57b76d97ec | ||
|
|
28d8210ce6 | ||
|
|
80ce60c56c | ||
|
|
2758ab07dc | ||
|
|
0828804de2 | ||
|
|
134b17d2f0 | ||
|
|
3af254cdda | ||
|
|
f3d3d54722 | ||
|
|
fa419809f6 | ||
|
|
da606826c6 | ||
|
|
b3d9cc156a | ||
|
|
ba03d26b2c | ||
|
|
40f02889fe | ||
|
|
4f8fb26d89 | ||
|
|
0ca11e2b88 | ||
|
|
0daf0d690c | ||
|
|
0cfdf0f335 | ||
|
|
cca1863b63 | ||
|
|
033f08a6d2 | ||
|
|
a83a6690ff | ||
|
|
83df457379 | ||
|
|
657e55cde3 | ||
|
|
90e76e3a0f | ||
|
|
2af1993383 | ||
|
|
6e650d977e | ||
|
|
8a76171dbe | ||
|
|
949b6fe944 | ||
|
|
3f90333090 | ||
|
|
aeaca0c5cd | ||
|
|
fb7f638a54 | ||
|
|
7994193a39 | ||
|
|
3334bf594d | ||
|
|
71193cc912 | ||
|
|
9fde8c447d | ||
|
|
117faa952e | ||
|
|
6427337728 | ||
|
|
81f97f6f88 | ||
|
|
b3b472d711 | ||
|
|
1c22e1cf99 | ||
|
|
3110d91bf6 | ||
|
|
624a11407a | ||
|
|
ead6d1268f | ||
|
|
80c00c5a8c | ||
|
|
da0f6acd01 | ||
|
|
485aa99dea | ||
|
|
5f68d7ce90 | ||
|
|
685fca6c8c | ||
|
|
9c609da332 | ||
|
|
84608b7d42 | ||
|
|
02cf2a80cb | ||
|
|
a74c6dd522 | ||
|
|
5d4ab23d95 | ||
|
|
a8faba3206 | ||
|
|
c603495b12 | ||
|
|
adce6103bd | ||
|
|
6b673017c5 | ||
|
|
e66bd43fc6 | ||
|
|
ff5cdb9a02 | ||
|
|
1aec5e443d | ||
|
|
0b1f7e9322 | ||
|
|
3ec2dec49b | ||
|
|
7cbebc8236 | ||
|
|
700076f278 | ||
|
|
7bf1bf61a7 | ||
|
|
ef2cb1b315 | ||
|
|
75bfc3a114 | ||
|
|
70f63090fe | ||
|
|
ab2cf0d0c3 | ||
|
|
ea1a34f57a | ||
|
|
765add6184 | ||
|
|
e5263d6c05 | ||
|
|
c391177d34 | ||
|
|
7d5f0aa906 | ||
|
|
2694a725d6 | ||
|
|
54ca40bbcd | ||
|
|
b20411f8f1 | ||
|
|
355e656caa | ||
|
|
383bdd5f15 | ||
|
|
96208c786d | ||
|
|
4c7b04cf27 | ||
|
|
a067a97e21 | ||
|
|
4a07603a7c | ||
|
|
7196c5b656 | ||
|
|
b5de2df119 | ||
|
|
2f72eb37ee | ||
|
|
0128cd3138 | ||
|
|
157d3093f8 | ||
|
|
4ca188973e | ||
|
|
f387d89a45 | ||
|
|
54567db22f | ||
|
|
2bee68dd40 | ||
|
|
e2b6ea5253 | ||
|
|
9974c5fa20 | ||
|
|
997b706d8a | ||
|
|
3f26412585 | ||
|
|
ac99d77fbb | ||
|
|
4f6f7632f5 | ||
|
|
f74248f0d7 | ||
|
|
bb8a15ca56 | ||
|
|
52432002c7 | ||
|
|
3fade48f8f | ||
|
|
fc81801c4c | ||
|
|
c23c5b2859 | ||
|
|
ccec57e32d | ||
|
|
56ae5fbf70 | ||
|
|
735b44856e | ||
|
|
1f6ea9f494 | ||
|
|
afa643519f | ||
|
|
1767b84026 | ||
|
|
e855e7692e | ||
|
|
94d37eb68a | ||
|
|
e10b19bcde | ||
|
|
e9192e75ea | ||
|
|
2fa4f68b1e | ||
|
|
08f53a4a37 | ||
|
|
c522295c56 | ||
|
|
7a45548387 | ||
|
|
810ea9c421 | ||
|
|
ba6a4fe6d7 | ||
|
|
4d144f7a8e | ||
|
|
45c41184c1 | ||
|
|
5c29c5e7dd | ||
|
|
4da9a84363 | ||
|
|
22d8fb7867 | ||
|
|
c7058cb3e6 | ||
|
|
e6092b2658 | ||
|
|
ae19b72e61 | ||
|
|
da117582d6 | ||
|
|
c7ca1ccbd7 | ||
|
|
911b5c406d | ||
|
|
71ed4b946a | ||
|
|
4ef9fcde59 | ||
|
|
7889b5ad69 | ||
|
|
be6d3ea337 | ||
|
|
64fd715973 | ||
|
|
315f99a03a | ||
|
|
7e1351c543 | ||
|
|
bd3c829653 | ||
|
|
4f6dde02d2 | ||
|
|
8cc7d1f67f | ||
|
|
2bbba9d755 | ||
|
|
e9e4755348 | ||
|
|
9fbb63df95 | ||
|
|
5b5a649589 | ||
|
|
79556affbd | ||
|
|
9cba19d4db | ||
|
|
4f377c04b8 | ||
|
|
763df5606b | ||
|
|
e1d20e3ec9 | ||
|
|
215c082a04 | ||
|
|
984985e650 | ||
|
|
249b3c3245 | ||
|
|
725786d6aa | ||
|
|
2edddaf487 | ||
|
|
49cbab08c1 | ||
|
|
a75df66151 | ||
|
|
43e9c13c5e | ||
|
|
5ad06f121b | ||
|
|
0eaaf7aacb | ||
|
|
dd44fdd1f2 | ||
|
|
669855de70 | ||
|
|
193ae2b7d6 | ||
|
|
af4b23e0e0 | ||
|
|
c35991315d | ||
|
|
9aa852370c | ||
|
|
8f18497551 | ||
|
|
4c59951e8c | ||
|
|
eb2a80d216 | ||
|
|
41d0175a6d | ||
|
|
2f6aa0f45b | ||
|
|
17c685bc4c |
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"ansible.python.interpreterPath": "/opt/homebrew/bin/python3"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -125,4 +125,4 @@ enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
https://www.contributor-covenant.org/translations.
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (b *BaseApi) PageAlert(c *gin.Context) {
|
||||
var req dto.AlertSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
total, alerts, err := alertService.PageAlert(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Total: total,
|
||||
Items: alerts,
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetAlerts(c *gin.Context) {
|
||||
alerts, err := alertService.GetAlerts()
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, alerts)
|
||||
}
|
||||
|
||||
func (b *BaseApi) CreateAlert(c *gin.Context) {
|
||||
var req dto.AlertCreate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := alertService.CreateAlert(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteAlert(c *gin.Context) {
|
||||
var req dto.DeleteRequest
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := alertService.DeleteAlert(req.ID)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UpdateAlert(c *gin.Context) {
|
||||
var req dto.AlertUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := alertService.UpdateAlert(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetAlert(c *gin.Context) {
|
||||
id, err := helper.GetParamID(c)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, errors.New("no such id in request param"))
|
||||
return
|
||||
}
|
||||
alert, err := alertService.GetAlert(id)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, alert)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UpdateAlertStatus(c *gin.Context) {
|
||||
var req dto.AlertUpdateStatus
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := alertService.UpdateStatus(req.ID, req.Status); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetDisks(c *gin.Context) {
|
||||
alerts, err := alertService.GetDisks()
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, alerts)
|
||||
}
|
||||
|
||||
func (b *BaseApi) PageAlertLogs(c *gin.Context) {
|
||||
var req dto.AlertLogSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
total, alertLogs, err := alertService.PageAlertLogs(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Total: total,
|
||||
Items: alertLogs,
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BaseApi) CleanAlertLogs(c *gin.Context) {
|
||||
if err := alertService.CleanAlertLogs(); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetClams(c *gin.Context) {
|
||||
clams, err := alertService.GetClams()
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, clams)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetCronJobs(c *gin.Context) {
|
||||
var req dto.CronJobReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
cronJobs, err := alertService.GetCronJobs(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, cronJobs)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetAlertConfig(c *gin.Context) {
|
||||
config, err := alertService.GetAlertConfig()
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, config)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UpdateAlertConfig(c *gin.Context) {
|
||||
var req dto.AlertConfigUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := alertService.UpdateAlertConfig(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteAlertConfig(c *gin.Context) {
|
||||
var req dto.DeleteRequest
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := alertService.DeleteAlertConfig(req.ID)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) TestAlertConfig(c *gin.Context) {
|
||||
var req dto.AlertConfigTest
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
flag, err := alertService.TestAlertConfig(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, flag)
|
||||
}
|
||||
@@ -327,3 +327,25 @@ func (b *BaseApi) UpdateAppConfig(c *gin.Context) {
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Get app install info
|
||||
// @Accept json
|
||||
// @Param appInstallId path integer true "App install id"
|
||||
// @Success 200 {object} dto.AppInstallInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /apps/installed/info/:appInstallId [get]
|
||||
func (b *BaseApi) GetAppInstallInfo(c *gin.Context) {
|
||||
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
info, err := appInstallService.GetAppInstallInfo(appInstallId)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, info)
|
||||
}
|
||||
|
||||
@@ -371,12 +371,12 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case "mysql", "mariadb":
|
||||
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||
if err := backupService.MysqlBackup(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||
if err := backupService.PostgresqlBackup(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
@@ -386,7 +386,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case "redis":
|
||||
case "redis", constant.AppRedisCluster:
|
||||
if err := backupService.RedisBackup(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
@@ -421,12 +421,12 @@ func (b *BaseApi) Recover(c *gin.Context) {
|
||||
}
|
||||
req.File = downloadPath
|
||||
switch req.Type {
|
||||
case "mysql", "mariadb":
|
||||
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||
if err := backupService.MysqlRecover(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||
if err := backupService.PostgresqlRecover(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
@@ -436,7 +436,7 @@ func (b *BaseApi) Recover(c *gin.Context) {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case "redis":
|
||||
case "redis", constant.AppRedisCluster:
|
||||
if err := backupService.RedisRecover(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
@@ -466,12 +466,12 @@ func (b *BaseApi) RecoverByUpload(c *gin.Context) {
|
||||
}
|
||||
|
||||
switch req.Type {
|
||||
case "mysql", "mariadb":
|
||||
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||
if err := backupService.MysqlRecoverByUpload(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
case constant.AppPostgresql:
|
||||
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||
if err := backupService.PostgresqlRecoverByUpload(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
|
||||
@@ -50,12 +50,7 @@ func (b *BaseApi) LoadContainerUsers(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
list, err := containerService.LoadUsers(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, list)
|
||||
helper.SuccessWithData(c, containerService.LoadUsers(req))
|
||||
}
|
||||
|
||||
// @Tags Container
|
||||
@@ -266,7 +261,7 @@ func (b *BaseApi) ContainerCreate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := containerService.ContainerCreate(req); err != nil {
|
||||
if err := containerService.ContainerCreate(req, true); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
@@ -53,6 +55,49 @@ func (b *BaseApi) LoadCronjobInfo(c *gin.Context) {
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
// @Summary Export cronjob list
|
||||
// @Accept json
|
||||
// @Param request body dto.OperateByIDs true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /cronjobs/export [post]
|
||||
func (b *BaseApi) ExportCronjob(c *gin.Context) {
|
||||
var req dto.OperateByIDs
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := cronjobService.Export(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
http.ServeContent(c.Writer, c.Request, "", time.Now(), strings.NewReader(content))
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
// @Summary Import cronjob list
|
||||
// @Accept json
|
||||
// @Param request body dto.CronjobImport true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /cronjobs/import [post]
|
||||
func (b *BaseApi) ImportCronjob(c *gin.Context) {
|
||||
var req dto.CronjobImport
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := cronjobService.Import(req.Cronjobs); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
// @Summary Load script options
|
||||
// @Success 200 {array} dto.ScriptOptions
|
||||
|
||||
@@ -11,13 +11,13 @@ import (
|
||||
// @Tags Database Redis
|
||||
// @Summary Load redis status info
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Param request body dto.LoadRedisStatus true "request"
|
||||
// @Success 200 {object} dto.RedisStatus
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /databases/redis/status [post]
|
||||
func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
var req dto.LoadRedisStatus
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -33,13 +33,13 @@ func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
||||
// @Tags Database Redis
|
||||
// @Summary Load redis conf
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Param request body dto.LoadRedisStatus true "request"
|
||||
// @Success 200 {object} dto.RedisConf
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /databases/redis/conf [post]
|
||||
func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
var req dto.LoadRedisStatus
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -55,13 +55,13 @@ func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
||||
// @Tags Database Redis
|
||||
// @Summary Load redis persistence conf
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Param request body dto.LoadRedisStatus true "request"
|
||||
// @Success 200 {object} dto.RedisPersistence
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /databases/redis/persistence/conf [post]
|
||||
func (b *BaseApi) LoadPersistenceConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
var req dto.LoadRedisStatus
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -70,4 +70,5 @@ var (
|
||||
websiteCAService = service.NewIWebsiteCAService()
|
||||
taskService = service.NewITaskService()
|
||||
groupService = service.NewIGroupService()
|
||||
alertService = service.NewIAlertService()
|
||||
)
|
||||
|
||||
@@ -296,7 +296,7 @@ func (b *BaseApi) SaveContent(c *gin.Context) {
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /files/upload [post]
|
||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
|
||||
// @x-panel-log {"bodyKeys":["path", "file"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"上传文件 [path]/[file]","formatEN":"Upload file [path]/[file]"}
|
||||
func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
form, err := c.MultipartForm()
|
||||
if err != nil {
|
||||
|
||||
@@ -98,20 +98,20 @@ func (b *BaseApi) CreateRepo(c *gin.Context) {
|
||||
// @Tags Container Image-repo
|
||||
// @Summary Delete image repo
|
||||
// @Accept json
|
||||
// @Param request body dto.ImageRepoDelete true "request"
|
||||
// @Param request body dto.OperateByID true "request"
|
||||
// @Produce json
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /containers/repo/del [post]
|
||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"ids","isList":true,"db":"image_repos","output_column":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
|
||||
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_column":"name","output_value":"name"}],"formatZH":"删除镜像仓库 [name]","formatEN":"delete image repo [name]"}
|
||||
func (b *BaseApi) DeleteRepo(c *gin.Context) {
|
||||
var req dto.ImageRepoDelete
|
||||
var req dto.OperateByID
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := imageRepoService.BatchDelete(req); err != nil {
|
||||
if err := imageRepoService.Delete(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -535,3 +535,23 @@ func (b *BaseApi) GetPHPContainerConfig(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Update runtime remark
|
||||
// @Accept json
|
||||
// @Param request body request.RuntimeRemarkUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /runtimes/remark [post]
|
||||
func (b *BaseApi) UpdateRuntimeRemark(c *gin.Context) {
|
||||
var req request.RuntimeRemark
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := runtimeService.UpdateRemark(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
@@ -89,8 +89,8 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
||||
var containerID string
|
||||
var initCmd []string
|
||||
switch source {
|
||||
case "redis":
|
||||
containerID, initCmd, err = loadRedisInitCmd(c)
|
||||
case "redis", "redis-cluster":
|
||||
containerID, initCmd, err = loadRedisInitCmd(c, source)
|
||||
case "ollama":
|
||||
containerID, initCmd, err = loadOllamaInitCmd(c)
|
||||
case "container":
|
||||
@@ -127,7 +127,7 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
||||
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||
}
|
||||
|
||||
func loadRedisInitCmd(c *gin.Context) (string, []string, error) {
|
||||
func loadRedisInitCmd(c *gin.Context, redisType string) (string, []string, error) {
|
||||
name := c.Query("name")
|
||||
from := c.Query("from")
|
||||
commands := []string{"exec", "-it"}
|
||||
@@ -136,7 +136,7 @@ func loadRedisInitCmd(c *gin.Context) (string, []string, error) {
|
||||
return "", nil, fmt.Errorf("no such database in db, err: %v", err)
|
||||
}
|
||||
if from == "local" {
|
||||
redisInfo, err := appInstallService.LoadConnInfo(dto.OperationWithNameAndType{Name: name, Type: "redis"})
|
||||
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)
|
||||
}
|
||||
|
||||
+311
-4
@@ -1,10 +1,17 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CreateOrUpdateAlert struct {
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertType string `json:"alertType"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
EntryID uint `json:"entryID"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertType string `json:"alertType"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
EntryID uint `json:"entryID"`
|
||||
}
|
||||
|
||||
type AlertBase struct {
|
||||
@@ -18,3 +25,303 @@ type PushAlert struct {
|
||||
EntryID uint `json:"entryID"`
|
||||
Param string `json:"param"`
|
||||
}
|
||||
|
||||
type AlertSearch struct {
|
||||
PageInfo
|
||||
OrderBy string `json:"orderBy" validate:"required,oneof=created_at"`
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
||||
type AlertDTO struct {
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Cycle uint `json:"cycle"`
|
||||
Count uint `json:"count"`
|
||||
Method string `json:"method"`
|
||||
Title string `json:"title"`
|
||||
Project string `json:"project"`
|
||||
Status string `json:"status"`
|
||||
SendCount uint `json:"sendCount"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type AlertCreate struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
Cycle uint `json:"cycle"`
|
||||
Count uint `json:"count"`
|
||||
Method string `json:"method" validate:"required"`
|
||||
Title string `json:"title"`
|
||||
Project string `json:"project"`
|
||||
Status string `json:"status"`
|
||||
SendCount uint `json:"sendCount"`
|
||||
}
|
||||
|
||||
type AlertUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Type string `json:"type"`
|
||||
Cycle uint `json:"cycle"`
|
||||
Count uint `json:"count"`
|
||||
Method string `json:"method"`
|
||||
Title string `json:"title"`
|
||||
Project string `json:"project"`
|
||||
Status string `json:"status"`
|
||||
SendCount uint `json:"sendCount"`
|
||||
}
|
||||
|
||||
type DeleteRequest struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type AlertUpdateStatus struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Status string `json:"status" validate:"required"`
|
||||
}
|
||||
|
||||
type DiskDTO struct {
|
||||
Path string `json:"path"`
|
||||
Type string `json:"type"`
|
||||
Device string `json:"device"`
|
||||
Total uint64 `json:"total"`
|
||||
Free uint64 `json:"free"`
|
||||
Used uint64 `json:"used"`
|
||||
UsedPercent float64 `json:"usedPercent"`
|
||||
|
||||
InodesTotal uint64 `json:"inodesTotal"`
|
||||
InodesUsed uint64 `json:"inodesUsed"`
|
||||
InodesFree uint64 `json:"inodesFree"`
|
||||
InodesUsedPercent float64 `json:"inodesUsedPercent"`
|
||||
}
|
||||
|
||||
type AlertLogSearch struct {
|
||||
PageInfo
|
||||
Count uint `json:"count"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type AlertLogDTO struct {
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Count uint `json:"count"`
|
||||
AlertId uint `json:"alertId"`
|
||||
AlertDetail AlertDetail `json:"alertDetail"`
|
||||
AlertRule AlertRule `json:"alertRule"`
|
||||
Status string `json:"status"`
|
||||
Method string `json:"method"`
|
||||
Message string `json:"message"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type AlertLogCreate struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
Count uint `json:"count" validate:"required"`
|
||||
AlertId uint `json:"alertId" validate:"required"`
|
||||
AlertDetail string `json:"alertDetail" validate:"required"`
|
||||
AlertRule string `json:"alertRule" validate:"required"`
|
||||
Status string `json:"status" validate:"required"`
|
||||
Method string `json:"method" validate:"required"`
|
||||
Message string `json:"message"`
|
||||
RecordId uint `json:"recordId"`
|
||||
LicenseId string `json:"licenseId" validate:"required"`
|
||||
}
|
||||
|
||||
type AlertLog struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type AlertDetail struct {
|
||||
LicenseId string `json:"licenseId"`
|
||||
Type string `json:"type"`
|
||||
SubType string `json:"subType"`
|
||||
Title string `json:"title"`
|
||||
Method string `json:"method"`
|
||||
LicenseCode string `json:"licenseCode"`
|
||||
DeviceId string `json:"deviceId"`
|
||||
Project string `json:"project"`
|
||||
Params []Param `json:"params"`
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
|
||||
type AlertRule struct {
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Cycle uint `json:"cycle"`
|
||||
Count uint `json:"count"`
|
||||
Method string `json:"method"`
|
||||
Title string `json:"title"`
|
||||
Project string `json:"project"`
|
||||
Status string `json:"status"`
|
||||
SendCount uint `json:"sendCount"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type Param struct {
|
||||
Index string `json:"index"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type ClamDTO struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type CronJobDTO struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type CronJobReq struct {
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type UpgradeInfo struct {
|
||||
TestVersion string `json:"testVersion"`
|
||||
NewVersion string `json:"newVersion"`
|
||||
LatestVersion string `json:"latestVersion"`
|
||||
ReleaseNote string `json:"releaseNote"`
|
||||
}
|
||||
|
||||
type AlertDiskInfo struct {
|
||||
Type string
|
||||
Mount string
|
||||
Device string
|
||||
}
|
||||
|
||||
type SyncResult struct {
|
||||
ID uint `json:"id"`
|
||||
LicenseID string `json:"licenseId"`
|
||||
SendStatus string `json:"sendStatus"`
|
||||
CreateTime string `json:"createTime"`
|
||||
UpdateTime string `json:"updateTime"`
|
||||
Remarks string `json:"remarks"`
|
||||
MsgCount int `json:"msgCount"`
|
||||
MsgCountMax int `json:"msgCountMax"`
|
||||
}
|
||||
|
||||
type QueryRequest struct {
|
||||
QueryIds []uint `json:"queryIds"`
|
||||
LicenseId string `json:"licenseId"`
|
||||
}
|
||||
|
||||
type AlertResponse struct {
|
||||
Result bool `json:"result"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type PushResult struct {
|
||||
RecordId uint `json:"recordId"`
|
||||
LicenseId string `json:"licenseId"`
|
||||
}
|
||||
|
||||
type UpdateOfflineAlertLog struct {
|
||||
ID uint `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
RecordId uint `json:"recordId"`
|
||||
LicenseId string `json:"licenseId"`
|
||||
}
|
||||
|
||||
type SyncOfflineAlertLogDTO struct {
|
||||
QueryRequest string `json:"queryRequest"`
|
||||
Ids []uint `json:"ids"`
|
||||
AlertLogs []model.AlertLog `json:"alertLogs"`
|
||||
LicenseId string `json:"licenseId"`
|
||||
}
|
||||
|
||||
type OfflineAlertResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type"`
|
||||
RemoteErr error `json:"remoteErr"`
|
||||
ResponseStruct AlertResponse `json:"responseStruct"`
|
||||
AlertLogs []model.AlertLog `json:"alertLogs"`
|
||||
Ids []uint `json:"ids"`
|
||||
LicenseId string `json:"licenseId"`
|
||||
}
|
||||
|
||||
type OfflineAlertLogDTO struct {
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Count uint `json:"count"`
|
||||
AlertId uint `json:"alertId"`
|
||||
AlertDetail string `json:"alertDetail"`
|
||||
AlertRule string `json:"alertRule"`
|
||||
Status string `json:"status"`
|
||||
Method string `json:"method"`
|
||||
Message string `json:"message"`
|
||||
RecordId uint `json:"recordId"`
|
||||
LicenseId string `json:"licenseId"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type OfflineQueryRequest struct {
|
||||
Ids []uint `json:"ids"`
|
||||
QueryIds []uint `json:"queryIds"`
|
||||
LicenseId string `json:"licenseId"`
|
||||
}
|
||||
|
||||
type AlertConfigUpdate struct {
|
||||
ID uint `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Status string `json:"status"`
|
||||
Config string `json:"config"`
|
||||
}
|
||||
|
||||
type AlertConfigTest struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Sender string `json:"sender"`
|
||||
Password string `json:"password"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Encryption string `json:"encryption"` // "ssl" / "tls" / "none"
|
||||
Recipient string `json:"recipient"`
|
||||
}
|
||||
|
||||
type AlertSendTimeRange struct {
|
||||
NoticeAlert struct {
|
||||
SendTimeRange string `json:"sendTimeRange"`
|
||||
Type []string `json:"type"`
|
||||
} `json:"noticeAlert"`
|
||||
ResourceAlert struct {
|
||||
SendTimeRange string `json:"sendTimeRange"`
|
||||
Type []string `json:"type"`
|
||||
} `json:"resourceAlert"`
|
||||
}
|
||||
|
||||
type AlertCommonConfig struct {
|
||||
IsOffline string `json:"isOffline"`
|
||||
AlertSendTimeRange AlertSendTimeRange `json:"alertSendTimeRange"`
|
||||
}
|
||||
|
||||
type AlertSmsConfig struct {
|
||||
Phone string `json:"phone"`
|
||||
AlertDailyNum uint `json:"alertDailyNum"`
|
||||
}
|
||||
|
||||
type AlertEmailConfig struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Sender string `json:"sender"`
|
||||
Password string `json:"password"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Encryption string `json:"encryption"` // "ssl" / "tls" / "none"
|
||||
Recipient string `json:"recipient"`
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ import (
|
||||
)
|
||||
|
||||
type AppDatabase struct {
|
||||
ServiceName string `json:"PANEL_DB_HOST"`
|
||||
DbName string `json:"PANEL_DB_NAME"`
|
||||
DbUser string `json:"PANEL_DB_USER"`
|
||||
Password string `json:"PANEL_DB_USER_PASSWORD"`
|
||||
ServiceName string `json:"PANEL_DB_HOST"`
|
||||
DbName string `json:"PANEL_DB_NAME"`
|
||||
DbUser string `json:"PANEL_DB_USER"`
|
||||
Password string `json:"PANEL_DB_USER_PASSWORD"`
|
||||
DatabaseName string `json:"DATABASE_NAME"`
|
||||
}
|
||||
|
||||
type AuthParam struct {
|
||||
@@ -126,6 +127,7 @@ type Locale struct {
|
||||
ZhHant string `json:"zh-hant" yaml:"zh-hant"`
|
||||
Zh string `json:"zh"`
|
||||
Ko string `json:"ko"`
|
||||
Tr string `json:"tr"`
|
||||
}
|
||||
|
||||
type AppForm struct {
|
||||
|
||||
@@ -54,7 +54,7 @@ type BackupOption struct {
|
||||
}
|
||||
|
||||
type CommonBackup struct {
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
@@ -65,7 +65,7 @@ type CommonBackup struct {
|
||||
}
|
||||
type CommonRecover struct {
|
||||
DownloadAccountID uint `json:"downloadAccountID" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
File string `json:"file"`
|
||||
|
||||
@@ -34,6 +34,7 @@ type ClamInfo struct {
|
||||
Spec string `json:"spec"`
|
||||
Description string `json:"description"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
}
|
||||
|
||||
type ClamLogSearch struct {
|
||||
@@ -74,6 +75,7 @@ type ClamCreate struct {
|
||||
Description string `json:"description"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
}
|
||||
|
||||
type ClamUpdate struct {
|
||||
@@ -87,6 +89,7 @@ type ClamUpdate struct {
|
||||
Description string `json:"description"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
}
|
||||
|
||||
type ClamUpdateStatus struct {
|
||||
|
||||
@@ -28,6 +28,9 @@ type OperationWithName struct {
|
||||
type OperateByID struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
type OperateByIDs struct {
|
||||
IDs []uint `json:"ids"`
|
||||
}
|
||||
|
||||
type Operate struct {
|
||||
Operation string `json:"operation" validate:"required"`
|
||||
|
||||
@@ -39,6 +39,11 @@ type ContainerInfo struct {
|
||||
Websites []string `json:"websites"`
|
||||
}
|
||||
|
||||
type ContainerOptions struct {
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
type ContainerStatus struct {
|
||||
All uint `json:"all"`
|
||||
Created uint `json:"created"`
|
||||
@@ -164,6 +169,8 @@ type ContainerCommit struct {
|
||||
Comment string `json:"comment"`
|
||||
Author string `json:"author"`
|
||||
Pause bool `json:"pause"`
|
||||
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
||||
type ContainerPrune struct {
|
||||
|
||||
+84
-23
@@ -29,25 +29,33 @@ type CronjobOperate struct {
|
||||
ContainerName string `json:"containerName"`
|
||||
User string `json:"user"`
|
||||
|
||||
ScriptID uint `json:"scriptID"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBType string `json:"dbType"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
IsDir bool `json:"isDir"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
ScriptID uint `json:"scriptID"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBType string `json:"dbType"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
IsDir bool `json:"isDir"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
SnapshotRule SnapshotRule `json:"snapshotRule"`
|
||||
|
||||
SourceAccountIDs string `json:"sourceAccountIDs"`
|
||||
DownloadAccountID uint `json:"downloadAccountID"`
|
||||
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
|
||||
RetryTimes int `json:"retryTimes" validate:"number,min=0"`
|
||||
Timeout uint `json:"timeout" validate:"number,min=1"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
Secret string `json:"secret"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
}
|
||||
|
||||
type SnapshotRule struct {
|
||||
WithImage bool `json:"withImage"`
|
||||
IgnoreAppIDs []uint `json:"ignoreAppIDs"`
|
||||
}
|
||||
|
||||
type CronjobUpdateStatus struct {
|
||||
@@ -87,18 +95,20 @@ type CronjobInfo struct {
|
||||
ContainerName string `json:"containerName"`
|
||||
User string `json:"user"`
|
||||
|
||||
ScriptID uint `json:"scriptID"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBType string `json:"dbType"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
IsDir bool `json:"isDir"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
RetainCopies int `json:"retainCopies"`
|
||||
RetryTimes int `json:"retryTimes"`
|
||||
Timeout uint `json:"timeout"`
|
||||
ScriptID uint `json:"scriptID"`
|
||||
AppID string `json:"appID"`
|
||||
Website string `json:"website"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
DBType string `json:"dbType"`
|
||||
DBName string `json:"dbName"`
|
||||
URL string `json:"url"`
|
||||
IsDir bool `json:"isDir"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
RetainCopies int `json:"retainCopies"`
|
||||
RetryTimes int `json:"retryTimes"`
|
||||
Timeout uint `json:"timeout"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
SnapshotRule SnapshotRule `json:"snapshotRule"`
|
||||
|
||||
SourceAccounts []string `json:"sourceAccounts"`
|
||||
DownloadAccount string `json:"downloadAccount"`
|
||||
@@ -113,6 +123,57 @@ type CronjobInfo struct {
|
||||
AlertCount uint `json:"alertCount"`
|
||||
}
|
||||
|
||||
type CronjobImport struct {
|
||||
Cronjobs []CronjobTrans `json:"cronjobs"`
|
||||
}
|
||||
type CronjobTrans struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SpecCustom bool `json:"specCustom"`
|
||||
Spec string `json:"spec"`
|
||||
|
||||
Executor string `json:"executor"`
|
||||
ScriptMode string `json:"scriptMode"`
|
||||
Script string `json:"script"`
|
||||
Command string `json:"command"`
|
||||
ContainerName string `json:"containerName"`
|
||||
User string `json:"user"`
|
||||
URL string `json:"url"`
|
||||
|
||||
ScriptName string `json:"scriptName"`
|
||||
Apps []TransHelper `json:"apps"`
|
||||
Websites []string `json:"websites"`
|
||||
DBType string `json:"dbType"`
|
||||
DBNames []TransHelper `json:"dbName"`
|
||||
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
|
||||
IsDir bool `json:"isDir"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
|
||||
RetainCopies uint64 `json:"retainCopies"`
|
||||
RetryTimes uint `json:"retryTimes"`
|
||||
Timeout uint `json:"timeout"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
SnapshotRule SnapshotTransHelper `json:"snapshotRule"`
|
||||
Secret string `json:"secret"`
|
||||
|
||||
SourceAccounts []string `json:"sourceAccounts"`
|
||||
DownloadAccount string `json:"downloadAccount"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
}
|
||||
type TransHelper struct {
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
}
|
||||
type SnapshotTransHelper struct {
|
||||
WithImage bool `json:"withImage"`
|
||||
IgnoreApps []TransHelper `json:"ignoreApps"`
|
||||
}
|
||||
|
||||
type ScriptOptions struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -74,8 +74,11 @@ type DashboardCurrent struct {
|
||||
CPUTotal int `json:"cpuTotal"`
|
||||
|
||||
MemoryTotal uint64 `json:"memoryTotal"`
|
||||
MemoryAvailable uint64 `json:"memoryAvailable"`
|
||||
MemoryUsed uint64 `json:"memoryUsed"`
|
||||
MemoryFree uint64 `json:"memoryFree"`
|
||||
MemoryShard uint64 `json:"memoryShard"`
|
||||
MemoryCache uint64 `json:"memoryCache"`
|
||||
MemoryAvailable uint64 `json:"memoryAvailable"`
|
||||
MemoryUsedPercent float64 `json:"memoryUsedPercent"`
|
||||
|
||||
SwapMemoryTotal uint64 `json:"swapMemoryTotal"`
|
||||
|
||||
@@ -4,14 +4,14 @@ import "time"
|
||||
|
||||
// common
|
||||
type DBConfUpdateByFile struct {
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql redis"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql redis mysql-cluster postgresql-cluster"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
type ChangeDBInfo struct {
|
||||
ID uint `json:"id"`
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb postgresql mysql-cluster postgresql-cluster"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Value string `json:"value" validate:"required"`
|
||||
}
|
||||
@@ -74,19 +74,19 @@ type BindUser struct {
|
||||
|
||||
type MysqlLoadDB struct {
|
||||
From string `json:"from" validate:"required,oneof=local remote"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
}
|
||||
|
||||
type MysqlDBDeleteCheck struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
}
|
||||
|
||||
type MysqlDBDelete struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
@@ -153,7 +153,7 @@ type MysqlVariables struct {
|
||||
}
|
||||
|
||||
type MysqlVariablesUpdate struct {
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb"`
|
||||
Type string `json:"type" validate:"required,oneof=mysql mariadb mysql-cluster"`
|
||||
Database string `json:"database" validate:"required"`
|
||||
Variables []MysqlVariablesUpdateHelper `json:"variables"`
|
||||
}
|
||||
@@ -174,6 +174,7 @@ type RedisConfUpdate struct {
|
||||
Timeout string `json:"timeout"`
|
||||
Maxclients string `json:"maxclients"`
|
||||
Maxmemory string `json:"maxmemory"`
|
||||
DBType string `json:"dbType" validate:"required,oneof=redis redis-cluster"`
|
||||
}
|
||||
type RedisConfPersistenceUpdate struct {
|
||||
Database string `json:"database" validate:"required"`
|
||||
@@ -181,6 +182,7 @@ type RedisConfPersistenceUpdate struct {
|
||||
Appendonly string `json:"appendonly"`
|
||||
Appendfsync string `json:"appendfsync"`
|
||||
Save string `json:"save"`
|
||||
DBType string `json:"dbType" validate:"required,oneof=redis redis-cluster"`
|
||||
}
|
||||
|
||||
type RedisConf struct {
|
||||
@@ -319,3 +321,8 @@ type DatabaseDelete struct {
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
}
|
||||
|
||||
type LoadRedisStatus struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ type ImageRepoCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
Protocol string `json:"protocol"`
|
||||
Username string `json:"username" validate:"max=256"`
|
||||
Password string `json:"password" validate:"max=256"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Auth bool `json:"auth"`
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ type ImageRepoUpdate struct {
|
||||
ID uint `json:"id"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
Protocol string `json:"protocol"`
|
||||
Username string `json:"username" validate:"max=256"`
|
||||
Password string `json:"password" validate:"max=256"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Auth bool `json:"auth"`
|
||||
}
|
||||
|
||||
|
||||
@@ -92,11 +92,12 @@ type FileWget struct {
|
||||
}
|
||||
|
||||
type FileMove struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
OldPaths []string `json:"oldPaths" validate:"required"`
|
||||
NewPath string `json:"newPath" validate:"required"`
|
||||
Name string `json:"name"`
|
||||
Cover bool `json:"cover"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
OldPaths []string `json:"oldPaths" validate:"required"`
|
||||
NewPath string `json:"newPath" validate:"required"`
|
||||
Name string `json:"name"`
|
||||
Cover bool `json:"cover"`
|
||||
CoverPaths []string `json:"coverPaths"`
|
||||
}
|
||||
|
||||
type FileDownload struct {
|
||||
|
||||
@@ -12,15 +12,17 @@ type RuntimeSearch struct {
|
||||
}
|
||||
|
||||
type RuntimeCreate struct {
|
||||
AppDetailID uint `json:"appDetailId"`
|
||||
Name string `json:"name"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Resource string `json:"resource"`
|
||||
Image string `json:"image"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Source string `json:"source"`
|
||||
CodeDir string `json:"codeDir"`
|
||||
AppDetailID uint `json:"appDetailId"`
|
||||
Name string `json:"name"`
|
||||
Resource string `json:"resource"`
|
||||
Image string `json:"image"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Source string `json:"source"`
|
||||
CodeDir string `json:"codeDir"`
|
||||
Remark string `json:"remark"`
|
||||
|
||||
Params map[string]interface{} `json:"params"`
|
||||
NodeConfig
|
||||
}
|
||||
|
||||
@@ -53,14 +55,16 @@ type RuntimeDelete struct {
|
||||
}
|
||||
|
||||
type RuntimeUpdate struct {
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Image string `json:"image"`
|
||||
Version string `json:"version"`
|
||||
Rebuild bool `json:"rebuild"`
|
||||
Source string `json:"source"`
|
||||
CodeDir string `json:"codeDir"`
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
Image string `json:"image"`
|
||||
Version string `json:"version"`
|
||||
Rebuild bool `json:"rebuild"`
|
||||
Source string `json:"source"`
|
||||
CodeDir string `json:"codeDir"`
|
||||
Remark string `json:"remark"`
|
||||
|
||||
Params map[string]interface{} `json:"params"`
|
||||
NodeConfig
|
||||
}
|
||||
|
||||
@@ -131,3 +135,8 @@ type PHPContainerConfig struct {
|
||||
Environments []Environment `json:"environments"`
|
||||
Volumes []Volume `json:"volumes"`
|
||||
}
|
||||
|
||||
type RuntimeRemark struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ type WebsiteCreate struct {
|
||||
TaskID string `json:"taskID"`
|
||||
ParentWebsiteID uint `json:"parentWebsiteID"`
|
||||
|
||||
SiteDir string `json:"siteDir"`
|
||||
|
||||
RuntimeConfig
|
||||
FtpConfig
|
||||
DataBaseConfig
|
||||
|
||||
@@ -129,6 +129,19 @@ type AppInstallDTO struct {
|
||||
Container string `json:"container"`
|
||||
}
|
||||
|
||||
type AppInstallInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
HttpPort int `json:"HttpPort"`
|
||||
Container string `json:"container"`
|
||||
ComposePath string `json:"composePath"`
|
||||
|
||||
Env map[string]interface{} `json:"env"`
|
||||
}
|
||||
|
||||
type DatabaseConn struct {
|
||||
Status string `json:"status"`
|
||||
Username string `json:"username"`
|
||||
@@ -158,6 +171,7 @@ type AppParam struct {
|
||||
ShowValue string `json:"showValue"`
|
||||
Required bool `json:"required"`
|
||||
Multiple bool `json:"multiple"`
|
||||
Label dto.Locale `json:"label"`
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
)
|
||||
|
||||
type FileInfo struct {
|
||||
@@ -37,11 +38,12 @@ type FileWgetRes struct {
|
||||
}
|
||||
|
||||
type FileLineContent struct {
|
||||
Content string `json:"content"`
|
||||
End bool `json:"end"`
|
||||
Path string `json:"path"`
|
||||
Total int `json:"total"`
|
||||
Lines []string `json:"lines"`
|
||||
Content string `json:"content"`
|
||||
End bool `json:"end"`
|
||||
Path string `json:"path"`
|
||||
Total int `json:"total"`
|
||||
TaskStatus string `json:"taskStatus"`
|
||||
Lines []string `json:"lines"`
|
||||
}
|
||||
|
||||
type FileExist struct {
|
||||
@@ -53,6 +55,7 @@ type ExistFileInfo struct {
|
||||
Path string `json:"path"`
|
||||
Size int64 `json:"size"`
|
||||
ModTime time.Time `json:"modTime"`
|
||||
IsDir bool `json:"isDir"`
|
||||
}
|
||||
|
||||
type UserInfo struct {
|
||||
|
||||
@@ -30,6 +30,7 @@ type RuntimeDTO struct {
|
||||
Volumes []request.Volume `json:"volumes"`
|
||||
ContainerStatus string `json:"containerStatus"`
|
||||
Container string `json:"container"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type PackageScripts struct {
|
||||
@@ -53,6 +54,7 @@ func NewRuntimeDTO(runtime model.Runtime) RuntimeDTO {
|
||||
Port: runtime.Port,
|
||||
Path: runtime.GetPath(),
|
||||
Container: runtime.ContainerName,
|
||||
Remark: runtime.Remark,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ type SettingInfo struct {
|
||||
AppStoreSyncStatus string `json:"appStoreSyncStatus"`
|
||||
|
||||
FileRecycleBin string `json:"fileRecycleBin"`
|
||||
|
||||
SnapshotIgnore string `json:"snapshotIgnore"`
|
||||
}
|
||||
|
||||
type SettingUpdate struct {
|
||||
|
||||
@@ -18,16 +18,20 @@ type SnapshotCreate struct {
|
||||
Description string `json:"description" validate:"max=256"`
|
||||
Secret string `json:"secret"`
|
||||
InterruptStep string `json:"interruptStep"`
|
||||
Timeout uint `json:"timeout"`
|
||||
|
||||
AppData []DataTree `json:"appData"`
|
||||
BackupData []DataTree `json:"backupData"`
|
||||
PanelData []DataTree `json:"panelData"`
|
||||
|
||||
WithDockerConf bool `json:"withDockerConf"`
|
||||
WithMonitorData bool `json:"withMonitorData"`
|
||||
WithLoginLog bool `json:"withLoginLog"`
|
||||
WithOperationLog bool `json:"withOperationLog"`
|
||||
WithSystemLog bool `json:"withSystemLog"`
|
||||
WithTaskLog bool `json:"withTaskLog"`
|
||||
|
||||
IgnoreFiles []string `json:"ignoreFiles"`
|
||||
}
|
||||
|
||||
type SnapshotData struct {
|
||||
@@ -35,11 +39,13 @@ type SnapshotData struct {
|
||||
BackupData []DataTree `json:"backupData"`
|
||||
PanelData []DataTree `json:"panelData"`
|
||||
|
||||
WithMonitorData bool `json:"withMonitorData"`
|
||||
WithLoginLog bool `json:"withLoginLog"`
|
||||
WithOperationLog bool `json:"withOperationLog"`
|
||||
WithSystemLog bool `json:"withSystemLog"`
|
||||
WithTaskLog bool `json:"withTaskLog"`
|
||||
WithDockerConf bool `json:"withDockerConf"`
|
||||
WithMonitorData bool `json:"withMonitorData"`
|
||||
WithLoginLog bool `json:"withLoginLog"`
|
||||
WithOperationLog bool `json:"withOperationLog"`
|
||||
WithSystemLog bool `json:"withSystemLog"`
|
||||
WithTaskLog bool `json:"withTaskLog"`
|
||||
IgnoreFiles []string `json:"ignoreFiles"`
|
||||
}
|
||||
type DataTree struct {
|
||||
ID string `json:"id"`
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package model
|
||||
|
||||
type Alert struct {
|
||||
BaseModel
|
||||
|
||||
Title string `gorm:"type:varchar(256);not null" json:"title"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Cycle uint `gorm:"type:integer;not null" json:"cycle"`
|
||||
Count uint `gorm:"type:integer;not null" json:"count"`
|
||||
Project string `gorm:"type:varchar(64)" json:"project"`
|
||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
||||
Method string `gorm:"type:varchar(64);not null" json:"method"`
|
||||
SendCount uint `gorm:"type:integer" json:"sendCount"`
|
||||
}
|
||||
|
||||
type AlertTask struct {
|
||||
BaseModel
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Quota string `gorm:"type:varchar(64)" json:"quota"`
|
||||
QuotaType string `gorm:"type:varchar(64)" json:"quotaType"`
|
||||
Method string `gorm:"type:varchar(64);not null;default:'sms" json:"method"`
|
||||
}
|
||||
|
||||
type AlertLog struct {
|
||||
BaseModel
|
||||
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
||||
AlertId uint `gorm:"type:integer;not null" json:"alertId"`
|
||||
AlertDetail string `gorm:"type:varchar(256);not null" json:"alertDetail"`
|
||||
AlertRule string `gorm:"type:varchar(256);not null" json:"alertRule"`
|
||||
Count uint `gorm:"type:integer;not null" json:"count"`
|
||||
Message string `gorm:"type:varchar(256);" json:"message"`
|
||||
RecordId uint `gorm:"type:integer;" json:"recordId"`
|
||||
LicenseId string `gorm:"type:varchar(256);not null;" json:"licenseId" `
|
||||
Method string `gorm:"type:varchar(64);not null;default:'sms" json:"method"`
|
||||
}
|
||||
|
||||
type AlertConfig struct {
|
||||
BaseModel
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Title string `gorm:"type:varchar(64);not null" json:"title"`
|
||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
||||
Config string `gorm:"type:varchar(256);not null" json:"config"`
|
||||
}
|
||||
@@ -29,12 +29,14 @@ type Cronjob struct {
|
||||
URL string `json:"url"`
|
||||
IsDir bool `json:"isDir"`
|
||||
SourceDir string `json:"sourceDir"`
|
||||
SnapshotRule string `json:"snapshotRule"`
|
||||
ExclusionRules string `json:"exclusionRules"`
|
||||
|
||||
SourceAccountIDs string `json:"sourceAccountIDs"`
|
||||
DownloadAccountID uint `json:"downloadAccountID"`
|
||||
RetryTimes uint `json:"retryTimes"`
|
||||
Timeout uint `json:"timeout"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
RetainCopies uint64 `json:"retainCopies"`
|
||||
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -23,6 +23,7 @@ type Runtime struct {
|
||||
Message string `json:"message"`
|
||||
CodeDir string `json:"codeDir"`
|
||||
ContainerName string `json:"containerName"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (r *Runtime) GetComposePath() string {
|
||||
|
||||
@@ -10,19 +10,23 @@ type Snapshot struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Version string `json:"version"`
|
||||
Timeout uint `json:"timeout"`
|
||||
|
||||
TaskID string `json:"taskID"`
|
||||
TaskRecoverID string `json:"taskRecoverID"`
|
||||
TaskRollbackID string `json:"taskRollbackID"`
|
||||
|
||||
AppData string `json:"appData"`
|
||||
PanelData string `json:"panelData"`
|
||||
BackupData string `json:"backupData"`
|
||||
AppData string `json:"appData"`
|
||||
PanelData string `json:"panelData"`
|
||||
BackupData string `json:"backupData"`
|
||||
|
||||
WithDockerConf bool `json:"withDockerConf"`
|
||||
WithMonitorData bool `json:"withMonitorData"`
|
||||
WithLoginLog bool `json:"withLoginLog"`
|
||||
WithOperationLog bool `json:"withOperationLog"`
|
||||
WithSystemLog bool `json:"withSystemLog"`
|
||||
WithTaskLog bool `json:"withTaskLog"`
|
||||
IgnoreFiles string `json:"ignoreFiles"`
|
||||
|
||||
InterruptStep string `json:"interruptStep"`
|
||||
RecoverStatus string `json:"recoverStatus"`
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"google.golang.org/genproto/googleapis/type/date"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AlertRepo struct{}
|
||||
|
||||
type IAlertRepo interface {
|
||||
WithByType(alertType string) DBOption
|
||||
WithByStatusIn(status []string) DBOption
|
||||
WithByProject(project string) DBOption
|
||||
WithByCount(count uint) DBOption
|
||||
WithByAlertId(alertId uint) DBOption
|
||||
WithByCreateAt(date *date.Date) DBOption
|
||||
WithByLicenseId(licenseId string) DBOption
|
||||
WithByRecordId(recordId uint) DBOption
|
||||
WithByMethod(method string) DBOption
|
||||
|
||||
Create(alert *model.Alert) error
|
||||
Get(opts ...DBOption) (model.Alert, error)
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.Alert, error)
|
||||
List(opts ...DBOption) ([]model.Alert, error)
|
||||
Delete(opts ...DBOption) error
|
||||
Save(alert *model.Alert) error
|
||||
Update(maps map[string]interface{}, opts ...DBOption) error
|
||||
|
||||
GetLog(opts ...DBOption) (model.AlertLog, error)
|
||||
CreateLog(alertLog *model.AlertLog) error
|
||||
PageLog(limit, offset int, opts ...DBOption) (int64, []model.AlertLog, error)
|
||||
ListLog(opts ...DBOption) ([]model.AlertLog, error)
|
||||
UpdateLog(id uint, maps map[string]interface{}) error
|
||||
BatchUpdateLogBy(maps map[string]interface{}, opts ...DBOption) error
|
||||
DeleteLog(opts ...DBOption) error
|
||||
CleanAlertLogs() error
|
||||
|
||||
CreateAlertTask(alertTaskBase *model.AlertTask) error
|
||||
DeleteAlertTask(opts ...DBOption) error
|
||||
GetAlertTask(opts ...DBOption) (model.AlertTask, error)
|
||||
LoadTaskCount(alertType string, project string, method string) (uint, uint, error)
|
||||
GetTaskLog(alertType string, alertId uint) (time.Time, error)
|
||||
GetLicensePushCount(method string) (uint, error)
|
||||
|
||||
GetConfig(opts ...DBOption) (model.AlertConfig, error)
|
||||
AlertConfigList(opts ...DBOption) ([]model.AlertConfig, error)
|
||||
UpdateAlertConfig(maps map[string]interface{}, opts ...DBOption) error
|
||||
CreateAlertConfig(config *model.AlertConfig) error
|
||||
DeleteAlertConfig(opts ...DBOption) error
|
||||
|
||||
SyncAll(data []model.AlertConfig) error
|
||||
}
|
||||
|
||||
func NewIAlertRepo() IAlertRepo {
|
||||
return &AlertRepo{}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByType(alertType string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("`type` = ?", alertType)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByStatusIn(status []string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("status in (?)", status)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByCount(count uint) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("count = ?", count)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByProject(project string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("project = ?", project)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByAlertId(alertId uint) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("alert_id = ?", alertId)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByLicenseId(licenseId string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("license_id = ?", licenseId)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByRecordId(recordId uint) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("record_id = ?", recordId)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByMethod(method string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("method = ?", method)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) WithByCreateAt(createAt *date.Date) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("DATE(created_at) = DATE(?)", createAt)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AlertRepo) Create(alert *model.Alert) error {
|
||||
return global.AlertDB.Model(&model.Alert{}).Create(alert).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) Save(alert *model.Alert) error {
|
||||
return global.AlertDB.Save(alert).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) Get(opts ...DBOption) (model.Alert, error) {
|
||||
var alert model.Alert
|
||||
db, _ := getAlertDB(opts...)
|
||||
err := db.First(&alert).Error
|
||||
return alert, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) Page(page, size int, opts ...DBOption) (int64, []model.Alert, error) {
|
||||
var alerts []model.Alert
|
||||
alertDb, _ := getAlertDB(opts...)
|
||||
db := alertDb.Model(&model.Alert{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&alerts).Error
|
||||
return count, alerts, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) List(opts ...DBOption) ([]model.Alert, error) {
|
||||
var alert []model.Alert
|
||||
db, _ := getAlertDB(opts...)
|
||||
err := db.Find(&alert).Error
|
||||
return alert, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) Update(maps map[string]interface{}, opts ...DBOption) error {
|
||||
db, _ := getAlertDB(opts...)
|
||||
return db.Model(&model.Alert{}).Updates(maps).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) Delete(opts ...DBOption) error {
|
||||
db, _ := getAlertDB(opts...)
|
||||
return db.Delete(&model.Alert{}).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) GetLog(opts ...DBOption) (model.AlertLog, error) {
|
||||
var alertLog model.AlertLog
|
||||
db, _ := getAlertDB(opts...)
|
||||
err := db.First(&alertLog).Error
|
||||
return alertLog, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) CreateLog(log *model.AlertLog) error {
|
||||
return global.AlertDB.Model(&model.AlertLog{}).Create(&log).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) UpdateLog(id uint, maps map[string]interface{}) error {
|
||||
return global.AlertDB.Model(&model.AlertLog{}).Where("id = ?", id).Updates(maps).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) BatchUpdateLogBy(maps map[string]interface{}, opts ...DBOption) error {
|
||||
db, _ := getAlertDB(opts...)
|
||||
if len(opts) == 0 {
|
||||
db = db.Where("1=1")
|
||||
}
|
||||
return db.Model(&model.AlertLog{}).Updates(&maps).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) PageLog(page, size int, opts ...DBOption) (int64, []model.AlertLog, error) {
|
||||
var alerts []model.AlertLog
|
||||
db := global.AlertDB.Model(&model.AlertLog{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
count := int64(0)
|
||||
db = db.Order("created_at desc").Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&alerts).Error
|
||||
return count, alerts, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) ListLog(opts ...DBOption) ([]model.AlertLog, error) {
|
||||
var alertLog []model.AlertLog
|
||||
db, _ := getAlertDB(opts...)
|
||||
err := db.Find(&alertLog).Error
|
||||
return alertLog, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) DeleteLog(opts ...DBOption) error {
|
||||
db, _ := getAlertDB(opts...)
|
||||
return db.Delete(&model.AlertLog{}).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) CleanAlertLogs() error {
|
||||
return global.AlertDB.Where("1 = 1").Delete(&model.AlertLog{}).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) CreateAlertTask(alertTaskBase *model.AlertTask) error {
|
||||
return global.AlertDB.Model(&model.AlertTask{}).Create(&alertTaskBase).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) DeleteAlertTask(opts ...DBOption) error {
|
||||
db, _ := getAlertDB(opts...)
|
||||
return db.Delete(&model.AlertTask{}).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) GetAlertTask(opts ...DBOption) (model.AlertTask, error) {
|
||||
var data model.AlertTask
|
||||
db, _ := getAlertDB(opts...)
|
||||
err := db.First(&data).Error
|
||||
return data, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) LoadTaskCount(alertType string, project string, method string) (uint, uint, error) {
|
||||
var (
|
||||
todayCount int64
|
||||
totalCount int64
|
||||
)
|
||||
_ = global.AlertDB.Model(&model.AlertTask{}).Where("type = ? AND quota_type = ? AND method = ?", alertType, project, method).Count(&totalCount).Error
|
||||
|
||||
now := time.Now()
|
||||
todayMidnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
tomorrowMidnight := todayMidnight.Add(24 * time.Hour)
|
||||
err := global.AlertDB.Model(&model.AlertTask{}).Where("type = ? AND quota_type = ? AND method = ? AND created_at > ? AND created_at < ?", alertType, project, method, todayMidnight, tomorrowMidnight).Count(&todayCount).Error
|
||||
return uint(todayCount), uint(totalCount), err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) GetTaskLog(alertType string, alertId uint) (time.Time, error) {
|
||||
var newDate time.Time
|
||||
status := []string{constant.AlertSuccess, constant.AlertPushSuccess, constant.AlertSyncError, constant.AlertPushing}
|
||||
now := time.Now()
|
||||
todayMidnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
tomorrowMidnight := todayMidnight.Add(24 * time.Hour)
|
||||
err := global.AlertDB.Model(&model.AlertLog{}).
|
||||
Where("type = ? AND alert_id = ? AND status in ? AND created_at > ? AND created_at < ?", alertType, alertId, status, todayMidnight, tomorrowMidnight).
|
||||
Order("created_at DESC").
|
||||
Limit(1).
|
||||
Pluck("created_at", &newDate).Error
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
if newDate.IsZero() {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
|
||||
return newDate, nil
|
||||
}
|
||||
|
||||
func getAlertDB(opts ...DBOption) (*gorm.DB, error) {
|
||||
var db *gorm.DB
|
||||
db = global.AlertDB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (a *AlertRepo) GetLicensePushCount(method string) (uint, error) {
|
||||
var (
|
||||
todayCount int64
|
||||
)
|
||||
now := time.Now()
|
||||
todayMidnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
tomorrowMidnight := todayMidnight.Add(24 * time.Hour)
|
||||
err := global.AlertDB.Model(&model.AlertTask{}).Where("created_at > ? AND created_at < ? AND method = ?", todayMidnight, tomorrowMidnight, method).Count(&todayCount).Error
|
||||
return uint(todayCount), err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) AlertConfigList(opts ...DBOption) ([]model.AlertConfig, error) {
|
||||
var config []model.AlertConfig
|
||||
db, _ := getAlertDB(opts...)
|
||||
err := db.Find(&config).Error
|
||||
return config, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) UpdateAlertConfig(maps map[string]interface{}, opts ...DBOption) error {
|
||||
db, _ := getAlertDB(opts...)
|
||||
return db.Model(&model.AlertConfig{}).Updates(maps).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) CreateAlertConfig(config *model.AlertConfig) error {
|
||||
return global.AlertDB.Model(&model.AlertConfig{}).Create(config).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) DeleteAlertConfig(opts ...DBOption) error {
|
||||
db, _ := getAlertDB(opts...)
|
||||
return db.Delete(&model.AlertConfig{}).Error
|
||||
}
|
||||
|
||||
func (a *AlertRepo) GetConfig(opts ...DBOption) (model.AlertConfig, error) {
|
||||
var alertConfig model.AlertConfig
|
||||
db, _ := getAlertDB(opts...)
|
||||
err := db.First(&alertConfig).Error
|
||||
return alertConfig, err
|
||||
}
|
||||
|
||||
func (a *AlertRepo) SyncAll(data []model.AlertConfig) error {
|
||||
tx := global.AlertDB.Begin()
|
||||
var oldConfigs []model.AlertConfig
|
||||
_ = tx.Find(&oldConfigs).Error
|
||||
oldConfigMap := make(map[string]uint)
|
||||
for _, item := range oldConfigs {
|
||||
oldConfigMap[item.Type] = item.ID
|
||||
}
|
||||
for _, item := range data {
|
||||
if val, ok := oldConfigMap[item.Type]; ok {
|
||||
item.ID = val
|
||||
delete(oldConfigMap, item.Type)
|
||||
} else {
|
||||
item.ID = 0
|
||||
}
|
||||
if err := tx.Model(model.AlertConfig{}).Where("id = ?", item.ID).Save(&item).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, val := range oldConfigMap {
|
||||
if err := tx.Where("id = ?", val).Delete(&model.AlertConfig{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
@@ -36,6 +36,7 @@ type IAppInstallRepo interface {
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.AppInstall, error)
|
||||
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
||||
LoadBaseInfo(key string, name string) (*RootInfo, error)
|
||||
LoadInstallAppByKeyAndName(key string, name string) (*model.AppInstall, error)
|
||||
GetFirstByCtx(ctx context.Context, opts ...DBOption) (model.AppInstall, error)
|
||||
}
|
||||
|
||||
@@ -206,17 +207,17 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
||||
return nil, err
|
||||
}
|
||||
switch app.Key {
|
||||
case "mysql", "mariadb":
|
||||
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
|
||||
if ok {
|
||||
info.Password = password
|
||||
}
|
||||
case "redis":
|
||||
case "redis", constant.AppRedisCluster:
|
||||
password, ok := envMap["PANEL_REDIS_ROOT_PASSWORD"].(string)
|
||||
if ok {
|
||||
info.Password = password
|
||||
}
|
||||
case "mongodb", constant.AppPostgresql:
|
||||
case "mongodb", constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||
user, ok := envMap["PANEL_DB_ROOT_USER"].(string)
|
||||
if ok {
|
||||
info.UserName = user
|
||||
@@ -246,3 +247,23 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
||||
info.Status = appInstall.Status
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallRepo) LoadInstallAppByKeyAndName(key string, name string) (*model.AppInstall, error) {
|
||||
var (
|
||||
app model.App
|
||||
appInstall model.AppInstall
|
||||
)
|
||||
if err := global.DB.Where("key = ?", key).First(&app).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(name) == 0 {
|
||||
if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := global.DB.Where("app_id = ? AND name = ?", app.ID, name).First(&appInstall).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &appInstall, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,507 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"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/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/copier"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/email"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AlertService struct{}
|
||||
|
||||
type IAlertService interface {
|
||||
PageAlert(req dto.AlertSearch) (int64, []dto.AlertDTO, error)
|
||||
GetAlerts() ([]dto.AlertDTO, error)
|
||||
CreateAlert(create dto.AlertCreate) error
|
||||
UpdateAlert(req dto.AlertUpdate) error
|
||||
DeleteAlert(id uint) error
|
||||
GetAlert(id uint) (dto.AlertDTO, error)
|
||||
UpdateStatus(id uint, status string) error
|
||||
ExternalUpdateAlert(req dto.AlertCreate) error
|
||||
|
||||
GetDisks() ([]dto.DiskDTO, error)
|
||||
PageAlertLogs(req dto.AlertLogSearch) (int64, []dto.AlertLogDTO, error)
|
||||
CleanAlertLogs() error
|
||||
GetClams() ([]dto.ClamDTO, error)
|
||||
GetCronJobs(req dto.CronJobReq) ([]dto.CronJobDTO, error)
|
||||
|
||||
GetAlertConfig() ([]model.AlertConfig, error)
|
||||
UpdateAlertConfig(req dto.AlertConfigUpdate) error
|
||||
DeleteAlertConfig(id uint) error
|
||||
TestAlertConfig(req dto.AlertConfigTest) (bool, error)
|
||||
}
|
||||
|
||||
func NewIAlertService() IAlertService {
|
||||
return &AlertService{}
|
||||
}
|
||||
|
||||
func (a AlertService) PageAlert(search dto.AlertSearch) (int64, []dto.AlertDTO, error) {
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
result []dto.AlertDTO
|
||||
)
|
||||
if search.Status != "" {
|
||||
opts = append(opts, repo.WithByStatus(search.Status))
|
||||
}
|
||||
if search.Type != "" {
|
||||
opts = append(opts, alertRepo.WithByType(search.Type))
|
||||
}
|
||||
opts = append(opts, repo.WithOrderBy("created_at desc"))
|
||||
|
||||
total, alerts, err := alertRepo.Page(search.Page, search.PageSize, opts...)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
for _, item := range alerts {
|
||||
|
||||
result = append(result, dto.AlertDTO{
|
||||
ID: item.ID,
|
||||
Type: item.Type,
|
||||
Cycle: item.Cycle,
|
||||
Count: item.Count,
|
||||
Method: item.Method,
|
||||
Title: item.Title,
|
||||
Project: item.Project,
|
||||
Status: item.Status,
|
||||
SendCount: item.SendCount,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
return total, result, err
|
||||
}
|
||||
|
||||
func (a AlertService) GetAlerts() ([]dto.AlertDTO, error) {
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
result []dto.AlertDTO
|
||||
)
|
||||
opts = append(opts, repo.WithByStatus(constant.AlertEnable))
|
||||
alerts, err := alertRepo.List(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range alerts {
|
||||
|
||||
result = append(result, dto.AlertDTO{
|
||||
ID: item.ID,
|
||||
Type: item.Type,
|
||||
Cycle: item.Cycle,
|
||||
Count: item.Count,
|
||||
Method: item.Method,
|
||||
Title: item.Title,
|
||||
Project: item.Project,
|
||||
Status: item.Status,
|
||||
SendCount: item.SendCount,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (a AlertService) CreateAlert(create dto.AlertCreate) error {
|
||||
var alertID uint
|
||||
var alertInfo model.Alert
|
||||
if create.Project != "" {
|
||||
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(create.Type), alertRepo.WithByProject(create.Project))
|
||||
alertID = alertInfo.ID
|
||||
} else {
|
||||
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(create.Type))
|
||||
alertID = alertInfo.ID
|
||||
}
|
||||
|
||||
if alertID != 0 {
|
||||
var upAlert dto.AlertUpdate
|
||||
if err := copier.Copy(&upAlert, &create); err != nil {
|
||||
return buserr.WithErr("ErrStructTransform", err)
|
||||
}
|
||||
upAlert.ID = alertID
|
||||
err := a.UpdateAlert(upAlert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
alertInfo.Status = constant.AlertEnable
|
||||
if err := copier.Copy(&alertInfo, &create); err != nil {
|
||||
return buserr.WithErr("ErrStructTransform", err)
|
||||
}
|
||||
|
||||
if err := alertRepo.Create(&alertInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
NewIAlertTaskHelper().InitTask(alertInfo.Type)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AlertService) UpdateAlert(req dto.AlertUpdate) error {
|
||||
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["id"] = req.ID
|
||||
upMap["type"] = req.Type
|
||||
upMap["cycle"] = req.Cycle
|
||||
upMap["count"] = req.Count
|
||||
upMap["method"] = req.Method
|
||||
upMap["title"] = req.Title
|
||||
upMap["project"] = req.Project
|
||||
upMap["status"] = req.Status
|
||||
upMap["send_count"] = req.SendCount
|
||||
|
||||
if err := alertRepo.Update(upMap, repo.WithByID(req.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
NewIAlertTaskHelper().InitTask(req.Type)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AlertService) DeleteAlert(id uint) error {
|
||||
return alertRepo.Delete(repo.WithByID(id))
|
||||
}
|
||||
|
||||
func (a AlertService) GetAlert(id uint) (dto.AlertDTO, error) {
|
||||
var res dto.AlertDTO
|
||||
alertInfo, err := alertRepo.Get(repo.WithByID(id))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
_ = copier.Copy(&res, &alertInfo)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a AlertService) UpdateStatus(id uint, status string) error {
|
||||
alertInfo, _ := alertRepo.Get(repo.WithByID(id))
|
||||
if alertInfo.ID == 0 {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
err := alertRepo.Update(map[string]interface{}{"status": status}, repo.WithByID(alertInfo.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
alerts, err := a.GetAlerts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(alerts) > 0 {
|
||||
NewIAlertTaskHelper().InitTask(alertInfo.Type)
|
||||
} else {
|
||||
NewIAlertTaskHelper().StopTask()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AlertService) GetDisks() ([]dto.DiskDTO, error) {
|
||||
var disks []dto.DiskDTO
|
||||
excludes := map[string]struct{}{
|
||||
"/mnt/cdrom": {}, "/boot": {}, "/boot/efi": {}, "/dev": {}, "/dev/shm": {},
|
||||
"/run/lock": {}, "/run": {}, "/run/shm": {}, "/run/user": {},
|
||||
}
|
||||
stdout, err := executeDiskCommand()
|
||||
if err != nil {
|
||||
return disks, nil
|
||||
}
|
||||
|
||||
lines := strings.Split(stdout, "\n")
|
||||
var mounts []dto.AlertDiskInfo
|
||||
|
||||
for _, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 7 {
|
||||
continue
|
||||
}
|
||||
mountPoint := strings.Join(fields[6:], " ")
|
||||
if shouldExclude(fields, mountPoint, excludes) {
|
||||
continue
|
||||
}
|
||||
mounts = append(mounts, dto.AlertDiskInfo{Type: fields[1], Device: fields[0], Mount: mountPoint})
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
mu sync.Mutex
|
||||
)
|
||||
wg.Add(len(mounts))
|
||||
for i := 0; i < len(mounts); i++ {
|
||||
go func(timeoutCh <-chan time.Time, mount dto.AlertDiskInfo) {
|
||||
defer wg.Done()
|
||||
|
||||
var itemData dto.DiskDTO
|
||||
itemData.Path = mount.Mount
|
||||
itemData.Type = mount.Type
|
||||
itemData.Device = mount.Device
|
||||
select {
|
||||
case <-timeoutCh:
|
||||
mu.Lock()
|
||||
disks = append(disks, itemData)
|
||||
mu.Unlock()
|
||||
global.LOG.Errorf("load disk info from %s failed, err: timeout", mount.Mount)
|
||||
default:
|
||||
state, err := disk.Usage(mount.Mount)
|
||||
if err != nil {
|
||||
mu.Lock()
|
||||
disks = append(disks, itemData)
|
||||
mu.Unlock()
|
||||
global.LOG.Errorf("load disk info from %s failed, err: %v", mount.Mount, err)
|
||||
return
|
||||
}
|
||||
itemData.Total = state.Total
|
||||
itemData.Free = state.Free
|
||||
itemData.Used = state.Used
|
||||
itemData.UsedPercent = state.UsedPercent
|
||||
itemData.InodesTotal = state.InodesTotal
|
||||
itemData.InodesUsed = state.InodesUsed
|
||||
itemData.InodesFree = state.InodesFree
|
||||
itemData.InodesUsedPercent = state.InodesUsedPercent
|
||||
mu.Lock()
|
||||
disks = append(disks, itemData)
|
||||
mu.Unlock()
|
||||
}
|
||||
}(time.After(5*time.Second), mounts[i])
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
sort.Slice(disks, func(i, j int) bool {
|
||||
return disks[i].Path < disks[j].Path
|
||||
})
|
||||
return disks, nil
|
||||
}
|
||||
|
||||
func executeDiskCommand() (string, error) {
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(2 * time.Second))
|
||||
stdout, err := cmdMgr.RunWithStdoutBashC("df -hT -P | grep '/' | grep -v tmpfs | grep -v 'snap/core' | grep -v udev")
|
||||
if err != nil {
|
||||
cmdMgr2 := cmd.NewCommandMgr(cmd.WithTimeout(1 * time.Second))
|
||||
stdout, err = cmdMgr2.RunWithStdoutBashC("df -lhT -P | grep '/' | grep -v tmpfs | grep -v 'snap/core' | grep -v udev")
|
||||
}
|
||||
return stdout, err
|
||||
}
|
||||
|
||||
func shouldExclude(fields []string, mountPoint string, excludes map[string]struct{}) bool {
|
||||
if strings.HasPrefix(mountPoint, "/snap") || len(strings.Split(mountPoint, "/")) > 10 {
|
||||
return true
|
||||
}
|
||||
if strings.TrimSpace(fields[1]) == "tmpfs" {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(fields[2], "K") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(mountPoint, "docker") {
|
||||
return true
|
||||
}
|
||||
_, excluded := excludes[mountPoint]
|
||||
return excluded
|
||||
}
|
||||
|
||||
func (a AlertService) PageAlertLogs(search dto.AlertLogSearch) (int64, []dto.AlertLogDTO, error) {
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
result []dto.AlertLogDTO
|
||||
)
|
||||
if search.Status != "" {
|
||||
opts = append(opts, repo.WithByStatus(search.Status))
|
||||
}
|
||||
if search.Count != 0 {
|
||||
opts = append(opts, alertRepo.WithByCount(search.Count))
|
||||
}
|
||||
opts = append(opts, repo.WithOrderBy("created_at desc"))
|
||||
|
||||
total, alerts, err := alertRepo.PageLog(search.Page, search.PageSize, opts...)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
for _, item := range alerts {
|
||||
alertLogDTO, err := a.parseAlertLog(item)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
result = append(result, alertLogDTO)
|
||||
}
|
||||
|
||||
return total, result, err
|
||||
}
|
||||
|
||||
func (a AlertService) parseAlertLog(item model.AlertLog) (dto.AlertLogDTO, error) {
|
||||
var alertDetail dto.AlertDetail
|
||||
var alertRule dto.AlertRule
|
||||
|
||||
if err := unmarshalAlertInfo(item.AlertDetail, &alertDetail); err != nil {
|
||||
return dto.AlertLogDTO{}, err
|
||||
}
|
||||
if err := unmarshalAlertInfo(item.AlertRule, &alertRule); err != nil {
|
||||
return dto.AlertLogDTO{}, err
|
||||
}
|
||||
return dto.AlertLogDTO{
|
||||
ID: item.ID,
|
||||
Count: item.Count,
|
||||
Type: item.Type,
|
||||
Status: item.Status,
|
||||
Method: item.Method,
|
||||
Message: item.Message,
|
||||
AlertId: item.AlertId,
|
||||
AlertDetail: alertDetail,
|
||||
AlertRule: alertRule,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func unmarshalAlertInfo(data string, v interface{}) error {
|
||||
if err := json.Unmarshal([]byte(data), v); err != nil {
|
||||
return fmt.Errorf("unmarshal alert info vars failed, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AlertService) CleanAlertLogs() error {
|
||||
return alertRepo.CleanAlertLogs()
|
||||
}
|
||||
|
||||
func (a AlertService) GetClams() ([]dto.ClamDTO, error) {
|
||||
var clams []dto.ClamDTO
|
||||
clamList, err := clamRepo.List()
|
||||
|
||||
for _, clam := range clamList {
|
||||
var clamDTO dto.ClamDTO
|
||||
clamDTO.ID = clam.ID
|
||||
clamDTO.Name = clam.Name
|
||||
clamDTO.Path = clam.Path
|
||||
clamDTO.Status = clam.Status
|
||||
clamDTO.UpdatedAt = clam.UpdatedAt
|
||||
clamDTO.CreatedAt = clam.CreatedAt
|
||||
clams = append(clams, clamDTO)
|
||||
}
|
||||
return clams, err
|
||||
}
|
||||
|
||||
func (a AlertService) GetCronJobs(req dto.CronJobReq) ([]dto.CronJobDTO, error) {
|
||||
var cronJobs []dto.CronJobDTO
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
)
|
||||
if req.Status != "" {
|
||||
opts = append(opts, repo.WithByStatus(req.Status))
|
||||
}
|
||||
if req.Type != "" {
|
||||
opts = append(opts, repo.WithByType(req.Type))
|
||||
}
|
||||
cronjobList, err := cronjobRepo.List(opts...)
|
||||
|
||||
for _, cronJob := range cronjobList {
|
||||
var cronJobDTO dto.CronJobDTO
|
||||
cronJobDTO.ID = cronJob.ID
|
||||
cronJobDTO.Name = cronJob.Name
|
||||
cronJobDTO.Status = cronJob.Status
|
||||
cronJobDTO.Type = cronJob.Type
|
||||
cronJobDTO.UpdatedAt = cronJob.UpdatedAt
|
||||
cronJobDTO.CreatedAt = cronJob.CreatedAt
|
||||
cronJobs = append(cronJobs, cronJobDTO)
|
||||
}
|
||||
return cronJobs, err
|
||||
}
|
||||
|
||||
func (a AlertService) GetAlertConfig() ([]model.AlertConfig, error) {
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
configs []model.AlertConfig
|
||||
)
|
||||
opts = append(opts, repo.WithByStatus(constant.AlertEnable))
|
||||
configs, err := alertRepo.AlertConfigList(opts...)
|
||||
return configs, err
|
||||
}
|
||||
|
||||
func (a AlertService) UpdateAlertConfig(req dto.AlertConfigUpdate) error {
|
||||
if req.ID != 0 {
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["id"] = req.ID
|
||||
upMap["type"] = req.Type
|
||||
upMap["title"] = req.Title
|
||||
upMap["status"] = req.Status
|
||||
upMap["config"] = req.Config
|
||||
if err := alertRepo.UpdateAlertConfig(upMap, repo.WithByID(req.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var alertConfig model.AlertConfig
|
||||
if err := copier.Copy(&alertConfig, &req); err != nil {
|
||||
return buserr.WithErr("ErrStructTransform", err)
|
||||
}
|
||||
if err := alertRepo.CreateAlertConfig(&alertConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AlertService) DeleteAlertConfig(id uint) error {
|
||||
return alertRepo.DeleteAlertConfig(repo.WithByID(id))
|
||||
}
|
||||
|
||||
func (a AlertService) TestAlertConfig(req dto.AlertConfigTest) (bool, error) {
|
||||
cfg := email.SMTPConfig{
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
Username: req.Sender,
|
||||
Password: req.Password,
|
||||
From: fmt.Sprintf("%s <%s>", req.DisplayName, req.Sender),
|
||||
Encryption: req.Encryption,
|
||||
Recipient: req.Recipient,
|
||||
}
|
||||
|
||||
msg := email.EmailMessage{
|
||||
Subject: i18n.GetMsgByKey("TestAlertTitle"),
|
||||
Body: i18n.GetMsgByKey("TestAlert"),
|
||||
IsHTML: false,
|
||||
}
|
||||
transport := xpack.LoadRequestTransport()
|
||||
if err := email.SendMail(cfg, msg, transport); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (a AlertService) ExternalUpdateAlert(updateAlert dto.AlertCreate) error {
|
||||
upMap := make(map[string]interface{})
|
||||
if updateAlert.SendCount == 0 {
|
||||
upMap["status"] = constant.AlertDisable
|
||||
} else {
|
||||
upMap["status"] = constant.AlertEnable
|
||||
upMap["send_count"] = updateAlert.SendCount
|
||||
}
|
||||
upMap["method"] = updateAlert.Method
|
||||
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(updateAlert.Type), alertRepo.WithByProject(updateAlert.Project))
|
||||
if alertInfo.ID > 0 {
|
||||
if err := alertRepo.Update(upMap, alertRepo.WithByProject(updateAlert.Project), alertRepo.WithByType(updateAlert.Type)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
updateAlert.Status = constant.AlertEnable
|
||||
err := a.CreateAlert(updateAlert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,894 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
versionUtil "github.com/1Panel-dev/1Panel/agent/utils/version"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
alertUtil "github.com/1Panel-dev/1Panel/agent/utils/alert"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/load"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v3/net"
|
||||
)
|
||||
|
||||
type AlertTaskHelper struct {
|
||||
DiskIO chan []disk.IOCountersStat
|
||||
NetIO chan []net.IOCountersStat
|
||||
}
|
||||
|
||||
type IAlertTaskHelper interface {
|
||||
StopTask()
|
||||
StartTask()
|
||||
ResetTask()
|
||||
InitTask(alertType string)
|
||||
}
|
||||
|
||||
var cpuLoad1, cpuLoad5, cpuLoad15 []float64
|
||||
var memoryLoad1, memoryLoad5, memoryLoad15 []float64
|
||||
|
||||
const ResourceAlertInterval = 30
|
||||
|
||||
var baseTypes = map[string]bool{"ssl": true, "siteEndTime": true, "panelPwdEndTime": true, "panelUpdate": true}
|
||||
var resourceTypes = map[string]bool{"cpu": true, "memory": true, "disk": true, "load": true}
|
||||
|
||||
func NewIAlertTaskHelper() IAlertTaskHelper {
|
||||
return &AlertTaskHelper{}
|
||||
}
|
||||
func (m *AlertTaskHelper) StartTask() {
|
||||
baseAlert, resourceAlert := handleTask()
|
||||
if len(baseAlert) == 0 && len(resourceAlert) == 0 {
|
||||
return
|
||||
}
|
||||
handleBaseAlerts(baseAlert)
|
||||
handleResourceAlerts(resourceAlert)
|
||||
}
|
||||
|
||||
func (m *AlertTaskHelper) StopTask() {
|
||||
stopBaseJob()
|
||||
stopResourceJob()
|
||||
}
|
||||
|
||||
func (m *AlertTaskHelper) ResetTask() {
|
||||
m.StopTask()
|
||||
m.StartTask()
|
||||
}
|
||||
|
||||
func (m *AlertTaskHelper) InitTask(alertType string) {
|
||||
if alertType == "cpu" {
|
||||
cpuLoad1 = []float64{}
|
||||
cpuLoad5 = []float64{}
|
||||
cpuLoad15 = []float64{}
|
||||
}
|
||||
if alertType == "memory" {
|
||||
memoryLoad1 = []float64{}
|
||||
memoryLoad5 = []float64{}
|
||||
memoryLoad15 = []float64{}
|
||||
}
|
||||
if baseTypes[alertType] {
|
||||
stopBaseJob()
|
||||
} else if resourceTypes[alertType] {
|
||||
stopResourceJob()
|
||||
}
|
||||
m.StartTask()
|
||||
}
|
||||
|
||||
func resourceTask(resourceAlert []dto.AlertDTO) {
|
||||
for _, alert := range resourceAlert {
|
||||
if !alertUtil.CheckSendTimeRange(alert.Type) {
|
||||
continue
|
||||
}
|
||||
switch alert.Type {
|
||||
case "cpu":
|
||||
loadCPUUsage(alert)
|
||||
case "memory":
|
||||
loadMemUsage(alert)
|
||||
case "load":
|
||||
loadLoadInfo(alert)
|
||||
case "disk":
|
||||
loadDiskUsage(alert)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func baseTask(baseAlert []dto.AlertDTO) {
|
||||
for _, alert := range baseAlert {
|
||||
if !alertUtil.CheckSendTimeRange(alert.Type) {
|
||||
continue
|
||||
}
|
||||
switch alert.Type {
|
||||
case "ssl":
|
||||
loadSSLInfo(alert)
|
||||
case "siteEndTime":
|
||||
loadWebsiteInfo(alert)
|
||||
case "panelPwdEndTime":
|
||||
if global.IsMaster {
|
||||
loadPanelPwd(alert)
|
||||
}
|
||||
case "panelUpdate":
|
||||
if global.IsMaster {
|
||||
loadPanelUpdate(alert)
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleTask() (baseAlert []dto.AlertDTO, resourceAlert []dto.AlertDTO) {
|
||||
alertList, _ := NewIAlertService().GetAlerts()
|
||||
baseAlert, resourceAlert = classifyAlerts(alertList)
|
||||
return baseAlert, resourceAlert
|
||||
}
|
||||
|
||||
func classifyAlerts(alertList []dto.AlertDTO) (baseAlert, resourceAlert []dto.AlertDTO) {
|
||||
for _, alert := range alertList {
|
||||
if baseTypes[alert.Type] {
|
||||
baseAlert = append(baseAlert, alert)
|
||||
} else if resourceTypes[alert.Type] {
|
||||
resourceAlert = append(resourceAlert, alert)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func handleBaseAlerts(baseAlert []dto.AlertDTO) {
|
||||
if len(baseAlert) > 0 {
|
||||
if global.AlertBaseJobID == 0 {
|
||||
baseTask(baseAlert)
|
||||
jobID, err := global.Cron.AddFunc("*/30 * * * *", func() {
|
||||
baseTask(baseAlert)
|
||||
})
|
||||
if err != nil {
|
||||
global.LOG.Errorf("alert base job start failed: %v", err)
|
||||
return
|
||||
}
|
||||
global.AlertBaseJobID = jobID
|
||||
global.LOG.Info("start alert base job")
|
||||
}
|
||||
} else {
|
||||
stopBaseJob()
|
||||
}
|
||||
}
|
||||
|
||||
func handleResourceAlerts(resourceAlert []dto.AlertDTO) {
|
||||
if len(resourceAlert) > 0 {
|
||||
if global.AlertResourceJobID == 0 {
|
||||
jobID, err := global.Cron.AddFunc("*/1 * * * *", func() {
|
||||
resourceTask(resourceAlert)
|
||||
})
|
||||
if err != nil {
|
||||
global.LOG.Errorf("alert resource job start failed: %v", err)
|
||||
return
|
||||
}
|
||||
global.AlertResourceJobID = jobID
|
||||
global.LOG.Info("start alert resource job")
|
||||
}
|
||||
} else {
|
||||
stopResourceJob()
|
||||
}
|
||||
}
|
||||
|
||||
func stopBaseJob() {
|
||||
if global.AlertBaseJobID != 0 {
|
||||
global.Cron.Remove(global.AlertBaseJobID)
|
||||
global.AlertBaseJobID = 0
|
||||
global.LOG.Info("stop alert base job")
|
||||
}
|
||||
}
|
||||
|
||||
func stopResourceJob() {
|
||||
if global.AlertResourceJobID != 0 {
|
||||
global.Cron.Remove(global.AlertResourceJobID)
|
||||
global.AlertResourceJobID = 0
|
||||
global.LOG.Info("stop alert resource job")
|
||||
}
|
||||
}
|
||||
|
||||
func loadSSLInfo(alert dto.AlertDTO) {
|
||||
var opts []repo.DBOption
|
||||
if alert.Project != "all" {
|
||||
itemID, _ := strconv.Atoi(alert.Project)
|
||||
opts = append(opts, repo.WithByID(uint(itemID)))
|
||||
}
|
||||
|
||||
sslList, _ := repo.NewISSLRepo().List(opts...)
|
||||
currentDate := time.Now()
|
||||
daysDifferenceMap := make(map[int][]string)
|
||||
projectMap := make(map[uint][]time.Time)
|
||||
for _, ssl := range sslList {
|
||||
daysDifference := int(ssl.ExpireDate.Sub(currentDate).Hours() / 24)
|
||||
if daysDifference > 0 && int(alert.Cycle) >= daysDifference {
|
||||
daysDifferenceMap[daysDifference] = append(daysDifferenceMap[daysDifference], ssl.PrimaryDomain)
|
||||
projectMap[ssl.ID] = append(projectMap[ssl.ID], ssl.ExpireDate)
|
||||
}
|
||||
}
|
||||
projectJSON := serializeAndSortProjects(projectMap)
|
||||
if projectJSON == "" {
|
||||
return
|
||||
}
|
||||
if len(daysDifferenceMap) > 0 {
|
||||
for daysDifference, ssl := range daysDifferenceMap {
|
||||
primaryDomain := strings.Join(ssl, ",")
|
||||
var params []dto.Param
|
||||
params = createAlertBaseParams(strconv.Itoa(len(ssl)), strconv.Itoa(daysDifference))
|
||||
methods := strings.Split(alert.Method, ",")
|
||||
for _, m := range methods {
|
||||
m = strings.TrimSpace(m)
|
||||
switch m {
|
||||
case constant.SMS:
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, projectJSON, constant.SMS)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: totalCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
if !alertUtil.CheckTaskFrequency(constant.SMS) {
|
||||
continue
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alert, create, primaryDomain, params, constant.SMS)
|
||||
alertUtil.CreateNewAlertTask(alert.Project, alert.Type, projectJSON, constant.SMS)
|
||||
case constant.Email:
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, projectJSON, constant.Email)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: totalCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
alertDetail := alertUtil.ProcessAlertDetail(alert, primaryDomain, params, constant.Email)
|
||||
alertRule := alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertRule = alertRule
|
||||
create.AlertDetail = alertDetail
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alert, params, transport)
|
||||
alertUtil.CreateNewAlertTask(alert.Project, alert.Type, projectJSON, constant.Email)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Info("SSL alert push successful")
|
||||
}
|
||||
}
|
||||
|
||||
func loadWebsiteInfo(alert dto.AlertDTO) {
|
||||
var opts []repo.DBOption
|
||||
if alert.Project != "all" {
|
||||
itemID, _ := strconv.Atoi(alert.Project)
|
||||
opts = append(opts, repo.WithByID(uint(itemID)))
|
||||
}
|
||||
|
||||
websiteList, _ := websiteRepo.List(opts...)
|
||||
currentDate := time.Now()
|
||||
daysDifferenceMap := make(map[int][]string)
|
||||
projectMap := make(map[uint][]time.Time)
|
||||
for _, website := range websiteList {
|
||||
daysDifference := int(website.ExpireDate.Sub(currentDate).Hours() / 24)
|
||||
if daysDifference > 0 && int(alert.Cycle) >= daysDifference {
|
||||
daysDifferenceMap[daysDifference] = append(daysDifferenceMap[daysDifference], website.PrimaryDomain)
|
||||
projectMap[website.ID] = append(projectMap[website.ID], website.ExpireDate)
|
||||
}
|
||||
}
|
||||
projectJSON := serializeAndSortProjects(projectMap)
|
||||
if projectJSON == "" {
|
||||
return
|
||||
}
|
||||
if len(daysDifferenceMap) > 0 {
|
||||
methods := strings.Split(alert.Method, ",")
|
||||
for daysDifference, websites := range daysDifferenceMap {
|
||||
primaryDomain := strings.Join(websites, ",")
|
||||
var params []dto.Param
|
||||
params = createAlertBaseParams(strconv.Itoa(len(websites)), strconv.Itoa(daysDifference))
|
||||
for _, m := range methods {
|
||||
m = strings.TrimSpace(m)
|
||||
switch m {
|
||||
case constant.SMS:
|
||||
if !alertUtil.CheckTaskFrequency(constant.SMS) {
|
||||
continue
|
||||
}
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, projectJSON, constant.SMS)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: totalCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alert, create, primaryDomain, params, constant.SMS)
|
||||
alertUtil.CreateNewAlertTask(alert.Project, alert.Type, projectJSON, constant.SMS)
|
||||
case constant.Email:
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, projectJSON, constant.Email)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: totalCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
alertDetail := alertUtil.ProcessAlertDetail(alert, primaryDomain, params, constant.Email)
|
||||
alertRule := alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertDetail = alertDetail
|
||||
create.AlertRule = alertRule
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alert, params, transport)
|
||||
alertUtil.CreateNewAlertTask(alert.Project, alert.Type, projectJSON, constant.Email)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
global.LOG.Info("website expiration alert push successful")
|
||||
}
|
||||
}
|
||||
|
||||
func loadPanelPwd(alert dto.AlertDTO) {
|
||||
// only master alert
|
||||
var expirationDays model.Setting
|
||||
if err := global.CoreDB.Model(&model.Setting{}).Where("key = ?", "ExpirationDays").First(&expirationDays).Error; err != nil {
|
||||
global.LOG.Errorf("load %s from db setting failed, err: %v", "ExpirationDays", err)
|
||||
return
|
||||
}
|
||||
if expirationDays.Value == "0" {
|
||||
global.LOG.Info("panel password expiration setting not enabled, skip")
|
||||
return
|
||||
}
|
||||
var expirationTime model.Setting
|
||||
if err := global.CoreDB.Model(&model.Setting{}).Where("key = ?", "ExpirationTime").First(&expirationTime).Error; err != nil {
|
||||
global.LOG.Errorf("load %s from db setting failed, err: %v", "ExpirationTime", err)
|
||||
return
|
||||
}
|
||||
|
||||
var params []dto.Param
|
||||
defaultDate, _ := time.Parse(constant.DateTimeLayout, expirationTime.Value)
|
||||
daysDifference := calculateDaysDifference(defaultDate)
|
||||
if daysDifference >= 0 && int(alert.Cycle) >= daysDifference {
|
||||
params = createAlertPwdParams(strconv.Itoa(daysDifference))
|
||||
methods := strings.Split(alert.Method, ",")
|
||||
for _, m := range methods {
|
||||
m = strings.TrimSpace(m)
|
||||
switch m {
|
||||
case constant.SMS:
|
||||
if !alertUtil.CheckTaskFrequency(constant.SMS) {
|
||||
continue
|
||||
}
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, expirationTime.Value, constant.SMS)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Count: totalCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alert, create, strconv.Itoa(daysDifference), params, constant.SMS)
|
||||
alertUtil.CreateNewAlertTask(expirationTime.Value, alert.Type, expirationTime.Value, constant.SMS)
|
||||
case constant.Email:
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, expirationTime.Value, constant.Email)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Count: totalCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
alertDetail := alertUtil.ProcessAlertDetail(alert, strconv.Itoa(daysDifference), params, constant.Email)
|
||||
alertRule := alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertRule = alertRule
|
||||
create.AlertDetail = alertDetail
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alert, params, transport)
|
||||
alertUtil.CreateNewAlertTask(expirationTime.Value, alert.Type, expirationTime.Value, constant.Email)
|
||||
default:
|
||||
}
|
||||
}
|
||||
global.LOG.Info("panel password expiration alert push successful")
|
||||
}
|
||||
}
|
||||
|
||||
func loadPanelUpdate(alert dto.AlertDTO) {
|
||||
// only master alert
|
||||
info, err := versionUtil.GetUpgradeVersionInfo()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error getting version, err: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取版本信息
|
||||
var version string
|
||||
// 检查哪个版本字段不为空,并赋值
|
||||
if info.NewVersion != "" {
|
||||
version = info.NewVersion
|
||||
} else if info.TestVersion != "" {
|
||||
version = info.TestVersion
|
||||
} else if info.LatestVersion != "" {
|
||||
version = info.LatestVersion
|
||||
}
|
||||
if version == "" {
|
||||
return
|
||||
}
|
||||
|
||||
var params []dto.Param
|
||||
methods := strings.Split(alert.Method, ",")
|
||||
for _, m := range methods {
|
||||
m = strings.TrimSpace(m)
|
||||
switch m {
|
||||
case constant.SMS:
|
||||
if !alertUtil.CheckTaskFrequency(constant.SMS) {
|
||||
continue
|
||||
}
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, version, constant.SMS)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
var create = dto.AlertLogCreate{
|
||||
Type: alert.Type,
|
||||
AlertId: alert.ID,
|
||||
Count: totalCount + 1,
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alert, create, version, params, constant.SMS)
|
||||
alertUtil.CreateNewAlertTask(version, alert.Type, version, constant.SMS)
|
||||
case constant.Email:
|
||||
todayCount, totalCount, err := alertRepo.LoadTaskCount(alert.Type, version, constant.Email)
|
||||
if err != nil || todayCount >= 1 || alert.SendCount <= totalCount {
|
||||
continue
|
||||
}
|
||||
var create = dto.AlertLogCreate{
|
||||
Type: alert.Type,
|
||||
AlertId: alert.ID,
|
||||
Count: totalCount + 1,
|
||||
}
|
||||
alertDetail := alertUtil.ProcessAlertDetail(alert, version, params, constant.Email)
|
||||
alertRule := alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertRule = alertRule
|
||||
create.AlertDetail = alertDetail
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alert, params, transport)
|
||||
alertUtil.CreateNewAlertTask(version, alert.Type, version, constant.Email)
|
||||
default:
|
||||
}
|
||||
}
|
||||
global.LOG.Info("panel update alert push successful")
|
||||
}
|
||||
|
||||
// 获取 CPU 使用率数据并发送到通道
|
||||
func loadCPUUsage(alert dto.AlertDTO) {
|
||||
percent, err := cpu.Percent(3*time.Second, false)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error getting cpu usage, err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(percent) > 0 {
|
||||
var cpuLoad *[]float64
|
||||
var threshold int
|
||||
|
||||
switch alert.Cycle {
|
||||
case 1:
|
||||
cpuLoad = &cpuLoad1
|
||||
threshold = 1
|
||||
case 5:
|
||||
cpuLoad = &cpuLoad5
|
||||
threshold = 5
|
||||
case 15:
|
||||
cpuLoad = &cpuLoad15
|
||||
threshold = 15
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
if checkAndSendAlert(alert, percent[0], cpuLoad, threshold) {
|
||||
global.LOG.Info("cpu alert push successful")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取内存使用情况数据并发送到通道
|
||||
func loadMemUsage(alert dto.AlertDTO) {
|
||||
|
||||
memStat, err := mem.VirtualMemory()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error getting memory usage, err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
percent := memStat.UsedPercent
|
||||
var memoryLoad *[]float64
|
||||
var threshold int
|
||||
|
||||
switch alert.Cycle {
|
||||
case 1:
|
||||
memoryLoad = &memoryLoad1
|
||||
threshold = 1
|
||||
case 5:
|
||||
memoryLoad = &memoryLoad5
|
||||
threshold = 5
|
||||
case 15:
|
||||
memoryLoad = &memoryLoad15
|
||||
threshold = 15
|
||||
default:
|
||||
return
|
||||
}
|
||||
if checkAndSendAlert(alert, percent, memoryLoad, threshold) {
|
||||
global.LOG.Info("memory alert push successful")
|
||||
}
|
||||
}
|
||||
|
||||
// 获取系统负载数据并发送到通道
|
||||
func loadLoadInfo(alert dto.AlertDTO) {
|
||||
avgStat, err := load.Avg()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error getting load usage, err: %v", err)
|
||||
return
|
||||
}
|
||||
var loadValue float64
|
||||
CPUTotal, _ := cpu.Counts(true)
|
||||
switch alert.Cycle {
|
||||
case 1:
|
||||
loadValue = avgStat.Load1 / (float64(CPUTotal*2) * 0.75) * 100
|
||||
case 5:
|
||||
loadValue = avgStat.Load5 / (float64(CPUTotal*2) * 0.75) * 100
|
||||
case 15:
|
||||
loadValue = avgStat.Load15 / (float64(CPUTotal*2) * 0.75) * 100
|
||||
default:
|
||||
return
|
||||
}
|
||||
newDate, err := alertRepo.GetTaskLog(alert.Type, alert.ID)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("task log record not found, err: %v", err)
|
||||
}
|
||||
if newDate.IsZero() || calculateMinutesDifference(newDate) > ResourceAlertInterval {
|
||||
if loadValue >= float64(alert.Count) {
|
||||
global.LOG.Infof("%d minute load: %f,detail: %v", alert.Cycle, loadValue, avgStat)
|
||||
createAndLogAlert(alert, loadValue)
|
||||
global.LOG.Info("load alert task push successful")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 内存/cpu检查是否需要发送告警并处理相关逻辑
|
||||
func checkAndSendAlert(alert dto.AlertDTO, currentUsage float64, usageLoad *[]float64, threshold int) bool {
|
||||
newDate, err := alertRepo.GetTaskLog(alert.Type, alert.ID)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("record not found, err: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
*usageLoad = append(*usageLoad, currentUsage)
|
||||
|
||||
if len(*usageLoad) > threshold {
|
||||
*usageLoad = (*usageLoad)[1:]
|
||||
}
|
||||
|
||||
if newDate.IsZero() || calculateMinutesDifference(newDate) > ResourceAlertInterval {
|
||||
if len(*usageLoad) == threshold {
|
||||
avgUsage := average(*usageLoad)
|
||||
if avgUsage >= float64(alert.Count) {
|
||||
global.LOG.Infof("%d minute %s: %f , usage: %v", threshold, alert.Type, avgUsage, usageLoad)
|
||||
createAndLogAlert(alert, avgUsage)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查是否超过今日发送次数限制
|
||||
func checkTaskFrequency(alertType, quotaType string, sendCount uint, method string) (uint, bool) {
|
||||
todayCount, _, err := alertRepo.LoadTaskCount(alertType, quotaType, method)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error getting task info, err: %v", err)
|
||||
return todayCount, false
|
||||
}
|
||||
if todayCount >= sendCount {
|
||||
return todayCount, false
|
||||
}
|
||||
|
||||
return todayCount, true
|
||||
}
|
||||
|
||||
// 创建告警日志和详情
|
||||
func createAndLogAlert(alert dto.AlertDTO, avgUsage float64) {
|
||||
avgUsagePercent := common.FormatPercent(avgUsage)
|
||||
params := createAlertAvgParams(strconv.Itoa(int(alert.Cycle)), getModule(alert.Type), avgUsagePercent)
|
||||
methods := strings.Split(alert.Method, ",")
|
||||
for _, m := range methods {
|
||||
m = strings.TrimSpace(m)
|
||||
switch m {
|
||||
case constant.SMS:
|
||||
if !alertUtil.CheckTaskFrequency(constant.SMS) {
|
||||
continue
|
||||
}
|
||||
todayCount, isValid := checkTaskFrequency(alert.Type, strconv.Itoa(int(alert.Cycle)), alert.SendCount, constant.SMS)
|
||||
if !isValid {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: todayCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alert, create, avgUsagePercent, params, constant.SMS)
|
||||
alertUtil.CreateNewAlertTask(avgUsagePercent, alert.Type, strconv.Itoa(int(alert.Cycle)), constant.SMS)
|
||||
case constant.Email:
|
||||
todayCount, isValid := checkTaskFrequency(alert.Type, strconv.Itoa(int(alert.Cycle)), alert.SendCount, constant.Email)
|
||||
if !isValid {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: todayCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
alertDetail := alertUtil.ProcessAlertDetail(alert, avgUsagePercent, params, constant.Email)
|
||||
alertRule := alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertRule = alertRule
|
||||
create.AlertDetail = alertDetail
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alert, params, transport)
|
||||
alertUtil.CreateNewAlertTask(avgUsagePercent, alert.Type, strconv.Itoa(int(alert.Cycle)), constant.Email)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getModule(alertType string) string {
|
||||
var module string
|
||||
switch alertType {
|
||||
case "cpu":
|
||||
module = " CPU "
|
||||
case "memory":
|
||||
module = "内存"
|
||||
case "load":
|
||||
module = "负载"
|
||||
default:
|
||||
}
|
||||
return module
|
||||
}
|
||||
|
||||
func loadDiskUsage(alert dto.AlertDTO) {
|
||||
newDate, err := alertRepo.GetTaskLog(alert.Type, alert.ID)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("record not found, err: %v", err)
|
||||
}
|
||||
|
||||
if newDate.IsZero() || calculateMinutesDifference(newDate) > ResourceAlertInterval {
|
||||
if strings.Contains(alert.Project, "all") {
|
||||
err = processAllDisks(alert)
|
||||
} else {
|
||||
err = processSingleDisk(alert)
|
||||
}
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error processing disk usage, err: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processAllDisks(alert dto.AlertDTO) error {
|
||||
diskList, err := NewIAlertService().GetDisks()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error getting disk list, err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
var flag bool
|
||||
for _, item := range diskList {
|
||||
if success, err := checkAndCreateDiskAlert(alert, item.Path); err == nil && success {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
if flag {
|
||||
global.LOG.Info("all disk alert push successful")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processSingleDisk(alert dto.AlertDTO) error {
|
||||
success, err := checkAndCreateDiskAlert(alert, alert.Project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if success {
|
||||
global.LOG.Info("disk alert push successful")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) (bool, error) {
|
||||
usageStat, err := disk.Usage(path)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("error getting disk usage for %s, err: %v", path, err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
usedTotal, usedStr := calculateUsedTotal(alert.Cycle, usageStat)
|
||||
commonTotal := float64(alert.Count)
|
||||
if alert.Cycle == 1 {
|
||||
commonTotal *= 1024 * 1024 * 1024
|
||||
}
|
||||
if usedTotal < commonTotal {
|
||||
return false, nil
|
||||
}
|
||||
global.LOG.Infof("disk「 %s 」usage: %s", path, usedStr)
|
||||
var params []dto.Param
|
||||
params = createAlertDiskParams(path, usedStr)
|
||||
methods := strings.Split(alert.Method, ",")
|
||||
for _, m := range methods {
|
||||
m = strings.TrimSpace(m)
|
||||
switch m {
|
||||
case constant.SMS:
|
||||
if !alertUtil.CheckTaskFrequency(constant.SMS) {
|
||||
continue
|
||||
}
|
||||
todayCount, isValid := checkTaskFrequency(alert.Type, alert.Project, alert.SendCount, constant.SMS)
|
||||
if !isValid {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: todayCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alert, create, path, params, constant.SMS)
|
||||
alertUtil.CreateNewAlertTask(strconv.Itoa(int(alert.Cycle)), alert.Type, alert.Project, constant.SMS)
|
||||
case constant.Email:
|
||||
todayCount, isValid := checkTaskFrequency(alert.Type, alert.Project, alert.SendCount, constant.Email)
|
||||
if !isValid {
|
||||
continue
|
||||
}
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: todayCount + 1,
|
||||
AlertId: alert.ID,
|
||||
Type: alert.Type,
|
||||
}
|
||||
alertDetail := alertUtil.ProcessAlertDetail(alert, path, params, constant.Email)
|
||||
alertRule := alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertRule = alertRule
|
||||
create.AlertDetail = alertDetail
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alert, params, transport)
|
||||
alertUtil.CreateNewAlertTask(strconv.Itoa(int(alert.Cycle)), alert.Type, alert.Project, constant.Email)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func calculateUsedTotal(cycle uint, usageStat *disk.UsageStat) (float64, string) {
|
||||
if cycle == 1 {
|
||||
return float64(usageStat.Used), common.FormatBytes(usageStat.Used)
|
||||
}
|
||||
return usageStat.UsedPercent, common.FormatPercent(usageStat.UsedPercent)
|
||||
}
|
||||
|
||||
func calculateDaysDifference(expirationTime time.Time) int {
|
||||
currentDate := time.Now()
|
||||
formattedTime := currentDate.Format(constant.DateTimeLayout)
|
||||
parsedTime, _ := time.Parse(constant.DateTimeLayout, formattedTime)
|
||||
timeGap := expirationTime.Sub(parsedTime).Milliseconds()
|
||||
if timeGap < 0 {
|
||||
return -1
|
||||
}
|
||||
daysDifference := int(math.Floor(float64(timeGap) / (3600 * 1000 * 24)))
|
||||
return daysDifference
|
||||
}
|
||||
|
||||
func calculateMinutesDifference(newDate time.Time) int {
|
||||
now := time.Now()
|
||||
if newDate.After(now) {
|
||||
return -1
|
||||
}
|
||||
minutesDifference := int(now.Sub(newDate).Minutes())
|
||||
return minutesDifference
|
||||
}
|
||||
|
||||
func average(arr []float64) float64 {
|
||||
total := 0.0
|
||||
for _, v := range arr {
|
||||
total += v
|
||||
}
|
||||
return total / float64(len(arr))
|
||||
}
|
||||
|
||||
func createAlertBaseParams(project, cycle string) []dto.Param {
|
||||
return []dto.Param{
|
||||
{
|
||||
Index: "1",
|
||||
Key: "project",
|
||||
Value: project,
|
||||
},
|
||||
{
|
||||
Index: "2",
|
||||
Key: "cycle",
|
||||
Value: cycle,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createAlertPwdParams(cycle string) []dto.Param {
|
||||
return []dto.Param{
|
||||
{
|
||||
Index: "1",
|
||||
Key: "cycle",
|
||||
Value: cycle,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createAlertAvgParams(cycle, module, count string) []dto.Param {
|
||||
return []dto.Param{
|
||||
{
|
||||
Index: "1",
|
||||
Key: "cycle",
|
||||
Value: cycle,
|
||||
},
|
||||
{
|
||||
Index: "2",
|
||||
Key: "module",
|
||||
Value: module,
|
||||
},
|
||||
{
|
||||
Index: "3",
|
||||
Key: "count",
|
||||
Value: count,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createAlertDiskParams(project, count string) []dto.Param {
|
||||
return []dto.Param{
|
||||
{
|
||||
Index: "1",
|
||||
Key: "project",
|
||||
Value: project,
|
||||
},
|
||||
{
|
||||
Index: "2",
|
||||
Key: "count",
|
||||
Value: count,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func serializeAndSortProjects(projectMap map[uint][]time.Time) string {
|
||||
keys := make([]int, 0, len(projectMap))
|
||||
for k := range projectMap {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
projectJSON, err := json.Marshal(projectMap)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("Failed to serialize projectMap: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(projectJSON)
|
||||
}
|
||||
@@ -483,6 +483,7 @@ func (a AppService) Install(req request.AppInstallCreate) (appInstall *model.App
|
||||
req.Params["PANEL_DB_HOST"] = database.Address
|
||||
req.Params["PANEL_DB_PORT"] = database.Port
|
||||
req.Params["PANEL_DB_HOST_NAME"] = hostName
|
||||
req.Params["DATABASE_NAME"] = database.Name
|
||||
}
|
||||
}
|
||||
paramByte, err = json.Marshal(req.Params)
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -15,28 +14,25 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/env"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx"
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
|
||||
"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/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/env"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type AppInstallService struct {
|
||||
@@ -60,6 +56,7 @@ type IAppInstallService interface {
|
||||
|
||||
UpdateAppConfig(req request.AppConfigUpdate) error
|
||||
GetInstallList() ([]dto.AppInstallInfo, error)
|
||||
GetAppInstallInfo(appInstallID uint) (*response.AppInstallInfo, error)
|
||||
}
|
||||
|
||||
func NewIAppInstalledService() IAppInstallService {
|
||||
@@ -124,7 +121,7 @@ func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []respo
|
||||
}
|
||||
}
|
||||
|
||||
installDTOs, err := handleInstalled(installs, req.Update, req.Sync)
|
||||
installDTOs, _ := handleInstalled(installs, req.Update, req.Sync)
|
||||
if req.Update {
|
||||
total = int64(len(installDTOs))
|
||||
}
|
||||
@@ -476,10 +473,20 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
||||
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
||||
var res []response.AppService
|
||||
if DatabaseKeys[key] > 0 {
|
||||
types := []string{key}
|
||||
if key == constant.AppPostgres {
|
||||
key = constant.AppPostgresql
|
||||
}
|
||||
dbs, _ := databaseRepo.GetList(repo.WithByType(key))
|
||||
switch key {
|
||||
case constant.AppMysql:
|
||||
types = []string{constant.AppMysql, constant.AppMysqlCluster}
|
||||
case constant.AppPostgresql:
|
||||
types = []string{constant.AppPostgresql, constant.AppPostgresqlCluster}
|
||||
case constant.AppRedis:
|
||||
types = []string{constant.AppRedis, constant.AppRedisCluster}
|
||||
}
|
||||
|
||||
dbs, _ := databaseRepo.GetList(repo.WithTypes(types))
|
||||
if len(dbs) == 0 {
|
||||
return res, nil
|
||||
}
|
||||
@@ -635,10 +642,14 @@ func (a *AppInstallService) DeleteCheck(installID uint) ([]dto.AppResource, erro
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(appInstall.ID), repo.WithByFrom(constant.AppResourceLocal))
|
||||
for _, resource := range resources {
|
||||
linkInstall, _ := appInstallRepo.GetFirst(repo.WithByID(resource.AppInstallId))
|
||||
res = append(res, dto.AppResource{
|
||||
Type: "app",
|
||||
Name: linkInstall.Name,
|
||||
})
|
||||
if linkInstall.ID > 0 {
|
||||
res = append(res, dto.AppResource{
|
||||
Type: "app",
|
||||
Name: linkInstall.Name,
|
||||
})
|
||||
} else {
|
||||
_ = appInstallResourceRepo.DeleteBy(context.Background(), appInstallResourceRepo.WithAppInstallId(resource.AppInstallId))
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -658,7 +669,7 @@ func (a *AppInstallService) GetDefaultConfigByKey(key, name string) (string, err
|
||||
return "", buserr.New("ErrPathNotFound")
|
||||
}
|
||||
|
||||
if key == constant.AppMysql || key == constant.AppMariaDB {
|
||||
if key == constant.AppMysql || key == constant.AppMariaDB || key == constant.AppMysqlCluster {
|
||||
filePath = path.Join(filePath, "my.cnf")
|
||||
}
|
||||
if key == constant.AppRedis {
|
||||
@@ -710,6 +721,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
||||
}
|
||||
appParam.LabelZh = form.LabelZh
|
||||
appParam.LabelEn = form.LabelEn
|
||||
appParam.Label = form.Label
|
||||
appParam.Value = v
|
||||
if form.Type == "service" {
|
||||
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
||||
@@ -763,6 +775,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
||||
Values: form.Values,
|
||||
Multiple: form.Multiple,
|
||||
Required: form.Required,
|
||||
Label: form.Label,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -898,3 +911,31 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) GetAppInstallInfo(installID uint) (*response.AppInstallInfo, error) {
|
||||
appInstall, _ := appInstallRepo.GetFirst(repo.WithByID(installID))
|
||||
if appInstall.ID == 0 {
|
||||
return &response.AppInstallInfo{
|
||||
Status: constant.StatusDeleted,
|
||||
}, nil
|
||||
}
|
||||
_ = syncAppInstallStatus(&appInstall, false)
|
||||
appInstall, _ = appInstallRepo.GetFirst(repo.WithByID(installID))
|
||||
var envMap map[string]interface{}
|
||||
err := json.Unmarshal([]byte(appInstall.Env), &envMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &response.AppInstallInfo{
|
||||
ID: appInstall.ID,
|
||||
Name: appInstall.Name,
|
||||
Version: appInstall.Version,
|
||||
Container: appInstall.ContainerName,
|
||||
HttpPort: appInstall.HttpPort,
|
||||
Status: appInstall.Status,
|
||||
Message: appInstall.Message,
|
||||
Env: envMap,
|
||||
ComposePath: appInstall.GetComposePath(),
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
+103
-142
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
@@ -19,39 +18,33 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx/parser"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/subosito/gotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/env"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"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/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/compose"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
composeV2 "github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/env"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx/parser"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/subosito/gotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type DatabaseOp string
|
||||
@@ -123,13 +116,16 @@ func checkPortExist(port int) error {
|
||||
}
|
||||
|
||||
var DatabaseKeys = map[string]uint{
|
||||
constant.AppMysql: 3306,
|
||||
constant.AppMariaDB: 3306,
|
||||
constant.AppPostgresql: 5432,
|
||||
constant.AppPostgres: 5432,
|
||||
constant.AppMongodb: 27017,
|
||||
constant.AppRedis: 6379,
|
||||
constant.AppMemcached: 11211,
|
||||
constant.AppMysql: 3306,
|
||||
constant.AppMariaDB: 3306,
|
||||
constant.AppPostgresql: 5432,
|
||||
constant.AppPostgres: 5432,
|
||||
constant.AppMongodb: 27017,
|
||||
constant.AppRedis: 6379,
|
||||
constant.AppMemcached: 11211,
|
||||
constant.AppMysqlCluster: 3306,
|
||||
constant.AppPostgresqlCluster: 5432,
|
||||
constant.AppRedisCluster: 6379,
|
||||
}
|
||||
|
||||
var ToolKeys = map[string]uint{
|
||||
@@ -145,7 +141,6 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
||||
}
|
||||
_ = deleteLink(del)
|
||||
}
|
||||
var dbConfig dto.AppDatabase
|
||||
if DatabaseKeys[app.Key] > 0 {
|
||||
handleDataBaseApp := func(task *task.Task) error {
|
||||
database := &model.Database{
|
||||
@@ -177,11 +172,11 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
||||
}
|
||||
|
||||
switch app.Key {
|
||||
case constant.AppMysql, constant.AppMariaDB, constant.AppPostgresql, constant.AppMongodb:
|
||||
case constant.AppMysql, constant.AppMariaDB, constant.AppPostgresql, constant.AppMongodb, constant.AppMysqlCluster, constant.AppPostgresqlCluster:
|
||||
if password, ok := params["PANEL_DB_ROOT_PASSWORD"]; ok {
|
||||
if password != "" {
|
||||
database.Password = password.(string)
|
||||
if app.Key == "mysql" || app.Key == "mariadb" {
|
||||
if app.Key == "mysql" || app.Key == "mariadb" || app.Key == constant.AppMysqlCluster {
|
||||
database.Username = "root"
|
||||
}
|
||||
if rootUser, ok := params["PANEL_DB_ROOT_USER"]; ok {
|
||||
@@ -199,7 +194,7 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
||||
|
||||
}
|
||||
}
|
||||
case constant.AppRedis:
|
||||
case constant.AppRedis, constant.AppRedisCluster:
|
||||
if password, ok := params["PANEL_REDIS_ROOT_PASSWORD"]; ok {
|
||||
authParam := dto.RedisAuthParam{
|
||||
RootPassword: "",
|
||||
@@ -236,6 +231,7 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
||||
}
|
||||
}
|
||||
|
||||
var dbConfig dto.AppDatabase
|
||||
if app.Type == "website" || app.Type == "tool" {
|
||||
paramByte, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
@@ -259,8 +255,11 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
||||
var resourceId uint
|
||||
if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" {
|
||||
switch database.Type {
|
||||
case constant.AppPostgresql, constant.AppPostgres:
|
||||
case constant.AppPostgresql, constant.AppPostgres, constant.AppPostgresqlCluster:
|
||||
oldPostgresqlDb, _ := postgresqlRepo.Get(repo.WithByName(dbConfig.DbName), repo.WithByFrom(constant.ResourceLocal))
|
||||
if oldPostgresqlDb.ID == 0 {
|
||||
oldPostgresqlDb, _ = postgresqlRepo.Get(repo.WithByName(dbConfig.DbName), postgresqlRepo.WithByPostgresqlName(dbConfig.DatabaseName), repo.WithByFrom(constant.AppResourceRemote))
|
||||
}
|
||||
resourceId = oldPostgresqlDb.ID
|
||||
if oldPostgresqlDb.ID > 0 {
|
||||
if oldPostgresqlDb.Username != dbConfig.DbUser || oldPostgresqlDb.Password != dbConfig.Password {
|
||||
@@ -281,8 +280,11 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
||||
}
|
||||
resourceId = pgdb.ID
|
||||
}
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
case constant.AppMysql, constant.AppMariaDB, constant.AppMysqlCluster:
|
||||
oldMysqlDb, _ := mysqlRepo.Get(repo.WithByName(dbConfig.DbName), repo.WithByFrom(constant.ResourceLocal))
|
||||
if oldMysqlDb.ID == 0 {
|
||||
oldMysqlDb, _ = mysqlRepo.Get(repo.WithByName(dbConfig.DbName), mysqlRepo.WithByMysqlName(dbConfig.DatabaseName), repo.WithByFrom(constant.AppResourceRemote))
|
||||
}
|
||||
resourceId = oldMysqlDb.ID
|
||||
if oldMysqlDb.ID > 0 {
|
||||
if oldMysqlDb.Username != dbConfig.DbUser || oldMysqlDb.Password != dbConfig.Password {
|
||||
@@ -386,21 +388,25 @@ func deleteAppInstall(deleteReq request.AppInstallDelete) error {
|
||||
}
|
||||
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if deleteReq.DeleteDB && len(resources) > 0 {
|
||||
del := dto.DelAppLink{
|
||||
Ctx: ctx,
|
||||
Install: &install,
|
||||
ForceDelete: deleteReq.ForceDelete,
|
||||
Task: uninstallTask,
|
||||
}
|
||||
t.LogWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"))
|
||||
if err = deleteLink(del); err != nil {
|
||||
t.LogFailedWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"), err)
|
||||
if !deleteReq.ForceDelete {
|
||||
return err
|
||||
if len(resources) > 0 {
|
||||
if deleteReq.DeleteDB {
|
||||
del := dto.DelAppLink{
|
||||
Ctx: ctx,
|
||||
Install: &install,
|
||||
ForceDelete: deleteReq.ForceDelete,
|
||||
Task: uninstallTask,
|
||||
}
|
||||
t.LogWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"))
|
||||
if err = deleteLink(del); err != nil {
|
||||
t.LogFailedWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"), err)
|
||||
if !deleteReq.ForceDelete {
|
||||
return err
|
||||
}
|
||||
}
|
||||
t.LogSuccessWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"))
|
||||
} else {
|
||||
_ = appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
}
|
||||
t.LogSuccessWithOps(task.TaskDelete, i18n.GetMsgByKey("Database"))
|
||||
}
|
||||
|
||||
if DatabaseKeys[install.App.Key] > 0 {
|
||||
@@ -408,9 +414,9 @@ func deleteAppInstall(deleteReq request.AppInstallDelete) error {
|
||||
}
|
||||
|
||||
switch install.App.Key {
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
case constant.AppMysql, constant.AppMariaDB, constant.AppMysqlCluster:
|
||||
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
|
||||
case constant.AppPostgresql:
|
||||
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||
_ = postgresqlRepo.Delete(ctx, postgresqlRepo.WithByPostgresqlName(install.Name))
|
||||
}
|
||||
|
||||
@@ -489,17 +495,14 @@ func deleteLink(del dto.DelAppLink) error {
|
||||
return appInstallResourceRepo.DeleteBy(del.Ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
}
|
||||
|
||||
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
||||
if detail.DockerCompose == "" {
|
||||
return "", nil
|
||||
}
|
||||
func handleUpgradeCompose(install model.AppInstall, detail model.AppDetail) (map[string]interface{}, error) {
|
||||
composeMap := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
value, ok := composeMap["services"]
|
||||
if !ok || value == nil {
|
||||
return "", buserr.New("ErrFileParse")
|
||||
return nil, buserr.New("ErrFileParse")
|
||||
}
|
||||
servicesMap := value.(map[string]interface{})
|
||||
if len(servicesMap) == 1 {
|
||||
@@ -517,6 +520,34 @@ func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string
|
||||
delete(servicesMap, oldServiceName)
|
||||
}
|
||||
}
|
||||
serviceValue := servicesMap[install.ServiceName].(map[string]interface{})
|
||||
|
||||
oldComposeMap := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal([]byte(install.DockerCompose), &oldComposeMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oldValue, ok := oldComposeMap["services"]
|
||||
if !ok || oldValue == nil {
|
||||
return nil, buserr.New("ErrFileParse")
|
||||
}
|
||||
oldValueMap := oldValue.(map[string]interface{})
|
||||
oldServiceValue := oldValueMap[install.ServiceName].(map[string]interface{})
|
||||
if oldServiceValue["deploy"] != nil {
|
||||
serviceValue["deploy"] = oldServiceValue["deploy"]
|
||||
}
|
||||
servicesMap[install.ServiceName] = serviceValue
|
||||
composeMap["services"] = servicesMap
|
||||
return composeMap, nil
|
||||
}
|
||||
|
||||
func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string, error) {
|
||||
if detail.DockerCompose == "" {
|
||||
return "", nil
|
||||
}
|
||||
composeMap, err := handleUpgradeCompose(install, detail)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
envs := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(install.Env), &envs); err != nil {
|
||||
return "", err
|
||||
@@ -617,7 +648,7 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dockerCLi, err := docker.NewClient()
|
||||
dockerCLi, _ := docker.NewClient()
|
||||
if req.PullImage {
|
||||
images, err := composeV2.GetDockerComposeImagesV2(content, []byte(detail.DockerCompose))
|
||||
if err != nil {
|
||||
@@ -634,10 +665,7 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
}
|
||||
|
||||
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
|
||||
stdout, _ := command.CombinedOutput()
|
||||
if stdout != nil {
|
||||
t.Logger.Printf("upgrade app [%s] [%s] cp file log : %s ", install.App.Key, install.Name, string(stdout))
|
||||
}
|
||||
_, _ = command.CombinedOutput()
|
||||
sourceScripts := path.Join(detailDir, "scripts")
|
||||
if fileOp.Stat(sourceScripts) {
|
||||
dstScripts := path.Join(install.GetPath(), "scripts")
|
||||
@@ -674,63 +702,6 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
}
|
||||
envParams := make(map[string]string, len(envs))
|
||||
handleMap(envs, envParams)
|
||||
if install.App.Key == "openresty" && install.App.Resource == "remote" && !common.CompareVersion(install.Version, "1.25.3.2-0-1") {
|
||||
t.Log(i18n.GetMsgByKey("MoveSiteDir"))
|
||||
siteDir := path.Join(global.Dir.DataDir, "www")
|
||||
envParams["WEBSITE_DIR"] = siteDir
|
||||
oldSiteDir := path.Join(install.GetPath(), "www")
|
||||
t.Log(i18n.GetWithName("MoveSiteToDir", siteDir))
|
||||
if err := fileOp.CopyDir(oldSiteDir, global.Dir.DataDir); err != nil {
|
||||
t.Log(i18n.GetMsgByKey("ErrMoveSiteDir"))
|
||||
return err
|
||||
}
|
||||
newConfDir := path.Join(global.Dir.DataDir, "www", "conf.d")
|
||||
_ = fileOp.CreateDir(newConfDir, constant.DirPerm)
|
||||
oldConfDir := path.Join(install.GetPath(), "conf/conf.d")
|
||||
items, err := os.ReadDir(oldConfDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
itemPath := path.Join(oldConfDir, item.Name())
|
||||
if item.IsDir() {
|
||||
_ = fileOp.Mv(itemPath, newConfDir)
|
||||
}
|
||||
if item.Name() != "default.conf" && item.Name() != "00.default.conf" {
|
||||
_ = fileOp.Mv(itemPath, newConfDir)
|
||||
}
|
||||
}
|
||||
nginxConfPath := path.Join(install.GetPath(), "conf", "nginx.conf")
|
||||
parse, err := parser.NewParser(nginxConfPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config, err := parse.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.FilePath = nginxConfPath
|
||||
httpDirective := config.FindHttp()
|
||||
httpDirective.UpdateDirective("include", []string{"/usr/local/openresty/nginx/conf/default/*.conf"})
|
||||
|
||||
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||
return buserr.WithErr("ErrUpdateBuWebsite", err)
|
||||
}
|
||||
t.Log(i18n.GetMsgByKey("DeleteRuntimePHP"))
|
||||
_ = fileOp.DeleteDir(path.Join(global.Dir.RuntimeDir, "php"))
|
||||
websites, _ := websiteRepo.List(repo.WithByType("runtime"))
|
||||
for _, website := range websites {
|
||||
runtime, _ := runtimeRepo.GetFirst(context.Background(), repo.WithByID(website.RuntimeID))
|
||||
if runtime != nil && runtime.Type == "php" {
|
||||
website.Type = constant.Static
|
||||
website.RuntimeID = 0
|
||||
_ = websiteRepo.SaveWithoutCtx(&website)
|
||||
}
|
||||
}
|
||||
_ = runtimeRepo.DeleteBy(repo.WithByType("php"))
|
||||
t.Log(i18n.GetMsgByKey("MoveSiteDirSuccess"))
|
||||
}
|
||||
|
||||
if err = env.Write(envParams, install.GetEnvPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1003,14 +974,16 @@ func runScript(task *task.Task, appInstall *model.AppInstall, operate string) er
|
||||
case "uninstall":
|
||||
scriptPath = path.Join(workDir, "scripts", "uninstall.sh")
|
||||
}
|
||||
if !files.NewFileOp().Stat(scriptPath) {
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(scriptPath) {
|
||||
return nil
|
||||
}
|
||||
_ = fileOp.ChmodR(scriptPath, constant.DirPerm, false)
|
||||
logStr := i18n.GetWithName("ExecShell", operate)
|
||||
task.LogStart(logStr)
|
||||
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute), cmd.WithScriptPath(scriptPath), cmd.WithWorkDir(workDir))
|
||||
out, err := cmdMgr.RunWithStdout("bash")
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute), cmd.WithWorkDir(workDir))
|
||||
out, err := cmdMgr.RunWithStdoutBashCf(scriptPath)
|
||||
if err != nil {
|
||||
if out != "" {
|
||||
err = errors.New(out)
|
||||
@@ -1055,12 +1028,12 @@ func upApp(task *task.Task, appInstall *model.AppInstall, pullImages bool) error
|
||||
errMsg string
|
||||
)
|
||||
if pullImages && appInstall.App.Type != "php" {
|
||||
projectName := strings.ToLower(appInstall.Name)
|
||||
//projectName := strings.ToLower(appInstall.Name)
|
||||
envByte, err := files.NewFileOp().GetContent(appInstall.GetEnvPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
images, err := composeV2.GetDockerComposeImages(projectName, envByte, []byte(appInstall.DockerCompose))
|
||||
images, err := composeV2.GetImagesFromDockerCompose(envByte, []byte(appInstall.DockerCompose))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1525,7 +1498,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
||||
continue
|
||||
}
|
||||
lastVersion := versions[0]
|
||||
if app.Key == constant.AppMysql {
|
||||
if app.Key == constant.AppMysql || app.Key == constant.AppMysqlCluster {
|
||||
for _, version := range versions {
|
||||
majorVersion := getMajorVersion(installed.Version)
|
||||
if !strings.HasPrefix(version, majorVersion) {
|
||||
@@ -1802,10 +1775,7 @@ func ignoreUpdate(installed model.AppInstall) bool {
|
||||
return true
|
||||
}
|
||||
ignores, _ := appIgnoreUpgradeRepo.List(appDetailRepo.WithAppId(installed.AppId), appIgnoreUpgradeRepo.WithScope("all"))
|
||||
if len(ignores) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return len(ignores) > 0
|
||||
}
|
||||
|
||||
func RequestDownloadCallBack(downloadCallBackUrl string) {
|
||||
@@ -1830,24 +1800,15 @@ func getAppTags(appID uint, lang string) ([]response.TagDTO, error) {
|
||||
}
|
||||
var res []response.TagDTO
|
||||
for _, t := range tags {
|
||||
if t.Name != "" {
|
||||
var translations = make(map[string]string)
|
||||
_ = json.Unmarshal([]byte(t.Translations), &translations)
|
||||
if name, ok := translations[lang]; ok {
|
||||
tagDTO := response.TagDTO{
|
||||
ID: t.ID,
|
||||
Key: t.Key,
|
||||
Name: t.Name,
|
||||
Name: name,
|
||||
}
|
||||
res = append(res, tagDTO)
|
||||
} else {
|
||||
var translations = make(map[string]string)
|
||||
_ = json.Unmarshal([]byte(t.Translations), &translations)
|
||||
if name, ok := translations[lang]; ok {
|
||||
tagDTO := response.TagDTO{
|
||||
ID: t.ID,
|
||||
Key: t.Key,
|
||||
Name: name,
|
||||
}
|
||||
res = append(res, tagDTO)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
|
||||
@@ -290,8 +290,6 @@ func (u *BackupService) RefreshToken(req dto.OperateByID) error {
|
||||
switch backup.Type {
|
||||
case constant.OneDrive:
|
||||
refreshToken, err = client.RefreshToken("refresh_token", "refreshToken", varMap)
|
||||
case constant.GoogleDrive:
|
||||
refreshToken, err = client.RefreshGoogleToken("refresh_token", "refreshToken", varMap)
|
||||
case constant.ALIYUN:
|
||||
refreshToken, err = client.RefreshALIToken(varMap)
|
||||
}
|
||||
@@ -543,11 +541,17 @@ func changeLocalBackup(oldPath, newPath string) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if fileOp.Stat(path.Join(oldPath, "master")) {
|
||||
if err := fileOp.CopyDir(path.Join(oldPath, "master"), newPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_ = fileOp.RmRf(path.Join(oldPath, "app"))
|
||||
_ = fileOp.RmRf(path.Join(oldPath, "database"))
|
||||
_ = fileOp.RmRf(path.Join(oldPath, "directory"))
|
||||
_ = fileOp.RmRf(path.Join(oldPath, "system_snapshot"))
|
||||
_ = fileOp.RmRf(path.Join(oldPath, "website"))
|
||||
_ = fileOp.RmRf(path.Join(oldPath, "log"))
|
||||
_ = fileOp.RmRf(path.Join(oldPath, "master"))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
@@ -194,7 +193,7 @@ func (u *BackupRecordService) ListFiles(req dto.OperateByID) []string {
|
||||
var datas []string
|
||||
for _, file := range files {
|
||||
fileName := path.Base(file)
|
||||
if len(file) != 0 && (strings.HasPrefix(fileName, "1panel-v2.") || strings.HasPrefix(fileName, "snapshot-1panel-v2.")) {
|
||||
if len(file) != 0 && checkSnapshotIsOk(fileName) {
|
||||
datas = append(datas, path.Base(file))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func (u *BackupService) RedisBackup(req dto.CommonBackup) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func (u *BackupService) RedisBackup(req dto.CommonBackup) error {
|
||||
}
|
||||
|
||||
func (u *BackupService) RedisRecover(req dto.CommonRecover) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -76,6 +76,7 @@ func (u *BackupService) RedisRecover(req dto.CommonRecover) error {
|
||||
}
|
||||
|
||||
func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDir, fileName, secret, taskID string) error {
|
||||
|
||||
var (
|
||||
err error
|
||||
itemTask *task.Task
|
||||
@@ -102,7 +103,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi
|
||||
}
|
||||
|
||||
if strings.HasSuffix(fileName, ".tar.gz") {
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data/appendonlydir", global.Dir.AppInstallDir, "redis", redisInfo.Name)
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data/appendonlydir", global.Dir.AppInstallDir, redisInfo.Key, redisInfo.Name)
|
||||
if err := fileOp.TarGzCompressPro(true, redisDataDir, path.Join(backupDir, fileName), secret, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -111,14 +112,14 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi
|
||||
if strings.HasSuffix(fileName, ".aof") {
|
||||
stdout1, err := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/appendonly.aof %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
||||
if err != nil {
|
||||
return errors.New(string(stdout1))
|
||||
return errors.New(stdout1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
stdout1, err1 := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/dump.rdb %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
||||
if err1 != nil {
|
||||
return errors.New(string(stdout1))
|
||||
return errors.New(stdout1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -196,12 +197,12 @@ func handleRedisRecover(redisInfo *repo.RootInfo, parentTask *task.Task, recover
|
||||
}
|
||||
}()
|
||||
}
|
||||
composeDir := fmt.Sprintf("%s/redis/%s", global.Dir.AppInstallDir, redisInfo.Name)
|
||||
composeDir := fmt.Sprintf("%s/%s/%s", global.Dir.AppInstallDir, redisInfo.Key, redisInfo.Name)
|
||||
if _, err := compose.Down(composeDir + "/docker-compose.yml"); err != nil {
|
||||
return err
|
||||
}
|
||||
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "7.") {
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data", global.Dir.AppInstallDir, "redis", redisInfo.Name)
|
||||
redisDataDir := fmt.Sprintf("%s/%s/%s/data", global.Dir.AppInstallDir, redisInfo.Key, redisInfo.Name)
|
||||
if err := fileOp.TarGzExtractPro(recoverFile, redisDataDir, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+22
-24
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/alert_push"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -158,9 +159,10 @@ func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interfa
|
||||
AlertType: "clams",
|
||||
EntryID: datas[i].ID,
|
||||
}
|
||||
alertCount := xpack.GetAlert(alertBase)
|
||||
if alertCount != 0 {
|
||||
datas[i].AlertCount = alertCount
|
||||
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(alertBase.AlertType), alertRepo.WithByProject(strconv.Itoa(int(alertBase.EntryID))), repo.WithByStatus(constant.AlertEnable))
|
||||
datas[i].AlertMethod = alertInfo.Method
|
||||
if alertInfo.SendCount != 0 {
|
||||
datas[i].AlertCount = alertInfo.SendCount
|
||||
} else {
|
||||
datas[i].AlertCount = 0
|
||||
}
|
||||
@@ -191,13 +193,15 @@ func (c *ClamService) Create(req dto.ClamCreate) error {
|
||||
return err
|
||||
}
|
||||
if req.AlertCount != 0 {
|
||||
createAlert := dto.CreateOrUpdateAlert{
|
||||
AlertTitle: req.AlertTitle,
|
||||
AlertCount: req.AlertCount,
|
||||
AlertType: "clams",
|
||||
EntryID: clam.ID,
|
||||
createAlert := dto.AlertCreate{
|
||||
Title: req.AlertTitle,
|
||||
SendCount: req.AlertCount,
|
||||
Method: req.AlertMethod,
|
||||
Type: "clams",
|
||||
Project: strconv.Itoa(int(clam.ID)),
|
||||
Status: constant.AlertEnable,
|
||||
}
|
||||
err := xpack.CreateAlert(createAlert)
|
||||
err := NewIAlertService().CreateAlert(createAlert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -247,13 +251,14 @@ func (c *ClamService) Update(req dto.ClamUpdate) error {
|
||||
if err := clamRepo.Update(req.ID, upMap); err != nil {
|
||||
return err
|
||||
}
|
||||
updateAlert := dto.CreateOrUpdateAlert{
|
||||
AlertTitle: req.AlertTitle,
|
||||
AlertType: "clams",
|
||||
AlertCount: req.AlertCount,
|
||||
EntryID: clam.ID,
|
||||
updateAlert := dto.AlertCreate{
|
||||
Title: req.AlertTitle,
|
||||
SendCount: req.AlertCount,
|
||||
Method: req.AlertMethod,
|
||||
Type: "clams",
|
||||
Project: strconv.Itoa(int(clam.ID)),
|
||||
}
|
||||
err := xpack.UpdateAlert(updateAlert)
|
||||
err := NewIAlertService().ExternalUpdateAlert(updateAlert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -297,11 +302,7 @@ func (c *ClamService) Delete(req dto.ClamDelete) error {
|
||||
if err := clamRepo.Delete(repo.WithByID(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
alertBase := dto.AlertBase{
|
||||
AlertType: "clams",
|
||||
EntryID: clam.ID,
|
||||
}
|
||||
err := xpack.DeleteAlert(alertBase)
|
||||
err := alertRepo.Delete(alertRepo.WithByProject(strconv.Itoa(int(clam.ID))), alertRepo.WithByType("clams"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -639,10 +640,7 @@ func handleAlert(stdout, clamName string, clamId uint) {
|
||||
EntryID: clamId,
|
||||
Param: strconv.Itoa(infectedFiles),
|
||||
}
|
||||
err := xpack.PushAlert(pushAlert)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("clamdscan push failed, err: %v", err)
|
||||
}
|
||||
_ = alert_push.PushAlert(pushAlert)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
+184
-112
@@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -33,7 +34,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
@@ -52,7 +53,7 @@ type ContainerService struct{}
|
||||
|
||||
type IContainerService interface {
|
||||
Page(req dto.PageContainer) (int64, interface{}, error)
|
||||
List() []string
|
||||
List() []dto.ContainerOptions
|
||||
LoadStatus() (dto.ContainerStatus, error)
|
||||
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
ListNetwork() ([]dto.Options, error)
|
||||
@@ -61,7 +62,7 @@ type IContainerService interface {
|
||||
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
CreateCompose(req dto.ComposeCreate) error
|
||||
ComposeOperation(req dto.ComposeOperation) error
|
||||
ContainerCreate(req dto.ContainerOperate) error
|
||||
ContainerCreate(req dto.ContainerOperate, inThread bool) error
|
||||
ContainerCreateByCommand(req dto.ContainerCreateByCommand) error
|
||||
ContainerUpdate(req dto.ContainerOperate) error
|
||||
ContainerUpgrade(req dto.ContainerUpgrade) error
|
||||
@@ -83,7 +84,7 @@ type IContainerService interface {
|
||||
ComposeUpdate(req dto.ComposeUpdate) error
|
||||
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
|
||||
|
||||
LoadUsers(req dto.OperationWithName) ([]string, error)
|
||||
LoadUsers(req dto.OperationWithName) []string
|
||||
|
||||
StreamLogs(ctx *gin.Context, params dto.StreamLog)
|
||||
}
|
||||
@@ -94,8 +95,8 @@ func NewIContainerService() IContainerService {
|
||||
|
||||
func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, error) {
|
||||
var (
|
||||
records []types.Container
|
||||
list []types.Container
|
||||
records []container.Summary
|
||||
list []container.Summary
|
||||
)
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
@@ -165,7 +166,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
|
||||
total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
if start > total {
|
||||
records = make([]types.Container, 0)
|
||||
records = make([]container.Summary, 0)
|
||||
} else {
|
||||
if end >= total {
|
||||
end = total
|
||||
@@ -221,7 +222,8 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
return int64(total), backDatas, nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) List() []string {
|
||||
func (u *ContainerService) List() []dto.ContainerOptions {
|
||||
var options []dto.ContainerOptions
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load docker client for contianer list failed, err: %v", err)
|
||||
@@ -230,19 +232,18 @@ func (u *ContainerService) List() []string {
|
||||
defer client.Close()
|
||||
containers, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load contianer list failed, err: %v", err)
|
||||
global.LOG.Errorf("load container list failed, err: %v", err)
|
||||
return nil
|
||||
}
|
||||
var datas []string
|
||||
for _, container := range containers {
|
||||
for _, name := range container.Names {
|
||||
if len(name) != 0 {
|
||||
datas = append(datas, strings.TrimPrefix(name, "/"))
|
||||
options = append(options, dto.ContainerOptions{Name: strings.TrimPrefix(name, "/"), State: container.State})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return datas
|
||||
return options
|
||||
}
|
||||
|
||||
func (u *ContainerService) LoadStatus() (dto.ContainerStatus, error) {
|
||||
@@ -307,7 +308,7 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(list))
|
||||
for i := 0; i < len(list); i++ {
|
||||
go func(item types.Container) {
|
||||
go func(item container.Summary) {
|
||||
datas = append(datas, loadCpuAndMem(client, item.ID))
|
||||
wg.Done()
|
||||
}(list[i])
|
||||
@@ -466,7 +467,7 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
|
||||
report.DeletedNumber = len(rep.VolumesDeleted)
|
||||
report.SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
case "buildcache":
|
||||
opts := types.BuildCachePruneOptions{}
|
||||
opts := build.CachePruneOptions{}
|
||||
opts.All = true
|
||||
rep, err := client.BuildCachePrune(context.Background(), opts)
|
||||
if err != nil {
|
||||
@@ -495,7 +496,7 @@ func (u *ContainerService) LoadResourceLimit() (*dto.ResourceLimit, error) {
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
||||
func (u *ContainerService) ContainerCreate(req dto.ContainerOperate, inThread bool) error {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -513,63 +514,62 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
taskItem.AddSubTask(i18n.GetWithName("ContainerImagePull", req.Image), func(t *task.Task) error {
|
||||
if !checkImageExist(client, req.Image) || req.ForcePull {
|
||||
if err := pullImages(taskItem, client, req.Image); err != nil {
|
||||
if !req.ForcePull {
|
||||
return err
|
||||
}
|
||||
taskItem.AddSubTask(i18n.GetWithName("ContainerImagePull", req.Image), func(t *task.Task) error {
|
||||
if !checkImageExist(client, req.Image) || req.ForcePull {
|
||||
if err := pullImages(taskItem, client, req.Image); err != nil {
|
||||
if !req.ForcePull {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("ContainerImageCheck"), func(t *task.Task) error {
|
||||
imageInfo, _, err := client.ImageInspectWithRaw(ctx, req.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(req.Entrypoint) == 0 {
|
||||
req.Entrypoint = imageInfo.Config.Entrypoint
|
||||
}
|
||||
if len(req.Cmd) == 0 {
|
||||
req.Cmd = imageInfo.Config.Cmd
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
taskItem.AddSubTask(i18n.GetWithName("ContainerCreate", req.Name), func(t *task.Task) error {
|
||||
config, hostConf, networkConf, err := loadConfigInfo(true, req, nil)
|
||||
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerLoadInfo"), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
con, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
|
||||
if err != nil {
|
||||
taskItem.Log(i18n.GetMsgByKey("ContainerCreateFailed"))
|
||||
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
||||
return err
|
||||
}
|
||||
err = client.ContainerStart(ctx, con.ID, container.StartOptions{})
|
||||
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerStartCheck"), err)
|
||||
if err != nil {
|
||||
taskItem.Log(i18n.GetMsgByKey("ContainerCreateFailed"))
|
||||
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
||||
return fmt.Errorf("create successful but start failed, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
if err := taskItem.Execute(); err != nil {
|
||||
global.LOG.Error(err.Error())
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
return nil
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("ContainerImageCheck"), func(t *task.Task) error {
|
||||
imageInfo, _, err := client.ImageInspectWithRaw(ctx, req.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(req.Entrypoint) == 0 {
|
||||
req.Entrypoint = imageInfo.Config.Entrypoint
|
||||
}
|
||||
if len(req.Cmd) == 0 {
|
||||
req.Cmd = imageInfo.Config.Cmd
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
taskItem.AddSubTask(i18n.GetWithName("ContainerCreate", req.Name), func(t *task.Task) error {
|
||||
config, hostConf, networkConf, err := loadConfigInfo(true, req, nil)
|
||||
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerLoadInfo"), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
con, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
|
||||
if err != nil {
|
||||
taskItem.Log(i18n.GetMsgByKey("ContainerCreateFailed"))
|
||||
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
||||
return err
|
||||
}
|
||||
err = client.ContainerStart(ctx, con.ID, container.StartOptions{})
|
||||
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerStartCheck"), err)
|
||||
if err != nil {
|
||||
taskItem.Log(i18n.GetMsgByKey("ContainerCreateFailed"))
|
||||
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
||||
return fmt.Errorf("create successful but start failed, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
if inThread {
|
||||
go func() {
|
||||
if err := taskItem.Execute(); err != nil {
|
||||
global.LOG.Error(err.Error())
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
return taskItem.Execute()
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.ContainerOperate, error) {
|
||||
@@ -676,7 +676,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
||||
|
||||
taskItem.AddSubTask(i18n.GetWithName("ContainerCreate", req.Name), func(t *task.Task) error {
|
||||
err := client.ContainerRemove(ctx, req.ContainerID, container.RemoveOptions{Force: true})
|
||||
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerRemoveOld"), err)
|
||||
taskItem.LogWithStatus(i18n.GetWithName("ContainerRemoveOld", req.Name), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -752,7 +752,7 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
|
||||
}
|
||||
}
|
||||
err := client.ContainerRemove(ctx, req.Name, container.RemoveOptions{Force: true})
|
||||
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerRemoveOld"), err)
|
||||
taskItem.LogWithStatus(i18n.GetWithName("ContainerRemoveOld", req.Name), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -809,10 +809,23 @@ func (u *ContainerService) ContainerCommit(req dto.ContainerCommit) error {
|
||||
Pause: req.Pause,
|
||||
Config: nil,
|
||||
}
|
||||
_, err = client.ContainerCommit(ctx, req.ContainerId, options)
|
||||
|
||||
taskItem, err := task.NewTaskWithOps(req.NewImageName, task.TaskCommit, task.TaskScopeContainer, req.TaskID, 1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to commit container, err: %v", err)
|
||||
return fmt.Errorf("new task for container commit failed, err: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
taskItem.AddSubTask(i18n.GetWithName("TaskCommit", req.NewImageName), func(t *task.Task) error {
|
||||
res, err := client.ContainerCommit(ctx, req.ContainerId, options)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to commit container, err: %v", err)
|
||||
}
|
||||
taskItem.Log(res.ID)
|
||||
return nil
|
||||
}, nil)
|
||||
_ = taskItem.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -915,9 +928,6 @@ func collectLogs(done <-chan struct{}, params dto.StreamLog, messageChan chan<-
|
||||
defer close(messageChan)
|
||||
defer close(errorChan)
|
||||
var cmdArgs []string
|
||||
if params.Type == "compose" {
|
||||
cmdArgs = []string{"compose", "-f", params.Compose}
|
||||
}
|
||||
cmdArgs = append(cmdArgs, "logs")
|
||||
if params.Follow {
|
||||
cmdArgs = append(cmdArgs, "-f")
|
||||
@@ -932,7 +942,20 @@ func collectLogs(done <-chan struct{}, params dto.StreamLog, messageChan chan<-
|
||||
cmdArgs = append(cmdArgs, params.Container)
|
||||
}
|
||||
|
||||
dockerCmd := exec.Command("docker", cmdArgs...)
|
||||
var dockerCmd *exec.Cmd
|
||||
if params.Type == "compose" {
|
||||
dockerComposCmd := common.GetDockerComposeCommand()
|
||||
if dockerComposCmd == "docker-compose" {
|
||||
newCmdArgs := append([]string{"-f", params.Compose}, cmdArgs...)
|
||||
dockerCmd = exec.Command(dockerComposCmd, newCmdArgs...)
|
||||
} else {
|
||||
newCmdArgs := append([]string{"compose", "-f", params.Compose}, cmdArgs...)
|
||||
dockerCmd = exec.Command("docker", newCmdArgs...)
|
||||
}
|
||||
} else {
|
||||
dockerCmd = exec.Command("docker", cmdArgs...)
|
||||
}
|
||||
|
||||
dockerCmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
|
||||
stdout, err := dockerCmd.StdoutPipe()
|
||||
@@ -958,7 +981,7 @@ func collectLogs(done <-chan struct{}, params dto.StreamLog, messageChan chan<-
|
||||
}
|
||||
}()
|
||||
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
reader := bufio.NewReader(stdout)
|
||||
|
||||
processKilled := false
|
||||
go func() {
|
||||
@@ -972,19 +995,30 @@ func collectLogs(done <-chan struct{}, params dto.StreamLog, messageChan chan<-
|
||||
}
|
||||
}()
|
||||
|
||||
for scanner.Scan() {
|
||||
message := scanner.Text()
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if len(line) > 0 {
|
||||
line = strings.TrimSuffix(line, "\n")
|
||||
select {
|
||||
case messageChan <- line:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
errorChan <- fmt.Errorf("reader error: %v", err)
|
||||
return
|
||||
}
|
||||
line = strings.TrimSuffix(line, "\n")
|
||||
select {
|
||||
case messageChan <- message:
|
||||
case messageChan <- line:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = scanner.Err(); err != nil && err != io.EOF {
|
||||
errorChan <- fmt.Errorf("scanner error: %v", err)
|
||||
}
|
||||
|
||||
_ = dockerCmd.Wait()
|
||||
}
|
||||
|
||||
@@ -993,9 +1027,15 @@ func (u *ContainerService) DownloadContainerLogs(containerType, container, since
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
commandArg := []string{"logs", container}
|
||||
dockerCommand := global.CONF.DockerConfig.Command
|
||||
if containerType == "compose" {
|
||||
commandArg = []string{"compose", "-f", container, "logs"}
|
||||
if dockerCommand == "docker-compose" {
|
||||
commandArg = []string{"-f", container, "logs"}
|
||||
} else {
|
||||
commandArg = []string{"compose", "-f", container, "logs"}
|
||||
}
|
||||
}
|
||||
|
||||
if tail != "0" {
|
||||
commandArg = append(commandArg, "--tail")
|
||||
commandArg = append(commandArg, tail)
|
||||
@@ -1004,16 +1044,20 @@ func (u *ContainerService) DownloadContainerLogs(containerType, container, since
|
||||
commandArg = append(commandArg, "--since")
|
||||
commandArg = append(commandArg, since)
|
||||
}
|
||||
|
||||
cmd := exec.Command("docker", commandArg...)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
var dockerCmd *exec.Cmd
|
||||
if containerType == "compose" && dockerCommand == "docker-compose" {
|
||||
dockerCmd = exec.Command("docker-compose", commandArg...)
|
||||
} else {
|
||||
dockerCmd = exec.Command("docker", commandArg...)
|
||||
}
|
||||
stdout, err := dockerCmd.StdoutPipe()
|
||||
if err != nil {
|
||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
||||
_ = dockerCmd.Process.Signal(syscall.SIGTERM)
|
||||
return err
|
||||
}
|
||||
cmd.Stderr = cmd.Stdout
|
||||
if err := cmd.Start(); err != nil {
|
||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
||||
dockerCmd.Stderr = dockerCmd.Stdout
|
||||
if err := dockerCmd.Start(); err != nil {
|
||||
_ = dockerCmd.Process.Signal(syscall.SIGTERM)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1030,9 +1074,11 @@ func (u *ContainerService) DownloadContainerLogs(containerType, container, since
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;?]*[A-Za-z]|\x1b=|\x1b>`)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if _, err := tempFile.WriteString(line + "\n"); err != nil {
|
||||
cleanLine := ansiRegex.ReplaceAllString(line, "")
|
||||
if _, err := tempFile.WriteString(cleanLine + "\n"); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
@@ -1093,19 +1139,19 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) LoadUsers(req dto.OperationWithName) ([]string, error) {
|
||||
func (u *ContainerService) LoadUsers(req dto.OperationWithName) []string {
|
||||
var users []string
|
||||
std, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s cat /etc/passwd", req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return users
|
||||
}
|
||||
var users []string
|
||||
lines := strings.Split(string(std), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, ":") {
|
||||
users = append(users, strings.Split(line, ":")[0])
|
||||
}
|
||||
}
|
||||
return users, nil
|
||||
return users
|
||||
}
|
||||
|
||||
func stringsToMap(list []string) map[string]string {
|
||||
@@ -1194,6 +1240,32 @@ func checkImageExist(client *client.Client, imageItem string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func checkImageLike(client *client.Client, imageName string) bool {
|
||||
if client == nil {
|
||||
var err error
|
||||
client, err = docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
images, err := client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, img := range images {
|
||||
for _, tag := range img.RepoTags {
|
||||
parts := strings.Split(tag, "/")
|
||||
imageNameWithTag := parts[len(parts)-1]
|
||||
|
||||
if imageNameWithTag == imageName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func pullImages(task *task.Task, client *client.Client, imageName string) error {
|
||||
dockerCli := docker.NewClientWithExist(client)
|
||||
options := image.PullOptions{}
|
||||
@@ -1300,7 +1372,7 @@ func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {
|
||||
return portMap, nil
|
||||
}
|
||||
|
||||
func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types.ContainerJSON) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) {
|
||||
func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *container.InspectResponse) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) {
|
||||
var config container.Config
|
||||
var hostConf container.HostConfig
|
||||
if !isCreate {
|
||||
@@ -1383,7 +1455,7 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
|
||||
return &config, &hostConf, &networkConf, nil
|
||||
}
|
||||
|
||||
func reCreateAfterUpdate(name string, client *client.Client, config *container.Config, hostConf *container.HostConfig, networkConf *types.NetworkSettings) {
|
||||
func reCreateAfterUpdate(name string, client *client.Client, config *container.Config, hostConf *container.HostConfig, networkConf *container.NetworkSettings) {
|
||||
ctx := context.Background()
|
||||
|
||||
var oldNetworkConf network.NetworkingConfig
|
||||
@@ -1405,7 +1477,7 @@ func reCreateAfterUpdate(name string, client *client.Client, config *container.C
|
||||
global.LOG.Info("recreate after container update successful")
|
||||
}
|
||||
|
||||
func loadVolumeBinds(binds []types.MountPoint) []dto.VolumeHelper {
|
||||
func loadVolumeBinds(binds []container.MountPoint) []dto.VolumeHelper {
|
||||
var datas []dto.VolumeHelper
|
||||
for _, bind := range binds {
|
||||
var volumeItem dto.VolumeHelper
|
||||
@@ -1425,13 +1497,13 @@ func loadVolumeBinds(binds []types.MountPoint) []dto.VolumeHelper {
|
||||
return datas
|
||||
}
|
||||
|
||||
func loadPortByInspect(id string, client *client.Client) ([]types.Port, error) {
|
||||
container, err := client.ContainerInspect(context.Background(), id)
|
||||
func loadPortByInspect(id string, client *client.Client) ([]container.Port, error) {
|
||||
containerItem, err := client.ContainerInspect(context.Background(), id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var itemPorts []types.Port
|
||||
for key, val := range container.ContainerJSONBase.HostConfig.PortBindings {
|
||||
var itemPorts []container.Port
|
||||
for key, val := range containerItem.ContainerJSONBase.HostConfig.PortBindings {
|
||||
if !strings.Contains(string(key), "/") {
|
||||
continue
|
||||
}
|
||||
@@ -1440,15 +1512,15 @@ func loadPortByInspect(id string, client *client.Client) ([]types.Port, error) {
|
||||
|
||||
for _, itemVal := range val {
|
||||
publicPort, _ := strconv.ParseUint(itemVal.HostPort, 10, 16)
|
||||
itemPorts = append(itemPorts, types.Port{PrivatePort: uint16(itemPort), Type: item[1], PublicPort: uint16(publicPort), IP: itemVal.HostIP})
|
||||
itemPorts = append(itemPorts, container.Port{PrivatePort: uint16(itemPort), Type: item[1], PublicPort: uint16(publicPort), IP: itemVal.HostIP})
|
||||
}
|
||||
}
|
||||
return itemPorts, nil
|
||||
}
|
||||
func transPortToStr(ports []types.Port) []string {
|
||||
func transPortToStr(ports []container.Port) []string {
|
||||
var (
|
||||
ipv4Ports []types.Port
|
||||
ipv6Ports []types.Port
|
||||
ipv4Ports []container.Port
|
||||
ipv6Ports []container.Port
|
||||
)
|
||||
for _, port := range ports {
|
||||
if strings.Contains(port.IP, ":") {
|
||||
@@ -1461,7 +1533,7 @@ func transPortToStr(ports []types.Port) []string {
|
||||
list2 := simplifyPort(ipv6Ports)
|
||||
return append(list1, list2...)
|
||||
}
|
||||
func simplifyPort(ports []types.Port) []string {
|
||||
func simplifyPort(ports []container.Port) []string {
|
||||
var datas []string
|
||||
if len(ports) == 0 {
|
||||
return datas
|
||||
@@ -1557,7 +1629,7 @@ func loadComposeCount(client *client.Client) int {
|
||||
|
||||
return len(composeMap)
|
||||
}
|
||||
func loadContainerPortForInfo(itemPorts []types.Port) []dto.PortHelper {
|
||||
func loadContainerPortForInfo(itemPorts []container.Port) []dto.PortHelper {
|
||||
var exposedPorts []dto.PortHelper
|
||||
samePortMap := make(map[string]dto.PortHelper)
|
||||
ports := transPortToStr(itemPorts)
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -174,7 +173,7 @@ func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
|
||||
if err := newComposeEnv(req.Path, req.Env); err != nil {
|
||||
return false, err
|
||||
}
|
||||
cmd := exec.Command("docker", "compose", "-f", req.Path, "config")
|
||||
cmd := getComposeCmd(req.Path, "config")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return false, errors.New(string(stdout))
|
||||
@@ -201,7 +200,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
|
||||
}
|
||||
go func() {
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("ComposeCreate"), func(t *task.Task) error {
|
||||
cmd := exec.Command("docker", "compose", "-f", req.Path, "up", "-d")
|
||||
cmd := getComposeCmd(req.Path, "up")
|
||||
out, err := cmd.CombinedOutput()
|
||||
taskItem.Log(i18n.GetWithName("ComposeCreateRes", string(out)))
|
||||
if err != nil {
|
||||
|
||||
+339
-27
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -9,14 +10,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
|
||||
"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/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/robfig/cron/v3"
|
||||
@@ -37,6 +37,8 @@ type ICronjobService interface {
|
||||
StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error)
|
||||
CleanRecord(req dto.CronjobClean) error
|
||||
|
||||
Export(req dto.OperateByIDs) (string, error)
|
||||
Import(req []dto.CronjobTrans) error
|
||||
LoadScriptOptions() []dto.ScriptOptions
|
||||
|
||||
LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, error)
|
||||
@@ -67,12 +69,15 @@ func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interfac
|
||||
AlertType: cronjob.Type,
|
||||
EntryID: cronjob.ID,
|
||||
}
|
||||
alertCount := xpack.GetAlert(alertBase)
|
||||
if alertCount != 0 {
|
||||
item.AlertCount = alertCount
|
||||
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(alertBase.AlertType), alertRepo.WithByProject(strconv.Itoa(int(alertBase.EntryID))), repo.WithByStatus(constant.AlertEnable))
|
||||
if alertInfo.SendCount != 0 {
|
||||
item.AlertCount = alertInfo.SendCount
|
||||
} else {
|
||||
item.AlertCount = 0
|
||||
}
|
||||
if cronjob.Type == "snapshot" && len(cronjob.SnapshotRule) != 0 {
|
||||
_ = json.Unmarshal([]byte(cronjob.SnapshotRule), &item.SnapshotRule)
|
||||
}
|
||||
dtoCronjobs = append(dtoCronjobs, item)
|
||||
}
|
||||
return total, dtoCronjobs, err
|
||||
@@ -88,15 +93,303 @@ func (u *CronjobService) LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, err
|
||||
AlertType: cronjob.Type,
|
||||
EntryID: cronjob.ID,
|
||||
}
|
||||
alertCount := xpack.GetAlert(alertBase)
|
||||
if alertCount != 0 {
|
||||
item.AlertCount = alertCount
|
||||
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(alertBase.AlertType), alertRepo.WithByProject(strconv.Itoa(int(alertBase.EntryID))), repo.WithByStatus(constant.AlertEnable))
|
||||
item.AlertMethod = alertInfo.Method
|
||||
if alertInfo.SendCount != 0 {
|
||||
item.AlertCount = alertInfo.SendCount
|
||||
} else {
|
||||
item.AlertCount = 0
|
||||
}
|
||||
if cronjob.Type == "snapshot" && len(cronjob.SnapshotRule) != 0 {
|
||||
_ = json.Unmarshal([]byte(cronjob.SnapshotRule), &item.SnapshotRule)
|
||||
}
|
||||
return &item, err
|
||||
}
|
||||
|
||||
func (u *CronjobService) Export(req dto.OperateByIDs) (string, error) {
|
||||
cronjobs, err := cronjobRepo.List(repo.WithByIDs(req.IDs))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var data []dto.CronjobTrans
|
||||
for _, cronjob := range cronjobs {
|
||||
item := dto.CronjobTrans{
|
||||
Name: cronjob.Name,
|
||||
Type: cronjob.Type,
|
||||
SpecCustom: cronjob.SpecCustom,
|
||||
Spec: cronjob.Spec,
|
||||
Executor: cronjob.Executor,
|
||||
ScriptMode: cronjob.ScriptMode,
|
||||
Script: cronjob.Script,
|
||||
Command: cronjob.Command,
|
||||
ContainerName: cronjob.ContainerName,
|
||||
User: cronjob.User,
|
||||
URL: cronjob.URL,
|
||||
DBType: cronjob.DBType,
|
||||
ExclusionRules: cronjob.ExclusionRules,
|
||||
IsDir: cronjob.IsDir,
|
||||
SourceDir: cronjob.SourceDir,
|
||||
RetainCopies: cronjob.RetainCopies,
|
||||
RetryTimes: cronjob.RetryTimes,
|
||||
Timeout: cronjob.Timeout,
|
||||
IgnoreErr: cronjob.IgnoreErr,
|
||||
Secret: cronjob.Secret,
|
||||
}
|
||||
switch cronjob.Type {
|
||||
case "app":
|
||||
if cronjob.AppID == "all" {
|
||||
break
|
||||
}
|
||||
apps := loadAppsForJob(cronjob)
|
||||
for _, app := range apps {
|
||||
item.Apps = append(item.Apps, dto.TransHelper{Name: app.App.Key, DetailName: app.Name})
|
||||
}
|
||||
case "website", "cutWebsiteLog":
|
||||
if cronjob.Website == "all" {
|
||||
break
|
||||
}
|
||||
websites := loadWebsForJob(cronjob)
|
||||
for _, website := range websites {
|
||||
item.Websites = append(item.Websites, website.Alias)
|
||||
}
|
||||
case "database":
|
||||
if cronjob.DBName == "all" {
|
||||
break
|
||||
}
|
||||
databases := loadDbsForJob(cronjob)
|
||||
for _, db := range databases {
|
||||
item.DBNames = append(item.DBNames, dto.TransHelper{Name: db.Database, DetailName: db.Name})
|
||||
}
|
||||
case "shell":
|
||||
if cronjob.ScriptMode == "library" {
|
||||
script, err := scriptRepo.Get(repo.WithByID(cronjob.ScriptID))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
item.ScriptName = script.Name
|
||||
}
|
||||
case "snapshot":
|
||||
if len(cronjob.SnapshotRule) == 0 {
|
||||
break
|
||||
}
|
||||
var snapRule dto.SnapshotRule
|
||||
if err := json.Unmarshal([]byte(cronjob.SnapshotRule), &snapRule); err != nil {
|
||||
return "", err
|
||||
}
|
||||
item.SnapshotRule.WithImage = snapRule.WithImage
|
||||
if len(snapRule.IgnoreAppIDs) != 0 {
|
||||
ignoreApps, _ := appInstallRepo.ListBy(context.Background(), repo.WithByIDs(snapRule.IgnoreAppIDs))
|
||||
for _, app := range ignoreApps {
|
||||
item.SnapshotRule.IgnoreApps = append(item.SnapshotRule.IgnoreApps, dto.TransHelper{Name: app.App.Key, DetailName: app.Name})
|
||||
}
|
||||
}
|
||||
}
|
||||
item.SourceAccounts, item.DownloadAccount, _ = loadBackupNamesByID(cronjob.SourceAccountIDs, cronjob.DownloadAccountID)
|
||||
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(cronjob.Type), alertRepo.WithByProject(strconv.Itoa(int(cronjob.ID))), repo.WithByStatus(constant.AlertEnable))
|
||||
if alertInfo.SendCount != 0 {
|
||||
item.AlertCount = alertInfo.SendCount
|
||||
item.AlertTitle = alertInfo.Title
|
||||
item.AlertMethod = alertInfo.Method
|
||||
} else {
|
||||
item.AlertCount = 0
|
||||
}
|
||||
data = append(data, item)
|
||||
}
|
||||
itemJson, err := json.Marshal(&data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(itemJson), nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) Import(req []dto.CronjobTrans) error {
|
||||
for _, item := range req {
|
||||
cronjobItem, _ := cronjobRepo.Get(repo.WithByName(item.Name))
|
||||
if cronjobItem.ID != 0 {
|
||||
continue
|
||||
}
|
||||
cronjob := model.Cronjob{
|
||||
Name: item.Name,
|
||||
Type: item.Type,
|
||||
SpecCustom: item.SpecCustom,
|
||||
Spec: item.Spec,
|
||||
Executor: item.Executor,
|
||||
ScriptMode: item.ScriptMode,
|
||||
Command: item.Command,
|
||||
ContainerName: item.ContainerName,
|
||||
User: item.User,
|
||||
URL: item.URL,
|
||||
DBType: item.DBType,
|
||||
ExclusionRules: item.ExclusionRules,
|
||||
IsDir: item.IsDir,
|
||||
RetainCopies: item.RetainCopies,
|
||||
RetryTimes: item.RetryTimes,
|
||||
Timeout: item.Timeout,
|
||||
IgnoreErr: item.IgnoreErr,
|
||||
Secret: item.Secret,
|
||||
}
|
||||
hasNotFound := false
|
||||
switch item.Type {
|
||||
case "app":
|
||||
if len(item.Apps) == 0 {
|
||||
cronjob.AppID = "all"
|
||||
break
|
||||
}
|
||||
var appIDs []string
|
||||
for _, app := range item.Apps {
|
||||
appItem, err := appInstallRepo.LoadInstallAppByKeyAndName(app.Name, app.DetailName)
|
||||
if err != nil {
|
||||
hasNotFound = true
|
||||
continue
|
||||
}
|
||||
appIDs = append(appIDs, fmt.Sprintf("%v", appItem.ID))
|
||||
}
|
||||
cronjob.AppID = strings.Join(appIDs, ",")
|
||||
case "website", "cutWebsiteLog":
|
||||
if len(item.Websites) == 0 {
|
||||
cronjob.Website = "all"
|
||||
break
|
||||
}
|
||||
var webIDs []string
|
||||
for _, web := range item.Websites {
|
||||
webItem, err := websiteRepo.GetFirst(websiteRepo.WithAlias(web))
|
||||
if err != nil {
|
||||
hasNotFound = true
|
||||
continue
|
||||
}
|
||||
webIDs = append(webIDs, fmt.Sprintf("%v", webItem.ID))
|
||||
}
|
||||
cronjob.Website = strings.Join(webIDs, ",")
|
||||
case "database":
|
||||
if len(item.DBNames) == 0 {
|
||||
cronjob.DBName = "all"
|
||||
break
|
||||
}
|
||||
var dbIDs []string
|
||||
if strings.Contains(cronjob.DBType, "postgresql") {
|
||||
for _, db := range item.DBNames {
|
||||
dbItem, err := postgresqlRepo.Get(postgresqlRepo.WithByPostgresqlName(db.Name), repo.WithByName(db.DetailName))
|
||||
if err != nil {
|
||||
hasNotFound = true
|
||||
continue
|
||||
}
|
||||
dbIDs = append(dbIDs, fmt.Sprintf("%v", dbItem.ID))
|
||||
}
|
||||
} else {
|
||||
for _, db := range item.DBNames {
|
||||
dbItem, err := mysqlRepo.Get(mysqlRepo.WithByMysqlName(db.Name), repo.WithByName(db.DetailName))
|
||||
if err != nil {
|
||||
hasNotFound = true
|
||||
continue
|
||||
}
|
||||
dbIDs = append(dbIDs, fmt.Sprintf("%v", dbItem.ID))
|
||||
}
|
||||
}
|
||||
cronjob.DBName = strings.Join(dbIDs, ",")
|
||||
case "shell":
|
||||
if len(item.ContainerName) != 0 {
|
||||
cronjob.Script = item.Script
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
hasNotFound = true
|
||||
break
|
||||
}
|
||||
defer client.Close()
|
||||
if _, err := client.ContainerStats(context.Background(), item.ContainerName, false); err != nil {
|
||||
hasNotFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
switch item.ScriptMode {
|
||||
case "library":
|
||||
library, _ := scriptRepo.Get(repo.WithByName(item.ScriptName))
|
||||
if library.ID == 0 {
|
||||
hasNotFound = true
|
||||
break
|
||||
}
|
||||
cronjob.ScriptID = library.ID
|
||||
case "select":
|
||||
if _, err := os.Stat(item.Script); err != nil {
|
||||
hasNotFound = true
|
||||
break
|
||||
}
|
||||
cronjob.Script = item.Script
|
||||
case "input":
|
||||
cronjob.Script = item.Script
|
||||
}
|
||||
case "directory":
|
||||
if item.IsDir {
|
||||
if _, err := os.Stat(item.SourceDir); err != nil {
|
||||
hasNotFound = true
|
||||
break
|
||||
}
|
||||
cronjob.SourceDir = item.SourceDir
|
||||
} else {
|
||||
fileList := strings.Split(item.SourceDir, ",")
|
||||
var newFiles []string
|
||||
for _, item := range fileList {
|
||||
if len(item) == 0 {
|
||||
continue
|
||||
}
|
||||
if _, err := os.Stat(item); err != nil {
|
||||
hasNotFound = true
|
||||
continue
|
||||
}
|
||||
newFiles = append(newFiles, item)
|
||||
}
|
||||
cronjob.SourceDir = strings.Join(newFiles, ",")
|
||||
}
|
||||
case "snapshot":
|
||||
if len(item.SnapshotRule.IgnoreApps) == 0 && !item.SnapshotRule.WithImage {
|
||||
break
|
||||
}
|
||||
var itemRules dto.SnapshotRule
|
||||
itemRules.WithImage = item.SnapshotRule.WithImage
|
||||
for _, app := range item.SnapshotRule.IgnoreApps {
|
||||
appItem, err := appInstallRepo.LoadInstallAppByKeyAndName(app.Name, app.DetailName)
|
||||
if err != nil {
|
||||
hasNotFound = true
|
||||
continue
|
||||
}
|
||||
itemRules.IgnoreAppIDs = append(itemRules.IgnoreAppIDs, appItem.ID)
|
||||
}
|
||||
itemRulesStr, _ := json.Marshal(itemRules)
|
||||
cronjob.SnapshotRule = string(itemRulesStr)
|
||||
}
|
||||
var acIDs []string
|
||||
for _, ac := range item.SourceAccounts {
|
||||
backup, err := backupRepo.Get(repo.WithByName(ac))
|
||||
if err != nil {
|
||||
hasNotFound = true
|
||||
continue
|
||||
}
|
||||
if ac == item.DownloadAccount {
|
||||
cronjob.DownloadAccountID = backup.ID
|
||||
}
|
||||
acIDs = append(acIDs, fmt.Sprintf("%v", backup.ID))
|
||||
}
|
||||
cronjob.SourceAccountIDs = strings.Join(acIDs, ",")
|
||||
if hasNotFound {
|
||||
cronjob.Status = constant.StatusPending
|
||||
} else {
|
||||
cronjob.Status = constant.StatusDisable
|
||||
}
|
||||
_ = cronjobRepo.Create(&cronjob)
|
||||
if item.AlertCount != 0 {
|
||||
createAlert := dto.AlertCreate{
|
||||
Title: item.AlertTitle,
|
||||
SendCount: item.AlertCount,
|
||||
Method: item.AlertMethod,
|
||||
Type: cronjob.Type,
|
||||
Project: strconv.Itoa(int(cronjob.ID)),
|
||||
Status: constant.AlertEnable,
|
||||
}
|
||||
_ = NewIAlertService().CreateAlert(createAlert)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) LoadScriptOptions() []dto.ScriptOptions {
|
||||
scripts, err := scriptRepo.List()
|
||||
if err != nil {
|
||||
@@ -279,6 +572,13 @@ func (u *CronjobService) Create(req dto.CronjobOperate) error {
|
||||
if err := copier.Copy(&cronjob, &req); err != nil {
|
||||
return buserr.WithDetail("ErrStructTransform", err.Error(), nil)
|
||||
}
|
||||
if cronjob.Type == "snapshot" {
|
||||
rule, err := json.Marshal(req.SnapshotRule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cronjob.SnapshotRule = string(rule)
|
||||
}
|
||||
if cronjob.Type == "cutWebsiteLog" {
|
||||
backupAccount, err := backupRepo.Get(repo.WithByType(constant.Local))
|
||||
if backupAccount.ID == 0 {
|
||||
@@ -300,13 +600,15 @@ func (u *CronjobService) Create(req dto.CronjobOperate) error {
|
||||
return err
|
||||
}
|
||||
if req.AlertCount != 0 {
|
||||
createAlert := dto.CreateOrUpdateAlert{
|
||||
AlertTitle: req.AlertTitle,
|
||||
AlertCount: req.AlertCount,
|
||||
AlertType: cronjob.Type,
|
||||
EntryID: cronjob.ID,
|
||||
createAlert := dto.AlertCreate{
|
||||
Title: req.AlertTitle,
|
||||
SendCount: req.AlertCount,
|
||||
Method: req.AlertMethod,
|
||||
Type: cronjob.Type,
|
||||
Project: strconv.Itoa(int(cronjob.ID)),
|
||||
Status: constant.AlertEnable,
|
||||
}
|
||||
err := xpack.CreateAlert(createAlert)
|
||||
err := NewIAlertService().CreateAlert(createAlert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -354,11 +656,7 @@ func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||
if err := cronjobRepo.Delete(repo.WithByID(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
alertBase := dto.AlertBase{
|
||||
AlertType: cronjob.Type,
|
||||
EntryID: cronjob.ID,
|
||||
}
|
||||
err := xpack.DeleteAlert(alertBase)
|
||||
err := alertRepo.Delete(alertRepo.WithByProject(strconv.Itoa(int(cronjob.ID))), alertRepo.WithByType(cronjob.Type))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -372,6 +670,13 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
||||
if err := copier.Copy(&cronjob, &req); err != nil {
|
||||
return buserr.WithDetail("ErrStructTransform", err.Error(), nil)
|
||||
}
|
||||
if req.Type == "snapshot" {
|
||||
itemRule, err := json.Marshal(req.SnapshotRule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cronjob.SnapshotRule = string(itemRule)
|
||||
}
|
||||
cronModel, err := cronjobRepo.Get(repo.WithByID(id))
|
||||
if err != nil {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
@@ -394,6 +699,9 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
||||
}
|
||||
}
|
||||
|
||||
if cronModel.Status == constant.StatusPending {
|
||||
upMap["status"] = constant.StatusEnable
|
||||
}
|
||||
upMap["name"] = req.Name
|
||||
upMap["spec_custom"] = req.SpecCustom
|
||||
upMap["spec"] = spec
|
||||
@@ -411,25 +719,29 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
||||
upMap["db_type"] = req.DBType
|
||||
upMap["db_name"] = req.DBName
|
||||
upMap["url"] = req.URL
|
||||
upMap["is_dir"] = req.IsDir
|
||||
upMap["source_dir"] = req.SourceDir
|
||||
upMap["snapshot_rule"] = cronjob.SnapshotRule
|
||||
|
||||
upMap["source_account_ids"] = req.SourceAccountIDs
|
||||
upMap["download_account_id"] = req.DownloadAccountID
|
||||
upMap["retain_copies"] = req.RetainCopies
|
||||
upMap["retry_times"] = req.RetryTimes
|
||||
upMap["timeout"] = req.Timeout
|
||||
upMap["ignore_err"] = req.IgnoreErr
|
||||
upMap["secret"] = req.Secret
|
||||
err = cronjobRepo.Update(id, upMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateAlert := dto.CreateOrUpdateAlert{
|
||||
AlertTitle: req.AlertTitle,
|
||||
AlertType: cronModel.Type,
|
||||
AlertCount: req.AlertCount,
|
||||
EntryID: cronModel.ID,
|
||||
updateAlert := dto.AlertCreate{
|
||||
Title: req.AlertTitle,
|
||||
SendCount: req.AlertCount,
|
||||
Method: req.AlertMethod,
|
||||
Type: cronjob.Type,
|
||||
Project: strconv.Itoa(int(cronModel.ID)),
|
||||
}
|
||||
err = xpack.UpdateAlert(updateAlert)
|
||||
err = NewIAlertService().ExternalUpdateAlert(updateAlert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -23,22 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, taskItem *task.Task) error {
|
||||
var apps []model.AppInstall
|
||||
if cronjob.AppID == "all" {
|
||||
apps, _ = appInstallRepo.ListBy(context.Background())
|
||||
} else {
|
||||
appIds := strings.Split(cronjob.AppID, ",")
|
||||
var idItems []uint
|
||||
for i := 0; i < len(appIds); i++ {
|
||||
itemID, _ := strconv.Atoi(appIds[i])
|
||||
idItems = append(idItems, uint(itemID))
|
||||
}
|
||||
appItems, err := appInstallRepo.ListBy(context.Background(), repo.WithByIDs(idItems))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apps = appItems
|
||||
}
|
||||
apps := loadAppsForJob(cronjob)
|
||||
if len(apps) == 0 {
|
||||
return errors.New("no such app in database!")
|
||||
}
|
||||
@@ -47,6 +34,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t
|
||||
return err
|
||||
}
|
||||
for _, app := range apps {
|
||||
retry := 0
|
||||
taskItem.AddSubTaskWithOps(task.GetTaskName(app.Name, task.TaskBackup, task.TaskScopeCronjob), func(task *task.Task) error {
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
@@ -55,14 +43,25 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t
|
||||
record.Name = app.App.Key
|
||||
record.DetailName = app.Name
|
||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
||||
backupDir := path.Join(global.Dir.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
||||
backupDir := path.Join(global.Dir.LocalBackupDir, fmt.Sprintf("tmp/app/%s/%s", app.App.Key, app.Name))
|
||||
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
if err := doAppBackup(&app, task, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||
return err
|
||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||
retry++
|
||||
return err
|
||||
} else {
|
||||
task.Log(i18n.GetMsgWithDetail("IgnoreBackupErr", err.Error()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(backupDir, record.FileName))
|
||||
if err != nil {
|
||||
return err
|
||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||
retry++
|
||||
return err
|
||||
}
|
||||
task.Log(i18n.GetMsgWithDetail("IgnoreUploadErr", err.Error()))
|
||||
return nil
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
@@ -86,6 +85,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||
return err
|
||||
}
|
||||
for _, web := range webs {
|
||||
retry := 0
|
||||
taskItem.AddSubTaskWithOps(task.GetTaskName(web.Alias, task.TaskBackup, task.TaskScopeCronjob), func(task *task.Task) error {
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
@@ -94,16 +94,27 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||
record.Name = web.Alias
|
||||
record.DetailName = web.Alias
|
||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
||||
backupDir := path.Join(global.Dir.TmpDir, fmt.Sprintf("website/%s", web.Alias))
|
||||
backupDir := path.Join(global.Dir.LocalBackupDir, fmt.Sprintf("tmp/website/%s", web.Alias))
|
||||
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.Alias, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
|
||||
if err := doWebsiteBackup(&web, taskItem, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||
return err
|
||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||
retry++
|
||||
return err
|
||||
} else {
|
||||
task.Log(i18n.GetMsgWithDetail("IgnoreBackupErr", err.Error()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(backupDir, record.FileName))
|
||||
if err != nil {
|
||||
return err
|
||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||
retry++
|
||||
return err
|
||||
}
|
||||
task.Log(i18n.GetMsgWithDetail("IgnoreUploadErr", err.Error()))
|
||||
return nil
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
@@ -127,6 +138,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
|
||||
return err
|
||||
}
|
||||
for _, dbInfo := range dbs {
|
||||
retry := 0
|
||||
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
|
||||
@@ -137,21 +149,38 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
|
||||
record.DetailName = dbInfo.Name
|
||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
||||
|
||||
backupDir := path.Join(global.Dir.TmpDir, fmt.Sprintf("database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name))
|
||||
backupDir := path.Join(global.Dir.LocalBackupDir, fmt.Sprintf("tmp/database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name))
|
||||
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" || cronjob.DBType == "mysql-cluster" {
|
||||
if err := doMysqlBackup(dbInfo, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||
retry++
|
||||
return err
|
||||
} else {
|
||||
task.Log(i18n.GetMsgWithDetail("IgnoreBackupErr", err.Error()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := doPostgresqlgBackup(dbInfo, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||
retry++
|
||||
return err
|
||||
} else {
|
||||
task.Log(i18n.GetMsgWithDetail("IgnoreBackupErr", err.Error()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, task, accountMap, path.Join(backupDir, record.FileName))
|
||||
if err != nil {
|
||||
return err
|
||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||
retry++
|
||||
return err
|
||||
}
|
||||
task.Log(i18n.GetMsgWithDetail("IgnoreUploadErr", err.Error()))
|
||||
return nil
|
||||
}
|
||||
record.FileDir = path.Dir(downloadPath)
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
@@ -171,8 +200,11 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileName := fmt.Sprintf("%s.tar.gz", startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||
backupDir := path.Join(global.Dir.TmpDir, fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name))
|
||||
fileName := fmt.Sprintf("%s.tar.gz", startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(2))
|
||||
if cronjob.IsDir || len(strings.Split(cronjob.SourceDir, ",")) == 1 {
|
||||
fileName = loadFileName(cronjob.SourceDir)
|
||||
}
|
||||
backupDir := path.Join(global.Dir.LocalBackupDir, fmt.Sprintf("tmp/%s/%s", cronjob.Type, cronjob.Name))
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
if cronjob.IsDir {
|
||||
@@ -218,7 +250,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
|
||||
}
|
||||
nameItem := startTime.Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
|
||||
fileName := fmt.Sprintf("system_log_%s.tar.gz", nameItem)
|
||||
backupDir := path.Join(global.Dir.TmpDir, "log", nameItem)
|
||||
backupDir := path.Join(global.Dir.LocalBackupDir, "tmp/log", nameItem)
|
||||
if err := handleBackupLogs(taskItem, backupDir, fileName, cronjob.Secret); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -250,10 +282,6 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, jobRecord model.J
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
itemData, err := NewISnapshotService().LoadSnapshotData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var record model.BackupRecord
|
||||
record.From = "cronjob"
|
||||
@@ -268,6 +296,11 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, jobRecord model.J
|
||||
if !global.IsMaster {
|
||||
scope = "agent"
|
||||
}
|
||||
|
||||
itemData, err := loadSnapWithRule(cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := dto.SnapshotCreate{
|
||||
Name: fmt.Sprintf("snapshot-1panel-%s-%s-linux-%s-%s", scope, versionItem.Value, loadOs(), jobRecord.StartTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5)),
|
||||
Secret: cronjob.Secret,
|
||||
@@ -278,11 +311,13 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, jobRecord model.J
|
||||
AppData: itemData.AppData,
|
||||
PanelData: itemData.PanelData,
|
||||
BackupData: itemData.BackupData,
|
||||
WithDockerConf: true,
|
||||
WithMonitorData: true,
|
||||
WithLoginLog: true,
|
||||
WithOperationLog: true,
|
||||
WithSystemLog: true,
|
||||
WithTaskLog: true,
|
||||
IgnoreFiles: strings.Split(cronjob.ExclusionRules, ","),
|
||||
}
|
||||
|
||||
if err := NewISnapshotService().SnapshotCreate(taskItem, req, jobRecord.ID, cronjob.RetryTimes, cronjob.Timeout); err != nil {
|
||||
@@ -298,6 +333,23 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, jobRecord model.J
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadAppsForJob(cronjob model.Cronjob) []model.AppInstall {
|
||||
var apps []model.AppInstall
|
||||
if cronjob.AppID == "all" {
|
||||
apps, _ = appInstallRepo.ListBy(context.Background())
|
||||
} else {
|
||||
appIds := strings.Split(cronjob.AppID, ",")
|
||||
var idItems []uint
|
||||
for i := 0; i < len(appIds); i++ {
|
||||
itemID, _ := strconv.Atoi(appIds[i])
|
||||
idItems = append(idItems, uint(itemID))
|
||||
}
|
||||
appItems, _ := appInstallRepo.ListBy(context.Background(), repo.WithByIDs(idItems))
|
||||
apps = appItems
|
||||
}
|
||||
return apps
|
||||
}
|
||||
|
||||
type DatabaseHelper struct {
|
||||
ID uint
|
||||
DBType string
|
||||
@@ -308,7 +360,7 @@ type DatabaseHelper struct {
|
||||
func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
var dbs []DatabaseHelper
|
||||
if cronjob.DBName == "all" {
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" || cronjob.DBType == "mysql-cluster" {
|
||||
databaseService := NewIDatabaseService()
|
||||
mysqlItems, _ := databaseService.LoadItems(cronjob.DBType)
|
||||
for _, mysql := range mysqlItems {
|
||||
@@ -335,7 +387,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
dbNames := strings.Split(cronjob.DBName, ",")
|
||||
for _, name := range dbNames {
|
||||
itemID, _ := strconv.Atoi(name)
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" || cronjob.DBType == "mysql-cluster" {
|
||||
mysqlItem, _ := mysqlRepo.Get(repo.WithByID(uint(itemID)))
|
||||
dbs = append(dbs, DatabaseHelper{
|
||||
ID: mysqlItem.ID,
|
||||
@@ -397,7 +449,7 @@ func handleBackupLogs(taskItem *task.Task, targetDir, fileName string, secret st
|
||||
}
|
||||
}
|
||||
}
|
||||
itemDir2 := path.Join(global.Dir.LocalBackupDir, "log/website", website.Alias)
|
||||
itemDir2 := path.Join(global.Dir.LocalBackupDir, "tmp/log/website", website.Alias)
|
||||
logFiles2, _ := os.ReadDir(itemDir2)
|
||||
if len(logFiles2) != 0 {
|
||||
for i := 0; i < len(logFiles2); i++ {
|
||||
@@ -451,3 +503,63 @@ func handleBackupLogs(taskItem *task.Task, targetDir, fileName string, secret st
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadSnapWithRule(cronjob model.Cronjob) (dto.SnapshotData, error) {
|
||||
itemData, err := NewISnapshotService().LoadSnapshotData()
|
||||
if err != nil {
|
||||
return itemData, err
|
||||
}
|
||||
|
||||
if len(cronjob.SnapshotRule) == 0 {
|
||||
return itemData, nil
|
||||
}
|
||||
var snapRule dto.SnapshotRule
|
||||
if err := json.Unmarshal([]byte(cronjob.SnapshotRule), &snapRule); err != nil {
|
||||
return itemData, err
|
||||
}
|
||||
if len(snapRule.IgnoreAppIDs) == 0 && !snapRule.WithImage {
|
||||
return itemData, nil
|
||||
}
|
||||
|
||||
var ignoreApps []model.AppInstall
|
||||
if len(snapRule.IgnoreAppIDs) != 0 {
|
||||
ignoreApps, _ = appInstallRepo.ListBy(context.Background(), repo.WithByIDs(snapRule.IgnoreAppIDs))
|
||||
}
|
||||
if len(ignoreApps) == 0 && !snapRule.WithImage {
|
||||
return itemData, nil
|
||||
}
|
||||
for i := 0; i < len(itemData.AppData); i++ {
|
||||
isIgnore := false
|
||||
for _, ignore := range ignoreApps {
|
||||
if ignore.App.Key == itemData.AppData[i].Key && ignore.Name == itemData.AppData[i].Name {
|
||||
isIgnore = true
|
||||
itemData.AppData[i].IsCheck = false
|
||||
for j := 0; j < len(itemData.AppData[i].Children); j++ {
|
||||
if itemData.AppData[i].Children[j].Label == "appData" {
|
||||
itemData.AppData[i].Children[j].IsCheck = false
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if snapRule.WithImage && !isIgnore {
|
||||
for j := 0; j < len(itemData.AppData[i].Children); j++ {
|
||||
if itemData.AppData[i].Children[j].Label == "appImage" {
|
||||
itemData.AppData[i].Children[j].IsCheck = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return itemData, nil
|
||||
}
|
||||
|
||||
func loadFileName(src string) string {
|
||||
dirs := strings.Split(filepath.ToSlash(src), "/")
|
||||
var keyPart string
|
||||
if len(dirs) >= 3 {
|
||||
keyPart = filepath.Join(dirs[len(dirs)-3], dirs[len(dirs)-2], dirs[len(dirs)-1])
|
||||
}
|
||||
cleanName := strings.ReplaceAll(keyPart, string(filepath.Separator), "_")
|
||||
timestamp := time.Now().Format(constant.DateTimeSlimLayout)
|
||||
return fmt.Sprintf("%s_%s_%s.tar.gz", cleanName, timestamp, common.RandStrAndNum(2))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/alert_push"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
@@ -19,7 +21,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ntp"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
)
|
||||
|
||||
func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
@@ -48,6 +49,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
global.LOG.Debugf("preper to handle cron job [%s] %s failed, err: %v", cronjob.Type, cronjob.Name, err)
|
||||
record.TaskID = ""
|
||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), record.Records)
|
||||
handleCronJobAlert(cronjob)
|
||||
return
|
||||
}
|
||||
if err := taskItem.Execute(); err != nil {
|
||||
@@ -268,9 +270,13 @@ func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, task *task
|
||||
}()
|
||||
var errItem error
|
||||
accounts := strings.Split(cronjob.SourceAccountIDs, ",")
|
||||
cloudSrc := strings.TrimPrefix(file, global.Dir.TmpDir+"/")
|
||||
cloudSrc := strings.TrimPrefix(file, global.Dir.LocalBackupDir+"/tmp/")
|
||||
for _, account := range accounts {
|
||||
if len(account) != 0 {
|
||||
task.LogStart(i18n.GetMsgWithMap("UploadFile", map[string]interface{}{
|
||||
"file": pathUtils.Join(accountMap[account].backupPath, cloudSrc),
|
||||
"backup": accountMap[account].name,
|
||||
}))
|
||||
_, err := accountMap[account].client.Upload(file, pathUtils.Join(accountMap[account].backupPath, cloudSrc))
|
||||
task.LogWithStatus(
|
||||
i18n.GetMsgWithMap("UploadFile", map[string]interface{}{
|
||||
@@ -355,9 +361,5 @@ func handleCronJobAlert(cronjob *model.Cronjob) {
|
||||
EntryID: cronjob.ID,
|
||||
Param: cronjob.Type,
|
||||
}
|
||||
err := xpack.PushAlert(pushAlert)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("cronjob alert push failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
_ = alert_push.PushAlert(pushAlert)
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func (u *DashboardService) LoadCurrentInfoForNode() *dto.NodeCurrent {
|
||||
memoryInfo, _ := mem.VirtualMemory()
|
||||
currentInfo.MemoryTotal = memoryInfo.Total
|
||||
currentInfo.MemoryAvailable = memoryInfo.Available
|
||||
currentInfo.MemoryUsed = memoryInfo.Used
|
||||
currentInfo.MemoryUsed = memoryInfo.Used + memoryInfo.Shared
|
||||
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
||||
|
||||
swapInfo, _ := mem.SwapMemory()
|
||||
@@ -210,8 +210,11 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
|
||||
memoryInfo, _ := mem.VirtualMemory()
|
||||
currentInfo.MemoryTotal = memoryInfo.Total
|
||||
currentInfo.MemoryUsed = memoryInfo.Used + memoryInfo.Shared
|
||||
currentInfo.MemoryFree = memoryInfo.Free
|
||||
currentInfo.MemoryCache = memoryInfo.Cached + memoryInfo.Buffers
|
||||
currentInfo.MemoryShard = memoryInfo.Shared
|
||||
currentInfo.MemoryAvailable = memoryInfo.Available
|
||||
currentInfo.MemoryUsed = memoryInfo.Used
|
||||
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
||||
|
||||
swapInfo, _ := mem.SwapMemory()
|
||||
@@ -390,10 +393,10 @@ type diskInfo struct {
|
||||
func loadDiskInfo() []dto.DiskInfo {
|
||||
var datas []dto.DiskInfo
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(2 * time.Second))
|
||||
stdout, err := cmdMgr.RunWithStdoutBashC("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")
|
||||
stdout, err := cmdMgr.RunWithStdoutBashC("timeout 2 df -hT -P | awk 'NR>1 && !/tmpfs|snap\\/core|udev/ {print}'")
|
||||
if err != nil {
|
||||
cmdMgr2 := cmd.NewCommandMgr(cmd.WithTimeout(1 * time.Second))
|
||||
stdout, err = cmdMgr2.RunWithStdoutBashC("df -lhT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")
|
||||
stdout, err = cmdMgr2.RunWithStdoutBashC("timeout 1 df -lhT -P | awk 'NR>1 && !/tmpfs|snap\\/core|udev/ {print}'")
|
||||
if err != nil {
|
||||
return datas
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func (u *DatabaseService) LoadItems(dbType string) ([]dto.DatabaseItem, error) {
|
||||
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
|
||||
var datas []dto.DatabaseItem
|
||||
for _, db := range dbs {
|
||||
if dbType == "postgresql" {
|
||||
if dbType == constant.AppPostgresql || dbType == constant.AppPostgresqlCluster {
|
||||
items, _ := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(db.Name))
|
||||
for _, item := range items {
|
||||
var dItem dto.DatabaseItem
|
||||
|
||||
@@ -34,7 +34,7 @@ func (u *DBCommonService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.D
|
||||
}
|
||||
data.ContainerName = app.ContainerName
|
||||
data.Name = app.Name
|
||||
data.Port = int64(app.Port)
|
||||
data.Port = app.Port
|
||||
|
||||
return &data, nil
|
||||
}
|
||||
@@ -42,6 +42,10 @@ func (u *DBCommonService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.D
|
||||
func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
|
||||
filePath := ""
|
||||
switch req.Type {
|
||||
case "mysql-cluster-conf":
|
||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql-cluster/%s/conf/my.cnf", req.Name))
|
||||
case "postgresql-cluster-conf":
|
||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/postgresql-cluster/%s/data/postgresql.conf", req.Name))
|
||||
case "mysql-conf":
|
||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
|
||||
case "mariadb-conf":
|
||||
@@ -50,6 +54,8 @@ func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (st
|
||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
|
||||
case "redis-conf":
|
||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
|
||||
case "redis-cluster-conf":
|
||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/redis-cluster/%s/conf/redis.conf", req.Name))
|
||||
}
|
||||
if _, err := os.Stat(filePath); err != nil {
|
||||
return "", buserr.New("ErrHttpReqNotFound")
|
||||
|
||||
@@ -534,7 +534,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
info.File = "OFF"
|
||||
info.Position = "OFF"
|
||||
masterStatus := "show master status;"
|
||||
if common.CompareAppVersion(app.Version, "8.4.0") && req.Type == constant.AppMysql {
|
||||
if common.CompareAppVersion(app.Version, "8.4.0") && (req.Type == constant.AppMysql || req.Type == constant.AppMysqlCluster) {
|
||||
masterStatus = "show binary log status;"
|
||||
}
|
||||
rows, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, masterStatus)
|
||||
@@ -553,10 +553,13 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
}
|
||||
|
||||
func executeSqlForMaps(containerName, dbType, password, command string) (map[string]string, error) {
|
||||
if dbType == "mysql-cluster" {
|
||||
dbType = "mysql"
|
||||
}
|
||||
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||
if err != nil || strings.HasPrefix(stdStr, "ERROR ") {
|
||||
return nil, errors.New(stdStr)
|
||||
}
|
||||
|
||||
@@ -572,10 +575,13 @@ func executeSqlForMaps(containerName, dbType, password, command string) (map[str
|
||||
}
|
||||
|
||||
func executeSqlForRows(containerName, dbType, password, command string) ([]string, error) {
|
||||
if dbType == "mysql-cluster" {
|
||||
dbType = "mysql"
|
||||
}
|
||||
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||
if err != nil || strings.HasPrefix(stdStr, "ERROR ") {
|
||||
return nil, errors.New(stdStr)
|
||||
}
|
||||
return strings.Split(stdStr, "\n"), nil
|
||||
|
||||
@@ -28,9 +28,9 @@ type IRedisService interface {
|
||||
UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error
|
||||
ChangePassword(info dto.ChangeRedisPass) error
|
||||
|
||||
LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error)
|
||||
LoadConf(req dto.OperationWithName) (*dto.RedisConf, error)
|
||||
LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error)
|
||||
LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, error)
|
||||
LoadConf(req dto.LoadRedisStatus) (*dto.RedisConf, error)
|
||||
LoadPersistenceConf(req dto.LoadRedisStatus) (*dto.RedisPersistence, error)
|
||||
|
||||
CheckHasCli() bool
|
||||
InstallCli() error
|
||||
@@ -41,7 +41,7 @@ func NewIRedisService() IRedisService {
|
||||
}
|
||||
|
||||
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Database)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.DBType, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||
confs = append(confs, redisConfig{key: "timeout", value: req.Timeout})
|
||||
confs = append(confs, redisConfig{key: "maxclients", value: req.Maxclients})
|
||||
confs = append(confs, redisConfig{key: "maxmemory", value: req.Maxmemory})
|
||||
if err := confSet(redisInfo.Name, "", confs); err != nil {
|
||||
if err := confSet(redisInfo.Name, req.DBType, "", confs); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/redis/%s/docker-compose.yml", global.Dir.AppInstallDir, redisInfo.Name)); err != nil {
|
||||
@@ -84,7 +84,7 @@ func (u *RedisService) InstallCli() error {
|
||||
Image: "redis:7.4.4",
|
||||
Network: "1panel-network",
|
||||
}
|
||||
return NewIContainerService().ContainerCreate(item)
|
||||
return NewIContainerService().ContainerCreate(item, false)
|
||||
}
|
||||
|
||||
func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
|
||||
@@ -107,7 +107,7 @@ func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
|
||||
}
|
||||
|
||||
func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Database)
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.DBType, req.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -119,18 +119,18 @@ func (u *RedisService) UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate)
|
||||
confs = append(confs, redisConfig{key: "appendonly", value: req.Appendonly})
|
||||
confs = append(confs, redisConfig{key: "appendfsync", value: req.Appendfsync})
|
||||
}
|
||||
if err := confSet(redisInfo.Name, req.Type, confs); err != nil {
|
||||
if err := confSet(redisInfo.Name, req.DBType, req.Type, confs); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/redis/%s/docker-compose.yml", global.Dir.AppInstallDir, redisInfo.Name)); err != nil {
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", global.Dir.AppInstallDir, req.DBType, redisInfo.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -157,8 +157,8 @@ func (u *RedisService) LoadStatus(req dto.OperationWithName) (*dto.RedisStatus,
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadConf(req dto.LoadRedisStatus) (*dto.RedisConf, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -174,8 +174,8 @@ func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, erro
|
||||
return &item, nil
|
||||
}
|
||||
|
||||
func (u *RedisService) LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
||||
func (u *RedisService) LoadPersistenceConf(req dto.LoadRedisStatus) (*dto.RedisPersistence, error) {
|
||||
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -214,8 +214,8 @@ type redisConfig struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func confSet(redisName string, updateType string, changeConf []redisConfig) error {
|
||||
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", global.Dir.AppInstallDir, redisName)
|
||||
func confSet(redisName string, redisType string, updateType string, changeConf []redisConfig) error {
|
||||
path := fmt.Sprintf("%s/%s/%s/conf/redis.conf", global.Dir.AppInstallDir, redisType, redisName)
|
||||
lineBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -120,7 +120,7 @@ func (u *DeviceService) Update(key, value string) error {
|
||||
if err := ntp.UpdateSystemTimeZone(value); err != nil {
|
||||
return err
|
||||
}
|
||||
go common.RestartService(true, true, false)
|
||||
go common.RestartService(global.IsMaster, true, false)
|
||||
case "DNS":
|
||||
if err := updateDNS(strings.Split(value, ",")); err != nil {
|
||||
return err
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
@@ -663,7 +664,7 @@ func dropBuildCache() {
|
||||
if err != nil {
|
||||
global.LOG.Errorf("do not get docker client")
|
||||
}
|
||||
opts := types.BuildCachePruneOptions{}
|
||||
opts := build.CachePruneOptions{}
|
||||
opts.All = true
|
||||
_, err = client.BuildCachePrune(context.Background(), opts)
|
||||
if err != nil {
|
||||
|
||||
@@ -220,16 +220,6 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate, withRestart bool) erro
|
||||
daemonMap["proxies"] = proxies
|
||||
}
|
||||
}
|
||||
if len(daemonMap) == 0 {
|
||||
if len(file) == 0 {
|
||||
return nil
|
||||
}
|
||||
_ = os.Remove(constant.DaemonJsonPath)
|
||||
if withRestart {
|
||||
return restartDocker()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -277,11 +267,6 @@ func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
|
||||
_ = json.Unmarshal(file, &daemonMap)
|
||||
|
||||
changeLogOption(daemonMap, req.LogMaxFile, req.LogMaxSize)
|
||||
if len(daemonMap) == 0 {
|
||||
_ = os.Remove(constant.DaemonJsonPath)
|
||||
_ = restartDocker()
|
||||
return nil
|
||||
}
|
||||
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -321,11 +306,6 @@ func (u *DockerService) UpdateIpv6Option(req dto.Ipv6Option) error {
|
||||
if req.Experimental {
|
||||
daemonMap["experimental"] = req.Experimental
|
||||
}
|
||||
if len(daemonMap) == 0 {
|
||||
_ = os.Remove(constant.DaemonJsonPath)
|
||||
_ = restartDocker()
|
||||
return nil
|
||||
}
|
||||
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -345,13 +325,6 @@ func (u *DockerService) UpdateIpv6Option(req dto.Ipv6Option) error {
|
||||
}
|
||||
|
||||
func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
|
||||
if len(req.File) == 0 {
|
||||
_ = os.Remove(constant.DaemonJsonPath)
|
||||
if err := restartDocker(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err := createIfNotExistDaemonJsonFile()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -50,4 +50,5 @@ var (
|
||||
taskRepo = repo.NewITaskRepo()
|
||||
|
||||
groupRepo = repo.NewIGroupRepo()
|
||||
alertRepo = repo.NewIAlertRepo()
|
||||
)
|
||||
|
||||
+31
-11
@@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/jinzhu/copier"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -18,6 +17,9 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/jinzhu/copier"
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
|
||||
@@ -27,7 +29,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"golang.org/x/net/html/charset"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
@@ -337,10 +338,17 @@ func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo,
|
||||
}
|
||||
if !utf8.Valid(content) {
|
||||
_, decodeName, _ := charset.DetermineEncoding(content, "")
|
||||
if decodeName == "windows-1252" || strings.ToLower(decodeName) == "gbk" {
|
||||
decoder := files.GetDecoderByName(decodeName)
|
||||
if decoder != nil {
|
||||
reader := strings.NewReader(info.Content)
|
||||
item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder())
|
||||
contents, err := io.ReadAll(item)
|
||||
var dec *encoding.Decoder
|
||||
if decodeName == "windows-1252" {
|
||||
dec = simplifiedchinese.GBK.NewDecoder()
|
||||
} else {
|
||||
dec = decoder.NewDecoder()
|
||||
}
|
||||
decodedReader := transform.NewReader(reader, dec)
|
||||
contents, err := io.ReadAll(decodedReader)
|
||||
if err != nil {
|
||||
return response.FileInfo{}, err
|
||||
}
|
||||
@@ -390,10 +398,18 @@ func (f *FileService) MvFile(m request.FileMove) error {
|
||||
return buserr.New("ErrMovePathFailed")
|
||||
}
|
||||
}
|
||||
var errs []error
|
||||
if m.Type == "cut" {
|
||||
if len(m.CoverPaths) > 0 {
|
||||
for _, src := range m.CoverPaths {
|
||||
if err := fo.CopyAndReName(src, m.NewPath, "", true); err != nil {
|
||||
errs = append(errs, err)
|
||||
global.LOG.Errorf("cut copy file [%s] to [%s] failed, err: %s", src, m.NewPath, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
return fo.Cut(m.OldPaths, m.NewPath, m.Name, m.Cover)
|
||||
}
|
||||
var errs []error
|
||||
if m.Type == "copy" {
|
||||
for _, src := range m.OldPaths {
|
||||
if err := fo.CopyAndReName(src, m.NewPath, m.Name, m.Cover); err != nil {
|
||||
@@ -463,6 +479,7 @@ func (f *FileService) DepthDirSize(req request.DirSizeReq) ([]response.DepthDirS
|
||||
|
||||
func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) {
|
||||
logFilePath := ""
|
||||
taskStatus := ""
|
||||
switch req.Type {
|
||||
case constant.TypeWebsite:
|
||||
website, err := websiteRepo.GetFirst(repo.WithByID(req.ID))
|
||||
@@ -518,6 +535,7 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||
return nil, err
|
||||
}
|
||||
logFilePath = taskModel.LogFile
|
||||
taskStatus = taskModel.Status
|
||||
case "mysql-slow-logs":
|
||||
logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
||||
case "mariadb-slow-logs":
|
||||
@@ -536,11 +554,12 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||
lines = append(preLines, lines...)
|
||||
}
|
||||
res := &response.FileLineContent{
|
||||
Content: strings.Join(lines, "\n"),
|
||||
End: isEndOfFile,
|
||||
Path: logFilePath,
|
||||
Total: total,
|
||||
Lines: lines,
|
||||
Content: strings.Join(lines, "\n"),
|
||||
End: isEndOfFile,
|
||||
Path: logFilePath,
|
||||
Total: total,
|
||||
TaskStatus: taskStatus,
|
||||
Lines: lines,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -565,6 +584,7 @@ func (f *FileService) BatchCheckFiles(req request.FilePathsCheck) []response.Exi
|
||||
Name: info.Name(),
|
||||
Path: filePath,
|
||||
ModTime: info.ModTime(),
|
||||
IsDir: info.IsDir(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ func getProcessStatus(config *response.SupervisorProcessConfig, containerName st
|
||||
out, err = exec.Command("supervisorctl", processNames...).Output()
|
||||
output = string(out)
|
||||
}
|
||||
if containerName == "" && err != nil {
|
||||
if output == "" && err != nil {
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(output, "\n")
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
@@ -189,7 +189,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) error {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := types.ImageBuildOptions{
|
||||
opts := build.ImageBuildOptions{
|
||||
Dockerfile: fileName,
|
||||
Tags: []string{req.Name},
|
||||
Remove: true,
|
||||
@@ -432,7 +432,7 @@ func formatFileSize(fileSize int64) (size string) {
|
||||
}
|
||||
}
|
||||
|
||||
func checkUsed(imageID string, containers []types.Container) bool {
|
||||
func checkUsed(imageID string, containers []container.Summary) bool {
|
||||
for _, container := range containers {
|
||||
if container.ImageID == imageID {
|
||||
return true
|
||||
|
||||
@@ -28,7 +28,7 @@ type IImageRepoService interface {
|
||||
Login(req dto.OperateByID) error
|
||||
Create(req dto.ImageRepoCreate) error
|
||||
Update(req dto.ImageRepoUpdate) error
|
||||
BatchDelete(req dto.ImageRepoDelete) error
|
||||
Delete(req dto.OperateByID) error
|
||||
}
|
||||
|
||||
func NewIImageRepoService() IImageRepoService {
|
||||
@@ -91,28 +91,7 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
||||
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
||||
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
||||
}
|
||||
if err := restartDocker(); err != nil {
|
||||
return err
|
||||
}
|
||||
ticker := time.NewTicker(3 * time.Second)
|
||||
defer ticker.Stop()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
||||
if err := func() error {
|
||||
for range ticker.C {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
cancel()
|
||||
return errors.New("the docker service cannot be restarted")
|
||||
default:
|
||||
stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl is-active docker")
|
||||
if string(stdout) == "active\n" && err == nil {
|
||||
global.LOG.Info("docker restart with new conf successful!")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
if err := stopBeforeUpdateRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -131,15 +110,32 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
||||
return imageRepoRepo.Create(&imageRepo)
|
||||
}
|
||||
|
||||
func (u *ImageRepoService) BatchDelete(req dto.ImageRepoDelete) error {
|
||||
for _, id := range req.Ids {
|
||||
if id == 1 {
|
||||
return errors.New("The default value cannot be edit !")
|
||||
}
|
||||
func (u *ImageRepoService) Delete(req dto.OperateByID) error {
|
||||
if req.ID == 1 {
|
||||
return errors.New("The default value cannot be edit !")
|
||||
}
|
||||
if err := imageRepoRepo.Delete(repo.WithByIDs(req.Ids)); err != nil {
|
||||
itemRepo, _ := imageRepoRepo.Get(repo.WithByID(req.ID))
|
||||
if itemRepo.ID == 0 {
|
||||
return buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
if itemRepo.Auth {
|
||||
_, _ = cmd.NewCommandMgr().RunWithStdout("docker", "logout", "-i", itemRepo.DownloadUrl)
|
||||
}
|
||||
if itemRepo.Protocol == "https" {
|
||||
return imageRepoRepo.Delete(repo.WithByID(req.ID))
|
||||
}
|
||||
if err := u.handleRegistries("", itemRepo.DownloadUrl, "delete"); err != nil {
|
||||
return fmt.Errorf("delete registry %s failed, err: %v", itemRepo.DownloadUrl, err)
|
||||
}
|
||||
if err := validateDockerConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := imageRepoRepo.Delete(repo.WithByID(req.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
_ = restartDocker()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -154,38 +150,39 @@ func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needRestart := false
|
||||
if repo.Protocol == "http" && req.Protocol == "https" {
|
||||
if err := u.handleRegistries("", repo.DownloadUrl, "delete"); err != nil {
|
||||
return fmt.Errorf("delete registry %s failed, err: %v", repo.DownloadUrl, err)
|
||||
}
|
||||
needRestart = true
|
||||
}
|
||||
if repo.Protocol == "http" && req.Protocol == "http" {
|
||||
if err := u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update"); err != nil {
|
||||
return fmt.Errorf("update registry %s => %s failed, err: %v", repo.DownloadUrl, req.DownloadUrl, err)
|
||||
}
|
||||
needRestart = repo.DownloadUrl == req.DownloadUrl
|
||||
}
|
||||
if repo.Protocol == "https" && req.Protocol == "http" {
|
||||
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
||||
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
||||
}
|
||||
}
|
||||
if repo.Auth != req.Auth || repo.DownloadUrl != req.DownloadUrl {
|
||||
if repo.Auth {
|
||||
cmdMgr := cmd.NewCommandMgr()
|
||||
_, _ = cmdMgr.RunWithStdout("docker", "logout", "-i", repo.DownloadUrl)
|
||||
}
|
||||
if req.Auth {
|
||||
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
|
||||
return err
|
||||
if req.DownloadUrl != repo.DownloadUrl {
|
||||
if err := u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update"); err != nil {
|
||||
return fmt.Errorf("update registry %s => %s failed, err: %v", repo.DownloadUrl, req.DownloadUrl, err)
|
||||
}
|
||||
needRestart = true
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateDockerConfig(); err != nil {
|
||||
return err
|
||||
if needRestart {
|
||||
if err := stopBeforeUpdateRepo(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := restartDocker(); err != nil {
|
||||
return err
|
||||
if repo.Auth {
|
||||
_, _ = cmd.NewCommandMgr().RunWithStdout("docker", "logout", "-i", repo.DownloadUrl)
|
||||
}
|
||||
if req.Auth {
|
||||
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
upMap := make(map[string]interface{})
|
||||
@@ -260,3 +257,34 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopBeforeUpdateRepo() error {
|
||||
if err := validateDockerConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := restartDocker(); err != nil {
|
||||
return err
|
||||
}
|
||||
ticker := time.NewTicker(3 * time.Second)
|
||||
defer ticker.Stop()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||
if err := func() error {
|
||||
for range ticker.C {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
cancel()
|
||||
return errors.New("the docker service cannot be restarted")
|
||||
default:
|
||||
stdout, err := cmd.RunDefaultWithStdoutBashC("systemctl is-active docker")
|
||||
if string(stdout) == "active\n" && err == nil {
|
||||
global.LOG.Info("docker restart with new conf successful!")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -283,11 +283,19 @@ func (m McpServerService) BindDomain(req request.McpBindDomain) error {
|
||||
}
|
||||
}
|
||||
group, _ := groupRepo.Get(groupRepo.WithByWebsiteDefault())
|
||||
|
||||
domain, err := ParseDomain(req.Domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if domain.Port == 0 {
|
||||
domain.Port = nginxInstall.HttpPort
|
||||
}
|
||||
createWebsiteReq := request.WebsiteCreate{
|
||||
Domains: []request.WebsiteDomain{
|
||||
{
|
||||
Domain: req.Domain,
|
||||
Port: 80,
|
||||
Domain: domain.Domain,
|
||||
Port: domain.Port,
|
||||
},
|
||||
},
|
||||
Alias: strings.ToLower(req.Domain),
|
||||
|
||||
@@ -52,6 +52,7 @@ type IRuntimeService interface {
|
||||
SyncForRestart() error
|
||||
SyncRuntimeStatus() error
|
||||
DeleteCheck(installID uint) ([]dto.AppResource, error)
|
||||
UpdateRemark(req request.RuntimeRemark) error
|
||||
|
||||
GetPHPExtensions(runtimeID uint) (response.PHPExtensionRes, error)
|
||||
InstallPHPExtension(req request.PHPExtensionInstallReq) error
|
||||
@@ -108,6 +109,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
|
||||
Type: create.Type,
|
||||
Version: create.Version,
|
||||
Status: constant.StatusNormal,
|
||||
Remark: create.Remark,
|
||||
}
|
||||
return nil, runtimeRepo.Create(context.Background(), runtime)
|
||||
}
|
||||
@@ -168,6 +170,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
|
||||
Version: create.Version,
|
||||
ContainerName: containerName.(string),
|
||||
Port: strings.Join(hostPorts, ","),
|
||||
Remark: create.Remark,
|
||||
}
|
||||
|
||||
switch create.Type {
|
||||
@@ -208,6 +211,9 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if len(runtimes) == 0 {
|
||||
return 0, res, nil
|
||||
}
|
||||
if err = SyncRuntimesStatus(runtimes); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
@@ -444,6 +450,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
if err := checkContainerName(containerName.(string)); err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.ContainerName = containerName.(string)
|
||||
}
|
||||
|
||||
projectDir := path.Join(global.Dir.RuntimeDir, runtime.Type, runtime.Name)
|
||||
@@ -454,6 +461,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
Params: req.Params,
|
||||
CodeDir: req.CodeDir,
|
||||
Version: req.Version,
|
||||
Remark: req.Remark,
|
||||
NodeConfig: request.NodeConfig{
|
||||
Install: true,
|
||||
ExposedPorts: req.ExposedPorts,
|
||||
@@ -465,6 +473,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.Remark = req.Remark
|
||||
runtime.Env = string(envContent)
|
||||
runtime.DockerCompose = string(composeContent)
|
||||
|
||||
@@ -719,25 +728,27 @@ func (r *RuntimeService) InstallPHPExtension(req request.PHPExtensionInstallReq)
|
||||
return err
|
||||
}
|
||||
client, err := docker.NewClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
if err == nil {
|
||||
oldImageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = cmdMgr.RunBashCf("docker commit %s %s", runtime.ContainerName, runtime.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newImageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err == nil && newImageID != oldImageID {
|
||||
if err := client.DeleteImage(oldImageID); err != nil {
|
||||
t.Log(fmt.Sprintf("delete old image error %v", err))
|
||||
} else {
|
||||
t.Log("delete old image success")
|
||||
}
|
||||
oldImageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = cmdMgr.RunBashCf("docker commit %s %s", runtime.ContainerName, runtime.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newImageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err == nil && newImageID != oldImageID {
|
||||
if err := client.DeleteImage(oldImageID); err != nil {
|
||||
t.Log(fmt.Sprintf("delete old image error %v", err))
|
||||
} else {
|
||||
t.Log("delete old image success")
|
||||
}
|
||||
}
|
||||
handlePHPDir(*runtime)
|
||||
if err = restartRuntime(runtime); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -887,7 +898,6 @@ func (r *RuntimeService) UpdatePHPConfig(req request.PHPConfigUpdate) (err error
|
||||
pattern := "^" + regexp.QuoteMeta("disable_functions") + "\\s*=\\s*.*$"
|
||||
if matched, _ := regexp.MatchString(pattern, line); matched {
|
||||
lines[i] = "disable_functions" + " = " + strings.Join(req.DisableFunctions, ",")
|
||||
break
|
||||
}
|
||||
case "upload_max_filesize":
|
||||
pattern := "^" + regexp.QuoteMeta("post_max_size") + "\\s*=\\s*.*$"
|
||||
@@ -1143,3 +1153,12 @@ func (r *RuntimeService) OperateSupervisorProcessFile(req request.PHPSupervisorP
|
||||
logFile := path.Join(supervisorDir, "log", fmt.Sprintf("%s.out.log", req.SupervisorProcessFileReq.Name))
|
||||
return handleSupervisorFile(req.SupervisorProcessFileReq, configDir, runtime.ContainerName, logFile)
|
||||
}
|
||||
|
||||
func (r *RuntimeService) UpdateRemark(req request.RuntimeRemark) error {
|
||||
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.Remark = req.Remark
|
||||
return runtimeRepo.Save(runtime)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
cmd2 "github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -17,6 +16,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cmd2 "github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
|
||||
@@ -89,7 +90,7 @@ func handlePHP(create request.RuntimeCreate, runtime *model.Runtime, fileOp file
|
||||
version, ok := create.Params["PHP_VERSION"]
|
||||
if ok {
|
||||
extensionsDir := path.Join(projectDir, "extensions", getExtensionDir(version.(string)))
|
||||
_ = fileOp.CreateDir(extensionsDir, 0644)
|
||||
_ = fileOp.CreateDir(extensionsDir, 0755)
|
||||
}
|
||||
|
||||
composeContent, envContent, forms, err := handleParams(create, projectDir)
|
||||
@@ -101,6 +102,13 @@ func handlePHP(create request.RuntimeCreate, runtime *model.Runtime, fileOp file
|
||||
runtime.Params = string(forms)
|
||||
runtime.Status = constant.StatusBuilding
|
||||
|
||||
go func() {
|
||||
appDetail, err := appDetailRepo.GetFirst(repo.WithByID(runtime.AppDetailID))
|
||||
if err == nil {
|
||||
RequestDownloadCallBack(appDetail.DownloadCallBackUrl)
|
||||
}
|
||||
}()
|
||||
|
||||
go buildRuntime(runtime, "", "", false)
|
||||
return
|
||||
}
|
||||
@@ -141,11 +149,27 @@ func reCreateRuntime(runtime *model.Runtime) {
|
||||
}
|
||||
}
|
||||
|
||||
func runComposeCmdWithLog(operate string, composePath string, logPath string) error {
|
||||
cmd := exec.Command("docker", "compose", "-f", composePath, operate)
|
||||
if operate == "up" {
|
||||
cmd = exec.Command("docker", "compose", "-f", composePath, operate, "-d")
|
||||
func getComposeCmd(composePath, operate string) *exec.Cmd {
|
||||
dockerCommand := global.CONF.DockerConfig.Command
|
||||
var cmd *exec.Cmd
|
||||
if dockerCommand == "docker-compose" {
|
||||
if operate == "up" {
|
||||
cmd = exec.Command("docker-compose", "-f", composePath, operate, "-d")
|
||||
} else {
|
||||
cmd = exec.Command("docker-compose", "-f", composePath, operate)
|
||||
}
|
||||
} else {
|
||||
if operate == "up" {
|
||||
cmd = exec.Command("docker", "compose", "-f", composePath, operate, "-d")
|
||||
} else {
|
||||
cmd = exec.Command("docker", "compose", "-f", composePath, operate)
|
||||
}
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runComposeCmdWithLog(operate string, composePath string, logPath string) error {
|
||||
cmd := getComposeCmd(composePath, operate)
|
||||
logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, constant.FilePerm)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("Failed to open log file: %v", err)
|
||||
@@ -287,10 +311,22 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, oldEnv string, rebu
|
||||
_ = logFile.Close()
|
||||
}()
|
||||
|
||||
newPHPVersion := getRuntimeEnv(runtime.Env, "PHP_VERSION")
|
||||
oldPHPVersion := getRuntimeEnv(oldEnv, "PHP_VERSION")
|
||||
if newPHPVersion != oldPHPVersion {
|
||||
_ = os.Rename(path.Join(runtimePath, "extensions", getExtensionDir(oldPHPVersion)), path.Join(runtimePath, "extensions", getExtensionDir(newPHPVersion)))
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Hour)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, "docker", "compose", "-f", composePath, "build")
|
||||
dockerCommand := global.CONF.DockerConfig.Command
|
||||
var cmd *exec.Cmd
|
||||
if dockerCommand == "docker-compose" {
|
||||
cmd = exec.CommandContext(ctx, "docker-compose", "-f", composePath, "build")
|
||||
} else {
|
||||
cmd = exec.CommandContext(ctx, "docker", "compose", "-f", composePath, "build")
|
||||
}
|
||||
cmd.Stdout = logFile
|
||||
var stderrBuf bytes.Buffer
|
||||
multiWriterStderr := io.MultiWriter(&stderrBuf, logFile)
|
||||
@@ -373,6 +409,7 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, oldEnv string, rebu
|
||||
if deleteImageID != "" {
|
||||
deleteImageByID(deleteImageID, runtime.Image, client)
|
||||
}
|
||||
handlePHPDir(*runtime)
|
||||
if out, err := compose.DownAndUp(composePath); err != nil {
|
||||
runtime.Status = constant.StatusStartErr
|
||||
runtime.Message = out
|
||||
@@ -553,7 +590,7 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
|
||||
serviceName = name
|
||||
serviceValue = service.(map[string]interface{})
|
||||
delete(serviceValue, "ports")
|
||||
if create.ExposedPorts != nil && len(create.ExposedPorts) > 0 {
|
||||
if len(create.ExposedPorts) > 0 {
|
||||
var ports []interface{}
|
||||
for i, port := range create.ExposedPorts {
|
||||
containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i)
|
||||
@@ -567,12 +604,12 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
|
||||
create.Params[hostIPStr] = port.HostIP
|
||||
}
|
||||
if create.Type == constant.RuntimePHP {
|
||||
ports = append(ports, fmt.Sprintf("127.0.0.1:${PANEL_APP_PORT_HTTP}:9000"))
|
||||
ports = append(ports, "127.0.0.1:${PANEL_APP_PORT_HTTP}:9000")
|
||||
}
|
||||
serviceValue["ports"] = ports
|
||||
} else {
|
||||
if create.Type == constant.RuntimePHP {
|
||||
serviceValue["ports"] = []interface{}{fmt.Sprintf("127.0.0.1:${PANEL_APP_PORT_HTTP}:9000")}
|
||||
serviceValue["ports"] = []interface{}{"127.0.0.1:${PANEL_APP_PORT_HTTP}:9000"}
|
||||
}
|
||||
}
|
||||
var environments []interface{}
|
||||
@@ -959,3 +996,43 @@ func handleRuntimeDTO(res *response.RuntimeDTO, runtime model.Runtime) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handlePHPDir(runtime model.Runtime) {
|
||||
fileOp := files.NewFileOp()
|
||||
dirs := []string{
|
||||
path.Join(runtime.GetPath(), "conf"),
|
||||
path.Join(runtime.GetPath(), "extensions"),
|
||||
path.Join(runtime.GetPath(), "composer"),
|
||||
path.Join(runtime.GetPath(), "log"),
|
||||
}
|
||||
for _, dir := range dirs {
|
||||
_ = fileOp.ChmodR(dir, 0755, true)
|
||||
_ = fileOp.ChownR(dir, strconv.Itoa(1000), strconv.Itoa(1000), true)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleOldPHPRuntime() {
|
||||
runtimes, _ := runtimeRepo.List(repo.WithByType(constant.RuntimePHP))
|
||||
if len(runtimes) == 0 {
|
||||
return
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
for _, runtime := range runtimes {
|
||||
composePtah := runtime.GetComposePath()
|
||||
composeBytes, _ := fileOp.GetContent(composePtah)
|
||||
composeContent := strings.ReplaceAll(string(composeBytes), "./conf:/usr/local/etc/php", "./conf/php.ini:/usr/local/etc/php/php.ini")
|
||||
composeContent = strings.ReplaceAll(composeContent, "./conf/php-fpm.conf:/usr/local/etc/php-fpm.d/www.conf", "./conf/php-fpm.conf:/usr/local/etc/php-fpm.conf")
|
||||
composeContent = strings.ReplaceAll(composeContent, "./extensions:${EXTENSION_DIR}", "./extensions:/usr/local/lib/php/extensions")
|
||||
_ = fileOp.WriteFile(composePtah, strings.NewReader(composeContent), constant.DirPerm)
|
||||
_ = fileOp.WriteFile(runtime.GetFPMPath(), bytes.NewReader(nginx_conf.GetWebsiteFile("php-fpm.conf")), constant.DirPerm)
|
||||
supervisorConfigPath := path.Join(runtime.GetPath(), "supervisor", "supervisor.d", "php-fpm.ini")
|
||||
supervisorConfigBytes, _ := fileOp.GetContent(supervisorConfigPath)
|
||||
if !strings.Contains(string(supervisorConfigBytes), "nodaemonize") {
|
||||
newConfigContent := strings.ReplaceAll(string(supervisorConfigBytes), "command=php-fpm", "command=php-fpm --nodaemonize")
|
||||
_ = fileOp.WriteFile(supervisorConfigPath, bytes.NewReader([]byte(newConfigContent)), constant.DirPerm)
|
||||
}
|
||||
go func() {
|
||||
_ = restartRuntime(&runtime)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
|
||||
}
|
||||
|
||||
for _, snapName := range req.Names {
|
||||
if !strings.HasPrefix(snapName, "1panel-v2.") && !strings.HasPrefix(snapName, "snapshot-1panel-v2.") {
|
||||
if !checkSnapshotIsOk(snapName) {
|
||||
return fmt.Errorf("incorrect snapshot name format of %s", snapName)
|
||||
}
|
||||
snap, _ := snapshotRepo.Get(repo.WithByName(strings.ReplaceAll(snapName, ".tar.gz", "")))
|
||||
@@ -77,11 +77,11 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
|
||||
}
|
||||
}
|
||||
for _, snap := range req.Names {
|
||||
shortName := strings.TrimPrefix(snap, "snapshot_")
|
||||
nameItems := strings.Split(shortName, "-")
|
||||
if !strings.HasPrefix(shortName, "1panel-v") || !strings.HasSuffix(shortName, ".tar.gz") || len(nameItems) < 3 {
|
||||
return fmt.Errorf("incorrect snapshot name format of %s", shortName)
|
||||
}
|
||||
shortName := strings.ReplaceAll(snap, "snapshot-", "")
|
||||
shortName = strings.ReplaceAll(shortName, "1panel-", "")
|
||||
shortName = strings.ReplaceAll(shortName, "core-", "")
|
||||
shortName = strings.ReplaceAll(shortName, "agent-", "")
|
||||
nameItems := strings.Split(shortName, "-linux")
|
||||
if strings.HasSuffix(snap, ".tar.gz") {
|
||||
snap = strings.ReplaceAll(snap, ".tar.gz", "")
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
|
||||
Name: snap,
|
||||
SourceAccountIDs: fmt.Sprintf("%v", req.BackupAccountID),
|
||||
DownloadAccountID: req.BackupAccountID,
|
||||
Version: nameItems[1],
|
||||
Version: nameItems[0],
|
||||
Description: req.Description,
|
||||
Status: constant.StatusSuccess,
|
||||
}
|
||||
@@ -110,6 +110,7 @@ func (u *SnapshotService) LoadSnapshotData() (dto.SnapshotData, error) {
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
data.WithDockerConf = true
|
||||
data.PanelData, err = loadPanelFile(fileOp)
|
||||
if err != nil {
|
||||
return data, err
|
||||
@@ -403,3 +404,13 @@ func loadFile(pathItem string, index int, fileOp fileUtils.FileOp) ([]dto.DataTr
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func checkSnapshotIsOk(name string) bool {
|
||||
names := []string{"1panel-core-v2.", "1panel-agent-v2.", "1panel-v2.", "snapshot-1panel-core-v2.", "snapshot-1panel-agent-v2."}
|
||||
for _, item := range names {
|
||||
if strings.HasPrefix(name, item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -34,7 +35,7 @@ func (u *SnapshotService) SnapshotCreate(parentTask *task.Task, req dto.Snapshot
|
||||
scope = "agent"
|
||||
}
|
||||
if jobID == 0 {
|
||||
req.Name = fmt.Sprintf("1panel-%s-%s-linux-%s-%s", versionItem.Value, scope, loadOs(), time.Now().Format(constant.DateTimeSlimLayout))
|
||||
req.Name = fmt.Sprintf("1panel-%s-%s-linux-%s-%s", scope, versionItem.Value, loadOs(), time.Now().Format(constant.DateTimeSlimLayout))
|
||||
}
|
||||
appItem, _ := json.Marshal(req.AppData)
|
||||
panelItem, _ := json.Marshal(req.PanelData)
|
||||
@@ -50,14 +51,17 @@ func (u *SnapshotService) SnapshotCreate(parentTask *task.Task, req dto.Snapshot
|
||||
AppData: string(appItem),
|
||||
PanelData: string(panelItem),
|
||||
BackupData: string(backupItem),
|
||||
WithDockerConf: req.WithDockerConf,
|
||||
WithMonitorData: req.WithMonitorData,
|
||||
WithLoginLog: req.WithLoginLog,
|
||||
WithOperationLog: req.WithOperationLog,
|
||||
WithTaskLog: req.WithTaskLog,
|
||||
WithSystemLog: req.WithSystemLog,
|
||||
IgnoreFiles: strings.Join(req.IgnoreFiles, ","),
|
||||
|
||||
Version: versionItem.Value,
|
||||
Status: constant.StatusWaiting,
|
||||
Timeout: req.Timeout,
|
||||
}
|
||||
if err := snapshotRepo.Create(&snap); err != nil {
|
||||
global.LOG.Errorf("create snapshot record to db failed, err: %v", err)
|
||||
@@ -76,7 +80,7 @@ func (u *SnapshotService) SnapshotCreate(parentTask *task.Task, req dto.Snapshot
|
||||
}
|
||||
if jobID == 0 {
|
||||
go func() {
|
||||
_ = handleSnapshot(req, taskItem, jobID, 3, 0)
|
||||
_ = handleSnapshot(req, taskItem, jobID, 3, snap.Timeout)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
@@ -106,28 +110,25 @@ func (u *SnapshotService) SnapshotReCreate(id uint) error {
|
||||
return err
|
||||
}
|
||||
req.TaskID = taskModel.ID
|
||||
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskCreate, task.TaskScopeSnapshot, req.TaskID, req.ID)
|
||||
taskItem, err := task.ReNewTaskWithOps(req.Name, task.TaskCreate, task.TaskScopeSnapshot, req.TaskID, req.ID)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("new task for create snapshot failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
_ = snapshotRepo.Update(req.ID, map[string]interface{}{"status": constant.StatusWaiting, "message": ""})
|
||||
go func() {
|
||||
_ = handleSnapshot(req, taskItem, 0, 0, 0)
|
||||
_ = handleSnapshot(req, taskItem, 0, 3, 0)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task, jobID, retry, timeout uint) error {
|
||||
rootDir := path.Join(global.Dir.TmpDir, "system", req.Name)
|
||||
rootDir := path.Join(global.Dir.LocalBackupDir, "tmp/system", req.Name)
|
||||
openrestyDir, _ := settingRepo.GetValueByKey("WEBSITE_DIR")
|
||||
itemHelper := snapHelper{SnapID: req.ID, Task: *taskItem, FileOp: files.NewFileOp(), Ctx: context.Background(), OpenrestyDir: openrestyDir}
|
||||
baseDir := path.Join(rootDir, "base")
|
||||
_ = os.MkdirAll(baseDir, os.ModePerm)
|
||||
|
||||
if timeout == 0 {
|
||||
timeout = 1800
|
||||
}
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"SnapDBInfo",
|
||||
func(t *task.Task) error {
|
||||
@@ -145,7 +146,7 @@ func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task, jobID, retry, t
|
||||
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapBaseInfo" {
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"SnapBaseInfo",
|
||||
func(t *task.Task) error { return snapBaseData(itemHelper, baseDir) },
|
||||
func(t *task.Task) error { return snapBaseData(itemHelper, baseDir, req.WithDockerConf) },
|
||||
nil, int(retry), time.Duration(timeout)*time.Second,
|
||||
)
|
||||
req.InterruptStep = ""
|
||||
@@ -233,6 +234,7 @@ func loadDbConn(snap *snapHelper, targetDir string, req dto.SnapshotCreate) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(path.Join(targetDir, "db/session.db"))
|
||||
|
||||
agentDb, err := common.LoadDBConnByPathWithErr(path.Join(targetDir, "db/agent.db"), "agent.db")
|
||||
snap.Task.LogWithStatus(i18n.GetWithName("SnapNewDB", "agent"), err)
|
||||
@@ -284,7 +286,7 @@ func loadDbConn(snap *snapHelper, targetDir string, req dto.SnapshotCreate) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func snapBaseData(snap snapHelper, targetDir string) error {
|
||||
func snapBaseData(snap snapHelper, targetDir string, withDockerConf bool) error {
|
||||
snap.Task.Log("---------------------- 2 / 8 ----------------------")
|
||||
snap.Task.LogStart(i18n.GetMsgByKey("SnapBaseInfo"))
|
||||
|
||||
@@ -321,11 +323,13 @@ func snapBaseData(snap snapHelper, targetDir string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if snap.FileOp.Stat("/etc/docker/daemon.json") {
|
||||
err = snap.FileOp.CopyFile("/etc/docker/daemon.json", targetDir)
|
||||
snap.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/etc/docker/daemon.json"), err)
|
||||
if err != nil {
|
||||
return err
|
||||
if withDockerConf {
|
||||
if snap.FileOp.Stat(constant.DaemonJsonPath) {
|
||||
err = snap.FileOp.CopyFile(constant.DaemonJsonPath, targetDir)
|
||||
snap.Task.LogWithStatus(i18n.GetWithName("SnapCopy", constant.DaemonJsonPath), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,8 +381,8 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err
|
||||
}
|
||||
}
|
||||
|
||||
snap.Task.Log(strings.Join(imageList, " "))
|
||||
if len(imageList) != 0 {
|
||||
snap.Task.Log(strings.Join(imageList, " "))
|
||||
snap.Task.Logf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz"))
|
||||
std, err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunWithStdoutBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz"))
|
||||
if err != nil {
|
||||
@@ -386,6 +390,8 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err
|
||||
return errors.New(std)
|
||||
}
|
||||
snap.Task.LogSuccess(i18n.GetMsgByKey("SnapDockerSave"))
|
||||
} else {
|
||||
snap.Task.Log(i18n.GetMsgByKey("SnapInstallAppImageEmpty"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -395,7 +401,9 @@ func snapBackupData(snap snapHelper, req dto.SnapshotCreate, targetDir string) e
|
||||
snap.Task.LogStart(i18n.GetMsgByKey("SnapLocalBackup"))
|
||||
|
||||
excludes := loadBackupExcludes(snap, req.BackupData)
|
||||
excludes = append(excludes, req.IgnoreFiles...)
|
||||
excludes = append(excludes, "./system_snapshot")
|
||||
excludes = append(excludes, "./tmp")
|
||||
for _, item := range req.AppData {
|
||||
for _, itemApp := range item.Children {
|
||||
if itemApp.Label == "appBackup" {
|
||||
@@ -418,7 +426,8 @@ func loadBackupExcludes(snap snapHelper, req []dto.DataTree) []string {
|
||||
if err := snap.snapAgentDB.Where("file_dir = ? AND file_name = ?", strings.TrimPrefix(path.Dir(item.Path), global.Dir.LocalBackupDir+"/"), path.Base(item.Path)).Delete(&model.BackupRecord{}).Error; err != nil {
|
||||
snap.Task.LogWithStatus("delete backup file from database", err)
|
||||
}
|
||||
excludes = append(excludes, "."+strings.TrimPrefix(item.Path, global.Dir.LocalBackupDir))
|
||||
itemDir, _ := filepath.Rel(item.Path, global.Dir.LocalBackupDir)
|
||||
excludes = append(excludes, itemDir)
|
||||
} else {
|
||||
excludes = append(excludes, loadBackupExcludes(snap, item.Children)...)
|
||||
}
|
||||
@@ -430,7 +439,8 @@ func loadAppBackupExcludes(req []dto.DataTree) []string {
|
||||
for _, item := range req {
|
||||
if len(item.Children) == 0 {
|
||||
if !item.IsCheck {
|
||||
excludes = append(excludes, "."+strings.TrimPrefix(item.Path, path.Join(global.Dir.LocalBackupDir)))
|
||||
itemDir, _ := filepath.Rel(item.Path, global.Dir.LocalBackupDir)
|
||||
excludes = append(excludes, itemDir)
|
||||
}
|
||||
} else {
|
||||
excludes = append(excludes, loadAppBackupExcludes(item.Children)...)
|
||||
@@ -463,26 +473,21 @@ func snapPanelData(snap snapHelper, req dto.SnapshotCreate, targetDir string) er
|
||||
|
||||
rootDir := global.Dir.DataDir
|
||||
if strings.Contains(global.Dir.LocalBackupDir, rootDir) {
|
||||
excludes = append(excludes, "."+strings.ReplaceAll(global.Dir.LocalBackupDir, rootDir, ""))
|
||||
itemDir, _ := filepath.Rel(rootDir, global.Dir.LocalBackupDir)
|
||||
excludes = append(excludes, itemDir)
|
||||
}
|
||||
if len(snap.OpenrestyDir) != 0 && strings.Contains(snap.OpenrestyDir, rootDir) {
|
||||
excludes = append(excludes, "."+strings.ReplaceAll(snap.OpenrestyDir, rootDir, ""))
|
||||
}
|
||||
ignoreVal, _ := settingRepo.Get(settingRepo.WithByKey("SnapshotIgnore"))
|
||||
rules := strings.Split(ignoreVal.Value, ",")
|
||||
for _, ignore := range rules {
|
||||
if len(ignore) == 0 || cmd.CheckIllegal(ignore) {
|
||||
continue
|
||||
}
|
||||
excludes = append(excludes, "."+strings.ReplaceAll(ignore, rootDir, ""))
|
||||
itemDir, _ := filepath.Rel(rootDir, snap.OpenrestyDir)
|
||||
excludes = append(excludes, itemDir)
|
||||
}
|
||||
excludes = append(excludes, req.IgnoreFiles...)
|
||||
err := snap.FileOp.TarGzCompressPro(false, rootDir, path.Join(targetDir, "1panel_data.tar.gz"), "", strings.Join(excludes, ","))
|
||||
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapCompressPanel"), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(snap.OpenrestyDir) != 0 {
|
||||
err := snap.FileOp.TarGzCompressPro(false, snap.OpenrestyDir, path.Join(targetDir, "website.tar.gz"), "", "")
|
||||
err := snap.FileOp.TarGzCompressPro(false, snap.OpenrestyDir, path.Join(targetDir, "website.tar.gz"), "", strings.Join(req.IgnoreFiles, ","))
|
||||
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapWebsite"), err)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -496,7 +501,8 @@ func loadPanelExcludes(req []dto.DataTree) []string {
|
||||
for _, item := range req {
|
||||
if len(item.Children) == 0 {
|
||||
if !item.IsCheck {
|
||||
excludes = append(excludes, "."+strings.TrimPrefix(item.Path, path.Join(global.Dir.BaseDir, "1panel")))
|
||||
itemDir, _ := filepath.Rel(item.Path, path.Join(global.Dir.BaseDir, "1panel"))
|
||||
excludes = append(excludes, itemDir)
|
||||
}
|
||||
} else {
|
||||
excludes = append(excludes, loadPanelExcludes(item.Children)...)
|
||||
@@ -509,7 +515,7 @@ func snapCompress(snap snapHelper, rootDir string, secret string) error {
|
||||
snap.Task.Log("---------------------- 7 / 8 ----------------------")
|
||||
snap.Task.LogStart(i18n.GetMsgByKey("SnapCompress"))
|
||||
|
||||
tmpDir := path.Join(global.Dir.TmpDir, "system")
|
||||
tmpDir := path.Join(global.Dir.LocalBackupDir, "tmp/system")
|
||||
fileName := fmt.Sprintf("%s.tar.gz", path.Base(rootDir))
|
||||
err := snap.FileOp.TarGzCompressPro(true, rootDir, path.Join(tmpDir, fileName), secret, "")
|
||||
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapCompressFile"), err)
|
||||
@@ -533,7 +539,7 @@ func snapUpload(snap snapHelper, accounts string, file string) error {
|
||||
snap.Task.Log("---------------------- 8 / 8 ----------------------")
|
||||
snap.Task.LogStart(i18n.GetMsgByKey("SnapUpload"))
|
||||
|
||||
source := path.Join(global.Dir.TmpDir, "system", path.Base(file))
|
||||
source := path.Join(global.Dir.LocalBackupDir, "tmp/system", path.Base(file))
|
||||
accountMap, err := NewBackupClientMap(strings.Split(accounts, ","))
|
||||
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapLoadBackup"), err)
|
||||
if err != nil {
|
||||
|
||||
@@ -38,6 +38,18 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"recover_status": constant.StatusFailed, "recover_message": errInfo})
|
||||
return errors.New(errInfo)
|
||||
}
|
||||
if !strings.Contains(snap.Name, "-v2.") {
|
||||
return errors.New("snapshots are currently not supported for recovery across major versions")
|
||||
}
|
||||
if !strings.Contains(snap.Name, "-core") && !strings.Contains(snap.Name, "-agent") {
|
||||
return errors.New("the name of the snapshot file does not conform to the format")
|
||||
}
|
||||
if strings.Contains(snap.Name, "-core") && !global.IsMaster {
|
||||
return errors.New("the snapshot of the master node cannot be restored on the agent nodes")
|
||||
}
|
||||
if strings.Contains(snap.Name, "-agent") && global.IsMaster {
|
||||
return errors.New("the snapshot of the agent node cannot be restored on the master node")
|
||||
}
|
||||
if len(snap.RollbackStatus) != 0 && snap.RollbackStatus != constant.StatusSuccess {
|
||||
req.IsNew = true
|
||||
}
|
||||
@@ -55,12 +67,18 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
} else {
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"task_recover_id": req.TaskID})
|
||||
}
|
||||
taskItem, err := task.NewTaskWithOps(snap.Name, task.TaskRecover, task.TaskScopeSnapshot, req.TaskID, snap.ID)
|
||||
|
||||
var taskItem *task.Task
|
||||
if req.IsNew {
|
||||
taskItem, err = task.NewTaskWithOps(snap.Name, task.TaskRecover, task.TaskScopeSnapshot, req.TaskID, snap.ID)
|
||||
} else {
|
||||
taskItem, err = task.ReNewTaskWithOps(snap.Name, task.TaskRecover, task.TaskScopeSnapshot, req.TaskID, snap.ID)
|
||||
}
|
||||
if err != nil {
|
||||
global.LOG.Errorf("new task for create snapshot failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
rootDir := path.Join(global.Dir.TmpDir, "system", snap.Name)
|
||||
rootDir := path.Join(global.Dir.LocalBackupDir, "tmp/system", snap.Name)
|
||||
if _, err := os.Stat(rootDir); err != nil && os.IsNotExist(err) {
|
||||
_ = os.MkdirAll(rootDir, os.ModePerm)
|
||||
}
|
||||
@@ -84,7 +102,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
"RecoverDecompress",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 2 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 2 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetWithName("RecoverDecompress", snap.Name))
|
||||
err := itemHelper.FileOp.TarGzExtractPro(fmt.Sprintf("%s/%s.tar.gz", rootDir, snap.Name), rootDir, req.Secret)
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
@@ -140,7 +158,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
"RecoverBackups",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 8 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 8 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetWithName("RecoverBackups", snap.Name))
|
||||
err := itemHelper.FileOp.TarGzExtractPro(path.Join(rootDir, snap.Name, "/1panel_backup.tar.gz"), snapJson.BackupDataDir, "")
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
@@ -150,11 +168,30 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverWebsite" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
"RecoverWebsite",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 9 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetWithName("RecoverWebsite", snap.Name))
|
||||
webFile := path.Join(rootDir, snap.Name, "/website.tar.gz")
|
||||
_ = itemHelper.FileOp.CreateDir(snapJson.OperestyDir, os.ModePerm)
|
||||
var err error
|
||||
if itemHelper.FileOp.Stat(webFile) {
|
||||
err = itemHelper.FileOp.TarGzExtractPro(webFile, snapJson.OperestyDir, "")
|
||||
}
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverPanelData" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
"RecoverPanelData",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 9 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 10 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetWithName("RecoverPanelData", snap.Name))
|
||||
err := itemHelper.FileOp.TarGzExtractPro(path.Join(rootDir, snap.Name, "/1panel_data.tar.gz"), path.Join(snapJson.BaseDir, "1panel"), "")
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
@@ -195,7 +232,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
}
|
||||
|
||||
func handleDownloadSnapshot(itemHelper *snapRecoverHelper, snap model.Snapshot, targetDir string) error {
|
||||
itemHelper.Task.Log("---------------------- 1 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 1 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetMsgByKey("RecoverDownload"))
|
||||
|
||||
account, client, err := NewBackupClientWithID(snap.DownloadAccountID)
|
||||
@@ -214,7 +251,7 @@ func handleDownloadSnapshot(itemHelper *snapRecoverHelper, snap model.Snapshot,
|
||||
}
|
||||
|
||||
func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error {
|
||||
itemHelper.Task.Log("---------------------- 3 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 3 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetMsgByKey("BackupBeforeRecover"))
|
||||
|
||||
rootDir := fmt.Sprintf("%s/1panel_original/original_%s", global.Dir.BaseDir, name)
|
||||
@@ -273,9 +310,9 @@ func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if itemHelper.FileOp.Stat("/etc/docker/daemon.json") {
|
||||
err = itemHelper.FileOp.CopyFile("/etc/docker/daemon.json", baseDir)
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", "/etc/docker/daemon.json"), err)
|
||||
if itemHelper.FileOp.Stat(constant.DaemonJsonPath) {
|
||||
err = itemHelper.FileOp.CopyFile(constant.DaemonJsonPath, baseDir)
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", constant.DaemonJsonPath), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -284,7 +321,7 @@ func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error {
|
||||
}
|
||||
|
||||
func readFromJson(rootDir string, itemHelper *snapRecoverHelper) (SnapshotJson, error) {
|
||||
itemHelper.Task.Log("---------------------- 4 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 4 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetMsgByKey("Readjson"))
|
||||
|
||||
snapJsonPath := path.Join(rootDir, "base/snapshot.json")
|
||||
@@ -308,7 +345,7 @@ func readFromJson(rootDir string, itemHelper *snapRecoverHelper) (SnapshotJson,
|
||||
}
|
||||
|
||||
func recoverAppData(src string, itemHelper *snapRecoverHelper) error {
|
||||
itemHelper.Task.Log("---------------------- 5 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 5 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetMsgByKey("RecoverApp"))
|
||||
|
||||
if _, err := os.Stat(path.Join(src, "images.tar.gz")); err != nil {
|
||||
@@ -325,7 +362,7 @@ func recoverAppData(src string, itemHelper *snapRecoverHelper) error {
|
||||
}
|
||||
|
||||
func recoverBaseData(src string, itemHelper *snapRecoverHelper) error {
|
||||
itemHelper.Task.Log("---------------------- 6 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 6 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetMsgByKey("SnapBaseInfo"))
|
||||
|
||||
if global.IsMaster {
|
||||
@@ -356,15 +393,11 @@ func recoverBaseData(src string, itemHelper *snapRecoverHelper) error {
|
||||
return err
|
||||
}
|
||||
|
||||
daemonJsonPath := "/etc/docker/daemon.json"
|
||||
_, errSrc := os.Stat(path.Join(src, "docker/daemon.json"))
|
||||
_, errPath := os.Stat(daemonJsonPath)
|
||||
if os.IsNotExist(errSrc) && os.IsNotExist(errPath) {
|
||||
if !itemHelper.FileOp.Stat(path.Join(src, "daemon.json")) {
|
||||
itemHelper.Task.Log(i18n.GetMsgByKey("RecoverDaemonJsonEmpty"))
|
||||
return nil
|
||||
}
|
||||
if errSrc == nil {
|
||||
err = itemHelper.FileOp.CopyFile(path.Join(src, "docker/daemon.json"), "/etc/docker")
|
||||
} else {
|
||||
err = itemHelper.FileOp.CopyFile(path.Join(src, "daemon.json"), path.Dir(constant.DaemonJsonPath))
|
||||
itemHelper.Task.Log(i18n.GetMsgByKey("RecoverDaemonJson"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("recover docker daemon.json failed, err: %v", err)
|
||||
@@ -378,7 +411,7 @@ func recoverBaseData(src string, itemHelper *snapRecoverHelper) error {
|
||||
}
|
||||
|
||||
func recoverDBData(src string, itemHelper *snapRecoverHelper) error {
|
||||
itemHelper.Task.Log("---------------------- 7 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 7 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetMsgByKey("RecoverDBData"))
|
||||
err := itemHelper.FileOp.CopyDirWithExclude(src, global.Dir.DataDir, nil)
|
||||
|
||||
@@ -387,7 +420,7 @@ func recoverDBData(src string, itemHelper *snapRecoverHelper) error {
|
||||
}
|
||||
|
||||
func restartCompose(composePath string, itemHelper *snapRecoverHelper) error {
|
||||
itemHelper.Task.Log("---------------------- 10 / 10 ----------------------")
|
||||
itemHelper.Task.Log("---------------------- 11 / 11 ----------------------")
|
||||
itemHelper.Task.LogStart(i18n.GetMsgByKey("RecoverCompose"))
|
||||
|
||||
composes, err := composeRepo.ListRecord()
|
||||
|
||||
@@ -76,9 +76,12 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
||||
nil,
|
||||
)
|
||||
taskItem.AddSubTask(
|
||||
i18n.GetWithName("SnapCopy", "/etc/docker/daemon.json"),
|
||||
i18n.GetWithName("SnapCopy", constant.DaemonJsonPath),
|
||||
func(t *task.Task) error {
|
||||
return FileOp.CopyFile(path.Join(baseDir, "daemon.json"), "/etc/docker")
|
||||
if FileOp.Stat(path.Join(baseDir, "daemon.json")) {
|
||||
return FileOp.CopyFile(path.Join(baseDir, "daemon.json"), path.Dir(constant.DaemonJsonPath))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
@@ -257,7 +257,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
var (
|
||||
domains []model.WebsiteDomain
|
||||
)
|
||||
domains, _, _, err = getWebsiteDomains(create.Domains, defaultHttpPort, 0)
|
||||
domains, _, _, err = getWebsiteDomains(create.Domains, defaultHttpPort, nginxInstall.HttpsPort, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -388,7 +388,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
switch runtime.Type {
|
||||
case constant.RuntimePHP:
|
||||
if runtime.Resource == constant.ResourceAppstore {
|
||||
if !checkImageExist(nil, runtime.Image) {
|
||||
if !checkImageLike(nil, runtime.Image) {
|
||||
return buserr.WithName("ErrImageNotExist", runtime.Name)
|
||||
}
|
||||
website.Proxy = fmt.Sprintf("127.0.0.1:%s", runtime.Port)
|
||||
@@ -415,6 +415,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
return err
|
||||
}
|
||||
website.ParentWebsiteID = parentWebsite.ID
|
||||
website.SiteDir = create.SiteDir
|
||||
}
|
||||
|
||||
configNginx := func(t *task.Task) error {
|
||||
@@ -679,7 +680,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
domainModels []model.WebsiteDomain
|
||||
addPorts []int
|
||||
)
|
||||
httpPort, _, err := getAppInstallPort(constant.AppOpenresty)
|
||||
httpPort, httpsPort, err := getAppInstallPort(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -688,7 +689,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domainModels, addPorts, _, err = getWebsiteDomains(create.Domains, httpPort, create.WebsiteID)
|
||||
domainModels, addPorts, _, err = getWebsiteDomains(create.Domains, httpPort, httpsPort, create.WebsiteID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -922,18 +923,12 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
|
||||
res response.WebsiteHTTPS
|
||||
httpsPorts []string
|
||||
)
|
||||
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteId))
|
||||
for _, domain := range websiteDomains {
|
||||
if domain.SSL {
|
||||
httpsPorts = append(httpsPorts, strconv.Itoa(domain.Port))
|
||||
}
|
||||
}
|
||||
if len(httpsPorts) == 0 {
|
||||
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||
res.HttpsPort = strconv.Itoa(nginxInstall.HttpsPort)
|
||||
} else {
|
||||
res.HttpsPort = strings.Join(httpsPorts, ",")
|
||||
|
||||
httpsPortsMap := getHttpsPort(websiteId)
|
||||
for port := range httpsPortsMap {
|
||||
httpsPorts = append(httpsPorts, strconv.Itoa(port))
|
||||
}
|
||||
res.HttpsPort = strings.Join(httpsPorts, ",")
|
||||
if website.WebsiteSSLID == 0 {
|
||||
res.Enable = false
|
||||
return res, nil
|
||||
@@ -981,10 +976,6 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
res response.WebsiteHTTPS
|
||||
websiteSSL model.WebsiteSSL
|
||||
)
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = ChangeHSTSConfig(req.Hsts, req.Http3, website); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -995,24 +986,27 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
|
||||
website.Protocol = constant.ProtocolHTTP
|
||||
website.WebsiteSSLID = 0
|
||||
|
||||
httpsPorts, err := getHttpsPort(&website)
|
||||
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(website.ID))
|
||||
|
||||
ports := make(map[int]struct{})
|
||||
for _, domain := range websiteDomains {
|
||||
ports[domain.Port] = struct{}{}
|
||||
}
|
||||
for port := range ports {
|
||||
if err = removeSSLListen(website, []string{strconv.Itoa(port)}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(httpsPorts) == 1 && httpsPorts[0] == nginxInstall.HttpsPort {
|
||||
httpsPortStr := strconv.Itoa(httpsPorts[0])
|
||||
if _, ok := ports[nginxInstall.HttpsPort]; !ok {
|
||||
httpsPortStr := strconv.Itoa(nginxInstall.HttpsPort)
|
||||
if err = deleteListenAndServerName(website, []string{httpsPortStr, "[::]:" + httpsPortStr}, []string{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
for _, port := range httpsPorts {
|
||||
httpsPortStr := strconv.Itoa(port)
|
||||
if err = removeSSLListen(website, []string{httpsPortStr}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nginxParams := getNginxParamsFromStaticFile(dto.SSL, nil)
|
||||
nginxParams = append(nginxParams,
|
||||
dto.NginxParam{
|
||||
@@ -1360,7 +1354,7 @@ func (w WebsiteService) ChangePHPVersion(req request.WebsitePHPVersionReq) error
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
if !checkImageExist(client, oldRuntime.Image) {
|
||||
if !checkImageLike(client, oldRuntime.Image) {
|
||||
return buserr.WithName("ErrImageNotExist", oldRuntime.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
|
||||
if update.OtherDomains != "" {
|
||||
otherDomainArray := strings.Split(update.OtherDomains, "\n")
|
||||
for _, domain := range otherDomainArray {
|
||||
if !common.IsValidDomain(domain) {
|
||||
if websiteSSL.Provider != constant.SelfSigned && !common.IsValidDomain(domain) {
|
||||
return buserr.WithName("ErrDomainFormat", domain)
|
||||
}
|
||||
domains = append(domains, domain)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -182,8 +183,8 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
return err
|
||||
}
|
||||
configPath := GetSitePath(*website, SiteConf)
|
||||
nginxContent := string(nginx_conf.WebsiteDefault)
|
||||
config, err := parser.NewStringParser(nginxContent).Parse()
|
||||
nginxContent := nginx_conf.GetWebsiteFile("website_default.conf")
|
||||
config, err := parser.NewStringParser(string(nginxContent)).Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -651,22 +652,33 @@ func createPemFile(website model.Website, websiteSSL model.WebsiteSSL) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHttpsPort(website *model.Website) ([]int, error) {
|
||||
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(website.ID))
|
||||
var httpsPorts []int
|
||||
for _, domain := range websiteDomains {
|
||||
if domain.SSL {
|
||||
httpsPorts = append(httpsPorts, domain.Port)
|
||||
func getHttpsPort(websiteID uint) map[int]struct{} {
|
||||
domains, err := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteID))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
httpsPorts := make(map[int]struct{})
|
||||
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||
hasDefaultPort := false
|
||||
for _, domain := range domains {
|
||||
if domain.Port == nginxInstall.HttpPort {
|
||||
hasDefaultPort = true
|
||||
}
|
||||
if domain.SSL {
|
||||
httpsPorts[domain.Port] = struct{}{}
|
||||
}
|
||||
}
|
||||
if hasDefaultPort {
|
||||
httpsPorts[nginxInstall.HttpsPort] = struct{}{}
|
||||
}
|
||||
if len(httpsPorts) == 0 {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, domain := range domains {
|
||||
if !domain.SSL {
|
||||
httpsPorts[domain.Port] = struct{}{}
|
||||
}
|
||||
}
|
||||
httpsPorts = append(httpsPorts, nginxInstall.HttpsPort)
|
||||
}
|
||||
return httpsPorts, nil
|
||||
return httpsPorts
|
||||
}
|
||||
|
||||
func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.WebsiteHTTPSOp) error {
|
||||
@@ -678,63 +690,71 @@ func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.W
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
noDefaultPort := true
|
||||
httpPorts := make(map[int]struct{})
|
||||
httpsPorts := make(map[int]struct{})
|
||||
|
||||
hasDefaultPort := false
|
||||
for _, domain := range domains {
|
||||
if domain.Port == 80 {
|
||||
noDefaultPort = false
|
||||
if domain.Port == nginxFull.Install.HttpPort {
|
||||
hasDefaultPort = true
|
||||
}
|
||||
if domain.Port != 80 && !domain.SSL {
|
||||
if domain.SSL {
|
||||
httpsPorts[domain.Port] = struct{}{}
|
||||
} else {
|
||||
httpPorts[domain.Port] = struct{}{}
|
||||
}
|
||||
}
|
||||
if hasDefaultPort {
|
||||
httpsPorts[nginxFull.Install.HttpsPort] = struct{}{}
|
||||
}
|
||||
if len(httpsPorts) == 0 {
|
||||
for port := range httpPorts {
|
||||
httpsPorts[port] = struct{}{}
|
||||
}
|
||||
}
|
||||
config := nginxFull.SiteConfig.Config
|
||||
server := config.FindServers()[0]
|
||||
|
||||
httpPort := strconv.Itoa(nginxFull.Install.HttpPort)
|
||||
httpsPort, err := getHttpsPort(website)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpPortIPV6 := "[::]:" + httpPort
|
||||
defaultHttpPort := strconv.Itoa(nginxFull.Install.HttpPort)
|
||||
defaultHttpPortIPV6 := "[::]:" + defaultHttpPort
|
||||
|
||||
for _, port := range httpsPort {
|
||||
if _, ok := httpPorts[port]; !ok {
|
||||
server.DeleteListen(strconv.Itoa(port))
|
||||
}
|
||||
setListen(server, strconv.Itoa(port), website.IPV6, req.Http3, website.DefaultServer, true)
|
||||
for port := range httpsPorts {
|
||||
portStr := strconv.Itoa(port)
|
||||
server.RemoveListenByBind(portStr)
|
||||
server.RemoveListenByBind("[::]:" + portStr)
|
||||
setListen(server, portStr, website.IPV6, req.Http3, website.DefaultServer, true)
|
||||
}
|
||||
|
||||
server.UpdateDirective("http2", []string{"on"})
|
||||
|
||||
switch req.HttpConfig {
|
||||
case constant.HTTPSOnly:
|
||||
server.RemoveListenByBind(httpPort)
|
||||
server.RemoveListenByBind(httpPortIPV6)
|
||||
server.RemoveListenByBind(defaultHttpPort)
|
||||
server.RemoveListenByBind(defaultHttpPortIPV6)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
case constant.HTTPToHTTPS:
|
||||
if !noDefaultPort {
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
}
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
if hasDefaultPort {
|
||||
server.UpdateListen(defaultHttpPort, website.DefaultServer)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(defaultHttpPortIPV6, website.DefaultServer)
|
||||
}
|
||||
}
|
||||
server.AddHTTP2HTTPS()
|
||||
case constant.HTTPAlso:
|
||||
if !noDefaultPort {
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
if hasDefaultPort {
|
||||
server.UpdateListen(defaultHttpPort, website.DefaultServer)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(defaultHttpPortIPV6, website.DefaultServer)
|
||||
}
|
||||
}
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
}
|
||||
}
|
||||
|
||||
if !req.Hsts {
|
||||
server.RemoveDirective("add_header", []string{"Strict-Transport-Security", "\"max-age=31536000\""})
|
||||
}
|
||||
if !req.Http3 {
|
||||
for _, port := range httpsPort {
|
||||
for port := range httpsPorts {
|
||||
server.RemoveListen(strconv.Itoa(port), "quic")
|
||||
if website.IPV6 {
|
||||
httpsPortIPV6 := "[::]:" + strconv.Itoa(port)
|
||||
@@ -1011,7 +1031,7 @@ func chownRootDir(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, websiteID uint) (domainModels []model.WebsiteDomain, addPorts []int, addDomains []string, err error) {
|
||||
func getWebsiteDomains(domains []request.WebsiteDomain, defaultHTTPPort, defaultHTTPsPort int, websiteID uint) (domainModels []model.WebsiteDomain, addPorts []int, addDomains []string, err error) {
|
||||
var (
|
||||
ports = make(map[int]struct{})
|
||||
existPort = make(map[int]struct{})
|
||||
@@ -1036,7 +1056,7 @@ func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, website
|
||||
domainModel.Domain = strings.ToLower(domainModel.Domain)
|
||||
domainModel.Port = domain.Port
|
||||
if domain.Port == 0 {
|
||||
domain.Port = defaultPort
|
||||
domain.Port = defaultHTTPPort
|
||||
}
|
||||
domainModel.SSL = domain.SSL
|
||||
domainModel.WebsiteID = websiteID
|
||||
@@ -1057,7 +1077,7 @@ func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, website
|
||||
}
|
||||
|
||||
for port := range ports {
|
||||
if port == defaultPort {
|
||||
if port == defaultHTTPPort || port == defaultHTTPsPort {
|
||||
addPorts = append(addPorts, port)
|
||||
continue
|
||||
}
|
||||
@@ -1078,7 +1098,7 @@ func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, website
|
||||
err = buserr.WithMap("ErrPortExist", errMap, nil)
|
||||
return
|
||||
}
|
||||
if common.ScanPort(port) {
|
||||
if port != defaultHTTPsPort && common.ScanPort(port) {
|
||||
err = buserr.WithDetail("ErrPortInUsed", port, nil)
|
||||
return
|
||||
}
|
||||
@@ -1117,7 +1137,6 @@ func saveCertificateFile(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
|
||||
func GetSystemSSL() (bool, uint) {
|
||||
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
|
||||
return false, 0
|
||||
}
|
||||
if sslSetting.Value == "enable" {
|
||||
@@ -1425,3 +1444,22 @@ func hasDefaultServer(params []string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ParseDomain(domain string) (*model.WebsiteDomain, error) {
|
||||
host, portStr, err := net.SplitHostPort(domain)
|
||||
if err != nil {
|
||||
return &model.WebsiteDomain{
|
||||
Domain: domain,
|
||||
Port: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid port in domain %s: %v", domain, err)
|
||||
}
|
||||
return &model.WebsiteDomain{
|
||||
Domain: host,
|
||||
Port: port,
|
||||
}, nil
|
||||
}
|
||||
|
||||
+36
-1
@@ -63,6 +63,7 @@ const (
|
||||
TaskSync = "TaskSync"
|
||||
TaskBuild = "TaskBuild"
|
||||
TaskPull = "TaskPull"
|
||||
TaskCommit = "TaskCommit"
|
||||
TaskPush = "TaskPush"
|
||||
TaskHandle = "TaskHandle"
|
||||
)
|
||||
@@ -142,6 +143,40 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func ReNewTaskWithOps(resourceName, operate, scope, taskID string, resourceID uint) (*Task, error) {
|
||||
return ReNewTask(GetTaskName(resourceName, operate, scope), operate, scope, taskID, resourceID)
|
||||
}
|
||||
func ReNewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, error) {
|
||||
if taskID == "" {
|
||||
return NewTask(name, operate, taskScope, taskID, resourceID)
|
||||
}
|
||||
logDir := path.Join(global.Dir.TaskDir, taskScope)
|
||||
if _, err := os.Stat(logDir); err != nil {
|
||||
if err = os.MkdirAll(logDir, constant.DirPerm); err != nil {
|
||||
return nil, fmt.Errorf("failed to create log directory: %w", err)
|
||||
}
|
||||
}
|
||||
logPath := path.Join(global.Dir.TaskDir, taskScope, taskID+".log")
|
||||
file, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, constant.FilePerm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open log file: %w", err)
|
||||
}
|
||||
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}
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func (t *Task) AddSubTask(name string, action ActionFunc, rollback RollbackFunc) {
|
||||
subTask := &SubTask{RootTask: t, Name: name, Retry: 0, Timeout: 30 * time.Minute, Action: action, Rollback: rollback}
|
||||
t.SubTasks = append(t.SubTasks, subTask)
|
||||
@@ -158,7 +193,7 @@ func (t *Task) AddSubTaskWithOps(name string, action ActionFunc, rollback Rollba
|
||||
}
|
||||
|
||||
func (t *Task) AddSubTaskWithAliasAndOps(key string, action ActionFunc, rollback RollbackFunc, retry int, timeout time.Duration) {
|
||||
subTask := &SubTask{RootTask: t, Name: i18n.GetMsgByKey(key), Retry: retry, Timeout: timeout, Action: action, Rollback: rollback}
|
||||
subTask := &SubTask{RootTask: t, Name: i18n.GetMsgByKey(key), StepAlias: key, Retry: retry, Timeout: timeout, Action: action, Rollback: rollback}
|
||||
t.SubTasks = append(t.SubTasks, subTask)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
base:
|
||||
install_dir: /opt
|
||||
mode: dev
|
||||
is_demo: false
|
||||
|
||||
remote_url:
|
||||
app_repo: https://apps-assets.fit2cloud.com
|
||||
|
||||
@@ -9,9 +9,6 @@ import (
|
||||
//go:embed ssl.conf
|
||||
var SSL []byte
|
||||
|
||||
//go:embed website_default.conf
|
||||
var WebsiteDefault []byte
|
||||
|
||||
//go:embed index.html
|
||||
var Index []byte
|
||||
|
||||
@@ -48,7 +45,7 @@ var Upstream []byte
|
||||
//go:embed sse.conf
|
||||
var SSE []byte
|
||||
|
||||
//go:embed *.json
|
||||
//go:embed *.json *.conf
|
||||
var websitesFiles embed.FS
|
||||
|
||||
func GetWebsiteFile(filename string) []byte {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
[global]
|
||||
error_log = /var/log/php/fpm.error.log
|
||||
log_level = notice
|
||||
[www]
|
||||
user = www-data
|
||||
group = www-data
|
||||
listen = 0.0.0.0:9000
|
||||
pm = dynamic
|
||||
pm.max_children = 10
|
||||
pm.start_servers = 2
|
||||
pm.min_spare_servers = 1
|
||||
pm.max_spare_servers = 3
|
||||
pm.status_path = /status
|
||||
slowlog = /var/log/php/fpm.slow.log
|
||||
request_slowlog_timeout = 3
|
||||
catch_workers_output = yes
|
||||
@@ -376,5 +376,12 @@
|
||||
"file": "pcntl.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "sodium",
|
||||
"check": "sodium",
|
||||
"file": "sodium.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||
"installed": false
|
||||
}
|
||||
]
|
||||
|
||||
@@ -15,9 +15,16 @@ server {
|
||||
|
||||
access_log /www/sites/domain/log/access.log main;
|
||||
error_log /www/sites/domain/log/error.log;
|
||||
|
||||
|
||||
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md){
|
||||
return 404;
|
||||
}
|
||||
location ^~ /.well-known{
|
||||
allow all;
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,3 +10,18 @@ const (
|
||||
AlertPushError = "PushError"
|
||||
AlertPushSuccess = "PushSuccess"
|
||||
)
|
||||
|
||||
const (
|
||||
CommonConfig = "common"
|
||||
SMSConfig = "sms"
|
||||
EmailConfig = "email"
|
||||
)
|
||||
|
||||
const (
|
||||
WeChat = "wechat"
|
||||
SMS = "sms"
|
||||
Email = "mail"
|
||||
WeCom = "weCom"
|
||||
DingTalk = "dingTalk"
|
||||
FeiShu = "feiShu"
|
||||
)
|
||||
|
||||
+11
-8
@@ -6,14 +6,17 @@ const (
|
||||
AppNormal = "Normal"
|
||||
AppTakeDown = "TakeDown"
|
||||
|
||||
AppOpenresty = "openresty"
|
||||
AppMysql = "mysql"
|
||||
AppMariaDB = "mariadb"
|
||||
AppPostgresql = "postgresql"
|
||||
AppRedis = "redis"
|
||||
AppPostgres = "postgres"
|
||||
AppMongodb = "mongodb"
|
||||
AppMemcached = "memcached"
|
||||
AppOpenresty = "openresty"
|
||||
AppMysql = "mysql"
|
||||
AppMariaDB = "mariadb"
|
||||
AppPostgresql = "postgresql"
|
||||
AppRedis = "redis"
|
||||
AppPostgres = "postgres"
|
||||
AppMongodb = "mongodb"
|
||||
AppMemcached = "memcached"
|
||||
AppMysqlCluster = "mysql-cluster"
|
||||
AppPostgresqlCluster = "postgresql-cluster"
|
||||
AppRedisCluster = "redis-cluster"
|
||||
|
||||
AppResourceLocal = "local"
|
||||
AppResourceRemote = "remote"
|
||||
|
||||
@@ -13,6 +13,6 @@ const (
|
||||
ComposeOpStop = "stop"
|
||||
ComposeOpRestart = "restart"
|
||||
ComposeOpRemove = "remove"
|
||||
|
||||
DaemonJsonPath = "/etc/docker/daemon.json"
|
||||
)
|
||||
|
||||
var DaemonJsonPath = "/etc/docker/daemon.json"
|
||||
|
||||
@@ -41,11 +41,11 @@ var RuntimeDefaultVolumes = map[string]string{
|
||||
|
||||
var PHPDefaultVolumes = map[string]string{
|
||||
"${PANEL_WEBSITE_DIR}": "/www/",
|
||||
"./conf": "/usr/local/etc/php",
|
||||
"./conf/php.ini": "/usr/local/etc/php/php.ini",
|
||||
"./conf/conf.d": "/usr/local/etc/php/conf.d",
|
||||
"./conf/php-fpm.conf": "/usr/local/etc/php-fpm.d/www.conf",
|
||||
"./conf/php-fpm.conf": "/usr/local/etc/php-fpm.conf",
|
||||
"./log": "/var/log/php",
|
||||
"./extensions": "${EXTENSION_DIR}",
|
||||
"./extensions": "/usr/local/lib/php/extensions",
|
||||
"./supervisor/supervisord.conf": "/etc/supervisord.conf",
|
||||
"./supervisor/supervisor.d/php-fpm.ini": "/etc/supervisor.d/php-fpm.ini",
|
||||
"./supervisor/supervisor.d": "/etc/supervisor.d",
|
||||
|
||||
@@ -5,6 +5,7 @@ const (
|
||||
StatusCanceled = "Canceled"
|
||||
StatusDone = "Done"
|
||||
StatusWaiting = "Waiting"
|
||||
StatusPending = "Pending"
|
||||
StatusSuccess = "Success"
|
||||
StatusFailed = "Failed"
|
||||
StatusUploading = "Uploading"
|
||||
|
||||
@@ -18,7 +18,7 @@ func NewBackupJob() *backup {
|
||||
|
||||
func (b *backup) Run() {
|
||||
var backups []model.BackupAccount
|
||||
_ = global.DB.Where("`type` in (?) AND is_public = 0", []string{constant.OneDrive, constant.ALIYUN, constant.GoogleDrive}).Find(&backups)
|
||||
_ = global.DB.Where("`type` in (?) AND is_public = 0", []string{constant.OneDrive, constant.ALIYUN}).Find(&backups)
|
||||
if len(backups) == 0 {
|
||||
return
|
||||
}
|
||||
@@ -39,8 +39,6 @@ func (b *backup) Run() {
|
||||
switch backupItem.Type {
|
||||
case constant.OneDrive:
|
||||
refreshToken, err = client.RefreshToken("refresh_token", "refreshToken", varMap)
|
||||
case constant.GoogleDrive:
|
||||
refreshToken, err = client.RefreshGoogleToken("refresh_token", "refreshToken", varMap)
|
||||
case constant.ALIYUN:
|
||||
refreshToken, err = client.RefreshALIToken(varMap)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ var (
|
||||
MonitorDB *gorm.DB
|
||||
TaskDB *gorm.DB
|
||||
CoreDB *gorm.DB
|
||||
AlertDB *gorm.DB
|
||||
|
||||
LOG *logrus.Logger
|
||||
CONF ServerConfig
|
||||
@@ -30,4 +31,7 @@ var (
|
||||
IsMaster bool
|
||||
|
||||
I18n *i18n.Localizer
|
||||
|
||||
AlertBaseJobID cron.EntryID
|
||||
AlertResourceJobID cron.EntryID
|
||||
)
|
||||
|
||||
+12
-12
@@ -40,6 +40,7 @@ require (
|
||||
github.com/shirou/gopsutil/v3 v3.24.5
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/afero v1.11.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/studio-b12/gowebdav v0.9.0
|
||||
github.com/subosito/gotenv v1.6.0
|
||||
@@ -47,13 +48,13 @@ require (
|
||||
github.com/upyun/go-sdk v2.1.0+incompatible
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/oauth2 v0.29.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/text v0.26.0
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/gorm v1.25.11
|
||||
gorm.io/gorm v1.30.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -98,7 +99,7 @@ require (
|
||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
@@ -106,7 +107,7 @@ require (
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
@@ -114,7 +115,6 @@ require (
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/h2non/filetype v1.1.1 // indirect
|
||||
@@ -162,6 +162,7 @@ require (
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/mozillazg/go-httpheader v0.2.1 // indirect
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
|
||||
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/mailinabox v0.2.0 // indirect
|
||||
@@ -184,7 +185,6 @@ require (
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 // indirect
|
||||
@@ -224,17 +224,17 @@ require (
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
|
||||
google.golang.org/grpc v1.72.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
modernc.org/libc v1.66.1 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.38.0 // indirect
|
||||
)
|
||||
|
||||
+43
-23
@@ -257,8 +257,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
|
||||
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
|
||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV4=
|
||||
@@ -311,8 +311,8 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
@@ -396,8 +396,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
@@ -571,9 +571,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
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/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
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=
|
||||
@@ -650,6 +649,8 @@ github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/
|
||||
github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
|
||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
@@ -755,7 +756,6 @@ github.com/qiniu/go-sdk/v7 v7.21.1/go.mod h1:8EM2awITynlem2VML2dXGHkMYP2UyECsGLO
|
||||
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
@@ -1004,8 +1004,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
@@ -1092,6 +1092,8 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1261,8 +1263,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1396,8 +1398,8 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
|
||||
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
|
||||
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -1407,14 +1409,32 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
|
||||
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
|
||||
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
|
||||
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
||||
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
|
||||
modernc.org/fileutil v1.3.3 h1:3qaU+7f7xxTUmvU1pJTZiDLAIoJVdUSSauJNHg9yXoA=
|
||||
modernc.org/fileutil v1.3.3/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/goabi0 v0.0.3 h1:y81b9r3asCh6Xtse6Nz85aYGB0cG3M3U6222yap1KWI=
|
||||
modernc.org/goabi0 v0.0.3/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.66.1 h1:4uQsntXbVyAgrV+j6NhKvDiUypoJL48BWQx6sy9y8ok=
|
||||
modernc.org/libc v1.66.1/go.mod h1:AiZxInURfEJx516LqEaFcrC+X38rt9G7+8ojIXQKHbo=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI=
|
||||
modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
@@ -133,6 +133,7 @@ func Init() {
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ru.yaml")
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
|
||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/tr.yaml")
|
||||
lang := GetLanguageFromDB()
|
||||
global.I18n = i18n.NewLocalizer(bundle, lang)
|
||||
}
|
||||
|
||||
+20
-2
@@ -177,7 +177,7 @@ ErrPgImagePull: 'Image pull timed out, please configure image acceleration or ma
|
||||
#runtime
|
||||
ErrFileNotExist: '{{ .detail }} file does not exist! Please check the integrity of the source file!'
|
||||
ErrImageBuildErr: 'Image build failed'
|
||||
ErrImageExist: 'Image already exists!'
|
||||
ErrImageExist: "Image already exists! Please modify the image name."
|
||||
ErrDelWithWebsite: 'The operating environment is already associated with a website and cannot be deleted'
|
||||
ErrRuntimeStart: 'Startup failed'
|
||||
ErrPackageJsonNotFound: 'package.json file does not exist'
|
||||
@@ -205,6 +205,8 @@ SystemLog: 'System Log'
|
||||
CutWebsiteLog: 'Rotate Website Log'
|
||||
FileOrDir: 'Directory / File'
|
||||
UploadFile: 'Uploading backup file {{ .file }} to {{ .backup }}'
|
||||
IgnoreBackupErr: 'Backup failed, error: {{ .detail }}, ignoring this error...'
|
||||
IgnoreUploadErr: 'Upload failed, error: {{ .detail }}, ignoring this error...'
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: 'The current user does not exist, please modify and try again!'
|
||||
@@ -285,6 +287,7 @@ TaskBackup: 'Backup'
|
||||
TaskRecover: 'Recover'
|
||||
TaskRollback: 'Rollback'
|
||||
TaskPull: 'Pull'
|
||||
TaskCommit: 'Commit'
|
||||
TaskBuild: 'Build'
|
||||
TaskPush: 'Push'
|
||||
TaskHandle: 'Execute'
|
||||
@@ -333,6 +336,7 @@ SnapDeleteLoginLog: 'Delete access log'
|
||||
SnapDeleteMonitor: 'Delete monitoring data'
|
||||
SnapRemoveSystemIP: 'Remove system IP'
|
||||
SnapBaseInfo: 'Write 1Panel basic information'
|
||||
SnapInstallAppImageEmpty: 'No application images selected, skipping...'
|
||||
SnapInstallApp: 'Backup 1Panel installed applications'
|
||||
SnapDockerSave: 'Compress installed applications'
|
||||
SnapLocalBackup: 'Backup 1Panel local backup directory'
|
||||
@@ -420,4 +424,18 @@ ErrAlertSync: 'Alarm information synchronization error, please check and try aga
|
||||
ErrAlertRemote: 'Alarm message remote error, please check and try again!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "An installation task is already in progress, please wait for the task to finish"
|
||||
ErrInstallExtension: "An installation task is already in progress, please wait for the task to finish"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "Panel Alert Notification"
|
||||
TestAlertTitle: "Test Email - Verify Email Connectivity"
|
||||
TestAlert: "This is a test email to verify that your email sending configuration is correct."
|
||||
LicenseExpirationAlert: "Your 1Panel license will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
CronJobFailedAlert: "Your 1Panel scheduled task '{{ .name }}' has failed. Please log in to the panel for details."
|
||||
ClamAlert: "Your 1Panel virus scan task has detected {{ .num }} infected files. Please log in to the panel for details."
|
||||
WebSiteAlert: "There are {{ .num }} websites on your 1Panel that will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
SSLAlert: "There are {{ .num }} SSL certificates on your 1Panel that will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
DiskUsedAlert: "Your 1Panel disk '{{ .name }}' has used {{ .used }}. Please log in to the panel for details."
|
||||
ResourceAlert: "The average {{ .name }} usage over {{ .time }} minutes on your 1Panel is {{ .used }}. Please log in to the panel for details."
|
||||
PanelVersionAlert: "A new version of 1Panel is available. Please log in to the panel to upgrade."
|
||||
PanelPwdExpirationAlert: "Your 1Panel password will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
+22
-4
@@ -177,7 +177,7 @@ ErrPgImagePull: 'イメージのプルがタイムアウトしました。イメ
|
||||
#runtime
|
||||
ErrFileNotExist: '{{ .detail }} ファイルが存在しません。ソース ファイルの整合性を確認してください。'
|
||||
ErrImageBuildErr: 'イメージのビルドに失敗しました'
|
||||
ErrImageExist: '画像がすでに存在します!'
|
||||
ErrImageExist: "イメージはすでに存在します!イメージ名を変更してください。"
|
||||
ErrDelWithWebsite: 'オペレーティング環境は既に Web サイトに関連付けられているため、削除できません'
|
||||
ErrRuntimeStart: '起動に失敗しました'
|
||||
ErrPackageJsonNotFound: 'package.json ファイルが存在しません'
|
||||
@@ -205,6 +205,8 @@ SystemLog: 'システムログ'
|
||||
CutWebsiteLog: 'ウェブサイトログのローテーション'
|
||||
FileOrDir: 'ディレクトリ / ファイル'
|
||||
UploadFile: 'バックアップファイル {{ .file }} を {{ .backup }} にアップロード中'
|
||||
IgnoreBackupErr: 'バックアップ失敗、エラー:{{ .detail }}、このエラーを無視します...'
|
||||
IgnoreUploadErr: 'アップロード失敗、エラー:{{ .detail }}、このエラーを無視します...'
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: '現在のユーザーは存在しません。変更してもう一度お試しください。'
|
||||
@@ -285,6 +287,7 @@ TaskBackup: 'バックアップ'
|
||||
TaskRecover: '回復'
|
||||
TaskRollback: 'ロールバック'
|
||||
TaskPull: 'プル'
|
||||
TaskCommit: 'コミット'
|
||||
TaskBuild: 'ビルド'
|
||||
TaskPush: 'プッシュ'
|
||||
TaskHandle: '実行'
|
||||
@@ -323,7 +326,7 @@ CustomAppstore: 'カスタム アプリケーション ウェアハウス'
|
||||
OllamaModelPull: 'Ollama モデル {{ .name }} をプルします'
|
||||
OllamaModelSize: "Ollama モデル {{ .name }} のサイズを取得します"
|
||||
|
||||
#task - snapshot
|
||||
#task - snapshot
|
||||
Snapshot: 'スナップショット'
|
||||
SnapDBInfo: '1Panel データベース情報を書き込む'
|
||||
SnapCopy: 'ファイルとディレクトリ {{ .name }} をコピーします'
|
||||
@@ -333,7 +336,8 @@ SnapDeleteLoginLog: 'アクセスログを削除する'
|
||||
SnapDeleteMonitor: '監視データを削除する'
|
||||
SnapRemoveSystemIP: 'システム IP を削除します'
|
||||
SnapBaseInfo: '1Panel の基本情報を書き込む'
|
||||
SnapInstallApp: '1Panel にインストールされたアプリケーションをバックアップする'
|
||||
SnapInstallAppImageEmpty: 'アプリケーションイメージが選択されていないため、スキップします...'
|
||||
SnapInstallApp: '1Panelインストール済みアプリケーションのバックアップ'
|
||||
SnapDockerSave: 'インストールされたアプリケーションを圧縮する'
|
||||
SnapLocalBackup: '1Panel ローカル バックアップ ディレクトリをバックアップします'
|
||||
SnapCompressBackup: 'ローカル バックアップ ディレクトリを圧縮する'
|
||||
@@ -420,4 +424,18 @@ ErrAlertSync: 'アラーム情報の同期エラーです。確認してもう
|
||||
ErrAlertRemote: 'アラーム メッセージのリモート エラーです。確認してもう一度お試しください。'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "インストールタスクが進行中です、タスクが終了するのを待ってください"
|
||||
ErrInstallExtension: "インストールタスクが進行中です、タスクが終了するのを待ってください"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "パネルアラート通知"
|
||||
TestAlertTitle: "テストメール - メール接続の確認"
|
||||
TestAlert: "これはテストメールです。メール送信設定が正しく構成されているかを確認します。"
|
||||
LicenseExpirationAlert: "お使いの 1Panel ライセンスは {{ .day }} 日後に有効期限が切れます。詳細はパネルにログインしてご確認ください。"
|
||||
CronJobFailedAlert: "1Panel のスケジュールタスク '{{ .name }}' の実行に失敗しました。詳細はパネルでご確認ください。"
|
||||
ClamAlert: "1Panel のウイルススキャンで {{ .num }} 件の感染ファイルが検出されました。詳細はパネルでご確認ください。"
|
||||
WebSiteAlert: "1Panel にある {{ .num }} 件のウェブサイトが {{ .day }} 日後に有効期限を迎えます。詳細はパネルでご確認ください。"
|
||||
SSLAlert: "1Panel にある {{ .num }} 枚のSSL証明書が {{ .day }} 日後に有効期限を迎えます。詳細はパネルでご確認ください。"
|
||||
DiskUsedAlert: "1Panel のディスク '{{ .name }}' は {{ .used }} 使用されています。詳細はパネルでご確認ください。"
|
||||
ResourceAlert: "1Panel の {{ .time }} 分間の平均 {{ .name }} 使用率は {{ .used }} です。詳細はパネルでご確認ください。"
|
||||
PanelVersionAlert: "1Panel に新しいバージョンが利用可能です。アップグレードはパネルから行ってください。"
|
||||
PanelPwdExpirationAlert: "1Panel のパスワードは {{ .day }} 日後に期限切れとなります。詳細はパネルでご確認ください。"
|
||||
+20
-2
@@ -177,7 +177,7 @@ ErrPgImagePull: '이미지 풀링 시간이 초과되었습니다. 이미지 가
|
||||
#실행 시간
|
||||
ErrFileNotExist: '{{ .detail }} 파일이 존재하지 않습니다! 소스 파일의 무결성을 확인하세요!'
|
||||
ErrImageBuildErr: '이미지 빌드 실패'
|
||||
ErrImageExist: '이미지가 이미 존재합니다!'
|
||||
ErrImageExist: "이미지가 이미 존재합니다! 이미지 이름을 수정하세요."
|
||||
ErrDelWithWebsite: '운영 환경이 이미 웹사이트와 연결되어 있어 삭제할 수 없습니다'
|
||||
ErrRuntimeStart: '시작 실패'
|
||||
ErrPackageJsonNotFound: 'package.json 파일이 존재하지 않습니다'
|
||||
@@ -205,6 +205,8 @@ SystemLog: '시스템 로그'
|
||||
CutWebsiteLog: '웹사이트 로그 회전'
|
||||
FileOrDir: '디렉터리 / 파일'
|
||||
UploadFile: '백업 파일 {{ .file }} 을(를) {{ .backup }}(으)로 업로드 중'
|
||||
IgnoreBackupErr: 'Sandaran gagal, ralat: {{ .detail }}, abaikan ralat ini...'
|
||||
IgnoreUploadErr: 'Muat naik gagal, ralat: {{ .detail }}, abaikan ralat ini...'
|
||||
|
||||
#도구상자
|
||||
ErrNotExistUser: '현재 사용자가 존재하지 않습니다. 수정한 후 다시 시도하세요!'
|
||||
@@ -285,6 +287,7 @@ TaskBackup: '백업'
|
||||
TaskRecover: '복구'
|
||||
TaskRollback: '롤백'
|
||||
TaskPull: '당기기'
|
||||
TaskCommit: '커밋'
|
||||
TaskBuild: '빌드'
|
||||
TaskPush: '푸시'
|
||||
TaskHandle: '실행'
|
||||
@@ -333,6 +336,7 @@ SnapDeleteLoginLog: '액세스 로그 삭제'
|
||||
SnapDeleteMonitor: '모니터링 데이터 삭제'
|
||||
SnapRemoveSystemIP: '시스템 IP 제거'
|
||||
SnapBaseInfo: '1패널 기본 정보 쓰기'
|
||||
SnapInstallAppImageEmpty: '애플리케이션 이미지가 선택되지 않아 건너뜁니다...'
|
||||
SnapInstallApp: '1Panel 설치된 애플리케이션 백업'
|
||||
SnapDockerSave: '설치된 애플리케이션 압축'
|
||||
SnapLocalBackup: '1Panel 로컬 백업 디렉토리 백업'
|
||||
@@ -420,4 +424,18 @@ ErrAlertSync: '알람 정보 동기화 오류입니다. 확인하고 다시 시
|
||||
ErrAlertRemote: '알람 메시지 원격 오류, 확인하고 다시 시도하세요!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "이미 설치 작업이 진행 중입니다. 작업이 완료될 때까지 기다려 주세요."
|
||||
ErrInstallExtension: "이미 설치 작업이 진행 중입니다. 작업이 완료될 때까지 기다려 주세요."
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "패널 알림 통지"
|
||||
TestAlertTitle: "테스트 이메일 - 이메일 연결 확인"
|
||||
TestAlert: "이것은 테스트 이메일이며 이메일 발송 설정이 올바른지 확인합니다."
|
||||
LicenseExpirationAlert: "귀하의 1Panel 라이선스는 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하세요."
|
||||
CronJobFailedAlert: "1Panel 예약 작업 '{{ .name }}' 실행에 실패했습니다. 자세한 내용은 패널에서 확인하세요."
|
||||
ClamAlert: "1Panel 바이러스 검사에서 {{ .num }}개의 감염된 파일이 발견되었습니다. 자세한 내용은 패널에서 확인하세요."
|
||||
WebSiteAlert: "1Panel 에 있는 {{ .num }}개의 웹사이트가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||
SSLAlert: "1Panel 에 있는 {{ .num }}개의 SSL 인증서가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||
DiskUsedAlert: "1Panel 디스크 '{{ .name }}'의 사용량은 {{ .used }}입니다. 자세한 내용은 패널에서 확인하세요."
|
||||
ResourceAlert: "1Panel 의 평균 {{ .time }}분 동안 {{ .name }} 사용률은 {{ .used }}입니다. 자세한 내용은 패널에서 확인하세요."
|
||||
PanelVersionAlert: "1Panel 의 새로운 버전이 이용 가능합니다. 패널에 로그인하여 업그레이드하세요."
|
||||
PanelPwdExpirationAlert: "1Panel 비밀번호가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||
+21
-3
@@ -176,7 +176,7 @@ ErrPgImagePull: 'Tarikh imej tamat masa, sila konfigurasikan pecutan imej atau t
|
||||
#masa berjalan
|
||||
ErrFileNotExist: 'Fail {{ .detail }} tidak wujud! Sila semak integriti fail sumber!'
|
||||
ErrImageBuildErr: 'Pembinaan imej gagal'
|
||||
ErrImageExist: 'Imej sudah wujud!'
|
||||
ErrImageExist: "Imej sudah wujud! Sila ubah nama imej."
|
||||
ErrDelWithWebsite: 'Persekitaran pengendalian sudah dikaitkan dengan tapak web dan tidak boleh dipadamkan'
|
||||
ErrRuntimeStart: 'Permulaan gagal'
|
||||
ErrPackageJsonNotFound: 'fail package.json tidak wujud'
|
||||
@@ -204,6 +204,8 @@ SystemLog: 'Log Sistem'
|
||||
CutWebsiteLog: 'Putar Log Laman Web'
|
||||
FileOrDir: 'Direktori / Fail'
|
||||
UploadFile: 'Muat naik fail sandaran {{ .file }} ke {{ .backup }}'
|
||||
IgnoreBackupErr: 'Sandaran gagal, ralat: {{ .detail }}, abaikan ralat ini...'
|
||||
IgnoreUploadErr: 'Muat naik gagal, ralat: {{ .detail }}, abaikan ralat ini...'
|
||||
|
||||
#kotak alat
|
||||
ErrNotExistUser: 'Pengguna semasa tidak wujud, sila ubah suai dan cuba lagi!'
|
||||
@@ -284,6 +286,7 @@ TaskBackup: 'Sandaran'
|
||||
TaskRecover: 'Pulihkan'
|
||||
TaskRollback: 'Rollback'
|
||||
TaskPull: 'Tarik'
|
||||
TaskCommit: 'Komit'
|
||||
TaskBuild: 'Bina'
|
||||
TaskPush: 'Tolak'
|
||||
TaskHandle: 'Laksanakan'
|
||||
@@ -332,7 +335,8 @@ SnapDeleteLoginLog: 'Padam log akses'
|
||||
SnapDeleteMonitor: 'Padamkan data pemantauan'
|
||||
SnapRemoveSystemIP: 'Alih keluar IP sistem'
|
||||
SnapBaseInfo: 'Tulis maklumat asas 1Panel'
|
||||
SnapInstallApp: 'Aplikasi yang dipasang sandaran 1Panel'
|
||||
SnapInstallAppImageEmpty: 'Tiada imej aplikasi dipilih, dilangkau...'
|
||||
SnapInstallApp: 'Sandaran aplikasi terpasang 1Panel'
|
||||
SnapDockerSave: 'Mampatkan aplikasi yang dipasang'
|
||||
SnapLocalBackup: 'Sandaran 1Panel direktori sandaran tempatan'
|
||||
SnapCompressBackup: 'Mampatkan direktori sandaran tempatan'
|
||||
@@ -419,4 +423,18 @@ ErrAlertSync: 'Ralat penyegerakan maklumat penggera, sila semak dan cuba lagi!'
|
||||
ErrAlertRemote: 'Ralat jauh mesej penggera, sila semak dan cuba lagi!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "Tugas pemasangan sudah sedang berjalan, silakan tunggu tugas selesai"
|
||||
ErrInstallExtension: "Tugas pemasangan sudah sedang berjalan, silakan tunggu tugas selesai"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "Notifikasi Amaran Panel"
|
||||
TestAlertTitle: "E-mel Ujian - Sahkan Sambungan E-mel"
|
||||
TestAlert: "Ini adalah e-mel ujian untuk mengesahkan konfigurasi penghantaran e-mel anda betul."
|
||||
LicenseExpirationAlert: "Lesen 1Panel anda akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
CronJobFailedAlert: "Tugas berjadual 1Panel '{{ .name }}' gagal dilaksanakan. Sila log masuk ke panel untuk butiran lanjut."
|
||||
ClamAlert: "Tugas imbasan virus 1Panel menemui {{ .num }} fail yang dijangkiti. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
WebSiteAlert: "Terdapat {{ .num }} laman web dalam 1Panel anda yang akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
SSLAlert: "Terdapat {{ .num }} sijil SSL dalam 1Panel anda yang akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
DiskUsedAlert: "Cakera '{{ .name }}' dalam 1Panel anda telah menggunakan {{ .used }}. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
ResourceAlert: "Penggunaan purata {{ .name }} selama {{ .time }} minit dalam 1Panel anda ialah {{ .used }}. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
PanelVersionAlert: "Versi baru 1Panel tersedia. Sila log masuk ke panel untuk menaik taraf."
|
||||
PanelPwdExpirationAlert: "Kata laluan 1Panel anda akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
@@ -177,7 +177,7 @@ ErrPgImagePull: 'Tempo limite para extração de imagem. Configure a aceleraçã
|
||||
#tempo de execução
|
||||
ErrFileNotExist: 'O arquivo {{ .detail }} não existe! Verifique a integridade do arquivo de origem!'
|
||||
ErrImageBuildErr: 'Falha na criação da imagem'
|
||||
ErrImageExist: 'A imagem já existe!'
|
||||
ErrImageExist: "A imagem já existe! Por favor, modifique o nome da imagem."
|
||||
ErrDelWithWebsite: 'O ambiente operacional já está associado a um site e não pode ser excluído'
|
||||
ErrRuntimeStart: 'Falha na inicialização'
|
||||
ErrPackageJsonNotFound: 'o arquivo package.json não existe'
|
||||
@@ -205,6 +205,8 @@ SystemLog: 'Log do Sistema'
|
||||
CutWebsiteLog: 'Rotacionar Log do Website'
|
||||
FileOrDir: 'Diretório / Arquivo'
|
||||
UploadFile: 'Enviando arquivo de backup {{ .file }} para {{ .backup }}'
|
||||
IgnoreBackupErr: 'Backup falhou, erro: {{ .detail }}, ignorando este erro...'
|
||||
IgnoreUploadErr: 'Upload falhou, erro: {{ .detail }}, ignorando este erro...'
|
||||
|
||||
#caixa de ferramentas
|
||||
ErrNotExistUser: 'O usuário atual não existe, modifique e tente novamente!'
|
||||
@@ -285,6 +287,7 @@ Backup de Tarefa: 'Backup'
|
||||
TaskRecover: 'Recuperar'
|
||||
TaskRollback: 'Reverter'
|
||||
TaskPull: 'Puxar'
|
||||
TaskCommit: 'Commit'
|
||||
TaskBuild: 'Construir'
|
||||
TaskPush: 'Empurrar'
|
||||
TaskHandle: 'Executar'
|
||||
@@ -333,7 +336,8 @@ SnapDeleteLoginLog: 'Excluir log de acesso'
|
||||
SnapDeleteMonitor: 'Excluir dados de monitoramento'
|
||||
SnapRemoveSystemIP: 'Remover IP do sistema'
|
||||
SnapBaseInfo: 'Escreva informações básicas do 1Panel'
|
||||
SnapInstallApp: 'Fazer backup dos aplicativos instalados do 1Panel'
|
||||
SnapInstallAppImageEmpty: 'Nenhuma imagem de aplicativo selecionada, pulando...'
|
||||
SnapInstallApp: 'Backup dos aplicativos instalados do 1Panel'
|
||||
SnapDockerSave: 'Compactar aplicativos instalados'
|
||||
SnapLocalBackup: 'Backup do diretório de backup local do 1Panel'
|
||||
SnapCompressBackup: 'Compactar diretório de backup local'
|
||||
@@ -420,4 +424,18 @@ ErrAlertSync: 'Erro de sincronização de informações de alarme, verifique e t
|
||||
ErrAlertRemote: 'Erro remoto na mensagem de alarme, verifique e tente novamente!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "Já existe uma tarefa de instalação em andamento, aguarde a conclusão da tarefa"
|
||||
ErrInstallExtension: "Já existe uma tarefa de instalação em andamento, aguarde a conclusão da tarefa"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "Notificação de Alerta do Painel"
|
||||
TestAlertTitle: "E-mail de Teste - Verificar Conectividade de E-mail"
|
||||
TestAlert: "Este é um e-mail de teste para verificar se sua configuração de envio de e-mails está correta."
|
||||
LicenseExpirationAlert: "A licença do seu 1Panel expirará em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
CronJobFailedAlert: "A tarefa agendada '{{ .name }}' do seu 1Panel falhou. Acesse o painel para mais detalhes."
|
||||
ClamAlert: "A verificação de vírus do 1Panel detectou {{ .num }} arquivos infectados. Acesse o painel para mais detalhes."
|
||||
WebSiteAlert: "{{ .num }} sites do seu 1Panel expirarão em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
SSLAlert: "{{ .num }} certificados SSL do seu 1Panel expirarão em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
DiskUsedAlert: "O disco '{{ .name }}' do seu 1Panel está com uso de {{ .used }}. Acesse o painel para mais detalhes."
|
||||
ResourceAlert: "O uso médio de {{ .name }} em {{ .time }} minutos no seu 1Panel é de {{ .used }}. Acesse o painel para mais detalhes."
|
||||
PanelVersionAlert: "Uma nova versão do 1Panel está disponível. Acesse o painel para atualizá-lo."
|
||||
PanelPwdExpirationAlert: "A senha do 1Panel expirará em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
+21
-3
@@ -177,7 +177,7 @@ ErrPgImagePull: 'Время извлечения изображения исте
|
||||
#время выполнения
|
||||
ErrFileNotExist: 'Файл {{ .detail }} не существует! Проверьте целостность исходного файла!'
|
||||
ErrImageBuildErr: 'Сборка образа не удалась'
|
||||
ErrImageExist: 'Изображение уже существует!'
|
||||
ErrImageExist: "Изображение уже существует! Пожалуйста, измените имя изображения."
|
||||
ErrDelWithWebsite: 'Операционная среда уже связана с веб-сайтом и не может быть удалена'
|
||||
ErrRuntimeStart: 'Запуск не удался'
|
||||
ErrPackageJsonNotFound: 'файл package.json не существует'
|
||||
@@ -205,6 +205,8 @@ SystemLog: 'Системный лог'
|
||||
CutWebsiteLog: 'Ротация логов сайта'
|
||||
FileOrDir: 'Каталог / Файл'
|
||||
UploadFile: 'Загрузка файла резервной копии {{ .file }} в {{ .backup }}'
|
||||
IgnoreBackupErr: 'Ошибка резервного копирования: {{ .detail }}, игнорируем эту ошибку...'
|
||||
IgnoreUploadErr: 'Ошибка загрузки: {{ .detail }}, игнорируем эту ошибку...'
|
||||
|
||||
#ящик для инструментов
|
||||
ErrNotExistUser: 'Текущий пользователь не существует, измените его и повторите попытку!'
|
||||
@@ -285,6 +287,7 @@ TaskBackup: 'Резервное копирование'
|
||||
TaskRecover: 'Восстановить'
|
||||
TaskRollback: 'Откат'
|
||||
TaskPull: 'Вытянуть'
|
||||
TaskCommit: 'Kоммит'
|
||||
ЗадачаСборка: 'Сборка'
|
||||
TaskPush: 'Push'
|
||||
TaskHandle: 'Выполнить'
|
||||
@@ -333,7 +336,8 @@ SnapDeleteLoginLog: 'Удалить журнал доступа'
|
||||
SnapDeleteMonitor: 'Удалить данные мониторинга'
|
||||
SnapRemoveSystemIP: 'Удалить системный IP'
|
||||
SnapBaseInfo: 'Записать основную информацию 1Panel'
|
||||
SnapInstallApp: 'Резервное копирование установленных приложений 1Panel'
|
||||
SnapInstallAppImageEmpty: 'Образы приложений не выбраны, пропускаем...'
|
||||
SnapInstallApp: 'Резервное копирование приложений, установленных в 1Panel'
|
||||
SnapDockerSave: 'Сжать установленные приложения'
|
||||
SnapLocalBackup: 'Резервное копирование локального каталога резервных копий 1Panel'
|
||||
SnapCompressBackup: 'Сжать локальный каталог резервных копий'
|
||||
@@ -420,4 +424,18 @@ ErrAlertSync: 'Ошибка синхронизации информации о
|
||||
ErrAlertRemote: 'Ошибка удаленного сообщения об ошибке, проверьте и повторите попытку!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "Уже выполняется задача установки, подождите, пока задача завершится"
|
||||
ErrInstallExtension: "Уже выполняется задача установки, подождите, пока задача завершится"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "Уведомление панели"
|
||||
TestAlertTitle: "Тестовое письмо - проверка подключения"
|
||||
TestAlert: "Это тестовое письмо для проверки правильности настройки отправки писем."
|
||||
LicenseExpirationAlert: "Срок действия лицензии на 1Panel истекает через {{ .day }} дней. Подробности смотрите в панели."
|
||||
CronJobFailedAlert: "Запланированное задание '{{ .name }}' на вашем 1Panel завершилось с ошибкой. Подробности в панели."
|
||||
ClamAlert: "Антивирусная проверка 1Panel обнаружила {{ .num }} заражённых файлов. Подробности смотрите в панели."
|
||||
WebSiteAlert: "На вашем 1Panel {{ .num }} веб-сайтов истекают через {{ .day }} дней. Подробности смотрите в панели."
|
||||
SSLAlert: "На вашем 1Panel {{ .num }} SSL-сертификатов истекают через {{ .day }} дней. Подробности смотрите в панели."
|
||||
DiskUsedAlert: "Диск '{{ .name }}' на вашем 1Panel использует {{ .used }}. Подробности смотрите в панели."
|
||||
ResourceAlert: "Средняя загрузка {{ .name }} за {{ .time }} минут составляет {{ .used }}. Подробности смотрите в панели."
|
||||
PanelVersionAlert: "Доступна новая версия 1Panel. Обновитесь через панель."
|
||||
PanelPwdExpirationAlert: "Пароль для 1Panel истекает через {{ .day }} дней. Подробности смотрите в панели."
|
||||
@@ -0,0 +1,439 @@
|
||||
ErrInvalidParams: 'İstek parametre hatası: {{ .detail }}'
|
||||
ErrTokenParse: 'Token oluşturma hatası: {{ .detail }}'
|
||||
ErrInitialPassword: 'Orijinal şifre yanlış'
|
||||
ErrInternalServer: 'Dahili sunucu hatası: {{ .detail }}'
|
||||
ErrRecordExist: 'Kayıt zaten mevcut'
|
||||
ErrRecordNotFound: 'Kayıt bulunamadı'
|
||||
ErrStructTransform: 'Tür dönüştürme başarısız: {{ .err }}'
|
||||
ErrNotLogin: 'Kullanıcı giriş yapmamış: {{ .detail }}'
|
||||
ErrPasswordExpired: 'Mevcut şifrenin süresi dolmuş: {{ .detail }}'
|
||||
ErrNotSupportType: 'Sistem mevcut türü desteklemiyor: {{ .name }}'
|
||||
ErrProxy: 'İstek hatası, lütfen düğüm durumunu kontrol edin: {{ .detail }}'
|
||||
ErrApiConfigStatusInvalid: 'API arayüzüne erişim yasak: {{ .detail }}'
|
||||
ErrApiConfigKeyInvalid: 'API arayüz anahtarı hatası: {{ .detail }}'
|
||||
ErrApiConfigIPInvalid: 'API arayüzünü çağırmak için kullanılan IP beyaz listede değil: {{ .detail }}'
|
||||
ErrApiConfigDisable: 'Bu arayüz API arayüz çağrılarının kullanımını yasaklıyor: {{ .detail }}'
|
||||
ErrApiConfigKeyTimeInvalid: 'API arayüz zaman damgası hatası: {{ .detail }}'
|
||||
|
||||
#common
|
||||
ErrUsernameIsExist: 'Kullanıcı adı zaten mevcut'
|
||||
ErrNameIsExist: 'İsim zaten mevcut'
|
||||
ErrDemoEnvironment: 'Demo sunucu, bu işlem yasak!'
|
||||
ErrCmdTimeout: 'Komut yürütme zaman aşımına uğradı!'
|
||||
ErrCmdIllegal: 'Yürütme komutunda yasak karakterler var, lütfen değiştirin ve tekrar deneyin!'
|
||||
ErrPortExist: '{{ .port }} portu zaten {{ .type }} [{{ .name }}] tarafından kullanılıyor'
|
||||
TYPE_APP: 'Uygulama'
|
||||
TYPE_RUNTIME: 'Çalışma ortamı'
|
||||
TYPE_DOMAIN: 'Alan Adı'
|
||||
ErrTypePort: 'Port {{ .name }} formatı yanlış'
|
||||
ErrTypePortRange: 'Port aralığının 1-65535 arasında olması gerekiyor'
|
||||
Success: 'Başarılı'
|
||||
Failed: 'Başarısız'
|
||||
SystemRestart: 'Sistem yeniden başlatması nedeniyle görev kesildi'
|
||||
ErrGroupIsDefault: 'Varsayılan grup, silinemez'
|
||||
ErrGroupIsInWebsiteUse: 'Grup başka bir web sitesi tarafından kullanılıyor ve silinemez.'
|
||||
|
||||
#backup
|
||||
ErrBackupInUsed: 'Yedekleme hesabı zamanlanmış görevde kullanıldı ve silinemez.'
|
||||
ErrBackupCheck: 'Yedekleme hesabı test bağlantısı başarısız {{ .err }}'
|
||||
ErrBackupLocalDelete: 'Yerel sunucu yedekleme hesabını silme henüz desteklenmiyor'
|
||||
ErrBackupLocalCreate: 'Yerel sunucu yedekleme hesapları oluşturma henüz desteklenmiyor'
|
||||
|
||||
#app
|
||||
ErrPortInUsed: '{{ .detail }} portu zaten kullanılıyor!'
|
||||
ErrAppLimit: 'Yüklenen uygulama sayısı sınırı aştı'
|
||||
ErrNotInstall: 'Uygulama yüklenmedi'
|
||||
ErrPortInOtherApp: '{{ .port }} portu zaten {{ .apps }} uygulaması tarafından kullanılıyor!'
|
||||
ErrDbUserNotValid: 'Mevcut veritabanı, kullanıcı adı ve şifre eşleşmiyor!'
|
||||
ErrUpdateBuWebsite: 'Uygulama başarıyla güncellendi, ancak web sitesi yapılandırma dosyası değiştirme başarısız. Lütfen yapılandırmayı kontrol edin! '
|
||||
Err1PanelNetworkFailed: 'Varsayılan konteyner ağ oluşturma başarısız! {{ .detail }}'
|
||||
ErrFileParse: 'Uygulama docker-compose dosya ayrıştırma başarısız!'
|
||||
ErrInstallDirNotFound: 'Kurulum dizini mevcut değil. Kaldırmanız gerekiyorsa, lütfen Zorla Kaldır seçeneğini seçin'
|
||||
AppStoreIsUpToDate: 'Uygulama mağazası zaten en son sürüm'
|
||||
LocalAppVersionNull: '{{ .name }} uygulaması sürüme senkronize edilmedi! Uygulama listesine eklenemez'
|
||||
LocalAppVersionErr: '{{ .name }} senkronizasyon sürümü {{ .version }} başarısız! {{ .err }}'
|
||||
ErrFileNotFound: '{{ .name }} dosyası mevcut değil'
|
||||
ErrFileParseApp: '{{ .name }} dosya ayrıştırma başarısız {{ .err }}'
|
||||
ErrAppDirNull: 'Sürüm klasörü mevcut değil'
|
||||
LocalAppErr: 'Uygulama {{ .name }} senkronizasyonu başarısız! {{ .err }}'
|
||||
ErrContainerName: 'Konteyner adı zaten mevcut'
|
||||
ErrCreateHttpClient: 'İstek oluşturma başarısız {{ .err }}'
|
||||
ErrHttpReqTimeOut: 'İstek zaman aşımı {{ .err }}'
|
||||
ErrHttpReqFailed: 'İstek başarısız {{ .err }}'
|
||||
ErrNoSuchHost: 'İstenen sunucu bulunamıyor {{ .err }}'
|
||||
ErrHttpReqNotFound: 'İstenen kaynak {{ .err }} bulunamadı'
|
||||
ErrImagePullTimeOut: 'Image çekme zaman aşımı'
|
||||
ErrContainerNotFound: '{{ .name }} konteyneri mevcut değil'
|
||||
ErrContainerMsg: '{{ .name }} konteyneri anormal. Lütfen ayrıntılar için konteyner sayfasındaki günlüğü kontrol edin'
|
||||
ErrAppBackup: '{{ .name }} uygulama yedeklemesi başarısız {{ .err }}'
|
||||
ErrVersionTooLow: 'Mevcut 1Panel sürümü Uygulama Mağazasını güncellemek için çok düşük. Lütfen işlemden önce sürümü yükseltin.'
|
||||
ErrAppNameExist: 'Uygulama adı zaten mevcut'
|
||||
AppStoreIsSyncing: 'Uygulama Mağazası senkronize ediliyor, lütfen daha sonra tekrar deneyin'
|
||||
ErrGetCompose: 'docker-compose.yml dosyası alınamadı! {{ .detail }}'
|
||||
ErrAppWarn: 'Anormal durum, lütfen günlüğü kontrol edin'
|
||||
ErrAppParamKey: 'Parametre {{ .name }} alanı anormal'
|
||||
ErrAppUpgrade: 'Uygulama {{ .name }} yükseltmesi başarısız {{ .err }}'
|
||||
AppRecover: 'Uygulama {{ .name }} geri alma'
|
||||
PullImageStart: 'Image {{ .name }} çekmeye başla'
|
||||
PullImageSuccess: 'Image çekme başarılı'
|
||||
AppStoreIsLastVersion: 'Uygulama Mağazası zaten en son sürüm'
|
||||
AppStoreSyncSuccess: 'Uygulama Mağazası senkronizasyonu başarılı'
|
||||
SyncAppDetail: 'Uygulama yapılandırmasını senkronize et'
|
||||
AppVersionNotMatch: '{{ .name }} uygulaması daha yüksek 1Panel sürümü gerektiriyor, senkronizasyon atlanıyor'
|
||||
MoveSiteDir: 'Mevcut yükseltme OpenResty web sitesi dizininin taşınmasını gerektiriyor'
|
||||
MoveSiteToDir: 'Site dizinini {{ .name }} konumuna taşı'
|
||||
ErrMoveSiteDir: 'Site dizini taşıma başarısız'
|
||||
MoveSiteDirSuccess: 'Web sitesi dizini taşıma başarılı'
|
||||
DeleteRuntimePHP: 'PHP çalışma zamanını sil'
|
||||
CustomAppStoreFileValid: 'Uygulama mağazası paketlerinin .tar.gz formatında olması gerekiyor'
|
||||
PullImageTimeout: 'Image çekme zaman aşımı, lütfen image hızlandırmayı artırmayı deneyin veya başka bir image hızlandırmaya geçin'
|
||||
ErrAppIsDown: '{{ .name }} uygulama durumu anormal, lütfen kontrol edin'
|
||||
ErrCustomApps: 'Yüklü bir uygulama var, lütfen önce kaldırın'
|
||||
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"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: 'Bu dosya önizlemeyi desteklemiyor'
|
||||
ErrFileToLarge: 'Dosya 10M'dan büyük ve açılamıyor'
|
||||
ErrPathNotFound: 'Dizin mevcut değil'
|
||||
ErrMovePathFailed: 'Hedef yol orijinal yolu içeremez!'
|
||||
ErrLinkPathNotFound: 'Hedef yol mevcut değil!'
|
||||
ErrFileIsExist: 'Dosya veya klasör zaten mevcut!'
|
||||
ErrFileUpload: '{{ .name }} dosya yükleme başarısız {{ .detail }}'
|
||||
ErrFileDownloadDir: 'Klasör indirme desteklenmiyor'
|
||||
ErrCmdNotFound: '{{ .name}} komutu mevcut değil, lütfen önce bu komutu host'a yükleyin'
|
||||
ErrSourcePathNotFound: 'Kaynak dizin mevcut değil'
|
||||
ErrFavoriteExist: 'Bu yol zaten favorilere eklendi'
|
||||
ErrInvalidChar: 'Yasak karakterlere izin verilmiyor'
|
||||
ErrPathNotDelete: 'Seçilen dizin silinemez'
|
||||
ErrLogFileToLarge: "Günlük dosyası 500MB'ı aşıyor ve açılamıyor"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: 'Takma ad zaten mevcut'
|
||||
ErrBackupMatch: 'Yedekleme dosyası mevcut web sitesi verilerinin bir kısmıyla eşleşmiyor {{ .detail }}'
|
||||
ErrBackupExist: 'Yedekleme dosyasındaki kaynak verilerin karşılık gelen kısmı mevcut değil {{ .detail }}'
|
||||
ErrPHPResource: 'Yerel işletim ortamı değiştirmeyi desteklemiyor! '
|
||||
ErrPathPermission: 'Dizin dizininde 1000:1000 olmayan izinlere sahip bir klasör tespit edildi, bu web sitesinde Erişim reddedildi hatasına neden olabilir. Lütfen yukarıdaki Kaydet düğmesine tıklayın'
|
||||
ErrDomainIsUsed: 'Alan adı zaten [{{ .name }}] web sitesi tarafından kullanılıyor'
|
||||
ErrDomainFormat: '{{ .name }} alan adı formatı yanlış'
|
||||
ErrDefaultAlias: 'default ayrılmış bir kod, lütfen başka bir kod kullanın'
|
||||
ErrParentWebsite: 'Önce {{ .name }} alt sitesini silmeniz gerekiyor'
|
||||
ErrBuildDirNotFound: 'Yapı dizini mevcut değil'
|
||||
ErrImageNotExist: 'İşletim ortamı {{ .name }} image mevcut değil, lütfen işletim ortamını yeniden düzenleyin'
|
||||
ErrProxyIsUsed: "Yük dengeleme ters proxy tarafından kullanıldı, silinemez"
|
||||
ErrSSLValid: 'Sertifika dosyası anormal, lütfen sertifika durumunu kontrol edin!'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: '{{ .name }} sertifikası bir web sitesi tarafından kullanılıyor ve silinemez'
|
||||
ErrAccountCannotDelete: 'Hesap bir sertifikayla ilişkili ve silinemez'
|
||||
ErrSSLApply: 'Sertifika yenileme başarılı, openresty yeniden yükleme başarısız, lütfen yapılandırmayı kontrol edin!'
|
||||
ErrEmailIsExist: 'Posta kutusu zaten mevcut'
|
||||
ErrSSLKeyNotFound: 'Özel anahtar dosyası mevcut değil'
|
||||
ErrSSLCertificateNotFound: 'Sertifika dosyası mevcut değil'
|
||||
ErrSSLKeyFormat: 'Özel anahtar dosyası doğrulama başarısız'
|
||||
ErrSSLCertificateFormat: 'Sertifika dosyası formatı yanlış, lütfen pem formatını kullanın'
|
||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid veya EabHmacKey boş olamaz'
|
||||
ErrOpenrestyNotFound: 'Http modu önce Openresty yüklenmesini gerektiriyor'
|
||||
ApplySSLStart: 'Sertifika başvurusu başlatılıyor, alan adı [{{ .domain }}] başvuru yöntemi [{{ .type }}] '
|
||||
dnsAccount: 'DNS Otomatik'
|
||||
dnsManual: 'DNS Manuel'
|
||||
http: 'HTTP'
|
||||
ApplySSLFailed: '[{{ .domain }}] sertifika başvurusu başarısız, {{ .detail }} '
|
||||
ApplySSLSuccess: '[{{ .domain }}] sertifika başvurusu başarılı! !'
|
||||
DNSAccountName: 'DNS hesabı [{{ .name }}] sağlayıcı [{{ .type }}]'
|
||||
PushDirLog: 'Sertifika [{{ .path }}] dizinine gönderildi {{ .status }}'
|
||||
ErrDeleteCAWithSSL: 'Mevcut kuruluşun verilmiş bir sertifikası var ve silinemez.'
|
||||
ErrDeleteWithPanelSSL: 'Panel SSL yapılandırması bu sertifikayı kullanıyor ve silinemez'
|
||||
ErrDefaultCA: 'Varsayılan otorite silinemez'
|
||||
ApplyWebSiteSSLLog: '{{ .name }} web sitesi sertifikası yenilemeyi başlatıyor'
|
||||
ErrUpdateWebsiteSSL: '{{ .name }} web sitesi sertifika güncelleme başarısız: {{ .err }}'
|
||||
ApplyWebSiteSSLSuccess: 'Web sitesi sertifikası güncelleme başarılı'
|
||||
ErrExecShell: 'Betik yürütme başarısız {{ .err }}'
|
||||
ExecShellStart: 'Betik yürütmeyi başlat'
|
||||
ExecShellSuccess: 'Betik yürütme başarılı'
|
||||
StartUpdateSystemSSL: 'Sistem sertifikası güncellemeyi başlat'
|
||||
UpdateSystemSSLSuccess: 'Sistem sertifikası güncelleme başarılı'
|
||||
ErrWildcardDomain: 'HTTP modunda joker alan adı sertifikası başvurusu yapılamıyor'
|
||||
|
||||
#mysql
|
||||
ErrUserIsExist: 'Mevcut kullanıcı zaten mevcut, lütfen yeniden girin'
|
||||
ErrDatabaseIsExist: 'Mevcut veritabanı zaten mevcut, lütfen yeniden girin'
|
||||
ErrExecTimeOut: 'SQL yürütme zaman aşımı, lütfen veritabanını kontrol edin'
|
||||
ErrRemoteExist: 'Uzak veritabanında bu adla zaten mevcut, lütfen değiştirin ve tekrar deneyin'
|
||||
ErrLocalExist: 'Yerel veritabanında bu ad zaten mevcut, lütfen değiştirin ve tekrar deneyin'
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'Kurtarma dosyası türü mevcut kalıcılık yöntemiyle eşleşmiyor, lütfen değiştirin ve tekrar deneyin'
|
||||
|
||||
#container
|
||||
ErrInUsed: '{{ .detail }} kullanımda ve silinemez'
|
||||
ErrObjectInUsed: 'Nesne kullanımda ve silinemez'
|
||||
ErrObjectBeDependent: 'Bu image diğer imagelere bağlı ve silinemez'
|
||||
ErrPortRules: 'Port numarası eşleşmiyor, lütfen yeniden girin!'
|
||||
ErrPgImagePull: 'Image çekme zaman aşımı, lütfen image hızlandırma yapılandırın veya manuel olarak {{ .name }} imageını çekin ve tekrar deneyin'
|
||||
|
||||
#runtime
|
||||
ErrFileNotExist: '{{ .detail }} dosyası mevcut değil! Lütfen kaynak dosyanın bütünlüğünü kontrol edin!'
|
||||
ErrImageBuildErr: 'Image yapı başarısız'
|
||||
ErrImageExist: "Görüntü zaten var! Lütfen görüntü adını değiştirin."
|
||||
ErrDelWithWebsite: 'İşletim ortamı zaten bir web sitesiyle ilişkili ve silinemez'
|
||||
ErrRuntimeStart: 'Başlatma başarısız'
|
||||
ErrPackageJsonNotFound: 'package.json dosyası mevcut değil'
|
||||
ErrScriptsNotFound: 'package.json içinde scripts yapılandırma öğesi bulunamadı'
|
||||
ErrContainerNameNotFound: 'Konteyner adı alınamıyor, lütfen .env dosyasını kontrol edin'
|
||||
ErrNodeModulesNotFound: 'node_modules klasörü mevcut değil! Lütfen çalışma ortamını düzenleyin veya çalışma ortamının başarıyla başlatılmasını bekleyin'
|
||||
ErrContainerNameIsNull: 'Konteyner adı mevcut değil'
|
||||
ErrPHPPortIsDefault: "9000 portu varsayılan port, lütfen değiştirin ve tekrar deneyin"
|
||||
ErrPHPRuntimePortFailed: "{{ .name }} portu mevcut çalışma ortamı tarafından zaten kullanılıyor, lütfen değiştirin ve tekrar deneyin"
|
||||
|
||||
#tool
|
||||
ErrConfigNotFound: 'Yapılandırma dosyası mevcut değil'
|
||||
ErrConfigParse: 'Yapılandırma dosyası formatı yanlış'
|
||||
ErrConfigIsNull: 'Yapılandırma dosyası boş olamaz'
|
||||
ErrConfigDirNotFound: 'Çalışma dizini mevcut değil'
|
||||
ErrConfigAlreadyExist: 'Aynı ada sahip bir yapılandırma dosyası zaten mevcut'
|
||||
ErrUserFindErr: 'Kullanıcı {{ .name }} arama başarısız {{ .err }}'
|
||||
|
||||
#cronjob
|
||||
CutWebsiteLogSuccess: '{{ .name }} web sitesi günlüğü başarıyla kesildi, yedekleme yolu {{ .path }}'
|
||||
HandleShell: 'Betik {{ .name }} yürüt'
|
||||
HandleNtpSync: 'Sistem zaman senkronizasyonu'
|
||||
HandleSystemClean: 'Sistem önbellek temizliği'
|
||||
SystemLog: 'Sistem Günlüğü'
|
||||
CutWebsiteLog: 'Web Sitesi Günlüğünü Döndür'
|
||||
FileOrDir: 'Dizin / Dosya'
|
||||
UploadFile: 'Yedekleme dosyası {{ .file }} {{ .backup }} konumuna yükleniyor'
|
||||
|
||||
#toolbox
|
||||
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!'
|
||||
|
||||
#waf
|
||||
ErrScope: 'Bu yapılandırmayı değiştirme desteklenmiyor'
|
||||
ErrStateChange: 'Durum değiştirme başarısız'
|
||||
ErrRuleExist: 'Kural zaten mevcut'
|
||||
ErrRuleNotExist: 'Kural mevcut değil'
|
||||
ErrParseIP: 'Yanlış IP formatı'
|
||||
ErrDefaultIP: 'default ayrılmış bir isim, lütfen başka bir isme değiştirin'
|
||||
ErrGroupInUse: 'IP grubu kara liste/beyaz liste tarafından kullanılıyor ve silinemez'
|
||||
ErrIPGroupAclUse: "IP grubu {{ .name }} web sitesinin özel kuralları tarafından kullanılıyor, silinemez"
|
||||
ErrGroupExist: 'IP grup adı zaten mevcut'
|
||||
ErrIPRange: 'Yanlış IP aralığı'
|
||||
ErrIPExist: 'IP zaten mevcut'
|
||||
urlDefense: 'URL kuralları'
|
||||
urlHelper: 'Yasak URL'
|
||||
dirFilter: 'Dizin filtresi'
|
||||
xss: 'XSS'
|
||||
phpExec: 'PHP betik yürütme'
|
||||
oneWordTrojan: 'Tek Kelime Truva Atı'
|
||||
appFilter: 'Tehlikeli dizin filtreleme uygula'
|
||||
webshell: 'Webshell'
|
||||
args: 'Parametre kuralları'
|
||||
protocolFilter: 'Protokol filtreleme'
|
||||
javaFileter: 'Java tehlikeli dosya filtresi'
|
||||
scannerFilter: 'Tarayıcı filtresi'
|
||||
escapeFilter: 'kaçış filtresi'
|
||||
customRule: 'Özel kural'
|
||||
httpMethod: 'HTTP yöntem filtreleme'
|
||||
fileExt: 'Dosya yükleme kısıtlamaları'
|
||||
defaultIpBlack: 'Kötü niyetli IP grubu'
|
||||
cookie: 'Cookie Kuralları'
|
||||
urlBlack: 'URL kara listesi'
|
||||
uaBlack: 'User-Agent kara listesi'
|
||||
attackCount: 'Saldırı sıklığı sınırı'
|
||||
fileExtCheck: 'Dosya yükleme kısıtlamaları'
|
||||
geoRestrict: 'Bölgesel erişim kısıtlamaları'
|
||||
unknownWebsite: 'Yetkisiz alan adı erişimi'
|
||||
notFoundCount: '404 Hız Sınırı'
|
||||
headerDefense: 'Başlık kuralları'
|
||||
defaultUaBlack: 'User-Agent kuralları'
|
||||
methodWhite: 'HTTP kuralları'
|
||||
captcha: 'insan-makine doğrulaması'
|
||||
fiveSeconds: '5 saniye doğrulaması'
|
||||
vulnCheck: 'Tamamlayıcı kurallar'
|
||||
acl: 'Özel kurallar'
|
||||
sql: 'SQL enjeksiyonu'
|
||||
cc: 'Erişim sıklığı sınırı'
|
||||
defaultUrlBlack: 'URL kuralları'
|
||||
sqlInject: 'SQL enjeksiyonu'
|
||||
ErrDBNotExist: 'Veritabanı mevcut değil'
|
||||
allow: 'izin ver'
|
||||
deny: 'reddet'
|
||||
OpenrestyNotFound: 'Openresty yüklü değil'
|
||||
remoteIpIsNull: "IP listesi boş"
|
||||
|
||||
#task
|
||||
TaskStart: '{{ .name }} görevi başlıyor [BAŞLAT]'
|
||||
TaskEnd: '{{ .name }} Görev tamamlandı [TAMAMLANDI]'
|
||||
TaskFailed: '{{ .name }} görev başarısız'
|
||||
TaskTimeout: '{{ .name }} zaman aşımına uğradı'
|
||||
TaskSuccess: '{{ .name }} Görev başarılı'
|
||||
TaskRetry: '{{ .name }}. yeniden denemeyi başlat'
|
||||
SubTaskSuccess: '{{ .name }} başarılı'
|
||||
SubTaskFailed: '{{ .name }} başarısız: {{ .err }}'
|
||||
TaskInstall: 'Yükle'
|
||||
TaskUninstall: 'Kaldır'
|
||||
TaskCreate: 'Oluştur'
|
||||
TaskDelete: 'Sil'
|
||||
TaskUpgrade: 'Yükselt'
|
||||
TaskUpdate: 'Güncelle'
|
||||
TaskRestart: 'Yeniden Başlat'
|
||||
TaskBackup: 'Yedekle'
|
||||
TaskRecover: 'Kurtar'
|
||||
TaskRollback: 'Geri Al'
|
||||
TaskPull: 'Çek'
|
||||
TaskCommit: 'işleme'
|
||||
TaskBuild: 'Yapı'
|
||||
TaskPush: 'Gönder'
|
||||
TaskHandle: 'Yürüt'
|
||||
Website: 'Web Sitesi'
|
||||
App: 'Uygulama'
|
||||
Runtime: 'Çalışma ortamı'
|
||||
Database: 'Veritabanı'
|
||||
ConfigFTP: 'FTP kullanıcısı {{ .name }} oluştur'
|
||||
ConfigOpenresty: 'Openresty yapılandırma dosyası oluştur'
|
||||
InstallAppSuccess: 'Uygulama {{ .name }} başarıyla yüklendi'
|
||||
ConfigRuntime: 'Çalışma ortamını yapılandır'
|
||||
ConfigApp: 'Uygulama Yapılandırması'
|
||||
SuccessStatus: '{{ .name }} başarılı'
|
||||
FailedStatus: '{{ .name }} başarısız {{ .err }}'
|
||||
HandleLink: 'Uygulama ilişkisini işle'
|
||||
HandleDatabaseApp: 'Uygulama parametrelerini işle'
|
||||
ExecShell: '{{ .name }} betiğini yürüt'
|
||||
PullImage: 'Image çek'
|
||||
Start: 'Başlat'
|
||||
Run: 'Başlat'
|
||||
Stop: 'Durdur'
|
||||
Image: 'Ayna'
|
||||
Compose: 'Düzenleme'
|
||||
Container: 'Konteyner'
|
||||
AppLink: 'Bağlantılı Uygulama'
|
||||
EnableSSL: 'HTTPS Etkinleştir'
|
||||
AppStore: 'Uygulama Mağazası'
|
||||
TaskSync: 'Senkronize Et'
|
||||
LocalApp: 'Yerel Uygulama'
|
||||
SubTask: 'Alt görev'
|
||||
RuntimeExtension: 'Çalışma Ortamı Uzantısı'
|
||||
TaskIsExecuting: 'Görev çalışıyor'
|
||||
CustomAppstore: 'Özel uygulama deposu'
|
||||
|
||||
# task - ai
|
||||
OllamaModelPull: 'Ollama modeli {{ .name }} çek'
|
||||
OllamaModelSize: 'Ollama modeli {{ .name }} boyutunu al'
|
||||
|
||||
# task-snapshot
|
||||
Snapshot: 'Anlık Görüntü'
|
||||
SnapDBInfo: '1Panel veritabanı bilgilerini yaz'
|
||||
SnapCopy: 'Dosya ve dizinleri {{ .name }} kopyala'
|
||||
SnapNewDB: 'Veritabanı {{ .name }} bağlantısını başlat'
|
||||
SnapDeleteOperationLog: 'İşlem günlüğünü sil'
|
||||
SnapDeleteLoginLog: 'Erişim günlüğünü sil'
|
||||
SnapDeleteMonitor: 'İzleme verilerini sil'
|
||||
SnapRemoveSystemIP: 'Sistem IP'sini kaldır'
|
||||
SnapBaseInfo: '1Panel temel bilgilerini yaz'
|
||||
SnapInstallAppImageEmpty: 'Uygulama imageı seçilmedi, atlanıyor...'
|
||||
SnapInstallApp: '1Panel yüklü uygulamaları yedekle'
|
||||
SnapDockerSave: 'Yüklü uygulamaları sıkıştır'
|
||||
SnapLocalBackup: '1Panel yerel yedekleme dizinini yedekle'
|
||||
SnapCompressBackup: 'Yerel yedekleme dizinini sıkıştır'
|
||||
SnapPanelData: '1Panel veri dizinini yedekle'
|
||||
SnapCompressPanel: 'Sıkıştırılmış Veri Dizini'
|
||||
SnapWebsite: '1Panel web sitesi dizinini yedekle'
|
||||
SnapCloseDBConn: 'Veritabanı bağlantısını kapat'
|
||||
SnapCompress: 'Anlık görüntü dosyaları oluştur'
|
||||
SnapCompressFile: 'Anlık görüntü dosyasını sıkıştır'
|
||||
SnapCheckCompress: 'Anlık görüntü sıkıştırma dosyasını kontrol et'
|
||||
SnapCompressSize: 'Anlık görüntü dosya boyutu {{ .name }}'
|
||||
SnapUpload: 'Anlık görüntü dosyasını yükle'
|
||||
SnapLoadBackup: 'Yedekleme hesabı bilgilerini al'
|
||||
SnapUploadTo: 'Anlık görüntü dosyasını {{ .name }} konumuna yükle'
|
||||
SnapUploadRes: 'Anlık görüntü dosyasını {{ .name }} konumuna yükle'
|
||||
|
||||
SnapshotRecover: 'Anlık Görüntü Geri Yükleme'
|
||||
RecoverDownload: 'Anlık görüntü dosyasını indir'
|
||||
Download: 'İndir'
|
||||
RecoverDownloadAccount: 'Anlık görüntü indirme yedek hesabı al {{ .name }}'
|
||||
RecoverDecompress: 'Anlık görüntü sıkıştırılmış dosyalarını açma'
|
||||
Decompress: 'Açma'
|
||||
BackupBeforeRecover: 'Anlık görüntü öncesi sistem ilgili verileri yedekleme'
|
||||
Readjson: 'Anlık görüntüdeki Json dosyasını oku'
|
||||
ReadjsonPath: 'Anlık görüntüdeki Json dosya yolunu al'
|
||||
ReadjsonContent: 'Json dosyasını oku'
|
||||
ReadjsonMarshal: 'Json kaçış işlemesi'
|
||||
RecoverApp: 'Yüklü uygulamaları geri yükle'
|
||||
RecoverWebsite: 'Web sitesi dizinini kurtar'
|
||||
RecoverAppImage: 'Anlık görüntü imaj yedeklemesini geri yükle'
|
||||
RecoverCompose: 'Diğer besteci içeriğini geri yükle'
|
||||
RecoverComposeList: 'Geri yüklenecek tüm bestecileri al'
|
||||
RecoverComposeItem: 'Besteci geri yükle {{ .name }}'
|
||||
RecoverAppEmpty: 'Anlık görüntü dosyasında uygulama imaj yedeklemesi bulunamadı'
|
||||
RecoverBaseData: 'Temel veri ve dosyaları kurtar'
|
||||
RecoverDaemonJsonEmpty: 'Hem anlık görüntü dosyası hem de mevcut makine konteyner yapılandırma daemon.json dosyasına sahip değil'
|
||||
RecoverDaemonJson: 'Konteyner yapılandırma daemon.json dosyasını geri yükle'
|
||||
RecoverDBData: 'Veritabanı verilerini kurtar'
|
||||
RecoverBackups: 'Yerel yedekleme dizinini geri yükle'
|
||||
RecoverPanelData: 'Veri dizinini kurtar'
|
||||
|
||||
# task - container
|
||||
ContainerNewCliet: 'Docker İstemcisini Başlat'
|
||||
ContainerImagePull: 'Konteyner imajını çek {{ .name }}'
|
||||
ContainerRemoveOld: 'Orijinal konteyneri kaldır {{ .name }}'
|
||||
ContainerImageCheck: 'İmajın normal çekilip çekilmediğini kontrol et'
|
||||
ContainerLoadInfo: 'Temel konteyner bilgilerini al'
|
||||
ContainerRecreate: 'Konteyner güncellemesi başarısız, şimdi orijinal konteyneri geri yüklemeye başlıyor'
|
||||
ContainerCreate: 'Yeni konteyner oluştur {{ .name }}'
|
||||
ContainerCreateFailed: 'Konteyner oluşturma başarısız, başarısız konteyneri sil'
|
||||
ContainerStartCheck: 'Konteynerin başlatılıp başlatılmadığını kontrol et'
|
||||
|
||||
# task - image
|
||||
ImageBuild: 'İmaj Oluşturma'
|
||||
ImageBuildStdoutCheck: 'İmaj çıktı içeriğini ayrıştır'
|
||||
ImageBuildRes: 'İmaj oluşturma çıktısı: {{ .name }}'
|
||||
ImagePull: 'İmaj çek'
|
||||
ImageRepoAuthFromDB: 'Veritabanından depo kimlik doğrulama bilgilerini al'
|
||||
ImaegPullRes: 'İmaj çekme çıktısı: {{ .name }}'
|
||||
ImagePush: 'İmaj gönder'
|
||||
ImageRenameTag: 'İmaj etiketini değiştir'
|
||||
ImageNewTag: 'Yeni imaj etiketi {{ .name }}'
|
||||
ImaegPushRes: 'İmaj gönderme çıktısı: {{ .name }}'
|
||||
ComposeCreate: 'Kompozisyon oluştur'
|
||||
ComposeCreateRes: 'Compose oluşturma çıktısı: {{ .name }}'
|
||||
|
||||
# task - website
|
||||
BackupNginxConfig: 'Web sitesi OpenResty yapılandırma dosyasını yedekle'
|
||||
CompressFileSuccess: 'Dizin başarıyla sıkıştırıldı, şuraya sıkıştırıldı {{ .name }}'
|
||||
CompressDir: 'Sıkıştırma dizini'
|
||||
DeCompressFile: 'Dosyayı aç {{ .name }}'
|
||||
ErrCheckValid: 'Yedekleme dosyası doğrulaması başarısız, {{ .name }}'
|
||||
Rollback: 'Geri alma'
|
||||
websiteDir: 'Web Sitesi Dizini'
|
||||
RecoverFailedStartRollBack: 'Kurtarma başarısız, geri almayı başlat'
|
||||
AppBackupFileIncomplete: 'Yedekleme dosyası eksik ve app.json veya app.tar.gz dosyalarından yoksun'
|
||||
AppAttributesNotMatch: 'Uygulama türü veya adı eşleşmiyor'
|
||||
|
||||
#alert
|
||||
ErrAlert: 'Uyarı mesajının formatı yanlış, lütfen kontrol edin ve tekrar deneyin!'
|
||||
ErrAlertPush: 'Uyarı bilgisi gönderiminde hata, lütfen kontrol edin ve tekrar deneyin!'
|
||||
ErrAlertSave: 'Alarm bilgisini kaydetmede hata, lütfen kontrol edin ve tekrar deneyin!'
|
||||
ErrAlertSync: 'Alarm bilgisi senkronizasyon hatası, lütfen kontrol edin ve tekrar deneyin!'
|
||||
ErrAlertRemote: 'Alarm mesajı uzak hata, lütfen kontrol edin ve tekrar deneyin!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "Zaten devam eden bir kurulum görevi var, görevin bitmesini bekleyin"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "Panel Uyarı Bildirimi"
|
||||
TestAlertTitle: "Test E-postası - E-posta Bağlantısını Doğrula"
|
||||
TestAlert: "Bu, e-posta gönderim ayarlarınızın doğru yapılandırıldığını doğrulamak için gönderilen bir test e-postasıdır."
|
||||
LicenseExpirationAlert: "1Panel lisansınız {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
CronJobFailedAlert: "1Panel zamanlanmış görevi '{{ .name }}' başarısız oldu. Detaylar için panele giriş yapın."
|
||||
ClamAlert: "1Panel virüs taraması {{ .num }} enfekte dosya tespit etti. Detaylar için panele giriş yapın."
|
||||
WebSiteAlert: "1Panel üzerindeki {{ .num }} web sitesi {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
SSLAlert: "1Panel üzerindeki {{ .num }} SSL sertifikası {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
DiskUsedAlert: "1Panel diski '{{ .name }}' {{ .used }} kullanıldı. Detaylar için panele giriş yapın."
|
||||
ResourceAlert: "1Panel üzerinde ortalama {{ .time }} dakikalık {{ .name }} kullanım oranı {{ .used }}. Detaylar için panele giriş yapın."
|
||||
PanelVersionAlert: "1Panel için yeni bir sürüm mevcut. Güncellemek için panele giriş yapın."
|
||||
PanelPwdExpirationAlert: "1Panel şifreniz {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
@@ -176,7 +176,7 @@ ErrPgImagePull: '鏡像拉取逾時,請配置鏡像加速或手動拉取{{ .na
|
||||
#runtime
|
||||
ErrFileNotExist: '{{ .detail }} 檔案不存在!請檢查來源檔案完整性!'
|
||||
ErrImageBuildErr: '鏡像build 失敗'
|
||||
ErrImageExist: '鏡像已存在!'
|
||||
ErrImageExist: "鏡像已存在!請修改鏡像名稱。"
|
||||
ErrDelWithWebsite: '執行環境已經關聯網站,無法刪除'
|
||||
ErrRuntimeStart: '啟動失敗'
|
||||
ErrPackageJsonNotFound: 'package.json 檔案不存在'
|
||||
@@ -204,6 +204,8 @@ SystemLog: '系統日誌'
|
||||
CutWebsiteLog: '切割網站日誌'
|
||||
FileOrDir: '目錄 / 檔案'
|
||||
UploadFile: '上傳備份文件 {{ .file }} 到 {{ .backup }}'
|
||||
IgnoreBackupErr: '備份失敗,錯誤:{{ .detail }},忽略本次錯誤...'
|
||||
IgnoreUploadErr: '上傳失敗,錯誤:{{ .detail }},忽略本次錯誤...'
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: '目前使用者不存在,請修改後重試!'
|
||||
@@ -284,6 +286,7 @@ TaskBackup: '備份'
|
||||
TaskRecover: '復原'
|
||||
TaskRollback: '回滾'
|
||||
TaskPull: '拉取'
|
||||
TaskCommit: '制作'
|
||||
TaskBuild: '建置'
|
||||
TaskPush: '推送'
|
||||
TaskHandle: '執行'
|
||||
@@ -332,7 +335,8 @@ SnapDeleteLoginLog: '刪除存取日誌'
|
||||
SnapDeleteMonitor: '刪除監控資料'
|
||||
SnapRemoveSystemIP: '移除系統IP'
|
||||
SnapBaseInfo: '寫入1Panel 基本資料'
|
||||
SnapInstallApp: '備份1Panel 已安裝應用程式'
|
||||
SnapInstallAppImageEmpty: '當前未勾選應用鏡像,跳過...'
|
||||
SnapInstallApp: '備份 1Panel 已安裝應用'
|
||||
SnapDockerSave: '壓縮已安裝應用'
|
||||
SnapLocalBackup: '備份1Panel 本機備份目錄'
|
||||
SnapCompressBackup: '壓縮本機備份目錄'
|
||||
@@ -420,3 +424,17 @@ ErrAlertRemote: '警告訊息遠端錯誤,請檢查後重試!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "已有安裝任務正在進行,請等待任務結束"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "面板警示通知"
|
||||
TestAlertTitle: "測試郵件 - 驗證郵箱連通性"
|
||||
TestAlert: "這是一封測試郵件,用於確認您的郵件發送設定是否正確。"
|
||||
LicenseExpirationAlert: "您的 1Panel 授權將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CronJobFailedAlert: "您的 1Panel 面板中,計畫任務 '{{ .name }}' 執行失敗,詳情請登入面板查看。"
|
||||
ClamAlert: "您的 1Panel 面板病毒掃描任務發現 {{ .num }} 個受感染的檔案,詳情請登入面板查看。"
|
||||
WebSiteAlert: "您的 1Panel 面板中有 {{ .num }} 個網站將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
SSLAlert: "您的 1Panel 面板中有 {{ .num }} 張 SSL 憑證將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
DiskUsedAlert: "您的 1Panel 面板磁碟 '{{ .name }}' 已使用 {{ .used }},詳情請登入面板查看。"
|
||||
ResourceAlert: "您的 1Panel 面板於 {{ .time }} 分鐘內的平均 {{ .name }} 使用率為 {{ .used }},詳情請登入面板查看。"
|
||||
PanelVersionAlert: "您的 1Panel 面板有可升級的新版本,詳情請登入面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 1Panel 面板密碼將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
|
||||
+42
-24
@@ -176,7 +176,7 @@ ErrPgImagePull: "镜像拉取超时,请配置镜像加速或手动拉取 {{ .n
|
||||
#runtime
|
||||
ErrFileNotExist: "{{ .detail }} 文件不存在!请检查源文件完整性!"
|
||||
ErrImageBuildErr: "镜像 build 失败"
|
||||
ErrImageExist: "镜像已存在!"
|
||||
ErrImageExist: "镜像已存在!请修改镜像名称"
|
||||
ErrDelWithWebsite: "运行环境已经关联网站,无法删除"
|
||||
ErrRuntimeStart: "启动失败"
|
||||
ErrPackageJsonNotFound: "package.json 文件不存在"
|
||||
@@ -204,6 +204,8 @@ SystemLog: "系统日志"
|
||||
CutWebsiteLog: "切割网站日志"
|
||||
FileOrDir: "目录 / 文件"
|
||||
UploadFile: "上传备份文件 {{ .file }} 到 {{ .backup }}"
|
||||
IgnoreBackupErr: "备份失败,错误:{{ .detail }},忽略本次错误..."
|
||||
IgnoreUploadErr: "上传失败,错误:{{ .detail }},忽略本次错误..."
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
||||
@@ -284,6 +286,7 @@ TaskBackup: "备份"
|
||||
TaskRecover: "恢复"
|
||||
TaskRollback: "回滚"
|
||||
TaskPull: "拉取"
|
||||
TaskCommit: "制作"
|
||||
TaskBuild: "构建"
|
||||
TaskPush: "推送"
|
||||
TaskHandle: "执行"
|
||||
@@ -296,7 +299,7 @@ ConfigOpenresty: "创建 Openresty 配置文件"
|
||||
InstallAppSuccess: "应用 {{ .name }} 安装成功"
|
||||
ConfigRuntime: "配置运行环境"
|
||||
ConfigApp: "配置应用"
|
||||
SuccessStatus: "{{ .name }} 成功"
|
||||
SuccessStatus: "{{ .name }} 成功"
|
||||
FailedStatus: "{{ .name }} 失败 {{ .err }}"
|
||||
HandleLink: "处理应用关联"
|
||||
HandleDatabaseApp: "处理应用参数"
|
||||
@@ -322,7 +325,7 @@ CustomAppstore: "自定义应用仓库"
|
||||
OllamaModelPull: "拉取 Ollama 模型 {{ .name }} "
|
||||
OllamaModelSize: "获取 Ollama 模型 {{ .name }} 大小 "
|
||||
|
||||
# task - snapshot
|
||||
# task - snapshot
|
||||
Snapshot: "快照"
|
||||
SnapDBInfo: "写入 1Panel 数据库信息"
|
||||
SnapCopy: "复制文件&目录 {{ .name }} "
|
||||
@@ -332,6 +335,7 @@ SnapDeleteLoginLog: "删除访问日志"
|
||||
SnapDeleteMonitor: "删除监控数据"
|
||||
SnapRemoveSystemIP: "移除系统 IP"
|
||||
SnapBaseInfo: "写入 1Panel 基本信息"
|
||||
SnapInstallAppImageEmpty: "当前未勾选应用镜像,跳过..."
|
||||
SnapInstallApp: "备份 1Panel 已安装应用"
|
||||
SnapDockerSave: "压缩已安装应用"
|
||||
SnapLocalBackup: "备份 1Panel 本地备份目录"
|
||||
@@ -375,29 +379,29 @@ RecoverBackups: "恢复本地备份目录"
|
||||
RecoverPanelData: "恢复数据目录"
|
||||
|
||||
# task - container
|
||||
ContainerNewCliet: "初始化 Docker Client"
|
||||
ContainerImagePull: "拉取容器镜像 {{ .name }}"
|
||||
ContainerNewCliet: "初始化 Docker Client"
|
||||
ContainerImagePull: "拉取容器镜像 {{ .name }}"
|
||||
ContainerRemoveOld: "删除原容器 {{ .name }}"
|
||||
ContainerImageCheck: "检查镜像是否正常拉取"
|
||||
ContainerLoadInfo: "获取容器基本信息"
|
||||
ContainerRecreate: "容器更新失败,现在开始恢复原容器"
|
||||
ContainerCreate: "创建新容器 {{ .name }}"
|
||||
ContainerCreateFailed: "容器创建失败,删除失败容器"
|
||||
ContainerStartCheck: "检查容器是否已启动"
|
||||
ContainerImageCheck: "检查镜像是否正常拉取"
|
||||
ContainerLoadInfo: "获取容器基本信息"
|
||||
ContainerRecreate: "容器更新失败,现在开始恢复原容器"
|
||||
ContainerCreate: "创建新容器 {{ .name }}"
|
||||
ContainerCreateFailed: "容器创建失败,删除失败容器"
|
||||
ContainerStartCheck: "检查容器是否已启动"
|
||||
|
||||
# task - image
|
||||
ImageBuild: "镜像构建"
|
||||
ImageBuildStdoutCheck: "解析镜像输出内容"
|
||||
ImageBuildRes: "镜像构建输出:{{ .name }}"
|
||||
ImagePull: "拉取镜像"
|
||||
ImageRepoAuthFromDB: "从数据库获取仓库认证信息"
|
||||
ImaegPullRes: "镜像拉取输出:{{ .name }}"
|
||||
ImagePush: "推送镜像"
|
||||
ImageRenameTag: "修改镜像 Tag"
|
||||
ImageNewTag: "新镜像 Tag {{ .name }}"
|
||||
ImaegPushRes: "镜像推送输出:{{ .name }}"
|
||||
ComposeCreate: "创建编排"
|
||||
ComposeCreateRes: "编排创建输出:{{ .name }}"
|
||||
ImageBuild: "镜像构建"
|
||||
ImageBuildStdoutCheck: "解析镜像输出内容"
|
||||
ImageBuildRes: "镜像构建输出:{{ .name }}"
|
||||
ImagePull: "拉取镜像"
|
||||
ImageRepoAuthFromDB: "从数据库获取仓库认证信息"
|
||||
ImaegPullRes: "镜像拉取输出:{{ .name }}"
|
||||
ImagePush: "推送镜像"
|
||||
ImageRenameTag: "修改镜像 Tag"
|
||||
ImageNewTag: "新镜像 Tag {{ .name }}"
|
||||
ImaegPushRes: "镜像推送输出:{{ .name }}"
|
||||
ComposeCreate: "创建编排"
|
||||
ComposeCreateRes: "编排创建输出:{{ .name }}"
|
||||
|
||||
# task - website
|
||||
BackupNginxConfig: "备份网站 OpenResty 配置文件"
|
||||
@@ -419,4 +423,18 @@ ErrAlertSync: "告警信息同步错误,请检查后重试!"
|
||||
ErrAlertRemote: "告警信息远端错误,请检查后重试!"
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "已有安装任务正在进行,请等待任务结束"
|
||||
ErrInstallExtension: "已有安装任务正在进行,请等待任务结束"
|
||||
|
||||
# alert mail template
|
||||
PanelAlertTitle: "面板告警通知"
|
||||
TestAlertTitle: "测试邮件 - 验证邮箱连通性"
|
||||
TestAlert: "这是一封测试邮件,旨在验证您的邮箱发件配置是否正确。"
|
||||
LicenseExpirationAlert: "您的 1Panel 面板,许可证将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
CronJobFailedAlert: "您的 1Panel 面板,计划任务-{{ .name }}执行失败,详情请登录面板查看。"
|
||||
ClamAlert: "您的 1Panel 面板,病毒扫描任务发现 {{ .num }} 个感染文件,详情请登录面板查看。"
|
||||
WebSiteAlert: "您的 1Panel 面板,有 {{ .num }} 个网站将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
SSLAlert: "您的 1Panel 面板,有 {{ .num }} 张SSL证书将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
DiskUsedAlert: "您的 1Panel 面板,磁盘 {{ .name }} 已使用 {{ .used }},详情请登录面板查看。"
|
||||
ResourceAlert: "您的 1Panel 面板,平均 {{ .time }} 分钟内的 {{ .name }} 使用率为 {{ .used }},详情请登录面板查看。"
|
||||
PanelVersionAlert: "您的 1Panel 面板,有最新面板版本可供升级,详情请登录面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 1Panel 面板,面板密码将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
@@ -11,6 +11,7 @@ func Init() {
|
||||
global.DB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "agent.db"), "agent")
|
||||
global.TaskDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "task.db"), "task")
|
||||
global.MonitorDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "monitor.db"), "monitor")
|
||||
global.AlertDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "alert.db"), "alert")
|
||||
|
||||
if global.IsMaster {
|
||||
global.CoreDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "core.db"), "core")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user