Compare commits

...
Author SHA1 Message Date
ssongliu 2c92226f88 chore: Modify cache cleanup internationalization (#11551) 2026-01-04 18:32:46 +08:00
CityFun cd9cb9b9c9 feat: Update website name validation rules (#11550) 2026-01-04 10:29:43 +00:00
CityFun b2777055bc fix: Fix website log cleanup selection state (#11549) 2026-01-04 10:27:40 +00:00
ssongliu c8673b60bb fix: Fix the issue of abnormal cache cleanup display (#11547) 2026-01-04 09:31:43 +00:00
ssongliu 21975dff2d chore: Rollback S3 backup account SDK version (#11546)
Refs #11486

aws v2 存在部分兼容性问题 https://github.com/aws/aws-sdk-go-v2/issues/3007
2026-01-04 08:51:40 +00:00
CityFun 6ab14185e0 perf: Optimize supervisor log reading (#11545)
Refs https://github.com/1Panel-dev/1Panel/issues/11515
2026-01-04 08:49:40 +00:00
CityFun 1f70646952 feat: Add enable UDP option for TCP/UDP website configuration (#11543) 2026-01-04 15:23:56 +08:00
ssongliu c90ed9e873 feat: Cache database default connections (#11540)
Refs  #10819
2026-01-04 06:39:40 +00:00
CityFun e4ee07d36b feat: Support batch installation of applications (#11539) 2026-01-04 05:43:40 +00:00
ssongliu 8fb3e78554 chore: Fix some internationalization content (#11528)
Refs #11517
2025-12-31 14:35:38 +00:00
CityFun 01ab004876 fix: update MdEditor component to prevent potential XSS attacks (#11527) 2025-12-31 14:33:38 +00:00
ssongliu 6205eac51c feat: Support enabling proxy when adding nodes (#11525) 2025-12-31 22:31:43 +08:00
王贺 d9a5418029 chore: update copyright (#11524) 2025-12-31 09:03:56 +08:00
CityFun 74a8e61f3e feat: change website http to https logic (#11522)
Refs https://github.com/1Panel-dev/1Panel/issues/11521
2025-12-30 06:33:36 +00:00
CityFun e18472f1a3 feat: optimize disk mount logic (#11519) 2025-12-30 06:31:35 +00:00
蘭 e3dea80cb7 fix: Fix the issue of garbled Chinese characters in recipient names and email titles in email alerts (#11516)
#11264
2025-12-29 09:37:35 +00:00
ssongliu 50947f4ddc feat: ICMP ping disable compatibility with Debian 13 (#11514)
Refs  #11472
2025-12-29 09:35:36 +00:00
KOMATA d302bc07b3 feat: Add support for Mux SSL mode and update related settings (#11509)
* feat: Add support for Mux SSL mode and update related settings

- Introduced a new SSL mode "Mux" in the settings, allowing for HTTP to HTTPS redirection.
- Updated the `SSL` field in the `SettingUpdate` struct to include "Mux" as a valid option.
- Modified the server logic to handle Mux connections, including certificate management and HTTP redirection.
- Updated frontend components to reflect the new SSL options and improved user guidance in multiple languages.

* fix: Update HTTPS related messages for improved clarity and security guidance in multiple languages
2025-12-29 15:41:15 +08:00
CityFun c6df20e565 feat: support sync 404 html page to websites (#11513)
Refs https://github.com/1Panel-dev/1Panel/issues/11489
2025-12-29 07:17:34 +00:00
CityFun 6f9a1321d1 feat: support custom DNS server for manual DNS mode when applying certificates (#11512) 2025-12-29 07:13:35 +00:00
ssongliu eb4eb31578 feat: Multi-machine management supports viewing node logs (#11510) 2025-12-29 07:11:34 +00:00
CityFun f8f5fcfca2 fix: Fixed Website configuration file automatically keeps adding HTTPS redirects (#11506)
#11490
2025-12-29 07:09:35 +00:00
l061x 4e7b654090 fix: Fix command argument formatting in terminal initlinux (#11484) 2025-12-26 22:03:24 +08:00
ssongliu e8059d3676 fix: Fix refresh issue during compose creation (#11482)
Refs #11463
2025-12-26 13:55:03 +00:00
ssongliu ffadc6721b fix: Fix issue where compose cannot be created when empty (#11481) 2025-12-26 09:13:04 +00:00
CityFun e2e774d215 feat: add website log clean option for clean cache (#11480) 2025-12-26 09:11:03 +00:00
ssongliu f23d3678fb fix: Fix backup account echo abnormality issue (#11479)
Refs #11478
2025-12-26 09:09:03 +00:00
ssongliu dfade50bd8 fix: Fix snapshot backup application image failure issue (#11477) 2025-12-26 16:49:03 +08:00
ssongliu d25b5f4f2a feat: Add quick operation features to node overview page (#11476) 2025-12-26 08:35:03 +00:00
CityFun 9a17bc74b0 feat: add 'nofail' option for disk mounting (#11475)
Refs https://github.com/1Panel-dev/1Panel/issues/11468
2025-12-26 08:33:03 +00:00
CityFun 015605526d fix: add missing intermediate certificates for IP certificate requests (#11470)
Refs https://github.com/1Panel-dev/1Panel/issues/11462
2025-12-26 08:31:03 +00:00
CityFun 099896dc96 feat: add app temporary download file cleanup option to cache cleaning (#11460) 2025-12-25 10:33:03 +00:00
CityFun aa1bc6fa8e feat: add website log cleanup option to cache cleaning (#11457) 2025-12-25 07:43:02 +00:00
ssongliu f27a429fc5 feat: Cache cleanup supports cleaning up unassociated backups (#11452) 2025-12-25 13:49:47 +08:00
117 changed files with 2381 additions and 1364 deletions
+20
View File
@@ -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)
}
+20 -19
View File
@@ -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 {
+1 -1
View File
@@ -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"`
}
+9
View File
@@ -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 {
+1
View File
@@ -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 {
+2
View File
@@ -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 {
+16 -11
View File
@@ -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"`
+1
View File
@@ -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"`
}
+1
View File
@@ -37,6 +37,7 @@ type SyncTime struct {
type CleanData struct {
SystemClean []CleanTree `json:"systemClean"`
BackupClean []CleanTree `json:"backupClean"`
UploadClean []CleanTree `json:"uploadClean"`
DownloadClean []CleanTree `json:"downloadClean"`
SystemLogClean []CleanTree `json:"systemLogClean"`
+1
View File
@@ -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:"-"`
+5 -20
View File
@@ -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
+34 -8
View File
@@ -47,6 +47,7 @@ type IAppService interface {
GetAppDetailByID(id uint) (*response.AppDetailDTO, error)
SyncAppListFromLocal(taskID string)
GetAppIcon(appID uint) ([]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
}
+1
View File
@@ -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
+493 -124
View File
@@ -11,36 +11,27 @@ import (
"strings"
"time"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/utils/controller"
"github.com/1Panel-dev/1Panel/agent/utils/docker"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/filters"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/app/task"
"github.com/1Panel-dev/1Panel/agent/constant"
"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/docker"
fileUtils "github.com/1Panel-dev/1Panel/agent/utils/files"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/filters"
"github.com/google/uuid"
)
const (
upgradePath = "1panel/tmp/upgrade"
snapshotTmpPath = "1panel/tmp/system"
rollbackPath = "1panel/tmp"
cachePath = "1panel/cache"
oldOriginalPath = "original"
oldAppBackupPath = "1panel/resource/apps_bak"
oldDownloadPath = "1panel/tmp/download"
oldUpgradePath = "1panel/tmp"
tmpUploadPath = "1panel/tmp/upload"
uploadPath = "1panel/uploads"
downloadPath = "1panel/download"
rollbackPath = "1panel/tmp"
upgradePath = "1panel/tmp/upgrade"
uploadPath = "1panel/uploads"
downloadPath = "1panel/download"
)
func (u *DeviceService) Scan() dto.CleanData {
@@ -61,54 +52,10 @@ func (u *DeviceService) Scan() dto.CleanData {
Type: "1panel_original",
Children: loadTreeWithDir(true, "1panel_original", originalPath, fileOp),
})
treeData = append(treeData, loadUpgradeTree(fileOp))
treeData = append(treeData, loadAgentPackage(fileOp))
upgradePath := path.Join(global.Dir.BaseDir, upgradePath)
upgradeSize, _ := fileOp.GetDirSize(upgradePath)
upgradeTree := dto.CleanTree{
ID: uuid.NewString(),
Label: "upgrade",
Size: uint64(upgradeSize),
IsCheck: false,
IsRecommend: true,
Type: "upgrade",
Children: loadTreeWithDir(true, "upgrade", upgradePath, fileOp),
}
if len(upgradeTree.Children) != 0 {
sort.Slice(upgradeTree.Children, func(i, j int) bool {
return common.CompareVersion(upgradeTree.Children[i].Label, upgradeTree.Children[j].Label)
})
if global.IsMaster {
var copiesSetting model.Setting
_ = global.CoreDB.Where("key = ?", "UpgradeBackupCopies").First(&copiesSetting).Error
copies, _ := strconv.Atoi(copiesSetting.Value)
if copies == 0 || copies > len(upgradeTree.Children) {
copies = len(upgradeTree.Children)
}
for i := 0; i < copies; i++ {
upgradeTree.Children[i].IsCheck = false
upgradeTree.Children[i].IsRecommend = false
}
} else {
upgradeTree.Children[0].IsCheck = false
upgradeTree.Children[0].IsRecommend = false
}
}
treeData = append(treeData, upgradeTree)
tmpBackupTree := loadTmpBackupTree(fileOp)
tmpBackupSize := uint64(0)
for _, tmp := range tmpBackupTree {
tmpBackupSize += tmp.Size
}
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "backup",
Size: tmpBackupSize,
IsCheck: tmpBackupSize > 0,
IsRecommend: true,
Type: "backup",
Children: tmpBackupTree,
})
SystemClean.BackupClean = loadBackupTree(fileOp)
rollBackTree := loadRollBackTree(fileOp)
rollbackSize := uint64(0)
@@ -124,17 +71,6 @@ func (u *DeviceService) Scan() dto.CleanData {
Type: "rollback",
Children: rollBackTree,
})
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.SystemClean = treeData
uploadTreeData := loadUploadTree(fileOp)
@@ -154,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 {
@@ -164,13 +99,13 @@ func (u *DeviceService) Clean(req []dto.Clean) {
case "upgrade":
dropFileOrDir(path.Join(global.Dir.BaseDir, upgradePath, item.Name))
case "backup":
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/app"))
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/database"))
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/website"))
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/directory"))
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/log"))
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/system"))
case "agent":
dropFileOrDir(path.Join(global.Dir.BaseDir, "1panel/agent/package", item.Name))
case "tmp_backup":
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp"))
case "unknown_backup":
dropFileOrDir(item.Name)
case "rollback":
dropFileOrDir(path.Join(global.Dir.BaseDir, rollbackPath, "app"))
@@ -183,25 +118,14 @@ 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))
if len(item.Name) == 0 {
dropFileOrDir(path.Join(global.Dir.BaseDir, tmpUploadPath))
}
case "upload_tmp":
dropFileOrDir(path.Join(global.Dir.BaseDir, tmpUploadPath, item.Name))
case "upload_app":
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "app", item.Name))
case "upload_database":
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "database", item.Name))
case "upload_website":
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "website", item.Name))
case "upload_directory":
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "directory", item.Name))
case "download":
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, item.Name))
case "download_app":
@@ -210,8 +134,6 @@ func (u *DeviceService) Clean(req []dto.Clean) {
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, "database", item.Name))
case "download_website":
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, "website", item.Name))
case "download_directory":
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, "directory", item.Name))
case "system_log":
if len(item.Name) == 0 {
@@ -243,6 +165,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":
@@ -253,16 +177,14 @@ 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))
}
}
_ = 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 {
@@ -284,25 +206,20 @@ func doSystemClean(taskItem *task.Task) func(t *task.Task) error {
}
}
dropWithTask(path.Join(global.Dir.BaseDir, snapshotTmpPath), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.LocalBackupDir, "tmp/system"), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, rollbackPath, "app"), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, rollbackPath, "website"), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, rollbackPath, "database"), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, oldOriginalPath), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, oldAppBackupPath), taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, oldDownloadPath), taskItem, &size, &fileCount)
oldUpgradePath := path.Join(global.Dir.BaseDir, oldUpgradePath)
oldUpgradeFiles, _ := os.ReadDir(oldUpgradePath)
upgrades := path.Join(global.Dir.BaseDir, upgradePath)
oldUpgradeFiles, _ := os.ReadDir(upgrades)
if len(oldUpgradeFiles) != 0 {
for i := 0; i < len(oldUpgradeFiles); i++ {
dropWithTask(path.Join(oldUpgradePath, oldUpgradeFiles[i].Name()), taskItem, &size, &fileCount)
dropWithTask(path.Join(upgrades, oldUpgradeFiles[i].Name()), taskItem, &size, &fileCount)
}
}
dropWithTask(path.Join(global.Dir.BaseDir, tmpUploadPath), taskItem, &size, &fileCount)
dropWithExclude(path.Join(global.Dir.BaseDir, uploadPath), []string{"theme"}, taskItem, &size, &fileCount)
dropWithTask(path.Join(global.Dir.BaseDir, downloadPath), taskItem, &size, &fileCount)
@@ -338,17 +255,356 @@ func doSystemClean(taskItem *task.Task) func(t *task.Task) error {
}
}
func loadTmpBackupTree(fileOp fileUtils.FileOp) []dto.CleanTree {
func loadUpgradeTree(fileOp fileUtils.FileOp) dto.CleanTree {
upgradePath := path.Join(global.Dir.BaseDir, upgradePath)
upgradeSize, _ := fileOp.GetDirSize(upgradePath)
upgradeTree := dto.CleanTree{
ID: uuid.NewString(),
Label: "upgrade",
Size: uint64(upgradeSize),
IsCheck: false,
IsRecommend: true,
Type: "upgrade",
Children: loadTreeWithDir(true, "upgrade", upgradePath, fileOp),
}
if len(upgradeTree.Children) != 0 {
sort.Slice(upgradeTree.Children, func(i, j int) bool {
return common.CompareVersion(upgradeTree.Children[i].Label, upgradeTree.Children[j].Label)
})
if global.IsMaster {
var copiesSetting model.Setting
_ = global.CoreDB.Where("key = ?", "UpgradeBackupCopies").First(&copiesSetting).Error
copies, _ := strconv.Atoi(copiesSetting.Value)
if copies == 0 || copies > len(upgradeTree.Children) {
copies = len(upgradeTree.Children)
}
for i := 0; i < copies; i++ {
upgradeTree.Children[i].IsCheck = false
upgradeTree.Children[i].IsRecommend = false
}
} else {
upgradeTree.Children[0].IsCheck = false
upgradeTree.Children[0].IsRecommend = false
}
}
return upgradeTree
}
func loadAgentPackage(fileOp fileUtils.FileOp) dto.CleanTree {
pathItem := path.Join(global.Dir.BaseDir, "1panel/agent/package")
itemTree := dto.CleanTree{
ID: uuid.NewString(),
Label: "agent_packages",
IsCheck: true,
IsRecommend: true,
Type: "agent",
}
files, _ := os.ReadDir(pathItem)
for _, file := range files {
if file.IsDir() {
itemSize, _ := fileOp.GetDirSize(path.Join(pathItem, file.Name()))
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,
IsRecommend: true,
Type: "agent",
})
} else {
if strings.HasPrefix(file.Name(), fmt.Sprintf("1panel-agent_%s_a", global.CONF.Base.Version)) {
continue
}
itemSize, _ := file.Info()
itemTree.Size += uint64(itemSize.Size())
itemTree.Children = append(itemTree.Children, dto.CleanTree{
ID: uuid.NewString(),
Label: file.Name(),
Name: file.Name(),
Size: uint64(itemSize.Size()),
IsCheck: true,
IsRecommend: true,
Type: "agent",
})
}
}
if itemTree.Size == 0 {
itemTree.IsCheck = false
}
return itemTree
}
func loadBackupTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/app"), "tmp_backup_app", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/website"), "tmp_backup_website", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/database"), "tmp_backup_database", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/system"), "tmp_backup_snapshot", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/directory"), "tmp_backup_directory", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/log"), "tmp_backup_log", fileOp)
tmpSize, _ := fileOp.GetDirSize(path.Join(global.Dir.LocalBackupDir, "tmp"))
treeData = append(treeData, dto.CleanTree{
ID: uuid.NewString(),
Label: "tmp_backup",
Size: uint64(tmpSize),
IsCheck: tmpSize != 0,
IsRecommend: true,
Type: "tmp_backup",
})
backupRecords, _ := backupRepo.ListRecord()
var recordMap = make(map[string][]string)
for _, record := range backupRecords {
if val, ok := recordMap[record.FileDir]; ok {
val = append(val, record.FileName)
recordMap[record.FileDir] = val
} else {
recordMap[record.FileDir] = []string{record.FileName}
}
}
treeData = append(treeData, loadUnknownApps(fileOp, recordMap))
treeData = append(treeData, loadUnknownDbs(fileOp, recordMap))
treeData = append(treeData, loadUnknownWebsites(fileOp, recordMap))
treeData = append(treeData, loadUnknownSnapshot(fileOp))
treeData = append(treeData, loadUnknownWebsiteLog(fileOp, recordMap))
return treeData
}
func loadUnknownApps(fileOp fileUtils.FileOp, recordMap map[string][]string) dto.CleanTree {
apps, _ := appInstallRepo.ListBy(context.Background())
var excludePaths []string
for _, app := range apps {
itemName := fmt.Sprintf("app/%s/%s", app.App.Key, app.Name)
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))
}
}
treeData := dto.CleanTree{
ID: uuid.NewString(),
Label: "unknown_app",
IsCheck: false,
IsRecommend: false,
Type: "unknown_backup",
}
_ = loadFileOrDirWithExclude(fileOp, 0, path.Join(global.Dir.LocalBackupDir, "app"), &treeData, excludePaths)
loadBackupIsCheck(&treeData)
return treeData
}
func loadUnknownDbs(fileOp fileUtils.FileOp, recordMap map[string][]string) dto.CleanTree {
apps, _ := appInstallRepo.ListBy(context.Background())
var excludePaths []string
appMap := make(map[string]struct{})
for _, app := range apps {
appMap[fmt.Sprintf("database/%s/%s", app.App.Key, app.Name)] = struct{}{}
}
for key, val := range recordMap {
itemName := path.Dir(key)
if _, ok := appMap[itemName]; ok {
for _, item := range val {
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, key, item))
}
}
}
treeData := dto.CleanTree{
ID: uuid.NewString(),
Label: "unknown_database",
IsCheck: false,
IsRecommend: false,
Type: "unknown_backup",
}
_ = loadFileOrDirWithExclude(fileOp, 0, path.Join(global.Dir.LocalBackupDir, "database"), &treeData, excludePaths)
loadBackupIsCheck(&treeData)
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)
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))
}
}
treeData := dto.CleanTree{
ID: uuid.NewString(),
Label: "unknown_website",
IsCheck: false,
IsRecommend: false,
Type: "unknown_backup",
}
_ = loadFileOrDirWithExclude(fileOp, 0, path.Join(global.Dir.LocalBackupDir, "website"), &treeData, excludePaths)
loadBackupIsCheck(&treeData)
return treeData
}
func loadUnknownSnapshot(fileOp fileUtils.FileOp) dto.CleanTree {
snaps, _ := snapshotRepo.GetList()
var excludePaths []string
for _, item := range snaps {
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, "system_snapshot", item.Name+".tar.gz"))
}
treeData := dto.CleanTree{
ID: uuid.NewString(),
Label: "unknown_snapshot",
IsCheck: false,
IsRecommend: false,
Type: "unknown_backup",
}
dir := path.Join(global.Dir.LocalBackupDir, "system_snapshot")
entries, _ := os.ReadDir(dir)
for _, entry := range entries {
childPath := filepath.Join(dir, entry.Name())
if isExactPathMatch(childPath, excludePaths) {
continue
}
childNode := dto.CleanTree{
ID: uuid.NewString(),
Label: entry.Name(),
IsCheck: false,
IsRecommend: false,
Name: childPath,
Type: "unknown_backup",
}
if entry.IsDir() {
itemSize, _ := fileOp.GetDirSize(childPath)
childNode.Size = uint64(itemSize)
childNode.IsCheck = true
childNode.IsRecommend = true
treeData.Size += childNode.Size
} else {
info, _ := entry.Info()
childNode.Size = uint64(info.Size())
treeData.Size += childNode.Size
}
treeData.Children = append(treeData.Children, childNode)
}
return treeData
}
func loadUnknownWebsiteLog(fileOp fileUtils.FileOp, recordMap map[string][]string) 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")
entries, _ := os.ReadDir(dir)
for _, entry := range entries {
if !entry.IsDir() {
continue
}
dirName := entry.Name()
itemName := fmt.Sprintf("log/website/%s", dirName)
if _, ok := recordMap[itemName]; !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)
if err != nil {
return err
}
for _, entry := range entries {
childPath := filepath.Join(dir, entry.Name())
if isExactPathMatch(childPath, excludes) {
continue
}
childNode := dto.CleanTree{
ID: uuid.NewString(),
Label: entry.Name(),
IsCheck: false,
IsRecommend: false,
Name: childPath,
Type: "unknown_backup",
}
if entry.IsDir() {
if index < 4 {
if err = loadFileOrDirWithExclude(fileOp, index, childPath, &childNode, excludes); err != nil {
return err
}
childNode.Size = 0
for _, child := range childNode.Children {
childNode.Size += child.Size
}
rootTree.Size += childNode.Size
} else {
itemSize, _ := fileOp.GetDirSize(childPath)
childNode.Size = uint64(itemSize)
rootTree.Size += childNode.Size
}
} else {
info, _ := entry.Info()
childNode.Size = uint64(info.Size())
rootTree.Size += childNode.Size
}
rootTree.Children = append(rootTree.Children, childNode)
}
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
}
if treeData.Label != "unknown_database" && treeData.Label != "unknown_app" {
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)
for _, excludePath := range excludePaths {
cleanExclude := filepath.Clean(excludePath)
if cleanPath == cleanExclude {
return true
}
}
return false
}
func loadRollBackTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, rollbackPath, "app"), "rollback_app", fileOp)
@@ -360,7 +616,6 @@ func loadRollBackTree(fileOp fileUtils.FileOp) []dto.CleanTree {
func loadUploadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
var treeData []dto.CleanTree
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, tmpUploadPath), "upload_tmp", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, uploadPath, "app"), "upload_app", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, uploadPath, "website"), "upload_website", fileOp)
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, uploadPath, "database"), "upload_database", fileOp)
@@ -382,6 +637,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
}
@@ -393,20 +664,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()
@@ -528,7 +885,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,
@@ -621,6 +978,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 {
+5 -1
View File
@@ -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)
}
}
+18 -1
View File
@@ -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
}
+3
View File
@@ -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
View File
@@ -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 {
_ = settingRepo.Update("BanPing", constant.StatusDisable)
return err
}
return nil
case "enableBanPing":
if err := firewall.UpdatePingStatus("1"); err != nil {
_ = settingRepo.Update("BanPing", constant.StatusEnable)
return err
}
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 {
+1 -1
View File
@@ -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
}
+22 -2
View File
@@ -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{
+22 -18
View File
@@ -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 ""
}
+1
View File
@@ -96,6 +96,7 @@ const (
TaskScopeCustomAppstore = "CustomAppstore"
TaskScopeTamper = "Tamper"
TaskScopeFileConvert = "Convert"
TaskScopeTask = "Task"
)
func GetTaskName(resourceName, operate, scope string) string {
+7 -11
View File
@@ -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
+7 -117
View File
@@ -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=
@@ -885,8 +822,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 +868,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 +887,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 +941,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 +953,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 +982,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 +1015,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 +1023,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 +1033,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 +1095,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 +1140,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 +1198,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 +1207,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 +1225,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 +1306,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 +1322,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 +1341,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 +1404,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 +1474,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 +1495,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=
+18
View File
@@ -18,6 +18,7 @@ func Init() {
if !needInit() {
return
}
InitPingStatus()
global.LOG.Info("initializing firewall settings...")
client, err := firewall.NewFirewallClient()
if err != nil {
@@ -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)
}
}
+1
View File
@@ -41,6 +41,7 @@ func initGlobalData() {
if len(node.Version) != 0 {
_ = settingRepo.Update("SystemVersion", node.Version)
}
global.CONF.Base.Version = node.Version
global.CONF.Base.EncryptKey, _ = settingRepo.GetValueByKey("EncryptKey")
}
+2
View File
@@ -59,6 +59,8 @@ func InitAgentDB() {
migrations.InitIptablesStatus,
migrations.UpdateWebsite,
migrations.AddisIPtoWebsiteSSL,
migrations.InitPingStatus,
migrations.UpdateApp,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
+18
View File
@@ -789,3 +789,21 @@ 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{})
},
}
+1
View File
@@ -19,6 +19,7 @@ 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)
+52 -72
View File
@@ -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
}
+5 -2
View File
@@ -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 {
+105
View File
@@ -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
}
+2 -2
View File
@@ -482,12 +482,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) {
+1
View File
@@ -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 {
+89 -5
View File
@@ -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"
@@ -123,7 +124,7 @@ func queryDNSRecords(domain string) (map[string]string, error) {
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,9 +159,22 @@ 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]
@@ -262,7 +276,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 +320,73 @@ 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)
for _, answer := range r.Answer {
if txt, ok := answer.(*dns.TXT); ok {
if len(txt.Txt) > 0 {
records[recordName] = txt.Txt[0]
break
}
}
}
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")
}
+1 -1
View File
@@ -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"`
+1 -1
View File
@@ -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 {
+7 -5
View File
@@ -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
View File
@@ -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
}
}
}
+37 -12
View File
@@ -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)
}
}
+36 -11
View File
@@ -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"
},
+2
View File
@@ -59,6 +59,7 @@ var WebUrlMap = map[string]struct{}{
"/ai": {},
"/ai/model": {},
"/ai/gpu": {},
"/ai/gpu/current": {},
"/ai/mcp": {},
"/ai/model/tensorrt": {},
"/ai/model/ollama": {},
@@ -165,6 +166,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": {},
+1
View File
@@ -21,6 +21,7 @@ const (
StatusEnable = "Enable"
StatusDisable = "Disable"
StatusMux = "Mux"
StatusInstalling = "Installing"
StatusNormal = "Normal"
+1
View File
@@ -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
+4
View File
@@ -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=
+5
View File
@@ -110,6 +110,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"
+5
View File
@@ -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 }}"
+5
View File
@@ -111,6 +111,11 @@ FailedStatus: "{{ .name }} 失敗 {{ .err }}"
Start: "開始"
SubTask: "サブタスク"
Skip: "エラーを無視して続行..."
PushAppInstallTaskToNode: "アプリインストールタスクをノード [{{ .name }}] にプッシュ"
TaskPush: "プッシュ"
AppInstallTask: "アプリインストールタスク"
PushAppFailed: "アプリインストールタスクのプッシュに失敗しました"
Success: "成功"
#script
ScriptLibrary: "スクリプトライブラリ"
+5
View File
@@ -110,6 +110,11 @@ FailedStatus: "{{ .name }} 실패 {{ .err }}"
Start: "시작"
SubTask: "서브 작업"
Skip: "오류 무시하고 계속..."
PushAppInstallTaskToNode: "노드 [{{ .name }}]에 앱 설치 작업 푸시"
TaskPush: "푸시"
AppInstallTask: "앱 설치 작업"
PushAppFailed: "앱 설치 작업 푸시 실패"
Success: "성공"
#script
ScriptLibrary: "스크립트 라이브러리"
+5
View File
@@ -105,6 +105,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"
+5
View File
@@ -110,6 +110,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"
+4
View File
@@ -110,6 +110,10 @@ FailedStatus: "{{ .name }} не удалось {{ .err }}"
Start: "Начать"
SubTask: "Подзадача"
Skip: "Пропустить ошибки и продолжить..."
TaskPush: "Отправить"
AppInstallTask: "Задача установки приложения"
PushAppFailed: "Не удалось отправить задачу установки приложения"
Success: "Успешно"
#script
ScriptLibrary: "Библиотека скриптов"
+5
View File
@@ -109,6 +109,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"
+5
View File
@@ -110,6 +110,11 @@ FailedStatus: "{{ .name }} 失敗 {{ .err }}"
Start: "開始"
SubTask: "子任務"
Skip: "忽略錯誤並繼續..."
PushAppInstallTaskToNode: "推送應用安裝任務到節點 [{{ .name }}]"
TaskPush: "推送"
AppInstallTask: "應用安裝任務"
PushAppFailed: "推送應用安裝任務失敗"
Success: "成功"
#script
ScriptLibrary: "腳本庫"
+5
View File
@@ -110,6 +110,11 @@ FailedStatus: "{{ .name }} 失败 {{ .err }}"
Start: "开始"
SubTask: "子任务"
Skip: "忽略错误并继续..."
PushAppInstallTaskToNode: "推送应用安装任务到节点 [{{ .name }}]"
TaskPush: "推送"
AppInstallTask: "应用安装任务"
PushAppFailed: "推送应用安装任务失败"
Success: "成功"
#script
ScriptLibrary: "脚本库"
+60 -4
View File
@@ -4,6 +4,11 @@ import (
"crypto/tls"
"encoding/gob"
"fmt"
"net"
"net/http"
"os"
"path"
"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 +17,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"
@@ -99,10 +101,64 @@ func Start() {
if err := server.ServeTLS(tcpKeepAliveListener{ln.(*net.TCPListener)}, "", ""); err != nil {
panic(err)
}
return
} else if global.CONF.Conn.SSL == constant.StatusMux {
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)
server.TLSConfig = &tls.Config{
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return constant.CertStore.Load().(*tls.Certificate), nil
},
}
global.LOG.Infof("listen at mux (http/https)://%s:%s [%s]", global.CONF.Conn.BindAddress, global.CONF.Conn.Port, tcpItem)
m := cmux.New(ln)
httpsL := m.Match(cmux.TLS())
httpL := 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() {
redirectServer := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
target := "https://" + r.Host + r.RequestURI
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
}),
}
if err := redirectServer.Serve(httpL); err != nil {
global.LOG.Errorf("HTTP Redirect Serve Error: %v", err)
}
}()
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
}
}
-103
View File
@@ -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
}
+81
View File
@@ -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
View File
@@ -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
}
}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1
View File
@@ -36,6 +36,7 @@
"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",
+3
View File
@@ -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 {
+1
View File
@@ -291,6 +291,7 @@ export namespace Host {
label: string;
autoMount: boolean;
mountPoint: string;
noFail: boolean;
}
export interface DiskMount {
+1
View File
@@ -36,6 +36,7 @@ export namespace Toolbox {
export interface CleanData {
systemClean: Array<CleanTree>;
backupClean: Array<CleanTree>;
uploadClean: Array<CleanTree>;
downloadClean: Array<CleanTree>;
systemLogClean: Array<CleanTree>;
+2
View File
@@ -28,6 +28,7 @@ export namespace Website {
dbType: string;
favorite: boolean;
streamPorts: string;
udp: boolean;
}
export interface WebsiteDTO extends Website {
@@ -612,6 +613,7 @@ export namespace Website {
export interface WebsiteHtmlUpdate {
type: string;
content: string;
sync: boolean;
}
export interface NginxUpstream {
+24 -16
View File
@@ -8,8 +8,9 @@ import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
// backup-agent
export const getLocalBackupDir = () => {
return http.get<string>(`/backups/local`);
export const getLocalBackupDir = (node?: string) => {
const params = node ? `?operateNode=${node}` : '';
return http.get<string>(`/backups/local${params}`);
};
export const searchBackup = (params: Backup.SearchWithType) => {
return http.post<ResPage<Backup.BackupInfo>>(`/backups/search`, params);
@@ -40,35 +41,42 @@ export const listBucket = (params: Backup.ForBucket) => {
}
return http.post('/backups/buckets', request, TimeoutEnum.T_40S);
};
export const handleBackup = (params: Backup.Backup) => {
return http.post(`/backups/backup`, params, TimeoutEnum.T_10M);
export const handleBackup = (params: Backup.Backup, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`/backups/backup${query}`, params, TimeoutEnum.T_10M);
};
export const listBackupOptions = () => {
return http.get<Array<Backup.BackupOption>>(`/backups/options`);
};
export const handleRecover = (params: Backup.Recover) => {
return http.post(`/backups/recover`, params, TimeoutEnum.T_10M);
export const handleRecover = (params: Backup.Recover, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`/backups/recover${query}`, params, TimeoutEnum.T_10M);
};
export const handleRecoverByUpload = (params: Backup.Recover) => {
return http.post(`/backups/recover/byupload`, params, TimeoutEnum.T_10M);
};
export const downloadBackupRecord = (params: Backup.RecordDownload) => {
return http.post<string>(`/backups/record/download`, params, TimeoutEnum.T_10M);
export const downloadBackupRecord = (params: Backup.RecordDownload, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post<string>(`/backups/record/download${query}`, params, TimeoutEnum.T_10M);
};
export const deleteBackupRecord = (params: { ids: number[] }) => {
return http.post(`/backups/record/del`, params);
export const deleteBackupRecord = (params: { ids: number[] }, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`/backups/record/del${query}`, params);
};
export const updateRecordDescription = (id: Number, description: String) => {
return http.post(`/backups/record/description/update`, { id: id, description: description });
export const updateRecordDescription = (id: Number, description: String, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`/backups/record/description/update${query}`, { id: id, description: description });
};
export const uploadByRecover = (filePath: string, targetDir: String) => {
return http.post(`/backups/upload`, { filePath: filePath, targetDir: targetDir });
};
export const searchBackupRecords = (params: Backup.SearchBackupRecord) => {
return http.post<ResPage<Backup.RecordInfo>>(`/backups/record/search`, params, TimeoutEnum.T_5M);
export const searchBackupRecords = (params: Backup.SearchBackupRecord, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post<ResPage<Backup.RecordInfo>>(`/backups/record/search${query}`, params, TimeoutEnum.T_5M);
};
export const loadRecordSize = (param: Backup.SearchForSize) => {
return http.post<Array<Backup.RecordFileSize>>(`/backups/record/size`, param);
export const loadRecordSize = (param: Backup.SearchForSize, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post<Array<Backup.RecordFileSize>>(`/backups/record/size${query}`, param);
};
export const searchBackupRecordsByCronjob = (params: Backup.SearchBackupRecordByCronjob) => {
return http.post<ResPage<Backup.RecordInfo>>(`/backups/record/search/bycronjob`, params, TimeoutEnum.T_5M);
+9 -6
View File
@@ -3,8 +3,9 @@ import { ResPage, SearchWithPage } from '../interface';
import { Cronjob } from '../interface/cronjob';
import { TimeoutEnum } from '@/enums/http-enum';
export const searchCronjobPage = (params: Cronjob.Search) => {
return http.post<ResPage<Cronjob.CronjobInfo>>(`/cronjobs/search`, params);
export const searchCronjobPage = (params: Cronjob.Search, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post<ResPage<Cronjob.CronjobInfo>>(`/cronjobs/search${query}`, params);
};
export const loadNextHandle = (spec: string) => {
@@ -58,12 +59,14 @@ export const cleanRecords = (id: number, cleanData: boolean, cleanRemoteData: bo
return http.post(`cronjobs/records/clean`, { cronjobID: id, cleanData: cleanData, cleanRemoteData });
};
export const updateStatus = (params: Cronjob.UpdateStatus) => {
return http.post(`cronjobs/status`, params);
export const updateStatus = (params: Cronjob.UpdateStatus, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`cronjobs/status${query}`, params);
};
export const handleOnce = (id: number) => {
return http.post(`cronjobs/handle`, { id: id });
export const handleOnce = (id: number, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`cronjobs/handle${query}`, { id: id });
};
export const searchScript = (params: SearchWithPage) => {
+9 -6
View File
@@ -30,8 +30,9 @@ export const bindPostgresqlUser = (params: Database.PgBind) => {
export const changePrivileges = (params: Database.PgChangePrivileges) => {
return http.post(`/databases/pg/privileges`, params, TimeoutEnum.T_40S);
};
export const searchPostgresqlDBs = (params: Database.SearchDBWithPage) => {
return http.post<ResPage<Database.PostgresqlDBInfo>>(`/databases/pg/search`, params);
export const searchPostgresqlDBs = (params: Database.SearchDBWithPage, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post<ResPage<Database.PostgresqlDBInfo>>(`/databases/pg/search${query}`, params);
};
export const updatePostgresqlDescription = (params: DescriptionUpdate) => {
return http.post(`/databases/pg/description`, params);
@@ -54,8 +55,9 @@ export const deletePostgresqlDB = (params: Database.PostgresqlDBDelete) => {
};
// mysql
export const searchMysqlDBs = (params: Database.SearchDBWithPage) => {
return http.post<ResPage<Database.MysqlDBInfo>>(`/databases/search`, params);
export const searchMysqlDBs = (params: Database.SearchDBWithPage, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post<ResPage<Database.MysqlDBInfo>>(`/databases/search${query}`, params);
};
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
let request = deepCopy(params) as Database.MysqlDBCreate;
@@ -152,8 +154,9 @@ export const getDatabase = (name: string) => {
export const searchDatabases = (params: Database.SearchDatabasePage) => {
return http.post<ResPage<Database.DatabaseInfo>>(`/databases/db/search`, params);
};
export const listDatabases = (type: string) => {
return http.get<Array<Database.DatabaseOption>>(`/databases/db/list/${type}`);
export const listDatabases = (type: string, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.get<Array<Database.DatabaseOption>>(`/databases/db/list/${type}${query}`);
};
export const listDbItems = (type: string) => {
return http.get<Array<Database.DbItem>>(`/databases/db/item/${type}`);
+3 -2
View File
@@ -10,8 +10,9 @@ export const getLoginLogs = (info: Log.SearchLgLog) => {
return http.post<ResPage<Log.OperationLog>>(`/core/logs/login`, info);
};
export const getSystemFiles = () => {
return http.get<Array<string>>(`/logs/system/files`);
export const getSystemFiles = (node?: string) => {
const params = node ? `?operateNode=${node}` : '';
return http.get<Array<string>>(`/logs/system/files${params}`);
};
export const cleanLogs = (param: Log.CleanLog) => {
+6 -4
View File
@@ -6,8 +6,9 @@ import { TimeoutEnum } from '@/enums/http-enum';
import { deepCopy } from '@/utils/util';
import { Base64 } from 'js-base64';
export const searchWebsites = (req: Website.WebSiteSearch) => {
return http.post<ResPage<Website.WebsiteRes>>(`/websites/search`, req);
export const searchWebsites = (req: Website.WebSiteSearch, node?: string) => {
const params = node ? `?operateNode=${node}` : '';
return http.post<ResPage<Website.WebsiteRes>>(`/websites/search${params}`, req);
};
export const listWebsites = () => {
@@ -22,8 +23,9 @@ export const createWebsite = (req: Website.WebSiteCreateReq) => {
return http.post<any>(`/websites`, request, TimeoutEnum.T_10M);
};
export const opWebsite = (req: Website.WebSiteOp) => {
return http.post<any>(`/websites/operate`, req);
export const opWebsite = (req: Website.WebSiteOp, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post<any>(`/websites/operate${query}`, req);
};
export const opWebsiteLog = (req: Website.WebSiteOpLog) => {
+12 -9
View File
@@ -200,6 +200,7 @@ const secret = ref();
const description = ref();
const timeoutItem = ref(30);
const timeoutUnit = ref('m');
const node = ref();
const open = ref();
const isBackup = ref();
@@ -212,9 +213,11 @@ interface DialogProps {
detailName: string;
status: string;
appInstallID?: number;
node?: string;
}
const acceptParams = (params: DialogProps): void => {
type.value = params.type;
node.value = params.node || currentNode.value;
if (type.value === 'app') {
appInstallID.value = params.appInstallID || 0;
loadBackupDir();
@@ -235,7 +238,7 @@ const handleBackupClose = () => {
};
const loadBackupDir = async () => {
const res = await getLocalBackupDir();
const res = await getLocalBackupDir(node.value);
backupPath.value = res.data;
};
@@ -244,7 +247,7 @@ const goFile = async () => {
};
const onChange = async (info: any) => {
await updateRecordDescription(info.id, info.description);
await updateRecordDescription(info.id, info.description, node.value);
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
};
@@ -257,7 +260,7 @@ const search = async () => {
detailName: detailName.value,
};
loading.value = true;
await searchBackupRecords(params)
await searchBackupRecords(params, node.value)
.then((res) => {
loading.value = false;
loadSize(params);
@@ -270,7 +273,7 @@ const search = async () => {
};
const loadSize = async (params: any) => {
await loadRecordSize(params)
await loadRecordSize(params, node.value)
.then((res) => {
let stats = res.data || [];
if (stats.length === 0) {
@@ -310,7 +313,7 @@ const backup = async () => {
description: description.value,
};
loading.value = true;
await handleBackup(params)
await handleBackup(params, node.value)
.then(() => {
loading.value = false;
openTaskLog(taskID);
@@ -335,7 +338,7 @@ const recover = async (row?: any) => {
timeout: timeoutItem.value === -1 ? -1 : transferTimeToSecond(timeoutItem.value + timeoutUnit.value),
};
loading.value = true;
await handleRecover(params)
await handleRecover(params, node.value)
.then(() => {
loading.value = false;
openTaskLog(taskID);
@@ -374,8 +377,8 @@ const onDownload = async (row: Backup.RecordInfo) => {
fileDir: row.fileDir,
fileName: row.fileName,
};
await downloadBackupRecord(params).then(async (res) => {
downloadFile(res.data, currentNode.value);
await downloadBackupRecord(params, node.value).then(async (res) => {
downloadFile(res.data, node.value);
});
};
@@ -399,7 +402,7 @@ const onBatchDelete = async (row: Backup.RecordInfo | null) => {
i18n.global.t('commons.button.backup'),
i18n.global.t('commons.button.delete'),
]),
params: { ids: ids },
params: { ids: ids, node: node.value },
});
};
@@ -2,11 +2,11 @@
<div>
<el-card :style="{ height: height }" class="home-card">
<div class="header">
<div class="header-left">
<div class="header-left flex flex-wrap gap-3">
<span class="header-span">{{ header }}</span>
<slot name="header-l" />
</div>
<div class="header-right">
<div class="header-right flex flex-wrap gap-3">
<slot name="header-r" />
</div>
</div>
@@ -0,0 +1,23 @@
<template>
<MdEditor previewOnly v-model="sanitizedReadMe" :theme="isDarkTheme ? 'dark' : 'light'" />
</template>
<script lang="ts" setup>
import MdEditor from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import DOMPurify from 'dompurify';
import { useGlobalStore } from '@/composables/useGlobalStore';
const { isDarkTheme } = useGlobalStore();
const props = defineProps({
content: {
type: String,
default: '',
},
});
const sanitizedReadMe = computed(() => {
return DOMPurify.sanitize(props.content);
});
</script>
@@ -32,7 +32,7 @@
<span class="icon-span">{{ item.fixCount }}</span>
</template>
<div class="panel-MdEditor">
<MdEditor v-model="item.content" previewOnly :theme="isDarkTheme ? 'dark' : 'light'" />
<MarkDownEditor :content="item.content" />
</div>
</el-collapse-item>
</div>
@@ -57,12 +57,11 @@
</template>
<script setup lang="ts">
import MarkDownEditor from '@/components/mkdown-editor/index.vue';
import { getSettingInfo, listReleases, updateSetting } from '@/api/modules/setting';
import MdEditor from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import { ref } from 'vue';
import { GlobalStore } from '@/store';
import { storeToRefs } from 'pinia';
import { FormInstance } from 'element-plus';
import { MsgSuccess } from '@/utils/message';
import i18n from '@/lang';
@@ -73,8 +72,6 @@ const mobile = computed(() => {
return globalStore.isMobile();
});
const { isDarkTheme } = storeToRefs(globalStore);
const drawerVisible = ref(false);
const currentVersion = ref(0);
const notes = ref([]);
@@ -15,12 +15,7 @@
{{ upgradeInfo.testVersion }}
</el-radio>
</el-radio-group>
<MdEditor
v-loading="loading"
v-model="upgradeInfo.releaseNote"
previewOnly
:theme="isDarkTheme ? 'dark' : 'light'"
/>
<MarkDownEditor v-loading="loading" :content="upgradeInfo.releaseNote" />
</div>
<template #footer>
<span class="dialog-footer">
@@ -32,18 +27,16 @@
</template>
<script setup lang="ts">
import MarkDownEditor from '@/components/mkdown-editor/index.vue';
import { loadReleaseNotes, upgrade } from '@/api/modules/setting';
import MdEditor from 'md-editor-v3';
import i18n from '@/lang';
import 'md-editor-v3/lib/style.css';
import { MsgSuccess } from '@/utils/message';
import { ref } from 'vue';
import { GlobalStore } from '@/store';
import { ElMessageBox } from 'element-plus';
import { storeToRefs } from 'pinia';
const globalStore = GlobalStore();
const { isDarkTheme } = storeToRefs(globalStore);
const drawerVisible = ref(false);
const upgradeInfo = ref();
+30 -12
View File
@@ -1224,6 +1224,7 @@ const message = {
interactive: 'Interactive script',
interactiveHelper: 'Requires user input during execution and cannot be used in scheduled tasks.',
library: 'Script Library',
remoteLibrary: 'Remote Script Library',
create: 'Add Script',
edit: 'Edit Script',
groupHelper:
@@ -1995,7 +1996,7 @@ const message = {
error444: 'Connection Closed',
error500: 'Internal Server Error',
https: 'Setting up HTTPS protocol access for the panel can enhance the security of panel access.',
https: 'Setting up HTTPS for the panel improves access security.\nStrict mode blocks non-HTTPS traffic from reaching the panel.\nMux mode redirects HTTP to HTTPS, but may reduce security.',
certType: 'Certificate type',
selfSigned: 'Self signed',
selfSignedHelper: `Browsers may not trust self-signed certificates and may display security warnings.`,
@@ -2196,35 +2197,44 @@ const message = {
selectScan: 'Total selected junk files: ',
system: 'System Junk Files',
systemHelper:
'Temporary files generated during snapshots, upgrades, and obsolete file contents during version iterations',
panelOriginal: 'System snapshot recovery backup files',
backup: 'Temporary backup directory',
systemHelper: 'Temporary files generated during snapshot, upgrade, and other processes',
panelOriginal: 'Backup files before system snapshot restore',
upgrade: 'System upgrade backup files',
agentPackages: 'Historical version child node upgrade/installation packages',
upgradeHelper: '(Recommend keeping the latest upgrade backup for system rollback)',
cache: 'System cache files',
cacheHelper: '(Proceed with caution, cleaning requires a service restart)',
snapshot: 'System snapshot temporary files',
rollback: 'Backup files before recover',
backup: 'System Backup',
backupHelper: 'Backup files not associated with local backup accounts',
unknownBackup: 'System Backup',
tmpBackup: 'Temporary Backup',
unknownApp: 'Unassociated App Backup',
unknownDatabase: 'Unassociated Database Backup',
unknownWebsite: 'Unassociated Website Backup',
unknownSnapshot: 'Unassociated Snapshot Backup',
upload: 'Temporary Upload Files',
uploadHelper: 'Temporary files uploaded from the system backup list',
download: 'Temporary Download Files',
downloadHelper: 'Temporary files downloaded from third-party backup accounts by the system',
directory: 'Directory',
systemLog: 'System Log Files',
systemLogHelper:
'System log information, container build or image pull log information, and log files generated in scheduled tasks',
systemLog: 'Log file',
systemLogHelper: 'System logs, task logs, website log files',
dockerLog: 'Container operation log files',
taskLog: 'Scheduled task execution log files',
shell: 'Shell script scheduled tasks',
containerShell: 'Container internal Shell script scheduled tasks',
containerShell: 'Shell script scheduled tasks executed inside containers',
curl: 'CURL scheduled tasks',
containerTrash: 'Container Trash',
docker: 'Container garbage',
dockerHelper: 'Files such as containers, images, volumes, build cache, etc.',
volumes: 'Volumes',
buildCache: 'Container Build Cache',
appTmpDownload: 'App temporary download file',
unknownWebsiteLog: 'Unlinked website log backup file',
},
app: {
app: 'Application | Applications',
@@ -2744,6 +2754,9 @@ const message = {
streamPortsHelper:
'Set the external listening port number, clients will access the service through this port, separated by commas, e.g., 5222,5223',
streamHelper: 'TCP/UDP Port Forwarding and Load Balancing',
udp: 'Enable UDP',
syncHtmlHelper: 'Sync to PHP and static websites',
},
php: {
short_open_tag: 'Short tag support',
@@ -2923,6 +2936,8 @@ const message = {
startFirewallHelper:
'After the firewall is enabled, the server security can be better protected. Do you want to continue?',
noPing: 'Disable ping',
enableBanPing: 'Block Ping',
disableBanPing: 'Unblock Ping',
noPingTitle: 'Disable ping',
noPingHelper: `This will disable ping, and the server won't echo ICMP response. Do you want to continue?`,
onPingHelper: 'This will enable ping, and hackers may discover your server. Do you want to continue?',
@@ -3179,6 +3194,7 @@ const message = {
model: 'Device Model',
diskType: 'Disk Type',
serial: 'Serial Number',
noFail: 'Mount failure does not affect system startup',
},
xpack: {
expiresTrialAlert:
@@ -3855,6 +3871,8 @@ const message = {
'Currently only supports migrating monolithic applications and applications associated only with MySQL, MariaDB, PostgreSQL databases',
opensslHelper:
'If using encrypted backup, the OpenSSL versions between the two nodes must be consistent, otherwise migration may fail.',
installApp: 'Batch install',
installAppHelper: 'Batch install apps to selected nodes',
},
alert: {
isAlert: 'Alert',
+38 -15
View File
@@ -1231,6 +1231,7 @@ const message = {
interactive: 'Script interactivo',
interactiveHelper:
'Requiere introducir datos durante la ejecución y no puede ser usada en tareas programadas.',
remoteLibrary: 'Biblioteca de Scripts Remota',
library: 'Librería de scripts',
create: 'Agregar script',
edit: 'Editar script',
@@ -2009,7 +2010,7 @@ const message = {
error416: 'Rango no satisfactorio',
error444: 'Conexión cerrada',
error500: 'Error interno del servidor',
https: 'Configurar acceso al panel mediante protocolo HTTPS puede mejorar la seguridad del acceso.',
https: 'Configurar HTTPS en el panel mejora la seguridad de acceso.\nEn modo Strict, el tráfico sin HTTPS no puede conectarse al panel.\nEl modo Mux redirige HTTP a HTTPS, pero puede reducir la seguridad.',
certType: 'Tipo de certificado',
selfSigned: 'Autofirmado',
selfSignedHelper:
@@ -2209,30 +2210,44 @@ const message = {
totalScan: 'Total a limpiar: ',
selectScan: 'Total seleccionado: ',
system: 'Archivos basura del sistema',
systemHelper: 'Archivos temporales de instantáneas, actualizaciones, archivos obsoletos, etc.',
panelOriginal: 'Archivos de recuperación de instantáneas',
backup: 'Temporary backup directory',
upgrade: 'Archivos de actualización',
systemHelper: 'Archivos temporales generados durante instantáneas, actualizaciones y otros procesos',
panelOriginal: 'Archivos de copia de seguridad antes de restaurar instantánea del sistema',
upgrade: 'Archivos de copia de seguridad de actualización del sistema',
agentPackages: 'Paquetes de actualización/instalación de nodos secundarios de versiones históricas',
upgradeHelper: '(Mantenga el último respaldo para restaurar el sistema)',
cache: 'Archivos de caché',
cacheHelper: '(Precaución, limpiar requiere reiniciar servicios)',
snapshot: 'Archivos temporales de instantáneas',
rollback: 'Archivos de respaldo antes de recuperación',
backup: 'Copia de Seguridad del Sistema',
backupHelper: 'Archivos de copia de seguridad no asociados con cuentas de copia de seguridad locales',
unknownBackup: 'Copia de Seguridad del Sistema',
tmpBackup: 'Copia de Seguridad Temporal',
unknownApp: 'Copia de Seguridad de Aplicación no Asociada',
unknownDatabase: 'Copia de Seguridad de Base de Datos no Asociada',
unknownWebsite: 'Copia de Seguridad de Sitio Web no Asociada',
unknownSnapshot: 'Copia de Seguridad de Instantánea no Asociada',
upload: 'Archivos temporales de carga',
uploadHelper: 'Archivos temporales subidos en la lista de respaldos',
download: 'Archivos temporales de descarga',
downloadHelper: 'Archivos temporales descargados desde respaldos externos',
directory: 'Directorio',
systemLog: 'Archivos de log del sistema',
systemLogHelper: 'Logs del sistema, construcción de contenedores, pulls, tareas programadas',
dockerLog: 'Logs de operaciones de contenedores',
taskLog: 'Logs de tareas programadas',
shell: 'Tareas programadas de shell',
containerShell: 'Tareas de shell dentro de contenedor',
curl: 'Tareas programadas CURL',
containerTrash: 'Papelera de contenedores',
systemLog: 'Archivo de registro',
systemLogHelper: 'Registros del sistema, registros de tareas, archivos de registro del sitio web',
dockerLog: 'Archivos de registro de operaciones de contenedores',
taskLog: 'Archivos de registro de ejecución de tareas programadas',
shell: 'Tareas programadas de script de shell',
containerShell: 'Tareas programadas de script de shell ejecutadas dentro de contenedores',
curl: 'Tareas programadas de CURL',
docker: 'Basura de contenedores',
dockerHelper: 'Archivos como contenedores, imágenes, volúmenes, caché de construcción, etc.',
volumes: 'Volúmenes',
buildCache: 'Caché de build de contenedores',
appTmpDownload: 'Archivo de descarga temporal de la aplicación',
unknownWebsiteLog: 'Archivo de respaldo de registro de sitio web no vinculado',
},
app: {
app: 'Aplicación | Aplicaciones',
@@ -2731,6 +2746,9 @@ const message = {
streamPortsHelper:
'Configura el número de puerto de escucha externo, los clientes accederán al servicio a través de este puerto, separado por comas, p. ej., 5222,5223',
streamHelper: 'Reenvío de Puertos y Balanceo de Carga TCP/UDP',
udp: 'Habilitar UDP',
syncHtmlHelper: 'Sincronizar con PHP y sitios web estáticos',
},
php: {
short_open_tag: 'Soporte de etiquetas cortas',
@@ -2901,6 +2919,8 @@ const message = {
startFirewallHelper:
'Tras habilitar el firewall, la seguridad del servidor podrá protegerse mejor. ¿Deseas continuar?',
noPing: 'Deshabilitar ping',
enableBanPing: 'Bloquear Ping',
disableBanPing: 'Desbloquear Ping',
noPingTitle: 'Deshabilitar ping',
noPingHelper: `Esto deshabilitará el ping, y el servidor no responderá con eco ICMP. ¿Deseas continuar?`,
onPingHelper: 'Esto habilitará el ping, y los atacantes podrían descubrir tu servidor. ¿Deseas continuar?',
@@ -3161,6 +3181,7 @@ const message = {
model: 'Modelo del dispositivo',
diskType: 'Tipo de disco',
serial: 'Núm. de serie',
noFail: 'El fallo de montaje no afecta al inicio del sistema',
},
xpack: {
expiresTrialAlert:
@@ -3812,6 +3833,8 @@ const message = {
'Actualmente solo admite la migración de aplicaciones monolíticas y aplicaciones asociadas únicamente con bases de datos MySQL, MariaDB, PostgreSQL',
opensslHelper:
'Si se utiliza copia de seguridad cifrada, las versiones de OpenSSL entre los dos nodos deben ser consistentes, de lo contrario la migración puede fallar.',
installApp: 'Instalación por lotes',
installAppHelper: 'Instalar aplicaciones por lotes en los nodos seleccionados',
},
alert: {
isAlert: 'Alerta',
+33 -14
View File
@@ -1921,7 +1921,7 @@ const message = {
error444: '接続が閉じた',
error500: 'サーバーエラー',
https: 'パネル用のHTTPSプロトコルアクセスをセットアップすると、パネルアクセスのセキュリティが強化されます。',
https: 'パネルに HTTPS を設定するとアクセスの安全性が向上します。\nStrict モードでは HTTPS 以外の通信はパネルに接続できません。\nMux モードは HTTP を HTTPS にリダイレクトしますが、安全性が低下する可能性があります。',
certType: '証明書の種類',
selfSigned: '自己署名',
selfSignedHelper: `ブラウザは、自己署名の証明書を信頼していない場合があり、セキュリティ警告を表示する場合があります。`,
@@ -2117,32 +2117,43 @@ const message = {
selectScan: '選択したジャンクファイルの合計:',
system: 'システムジャンクファイル',
systemHelper:
'スナップショット中に生成された一時ファイル、アップグレード、およびバージョンの反復中にファイルのコンテンツが廃止されました',
panelOriginal: 'システムスナップショットリカバリバックアップファイル',
backup: '一時バックアップディレクトリ',
upgrade: 'システムアップグレードバックアップファイル',
systemHelper: 'スナップショット、アップグレードなどのプロセスで生成された一時ファイル',
panelOriginal: 'システムスナップショット復元前のバックアップファイル',
upgrade: 'システムアップグレードのバックアップファイル',
agentPackages: '履歴バージョンの子ノードアップグレード/インストールパッケージ',
upgradeHelper: '(システムロールバックのために最新のアップグレードバックアップを保持することをお勧めします)',
cache: 'システムキャッシュファイル',
cacheHelper: '(注意を払って進むには、クリーニングにはサービスの再起動が必要です)',
rollback: '回復する前にファイルをバックアップします',
backup: 'システムバックアップ',
backupHelper: 'ローカルバックアップアカウントに関連付けられていないバックアップファイル',
unknownBackup: 'システムバックアップ',
tmpBackup: '一時バックアップ',
unknownApp: '関連付けられていないアプリバックアップ',
unknownDatabase: '関連付けられていないデータベースバックアップ',
unknownWebsite: '関連付けられていないWebサイトバックアップ',
unknownSnapshot: '関連付けられていないスナップショットバックアップ',
upload: '一時的なアップロードファイル',
uploadHelper: 'システムバックアップリストからアップロードされた一時ファイル',
download: '一時的なダウンロードファイル',
downloadHelper: 'システムによってサードパーティのバックアップアカウントからダウンロードされた一時ファイル',
directory: 'ディレクトリ',
systemLog: 'システムログファイル',
systemLogHelper:
'システムログ情報、コンテナビルドまたは画像プルログ情報、およびスケジュールされたタスクで生成されたログファイル',
systemLog: 'ログファイル',
systemLogHelper: 'システムログ、タスクログ、ウェブサイトログファイル',
dockerLog: 'コンテナ操作ログファイル',
taskLog: 'スケジュールされたタスク実行ログファイル',
containerShell: 'コンテナ内部シェルスクリプトスケジュールされたタスク',
taskLog: 'スケジュールタスク実行ログファイル',
shell: 'シェルスクリプトスケジュールタスク',
containerShell: 'コンテナ内で実行するシェルスクリプトスケジュールタスク',
curl: 'CURLスケジュールタスク',
containerTrash: 'コンテナのゴミ',
docker: 'コンテナゴミ',
dockerHelper: 'コンテナ、イメージ、ボリューム、ビルドキャッシュなどのファイル',
volumes: 'ボリューム',
buildCache: 'コンテナビルドキャッシュ',
appTmpDownload: 'Archivo de descarga temporal de la aplicación',
unknownWebsiteLog: '未関連ウェブサイトログバックアップファイル',
},
app: {
app: 'アプリケーション|アプリケーション',
@@ -2666,6 +2677,9 @@ const message = {
streamPortsHelper:
'外部リスニングポート番号を設定します。クライアントはこのポートを通じてサービスにアクセスします。カンマで区切ってください。例:5222,5223',
streamHelper: 'TCP/UDP ポート転送とロードバランシング',
udp: 'UDPを有効化',
syncHtmlHelper: 'PHP と静的ウェブサイトに同期',
},
php: {
short_open_tag: '短いタグサポート',
@@ -2841,6 +2855,8 @@ const message = {
startFirewallHelper:
'ファイアウォールが有効になった後、サーバーのセキュリティをよりよく保護できます。続けたいですか?',
noPing: 'pingを無効にします',
enableBanPing: 'Ping禁止',
disableBanPing: 'Ping禁止解除',
noPingTitle: 'pingを無効にします',
noPingHelper: `これによりPingが無効になり、サーバーはICMP応答をエコーし​​ません。続けたいですか?`,
onPingHelper: 'これによりPingが可能になり、ハッカーはサーバーを発見する場合があります。続けたいですか?',
@@ -3078,6 +3094,7 @@ const message = {
model: 'デバイスモデル',
diskType: 'ディスクタイプ',
serial: 'シリアルナンバー',
noFail: 'マウント失敗はシステム起動に影響しません',
},
xpack: {
expiresTrialAlert:
@@ -3744,6 +3761,8 @@ const message = {
'現在、単体アプリケーションと MySQL、MariaDB、PostgreSQL データベースのみに関連するアプリケーションの移行のみをサポートしています',
opensslHelper:
'暗号化バックアップを使用する場合、2つのノード間のOpenSSLバージョンは一致している必要があります。そうしないと、移行が失敗する可能性があります。',
installApp: '一括インストール',
installAppHelper: '選択したノードにアプリを一括インストール',
},
alert: {
isAlert: 'アラート',
+34 -12
View File
@@ -1178,6 +1178,7 @@ const message = {
interactive: '대화형 스크립트',
interactiveHelper: '실행 중 사용자 입력이 필요하며 예약 작업에서는 사용할 수 없습니다.',
library: '스크립트 라이브러리',
remoteLibrary: 'リモートスクリプトライブラリ',
create: '스크립트 추가',
edit: '스크립트 수정',
groupHelper:
@@ -1890,7 +1891,7 @@ const message = {
error444: '연결 닫힘',
error500: '서버 오류',
https: '패널의 HTTPS 프로토콜 접근 설정은 패널 접근 보안을 강화할 수 있습니다.',
https: '패널에 HTTPS를 설정하면 접근 보안이 향상됩니다.\nStrict 모드에서는 HTTPS가 아닌 트래픽이 패널에 연결할 수 없습니다.\nMux 모드는 HTTP를 HTTPS로 리다이렉트하지만 보안이 다소 낮아질 수 있습니다.',
certType: '인증서 유형',
selfSigned: '자가 서명',
selfSignedHelper: '자가 서명 인증서는 브라우저에서 신뢰하지 않을 수 있으며 보안 경고가 표시될 수 있습니다.',
@@ -2081,30 +2082,43 @@ const message = {
selectScan: '선택된 불필요 파일 총합: ',
system: '시스템 불필요 파일',
systemHelper: '스냅샷, 업그레이드 중에 생성된 임시 파일과 버전 업데이트 중에 불필요해진 파일 내용',
panelOriginal: '시스템 스냅샷 복구 백업 파일',
backup: '임시 백업 디렉터리',
systemHelper: '스냅샷, 업그레이드 및 기타 프로세스 중에 생성된 임시 파일',
panelOriginal: '시스템 스냅샷 복원 전 백업 파일',
upgrade: '시스템 업그레이드 백업 파일',
agentPackages: '이전 버전 자식 노드 업그레이드/설치 패키지',
upgradeHelper: '(시스템 롤백을 위해 최신 업그레이드 백업을 유지하는 것이 좋습니다)',
cache: '시스템 캐시 파일',
cacheHelper: '(주의하여 진행, 정리 후 서비스 재시작 필요)',
rollback: '복구 전 백업 파일',
backup: '시스템 백업',
backupHelper: '로컬 백업 계정에 연결되지 않은 백업 파일',
unknownBackup: '시스템 백업',
tmpBackup: '임시 백업',
unknownApp: '연결되지 않은 앱 백업',
unknownDatabase: '연결되지 않은 데이터베이스 백업',
unknownWebsite: '연결되지 않은 웹사이트 백업',
unknownSnapshot: '연결되지 않은 스냅샷 백업',
upload: '임시 업로드 파일',
uploadHelper: '시스템 백업 리스트에서 업로드된 임시 파일',
download: '임시 다운로드 파일',
downloadHelper: '시스템에서 제3자 백업 계정으로 다운로드된 임시 파일',
directory: '디렉터리',
systemLog: '시스템 로그 파일',
systemLogHelper: '시스템 로그 정보, 컨테이너 빌드 또는 이미지 풀 로그 정보, 예약된 작업에서 생성된 로그 파일',
dockerLog: '컨테이너 운영 로그 파일',
taskLog: '예약된 작업 실행 로그 파일',
containerShell: '컨테이너 내 쉘 스크립트 예약 작업',
systemLog: '로그 파일',
systemLogHelper: '시스템 로그, 작업 로그, 웹사이트 로그 파일',
dockerLog: '컨테이너 작업 로그 파일',
taskLog: '예약 작업 실행 로그 파일',
shell: '셸 스크립트 예약 작업',
containerShell: '컨테이너 내에서 실행하는 셸 스크립트 예약 작업',
curl: 'CURL 예약 작업',
containerTrash: '컨테이너 휴지통',
docker: '컨테이너 쓰레기',
dockerHelper: '컨테이너, 이미지, 볼륨, 빌드 캐시 등의 파일',
volumes: '볼륨',
buildCache: '컨테이너 빌드 캐시',
appTmpDownload: '앱 임시 다운로드 파일',
unknownWebsiteLog: '연결되지 않은 웹사이트 로그 백업 파일',
},
app: {
app: '애플리케이션 | 애플리케이션들',
@@ -2619,6 +2633,9 @@ const message = {
streamPortsHelper:
'외부 수신 포트 번호를 설정합니다. 클라이언트는 이 포트를 통해 서비스에 액세스합니다. 쉼표로 구분하세요. 예: 5222,5223',
streamHelper: 'TCP/UDP 포트 포워딩 및 로드 밸런싱',
udp: 'UDP 활성화',
syncHtmlHelper: 'PHP 및 정적 웹사이트에 동기화',
},
php: {
short_open_tag: '짧은 태그 지원',
@@ -2786,6 +2803,8 @@ const message = {
stopFirewallHelper: '이 작업은 서버 보안을 잃게 만듭니다. 계속하시겠습니까?',
startFirewallHelper: '방화벽이 활성화되면 서버 보안이 강화됩니다. 계속하시겠습니까?',
noPing: 'Ping 비활성화',
enableBanPing: 'Ping 차단',
disableBanPing: 'Ping 차단 해제',
noPingTitle: 'Ping 비활성화',
noPingHelper: '이 작업은 Ping 을 비활성화하며 서버는 ICMP 응답을 보내지 않게 됩니다. 계속하시겠습니까?',
onPingHelper: '이 작업은 Ping 을 활성화하여 해커가 서버를 발견할 수 있습니다. 계속하시겠습니까?',
@@ -3021,6 +3040,7 @@ const message = {
model: '장치 모델',
diskType: '디스크 유형',
serial: '시리얼 번호',
noFail: '마운트 실패는 시스템 시작에 영향을 미치지 않습니다',
},
xpack: {
expiresTrialAlert:
@@ -3674,6 +3694,8 @@ const message = {
'현재 단일 애플리케이션과 MySQL, MariaDB, PostgreSQL 데이터베이스만 연결된 애플리케이션의 마이그레이션만 지원합니다',
opensslHelper:
'암호화된 백업을 사용하는 경우 두 노드 간의 OpenSSL 버전이 일치해야 합니다. 그렇지 않으면 마이그레이션이 실패할 수 있습니다.',
installApp: '일괄 설치',
installAppHelper: '선택한 노드에 앱 일괄 설치',
},
alert: {
isAlert: '알림',
+34 -14
View File
@@ -1216,6 +1216,7 @@ const message = {
interactiveHelper:
'Memerlukan input pengguna semasa pelaksanaan dan tidak boleh digunakan dalam tugas terjadual.',
library: 'Perpustakaan Skrip',
remoteLibrary: 'Pustaka Skrip Jauh',
create: 'Tambah Skrip',
edit: 'Sunting Skrip',
groupHelper:
@@ -1977,7 +1978,7 @@ const message = {
error444: 'Sambungan ditutup',
error500: 'Ralat Pelayan',
https: 'Menetapkan protokol akses HTTPS untuk panel boleh meningkatkan keselamatan akses panel.',
https: 'Menetapkan HTTPS untuk panel meningkatkan keselamatan akses.\nDalam mod Strict, trafik bukan HTTPS tidak boleh menyambung ke panel.\nMod Mux mengalih hala HTTP ke HTTPS, tetapi mungkin mengurangkan keselamatan.',
certType: 'Jenis sijil',
selfSigned: 'Diterbitkan sendiri',
selfSignedHelper:
@@ -2176,32 +2177,43 @@ const message = {
selectScan: 'Jumlah fail sampah yang dipilih: ',
system: 'Fail Sampah Sistem',
systemHelper:
'Fail sementara yang dihasilkan semasa snapshot, peningkatan, dan kandungan fail usang semasa iterasi versi',
panelOriginal: 'Fail sandaran pemulihan snapshot sistem',
backup: 'Direktori sandaran sementara',
upgrade: 'Fail sandaran peningkatan sistem',
systemHelper: 'Fail sementara dijana semasa snapshot, naik taraf, dan proses lain',
panelOriginal: 'Fail sandaran sebelum pemulihan snapshot sistem',
upgrade: 'Fail sandaran naik taraf sistem',
agentPackages: 'Pakej naik taraf/pemasangan nod anak versi sejarah',
upgradeHelper: '(Disarankan untuk mengekalkan sandaran peningkatan terbaru untuk pemulihan sistem)',
cache: 'Fail cache sistem',
cacheHelper: '(Berhati-hati, pembersihan memerlukan permulaan semula perkhidmatan)',
rollback: 'Fail sandaran sebelum pemulihan',
backup: 'Sandaran Sistem',
backupHelper: 'Fail sandaran tidak dikaitkan dengan akaun sandaran tempatan',
unknownBackup: 'Sandaran Sistem',
tmpBackup: 'Sandaran Sementara',
unknownApp: 'Sandaran Apl Tidak Dikaitkan',
unknownDatabase: 'Sandaran Pangkalan Data Tidak Dikaitkan',
unknownWebsite: 'Sandaran Laman Web Tidak Dikaitkan',
unknownSnapshot: 'Sandaran Snapshot Tidak Dikaitkan',
upload: 'Fail Muat Naik Sementara',
uploadHelper: 'Fail sementara dimuat naik dari senarai sandaran sistem',
download: 'Fail Muat Turun Sementara',
downloadHelper: 'Fail sementara dimuat turun dari akaun sandaran pihak ketiga oleh sistem',
directory: 'Direktori',
systemLog: 'Fail Log Sistem',
systemLogHelper:
'Maklumat log sistem, maklumat log pembinaan kontena atau muat turun imej, dan fail log yang dihasilkan dalam tugas berjadual',
dockerLog: 'Fail log operasi kontena',
systemLog: 'Fail log',
systemLogHelper: 'Log sistem, log tugas, fail log laman web',
dockerLog: 'Fail log operasi bekas',
taskLog: 'Fail log pelaksanaan tugas berjadual',
containerShell: 'Tugas berjadual skrip Shell dalam kontena',
shell: 'Tugas berjadual skrip Shell',
containerShell: 'Tugas berjadual skrip Shell dilaksanakan di dalam bekas',
curl: 'Tugas berjadual CURL',
containerTrash: 'Tong Sampah Kontena',
docker: 'Sampah bekas',
dockerHelper: 'Fail seperti bekas, imej, isipadu, cache binaan, dsb.',
volumes: 'Isipadu',
buildCache: 'Cache Pembinaan Kontena',
appTmpDownload: 'Fail muat turun sementara aplikasi',
unknownWebsiteLog: 'Fail sandaran log laman web tidak dikaitkan',
},
app: {
app: 'Aplikasi | Aplikasi',
@@ -2723,6 +2735,9 @@ const message = {
streamPortsHelper:
'Tetapkan nombor port pendengaran luaran, pelanggan akan mengakses perkhidmatan melalui port ini, dipisahkan dengan koma, cth., 5222,5223',
streamHelper: 'Penerusan Port dan Pengimbangan Beban TCP/UDP',
udp: 'Dayakan UDP',
syncHtmlHelper: 'Segerakkan ke PHP dan laman web statik',
},
php: {
short_open_tag: 'Sokongan tag pendek',
@@ -2902,6 +2917,8 @@ const message = {
startFirewallHelper:
'Selepas firewall diaktifkan, keselamatan pelayan boleh dilindungi dengan lebih baik. Adakah anda mahu meneruskan?',
noPing: 'Lumpuhkan ping',
enableBanPing: 'Sekat Ping',
disableBanPing: 'Nyahsekat Ping',
noPingTitle: 'Lumpuhkan ping',
noPingHelper: `Ini akan melumpuhkan ping, dan pelayan tidak akan memberikan tindak balas ICMP. Adakah anda mahu meneruskan?`,
onPingHelper:
@@ -3135,6 +3152,7 @@ const message = {
model: 'Model Peranti',
diskType: 'Jenis Cakera',
serial: 'Nombor Siri',
noFail: 'Kegagalan pemasangan tidak menjejaskan permulaan sistem',
},
xpack: {
expiresTrialAlert:
@@ -3813,6 +3831,8 @@ const message = {
'Kini hanya menyokong penghijrahan aplikasi monolitik dan aplikasi yang hanya dikaitkan dengan pangkalan data MySQL, MariaDB, PostgreSQL',
opensslHelper:
'Jika menggunakan sandaran terenkripsi, versi OpenSSL antara dua nod mesti konsisten, jika tidak penghijrahan mungkin gagal.',
installApp: 'Pemasangan kelompok',
installAppHelper: 'Pasang aplikasi secara kelompok ke nod yang dipilih',
},
alert: {
isAlert: 'Amaran',
+34 -14
View File
@@ -1209,6 +1209,7 @@ const message = {
interactiveHelper:
'Requer entrada do usuário durante a execução e não pode ser usado em tarefas agendadas.',
library: 'Biblioteca de Scripts',
remoteLibrary: 'Biblioteca de Scripts Remota',
create: 'Adicionar Script',
edit: 'Editar Script',
groupHelper:
@@ -1965,7 +1966,7 @@ const message = {
error444: 'Conexão fechada',
error500: 'Erro no servidor',
https: 'Configurar o acesso via protocolo HTTPS para o painel pode melhorar a segurança do acesso ao painel.',
https: 'Configurar HTTPS no painel melhora a segurança de acesso.\nNo modo Strict, tráfego sem HTTPS não consegue se conectar ao painel.\nO modo Mux redireciona HTTP para HTTPS, mas pode reduzir a segurança.',
certType: 'Tipo de certificado',
selfSigned: 'Autoassinado',
selfSignedHelper:
@@ -2170,32 +2171,43 @@ const message = {
selectScan: 'Total de arquivos inúteis selecionados: ',
system: 'Arquivos inúteis do sistema',
systemHelper:
'Arquivos temporários gerados durante snapshots, atualizações e conteúdos obsoletos durante iterações de versão',
panelOriginal: 'Arquivos de backup de recuperação de snapshot do sistema',
backup: 'Diretório de backup temporário',
upgrade: 'Arquivos de backup de atualização do sistema',
systemHelper: 'Arquivos temporários gerados durante processos como snapshots e atualizações.',
panelOriginal: 'Arquivos de backup antes da restauração do snapshot do sistema.',
upgrade: 'Arquivos de backup de atualização do sistema.',
agentPackages: 'Pacotes de atualização/instalação de nós filhos de versões históricas.',
upgradeHelper: '(Recomenda-se manter o backup de atualização mais recente para rollback do sistema)',
cache: 'Arquivos de cache do sistema',
cacheHelper: '(Prossiga com cautela, a limpeza exige reinício do serviço)',
rollback: 'Arquivos de backup antes da recuperação',
backup: 'Backup do Sistema',
backupHelper: 'Arquivos de backup não associados a contas de backup locais',
unknownBackup: 'Backup do Sistema',
tmpBackup: 'Backup Temporário',
unknownApp: 'Backup de Aplicativo não Associado',
unknownDatabase: 'Backup de Banco de Dados não Associado',
unknownWebsite: 'Backup de Site não Associado',
unknownSnapshot: 'Backup de Instantâneo não Associado',
upload: 'Arquivos temporários de upload',
uploadHelper: 'Arquivos temporários enviados da lista de backup do sistema',
download: 'Arquivos temporários de download',
downloadHelper: 'Arquivos temporários baixados de contas de backup de terceiros pelo sistema',
directory: 'Diretório',
systemLog: 'Arquivos de log do sistema',
systemLogHelper:
'Informações de log do sistema, logs de construção de container ou pull de imagem, e logs gerados em tarefas agendadas',
dockerLog: 'Arquivos de log de operação de container',
systemLog: 'Arquivo de log',
systemLogHelper: 'Logs do sistema, logs de tarefas, arquivos de log do site',
dockerLog: 'Arquivos de log de operação de contêineres',
taskLog: 'Arquivos de log de execução de tarefas agendadas',
containerShell: 'Tarefas agendadas de script Shell interno do container',
shell: 'Tarefas agendadas de script de shell',
containerShell: 'Tarefas agendadas de script de shell executadas dentro de contêineres',
curl: 'Tarefas agendadas de CURL',
containerTrash: 'Lixeira do container',
docker: 'Lixo de contêineres',
dockerHelper: 'Arquivos como contêineres, imagens, volumes, cache de compilação, etc.',
volumes: 'Volumes',
buildCache: 'Cache de construção do container',
appTmpDownload: 'Arquivo de download temporário do aplicativo',
unknownWebsiteLog: 'Fail sandaran log laman web tidak dikaitkan',
},
app: {
app: 'Aplicativo | Aplicativos',
@@ -2728,6 +2740,9 @@ const message = {
streamPortsHelper:
'Defina o número da porta de escuta externa, os clientes acessarão o serviço através desta porta, separados por vírgulas, por exemplo: 5222,5223',
streamHelper: 'Encaminhamento de Portas e Balanceamento de Carga TCP/UDP',
udp: 'Habilitar UDP',
syncHtmlHelper: 'Sincronizar com PHP e sites estáticos',
},
php: {
short_open_tag: 'Suporte para short tags',
@@ -2907,6 +2922,8 @@ const message = {
startFirewallHelper:
'Depois que o firewall for habilitado, a segurança do servidor será melhor protegida. Deseja continuar?',
noPing: 'Desativar ping',
enableBanPing: 'Bloquear Ping',
disableBanPing: 'Desbloquear Ping',
noPingTitle: 'Desativar ping',
noPingHelper: 'Isso desativará o ping, e o servidor não responderá ao ICMP. Deseja continuar?',
onPingHelper: 'Isso ativará o ping, permitindo que hackers descubram seu servidor. Deseja continuar?',
@@ -3149,6 +3166,7 @@ const message = {
model: 'Modelo do Dispositivo',
diskType: 'Tipo de Disco',
serial: 'Número de Série',
noFail: 'Falha na montagem não afeta a inicialização do sistema',
},
xpack: {
expiresTrialAlert:
@@ -3832,6 +3850,8 @@ const message = {
'Atualmente suporta apenas a migração de aplicações monolíticas e aplicações associadas apenas a bancos de dados MySQL, MariaDB, PostgreSQL',
opensslHelper:
'Se usar backup criptografado, as versões do OpenSSL entre os dois nós devem ser consistentes, caso contrário a migração pode falhar.',
installApp: 'Instalação em lote',
installAppHelper: 'Instalar aplicativos em lote nos nós selecionados',
},
alert: {
isAlert: 'Alerta',
+35 -15
View File
@@ -1211,6 +1211,7 @@ const message = {
interactiveHelper:
'Требует ввода пользователя во время выполнения и не может использоваться в запланированных задачах.',
library: 'Библиотека скриптов',
remoteLibrary: 'Удаленная Библиотека Скриптов',
create: 'Добавить скрипт',
edit: 'Редактировать скрипт',
groupHelper:
@@ -1963,7 +1964,7 @@ const message = {
error444: 'Соединение закрыто',
error500: 'Ошибка сервера',
https: 'Настройка доступа по протоколу HTTPS для панели может повысить безопасность доступа к панели.',
https: 'Настройка HTTPS для панели повышает безопасность доступа.\nВ режиме Strict трафик без HTTPS не может подключиться к панели.\nРежим Mux перенаправляет HTTP на HTTPS, но может снизить безопасность.',
certType: 'Тип сертификата',
selfSigned: 'Самоподписанный',
selfSignedHelper:
@@ -2165,32 +2166,43 @@ const message = {
selectScan: 'Всего выбранных мусорных файлов: ',
system: 'Системные мусорные файлы',
systemHelper:
'Временные файлы, созданные во время снапшотов, обновлений, и устаревшее содержимое файлов при итерациях версий',
panelOriginal: 'Файлы резервных копий восстановления системных снапшотов',
backup: 'Временный резервный каталог',
upgrade: 'Файлы резервных копий системных обновлений',
systemHelper: 'Временные файлы, созданные во время снимков, обновлений и других процессов',
panelOriginal: 'Файлы резервных копий перед восстановлением снимка системы',
upgrade: 'Файлы резервных копий обновления системы',
agentPackages: 'Пакеты обновления/установки дочерних узлов исторических версий',
upgradeHelper: '(Рекомендуется сохранять последнюю резервную копию обновления для отката системы)',
cache: 'Системные файлы кэша',
cacheHelper: '(Действуйте с осторожностью, очистка требует перезапуска службы)',
rollback: 'Файлы резервных копий перед восстановлением',
backup: 'Резервная Копия Системы',
backupHelper: 'Файлы резервных копий, не связанные с локальными учетными записями резервного копирования',
unknownBackup: 'Резервная Копия Системы',
tmpBackup: 'Временная Резервная Копия',
unknownApp: 'Несвязанная Резервная Копия Приложения',
unknownDatabase: 'Несвязанная Резервная Копия Базы Данных',
unknownWebsite: 'Несвязанная Резервная Копия Веб-сайта',
unknownSnapshot: 'Несвязанная Резервная Копия Снимка',
upload: 'Временные файлы загрузки',
uploadHelper: 'Временные файлы, загруженные из списка системных резервных копий',
download: 'Временные файлы скачивания',
downloadHelper: 'Временные файлы, скачанные из сторонних аккаунтов резервного копирования системой',
directory: 'Директория',
systemLog: 'Системные файлы логов',
systemLogHelper:
'Системная информация логов, логи сборки контейнеров или загрузки образов, и файлы логов, созданные в запланированных задачах',
dockerLog: 'Файлы логов операций с контейнерами',
taskLog: 'Файлы логов выполнения запланированных задач',
containerShell: 'Запланированные задачи Shell-скриптов внутри контейнера',
systemLog: 'Файл журнала',
systemLogHelper: 'Системные журналы, журналы задач, файлы журналов веб-сайта',
dockerLog: 'Файлы журналов операций с контейнерами',
taskLog: 'Файлы журналов выполнения запланированных задач',
shell: 'Запланированные задачи скриптов оболочки',
containerShell: 'Запланированные задачи скриптов оболочки, выполняемые внутри контейнеров',
curl: 'Запланированные задачи CURL',
containerTrash: 'Корзина контейнеров',
docker: 'Мусор контейнеров',
dockerHelper: 'Файлы, такие как контейнеры, образы, тома, кэш сборки и т.д.',
volumes: 'Тома',
buildCache: 'Кэш сборки контейнеров',
appTmpDownload: 'Временный файл загрузки приложения',
unknownWebsiteLog: 'Arquivo de backup de log de site não vinculado',
},
app: {
app: 'Приложение | Приложения',
@@ -2723,6 +2735,9 @@ const message = {
streamPortsHelper:
'Установите номер внешнего порта прослушивания, клиенты будут получать доступ к службе через этот порт, разделяйте запятыми, например: 5222,5223',
streamHelper: 'Перенаправление портов и балансировка нагрузки TCP/UDP',
udp: 'Включить UDP',
syncHtmlHelper: 'Синхронизировать с PHP и статическими сайтами',
},
php: {
short_open_tag: 'Поддержка коротких тегов',
@@ -2900,6 +2915,8 @@ const message = {
startFirewallHelper:
'После включения межсетевого экрана безопасность сервера будет лучше защищена. Хотите продолжить?',
noPing: 'Отключить ping',
enableBanPing: 'Блокировать Ping',
disableBanPing: 'Разблокировать Ping',
noPingTitle: 'Отключить ping',
noPingHelper: 'Это отключит ping, и сервер не будет отвечать на ICMP-запросы. Хотите продолжить?',
onPingHelper: 'Это включит ping, и хакеры смогут обнаружить ваш сервер. Хотите продолжить?',
@@ -3138,6 +3155,7 @@ const message = {
model: 'Модель устройства',
diskType: 'Тип диска',
serial: 'Серийный номер',
noFail: 'Сбой монтирования не влияет на запуск системы',
},
xpack: {
expiresTrialAlert:
@@ -3819,6 +3837,8 @@ const message = {
'В настоящее время поддерживает миграцию только монолитных приложений и приложений, связанных только с базами данных MySQL, MariaDB, PostgreSQL',
opensslHelper:
'При использовании зашифрованного резервного копирования версии OpenSSL между двумя узлами должны быть согласованы, иначе миграция может завершиться неудачей.',
installApp: 'Пакетная установка',
installAppHelper: 'Пакетная установка приложений на выбранные узлы',
},
alert: {
isAlert: 'Оповещение',
+34 -16
View File
@@ -1237,6 +1237,7 @@ const message = {
interactive: 'Etkileşimli script',
interactiveHelper: 'Yürütme sırasında kullanıcı girişi gerektirir ve zamanlanmış görevlerde kullanılamaz.',
library: 'Script Kütüphanesi',
remoteLibrary: 'Uzak Komut Dosyası Kütüphanesi',
create: 'Script Ekle',
edit: 'Script Düzenle',
groupHelper:
@@ -2018,7 +2019,7 @@ const message = {
error416: 'Aralık Karşılanamadı',
error444: 'Bağlantı Kapalı',
error500: 'Dahili Sunucu Hatası',
https: 'Panel için HTTPS protokolü erişimini ayarlamak, panel erişiminin güvenliğini artırabilir.',
https: "Panel için HTTPS ayarlamak erişim güvenliğini artırır.\nStrict modda HTTPS olmayan trafik panele bağlanamaz.\nMux modu HTTP'yi HTTPS'e yönlendirir, ancak güvenliği biraz azaltabilir.",
certType: 'Sertifika türü',
selfSigned: 'Kendi kendine imzalı',
selfSignedHelper:
@@ -2221,35 +2222,44 @@ const message = {
selectScan: 'Seçilen toplam gereksiz dosya: ',
system: 'Sistem Gereksiz Dosyaları',
systemHelper:
'Anlık görüntüler, yükseltmeler ve sürüm iterasyonları sırasında eski dosya içerikleri sırasında üretilen geçici dosyalar',
panelOriginal: 'Sistem anlık görüntü kurtarma yedek dosyaları',
backup: 'Geçici yedekleme dizini',
upgrade: 'Sistem yükseltme yedek dosyaları',
systemHelper: 'Anlık görüntü, yükseltme ve diğer işlemler sırasında oluşturulan geçici dosyalar',
panelOriginal: 'Sistem anlık görüntüsü geri yükleme öncesi yedekleme dosyaları',
upgrade: 'Sistem yükseltme yedekleme dosyaları',
agentPackages: 'Geçmiş sürüm alt düğüm yükseltme/kurulum paketleri',
upgradeHelper: '(Sistem geri alımı için en son yükseltme yedeğini tutmanız önerilir)',
cache: 'Sistem önbellek dosyaları',
cacheHelper: '(Dikkatli ilerleyin, temizleme servis yeniden başlatılmasını gerektirir)',
snapshot: 'Sistem anlık görüntü geçici dosyaları',
rollback: 'Kurtarma öncesi yedek dosyaları',
backup: 'Sistem Yedekleme',
backupHelper: 'Yerel yedekleme hesaplarıyla ilişkili olmayan yedekleme dosyaları',
unknownBackup: 'Sistem Yedekleme',
tmpBackup: 'Geçici Yedekleme',
unknownApp: 'İlişkili Olmayan Uygulama Yedeklemesi',
unknownDatabase: 'İlişkili Olmayan Veritabanı Yedeklemesi',
unknownWebsite: 'İlişkili Olmayan Web Sitesi Yedeklemesi',
unknownSnapshot: 'İlişkili Olmayan Anlık Görüntü Yedeklemesi',
upload: 'Geçici Yükleme Dosyaları',
uploadHelper: 'Sistem yedek listesinden yüklenen geçici dosyalar',
download: 'Geçici İndirme Dosyaları',
downloadHelper: 'Sistem tarafından üçüncü taraf yedek hesaplarından indirilen geçici dosyalar',
directory: 'Dizin',
systemLog: 'Sistem Günlük Dosyaları',
systemLogHelper:
'Sistem günlük bilgileri, konteyner oluşturma veya görüntü çekme günlük bilgileri ve zamanlanmış görevlerde üretilen günlük dosyaları',
dockerLog: 'Konteyner işlem günlük dosyaları',
taskLog: 'Zamanlanmış görev yürütme günlük dosyaları',
shell: 'Shell betik zamanlanmış görevler',
containerShell: 'Konteyner içi Shell betik zamanlanmış görevler',
systemLog: 'Günlük dosyası',
systemLogHelper: 'Sistem günlükleri, görev günlükleri, web sitesi günlük dosyaları',
dockerLog: 'Konteyner işlem günlüğü dosyaları',
taskLog: 'Zamanlanmış görev yürütme günlüğü dosyaları',
shell: 'Shell script zamanlanmış görevler',
containerShell: 'Konteynerler içinde yürütülen shell script zamanlanmış görevler',
curl: 'CURL zamanlanmış görevler',
containerTrash: 'Konteyner Çöpü',
docker: 'Konteyner çöpü',
dockerHelper: 'Konteynerler, görüntüler, hacimler, derleme önbelleği vb. dosyalar',
volumes: 'Birimler',
buildCache: 'Konteyner Oluşturma Önbelleği',
appTmpDownload: 'Uygulama geçici indirme dosyası',
unknownWebsiteLog: 'Bağlantısız web sitesi günlük yedekleme dosyası',
},
app: {
app: 'Uygulama | Uygulamalar',
@@ -2782,6 +2792,9 @@ const message = {
streamPortsHelper:
'Harici dinleme bağlantı noktası numarasını ayarlayın, istemciler bu bağlantı noktası üzerinden hizmete erişecektir, virgülle ayırın, örn.: 5222,5223',
streamHelper: 'TCP/UDP Port Yönlendirme ve Yük Dengeleme',
udp: "UDP'yi etkinleştir",
syncHtmlHelper: 'PHP ve statik web siteleriyle senkronize et',
},
php: {
short_open_tag: 'Kısa etiket desteği',
@@ -2961,6 +2974,8 @@ const message = {
startFirewallHelper:
'Güvenlik duvarı etkinleştirildiğinde, sunucu güvenliği daha iyi korunabilir. Devam etmek istiyor musunuz?',
noPing: 'Ping’i devre dışı bırak',
enableBanPing: 'Ping Engelle',
disableBanPing: 'Ping Engellemeyi Kaldır',
noPingTitle: 'Ping’i devre dışı bırak',
noPingHelper:
'Bu, ping’i devre dışı bırakacak ve sunucu ICMP yanıtını geri göndermeyecek. Devam etmek istiyor musunuz?',
@@ -3221,6 +3236,7 @@ const message = {
model: 'Cihaz Modeli',
diskType: 'Disk Türü',
serial: 'Seri Numarası',
noFail: 'Bağlama hatası sistem başlangıcını etkilemez',
},
xpack: {
expiresTrialAlert:
@@ -3896,6 +3912,8 @@ const message = {
'Şu anda yalnızca tek parça uygulamaların ve yalnızca MySQL, MariaDB, PostgreSQL veritabanlarıyla ilişkili uygulamaların taşınmasını destekler',
opensslHelper:
'Şifreli yedekleme kullanılıyorsa, iki düğüm arasındaki OpenSSL sürümleri tutarlı olmalıdır, aksi takdirde geçiş başarısız olabilir.',
installApp: 'Toplu kurulum',
installAppHelper: 'Seçilen düğümlere uygulamaları toplu kur',
},
alert: {
isAlert: 'Uyarı',
+30 -10
View File
@@ -1158,6 +1158,7 @@ const message = {
interactive: '互動式腳本',
interactiveHelper: '在腳本執行過程中需要使用者輸入參數或做出選擇,且無法用於計劃任務中。',
library: '腳本庫',
remoteLibrary: '遠端腳本庫',
create: '新增腳本',
edit: '修改腳本',
groupHelper: '根據腳本特徵設定不同的分組,可以更快地對腳本進行篩選操作。',
@@ -1944,7 +1945,7 @@ const message = {
error444: '連線已關閉',
error500: '內部伺服器錯誤',
https: '為面板設定 https 協議訪問,提升面板訪問安全性',
https: '為面板設定 HTTPS 可提升訪問安全性 \nStrict 模式下非 HTTPS 流量無法連接面板\nMux 模式會將 HTTP 重新導向到 HTTPS,但可能會降低安全性',
certType: '證書類型',
selfSigned: '自簽名',
selfSignedHelper: '自簽證書,不被瀏覽器信任,顯示不安全是正常現象',
@@ -2045,33 +2046,44 @@ const message = {
selectScan: '已選中垃圾文件共計: ',
system: '系統垃圾',
systemHelper: '快照、升級等過程中產生的暫存檔以及版本疊代過程中廢棄的文件內容',
panelOriginal: '系統快照復原前備份文件',
backup: '臨時備份目錄',
upgrade: '系統升級備份文件',
systemHelper: '快照、升級等過程中產生的臨時檔案',
panelOriginal: '系統快照恢復前備份檔案',
upgrade: '系統升級備份檔案',
agentPackages: '歷史版本子節點升級/安裝套件',
upgradeHelper: '( 建議保留最新的升級備份用於系統回滾 )',
cache: '系統快取文件',
cacheHelper: '( 謹慎操作,清理需要重啟服務 )',
snapshot: '系統快照暫存檔',
rollback: '復原前備份目錄',
backup: '系統備份',
backupHelper: '本地備份帳號中未關聯的備份檔案',
unknownBackup: '系統備份',
tmpBackup: '臨時備份',
unknownApp: '未關聯應用備份',
unknownDatabase: '未關聯資料庫備份',
unknownWebsite: '未關聯網站備份',
unknownSnapshot: '未關聯快照備份',
upload: '臨時上傳文件',
uploadHelper: '系統上傳備份列表中上傳的暫存檔',
download: '臨時下載文件',
downloadHelper: '系統從第三方備份帳號下載的暫存檔',
directory: '資料夾',
systemLog: '系統日誌檔案',
systemLogHelper: '系統日誌資訊、容器構建或鏡像拉取等日誌資訊以及計劃任務中產生的日誌檔案',
systemLog: '日誌檔案',
systemLogHelper: '系統日誌、任務日誌、網站日誌檔案',
dockerLog: '容器操作日誌檔案',
taskLog: '計劃任務執行日誌檔案',
shell: 'Shell 腳本計劃任務',
containerShell: '容器內執行 Shell 腳本計劃任務',
curl: 'CURL 計劃任務',
containerTrash: '容器垃圾',
docker: '容器垃圾',
dockerHelper: '容器、映像、儲存卷、建置快取等檔案',
volumes: '磁碟區',
buildCache: '容器建置快取',
appTmpDownload: '應用程式暫存下載檔案',
unknownWebsiteLog: '未關聯網站日誌備份檔案',
},
app: {
app: '應用',
@@ -2552,6 +2564,9 @@ const message = {
streamPorts: '監聽端口',
streamPortsHelper: '設定對外監聽的埠號,客戶端將透過此埠存取服務,按逗號分割,例如:5222,5223',
streamHelper: 'TCP/UDP 端口轉發與負載均衡',
udp: '啟用 UDP',
syncHtmlHelper: '同步到 PHP 和靜態網站',
},
php: {
short_open_tag: '短標籤支援',
@@ -2715,6 +2730,8 @@ const message = {
stopFirewallHelper: '系統防火牆關閉後,伺服器將失去安全防護,是否繼續?',
startFirewallHelper: '系統防火牆開啟後,可以更好的防護伺服器安全,是否繼續?',
noPing: '禁 ping',
enableBanPing: '禁 Ping',
disableBanPing: '解除禁 Ping',
noPingTitle: '是否禁 ping',
noPingHelper: '禁 ping 後將無法 ping 通伺服器,是否繼續?',
onPingHelper: '解除禁 ping 後您的伺服器可能會被駭客發現,是否繼續?',
@@ -2950,6 +2967,7 @@ const message = {
model: '裝置型號',
diskType: '磁碟類型',
serial: '序號',
noFail: '掛載失敗不影響系統啟動',
},
xpack: {
expiresAlert: '溫馨提醒:您的專業版許可證將在 {0} 天後到期,屆時所有專業版功能將無法繼續使用。',
@@ -3554,6 +3572,8 @@ const message = {
nodeHelper: '不能選擇當前節點',
migrateHelper: '目前僅支持遷移單體應用和只關聯 MySQL、MariaDB、PostgreSQL 數據庫的應用',
opensslHelper: '如果使用加密備份,兩個節點之間的 OpenSSL 版本必須保持一致,否則可能導致遷移失敗。',
installApp: '批量安裝',
installAppHelper: '批量安裝應用到選擇的節點中',
},
alert: {
isAlert: '是否告警',
+28 -8
View File
@@ -1162,6 +1162,7 @@ const message = {
interactive: '交互式脚本',
interactiveHelper: '在脚本执行过程中需要用户输入参数或做出选择,且无法用于计划任务中。',
library: '脚本库',
remoteLibrary: '远程脚本库',
create: '添加脚本',
edit: '修改脚本',
groupHelper: '针对脚本特征设置不同的分组,可以更加快速的对脚本进行筛选操作。',
@@ -1943,7 +1944,7 @@ const message = {
error444: '连接被关闭',
error500: '内部错误',
https: '为面板设置 https 协议访问,提升面板访问安全性',
https: '为面板设置HTTPS可提升访问安全性 \n Strict模式下非HTTPS流量无法连接面板\nMux模式会将 HTTP 重定向到 HTTPS ,但可能会降低安全性',
certType: '证书类型',
selfSigned: '自签名',
selfSignedHelper: '自签证书,不被浏览器信任,显示不安全是正常现象',
@@ -2042,33 +2043,44 @@ const message = {
selectScan: '已选中垃圾文件共计: ',
system: '系统垃圾',
systemHelper: '快照、升级等过程中产生的临时文件以及版本迭代过程中废弃的文件内容',
systemHelper: '快照、升级等过程中产生的临时文件',
panelOriginal: '系统快照恢复前备份文件',
backup: '临时备份目录',
upgrade: '系统升级备份文件',
agentPackages: '历史版本子节点升级 / 安装包',
upgradeHelper: '( 建议保留最新的升级备份用于系统回滚 )',
cache: '系统缓存文件',
cacheHelper: '( 谨慎操作,清理需要重启服务 )',
snapshot: '系统快照临时文件',
rollback: '恢复前备份目录',
backup: '系统备份',
backupHelper: '本地备份账号中未关联的备份文件',
unknownBackup: '系统备份',
tmpBackup: '临时备份',
unknownApp: '未关联应用备份',
unknownDatabase: '未关联数据库备份',
unknownWebsite: '未关联网站备份',
unknownSnapshot: '未关联快照备份',
upload: '临时上传文件',
uploadHelper: '系统上传备份列表中上传的临时文件',
download: '临时下载文件',
downloadHelper: '系统从第三方备份账号下载的临时文件',
directory: '文件夹',
systemLog: '系统日志文件',
systemLogHelper: '系统日志信息、容器构建或镜像拉取等日志信息以及计划任务中产生的日志文件',
systemLog: '日志文件',
systemLogHelper: '系统日志、任务日志、网站日志文件',
dockerLog: '容器操作日志文件',
taskLog: '计划任务执行日志文件',
shell: 'Shell 脚本计划任务',
containerShell: '容器内执行 Shell 脚本计划任务',
curl: 'CURL 计划任务',
containerTrash: '容器垃圾',
docker: '容器垃圾',
dockerHelper: '容器、镜像、存储卷、构建缓存等文件',
volumes: '存储卷',
buildCache: '构建缓存',
appTmpDownload: '应用临时下载文件',
unknownWebsiteLog: '未关联网站日志备份文件',
},
app: {
app: '应用',
@@ -2549,6 +2561,9 @@ const message = {
streamPorts: '监听端口',
streamPortsHelper: '设置对外监听的端口号,客户端将通过此端口访问服务,按逗号分割,例如:5222,5223',
streamHelper: 'TCP/UDP 端口转发与负载均衡',
udp: '启用 UDP',
syncHtmlHelper: '同步到 PHP 和静态网站',
},
php: {
short_open_tag: '短标签支持',
@@ -2714,6 +2729,8 @@ const message = {
stopFirewallHelper: '系统防火墙关闭后,服务器将失去安全防护,是否继续?',
startFirewallHelper: '系统防火墙开启后,可以更好的防护服务器安全,是否继续?',
noPing: '禁 ping',
enableBanPing: '禁 ping',
disableBanPing: '解除禁 ping',
noPingTitle: '是否禁 ping',
noPingHelper: '禁 ping 后将无法 ping 通服务器,是否继续?',
onPingHelper: '解除禁 ping 后您的服务器可能会被黑客发现,是否继续?',
@@ -2950,6 +2967,7 @@ const message = {
model: '设备型号',
diskType: '磁盘类型',
serial: '序列号',
noFail: '挂载失败不影响系统启动',
},
xpack: {
expiresAlert: '温馨提醒:专业版试用将于 [{0}] 天后到期,届时将停止使用所有专业版功能。',
@@ -3547,6 +3565,8 @@ const message = {
nodeHelper: '不能选择当前节点',
migrateHelper: '当前仅支持迁移单体应用和只关联 MySQL、MariaDB、PostgreSQL 数据库的应用',
opensslHelper: '如果使用加密备份,两个节点之间的 openssl 版本必须保持一致,不然会导致迁移失败',
installApp: '批量安装',
installAppHelper: '批量安装应用到选择的节点中',
},
alert: {
isAlert: '是否告警',
+1
View File
@@ -44,6 +44,7 @@ export interface GlobalState {
device: DeviceType;
lastFilePath: string;
currentDB: string;
currentPgDB: string;
currentRedisDB: string;
showEntranceWarn: boolean;
defaultNetwork: string;
+4
View File
@@ -38,6 +38,7 @@ const GlobalStore = defineStore({
device: DeviceType.Desktop,
lastFilePath: '',
currentDB: '',
currentPgDB: '',
currentRedisDB: '',
showEntranceWarn: true,
defaultNetwork: 'all',
@@ -110,6 +111,9 @@ const GlobalStore = defineStore({
setCurrentDB(name: string) {
this.currentDB = name;
},
setCurrentPgDB(name: string) {
this.currentPgDB = name;
},
setCurrentRedisDB(name: string) {
this.currentRedisDB = name;
},
+40 -1
View File
@@ -126,7 +126,7 @@ html {
}
.search-button {
width: 250px;
width: 200px;
}
.drawer-header-button {
@@ -351,3 +351,42 @@ html {
--el-dialog-padding-primary: 0px !important;
}
}
.node-dashboard-card {
.header {
display: flex;
justify-content: space-between;
align-items: center;
.header-left {
display: flex;
align-items: center;
gap: 12px;
.header-span {
position: relative;
font-size: 16px;
font-weight: 500;
margin-left: 18px;
display: flex;
align-items: center;
&::before {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: -13px;
width: 4px;
height: 14px;
content: '';
background: $primary-color;
border-radius: 10px;
}
}
}
.header-right {
display: flex;
align-items: center;
}
}
}
@@ -122,6 +122,15 @@
<span class="input-help">{{ $t('app.pullImageHelper') }}</span>
</el-form-item>
<PushtoNode
v-if="isMaster && isMasterProductPro && batchInstallSupport"
:push-node="formData.pushNode"
:nodes="formData.nodes"
type="app"
@update:push-node="formData.pushNode = $event"
@update:nodes="formData.nodes = $event"
/>
<el-form-item prop="editCompose">
<el-checkbox v-model="formData.editCompose" :label="$t('app.editCompose')" size="large" />
<span class="input-help">{{ $t('app.editComposeHelper') }}</span>
@@ -147,7 +156,16 @@ import CodemirrorPro from '@/components/codemirror-pro/index.vue';
import { computeSizeFromMB } from '@/utils/util';
import { loadResourceLimit } from '@/api/modules/container';
import { useGlobalStore } from '@/composables/useGlobalStore';
const { isOffLine } = useGlobalStore();
const { isOffLine, isMasterProductPro, isMaster } = useGlobalStore();
const PushtoNode = defineAsyncComponent(async () => {
const modules = import.meta.glob('@/xpack/views/ssl/index.vue');
const loader = modules['/src/xpack/views/ssl/index.vue'];
if (loader) {
return ((await loader()) as any).default;
}
return { template: '<div></div>' };
});
interface ClusterProps {
key: string;
@@ -161,6 +179,7 @@ interface ClusterProps {
interface Props {
loading?: boolean;
modelValue?: any;
batchInstallSupport?: boolean;
}
const limits = ref<Container.ResourceLimit>({
@@ -170,6 +189,7 @@ const limits = ref<Container.ResourceLimit>({
const props = withDefaults(defineProps<Props>(), {
loading: false,
batchInstallSupport: false,
});
interface Emits {
@@ -223,6 +243,8 @@ const initFormData = () => ({
gpuConfig: false,
specifyIP: '',
restartPolicy: 'always',
pushNode: false,
nodes: [],
});
const formData = ref(props.modelValue || initFormData());
@@ -66,22 +66,22 @@
</el-descriptions>
</div>
</div>
<MdEditor previewOnly v-model="app.readMe" :theme="isDarkTheme ? 'dark' : 'light'" />
<MarkDownEditor :content="app.readMe" />
</template>
</DrawerPro>
<Install ref="installRef" />
</template>
<script lang="ts" setup>
import MarkDownEditor from '@/components/mkdown-editor/index.vue';
import { getAppByKey, getAppDetail, getAppIconUrl } from '@/api/modules/app';
import MdEditor from 'md-editor-v3';
import { ref } from 'vue';
import Install from './install/index.vue';
import { computeSizeFromMB } from '@/utils/util';
import { jumpToInstall } from '@/utils/app';
import { useGlobalStore } from '@/composables/useGlobalStore';
const { currentNode, isDarkTheme } = useGlobalStore();
const { currentNode } = useGlobalStore();
const app = ref<any>({});
const appDetail = ref<any>({});
@@ -1,6 +1,11 @@
<template>
<DrawerPro v-model="open" :header="$t('commons.button.install')" @close="handleClose" size="large">
<AppInstallForm ref="installFormRef" v-model="formData" :loading="loading" />
<AppInstallForm
ref="installFormRef"
v-model="formData"
:loading="loading"
:batch-install-support="batchInstallSupport"
/>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose" :disabled="loading">
@@ -24,12 +29,15 @@ import { newUUID } from '@/utils/util';
import { routerToName } from '@/utils/router';
import TaskLog from '@/components/log/task/index.vue';
import i18n from '@/lang';
import { installAppToNodes } from '@/xpack/api/modules/appstore';
const router = useRouter();
const open = ref(false);
const loading = ref(false);
const installFormRef = ref<InstanceType<typeof AppInstallForm>>();
const taskLogRef = ref();
const appKey = ref('');
const batchInstallSupport = ref(false);
const formData = ref({
appDetailId: 0,
@@ -98,7 +106,12 @@ const install = async (submitData: any) => {
submitData.taskID = taskID;
try {
await installApp(submitData);
if (submitData.pushNode) {
submitData.appKey = appKey.value;
await installAppToNodes(submitData);
} else {
await installApp(submitData);
}
handleClose();
openTaskLog(taskID);
} catch (error) {
@@ -112,6 +125,8 @@ const openTaskLog = (taskID: string) => {
};
const acceptParams = async (props: { app: any; params?: any }) => {
appKey.value = props.app.key;
batchInstallSupport.value = props.app.batchInstallSupport;
open.value = true;
await nextTick();
installFormRef.value?.resetForm();
+17 -4
View File
@@ -16,10 +16,10 @@
<template #rightToolBar>
<TableSearch @search="search()" v-model:searchName="searchName" />
<TableRefresh @search="search()" />
<TableSetting title="container-refresh" @search="search()" />
<TableSetting title="container-refresh" @search="refresh()" />
</template>
<template #main>
<el-row v-if="data.length > 0" :gutter="20" class="row-box">
<el-row v-if="data.length > 0 || isOnCreate" :gutter="20" class="row-box">
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="6">
<el-card>
<el-table
@@ -468,13 +468,27 @@ const loadFrom = (row: any) => {
};
const loadTableHeight = () => {
if (currentCompose.value.createdBy === '1Panel') {
if (currentCompose.value?.createdBy === '1Panel') {
return `calc(100vh - 120px)`;
} else {
return `calc(100vh - 240px)`;
}
};
const refresh = async () => {
if (!isActive.value || !isExist.value) {
return;
}
let params = {
info: searchName.value,
page: 1,
pageSize: 100,
};
await searchCompose(params).then((res) => {
data.value = res.data.items || [];
});
};
const search = async (withRefreshDetail?: boolean) => {
if (!isActive.value || !isExist.value) {
return;
@@ -484,7 +498,6 @@ const search = async (withRefreshDetail?: boolean) => {
page: 1,
pageSize: 100,
};
isOnCreate.value = false;
loading.value = true;
await searchCompose(params)
.then((res) => {
@@ -649,7 +649,7 @@ const onTerminal = (row: any) => {
};
const onInspect = async (row: any) => {
const res = await inspect({ id: row.containerID, type: 'container' });
const res = await inspect({ id: row.containerID, type: 'container', detail: '' });
containerInspectRef.value!.acceptParams({ data: res.data, ports: row.ports });
};
@@ -64,6 +64,8 @@ import { reactive, ref, nextTick } from 'vue';
import { ElForm, FormInstance } from 'element-plus';
import { Rules } from '@/global/form-rules';
import Terminal from '@/components/terminal/index.vue';
import { useGlobalStore } from '@/composables/useGlobalStore';
const { currentNode } = useGlobalStore();
const title = ref();
const terminalVisible = ref(false);
@@ -74,6 +76,7 @@ const form = reactive({
user: '',
containerID: '',
containerIDList: [],
node: '',
});
const formRef = ref();
const terminalRef = ref<InstanceType<typeof Terminal> | null>(null);
@@ -81,6 +84,7 @@ const terminalRef = ref<InstanceType<typeof Terminal> | null>(null);
interface DialogProps {
containerID: string;
title: string;
node?: string;
}
const acceptParams = async (params: DialogProps): Promise<void> => {
terminalVisible.value = true;
@@ -90,6 +94,7 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
form.isCustom = false;
form.user = '';
form.command = '/bin/sh';
form.node = params.node || currentNode.value;
terminalOpen.value = false;
};
@@ -105,7 +110,7 @@ const initTerm = (formEl: FormInstance | undefined) => {
await nextTick();
terminalRef.value!.acceptParams({
endpoint: '/api/v2/containers/exec',
args: `source=container&containerid=${form.containerID}&user=${form.user}&command=${form.command}`,
args: `source=container&containerid=${form.containerID}&user=${form.user}&command=${form.command}&node=${form.node}`,
error: '',
initCmd: '',
});
+1 -1
View File
@@ -252,7 +252,7 @@ const changePinned = (row: any, isPinned: boolean) => {
};
const onInspect = async (id: string) => {
const res = await inspect({ id: id, type: 'image' });
const res = await inspect({ id: id, type: 'image', detail: '' });
let detailInfo = JSON.stringify(JSON.parse(res.data), null, 2);
let param = {
header: i18n.global.t('commons.button.view'),
@@ -215,7 +215,7 @@ const batchDelete = async (row: Container.NetworkInfo | null) => {
};
const onInspect = async (id: string) => {
const res = await inspect({ id: id, type: 'network' });
const res = await inspect({ id: id, type: 'network', detail: '' });
let networkData = JSON.parse(res.data);
detailDrawerRef.value!.acceptParams({ data: networkData });
};
@@ -190,7 +190,7 @@ const search = async () => {
};
const onInspect = async (id: string) => {
const res = await inspect({ id: id, type: 'volume' });
const res = await inspect({ id: id, type: 'volume', detail: '' });
let detailInfo = JSON.stringify(JSON.parse(res.data), null, 2);
let param = {
header: i18n.global.t('commons.button.view'),
+2 -1
View File
@@ -398,6 +398,7 @@ const changeDatabase = async () => {
for (const item of dbOptionsLocal.value) {
if (item.database == currentDBName.value) {
currentDB.value = item;
globalStore.setCurrentDB(currentDB.value.database);
appKey.value = item.type;
appName.value = item.database;
search();
@@ -409,6 +410,7 @@ const changeDatabase = async () => {
if (item.database == currentDBName.value) {
maskShow.value = false;
currentDB.value = item;
globalStore.setCurrentDB(currentDB.value.database);
break;
}
}
@@ -532,7 +534,6 @@ const loadDBOptions = async () => {
if (currentDB.value?.from === 'remote') {
maskShow.value = false;
}
globalStore.setCurrentDB('');
search();
return;
}
@@ -335,7 +335,7 @@ const onChangeConn = async () => {
const goRemoteDB = async () => {
if (currentDB.value) {
globalStore.setCurrentDB(currentDB.value.database);
globalStore.setCurrentPgDB(currentDB.value.database);
}
routerToName('PostgreSQL-Remote');
};
@@ -348,7 +348,7 @@ const passwordRef = ref();
const onSetting = async () => {
if (currentDB.value) {
globalStore.setCurrentDB(currentDB.value.database);
globalStore.setCurrentPgDB(currentDB.value.database);
}
routerToNameWithParams('PostgreSQL-Setting', { type: currentDB.value.type, database: currentDB.value.database });
};
@@ -357,6 +357,7 @@ const changeDatabase = async () => {
for (const item of dbOptionsLocal.value) {
if (item.database == currentDBName.value) {
currentDB.value = item;
globalStore.setCurrentPgDB(currentDB.value.database);
appKey.value = item.type;
appName.value = item.database;
search();
@@ -368,6 +369,7 @@ const changeDatabase = async () => {
if (item.database == currentDBName.value) {
maskShow.value = false;
currentDB.value = item;
globalStore.setCurrentPgDB(currentDB.value.database);
break;
}
}
@@ -461,7 +463,7 @@ const loadDBOptions = async () => {
let datas = res.data || [];
dbOptionsLocal.value = [];
dbOptionsRemote.value = [];
currentDBName.value = globalStore.currentDB;
currentDBName.value = globalStore.currentPgDB;
for (const item of datas) {
if (currentDBName.value && item.database === currentDBName.value) {
currentDB.value = item;
@@ -480,7 +482,6 @@ const loadDBOptions = async () => {
if (currentDB.value?.from === 'remote') {
maskShow.value = false;
}
globalStore.setCurrentDB('');
search();
return;
}

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