mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 08:00:27 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b7562f546 | ||
|
|
e7f4e312b9 | ||
|
|
98d3870477 | ||
|
|
b1ceb2e53d | ||
|
|
075d2468ea | ||
|
|
8b9e7aef4a | ||
|
|
15e499c1e9 | ||
|
|
55ccb9fe61 | ||
|
|
a5816f1dc9 | ||
|
|
95a613f59f | ||
|
|
6777941dee | ||
|
|
e55128b7fa | ||
|
|
9ac11002f8 | ||
|
|
1cc7bfb4a9 | ||
|
|
e59534e54f | ||
|
|
8c2368c1d2 | ||
|
|
8e8f181cae | ||
|
|
2fcab77565 | ||
|
|
d29f0c6c31 | ||
|
|
79f1b1458b | ||
|
|
b279ee6b82 | ||
|
|
c64a58d814 | ||
|
|
57c60ab3f8 | ||
|
|
e37d90d6e1 | ||
|
|
22055ed99a | ||
|
|
e263331b94 | ||
|
|
eb3d613e3d | ||
|
|
cc23444776 | ||
|
|
1931d3f262 | ||
|
|
79cbbbdf0a | ||
|
|
38cd785aa3 | ||
|
|
dabec3f87a | ||
|
|
6c94cb2bdf | ||
|
|
f67bdf0c22 | ||
|
|
6c51b31270 | ||
|
|
ef6e342737 | ||
|
|
ac0ef98dde | ||
|
|
523775e56b | ||
|
|
b6e741a150 | ||
|
|
54357fbe2b | ||
|
|
040dda5bec | ||
|
|
77b4d58fb8 | ||
|
|
0c9e551492 | ||
|
|
2ba1e2e22e | ||
|
|
d8a08a6c0c | ||
|
|
2c92226f88 | ||
|
|
cd9cb9b9c9 | ||
|
|
b2777055bc | ||
|
|
c8673b60bb | ||
|
|
21975dff2d | ||
|
|
6ab14185e0 | ||
|
|
1f70646952 | ||
|
|
c90ed9e873 | ||
|
|
e4ee07d36b | ||
|
|
8fb3e78554 | ||
|
|
01ab004876 | ||
|
|
6205eac51c | ||
|
|
d9a5418029 | ||
|
|
74a8e61f3e | ||
|
|
e18472f1a3 | ||
|
|
e3dea80cb7 | ||
|
|
50947f4ddc | ||
|
|
d302bc07b3 | ||
|
|
c6df20e565 | ||
|
|
6f9a1321d1 | ||
|
|
eb4eb31578 | ||
|
|
f8f5fcfca2 | ||
|
|
4e7b654090 | ||
|
|
e8059d3676 | ||
|
|
ffadc6721b | ||
|
|
e2e774d215 | ||
|
|
f23d3678fb | ||
|
|
dfade50bd8 | ||
|
|
d25b5f4f2a | ||
|
|
9a17bc74b0 | ||
|
|
015605526d | ||
|
|
099896dc96 | ||
|
|
aa1bc6fa8e |
+7
-1
@@ -62,4 +62,10 @@ cmd/server/fileList.txt
|
||||
1Panel.code-workspace
|
||||
|
||||
core/.golangci.yml
|
||||
agent/.golangci.yml
|
||||
agent/.golangci.yml
|
||||
|
||||
.opencode
|
||||
openspec
|
||||
CLAUDE.md
|
||||
AGENTS.md
|
||||
opencode.json
|
||||
+23
-3
@@ -203,14 +203,14 @@ func (b *BaseApi) GetAppListUpdate(c *gin.Context) {
|
||||
// @Success 200 {file} file "app icon"
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /apps/icon/:appId [get]
|
||||
// @Router /apps/icon/:key [get]
|
||||
func (b *BaseApi) GetAppIcon(c *gin.Context) {
|
||||
appID, err := helper.GetIntParamByKey(c, "appID")
|
||||
appKey, err := helper.GetStrParamByKey(c, "key")
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
iconBytes, err := appService.GetAppIcon(appID)
|
||||
iconBytes, err := appService.GetAppIcon(appKey)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
@@ -220,3 +220,23 @@ func (b *BaseApi) GetAppIcon(c *gin.Context) {
|
||||
c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
|
||||
c.Data(http.StatusOK, "image/png", iconBytes)
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Search app detail by appkey and version
|
||||
// @Accept json
|
||||
// @Param appId path integer true "app key"
|
||||
// @Param version path string true "app version"
|
||||
// @Success 200 {object} response.AppDetailSimpleDTO
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /apps/detail/node/:appKey/:version [get]
|
||||
func (b *BaseApi) GetAppDetailForNode(c *gin.Context) {
|
||||
appKey := c.Param("appKey")
|
||||
version := c.Param("version")
|
||||
appDetailDTO, err := appService.GetAppDetailByKey(appKey, version)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, appDetailDTO)
|
||||
}
|
||||
|
||||
@@ -330,3 +330,8 @@ type AlertEmailConfig struct {
|
||||
Encryption string `json:"encryption"` // "ssl" / "tls" / "none"
|
||||
Recipient string `json:"recipient"`
|
||||
}
|
||||
|
||||
type AgentInfo struct {
|
||||
NodeName string `json:"nodeName"`
|
||||
NodeAddr string `json:"nodeAddr"`
|
||||
}
|
||||
|
||||
+20
-19
@@ -84,25 +84,26 @@ type ExtraProperties struct {
|
||||
}
|
||||
|
||||
type AppProperty struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Tags []string `json:"tags"`
|
||||
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh"`
|
||||
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn"`
|
||||
Description Locale `json:"description"`
|
||||
Key string `json:"key"`
|
||||
Required []string `json:"Required"`
|
||||
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
|
||||
Limit int `json:"limit" yaml:"limit"`
|
||||
Recommend int `json:"recommend" yaml:"recommend"`
|
||||
Website string `json:"website"`
|
||||
Github string `json:"github"`
|
||||
Document string `json:"document"`
|
||||
Architectures []string `json:"architectures"`
|
||||
MemoryRequired int `json:"memoryRequired" yaml:"memoryRequired"`
|
||||
GpuSupport bool `json:"gpuSupport" yaml:"gpuSupport"`
|
||||
Version float64 `json:"version"`
|
||||
Deprecated float64 `json:"deprecated"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Tags []string `json:"tags"`
|
||||
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh"`
|
||||
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn"`
|
||||
Description Locale `json:"description"`
|
||||
Key string `json:"key"`
|
||||
Required []string `json:"Required"`
|
||||
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
|
||||
Limit int `json:"limit" yaml:"limit"`
|
||||
Recommend int `json:"recommend" yaml:"recommend"`
|
||||
Website string `json:"website"`
|
||||
Github string `json:"github"`
|
||||
Document string `json:"document"`
|
||||
Architectures []string `json:"architectures"`
|
||||
MemoryRequired int `json:"memoryRequired" yaml:"memoryRequired"`
|
||||
GpuSupport bool `json:"gpuSupport" yaml:"gpuSupport"`
|
||||
Version float64 `json:"version"`
|
||||
Deprecated float64 `json:"deprecated"`
|
||||
BatchInstallSupport bool `json:"batchInstallSupport"`
|
||||
}
|
||||
|
||||
type AppConfigVersion struct {
|
||||
|
||||
@@ -65,12 +65,13 @@ type UploadForRecover struct {
|
||||
}
|
||||
|
||||
type CommonBackup struct {
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
Args []string `json:"args"`
|
||||
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type CronjobOperate struct {
|
||||
Timeout uint `json:"timeout" validate:"number,min=1"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
@@ -123,6 +124,7 @@ type CronjobInfo struct {
|
||||
LastRecordTime string `json:"lastRecordTime"`
|
||||
Status string `json:"status"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
}
|
||||
@@ -162,6 +164,7 @@ type CronjobTrans struct {
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
SnapshotRule SnapshotTransHelper `json:"snapshotRule"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
SourceAccounts []string `json:"sourceAccounts"`
|
||||
DownloadAccount string `json:"downloadAccount"`
|
||||
|
||||
@@ -19,7 +19,7 @@ type RuleSearch struct {
|
||||
}
|
||||
|
||||
type FirewallOperation struct {
|
||||
Operation string `json:"operation" validate:"required,oneof=start stop restart disablePing enablePing"`
|
||||
Operation string `json:"operation" validate:"required,oneof=start stop restart disableBanPing enableBanPing"`
|
||||
WithDockerRestart bool `json:"withDockerRestart"`
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,16 @@ type AppInstallCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Services map[string]string `json:"services"`
|
||||
TaskID string `json:"taskID"`
|
||||
|
||||
AppContainerConfig
|
||||
NodePushConfig
|
||||
}
|
||||
|
||||
type NodePushConfig struct {
|
||||
Nodes []string `json:"nodes"`
|
||||
PushNode bool `json:"pushNode"`
|
||||
AppKey string `json:"appKey"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type AppContainerConfig struct {
|
||||
|
||||
@@ -13,6 +13,7 @@ type DiskMountRequest struct {
|
||||
MountPoint string `json:"mountPoint" validate:"required"`
|
||||
Filesystem string `json:"filesystem" validate:"required,oneof=ext4 xfs"`
|
||||
AutoMount bool `json:"autoMount"`
|
||||
NoFail bool `json:"noFail"`
|
||||
}
|
||||
|
||||
type DiskUnmountRequest struct {
|
||||
|
||||
@@ -45,6 +45,7 @@ type StreamConfig struct {
|
||||
StreamPorts string `json:"streamPorts"`
|
||||
Name string `json:"name"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
UDP bool `json:"udp"`
|
||||
|
||||
Servers []dto.NginxUpstreamServer `json:"servers"`
|
||||
}
|
||||
@@ -310,6 +311,7 @@ type WebsiteHtmlReq struct {
|
||||
type WebsiteHtmlUpdate struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
Sync bool `json:"sync"`
|
||||
}
|
||||
|
||||
type WebsiteLBCreate struct {
|
||||
|
||||
@@ -29,17 +29,18 @@ type AppDTO struct {
|
||||
}
|
||||
|
||||
type AppItem struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
ID uint `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Installed bool `json:"installed"`
|
||||
Limit int `json:"limit"`
|
||||
Tags []string `json:"tags"`
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
Recommend int `json:"recommend"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
ID uint `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Installed bool `json:"installed"`
|
||||
Limit int `json:"limit"`
|
||||
Tags []string `json:"tags"`
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
Recommend int `json:"recommend"`
|
||||
Type string `json:"type"`
|
||||
BatchInstallSupport bool `json:"batchInstallSupport"`
|
||||
}
|
||||
|
||||
type TagDTO struct {
|
||||
@@ -75,6 +76,10 @@ type AppDetailDTO struct {
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
}
|
||||
|
||||
type AppDetailSimpleDTO struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
||||
type IgnoredApp struct {
|
||||
Icon string `json:"icon"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -18,6 +18,7 @@ type WebsiteDTO struct {
|
||||
SiteDir string `json:"siteDir"`
|
||||
OpenBaseDir bool `json:"openBaseDir"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
UDP bool `json:"udp"`
|
||||
|
||||
Servers []dto.NginxUpstreamServer `json:"servers"`
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type App struct {
|
||||
MemoryRequired int `json:"memoryRequired"`
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
RequiredPanelVersion float64 `json:"requiredPanelVersion"`
|
||||
BatchInstallSupport bool `json:"batchInstallSupport" yaml:"batchInstallSupport"`
|
||||
|
||||
Details []AppDetail `json:"-" gorm:"-:migration"`
|
||||
TagsKey []string `json:"tags" yaml:"tags" gorm:"-"`
|
||||
|
||||
@@ -37,6 +37,7 @@ type Cronjob struct {
|
||||
Timeout uint `json:"timeout"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
RetainCopies uint64 `json:"retainCopies"`
|
||||
Args string `json:"args"`
|
||||
|
||||
IsExecuting bool `json:"isExecuting"`
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -73,28 +73,13 @@ func (u *MonitorRepo) CreateMonitorBase(model model.MonitorBase) error {
|
||||
return global.MonitorDB.Create(&model).Error
|
||||
}
|
||||
func (s *MonitorRepo) BatchCreateMonitorGPU(list []model.MonitorGPU) error {
|
||||
for _, item := range list {
|
||||
if err := global.GPUMonitorDB.Create(&item).Error; err != nil {
|
||||
global.LOG.Errorf("create Monitor GPU record failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return global.GPUMonitorDB.CreateInBatches(&list, len(list)).Error
|
||||
}
|
||||
func (u *MonitorRepo) BatchCreateMonitorIO(list []model.MonitorIO) error {
|
||||
for _, item := range list {
|
||||
if err := global.MonitorDB.Create(&item).Error; err != nil {
|
||||
global.LOG.Errorf("create Monitor IO record failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (u *MonitorRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
|
||||
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
|
||||
}
|
||||
func (u *MonitorRepo) BatchCreateMonitorNet(list []model.MonitorNetwork) error {
|
||||
for _, item := range list {
|
||||
if err := global.MonitorDB.Create(&item).Error; err != nil {
|
||||
global.LOG.Errorf("create Monitor Network record failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (u *MonitorRepo) BatchCreateMonitorNet(ioList []model.MonitorNetwork) error {
|
||||
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
|
||||
}
|
||||
func (u *MonitorRepo) DelMonitorBase(timeForDelete time.Time) error {
|
||||
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
|
||||
|
||||
@@ -580,7 +580,11 @@ func sendAlerts(alert dto.AlertDTO, alertType, quota, quotaType string, params [
|
||||
AlertId: alert.ID,
|
||||
Count: todayCount + 1,
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alertType, alert, create, quotaType, params, constant.SMS)
|
||||
alertErr := xpack.CreateSMSAlertLog(alertType, alert, create, quotaType, params, constant.SMS)
|
||||
if alertErr != nil {
|
||||
global.LOG.Infof("%s alert sms push faild, err: %v", alertType, alertErr.Error())
|
||||
continue
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, alertType, quotaType, constant.SMS)
|
||||
global.LOG.Infof("%s alert sms push successful", alertType)
|
||||
|
||||
@@ -599,7 +603,12 @@ func sendAlerts(alert dto.AlertDTO, alertType, quota, quotaType string, params [
|
||||
create.AlertRule = alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertDetail = alertUtil.ProcessAlertDetail(alertInfo, quotaType, params, constant.Email)
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alertInfo, params, transport)
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
alertErr := alertUtil.CreateEmailAlertLog(create, alertInfo, params, transport, agentInfo)
|
||||
if alertErr != nil {
|
||||
global.LOG.Infof("%s alert email push faild, err: %v", alertType, alertErr.Error())
|
||||
continue
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, alertType, quotaType, constant.Email)
|
||||
global.LOG.Infof("%s alert email push successful", alertType)
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ func (s *AlertSender) sendEmail(quota string, params []dto.Param) {
|
||||
}
|
||||
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, s.alert, params, transport)
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, s.alert, params, transport, agentInfo)
|
||||
alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.Email)
|
||||
global.LOG.Infof("%s alert email push successful", s.alert.Type)
|
||||
}
|
||||
@@ -131,7 +132,8 @@ func (s *AlertSender) sendResourceEmail(quota string, params []dto.Param) {
|
||||
}
|
||||
|
||||
transport := xpack.LoadRequestTransport()
|
||||
if err := alertUtil.CreateEmailAlertLog(create, s.alert, params, transport); err != nil {
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
if err := alertUtil.CreateEmailAlertLog(create, s.alert, params, transport, agentInfo); err != nil {
|
||||
global.LOG.Errorf("failed to send Email alert: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
+42
-11
@@ -46,7 +46,8 @@ type IAppService interface {
|
||||
GetAppUpdate() (*response.AppUpdateRes, error)
|
||||
GetAppDetailByID(id uint) (*response.AppDetailDTO, error)
|
||||
SyncAppListFromLocal(taskID string)
|
||||
GetAppIcon(appID uint) ([]byte, error)
|
||||
GetAppIcon(key string) ([]byte, error)
|
||||
GetAppDetailByKey(appKey, version string) (response.AppDetailSimpleDTO, error)
|
||||
}
|
||||
|
||||
func NewIAppService() IAppService {
|
||||
@@ -118,14 +119,15 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (*response.
|
||||
}
|
||||
}
|
||||
appDTO := &response.AppItem{
|
||||
ID: ap.ID,
|
||||
Name: ap.Name,
|
||||
Key: ap.Key,
|
||||
Limit: ap.Limit,
|
||||
GpuSupport: ap.GpuSupport,
|
||||
Recommend: ap.Recommend,
|
||||
Description: ap.GetDescription(ctx),
|
||||
Type: ap.Type,
|
||||
ID: ap.ID,
|
||||
Name: ap.Name,
|
||||
Key: ap.Key,
|
||||
Limit: ap.Limit,
|
||||
GpuSupport: ap.GpuSupport,
|
||||
Recommend: ap.Recommend,
|
||||
Description: ap.GetDescription(ctx),
|
||||
Type: ap.Type,
|
||||
BatchInstallSupport: ap.BatchInstallSupport,
|
||||
}
|
||||
appDTOs = append(appDTOs, appDTO)
|
||||
tags, err := getAppTags(ap.ID, lang)
|
||||
@@ -203,6 +205,20 @@ func (a AppService) GetApp(ctx *gin.Context, key string) (*response.AppDTO, erro
|
||||
return &appDTO, nil
|
||||
}
|
||||
|
||||
func (a AppService) GetAppDetailByKey(appKey, version string) (response.AppDetailSimpleDTO, error) {
|
||||
var appDetailDTO response.AppDetailSimpleDTO
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(appKey))
|
||||
if err != nil {
|
||||
return appDetailDTO, err
|
||||
}
|
||||
appDetail, err := appDetailRepo.GetFirst(appDetailRepo.WithAppId(app.ID), appDetailRepo.WithVersion(version))
|
||||
if err != nil {
|
||||
return appDetailDTO, err
|
||||
}
|
||||
appDetailDTO.ID = appDetail.ID
|
||||
return appDetailDTO, nil
|
||||
}
|
||||
|
||||
func (a AppService) GetAppDetail(appID uint, version, appType string) (response.AppDetailDTO, error) {
|
||||
var (
|
||||
appDetailDTO response.AppDetailDTO
|
||||
@@ -386,11 +402,21 @@ func (a AppService) Install(req request.AppInstallCreate) (appInstall *model.App
|
||||
App: app,
|
||||
}
|
||||
composeMap := make(map[string]interface{})
|
||||
var composeRes []byte
|
||||
if req.EditCompose {
|
||||
if err = yaml.Unmarshal([]byte(req.DockerCompose), &composeMap); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if appDetail.DockerCompose == "" {
|
||||
dockerComposeUrl := fmt.Sprintf("%s/%s/1panel/%s/%s/docker-compose.yml", global.CONF.RemoteURL.AppRepo, global.CONF.Base.Mode, app.Key, appDetail.Version)
|
||||
_, composeRes, err = req_helper.HandleRequest(dockerComposeUrl, http.MethodGet, constant.TimeOut20s)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appDetail.DockerCompose = string(composeRes)
|
||||
_ = appDetailRepo.Update(context.Background(), appDetail)
|
||||
}
|
||||
if err = yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -776,6 +802,11 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||
res := &response.AppUpdateRes{
|
||||
CanUpdate: false,
|
||||
}
|
||||
mysql, _ := appRepo.GetFirst(appRepo.WithKey("mysql"))
|
||||
if !mysql.BatchInstallSupport {
|
||||
res.CanUpdate = true
|
||||
return res, nil
|
||||
}
|
||||
|
||||
versionUrl := fmt.Sprintf("%s/%s/1panel.json.version.txt", global.CONF.RemoteURL.AppRepo, global.CONF.Base.Mode)
|
||||
_, versionRes, err := req_helper.HandleRequest(versionUrl, http.MethodGet, constant.TimeOut20s)
|
||||
@@ -1146,8 +1177,8 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppService) GetAppIcon(appID uint) ([]byte, error) {
|
||||
app, err := appRepo.GetFirst(repo.WithByID(appID))
|
||||
func (a AppService) GetAppIcon(key string) ([]byte, error) {
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1312,6 +1312,7 @@ func getApps(oldApps []model.App, items []dto.AppDefine, systemVersion string, t
|
||||
app.MemoryRequired = config.MemoryRequired
|
||||
app.Architectures = strings.Join(config.Architectures, ",")
|
||||
app.GpuSupport = config.GpuSupport
|
||||
app.BatchInstallSupport = config.BatchInstallSupport
|
||||
apps[key] = app
|
||||
}
|
||||
return apps
|
||||
|
||||
@@ -44,7 +44,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
return err
|
||||
}
|
||||
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName}
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName, Args: req.Args}
|
||||
if err := handleMysqlBackup(databaseHelper, nil, record.ID, targetDir, fileName, req.TaskID, req.Secret); err != nil {
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return err
|
||||
@@ -87,7 +87,12 @@ func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint,
|
||||
}
|
||||
}
|
||||
|
||||
itemHandler := func() error { return doMysqlBackup(db, targetDir, fileName, secret) }
|
||||
itemHandler := func() error {
|
||||
if len(db.Args) != 0 {
|
||||
backupTask.Logf("%s: %v", i18n.GetMsgByKey("Arg"), db.Args)
|
||||
}
|
||||
return doMysqlBackup(db, targetDir, fileName, secret)
|
||||
}
|
||||
if parentTask != nil {
|
||||
return itemHandler()
|
||||
}
|
||||
@@ -225,6 +230,7 @@ func doMysqlBackup(db DatabaseHelper, targetDir, fileName, secret string) error
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: targetDir,
|
||||
FileName: fileName,
|
||||
Args: db.Args,
|
||||
}
|
||||
if err := cli.Backup(backupInfo); err != nil {
|
||||
return err
|
||||
|
||||
@@ -435,7 +435,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
}
|
||||
}
|
||||
taskItem.Log(i18n.GetMsgByKey("PruneStart"))
|
||||
DeletedNumber := 0
|
||||
SpaceReclaimed := 0
|
||||
switch req.PruneType {
|
||||
case "container":
|
||||
@@ -443,21 +442,18 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
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)
|
||||
_, 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 {
|
||||
@@ -470,7 +466,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DeletedNumber = len(rep.VolumesDeleted)
|
||||
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
case "buildcache":
|
||||
opts := build.CachePruneOptions{}
|
||||
@@ -479,10 +474,9 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
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))}))
|
||||
taskItem.Log(i18n.GetMsgWithMap("PruneHelper", map[string]interface{}{"name": i18n.GetMsgByKey(name), "size": common.LoadSizeUnit2F(float64(SpaceReclaimed))}))
|
||||
return nil
|
||||
}, nil)
|
||||
go func() {
|
||||
|
||||
@@ -143,6 +143,7 @@ func (u *CronjobService) Export(req dto.OperateByIDs) (string, error) {
|
||||
Timeout: cronjob.Timeout,
|
||||
IgnoreErr: cronjob.IgnoreErr,
|
||||
Secret: cronjob.Secret,
|
||||
Args: cronjob.Args,
|
||||
}
|
||||
switch cronjob.Type {
|
||||
case "app":
|
||||
@@ -237,6 +238,7 @@ func (u *CronjobService) Import(req []dto.CronjobTrans) error {
|
||||
Timeout: item.Timeout,
|
||||
IgnoreErr: item.IgnoreErr,
|
||||
Secret: item.Secret,
|
||||
Args: item.Args,
|
||||
}
|
||||
hasNotFound := false
|
||||
switch item.Type {
|
||||
@@ -733,6 +735,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
||||
upMap["timeout"] = req.Timeout
|
||||
upMap["ignore_err"] = req.IgnoreErr
|
||||
upMap["secret"] = req.Secret
|
||||
upMap["args"] = req.Args
|
||||
err = cronjobRepo.Update(id, upMap)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -379,6 +379,7 @@ type DatabaseHelper struct {
|
||||
DBType string
|
||||
Database string
|
||||
Name string
|
||||
Args []string
|
||||
}
|
||||
|
||||
func addSkipTask(source string, taskItem *task.Task) {
|
||||
@@ -400,6 +401,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysql.Database,
|
||||
Name: mysql.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@@ -410,6 +412,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: pg.PostgresqlName,
|
||||
Name: pg.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -425,6 +428,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysqlItem.MysqlName,
|
||||
Name: mysqlItem.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
} else {
|
||||
pgItem, _ := postgresqlRepo.Get(repo.WithByID(uint(itemID)))
|
||||
@@ -433,6 +437,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: pgItem.PostgresqlName,
|
||||
Name: pgItem.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/controller"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
fileUtils "github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -30,7 +29,6 @@ import (
|
||||
|
||||
const (
|
||||
rollbackPath = "1panel/tmp"
|
||||
cachePath = "1panel/cache"
|
||||
upgradePath = "1panel/tmp/upgrade"
|
||||
uploadPath = "1panel/uploads"
|
||||
downloadPath = "1panel/download"
|
||||
@@ -56,16 +54,6 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
})
|
||||
treeData = append(treeData, loadUpgradeTree(fileOp))
|
||||
treeData = append(treeData, loadAgentPackage(fileOp))
|
||||
cachePath := path.Join(global.Dir.BaseDir, cachePath)
|
||||
cacheSize, _ := fileOp.GetDirSize(cachePath)
|
||||
treeData = append(treeData, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "cache",
|
||||
Size: uint64(cacheSize),
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "cache",
|
||||
})
|
||||
|
||||
SystemClean.BackupClean = loadBackupTree(fileOp)
|
||||
|
||||
@@ -102,7 +90,6 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
|
||||
func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
size := uint64(0)
|
||||
restart := false
|
||||
for _, item := range req {
|
||||
size += item.Size
|
||||
switch item.TreeType {
|
||||
@@ -118,7 +105,11 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
case "tmp_backup":
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp"))
|
||||
case "unknown_backup":
|
||||
dropFileOrDir(item.Name)
|
||||
if strings.HasPrefix(item.Name, path.Join(global.Dir.LocalBackupDir, "log/website")) {
|
||||
dropFileOrDir(item.Name)
|
||||
} else {
|
||||
dropFile(item.Name)
|
||||
}
|
||||
|
||||
case "rollback":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, rollbackPath, "app"))
|
||||
@@ -131,10 +122,6 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
case "rollback_website":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, rollbackPath, "website", item.Name))
|
||||
|
||||
case "cache":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, cachePath, item.Name))
|
||||
restart = true
|
||||
|
||||
case "upload":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, item.Name))
|
||||
case "upload_app":
|
||||
@@ -182,6 +169,8 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
} else {
|
||||
dropTaskLog(path.Join(global.Dir.TaskDir, item.Name))
|
||||
}
|
||||
case "website_log":
|
||||
dropWebsiteLog(item.Name)
|
||||
case "script":
|
||||
dropFileOrDir(path.Join(global.Dir.TmpDir, "script", item.Name))
|
||||
case "images":
|
||||
@@ -192,16 +181,15 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
_, _ = dropVolumes()
|
||||
case "build_cache":
|
||||
_, _ = dropBuildCache()
|
||||
case "app_tmp_download_version":
|
||||
dropFileOrDir(path.Join(global.Dir.RemoteAppResourceDir, item.Name))
|
||||
}
|
||||
}
|
||||
|
||||
_ = cleanEmptyDirs(global.Dir.LocalBackupDir)
|
||||
_ = settingRepo.Update("LastCleanTime", time.Now().Format(constant.DateTimeLayout))
|
||||
_ = settingRepo.Update("LastCleanSize", fmt.Sprintf("%v", size))
|
||||
_ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", len(req)))
|
||||
|
||||
if restart {
|
||||
go controller.RestartPanel(false, true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func doSystemClean(taskItem *task.Task) func(t *task.Task) error {
|
||||
@@ -312,7 +300,7 @@ func loadAgentPackage(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
itemTree := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "agent_packages",
|
||||
IsCheck: true,
|
||||
IsCheck: false,
|
||||
IsRecommend: true,
|
||||
Type: "agent",
|
||||
}
|
||||
@@ -323,6 +311,7 @@ func loadAgentPackage(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
itemTree.Size += uint64(itemSize)
|
||||
itemTree.Children = append(itemTree.Children, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: file.Name(),
|
||||
Name: file.Name(),
|
||||
Size: uint64(itemSize),
|
||||
IsCheck: true,
|
||||
@@ -330,16 +319,19 @@ func loadAgentPackage(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
Type: "agent",
|
||||
})
|
||||
} else {
|
||||
if strings.HasPrefix(file.Name(), fmt.Sprintf("1panel-agent_%s_a", global.CONF.Base.Version)) {
|
||||
itemSize, _ := file.Info()
|
||||
itemName := file.Name()
|
||||
isCurrentVersion := strings.HasPrefix(itemName, fmt.Sprintf("1panel-agent_%s_", global.CONF.Base.Version))
|
||||
if isCurrentVersion {
|
||||
continue
|
||||
}
|
||||
itemSize, _ := file.Info()
|
||||
itemTree.Size += uint64(itemSize.Size())
|
||||
itemTree.Children = append(itemTree.Children, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: file.Name(),
|
||||
Label: itemName,
|
||||
Name: itemName,
|
||||
Size: uint64(itemSize.Size()),
|
||||
IsCheck: true,
|
||||
IsCheck: !isCurrentVersion,
|
||||
IsRecommend: true,
|
||||
Type: "agent",
|
||||
})
|
||||
@@ -378,6 +370,7 @@ func loadBackupTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
treeData = append(treeData, loadUnknownDbs(fileOp, recordMap))
|
||||
treeData = append(treeData, loadUnknownWebsites(fileOp, recordMap))
|
||||
treeData = append(treeData, loadUnknownSnapshot(fileOp))
|
||||
treeData = append(treeData, loadUnknownWebsiteLog(fileOp))
|
||||
return treeData
|
||||
}
|
||||
|
||||
@@ -390,70 +383,68 @@ func loadUnknownApps(fileOp fileUtils.FileOp, recordMap map[string][]string) dto
|
||||
for _, item := range val {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, itemName, item))
|
||||
}
|
||||
} else {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, itemName))
|
||||
}
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "app")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_app",
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Name: backupPath,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, path.Join(global.Dir.LocalBackupDir, "app"), &treeData, excludePaths)
|
||||
loadBackupIsCheck(&treeData)
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, backupPath, &treeData, excludePaths)
|
||||
return treeData
|
||||
}
|
||||
func loadUnknownDbs(fileOp fileUtils.FileOp, recordMap map[string][]string) dto.CleanTree {
|
||||
apps, _ := appInstallRepo.ListBy(context.Background())
|
||||
dbs, _ := databaseRepo.GetList()
|
||||
var excludePaths []string
|
||||
appMap := make(map[string]struct{})
|
||||
for _, app := range apps {
|
||||
appMap[fmt.Sprintf("database/%s/%s", app.App.Key, app.Name)] = struct{}{}
|
||||
dbMap := make(map[string]struct{})
|
||||
for _, db := range dbs {
|
||||
dbMap[fmt.Sprintf("database/%s/%s", db.Type, db.Name)] = struct{}{}
|
||||
}
|
||||
for key, val := range recordMap {
|
||||
itemName := path.Dir(key)
|
||||
if _, ok := appMap[itemName]; ok {
|
||||
if _, ok := dbMap[itemName]; ok {
|
||||
for _, item := range val {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, key, item))
|
||||
}
|
||||
}
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "database")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_database",
|
||||
Name: backupPath,
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, path.Join(global.Dir.LocalBackupDir, "database"), &treeData, excludePaths)
|
||||
|
||||
loadBackupIsCheck(&treeData)
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, backupPath, &treeData, excludePaths)
|
||||
return treeData
|
||||
}
|
||||
func loadUnknownWebsites(fileOp fileUtils.FileOp, recordMap map[string][]string) dto.CleanTree {
|
||||
websites, _ := websiteRepo.List()
|
||||
var excludePaths []string
|
||||
for _, website := range websites {
|
||||
itemName := fmt.Sprintf("website/%s", website.PrimaryDomain)
|
||||
itemName := fmt.Sprintf("website/%s", website.Alias)
|
||||
if val, ok := recordMap[itemName]; ok {
|
||||
for _, item := range val {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, itemName, item))
|
||||
}
|
||||
} else {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, itemName))
|
||||
}
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "website")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_website",
|
||||
Name: backupPath,
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, path.Join(global.Dir.LocalBackupDir, "website"), &treeData, excludePaths)
|
||||
loadBackupIsCheck(&treeData)
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, backupPath, &treeData, excludePaths)
|
||||
return treeData
|
||||
}
|
||||
func loadUnknownSnapshot(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
@@ -462,21 +453,21 @@ func loadUnknownSnapshot(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
for _, item := range snaps {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, "system_snapshot", item.Name+".tar.gz"))
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "system_snapshot")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_snapshot",
|
||||
Name: backupPath,
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
dir := path.Join(global.Dir.LocalBackupDir, "system_snapshot")
|
||||
entries, _ := os.ReadDir(dir)
|
||||
entries, _ := os.ReadDir(backupPath)
|
||||
for _, entry := range entries {
|
||||
childPath := filepath.Join(dir, entry.Name())
|
||||
childPath := filepath.Join(backupPath, entry.Name())
|
||||
if isExactPathMatch(childPath, excludePaths) {
|
||||
continue
|
||||
}
|
||||
|
||||
childNode := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: entry.Name(),
|
||||
@@ -502,6 +493,49 @@ func loadUnknownSnapshot(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadUnknownWebsiteLog(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_website_log",
|
||||
IsCheck: false,
|
||||
IsRecommend: true,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
dir := path.Join(global.Dir.LocalBackupDir, "log/website")
|
||||
websites, _ := websiteRepo.List()
|
||||
websiteMap := make(map[string]struct{})
|
||||
for _, website := range websites {
|
||||
websiteMap[website.Alias] = struct{}{}
|
||||
}
|
||||
|
||||
entries, _ := os.ReadDir(dir)
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
dirName := entry.Name()
|
||||
if _, ok := websiteMap[dirName]; !ok {
|
||||
dirPath := path.Join(dir, dirName)
|
||||
itemSize, _ := fileOp.GetDirSize(dirPath)
|
||||
childData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: dirName,
|
||||
IsCheck: true,
|
||||
IsRecommend: true,
|
||||
Name: dirPath,
|
||||
Type: "unknown_backup",
|
||||
Size: uint64(itemSize),
|
||||
}
|
||||
treeData.Size += uint64(itemSize)
|
||||
treeData.Children = append(treeData.Children, childData)
|
||||
}
|
||||
}
|
||||
if treeData.Size > 0 {
|
||||
treeData.IsCheck = true
|
||||
}
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadFileOrDirWithExclude(fileOp fileUtils.FileOp, index uint, dir string, rootTree *dto.CleanTree, excludes []string) error {
|
||||
index++
|
||||
entries, err := os.ReadDir(dir)
|
||||
@@ -513,7 +547,6 @@ func loadFileOrDirWithExclude(fileOp fileUtils.FileOp, index uint, dir string, r
|
||||
if isExactPathMatch(childPath, excludes) {
|
||||
continue
|
||||
}
|
||||
|
||||
childNode := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: entry.Name(),
|
||||
@@ -548,23 +581,6 @@ func loadFileOrDirWithExclude(fileOp fileUtils.FileOp, index uint, dir string, r
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadBackupIsCheck(treeData *dto.CleanTree) {
|
||||
for i := 0; i < len(treeData.Children); i++ {
|
||||
if len(treeData.Children[i].Children) == 0 {
|
||||
treeData.Children[i].IsCheck = true
|
||||
treeData.Children[i].IsRecommend = true
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(treeData.Children[i].Children); j++ {
|
||||
if len(treeData.Children[i].Children[j].Children) == 0 {
|
||||
treeData.Children[i].Children[j].IsCheck = true
|
||||
treeData.Children[i].Children[j].IsRecommend = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isExactPathMatch(path string, excludePaths []string) bool {
|
||||
cleanPath := filepath.Clean(path)
|
||||
|
||||
@@ -610,6 +626,22 @@ func loadDownloadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
uploadTreeData := loadTreeWithAllFile(true, path5, "download", path5, fileOp)
|
||||
treeData = append(treeData, uploadTreeData...)
|
||||
|
||||
appTmpDownloadTree := loadAppTmpDownloadTree(fileOp)
|
||||
if len(appTmpDownloadTree) > 0 {
|
||||
parentTree := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "app_tmp_download",
|
||||
IsCheck: true,
|
||||
IsRecommend: true,
|
||||
Type: "app_tmp_download",
|
||||
Name: "apps",
|
||||
}
|
||||
for _, child := range appTmpDownloadTree {
|
||||
parentTree.Size += child.Size
|
||||
}
|
||||
parentTree.Children = appTmpDownloadTree
|
||||
treeData = append(treeData, parentTree)
|
||||
}
|
||||
return treeData
|
||||
}
|
||||
|
||||
@@ -621,20 +653,106 @@ func loadLogTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
for _, file := range list1 {
|
||||
size += file.Size
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "system_log", Size: uint64(size), Children: list1, Type: "system_log", IsRecommend: true})
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "system_log", Size: size, Children: list1, Type: "system_log", IsRecommend: true})
|
||||
|
||||
path2 := path.Join(global.Dir.TaskDir)
|
||||
list2 := loadTreeWithDir(false, "task_log", path2, fileOp)
|
||||
size2, _ := fileOp.GetDirSize(path2)
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "task_log", Size: uint64(size2), Children: list2, Type: "task_log"})
|
||||
|
||||
path3 := path.Join(global.Dir.TmpDir, "script")
|
||||
list3 := loadTreeWithAllFile(true, path3, "script", path3, fileOp)
|
||||
size3, _ := fileOp.GetDirSize(path3)
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "script", Size: uint64(size3), Children: list3, Type: "script", IsRecommend: true})
|
||||
websiteLogList := loadWebsiteLogTree(fileOp)
|
||||
logTotalSize := uint64(0)
|
||||
for _, websiteLog := range websiteLogList {
|
||||
logTotalSize += websiteLog.Size
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "website_log", Size: logTotalSize, Children: websiteLogList, Type: "website_log", IsRecommend: false})
|
||||
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadWebsiteLogTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
websites, _ := websiteRepo.List()
|
||||
if len(websites) == 0 {
|
||||
return nil
|
||||
}
|
||||
var res []dto.CleanTree
|
||||
for _, website := range websites {
|
||||
size3, _ := fileOp.GetDirSize(path.Join(GetSiteDir(website.Alias), "log"))
|
||||
res = append(res, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: website.PrimaryDomain,
|
||||
Size: uint64(size3),
|
||||
Type: "website_log",
|
||||
Name: website.Alias,
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func loadAppTmpDownloadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
appDirs, err := os.ReadDir(global.Dir.RemoteAppResourceDir)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var res []dto.CleanTree
|
||||
for _, appDir := range appDirs {
|
||||
if !appDir.IsDir() {
|
||||
continue
|
||||
}
|
||||
appKey := appDir.Name()
|
||||
app, _ := appRepo.GetFirst(appRepo.WithKey(appKey))
|
||||
if app.ID == 0 {
|
||||
continue
|
||||
}
|
||||
appPath := filepath.Join(global.Dir.RemoteAppResourceDir, appKey)
|
||||
versionDirs, err := os.ReadDir(appPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
appDetails, _ := appDetailRepo.GetBy(appDetailRepo.WithAppId(app.ID))
|
||||
existingVersions := make(map[string]bool)
|
||||
for _, appDetail := range appDetails {
|
||||
existingVersions[appDetail.Version] = true
|
||||
}
|
||||
var missingVersions []string
|
||||
for _, versionDir := range versionDirs {
|
||||
if !versionDir.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
version := versionDir.Name()
|
||||
if !existingVersions[version] {
|
||||
missingVersions = append(missingVersions, version)
|
||||
}
|
||||
}
|
||||
if len(missingVersions) > 0 {
|
||||
var appTree dto.CleanTree
|
||||
appTree.ID = uuid.NewString()
|
||||
appTree.Label = app.Name
|
||||
appTree.Type = "app_tmp_download"
|
||||
appTree.Name = appKey
|
||||
appTree.IsRecommend = true
|
||||
appTree.IsCheck = true
|
||||
for _, version := range missingVersions {
|
||||
versionPath := filepath.Join(appPath, version)
|
||||
size, _ := fileOp.GetDirSize(versionPath)
|
||||
appTree.Size += uint64(size)
|
||||
appTree.Children = append(appTree.Children, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: version,
|
||||
Size: uint64(size),
|
||||
IsCheck: true,
|
||||
IsRecommend: true,
|
||||
Type: "app_tmp_download_version",
|
||||
Name: path.Join(appKey, version),
|
||||
})
|
||||
}
|
||||
res = append(res, appTree)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func loadContainerTree() []dto.CleanTree {
|
||||
var treeData []dto.CleanTree
|
||||
client, err := docker.NewDockerClient()
|
||||
@@ -756,7 +874,7 @@ func loadTreeWithAllFile(isCheck bool, originalPath, treeType, pathItem string,
|
||||
ID: uuid.NewString(),
|
||||
Label: file.Name(),
|
||||
Type: treeType,
|
||||
Size: uint64(size),
|
||||
Size: size,
|
||||
Name: name,
|
||||
IsCheck: isCheck,
|
||||
IsRecommend: isCheck,
|
||||
@@ -774,6 +892,18 @@ func dropFileOrDir(itemPath string) {
|
||||
global.LOG.Errorf("drop file %s failed, err %v", itemPath, err)
|
||||
}
|
||||
}
|
||||
func dropFile(itemPath string) {
|
||||
info, err := os.Stat(itemPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if info.IsDir() {
|
||||
return
|
||||
}
|
||||
if err := os.Remove(itemPath); err != nil {
|
||||
global.LOG.Errorf("drop file %s failed, err %v", itemPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropBuildCache() (int, int) {
|
||||
client, err := docker.NewDockerClient()
|
||||
@@ -849,6 +979,18 @@ func dropVolumes() (int, int) {
|
||||
return len(res.VolumesDeleted), int(res.SpaceReclaimed)
|
||||
}
|
||||
|
||||
func dropWebsiteLog(alias string) {
|
||||
accessLogPath := path.Join(GetSiteDir(alias), "log", "access.log")
|
||||
errorLogPath := path.Join(GetSiteDir(alias), "log", "error.log")
|
||||
if err := os.Truncate(accessLogPath, 0); err != nil {
|
||||
global.LOG.Errorf("truncate access log %s failed, err %v", accessLogPath, err)
|
||||
}
|
||||
|
||||
if err := os.Truncate(errorLogPath, 0); err != nil {
|
||||
global.LOG.Errorf("truncate error log %s failed, err %v", errorLogPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropTaskLog(logDir string) {
|
||||
files, err := os.ReadDir(logDir)
|
||||
if err != nil {
|
||||
@@ -960,3 +1102,36 @@ func scanFile(pathItem string, size *int64, count *int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanEmptyDirs(root string) error {
|
||||
dirsToCheck := make([]string, 0)
|
||||
err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() {
|
||||
dirsToCheck = append(dirsToCheck, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := len(dirsToCheck) - 1; i >= 0; i-- {
|
||||
dir := dirsToCheck[i]
|
||||
if dir == root {
|
||||
continue
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
_ = os.Remove(dir)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -131,7 +131,11 @@ func (s *DiskService) MountDisk(req request.DiskMountRequest) error {
|
||||
return buserr.WithErr("MountDiskErr", err)
|
||||
}
|
||||
if req.AutoMount {
|
||||
if err := addToFstabWithOptions(req.Device, req.MountPoint, req.Filesystem, ""); err != nil {
|
||||
options := ""
|
||||
if req.NoFail {
|
||||
options = "defaults,nofail"
|
||||
}
|
||||
if err := addToFstabWithOptions(req.Device, req.MountPoint, req.Filesystem, options); err != nil {
|
||||
return buserr.WithErr("MountDiskErr", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,6 +463,11 @@ func isPointMounted(mountPoint string) bool {
|
||||
}
|
||||
|
||||
func addToFstabWithOptions(device, mountPoint, filesystem, options string) error {
|
||||
uuid, err := getDeviceUUID(device)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get UUID for device %s: %v", device, err)
|
||||
}
|
||||
|
||||
if filesystem == "" {
|
||||
fsType, err := getFilesystemType(device)
|
||||
if err != nil {
|
||||
@@ -476,7 +481,7 @@ func addToFstabWithOptions(device, mountPoint, filesystem, options string) error
|
||||
options = "defaults"
|
||||
}
|
||||
|
||||
entry := fmt.Sprintf("%s %s %s %s 0 2\n", device, mountPoint, filesystem, options)
|
||||
entry := fmt.Sprintf("UUID=%s %s %s %s 0 2\n", uuid, mountPoint, filesystem, options)
|
||||
|
||||
file, err := os.OpenFile("/etc/fstab", os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
@@ -568,3 +573,15 @@ func parseSizeToBytes(sizeStr string) int64 {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
func getDeviceUUID(device string) (string, error) {
|
||||
output, err := cmd.RunDefaultWithStdoutBashC(fmt.Sprintf("blkid -s UUID -o value %s", device))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
uuid := strings.TrimSpace(output)
|
||||
if uuid == "" {
|
||||
return "", fmt.Errorf("no UUID found for device %s", device)
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
@@ -658,6 +658,9 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||
configPath = pathSet.Value
|
||||
}
|
||||
logFilePath, _ = ini_conf.GetIniValue(configPath, "supervisord", "logfile")
|
||||
case constant.Supervisor:
|
||||
logDir := path.Join(global.Dir.DataDir, "tools", "supervisord", "log")
|
||||
logFilePath = path.Join(logDir, req.Name)
|
||||
}
|
||||
|
||||
file, err := os.Open(logFilePath)
|
||||
|
||||
+13
-109
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -14,7 +13,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/controller"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
@@ -23,9 +21,6 @@ import (
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
const confPath = "/etc/sysctl.conf"
|
||||
const panelSysctlPath = "/etc/sysctl.d/98-onepanel.conf"
|
||||
|
||||
type FirewallService struct{}
|
||||
|
||||
type IFirewallService interface {
|
||||
@@ -62,7 +57,7 @@ func (u *FirewallService) LoadBaseInfo(tab string) (dto.FirewallBaseInfo, error)
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
baseInfo.PingStatus = u.pingStatus()
|
||||
baseInfo.PingStatus = firewall.LoadPingStatus()
|
||||
baseInfo.Version, _ = client.Version()
|
||||
}()
|
||||
go func() {
|
||||
@@ -206,10 +201,18 @@ func (u *FirewallService) OperateFirewall(req dto.FirewallOperation) error {
|
||||
return err
|
||||
}
|
||||
needRestartDocker = true
|
||||
case "disablePing":
|
||||
return u.updatePingStatus("0")
|
||||
case "enablePing":
|
||||
return u.updatePingStatus("1")
|
||||
case "disableBanPing":
|
||||
if err := firewall.UpdatePingStatus("0"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = settingRepo.Update("BanPing", constant.StatusDisable)
|
||||
return nil
|
||||
case "enableBanPing":
|
||||
if err := firewall.UpdatePingStatus("1"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = settingRepo.Update("BanPing", constant.StatusEnable)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("not supported operation: %s", req.Operation)
|
||||
}
|
||||
@@ -589,105 +592,6 @@ func (u *FirewallService) cleanUnUsedData(client firewall.FirewallClient) {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *FirewallService) pingStatus() string {
|
||||
data, err := os.ReadFile("/proc/sys/net/ipv4/icmp_echo_ignore_all")
|
||||
if err != nil {
|
||||
return constant.StatusNone
|
||||
}
|
||||
v6Data, v6err := os.ReadFile("/proc/sys/net/ipv6/icmp/echo_ignore_all")
|
||||
if v6err != nil {
|
||||
if strings.TrimSpace(string(data)) == "1" {
|
||||
return constant.StatusEnable
|
||||
}
|
||||
return constant.StatusDisable
|
||||
} else {
|
||||
if strings.TrimSpace(string(data)) == "1" && strings.TrimSpace(string(v6Data)) == "1" {
|
||||
return constant.StatusEnable
|
||||
}
|
||||
return constant.StatusDisable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (u *FirewallService) updatePingStatus(enable string) error {
|
||||
var targetPath string
|
||||
var applyCmd string
|
||||
|
||||
if _, err := os.Stat(confPath); os.IsNotExist(err) {
|
||||
// Debian 13
|
||||
targetPath = panelSysctlPath
|
||||
applyCmd = fmt.Sprintf("%s sysctl --system", cmd.SudoHandleCmd())
|
||||
if err := cmd.RunDefaultBashCf("%s mkdir -p /etc/sysctl.d", cmd.SudoHandleCmd()); err != nil {
|
||||
return fmt.Errorf("failed to create directory /etc/sysctl.d: %v", err)
|
||||
}
|
||||
} else {
|
||||
targetPath = confPath
|
||||
applyCmd = fmt.Sprintf("%s sysctl -p", cmd.SudoHandleCmd())
|
||||
}
|
||||
|
||||
lineBytes, err := os.ReadFile(targetPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("failed to read %s: %v", targetPath, err)
|
||||
}
|
||||
|
||||
if err := cmd.RunDefaultBashCf("echo %s | %s tee /proc/sys/net/ipv4/icmp_echo_ignore_all > /dev/null", enable, cmd.SudoHandleCmd()); err != nil {
|
||||
return fmt.Errorf("failed to apply ipv4 ping status temporarily: %v", err)
|
||||
}
|
||||
|
||||
var hasIpv6 bool
|
||||
if _, err := os.Stat("/proc/sys/net/ipv6/icmp/echo_ignore_all"); err == nil {
|
||||
hasIpv6 = true
|
||||
if err := cmd.RunDefaultBashCf("echo %s | %s tee /proc/sys/net/ipv6/icmp/echo_ignore_all > /dev/null", enable, cmd.SudoHandleCmd()); err != nil {
|
||||
global.LOG.Warnf("failed to apply ipv6 ping status temporarily: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var files []string
|
||||
if err == nil {
|
||||
files = strings.Split(string(lineBytes), "\n")
|
||||
}
|
||||
|
||||
var newFiles []string
|
||||
hasIPv4Line, hasIPv6Line := false, false
|
||||
|
||||
for _, line := range files {
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "net.ipv4.icmp_echo_ignore_all") {
|
||||
newFiles = append(newFiles, "net.ipv4.icmp_echo_ignore_all="+enable)
|
||||
hasIPv4Line = true
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "net.ipv6.icmp.echo_ignore_all") {
|
||||
newFiles = append(newFiles, "net.ipv6.icmp.echo_ignore_all="+enable)
|
||||
hasIPv6Line = true
|
||||
continue
|
||||
}
|
||||
newFiles = append(newFiles, line)
|
||||
}
|
||||
|
||||
if !hasIPv4Line {
|
||||
newFiles = append(newFiles, "net.ipv4.icmp_echo_ignore_all="+enable)
|
||||
}
|
||||
if hasIpv6 && !hasIPv6Line {
|
||||
newFiles = append(newFiles, "net.ipv6.icmp.echo_ignore_all="+enable)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(targetPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, constant.FilePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open %s: %v", targetPath, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err = file.WriteString(strings.Join(newFiles, "\n")); err != nil {
|
||||
return fmt.Errorf("failed to write to %s: %v", targetPath, err)
|
||||
}
|
||||
|
||||
if err := cmd.RunDefaultBashC(applyCmd); err != nil {
|
||||
global.LOG.Warnf("failed to apply persistent config with '%s': %v", applyCmd, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) error {
|
||||
if !global.IsMaster {
|
||||
if err := client.Port(fireClient.FireInfo{Port: global.CONF.Base.Port, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||
|
||||
@@ -230,6 +230,18 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error {
|
||||
}
|
||||
_ = settingRepo.Update("IptablesStatus", constant.StatusEnable)
|
||||
return nil
|
||||
case "bind-base-without-init":
|
||||
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicBefore, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasic, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = settingRepo.Update("IptablesStatus", constant.StatusEnable)
|
||||
return nil
|
||||
case "unbind-base":
|
||||
if err := iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter); err != nil {
|
||||
return err
|
||||
|
||||
@@ -405,7 +405,7 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err
|
||||
if len(imageList) != 0 {
|
||||
snap.Task.Log(strings.Join(imageList, " "))
|
||||
snap.Task.Logf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz"))
|
||||
if err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")); err != nil {
|
||||
if err := cmd.RunDefaultBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")); err != nil {
|
||||
snap.Task.LogFailedWithErr(i18n.GetMsgByKey("SnapDockerSave"), err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -101,15 +101,15 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
}()
|
||||
|
||||
if req.IsNew || snap.InterruptStep == "RecoverDownload" || req.ReDownload {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDownload",
|
||||
func(t *task.Task) error { return handleDownloadSnapshot(&itemHelper, snap, rootDir) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverDecompress" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDecompress",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 2 / 11 ----------------------")
|
||||
@@ -118,54 +118,54 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "BackupBeforeRecover" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"BackupBeforeRecover",
|
||||
func(t *task.Task) error { return backupBeforeRecover(snap.Name, &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
|
||||
var snapJson SnapshotJson
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"Readjson",
|
||||
func(t *task.Task) error {
|
||||
snapJson, err = readFromJson(path.Join(rootDir, snap.Name), &itemHelper)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
if req.IsNew || snap.InterruptStep == "RecoverApp" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverApp",
|
||||
func(t *task.Task) error { return recoverAppData(path.Join(rootDir, snap.Name), &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverBaseData" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverBaseData",
|
||||
func(t *task.Task) error { return recoverBaseData(path.Join(rootDir, snap.Name, "base"), &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverDBData" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDBData",
|
||||
func(t *task.Task) error { return recoverDBData(path.Join(rootDir, snap.Name, "db"), &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverBackups" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverBackups",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 8 / 11 ----------------------")
|
||||
@@ -174,12 +174,12 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverWebsite" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverWebsite",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 9 / 11 ----------------------")
|
||||
@@ -193,12 +193,12 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverPanelData" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverPanelData",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 10 / 11 ----------------------")
|
||||
@@ -218,16 +218,16 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
}
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDBData",
|
||||
func(t *task.Task) error {
|
||||
return restartCompose(path.Join(snapJson.BaseDir, "1panel/docker/compose"), &itemHelper)
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
|
||||
if err := taskItem.Execute(); err != nil {
|
||||
@@ -277,14 +277,15 @@ func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := itemHelper.FileOp.CopyDirWithExclude(global.Dir.DataDir, rootDir, []string{"cache", "tmp"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", global.Dir.DataDir), err)
|
||||
dataDir := global.Dir.DataDir
|
||||
err := itemHelper.FileOp.CopyDirWithExclude(dataDir, rootDir, []string{"cache", "tmp", "backup"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", dataDir), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
openrestyDir, _ := settingRepo.GetValueByKey("WEBSITE_DIR")
|
||||
if len(openrestyDir) != 0 && !strings.Contains(openrestyDir, global.Dir.DataDir) {
|
||||
if len(openrestyDir) != 0 && !strings.Contains(openrestyDir, dataDir) {
|
||||
err := itemHelper.FileOp.CopyDirWithExclude(openrestyDir, rootDir, nil)
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", openrestyDir), err)
|
||||
if err != nil {
|
||||
@@ -292,9 +293,10 @@ func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error {
|
||||
}
|
||||
}
|
||||
|
||||
if len(global.Dir.LocalBackupDir) != 0 && !strings.Contains(global.Dir.LocalBackupDir, global.Dir.DataDir) {
|
||||
err = itemHelper.FileOp.CopyDirWithExclude(global.Dir.LocalBackupDir, rootDir, []string{"system_snapshot"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", global.Dir.LocalBackupDir), err)
|
||||
backupDir := global.Dir.LocalBackupDir
|
||||
if len(backupDir) != 0 && (backupDir == dataDir+"/backup" || !strings.HasPrefix(backupDir, dataDir)) {
|
||||
err = itemHelper.FileOp.CopyDirWithExclude(backupDir, rootDir, []string{"system_snapshot", "tmp"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", backupDir), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
|
||||
@@ -88,7 +89,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
||||
taskItem.AddSubTask(
|
||||
i18n.GetWithName("SnapCopy", global.Dir.LocalBackupDir),
|
||||
func(t *task.Task) error {
|
||||
return FileOp.CopyDir(path.Join(rootDir, "backup"), global.Dir.LocalBackupDir)
|
||||
return FileOp.CopyDir(path.Join(rootDir, "backup"), strings.TrimSuffix(global.Dir.LocalBackupDir, "/backup"))
|
||||
},
|
||||
nil,
|
||||
)
|
||||
@@ -97,7 +98,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
||||
taskItem.AddSubTask(
|
||||
i18n.GetWithName("SnapCopy", openrestyDir),
|
||||
func(t *task.Task) error {
|
||||
return FileOp.CopyDir(path.Join(rootDir, "www"), openrestyDir)
|
||||
return FileOp.CopyDir(path.Join(rootDir, "www"), strings.TrimSuffix(openrestyDir, "/www"))
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
@@ -617,6 +617,13 @@ func (w WebsiteService) GetWebsite(id uint) (response.WebsiteDTO, error) {
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
listens := config.FindDirectives("listen")
|
||||
for _, listen := range listens {
|
||||
params := listen.GetParameters()
|
||||
if len(params) > 1 && params[1] == "udp" {
|
||||
res.UDP = true
|
||||
}
|
||||
}
|
||||
upstreams := config.FindUpstreams()
|
||||
for _, up := range upstreams {
|
||||
directives := up.GetDirectives()
|
||||
@@ -2028,6 +2035,15 @@ func (w WebsiteService) UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error {
|
||||
switch req.Type {
|
||||
case "404":
|
||||
resourcePath = path.Join(defaultPath, "404.html")
|
||||
if req.Sync {
|
||||
websites, _ := websiteRepo.GetBy(repo.WithTypes([]string{constant.Static, constant.Runtime}))
|
||||
for _, website := range websites {
|
||||
filePath := path.Join(GetSitePath(website, SiteIndexDir), "404.html")
|
||||
if fileOp.Stat(filePath) {
|
||||
_ = fileOp.SaveFile(filePath, req.Content, constant.DirPerm)
|
||||
}
|
||||
}
|
||||
}
|
||||
case "php":
|
||||
resourcePath = path.Join(defaultPath, "index.php")
|
||||
case "index":
|
||||
@@ -2333,10 +2349,14 @@ func (w WebsiteService) UpdateStream(req request.StreamUpdate) error {
|
||||
}
|
||||
server := servers[0]
|
||||
server.Listens = []*components.ServerListen{}
|
||||
var params []string
|
||||
if req.UDP {
|
||||
params = []string{"udp"}
|
||||
}
|
||||
for _, port := range ports {
|
||||
server.UpdateListen(port, false)
|
||||
server.UpdateListen(port, false, params...)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:"+port, false)
|
||||
server.UpdateListen("[::]:"+port, false, params...)
|
||||
}
|
||||
}
|
||||
upstream := components.Upstream{
|
||||
|
||||
@@ -131,7 +131,7 @@ func createProxyFile(website *model.Website) error {
|
||||
}
|
||||
|
||||
func createWebsiteFolder(website *model.Website, runtime *model.Runtime) error {
|
||||
siteFolder := GteSiteDir(website.Alias)
|
||||
siteFolder := GetSiteDir(website.Alias)
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(siteFolder) {
|
||||
if err := fileOp.CreateDir(siteFolder, constant.DirPerm); err != nil {
|
||||
@@ -206,10 +206,14 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
}
|
||||
server := servers[0]
|
||||
ports := strings.Split(streamConfig.StreamPorts, ",")
|
||||
var params []string
|
||||
if streamConfig.UDP {
|
||||
params = []string{"udp"}
|
||||
}
|
||||
for _, port := range ports {
|
||||
server.UpdateListen(port, false)
|
||||
server.UpdateListen(port, false, params...)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:"+port, false)
|
||||
server.UpdateListen("[::]:"+port, false, params...)
|
||||
}
|
||||
}
|
||||
siteFolder := path.Join("/www", "sites", website.Alias)
|
||||
@@ -491,7 +495,7 @@ func delNginxConfig(website model.Website, force bool) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sitePath := GteSiteDir(website.Alias)
|
||||
sitePath := GetSiteDir(website.Alias)
|
||||
if fileOp.Stat(sitePath) {
|
||||
xpack.RemoveTamper(website.Alias)
|
||||
_ = fileOp.DeleteDir(sitePath)
|
||||
@@ -1357,7 +1361,7 @@ func GetWebSiteRootDir() string {
|
||||
return dir
|
||||
}
|
||||
|
||||
func GteSiteDir(alias string) string {
|
||||
func GetSiteDir(alias string) string {
|
||||
return path.Join(GetWebSiteRootDir(), "sites", alias)
|
||||
}
|
||||
|
||||
@@ -1399,31 +1403,31 @@ func GetSitePath(website model.Website, confType string) string {
|
||||
case StreamConf:
|
||||
return path.Join(GetWebSiteRootDir(), "stream.d", website.Alias+".conf")
|
||||
case SiteAccessLog:
|
||||
return path.Join(GteSiteDir(website.Alias), "log", "access.log")
|
||||
return path.Join(GetSiteDir(website.Alias), "log", "access.log")
|
||||
case SiteErrorLog:
|
||||
return path.Join(GteSiteDir(website.Alias), "log", "error.log")
|
||||
return path.Join(GetSiteDir(website.Alias), "log", "error.log")
|
||||
case SiteDir:
|
||||
return GteSiteDir(website.Alias)
|
||||
return GetSiteDir(website.Alias)
|
||||
case SiteIndexDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "index")
|
||||
return path.Join(GetSiteDir(website.Alias), "index")
|
||||
case SiteCacheDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "cache")
|
||||
return path.Join(GetSiteDir(website.Alias), "cache")
|
||||
case SiteProxyDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "proxy")
|
||||
return path.Join(GetSiteDir(website.Alias), "proxy")
|
||||
case SiteSSLDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "ssl")
|
||||
return path.Join(GetSiteDir(website.Alias), "ssl")
|
||||
case SiteReWritePath:
|
||||
return path.Join(GteSiteDir(website.Alias), "rewrite", website.Alias+".conf")
|
||||
return path.Join(GetSiteDir(website.Alias), "rewrite", website.Alias+".conf")
|
||||
case SiteRedirectDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "redirect")
|
||||
return path.Join(GetSiteDir(website.Alias), "redirect")
|
||||
case SiteRootAuthBasicPath:
|
||||
return path.Join(GteSiteDir(website.Alias), "auth_basic", "auth.pass")
|
||||
return path.Join(GetSiteDir(website.Alias), "auth_basic", "auth.pass")
|
||||
case SitePathAuthBasicDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "path_auth")
|
||||
return path.Join(GetSiteDir(website.Alias), "path_auth")
|
||||
case SiteUpstreamDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "upstream")
|
||||
return path.Join(GetSiteDir(website.Alias), "upstream")
|
||||
case SiteCorsPath:
|
||||
return path.Join(GteSiteDir(website.Alias), "cors", "cors.conf")
|
||||
return path.Join(GetSiteDir(website.Alias), "cors", "cors.conf")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ const (
|
||||
TaskScopeCustomAppstore = "CustomAppstore"
|
||||
TaskScopeTamper = "Tamper"
|
||||
TaskScopeFileConvert = "Convert"
|
||||
TaskScopeTask = "Task"
|
||||
)
|
||||
|
||||
func GetTaskName(resourceName, operate, scope string) string {
|
||||
|
||||
+8
-11
@@ -4,12 +4,7 @@ go 1.24.9
|
||||
|
||||
require (
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.7
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0
|
||||
github.com/aws/smithy-go v1.24.0
|
||||
github.com/aws/aws-sdk-go v1.55.0
|
||||
github.com/compose-spec/compose-go/v2 v2.9.0
|
||||
github.com/creack/pty v1.1.24
|
||||
github.com/docker/compose/v2 v2.40.2
|
||||
@@ -33,6 +28,7 @@ require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/klauspost/compress v1.18.1
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8
|
||||
github.com/miekg/dns v1.1.69
|
||||
github.com/minio/minio-go/v7 v7.0.74
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||
github.com/opencontainers/image-spec v1.1.1
|
||||
@@ -75,21 +71,21 @@ require (
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
|
||||
github.com/aliyun/credentials-go v1.4.7 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.254 // indirect
|
||||
github.com/bodgit/plumbing v1.2.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.3.0 // indirect
|
||||
@@ -162,6 +158,7 @@ require (
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
@@ -174,7 +171,6 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/miekg/dns v1.1.69 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
@@ -199,6 +195,7 @@ require (
|
||||
github.com/nrdcg/freemyip v0.3.0 // indirect
|
||||
github.com/nrdcg/goacmedns v0.2.0 // indirect
|
||||
github.com/nrdcg/namesilo v0.5.0 // indirect
|
||||
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/ovh/go-ovh v1.9.0 // indirect
|
||||
|
||||
+9
-117
@@ -100,7 +100,6 @@ github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/Ke
|
||||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||
github.com/alibabacloud-go/tea v1.3.13 h1:WhGy6LIXaMbBM6VBYcsDCz6K/TPsT1Ri2hPmmZffZ94=
|
||||
github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||
github.com/alibabacloud-go/tea v1.3.14 h1:/Uzj5ZCFPpbPR+Bs7jfzsyXkYIVsi5TOIuQNOWwc/9c=
|
||||
github.com/alibabacloud-go/tea v1.3.14/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||
@@ -129,91 +128,41 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go v1.55.0 h1:hVALKPjXz33kP1R9nTyJpUK7qF59dO2mleQxUW9mCVE=
|
||||
github.com/aws/aws-sdk-go v1.55.0/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.2 h1:4liUsdEpUUPZs5WVapsJLx5NPmQhQdez7nYFcovrytk=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.2/go.mod h1:l0hs06IFz1eCT+jTacU/qZtC33nvcnLADAPL/XyrkZI=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5 h1:pz3duhAfUgnxbtVhIK39PGF/AHYyrzGEyRD9Og0QrE8=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5/go.mod h1:xmDjzSUs/d0BB7ClzYPAZMmgQdrodNjPPhd6bGASwoE=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.2 h1:qZry8VUyTK4VIo5aEdUcBjPZHL2v4FyQ3QEOaWcFLu4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.2/go.mod h1:YUqm5a1/kBnoK+/NY5WEiMocZihKSo15/tJdmdXnM5g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 h1:xMo63RlqP3ZZydpJDMBsH9uJ10hgHYfQFIk1cHDXrR4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5/go.mod h1:hhbH6oRcou+LpXfA/0vPElh/e0M3aFeOblE1sssAAEk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 h1:WZVR5DbDgxzA0BJeudId89Kmgy6DIU4ORpxwsVHz0qA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14/go.mod h1:Dadl9QO0kHgbrH1GRqGiZdYtW5w+IXXaBNCHTIaheM4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.7 h1:u8danF+A2Zv//pFZvj5V23v/6XG4AxuSVup5s6nxSnI=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.7/go.mod h1:uvLIvU8iJPEU5so7b6lLDNArWpOX6sRBfL5wBABmlfc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 h1:ITi7qiDSv/mSGDSWNpZ4k4Ve0DQR6Ug2SJQ8zEHoDXg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14/go.mod h1:k1xtME53H1b6YpZt74YmwlONMWf4ecM+lut1WQLAF/U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 h1:Hjkh7kE6D81PgrHlE/m9gx+4TyyeLHuY8xJs7yXN5C4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5/go.mod h1:nPRXgyCfAurhyaTMoBMwRBYBhaHI4lNPAnJmjM0Tslc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 h1:FIouAnCE46kyYqyhs0XEBDFFSREtdnr8HQuLPQPLCrY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14/go.mod h1:UTwDc5COa5+guonQU8qBikJo1ZJ4ln2r1MkF7Dqag1E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 h1:FzQE21lNtUor0Fb7QNgnEyiRCBlolLTX/Z1j65S7teM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14/go.mod h1:s1ydyWG9pm3ZwmmYN21HKyG9WzAZhYVW85wMHs5FV6w=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0 h1:W3+0Cbc9awFBr9Yt7nFUkvB4N4e7vVIGtKD1qDttXn4=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0/go.mod h1:Wa3q5R2uwIfIL3HZH+vG1/P9y7CjjfzTgcz5IWXlsZs=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 h1:80pDB3Tpmb2RCSZORrK9/3iQxsd+w6vSzVqpT1FGiwE=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0/go.mod h1:6EZUGGNLPLh5Unt30uEoA+KQcByERfXIkax9qrc80nA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1 h1:OgQy/+0+Kc3khtqiEOk23xQAglXi3Tj0y5doOxbi5tg=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1/go.mod h1:wYNqY3L02Z3IgRYxOBPH9I1zD9Cjh9hI5QOy/eOjQvw=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0 h1:SWTxh/EcUCDVqi/0s26V6pVUq0BBG7kx0tDTmF/hCgA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 h1:MxMBdKTYBjPQChlJhi4qlEueqB1p1KcbTEa7tD5aqPs=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 h1:ksUT5KtgpZd3SAiFJNJ0AFEJVva3gjBmN7eXUZjzUwQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 h1:eYnlt6QxnFINKzwxP5/Ucs1vkG7VT3Iezmvfgc2waUw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 h1:GtsxyiF3Nd3JahRBJbxLCCdYW9ltGQYrFWg8XdkGDd8=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 h1:a5UTtD4mHBU3t0o6aHQZFJTNKVfxFWfPX7J0Lr7G+uY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
||||
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
||||
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/baidubce/bce-sdk-go v0.9.252 h1:TONS/utgfEkDjvHllVZFBrTsjsNhk51rhWuj3ppcL4s=
|
||||
github.com/baidubce/bce-sdk-go v0.9.252/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/baidubce/bce-sdk-go v0.9.254 h1:A7GtBOt7z2lnV7fqlZPZefhcBFg7z6iliUAhEOiIhoE=
|
||||
github.com/baidubce/bce-sdk-go v0.9.254/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@@ -350,8 +299,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
|
||||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
@@ -398,12 +345,8 @@ github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GM
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-acme/alidns-20150109/v4 v4.7.0 h1:PqJ/wR0JTpL4v0Owu1uM7bPQ1Yww0eQLAuuSdLjjQaQ=
|
||||
github.com/go-acme/alidns-20150109/v4 v4.7.0/go.mod h1:btQvB6xZoN6ykKB74cPhiR+uvhrEE2AFVXm6RDmCHm0=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.1 h1:pog3UlF5d+3LPoo1L8u8PqB189recIXX8T7pGoEz18A=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.1/go.mod h1:ZYdN9EN9ikn26SNapxCVjZ65pHT/1qm4fzuJ7QGVX6g=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.3 h1:xXOMRex148wKEHbv7Izn73/HdAxSmz5GOaF4HdnqN+M=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.3/go.mod h1:ZYdN9EN9ikn26SNapxCVjZ65pHT/1qm4fzuJ7QGVX6g=
|
||||
github.com/go-acme/lego/v4 v4.29.0 h1:vKMEtvoKb0gOO9rWO9zMBwE4CgI5A5CWDsK4QEeBqzo=
|
||||
github.com/go-acme/lego/v4 v4.29.0/go.mod h1:rnYyDj1NdDd9y1dHkVuUS97j7bfe9I61+oY9odKaHM8=
|
||||
github.com/go-acme/lego/v4 v4.30.1 h1:tmb6U0lvy8Mc3lQbqKwTat7oAhE8FUYNJ3D0gSg6pJU=
|
||||
github.com/go-acme/lego/v4 v4.30.1/go.mod h1:V7m/Ip+EeFkjOe028+zeH+SwWtESxw1LHelwMIfAjm4=
|
||||
github.com/go-acme/tencentclouddnspod v1.1.25 h1:7H3ZKshkaHzCXfRpAHVB5nvxeDDl2XLeNZfrNHiZj/s=
|
||||
@@ -450,8 +393,6 @@ github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-resty/resty/v2 v2.17.0 h1:pW9DeXcaL4Rrym4EZ8v7L19zZiIlWPg5YXAcVmt+gN0=
|
||||
github.com/go-resty/resty/v2 v2.17.0/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
@@ -601,8 +542,6 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
|
||||
github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@@ -615,8 +554,6 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg
|
||||
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.178 h1:eNVkjzdPMgM2qih9aECiFUI8S9zgpOwXxeBPAwQqtvU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.178/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.180 h1:uia+R3K1izQRGpxTV+bS4q3/ueMW7ProAMWqM6OlqOU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.180/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
|
||||
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
|
||||
@@ -652,7 +589,9 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
@@ -741,8 +680,6 @@ github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60V
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
||||
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/miekg/dns v1.1.69 h1:Kb7Y/1Jo+SG+a2GtfoFUfDkG//csdRPwRLkCsxDG9Sc=
|
||||
github.com/miekg/dns v1.1.69/go.mod h1:7OyjD9nEba5OkqQ/hB4fy3PIoxafSZJtducccIelz3g=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
@@ -827,6 +764,8 @@ github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0
|
||||
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
|
||||
github.com/nrdcg/namesilo v0.5.0 h1:6QNxT/XxE+f5B+7QlfWorthNzOzcGlBLRQxqi6YeBrE=
|
||||
github.com/nrdcg/namesilo v0.5.0/go.mod h1:4UkwlwQfDt74kSGmhLaDylnBrD94IfflnpoEaj6T2qw=
|
||||
github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
|
||||
github.com/nrdcg/porkbun v0.4.0/go.mod h1:/QMskrHEIM0IhC/wY7iTCUgINsxdT2WcOphktJ9+Q54=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
@@ -885,8 +824,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
@@ -933,8 +870,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -952,8 +889,6 @@ github.com/secure-systems-lab/go-securesystemslib v0.6.0 h1:T65atpAVCJQK14UA57LM
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.6.0/go.mod h1:8Mtpo9JKks/qhPG4HGZ2LGMvrPbzuxwfz/f/zLfEWkk=
|
||||
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
|
||||
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
@@ -1008,8 +943,6 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.25/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.3 h1:r05ohLc0LVEpiEQeOJ5QwCiKk6XM9kjTca6+UAbNR/8=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.3/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.12 h1:/ABtv4x4FSGxGW0d6Sc88iQn6Up2LalWKwt/Tj7Dtz8=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.12/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
|
||||
@@ -1022,12 +955,8 @@ github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnH
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
|
||||
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
|
||||
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||
github.com/tomasen/fcgi_client v0.0.0-20180423082037-2bb3d819fd19 h1:ZCmSnT6CLGhfoQ2lPEhL4nsJstKDCw1F1RfN8/smTCU=
|
||||
@@ -1055,8 +984,6 @@ github.com/upyun/go-sdk v2.1.0+incompatible/go.mod h1:eu3F5Uz4b9ZE5bE5QsCL6mgSNW
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
|
||||
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.229 h1:gOkDltTS6Fta8OyfYrbeY9bqCHHyiJuGYNJpR5MR+Fo=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.229/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.230 h1:84/MOF0zUPtAHt3e1+MsFq5qrnQRC+e3XzTUwIOzZxw=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.230/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
@@ -1090,8 +1017,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
@@ -1100,8 +1025,6 @@ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
|
||||
@@ -1112,20 +1035,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
@@ -1182,8 +1097,6 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1229,8 +1142,6 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1289,8 +1200,6 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1300,8 +1209,6 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/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.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
|
||||
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1320,8 +1227,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1403,8 +1308,6 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
@@ -1421,9 +1324,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1441,8 +1343,6 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1506,8 +1406,6 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1578,12 +1476,8 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
|
||||
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -1603,8 +1497,6 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
||||
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
||||
+15
-14
@@ -201,6 +201,7 @@ ErrRemoteExist: 'The remote database already exists with this name, please modif
|
||||
ErrLocalExist: 'The name already exists in the local database, please modify it and try again'
|
||||
RemoteBackup: "To back up the remote database, the local container database service needs to be started first using the image {{ .name }}, please wait..."
|
||||
RemoteRecover: "To restore the remote database, the local container database service needs to be started first using the image {{ .name }}, please wait..."
|
||||
Arg: "Argument"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'The recovery file type does not match the current persistence method, please modify it and try again'
|
||||
@@ -211,7 +212,7 @@ ErrObjectInUsed: "This object is in use and cannot be deleted!"
|
||||
ErrObjectBeDependent: "This image is depended on by other images and cannot be deleted!"
|
||||
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'
|
||||
PruneHelper: "This cleanup removed {{ .name }} {{ .count }} items, freeing {{ .size }} disk space"
|
||||
PruneHelper: "This cleanup {{ .name }} freed disk space {{ .size }}"
|
||||
ImageRemoveHelper: "Deleted image {{ .name }}, freeing {{ .size }} disk space"
|
||||
BuildCache: "Build cache"
|
||||
Volume: "Storage volume"
|
||||
@@ -505,19 +506,19 @@ ErrInstallExtension: "An installation task is already in progress, please wait f
|
||||
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."
|
||||
CommonAlert: "Your 1Panel, {{ .msg }}, please log in to the panel for details."
|
||||
NodeExceptionAlert: "Your 1Panel, {{ .num }} nodes are abnormal, please log in to the panel for details."
|
||||
LicenseExceptionAlert: "Your 1Panel, {{ .num }} licenses are abnormal, please log in to the panel for details."
|
||||
SSHAndPanelLoginAlert: "Your 1Panel, abnormal panel {{ .name }} login from {{ .ip }}, please log in to the panel for details."
|
||||
LicenseExpirationAlert: "Your {{ .node }}{{ .ip }} Panel, the license will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
CronJobFailedAlert: "Your {{ .node }}{{ .ip }} Panel, scheduled task - {{ .name }} execution failed. Please log in to the panel for details."
|
||||
ClamAlert: "Your {{ .node }}{{ .ip }} Panel, the virus scan task detected {{ .num }} infected files. Please log in to the panel for details."
|
||||
WebSiteAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} websites will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
SSLAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} SSL certificates will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
DiskUsedAlert: "Your {{ .node }}{{ .ip }} Panel, disk {{ .name }} usage has reached {{ .used }}. Please log in to the panel for details."
|
||||
ResourceAlert: "Your {{ .node }}{{ .ip }} Panel, the average {{ .name }} usage rate in {{ .time }} minutes is {{ .used }}. Please log in to the panel for details."
|
||||
PanelVersionAlert: "Your {{ .node }}{{ .ip }} Panel, the latest panel version is available for upgrade. Please log in to the panel for details."
|
||||
PanelPwdExpirationAlert: "Your {{ .node }}{{ .ip }} Panel, the panel password will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
CommonAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .msg }}. Please log in to the panel for details."
|
||||
NodeExceptionAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} nodes are abnormal. Please log in to the panel for details."
|
||||
LicenseExceptionAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} licenses are abnormal. Please log in to the panel for details."
|
||||
SSHAndPanelLoginAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .name }} login from {{ .loginIp }} is abnormal. Please log in to the panel for details."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Device {{ .name }} not found"
|
||||
|
||||
+15
-14
@@ -200,6 +200,7 @@ ErrRemoteExist: 'La base de datos remota ya existe con ese nombre, modifíquelo
|
||||
ErrLocalExist: 'El nombre ya existe en la base de datos local, modifíquelo e intente de nuevo'
|
||||
RemoteBackup: "Para hacer una copia de seguridad de la base de datos remota, primero debe iniciarse el servicio de base de datos del contenedor local utilizando la imagen {{ .name }}, espere por favor..."
|
||||
RemoteRecover: "Para restaurar la base de datos remota, primero debe iniciarse el servicio de base de datos del contenedor local utilizando la imagen {{ .name }}, espere por favor..."
|
||||
Arg: "Argumento"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'El tipo de archivo de recuperación no coincide con el método de persistencia actual, modifíquelo e intente'
|
||||
@@ -210,7 +211,7 @@ ErrObjectInUsed: "Este objeto está en uso y no se puede eliminar!"
|
||||
ErrObjectBeDependent: "Esta imagen es dependida por otras imágenes y no se puede eliminar!"
|
||||
ErrPortRules: 'El número de puerto no coincide, ingrese de nuevo'
|
||||
ErrPgImagePull: 'Tiempo de espera al descargar la imagen, configure la aceleración o descárguela manualmente ({{ .name }}) e intente de nuevo'
|
||||
PruneHelper: "Esta limpieza eliminó {{ .name }} {{ .count }} elementos, liberando {{ .size }} de espacio en disco"
|
||||
PruneHelper: "Esta limpieza {{ .name }} liberó espacio en disco {{ .size }}"
|
||||
ImageRemoveHelper: "Imagen {{ .name }} eliminada, liberando {{ .size }} de espacio en disco"
|
||||
BuildCache: "Caché de compilación"
|
||||
Volume: "Volumen de almacenamiento"
|
||||
@@ -495,10 +496,6 @@ ErrAlertPush: 'Error al enviar la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertSave: 'Error al guardar la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertSync: 'Error en la sincronización de la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertRemote: 'Error remoto de alerta, ¡revise e intente de nuevo!'
|
||||
CommonAlert: "Su 1Panel: {{ .msg }}, por favor inicie sesión en el panel para más detalles."
|
||||
NodeExceptionAlert: "Su 1Panel tiene {{ .num }} nodos anómalos, inicie sesión para más detalles."
|
||||
LicenseExceptionAlert: "Su 1Panel tiene {{ .num }} licencias anómalas, inicie sesión para más detalles."
|
||||
SSHAndPanelLoginAlert: "Su 1Panel detectó un inicio de sesión anómalo en el panel {{ .name }} desde {{ .ip }}, revise en el panel para más detalles."
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "Ya hay una tarea de instalación en curso, espere a que termine"
|
||||
@@ -507,15 +504,19 @@ ErrInstallExtension: "Ya hay una tarea de instalación en curso, espere a que te
|
||||
PanelAlertTitle: "Notificación de alerta del panel"
|
||||
TestAlertTitle: "Correo de prueba - Verificar conectividad de correo"
|
||||
TestAlert: "Este es un correo de prueba para verificar que la configuración de envío de correos es correcta."
|
||||
LicenseExpirationAlert: "Su licencia de 1Panel expirará en {{ .day }} días. Inicie sesión para más detalles."
|
||||
CronJobFailedAlert: "Su tarea programada '{{ .name }}' ha fallado. Inicie sesión en el panel para más detalles."
|
||||
ClamAlert: "La tarea de escaneo de virus detectó {{ .num }} archivos infectados. Inicie sesión para detalles."
|
||||
WebSiteAlert: "Hay {{ .num }} sitios web en su 1Panel que expirarán en {{ .day }} días. Inicie sesión para más detalles."
|
||||
SSLAlert: "Hay {{ .num }} certificados SSL en su 1Panel que expirarán en {{ .day }} días. Inicie sesión para detalles."
|
||||
DiskUsedAlert: "El disco '{{ .name }}' de su 1Panel ha utilizado {{ .used }}. Inicie sesión para más detalles."
|
||||
ResourceAlert: "El uso promedio de {{ .name }} en {{ .time }} minutos es de {{ .used }}. Inicie sesión para más detalles."
|
||||
PanelVersionAlert: "Hay una nueva versión de 1Panel disponible. Inicie sesión para actualizar."
|
||||
PanelPwdExpirationAlert: "Su contraseña de 1Panel expirará en {{ .day }} días. Inicie sesión para más detalles."
|
||||
LicenseExpirationAlert: "Su Panel {{ .node }}{{ .ip }}, la licencia expirará en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
CronJobFailedAlert: "Su Panel {{ .node }}{{ .ip }}, la ejecución de la tarea programada {{ .name }} falló. Inicie sesión en el panel para ver los detalles."
|
||||
ClamAlert: "Su Panel {{ .node }}{{ .ip }}, la tarea de escaneo antivirus detectó {{ .num }} archivos infectados. Inicie sesión en el panel para ver los detalles."
|
||||
WebSiteAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} sitios web expirarán en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
SSLAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} certificados SSL expirarán en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
DiskUsedAlert: "Su Panel {{ .node }}{{ .ip }}, el uso del disco {{ .name }} ha alcanzado {{ .used }}. Inicie sesión en el panel para ver los detalles."
|
||||
ResourceAlert: "Su Panel {{ .node }}{{ .ip }}, la tasa de uso promedio de {{ .name }} en {{ .time }} minutos es {{ .used }}. Inicie sesión en el panel para ver los detalles."
|
||||
PanelVersionAlert: "Su Panel {{ .node }}{{ .ip }}, está disponible la última versión del panel para actualizar. Inicie sesión en el panel para ver los detalles."
|
||||
PanelPwdExpirationAlert: "Su Panel {{ .node }}{{ .ip }}, la contraseña del panel expirará en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
CommonAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .msg }}. Inicie sesión en el panel para ver los detalles."
|
||||
NodeExceptionAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} nodos son anómalos. Inicie sesión en el panel para ver los detalles."
|
||||
LicenseExceptionAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} licencias son anómalas. Inicie sesión en el panel para ver los detalles."
|
||||
SSHAndPanelLoginAlert: "Su Panel {{ .node }}{{ .ip }}, el inicio de sesión {{ .name }} desde {{ .loginIp }} es anómalo. Inicie sesión en el panel para ver los detalles."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Dispositivo {{ .name }} no encontrado"
|
||||
|
||||
+15
-14
@@ -200,6 +200,7 @@ ErrRemoteExist: 'この名前のリモート データベースは既に存在
|
||||
ErrLocalExist: '名前はローカル データベースに既に存在します。変更してもう一度お試しください'
|
||||
RemoteBackup: "リモートデータベースをバックアップするには、まずイメージ {{ .name }} を使用してローカルコンテナデータベースサービスを起動する必要があります。しばらくお待ちください..."
|
||||
RemoteRecover: "リモートデータベースを復元するには、まずイメージ {{ .name }} を使用してローカルコンテナデータベースサービスを起動する必要があります。しばらくお待ちください..."
|
||||
Arg: "引数"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'リカバリ ファイルの種類が現在の永続化方法と一致しません。変更して再試行してください'
|
||||
@@ -210,7 +211,7 @@ ErrObjectInUsed: "このオブジェクトは使用中であり、削除でき
|
||||
ErrObjectBeDependent: "このイメージは他のイメージに依存されているため、削除できません!"
|
||||
ErrPortRules: 'ポート番号が一致しません。再入力してください。'
|
||||
ErrPgImagePull: 'イメージのプルがタイムアウトしました。イメージのアクセラレーションを設定するか、{{ .name }} イメージを手動でプルして再試行してください'
|
||||
PruneHelper: "今回のクリーンアップで{{ .name }} {{ .count }}個を削除し、{{ .size }}のディスク領域を解放しました"
|
||||
PruneHelper: "今回のクリーンアップ {{ .name }} でディスク領域 {{ .size }} を解放しました"
|
||||
ImageRemoveHelper: "イメージ{{ .name }}を削除し、{{ .size }}のディスク領域を解放しました"
|
||||
BuildCache: "ビルドキャッシュ"
|
||||
Volume: "ストレージボリューム"
|
||||
@@ -504,19 +505,19 @@ ErrInstallExtension: "インストールタスクが進行中です、タスク
|
||||
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 }} 日後に期限切れとなります。詳細はパネルでご確認ください。"
|
||||
CommonAlert: "お使いの1Panel、{{ .msg }}、詳細はパネルにログインしてご確認ください。"
|
||||
NodeExceptionAlert: "お使いの1Panel、{{ .num }}個のノードに異常があります。詳細はパネルにログインしてご確認ください。"
|
||||
LicenseExceptionAlert: "お使いの1Panel、{{ .num }}個のライセンスに異常があります。詳細はパネルにログインしてご確認ください。"
|
||||
SSHAndPanelLoginAlert: "お使いの1Panel、パネル{{ .name }}が{{ .ip }}から異常ログインしました。詳細はパネルにログインしてご確認ください。"
|
||||
LicenseExpirationAlert: "あなたの {{ .node }}{{ .ip }} パネル、ライセンスは {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
CronJobFailedAlert: "あなたの {{ .node }}{{ .ip }} パネル、スケジュールタスク {{ .name }} の実行に失敗しました。詳細はパネルにログインしてご確認ください。"
|
||||
ClamAlert: "あなたの {{ .node }}{{ .ip }} パネル、ウイルススキャンタスクで {{ .num }} 個の感染ファイルを検出しました。詳細はパネルにログインしてご確認ください。"
|
||||
WebSiteAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 個のウェブサイトが {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
SSLAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 枚のSSL証明書が {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
DiskUsedAlert: "あなたの {{ .node }}{{ .ip }} パネル、ディスク {{ .name }} の使用率が {{ .used }} に達しました。詳細はパネルにログインしてご確認ください。"
|
||||
ResourceAlert: "あなたの {{ .node }}{{ .ip }} パネル、過去 {{ .time }} 分間の {{ .name }} 平均使用率は {{ .used }} です。詳細はパネルにログインしてご確認ください。"
|
||||
PanelVersionAlert: "あなたの {{ .node }}{{ .ip }} パネル、最新バージョンがアップグレード可能です。詳細はパネルにログインしてご確認ください。"
|
||||
PanelPwdExpirationAlert: "あなたの {{ .node }}{{ .ip }} パネル、パネルパスワードは {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
CommonAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .msg }}。詳細はパネルにログインしてご確認ください。"
|
||||
NodeExceptionAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 個のノードに異常が発生しています。詳細はパネルにログインしてご確認ください。"
|
||||
LicenseExceptionAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 個のライセンスに異常が発生しています。詳細はパネルにログインしてご確認ください。"
|
||||
SSHAndPanelLoginAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .loginIp }} からの {{ .name }} ログインに異常があります。詳細はパネルにログインしてご確認ください。"
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "デバイス {{ .name }} が見つかりません"
|
||||
|
||||
+15
-14
@@ -201,6 +201,7 @@ ErrRemoteExist: '이 이름을 가진 원격 데이터베이스가 이미 존재
|
||||
ErrLocalExist: '이름이 로컬 데이터베이스에 이미 존재합니다. 이름을 수정하고 다시 시도하세요'
|
||||
RemoteBackup: "원격 데이터베이스를 백업하려면 먼저 이미지 {{ .name }}을(를) 사용하여 로컬 컨테이너 데이터베이스 서비스를 시작해야 합니다. 잠시만 기다려 주세요..."
|
||||
RemoteRecover: "원격 데이터베이스를 복원하려면 먼저 이미지 {{ .name }}을(를) 사용하여 로컬 컨테이너 데이터베이스 서비스를 시작해야 합니다. 잠시만 기다려 주세요..."
|
||||
Arg: "인수"
|
||||
|
||||
#레디스
|
||||
ErrTypeOfRedis: '복구 파일 유형이 현재 지속성 방법과 일치하지 않습니다. 수정하고 다시 시도하세요'
|
||||
@@ -211,7 +212,7 @@ ErrObjectInUsed: "이 객체는 사용 중이어서 삭제할 수 없습니다!"
|
||||
ErrObjectBeDependent: "이 이미지는 다른 이미지에 의존되어 있어 삭제할 수 없습니다!"
|
||||
ErrPortRules: '포트 번호가 일치하지 않습니다. 다시 입력하세요!'
|
||||
ErrPgImagePull: '이미지 풀링 시간이 초과되었습니다. 이미지 가속을 구성하거나 {{ .name }} 이미지를 수동으로 풀링한 다음 다시 시도하세요.'
|
||||
PruneHelper: "이번 정리에서 {{ .name }} {{ .count }}개를 제거하여 {{ .size }} 디스크 공간을 확보했습니다"
|
||||
PruneHelper: "이번 정리 {{ .name }}가 디스크 공간 {{ .size }}을(를) 확보했습니다"
|
||||
ImageRemoveHelper: "이미지 {{ .name }} 삭제, {{ .size }} 디스크 공간 확보"
|
||||
BuildCache: "빌드 캐시"
|
||||
Volume: "스토리지 볼륨"
|
||||
@@ -505,19 +506,19 @@ ErrInstallExtension: "이미 설치 작업이 진행 중입니다. 작업이 완
|
||||
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 }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||
CommonAlert: "귀하의 1Panel, {{ .msg }}. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
NodeExceptionAlert: "귀하의 1Panel, {{ .num }}개의 노드에 이상이 있습니다. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
LicenseExceptionAlert: "귀하의 1Panel, {{ .num }}개의 라이선스에 이상이 있습니다. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
SSHAndPanelLoginAlert: "귀하의 1Panel, 패널 {{ .name }}이(가) {{ .ip }}에서 비정상 로그인했습니다. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
LicenseExpirationAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 라이센스가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
CronJobFailedAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 예약 작업 {{ .name }} 실행에 실패했습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
ClamAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 바이러스 스캔 작업에서 {{ .num }}개의 감염 파일이 감지되었습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
WebSiteAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 웹사이트가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
SSLAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 SSL 인증서가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
DiskUsedAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 디스크 {{ .name }} 사용률이 {{ .used }}에 도달했습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
ResourceAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 최근 {{ .time }}분간 {{ .name }} 평균 사용률은 {{ .used }}입니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
PanelVersionAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 최신 버전으로 업그레이드할 수 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
PanelPwdExpirationAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 패널 비밀번호가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
CommonAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .msg }}。자세한 내용은 패널에 로그인하십시오."
|
||||
NodeExceptionAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 노드에 이상이 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
LicenseExceptionAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 라이센스에 이상이 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
SSHAndPanelLoginAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .loginIp }}에서의 {{ .name }} 로그인에 이상이 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "장치 {{ .name }} 을(를) 찾을 수 없습니다"
|
||||
|
||||
+15
-14
@@ -201,6 +201,7 @@ ErrRemoteExist: 'Pangkalan data jauh sudah wujud dengan nama ini, sila ubah suai
|
||||
ErrLocalExist: 'Nama sudah wujud dalam pangkalan data tempatan, sila ubah suai dan cuba lagi'
|
||||
RemoteBackup: "Untuk menyandarkan pangkalan data jauh, perkhidmatan pangkalan data bekas tempatan perlu dimulakan terlebih dahulu menggunakan imej {{ .name }}, sila tunggu..."
|
||||
RemoteRecover: "Untuk memulihkan pangkalan data jauh, perkhidmatan pangkalan data bekas tempatan perlu dimulakan terlebih dahulu menggunakan imej {{ .name }}, sila tunggu..."
|
||||
Arg: "Hujah"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'Jenis fail pemulihan tidak sepadan dengan kaedah kegigihan semasa, sila ubah suai dan cuba lagi'
|
||||
@@ -211,7 +212,7 @@ ErrObjectInUsed: "Objek ini sedang digunakan dan tidak boleh dipadam!"
|
||||
ErrObjectBeDependent: "Imej ini digantungkan oleh imej lain dan tidak boleh dipadam!"
|
||||
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'
|
||||
PruneHelper: "Pembersihan ini membuang {{ .name }} {{ .count }} item, membebaskan {{ .size }} ruang cakera"
|
||||
PruneHelper: "Pembersihan ini {{ .name }} membebaskan ruang cakera {{ .size }}"
|
||||
ImageRemoveHelper: "Padam imej {{ .name }}, membebaskan {{ .size }} ruang cakera"
|
||||
BuildCache: "Cache binaan"
|
||||
Volume: "Jilid storan"
|
||||
@@ -505,19 +506,19 @@ ErrInstallExtension: "Tugas pemasangan sudah sedang berjalan, silakan tunggu tug
|
||||
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."
|
||||
CommonAlert: "1Panel anda, {{ .msg }}, sila log masuk ke panel untuk maklumat lanjut."
|
||||
NodeExceptionAlert: "1Panel anda, {{ .num }} nod bermasalah, sila log masuk ke panel untuk maklumat lanjut."
|
||||
LicenseExceptionAlert: "1Panel anda, {{ .num }} lesen bermasalah, sila log masuk ke panel untuk maklumat lanjut."
|
||||
SSHAndPanelLoginAlert: "1Panel anda, log masuk panel {{ .name }} yang tidak normal dari {{ .ip }}, sila log masuk ke panel untuk maklumat lanjut."
|
||||
LicenseExpirationAlert: "Panel {{ .node }}{{ .ip }} Anda, lesen akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
CronJobFailedAlert: "Panel {{ .node }}{{ .ip }} Anda, tugas jadual {{ .name }} gagal dilaksanakan. Sila log masuk ke panel untuk butiran lanjut."
|
||||
ClamAlert: "Panel {{ .node }}{{ .ip }} Anda, tugas imbasan virus mengesan {{ .num }} fail yang dijangkiti. Sila log masuk ke panel untuk butiran lanjut."
|
||||
WebSiteAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} laman web akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
SSLAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} sijil SSL akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
DiskUsedAlert: "Panel {{ .node }}{{ .ip }} Anda, penggunaan cakera {{ .name }} telah mencapai {{ .used }}. Sila log masuk ke panel untuk butiran lanjut."
|
||||
ResourceAlert: "Panel {{ .node }}{{ .ip }} Anda, kadar penggunaan purata {{ .name }} dalam tempoh {{ .time }} minit ialah {{ .used }}. Sila log masuk ke panel untuk butiran lanjut."
|
||||
PanelVersionAlert: "Panel {{ .node }}{{ .ip }} Anda, versi panel terkini tersedia untuk dinaik taraf. Sila log masuk ke panel untuk butiran lanjut."
|
||||
PanelPwdExpirationAlert: "Panel {{ .node }}{{ .ip }} Anda, kata laluan panel akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
CommonAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .msg }}. Sila log masuk ke panel untuk butiran lanjut."
|
||||
NodeExceptionAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} nod tidak normal. Sila log masuk ke panel untuk butiran lanjut."
|
||||
LicenseExceptionAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} lesen tidak normal. Sila log masuk ke panel untuk butiran lanjut."
|
||||
SSHAndPanelLoginAlert: "Panel {{ .node }}{{ .ip }} Anda, log masuk {{ .name }} dari {{ .loginIp }} tidak normal. Sila log masuk ke panel untuk butiran lanjut."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Peranti {{ .name }} tidak ditemui"
|
||||
|
||||
+15
-14
@@ -201,6 +201,7 @@ ErrRemoteExist: 'O banco de dados remoto já existe com este nome, modifique-o e
|
||||
ErrLocalExist: 'O nome já existe no banco de dados local, modifique-o e tente novamente'
|
||||
RemoteBackup: "Para fazer backup do banco de dados remoto, o serviço de banco de dados do contêiner local precisa ser iniciado primeiro usando a imagem {{ .name }}, por favor aguarde..."
|
||||
RemoteRecover: "Para restaurar o banco de dados remoto, o serviço de banco de dados do contêiner local precisa ser iniciado primeiro usando a imagem {{ .name }}, por favor aguarde..."
|
||||
Arg: "Argumento"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'O tipo de arquivo de recuperação não corresponde ao método de persistência atual, modifique-o e tente novamente'
|
||||
@@ -211,7 +212,7 @@ ErrObjectInUsed: "Este objeto está em uso e não pode ser excluído!"
|
||||
ErrObjectBeDependent: "Esta imagem é dependida por outras imagens e não pode ser excluída!"
|
||||
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'
|
||||
PruneHelper: "Esta limpeza removeu {{ .name }} {{ .count }} itens, liberando {{ .size }} de espaço em disco"
|
||||
PruneHelper: "Esta limpeza {{ .name }} liberou espaço em disco {{ .size }}"
|
||||
ImageRemoveHelper: "Excluída a imagem {{ .name }}, liberando {{ .size }} de espaço em disco"
|
||||
BuildCache: "Cache de construção"
|
||||
Volume: "Volume de armazenamento"
|
||||
@@ -505,19 +506,19 @@ ErrInstallExtension: "Já existe uma tarefa de instalação em andamento, aguard
|
||||
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."
|
||||
CommonAlert: "Seu 1Panel, {{ .msg }}. Para mais detalhes, faça login no painel."
|
||||
NodeExceptionAlert: "Seu 1Panel, {{ .num }} nós estão com problemas. Para mais detalhes, faça login no painel."
|
||||
LicenseExceptionAlert: "Seu 1Panel, {{ .num }} licenças estão com problemas. Para mais detalhes, faça login no painel."
|
||||
SSHAndPanelLoginAlert: "Seu 1Panel, login anormal no painel {{ .name }} a partir de {{ .ip }}. Para mais detalhes, faça login no painel."
|
||||
LicenseExpirationAlert: "Seu Painel {{ .node }}{{ .ip }}, a licença expirará em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
CronJobFailedAlert: "Seu Painel {{ .node }}{{ .ip }}, a execução da tarefa agendada {{ .name }} falhou. Faça login no painel para obter detalhes."
|
||||
ClamAlert: "Seu Painel {{ .node }}{{ .ip }}, a tarefa de verificação de vírus detectou {{ .num }} arquivos infectados. Faça login no painel para obter detalhes."
|
||||
WebSiteAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} sites expirarão em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
SSLAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} certificados SSL expirarão em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
DiskUsedAlert: "Seu Painel {{ .node }}{{ .ip }}, o uso do disco {{ .name }} atingiu {{ .used }}. Faça login no painel para obter detalhes."
|
||||
ResourceAlert: "Seu Painel {{ .node }}{{ .ip }}, a taxa de uso médio do {{ .name }} nos últimos {{ .time }} minutos é {{ .used }}. Faça login no painel para obter detalhes."
|
||||
PanelVersionAlert: "Seu Painel {{ .node }}{{ .ip }}, a versão mais recente do painel está disponível para atualização. Faça login no painel para obter detalhes."
|
||||
PanelPwdExpirationAlert: "Seu Painel {{ .node }}{{ .ip }}, a senha do painel expirará em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
CommonAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .msg }}. Faça login no painel para obter detalhes."
|
||||
NodeExceptionAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} nós estão anormais. Faça login no painel para obter detalhes."
|
||||
LicenseExceptionAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} licenças estão anormais. Faça login no painel para obter detalhes."
|
||||
SSHAndPanelLoginAlert: "Seu Painel {{ .node }}{{ .ip }}, o login {{ .name }} a partir de {{ .loginIp }} é anormal. Faça login no painel para obter detalhes."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Dispositivo {{ .name }} não encontrado"
|
||||
|
||||
+15
-14
@@ -201,6 +201,7 @@ ErrRemoteExist: 'Удаленная база данных с таким имен
|
||||
ErrLocalExist: 'Имя уже существует в локальной базе данных, измените его и повторите попытку'
|
||||
RemoteBackup: "Для резервного копирования удаленной базы данных необходимо сначала запустить службу базы данных локального контейнера с помощью образа {{ .name }}, пожалуйста, подождите..."
|
||||
RemoteRecover: "Для восстановления удаленной базы данных необходимо сначала запустить службу базы данных локального контейнера с помощью образа {{ .name }}, пожалуйста, подождите..."
|
||||
Arg: "Аргумент"
|
||||
|
||||
#редис
|
||||
ErrTypeOfRedis: 'Тип файла восстановления не соответствует текущему методу сохранения. Измените его и повторите попытку'
|
||||
@@ -211,7 +212,7 @@ ErrObjectInUsed: "Этот объект используется и не мож
|
||||
ErrObjectBeDependent: "Этот образ зависит от других образов и не может быть удален!"
|
||||
ErrPortRules: 'Номер порта не совпадает, введите заново!'
|
||||
ErrPgImagePull: 'Время извлечения изображения истекло. Настройте ускорение изображения или вручную извлеките изображение {{ .name }} и повторите попытку'
|
||||
PruneHelper: "Очистка удалила {{ .name }} в количестве {{ .count }}, освободив {{ .size }} дискового пространства"
|
||||
PruneHelper: "Эта очистка {{ .name }} освободила дисковое пространство {{ .size }}"
|
||||
ImageRemoveHelper: "Удалён образ {{ .name }}, освобождено {{ .size }} дискового пространства"
|
||||
BuildCache: "Кэш сборки"
|
||||
Volume: "Том хранилища"
|
||||
@@ -505,19 +506,19 @@ ErrInstallExtension: "Уже выполняется задача установ
|
||||
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 }} дней. Подробности смотрите в панели."
|
||||
CommonAlert: "Ваш 1Panel, {{ .msg }}. Подробности смотрите, войдя в панель."
|
||||
NodeExceptionAlert: "Ваш 1Panel, {{ .num }} узлов работают неправильно. Подробности смотрите, войдя в панель."
|
||||
LicenseExceptionAlert: "Ваш 1Panel, {{ .num }} лицензий работают неправильно. Подробности смотрите, войдя в панель."
|
||||
SSHAndPanelLoginAlert: "Ваш 1Panel, обнаружен аномальный вход в панель {{ .name }} с {{ .ip }}. Подробности смотрите, войдя в панель."
|
||||
LicenseExpirationAlert: "Ваш панель {{ .node }}{{ .ip }}, лицензия истечет через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
CronJobFailedAlert: "Ваш панель {{ .node }}{{ .ip }}, выполнение запланированной задачи {{ .name }} не удалось. Войдите в панель для получения деталей."
|
||||
ClamAlert: "Ваш панель {{ .node }}{{ .ip }}, задача сканирования на вирусы обнаружила {{ .num }} зараженных файлов. Войдите в панель для получения деталей."
|
||||
WebSiteAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} веб-сайтов истечут через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
SSLAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} сертификатов SSL истечут через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
DiskUsedAlert: "Ваш панель {{ .node }}{{ .ip }}, использование диска {{ .name }} достигло {{ .used }}. Войдите в панель для получения деталей."
|
||||
ResourceAlert: "Ваш панель {{ .node }}{{ .ip }}, средний уровень использования {{ .name }} за {{ .time }} минут составляет {{ .used }}. Войдите в панель для получения деталей."
|
||||
PanelVersionAlert: "Ваш панель {{ .node }}{{ .ip }}, доступна последняя версия панели для обновления. Войдите в панель для получения деталей."
|
||||
PanelPwdExpirationAlert: "Ваш панель {{ .node }}{{ .ip }}, пароль панели истечет через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
CommonAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .msg }}. Войдите в панель для получения деталей."
|
||||
NodeExceptionAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} узлов работают с ошибками. Войдите в панель для получения деталей."
|
||||
LicenseExceptionAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} лицензий имеют ошибки. Войдите в панель для получения деталей."
|
||||
SSHAndPanelLoginAlert: "Ваш панель {{ .node }}{{ .ip }}, вход {{ .name }} с адреса {{ .loginIp }} является аномальным. Войдите в панель для получения деталей."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Устройство {{ .name }} не найдено"
|
||||
|
||||
+15
-14
@@ -202,6 +202,7 @@ ErrRemoteExist: 'Uzak veritabanında bu adla zaten mevcut, lütfen değiştirin
|
||||
ErrLocalExist: 'Yerel veritabanında bu ad zaten mevcut, lütfen değiştirin ve tekrar deneyin'
|
||||
RemoteBackup: "Uzak veritabanını yedeklemek için önce {{ .name }} görüntüsü kullanılarak yerel konteyner veritabanı hizmetinin başlatılması gerekiyor, lütfen bekleyin..."
|
||||
RemoteRecover: "Uzak veritabanını geri yüklemek için önce {{ .name }} görüntüsü kullanılarak yerel konteyner veritabanı hizmetinin başlatılması gerekiyor, lütfen bekleyin..."
|
||||
Arg: "Argüman"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'Kurtarma dosyası türü mevcut kalıcılık yöntemiyle eşleşmiyor, lütfen değiştirin ve tekrar deneyin'
|
||||
@@ -212,7 +213,7 @@ ErrObjectInUsed: "Bu nesne kullanımda ve silinemez!"
|
||||
ErrObjectBeDependent: "Bu görüntü diğer görüntüler tarafından bağımlıdır ve silinemez!"
|
||||
ErrPortRules: 'Port numarası eşleşmiyor, lütfen yeniden girin!'
|
||||
ErrPgImagePull: 'Image çekme zaman aşımı, lütfen image hızlandırma yapılandırın veya manuel olarak {{ .name }} imageını çekin ve tekrar deneyin'
|
||||
PruneHelper: "Bu temizleme {{ .name }} {{ .count }} öğe kaldırdı, {{ .size }} disk alanı boşalttı"
|
||||
PruneHelper: "Bu temizlik {{ .name }} disk alanı {{ .size }} boşalttı"
|
||||
ImageRemoveHelper: "{{ .name }} imajı silindi, {{ .size }} disk alanı boşalttı"
|
||||
BuildCache: "Derleme önbelleği"
|
||||
Volume: "Depolama hacmi"
|
||||
@@ -506,19 +507,19 @@ ErrInstallExtension: "Zaten devam eden bir kurulum görevi var, görevin bitmesi
|
||||
PanelAlertTitle: "Panel Uyarı Bildirimi"
|
||||
TestAlertTitle: "Test E-postası - E-posta Bağlantısını Doğrula"
|
||||
TestAlert: "Bu, e-posta gönderim ayarlarınızın doğru yapılandırıldığını doğrulamak için gönderilen bir test e-postasıdır."
|
||||
LicenseExpirationAlert: "1Panel lisansınız {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
CronJobFailedAlert: "1Panel zamanlanmış görevi '{{ .name }}' başarısız oldu. Detaylar için panele giriş yapın."
|
||||
ClamAlert: "1Panel virüs taraması {{ .num }} enfekte dosya tespit etti. Detaylar için panele giriş yapın."
|
||||
WebSiteAlert: "1Panel üzerindeki {{ .num }} web sitesi {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
SSLAlert: "1Panel üzerindeki {{ .num }} SSL sertifikası {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
DiskUsedAlert: "1Panel diski '{{ .name }}' {{ .used }} kullanıldı. Detaylar için panele giriş yapın."
|
||||
ResourceAlert: "1Panel üzerinde ortalama {{ .time }} dakikalık {{ .name }} kullanım oranı {{ .used }}. Detaylar için panele giriş yapın."
|
||||
PanelVersionAlert: "1Panel için yeni bir sürüm mevcut. Güncellemek için panele giriş yapın."
|
||||
PanelPwdExpirationAlert: "1Panel şifreniz {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
CommonAlert: "1Panel'iniz, {{ .msg }}. Detaylar için panele giriş yapınız."
|
||||
NodeExceptionAlert: "1Panel'iniz, {{ .num }} düğümde sorun var. Detaylar için panele giriş yapınız."
|
||||
LicenseExceptionAlert: "1Panel'iniz, {{ .num }} lisansda sorun var. Detaylar için panele giriş yapınız."
|
||||
SSHAndPanelLoginAlert: "1Panel'iniz, {{ .ip }} adresinden {{ .name }} paneline anormal giriş tespit edildi. Detaylar için panele giriş yapınız."
|
||||
LicenseExpirationAlert: "Paneliniz {{ .node }}{{ .ip }}, lisans {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
CronJobFailedAlert: "Paneliniz {{ .node }}{{ .ip }}, zamanlanmış görev {{ .name }} çalıştırma başarısız oldu. Detaylar için paneline giriş yapın."
|
||||
ClamAlert: "Paneliniz {{ .node }}{{ .ip }}, virüs tarama görevi {{ .num }} enfekte dosya tespit etti. Detaylar için paneline giriş yapın."
|
||||
WebSiteAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} web sitesi {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
SSLAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} SSL sertifikası {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
DiskUsedAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .name }} diski kullanımı {{ .used }}'a ulaştı. Detaylar için paneline giriş yapın."
|
||||
ResourceAlert: "Paneliniz {{ .node }}{{ .ip }}, son {{ .time }} dakika içindeki ortalama {{ .name }} kullanım oranı {{ .used }}'dır. Detaylar için paneline giriş yapın."
|
||||
PanelVersionAlert: "Paneliniz {{ .node }}{{ .ip }}, en son panel sürümü yükseltme için mevcut. Detaylar için paneline giriş yapın."
|
||||
PanelPwdExpirationAlert: "Paneliniz {{ .node }}{{ .ip }}, panel şifresi {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
CommonAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .msg }}. Detaylar için paneline giriş yapın."
|
||||
NodeExceptionAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} düğüm anormal durumda. Detaylar için paneline giriş yapın."
|
||||
LicenseExceptionAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} lisans anormal durumda. Detaylar için paneline giriş yapın."
|
||||
SSHAndPanelLoginAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .loginIp }} adresinden {{ .name }} girişi anormal. Detaylar için paneline giriş yapın."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Cihaz {{ .name }} bulunamadı"
|
||||
|
||||
@@ -200,6 +200,7 @@ ErrRemoteExist: '遠端資料庫已存在該名稱,請修改後重試'
|
||||
ErrLocalExist: '本機資料庫已存在該名稱,請修改後重試'
|
||||
RemoteBackup: "備份遠端資料庫需要先使用映像 {{ .name }} 啟動本機容器資料庫服務,請稍候..."
|
||||
RemoteRecover: "恢復遠端資料庫需要先使用映像 {{ .name }} 啟動本機容器資料庫服務,請稍候..."
|
||||
Arg: "參數"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: '復原檔案類型與目前持久化方式不符,請修改後重試'
|
||||
@@ -210,7 +211,7 @@ ErrObjectInUsed: "該對象正被使用,無法刪除!"
|
||||
ErrObjectBeDependent: "該映像正被其他映像所依賴,無法刪除!"
|
||||
ErrPortRules: '連接埠數目不匹配,請重新輸入!'
|
||||
ErrPgImagePull: '鏡像拉取逾時,請配置鏡像加速或手動拉取{{ .name }} 鏡像後重試'
|
||||
PruneHelper: "本次清理 {{ .name }} {{ .count }} 個,釋放磁碟空間 {{ .size }}"
|
||||
PruneHelper: "本次清理 {{ .name }} 釋放磁碟空間 {{ .size }}"
|
||||
ImageRemoveHelper: "刪除鏡像 {{ .name }} ,釋放磁碟空間 {{ .size }}"
|
||||
BuildCache: "構建快取"
|
||||
Volume: "磁碟區"
|
||||
@@ -504,19 +505,19 @@ ErrInstallExtension: "已有安裝任務正在進行,請等待任務結束"
|
||||
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 }} 天後到期,詳情請登入面板查看。"
|
||||
CommonAlert: "您的 1Panel 面板,{{ .msg }},詳情請登入面板查看。"
|
||||
NodeExceptionAlert: "您的 1Panel 面板,{{ .num }} 個節點存在異常,詳情請登入面板查看。"
|
||||
LicenseExceptionAlert: "您的 1Panel 面板,{{ .num }} 個許可證存在異常,詳情請登入面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 1Panel 面板,面板{{ .name }}從 {{ .ip }} 登入異常,詳情請登入面板查看。"
|
||||
LicenseExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,授權將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CronJobFailedAlert: "您的 {{ .node }}{{ .ip }} 面板,排程任務{{ .name }}執行失敗,詳情請登入面板查看。"
|
||||
ClamAlert: "您的 {{ .node }}{{ .ip }} 面板,病毒掃描任務偵測到 {{ .num }} 個感染檔案,詳情請登入面板查看。"
|
||||
WebSiteAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 個網站將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
SSLAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 張SSL憑證將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
DiskUsedAlert: "您的 {{ .node }}{{ .ip }} 面板,磁碟 {{ .name }} 使用率已達 {{ .used }},詳情請登入面板查看。"
|
||||
ResourceAlert: "您的 {{ .node }}{{ .ip }} 面板,過去 {{ .time }} 分鐘內 {{ .name }} 平均使用率為 {{ .used }},詳情請登入面板查看。"
|
||||
PanelVersionAlert: "您的 {{ .node }}{{ .ip }} 面板,已有最新版本可供升級,詳情請登入面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,面板密碼將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CommonAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .msg }},詳情請登入面板查看。"
|
||||
NodeExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 個節點出現異常,詳情請登入面板查看。"
|
||||
LicenseExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 個授權出現異常,詳情請登入面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 {{ .node }}{{ .ip }} 面板,來自 {{ .loginIp }} 的 {{ .name }} 登入出現異常,詳情請登入面板查看。"
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "裝置 {{ .name }} 未找到"
|
||||
|
||||
+15
-14
@@ -201,6 +201,7 @@ ErrRemoteExist: "远程数据库已存在该名称,请修改后重试"
|
||||
ErrLocalExist: "本地数据库已存在该名称,请修改后重试"
|
||||
RemoteBackup: "备份远程数据库需要先使用镜像 {{ .name }} 启动本地容器数据库服务,请稍候..."
|
||||
RemoteRecover: "恢复远程数据库需要先使用镜像 {{ .name }} 启动本地容器数据库服务,请稍候..."
|
||||
Arg: "参数"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
|
||||
@@ -211,7 +212,7 @@ ErrObjectInUsed: "该对象正被使用,无法删除!"
|
||||
ErrObjectBeDependent: "该镜像正被其他镜像所依赖,无法删除!"
|
||||
ErrPortRules: "端口数目不匹配,请重新输入!"
|
||||
ErrPgImagePull: "镜像拉取超时,请配置镜像加速或手动拉取 {{ .name }} 镜像后重试"
|
||||
PruneHelper: "本次清理 {{ .name }} {{ .count }} 个,释放磁盘空间 {{ .size }}"
|
||||
PruneHelper: "本次清理 {{ .name }} 释放磁盘空间 {{ .size }}"
|
||||
ImageRemoveHelper: "删除镜像 {{ .name }} ,释放磁盘空间 {{ .size }}"
|
||||
BuildCache: "构建缓存"
|
||||
Volume: "存储卷"
|
||||
@@ -506,19 +507,19 @@ ErrInstallExtension: "已有安装任务正在进行,请等待任务结束"
|
||||
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 }} 天后到期,详情请登录面板查看。"
|
||||
CommonAlert: "您的 1Panel 面板,{{ .msg }},详情请登录面板查看。"
|
||||
NodeExceptionAlert: "您的 1Panel 面板,{{ .num }} 个节点存在异常,详情请登录面板查看。"
|
||||
LicenseExceptionAlert: "您的 1Panel 面板,{{ .num }} 个许可证存在异常,详情请登录面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 1Panel 面板,面板{{ .name }}登录{{ .ip }}异常,详情请登录面板查看。"
|
||||
LicenseExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,许可证将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
CronJobFailedAlert: "您的 {{ .node }}{{ .ip }} 面板,计划任务-{{ .name }}执行失败,详情请登录面板查看。"
|
||||
ClamAlert: "您的 {{ .node }}{{ .ip }} 面板,病毒扫描任务发现 {{ .num }} 个感染文件,详情请登录面板查看。"
|
||||
WebSiteAlert: "您的 {{ .node }}{{ .ip }} 面板,有 {{ .num }} 个网站将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
SSLAlert: "您的 {{ .node }}{{ .ip }} 面板,有 {{ .num }} 张SSL证书将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
DiskUsedAlert: "您的 {{ .node }}{{ .ip }} 面板,磁盘 {{ .name }} 已使用 {{ .used }},详情请登录面板查看。"
|
||||
ResourceAlert: "您的 {{ .node }}{{ .ip }} 面板,平均 {{ .time }} 分钟内的 {{ .name }} 使用率为 {{ .used }},详情请登录面板查看。"
|
||||
PanelVersionAlert: "您的 {{ .node }}{{ .ip }} 面板,有最新面板版本可供升级,详情请登录面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,面板密码将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
CommonAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .msg }},详情请登录面板查看。"
|
||||
NodeExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 个节点存在异常,详情请登录面板查看。"
|
||||
LicenseExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 个许可证存在异常,详情请登录面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 {{ .node }}{{ .ip }} 面板,面板{{ .name }}登录{{ .loginIp }}异常,详情请登录面板查看。"
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "设备 {{ .name }} 未找到"
|
||||
|
||||
@@ -18,6 +18,7 @@ func Init() {
|
||||
if !needInit() {
|
||||
return
|
||||
}
|
||||
InitPingStatus()
|
||||
global.LOG.Info("initializing firewall settings...")
|
||||
client, err := firewall.NewFirewallClient()
|
||||
if err != nil {
|
||||
@@ -78,7 +79,7 @@ func Init() {
|
||||
iptablesService := service.IptablesService{}
|
||||
iptablesStatus, _ := settingRepo.GetValueByKey("IptablesStatus")
|
||||
if iptablesStatus == constant.StatusEnable {
|
||||
if err := iptablesService.Operate(dto.IptablesOp{Operate: "bind-base"}); err != nil {
|
||||
if err := iptablesService.Operate(dto.IptablesOp{Operate: "bind-base-without-init"}); err != nil {
|
||||
global.LOG.Errorf("bind base chains failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
@@ -122,3 +123,20 @@ func needInit() bool {
|
||||
fmt.Fprintf(file, "Boot Mark for 1panel\n")
|
||||
return true
|
||||
}
|
||||
|
||||
func InitPingStatus() {
|
||||
global.LOG.Info("initializing ban ping status from settings...")
|
||||
status := firewall.LoadPingStatus()
|
||||
statusInDB, _ := repo.NewISettingRepo().GetValueByKey("BanPing")
|
||||
if statusInDB == status {
|
||||
return
|
||||
}
|
||||
|
||||
enable := "1"
|
||||
if statusInDB == constant.StatusDisable {
|
||||
enable = "0"
|
||||
}
|
||||
if err := firewall.UpdatePingStatus(enable); err != nil {
|
||||
global.LOG.Errorf("initialize ping status failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ func InitAgentDB() {
|
||||
migrations.InitIptablesStatus,
|
||||
migrations.UpdateWebsite,
|
||||
migrations.AddisIPtoWebsiteSSL,
|
||||
migrations.InitPingStatus,
|
||||
migrations.UpdateApp,
|
||||
migrations.AddCronjobArgs,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -789,3 +789,28 @@ var AddisIPtoWebsiteSSL = &gormigrate.Migration{
|
||||
return tx.AutoMigrate(&model.WebsiteSSL{})
|
||||
},
|
||||
}
|
||||
|
||||
var InitPingStatus = &gormigrate.Migration{
|
||||
ID: "20251201-init-ping-status",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
status := firewall.LoadPingStatus()
|
||||
if err := tx.Create(&model.Setting{Key: "BanPing", Value: status}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var UpdateApp = &gormigrate.Migration{
|
||||
ID: "20251228-update-app",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.App{})
|
||||
},
|
||||
}
|
||||
|
||||
var AddCronjobArgs = &gormigrate.Migration{
|
||||
ID: "20260106-add-cronjob-args",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.Cronjob{})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,10 +19,11 @@ func (a *AppRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
appRouter.POST("/search", baseApi.SearchApp)
|
||||
appRouter.GET("/:key", baseApi.GetApp)
|
||||
appRouter.GET("/detail/:appId/:version/:type", baseApi.GetAppDetail)
|
||||
appRouter.GET("/detail/node/:appKey/:version", baseApi.GetAppDetailForNode)
|
||||
appRouter.GET("/details/:id", baseApi.GetAppDetailByID)
|
||||
appRouter.POST("/install", baseApi.InstallApp)
|
||||
appRouter.GET("/tags", baseApi.GetAppTags)
|
||||
appRouter.GET("/icon/:appID", baseApi.GetAppIcon)
|
||||
appRouter.GET("/icon/:key", baseApi.GetAppIcon)
|
||||
|
||||
appRouter.POST("/installed/check", baseApi.CheckAppInstalled)
|
||||
appRouter.POST("/installed/loadport", baseApi.LoadPort)
|
||||
|
||||
+116
-37
@@ -4,16 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
@@ -22,21 +12,31 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/email"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/psutil"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/re"
|
||||
"github.com/jinzhu/copier"
|
||||
network "net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var cronJobAlertTypes = []string{"shell", "app", "website", "database", "directory", "log", "snapshot", "curl", "cutWebsiteLog", "clean", "ntp"}
|
||||
|
||||
func CreateTaskScanEmailAlertLog(alert dto.AlertDTO, create dto.AlertLogCreate, pushAlert dto.PushAlert, method string, transport *http.Transport) error {
|
||||
func CreateTaskScanEmailAlertLog(alert dto.AlertDTO, create dto.AlertLogCreate, pushAlert dto.PushAlert, method string, transport *http.Transport, agentInfo *dto.AgentInfo) error {
|
||||
params := CreateAlertParams(GetCronJobTypeName(pushAlert.Param))
|
||||
alertDetail := ProcessAlertDetail(alert, pushAlert.TaskName, params, method)
|
||||
alertRule := ProcessAlertRule(alert)
|
||||
create.AlertRule = alertRule
|
||||
create.AlertDetail = alertDetail
|
||||
return CreateEmailAlertLog(create, alert, params, transport)
|
||||
return CreateEmailAlertLog(create, alert, params, transport, agentInfo)
|
||||
}
|
||||
|
||||
func CreateEmailAlertLog(create dto.AlertLogCreate, alert dto.AlertDTO, params []dto.Param, transport *http.Transport) error {
|
||||
func CreateEmailAlertLog(create dto.AlertLogCreate, alert dto.AlertDTO, params []dto.Param, transport *http.Transport, agentInfo *dto.AgentInfo) error {
|
||||
var alertLog model.AlertLog
|
||||
alertRepo := repo.NewIAlertRepo()
|
||||
config, err := alertRepo.GetConfig(alertRepo.WithByType(constant.CommonConfig))
|
||||
@@ -49,7 +49,6 @@ func CreateEmailAlertLog(create dto.AlertLogCreate, alert dto.AlertDTO, params [
|
||||
return err
|
||||
}
|
||||
create.Method = constant.Email
|
||||
// 获取远端推送信息
|
||||
if !global.IsMaster && cfg.IsOffline == constant.StatusEnable {
|
||||
create.Status = constant.AlertPushing
|
||||
return SaveAlertLog(create, &alertLog)
|
||||
@@ -77,9 +76,9 @@ func CreateEmailAlertLog(create dto.AlertLogCreate, alert dto.AlertDTO, params [
|
||||
Encryption: emailInfo.Encryption,
|
||||
Recipient: emailInfo.Recipient,
|
||||
}
|
||||
content := i18n.GetMsgWithMap("CommonAlert", map[string]interface{}{"msg": alert.Title})
|
||||
if GetEmailContent(alert.Type, params) != "" {
|
||||
content = GetEmailContent(alert.Type, params)
|
||||
content := GetEmailContent(alert.Type, params, agentInfo)
|
||||
if content == "" {
|
||||
content = i18n.GetMsgWithMap("CommonAlert", map[string]interface{}{"msg": alert.Title})
|
||||
}
|
||||
msg := email.EmailMessage{
|
||||
Subject: i18n.GetMsgByKey("PanelAlertTitle"),
|
||||
@@ -209,7 +208,7 @@ func CheckSMSSendLimit(method string) bool {
|
||||
return false
|
||||
}
|
||||
var cfg dto.AlertSmsConfig
|
||||
err = json.Unmarshal([]byte(config.Config), &cfg)
|
||||
cfg, err = ParseAlertSmsConfig(config.Config)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -241,7 +240,6 @@ type Category struct {
|
||||
Type []string `json:"type"`
|
||||
}
|
||||
|
||||
// CheckSendTimeRange 是否在时间范围内
|
||||
func CheckSendTimeRange(alertType string) bool {
|
||||
alertRepo := repo.NewIAlertRepo()
|
||||
config, err := alertRepo.GetConfig(alertRepo.WithByType(constant.CommonConfig))
|
||||
@@ -302,42 +300,42 @@ func isWithinTimeRange(savedTimeString string) bool {
|
||||
return now.After(skipTime) && now.Before(endSkipTime)
|
||||
}
|
||||
|
||||
func GetEmailContent(alertType string, params []dto.Param) string {
|
||||
func GetEmailContent(alertType string, params []dto.Param, agentInfo *dto.AgentInfo) string {
|
||||
switch GetCronJobType(alertType) {
|
||||
case "ssl":
|
||||
return i18n.GetMsgWithMap("SSLAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "day": getValueByIndex(params, "2")})
|
||||
return i18n.GetMsgWithMap("SSLAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "day": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "siteEndTime":
|
||||
return i18n.GetMsgWithMap("WebSiteAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "day": getValueByIndex(params, "2")})
|
||||
return i18n.GetMsgWithMap("WebSiteAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "day": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "panelPwdEndTime":
|
||||
return i18n.GetMsgWithMap("PanelPwdExpirationAlert", map[string]interface{}{"day": getValueByIndex(params, "1")})
|
||||
return i18n.GetMsgWithMap("PanelPwdExpirationAlert", map[string]interface{}{"day": getValueByIndex(params, "1"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "licenseTime":
|
||||
return i18n.GetMsgWithMap("LicenseExpirationAlert", map[string]interface{}{"day": getValueByIndex(params, "1")})
|
||||
return i18n.GetMsgWithMap("LicenseExpirationAlert", map[string]interface{}{"day": getValueByIndex(params, "1"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "panelUpdate":
|
||||
return i18n.GetMsgByKey("PanelVersionAlert")
|
||||
return i18n.GetMsgWithMap("PanelVersionAlert", map[string]interface{}{"node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "cpu":
|
||||
return i18n.GetMsgWithMap("ResourceAlert", map[string]interface{}{"time": getValueByIndex(params, "1"), "name": getValueByIndex(params, "2"), "used": getValueByIndex(params, "3")})
|
||||
return i18n.GetMsgWithMap("ResourceAlert", map[string]interface{}{"time": getValueByIndex(params, "1"), "name": getValueByIndex(params, "2"), "used": getValueByIndex(params, "3"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "memory":
|
||||
return i18n.GetMsgWithMap("ResourceAlert", map[string]interface{}{"time": getValueByIndex(params, "1"), "name": getValueByIndex(params, "2"), "used": getValueByIndex(params, "3")})
|
||||
return i18n.GetMsgWithMap("ResourceAlert", map[string]interface{}{"time": getValueByIndex(params, "1"), "name": getValueByIndex(params, "2"), "used": getValueByIndex(params, "3"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "load":
|
||||
return i18n.GetMsgWithMap("ResourceAlert", map[string]interface{}{"time": getValueByIndex(params, "1"), "name": getValueByIndex(params, "2"), "used": getValueByIndex(params, "3")})
|
||||
return i18n.GetMsgWithMap("ResourceAlert", map[string]interface{}{"time": getValueByIndex(params, "1"), "name": getValueByIndex(params, "2"), "used": getValueByIndex(params, "3"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "disk":
|
||||
return i18n.GetMsgWithMap("DiskUsedAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "used": getValueByIndex(params, "2")})
|
||||
return i18n.GetMsgWithMap("DiskUsedAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "used": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "cronJob":
|
||||
return i18n.GetMsgWithMap("CronJobFailedAlert", map[string]interface{}{"name": getValueByIndex(params, "1")})
|
||||
return i18n.GetMsgWithMap("CronJobFailedAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "clams":
|
||||
return i18n.GetMsgWithMap("ClamAlert", map[string]interface{}{"num": getValueByIndex(params, "1")})
|
||||
return i18n.GetMsgWithMap("ClamAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "panelLogin":
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "ip": getValueByIndex(params, "2")})
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "loginIp": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "sshLogin":
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "ip": getValueByIndex(params, "2")})
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "loginIp": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "panelIpLogin":
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "ip": getValueByIndex(params, "2")})
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "loginIp": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "sshIpLogin":
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "ip": getValueByIndex(params, "2")})
|
||||
return i18n.GetMsgWithMap("SSHAndPanelLoginAlert", map[string]interface{}{"name": getValueByIndex(params, "1"), "loginIp": getValueByIndex(params, "2"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "nodeException":
|
||||
return i18n.GetMsgWithMap("NodeExceptionAlert", map[string]interface{}{"num": getValueByIndex(params, "1")})
|
||||
return i18n.GetMsgWithMap("NodeExceptionAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
case "licenseException":
|
||||
return i18n.GetMsgWithMap("LicenseExceptionAlert", map[string]interface{}{"num": getValueByIndex(params, "1")})
|
||||
return i18n.GetMsgWithMap("LicenseExceptionAlert", map[string]interface{}{"num": getValueByIndex(params, "1"), "node": getNodeName(agentInfo), "ip": getNodeIp(agentInfo)})
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
@@ -517,3 +515,84 @@ func parseLogTime(line string) (time.Time, error) {
|
||||
}
|
||||
return parsedTime.AddDate(time.Now().Year(), 0, 0), nil
|
||||
}
|
||||
|
||||
func getNodeName(agentInfo *dto.AgentInfo) string {
|
||||
var nodeName string
|
||||
if agentInfo != nil && agentInfo.NodeName != "" {
|
||||
nodeName = agentInfo.NodeName
|
||||
}
|
||||
|
||||
return formatWithFallback(nodeName, getFallbackHostname)
|
||||
}
|
||||
|
||||
func getNodeIp(agentInfo *dto.AgentInfo) string {
|
||||
var nodeIP string
|
||||
if agentInfo != nil && agentInfo.NodeAddr != "" && agentInfo.NodeAddr != "127.0.0.1" {
|
||||
nodeIP = agentInfo.NodeAddr
|
||||
}
|
||||
|
||||
return formatWithFallback(nodeIP, getFallbackIP)
|
||||
}
|
||||
|
||||
func formatWithFallback(value string, fallback func() string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
value = strings.TrimSpace(fallback())
|
||||
}
|
||||
|
||||
if value == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf("「%s」", value)
|
||||
}
|
||||
|
||||
func getFallbackHostname() string {
|
||||
hostInfo, err := psutil.HOST.GetHostInfo(false)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return hostInfo.Hostname
|
||||
}
|
||||
|
||||
func getFallbackIP() string {
|
||||
if systemIP, err := repo.NewISettingRepo().GetValueByKey("SystemIP"); err == nil && systemIP != "" {
|
||||
return systemIP
|
||||
}
|
||||
return loadOutboundIP()
|
||||
}
|
||||
|
||||
func loadOutboundIP() string {
|
||||
conn, err := network.Dial("udp", "8.8.8.8:80")
|
||||
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer conn.Close()
|
||||
localAddr := conn.LocalAddr().(*network.UDPAddr)
|
||||
return localAddr.IP.String()
|
||||
}
|
||||
|
||||
func ParseAlertSmsConfig(configJSON string) (dto.AlertSmsConfig, error) {
|
||||
var tempMap map[string]interface{}
|
||||
err := json.Unmarshal([]byte(configJSON), &tempMap)
|
||||
if err != nil {
|
||||
return dto.AlertSmsConfig{}, err
|
||||
}
|
||||
|
||||
var cfg dto.AlertSmsConfig
|
||||
if phone, ok := tempMap["phone"].(string); ok {
|
||||
cfg.Phone = phone
|
||||
}
|
||||
|
||||
switch v := tempMap["alertDailyNum"].(type) {
|
||||
case float64:
|
||||
cfg.AlertDailyNum = strconv.FormatFloat(v, 'f', 0, 64)
|
||||
case string:
|
||||
cfg.AlertDailyNum = v
|
||||
default:
|
||||
cfg.AlertDailyNum = "50"
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ func PushAlert(pushAlert dto.PushAlert) error {
|
||||
var alert dto.AlertDTO
|
||||
_ = copier.Copy(&alert, &alertInfo)
|
||||
|
||||
// 根据发送方式推送不同的日志记录
|
||||
methods := strings.Split(alert.Method, ",")
|
||||
for _, m := range methods {
|
||||
m = strings.TrimSpace(m)
|
||||
@@ -45,6 +44,7 @@ func PushAlert(pushAlert dto.PushAlert) error {
|
||||
}
|
||||
_ = xpack.CreateTaskScanSMSAlertLog(alert, alert.Type, create, pushAlert, constant.SMS)
|
||||
alertUtil.CreateNewAlertTask(strconv.Itoa(int(pushAlert.EntryID)), alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), constant.SMS)
|
||||
global.LOG.Infof("%s %s alert push successful", alert.Type, constant.SMS)
|
||||
case constant.Email:
|
||||
todayCount, _, err := alertRepo.LoadTaskCount(alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), constant.Email)
|
||||
if err != nil || alert.SendCount <= todayCount {
|
||||
@@ -56,14 +56,15 @@ func PushAlert(pushAlert dto.PushAlert) error {
|
||||
Count: todayCount + 1,
|
||||
}
|
||||
transport := xpack.LoadRequestTransport()
|
||||
err = alertUtil.CreateTaskScanEmailAlertLog(alert, create, pushAlert, constant.Email, transport)
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
err = alertUtil.CreateTaskScanEmailAlertLog(alert, create, pushAlert, constant.Email, transport, agentInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(strconv.Itoa(int(pushAlert.EntryID)), alertUtil.GetCronJobType(alert.Type), strconv.Itoa(int(pushAlert.EntryID)), constant.Email)
|
||||
global.LOG.Infof("%s %s alert push successful", alert.Type, constant.Email)
|
||||
default:
|
||||
}
|
||||
}
|
||||
global.LOG.Infof("%s alert push successful", alert.Type)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/aws/smithy-go"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
)
|
||||
|
||||
type s3Client struct {
|
||||
scType string
|
||||
bucket string
|
||||
client *s3.Client
|
||||
Sess session.Session
|
||||
}
|
||||
|
||||
func NewS3Client(vars map[string]interface{}) (*s3Client, error) {
|
||||
@@ -36,26 +31,22 @@ func NewS3Client(vars map[string]interface{}) (*s3Client, error) {
|
||||
if len(mode) == 0 {
|
||||
mode = "virtual hosted"
|
||||
}
|
||||
cfg, err := config.LoadDefaultConfig(context.Background(),
|
||||
config.WithRegion(region),
|
||||
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")),
|
||||
)
|
||||
sess, err := session.NewSession(&aws.Config{
|
||||
Credentials: credentials.NewStaticCredentials(accessKey, secretKey, ""),
|
||||
Endpoint: aws.String(endpoint),
|
||||
Region: aws.String(region),
|
||||
DisableSSL: aws.Bool(true), S3ForcePathStyle: aws.Bool(mode == "path"),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
|
||||
o.UsePathStyle = mode == "path"
|
||||
if endpoint != "" {
|
||||
o.BaseEndpoint = aws.String(normalizeEndpoint(endpoint))
|
||||
}
|
||||
})
|
||||
|
||||
return &s3Client{scType: scType, bucket: bucket, client: client}, nil
|
||||
return &s3Client{scType: scType, bucket: bucket, Sess: *sess}, nil
|
||||
}
|
||||
|
||||
func (s *s3Client) ListBuckets() ([]interface{}, error) {
|
||||
func (s s3Client) ListBuckets() ([]interface{}, error) {
|
||||
var result []interface{}
|
||||
res, err := s.client.ListBuckets(context.Background(), &s3.ListBucketsInput{})
|
||||
svc := s3.New(&s.Sess)
|
||||
res, err := svc.ListBuckets(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,54 +56,50 @@ func (s *s3Client) ListBuckets() ([]interface{}, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *s3Client) Exist(path string) (bool, error) {
|
||||
_, err := s.client.HeadObject(context.Background(), &s3.HeadObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(path),
|
||||
})
|
||||
if err != nil {
|
||||
var apiErr smithy.APIError
|
||||
if errors.As(err, &apiErr) {
|
||||
switch apiErr.ErrorCode() {
|
||||
case "NotFound", "NoSuchKey":
|
||||
func (s s3Client) Exist(path string) (bool, error) {
|
||||
svc := s3.New(&s.Sess)
|
||||
if _, err := svc.HeadObject(&s3.HeadObjectInput{
|
||||
Bucket: &s.bucket,
|
||||
Key: &path,
|
||||
}); err != nil {
|
||||
if aerr, ok := err.(awserr.RequestFailure); ok {
|
||||
if aerr.StatusCode() == 404 {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
return false, aerr
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *s3Client) Size(path string) (int64, error) {
|
||||
file, err := s.client.GetObject(context.Background(), &s3.GetObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(path),
|
||||
svc := s3.New(&s.Sess)
|
||||
file, err := svc.GetObject(&s3.GetObjectInput{
|
||||
Bucket: &s.bucket,
|
||||
Key: &path,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer file.Body.Close()
|
||||
return aws.ToInt64(file.ContentLength), nil
|
||||
return *file.ContentLength, nil
|
||||
}
|
||||
|
||||
func (s *s3Client) Delete(path string) (bool, error) {
|
||||
if _, err := s.client.DeleteObject(context.Background(), &s3.DeleteObjectInput{
|
||||
func (s s3Client) Delete(path string) (bool, error) {
|
||||
svc := s3.New(&s.Sess)
|
||||
if _, err := svc.DeleteObject(&s3.DeleteObjectInput{Bucket: aws.String(s.bucket), Key: aws.String(path)}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(path),
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
waiter := s3.NewObjectNotExistsWaiter(s.client)
|
||||
if err := waiter.Wait(context.Background(), &s3.HeadObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(path),
|
||||
}, 30*time.Second); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *s3Client) Upload(src, target string) (bool, error) {
|
||||
func (s s3Client) Upload(src, target string) (bool, error) {
|
||||
fileInfo, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -123,23 +110,22 @@ func (s *s3Client) Upload(src, target string) (bool, error) {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
uploader := manager.NewUploader(s.client)
|
||||
maxUploadSize := int64(manager.MaxUploadParts) * manager.DefaultUploadPartSize
|
||||
if fileInfo.Size() > maxUploadSize {
|
||||
uploader.PartSize = fileInfo.Size() / (int64(manager.MaxUploadParts) - 1)
|
||||
uploader := s3manager.NewUploader(&s.Sess)
|
||||
if fileInfo.Size() > s3manager.MaxUploadParts*s3manager.DefaultUploadPartSize {
|
||||
uploader.PartSize = fileInfo.Size() / (s3manager.MaxUploadParts - 1)
|
||||
}
|
||||
if _, err := uploader.Upload(context.Background(), &s3.PutObjectInput{
|
||||
if _, err := uploader.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(target),
|
||||
Body: file,
|
||||
StorageClass: types.StorageClass(s.scType),
|
||||
StorageClass: &s.scType,
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *s3Client) Download(src, target string) (bool, error) {
|
||||
func (s s3Client) Download(src, target string) (bool, error) {
|
||||
if _, err := os.Stat(target); err == nil {
|
||||
_ = os.Remove(target)
|
||||
}
|
||||
@@ -148,8 +134,8 @@ func (s *s3Client) Download(src, target string) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
defer file.Close()
|
||||
downloader := manager.NewDownloader(s.client)
|
||||
if _, err = downloader.Download(context.Background(), file, &s3.GetObjectInput{
|
||||
downloader := s3manager.NewDownloader(&s.Sess)
|
||||
if _, err = downloader.Download(file, &s3.GetObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(src),
|
||||
}); err != nil {
|
||||
@@ -160,23 +146,17 @@ func (s *s3Client) Download(src, target string) (bool, error) {
|
||||
}
|
||||
|
||||
func (s *s3Client) ListObjects(prefix string) ([]string, error) {
|
||||
svc := s3.New(&s.Sess)
|
||||
var result []string
|
||||
outputs, err := s.client.ListObjectsV2(context.Background(), &s3.ListObjectsV2Input{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Prefix: aws.String(prefix),
|
||||
outputs, err := svc.ListObjects(&s3.ListObjectsInput{
|
||||
Bucket: &s.bucket,
|
||||
Prefix: &prefix,
|
||||
})
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, item := range outputs.Contents {
|
||||
result = append(result, aws.ToString(item.Key))
|
||||
result = append(result, *item.Key)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func normalizeEndpoint(endpoint string) string {
|
||||
if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") {
|
||||
return endpoint
|
||||
}
|
||||
return "http://" + endpoint
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/smtp"
|
||||
@@ -119,9 +120,11 @@ func parseRecipients(recipient string) []string {
|
||||
|
||||
func buildMessage(config SMTPConfig, message EmailMessage, toList []string) (string, error) {
|
||||
headers := make(map[string]string)
|
||||
headers["From"] = config.From
|
||||
encodedFrom := mime.BEncoding.Encode("UTF-8", config.From)
|
||||
headers["From"] = encodedFrom
|
||||
encodedSubject := mime.BEncoding.Encode("UTF-8", message.Subject)
|
||||
headers["Subject"] = encodedSubject
|
||||
headers["To"] = strings.Join(toList, ",")
|
||||
headers["Subject"] = message.Subject
|
||||
headers["Date"] = time.Now().UTC().Format(time.RFC1123Z)
|
||||
|
||||
if message.IsHTML {
|
||||
|
||||
@@ -2,7 +2,12 @@ package firewall
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/client"
|
||||
)
|
||||
@@ -47,3 +52,103 @@ func NewFirewallClient() (FirewallClient, error) {
|
||||
}
|
||||
return nil, errors.New("No system firewall service detected (firewalld/ufw/iptables), please check and try again!")
|
||||
}
|
||||
|
||||
func LoadPingStatus() string {
|
||||
data, err := os.ReadFile("/proc/sys/net/ipv4/icmp_echo_ignore_all")
|
||||
if err != nil {
|
||||
return constant.StatusNone
|
||||
}
|
||||
v6Data, v6err := os.ReadFile("/proc/sys/net/ipv6/icmp/echo_ignore_all")
|
||||
if v6err != nil {
|
||||
if strings.TrimSpace(string(data)) == "1" {
|
||||
return constant.StatusEnable
|
||||
}
|
||||
return constant.StatusDisable
|
||||
} else {
|
||||
if strings.TrimSpace(string(data)) == "1" && strings.TrimSpace(string(v6Data)) == "1" {
|
||||
return constant.StatusEnable
|
||||
}
|
||||
return constant.StatusDisable
|
||||
}
|
||||
}
|
||||
|
||||
func UpdatePingStatus(enable string) error {
|
||||
const confPath = "/etc/sysctl.conf"
|
||||
const panelSysctlPath = "/etc/sysctl.d/98-onepanel.conf"
|
||||
|
||||
var targetPath string
|
||||
var applyCmd string
|
||||
|
||||
if _, err := os.Stat(confPath); os.IsNotExist(err) {
|
||||
targetPath = panelSysctlPath
|
||||
applyCmd = fmt.Sprintf("%s sysctl --system", cmd.SudoHandleCmd())
|
||||
if err := cmd.RunDefaultBashCf("%s mkdir -p /etc/sysctl.d", cmd.SudoHandleCmd()); err != nil {
|
||||
return fmt.Errorf("failed to create directory /etc/sysctl.d: %v", err)
|
||||
}
|
||||
} else {
|
||||
targetPath = confPath
|
||||
applyCmd = fmt.Sprintf("%s sysctl -p", cmd.SudoHandleCmd())
|
||||
}
|
||||
|
||||
lineBytes, err := os.ReadFile(targetPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("failed to read %s: %v", targetPath, err)
|
||||
}
|
||||
|
||||
if err := cmd.RunDefaultBashCf("echo %s | %s tee /proc/sys/net/ipv4/icmp_echo_ignore_all > /dev/null", enable, cmd.SudoHandleCmd()); err != nil {
|
||||
return fmt.Errorf("failed to apply ipv4 ping status temporarily: %v", err)
|
||||
}
|
||||
|
||||
var hasIpv6 bool
|
||||
if _, err := os.Stat("/proc/sys/net/ipv6/icmp/echo_ignore_all"); err == nil {
|
||||
hasIpv6 = true
|
||||
if err := cmd.RunDefaultBashCf("echo %s | %s tee /proc/sys/net/ipv6/icmp/echo_ignore_all > /dev/null", enable, cmd.SudoHandleCmd()); err != nil {
|
||||
global.LOG.Warnf("failed to apply ipv6 ping status temporarily: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var files []string
|
||||
if err == nil {
|
||||
files = strings.Split(string(lineBytes), "\n")
|
||||
}
|
||||
|
||||
var newFiles []string
|
||||
hasIPv4Line, hasIPv6Line := false, false
|
||||
|
||||
for _, line := range files {
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "net.ipv4.icmp_echo_ignore_all") {
|
||||
newFiles = append(newFiles, "net.ipv4.icmp_echo_ignore_all="+enable)
|
||||
hasIPv4Line = true
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "net.ipv6.icmp.echo_ignore_all") {
|
||||
newFiles = append(newFiles, "net.ipv6.icmp.echo_ignore_all="+enable)
|
||||
hasIPv6Line = true
|
||||
continue
|
||||
}
|
||||
newFiles = append(newFiles, line)
|
||||
}
|
||||
|
||||
if !hasIPv4Line {
|
||||
newFiles = append(newFiles, "net.ipv4.icmp_echo_ignore_all="+enable)
|
||||
}
|
||||
if hasIpv6 && !hasIPv6Line {
|
||||
newFiles = append(newFiles, "net.ipv6.icmp.echo_ignore_all="+enable)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(targetPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, constant.FilePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open %s: %v", targetPath, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err = file.WriteString(strings.Join(newFiles, "\n")); err != nil {
|
||||
return fmt.Errorf("failed to write to %s: %v", targetPath, err)
|
||||
}
|
||||
|
||||
if err := cmd.RunDefaultBashC(applyCmd); err != nil {
|
||||
global.LOG.Warnf("failed to apply persistent config with '%s': %v", applyCmd, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -148,10 +148,8 @@ func (i *Iptables) Port(port FireInfo, operation string) error {
|
||||
if port.Chain == iptables.Chain1PanelBasicBefore {
|
||||
name = iptables.BasicBeforeFileName
|
||||
}
|
||||
if port.Chain == iptables.Chain1PanelBasic {
|
||||
if err := iptables.SaveRulesToFile(iptables.FilterTab, port.Chain, name); err != nil {
|
||||
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
|
||||
}
|
||||
if err := iptables.SaveRulesToFile(iptables.FilterTab, port.Chain, name); err != nil {
|
||||
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -215,10 +213,8 @@ func (i *Iptables) RichRules(rule FireInfo, operation string) error {
|
||||
if rule.Chain == iptables.Chain1PanelBasicBefore {
|
||||
name = iptables.BasicBeforeFileName
|
||||
}
|
||||
if rule.Chain == iptables.Chain1PanelBasic {
|
||||
if err := iptables.SaveRulesToFile(iptables.FilterTab, rule.Chain, name); err != nil {
|
||||
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
|
||||
}
|
||||
if err := iptables.SaveRulesToFile(iptables.FilterTab, rule.Chain, name); err != nil {
|
||||
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -72,12 +72,13 @@ type AccessChangeInfo struct {
|
||||
}
|
||||
|
||||
type BackupInfo struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Format string `json:"format"`
|
||||
TargetDir string `json:"targetDir"`
|
||||
FileName string `json:"fileName"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Format string `json:"format"`
|
||||
TargetDir string `json:"targetDir"`
|
||||
FileName string `json:"fileName"`
|
||||
Args []string `json:"args"`
|
||||
|
||||
Timeout uint `json:"timeout"` // second
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
)
|
||||
|
||||
@@ -237,9 +238,19 @@ func (r *Local) Backup(info BackupInfo) error {
|
||||
if r.Type == constant.AppMariaDB {
|
||||
dumpCmd = "mariadb-dump"
|
||||
}
|
||||
global.LOG.Infof("start to %s | gzip > %s.gzip", dumpCmd, info.TargetDir+"/"+info.FileName)
|
||||
global.LOG.Infof("start to %s | gzip > %s.gzip, args: %v", dumpCmd, info.TargetDir+"/"+info.FileName, info.Args)
|
||||
|
||||
cmd := exec.Command("docker", "exec", r.ContainerName, dumpCmd, "--routines", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
|
||||
info.Args = append(info.Args, "--routines")
|
||||
itemArgs := common.RemoveRepeatStr(info.Args)
|
||||
args := []string{"exec", r.ContainerName, dumpCmd, "-uroot", "-p" + r.Password, "--default-character-set=" + info.Format}
|
||||
for _, arg := range itemArgs {
|
||||
if len(arg) == 0 {
|
||||
continue
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
args = append(args, info.Name)
|
||||
cmd := exec.Command("docker", args...)
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/client"
|
||||
@@ -253,8 +254,18 @@ func (r *Remote) Backup(info BackupInfo) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
backupCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c '%s --routines -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
|
||||
image, dumpCmd, r.Address, r.Port, r.User, r.Password, sslSkip(info.Version, r.Type), info.Format, info.Name)
|
||||
info.Args = append(info.Args, "--routines")
|
||||
itemArgs := common.RemoveRepeatStr(info.Args)
|
||||
var args []string
|
||||
for _, arg := range itemArgs {
|
||||
if len(arg) == 0 {
|
||||
continue
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
|
||||
backupCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c '%s %s -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
|
||||
image, dumpCmd, strings.Join(args, " "), r.Address, r.Port, r.User, r.Password, sslSkip(info.Version, r.Type), info.Format, info.Name)
|
||||
|
||||
global.LOG.Debug(strings.ReplaceAll(backupCmd, r.Password, "******"))
|
||||
cmd := exec.Command("bash", "-c", backupCmd)
|
||||
|
||||
@@ -424,12 +424,41 @@ func (s *Server) UpdatePHPProxy(proxy []string, localPath string) {
|
||||
},
|
||||
)
|
||||
if localPath == "" {
|
||||
block.AppendDirectives(&Directive{
|
||||
Name: "set",
|
||||
Parameters: []string{"$real_script_name", "$fastcgi_script_name"},
|
||||
})
|
||||
ifDir := &Directive{
|
||||
Name: "if",
|
||||
Parameters: []string{"($fastcgi_script_name ~ \"^(.+?\\.php)(/.+)$\")"},
|
||||
}
|
||||
ifDir.Block = &Block{
|
||||
Directives: []IDirective{
|
||||
&Directive{
|
||||
Name: "set",
|
||||
Parameters: []string{"$real_script_name", "$1"},
|
||||
},
|
||||
&Directive{
|
||||
Name: "set",
|
||||
Parameters: []string{"$path_info", "$2"},
|
||||
},
|
||||
},
|
||||
}
|
||||
block.AppendDirectives(
|
||||
ifDir,
|
||||
&Directive{
|
||||
Name: "fastcgi_param",
|
||||
Parameters: []string{"SCRIPT_FILENAME", "$document_root$fastcgi_script_name"},
|
||||
Parameters: []string{"SCRIPT_FILENAME", "$document_root$real_script_name"},
|
||||
},
|
||||
)
|
||||
&Directive{
|
||||
Name: "fastcgi_param",
|
||||
Parameters: []string{"SCRIPT_NAME", "$real_script_name"},
|
||||
},
|
||||
&Directive{
|
||||
Name: "fastcgi_param",
|
||||
Parameters: []string{"PATH_INFO", "$path_info"},
|
||||
})
|
||||
|
||||
} else {
|
||||
block.AppendDirectives(&Directive{
|
||||
Name: "fastcgi_param",
|
||||
@@ -482,12 +511,12 @@ func (s *Server) AddHTTP2HTTPS(httpsPort int) {
|
||||
} else {
|
||||
block.AppendDirectives(&Directive{
|
||||
Name: "return",
|
||||
Parameters: []string{"301", fmt.Sprintf("https://$host$request_uri:%d", httpsPort)},
|
||||
Parameters: []string{"301", fmt.Sprintf("https://$host:%d$request_uri", httpsPort)},
|
||||
})
|
||||
}
|
||||
|
||||
newDir.Block = block
|
||||
s.UpdateDirectiveBySecondKey("if", " ($scheme", newDir)
|
||||
s.UpdateDirectiveBySecondKey("if", "($scheme", newDir)
|
||||
}
|
||||
|
||||
func (s *Server) UpdateAllowIPs(ips []string) {
|
||||
|
||||
@@ -121,6 +121,7 @@ func (c *AcmeClient) ObtainIPSSL(ipAddress string, privKey crypto.PrivateKey) (c
|
||||
CSR: csr,
|
||||
PrivateKey: privKey,
|
||||
Profile: "shortlived",
|
||||
Bundle: true,
|
||||
}
|
||||
certificates, err := c.Client.Certificate.ObtainForCSR(req)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/go-acme/lego/v4/providers/dns/namedotcom"
|
||||
"github.com/go-acme/lego/v4/providers/dns/namesilo"
|
||||
"github.com/go-acme/lego/v4/providers/dns/ovh"
|
||||
"github.com/go-acme/lego/v4/providers/dns/porkbun"
|
||||
"github.com/go-acme/lego/v4/providers/dns/rainyun"
|
||||
"github.com/go-acme/lego/v4/providers/dns/regru"
|
||||
"github.com/go-acme/lego/v4/providers/dns/route53"
|
||||
@@ -57,6 +58,7 @@ const (
|
||||
BaiduCloud DnsType = "BaiduCloud"
|
||||
Ovh DnsType = "Ovh"
|
||||
AcmeDNS DnsType = "AcmeDNS"
|
||||
PorkBun DnsType = "PorkBun"
|
||||
)
|
||||
|
||||
type DNSParam struct {
|
||||
@@ -291,6 +293,14 @@ func getDNSProviderConfig(dnsType DnsType, params string) (challenge.Provider, e
|
||||
config.APIBase = param.Endpoint
|
||||
config.StorageBaseURL = param.BaseURL
|
||||
p, err = acmedns.NewDNSProviderConfig(config)
|
||||
case PorkBun:
|
||||
config := porkbun.NewDefaultConfig()
|
||||
config.APIKey = param.APIkey
|
||||
config.SecretAPIKey = param.SecretKey
|
||||
config.PropagationTimeout = propagationTimeout
|
||||
config.PollingInterval = pollingInterval
|
||||
config.TTL = ttl
|
||||
p, err = porkbun.NewDNSProviderConfig(config)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/miekg/dns"
|
||||
"golang.org/x/crypto/acme"
|
||||
"log"
|
||||
"net"
|
||||
@@ -70,12 +71,39 @@ type Resolve struct {
|
||||
}
|
||||
|
||||
func (c *ManualClient) GetDNSResolve(ctx context.Context, websiteSSL *model.WebsiteSSL) (map[string]Resolve, error) {
|
||||
order, err := c.client.AuthorizeOrder(ctx, acme.DomainIDs(getWebsiteSSLDomains(websiteSSL)...))
|
||||
var order *acme.Order
|
||||
var err error
|
||||
|
||||
// Check if we have an existing valid order for this SSL
|
||||
existingOrder, exists := Orders[websiteSSL.ID]
|
||||
if exists && existingOrder != nil {
|
||||
// Verify the order is still valid (not expired and still pending)
|
||||
// If Expires is zero, order is still valid (ACME doesn't always set expiry immediately)
|
||||
isNotExpired := existingOrder.Expires.IsZero() || existingOrder.Expires.After(time.Now())
|
||||
if isNotExpired && (existingOrder.Status == acme.StatusPending || existingOrder.Status == acme.StatusReady) {
|
||||
// Try to reuse the existing order
|
||||
records, err := c.extractDNSChallenges(ctx, existingOrder)
|
||||
if err == nil && len(records) > 0 {
|
||||
return records, nil
|
||||
}
|
||||
// If extraction failed, fall through to create a new order
|
||||
}
|
||||
// Existing order is expired or invalid, remove it
|
||||
delete(Orders, websiteSSL.ID)
|
||||
}
|
||||
|
||||
// Create a new order
|
||||
order, err = c.client.AuthorizeOrder(ctx, acme.DomainIDs(getWebsiteSSLDomains(websiteSSL)...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
Orders[websiteSSL.ID] = order
|
||||
|
||||
return c.extractDNSChallenges(ctx, order)
|
||||
}
|
||||
|
||||
// extractDNSChallenges extracts DNS-01 challenge values from an ACME order
|
||||
func (c *ManualClient) extractDNSChallenges(ctx context.Context, order *acme.Order) (map[string]Resolve, error) {
|
||||
records := make(map[string]Resolve)
|
||||
|
||||
for _, authzURL := range order.AuthzURLs {
|
||||
@@ -102,7 +130,14 @@ func (c *ManualClient) GetDNSResolve(ctx context.Context, websiteSSL *model.Webs
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records[domain] = Resolve{
|
||||
// Use different map key for wildcard vs non-wildcard to avoid overwriting
|
||||
// Both use the same DNS record name (_acme-challenge.domain) but different values
|
||||
mapKey := domain
|
||||
if authz.Wildcard {
|
||||
mapKey = "*." + domain
|
||||
}
|
||||
|
||||
records[mapKey] = Resolve{
|
||||
Key: fmt.Sprintf("_acme-challenge.%s", domain),
|
||||
Value: txtValue,
|
||||
}
|
||||
@@ -110,20 +145,20 @@ func (c *ManualClient) GetDNSResolve(ctx context.Context, websiteSSL *model.Webs
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func queryDNSRecords(domain string) (map[string]string, error) {
|
||||
func queryDNSRecords(domain string) (map[string][]string, error) {
|
||||
recordName := fmt.Sprintf("_acme-challenge.%s", domain)
|
||||
txts, err := net.LookupTXT(recordName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records := make(map[string]string)
|
||||
records := make(map[string][]string)
|
||||
if len(txts) > 0 {
|
||||
records[recordName] = txts[0]
|
||||
records[recordName] = txts
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (c *ManualClient) handleAuthorization(ctx context.Context, authzURL string) error {
|
||||
func (c *ManualClient) handleAuthorization(ctx context.Context, authzURL string, nameservers []string) error {
|
||||
authz, err := c.client.GetAuthorization(ctx, authzURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get authorization: %v", err)
|
||||
@@ -158,21 +193,44 @@ func (c *ManualClient) handleAuthorization(ctx context.Context, authzURL string)
|
||||
|
||||
for {
|
||||
c.logger.Printf("[INFO] [%s] acme: Checking DNS record propagation.", domain)
|
||||
currentRecords, err := queryDNSRecords(domain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to query DNS records: %v", err)
|
||||
var currentRecords map[string][]string
|
||||
var queryErr error
|
||||
if len(nameservers) == 0 {
|
||||
currentRecords, queryErr = queryDNSRecords(domain)
|
||||
} else {
|
||||
var errs []string
|
||||
for _, nameserver := range nameservers {
|
||||
currentRecords, queryErr = queryDNSRecordsWithResolver(ctx, c.logger, domain, nameserver)
|
||||
errs = append(errs, fmt.Sprintf("%s: %v", nameserver, queryErr))
|
||||
}
|
||||
if queryErr != nil && len(errs) > 0 {
|
||||
queryErr = fmt.Errorf("all nameservers failed: %s", strings.Join(errs, "; "))
|
||||
}
|
||||
}
|
||||
if currentRecords == nil && queryErr != nil {
|
||||
return fmt.Errorf("failed to query DNS records: %v", queryErr)
|
||||
}
|
||||
recordName := fmt.Sprintf("_acme-challenge.%s", domain)
|
||||
providedRecord, exists := currentRecords[recordName]
|
||||
if exists && providedRecord == expectedRecord {
|
||||
providedRecords, exists := currentRecords[recordName]
|
||||
// Check if expected record is in any of the TXT values
|
||||
found := false
|
||||
if exists {
|
||||
for _, record := range providedRecords {
|
||||
if record == expectedRecord {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if found {
|
||||
break
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
if !exists {
|
||||
if !exists || len(providedRecords) == 0 {
|
||||
return fmt.Errorf("TXT record not provided for domain %s after retrying", domain)
|
||||
}
|
||||
c.logger.Printf("[INFO] [%s] TXT record mismatch for %s: expected %s, got %s\"", domain, domain, expectedRecord, providedRecord)
|
||||
return fmt.Errorf("TXT record mismatch for %s: expected %s, got %s", domain, expectedRecord, providedRecord)
|
||||
c.logger.Printf("[INFO] [%s] TXT record mismatch for %s: expected %s, got %v", domain, domain, expectedRecord, providedRecords)
|
||||
return fmt.Errorf("TXT record mismatch for %s: expected %s, got %v", domain, expectedRecord, providedRecords)
|
||||
}
|
||||
time.Sleep(pollingInterval)
|
||||
}
|
||||
@@ -262,7 +320,7 @@ func (c *ManualClient) RequestCertificate(ctx context.Context, websiteSSL *model
|
||||
defer delete(Orders, websiteSSL.ID)
|
||||
|
||||
for _, authzURL := range order.AuthzURLs {
|
||||
if err := c.handleAuthorization(ctx, authzURL); err != nil {
|
||||
if err := c.handleAuthorization(ctx, authzURL, getNameservers(*websiteSSL)); err != nil {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
@@ -306,3 +364,76 @@ func (c *ManualClient) RequestCertificate(ctx context.Context, websiteSSL *model
|
||||
}
|
||||
return resource, nil
|
||||
}
|
||||
|
||||
func getNameservers(websiteSSL model.WebsiteSSL) []string {
|
||||
var nameservers []string
|
||||
if websiteSSL.Nameserver1 != "" {
|
||||
nameservers = append(nameservers, handleNameserver(websiteSSL.Nameserver1))
|
||||
}
|
||||
if websiteSSL.Nameserver2 != "" {
|
||||
nameservers = append(nameservers, handleNameserver(websiteSSL.Nameserver2))
|
||||
}
|
||||
return nameservers
|
||||
}
|
||||
|
||||
func handleNameserver(nameserver string) string {
|
||||
if strings.Contains(nameserver, ":") {
|
||||
return nameserver
|
||||
}
|
||||
return fmt.Sprintf("%s:53", nameserver)
|
||||
}
|
||||
|
||||
func queryDNSRecordsWithResolver(ctx context.Context, logger *log.Logger, domain string, dnsServer string) (map[string][]string, error) {
|
||||
recordName := fmt.Sprintf("_acme-challenge.%s", domain)
|
||||
c := new(dns.Client)
|
||||
c.Timeout = 10 * time.Second
|
||||
c.Net = "udp"
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(dns.Fqdn(recordName), dns.TypeTXT)
|
||||
m.RecursionDesired = true
|
||||
|
||||
r, _, err := c.ExchangeContext(ctx, m, dnsServer)
|
||||
if isNetworkError(err) {
|
||||
logger.Printf("[WARN] Network error occurred while querying DNS: %v", err)
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS query failed: %w", err)
|
||||
}
|
||||
|
||||
if r.Rcode == dns.RcodeNameError {
|
||||
logger.Printf("[INFO] DNS record does not exist yet (NXDOMAIN)")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if r.Rcode != dns.RcodeSuccess {
|
||||
return nil, fmt.Errorf("DNS query failed with code: %s", dns.RcodeToString[r.Rcode])
|
||||
}
|
||||
|
||||
records := make(map[string][]string)
|
||||
var txtValues []string
|
||||
|
||||
for _, answer := range r.Answer {
|
||||
if txt, ok := answer.(*dns.TXT); ok {
|
||||
if len(txt.Txt) > 0 {
|
||||
txtValues = append(txtValues, txt.Txt[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(txtValues) > 0 {
|
||||
records[recordName] = txtValues
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func isNetworkError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(err.Error(), "i/o timeout") ||
|
||||
strings.Contains(err.Error(), "connection refused") ||
|
||||
strings.Contains(err.Error(), "network is unreachable") ||
|
||||
strings.Contains(err.Error(), "no route to host")
|
||||
}
|
||||
|
||||
@@ -89,3 +89,7 @@ func ValidateCertificate(c *gin.Context) bool {
|
||||
func PushSSLToNode(websiteSSL *model.WebsiteSSL) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAgentInfo() (*dto.AgentInfo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -3,15 +3,16 @@ package v2
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/buserr"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/mfa"
|
||||
@@ -93,7 +94,7 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
|
||||
}
|
||||
if req.Key == "SecurityEntrance" {
|
||||
if !checkEntrancePattern(req.Value) {
|
||||
helper.ErrorWithDetail(c, http.StatusBadRequest, "ErrInvalidParams", fmt.Errorf("the format of the security entrance %s is incorrect.", req.Value))
|
||||
helper.ErrorWithDetail(c, http.StatusBadRequest, "ErrInvalidParams", buserr.WithName("ErrEntranceFormat", req.Value))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -522,5 +523,30 @@ func checkEntrancePattern(val string) bool {
|
||||
return true
|
||||
}
|
||||
result, _ := regexp.MatchString("^[a-zA-Z0-9]{5,116}$", val)
|
||||
return result
|
||||
if !result {
|
||||
return false
|
||||
}
|
||||
lowerVal := strings.ToLower(val)
|
||||
for key := range constant.WebUrlMap {
|
||||
if key == "/" || !strings.HasPrefix(key, "/") {
|
||||
continue
|
||||
}
|
||||
if strings.Count(key, "/") != 1 {
|
||||
continue
|
||||
}
|
||||
segment := strings.ToLower(strings.TrimPrefix(key, "/"))
|
||||
if len(segment) < 5 {
|
||||
continue
|
||||
}
|
||||
if lowerVal == segment {
|
||||
return false
|
||||
}
|
||||
}
|
||||
assetsList := [2]string{"public", "assets"}
|
||||
for _, item := range assetsList {
|
||||
if lowerVal == item {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ type SettingUpdate struct {
|
||||
type SSLUpdate struct {
|
||||
SSLType string `json:"sslType" validate:"required,oneof=self select import import-paste import-local"`
|
||||
Domain string `json:"domain"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=Enable Disable"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=Enable Disable Mux"`
|
||||
Cert string `json:"cert"`
|
||||
Key string `json:"key"`
|
||||
SSLID uint `json:"sslID"`
|
||||
|
||||
@@ -709,7 +709,7 @@ func checkProxy(req dto.ProxyUpdate) error {
|
||||
if len(req.ProxyUser) != 0 {
|
||||
proxyURL.User = url.UserPassword(req.ProxyUser, req.ProxyPasswd)
|
||||
}
|
||||
transport = http.Transport{Proxy: http.ProxyURL(proxyURL)}
|
||||
transport = http.Transport{Proxy: http.ProxyURL(proxyURL), TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
|
||||
case "socks5":
|
||||
var auth *proxy.Auth
|
||||
if len(req.ProxyUser) == 0 {
|
||||
|
||||
@@ -56,14 +56,16 @@ const (
|
||||
TaskInstallCluster = "TaskInstallCluster"
|
||||
TaskCreateCluster = "TaskCreateCluster"
|
||||
TaskBackup = "TaskBackup"
|
||||
TaskPush = "TaskPush"
|
||||
)
|
||||
|
||||
const (
|
||||
TaskScopeSystem = "System"
|
||||
TaskScopeScript = "ScriptLibrary"
|
||||
TaskScopeNodeFile = "NodeFile"
|
||||
TaskScopeAppBackup = "AppBackup"
|
||||
TaskScopeCluster = "Cluster"
|
||||
TaskScopeSystem = "System"
|
||||
TaskScopeScript = "ScriptLibrary"
|
||||
TaskScopeNodeFile = "NodeFile"
|
||||
TaskScopeAppBackup = "AppBackup"
|
||||
TaskScopeCluster = "Cluster"
|
||||
TaskScopeAppInstall = "AppInstallTask"
|
||||
)
|
||||
|
||||
func GetTaskName(resourceName, operate, scope string) string {
|
||||
|
||||
+34
-5
@@ -30,12 +30,16 @@ func (e BusinessError) Error() string {
|
||||
return content
|
||||
}
|
||||
|
||||
func New(Key string) BusinessError {
|
||||
return BusinessError{
|
||||
Msg: Key,
|
||||
Detail: nil,
|
||||
Err: nil,
|
||||
func New(key string, opts ...Option) BusinessError {
|
||||
be := BusinessError{
|
||||
Msg: key,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&be)
|
||||
}
|
||||
|
||||
return be
|
||||
}
|
||||
|
||||
func WithErr(Key string, err error) BusinessError {
|
||||
@@ -76,3 +80,28 @@ func WithName(Key string, name string) BusinessError {
|
||||
Map: paramMap,
|
||||
}
|
||||
}
|
||||
|
||||
type Option func(*BusinessError)
|
||||
|
||||
func WithNameOption(name string) Option {
|
||||
return func(be *BusinessError) {
|
||||
if name != "" {
|
||||
if be.Map == nil {
|
||||
be.Map = make(map[string]interface{})
|
||||
}
|
||||
be.Map["name"] = name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithErrOption(err error) Option {
|
||||
return func(be *BusinessError) {
|
||||
be.Err = err
|
||||
if err != nil {
|
||||
if be.Map == nil {
|
||||
be.Map = make(map[string]interface{})
|
||||
}
|
||||
be.Map["err"] = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22560,6 +22560,12 @@ const docTemplate = `{
|
||||
},
|
||||
"dto.CleanData": {
|
||||
"properties": {
|
||||
"backupClean": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.CleanTree"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"containerClean": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.CleanTree"
|
||||
@@ -22821,10 +22827,7 @@ const docTemplate = `{
|
||||
"dto.ComposeCreate": {
|
||||
"properties": {
|
||||
"env": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
@@ -22857,6 +22860,9 @@ const docTemplate = `{
|
||||
},
|
||||
"dto.ComposeLogClean": {
|
||||
"properties": {
|
||||
"detailPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -22972,11 +22978,11 @@ const docTemplate = `{
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"detailPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"env": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -24591,8 +24597,8 @@ const docTemplate = `{
|
||||
"start",
|
||||
"stop",
|
||||
"restart",
|
||||
"disablePing",
|
||||
"enablePing"
|
||||
"disableBanPing",
|
||||
"enableBanPing"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -25254,6 +25260,9 @@ const docTemplate = `{
|
||||
},
|
||||
"dto.InspectReq": {
|
||||
"properties": {
|
||||
"detail": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -27541,7 +27550,8 @@ const docTemplate = `{
|
||||
"ssl": {
|
||||
"enum": [
|
||||
"Enable",
|
||||
"Disable"
|
||||
"Disable",
|
||||
"Mux"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -29048,6 +29058,9 @@ const docTemplate = `{
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"isIP": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"keyType": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -29689,6 +29702,9 @@ const docTemplate = `{
|
||||
},
|
||||
"mountPoint": {
|
||||
"type": "string"
|
||||
},
|
||||
"noFail": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -32179,6 +32195,9 @@ const docTemplate = `{
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"sync": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -32535,6 +32554,9 @@ const docTemplate = `{
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"isIp": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"keyType": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -34692,6 +34714,9 @@ const docTemplate = `{
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"isIP": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"keyType": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -34782,4 +34807,4 @@ var SwaggerInfo = &swag.Spec{
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||
}
|
||||
}
|
||||
@@ -22556,6 +22556,12 @@
|
||||
},
|
||||
"dto.CleanData": {
|
||||
"properties": {
|
||||
"backupClean": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.CleanTree"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"containerClean": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.CleanTree"
|
||||
@@ -22817,10 +22823,7 @@
|
||||
"dto.ComposeCreate": {
|
||||
"properties": {
|
||||
"env": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
@@ -22853,6 +22856,9 @@
|
||||
},
|
||||
"dto.ComposeLogClean": {
|
||||
"properties": {
|
||||
"detailPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -22968,11 +22974,11 @@
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"detailPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"env": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -24587,8 +24593,8 @@
|
||||
"start",
|
||||
"stop",
|
||||
"restart",
|
||||
"disablePing",
|
||||
"enablePing"
|
||||
"disableBanPing",
|
||||
"enableBanPing"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -25250,6 +25256,9 @@
|
||||
},
|
||||
"dto.InspectReq": {
|
||||
"properties": {
|
||||
"detail": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -27537,7 +27546,8 @@
|
||||
"ssl": {
|
||||
"enum": [
|
||||
"Enable",
|
||||
"Disable"
|
||||
"Disable",
|
||||
"Mux"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
@@ -29044,6 +29054,9 @@
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"isIP": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"keyType": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -29685,6 +29698,9 @@
|
||||
},
|
||||
"mountPoint": {
|
||||
"type": "string"
|
||||
},
|
||||
"noFail": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -32175,6 +32191,9 @@
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"sync": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -32531,6 +32550,9 @@
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"isIp": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"keyType": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -34688,6 +34710,9 @@
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"isIP": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"keyType": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -59,6 +59,8 @@ var WebUrlMap = map[string]struct{}{
|
||||
"/ai": {},
|
||||
"/ai/model": {},
|
||||
"/ai/gpu": {},
|
||||
"/ai/gpu/current": {},
|
||||
"/ai/gpu/history": {},
|
||||
"/ai/mcp": {},
|
||||
"/ai/model/tensorrt": {},
|
||||
"/ai/model/ollama": {},
|
||||
@@ -165,6 +167,7 @@ var WebUrlMap = map[string]struct{}{
|
||||
"/xpack/alert/log": {},
|
||||
"/xpack/alert/setting": {},
|
||||
"/xpack/setting": {},
|
||||
"/xpack/node/dashboard": {},
|
||||
"/xpack/node": {},
|
||||
"/xpack/simple-node": {},
|
||||
"/xpack/exchange/file": {},
|
||||
|
||||
@@ -21,6 +21,7 @@ const (
|
||||
|
||||
StatusEnable = "Enable"
|
||||
StatusDisable = "Disable"
|
||||
StatusMux = "Mux"
|
||||
|
||||
StatusInstalling = "Installing"
|
||||
StatusNormal = "Normal"
|
||||
|
||||
@@ -81,6 +81,7 @@ require (
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
|
||||
@@ -250,6 +250,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
@@ -342,6 +344,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@@ -363,6 +366,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "Request failed {{ .err }}"
|
||||
ErrHttpReqTimeOut: "Request timed out {{ .err }}"
|
||||
ErrCreateHttpClient: "Failed to create request {{ .err }}"
|
||||
ErrProxySetting: "Proxy server information unavailable {{ .err }}, please check and try again!"
|
||||
ErrEntranceFormat: "Security entrance {{ .name }} is not currently supported. Please check and try again!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "Demo server, this operation is prohibited!"
|
||||
@@ -110,6 +111,11 @@ FailedStatus: "{{ .name }} failed {{ .err }}"
|
||||
Start: "Start"
|
||||
SubTask: "Subtask"
|
||||
Skip: "Skip errors and continue..."
|
||||
PushAppInstallTaskToNode: "Push app installation task to node [{{ .name }}]"
|
||||
TaskPush: "Push"
|
||||
AppInstallTask: "App installation task"
|
||||
PushAppFailed: "Failed to push app installation task"
|
||||
Success: "Success"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "Script Library"
|
||||
|
||||
@@ -14,6 +14,11 @@ ErrApiConfigKeyInvalid: "Error de clave API: {{ .detail }}"
|
||||
ErrApiConfigIPInvalid: "La IP de la solicitud API no está en la lista blanca: {{ .detail }}"
|
||||
ErrApiConfigDisable: "Esta interfaz prohíbe llamadas a la API: {{ .detail }}"
|
||||
ErrApiConfigKeyTimeInvalid: "Error de marca de tiempo de API: {{ .detail }}"
|
||||
PushAppInstallTaskToNode: "Enviar tarea de instalación de aplicación al nodo [{{ .name }}]"
|
||||
TaskPush: "Enviar"
|
||||
AppInstallTask: "Tarea de instalación de aplicación"
|
||||
PushAppFailed: "Error al enviar tarea de instalación de aplicación"
|
||||
Success: "Éxito"
|
||||
|
||||
# request
|
||||
ErrNoSuchHost: "No se pudo encontrar el servidor solicitado {{ .err }}"
|
||||
@@ -22,6 +27,7 @@ ErrHttpReqFailed: "Solicitud fallida {{ .err }}"
|
||||
ErrHttpReqTimeOut: "La solicitud ha expirado {{ .err }}"
|
||||
ErrCreateHttpClient: "Error al crear la solicitud {{ .err }}"
|
||||
ErrProxySetting: "Información del servidor proxy no disponible {{ .err }}, ¡compruebe e inténtelo de nuevo!"
|
||||
ErrEntranceFormat: "La entrada de seguridad {{ .name }} no está actualmente soportada. ¡Por favor verifique e inténtelo de nuevo!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "Servidor de demostración, ¡esta operación está prohibida!"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "リクエスト失敗 {{ .err }}"
|
||||
ErrHttpReqTimeOut: "リクエストタイムアウト {{ .err }}"
|
||||
ErrCreateHttpClient: "リクエストの作成に失敗しました {{ .err }}"
|
||||
ErrProxySetting: "プロキシサーバー情報が利用できません {{ .err }}、確認して再試行してください!"
|
||||
ErrEntranceFormat: "セキュリティエントランス {{ .name }} は現在サポートされていません。確認して再試行してください!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "デモサーバーではこの操作は許可されていません!"
|
||||
@@ -111,6 +112,11 @@ FailedStatus: "{{ .name }} 失敗 {{ .err }}"
|
||||
Start: "開始"
|
||||
SubTask: "サブタスク"
|
||||
Skip: "エラーを無視して続行..."
|
||||
PushAppInstallTaskToNode: "アプリインストールタスクをノード [{{ .name }}] にプッシュ"
|
||||
TaskPush: "プッシュ"
|
||||
AppInstallTask: "アプリインストールタスク"
|
||||
PushAppFailed: "アプリインストールタスクのプッシュに失敗しました"
|
||||
Success: "成功"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "スクリプトライブラリ"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "요청 실패 {{ .err }}"
|
||||
ErrHttpReqTimeOut: "요청 시간이 초과되었습니다 {{ .err }}"
|
||||
ErrCreateHttpClient: "요청 생성 실패 {{ .err }}"
|
||||
ErrProxySetting: "프록시 서버 정보를 사용할 수 없음 {{ .err }}, 확인 후 다시 시도하세요!"
|
||||
ErrEntranceFormat: "보안 입구 {{ .name }}은(는) 현재 지원되지 않습니다. 확인 후 다시 시도해 주세요!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "데모 서버에서는 이 작업이 금지되어 있습니다!"
|
||||
@@ -110,6 +111,11 @@ FailedStatus: "{{ .name }} 실패 {{ .err }}"
|
||||
Start: "시작"
|
||||
SubTask: "서브 작업"
|
||||
Skip: "오류 무시하고 계속..."
|
||||
PushAppInstallTaskToNode: "노드 [{{ .name }}]에 앱 설치 작업 푸시"
|
||||
TaskPush: "푸시"
|
||||
AppInstallTask: "앱 설치 작업"
|
||||
PushAppFailed: "앱 설치 작업 푸시 실패"
|
||||
Success: "성공"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "스크립트 라이브러리"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "Permintaan gagal {{ .err }}"
|
||||
ErrHttpReqTimeOut: "Permintaan telah tamat masa {{ .err }}"
|
||||
ErrCreateHttpClient: "Gagal mencipta permintaan {{ .err }}"
|
||||
ErrProxySetting: "Maklumat pelayan proksi tidak tersedia {{ .err }}, sila periksa dan cuba lagi!"
|
||||
ErrEntranceFormat: "Pintu masuk keselamatan {{ .name }} tidak disokong buat masa ini. Sila periksa dan cuba lagi!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "Pelayan demo, operasi ini dilarang!"
|
||||
@@ -105,6 +106,11 @@ FailedStatus: "{{ .name }} gagal {{ .err }}"
|
||||
Start: "Mula"
|
||||
SubTask: "Tugas Sub"
|
||||
Skip: "Abaikan ralat dan teruskan..."
|
||||
PushAppInstallTaskToNode: "Tolak tugas pemasangan aplikasi ke nod [{{ .name }}]"
|
||||
TaskPush: "Tolak"
|
||||
AppInstallTask: "Tugas pemasangan aplikasi"
|
||||
PushAppFailed: "Gagal menolak tugas pemasangan aplikasi"
|
||||
Success: "Berjaya"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "Pustaka Skrip"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "Falha na requisição {{ .err }}"
|
||||
ErrHttpReqTimeOut: "Tempo de requisição esgotado {{ .err }}"
|
||||
ErrCreateHttpClient: "Falha ao criar a requisição {{ .err }}"
|
||||
ErrProxySetting: "Informação do servidor proxy indisponível {{ .err }}, verifique e tente novamente!"
|
||||
ErrEntranceFormat: "A entrada de segurança {{ .name }} não é suportada atualmente. Por favor verifique e tente novamente!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "Servidor de demonstração, essa operação é proibida!"
|
||||
@@ -110,6 +111,11 @@ FailedStatus: "{{ .name }} falhou {{ .err }}"
|
||||
Start: "Iniciar"
|
||||
SubTask: "Subtarefa"
|
||||
Skip: "Ignorar erros e continuar..."
|
||||
PushAppInstallTaskToNode: "Enviar tarefa de instalação de aplicativo para o nó [{{ .name }}]"
|
||||
TaskPush: "Enviar"
|
||||
AppInstallTask: "Tarefa de instalação de aplicativo"
|
||||
PushAppFailed: "Falha ao enviar tarefa de instalação de aplicativo"
|
||||
Success: "Sucesso"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "Biblioteca de Scripts"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "Ошибка запроса {{ .err }}"
|
||||
ErrHttpReqTimeOut: "Время ожидания запроса истекло {{ .err }}"
|
||||
ErrCreateHttpClient: "Ошибка создания запроса {{ .err }}"
|
||||
ErrProxySetting: "Информация о прокси-сервере недоступна {{ .err }}, проверьте и повторите попытку!"
|
||||
ErrEntranceFormat: "Защищенный вход {{ .name }} в настоящее время не поддерживается. Пожалуйста, проверьте и повторите попытку!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "Демонстрационный сервер, эта операция запрещена!"
|
||||
@@ -110,6 +111,10 @@ FailedStatus: "{{ .name }} не удалось {{ .err }}"
|
||||
Start: "Начать"
|
||||
SubTask: "Подзадача"
|
||||
Skip: "Пропустить ошибки и продолжить..."
|
||||
TaskPush: "Отправить"
|
||||
AppInstallTask: "Задача установки приложения"
|
||||
PushAppFailed: "Не удалось отправить задачу установки приложения"
|
||||
Success: "Успешно"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "Библиотека скриптов"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "İstek başarısız {{ .err }}"
|
||||
ErrHttpReqTimeOut: "İstek zaman aşımına uğradı {{ .err }}"
|
||||
ErrCreateHttpClient: "İstek oluşturma başarısız {{ .err }}"
|
||||
ErrProxySetting: "Proxy sunucu bilgisi kullanılamıyor {{ .err }}, lütfen kontrol edip tekrar deneyin!"
|
||||
ErrEntranceFormat: "{{ .name }} güvenlik girişi şu anda desteklenmiyor. Lütfen kontrol edip tekrar deneyin!"
|
||||
|
||||
# common
|
||||
ErrDemoEnvironment: "Demo sunucu, bu işlem yasak!"
|
||||
@@ -109,6 +110,11 @@ FailedStatus: "{{ .name }} başarısız {{ .err }}"
|
||||
Start: "Başla"
|
||||
SubTask: "Alt görev"
|
||||
Skip: "Hataları atla ve devam et..."
|
||||
PushAppInstallTaskToNode: "Uygulama kurulum görevini düğüme [{{ .name }}] gönder"
|
||||
TaskPush: "Gönder"
|
||||
AppInstallTask: "Uygulama kurulum görevi"
|
||||
PushAppFailed: "Uygulama kurulum görevi gönderilemedi"
|
||||
Success: "Başarılı"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "Betik Kütüphanesi"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "請求失敗 {{ .err }}"
|
||||
ErrHttpReqTimeOut: "請求逾時 {{ .err }}"
|
||||
ErrCreateHttpClient: "建立請求失敗 {{ .err }}"
|
||||
ErrProxySetting: "代理伺服器資訊不可用 {{ .err }},請檢查後重試!"
|
||||
ErrEntranceFormat: "暫不支援安全入口 {{ .name }} ,請檢查後重試!"
|
||||
|
||||
#common
|
||||
ErrDemoEnvironment: "示範伺服器,禁止此操作!"
|
||||
@@ -110,6 +111,11 @@ FailedStatus: "{{ .name }} 失敗 {{ .err }}"
|
||||
Start: "開始"
|
||||
SubTask: "子任務"
|
||||
Skip: "忽略錯誤並繼續..."
|
||||
PushAppInstallTaskToNode: "推送應用安裝任務到節點 [{{ .name }}]"
|
||||
TaskPush: "推送"
|
||||
AppInstallTask: "應用安裝任務"
|
||||
PushAppFailed: "推送應用安裝任務失敗"
|
||||
Success: "成功"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "腳本庫"
|
||||
|
||||
@@ -22,6 +22,7 @@ ErrHttpReqFailed: "请求失败 {{ .err }}"
|
||||
ErrHttpReqTimeOut: "请求超时 {{ .err }}"
|
||||
ErrCreateHttpClient: "创建请求失败 {{ .err }}"
|
||||
ErrProxySetting: "代理服务器信息不可用 {{ .err }},请检查后重试!"
|
||||
ErrEntranceFormat: "暂不支持安全入口 {{ .name }} ,请检查后重试!"
|
||||
|
||||
#common
|
||||
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
||||
@@ -110,6 +111,11 @@ FailedStatus: "{{ .name }} 失败 {{ .err }}"
|
||||
Start: "开始"
|
||||
SubTask: "子任务"
|
||||
Skip: "忽略错误并继续..."
|
||||
PushAppInstallTaskToNode: "推送应用安装任务到节点 [{{ .name }}]"
|
||||
TaskPush: "推送"
|
||||
AppInstallTask: "应用安装任务"
|
||||
PushAppFailed: "推送应用安装任务失败"
|
||||
Success: "成功"
|
||||
|
||||
#script
|
||||
ScriptLibrary: "脚本库"
|
||||
|
||||
@@ -3,10 +3,11 @@ package helper
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/core/app/model"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func LoadMenus() string {
|
||||
@@ -43,7 +44,7 @@ func LoadMenus() string {
|
||||
Children: []dto.ShowMenu{
|
||||
{ID: "118", Disabled: false, Title: "xpack.app.app", IsShow: true, Label: "XApp", Path: "/xpack/app", Sort: 100},
|
||||
{ID: "112", Disabled: false, Title: "xpack.waf.name", IsShow: true, Label: "Dashboard", Path: "/xpack/waf/dashboard", Sort: 200},
|
||||
{ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "Node", Path: "/xpack/node", Sort: 300},
|
||||
{ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "NodeDashboard", Path: "/xpack/node/dashboard", Sort: 300},
|
||||
{ID: "119", Disabled: false, Title: "xpack.upage", IsShow: true, Label: "Upage", Path: "/xpack/upage", Sort: 400},
|
||||
{ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard", Sort: 500},
|
||||
{ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper", Sort: 600},
|
||||
|
||||
@@ -26,6 +26,7 @@ func Init() {
|
||||
migrations.AddUpgradeBackupCopies,
|
||||
migrations.AddScriptSync,
|
||||
migrations.UpdateXpackHideMenuSort,
|
||||
migrations.AdjustXpackNode,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -602,3 +602,44 @@ var UpdateXpackHideMenuSort = &gormigrate.Migration{
|
||||
return tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Update("value", string(updatedJSON)).Error
|
||||
},
|
||||
}
|
||||
|
||||
var AdjustXpackNode = &gormigrate.Migration{
|
||||
ID: "20260108-adjust-xpack-node",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var menuJSON string
|
||||
if err := tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Pluck("value", &menuJSON).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if menuJSON == "" {
|
||||
menuJSON = helper.LoadMenus()
|
||||
}
|
||||
var menus []dto.ShowMenu
|
||||
if err := json.Unmarshal([]byte(menuJSON), &menus); err != nil {
|
||||
return tx.Model(&model.Setting{}).
|
||||
Where("key = ?", "HideMenu").
|
||||
Update("value", helper.LoadMenus()).Error
|
||||
}
|
||||
|
||||
for i := 0; i < len(menus); i++ {
|
||||
if menus[i].Label != "Xpack-Menu" {
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(menus[i].Children); j++ {
|
||||
if menus[i].Children[j].Label == "Node" {
|
||||
menus[i].Children[j].Label = "NodeDashboard"
|
||||
menus[i].Children[j].Path = "/xpack/node/dashboard"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updatedJSON, err := json.Marshal(menus)
|
||||
if err != nil {
|
||||
return tx.Model(&model.Setting{}).
|
||||
Where("key = ?", "HideMenu").
|
||||
Update("value", helper.LoadMenus()).Error
|
||||
}
|
||||
|
||||
return tx.Model(&model.Setting{}).Where("key = ?", "HideMenu").Update("value", string(updatedJSON)).Error
|
||||
},
|
||||
}
|
||||
|
||||
+131
-21
@@ -1,9 +1,17 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/init/auth"
|
||||
"github.com/1Panel-dev/1Panel/core/init/db"
|
||||
"github.com/1Panel-dev/1Panel/core/init/geo"
|
||||
@@ -12,10 +20,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/core/init/proxy"
|
||||
"github.com/1Panel-dev/1Panel/core/init/run"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"github.com/soheilhy/cmux"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
@@ -62,8 +67,12 @@ func Start() {
|
||||
global.CONF.Conn.BindAddress = fmt.Sprintf("[%s]", global.CONF.Conn.BindAddress)
|
||||
}
|
||||
server := &http.Server{
|
||||
Addr: global.CONF.Conn.BindAddress + ":" + global.CONF.Conn.Port,
|
||||
Handler: rootRouter,
|
||||
Addr: global.CONF.Conn.BindAddress + ":" + global.CONF.Conn.Port,
|
||||
Handler: rootRouter,
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
ReadTimeout: 600 * time.Second,
|
||||
WriteTimeout: 600 * time.Second,
|
||||
IdleTimeout: 240 * time.Second,
|
||||
}
|
||||
ln, err := net.Listen(tcpItem, server.Addr)
|
||||
if err != nil {
|
||||
@@ -73,21 +82,7 @@ func Start() {
|
||||
*net.TCPListener
|
||||
}
|
||||
if global.CONF.Conn.SSL == constant.StatusEnable {
|
||||
certPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt")
|
||||
keyPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.key")
|
||||
certificate, err := os.ReadFile(certPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
key, err := os.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cert, err := tls.X509KeyPair(certificate, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
constant.CertStore.Store(&cert)
|
||||
constant.CertStore.Store(loadCert())
|
||||
|
||||
server.TLSConfig = &tls.Config{
|
||||
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
@@ -99,10 +94,125 @@ func Start() {
|
||||
if err := server.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, "", ""); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
} else if global.CONF.Conn.SSL == constant.StatusMux {
|
||||
constant.CertStore.Store(loadCert())
|
||||
|
||||
server.TLSConfig = &tls.Config{
|
||||
NextProtos: []string{"h2", "http/1.1"},
|
||||
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return constant.CertStore.Load().(*tls.Certificate), nil
|
||||
},
|
||||
}
|
||||
|
||||
m := cmux.New(ln)
|
||||
|
||||
httpsL := m.Match(cmux.TLS())
|
||||
httpL := m.Match(cmux.HTTP1Fast())
|
||||
anyL := m.Match(cmux.Any())
|
||||
|
||||
go func() {
|
||||
if err := server.Serve(tls.NewListener(httpsL, server.TLSConfig)); err != nil {
|
||||
global.LOG.Errorf("HTTPS Serve Error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := httpL.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go handleMuxHttpConn(conn)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := anyL.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
global.LOG.Infof("listen at mux (http/https)://%s:%s [%s]", global.CONF.Conn.BindAddress, global.CONF.Conn.Port, tcpItem)
|
||||
|
||||
if err := m.Serve(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
global.LOG.Infof("listen at http://%s:%s [%s]", global.CONF.Conn.BindAddress, global.CONF.Conn.Port, tcpItem)
|
||||
if err := server.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func loadCert() *tls.Certificate {
|
||||
certPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt")
|
||||
keyPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.key")
|
||||
certificate, err := os.ReadFile(certPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
key, err := os.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cert, err := tls.X509KeyPair(certificate, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &cert
|
||||
}
|
||||
|
||||
func handleMuxHttpConn(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
req, err := http.ReadRequest(bufio.NewReader(conn))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if req.Host == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ua := req.Header.Get("User-Agent")
|
||||
if ua == "" {
|
||||
return
|
||||
}
|
||||
|
||||
switch req.Method {
|
||||
case http.MethodGet, http.MethodHead, http.MethodPost:
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.RequestURI) > 4096 {
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(req.URL.Path, "/") {
|
||||
return
|
||||
}
|
||||
|
||||
target := "https://" + req.Host + req.URL.RequestURI()
|
||||
|
||||
resp := &http.Response{
|
||||
StatusCode: http.StatusTemporaryRedirect,
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
Header: make(http.Header),
|
||||
}
|
||||
resp.Header.Set("Location", target)
|
||||
resp.Header.Set("Connection", "close")
|
||||
|
||||
_ = resp.Write(conn)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
package cloud_storage
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/pkg/sftp"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type SftpClient struct {
|
||||
connInfo string
|
||||
config *ssh.ClientConfig
|
||||
}
|
||||
|
||||
func NewSftpClient(vars map[string]interface{}) (*SftpClient, error) {
|
||||
address := loadParamFromVars("address", vars)
|
||||
port := loadParamFromVars("port", vars)
|
||||
if len(port) == 0 {
|
||||
global.LOG.Errorf("load param port from vars failed, err: not exist!")
|
||||
}
|
||||
authMode := loadParamFromVars("authMode", vars)
|
||||
passPhrase := loadParamFromVars("passPhrase", vars)
|
||||
username := loadParamFromVars("username", vars)
|
||||
password := loadParamFromVars("password", vars)
|
||||
|
||||
var auth []ssh.AuthMethod
|
||||
if authMode == "key" {
|
||||
var signer ssh.Signer
|
||||
var err error
|
||||
if len(passPhrase) != 0 {
|
||||
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(password), []byte(passPhrase))
|
||||
} else {
|
||||
signer, err = ssh.ParsePrivateKey([]byte(password))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
auth = []ssh.AuthMethod{ssh.PublicKeys(signer)}
|
||||
} else {
|
||||
auth = []ssh.AuthMethod{ssh.Password(password)}
|
||||
}
|
||||
clientConfig := &ssh.ClientConfig{
|
||||
User: username,
|
||||
Auth: auth,
|
||||
Timeout: 30 * time.Second,
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
addr := net.JoinHostPort(address, port)
|
||||
if _, err := ssh.Dial("tcp", addr, clientConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SftpClient{connInfo: addr, config: clientConfig}, nil
|
||||
}
|
||||
|
||||
func (s SftpClient) Upload(src, target string) (bool, error) {
|
||||
sshClient, err := ssh.Dial("tcp", s.connInfo, s.config)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
client, err := sftp.NewClient(sshClient)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
targetDir, _ := path.Split(target)
|
||||
if len(targetDir) != 0 {
|
||||
if _, err = client.Stat(targetDir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err = client.MkdirAll(targetDir); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
dstFile, err := client.Create(target)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
if _, err := io.Copy(dstFile, srcFile); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func CopyItem(isDir, withName bool, src, dst string) error {
|
||||
if !isDir {
|
||||
cmdStr = fmt.Sprintf(`cp -f %s %s`, src, dst+"/")
|
||||
}
|
||||
stdout, err := cmd.RunDefaultWithStdoutBashC(cmdStr)
|
||||
stdout, err := cmd.NewCommandMgr(cmd.WithTimeout(60 * time.Second)).RunWithStdoutBashC(cmdStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle %s failed, stdout: %s, err: %v", cmdStr, stdout, err)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ package security
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/app/service"
|
||||
"github.com/1Panel-dev/1Panel/core/cmd/server/res"
|
||||
@@ -11,10 +16,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func HandleNotRoute(c *gin.Context) bool {
|
||||
@@ -98,7 +99,7 @@ func HandleNotSecurity(c *gin.Context, resType string) {
|
||||
return
|
||||
}
|
||||
if resPage == "444" {
|
||||
c.String(444, "")
|
||||
CloseDirectly(c)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -183,3 +184,19 @@ func checkSession(c *gin.Context) bool {
|
||||
_, err := global.SESSION.Get(c)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func CloseDirectly(c *gin.Context) {
|
||||
hijacker, ok := c.Writer.(http.Hijacker)
|
||||
if !ok {
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
conn, _, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
c.Abort()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
)
|
||||
|
||||
type HTTPProxyDialer struct {
|
||||
Type string
|
||||
URL string
|
||||
User string
|
||||
Password string
|
||||
}
|
||||
|
||||
func HTTPDial(dialer HTTPProxyDialer, network, addr string) (net.Conn, error) {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
|
||||
global.LOG.Debugf("Dialing HTTP proxy %s for %s", dialer.URL, addr)
|
||||
dialer.URL = strings.TrimPrefix(dialer.URL, dialer.Type+"://")
|
||||
if dialer.Type == "https" {
|
||||
conn, err = tls.DialWithDialer(
|
||||
&net.Dialer{Timeout: 30 * time.Second},
|
||||
network,
|
||||
dialer.URL,
|
||||
&tls.Config{InsecureSkipVerify: true},
|
||||
)
|
||||
} else {
|
||||
conn, err = net.DialTimeout(network, dialer.URL, 30*time.Second)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(30 * time.Second))
|
||||
connectReq := fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", addr)
|
||||
connectReq += fmt.Sprintf("Host: %s\r\n", addr)
|
||||
connectReq += "User-Agent: Go-ssh-client/1.0\r\n"
|
||||
|
||||
if dialer.User != "" {
|
||||
auth := base64.StdEncoding.EncodeToString(
|
||||
[]byte(dialer.User + ":" + dialer.Password),
|
||||
)
|
||||
connectReq += fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", auth)
|
||||
}
|
||||
connectReq += "Connection: keep-alive\r\n\r\n"
|
||||
if _, err := conn.Write([]byte(connectReq)); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
reader := bufio.NewReader(conn)
|
||||
response, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasPrefix(response, "HTTP/1.1 200") &&
|
||||
!strings.HasPrefix(response, "HTTP/1.0 200") {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("proxy connection failed: %s", strings.TrimSpace(response))
|
||||
}
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if line == "\r\n" || line == "\n" {
|
||||
break
|
||||
}
|
||||
}
|
||||
conn.SetDeadline(time.Time{})
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
+73
-10
@@ -8,18 +8,23 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/encrypt"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
type ConnInfo struct {
|
||||
User string `json:"user"`
|
||||
Addr string `json:"addr"`
|
||||
Port int `json:"port"`
|
||||
AuthMode string `json:"authMode"`
|
||||
Password string `json:"password"`
|
||||
PrivateKey []byte `json:"privateKey"`
|
||||
PassPhrase []byte `json:"passPhrase"`
|
||||
User string `json:"user"`
|
||||
Addr string `json:"addr"`
|
||||
Port int `json:"port"`
|
||||
AuthMode string `json:"authMode"`
|
||||
Password string `json:"password"`
|
||||
PrivateKey []byte `json:"privateKey"`
|
||||
PassPhrase []byte `json:"passPhrase"`
|
||||
|
||||
UseProxy bool `json:"useProxy"`
|
||||
DialTimeOut time.Duration `json:"dialTimeOut"`
|
||||
}
|
||||
|
||||
@@ -52,7 +57,7 @@ func NewClient(c ConnInfo) (*SSHClient, error) {
|
||||
if strings.Contains(c.Addr, ":") {
|
||||
proto = "tcp6"
|
||||
}
|
||||
client, err := DialWithTimeout(proto, addr, config)
|
||||
client, err := DialWithTimeout(proto, addr, c.UseProxy, config)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
@@ -240,8 +245,14 @@ func (c *SSHClient) RunWithStreamOutput(command string, outputCallback func(stri
|
||||
return err
|
||||
}
|
||||
|
||||
func DialWithTimeout(network, addr string, config *gossh.ClientConfig) (*gossh.Client, error) {
|
||||
conn, err := net.DialTimeout(network, addr, config.Timeout)
|
||||
func DialWithTimeout(network, addr string, useProxy bool, config *gossh.ClientConfig) (*gossh.Client, error) {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
if useProxy {
|
||||
conn, err = loadSSHConnByProxy(network, addr, config.Timeout)
|
||||
} else {
|
||||
conn, err = net.DialTimeout(network, addr, config.Timeout)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -256,3 +267,55 @@ func DialWithTimeout(network, addr string, config *gossh.ClientConfig) (*gossh.C
|
||||
}
|
||||
return gossh.NewClient(c, chans, reqs), nil
|
||||
}
|
||||
|
||||
func loadSSHConnByProxy(network, addr string, timeout time.Duration) (net.Conn, error) {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
proxyType, err := settingRepo.Get(repo.WithByKey("ProxyType"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get proxy type from db failed, err: %v", err)
|
||||
}
|
||||
if len(proxyType.Value) == 0 {
|
||||
return nil, fmt.Errorf("get proxy type from db failed, err: %v", err)
|
||||
}
|
||||
proxyUrl, _ := settingRepo.Get(repo.WithByKey("ProxyUrl"))
|
||||
port, _ := settingRepo.Get(repo.WithByKey("ProxyPort"))
|
||||
user, _ := settingRepo.Get(repo.WithByKey("ProxyUser"))
|
||||
passwd, _ := settingRepo.Get(repo.WithByKey("ProxyPasswd"))
|
||||
|
||||
pass, _ := encrypt.StringDecrypt(passwd.Value)
|
||||
proxyItem := fmt.Sprintf("%s:%s", proxyUrl.Value, port.Value)
|
||||
switch proxyType.Value {
|
||||
case "http", "https":
|
||||
item := HTTPProxyDialer{
|
||||
Type: proxyType.Value,
|
||||
URL: proxyItem,
|
||||
User: user.Value,
|
||||
Password: pass,
|
||||
}
|
||||
return HTTPDial(item, network, addr)
|
||||
case "socks5":
|
||||
var auth *proxy.Auth
|
||||
if len(user.Value) == 0 {
|
||||
auth = nil
|
||||
} else {
|
||||
auth = &proxy.Auth{
|
||||
User: user.Value,
|
||||
Password: pass,
|
||||
}
|
||||
}
|
||||
dialer, err := proxy.SOCKS5("tcp", proxyItem, auth, &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("new socks5 proxy failed, err: %v", err)
|
||||
}
|
||||
return dialer.Dial(network, addr)
|
||||
default:
|
||||
conn, err := net.DialTimeout(network, addr, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2014-2025 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
Copyright (c) 2014-2026 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2014-2025 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
Copyright (c) 2014-2026 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
|
||||
@@ -36,9 +36,10 @@
|
||||
"axios": "^1.7.2",
|
||||
"codemirror": "^6.0.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dompurify": "^3.3.1",
|
||||
"echarts": "^5.5.0",
|
||||
"element-plus": "2.11.9",
|
||||
"fit2cloud-ui-plus": "^1.2.3",
|
||||
"fit2cloud-ui-plus": "^1.2.4",
|
||||
"highlight.js": "^11.9.0",
|
||||
"js-base64": "^3.7.7",
|
||||
"jsencrypt": "^3.3.2",
|
||||
|
||||
@@ -17,6 +17,7 @@ export namespace App {
|
||||
website?: string;
|
||||
github?: string;
|
||||
readme: string;
|
||||
batchInstallSupport: boolean;
|
||||
}
|
||||
|
||||
interface Locale {
|
||||
@@ -55,6 +56,7 @@ export namespace App {
|
||||
tags: string[];
|
||||
gpuSupport: boolean;
|
||||
recommend: number;
|
||||
batchInstallSupport: boolean;
|
||||
}
|
||||
|
||||
export interface AppResPage {
|
||||
@@ -132,6 +134,7 @@ export namespace App {
|
||||
appDetailId: number;
|
||||
params: any;
|
||||
taskID: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AppInstallSearch extends ReqPage {
|
||||
@@ -351,4 +354,10 @@ export namespace App {
|
||||
status: string;
|
||||
imagePrefix: string;
|
||||
}
|
||||
|
||||
export interface InstallAppToNodes extends AppInstall {
|
||||
nodes: string[];
|
||||
appKey: string;
|
||||
version: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ export namespace Cronjob {
|
||||
alertMethodItems: Array<string>;
|
||||
|
||||
scopes: string[];
|
||||
args: string;
|
||||
argItems: Array<string>;
|
||||
}
|
||||
export interface Item {
|
||||
val: string;
|
||||
@@ -113,6 +115,7 @@ export namespace Cronjob {
|
||||
alertMethod: string;
|
||||
|
||||
scopes?: string[];
|
||||
args: string;
|
||||
}
|
||||
export interface CronjobTrans {
|
||||
name: string;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user