mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-12 16:00:33 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3a55ea44d | ||
|
|
270411f7fd | ||
|
|
3c01198e61 | ||
|
|
483b47ad63 | ||
|
|
b10de66ed3 | ||
|
|
305eff048c | ||
|
|
da7968d364 | ||
|
|
d3e2c8e9d3 | ||
|
|
e3a9f2dfb7 | ||
|
|
3c967f8906 | ||
|
|
39bb7acdba | ||
|
|
a30066989b | ||
|
|
0c30dfa092 | ||
|
|
7a44493d13 | ||
|
|
9b726d5d22 | ||
|
|
78e3d9e5fb | ||
|
|
d74b41a5f2 | ||
|
|
f122afdbec | ||
|
|
37308b5c42 | ||
|
|
9c5a6e3925 | ||
|
|
58b95ef2ba | ||
|
|
f617c9d5dd | ||
|
|
c661cc37b3 | ||
|
|
7c49f6c79b | ||
|
|
12b9356c17 | ||
|
|
d3a34293f7 | ||
|
|
c131061f81 | ||
|
|
6a5e1ebaa5 | ||
|
|
a07d016951 | ||
|
|
9d343a90db | ||
|
|
4c813be09d | ||
|
|
d48166f546 | ||
|
|
0f138c1b7c | ||
|
|
8542323c0b | ||
|
|
00f103c66a | ||
|
|
430c75e7ed | ||
|
|
67ffb5e938 | ||
|
|
9c292bebf0 | ||
|
|
ba4307c1dc | ||
|
|
b8b2041a0c | ||
|
|
c45bb60b50 | ||
|
|
fba46be47a | ||
|
|
be0a460935 | ||
|
|
c0a041d024 | ||
|
|
2ce5ad82ce | ||
|
|
50dcb6c7e4 | ||
|
|
017424bf7b | ||
|
|
c7e7407f7c | ||
|
|
cab42b3c7d | ||
|
|
78f280c88f | ||
|
|
22f5a975c3 | ||
|
|
90ba036e39 | ||
|
|
d1e18e43ee | ||
|
|
a801140a82 | ||
|
|
951ab2502e | ||
|
|
0316cb0662 | ||
|
|
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 |
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"ansible.python.interpreterPath": "/opt/homebrew/bin/python3"
|
"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
|
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/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)
|
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)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "mysql", "mariadb":
|
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||||
if err := backupService.MysqlBackup(req); err != nil {
|
if err := backupService.MysqlBackup(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case constant.AppPostgresql:
|
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||||
if err := backupService.PostgresqlBackup(req); err != nil {
|
if err := backupService.PostgresqlBackup(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
@@ -386,7 +386,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
|||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "redis":
|
case "redis", constant.AppRedisCluster:
|
||||||
if err := backupService.RedisBackup(req); err != nil {
|
if err := backupService.RedisBackup(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
@@ -421,12 +421,12 @@ func (b *BaseApi) Recover(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
req.File = downloadPath
|
req.File = downloadPath
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case "mysql", "mariadb":
|
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||||
if err := backupService.MysqlRecover(req); err != nil {
|
if err := backupService.MysqlRecover(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case constant.AppPostgresql:
|
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||||
if err := backupService.PostgresqlRecover(req); err != nil {
|
if err := backupService.PostgresqlRecover(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
@@ -436,7 +436,7 @@ func (b *BaseApi) Recover(c *gin.Context) {
|
|||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "redis":
|
case "redis", constant.AppRedisCluster:
|
||||||
if err := backupService.RedisRecover(req); err != nil {
|
if err := backupService.RedisRecover(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
@@ -466,12 +466,12 @@ func (b *BaseApi) RecoverByUpload(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case "mysql", "mariadb":
|
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||||
if err := backupService.MysqlRecoverByUpload(req); err != nil {
|
if err := backupService.MysqlRecoverByUpload(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case constant.AppPostgresql:
|
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||||
if err := backupService.PostgresqlRecoverByUpload(req); err != nil {
|
if err := backupService.PostgresqlRecoverByUpload(req); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -50,12 +50,7 @@ func (b *BaseApi) LoadContainerUsers(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := containerService.LoadUsers(req)
|
helper.SuccessWithData(c, containerService.LoadUsers(req))
|
||||||
if err != nil {
|
|
||||||
helper.InternalServer(c, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
helper.SuccessWithData(c, list)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container
|
// @Tags Container
|
||||||
@@ -266,7 +261,7 @@ func (b *BaseApi) ContainerCreate(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := containerService.ContainerCreate(req); err != nil {
|
if err := containerService.ContainerCreate(req, true); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -320,7 +315,7 @@ func (b *BaseApi) ContainerUpgrade(c *gin.Context) {
|
|||||||
// @Summary Clean container
|
// @Summary Clean container
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.ContainerPrune true "request"
|
// @Param request body dto.ContainerPrune true "request"
|
||||||
// @Success 200 {object} dto.ContainerPruneReport
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/prune [post]
|
// @Router /containers/prune [post]
|
||||||
@@ -331,12 +326,11 @@ func (b *BaseApi) ContainerPrune(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
report, err := containerService.Prune(req)
|
if err := containerService.Prune(req); err != nil {
|
||||||
if err != nil {
|
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, report)
|
helper.Success(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container
|
// @Tags Container
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
"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)
|
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
|
// @Tags Cronjob
|
||||||
// @Summary Load script options
|
// @Summary Load script options
|
||||||
// @Success 200 {array} dto.ScriptOptions
|
// @Success 200 {array} dto.ScriptOptions
|
||||||
@@ -225,6 +270,28 @@ func (b *BaseApi) UpdateCronjob(c *gin.Context) {
|
|||||||
helper.Success(c)
|
helper.Success(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Cronjob
|
||||||
|
// @Summary Update cronjob group
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.ChangeGroup true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /cronjobs/group/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"更新计划任务分组 [name]","formatEN":"update cronjob group [name]"}
|
||||||
|
func (b *BaseApi) UpdateCronjobGroup(c *gin.Context) {
|
||||||
|
var req dto.ChangeGroup
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cronjobService.UpdateGroup(req); err != nil {
|
||||||
|
helper.InternalServer(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.Success(c)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Cronjob
|
// @Tags Cronjob
|
||||||
// @Summary Update cronjob status
|
// @Summary Update cronjob status
|
||||||
// @Accept json
|
// @Accept json
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import (
|
|||||||
// @Tags Database Redis
|
// @Tags Database Redis
|
||||||
// @Summary Load redis status info
|
// @Summary Load redis status info
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperationWithName true "request"
|
// @Param request body dto.LoadRedisStatus true "request"
|
||||||
// @Success 200 {object} dto.RedisStatus
|
// @Success 200 {object} dto.RedisStatus
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/redis/status [post]
|
// @Router /databases/redis/status [post]
|
||||||
func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
||||||
var req dto.OperationWithName
|
var req dto.LoadRedisStatus
|
||||||
if err := helper.CheckBind(&req, c); err != nil {
|
if err := helper.CheckBind(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -33,13 +33,13 @@ func (b *BaseApi) LoadRedisStatus(c *gin.Context) {
|
|||||||
// @Tags Database Redis
|
// @Tags Database Redis
|
||||||
// @Summary Load redis conf
|
// @Summary Load redis conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperationWithName true "request"
|
// @Param request body dto.LoadRedisStatus true "request"
|
||||||
// @Success 200 {object} dto.RedisConf
|
// @Success 200 {object} dto.RedisConf
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/redis/conf [post]
|
// @Router /databases/redis/conf [post]
|
||||||
func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
||||||
var req dto.OperationWithName
|
var req dto.LoadRedisStatus
|
||||||
if err := helper.CheckBind(&req, c); err != nil {
|
if err := helper.CheckBind(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -55,13 +55,13 @@ func (b *BaseApi) LoadRedisConf(c *gin.Context) {
|
|||||||
// @Tags Database Redis
|
// @Tags Database Redis
|
||||||
// @Summary Load redis persistence conf
|
// @Summary Load redis persistence conf
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.OperationWithName true "request"
|
// @Param request body dto.LoadRedisStatus true "request"
|
||||||
// @Success 200 {object} dto.RedisPersistence
|
// @Success 200 {object} dto.RedisPersistence
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /databases/redis/persistence/conf [post]
|
// @Router /databases/redis/persistence/conf [post]
|
||||||
func (b *BaseApi) LoadPersistenceConf(c *gin.Context) {
|
func (b *BaseApi) LoadPersistenceConf(c *gin.Context) {
|
||||||
var req dto.OperationWithName
|
var req dto.LoadRedisStatus
|
||||||
if err := helper.CheckBind(&req, c); err != nil {
|
if err := helper.CheckBind(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,4 +70,5 @@ var (
|
|||||||
websiteCAService = service.NewIWebsiteCAService()
|
websiteCAService = service.NewIWebsiteCAService()
|
||||||
taskService = service.NewITaskService()
|
taskService = service.NewITaskService()
|
||||||
groupService = service.NewIGroupService()
|
groupService = service.NewIGroupService()
|
||||||
|
alertService = service.NewIAlertService()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func (b *BaseApi) ImagePush(c *gin.Context) {
|
|||||||
// @Summary Delete image
|
// @Summary Delete image
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.BatchDelete true "request"
|
// @Param request body dto.BatchDelete true "request"
|
||||||
// @Success 200 {object} dto.ContainerPruneReport
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /containers/image/remove [post]
|
// @Router /containers/image/remove [post]
|
||||||
@@ -149,13 +149,12 @@ func (b *BaseApi) ImageRemove(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := imageService.ImageRemove(req)
|
if err := imageService.ImageRemove(req); err != nil {
|
||||||
if err != nil {
|
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.SuccessWithData(c, data)
|
helper.Success(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container Image
|
// @Tags Container Image
|
||||||
|
|||||||
@@ -157,3 +157,39 @@ func (b *BaseApi) GetNginxModules(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, modules)
|
helper.SuccessWithData(c, modules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags OpenResty
|
||||||
|
// @Summary Operate default HTTPs
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxOperateReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /openresty/https [post]
|
||||||
|
func (b *BaseApi) OperateDefaultHTTPs(c *gin.Context) {
|
||||||
|
var req request.NginxOperateReq
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := nginxService.OperateDefaultHTTPs(req); err != nil {
|
||||||
|
helper.InternalServer(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.Success(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags OpenResty
|
||||||
|
// @Summary Get default HTTPs status
|
||||||
|
// @Success 200 {object} response.NginxConfigRes
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /openresty/https [get]
|
||||||
|
func (b *BaseApi) GetDefaultHTTPsStatus(c *gin.Context) {
|
||||||
|
res, err := nginxService.GetDefaultHttpsStatus()
|
||||||
|
if err != nil {
|
||||||
|
helper.InternalServer(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func loadLocalConn() (*ssh.SSHClient, error) {
|
|||||||
itemPath = path.Join(currentInfo.HomeDir, ".ssh/id_ed25519_1panel")
|
itemPath = path.Join(currentInfo.HomeDir, ".ssh/id_ed25519_1panel")
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(itemPath); err != nil {
|
if _, err := os.Stat(itemPath); err != nil {
|
||||||
_ = sshService.GenerateSSH(dto.GenerateSSH{EncryptionMode: "ed25519", Name: "_1panel"})
|
_ = sshService.CreateRootCert(dto.CreateRootCert{EncryptionMode: "ed25519", Name: "1panel", Description: "1Panel Terminal"})
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey, _ := os.ReadFile(itemPath)
|
privateKey, _ := os.ReadFile(itemPath)
|
||||||
|
|||||||
+78
-12
@@ -1,6 +1,8 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -90,19 +92,58 @@ func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
|
|||||||
// @Tags SSH
|
// @Tags SSH
|
||||||
// @Summary Generate host SSH secret
|
// @Summary Generate host SSH secret
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.GenerateSSH true "request"
|
// @Param request body dto.CreateRootCert true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/ssh/generate [post]
|
// @Router /hosts/ssh/cert [post]
|
||||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
|
||||||
func (b *BaseApi) GenerateSSH(c *gin.Context) {
|
func (b *BaseApi) CreateRootCert(c *gin.Context) {
|
||||||
var req dto.GenerateSSH
|
var req dto.CreateRootCert
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(req.PassPhrase) != 0 {
|
||||||
|
passPhrase, err := base64.StdEncoding.DecodeString(req.PassPhrase)
|
||||||
|
if err != nil {
|
||||||
|
helper.BadRequest(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.PassPhrase = string(passPhrase)
|
||||||
|
}
|
||||||
|
if len(req.PrivateKey) != 0 {
|
||||||
|
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
helper.BadRequest(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.PrivateKey = string(privateKey)
|
||||||
|
}
|
||||||
|
if len(req.PublicKey) != 0 {
|
||||||
|
publicKey, err := base64.StdEncoding.DecodeString(req.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
helper.BadRequest(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.PublicKey = string(publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
if err := sshService.GenerateSSH(req); err != nil {
|
if err := sshService.CreateRootCert(req); err != nil {
|
||||||
|
helper.InternalServer(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.Success(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags SSH
|
||||||
|
// @Summary Sycn host SSH secret
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /hosts/ssh/cert/sync [post]
|
||||||
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"同步 SSH 密钥 ","formatEN":"sync SSH secret"}
|
||||||
|
func (b *BaseApi) SyncRootCert(c *gin.Context) {
|
||||||
|
if err := sshService.SyncRootCert(); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -112,23 +153,48 @@ func (b *BaseApi) GenerateSSH(c *gin.Context) {
|
|||||||
// @Tags SSH
|
// @Tags SSH
|
||||||
// @Summary Load host SSH secret
|
// @Summary Load host SSH secret
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.GenerateLoad true "request"
|
// @Param request body dto.SearchWithPage true "request"
|
||||||
// @Success 200 {string} secret
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Security Timestamp
|
// @Security Timestamp
|
||||||
// @Router /hosts/ssh/secret [post]
|
// @Router /hosts/ssh/cert/search [post]
|
||||||
func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
|
func (b *BaseApi) SearchRootCert(c *gin.Context) {
|
||||||
var req dto.GenerateLoad
|
var req dto.SearchWithPage
|
||||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := sshService.LoadSSHSecret(req.EncryptionMode)
|
total, data, err := sshService.SearchRootCerts(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, data)
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Total: total,
|
||||||
|
Items: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags SSH
|
||||||
|
// @Summary Delete host SSH secret
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.ForceDelete true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Security Timestamp
|
||||||
|
// @Router /hosts/ssh/cert/delete [post]
|
||||||
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"删除 SSH 密钥 ","formatEN":"delete SSH secret"}
|
||||||
|
func (b *BaseApi) DeleteRootCert(c *gin.Context) {
|
||||||
|
var req dto.ForceDelete
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sshService.DeleteRootCerts(req); err != nil {
|
||||||
|
helper.InternalServer(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.Success(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags SSH
|
// @Tags SSH
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
|||||||
var containerID string
|
var containerID string
|
||||||
var initCmd []string
|
var initCmd []string
|
||||||
switch source {
|
switch source {
|
||||||
case "redis":
|
case "redis", "redis-cluster":
|
||||||
containerID, initCmd, err = loadRedisInitCmd(c)
|
containerID, initCmd, err = loadRedisInitCmd(c, source)
|
||||||
case "ollama":
|
case "ollama":
|
||||||
containerID, initCmd, err = loadOllamaInitCmd(c)
|
containerID, initCmd, err = loadOllamaInitCmd(c)
|
||||||
case "container":
|
case "container":
|
||||||
@@ -127,7 +127,7 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
|||||||
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
_ = 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")
|
name := c.Query("name")
|
||||||
from := c.Query("from")
|
from := c.Query("from")
|
||||||
commands := []string{"exec", "-it"}
|
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)
|
return "", nil, fmt.Errorf("no such database in db, err: %v", err)
|
||||||
}
|
}
|
||||||
if from == "local" {
|
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 {
|
if err != nil {
|
||||||
return "", nil, fmt.Errorf("no such app in db, err: %v", err)
|
return "", nil, fmt.Errorf("no such app in db, err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+311
-4
@@ -1,10 +1,17 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type CreateOrUpdateAlert struct {
|
type CreateOrUpdateAlert struct {
|
||||||
AlertTitle string `json:"alertTitle"`
|
AlertTitle string `json:"alertTitle"`
|
||||||
AlertType string `json:"alertType"`
|
AlertType string `json:"alertType"`
|
||||||
AlertCount uint `json:"alertCount"`
|
AlertMethod string `json:"alertMethod"`
|
||||||
EntryID uint `json:"entryID"`
|
AlertCount uint `json:"alertCount"`
|
||||||
|
EntryID uint `json:"entryID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlertBase struct {
|
type AlertBase struct {
|
||||||
@@ -18,3 +25,303 @@ type PushAlert struct {
|
|||||||
EntryID uint `json:"entryID"`
|
EntryID uint `json:"entryID"`
|
||||||
Param string `json:"param"`
|
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 {
|
type AppDatabase struct {
|
||||||
ServiceName string `json:"PANEL_DB_HOST"`
|
ServiceName string `json:"PANEL_DB_HOST"`
|
||||||
DbName string `json:"PANEL_DB_NAME"`
|
DbName string `json:"PANEL_DB_NAME"`
|
||||||
DbUser string `json:"PANEL_DB_USER"`
|
DbUser string `json:"PANEL_DB_USER"`
|
||||||
Password string `json:"PANEL_DB_USER_PASSWORD"`
|
Password string `json:"PANEL_DB_USER_PASSWORD"`
|
||||||
|
DatabaseName string `json:"DATABASE_NAME"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthParam struct {
|
type AuthParam struct {
|
||||||
@@ -126,6 +127,7 @@ type Locale struct {
|
|||||||
ZhHant string `json:"zh-hant" yaml:"zh-hant"`
|
ZhHant string `json:"zh-hant" yaml:"zh-hant"`
|
||||||
Zh string `json:"zh"`
|
Zh string `json:"zh"`
|
||||||
Ko string `json:"ko"`
|
Ko string `json:"ko"`
|
||||||
|
Tr string `json:"tr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppForm struct {
|
type AppForm struct {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ type BackupOption struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CommonBackup 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"`
|
Name string `json:"name"`
|
||||||
DetailName string `json:"detailName"`
|
DetailName string `json:"detailName"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
@@ -65,7 +65,7 @@ type CommonBackup struct {
|
|||||||
}
|
}
|
||||||
type CommonRecover struct {
|
type CommonRecover struct {
|
||||||
DownloadAccountID uint `json:"downloadAccountID" validate:"required"`
|
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"`
|
Name string `json:"name"`
|
||||||
DetailName string `json:"detailName"`
|
DetailName string `json:"detailName"`
|
||||||
File string `json:"file"`
|
File string `json:"file"`
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type ClamInfo struct {
|
|||||||
Spec string `json:"spec"`
|
Spec string `json:"spec"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
AlertCount uint `json:"alertCount"`
|
AlertCount uint `json:"alertCount"`
|
||||||
|
AlertMethod string `json:"alertMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClamLogSearch struct {
|
type ClamLogSearch struct {
|
||||||
@@ -74,6 +75,7 @@ type ClamCreate struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
AlertCount uint `json:"alertCount"`
|
AlertCount uint `json:"alertCount"`
|
||||||
AlertTitle string `json:"alertTitle"`
|
AlertTitle string `json:"alertTitle"`
|
||||||
|
AlertMethod string `json:"alertMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClamUpdate struct {
|
type ClamUpdate struct {
|
||||||
@@ -87,6 +89,7 @@ type ClamUpdate struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
AlertCount uint `json:"alertCount"`
|
AlertCount uint `json:"alertCount"`
|
||||||
AlertTitle string `json:"alertTitle"`
|
AlertTitle string `json:"alertTitle"`
|
||||||
|
AlertMethod string `json:"alertMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClamUpdateStatus struct {
|
type ClamUpdateStatus struct {
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ type OperationWithName struct {
|
|||||||
type OperateByID struct {
|
type OperateByID struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
type OperateByIDs struct {
|
||||||
|
IDs []uint `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
type Operate struct {
|
type Operate struct {
|
||||||
Operation string `json:"operation" validate:"required"`
|
Operation string `json:"operation" validate:"required"`
|
||||||
@@ -76,3 +79,8 @@ type ForceDelete struct {
|
|||||||
IDs []uint `json:"ids"`
|
IDs []uint `json:"ids"`
|
||||||
ForceDelete bool `json:"forceDelete"`
|
ForceDelete bool `json:"forceDelete"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChangeGroup struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
GroupID uint `json:"groupID" validate:"required"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ type ContainerInfo struct {
|
|||||||
Websites []string `json:"websites"`
|
Websites []string `json:"websites"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ContainerOptions struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
type ContainerStatus struct {
|
type ContainerStatus struct {
|
||||||
All uint `json:"all"`
|
All uint `json:"all"`
|
||||||
Created uint `json:"created"`
|
Created uint `json:"created"`
|
||||||
@@ -164,18 +169,16 @@ type ContainerCommit struct {
|
|||||||
Comment string `json:"comment"`
|
Comment string `json:"comment"`
|
||||||
Author string `json:"author"`
|
Author string `json:"author"`
|
||||||
Pause bool `json:"pause"`
|
Pause bool `json:"pause"`
|
||||||
|
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerPrune struct {
|
type ContainerPrune struct {
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network buildcache"`
|
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network buildcache"`
|
||||||
WithTagAll bool `json:"withTagAll"`
|
WithTagAll bool `json:"withTagAll"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerPruneReport struct {
|
|
||||||
DeletedNumber int `json:"deletedNumber"`
|
|
||||||
SpaceReclaimed int `json:"spaceReclaimed"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Network struct {
|
type Network struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -220,8 +223,9 @@ type VolumeCreate struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BatchDelete struct {
|
type BatchDelete struct {
|
||||||
Force bool `json:"force"`
|
TaskID string `json:"taskID"`
|
||||||
Names []string `json:"names" validate:"required"`
|
Force bool `json:"force"`
|
||||||
|
Names []string `json:"names" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComposeInfo struct {
|
type ComposeInfo struct {
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import (
|
|||||||
|
|
||||||
type PageCronjob struct {
|
type PageCronjob struct {
|
||||||
PageInfo
|
PageInfo
|
||||||
Info string `json:"info"`
|
Info string `json:"info"`
|
||||||
OrderBy string `json:"orderBy" validate:"required,oneof=name status createdAt"`
|
GroupIDs []uint `json:"groupIDs"`
|
||||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
OrderBy string `json:"orderBy" validate:"required,oneof=name status createdAt"`
|
||||||
|
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CronjobSpec struct {
|
type CronjobSpec struct {
|
||||||
@@ -19,6 +20,7 @@ type CronjobOperate struct {
|
|||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Type string `json:"type" validate:"required"`
|
Type string `json:"type" validate:"required"`
|
||||||
|
GroupID uint `json:"groupID"`
|
||||||
SpecCustom bool `json:"specCustom"`
|
SpecCustom bool `json:"specCustom"`
|
||||||
Spec string `json:"spec" validate:"required"`
|
Spec string `json:"spec" validate:"required"`
|
||||||
|
|
||||||
@@ -48,8 +50,9 @@ type CronjobOperate struct {
|
|||||||
IgnoreErr bool `json:"ignoreErr"`
|
IgnoreErr bool `json:"ignoreErr"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
|
|
||||||
AlertCount uint `json:"alertCount"`
|
AlertCount uint `json:"alertCount"`
|
||||||
AlertTitle string `json:"alertTitle"`
|
AlertTitle string `json:"alertTitle"`
|
||||||
|
AlertMethod string `json:"alertMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SnapshotRule struct {
|
type SnapshotRule struct {
|
||||||
@@ -84,6 +87,7 @@ type CronjobInfo struct {
|
|||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
GroupID uint `json:"groupID"`
|
||||||
SpecCustom bool `json:"specCustom"`
|
SpecCustom bool `json:"specCustom"`
|
||||||
Spec string `json:"spec"`
|
Spec string `json:"spec"`
|
||||||
|
|
||||||
@@ -122,6 +126,58 @@ type CronjobInfo struct {
|
|||||||
AlertCount uint `json:"alertCount"`
|
AlertCount uint `json:"alertCount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CronjobImport struct {
|
||||||
|
Cronjobs []CronjobTrans `json:"cronjobs"`
|
||||||
|
}
|
||||||
|
type CronjobTrans struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
GroupID uint `json:"groupID"`
|
||||||
|
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 {
|
type ScriptOptions struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|||||||
@@ -74,8 +74,11 @@ type DashboardCurrent struct {
|
|||||||
CPUTotal int `json:"cpuTotal"`
|
CPUTotal int `json:"cpuTotal"`
|
||||||
|
|
||||||
MemoryTotal uint64 `json:"memoryTotal"`
|
MemoryTotal uint64 `json:"memoryTotal"`
|
||||||
MemoryAvailable uint64 `json:"memoryAvailable"`
|
|
||||||
MemoryUsed uint64 `json:"memoryUsed"`
|
MemoryUsed uint64 `json:"memoryUsed"`
|
||||||
|
MemoryFree uint64 `json:"memoryFree"`
|
||||||
|
MemoryShard uint64 `json:"memoryShard"`
|
||||||
|
MemoryCache uint64 `json:"memoryCache"`
|
||||||
|
MemoryAvailable uint64 `json:"memoryAvailable"`
|
||||||
MemoryUsedPercent float64 `json:"memoryUsedPercent"`
|
MemoryUsedPercent float64 `json:"memoryUsedPercent"`
|
||||||
|
|
||||||
SwapMemoryTotal uint64 `json:"swapMemoryTotal"`
|
SwapMemoryTotal uint64 `json:"swapMemoryTotal"`
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import "time"
|
|||||||
|
|
||||||
// common
|
// common
|
||||||
type DBConfUpdateByFile struct {
|
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 redis-cluster"`
|
||||||
Database string `json:"database" validate:"required"`
|
Database string `json:"database" validate:"required"`
|
||||||
File string `json:"file"`
|
File string `json:"file"`
|
||||||
}
|
}
|
||||||
type ChangeDBInfo struct {
|
type ChangeDBInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
From string `json:"from" validate:"required,oneof=local remote"`
|
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 redis mysql-cluster postgresql-cluster redis-cluster"`
|
||||||
Database string `json:"database" validate:"required"`
|
Database string `json:"database" validate:"required"`
|
||||||
Value string `json:"value" validate:"required"`
|
Value string `json:"value" validate:"required"`
|
||||||
}
|
}
|
||||||
@@ -74,19 +74,19 @@ type BindUser struct {
|
|||||||
|
|
||||||
type MysqlLoadDB struct {
|
type MysqlLoadDB struct {
|
||||||
From string `json:"from" validate:"required,oneof=local remote"`
|
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"`
|
Database string `json:"database" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MysqlDBDeleteCheck struct {
|
type MysqlDBDeleteCheck struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
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"`
|
Database string `json:"database" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MysqlDBDelete struct {
|
type MysqlDBDelete struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
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"`
|
Database string `json:"database" validate:"required"`
|
||||||
ForceDelete bool `json:"forceDelete"`
|
ForceDelete bool `json:"forceDelete"`
|
||||||
DeleteBackup bool `json:"deleteBackup"`
|
DeleteBackup bool `json:"deleteBackup"`
|
||||||
@@ -153,7 +153,7 @@ type MysqlVariables struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MysqlVariablesUpdate 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"`
|
Database string `json:"database" validate:"required"`
|
||||||
Variables []MysqlVariablesUpdateHelper `json:"variables"`
|
Variables []MysqlVariablesUpdateHelper `json:"variables"`
|
||||||
}
|
}
|
||||||
@@ -174,6 +174,7 @@ type RedisConfUpdate struct {
|
|||||||
Timeout string `json:"timeout"`
|
Timeout string `json:"timeout"`
|
||||||
Maxclients string `json:"maxclients"`
|
Maxclients string `json:"maxclients"`
|
||||||
Maxmemory string `json:"maxmemory"`
|
Maxmemory string `json:"maxmemory"`
|
||||||
|
DBType string `json:"dbType" validate:"required,oneof=redis redis-cluster"`
|
||||||
}
|
}
|
||||||
type RedisConfPersistenceUpdate struct {
|
type RedisConfPersistenceUpdate struct {
|
||||||
Database string `json:"database" validate:"required"`
|
Database string `json:"database" validate:"required"`
|
||||||
@@ -181,6 +182,7 @@ type RedisConfPersistenceUpdate struct {
|
|||||||
Appendonly string `json:"appendonly"`
|
Appendonly string `json:"appendonly"`
|
||||||
Appendfsync string `json:"appendfsync"`
|
Appendfsync string `json:"appendfsync"`
|
||||||
Save string `json:"save"`
|
Save string `json:"save"`
|
||||||
|
DBType string `json:"dbType" validate:"required,oneof=redis redis-cluster"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RedisConf struct {
|
type RedisConf struct {
|
||||||
@@ -258,6 +260,7 @@ type DatabaseInfo struct {
|
|||||||
ClientCert string `json:"clientCert"`
|
ClientCert string `json:"clientCert"`
|
||||||
SkipVerify bool `json:"skipVerify"`
|
SkipVerify bool `json:"skipVerify"`
|
||||||
|
|
||||||
|
Timeout uint `json:"timeout"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,6 +296,7 @@ type DatabaseCreate struct {
|
|||||||
ClientCert string `json:"clientCert"`
|
ClientCert string `json:"clientCert"`
|
||||||
SkipVerify bool `json:"skipVerify"`
|
SkipVerify bool `json:"skipVerify"`
|
||||||
|
|
||||||
|
Timeout uint `json:"timeout"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,6 +315,7 @@ type DatabaseUpdate struct {
|
|||||||
ClientCert string `json:"clientCert"`
|
ClientCert string `json:"clientCert"`
|
||||||
SkipVerify bool `json:"skipVerify"`
|
SkipVerify bool `json:"skipVerify"`
|
||||||
|
|
||||||
|
Timeout uint `json:"timeout"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,3 +324,8 @@ type DatabaseDelete struct {
|
|||||||
ForceDelete bool `json:"forceDelete"`
|
ForceDelete bool `json:"forceDelete"`
|
||||||
DeleteBackup bool `json:"deleteBackup"`
|
DeleteBackup bool `json:"deleteBackup"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoadRedisStatus struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -60,26 +60,20 @@ type PostgresqlPrivileges struct {
|
|||||||
|
|
||||||
type PostgresqlLoadDB struct {
|
type PostgresqlLoadDB struct {
|
||||||
From string `json:"from" validate:"required,oneof=local remote"`
|
From string `json:"from" validate:"required,oneof=local remote"`
|
||||||
Type string `json:"type" validate:"required,oneof=postgresql"`
|
Type string `json:"type" validate:"required,oneof=postgresql postgresql-cluster"`
|
||||||
Database string `json:"database" validate:"required"`
|
Database string `json:"database" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostgresqlDBDeleteCheck struct {
|
type PostgresqlDBDeleteCheck struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
Type string `json:"type" validate:"required,oneof=postgresql"`
|
Type string `json:"type" validate:"required,oneof=postgresql postgresql-cluster"`
|
||||||
Database string `json:"database" validate:"required"`
|
Database string `json:"database" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostgresqlDBDelete struct {
|
type PostgresqlDBDelete struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
Type string `json:"type" validate:"required,oneof=postgresql"`
|
Type string `json:"type" validate:"required,oneof=postgresql postgresql-cluster"`
|
||||||
Database string `json:"database" validate:"required"`
|
Database string `json:"database" validate:"required"`
|
||||||
ForceDelete bool `json:"forceDelete"`
|
ForceDelete bool `json:"forceDelete"`
|
||||||
DeleteBackup bool `json:"deleteBackup"`
|
DeleteBackup bool `json:"deleteBackup"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostgresqlConfUpdateByFile struct {
|
|
||||||
Type string `json:"type" validate:"required,oneof=postgresql mariadb"`
|
|
||||||
Database string `json:"database" validate:"required"`
|
|
||||||
File string `json:"file"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type SupervisorProcessConfig struct {
|
|||||||
Dir string `json:"dir"`
|
Dir string `json:"dir"`
|
||||||
Numprocs string `json:"numprocs"`
|
Numprocs string `json:"numprocs"`
|
||||||
AutoRestart string `json:"autoRestart"`
|
AutoRestart string `json:"autoRestart"`
|
||||||
|
AutoStart string `json:"autoStart"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SupervisorProcessFileReq struct {
|
type SupervisorProcessFileReq struct {
|
||||||
|
|||||||
@@ -9,15 +9,17 @@ type McpServerSearch struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type McpServerCreate struct {
|
type McpServerCreate struct {
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Command string `json:"command" validate:"required"`
|
Command string `json:"command" validate:"required"`
|
||||||
Environments []Environment `json:"environments"`
|
Environments []Environment `json:"environments"`
|
||||||
Volumes []Volume `json:"volumes"`
|
Volumes []Volume `json:"volumes"`
|
||||||
Port int `json:"port" validate:"required"`
|
Port int `json:"port" validate:"required"`
|
||||||
ContainerName string `json:"containerName"`
|
ContainerName string `json:"containerName"`
|
||||||
BaseURL string `json:"baseUrl"`
|
BaseURL string `json:"baseUrl"`
|
||||||
SsePath string `json:"ssePath"`
|
SsePath string `json:"ssePath"`
|
||||||
HostIP string `json:"hostIP"`
|
HostIP string `json:"hostIP"`
|
||||||
|
StreamableHttpPath string `json:"streamableHttpPath"`
|
||||||
|
OutputTransport string `json:"outputTransport" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type McpServerUpdate struct {
|
type McpServerUpdate struct {
|
||||||
|
|||||||
@@ -126,3 +126,7 @@ type NginxModuleUpdate struct {
|
|||||||
Enable bool `json:"enable"`
|
Enable bool `json:"enable"`
|
||||||
Params string `json:"params"`
|
Params string `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NginxOperateReq struct {
|
||||||
|
Operate string `json:"operate" validate:"required,oneof=enable disable"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -129,6 +129,19 @@ type AppInstallDTO struct {
|
|||||||
Container string `json:"container"`
|
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 {
|
type DatabaseConn struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -158,6 +171,7 @@ type AppParam struct {
|
|||||||
ShowValue string `json:"showValue"`
|
ShowValue string `json:"showValue"`
|
||||||
Required bool `json:"required"`
|
Required bool `json:"required"`
|
||||||
Multiple bool `json:"multiple"`
|
Multiple bool `json:"multiple"`
|
||||||
|
Label dto.Locale `json:"label"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ type AppIgnoreUpgradeDTO struct {
|
|||||||
AppDetailID uint `json:"appDetailID"`
|
AppDetailID uint `json:"appDetailID"`
|
||||||
Scope string `json:"scope"`
|
Scope string `json:"scope"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Icon string `json:"icon"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package response
|
package response
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileInfo struct {
|
type FileInfo struct {
|
||||||
@@ -37,11 +38,12 @@ type FileWgetRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FileLineContent struct {
|
type FileLineContent struct {
|
||||||
Content string `json:"content"`
|
End bool `json:"end"`
|
||||||
End bool `json:"end"`
|
Path string `json:"path"`
|
||||||
Path string `json:"path"`
|
Total int `json:"total"`
|
||||||
Total int `json:"total"`
|
TaskStatus string `json:"taskStatus"`
|
||||||
Lines []string `json:"lines"`
|
Lines []string `json:"lines"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileExist struct {
|
type FileExist struct {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type SupervisorProcessConfig struct {
|
|||||||
Msg string `json:"msg"`
|
Msg string `json:"msg"`
|
||||||
Status []ProcessStatus `json:"status"`
|
Status []ProcessStatus `json:"status"`
|
||||||
AutoRestart string `json:"autoRestart"`
|
AutoRestart string `json:"autoRestart"`
|
||||||
|
AutoStart string `json:"autoStart"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessStatus struct {
|
type ProcessStatus struct {
|
||||||
|
|||||||
@@ -80,3 +80,7 @@ type NginxBuildConfig struct {
|
|||||||
Mirror string `json:"mirror"`
|
Mirror string `json:"mirror"`
|
||||||
Modules []NginxModule `json:"modules"`
|
Modules []NginxModule `json:"modules"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NginxConfigRes struct {
|
||||||
|
Https bool `json:"https"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type SnapshotCreate struct {
|
|||||||
Description string `json:"description" validate:"max=256"`
|
Description string `json:"description" validate:"max=256"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
InterruptStep string `json:"interruptStep"`
|
InterruptStep string `json:"interruptStep"`
|
||||||
|
Timeout uint `json:"timeout"`
|
||||||
|
|
||||||
AppData []DataTree `json:"appData"`
|
AppData []DataTree `json:"appData"`
|
||||||
BackupData []DataTree `json:"backupData"`
|
BackupData []DataTree `json:"backupData"`
|
||||||
|
|||||||
+18
-3
@@ -19,12 +19,27 @@ type SSHInfo struct {
|
|||||||
PubkeyAuthentication string `json:"pubkeyAuthentication"`
|
PubkeyAuthentication string `json:"pubkeyAuthentication"`
|
||||||
PermitRootLogin string `json:"permitRootLogin"`
|
PermitRootLogin string `json:"permitRootLogin"`
|
||||||
UseDNS string `json:"useDNS"`
|
UseDNS string `json:"useDNS"`
|
||||||
|
CurrentUser string `json:"currentUser"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenerateSSH struct {
|
type CreateRootCert struct {
|
||||||
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
PublicKey string `json:"publicKey"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
type RootCert struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
EncryptionMode string `json:"encryptionMode"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
PublicKey string `json:"publicKey"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenerateLoad struct {
|
type GenerateLoad struct {
|
||||||
|
|||||||
@@ -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"`
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ type Cronjob struct {
|
|||||||
|
|
||||||
Name string `gorm:"not null" json:"name"`
|
Name string `gorm:"not null" json:"name"`
|
||||||
Type string `gorm:"not null" json:"type"`
|
Type string `gorm:"not null" json:"type"`
|
||||||
|
GroupID uint `json:"groupID"`
|
||||||
SpecCustom bool `json:"specCustom"`
|
SpecCustom bool `json:"specCustom"`
|
||||||
Spec string `gorm:"not null" json:"spec"`
|
Spec string `gorm:"not null" json:"spec"`
|
||||||
|
|
||||||
|
|||||||
@@ -18,5 +18,6 @@ type Database struct {
|
|||||||
ClientCert string `json:"clientCert"`
|
ClientCert string `json:"clientCert"`
|
||||||
SkipVerify bool `json:"skipVerify"`
|
SkipVerify bool `json:"skipVerify"`
|
||||||
|
|
||||||
|
Timeout uint `json:"timeout"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,19 @@ package model
|
|||||||
|
|
||||||
type McpServer struct {
|
type McpServer struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
DockerCompose string `json:"dockerCompose"`
|
DockerCompose string `json:"dockerCompose"`
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
ContainerName string `json:"containerName"`
|
ContainerName string `json:"containerName"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Env string `json:"env"`
|
Env string `json:"env"`
|
||||||
BaseURL string `json:"baseUrl"`
|
BaseURL string `json:"baseUrl"`
|
||||||
SsePath string `json:"ssePath"`
|
SsePath string `json:"ssePath"`
|
||||||
WebsiteID int `json:"websiteID"`
|
WebsiteID int `json:"websiteID"`
|
||||||
Dir string `json:"dir"`
|
Dir string `json:"dir"`
|
||||||
HostIP string `json:"hostIP"`
|
HostIP string `json:"hostIP"`
|
||||||
|
StreamableHttpPath string `json:"streamableHttpPath"`
|
||||||
|
OutputTransport string `json:"outputTransport"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type Snapshot struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
Timeout uint `json:"timeout"`
|
||||||
|
|
||||||
TaskID string `json:"taskID"`
|
TaskID string `json:"taskID"`
|
||||||
TaskRecoverID string `json:"taskRecoverID"`
|
TaskRecoverID string `json:"taskRecoverID"`
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type RootCert struct {
|
||||||
|
BaseModel
|
||||||
|
Name string `json:"name" gorm:"not null;"`
|
||||||
|
EncryptionMode string `json:"encryptionMode"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
PublicKeyPath string `json:"publicKeyPath"`
|
||||||
|
PrivateKeyPath string `json:"privateKeyPath"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ type AppIgnoreUpgradeRepo struct {
|
|||||||
|
|
||||||
type IAppIgnoreUpgradeRepo interface {
|
type IAppIgnoreUpgradeRepo interface {
|
||||||
WithScope(scope string) DBOption
|
WithScope(scope string) DBOption
|
||||||
|
WithAppID(appID uint) DBOption
|
||||||
List(opts ...DBOption) ([]model.AppIgnoreUpgrade, error)
|
List(opts ...DBOption) ([]model.AppIgnoreUpgrade, error)
|
||||||
Create(appIgnoreUpgrade *model.AppIgnoreUpgrade) error
|
Create(appIgnoreUpgrade *model.AppIgnoreUpgrade) error
|
||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
@@ -26,6 +27,12 @@ func (a AppIgnoreUpgradeRepo) WithScope(scope string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppIgnoreUpgradeRepo) WithAppID(appID uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("app_id = ?", appID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppIgnoreUpgradeRepo) List(opts ...DBOption) ([]model.AppIgnoreUpgrade, error) {
|
func (a AppIgnoreUpgradeRepo) List(opts ...DBOption) ([]model.AppIgnoreUpgrade, error) {
|
||||||
var appIgnoreUpgradeList []model.AppIgnoreUpgrade
|
var appIgnoreUpgradeList []model.AppIgnoreUpgrade
|
||||||
err := getDb(opts...).Find(&appIgnoreUpgradeList).Error
|
err := getDb(opts...).Find(&appIgnoreUpgradeList).Error
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ type IAppInstallRepo interface {
|
|||||||
Page(page, size int, opts ...DBOption) (int64, []model.AppInstall, error)
|
Page(page, size int, opts ...DBOption) (int64, []model.AppInstall, error)
|
||||||
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
||||||
LoadBaseInfo(key string, name string) (*RootInfo, 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)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
switch app.Key {
|
switch app.Key {
|
||||||
case "mysql", "mariadb":
|
case "mysql", "mariadb", constant.AppMysqlCluster:
|
||||||
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
|
password, ok := envMap["PANEL_DB_ROOT_PASSWORD"].(string)
|
||||||
if ok {
|
if ok {
|
||||||
info.Password = password
|
info.Password = password
|
||||||
}
|
}
|
||||||
case "redis":
|
case "redis", constant.AppRedisCluster:
|
||||||
password, ok := envMap["PANEL_REDIS_ROOT_PASSWORD"].(string)
|
password, ok := envMap["PANEL_REDIS_ROOT_PASSWORD"].(string)
|
||||||
if ok {
|
if ok {
|
||||||
info.Password = password
|
info.Password = password
|
||||||
}
|
}
|
||||||
case "mongodb", constant.AppPostgresql:
|
case "mongodb", constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||||
user, ok := envMap["PANEL_DB_ROOT_USER"].(string)
|
user, ok := envMap["PANEL_DB_ROOT_USER"].(string)
|
||||||
if ok {
|
if ok {
|
||||||
info.UserName = user
|
info.UserName = user
|
||||||
@@ -246,3 +247,23 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
|||||||
info.Status = appInstall.Status
|
info.Status = appInstall.Status
|
||||||
return &info, nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,8 +17,10 @@ type IAppTagRepo interface {
|
|||||||
GetByAppId(appId uint) ([]model.AppTag, error)
|
GetByAppId(appId uint) ([]model.AppTag, error)
|
||||||
GetByTagIds(tagIds []uint) ([]model.AppTag, error)
|
GetByTagIds(tagIds []uint) ([]model.AppTag, error)
|
||||||
DeleteBy(ctx context.Context, opts ...DBOption) error
|
DeleteBy(ctx context.Context, opts ...DBOption) error
|
||||||
|
GetFirst(opts ...DBOption) (*model.AppTag, error)
|
||||||
|
|
||||||
WithByTagID(tagID uint) DBOption
|
WithByTagID(tagID uint) DBOption
|
||||||
|
WithByAppID(appId uint) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAppTagRepo() IAppTagRepo {
|
func NewIAppTagRepo() IAppTagRepo {
|
||||||
@@ -31,6 +33,12 @@ func (a AppTagRepo) WithByTagID(tagID uint) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppTagRepo) WithByAppID(appId uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("app_id = ?", appId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppTagRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
|
func (a AppTagRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
|
||||||
return getTx(ctx).Create(&tags).Error
|
return getTx(ctx).Create(&tags).Error
|
||||||
}
|
}
|
||||||
@@ -62,3 +70,12 @@ func (a AppTagRepo) GetByTagIds(tagIds []uint) ([]model.AppTag, error) {
|
|||||||
func (a AppTagRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
|
func (a AppTagRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
|
||||||
return getTx(ctx, opts...).Delete(&model.AppTag{}).Error
|
return getTx(ctx, opts...).Delete(&model.AppTag{}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppTagRepo) GetFirst(opts ...DBOption) (*model.AppTag, error) {
|
||||||
|
var appTag model.AppTag
|
||||||
|
if err := getDb(opts...).First(&appTag).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &appTag, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,6 +104,15 @@ func WithByDate(startTime, endTime time.Time) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithByGroups(groupIDs []uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
if len(groupIDs) == 0 {
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
return g.Where("group_id in (?)", groupIDs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WithByCreatedAt(startTime, endTime time.Time) DBOption {
|
func WithByCreatedAt(startTime, endTime time.Time) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("created_at > ? AND created_at < ?", startTime, endTime)
|
return g.Where("created_at > ? AND created_at < ?", startTime, endTime)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HostRepo struct{}
|
type HostRepo struct{}
|
||||||
@@ -13,6 +14,14 @@ type IHostRepo interface {
|
|||||||
SaveFirewallRecord(firewall *model.Firewall) error
|
SaveFirewallRecord(firewall *model.Firewall) error
|
||||||
DeleteFirewallRecordByID(id uint) error
|
DeleteFirewallRecordByID(id uint) error
|
||||||
DeleteFirewallRecord(fType, port, protocol, address, strategy string) error
|
DeleteFirewallRecord(fType, port, protocol, address, strategy string) error
|
||||||
|
|
||||||
|
SyncCert(data []model.RootCert) error
|
||||||
|
GetCert(opts ...DBOption) (model.RootCert, error)
|
||||||
|
PageCert(limit, offset int, opts ...DBOption) (int64, []model.RootCert, error)
|
||||||
|
ListCert(opts ...DBOption) ([]model.RootCert, error)
|
||||||
|
CreateCert(cert *model.RootCert) error
|
||||||
|
UpdateCert(id uint, vars map[string]interface{}) error
|
||||||
|
DeleteCert(opts ...DBOption) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIHostRepo() IHostRepo {
|
func NewIHostRepo() IHostRepo {
|
||||||
@@ -63,3 +72,82 @@ func (h *HostRepo) DeleteFirewallRecordByID(id uint) error {
|
|||||||
func (h *HostRepo) DeleteFirewallRecord(fType, port, protocol, address, strategy string) error {
|
func (h *HostRepo) DeleteFirewallRecord(fType, port, protocol, address, strategy string) error {
|
||||||
return global.DB.Where("type = ? AND port = ? AND protocol = ? AND address = ? AND strategy = ?", fType, port, protocol, address, strategy).Delete(&model.Firewall{}).Error
|
return global.DB.Where("type = ? AND port = ? AND protocol = ? AND address = ? AND strategy = ?", fType, port, protocol, address, strategy).Delete(&model.Firewall{}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *HostRepo) GetCert(opts ...DBOption) (model.RootCert, error) {
|
||||||
|
var cert model.RootCert
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.First(&cert).Error
|
||||||
|
return cert, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *HostRepo) PageCert(page, size int, opts ...DBOption) (int64, []model.RootCert, error) {
|
||||||
|
var ops []model.RootCert
|
||||||
|
db := global.DB.Model(&model.RootCert{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&ops).Error
|
||||||
|
return count, ops, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *HostRepo) ListCert(opts ...DBOption) ([]model.RootCert, error) {
|
||||||
|
var ops []model.RootCert
|
||||||
|
db := global.DB.Model(&model.RootCert{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Find(&ops).Error
|
||||||
|
return ops, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *HostRepo) CreateCert(cert *model.RootCert) error {
|
||||||
|
return global.DB.Create(cert).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *HostRepo) UpdateCert(id uint, vars map[string]interface{}) error {
|
||||||
|
return global.DB.Model(&model.RootCert{}).Where("id = ?", id).Updates(vars).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *HostRepo) DeleteCert(opts ...DBOption) error {
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
return db.Delete(&model.RootCert{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *HostRepo) SyncCert(data []model.RootCert) error {
|
||||||
|
tx := global.DB.Begin()
|
||||||
|
var oldCerts []model.RootCert
|
||||||
|
_ = tx.Where("1 = ?", 1).Find(&oldCerts).Error
|
||||||
|
oldCertsMap := make(map[string]uint)
|
||||||
|
for _, item := range oldCerts {
|
||||||
|
oldCertsMap[item.Name] = item.ID
|
||||||
|
}
|
||||||
|
for _, item := range data {
|
||||||
|
if _, ok := oldCertsMap[item.Name]; ok {
|
||||||
|
delete(oldCertsMap, item.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
item.PassPhrase, _ = encrypt.StringEncrypt("<UN-SET>")
|
||||||
|
if err := tx.Model(model.RootCert{}).Create(&item).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, val := range oldCertsMap {
|
||||||
|
if err := tx.Where("id = ?", val).Delete(&model.RootCert{}).Error; err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type ITagRepo interface {
|
|||||||
DeleteByID(ctx context.Context, id uint) error
|
DeleteByID(ctx context.Context, id uint) error
|
||||||
Create(ctx context.Context, tag *model.Tag) error
|
Create(ctx context.Context, tag *model.Tag) error
|
||||||
Save(ctx context.Context, tag *model.Tag) error
|
Save(ctx context.Context, tag *model.Tag) error
|
||||||
|
GetByKey(key string) (*model.Tag, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewITagRepo() ITagRepo {
|
func NewITagRepo() ITagRepo {
|
||||||
@@ -41,6 +42,14 @@ func (t TagRepo) All() ([]model.Tag, error) {
|
|||||||
return tags, nil
|
return tags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t TagRepo) GetByKey(key string) (*model.Tag, error) {
|
||||||
|
var tag model.Tag
|
||||||
|
if err := getDb().Where("key = ?", key).First(&tag).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t TagRepo) GetByIds(ids []uint) ([]model.Tag, error) {
|
func (t TagRepo) GetByIds(ids []uint) ([]model.Tag, error) {
|
||||||
var tags []model.Tag
|
var tags []model.Tag
|
||||||
if err := getDb().Where("id in (?)", ids).Find(&tags).Error; err != nil {
|
if err := getDb().Where("id in (?)", ids).Find(&tags).Error; err != 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)
|
||||||
|
}
|
||||||
+14
-24
@@ -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_HOST"] = database.Address
|
||||||
req.Params["PANEL_DB_PORT"] = database.Port
|
req.Params["PANEL_DB_PORT"] = database.Port
|
||||||
req.Params["PANEL_DB_HOST_NAME"] = hostName
|
req.Params["PANEL_DB_HOST_NAME"] = hostName
|
||||||
|
req.Params["DATABASE_NAME"] = database.Name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
paramByte, err = json.Marshal(req.Params)
|
paramByte, err = json.Marshal(req.Params)
|
||||||
@@ -927,18 +928,11 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
tags []*model.Tag
|
|
||||||
appTags []*model.AppTag
|
appTags []*model.AppTag
|
||||||
oldAppIds []uint
|
oldAppIds []uint
|
||||||
)
|
)
|
||||||
for _, tag := range list.Extra.Tags {
|
if err = SyncTags(list.Extra); err != nil {
|
||||||
translations, _ := json.Marshal(tag.Locales)
|
return err
|
||||||
tags = append(tags, &model.Tag{
|
|
||||||
Name: tag.Name,
|
|
||||||
Translations: string(translations),
|
|
||||||
Sort: tag.Sort,
|
|
||||||
Key: tag.Key,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
deleteCustomApp()
|
deleteCustomApp()
|
||||||
oldApps, err := appRepo.GetBy(appRepo.WithNotLocal())
|
oldApps, err := appRepo.GetBy(appRepo.WithNotLocal())
|
||||||
@@ -1014,6 +1008,7 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
|
|||||||
}
|
}
|
||||||
t.LogSuccess(i18n.GetMsgByKey("SyncAppDetail"))
|
t.LogSuccess(i18n.GetMsgByKey("SyncAppDetail"))
|
||||||
|
|
||||||
|
tags, _ := tagRepo.All()
|
||||||
var (
|
var (
|
||||||
addAppArray []model.App
|
addAppArray []model.App
|
||||||
updateAppArray []model.App
|
updateAppArray []model.App
|
||||||
@@ -1060,16 +1055,8 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = tagRepo.DeleteAll(ctx); err != nil {
|
for _, tag := range tags {
|
||||||
return
|
tagMap[tag.Key] = tag.ID
|
||||||
}
|
|
||||||
if len(tags) > 0 {
|
|
||||||
if err = tagRepo.BatchCreate(ctx, tags); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, tag := range tags {
|
|
||||||
tagMap[tag.Key] = tag.ID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, update := range updateAppArray {
|
for _, update := range updateAppArray {
|
||||||
if err = appRepo.Save(ctx, &update); err != nil {
|
if err = appRepo.Save(ctx, &update); err != nil {
|
||||||
@@ -1087,10 +1074,13 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
|
|||||||
for _, tag := range app.TagsKey {
|
for _, tag := range app.TagsKey {
|
||||||
tagId, ok := tagMap[tag]
|
tagId, ok := tagMap[tag]
|
||||||
if ok {
|
if ok {
|
||||||
appTags = append(appTags, &model.AppTag{
|
exist, _ := appTagRepo.GetFirst(appTagRepo.WithByTagID(tagId), appTagRepo.WithByAppID(app.ID))
|
||||||
AppId: app.ID,
|
if exist != nil {
|
||||||
TagId: tagId,
|
appTags = append(appTags, &model.AppTag{
|
||||||
})
|
AppId: app.ID,
|
||||||
|
TagId: tagId,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, d := range app.Details {
|
for _, d := range app.Details {
|
||||||
@@ -1133,7 +1123,7 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(oldAppIds) > 0 {
|
if len(oldAppIds) > 0 {
|
||||||
if err = appTagRepo.DeleteByAppIds(ctx, oldAppIds); err != nil {
|
if err = appTagRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func (a AppIgnoreUpgradeService) List() ([]response.AppIgnoreUpgradeDTO, error)
|
|||||||
_ = appIgnoreUpgradeRepo.Delete(repo.WithByID(ignore.ID))
|
_ = appIgnoreUpgradeRepo.Delete(repo.WithByID(ignore.ID))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dto.Icon = app.Icon
|
dto.Name = app.Name
|
||||||
if ignore.Scope == "version" {
|
if ignore.Scope == "version" {
|
||||||
appDetail, err := appDetailRepo.GetFirst(repo.WithByID(ignore.AppDetailID))
|
appDetail, err := appDetailRepo.GetFirst(repo.WithByID(ignore.AppDetailID))
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ type IAppInstallService interface {
|
|||||||
|
|
||||||
UpdateAppConfig(req request.AppConfigUpdate) error
|
UpdateAppConfig(req request.AppConfigUpdate) error
|
||||||
GetInstallList() ([]dto.AppInstallInfo, error)
|
GetInstallList() ([]dto.AppInstallInfo, error)
|
||||||
|
GetAppInstallInfo(appInstallID uint) (*response.AppInstallInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAppInstalledService() IAppInstallService {
|
func NewIAppInstalledService() IAppInstallService {
|
||||||
@@ -472,10 +473,20 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
|||||||
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
|
||||||
var res []response.AppService
|
var res []response.AppService
|
||||||
if DatabaseKeys[key] > 0 {
|
if DatabaseKeys[key] > 0 {
|
||||||
|
types := []string{key}
|
||||||
if key == constant.AppPostgres {
|
if key == constant.AppPostgres {
|
||||||
key = constant.AppPostgresql
|
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 {
|
if len(dbs) == 0 {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@@ -658,10 +669,10 @@ func (a *AppInstallService) GetDefaultConfigByKey(key, name string) (string, err
|
|||||||
return "", buserr.New("ErrPathNotFound")
|
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")
|
filePath = path.Join(filePath, "my.cnf")
|
||||||
}
|
}
|
||||||
if key == constant.AppRedis {
|
if key == constant.AppRedis || key == constant.AppRedisCluster {
|
||||||
filePath = path.Join(filePath, "redis.conf")
|
filePath = path.Join(filePath, "redis.conf")
|
||||||
}
|
}
|
||||||
if key == constant.AppOpenresty {
|
if key == constant.AppOpenresty {
|
||||||
@@ -710,6 +721,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
|||||||
}
|
}
|
||||||
appParam.LabelZh = form.LabelZh
|
appParam.LabelZh = form.LabelZh
|
||||||
appParam.LabelEn = form.LabelEn
|
appParam.LabelEn = form.LabelEn
|
||||||
|
appParam.Label = form.Label
|
||||||
appParam.Value = v
|
appParam.Value = v
|
||||||
if form.Type == "service" {
|
if form.Type == "service" {
|
||||||
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
||||||
@@ -763,6 +775,7 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
|
|||||||
Values: form.Values,
|
Values: form.Values,
|
||||||
Multiple: form.Multiple,
|
Multiple: form.Multiple,
|
||||||
Required: form.Required,
|
Required: form.Required,
|
||||||
|
Label: form.Label,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -898,3 +911,31 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
|
|||||||
}
|
}
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
+109
-43
@@ -116,13 +116,16 @@ func checkPortExist(port int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var DatabaseKeys = map[string]uint{
|
var DatabaseKeys = map[string]uint{
|
||||||
constant.AppMysql: 3306,
|
constant.AppMysql: 3306,
|
||||||
constant.AppMariaDB: 3306,
|
constant.AppMariaDB: 3306,
|
||||||
constant.AppPostgresql: 5432,
|
constant.AppPostgresql: 5432,
|
||||||
constant.AppPostgres: 5432,
|
constant.AppPostgres: 5432,
|
||||||
constant.AppMongodb: 27017,
|
constant.AppMongodb: 27017,
|
||||||
constant.AppRedis: 6379,
|
constant.AppRedis: 6379,
|
||||||
constant.AppMemcached: 11211,
|
constant.AppMemcached: 11211,
|
||||||
|
constant.AppMysqlCluster: 3306,
|
||||||
|
constant.AppPostgresqlCluster: 5432,
|
||||||
|
constant.AppRedisCluster: 6379,
|
||||||
}
|
}
|
||||||
|
|
||||||
var ToolKeys = map[string]uint{
|
var ToolKeys = map[string]uint{
|
||||||
@@ -138,7 +141,6 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
|||||||
}
|
}
|
||||||
_ = deleteLink(del)
|
_ = deleteLink(del)
|
||||||
}
|
}
|
||||||
var dbConfig dto.AppDatabase
|
|
||||||
if DatabaseKeys[app.Key] > 0 {
|
if DatabaseKeys[app.Key] > 0 {
|
||||||
handleDataBaseApp := func(task *task.Task) error {
|
handleDataBaseApp := func(task *task.Task) error {
|
||||||
database := &model.Database{
|
database := &model.Database{
|
||||||
@@ -170,11 +172,11 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch app.Key {
|
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, ok := params["PANEL_DB_ROOT_PASSWORD"]; ok {
|
||||||
if password != "" {
|
if password != "" {
|
||||||
database.Password = password.(string)
|
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"
|
database.Username = "root"
|
||||||
}
|
}
|
||||||
if rootUser, ok := params["PANEL_DB_ROOT_USER"]; ok {
|
if rootUser, ok := params["PANEL_DB_ROOT_USER"]; ok {
|
||||||
@@ -192,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 {
|
if password, ok := params["PANEL_REDIS_ROOT_PASSWORD"]; ok {
|
||||||
authParam := dto.RedisAuthParam{
|
authParam := dto.RedisAuthParam{
|
||||||
RootPassword: "",
|
RootPassword: "",
|
||||||
@@ -229,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" {
|
if app.Type == "website" || app.Type == "tool" {
|
||||||
paramByte, err := json.Marshal(params)
|
paramByte, err := json.Marshal(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -252,8 +255,11 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
|||||||
var resourceId uint
|
var resourceId uint
|
||||||
if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" {
|
if dbConfig.DbName != "" && dbConfig.DbUser != "" && dbConfig.Password != "" {
|
||||||
switch database.Type {
|
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))
|
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
|
resourceId = oldPostgresqlDb.ID
|
||||||
if oldPostgresqlDb.ID > 0 {
|
if oldPostgresqlDb.ID > 0 {
|
||||||
if oldPostgresqlDb.Username != dbConfig.DbUser || oldPostgresqlDb.Password != dbConfig.Password {
|
if oldPostgresqlDb.Username != dbConfig.DbUser || oldPostgresqlDb.Password != dbConfig.Password {
|
||||||
@@ -274,8 +280,11 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
|
|||||||
}
|
}
|
||||||
resourceId = pgdb.ID
|
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))
|
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
|
resourceId = oldMysqlDb.ID
|
||||||
if oldMysqlDb.ID > 0 {
|
if oldMysqlDb.ID > 0 {
|
||||||
if oldMysqlDb.Username != dbConfig.DbUser || oldMysqlDb.Password != dbConfig.Password {
|
if oldMysqlDb.Username != dbConfig.DbUser || oldMysqlDb.Password != dbConfig.Password {
|
||||||
@@ -405,9 +414,9 @@ func deleteAppInstall(deleteReq request.AppInstallDelete) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch install.App.Key {
|
switch install.App.Key {
|
||||||
case constant.AppMysql, constant.AppMariaDB:
|
case constant.AppMysql, constant.AppMariaDB, constant.AppMysqlCluster:
|
||||||
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
|
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
|
||||||
case constant.AppPostgresql:
|
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||||
_ = postgresqlRepo.Delete(ctx, postgresqlRepo.WithByPostgresqlName(install.Name))
|
_ = postgresqlRepo.Delete(ctx, postgresqlRepo.WithByPostgresqlName(install.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +440,11 @@ func deleteAppInstall(deleteReq request.AppInstallDelete) error {
|
|||||||
_ = op.DeleteDir(parentDir)
|
_ = op.DeleteDir(parentDir)
|
||||||
}
|
}
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
|
|
||||||
|
existApps, _ := appInstallRepo.ListBy(context.Background(), appInstallRepo.WithAppId(install.AppId))
|
||||||
|
if len(existApps) == 0 {
|
||||||
|
_ = appIgnoreUpgradeRepo.Delete(appIgnoreUpgradeRepo.WithAppID(install.AppId))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
uninstallTask.AddSubTask(task.GetTaskName(install.Name, task.TaskUninstall, task.TaskScopeApp), uninstall, nil)
|
uninstallTask.AddSubTask(task.GetTaskName(install.Name, task.TaskUninstall, task.TaskScopeApp), uninstall, nil)
|
||||||
@@ -641,7 +655,11 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
|||||||
}
|
}
|
||||||
dockerCLi, _ := docker.NewClient()
|
dockerCLi, _ := docker.NewClient()
|
||||||
if req.PullImage {
|
if req.PullImage {
|
||||||
images, err := composeV2.GetDockerComposeImagesV2(content, []byte(detail.DockerCompose))
|
composeContent := []byte(detail.DockerCompose)
|
||||||
|
if req.DockerCompose != "" {
|
||||||
|
composeContent = []byte(req.DockerCompose)
|
||||||
|
}
|
||||||
|
images, err := composeV2.GetDockerComposeImagesV2(content, composeContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -656,10 +674,7 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
|
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
|
||||||
stdout, _ := command.CombinedOutput()
|
_, _ = command.CombinedOutput()
|
||||||
if stdout != nil {
|
|
||||||
t.Logger.Printf("upgrade app [%s] [%s] cp file log : %s ", install.App.Key, install.Name, string(stdout))
|
|
||||||
}
|
|
||||||
sourceScripts := path.Join(detailDir, "scripts")
|
sourceScripts := path.Join(detailDir, "scripts")
|
||||||
if fileOp.Stat(sourceScripts) {
|
if fileOp.Stat(sourceScripts) {
|
||||||
dstScripts := path.Join(install.GetPath(), "scripts")
|
dstScripts := path.Join(install.GetPath(), "scripts")
|
||||||
@@ -968,14 +983,16 @@ func runScript(task *task.Task, appInstall *model.AppInstall, operate string) er
|
|||||||
case "uninstall":
|
case "uninstall":
|
||||||
scriptPath = path.Join(workDir, "scripts", "uninstall.sh")
|
scriptPath = path.Join(workDir, "scripts", "uninstall.sh")
|
||||||
}
|
}
|
||||||
if !files.NewFileOp().Stat(scriptPath) {
|
fileOp := files.NewFileOp()
|
||||||
|
if !fileOp.Stat(scriptPath) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
_ = fileOp.ChmodR(scriptPath, constant.DirPerm, false)
|
||||||
logStr := i18n.GetWithName("ExecShell", operate)
|
logStr := i18n.GetWithName("ExecShell", operate)
|
||||||
task.LogStart(logStr)
|
task.LogStart(logStr)
|
||||||
|
|
||||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute), cmd.WithScriptPath(scriptPath), cmd.WithWorkDir(workDir))
|
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute), cmd.WithWorkDir(workDir))
|
||||||
out, err := cmdMgr.RunWithStdout("bash")
|
out, err := cmdMgr.RunWithStdoutBashCf(scriptPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if out != "" {
|
if out != "" {
|
||||||
err = errors.New(out)
|
err = errors.New(out)
|
||||||
@@ -1020,12 +1037,11 @@ func upApp(task *task.Task, appInstall *model.AppInstall, pullImages bool) error
|
|||||||
errMsg string
|
errMsg string
|
||||||
)
|
)
|
||||||
if pullImages && appInstall.App.Type != "php" {
|
if pullImages && appInstall.App.Type != "php" {
|
||||||
projectName := strings.ToLower(appInstall.Name)
|
|
||||||
envByte, err := files.NewFileOp().GetContent(appInstall.GetEnvPath())
|
envByte, err := files.NewFileOp().GetContent(appInstall.GetEnvPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
images, err := composeV2.GetDockerComposeImages(projectName, envByte, []byte(appInstall.DockerCompose))
|
images, err := composeV2.GetImagesFromDockerCompose(envByte, []byte(appInstall.DockerCompose))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1050,8 +1066,8 @@ func upApp(task *task.Task, appInstall *model.AppInstall, pullImages bool) error
|
|||||||
if strings.Contains(errOur, "no such host") {
|
if strings.Contains(errOur, "no such host") {
|
||||||
errMsg = i18n.GetMsgByKey("ErrNoSuchHost") + ":"
|
errMsg = i18n.GetMsgByKey("ErrNoSuchHost") + ":"
|
||||||
}
|
}
|
||||||
if strings.Contains(errOur, "timeout") {
|
if strings.Contains(errOur, "Error response from daemon") {
|
||||||
errMsg = i18n.GetMsgByKey("ErrImagePullTimeOut") + ":"
|
errMsg = i18n.GetMsgByKey("PullImageTimeout") + ":"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appInstall.Message = errMsg + errOur
|
appInstall.Message = errMsg + errOur
|
||||||
@@ -1490,7 +1506,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lastVersion := versions[0]
|
lastVersion := versions[0]
|
||||||
if app.Key == constant.AppMysql {
|
if app.Key == constant.AppMysql || app.Key == constant.AppMysqlCluster {
|
||||||
for _, version := range versions {
|
for _, version := range versions {
|
||||||
majorVersion := getMajorVersion(installed.Version)
|
majorVersion := getMajorVersion(installed.Version)
|
||||||
if !strings.HasPrefix(version, majorVersion) {
|
if !strings.HasPrefix(version, majorVersion) {
|
||||||
@@ -1756,6 +1772,10 @@ func ignoreUpdate(installed model.AppInstall) bool {
|
|||||||
if installed.App.Type == "php" || installed.Status == constant.StatusInstalling {
|
if installed.App.Type == "php" || installed.Status == constant.StatusInstalling {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
ignores, _ := appIgnoreUpgradeRepo.List(appDetailRepo.WithAppId(installed.AppId), appIgnoreUpgradeRepo.WithScope("all"))
|
||||||
|
if len(ignores) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if installed.App.Key == constant.AppMysql {
|
if installed.App.Key == constant.AppMysql {
|
||||||
majorVersion := getMajorVersion(installed.Version)
|
majorVersion := getMajorVersion(installed.Version)
|
||||||
appDetails, _ := appDetailRepo.GetBy(appDetailRepo.WithAppId(installed.App.ID))
|
appDetails, _ := appDetailRepo.GetBy(appDetailRepo.WithAppId(installed.App.ID))
|
||||||
@@ -1766,8 +1786,7 @@ func ignoreUpdate(installed model.AppInstall) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
ignores, _ := appIgnoreUpgradeRepo.List(appDetailRepo.WithAppId(installed.AppId), appIgnoreUpgradeRepo.WithScope("all"))
|
return false
|
||||||
return len(ignores) > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RequestDownloadCallBack(downloadCallBackUrl string) {
|
func RequestDownloadCallBack(downloadCallBackUrl string) {
|
||||||
@@ -1792,24 +1811,15 @@ func getAppTags(appID uint, lang string) ([]response.TagDTO, error) {
|
|||||||
}
|
}
|
||||||
var res []response.TagDTO
|
var res []response.TagDTO
|
||||||
for _, t := range tags {
|
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{
|
tagDTO := response.TagDTO{
|
||||||
ID: t.ID,
|
ID: t.ID,
|
||||||
Key: t.Key,
|
Key: t.Key,
|
||||||
Name: t.Name,
|
Name: name,
|
||||||
}
|
}
|
||||||
res = append(res, tagDTO)
|
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
|
return res, nil
|
||||||
@@ -1900,3 +1910,59 @@ func handleSSLConfig(appInstall *model.AppInstall, hasDefaultWebsite bool) error
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SyncTags(remoteProperties dto.ExtraProperties) error {
|
||||||
|
tx, ctx := getTxAndContext()
|
||||||
|
defer tx.Rollback()
|
||||||
|
localTags, _ := tagRepo.All()
|
||||||
|
localTagsMap := make(map[string]*model.Tag)
|
||||||
|
for i := range localTags {
|
||||||
|
localTagsMap[localTags[i].Key] = &localTags[i]
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
remoteTagsMap := make(map[string]*dto.Tag)
|
||||||
|
for i := range remoteProperties.Tags {
|
||||||
|
remoteTagsMap[remoteProperties.Tags[i].Key] = &remoteProperties.Tags[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, localTag := range localTagsMap {
|
||||||
|
if _, exists := remoteTagsMap[key]; !exists {
|
||||||
|
_ = tagRepo.DeleteByID(ctx, localTag.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, remoteTag := range remoteProperties.Tags {
|
||||||
|
translations, _ := json.Marshal(remoteTag.Locales)
|
||||||
|
|
||||||
|
if existTag, exists := localTagsMap[remoteTag.Key]; exists {
|
||||||
|
if needsUpdate(existTag, remoteTag, string(translations)) {
|
||||||
|
existTag.Name = remoteTag.Name
|
||||||
|
existTag.Sort = remoteTag.Sort
|
||||||
|
existTag.Translations = string(translations)
|
||||||
|
|
||||||
|
if err = tagRepo.Save(ctx, existTag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newTag := &model.Tag{
|
||||||
|
Key: remoteTag.Key,
|
||||||
|
Name: remoteTag.Name,
|
||||||
|
Sort: remoteTag.Sort,
|
||||||
|
Translations: string(translations),
|
||||||
|
}
|
||||||
|
if err = tagRepo.Create(ctx, newTag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsUpdate(localTag *model.Tag, remoteTag dto.Tag, translations string) bool {
|
||||||
|
return localTag.Name != remoteTag.Name ||
|
||||||
|
localTag.Sort != remoteTag.Sort ||
|
||||||
|
localTag.Translations != translations
|
||||||
|
}
|
||||||
|
|||||||
@@ -541,11 +541,17 @@ func changeLocalBackup(oldPath, newPath string) error {
|
|||||||
return err
|
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, "app"))
|
||||||
_ = fileOp.RmRf(path.Join(oldPath, "database"))
|
_ = fileOp.RmRf(path.Join(oldPath, "database"))
|
||||||
_ = fileOp.RmRf(path.Join(oldPath, "directory"))
|
_ = fileOp.RmRf(path.Join(oldPath, "directory"))
|
||||||
_ = fileOp.RmRf(path.Join(oldPath, "system_snapshot"))
|
_ = fileOp.RmRf(path.Join(oldPath, "system_snapshot"))
|
||||||
_ = fileOp.RmRf(path.Join(oldPath, "website"))
|
_ = fileOp.RmRf(path.Join(oldPath, "website"))
|
||||||
_ = fileOp.RmRf(path.Join(oldPath, "log"))
|
_ = fileOp.RmRf(path.Join(oldPath, "log"))
|
||||||
|
_ = fileOp.RmRf(path.Join(oldPath, "master"))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, targetDir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
itemHandler := func() error { return doPostgresqlgBackup(db, targetDir, fileName) }
|
itemHandler := func() error { return doPostgresqlgBackup(db, targetDir, fileName) }
|
||||||
backupTask.AddSubTask(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeWebsite), func(task *task.Task) error { return itemHandler() }, nil)
|
backupTask.AddSubTask(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeDatabase), func(task *task.Task) error { return itemHandler() }, nil)
|
||||||
if parentTask != nil {
|
if parentTask != nil {
|
||||||
return itemHandler()
|
return itemHandler()
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
|
|||||||
}
|
}
|
||||||
itemTask = parentTask
|
itemTask = parentTask
|
||||||
if parentTask == nil {
|
if parentTask == nil {
|
||||||
itemTask, err = task.NewTaskWithOps("Redis", task.TaskRecover, task.TaskScopeDatabase, req.TaskID, dbInfo.ID)
|
itemTask, err = task.NewTaskWithOps(req.Name, task.TaskRecover, task.TaskScopeDatabase, req.TaskID, dbInfo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (u *BackupService) RedisBackup(req dto.CommonBackup) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ func (u *BackupService) RedisBackup(req dto.CommonBackup) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) RedisRecover(req dto.CommonRecover) 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 {
|
if err != nil {
|
||||||
return err
|
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 {
|
func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDir, fileName, secret, taskID string) error {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
itemTask *task.Task
|
itemTask *task.Task
|
||||||
@@ -102,7 +103,7 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(fileName, ".tar.gz") {
|
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 {
|
if err := fileOp.TarGzCompressPro(true, redisDataDir, path.Join(backupDir, fileName), secret, ""); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -111,14 +112,14 @@ func handleRedisBackup(redisInfo *repo.RootInfo, parentTask *task.Task, backupDi
|
|||||||
if strings.HasSuffix(fileName, ".aof") {
|
if strings.HasSuffix(fileName, ".aof") {
|
||||||
stdout1, err := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/appendonly.aof %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
stdout1, err := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/appendonly.aof %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(string(stdout1))
|
return errors.New(stdout1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout1, err1 := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/dump.rdb %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
stdout1, err1 := cmd.RunDefaultWithStdoutBashCf("docker cp %s:/data/dump.rdb %s/%s", redisInfo.ContainerName, backupDir, fileName)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return errors.New(string(stdout1))
|
return errors.New(stdout1)
|
||||||
}
|
}
|
||||||
return nil
|
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 {
|
if _, err := compose.Down(composeDir + "/docker-compose.yml"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "7.") {
|
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 {
|
if err := fileOp.TarGzExtractPro(recoverFile, redisDataDir, secret); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-21
@@ -3,6 +3,7 @@ package service
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/alert_push"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
@@ -158,9 +159,10 @@ func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interfa
|
|||||||
AlertType: "clams",
|
AlertType: "clams",
|
||||||
EntryID: datas[i].ID,
|
EntryID: datas[i].ID,
|
||||||
}
|
}
|
||||||
alertCount := xpack.GetAlert(alertBase)
|
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(alertBase.AlertType), alertRepo.WithByProject(strconv.Itoa(int(alertBase.EntryID))), repo.WithByStatus(constant.AlertEnable))
|
||||||
if alertCount != 0 {
|
datas[i].AlertMethod = alertInfo.Method
|
||||||
datas[i].AlertCount = alertCount
|
if alertInfo.SendCount != 0 {
|
||||||
|
datas[i].AlertCount = alertInfo.SendCount
|
||||||
} else {
|
} else {
|
||||||
datas[i].AlertCount = 0
|
datas[i].AlertCount = 0
|
||||||
}
|
}
|
||||||
@@ -191,13 +193,15 @@ func (c *ClamService) Create(req dto.ClamCreate) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if req.AlertCount != 0 {
|
if req.AlertCount != 0 {
|
||||||
createAlert := dto.CreateOrUpdateAlert{
|
createAlert := dto.AlertCreate{
|
||||||
AlertTitle: req.AlertTitle,
|
Title: req.AlertTitle,
|
||||||
AlertCount: req.AlertCount,
|
SendCount: req.AlertCount,
|
||||||
AlertType: "clams",
|
Method: req.AlertMethod,
|
||||||
EntryID: clam.ID,
|
Type: "clams",
|
||||||
|
Project: strconv.Itoa(int(clam.ID)),
|
||||||
|
Status: constant.AlertEnable,
|
||||||
}
|
}
|
||||||
err := xpack.CreateAlert(createAlert)
|
err := NewIAlertService().CreateAlert(createAlert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -247,13 +251,14 @@ func (c *ClamService) Update(req dto.ClamUpdate) error {
|
|||||||
if err := clamRepo.Update(req.ID, upMap); err != nil {
|
if err := clamRepo.Update(req.ID, upMap); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
updateAlert := dto.CreateOrUpdateAlert{
|
updateAlert := dto.AlertCreate{
|
||||||
AlertTitle: req.AlertTitle,
|
Title: req.AlertTitle,
|
||||||
AlertType: "clams",
|
SendCount: req.AlertCount,
|
||||||
AlertCount: req.AlertCount,
|
Method: req.AlertMethod,
|
||||||
EntryID: clam.ID,
|
Type: "clams",
|
||||||
|
Project: strconv.Itoa(int(clam.ID)),
|
||||||
}
|
}
|
||||||
err := xpack.UpdateAlert(updateAlert)
|
err := NewIAlertService().ExternalUpdateAlert(updateAlert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -297,11 +302,7 @@ func (c *ClamService) Delete(req dto.ClamDelete) error {
|
|||||||
if err := clamRepo.Delete(repo.WithByID(id)); err != nil {
|
if err := clamRepo.Delete(repo.WithByID(id)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
alertBase := dto.AlertBase{
|
err := alertRepo.Delete(alertRepo.WithByProject(strconv.Itoa(int(clam.ID))), alertRepo.WithByType("clams"))
|
||||||
AlertType: "clams",
|
|
||||||
EntryID: clam.ID,
|
|
||||||
}
|
|
||||||
err := xpack.DeleteAlert(alertBase)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -639,7 +640,7 @@ func handleAlert(stdout, clamName string, clamId uint) {
|
|||||||
EntryID: clamId,
|
EntryID: clamId,
|
||||||
Param: strconv.Itoa(infectedFiles),
|
Param: strconv.Itoa(infectedFiles),
|
||||||
}
|
}
|
||||||
_ = xpack.PushAlert(pushAlert)
|
_ = alert_push.PushAlert(pushAlert)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+209
-131
@@ -12,6 +12,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -52,7 +53,7 @@ type ContainerService struct{}
|
|||||||
|
|
||||||
type IContainerService interface {
|
type IContainerService interface {
|
||||||
Page(req dto.PageContainer) (int64, interface{}, error)
|
Page(req dto.PageContainer) (int64, interface{}, error)
|
||||||
List() []string
|
List() []dto.ContainerOptions
|
||||||
LoadStatus() (dto.ContainerStatus, error)
|
LoadStatus() (dto.ContainerStatus, error)
|
||||||
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
|
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
ListNetwork() ([]dto.Options, error)
|
ListNetwork() ([]dto.Options, error)
|
||||||
@@ -61,7 +62,7 @@ type IContainerService interface {
|
|||||||
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
CreateCompose(req dto.ComposeCreate) error
|
CreateCompose(req dto.ComposeCreate) error
|
||||||
ComposeOperation(req dto.ComposeOperation) error
|
ComposeOperation(req dto.ComposeOperation) error
|
||||||
ContainerCreate(req dto.ContainerOperate) error
|
ContainerCreate(req dto.ContainerOperate, inThread bool) error
|
||||||
ContainerCreateByCommand(req dto.ContainerCreateByCommand) error
|
ContainerCreateByCommand(req dto.ContainerCreateByCommand) error
|
||||||
ContainerUpdate(req dto.ContainerOperate) error
|
ContainerUpdate(req dto.ContainerOperate) error
|
||||||
ContainerUpgrade(req dto.ContainerUpgrade) error
|
ContainerUpgrade(req dto.ContainerUpgrade) error
|
||||||
@@ -81,9 +82,9 @@ type IContainerService interface {
|
|||||||
CreateVolume(req dto.VolumeCreate) error
|
CreateVolume(req dto.VolumeCreate) error
|
||||||
TestCompose(req dto.ComposeCreate) (bool, error)
|
TestCompose(req dto.ComposeCreate) (bool, error)
|
||||||
ComposeUpdate(req dto.ComposeUpdate) error
|
ComposeUpdate(req dto.ComposeUpdate) error
|
||||||
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
|
Prune(req dto.ContainerPrune) error
|
||||||
|
|
||||||
LoadUsers(req dto.OperationWithName) ([]string, error)
|
LoadUsers(req dto.OperationWithName) []string
|
||||||
|
|
||||||
StreamLogs(ctx *gin.Context, params dto.StreamLog)
|
StreamLogs(ctx *gin.Context, params dto.StreamLog)
|
||||||
}
|
}
|
||||||
@@ -221,7 +222,8 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
|||||||
return int64(total), backDatas, nil
|
return int64(total), backDatas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) List() []string {
|
func (u *ContainerService) List() []dto.ContainerOptions {
|
||||||
|
var options []dto.ContainerOptions
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("load docker client for contianer list failed, err: %v", err)
|
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()
|
defer client.Close()
|
||||||
containers, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
|
containers, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
var datas []string
|
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
for _, name := range container.Names {
|
for _, name := range container.Names {
|
||||||
if len(name) != 0 {
|
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) {
|
func (u *ContainerService) LoadStatus() (dto.ContainerStatus, error) {
|
||||||
@@ -416,66 +417,93 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
|||||||
return string(bytes), nil
|
return string(bytes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error) {
|
func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||||
report := dto.ContainerPruneReport{}
|
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return err
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
pruneFilters := filters.NewArgs()
|
name := ""
|
||||||
if req.WithTagAll {
|
|
||||||
pruneFilters.Add("dangling", "false")
|
|
||||||
if req.PruneType != "image" {
|
|
||||||
pruneFilters.Add("until", "24h")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch req.PruneType {
|
switch req.PruneType {
|
||||||
case "container":
|
case "container":
|
||||||
rep, err := client.ContainersPrune(context.Background(), pruneFilters)
|
name = "Container"
|
||||||
if err != nil {
|
|
||||||
return report, err
|
|
||||||
}
|
|
||||||
report.DeletedNumber = len(rep.ContainersDeleted)
|
|
||||||
report.SpaceReclaimed = int(rep.SpaceReclaimed)
|
|
||||||
case "image":
|
case "image":
|
||||||
rep, err := client.ImagesPrune(context.Background(), pruneFilters)
|
name = "Image"
|
||||||
if err != nil {
|
|
||||||
return report, err
|
|
||||||
}
|
|
||||||
report.DeletedNumber = len(rep.ImagesDeleted)
|
|
||||||
report.SpaceReclaimed = int(rep.SpaceReclaimed)
|
|
||||||
case "network":
|
|
||||||
rep, err := client.NetworksPrune(context.Background(), pruneFilters)
|
|
||||||
if err != nil {
|
|
||||||
return report, err
|
|
||||||
}
|
|
||||||
report.DeletedNumber = len(rep.NetworksDeleted)
|
|
||||||
case "volume":
|
case "volume":
|
||||||
versions, err := client.ServerVersion(context.Background())
|
name = "Volume"
|
||||||
if err != nil {
|
|
||||||
return report, err
|
|
||||||
}
|
|
||||||
if common.ComparePanelVersion(versions.APIVersion, "1.42") {
|
|
||||||
pruneFilters.Add("all", "true")
|
|
||||||
}
|
|
||||||
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
|
|
||||||
if err != nil {
|
|
||||||
return report, err
|
|
||||||
}
|
|
||||||
report.DeletedNumber = len(rep.VolumesDeleted)
|
|
||||||
report.SpaceReclaimed = int(rep.SpaceReclaimed)
|
|
||||||
case "buildcache":
|
case "buildcache":
|
||||||
opts := build.CachePruneOptions{}
|
name = "BuildCache"
|
||||||
opts.All = true
|
case "network":
|
||||||
rep, err := client.BuildCachePrune(context.Background(), opts)
|
name = "Network"
|
||||||
if err != nil {
|
|
||||||
return report, err
|
|
||||||
}
|
|
||||||
report.DeletedNumber = len(rep.CachesDeleted)
|
|
||||||
report.SpaceReclaimed = int(rep.SpaceReclaimed)
|
|
||||||
}
|
}
|
||||||
return report, nil
|
taskItem, err := task.NewTaskWithOps(i18n.GetMsgByKey(name), task.TaskClean, task.TaskScopeContainer, req.TaskID, 1)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("new task for create container failed, err: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
taskItem.AddSubTask(i18n.GetMsgByKey("TaskClean"), func(t *task.Task) error {
|
||||||
|
pruneFilters := filters.NewArgs()
|
||||||
|
if req.WithTagAll {
|
||||||
|
pruneFilters.Add("dangling", "false")
|
||||||
|
if req.PruneType != "image" {
|
||||||
|
pruneFilters.Add("until", "24h")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeletedNumber := 0
|
||||||
|
SpaceReclaimed := 0
|
||||||
|
switch req.PruneType {
|
||||||
|
case "container":
|
||||||
|
rep, err := client.ContainersPrune(context.Background(), pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DeletedNumber = len(rep.ContainersDeleted)
|
||||||
|
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||||
|
case "image":
|
||||||
|
rep, err := client.ImagesPrune(context.Background(), pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DeletedNumber = len(rep.ImagesDeleted)
|
||||||
|
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||||
|
case "network":
|
||||||
|
rep, err := client.NetworksPrune(context.Background(), pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DeletedNumber = len(rep.NetworksDeleted)
|
||||||
|
case "volume":
|
||||||
|
versions, err := client.ServerVersion(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if common.ComparePanelVersion(versions.APIVersion, "1.42") {
|
||||||
|
pruneFilters.Add("all", "true")
|
||||||
|
}
|
||||||
|
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DeletedNumber = len(rep.VolumesDeleted)
|
||||||
|
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||||
|
case "buildcache":
|
||||||
|
opts := build.CachePruneOptions{}
|
||||||
|
opts.All = true
|
||||||
|
rep, err := client.BuildCachePrune(context.Background(), opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DeletedNumber = len(rep.CachesDeleted)
|
||||||
|
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||||
|
}
|
||||||
|
taskItem.Log(i18n.GetMsgWithMap("PruneHelper", map[string]interface{}{"name": i18n.GetMsgByKey(name), "count": DeletedNumber, "size": common.LoadSizeUnit2F(float64(SpaceReclaimed))}))
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
go func() {
|
||||||
|
_ = taskItem.Execute()
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) LoadResourceLimit() (*dto.ResourceLimit, error) {
|
func (u *ContainerService) LoadResourceLimit() (*dto.ResourceLimit, error) {
|
||||||
@@ -495,7 +523,7 @@ func (u *ContainerService) LoadResourceLimit() (*dto.ResourceLimit, error) {
|
|||||||
return &data, nil
|
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()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -513,63 +541,62 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
taskItem.AddSubTask(i18n.GetWithName("ContainerImagePull", req.Image), func(t *task.Task) error {
|
||||||
wg.Add(1)
|
if !checkImageExist(client, req.Image) || req.ForcePull {
|
||||||
go func() {
|
if err := pullImages(taskItem, client, req.Image); err != nil {
|
||||||
defer wg.Done()
|
if !req.ForcePull {
|
||||||
taskItem.AddSubTask(i18n.GetWithName("ContainerImagePull", req.Image), func(t *task.Task) error {
|
return err
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
}()
|
return nil
|
||||||
wg.Wait()
|
}, nil)
|
||||||
return 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) {
|
func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.ContainerOperate, error) {
|
||||||
@@ -676,7 +703,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
|||||||
|
|
||||||
taskItem.AddSubTask(i18n.GetWithName("ContainerCreate", req.Name), func(t *task.Task) error {
|
taskItem.AddSubTask(i18n.GetWithName("ContainerCreate", req.Name), func(t *task.Task) error {
|
||||||
err := client.ContainerRemove(ctx, req.ContainerID, container.RemoveOptions{Force: true})
|
err := client.ContainerRemove(ctx, req.ContainerID, container.RemoveOptions{Force: true})
|
||||||
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerRemoveOld"), err)
|
taskItem.LogWithStatus(i18n.GetWithName("ContainerRemoveOld", req.Name), err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -752,7 +779,7 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := client.ContainerRemove(ctx, req.Name, container.RemoveOptions{Force: true})
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -809,10 +836,23 @@ func (u *ContainerService) ContainerCommit(req dto.ContainerCommit) error {
|
|||||||
Pause: req.Pause,
|
Pause: req.Pause,
|
||||||
Config: nil,
|
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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,9 +1054,15 @@ func (u *ContainerService) DownloadContainerLogs(containerType, container, since
|
|||||||
return buserr.New("ErrCmdIllegal")
|
return buserr.New("ErrCmdIllegal")
|
||||||
}
|
}
|
||||||
commandArg := []string{"logs", container}
|
commandArg := []string{"logs", container}
|
||||||
|
dockerCommand := global.CONF.DockerConfig.Command
|
||||||
if containerType == "compose" {
|
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" {
|
if tail != "0" {
|
||||||
commandArg = append(commandArg, "--tail")
|
commandArg = append(commandArg, "--tail")
|
||||||
commandArg = append(commandArg, tail)
|
commandArg = append(commandArg, tail)
|
||||||
@@ -1025,16 +1071,20 @@ func (u *ContainerService) DownloadContainerLogs(containerType, container, since
|
|||||||
commandArg = append(commandArg, "--since")
|
commandArg = append(commandArg, "--since")
|
||||||
commandArg = append(commandArg, since)
|
commandArg = append(commandArg, since)
|
||||||
}
|
}
|
||||||
|
var dockerCmd *exec.Cmd
|
||||||
cmd := exec.Command("docker", commandArg...)
|
if containerType == "compose" && dockerCommand == "docker-compose" {
|
||||||
stdout, err := cmd.StdoutPipe()
|
dockerCmd = exec.Command("docker-compose", commandArg...)
|
||||||
|
} else {
|
||||||
|
dockerCmd = exec.Command("docker", commandArg...)
|
||||||
|
}
|
||||||
|
stdout, err := dockerCmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
_ = dockerCmd.Process.Signal(syscall.SIGTERM)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cmd.Stderr = cmd.Stdout
|
dockerCmd.Stderr = dockerCmd.Stdout
|
||||||
if err := cmd.Start(); err != nil {
|
if err := dockerCmd.Start(); err != nil {
|
||||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
_ = dockerCmd.Process.Signal(syscall.SIGTERM)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1051,9 +1101,11 @@ func (u *ContainerService) DownloadContainerLogs(containerType, container, since
|
|||||||
errCh := make(chan error)
|
errCh := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
scanner := bufio.NewScanner(stdout)
|
scanner := bufio.NewScanner(stdout)
|
||||||
|
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;?]*[A-Za-z]|\x1b=|\x1b>`)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
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
|
errCh <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1114,19 +1166,19 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
|
|||||||
return &data, nil
|
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)
|
std, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s cat /etc/passwd", req.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return users
|
||||||
}
|
}
|
||||||
var users []string
|
|
||||||
lines := strings.Split(string(std), "\n")
|
lines := strings.Split(string(std), "\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if strings.Contains(line, ":") {
|
if strings.Contains(line, ":") {
|
||||||
users = append(users, strings.Split(line, ":")[0])
|
users = append(users, strings.Split(line, ":")[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return users, nil
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringsToMap(list []string) map[string]string {
|
func stringsToMap(list []string) map[string]string {
|
||||||
@@ -1215,6 +1267,32 @@ func checkImageExist(client *client.Client, imageItem string) bool {
|
|||||||
return false
|
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 {
|
func pullImages(task *task.Task, client *client.Client, imageName string) error {
|
||||||
dockerCli := docker.NewClientWithExist(client)
|
dockerCli := docker.NewClientWithExist(client)
|
||||||
options := image.PullOptions{}
|
options := image.PullOptions{}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -174,7 +173,7 @@ func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
|
|||||||
if err := newComposeEnv(req.Path, req.Env); err != nil {
|
if err := newComposeEnv(req.Path, req.Env); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
cmd := exec.Command("docker", "compose", "-f", req.Path, "config")
|
cmd := getComposeCmd(req.Path, "config")
|
||||||
stdout, err := cmd.CombinedOutput()
|
stdout, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.New(string(stdout))
|
return false, errors.New(string(stdout))
|
||||||
@@ -201,7 +200,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
|
|||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
taskItem.AddSubTask(i18n.GetMsgByKey("ComposeCreate"), func(t *task.Task) error {
|
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()
|
out, err := cmd.CombinedOutput()
|
||||||
taskItem.Log(i18n.GetWithName("ComposeCreateRes", string(out)))
|
taskItem.Log(i18n.GetWithName("ComposeCreateRes", string(out)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+334
-28
@@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@@ -9,14 +10,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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/dto"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"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/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
@@ -32,11 +32,14 @@ type ICronjobService interface {
|
|||||||
HandleOnce(id uint) error
|
HandleOnce(id uint) error
|
||||||
Update(id uint, req dto.CronjobOperate) error
|
Update(id uint, req dto.CronjobOperate) error
|
||||||
UpdateStatus(id uint, status string) error
|
UpdateStatus(id uint, status string) error
|
||||||
|
UpdateGroup(req dto.ChangeGroup) error
|
||||||
Delete(req dto.CronjobBatchDelete) error
|
Delete(req dto.CronjobBatchDelete) error
|
||||||
Download(down dto.CronjobDownload) (string, error)
|
Download(down dto.CronjobDownload) (string, error)
|
||||||
StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error)
|
StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error)
|
||||||
CleanRecord(req dto.CronjobClean) error
|
CleanRecord(req dto.CronjobClean) error
|
||||||
|
|
||||||
|
Export(req dto.OperateByIDs) (string, error)
|
||||||
|
Import(req []dto.CronjobTrans) error
|
||||||
LoadScriptOptions() []dto.ScriptOptions
|
LoadScriptOptions() []dto.ScriptOptions
|
||||||
|
|
||||||
LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, error)
|
LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, error)
|
||||||
@@ -48,7 +51,11 @@ func NewICronjobService() ICronjobService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interface{}, error) {
|
func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interface{}, error) {
|
||||||
total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, repo.WithByLikeName(search.Info), repo.WithOrderRuleBy(search.OrderBy, search.Order))
|
total, cronjobs, err := cronjobRepo.Page(search.Page,
|
||||||
|
search.PageSize,
|
||||||
|
repo.WithByGroups(search.GroupIDs),
|
||||||
|
repo.WithByLikeName(search.Info),
|
||||||
|
repo.WithOrderRuleBy(search.OrderBy, search.Order))
|
||||||
var dtoCronjobs []dto.CronjobInfo
|
var dtoCronjobs []dto.CronjobInfo
|
||||||
for _, cronjob := range cronjobs {
|
for _, cronjob := range cronjobs {
|
||||||
var item dto.CronjobInfo
|
var item dto.CronjobInfo
|
||||||
@@ -67,9 +74,9 @@ func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interfac
|
|||||||
AlertType: cronjob.Type,
|
AlertType: cronjob.Type,
|
||||||
EntryID: cronjob.ID,
|
EntryID: cronjob.ID,
|
||||||
}
|
}
|
||||||
alertCount := xpack.GetAlert(alertBase)
|
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(alertBase.AlertType), alertRepo.WithByProject(strconv.Itoa(int(alertBase.EntryID))), repo.WithByStatus(constant.AlertEnable))
|
||||||
if alertCount != 0 {
|
if alertInfo.SendCount != 0 {
|
||||||
item.AlertCount = alertCount
|
item.AlertCount = alertInfo.SendCount
|
||||||
} else {
|
} else {
|
||||||
item.AlertCount = 0
|
item.AlertCount = 0
|
||||||
}
|
}
|
||||||
@@ -91,9 +98,10 @@ func (u *CronjobService) LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, err
|
|||||||
AlertType: cronjob.Type,
|
AlertType: cronjob.Type,
|
||||||
EntryID: cronjob.ID,
|
EntryID: cronjob.ID,
|
||||||
}
|
}
|
||||||
alertCount := xpack.GetAlert(alertBase)
|
alertInfo, _ := alertRepo.Get(alertRepo.WithByType(alertBase.AlertType), alertRepo.WithByProject(strconv.Itoa(int(alertBase.EntryID))), repo.WithByStatus(constant.AlertEnable))
|
||||||
if alertCount != 0 {
|
item.AlertMethod = alertInfo.Method
|
||||||
item.AlertCount = alertCount
|
if alertInfo.SendCount != 0 {
|
||||||
|
item.AlertCount = alertInfo.SendCount
|
||||||
} else {
|
} else {
|
||||||
item.AlertCount = 0
|
item.AlertCount = 0
|
||||||
}
|
}
|
||||||
@@ -103,6 +111,292 @@ func (u *CronjobService) LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, err
|
|||||||
return &item, err
|
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,
|
||||||
|
GroupID: cronjob.GroupID,
|
||||||
|
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,
|
||||||
|
GroupID: item.GroupID,
|
||||||
|
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 {
|
func (u *CronjobService) LoadScriptOptions() []dto.ScriptOptions {
|
||||||
scripts, err := scriptRepo.List()
|
scripts, err := scriptRepo.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -313,13 +607,15 @@ func (u *CronjobService) Create(req dto.CronjobOperate) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if req.AlertCount != 0 {
|
if req.AlertCount != 0 {
|
||||||
createAlert := dto.CreateOrUpdateAlert{
|
createAlert := dto.AlertCreate{
|
||||||
AlertTitle: req.AlertTitle,
|
Title: req.AlertTitle,
|
||||||
AlertCount: req.AlertCount,
|
SendCount: req.AlertCount,
|
||||||
AlertType: cronjob.Type,
|
Method: req.AlertMethod,
|
||||||
EntryID: cronjob.ID,
|
Type: cronjob.Type,
|
||||||
|
Project: strconv.Itoa(int(cronjob.ID)),
|
||||||
|
Status: constant.AlertEnable,
|
||||||
}
|
}
|
||||||
err := xpack.CreateAlert(createAlert)
|
err := NewIAlertService().CreateAlert(createAlert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -367,11 +663,7 @@ func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
|||||||
if err := cronjobRepo.Delete(repo.WithByID(id)); err != nil {
|
if err := cronjobRepo.Delete(repo.WithByID(id)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
alertBase := dto.AlertBase{
|
err := alertRepo.Delete(alertRepo.WithByProject(strconv.Itoa(int(cronjob.ID))), alertRepo.WithByType(cronjob.Type))
|
||||||
AlertType: cronjob.Type,
|
|
||||||
EntryID: cronjob.ID,
|
|
||||||
}
|
|
||||||
err := xpack.DeleteAlert(alertBase)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -414,7 +706,11 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cronModel.Status == constant.StatusPending {
|
||||||
|
upMap["status"] = constant.StatusEnable
|
||||||
|
}
|
||||||
upMap["name"] = req.Name
|
upMap["name"] = req.Name
|
||||||
|
upMap["group_id"] = req.GroupID
|
||||||
upMap["spec_custom"] = req.SpecCustom
|
upMap["spec_custom"] = req.SpecCustom
|
||||||
upMap["spec"] = spec
|
upMap["spec"] = spec
|
||||||
upMap["script"] = req.Script
|
upMap["script"] = req.Script
|
||||||
@@ -431,6 +727,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
|||||||
upMap["db_type"] = req.DBType
|
upMap["db_type"] = req.DBType
|
||||||
upMap["db_name"] = req.DBName
|
upMap["db_name"] = req.DBName
|
||||||
upMap["url"] = req.URL
|
upMap["url"] = req.URL
|
||||||
|
upMap["is_dir"] = req.IsDir
|
||||||
upMap["source_dir"] = req.SourceDir
|
upMap["source_dir"] = req.SourceDir
|
||||||
upMap["snapshot_rule"] = cronjob.SnapshotRule
|
upMap["snapshot_rule"] = cronjob.SnapshotRule
|
||||||
|
|
||||||
@@ -445,13 +742,14 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
updateAlert := dto.CreateOrUpdateAlert{
|
updateAlert := dto.AlertCreate{
|
||||||
AlertTitle: req.AlertTitle,
|
Title: req.AlertTitle,
|
||||||
AlertType: cronModel.Type,
|
SendCount: req.AlertCount,
|
||||||
AlertCount: req.AlertCount,
|
Method: req.AlertMethod,
|
||||||
EntryID: cronModel.ID,
|
Type: cronjob.Type,
|
||||||
|
Project: strconv.Itoa(int(cronModel.ID)),
|
||||||
}
|
}
|
||||||
err = xpack.UpdateAlert(updateAlert)
|
err = NewIAlertService().ExternalUpdateAlert(updateAlert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -484,6 +782,14 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
|
|||||||
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status, "entry_ids": entryIDs})
|
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status, "entry_ids": entryIDs})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) UpdateGroup(req dto.ChangeGroup) error {
|
||||||
|
cronjob, _ := cronjobRepo.Get(repo.WithByID(req.ID))
|
||||||
|
if cronjob.ID == 0 {
|
||||||
|
return buserr.New("ErrRecordNotFound")
|
||||||
|
}
|
||||||
|
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"group_id": req.GroupID})
|
||||||
|
}
|
||||||
|
|
||||||
func (u *CronjobService) AddCronJob(cronjob *model.Cronjob) (int, error) {
|
func (u *CronjobService) AddCronJob(cronjob *model.Cronjob) (int, error) {
|
||||||
addFunc := func() {
|
addFunc := func() {
|
||||||
u.HandleJob(cronjob)
|
u.HandleJob(cronjob)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -24,22 +25,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, taskItem *task.Task) error {
|
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, taskItem *task.Task) error {
|
||||||
var apps []model.AppInstall
|
apps := loadAppsForJob(cronjob)
|
||||||
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
|
|
||||||
}
|
|
||||||
if len(apps) == 0 {
|
if len(apps) == 0 {
|
||||||
return errors.New("no such app in database!")
|
return errors.New("no such app in database!")
|
||||||
}
|
}
|
||||||
@@ -57,7 +43,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t
|
|||||||
record.Name = app.App.Key
|
record.Name = app.App.Key
|
||||||
record.DetailName = app.Name
|
record.DetailName = app.Name
|
||||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
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))
|
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 {
|
if err := doAppBackup(&app, task, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||||
@@ -108,7 +94,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
|||||||
record.Name = web.Alias
|
record.Name = web.Alias
|
||||||
record.DetailName = web.Alias
|
record.DetailName = web.Alias
|
||||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
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))
|
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 {
|
if err := doWebsiteBackup(&web, taskItem, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret); err != nil {
|
||||||
@@ -163,9 +149,9 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
|
|||||||
record.DetailName = dbInfo.Name
|
record.DetailName = dbInfo.Name
|
||||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
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))
|
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 {
|
if err := doMysqlBackup(dbInfo, backupDir, record.FileName); err != nil {
|
||||||
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
|
||||||
retry++
|
retry++
|
||||||
@@ -214,8 +200,11 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fileName := fmt.Sprintf("%s.tar.gz", startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
fileName := fmt.Sprintf("%s.tar.gz", startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(2))
|
||||||
backupDir := path.Join(global.Dir.TmpDir, fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name))
|
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()
|
fileOp := files.NewFileOp()
|
||||||
if cronjob.IsDir {
|
if cronjob.IsDir {
|
||||||
@@ -261,7 +250,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
|
|||||||
}
|
}
|
||||||
nameItem := startTime.Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
|
nameItem := startTime.Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
|
||||||
fileName := fmt.Sprintf("system_log_%s.tar.gz", nameItem)
|
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 {
|
if err := handleBackupLogs(taskItem, backupDir, fileName, cronjob.Secret); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -344,6 +333,23 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, jobRecord model.J
|
|||||||
return nil
|
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 {
|
type DatabaseHelper struct {
|
||||||
ID uint
|
ID uint
|
||||||
DBType string
|
DBType string
|
||||||
@@ -354,7 +360,7 @@ type DatabaseHelper struct {
|
|||||||
func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||||
var dbs []DatabaseHelper
|
var dbs []DatabaseHelper
|
||||||
if cronjob.DBName == "all" {
|
if cronjob.DBName == "all" {
|
||||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" || cronjob.DBType == "mysql-cluster" {
|
||||||
databaseService := NewIDatabaseService()
|
databaseService := NewIDatabaseService()
|
||||||
mysqlItems, _ := databaseService.LoadItems(cronjob.DBType)
|
mysqlItems, _ := databaseService.LoadItems(cronjob.DBType)
|
||||||
for _, mysql := range mysqlItems {
|
for _, mysql := range mysqlItems {
|
||||||
@@ -381,7 +387,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
|||||||
dbNames := strings.Split(cronjob.DBName, ",")
|
dbNames := strings.Split(cronjob.DBName, ",")
|
||||||
for _, name := range dbNames {
|
for _, name := range dbNames {
|
||||||
itemID, _ := strconv.Atoi(name)
|
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)))
|
mysqlItem, _ := mysqlRepo.Get(repo.WithByID(uint(itemID)))
|
||||||
dbs = append(dbs, DatabaseHelper{
|
dbs = append(dbs, DatabaseHelper{
|
||||||
ID: mysqlItem.ID,
|
ID: mysqlItem.ID,
|
||||||
@@ -443,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)
|
logFiles2, _ := os.ReadDir(itemDir2)
|
||||||
if len(logFiles2) != 0 {
|
if len(logFiles2) != 0 {
|
||||||
for i := 0; i < len(logFiles2); i++ {
|
for i := 0; i < len(logFiles2); i++ {
|
||||||
@@ -546,3 +552,14 @@ func loadSnapWithRule(cronjob model.Cronjob) (dto.SnapshotData, error) {
|
|||||||
}
|
}
|
||||||
return itemData, nil
|
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"
|
"strings"
|
||||||
"time"
|
"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/dto"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
"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/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/ntp"
|
"github.com/1Panel-dev/1Panel/agent/utils/ntp"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
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)
|
global.LOG.Debugf("preper to handle cron job [%s] %s failed, err: %v", cronjob.Type, cronjob.Name, err)
|
||||||
record.TaskID = ""
|
record.TaskID = ""
|
||||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), record.Records)
|
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), record.Records)
|
||||||
|
handleCronJobAlert(cronjob)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := taskItem.Execute(); err != nil {
|
if err := taskItem.Execute(); err != nil {
|
||||||
@@ -268,7 +270,7 @@ func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, task *task
|
|||||||
}()
|
}()
|
||||||
var errItem error
|
var errItem error
|
||||||
accounts := strings.Split(cronjob.SourceAccountIDs, ",")
|
accounts := strings.Split(cronjob.SourceAccountIDs, ",")
|
||||||
cloudSrc := strings.TrimPrefix(file, global.Dir.TmpDir+"/")
|
cloudSrc := strings.TrimPrefix(file, global.Dir.LocalBackupDir+"/tmp/")
|
||||||
for _, account := range accounts {
|
for _, account := range accounts {
|
||||||
if len(account) != 0 {
|
if len(account) != 0 {
|
||||||
task.LogStart(i18n.GetMsgWithMap("UploadFile", map[string]interface{}{
|
task.LogStart(i18n.GetMsgWithMap("UploadFile", map[string]interface{}{
|
||||||
@@ -359,5 +361,5 @@ func handleCronJobAlert(cronjob *model.Cronjob) {
|
|||||||
EntryID: cronjob.ID,
|
EntryID: cronjob.ID,
|
||||||
Param: cronjob.Type,
|
Param: cronjob.Type,
|
||||||
}
|
}
|
||||||
_ = xpack.PushAlert(pushAlert)
|
_ = alert_push.PushAlert(pushAlert)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func (u *DashboardService) LoadCurrentInfoForNode() *dto.NodeCurrent {
|
|||||||
memoryInfo, _ := mem.VirtualMemory()
|
memoryInfo, _ := mem.VirtualMemory()
|
||||||
currentInfo.MemoryTotal = memoryInfo.Total
|
currentInfo.MemoryTotal = memoryInfo.Total
|
||||||
currentInfo.MemoryAvailable = memoryInfo.Available
|
currentInfo.MemoryAvailable = memoryInfo.Available
|
||||||
currentInfo.MemoryUsed = memoryInfo.Used
|
currentInfo.MemoryUsed = memoryInfo.Used + memoryInfo.Shared
|
||||||
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
||||||
|
|
||||||
swapInfo, _ := mem.SwapMemory()
|
swapInfo, _ := mem.SwapMemory()
|
||||||
@@ -210,8 +210,11 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
|||||||
|
|
||||||
memoryInfo, _ := mem.VirtualMemory()
|
memoryInfo, _ := mem.VirtualMemory()
|
||||||
currentInfo.MemoryTotal = memoryInfo.Total
|
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.MemoryAvailable = memoryInfo.Available
|
||||||
currentInfo.MemoryUsed = memoryInfo.Used
|
|
||||||
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
|
||||||
|
|
||||||
swapInfo, _ := mem.SwapMemory()
|
swapInfo, _ := mem.SwapMemory()
|
||||||
|
|||||||
@@ -6,19 +6,17 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/postgresql"
|
|
||||||
pgclient "github.com/1Panel-dev/1Panel/agent/utils/postgresql/client"
|
|
||||||
redisclient "github.com/1Panel-dev/1Panel/agent/utils/redis"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/mysql"
|
"github.com/1Panel-dev/1Panel/agent/utils/mysql"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/mysql/client"
|
"github.com/1Panel-dev/1Panel/agent/utils/mysql/client"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/postgresql"
|
||||||
|
pgclient "github.com/1Panel-dev/1Panel/agent/utils/postgresql/client"
|
||||||
|
redisclient "github.com/1Panel-dev/1Panel/agent/utils/redis"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -92,7 +90,7 @@ func (u *DatabaseService) LoadItems(dbType string) ([]dto.DatabaseItem, error) {
|
|||||||
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
|
dbs, err := databaseRepo.GetList(databaseRepo.WithTypeList(dbType))
|
||||||
var datas []dto.DatabaseItem
|
var datas []dto.DatabaseItem
|
||||||
for _, db := range dbs {
|
for _, db := range dbs {
|
||||||
if dbType == "postgresql" {
|
if dbType == constant.AppPostgresql || dbType == constant.AppPostgresqlCluster {
|
||||||
items, _ := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(db.Name))
|
items, _ := postgresqlRepo.List(postgresqlRepo.WithByPostgresqlName(db.Name))
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
var dItem dto.DatabaseItem
|
var dItem dto.DatabaseItem
|
||||||
@@ -118,6 +116,9 @@ func (u *DatabaseService) LoadItems(dbType string) ([]dto.DatabaseItem, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
||||||
|
if req.Timeout == 0 {
|
||||||
|
req.Timeout = 30
|
||||||
|
}
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case constant.AppPostgresql:
|
case constant.AppPostgresql:
|
||||||
_, err := postgresql.NewPostgresqlClient(pgclient.DBInfo{
|
_, err := postgresql.NewPostgresqlClient(pgclient.DBInfo{
|
||||||
@@ -126,7 +127,7 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
|||||||
Port: req.Port,
|
Port: req.Port,
|
||||||
Username: req.Username,
|
Username: req.Username,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
Timeout: 6,
|
Timeout: req.Timeout,
|
||||||
})
|
})
|
||||||
return err == nil
|
return err == nil
|
||||||
case constant.AppRedis:
|
case constant.AppRedis:
|
||||||
@@ -134,6 +135,7 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
|||||||
Address: req.Address,
|
Address: req.Address,
|
||||||
Port: req.Port,
|
Port: req.Port,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
|
Timeout: req.Timeout,
|
||||||
})
|
})
|
||||||
return err == nil
|
return err == nil
|
||||||
case "mysql", "mariadb":
|
case "mysql", "mariadb":
|
||||||
@@ -149,7 +151,7 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
|||||||
ClientKey: req.ClientKey,
|
ClientKey: req.ClientKey,
|
||||||
ClientCert: req.ClientCert,
|
ClientCert: req.ClientCert,
|
||||||
SkipVerify: req.SkipVerify,
|
SkipVerify: req.SkipVerify,
|
||||||
Timeout: 6,
|
Timeout: req.Timeout,
|
||||||
})
|
})
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
@@ -158,6 +160,9 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
||||||
|
if req.Timeout == 0 {
|
||||||
|
req.Timeout = 30
|
||||||
|
}
|
||||||
db, _ := databaseRepo.Get(repo.WithByName(req.Name))
|
db, _ := databaseRepo.Get(repo.WithByName(req.Name))
|
||||||
if db.ID != 0 {
|
if db.ID != 0 {
|
||||||
if db.From == "local" {
|
if db.From == "local" {
|
||||||
@@ -173,7 +178,7 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
|||||||
Port: req.Port,
|
Port: req.Port,
|
||||||
Username: req.Username,
|
Username: req.Username,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
Timeout: 6,
|
Timeout: req.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -182,6 +187,7 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
|||||||
Address: req.Address,
|
Address: req.Address,
|
||||||
Port: req.Port,
|
Port: req.Port,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
|
Timeout: req.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -198,7 +204,7 @@ func (u *DatabaseService) Create(req dto.DatabaseCreate) error {
|
|||||||
ClientKey: req.ClientKey,
|
ClientKey: req.ClientKey,
|
||||||
ClientCert: req.ClientCert,
|
ClientCert: req.ClientCert,
|
||||||
SkipVerify: req.SkipVerify,
|
SkipVerify: req.SkipVerify,
|
||||||
Timeout: 6,
|
Timeout: req.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -273,7 +279,7 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
|||||||
Port: req.Port,
|
Port: req.Port,
|
||||||
Username: req.Username,
|
Username: req.Username,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
Timeout: 300,
|
Timeout: req.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -282,6 +288,7 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
|||||||
Address: req.Address,
|
Address: req.Address,
|
||||||
Port: req.Port,
|
Port: req.Port,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
|
Timeout: req.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -298,7 +305,7 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
|||||||
ClientKey: req.ClientKey,
|
ClientKey: req.ClientKey,
|
||||||
ClientCert: req.ClientCert,
|
ClientCert: req.ClientCert,
|
||||||
SkipVerify: req.SkipVerify,
|
SkipVerify: req.SkipVerify,
|
||||||
Timeout: 300,
|
Timeout: req.Timeout,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -318,6 +325,7 @@ func (u *DatabaseService) Update(req dto.DatabaseUpdate) error {
|
|||||||
upMap["port"] = req.Port
|
upMap["port"] = req.Port
|
||||||
upMap["username"] = req.Username
|
upMap["username"] = req.Username
|
||||||
upMap["password"] = pass
|
upMap["password"] = pass
|
||||||
|
upMap["timeout"] = req.Timeout
|
||||||
upMap["description"] = req.Description
|
upMap["description"] = req.Description
|
||||||
upMap["ssl"] = req.SSL
|
upMap["ssl"] = req.SSL
|
||||||
upMap["client_key"] = req.ClientKey
|
upMap["client_key"] = req.ClientKey
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (u *DBCommonService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.D
|
|||||||
}
|
}
|
||||||
data.ContainerName = app.ContainerName
|
data.ContainerName = app.ContainerName
|
||||||
data.Name = app.Name
|
data.Name = app.Name
|
||||||
data.Port = int64(app.Port)
|
data.Port = app.Port
|
||||||
|
|
||||||
return &data, nil
|
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) {
|
func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
|
||||||
filePath := ""
|
filePath := ""
|
||||||
switch req.Type {
|
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":
|
case "mysql-conf":
|
||||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
|
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
|
||||||
case "mariadb-conf":
|
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))
|
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
|
||||||
case "redis-conf":
|
case "redis-conf":
|
||||||
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
|
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 {
|
if _, err := os.Stat(filePath); err != nil {
|
||||||
return "", buserr.New("ErrHttpReqNotFound")
|
return "", buserr.New("ErrHttpReqNotFound")
|
||||||
@@ -68,11 +74,11 @@ func (u *DBCommonService) UpdateConfByFile(req dto.DBConfUpdateByFile) error {
|
|||||||
}
|
}
|
||||||
path := ""
|
path := ""
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case constant.AppMariaDB, constant.AppMysql:
|
case constant.AppMariaDB, constant.AppMysql, constant.AppMysqlCluster:
|
||||||
path = fmt.Sprintf("%s/%s/%s/conf/my.cnf", global.Dir.AppInstallDir, req.Type, app.Name)
|
path = fmt.Sprintf("%s/%s/%s/conf/my.cnf", global.Dir.AppInstallDir, req.Type, app.Name)
|
||||||
case constant.AppPostgresql:
|
case constant.AppPostgresql, constant.AppPostgresqlCluster:
|
||||||
path = fmt.Sprintf("%s/%s/%s/data/postgresql.conf", global.Dir.AppInstallDir, req.Type, app.Name)
|
path = fmt.Sprintf("%s/%s/%s/data/postgresql.conf", global.Dir.AppInstallDir, req.Type, app.Name)
|
||||||
case constant.AppRedis:
|
case constant.AppRedis, constant.AppRedisCluster:
|
||||||
path = fmt.Sprintf("%s/%s/%s/conf/redis.conf", global.Dir.AppInstallDir, req.Type, app.Name)
|
path = fmt.Sprintf("%s/%s/%s/conf/redis.conf", global.Dir.AppInstallDir, req.Type, app.Name)
|
||||||
}
|
}
|
||||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||||
|
|||||||
@@ -534,7 +534,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
|||||||
info.File = "OFF"
|
info.File = "OFF"
|
||||||
info.Position = "OFF"
|
info.Position = "OFF"
|
||||||
masterStatus := "show master status;"
|
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;"
|
masterStatus = "show binary log status;"
|
||||||
}
|
}
|
||||||
rows, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, masterStatus)
|
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) {
|
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)
|
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||||
stdout, err := cmd.CombinedOutput()
|
stdout, err := cmd.CombinedOutput()
|
||||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
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 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) {
|
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)
|
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||||
stdout, err := cmd.CombinedOutput()
|
stdout, err := cmd.CombinedOutput()
|
||||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
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 nil, errors.New(stdStr)
|
||||||
}
|
}
|
||||||
return strings.Split(stdStr, "\n"), nil
|
return strings.Split(stdStr, "\n"), nil
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ type IRedisService interface {
|
|||||||
UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error
|
UpdatePersistenceConf(req dto.RedisConfPersistenceUpdate) error
|
||||||
ChangePassword(info dto.ChangeRedisPass) error
|
ChangePassword(info dto.ChangeRedisPass) error
|
||||||
|
|
||||||
LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error)
|
LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, error)
|
||||||
LoadConf(req dto.OperationWithName) (*dto.RedisConf, error)
|
LoadConf(req dto.LoadRedisStatus) (*dto.RedisConf, error)
|
||||||
LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error)
|
LoadPersistenceConf(req dto.LoadRedisStatus) (*dto.RedisPersistence, error)
|
||||||
|
|
||||||
CheckHasCli() bool
|
CheckHasCli() bool
|
||||||
InstallCli() error
|
InstallCli() error
|
||||||
@@ -41,7 +41,7 @@ func NewIRedisService() IRedisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -50,10 +50,10 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
|||||||
confs = append(confs, redisConfig{key: "timeout", value: req.Timeout})
|
confs = append(confs, redisConfig{key: "timeout", value: req.Timeout})
|
||||||
confs = append(confs, redisConfig{key: "maxclients", value: req.Maxclients})
|
confs = append(confs, redisConfig{key: "maxclients", value: req.Maxclients})
|
||||||
confs = append(confs, redisConfig{key: "maxmemory", value: req.Maxmemory})
|
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
|
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 err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ func (u *RedisService) InstallCli() error {
|
|||||||
Image: "redis:7.4.4",
|
Image: "redis:7.4.4",
|
||||||
Network: "1panel-network",
|
Network: "1panel-network",
|
||||||
}
|
}
|
||||||
return NewIContainerService().ContainerCreate(item)
|
return NewIContainerService().ContainerCreate(item, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) ChangePassword(req dto.ChangeRedisPass) error {
|
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 {
|
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 {
|
if err != nil {
|
||||||
return err
|
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: "appendonly", value: req.Appendonly})
|
||||||
confs = append(confs, redisConfig{key: "appendfsync", value: req.Appendfsync})
|
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
|
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 err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) LoadStatus(req dto.OperationWithName) (*dto.RedisStatus, error) {
|
func (u *RedisService) LoadStatus(req dto.LoadRedisStatus) (*dto.RedisStatus, error) {
|
||||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -157,8 +157,8 @@ func (u *RedisService) LoadStatus(req dto.OperationWithName) (*dto.RedisStatus,
|
|||||||
return &info, nil
|
return &info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, error) {
|
func (u *RedisService) LoadConf(req dto.LoadRedisStatus) (*dto.RedisConf, error) {
|
||||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -174,8 +174,8 @@ func (u *RedisService) LoadConf(req dto.OperationWithName) (*dto.RedisConf, erro
|
|||||||
return &item, nil
|
return &item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *RedisService) LoadPersistenceConf(req dto.OperationWithName) (*dto.RedisPersistence, error) {
|
func (u *RedisService) LoadPersistenceConf(req dto.LoadRedisStatus) (*dto.RedisPersistence, error) {
|
||||||
redisInfo, err := appInstallRepo.LoadBaseInfo("redis", req.Name)
|
redisInfo, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -214,8 +214,8 @@ type redisConfig struct {
|
|||||||
value string
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func confSet(redisName string, updateType string, changeConf []redisConfig) error {
|
func confSet(redisName string, redisType string, updateType string, changeConf []redisConfig) error {
|
||||||
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", global.Dir.AppInstallDir, redisName)
|
path := fmt.Sprintf("%s/%s/%s/conf/redis.conf", global.Dir.AppInstallDir, redisType, redisName)
|
||||||
lineBytes, err := os.ReadFile(path)
|
lineBytes, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -244,6 +244,10 @@ func confSet(redisName string, updateType string, changeConf []redisConfig) erro
|
|||||||
}
|
}
|
||||||
newFiles = append(newFiles, files[i])
|
newFiles = append(newFiles, files[i])
|
||||||
}
|
}
|
||||||
|
if startIndex == 0 {
|
||||||
|
newFiles = append(newFiles, "# Redis configuration rewrite by 1Panel")
|
||||||
|
startIndex = len(newFiles) - 1
|
||||||
|
}
|
||||||
endIndex = endIndex - emptyLine
|
endIndex = endIndex - emptyLine
|
||||||
for _, item := range changeConf {
|
for _, item := range changeConf {
|
||||||
if item.key == "save" {
|
if item.key == "save" {
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ func (u *DeviceService) Update(key, value string) error {
|
|||||||
if err := ntp.UpdateSystemTimeZone(value); err != nil {
|
if err := ntp.UpdateSystemTimeZone(value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go common.RestartService(true, true, false)
|
go common.RestartService(global.IsMaster, true, false)
|
||||||
case "DNS":
|
case "DNS":
|
||||||
if err := updateDNS(strings.Split(value, ",")); err != nil {
|
if err := updateDNS(strings.Split(value, ",")); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -50,4 +50,5 @@ var (
|
|||||||
taskRepo = repo.NewITaskRepo()
|
taskRepo = repo.NewITaskRepo()
|
||||||
|
|
||||||
groupRepo = repo.NewIGroupRepo()
|
groupRepo = repo.NewIGroupRepo()
|
||||||
|
alertRepo = repo.NewIAlertRepo()
|
||||||
)
|
)
|
||||||
|
|||||||
+84
-39
@@ -4,10 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
|
||||||
"github.com/jinzhu/copier"
|
|
||||||
"golang.org/x/text/encoding"
|
|
||||||
"golang.org/x/text/encoding/simplifiedchinese"
|
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
@@ -18,6 +14,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"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"
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||||
|
|
||||||
@@ -96,19 +98,25 @@ func (f *FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (in
|
|||||||
files []response.UploadInfo
|
files []response.UploadInfo
|
||||||
backData []response.UploadInfo
|
backData []response.UploadInfo
|
||||||
)
|
)
|
||||||
_ = filepath.Walk(req.Path, func(path string, info os.FileInfo, err error) error {
|
fileList, err := os.ReadDir(req.Path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, files, nil
|
||||||
|
}
|
||||||
|
for _, item := range fileList {
|
||||||
|
if item.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fileItem, err := item.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
continue
|
||||||
}
|
}
|
||||||
if !info.IsDir() {
|
files = append(files, response.UploadInfo{
|
||||||
files = append(files, response.UploadInfo{
|
CreatedAt: fileItem.ModTime().Format(constant.DateTimeLayout),
|
||||||
CreatedAt: info.ModTime().Format(constant.DateTimeLayout),
|
Size: int(fileItem.Size()),
|
||||||
Size: int(info.Size()),
|
Name: item.Name(),
|
||||||
Name: info.Name(),
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
total, start, end := len(files), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
total, start, end := len(files), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||||
if start > total {
|
if start > total {
|
||||||
backData = make([]response.UploadInfo, 0)
|
backData = make([]response.UploadInfo, 0)
|
||||||
@@ -334,22 +342,24 @@ func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo,
|
|||||||
if len(content) > 1024 {
|
if len(content) > 1024 {
|
||||||
content = content[:1024]
|
content = content[:1024]
|
||||||
}
|
}
|
||||||
_, decodeName, _ := charset.DetermineEncoding(content, "")
|
if !utf8.Valid(content) {
|
||||||
decoder := files.GetDecoderByName(decodeName)
|
_, decodeName, _ := charset.DetermineEncoding(content, "")
|
||||||
if decoder != nil {
|
decoder := files.GetDecoderByName(decodeName)
|
||||||
reader := strings.NewReader(info.Content)
|
if decoder != nil {
|
||||||
var dec *encoding.Decoder
|
reader := strings.NewReader(info.Content)
|
||||||
if decodeName == "windows-1252" {
|
var dec *encoding.Decoder
|
||||||
dec = simplifiedchinese.GBK.NewDecoder()
|
if decodeName == "windows-1252" {
|
||||||
} else {
|
dec = simplifiedchinese.GBK.NewDecoder()
|
||||||
dec = decoder.NewDecoder()
|
} else {
|
||||||
|
dec = decoder.NewDecoder()
|
||||||
|
}
|
||||||
|
decodedReader := transform.NewReader(reader, dec)
|
||||||
|
contents, err := io.ReadAll(decodedReader)
|
||||||
|
if err != nil {
|
||||||
|
return response.FileInfo{}, err
|
||||||
|
}
|
||||||
|
info.Content = string(contents)
|
||||||
}
|
}
|
||||||
decodedReader := transform.NewReader(reader, dec)
|
|
||||||
contents, err := io.ReadAll(decodedReader)
|
|
||||||
if err != nil {
|
|
||||||
return response.FileInfo{}, err
|
|
||||||
}
|
|
||||||
info.Content = string(contents)
|
|
||||||
}
|
}
|
||||||
return response.FileInfo{FileInfo: *info}, nil
|
return response.FileInfo{FileInfo: *info}, nil
|
||||||
}
|
}
|
||||||
@@ -413,6 +423,14 @@ func (f *FileService) MvFile(m request.FileMove) error {
|
|||||||
global.LOG.Errorf("copy file [%s] to [%s] failed, err: %s", src, m.NewPath, err.Error())
|
global.LOG.Errorf("copy file [%s] to [%s] failed, err: %s", src, m.NewPath, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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("copy file [%s] to [%s] failed, err: %s", src, m.NewPath, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var errString string
|
var errString string
|
||||||
@@ -475,6 +493,7 @@ func (f *FileService) DepthDirSize(req request.DirSizeReq) ([]response.DepthDirS
|
|||||||
|
|
||||||
func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) {
|
func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) {
|
||||||
logFilePath := ""
|
logFilePath := ""
|
||||||
|
taskStatus := ""
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case constant.TypeWebsite:
|
case constant.TypeWebsite:
|
||||||
website, err := websiteRepo.GetFirst(repo.WithByID(req.ID))
|
website, err := websiteRepo.GetFirst(repo.WithByID(req.ID))
|
||||||
@@ -530,29 +549,55 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logFilePath = taskModel.LogFile
|
logFilePath = taskModel.LogFile
|
||||||
|
taskStatus = taskModel.Status
|
||||||
case "mysql-slow-logs":
|
case "mysql-slow-logs":
|
||||||
logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
|
||||||
case "mariadb-slow-logs":
|
case "mariadb-slow-logs":
|
||||||
logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
|
logFilePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mariadb/%s/db/data/1Panel-slow.log", req.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
|
file, err := os.Open(logFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if req.Latest && req.Page == 1 && len(lines) < 1000 && total > 1 {
|
defer file.Close()
|
||||||
preLines, _, _, err := files.ReadFileByLine(logFilePath, total-1, req.PageSize, false)
|
stat, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
lines []string
|
||||||
|
isEndOfFile bool
|
||||||
|
total int
|
||||||
|
scope string
|
||||||
|
)
|
||||||
|
|
||||||
|
if stat.Size() > 500*1024*1024 {
|
||||||
|
lines, err = files.TailFromEnd(logFilePath, req.PageSize)
|
||||||
|
isEndOfFile = true
|
||||||
|
scope = "tail"
|
||||||
|
} else {
|
||||||
|
lines, isEndOfFile, total, err = files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
lines = append(preLines, lines...)
|
if req.Latest && req.Page == 1 && len(lines) < 1000 && total > 1 {
|
||||||
|
preLines, _, _, err := files.ReadFileByLine(logFilePath, total-1, req.PageSize, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lines = append(preLines, lines...)
|
||||||
|
}
|
||||||
|
scope = "page"
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &response.FileLineContent{
|
res := &response.FileLineContent{
|
||||||
Content: strings.Join(lines, "\n"),
|
End: isEndOfFile,
|
||||||
End: isEndOfFile,
|
Path: logFilePath,
|
||||||
Path: logFilePath,
|
Total: total,
|
||||||
Total: total,
|
TaskStatus: taskStatus,
|
||||||
Lines: lines,
|
Lines: lines,
|
||||||
|
Scope: scope,
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ func handleProcess(supervisordDir string, req request.SupervisorProcessConfig, c
|
|||||||
_, _ = section.NewKey("command", strings.TrimSpace(req.Command))
|
_, _ = section.NewKey("command", strings.TrimSpace(req.Command))
|
||||||
_, _ = section.NewKey("directory", req.Dir)
|
_, _ = section.NewKey("directory", req.Dir)
|
||||||
_, _ = section.NewKey("autorestart", req.AutoRestart)
|
_, _ = section.NewKey("autorestart", req.AutoRestart)
|
||||||
|
_, _ = section.NewKey("autostart", req.AutoStart)
|
||||||
_, _ = section.NewKey("startsecs", "3")
|
_, _ = section.NewKey("startsecs", "3")
|
||||||
_, _ = section.NewKey("stdout_logfile", outLog)
|
_, _ = section.NewKey("stdout_logfile", outLog)
|
||||||
_, _ = section.NewKey("stderr_logfile", errLog)
|
_, _ = section.NewKey("stderr_logfile", errLog)
|
||||||
@@ -360,6 +361,8 @@ func handleProcess(supervisordDir string, req request.SupervisorProcessConfig, c
|
|||||||
numprocsKey.SetValue(req.Numprocs)
|
numprocsKey.SetValue(req.Numprocs)
|
||||||
autoRestart := section.Key("autorestart")
|
autoRestart := section.Key("autorestart")
|
||||||
autoRestart.SetValue(req.AutoRestart)
|
autoRestart.SetValue(req.AutoRestart)
|
||||||
|
autoStart := section.Key("autostart")
|
||||||
|
autoStart.SetValue(req.AutoStart)
|
||||||
|
|
||||||
if err = configFile.SaveTo(iniPath); err != nil {
|
if err = configFile.SaveTo(iniPath); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -429,6 +432,9 @@ func handleProcessConfig(configDir, containerName string) ([]response.Supervisor
|
|||||||
if autoRestart, _ := section.GetKey("autorestart"); autoRestart != nil {
|
if autoRestart, _ := section.GetKey("autorestart"); autoRestart != nil {
|
||||||
config.AutoRestart = autoRestart.Value()
|
config.AutoRestart = autoRestart.Value()
|
||||||
}
|
}
|
||||||
|
if autoStart, _ := section.GetKey("autostart"); autoStart != nil {
|
||||||
|
config.AutoStart = autoStart.Value()
|
||||||
|
}
|
||||||
_ = getProcessStatus(&config, containerName)
|
_ = getProcessStatus(&config, containerName)
|
||||||
result = append(result, config)
|
result = append(result, config)
|
||||||
}
|
}
|
||||||
@@ -609,7 +615,7 @@ func getProcessStatus(config *response.SupervisorProcessConfig, containerName st
|
|||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
line = strings.TrimPrefix(line, "stdout:")
|
line = strings.TrimPrefix(line, "stdout:")
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
if len(fields) >= 5 {
|
if len(fields) >= 4 {
|
||||||
status := response.ProcessStatus{
|
status := response.ProcessStatus{
|
||||||
Name: fields[0],
|
Name: fields[0],
|
||||||
Status: fields[1],
|
Status: fields[1],
|
||||||
|
|||||||
+35
-24
@@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||||
"github.com/docker/docker/api/types/build"
|
"github.com/docker/docker/api/types/build"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
@@ -41,7 +42,7 @@ type IImageService interface {
|
|||||||
ImageLoad(req dto.ImageLoad) error
|
ImageLoad(req dto.ImageLoad) error
|
||||||
ImageSave(req dto.ImageSave) error
|
ImageSave(req dto.ImageSave) error
|
||||||
ImagePush(req dto.ImagePush) error
|
ImagePush(req dto.ImagePush) error
|
||||||
ImageRemove(req dto.BatchDelete) (dto.ContainerPruneReport, error)
|
ImageRemove(req dto.BatchDelete) error
|
||||||
ImageTag(req dto.ImageTag) error
|
ImageTag(req dto.ImageTag) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,34 +387,44 @@ func (u *ImageService) ImagePush(req dto.ImagePush) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageService) ImageRemove(req dto.BatchDelete) (dto.ContainerPruneReport, error) {
|
func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
||||||
report := dto.ContainerPruneReport{}
|
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return err
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
for _, id := range req.Names {
|
taskItem, err := task.NewTaskWithOps(task.TaskScopeImage, task.TaskDelete, task.TaskScopeContainer, req.TaskID, 1)
|
||||||
imageItem, _, err := client.ImageInspectWithRaw(context.TODO(), id)
|
if err != nil {
|
||||||
if err != nil {
|
global.LOG.Errorf("new task for create container failed, err: %v", err)
|
||||||
return report, err
|
return err
|
||||||
}
|
|
||||||
if _, err := client.ImageRemove(context.TODO(), id, image.RemoveOptions{Force: req.Force, PruneChildren: true}); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "image is being used") || strings.Contains(err.Error(), "is using") {
|
|
||||||
if strings.Contains(id, "sha256:") {
|
|
||||||
return report, buserr.New("ErrObjectInUsed")
|
|
||||||
}
|
|
||||||
return report, buserr.WithDetail("ErrInUsed", id, nil)
|
|
||||||
}
|
|
||||||
if strings.Contains(err.Error(), "image has dependent") {
|
|
||||||
return report, buserr.New("ErrObjectBeDependent")
|
|
||||||
}
|
|
||||||
return report, err
|
|
||||||
}
|
|
||||||
report.DeletedNumber++
|
|
||||||
report.SpaceReclaimed += int(imageItem.Size)
|
|
||||||
}
|
}
|
||||||
return report, nil
|
|
||||||
|
for _, id := range req.Names {
|
||||||
|
taskItem.AddSubTask(i18n.GetMsgByKey("TaskDelete")+id, func(t *task.Task) error {
|
||||||
|
imageItem, err := client.ImageInspect(context.TODO(), id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := client.ImageRemove(context.TODO(), id, image.RemoveOptions{Force: req.Force, PruneChildren: true}); err != nil {
|
||||||
|
if strings.Contains(err.Error(), "image is being used") || strings.Contains(err.Error(), "is using") {
|
||||||
|
if strings.Contains(id, "sha256:") {
|
||||||
|
return buserr.New("ErrObjectInUsed")
|
||||||
|
}
|
||||||
|
return buserr.WithDetail("ErrInUsed", id, nil)
|
||||||
|
}
|
||||||
|
if strings.Contains(err.Error(), "image has dependent") {
|
||||||
|
return buserr.New("ErrObjectBeDependent")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
taskItem.Log(i18n.GetMsgWithMap("ImageRemoveHelper", map[string]interface{}{"name": id, "size": common.LoadSizeUnit2F(float64(imageItem.Size))}))
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
_ = taskItem.Execute()
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatFileSize(fileSize int64) (size string) {
|
func formatFileSize(fileSize int64) (size string) {
|
||||||
|
|||||||
@@ -164,10 +164,12 @@ func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error {
|
|||||||
needRestart = repo.DownloadUrl == req.DownloadUrl
|
needRestart = repo.DownloadUrl == req.DownloadUrl
|
||||||
}
|
}
|
||||||
if repo.Protocol == "https" && req.Protocol == "http" {
|
if repo.Protocol == "https" && req.Protocol == "http" {
|
||||||
if err := u.handleRegistries(req.DownloadUrl, "", "create"); err != nil {
|
if req.DownloadUrl != repo.DownloadUrl {
|
||||||
return fmt.Errorf("create registry %s failed, err: %v", req.DownloadUrl, err)
|
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
|
||||||
}
|
}
|
||||||
needRestart = true
|
|
||||||
}
|
}
|
||||||
if needRestart {
|
if needRestart {
|
||||||
if err := stopBeforeUpdateRepo(); err != nil {
|
if err := stopBeforeUpdateRepo(); err != nil {
|
||||||
|
|||||||
@@ -86,6 +86,11 @@ func (m McpServerService) Page(req request.McpServerSearch) response.McpServersR
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m McpServerService) Update(req request.McpServerUpdate) error {
|
func (m McpServerService) Update(req request.McpServerUpdate) error {
|
||||||
|
go func() {
|
||||||
|
if err := docker.PullImage("supercorp/supergateway:latest"); err != nil {
|
||||||
|
global.LOG.Errorf("docker pull mcp image error: %s", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
mcpServer, err := mcpServerRepo.GetFirst(repo.WithByID(req.ID))
|
mcpServer, err := mcpServerRepo.GetFirst(repo.WithByID(req.ID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -108,6 +113,8 @@ func (m McpServerService) Update(req request.McpServerUpdate) error {
|
|||||||
mcpServer.BaseURL = req.BaseURL
|
mcpServer.BaseURL = req.BaseURL
|
||||||
mcpServer.SsePath = req.SsePath
|
mcpServer.SsePath = req.SsePath
|
||||||
mcpServer.HostIP = req.HostIP
|
mcpServer.HostIP = req.HostIP
|
||||||
|
mcpServer.StreamableHttpPath = req.StreamableHttpPath
|
||||||
|
mcpServer.OutputTransport = req.OutputTransport
|
||||||
if err := handleCreateParams(mcpServer, req.Environments, req.Volumes); err != nil {
|
if err := handleCreateParams(mcpServer, req.Environments, req.Volumes); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -130,6 +137,11 @@ func (m McpServerService) Update(req request.McpServerUpdate) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m McpServerService) Create(create request.McpServerCreate) error {
|
func (m McpServerService) Create(create request.McpServerCreate) error {
|
||||||
|
go func() {
|
||||||
|
if err := docker.PullImage("supercorp/supergateway:latest"); err != nil {
|
||||||
|
global.LOG.Errorf("docker pull mcp image error: %s", err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
servers, _ := mcpServerRepo.List()
|
servers, _ := mcpServerRepo.List()
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
if server.Port == create.Port {
|
if server.Port == create.Port {
|
||||||
@@ -154,15 +166,17 @@ func (m McpServerService) Create(create request.McpServerCreate) error {
|
|||||||
}
|
}
|
||||||
mcpDir := path.Join(global.Dir.McpDir, create.Name)
|
mcpDir := path.Join(global.Dir.McpDir, create.Name)
|
||||||
mcpServer := &model.McpServer{
|
mcpServer := &model.McpServer{
|
||||||
Name: create.Name,
|
Name: create.Name,
|
||||||
ContainerName: create.ContainerName,
|
ContainerName: create.ContainerName,
|
||||||
Port: create.Port,
|
Port: create.Port,
|
||||||
Command: create.Command,
|
Command: create.Command,
|
||||||
Status: constant.StatusStarting,
|
Status: constant.StatusStarting,
|
||||||
BaseURL: create.BaseURL,
|
BaseURL: create.BaseURL,
|
||||||
SsePath: create.SsePath,
|
SsePath: create.SsePath,
|
||||||
Dir: mcpDir,
|
Dir: mcpDir,
|
||||||
HostIP: create.HostIP,
|
HostIP: create.HostIP,
|
||||||
|
StreamableHttpPath: create.StreamableHttpPath,
|
||||||
|
OutputTransport: create.OutputTransport,
|
||||||
}
|
}
|
||||||
if err := handleCreateParams(mcpServer, create.Environments, create.Volumes); err != nil {
|
if err := handleCreateParams(mcpServer, create.Environments, create.Volumes); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -283,11 +297,19 @@ func (m McpServerService) BindDomain(req request.McpBindDomain) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
group, _ := groupRepo.Get(groupRepo.WithByWebsiteDefault())
|
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{
|
createWebsiteReq := request.WebsiteCreate{
|
||||||
Domains: []request.WebsiteDomain{
|
Domains: []request.WebsiteDomain{
|
||||||
{
|
{
|
||||||
Domain: req.Domain,
|
Domain: domain.Domain,
|
||||||
Port: 80,
|
Port: domain.Port,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Alias: strings.ToLower(req.Domain),
|
Alias: strings.ToLower(req.Domain),
|
||||||
@@ -516,6 +538,8 @@ func handleEnv(mcpServer *model.McpServer) gotenv.Env {
|
|||||||
env["BASE_URL"] = mcpServer.BaseURL
|
env["BASE_URL"] = mcpServer.BaseURL
|
||||||
env["SSE_PATH"] = mcpServer.SsePath
|
env["SSE_PATH"] = mcpServer.SsePath
|
||||||
env["HOST_IP"] = mcpServer.HostIP
|
env["HOST_IP"] = mcpServer.HostIP
|
||||||
|
env["STREAMABLE_HTTP_PATH"] = mcpServer.StreamableHttpPath
|
||||||
|
env["OUTPUT_TRANSPORT"] = mcpServer.OutputTransport
|
||||||
envStr, _ := gotenv.Marshal(env)
|
envStr, _ := gotenv.Marshal(env)
|
||||||
mcpServer.Env = envStr
|
mcpServer.Env = envStr
|
||||||
return env
|
return env
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/nginx"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/nginx/parser"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -42,6 +44,9 @@ type INginxService interface {
|
|||||||
Build(req request.NginxBuildReq) error
|
Build(req request.NginxBuildReq) error
|
||||||
GetModules() (*response.NginxBuildConfig, error)
|
GetModules() (*response.NginxBuildConfig, error)
|
||||||
UpdateModule(req request.NginxModuleUpdate) error
|
UpdateModule(req request.NginxModuleUpdate) error
|
||||||
|
|
||||||
|
OperateDefaultHTTPs(req request.NginxOperateReq) error
|
||||||
|
GetDefaultHttpsStatus() (*response.NginxConfigRes, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewINginxService() INginxService {
|
func NewINginxService() INginxService {
|
||||||
@@ -348,3 +353,70 @@ func (n NginxService) UpdateModule(req request.NginxModuleUpdate) error {
|
|||||||
}
|
}
|
||||||
return fileOp.SaveFileWithByte(moduleConfigPath, moduleByte, constant.DirPerm)
|
return fileOp.SaveFileWithByte(moduleConfigPath, moduleByte, constant.DirPerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n NginxService) OperateDefaultHTTPs(req request.NginxOperateReq) error {
|
||||||
|
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
websites, _ := websiteRepo.List()
|
||||||
|
hasDefaultWebsite := false
|
||||||
|
for _, website := range websites {
|
||||||
|
if website.DefaultServer {
|
||||||
|
hasDefaultWebsite = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defaultConfigPath := path.Join(appInstall.GetPath(), "conf", "default", "00.default.conf")
|
||||||
|
content, err := os.ReadFile(defaultConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.Operate == "enable" {
|
||||||
|
if err := handleSSLConfig(&appInstall, hasDefaultWebsite); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if req.Operate == "disable" {
|
||||||
|
defaultConfig, err := parser.NewStringParser(string(content)).Parse()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defaultConfig.FilePath = defaultConfigPath
|
||||||
|
defaultServer := defaultConfig.FindServers()[0]
|
||||||
|
defaultServer.RemoveListen(fmt.Sprintf("%d", appInstall.HttpsPort))
|
||||||
|
defaultServer.RemoveListen(fmt.Sprintf("[::]:%d", appInstall.HttpsPort))
|
||||||
|
defaultServer.RemoveDirective("include", []string{"/usr/local/openresty/nginx/conf/ssl/root_ssl.conf"})
|
||||||
|
defaultServer.RemoveDirective("http2", []string{"on"})
|
||||||
|
if err = nginx.WriteConfig(defaultConfig, nginx.IndentedStyle); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nginxCheckAndReload(string(content), defaultConfigPath, appInstall.ContainerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NginxService) GetDefaultHttpsStatus() (*response.NginxConfigRes, error) {
|
||||||
|
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defaultConfigPath := path.Join(appInstall.GetPath(), "conf", "default", "00.default.conf")
|
||||||
|
content, err := os.ReadFile(defaultConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defaultConfig, err := parser.NewStringParser(string(content)).Parse()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defaultConfig.FilePath = defaultConfigPath
|
||||||
|
defaultServer := defaultConfig.FindServers()[0]
|
||||||
|
res := &response.NginxConfigRes{}
|
||||||
|
for _, directive := range defaultServer.GetDirectives() {
|
||||||
|
if directive.GetName() == "include" && directive.GetParameters()[0] == "/usr/local/openresty/nginx/conf/ssl/root_ssl.conf" {
|
||||||
|
return &response.NginxConfigRes{
|
||||||
|
Https: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -211,6 +211,9 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
if len(runtimes) == 0 {
|
||||||
|
return 0, res, nil
|
||||||
|
}
|
||||||
if err = SyncRuntimesStatus(runtimes); err != nil {
|
if err = SyncRuntimesStatus(runtimes); err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
@@ -447,6 +450,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
|||||||
if err := checkContainerName(containerName.(string)); err != nil {
|
if err := checkContainerName(containerName.(string)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
runtime.ContainerName = containerName.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
projectDir := path.Join(global.Dir.RuntimeDir, runtime.Type, runtime.Name)
|
projectDir := path.Join(global.Dir.RuntimeDir, runtime.Type, runtime.Name)
|
||||||
|
|||||||
@@ -102,6 +102,13 @@ func handlePHP(create request.RuntimeCreate, runtime *model.Runtime, fileOp file
|
|||||||
runtime.Params = string(forms)
|
runtime.Params = string(forms)
|
||||||
runtime.Status = constant.StatusBuilding
|
runtime.Status = constant.StatusBuilding
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(repo.WithByID(runtime.AppDetailID))
|
||||||
|
if err == nil {
|
||||||
|
RequestDownloadCallBack(appDetail.DownloadCallBackUrl)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
go buildRuntime(runtime, "", "", false)
|
go buildRuntime(runtime, "", "", false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ func (u *SnapshotService) SnapshotCreate(parentTask *task.Task, req dto.Snapshot
|
|||||||
|
|
||||||
Version: versionItem.Value,
|
Version: versionItem.Value,
|
||||||
Status: constant.StatusWaiting,
|
Status: constant.StatusWaiting,
|
||||||
|
Timeout: req.Timeout,
|
||||||
}
|
}
|
||||||
if err := snapshotRepo.Create(&snap); err != nil {
|
if err := snapshotRepo.Create(&snap); err != nil {
|
||||||
global.LOG.Errorf("create snapshot record to db failed, err: %v", err)
|
global.LOG.Errorf("create snapshot record to db failed, err: %v", err)
|
||||||
@@ -79,7 +80,7 @@ func (u *SnapshotService) SnapshotCreate(parentTask *task.Task, req dto.Snapshot
|
|||||||
}
|
}
|
||||||
if jobID == 0 {
|
if jobID == 0 {
|
||||||
go func() {
|
go func() {
|
||||||
_ = handleSnapshot(req, taskItem, jobID, 3, 0)
|
_ = handleSnapshot(req, taskItem, jobID, 3, snap.Timeout)
|
||||||
}()
|
}()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -123,15 +124,11 @@ func (u *SnapshotService) SnapshotReCreate(id uint) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task, jobID, retry, timeout uint) error {
|
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")
|
openrestyDir, _ := settingRepo.GetValueByKey("WEBSITE_DIR")
|
||||||
itemHelper := snapHelper{SnapID: req.ID, Task: *taskItem, FileOp: files.NewFileOp(), Ctx: context.Background(), OpenrestyDir: openrestyDir}
|
itemHelper := snapHelper{SnapID: req.ID, Task: *taskItem, FileOp: files.NewFileOp(), Ctx: context.Background(), OpenrestyDir: openrestyDir}
|
||||||
baseDir := path.Join(rootDir, "base")
|
baseDir := path.Join(rootDir, "base")
|
||||||
_ = os.MkdirAll(baseDir, os.ModePerm)
|
_ = os.MkdirAll(baseDir, os.ModePerm)
|
||||||
|
|
||||||
if timeout == 0 {
|
|
||||||
timeout = 1800
|
|
||||||
}
|
|
||||||
taskItem.AddSubTaskWithAliasAndOps(
|
taskItem.AddSubTaskWithAliasAndOps(
|
||||||
"SnapDBInfo",
|
"SnapDBInfo",
|
||||||
func(t *task.Task) error {
|
func(t *task.Task) error {
|
||||||
@@ -406,6 +403,7 @@ func snapBackupData(snap snapHelper, req dto.SnapshotCreate, targetDir string) e
|
|||||||
excludes := loadBackupExcludes(snap, req.BackupData)
|
excludes := loadBackupExcludes(snap, req.BackupData)
|
||||||
excludes = append(excludes, req.IgnoreFiles...)
|
excludes = append(excludes, req.IgnoreFiles...)
|
||||||
excludes = append(excludes, "./system_snapshot")
|
excludes = append(excludes, "./system_snapshot")
|
||||||
|
excludes = append(excludes, "./tmp")
|
||||||
for _, item := range req.AppData {
|
for _, item := range req.AppData {
|
||||||
for _, itemApp := range item.Children {
|
for _, itemApp := range item.Children {
|
||||||
if itemApp.Label == "appBackup" {
|
if itemApp.Label == "appBackup" {
|
||||||
@@ -517,7 +515,7 @@ func snapCompress(snap snapHelper, rootDir string, secret string) error {
|
|||||||
snap.Task.Log("---------------------- 7 / 8 ----------------------")
|
snap.Task.Log("---------------------- 7 / 8 ----------------------")
|
||||||
snap.Task.LogStart(i18n.GetMsgByKey("SnapCompress"))
|
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))
|
fileName := fmt.Sprintf("%s.tar.gz", path.Base(rootDir))
|
||||||
err := snap.FileOp.TarGzCompressPro(true, rootDir, path.Join(tmpDir, fileName), secret, "")
|
err := snap.FileOp.TarGzCompressPro(true, rootDir, path.Join(tmpDir, fileName), secret, "")
|
||||||
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapCompressFile"), err)
|
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapCompressFile"), err)
|
||||||
@@ -541,7 +539,7 @@ func snapUpload(snap snapHelper, accounts string, file string) error {
|
|||||||
snap.Task.Log("---------------------- 8 / 8 ----------------------")
|
snap.Task.Log("---------------------- 8 / 8 ----------------------")
|
||||||
snap.Task.LogStart(i18n.GetMsgByKey("SnapUpload"))
|
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, ","))
|
accountMap, err := NewBackupClientMap(strings.Split(accounts, ","))
|
||||||
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapLoadBackup"), err)
|
snap.Task.LogWithStatus(i18n.GetMsgByKey("SnapLoadBackup"), err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
|||||||
global.LOG.Errorf("new task for create snapshot failed, err: %v", err)
|
global.LOG.Errorf("new task for create snapshot failed, err: %v", err)
|
||||||
return 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) {
|
if _, err := os.Stat(rootDir); err != nil && os.IsNotExist(err) {
|
||||||
_ = os.MkdirAll(rootDir, os.ModePerm)
|
_ = os.MkdirAll(rootDir, os.ModePerm)
|
||||||
}
|
}
|
||||||
@@ -175,6 +175,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
|||||||
itemHelper.Task.Log("---------------------- 9 / 11 ----------------------")
|
itemHelper.Task.Log("---------------------- 9 / 11 ----------------------")
|
||||||
itemHelper.Task.LogStart(i18n.GetWithName("RecoverWebsite", snap.Name))
|
itemHelper.Task.LogStart(i18n.GetWithName("RecoverWebsite", snap.Name))
|
||||||
webFile := path.Join(rootDir, snap.Name, "/website.tar.gz")
|
webFile := path.Join(rootDir, snap.Name, "/website.tar.gz")
|
||||||
|
_ = itemHelper.FileOp.CreateDir(snapJson.OperestyDir, os.ModePerm)
|
||||||
var err error
|
var err error
|
||||||
if itemHelper.FileOp.Stat(webFile) {
|
if itemHelper.FileOp.Stat(webFile) {
|
||||||
err = itemHelper.FileOp.TarGzExtractPro(webFile, snapJson.OperestyDir, "")
|
err = itemHelper.FileOp.TarGzExtractPro(webFile, snapJson.OperestyDir, "")
|
||||||
|
|||||||
+184
-52
@@ -1,24 +1,30 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/copier"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/geo"
|
"github.com/1Panel-dev/1Panel/agent/utils/geo"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"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/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/systemctl"
|
"github.com/1Panel-dev/1Panel/agent/utils/systemctl"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -32,11 +38,13 @@ type ISSHService interface {
|
|||||||
OperateSSH(operation string) error
|
OperateSSH(operation string) error
|
||||||
UpdateByFile(value string) error
|
UpdateByFile(value string) error
|
||||||
Update(req dto.SSHUpdate) error
|
Update(req dto.SSHUpdate) error
|
||||||
GenerateSSH(req dto.GenerateSSH) error
|
|
||||||
LoadSSHSecret(mode string) (string, error)
|
|
||||||
LoadLog(ctx *gin.Context, req dto.SearchSSHLog) (*dto.SSHLog, error)
|
LoadLog(ctx *gin.Context, req dto.SearchSSHLog) (*dto.SSHLog, error)
|
||||||
|
|
||||||
LoadSSHConf() (string, error)
|
LoadSSHConf() (string, error)
|
||||||
|
|
||||||
|
SyncRootCert() error
|
||||||
|
CreateRootCert(req dto.CreateRootCert) error
|
||||||
|
SearchRootCerts(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
|
DeleteRootCerts(req dto.ForceDelete) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewISSHService() ISSHService {
|
func NewISSHService() ISSHService {
|
||||||
@@ -110,6 +118,14 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
|
|||||||
data.UseDNS = strings.ReplaceAll(line, "UseDNS ", "")
|
data.UseDNS = strings.ReplaceAll(line, "UseDNS ", "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentUser, err := user.Current()
|
||||||
|
if err != nil || len(currentUser.Name) == 0 {
|
||||||
|
data.CurrentUser = "root"
|
||||||
|
} else {
|
||||||
|
data.CurrentUser = currentUser.Name
|
||||||
|
}
|
||||||
|
|
||||||
return &data, nil
|
return &data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,70 +230,163 @@ func (u *SSHService) UpdateByFile(value string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error {
|
func (u *SSHService) SyncRootCert() error {
|
||||||
if cmd.CheckIllegal(req.EncryptionMode, req.Password) {
|
currentUser, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("load current user failed, err: %v", err)
|
||||||
|
}
|
||||||
|
sshDir := fmt.Sprintf("%s/.ssh", currentUser.HomeDir)
|
||||||
|
|
||||||
|
fileList, err := os.ReadDir(sshDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var rootCerts []model.RootCert
|
||||||
|
fileMap := make(map[string]bool)
|
||||||
|
for _, item := range fileList {
|
||||||
|
if !item.IsDir() {
|
||||||
|
fileMap[item.Name()] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for item := range fileMap {
|
||||||
|
if !strings.HasSuffix(item, ".pub") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !fileMap[strings.TrimSuffix(item, ".pub")] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cert := model.RootCert{Name: strings.TrimSuffix(item, ".pub"), PublicKeyPath: path.Join(sshDir, item), PrivateKeyPath: path.Join(sshDir, strings.TrimSuffix(item, ".pub"))}
|
||||||
|
pubItem, err := os.ReadFile(path.Join(sshDir, item))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("read pubic key of %s for sync failed, err: %v", item, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cert.EncryptionMode = loadEncryptioMode(string(pubItem))
|
||||||
|
rootCerts = append(rootCerts, cert)
|
||||||
|
}
|
||||||
|
return hostRepo.SyncCert(rootCerts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SSHService) CreateRootCert(req dto.CreateRootCert) error {
|
||||||
|
if cmd.CheckIllegal(req.EncryptionMode, req.PassPhrase) {
|
||||||
return buserr.New("ErrCmdIllegal")
|
return buserr.New("ErrCmdIllegal")
|
||||||
}
|
}
|
||||||
|
certItem, _ := hostRepo.GetCert(repo.WithByName(req.Name))
|
||||||
|
if certItem.ID != 0 {
|
||||||
|
return buserr.New("ErrRecordExist")
|
||||||
|
}
|
||||||
currentUser, err := user.Current()
|
currentUser, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("load current user failed, err: %v", err)
|
return fmt.Errorf("load current user failed, err: %v", err)
|
||||||
}
|
}
|
||||||
secretFile := fmt.Sprintf("%s/.ssh/id_item_%s", currentUser.HomeDir, req.EncryptionMode)
|
var cert model.RootCert
|
||||||
secretPubFile := fmt.Sprintf("%s/.ssh/id_item_%s.pub", currentUser.HomeDir, req.EncryptionMode)
|
if err := copier.Copy(&cert, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
privatePath := fmt.Sprintf("%s/.ssh/%s", currentUser.HomeDir, req.Name)
|
||||||
|
publicPath := fmt.Sprintf("%s/.ssh/%s.pub", currentUser.HomeDir, req.Name)
|
||||||
authFilePath := currentUser.HomeDir + "/.ssh/authorized_keys"
|
authFilePath := currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||||
|
|
||||||
command := fmt.Sprintf("ssh-keygen -t %s -f %s/.ssh/id_item_%s | echo y", req.EncryptionMode, currentUser.HomeDir, req.EncryptionMode)
|
if req.Mode == "input" || req.Mode == "import" {
|
||||||
if len(req.Password) != 0 {
|
if err := os.WriteFile(privatePath, []byte(req.PrivateKey), constant.FilePerm); err != nil {
|
||||||
command = fmt.Sprintf("ssh-keygen -t %s -P %s -f %s/.ssh/id_item_%s | echo y", req.EncryptionMode, req.Password, currentUser.HomeDir, req.EncryptionMode)
|
return err
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(publicPath, []byte(req.PublicKey), constant.FilePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
command := fmt.Sprintf("ssh-keygen -t %s -f %s/.ssh/%s -N ''", req.EncryptionMode, currentUser.HomeDir, req.Name)
|
||||||
|
if len(req.PassPhrase) != 0 {
|
||||||
|
command = fmt.Sprintf("ssh-keygen -t %s -P %s -f %s/.ssh/%s | echo y", req.EncryptionMode, req.PassPhrase, currentUser.HomeDir, req.Name)
|
||||||
|
}
|
||||||
|
stdout, err := cmd.RunDefaultWithStdoutBashC(command)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stdout, err := cmd.RunDefaultWithStdoutBashC(command)
|
|
||||||
|
stdout, err := cmd.RunDefaultWithStdoutBashCf("cat %s >> %s", publicPath, authFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout)
|
return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout)
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
_ = os.Remove(secretFile)
|
|
||||||
}()
|
|
||||||
defer func() {
|
|
||||||
_ = os.Remove(secretPubFile)
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := os.Stat(authFilePath); err != nil && errors.Is(err, os.ErrNotExist) {
|
cert.PrivateKeyPath = privatePath
|
||||||
authFile, err := os.Create(authFilePath)
|
cert.PublicKeyPath = publicPath
|
||||||
if err != nil {
|
if len(cert.PassPhrase) != 0 {
|
||||||
|
cert.PassPhrase, _ = encrypt.StringEncrypt(cert.PassPhrase)
|
||||||
|
}
|
||||||
|
return hostRepo.CreateCert(&cert)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SSHService) SearchRootCerts(req dto.SearchWithPage) (int64, interface{}, error) {
|
||||||
|
total, records, err := hostRepo.PageCert(req.Page, req.PageSize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
var datas []dto.RootCert
|
||||||
|
for i := 0; i < len(records); i++ {
|
||||||
|
publicItem, err := os.ReadFile(records[i].PublicKeyPath)
|
||||||
|
var publicBase64 string
|
||||||
|
if err == nil && len(publicItem) != 0 {
|
||||||
|
publicBase64 = base64.StdEncoding.EncodeToString(publicItem)
|
||||||
|
}
|
||||||
|
privateItem, _ := os.ReadFile(records[i].PrivateKeyPath)
|
||||||
|
var privateBase64 string
|
||||||
|
if err == nil && len(publicItem) != 0 {
|
||||||
|
privateBase64 = base64.StdEncoding.EncodeToString(privateItem)
|
||||||
|
}
|
||||||
|
passPhrase, _ := encrypt.StringDecryptWithBase64(records[i].PassPhrase)
|
||||||
|
datas = append(datas, dto.RootCert{
|
||||||
|
ID: records[i].ID,
|
||||||
|
CreatedAt: records[i].CreatedAt,
|
||||||
|
Name: records[i].Name,
|
||||||
|
EncryptionMode: records[i].EncryptionMode,
|
||||||
|
PassPhrase: passPhrase,
|
||||||
|
PublicKey: publicBase64,
|
||||||
|
PrivateKey: privateBase64,
|
||||||
|
Description: records[i].Description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return total, datas, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SSHService) DeleteRootCerts(req dto.ForceDelete) error {
|
||||||
|
currentUser, err := user.Current()
|
||||||
|
if err != nil && !req.ForceDelete {
|
||||||
|
return fmt.Errorf("load current user failed, err: %v", err)
|
||||||
|
}
|
||||||
|
authFilePath := currentUser.HomeDir + "/.ssh/authorized_keys"
|
||||||
|
authItem, err := os.ReadFile(authFilePath)
|
||||||
|
if err != nil && !req.ForceDelete {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, id := range req.IDs {
|
||||||
|
cert, _ := hostRepo.GetCert(repo.WithByID(id))
|
||||||
|
if cert.ID == 0 {
|
||||||
|
if !req.ForceDelete {
|
||||||
|
return buserr.New("ErrRecordNotFound")
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publicItem, err := os.ReadFile(cert.PublicKeyPath)
|
||||||
|
if err != nil && !req.ForceDelete {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newFile := bytes.ReplaceAll(authItem, publicItem, nil)
|
||||||
|
if err := os.WriteFile(authFilePath, newFile, constant.FilePerm); err != nil && !req.ForceDelete {
|
||||||
|
return fmt.Errorf("refresh authorized_keys failed, err: %v", err)
|
||||||
|
}
|
||||||
|
_ = os.Remove(cert.PublicKeyPath)
|
||||||
|
_ = os.Remove(cert.PrivateKeyPath)
|
||||||
|
if err := hostRepo.DeleteCert(repo.WithByID(id)); err != nil && !req.ForceDelete {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer authFile.Close()
|
|
||||||
}
|
|
||||||
stdout1, err := cmd.RunDefaultWithStdoutBashCf("cat %s >> %s/.ssh/authorized_keys", secretPubFile, currentUser.HomeDir)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileOp := files.NewFileOp()
|
|
||||||
if err := fileOp.Rename(secretFile, fmt.Sprintf("%s/.ssh/id_%s%s", currentUser.HomeDir, req.EncryptionMode, req.Name)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := fileOp.Rename(secretPubFile, fmt.Sprintf("%s/.ssh/id_%s%s.pub", currentUser.HomeDir, req.EncryptionMode, req.Name)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *SSHService) LoadSSHSecret(mode string) (string, error) {
|
|
||||||
currentUser, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("load current user failed, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
homeDir := currentUser.HomeDir
|
|
||||||
if _, err := os.Stat(fmt.Sprintf("%s/.ssh/id_%s", homeDir, mode)); err != nil {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
file, err := os.ReadFile(fmt.Sprintf("%s/.ssh/id_%s", homeDir, mode))
|
|
||||||
return string(file), err
|
|
||||||
}
|
|
||||||
|
|
||||||
type sshFileItem struct {
|
type sshFileItem struct {
|
||||||
Name string
|
Name string
|
||||||
Year int
|
Year int
|
||||||
@@ -433,7 +542,7 @@ func loadSSHData(ctx *gin.Context, command string, showCountFrom, showCountTo, c
|
|||||||
switch {
|
switch {
|
||||||
case strings.Contains(lines[i], "Failed password for"):
|
case strings.Contains(lines[i], "Failed password for"):
|
||||||
itemData = loadFailedSecureDatas(lines[i])
|
itemData = loadFailedSecureDatas(lines[i])
|
||||||
if len(itemData.Address) != 0 {
|
if checkIsStandard(itemData) {
|
||||||
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
|
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
|
||||||
itemData.Area, _ = geo.GetIPLocation(getLoc, itemData.Address, common.GetLang(ctx))
|
itemData.Area, _ = geo.GetIPLocation(getLoc, itemData.Address, common.GetLang(ctx))
|
||||||
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
|
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
|
||||||
@@ -443,7 +552,7 @@ func loadSSHData(ctx *gin.Context, command string, showCountFrom, showCountTo, c
|
|||||||
}
|
}
|
||||||
case strings.Contains(lines[i], "Connection closed by authenticating user"):
|
case strings.Contains(lines[i], "Connection closed by authenticating user"):
|
||||||
itemData = loadFailedAuthDatas(lines[i])
|
itemData = loadFailedAuthDatas(lines[i])
|
||||||
if len(itemData.Address) != 0 {
|
if checkIsStandard(itemData) {
|
||||||
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
|
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
|
||||||
itemData.Area, _ = geo.GetIPLocation(getLoc, itemData.Address, common.GetLang(ctx))
|
itemData.Area, _ = geo.GetIPLocation(getLoc, itemData.Address, common.GetLang(ctx))
|
||||||
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
|
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
|
||||||
@@ -453,7 +562,7 @@ func loadSSHData(ctx *gin.Context, command string, showCountFrom, showCountTo, c
|
|||||||
}
|
}
|
||||||
case strings.Contains(lines[i], "Accepted "):
|
case strings.Contains(lines[i], "Accepted "):
|
||||||
itemData = loadSuccessDatas(lines[i])
|
itemData = loadSuccessDatas(lines[i])
|
||||||
if len(itemData.Address) != 0 {
|
if checkIsStandard(itemData) {
|
||||||
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
|
if successCount+failedCount >= showCountFrom && successCount+failedCount < showCountTo {
|
||||||
itemData.Area, _ = geo.GetIPLocation(getLoc, itemData.Address, common.GetLang(ctx))
|
itemData.Area, _ = geo.GetIPLocation(getLoc, itemData.Address, common.GetLang(ctx))
|
||||||
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
|
itemData.Date = loadDate(currentYear, itemData.DateStr, nyc)
|
||||||
@@ -481,7 +590,6 @@ func loadSuccessDatas(line string) dto.SSHHistory {
|
|||||||
data.Status = constant.StatusSuccess
|
data.Status = constant.StatusSuccess
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadFailedAuthDatas(line string) dto.SSHHistory {
|
func loadFailedAuthDatas(line string) dto.SSHHistory {
|
||||||
var data dto.SSHHistory
|
var data dto.SSHHistory
|
||||||
parts := strings.Fields(line)
|
parts := strings.Fields(line)
|
||||||
@@ -531,6 +639,14 @@ func loadFailedSecureDatas(line string) dto.SSHHistory {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkIsStandard(item dto.SSHHistory) bool {
|
||||||
|
if len(item.Address) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
portItem, _ := strconv.Atoi(item.Port)
|
||||||
|
return portItem != 0
|
||||||
|
}
|
||||||
|
|
||||||
func handleGunzip(path string) error {
|
func handleGunzip(path string) error {
|
||||||
if _, err := cmd.RunDefaultWithStdoutBashCf("gunzip %s", path); err != nil {
|
if _, err := cmd.RunDefaultWithStdoutBashCf("gunzip %s", path); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -576,3 +692,19 @@ func analyzeDateStr(parts []string) (int, string) {
|
|||||||
}
|
}
|
||||||
return 2, fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2])
|
return 2, fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadEncryptioMode(content string) string {
|
||||||
|
if strings.HasPrefix(content, "ssh-rsa") {
|
||||||
|
return "rsa"
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(content, "ssh-ed25519") {
|
||||||
|
return "ed25519"
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(content, "ssh-ecdsa") {
|
||||||
|
return "ecdsa"
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(content, "ssh-dsa") {
|
||||||
|
return "dsa"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
|||||||
var (
|
var (
|
||||||
domains []model.WebsiteDomain
|
domains []model.WebsiteDomain
|
||||||
)
|
)
|
||||||
domains, _, _, err = getWebsiteDomains(create.Domains, defaultHttpPort, 0)
|
domains, _, _, err = getWebsiteDomains(create.Domains, defaultHttpPort, nginxInstall.HttpsPort, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -388,7 +388,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
|||||||
switch runtime.Type {
|
switch runtime.Type {
|
||||||
case constant.RuntimePHP:
|
case constant.RuntimePHP:
|
||||||
if runtime.Resource == constant.ResourceAppstore {
|
if runtime.Resource == constant.ResourceAppstore {
|
||||||
if !checkImageExist(nil, runtime.Image) {
|
if !checkImageLike(nil, runtime.Image) {
|
||||||
return buserr.WithName("ErrImageNotExist", runtime.Name)
|
return buserr.WithName("ErrImageNotExist", runtime.Name)
|
||||||
}
|
}
|
||||||
website.Proxy = fmt.Sprintf("127.0.0.1:%s", runtime.Port)
|
website.Proxy = fmt.Sprintf("127.0.0.1:%s", runtime.Port)
|
||||||
@@ -680,7 +680,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
|||||||
domainModels []model.WebsiteDomain
|
domainModels []model.WebsiteDomain
|
||||||
addPorts []int
|
addPorts []int
|
||||||
)
|
)
|
||||||
httpPort, _, err := getAppInstallPort(constant.AppOpenresty)
|
httpPort, httpsPort, err := getAppInstallPort(constant.AppOpenresty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -689,7 +689,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
|||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1354,7 +1354,7 @@ func (w WebsiteService) ChangePHPVersion(req request.WebsitePHPVersionReq) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
if !checkImageExist(client, oldRuntime.Image) {
|
if !checkImageLike(client, oldRuntime.Image) {
|
||||||
return buserr.WithName("ErrImageNotExist", oldRuntime.Name)
|
return buserr.WithName("ErrImageNotExist", oldRuntime.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1787,9 +1787,15 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e
|
|||||||
}
|
}
|
||||||
directives := config.GetDirectives()
|
directives := config.GetDirectives()
|
||||||
|
|
||||||
location, ok := directives[0].(*components.Location)
|
var location *components.Location
|
||||||
if !ok {
|
for _, directive := range directives {
|
||||||
err = errors.New("error")
|
if loc, ok := directive.(*components.Location); ok {
|
||||||
|
location = loc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if location == nil {
|
||||||
|
err = errors.New("invalid proxy config, no location found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
proxyConfig.ProxyPass = location.ProxyPass
|
proxyConfig.ProxyPass = location.ProxyPass
|
||||||
|
|||||||
@@ -185,6 +185,8 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
create.ID = websiteSSL.ID
|
create.ID = websiteSSL.ID
|
||||||
|
logFile, _ := os.OpenFile(path.Join(global.Dir.SSLLogDir, fmt.Sprintf("%s-ssl-%d.log", websiteSSL.PrimaryDomain, websiteSSL.ID)), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
||||||
|
logFile.Close()
|
||||||
go func() {
|
go func() {
|
||||||
if create.Provider != constant.DnsManual {
|
if create.Provider != constant.DnsManual {
|
||||||
if err = w.ObtainSSL(request.WebsiteSSLApply{
|
if err = w.ObtainSSL(request.WebsiteSSLApply{
|
||||||
@@ -442,12 +444,15 @@ func (w WebsiteSSLService) GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) Delete(ids []uint) error {
|
func (w WebsiteSSLService) Delete(ids []uint) error {
|
||||||
var names []string
|
var (
|
||||||
|
websiteSSLS []string
|
||||||
|
applySSLS []string
|
||||||
|
)
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
if websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(id)); len(websites) > 0 {
|
if websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(id)); len(websites) > 0 {
|
||||||
oldSSL, _ := websiteSSLRepo.GetFirst(repo.WithByID(id))
|
oldSSL, _ := websiteSSLRepo.GetFirst(repo.WithByID(id))
|
||||||
if oldSSL.ID > 0 {
|
if oldSSL.ID > 0 {
|
||||||
names = append(names, oldSSL.PrimaryDomain)
|
websiteSSLS = append(websiteSSLS, oldSSL.PrimaryDomain)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -463,23 +468,36 @@ func (w WebsiteSSLService) Delete(ids []uint) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if websiteSSL.Status == constant.SSLApply {
|
||||||
|
applySSLS = append(applySSLS, websiteSSL.PrimaryDomain)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if websiteSSL.Provider != constant.Manual && websiteSSL.Provider != constant.SelfSigned {
|
if websiteSSL.Provider != constant.Manual && websiteSSL.Provider != constant.SelfSigned {
|
||||||
acmeAccount, err := websiteAcmeRepo.GetFirst(repo.WithByID(websiteSSL.AcmeAccountID))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
client, err := ssl.NewAcmeClient(acmeAccount, getSystemProxy(acmeAccount.UseProxy))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go func() {
|
go func() {
|
||||||
_ = client.RevokeSSL([]byte(websiteSSL.Pem))
|
acmeAccount, err := websiteAcmeRepo.GetFirst(repo.WithByID(websiteSSL.AcmeAccountID))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("Failed to get acme account for SSL revoke, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client, err := ssl.NewAcmeClient(acmeAccount, getSystemProxy(acmeAccount.UseProxy))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("Failed to create ACME client for SSL revoke, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = client.RevokeSSL([]byte(websiteSSL.Pem))
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("Failed to revoke SSL for domain %s, err: %v", websiteSSL.PrimaryDomain, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
_ = websiteSSLRepo.DeleteBy(repo.WithByID(id))
|
_ = websiteSSLRepo.DeleteBy(repo.WithByID(id))
|
||||||
}
|
}
|
||||||
if len(names) > 0 {
|
if len(websiteSSLS) > 0 {
|
||||||
return buserr.WithName("ErrSSLCannotDelete", strings.Join(names, ","))
|
return buserr.WithName("ErrSSLCannotDelete", strings.Join(websiteSSLS, ","))
|
||||||
|
}
|
||||||
|
if len(applySSLS) > 0 {
|
||||||
|
return buserr.WithName("ErrApplySSLCanNotDelete", strings.Join(applySSLS, ","))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -524,7 +542,7 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
|
|||||||
if update.OtherDomains != "" {
|
if update.OtherDomains != "" {
|
||||||
otherDomainArray := strings.Split(update.OtherDomains, "\n")
|
otherDomainArray := strings.Split(update.OtherDomains, "\n")
|
||||||
for _, domain := range otherDomainArray {
|
for _, domain := range otherDomainArray {
|
||||||
if !common.IsValidDomain(domain) {
|
if websiteSSL.Provider != constant.SelfSigned && !common.IsValidDomain(domain) {
|
||||||
return buserr.WithName("ErrDomainFormat", domain)
|
return buserr.WithName("ErrDomainFormat", domain)
|
||||||
}
|
}
|
||||||
domains = append(domains, domain)
|
domains = append(domains, domain)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -954,7 +955,7 @@ func opWebsite(website *model.Website, operate string) error {
|
|||||||
}
|
}
|
||||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||||
} else {
|
} else {
|
||||||
proxy := fmt.Sprintf("http://127.0.0.1:%s", runtime.Port)
|
proxy := fmt.Sprintf("http://%s", website.Proxy)
|
||||||
server.UpdateRootProxy([]string{proxy})
|
server.UpdateRootProxy([]string{proxy})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1030,7 +1031,7 @@ func chownRootDir(path string) error {
|
|||||||
return nil
|
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 (
|
var (
|
||||||
ports = make(map[int]struct{})
|
ports = make(map[int]struct{})
|
||||||
existPort = make(map[int]struct{})
|
existPort = make(map[int]struct{})
|
||||||
@@ -1055,7 +1056,7 @@ func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, website
|
|||||||
domainModel.Domain = strings.ToLower(domainModel.Domain)
|
domainModel.Domain = strings.ToLower(domainModel.Domain)
|
||||||
domainModel.Port = domain.Port
|
domainModel.Port = domain.Port
|
||||||
if domain.Port == 0 {
|
if domain.Port == 0 {
|
||||||
domain.Port = defaultPort
|
domain.Port = defaultHTTPPort
|
||||||
}
|
}
|
||||||
domainModel.SSL = domain.SSL
|
domainModel.SSL = domain.SSL
|
||||||
domainModel.WebsiteID = websiteID
|
domainModel.WebsiteID = websiteID
|
||||||
@@ -1076,7 +1077,7 @@ func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, website
|
|||||||
}
|
}
|
||||||
|
|
||||||
for port := range ports {
|
for port := range ports {
|
||||||
if port == defaultPort {
|
if port == defaultHTTPPort || port == defaultHTTPsPort {
|
||||||
addPorts = append(addPorts, port)
|
addPorts = append(addPorts, port)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1097,7 +1098,7 @@ func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, website
|
|||||||
err = buserr.WithMap("ErrPortExist", errMap, nil)
|
err = buserr.WithMap("ErrPortExist", errMap, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if port != 443 && common.ScanPort(port) {
|
if port != defaultHTTPsPort && common.ScanPort(port) {
|
||||||
err = buserr.WithDetail("ErrPortInUsed", port, nil)
|
err = buserr.WithDetail("ErrPortInUsed", port, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1443,3 +1444,22 @@ func hasDefaultServer(params []string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,7 +63,9 @@ const (
|
|||||||
TaskSync = "TaskSync"
|
TaskSync = "TaskSync"
|
||||||
TaskBuild = "TaskBuild"
|
TaskBuild = "TaskBuild"
|
||||||
TaskPull = "TaskPull"
|
TaskPull = "TaskPull"
|
||||||
|
TaskCommit = "TaskCommit"
|
||||||
TaskPush = "TaskPush"
|
TaskPush = "TaskPush"
|
||||||
|
TaskClean = "TaskClean"
|
||||||
TaskHandle = "TaskHandle"
|
TaskHandle = "TaskHandle"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
base:
|
base:
|
||||||
install_dir: /opt
|
install_dir: /opt
|
||||||
mode: dev
|
mode: dev
|
||||||
|
is_demo: false
|
||||||
|
|
||||||
remote_url:
|
remote_url:
|
||||||
app_repo: https://apps-assets.fit2cloud.com
|
app_repo: https://apps-assets.fit2cloud.com
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ services:
|
|||||||
- "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${PANEL_APP_PORT_HTTP}"
|
- "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${PANEL_APP_PORT_HTTP}"
|
||||||
command: [
|
command: [
|
||||||
"--stdio", "${COMMAND}",
|
"--stdio", "${COMMAND}",
|
||||||
|
"--outputTransport","${OUTPUT_TRANSPORT}",
|
||||||
"--port", "${PANEL_APP_PORT_HTTP}",
|
"--port", "${PANEL_APP_PORT_HTTP}",
|
||||||
"--baseUrl", "${BASE_URL}",
|
"--baseUrl", "${BASE_URL}",
|
||||||
"--ssePath", "${SSE_PATH}",
|
"--ssePath", "${SSE_PATH}",
|
||||||
|
"--streamableHttpPath", "${STREAMABLE_HTTP_PATH}",
|
||||||
"--messagePath", "${SSE_PATH}/messages"
|
"--messagePath", "${SSE_PATH}/messages"
|
||||||
]
|
]
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -376,5 +376,12 @@
|
|||||||
"file": "pcntl.so",
|
"file": "pcntl.so",
|
||||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||||
"installed": false
|
"installed": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sodium",
|
||||||
|
"check": "sodium",
|
||||||
|
"file": "sodium.so",
|
||||||
|
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83","84"],
|
||||||
|
"installed": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -10,3 +10,18 @@ const (
|
|||||||
AlertPushError = "PushError"
|
AlertPushError = "PushError"
|
||||||
AlertPushSuccess = "PushSuccess"
|
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"
|
AppNormal = "Normal"
|
||||||
AppTakeDown = "TakeDown"
|
AppTakeDown = "TakeDown"
|
||||||
|
|
||||||
AppOpenresty = "openresty"
|
AppOpenresty = "openresty"
|
||||||
AppMysql = "mysql"
|
AppMysql = "mysql"
|
||||||
AppMariaDB = "mariadb"
|
AppMariaDB = "mariadb"
|
||||||
AppPostgresql = "postgresql"
|
AppPostgresql = "postgresql"
|
||||||
AppRedis = "redis"
|
AppRedis = "redis"
|
||||||
AppPostgres = "postgres"
|
AppPostgres = "postgres"
|
||||||
AppMongodb = "mongodb"
|
AppMongodb = "mongodb"
|
||||||
AppMemcached = "memcached"
|
AppMemcached = "memcached"
|
||||||
|
AppMysqlCluster = "mysql-cluster"
|
||||||
|
AppPostgresqlCluster = "postgresql-cluster"
|
||||||
|
AppRedisCluster = "redis-cluster"
|
||||||
|
|
||||||
AppResourceLocal = "local"
|
AppResourceLocal = "local"
|
||||||
AppResourceRemote = "remote"
|
AppResourceRemote = "remote"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const (
|
|||||||
StatusCanceled = "Canceled"
|
StatusCanceled = "Canceled"
|
||||||
StatusDone = "Done"
|
StatusDone = "Done"
|
||||||
StatusWaiting = "Waiting"
|
StatusWaiting = "Waiting"
|
||||||
|
StatusPending = "Pending"
|
||||||
StatusSuccess = "Success"
|
StatusSuccess = "Success"
|
||||||
StatusFailed = "Failed"
|
StatusFailed = "Failed"
|
||||||
StatusUploading = "Uploading"
|
StatusUploading = "Uploading"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ var (
|
|||||||
MonitorDB *gorm.DB
|
MonitorDB *gorm.DB
|
||||||
TaskDB *gorm.DB
|
TaskDB *gorm.DB
|
||||||
CoreDB *gorm.DB
|
CoreDB *gorm.DB
|
||||||
|
AlertDB *gorm.DB
|
||||||
|
|
||||||
LOG *logrus.Logger
|
LOG *logrus.Logger
|
||||||
CONF ServerConfig
|
CONF ServerConfig
|
||||||
@@ -30,4 +31,7 @@ var (
|
|||||||
IsMaster bool
|
IsMaster bool
|
||||||
|
|
||||||
I18n *i18n.Localizer
|
I18n *i18n.Localizer
|
||||||
|
|
||||||
|
AlertBaseJobID cron.EntryID
|
||||||
|
AlertResourceJobID cron.EntryID
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-2
@@ -8,7 +8,7 @@ require (
|
|||||||
github.com/compose-spec/compose-go/v2 v2.6.4
|
github.com/compose-spec/compose-go/v2 v2.6.4
|
||||||
github.com/creack/pty v1.1.24
|
github.com/creack/pty v1.1.24
|
||||||
github.com/docker/compose/v2 v2.37.0
|
github.com/docker/compose/v2 v2.37.0
|
||||||
github.com/docker/docker v28.2.2+incompatible
|
github.com/docker/docker v28.3.3+incompatible
|
||||||
github.com/docker/go-connections v0.5.0
|
github.com/docker/go-connections v0.5.0
|
||||||
github.com/fsnotify/fsnotify v1.9.0
|
github.com/fsnotify/fsnotify v1.9.0
|
||||||
github.com/gin-gonic/gin v1.10.0
|
github.com/gin-gonic/gin v1.10.0
|
||||||
@@ -48,7 +48,7 @@ require (
|
|||||||
github.com/upyun/go-sdk v2.1.0+incompatible
|
github.com/upyun/go-sdk v2.1.0+incompatible
|
||||||
golang.org/x/crypto v0.39.0
|
golang.org/x/crypto v0.39.0
|
||||||
golang.org/x/net v0.41.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/sys v0.33.0
|
||||||
golang.org/x/text v0.26.0
|
golang.org/x/text v0.26.0
|
||||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38
|
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38
|
||||||
|
|||||||
@@ -202,6 +202,8 @@ github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBi
|
|||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
|
github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
|
||||||
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
|
||||||
|
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||||
@@ -1092,6 +1094,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.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 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
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-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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ func Init() {
|
|||||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ru.yaml")
|
_, _ = bundle.LoadMessageFileFS(fs, "lang/ru.yaml")
|
||||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
|
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
|
||||||
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
|
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
|
||||||
|
_, _ = bundle.LoadMessageFileFS(fs, "lang/tr.yaml")
|
||||||
lang := GetLanguageFromDB()
|
lang := GetLanguageFromDB()
|
||||||
global.I18n = i18n.NewLocalizer(bundle, lang)
|
global.I18n = i18n.NewLocalizer(bundle, lang)
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-3
@@ -62,7 +62,6 @@ ErrHttpReqTimeOut: 'Request timed out {{ .err }}'
|
|||||||
ErrHttpReqFailed: 'Request failed {{ .err }}'
|
ErrHttpReqFailed: 'Request failed {{ .err }}'
|
||||||
ErrNoSuchHost: 'Unable to find the requested server {{ .err }}'
|
ErrNoSuchHost: 'Unable to find the requested server {{ .err }}'
|
||||||
ErrHttpReqNotFound: 'The requested resource {{ .err }} could not be found'
|
ErrHttpReqNotFound: 'The requested resource {{ .err }} could not be found'
|
||||||
ErrImagePullTimeOut: 'Image pull timeout'
|
|
||||||
ErrContainerNotFound: '{{ .name }} container does not exist'
|
ErrContainerNotFound: '{{ .name }} container does not exist'
|
||||||
ErrContainerMsg: '{{ .name }} container is abnormal. Please check the log on the container page for details'
|
ErrContainerMsg: '{{ .name }} container is abnormal. Please check the log on the container page for details'
|
||||||
ErrAppBackup: '{{ .name }} application backup failed {{ .err }}'
|
ErrAppBackup: '{{ .name }} application backup failed {{ .err }}'
|
||||||
@@ -156,6 +155,7 @@ ExecShellSuccess: 'Script execution successful'
|
|||||||
StartUpdateSystemSSL: 'Start updating system certificate'
|
StartUpdateSystemSSL: 'Start updating system certificate'
|
||||||
UpdateSystemSSLSuccess: 'Update system certificate successfully'
|
UpdateSystemSSLSuccess: 'Update system certificate successfully'
|
||||||
ErrWildcardDomain: 'Unable to apply for wildcard domain name certificate in HTTP mode'
|
ErrWildcardDomain: 'Unable to apply for wildcard domain name certificate in HTTP mode'
|
||||||
|
ErrApplySSLCanNotDelete: "The certificate {{.name}} being applied for cannot be deleted, please try again later."
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: 'The current user already exists, please re-enter'
|
ErrUserIsExist: 'The current user already exists, please re-enter'
|
||||||
@@ -173,11 +173,16 @@ ErrObjectInUsed: 'The object is in use and cannot be deleted'
|
|||||||
ErrObjectBeDependent: 'This image depends on other images and cannot be deleted'
|
ErrObjectBeDependent: 'This image depends on other images and cannot be deleted'
|
||||||
ErrPortRules: 'Port number does not match, please re-enter!'
|
ErrPortRules: 'Port number does not match, please re-enter!'
|
||||||
ErrPgImagePull: 'Image pull timed out, please configure image acceleration or manually pull the {{ .name }} image and try again'
|
ErrPgImagePull: 'Image pull timed out, please configure image acceleration or manually pull the {{ .name }} image and try again'
|
||||||
|
PruneHelper: "This cleanup removed {{ .name }} {{ .count }} items, freeing {{ .size }} disk space"
|
||||||
|
ImageRemoveHelper: "Deleted image {{ .name }}, freeing {{ .size }} disk space"
|
||||||
|
BuildCache: "Build cache"
|
||||||
|
Volume: "Storage volume"
|
||||||
|
Network: "Network"
|
||||||
|
|
||||||
#runtime
|
#runtime
|
||||||
ErrFileNotExist: '{{ .detail }} file does not exist! Please check the integrity of the source file!'
|
ErrFileNotExist: '{{ .detail }} file does not exist! Please check the integrity of the source file!'
|
||||||
ErrImageBuildErr: 'Image build failed'
|
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'
|
ErrDelWithWebsite: 'The operating environment is already associated with a website and cannot be deleted'
|
||||||
ErrRuntimeStart: 'Startup failed'
|
ErrRuntimeStart: 'Startup failed'
|
||||||
ErrPackageJsonNotFound: 'package.json file does not exist'
|
ErrPackageJsonNotFound: 'package.json file does not exist'
|
||||||
@@ -266,6 +271,7 @@ allow: 'allow'
|
|||||||
deny: 'deny'
|
deny: 'deny'
|
||||||
OpenrestyNotFound: 'Openresty is not installed'
|
OpenrestyNotFound: 'Openresty is not installed'
|
||||||
remoteIpIsNull: "IP list is empty"
|
remoteIpIsNull: "IP list is empty"
|
||||||
|
OpenrestyVersionErr: "Openresty version is too low, please upgrade Openresty to 1.27.1.2-2-2-focal"
|
||||||
|
|
||||||
#task
|
#task
|
||||||
TaskStart: '{{ .name }} task starts [START]'
|
TaskStart: '{{ .name }} task starts [START]'
|
||||||
@@ -287,8 +293,10 @@ TaskBackup: 'Backup'
|
|||||||
TaskRecover: 'Recover'
|
TaskRecover: 'Recover'
|
||||||
TaskRollback: 'Rollback'
|
TaskRollback: 'Rollback'
|
||||||
TaskPull: 'Pull'
|
TaskPull: 'Pull'
|
||||||
|
TaskCommit: 'Commit'
|
||||||
TaskBuild: 'Build'
|
TaskBuild: 'Build'
|
||||||
TaskPush: 'Push'
|
TaskPush: 'Push'
|
||||||
|
TaskClean: "Cleanup"
|
||||||
TaskHandle: 'Execute'
|
TaskHandle: 'Execute'
|
||||||
Website: 'Website'
|
Website: 'Website'
|
||||||
App: 'Application'
|
App: 'Application'
|
||||||
@@ -423,4 +431,18 @@ ErrAlertSync: 'Alarm information synchronization error, please check and try aga
|
|||||||
ErrAlertRemote: 'Alarm message remote error, please check and try again!'
|
ErrAlertRemote: 'Alarm message remote error, please check and try again!'
|
||||||
|
|
||||||
#task - runtime
|
#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."
|
||||||
+26
-4
@@ -62,7 +62,6 @@ ErrHttpReqTimeOut: 'リクエストがタイムアウトしました {{ .err }}'
|
|||||||
ErrHttpReqFailed: 'リクエストが失敗しました {{ .err }}'
|
ErrHttpReqFailed: 'リクエストが失敗しました {{ .err }}'
|
||||||
ErrNoSuchHost: '要求されたサーバー {{ .err }} が見つかりません'
|
ErrNoSuchHost: '要求されたサーバー {{ .err }} が見つかりません'
|
||||||
ErrHttpReqNotFound: '要求されたリソース {{ .err }} が見つかりませんでした'
|
ErrHttpReqNotFound: '要求されたリソース {{ .err }} が見つかりませんでした'
|
||||||
ErrImagePullTimeOut: 'イメージ プル タイムアウト'
|
|
||||||
ErrContainerNotFound: '{{ .name }} コンテナが存在しません'
|
ErrContainerNotFound: '{{ .name }} コンテナが存在しません'
|
||||||
ErrContainerMsg: '{{ .name }} コンテナが異常です。詳細についてはコンテナページのログを確認してください。'
|
ErrContainerMsg: '{{ .name }} コンテナが異常です。詳細についてはコンテナページのログを確認してください。'
|
||||||
ErrAppBackup: '{{ .name }} アプリケーションのバックアップに失敗しました。エラー {{ .err }}'
|
ErrAppBackup: '{{ .name }} アプリケーションのバックアップに失敗しました。エラー {{ .err }}'
|
||||||
@@ -156,6 +155,7 @@ ExecShellSuccess: 'スクリプトの実行が成功しました'
|
|||||||
StartUpdateSystemSSL: 'システム証明書の更新を開始します'
|
StartUpdateSystemSSL: 'システム証明書の更新を開始します'
|
||||||
UpdateSystemSSLSuccess: 'システム証明書を正常に更新しました'
|
UpdateSystemSSLSuccess: 'システム証明書を正常に更新しました'
|
||||||
ErrWildcardDomain: 'HTTP モードでワイルドカード ドメイン名証明書を申請できません'
|
ErrWildcardDomain: 'HTTP モードでワイルドカード ドメイン名証明書を申請できません'
|
||||||
|
ErrApplySSLCanNotDelete: "申請中の証明書 {{.name}} は削除できません。しばらくしてからもう一度お試しください。"
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: '現在のユーザーは既に存在します。再入力してください'
|
ErrUserIsExist: '現在のユーザーは既に存在します。再入力してください'
|
||||||
@@ -173,11 +173,16 @@ ErrObjectInUsed: 'オブジェクトは使用中のため削除できません'
|
|||||||
ErrObjectBeDependent: 'このイメージは他のイメージに依存しているため、削除できません'
|
ErrObjectBeDependent: 'このイメージは他のイメージに依存しているため、削除できません'
|
||||||
ErrPortRules: 'ポート番号が一致しません。再入力してください。'
|
ErrPortRules: 'ポート番号が一致しません。再入力してください。'
|
||||||
ErrPgImagePull: 'イメージのプルがタイムアウトしました。イメージのアクセラレーションを設定するか、{{ .name }} イメージを手動でプルして再試行してください'
|
ErrPgImagePull: 'イメージのプルがタイムアウトしました。イメージのアクセラレーションを設定するか、{{ .name }} イメージを手動でプルして再試行してください'
|
||||||
|
PruneHelper: "今回のクリーンアップで{{ .name }} {{ .count }}個を削除し、{{ .size }}のディスク領域を解放しました"
|
||||||
|
ImageRemoveHelper: "イメージ{{ .name }}を削除し、{{ .size }}のディスク領域を解放しました"
|
||||||
|
BuildCache: "ビルドキャッシュ"
|
||||||
|
Volume: "ストレージボリューム"
|
||||||
|
Network: "ネットワーク"
|
||||||
|
|
||||||
#runtime
|
#runtime
|
||||||
ErrFileNotExist: '{{ .detail }} ファイルが存在しません。ソース ファイルの整合性を確認してください。'
|
ErrFileNotExist: '{{ .detail }} ファイルが存在しません。ソース ファイルの整合性を確認してください。'
|
||||||
ErrImageBuildErr: 'イメージのビルドに失敗しました'
|
ErrImageBuildErr: 'イメージのビルドに失敗しました'
|
||||||
ErrImageExist: '画像がすでに存在します!'
|
ErrImageExist: "イメージはすでに存在します!イメージ名を変更してください。"
|
||||||
ErrDelWithWebsite: 'オペレーティング環境は既に Web サイトに関連付けられているため、削除できません'
|
ErrDelWithWebsite: 'オペレーティング環境は既に Web サイトに関連付けられているため、削除できません'
|
||||||
ErrRuntimeStart: '起動に失敗しました'
|
ErrRuntimeStart: '起動に失敗しました'
|
||||||
ErrPackageJsonNotFound: 'package.json ファイルが存在しません'
|
ErrPackageJsonNotFound: 'package.json ファイルが存在しません'
|
||||||
@@ -266,6 +271,7 @@ allow: '許可'
|
|||||||
deny: '拒否'
|
deny: '拒否'
|
||||||
OpenrestyNotFound: 'Openresty がインストールされていません'
|
OpenrestyNotFound: 'Openresty がインストールされていません'
|
||||||
remoteIpIsNull: "IPリストが空です"
|
remoteIpIsNull: "IPリストが空です"
|
||||||
|
OpenrestyVersionErr: "Openrestyのバージョンが低すぎます。Openrestyを1.27.1.2-2-2-focalにアップグレードしてください"
|
||||||
|
|
||||||
#task
|
#task
|
||||||
TaskStart: '{{ .name }} タスクが開始されました [START]'
|
TaskStart: '{{ .name }} タスクが開始されました [START]'
|
||||||
@@ -287,8 +293,10 @@ TaskBackup: 'バックアップ'
|
|||||||
TaskRecover: '回復'
|
TaskRecover: '回復'
|
||||||
TaskRollback: 'ロールバック'
|
TaskRollback: 'ロールバック'
|
||||||
TaskPull: 'プル'
|
TaskPull: 'プル'
|
||||||
|
TaskCommit: 'コミット'
|
||||||
TaskBuild: 'ビルド'
|
TaskBuild: 'ビルド'
|
||||||
TaskPush: 'プッシュ'
|
TaskPush: 'プッシュ'
|
||||||
|
TaskClean: "クリーンアップ"
|
||||||
TaskHandle: '実行'
|
TaskHandle: '実行'
|
||||||
Website: 'ウェブサイト'
|
Website: 'ウェブサイト'
|
||||||
App: 'アプリケーション'
|
App: 'アプリケーション'
|
||||||
@@ -325,7 +333,7 @@ CustomAppstore: 'カスタム アプリケーション ウェアハウス'
|
|||||||
OllamaModelPull: 'Ollama モデル {{ .name }} をプルします'
|
OllamaModelPull: 'Ollama モデル {{ .name }} をプルします'
|
||||||
OllamaModelSize: "Ollama モデル {{ .name }} のサイズを取得します"
|
OllamaModelSize: "Ollama モデル {{ .name }} のサイズを取得します"
|
||||||
|
|
||||||
#task - snapshot
|
#task - snapshot
|
||||||
Snapshot: 'スナップショット'
|
Snapshot: 'スナップショット'
|
||||||
SnapDBInfo: '1Panel データベース情報を書き込む'
|
SnapDBInfo: '1Panel データベース情報を書き込む'
|
||||||
SnapCopy: 'ファイルとディレクトリ {{ .name }} をコピーします'
|
SnapCopy: 'ファイルとディレクトリ {{ .name }} をコピーします'
|
||||||
@@ -423,4 +431,18 @@ ErrAlertSync: 'アラーム情報の同期エラーです。確認してもう
|
|||||||
ErrAlertRemote: 'アラーム メッセージのリモート エラーです。確認してもう一度お試しください。'
|
ErrAlertRemote: 'アラーム メッセージのリモート エラーです。確認してもう一度お試しください。'
|
||||||
|
|
||||||
#task - runtime
|
#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 }} 日後に期限切れとなります。詳細はパネルでご確認ください。"
|
||||||
+25
-3
@@ -62,7 +62,6 @@ ErrHttpReqTimeOut: '요청 시간이 초과되었습니다 {{ .err }}'
|
|||||||
ErrHttpReqFailed: '요청이 실패했습니다 {{ .err }}'
|
ErrHttpReqFailed: '요청이 실패했습니다 {{ .err }}'
|
||||||
ErrNoSuchHost: '요청한 서버 {{ .err }}을 찾을 수 없습니다'
|
ErrNoSuchHost: '요청한 서버 {{ .err }}을 찾을 수 없습니다'
|
||||||
ErrHttpReqNotFound: '요청한 리소스 {{ .err }}을 찾을 수 없습니다.'
|
ErrHttpReqNotFound: '요청한 리소스 {{ .err }}을 찾을 수 없습니다.'
|
||||||
ErrImagePullTimeOut: '이미지 풀링 시간 초과'
|
|
||||||
ErrContainerNotFound: '{{ .name }} 컨테이너가 존재하지 않습니다'
|
ErrContainerNotFound: '{{ .name }} 컨테이너가 존재하지 않습니다'
|
||||||
ErrContainerMsg: '{{ .name }} 컨테이너가 비정상입니다. 자세한 내용은 컨테이너 페이지의 로그를 확인하세요.'
|
ErrContainerMsg: '{{ .name }} 컨테이너가 비정상입니다. 자세한 내용은 컨테이너 페이지의 로그를 확인하세요.'
|
||||||
ErrAppBackup: '{{ .name }} 애플리케이션 백업에 실패했습니다 {{ .err }}'
|
ErrAppBackup: '{{ .name }} 애플리케이션 백업에 실패했습니다 {{ .err }}'
|
||||||
@@ -156,6 +155,7 @@ ExecShellSuccess: '스크립트 실행 성공'
|
|||||||
StartUpdateSystemSSL: '시스템 인증서 업데이트 시작'
|
StartUpdateSystemSSL: '시스템 인증서 업데이트 시작'
|
||||||
UpdateSystemSSLSuccess: '시스템 인증서 업데이트가 성공적으로 완료되었습니다.'
|
UpdateSystemSSLSuccess: '시스템 인증서 업데이트가 성공적으로 완료되었습니다.'
|
||||||
ErrWildcardDomain: 'HTTP 모드에서 와일드카드 도메인 이름 인증서를 신청할 수 없습니다'
|
ErrWildcardDomain: 'HTTP 모드에서 와일드카드 도메인 이름 인증서를 신청할 수 없습니다'
|
||||||
|
ErrApplySSLCanNotDelete: "신청 중인 인증서 {{.name}}는 삭제할 수 없습니다. 나중에 다시 시도해 주세요."
|
||||||
|
|
||||||
#마이SQL
|
#마이SQL
|
||||||
ErrUserIsExist: '현재 사용자가 이미 존재합니다. 다시 입력하세요'
|
ErrUserIsExist: '현재 사용자가 이미 존재합니다. 다시 입력하세요'
|
||||||
@@ -173,11 +173,16 @@ ErrObjectInUsed: '개체가 사용 중이므로 삭제할 수 없습니다'
|
|||||||
ErrObjectBeDependent: '이 이미지는 다른 이미지에 의존하므로 삭제할 수 없습니다'
|
ErrObjectBeDependent: '이 이미지는 다른 이미지에 의존하므로 삭제할 수 없습니다'
|
||||||
ErrPortRules: '포트 번호가 일치하지 않습니다. 다시 입력하세요!'
|
ErrPortRules: '포트 번호가 일치하지 않습니다. 다시 입력하세요!'
|
||||||
ErrPgImagePull: '이미지 풀링 시간이 초과되었습니다. 이미지 가속을 구성하거나 {{ .name }} 이미지를 수동으로 풀링한 다음 다시 시도하세요.'
|
ErrPgImagePull: '이미지 풀링 시간이 초과되었습니다. 이미지 가속을 구성하거나 {{ .name }} 이미지를 수동으로 풀링한 다음 다시 시도하세요.'
|
||||||
|
PruneHelper: "이번 정리에서 {{ .name }} {{ .count }}개를 제거하여 {{ .size }} 디스크 공간을 확보했습니다"
|
||||||
|
ImageRemoveHelper: "이미지 {{ .name }} 삭제, {{ .size }} 디스크 공간 확보"
|
||||||
|
BuildCache: "빌드 캐시"
|
||||||
|
Volume: "스토리지 볼륨"
|
||||||
|
Network: "네트워크"
|
||||||
|
|
||||||
#실행 시간
|
#실행 시간
|
||||||
ErrFileNotExist: '{{ .detail }} 파일이 존재하지 않습니다! 소스 파일의 무결성을 확인하세요!'
|
ErrFileNotExist: '{{ .detail }} 파일이 존재하지 않습니다! 소스 파일의 무결성을 확인하세요!'
|
||||||
ErrImageBuildErr: '이미지 빌드 실패'
|
ErrImageBuildErr: '이미지 빌드 실패'
|
||||||
ErrImageExist: '이미지가 이미 존재합니다!'
|
ErrImageExist: "이미지가 이미 존재합니다! 이미지 이름을 수정하세요."
|
||||||
ErrDelWithWebsite: '운영 환경이 이미 웹사이트와 연결되어 있어 삭제할 수 없습니다'
|
ErrDelWithWebsite: '운영 환경이 이미 웹사이트와 연결되어 있어 삭제할 수 없습니다'
|
||||||
ErrRuntimeStart: '시작 실패'
|
ErrRuntimeStart: '시작 실패'
|
||||||
ErrPackageJsonNotFound: 'package.json 파일이 존재하지 않습니다'
|
ErrPackageJsonNotFound: 'package.json 파일이 존재하지 않습니다'
|
||||||
@@ -266,6 +271,7 @@ allow: '허용하다'
|
|||||||
deny: '거부하다'
|
deny: '거부하다'
|
||||||
OpenrestyNotFound: 'Openresty가 설치되지 않았습니다'
|
OpenrestyNotFound: 'Openresty가 설치되지 않았습니다'
|
||||||
remoteIpIsNull: "IP 목록이 비어 있습니다"
|
remoteIpIsNull: "IP 목록이 비어 있습니다"
|
||||||
|
OpenrestyVersionErr: "Openresty 버전이 너무 낮습니다. Openresty를 1.27.1.2-2-2-focal로 업그레이드하세요"
|
||||||
|
|
||||||
#일
|
#일
|
||||||
TaskStart: '[START] {{ .name }} 작업이 시작됩니다.'
|
TaskStart: '[START] {{ .name }} 작업이 시작됩니다.'
|
||||||
@@ -287,8 +293,10 @@ TaskBackup: '백업'
|
|||||||
TaskRecover: '복구'
|
TaskRecover: '복구'
|
||||||
TaskRollback: '롤백'
|
TaskRollback: '롤백'
|
||||||
TaskPull: '당기기'
|
TaskPull: '당기기'
|
||||||
|
TaskCommit: '커밋'
|
||||||
TaskBuild: '빌드'
|
TaskBuild: '빌드'
|
||||||
TaskPush: '푸시'
|
TaskPush: '푸시'
|
||||||
|
TaskClean: "정리"
|
||||||
TaskHandle: '실행'
|
TaskHandle: '실행'
|
||||||
Website: '웹사이트'
|
Website: '웹사이트'
|
||||||
App: '애플리케이션'
|
App: '애플리케이션'
|
||||||
@@ -423,4 +431,18 @@ ErrAlertSync: '알람 정보 동기화 오류입니다. 확인하고 다시 시
|
|||||||
ErrAlertRemote: '알람 메시지 원격 오류, 확인하고 다시 시도하세요!'
|
ErrAlertRemote: '알람 메시지 원격 오류, 확인하고 다시 시도하세요!'
|
||||||
|
|
||||||
#task - runtime
|
#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 }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||||
+25
-3
@@ -62,7 +62,6 @@ ErrHttpReqTimeOut: 'Permintaan tamat masa {{ .err }}'
|
|||||||
ErrHttpReqFailed: 'Permintaan gagal {{ .err }}'
|
ErrHttpReqFailed: 'Permintaan gagal {{ .err }}'
|
||||||
ErrNoSuchHost: 'Tidak dapat mencari pelayan yang diminta {{ .err }}'
|
ErrNoSuchHost: 'Tidak dapat mencari pelayan yang diminta {{ .err }}'
|
||||||
ErrHttpReqNotFound: 'Sumber yang diminta {{ .err }} tidak dapat ditemui'
|
ErrHttpReqNotFound: 'Sumber yang diminta {{ .err }} tidak dapat ditemui'
|
||||||
ErrImagePullTimeOut: 'Tamat masa tarik imej'
|
|
||||||
ErrContainerNotFound: 'Bekas {{ .name }} tidak wujud'
|
ErrContainerNotFound: 'Bekas {{ .name }} tidak wujud'
|
||||||
ErrContainerMsg: Bekas '{{ .name }} adalah tidak normal. Sila semak log pada halaman kontena untuk butiran'
|
ErrContainerMsg: Bekas '{{ .name }} adalah tidak normal. Sila semak log pada halaman kontena untuk butiran'
|
||||||
ErrAppBackup: '{{ .name }} sandaran aplikasi gagal {{ .err }}'
|
ErrAppBackup: '{{ .name }} sandaran aplikasi gagal {{ .err }}'
|
||||||
@@ -155,6 +154,7 @@ ExecShellSuccess: 'Pelaksanaan skrip berjaya'
|
|||||||
StartUpdateSystemSSL: 'Mula mengemas kini sijil sistem'
|
StartUpdateSystemSSL: 'Mula mengemas kini sijil sistem'
|
||||||
UpdateSystemSSLSuccess: 'Berjaya kemas kini sijil sistem'
|
UpdateSystemSSLSuccess: 'Berjaya kemas kini sijil sistem'
|
||||||
ErrWildcardDomain: 'Tidak dapat memohon sijil nama domain kad bebas dalam mod HTTP'
|
ErrWildcardDomain: 'Tidak dapat memohon sijil nama domain kad bebas dalam mod HTTP'
|
||||||
|
ErrApplySSLCanNotDelete: "Sertifikat {{.name}} yang sedang diajukan tidak dapat dihapus, sila cuba lagi kemudian."
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: 'Pengguna semasa sudah wujud, sila masukkan semula'
|
ErrUserIsExist: 'Pengguna semasa sudah wujud, sila masukkan semula'
|
||||||
@@ -172,11 +172,16 @@ ErrObjectInUsed: 'Objek sedang digunakan dan tidak boleh dipadamkan'
|
|||||||
ErrObjectBeDependent: 'Imej ini bergantung pada imej lain dan tidak boleh dipadamkan'
|
ErrObjectBeDependent: 'Imej ini bergantung pada imej lain dan tidak boleh dipadamkan'
|
||||||
ErrPortRules: 'Nombor port tidak sepadan, sila masukkan semula!'
|
ErrPortRules: 'Nombor port tidak sepadan, sila masukkan semula!'
|
||||||
ErrPgImagePull: 'Tarikh imej tamat masa, sila konfigurasikan pecutan imej atau tarik imej {{ .name }} secara manual dan cuba lagi'
|
ErrPgImagePull: 'Tarikh imej tamat masa, sila konfigurasikan pecutan imej atau tarik imej {{ .name }} secara manual dan cuba lagi'
|
||||||
|
PruneHelper: "Pembersihan ini membuang {{ .name }} {{ .count }} item, membebaskan {{ .size }} ruang cakera"
|
||||||
|
ImageRemoveHelper: "Padam imej {{ .name }}, membebaskan {{ .size }} ruang cakera"
|
||||||
|
BuildCache: "Cache binaan"
|
||||||
|
Volume: "Jilid storan"
|
||||||
|
Network: "Rangkaian"
|
||||||
|
|
||||||
#masa berjalan
|
#masa berjalan
|
||||||
ErrFileNotExist: 'Fail {{ .detail }} tidak wujud! Sila semak integriti fail sumber!'
|
ErrFileNotExist: 'Fail {{ .detail }} tidak wujud! Sila semak integriti fail sumber!'
|
||||||
ErrImageBuildErr: 'Pembinaan imej gagal'
|
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'
|
ErrDelWithWebsite: 'Persekitaran pengendalian sudah dikaitkan dengan tapak web dan tidak boleh dipadamkan'
|
||||||
ErrRuntimeStart: 'Permulaan gagal'
|
ErrRuntimeStart: 'Permulaan gagal'
|
||||||
ErrPackageJsonNotFound: 'fail package.json tidak wujud'
|
ErrPackageJsonNotFound: 'fail package.json tidak wujud'
|
||||||
@@ -265,6 +270,7 @@ allow: 'membenarkan'
|
|||||||
deny: 'menafikan'
|
deny: 'menafikan'
|
||||||
OpenrestyNotFound: 'Openresty tidak dipasang'
|
OpenrestyNotFound: 'Openresty tidak dipasang'
|
||||||
remoteIpIsNull: "Senarai IP kosong"
|
remoteIpIsNull: "Senarai IP kosong"
|
||||||
|
OpenrestyVersionErr: "Versi Openresty terlalu rendah, sila naik taraf Openresty ke 1.27.1.2-2-2-focal"
|
||||||
|
|
||||||
#tugas
|
#tugas
|
||||||
TaskStart: '{{ .name }} Task mula [MULA]'
|
TaskStart: '{{ .name }} Task mula [MULA]'
|
||||||
@@ -286,8 +292,10 @@ TaskBackup: 'Sandaran'
|
|||||||
TaskRecover: 'Pulihkan'
|
TaskRecover: 'Pulihkan'
|
||||||
TaskRollback: 'Rollback'
|
TaskRollback: 'Rollback'
|
||||||
TaskPull: 'Tarik'
|
TaskPull: 'Tarik'
|
||||||
|
TaskCommit: 'Komit'
|
||||||
TaskBuild: 'Bina'
|
TaskBuild: 'Bina'
|
||||||
TaskPush: 'Tolak'
|
TaskPush: 'Tolak'
|
||||||
|
TaskClean: "Pembersihan"
|
||||||
TaskHandle: 'Laksanakan'
|
TaskHandle: 'Laksanakan'
|
||||||
Website: 'Laman web'
|
Website: 'Laman web'
|
||||||
App: 'Aplikasi'
|
App: 'Aplikasi'
|
||||||
@@ -422,4 +430,18 @@ ErrAlertSync: 'Ralat penyegerakan maklumat penggera, sila semak dan cuba lagi!'
|
|||||||
ErrAlertRemote: 'Ralat jauh mesej penggera, sila semak dan cuba lagi!'
|
ErrAlertRemote: 'Ralat jauh mesej penggera, sila semak dan cuba lagi!'
|
||||||
|
|
||||||
#task - runtime
|
#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."
|
||||||
@@ -62,7 +62,6 @@ ErrHttpReqTimeOut: 'Tempo limite da solicitação esgotado {{ .err }}'
|
|||||||
ErrHttpReqFailed: 'Falha na solicitação {{ .err }}'
|
ErrHttpReqFailed: 'Falha na solicitação {{ .err }}'
|
||||||
ErrNoSuchHost: 'Não foi possível encontrar o servidor solicitado {{ .err }}'
|
ErrNoSuchHost: 'Não foi possível encontrar o servidor solicitado {{ .err }}'
|
||||||
ErrHttpReqNotFound: 'O recurso solicitado {{ .err }} não pôde ser encontrado'
|
ErrHttpReqNotFound: 'O recurso solicitado {{ .err }} não pôde ser encontrado'
|
||||||
ErrImagePullTimeOut: 'Tempo limite de extração de imagem'
|
|
||||||
ErrContainerNotFound: '{{ .name }} container não existe'
|
ErrContainerNotFound: '{{ .name }} container não existe'
|
||||||
ErrContainerMsg: 'O contêiner {{ .name }} está anormal. Por favor, verifique o log na página do contêiner para obter detalhes.'
|
ErrContainerMsg: 'O contêiner {{ .name }} está anormal. Por favor, verifique o log na página do contêiner para obter detalhes.'
|
||||||
ErrAppBackup: '{{ .name }} falha no backup do aplicativo {{ .err }}'
|
ErrAppBackup: '{{ .name }} falha no backup do aplicativo {{ .err }}'
|
||||||
@@ -156,6 +155,7 @@ ExecShellSuccess: 'Execução do script bem-sucedida'
|
|||||||
StartUpdateSystemSSL: 'Iniciar atualização do certificado do sistema'
|
StartUpdateSystemSSL: 'Iniciar atualização do certificado do sistema'
|
||||||
UpdateSystemSSLSuccess: 'Atualizar certificado do sistema com sucesso'
|
UpdateSystemSSLSuccess: 'Atualizar certificado do sistema com sucesso'
|
||||||
ErrWildcardDomain: 'Não é possível solicitar certificado de nome de domínio curinga no modo HTTP'
|
ErrWildcardDomain: 'Não é possível solicitar certificado de nome de domínio curinga no modo HTTP'
|
||||||
|
ErrApplySSLCanNotDelete: "O certificado {{.name}} que está sendo solicitado não pode ser excluído, tente novamente mais tarde."
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: 'O usuário atual já existe, digite novamente'
|
ErrUserIsExist: 'O usuário atual já existe, digite novamente'
|
||||||
@@ -173,11 +173,16 @@ ErrObjectInUsed: 'O objeto está em uso e não pode ser excluído'
|
|||||||
ErrObjectBeDependent: 'Esta imagem depende de outras imagens e não pode ser excluída'
|
ErrObjectBeDependent: 'Esta imagem depende de outras imagens e não pode ser excluída'
|
||||||
ErrPortRules: 'O número da porta não corresponde, digite novamente!'
|
ErrPortRules: 'O número da porta não corresponde, digite novamente!'
|
||||||
ErrPgImagePull: 'Tempo limite para extração de imagem. Configure a aceleração de imagem ou extraia manualmente a imagem {{ .name }} e tente novamente'
|
ErrPgImagePull: 'Tempo limite para extração de imagem. Configure a aceleração de imagem ou extraia manualmente a imagem {{ .name }} e tente novamente'
|
||||||
|
PruneHelper: "Esta limpeza removeu {{ .name }} {{ .count }} itens, liberando {{ .size }} de espaço em disco"
|
||||||
|
ImageRemoveHelper: "Excluída a imagem {{ .name }}, liberando {{ .size }} de espaço em disco"
|
||||||
|
BuildCache: "Cache de construção"
|
||||||
|
Volume: "Volume de armazenamento"
|
||||||
|
Network: "Rede"
|
||||||
|
|
||||||
#tempo de execução
|
#tempo de execução
|
||||||
ErrFileNotExist: 'O arquivo {{ .detail }} não existe! Verifique a integridade do arquivo de origem!'
|
ErrFileNotExist: 'O arquivo {{ .detail }} não existe! Verifique a integridade do arquivo de origem!'
|
||||||
ErrImageBuildErr: 'Falha na criação da imagem'
|
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'
|
ErrDelWithWebsite: 'O ambiente operacional já está associado a um site e não pode ser excluído'
|
||||||
ErrRuntimeStart: 'Falha na inicialização'
|
ErrRuntimeStart: 'Falha na inicialização'
|
||||||
ErrPackageJsonNotFound: 'o arquivo package.json não existe'
|
ErrPackageJsonNotFound: 'o arquivo package.json não existe'
|
||||||
@@ -266,6 +271,7 @@ allow: 'permitir'
|
|||||||
deny: 'negar'
|
deny: 'negar'
|
||||||
OpenrestyNotFound: 'Openresty não está instalado'
|
OpenrestyNotFound: 'Openresty não está instalado'
|
||||||
remoteIpIsNull: "A lista de IP está vazia"
|
remoteIpIsNull: "A lista de IP está vazia"
|
||||||
|
OpenrestyVersionErr: "A versão do Openresty é muito baixa, por favor atualize o Openresty para 1.27.1.2-2-2-focal"
|
||||||
|
|
||||||
#tarefa
|
#tarefa
|
||||||
TaskStart: '{{ .name }} A tarefa inicia [START]'
|
TaskStart: '{{ .name }} A tarefa inicia [START]'
|
||||||
@@ -287,8 +293,10 @@ Backup de Tarefa: 'Backup'
|
|||||||
TaskRecover: 'Recuperar'
|
TaskRecover: 'Recuperar'
|
||||||
TaskRollback: 'Reverter'
|
TaskRollback: 'Reverter'
|
||||||
TaskPull: 'Puxar'
|
TaskPull: 'Puxar'
|
||||||
|
TaskCommit: 'Commit'
|
||||||
TaskBuild: 'Construir'
|
TaskBuild: 'Construir'
|
||||||
TaskPush: 'Empurrar'
|
TaskPush: 'Empurrar'
|
||||||
|
TaskClean: "Limpeza"
|
||||||
TaskHandle: 'Executar'
|
TaskHandle: 'Executar'
|
||||||
Website: 'Site'
|
Website: 'Site'
|
||||||
App: 'Aplicativo'
|
App: 'Aplicativo'
|
||||||
@@ -423,4 +431,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!'
|
ErrAlertRemote: 'Erro remoto na mensagem de alarme, verifique e tente novamente!'
|
||||||
|
|
||||||
#task - runtime
|
#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."
|
||||||
+25
-3
@@ -62,7 +62,6 @@ ErrHttpReqTimeOut: 'Истекло время ожидания запроса {{
|
|||||||
ErrHttpReqFailed: 'Запрос не выполнен {{ .err }}'
|
ErrHttpReqFailed: 'Запрос не выполнен {{ .err }}'
|
||||||
ErrNoSuchHost: 'Не удалось найти запрошенный сервер {{ .err }}'
|
ErrNoSuchHost: 'Не удалось найти запрошенный сервер {{ .err }}'
|
||||||
ErrHttpReqNotFound: 'Запрошенный ресурс {{ .err }} не найден'
|
ErrHttpReqNotFound: 'Запрошенный ресурс {{ .err }} не найден'
|
||||||
ErrImagePullTimeOut: 'Истекло время ожидания извлечения изображения'
|
|
||||||
ErrContainerNotFound: 'Контейнер {{ .name }} не существует'
|
ErrContainerNotFound: 'Контейнер {{ .name }} не существует'
|
||||||
ErrContainerMsg: 'Контейнер {{ .name }} ненормален. Подробности смотрите в журнале на странице контейнера.'
|
ErrContainerMsg: 'Контейнер {{ .name }} ненормален. Подробности смотрите в журнале на странице контейнера.'
|
||||||
ErrAppBackup: '{{ .name }} резервное копирование приложения не удалось {{ .err }}'
|
ErrAppBackup: '{{ .name }} резервное копирование приложения не удалось {{ .err }}'
|
||||||
@@ -156,6 +155,7 @@ ExecShellSuccess: 'Скрипт выполнен успешно'
|
|||||||
StartUpdateSystemSSL: 'Начать обновление системного сертификата'
|
StartUpdateSystemSSL: 'Начать обновление системного сертификата'
|
||||||
UpdateSystemSSLSuccess: 'Сертификат системы обновлен успешно'
|
UpdateSystemSSLSuccess: 'Сертификат системы обновлен успешно'
|
||||||
ErrWildcardDomain: 'Невозможно подать заявку на получение подстановочного сертификата доменного имени в режиме HTTP'
|
ErrWildcardDomain: 'Невозможно подать заявку на получение подстановочного сертификата доменного имени в режиме HTTP'
|
||||||
|
ErrApplySSLCanNotDelete: "Нельзя удалить сертификат {{.name}}, который находится в процессе выпуска. Пожалуйста, попробуйте позже."
|
||||||
|
|
||||||
#mysql
|
#mysql
|
||||||
ErrUserIsExist: 'Текущий пользователь уже существует, пожалуйста, введите еще раз'
|
ErrUserIsExist: 'Текущий пользователь уже существует, пожалуйста, введите еще раз'
|
||||||
@@ -173,11 +173,16 @@ ErrObjectInUsed: 'Объект используется и не может бы
|
|||||||
ErrObjectBeDependent: 'Это изображение зависит от других изображений и не может быть удалено'
|
ErrObjectBeDependent: 'Это изображение зависит от других изображений и не может быть удалено'
|
||||||
ErrPortRules: 'Номер порта не совпадает, введите заново!'
|
ErrPortRules: 'Номер порта не совпадает, введите заново!'
|
||||||
ErrPgImagePull: 'Время извлечения изображения истекло. Настройте ускорение изображения или вручную извлеките изображение {{ .name }} и повторите попытку'
|
ErrPgImagePull: 'Время извлечения изображения истекло. Настройте ускорение изображения или вручную извлеките изображение {{ .name }} и повторите попытку'
|
||||||
|
PruneHelper: "Очистка удалила {{ .name }} в количестве {{ .count }}, освободив {{ .size }} дискового пространства"
|
||||||
|
ImageRemoveHelper: "Удалён образ {{ .name }}, освобождено {{ .size }} дискового пространства"
|
||||||
|
BuildCache: "Кэш сборки"
|
||||||
|
Volume: "Том хранилища"
|
||||||
|
Network: "Сеть"
|
||||||
|
|
||||||
#время выполнения
|
#время выполнения
|
||||||
ErrFileNotExist: 'Файл {{ .detail }} не существует! Проверьте целостность исходного файла!'
|
ErrFileNotExist: 'Файл {{ .detail }} не существует! Проверьте целостность исходного файла!'
|
||||||
ErrImageBuildErr: 'Сборка образа не удалась'
|
ErrImageBuildErr: 'Сборка образа не удалась'
|
||||||
ErrImageExist: 'Изображение уже существует!'
|
ErrImageExist: "Изображение уже существует! Пожалуйста, измените имя изображения."
|
||||||
ErrDelWithWebsite: 'Операционная среда уже связана с веб-сайтом и не может быть удалена'
|
ErrDelWithWebsite: 'Операционная среда уже связана с веб-сайтом и не может быть удалена'
|
||||||
ErrRuntimeStart: 'Запуск не удался'
|
ErrRuntimeStart: 'Запуск не удался'
|
||||||
ErrPackageJsonNotFound: 'файл package.json не существует'
|
ErrPackageJsonNotFound: 'файл package.json не существует'
|
||||||
@@ -266,6 +271,7 @@ allow: 'разрешить'
|
|||||||
deny: 'отрицать'
|
deny: 'отрицать'
|
||||||
OpenrestyNotFound: 'Openresty не установлен'
|
OpenrestyNotFound: 'Openresty не установлен'
|
||||||
remoteIpIsNull: "Список IP пуст"
|
remoteIpIsNull: "Список IP пуст"
|
||||||
|
OpenrestyVersionErr: "Версия Openresty слишком низкая, пожалуйста, обновите Openresty до 1.27.1.2-2-2-focal"
|
||||||
|
|
||||||
#задача
|
#задача
|
||||||
TaskStart: '{{ .name }} Задача начинается [START]'
|
TaskStart: '{{ .name }} Задача начинается [START]'
|
||||||
@@ -287,8 +293,10 @@ TaskBackup: 'Резервное копирование'
|
|||||||
TaskRecover: 'Восстановить'
|
TaskRecover: 'Восстановить'
|
||||||
TaskRollback: 'Откат'
|
TaskRollback: 'Откат'
|
||||||
TaskPull: 'Вытянуть'
|
TaskPull: 'Вытянуть'
|
||||||
|
TaskCommit: 'Kоммит'
|
||||||
ЗадачаСборка: 'Сборка'
|
ЗадачаСборка: 'Сборка'
|
||||||
TaskPush: 'Push'
|
TaskPush: 'Push'
|
||||||
|
TaskClean: "Очистка"
|
||||||
TaskHandle: 'Выполнить'
|
TaskHandle: 'Выполнить'
|
||||||
Website: 'Be6-сайт'
|
Website: 'Be6-сайт'
|
||||||
App: 'Приложение'
|
App: 'Приложение'
|
||||||
@@ -423,4 +431,18 @@ ErrAlertSync: 'Ошибка синхронизации информации о
|
|||||||
ErrAlertRemote: 'Ошибка удаленного сообщения об ошибке, проверьте и повторите попытку!'
|
ErrAlertRemote: 'Ошибка удаленного сообщения об ошибке, проверьте и повторите попытку!'
|
||||||
|
|
||||||
#task - runtime
|
#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 }} дней. Подробности смотрите в панели."
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user