Compare commits

..
97 Commits
Author SHA1 Message Date
ssongliu b3350b54b3 fix: Add iptables execution timeout (#11176) 2025-12-04 11:22:25 +08:00
CityFun cd4e0374d0 refactor: Refactored agent core.db loading logic (#11175) 2025-12-04 11:15:40 +08:00
KOMATA 5d2084fda4 feat: improve linux distribution information get logic (#11171)
* feat: Add PrettyDistro field to dashboard information and update related services and frontend components

* fix: Trim whitespace and parentheses from detected Linux distribution name in GetDistro method

* fix: Correctly trim parentheses from detected Linux distribution name in GetDistro method

* refactor: Simplify Linux distribution detection by removing unnecessary checks and consolidating logic
2025-12-03 14:14:35 +08:00
ssongliu 8c32fa3e6c fix: Fix the issue of abnormal clam scan status judgment (#11172) 2025-12-03 14:13:22 +08:00
KOMATA fef13211a0 feat: Enhance CPU metrics by adding CPU detailed information (#11169)
* fix: Update CPU usage retrieval to include detailed percentage information

* feat: Enhance CPU metrics by adding CPU frequency and detailed usage percentages

* feat: Add CPU frequency metric to dashboard base information
2025-12-03 13:37:57 +08:00
CityFun 5ff5b0a5ad feat: revised some of the translations (#11168) 2025-12-03 03:58:14 +00:00
CityFun 8ac9d022b6 fix: fix missing version issue during mssql installation (#11167) 2025-12-03 03:56:15 +00:00
CityFun 2c02dc07e9 fix: resolve i18n file loading failure issue (#11164) 2025-12-03 10:08:20 +08:00
ssongliu ba999c516a chore: Modify the default runtime value on the overview page (#11159) 2025-12-02 10:21:42 +00:00
AirboZH 28303ffa82 feat: Add support for AWS Route 53 DNS provider (#11158) 2025-12-02 18:20:35 +08:00
ssongliu 1f9a3aa51a feat: Add refresh after resource release in container overview (#11157) 2025-12-02 09:29:41 +00:00
ssongliu 656dda234c perf: Optimize GPU monitoring display (#11156) 2025-12-02 09:21:41 +00:00
KOMATA 63b62f4074 fix: Enhance error handling in file saving process (#11152)
* fix: Enhance error handling in file saving process

* f

* f
2025-12-02 17:19:22 +08:00
KOMATA 158180a052 fix: Enhance error handling for additional HTTP status codes in RequestHttp class (#11151) 2025-12-02 17:11:55 +08:00
ssongliu dbe479e920 fix: Fix agent packaging failure issue (#11150) 2025-12-02 02:57:40 +00:00
蘭 7aefa34871 fix: Fix the issue of software link creation errors (#11149) 2025-12-02 02:53:41 +00:00
ssongliu 7d92436b92 perf: Change container overview page disk usage to asynchronous requests (#11148) 2025-12-02 02:29:39 +00:00
AirboZH 66a070c239 feat: Add support for AliESA DNS provider (#11147) 2025-12-02 10:11:46 +08:00
ssongliu bb9d9042f0 chore: Modify iptables initialization logic (#11145) 2025-12-01 22:20:17 +08:00
ssongliu a5d86d4c00 fix: Fix the issue where container details cannot be fully selected and copied (#11144) 2025-12-01 22:06:59 +08:00
KOMATA e867deb547 feat: Add copy function for raw JSON in container and network detail views (#11141)
* feat: Add copy button for raw JSON in container and network detail views

* refactor: Change CodemirrorPro component from disabled to readonly in container and network detail views

* feat: Add readonly prop to CodemirrorPro component for enhanced editing control
2025-12-01 18:13:52 +08:00
ssongliu af15659d99 fix: Fix display issues caused by default table height (#11143) 2025-12-01 10:05:37 +00:00
ssongliu f63658db9e fix: Fix the issue of extremely slow container list retrieval (#11142)
Refs #11129
2025-12-01 10:03:37 +00:00
ssongliu d4edf2f874 fix: Fix the issue of abnormal time filtering in GPU monitoring (#11139) 2025-12-01 08:43:38 +00:00
ssongliu 94f7d78cc9 fix: Fix iptables state persistence issue (#11137)
Refs #11126
2025-12-01 06:33:38 +00:00
ssongliu 5cede39e5c fix: Fix log display issue when backup account is unavailable during … (#11135)
Refs #11123
2025-12-01 02:15:37 +00:00
KOMATA 508ac2ae84 fix: Improve error handling in file download API (#11127) 2025-12-01 09:40:48 +08:00
KOMATA 997b820a42 perf: use gzipped data for improved load speed in large response (#11128)
* perf: use gzipped data for improved load speed in big files

* perf: switch to gzipped response for GetFileTree to enhance performance

* perf: switch to gzipped response for SearchApp to improve performance

* perf: update file size conditions for gzipped response to enhance performance
2025-12-01 09:40:32 +08:00
KOMATA 5de83985e3 feat: Add path protection mechanism to prevent deletion of system dir (#11130)
* feat: Add path protection mechanism to prevent deletion of critical system directories

* feat: Enhance recycle bin service with path protection for deletion requests
2025-12-01 09:40:00 +08:00
ssongliu c0220dbed0 fix: Disable caching for recommended apps on the overview page (#11117) 2025-11-28 10:19:27 +00:00
ssongliu 2e9305b9b1 fix: Fix some overview page caching issues (#11114) 2025-11-28 09:05:29 +00:00
王贺 b18bdea1c9 chore: limit gitee sync workflow to main repo (#11112) 2025-11-28 16:47:37 +08:00
ssongliu 25fb431163 fix: Fix the upgrade service file location issue (#11109) 2025-11-28 11:07:49 +08:00
CityFun ac43f00273 perf: optimize login API logic (#11104) 2025-11-28 03:05:27 +00:00
ssongliu 8ccf1fcbf3 fix: Fix the issue of abnormal runtime refresh on the overview page (#11106) 2025-11-27 10:37:24 +00:00
ssongliu b2803f574b chore: Remove some unused code (#11105) 2025-11-27 17:59:48 +08:00
ssongliu bbc14bb723 feat: Add GPU monitoring settings redirection (#11103) 2025-11-27 09:57:25 +00:00
KOMATA e89311d5d4 feat: Implement dashboard caching and refresh functionality (#11100)
* feat: Implement dashboard caching and refresh functionality

* feat: Enhance dashboard and launcher with hover refresh functionality and improve caching strategy

* feat: Introduce dashboard caching utility functions for improved data management
2025-11-27 17:54:54 +08:00
CityFun b5e56c6b65 feat: optimize IP whitelist validation logic (#11102) 2025-11-27 16:29:31 +08:00
ssongliu 3d2023858c feat: Compatible with XPU monitoring (#11099) 2025-11-27 05:57:24 +00:00
KOMATA 74b48a18be fix: Improve app list loading by switching to JSON decoder from file stream (#11095) 2025-11-27 13:47:03 +08:00
CityFun 42f61f60fb fix: Fixed issue with edit runtime port failed (#11096)
Refs https://github.com/1Panel-dev/1Panel/issues/11091
2025-11-27 03:51:24 +00:00
KOMATA e32a11910e fix: adjust WebSocket buffer sizes in terminal and host API (#11094) 2025-11-27 11:22:33 +08:00
CityFun dc9fdf897b feat: add more fields to process detail view (#11093) 2025-11-27 11:21:44 +08:00
CityFun 35c946a064 feat: support creating databases with custom charset and collation during app installation (#11092) 2025-11-27 03:21:23 +00:00
KOMATAand王贺 747a0c45ee feat: async load data of top CPU and memory processes data (#11081)
* feat: async load data of top CPU and memory processes data

* refactor: Update CPU and memory top toggle functionality and state management

---------

Co-authored-by: 王贺 <wanghe@fit2cloud.com>
2025-11-26 23:02:09 +08:00
ssongliu 8e03b24b0c feat: Compatible with XPU monitoring (#11088) 2025-11-26 22:30:15 +08:00
ssongliu 18c65c3096 fix: Fix the issue of snapshots not automatically restarting after restoration (#11087) 2025-11-26 22:29:59 +08:00
ssongliu 3b306f990a chore: Optimize iptables initial state loading speed (#11085) 2025-11-26 22:29:48 +08:00
CityFun 92fa6552b1 style: change file management terminal style (#11084) 2025-11-26 10:35:21 +00:00
ssongliu a39dc33770 fix: Handle empty character set in MariaDB compatibility (#11082) 2025-11-26 09:21:21 +00:00
KOMATA 0a42d4942c perf: replace gopsutil sampling with cached metrics and optimize system info retrieval (#11079)
* refactor: change psutil method
2025-11-26 16:33:47 +08:00
ssongliu 8086d5cecb fix: Fix uppercase exclusion in container compose (#11080) 2025-11-26 07:53:24 +00:00
ssongliu a6875614f6 style: Optimize container compose page style (#11076) 2025-11-26 04:39:20 +00:00
CityFun 6b061fa327 perf: change db connect params (#11075) 2025-11-26 11:11:11 +08:00
KOMATA b416e6b6f1 refactor: Optimize log file reading logic (#11064)
* refactor: Optimize log file reading with buffered reader pool and improve pagination logic

* refactor: Enhance file reading logic with improved buffer management and constant usage

* refactor: Adjust maximum read file size and enhance line reading functionality
2025-11-25 22:42:29 +08:00
ssongliu ac1f49f8dd fix: Fix the issue of abnormal image list retrieval in snapshots (#11074)
Refs #11030
2025-11-25 14:25:18 +00:00
ssongliu 6ddee2649d feat: Add default values for curl scheduled tasks (#11073) 2025-11-25 14:17:18 +00:00
ssongliu fd14f53cb9 style: Adjust container network details style (#11072) 2025-11-25 10:51:18 +00:00
CityFun 029e2210f5 perf: change db connect params (#11071) 2025-11-25 18:48:47 +08:00
ssongliu 69769e6203 fix: Fix the issue of database connections not being released (#11070) 2025-11-25 10:07:19 +00:00
ssongliu 2a21f194d3 feat: Optimize orchestration creation logs (#11069)
Refs  #11068
2025-11-25 09:21:18 +00:00
ssongliu e46d8c5812 feat: Support MySQL data synchronization collation (#11067) 2025-11-25 15:02:37 +08:00
CityFun 938605a169 fix: Resolve application list display error caused by docker-compose.yml modifications (#11065) 2025-11-25 06:27:18 +00:00
ssongliu c3cc26a136 fix: Fix the issue of abnormal iptables persistence loading (#11066) 2025-11-25 14:21:24 +08:00
KOMATA dda83b6307 feat: Implement Gzip compression for successful log API responses (#11063)
* feat: Implement Gzip compression for successful API responses

* refactor: Optimize Gzip compression handling in API responses using sync.Pool
2025-11-25 13:39:08 +08:00
CityFun 48e2e01a57 feat: Add MySQL character set and collation configuration during application installation (#11062) 2025-11-25 03:51:17 +00:00
ssongliu d6b00967ca fix: Fix the issue of database backup failure (#11060) 2025-11-25 03:19:18 +00:00
ssongliu 6d4c1f8e79 fix: Fix the issue of abnormal container list sorting (#11059) 2025-11-25 11:17:34 +08:00
ssongliu e88fe0ac2f fix: Fix the issue of database creation failure (#11057) 2025-11-24 14:35:16 +00:00
ssongliu 496c0b50b4 fix: Fix the issue of abnormal iptables rule persistence (#11056)
Refs #11027
2025-11-24 14:33:15 +00:00
wanghe-fit2cloud 9d73d74c63 chore: remove UPX compression 2025-11-24 18:27:54 +08:00
CityFun 7e4e12107a perf: change db connect params (#11055) 2025-11-24 10:03:15 +00:00
CityFun 5b15de91e6 fix: Fixed issue with build failed (#11054) 2025-11-24 16:29:48 +08:00
KOMATA 98b3dc9d7d refactor: update Swagger serving and processing method (#11052)
* feat: Add Swagger UI support and update Go module dependencies
2025-11-24 16:14:06 +08:00
ssongliu c05e610b13 feat: Support more MySQL character sets and collations (#11053) 2025-11-24 08:07:14 +00:00
ssongliu 63f9368e26 feat: GPU monitoring data supports persistence (#11051)
Refs #9496
2025-11-24 07:59:15 +00:00
ssongliu 3f47a6e701 feat: Support multiple URL access for cronjob (#11050)
Refs #10279
2025-11-24 07:57:18 +00:00
ssongliu d7c9b3b192 feat: Support favorite operations for containers and images (#11049)
Refs #10035 #3372
2025-11-24 07:55:14 +00:00
CityFun 063ed23acb perf: Optimize disk management formatting process (#11047)
https://github.com/1Panel-dev/1Panel/issues/11031
2025-11-24 07:51:15 +00:00
ssongliu 7c33dd9026 feat: PG remote databases version 18.x support backup and restore (#11048)
Refs #10917
2025-11-24 07:47:14 +00:00
CityFun a853d8c869 perf: change base64Captcha (#11046) 2025-11-24 14:47:58 +08:00
KOMATA 4ddeb81972 refactor: Update database connection settings to limit concurrency and idle connections (#11045) 2025-11-24 14:04:54 +08:00
CityFun 4dd9f00637 perf: Increase supervisor API timeout duration (#11043)
Refs https://github.com/1Panel-dev/1Panel/issues/11041
2025-11-24 03:59:14 +00:00
ssongliu 49f3779fd2 fix: Fix the issue of abnormal WebDAV connection (#11038) 2025-11-24 11:36:58 +08:00
KOMATAandssongliu 7389aad122 feat: Add ComposeDetail view for enhanced container management (#10981)
* feat: Add ComposeDetail view for enhanced container management

* feat: Update container log management with new table layout and improved stats display

* feat: Update log search mode to 'all' for comprehensive log retrieval

* cleanup

* feat: Enhance log container and compose management with new UI components and improved functionality

* refactor: Remove unused ComposeDetail route and enhance UI components in container management

* refactor: Improve UI styling and interaction for compose list items in container management

* refactor: Update styling and hover effects for compose list items in container management

* refactor: Enhance container compose header with additional context and improve port handling in inspect view

* refactor: Update .env label to use translation for improved localization in container compose view

* refactor: Adjust height and placeholder text for YAML editor in container compose view

* refactor: Adjust docker compose layout

---------

Co-authored-by: ssongliu <songlius11@163.com>
2025-11-21 18:20:19 +08:00
KOMATA bf095c677c feat: Migrate AWS SDK to v2 (#10983)
* refactor: Migrate S3 client to AWS SDK v2

* refactor: Migrate S3 client to AWS SDK v2 and update dependencies

* refactor: Simplify endpoint handling in S3 client initialization

* refactor: Update S3 client method receivers to pointer types for consistency
2025-11-21 16:18:38 +08:00
ssongliu fb929687d8 fix: Fix the issue of abnormal sshd service auto-start status (#11022)
Refs #11017
2025-11-21 08:13:06 +00:00
CityFun bddcf76fc3 fix: Fixed issue with uninstall extension failed (#11021) 2025-11-21 07:59:08 +00:00
KOMATA 9370bdb5ac fix: Update Cache-Control headers for static resources in router (#11020)
* fix: Update Cache-Control headers for static resources in router

* chore: Remove Cache-Control header from static resource response in router
2025-11-21 15:47:48 +08:00
KOMATA ef6d8bb17b fix: improve logic and fix bug in i18n module (#11019)
* feat: Implement language caching and improve language handling in i18n module

* refactor: Optimize i18n initialization with sync.Once for thread safety

* fix: Replace logging with fmt.Println for language file loading errors in i18n module

* fix: Correct format string in error logging for language file loading in i18n module

* fix: Update language files and improve error handling in i18n module

* fix: Update Malay language file extension from .yml to .yaml and add new translations in i18n module

* fix: Improve error messages for language file loading in i18n module

* fix: Ensure cached database language is set correctly during i18n initialization

* fix: Enhance language detection in i18n module by using Accept-Language header
2025-11-21 15:37:01 +08:00
CityFun 99c2eb04c9 feat: Add memory requirement field display for local applications (#11018)
Refs https://github.com/1Panel-dev/1Panel/issues/11015
2025-11-21 04:05:05 +00:00
CityFun d83b673c90 perf: significantly improve app store homepage loading speed (#11013) 2025-11-20 18:57:49 +08:00
ssongliu 7498f3f66b feat: Container networks support multi-NIC operations (#11011)
Refs #11007
2025-11-20 08:35:03 +00:00
ssongliu 147eda529c fix: Fix the issue with PostgreSQL configuration file abnormalities (#11010)
Refs #11004
2025-11-20 08:33:02 +00:00
CityFun c1f0da4248 refactor: remove debug cmd for agent and core (#11009) 2025-11-20 08:31:03 +00:00
KOMATA 8656dada06 fix: correct suitable log queue size to improve performance (#11008)
* fix: Update log queue size to improve performance and ensure proper handling of log entries

* fix: Adjust log queue size to maintain consistency with queue size limit
2025-11-20 16:28:03 +08:00
244 changed files with 7013 additions and 2991 deletions
+1
View File
@@ -6,6 +6,7 @@ permissions:
jobs:
generic_handler:
name: Add Labels to PR
if: github.repository == '1Panel-dev/1Panel'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
go-version: '1.24'
- name: Build Release
uses: goreleaser/goreleaser-action@v6
with:
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
go-version: '1.24'
- name: Build Release
uses: goreleaser/goreleaser-action@v6
with:
+1
View File
@@ -8,6 +8,7 @@ on:
jobs:
sonarcloud:
name: SonarCloud
if: github.repository == '1Panel-dev/1Panel'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
+1
View File
@@ -2,6 +2,7 @@ name: Synchronize to Gitee
on: [push]
jobs:
repo-sync:
if: github.repository == '1Panel-dev/1Panel'
runs-on: ubuntu-latest
steps:
- name: Mirror the Github organization repos to Gitee.
-6
View File
@@ -33,9 +33,6 @@ builds:
- ppc64le
- s390x
- riscv64
hooks:
post:
- ./ci/script.sh compress_binary {{ .Path }} {{ .Arch }}
- id: core
dir: core
@@ -59,9 +56,6 @@ builds:
- ppc64le
- s390x
- riscv64
hooks:
post:
- ./ci/script.sh compress_binary {{ .Path }} {{ .Arch }}
archives:
- formats: [ 'tar.gz' ]
+1 -1
View File
@@ -46,4 +46,4 @@ build_agent_on_darwin:
build_all: build_frontend build_core_on_linux build_agent_on_linux
build_on_local: clean_assets build_frontend build_core_on_darwin build_agent_on_darwin upx_bin
build_on_local: clean_assets build_frontend build_core_on_darwin build_agent_on_darwin
+29 -1
View File
@@ -1,6 +1,9 @@
package v2
import (
"net/http"
"time"
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
@@ -26,7 +29,7 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, list)
helper.SuccessWithDataGzipped(c, list)
}
// @Tags App
@@ -192,3 +195,28 @@ func (b *BaseApi) GetAppListUpdate(c *gin.Context) {
}
helper.SuccessWithData(c, res)
}
// @Tags App
// @Summary Get app icon by app_id
// @Accept json
// @Param appId path integer true "app id"
// @Success 200 {file} file "app icon"
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /apps/icon/:appId [get]
func (b *BaseApi) GetAppIcon(c *gin.Context) {
appID, err := helper.GetIntParamByKey(c, "appID")
if err != nil {
helper.BadRequest(c, err)
return
}
iconBytes, err := appService.GetAppIcon(appID)
if err != nil {
helper.InternalServer(c, err)
return
}
c.Header("Content-Type", "image/png")
c.Header("Cache-Control", "public, max-age=31536000, immutable")
c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
c.Data(http.StatusOK, "image/png", iconBytes)
}
+21
View File
@@ -263,6 +263,27 @@ func (b *BaseApi) ContainerListStats(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Summary Load container stats size
// @Accept json
// @Param request body dto.OperationWithName true "request"
// @Success 200 {object} dto.ContainerItemStats
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /containers/item/stats [post]
func (b *BaseApi) ContainerItemStats(c *gin.Context) {
var req dto.OperationWithName
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := containerService.ContainerItemStats(req)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Container
// @Summary Create container
// @Accept json
+23 -1
View File
@@ -37,7 +37,7 @@ func (b *BaseApi) LoadAppLauncher(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, data)
helper.SuccessWithDataGzipped(c, data)
}
// @Tags Dashboard
@@ -179,6 +179,28 @@ func (b *BaseApi) LoadDashboardCurrentInfo(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Tags Dashboard
// @Summary Load top cpu processes
// @Success 200 {Array} dto.Process
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /dashboard/current/top/cpu [get]
func (b *BaseApi) LoadDashboardTopCPU(c *gin.Context) {
data := dashboardService.LoadTopCPU()
helper.SuccessWithData(c, data)
}
// @Tags Dashboard
// @Summary Load top memory processes
// @Success 200 {Array} dto.Process
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /dashboard/current/top/mem [get]
func (b *BaseApi) LoadDashboardTopMem(c *gin.Context) {
data := dashboardService.LoadTopMem()
helper.SuccessWithData(c, data)
}
// @Tags Dashboard
// @Summary System restart
// @Accept json
+8 -10
View File
@@ -195,21 +195,19 @@ func (b *BaseApi) SearchMysql(c *gin.Context) {
}
// @Tags Database Mysql
// @Summary List mysql database names
// @Summary List mysql database format collation options
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Success 200 {array} dto.MysqlOption
// @Param request body dto.OperationWithName true "request"
// @Success 200 {array} dto.MysqlFormatCollationOption
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /databases/options [get]
func (b *BaseApi) ListDBName(c *gin.Context) {
list, err := mysqlService.ListDBOption()
if err != nil {
helper.InternalServer(c, err)
// @Router /databases/format/options [post]
func (b *BaseApi) ListDBFormatCollationOptions(c *gin.Context) {
var req dto.OperationWithName
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
helper.SuccessWithData(c, list)
helper.SuccessWithData(c, mysqlService.LoadFormatOption(req))
}
// @Tags Database Mysql
+17 -4
View File
@@ -90,7 +90,7 @@ func (b *BaseApi) GetFileTree(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, tree)
helper.SuccessWithDataGzipped(c, tree)
}
// @Tags File
@@ -265,7 +265,11 @@ func (b *BaseApi) GetContent(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, info)
if info.Size > 2*1024 && info.Size < 5*1024*1024 {
helper.SuccessWithDataGzipped(c, info)
} else {
helper.SuccessWithData(c, info)
}
}
// @Tags File
@@ -521,9 +525,14 @@ func (b *BaseApi) Download(c *gin.Context) {
file, err := os.Open(filePath)
if err != nil {
helper.InternalServer(c, err)
return
}
defer file.Close()
info, _ := file.Stat()
info, err := file.Stat()
if err != nil {
helper.InternalServer(c, err)
return
}
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
@@ -841,7 +850,11 @@ func (b *BaseApi) ReadFileByLine(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, res)
if res.TotalLines > 100 {
helper.SuccessWithDataGzipped(c, res)
} else {
helper.SuccessWithData(c, res)
}
}
// @Tags File
+1 -1
View File
@@ -269,7 +269,7 @@ func (b *BaseApi) OperateFilterRule(c *gin.Context) {
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := iptablesService.OperateRule(req); err != nil {
if err := iptablesService.OperateRule(req, true); err != nil {
helper.InternalServer(c, err)
return
}
+40
View File
@@ -1,10 +1,14 @@
package helper
import (
"compress/gzip"
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
"sync"
"github.com/1Panel-dev/1Panel/agent/global"
"gorm.io/gorm"
@@ -46,6 +50,42 @@ func SuccessWithData(ctx *gin.Context, data interface{}) {
ctx.Abort()
}
var gzipWriterPool = sync.Pool{
New: func() interface{} {
return gzip.NewWriter(nil)
},
}
func SuccessWithDataGzipped(ctx *gin.Context, data interface{}) {
if !strings.Contains(ctx.GetHeader("Accept-Encoding"), "gzip") {
SuccessWithData(ctx, data)
return
}
if data == nil {
data = gin.H{}
}
res := dto.Response{
Code: http.StatusOK,
Data: data,
}
jsonBytes, err := json.Marshal(res)
if err != nil {
ErrorWithDetail(ctx, http.StatusInternalServerError, "ErrInternalServer", err)
return
}
ctx.Header("Content-Encoding", "gzip")
ctx.Header("Content-Type", "application/json; charset=utf-8")
ctx.Status(http.StatusOK)
gz := gzipWriterPool.Get().(*gzip.Writer)
gz.Reset(ctx.Writer)
_, _ = gz.Write(jsonBytes)
_ = gz.Close()
gzipWriterPool.Put(gz)
ctx.Abort()
}
func Success(ctx *gin.Context) {
res := dto.Response{
Code: http.StatusOK,
+25
View File
@@ -28,6 +28,27 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithDataGzipped(c, data)
}
// @Tags Monitor
// @Summary Load monitor data
// @Param request body dto.MonitorGPUSearch true "request"
// @Success 200 {object} dto.dto.MonitorGPUData
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /hosts/monitor/gpu/search [post]
func (b *BaseApi) LoadGPUMonitor(c *gin.Context) {
var req dto.MonitorGPUSearch
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := monitorService.LoadGPUMonitorData(req)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, data)
}
@@ -105,3 +126,7 @@ func (b *BaseApi) GetIOOptions(c *gin.Context) {
sort.Strings(options)
helper.SuccessWithData(c, options)
}
func (b *BaseApi) GetCPUOptions(c *gin.Context) {
helper.SuccessWithData(c, monitorService.LoadGPUOptions())
}
+21
View File
@@ -155,3 +155,24 @@ func (b *BaseApi) GetSettingByKey(c *gin.Context) {
value := settingService.GetSettingByKey(key)
helper.SuccessWithData(c, value)
}
// @Tags System Setting
// @Summary Save common description
// @Accept json
// @Param request body dto.CommonDescription true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /settings/description/save [post]
func (b *BaseApi) SaveDescription(c *gin.Context) {
var req dto.CommonDescription
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := settingService.SaveDescription(req); err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}
+2 -2
View File
@@ -228,8 +228,8 @@ func wshandleError(ws *websocket.Conn, err error) bool {
}
var upGrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024 * 1024 * 10,
ReadBufferSize: 4096,
WriteBufferSize: 16384,
CheckOrigin: func(r *http.Request) bool {
return true
},
+4 -3
View File
@@ -1,7 +1,6 @@
package v2
import (
"github.com/1Panel-dev/1Panel/agent/app/model"
"io"
"mime/multipart"
"net/http"
@@ -9,6 +8,8 @@ import (
"reflect"
"strconv"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
@@ -34,7 +35,7 @@ func (b *BaseApi) PageWebsiteSSL(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
helper.SuccessWithDataGzipped(c, dto.PageResult{
Total: total,
Items: accounts,
})
@@ -44,7 +45,7 @@ func (b *BaseApi) PageWebsiteSSL(c *gin.Context) {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, list)
helper.SuccessWithDataGzipped(c, list)
}
}
+5 -3
View File
@@ -12,6 +12,8 @@ type AppDatabase struct {
DbUser string `json:"PANEL_DB_USER"`
Password string `json:"PANEL_DB_USER_PASSWORD"`
DatabaseName string `json:"DATABASE_NAME"`
Format string `json:"format"`
Collation string `json:"collation"`
}
type AuthParam struct {
@@ -91,13 +93,13 @@ type AppProperty struct {
Key string `json:"key"`
Required []string `json:"Required"`
CrossVersionUpdate bool `json:"crossVersionUpdate"`
Limit int `json:"limit"`
Recommend int `json:"recommend"`
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"`
MemoryRequired int `json:"memoryRequired" yaml:"memoryRequired"`
GpuSupport bool `json:"gpuSupport"`
Version float64 `json:"version"`
Deprecated float64 `json:"deprecated"`
+32 -23
View File
@@ -31,15 +31,15 @@ type ContainerInfo struct {
Network []string `json:"network"`
Ports []string `json:"ports"`
SizeRw int64 `json:"sizeRw"`
SizeRootFs int64 `json:"sizeRootFs"`
IsFromApp bool `json:"isFromApp"`
IsFromCompose bool `json:"isFromCompose"`
AppName string `json:"appName"`
AppInstallName string `json:"appInstallName"`
Websites []string `json:"websites"`
IsPinned bool `json:"isPinned"`
Description string `json:"description"`
}
type ContainerOptions struct {
@@ -63,15 +63,6 @@ type ContainerStatus struct {
NetworkCount int `json:"networkCount"`
VolumeCount int `json:"volumeCount"`
RepoCount int `json:"repoCount"`
ContainerUsage int64 `json:"containerUsage"`
ContainerReclaimable int64 `json:"containerReclaimable"`
ImageUsage int64 `json:"imageUsage"`
ImageReclaimable int64 `json:"imageReclaimable"`
VolumeUsage int64 `json:"volumeUsage"`
VolumeReclaimable int64 `json:"volumeReclaimable"`
BuildCacheUsage int64 `json:"buildCacheUsage"`
BuildCacheReclaimable int64 `json:"buildCacheReclaimable"`
}
type ResourceLimit struct {
CPU int `json:"cpu"`
@@ -79,17 +70,16 @@ type ResourceLimit struct {
}
type ContainerOperate struct {
TaskID string `json:"taskID"`
ForcePull bool `json:"forcePull"`
Name string `json:"name" validate:"required"`
Image string `json:"image" validate:"required"`
Network string `json:"network"`
Hostname string `json:"hostname"`
DomainName string `json:"domainName"`
MacAddr string `json:"macAddr"`
DNS []string `json:"dns"`
Ipv4 string `json:"ipv4"`
Ipv6 string `json:"ipv6"`
TaskID string `json:"taskID"`
ForcePull bool `json:"forcePull"`
Name string `json:"name" validate:"required"`
Image string `json:"image" validate:"required"`
Hostname string `json:"hostname"`
DomainName string `json:"domainName"`
DNS []string `json:"dns"`
Networks []ContainerNetwork `json:"networks"`
PublishAllPorts bool `json:"publishAllPorts"`
ExposedPorts []PortHelper `json:"exposedPorts"`
Tty bool `json:"tty"`
@@ -108,6 +98,12 @@ type ContainerOperate struct {
Env []string `json:"env"`
RestartPolicy string `json:"restartPolicy"`
}
type ContainerNetwork struct {
Network string `json:"network"`
Ipv4 string `json:"ipv4"`
Ipv6 string `json:"ipv6"`
MacAddr string `json:"macAddr"`
}
type ContainerCreateByCommand struct {
TaskID string `json:"taskID"`
@@ -121,6 +117,19 @@ type ContainerUpgrade struct {
ForcePull bool `json:"forcePull"`
}
type ContainerItemStats struct {
SizeRw int64 `json:"sizeRw"`
SizeRootFs int64 `json:"sizeRootFs"`
ContainerUsage int64 `json:"containerUsage"`
ContainerReclaimable int64 `json:"containerReclaimable"`
ImageUsage int64 `json:"imageUsage"`
ImageReclaimable int64 `json:"imageReclaimable"`
VolumeUsage int64 `json:"volumeUsage"`
VolumeReclaimable int64 `json:"volumeReclaimable"`
BuildCacheUsage int64 `json:"buildCacheUsage"`
BuildCacheReclaimable int64 `json:"buildCacheReclaimable"`
}
type ContainerListStats struct {
ContainerID string `json:"containerID"`
+15 -10
View File
@@ -13,15 +13,17 @@ type DashboardBase struct {
Platform string `json:"platform"`
PlatformFamily string `json:"platformFamily"`
PlatformVersion string `json:"platformVersion"`
PrettyDistro string `json:"prettyDistro"`
KernelArch string `json:"kernelArch"`
KernelVersion string `json:"kernelVersion"`
VirtualizationSystem string `json:"virtualizationSystem"`
IpV4Addr string `json:"ipV4Addr"`
SystemProxy string `json:"systemProxy"`
CPUCores int `json:"cpuCores"`
CPULogicalCores int `json:"cpuLogicalCores"`
CPUModelName string `json:"cpuModelName"`
CPUCores int `json:"cpuCores"`
CPULogicalCores int `json:"cpuLogicalCores"`
CPUModelName string `json:"cpuModelName"`
CPUMhz float64 `json:"cpuMhz"`
QuickJumps []QuickJump `json:"quickJump"`
CurrentInfo DashboardCurrent `json:"currentInfo"`
@@ -48,6 +50,7 @@ type OsInfo struct {
PlatformFamily string `json:"platformFamily"`
KernelArch string `json:"kernelArch"`
KernelVersion string `json:"kernelVersion"`
PrettyDistro string `json:"prettyDistro"`
DiskSize int64 `json:"diskSize"`
}
@@ -58,9 +61,10 @@ type NodeCurrent struct {
Load15 float64 `json:"load15"`
LoadUsagePercent float64 `json:"loadUsagePercent"`
CPUUsedPercent float64 `json:"cpuUsedPercent"`
CPUUsed float64 `json:"cpuUsed"`
CPUTotal int `json:"cpuTotal"`
CPUUsedPercent float64 `json:"cpuUsedPercent"`
CPUUsed float64 `json:"cpuUsed"`
CPUTotal int `json:"cpuTotal"`
CPUDetailedPercent []float64 `json:"cpuDetailedPercent"`
MemoryTotal uint64 `json:"memoryTotal"`
MemoryAvailable uint64 `json:"memoryAvailable"`
@@ -84,10 +88,11 @@ type DashboardCurrent struct {
Load15 float64 `json:"load15"`
LoadUsagePercent float64 `json:"loadUsagePercent"`
CPUPercent []float64 `json:"cpuPercent"`
CPUUsedPercent float64 `json:"cpuUsedPercent"`
CPUUsed float64 `json:"cpuUsed"`
CPUTotal int `json:"cpuTotal"`
CPUPercent []float64 `json:"cpuPercent"`
CPUUsedPercent float64 `json:"cpuUsedPercent"`
CPUUsed float64 `json:"cpuUsed"`
CPUTotal int `json:"cpuTotal"`
CPUDetailedPercent []float64 `json:"cpuDetailedPercent"`
MemoryTotal uint64 `json:"memoryTotal"`
MemoryUsed uint64 `json:"memoryUsed"`
+8 -1
View File
@@ -38,6 +38,7 @@ type MysqlDBInfo struct {
From string `json:"from"`
MysqlName string `json:"mysqlName"`
Format string `json:"format"`
Collation string `json:"collation"`
Username string `json:"username"`
Password string `json:"password"`
Permission string `json:"permission"`
@@ -57,13 +58,19 @@ type MysqlDBCreate struct {
Name string `json:"name" validate:"required"`
From string `json:"from" validate:"required,oneof=local remote"`
Database string `json:"database" validate:"required"`
Format string `json:"format" validate:"required,oneof=utf8mb4 utf8 gbk big5"`
Format string `json:"format" validate:"required"`
Collation string `json:"collation"`
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
Permission string `json:"permission" validate:"required"`
Description string `json:"description"`
}
type MysqlFormatCollationOption struct {
Format string `json:"format"`
Collations []string `json:"collations"`
}
type BindUser struct {
Database string `json:"database" validate:"required"`
DB string `json:"db" validate:"required"`
+3
View File
@@ -15,6 +15,9 @@ type ImageInfo struct {
IsUsed bool `json:"isUsed"`
Tags []string `json:"tags"`
Size int64 `json:"size"`
IsPinned bool `json:"isPinned"`
Description string `json:"description"`
}
type ImageLoad struct {
+32 -1
View File
@@ -11,7 +11,7 @@ type MonitorSearch struct {
}
type MonitorData struct {
Param string `json:"param" validate:"required,oneof=cpu memory load io network"`
Param string `json:"param"`
Date []time.Time `json:"date"`
Value []interface{} `json:"value"`
}
@@ -37,3 +37,34 @@ type MonitorSettingUpdate struct {
Key string `json:"key" validate:"required,oneof=MonitorStatus MonitorStoreDays MonitorInterval DefaultNetwork DefaultIO"`
Value string `json:"value"`
}
type MonitorGPUOptions struct {
GPUType string `json:"gpuType"`
Options []string `json:"options"`
}
type MonitorGPUSearch struct {
ProductName string `json:"productName"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
}
type MonitorGPUData struct {
Date []time.Time `json:"date"`
GPUValue []float64 `json:"gpuValue"`
TemperatureValue []float64 `json:"temperatureValue"`
PowerTotal []float64 `json:"powerTotal"`
PowerUsed []float64 `json:"powerUsed"`
PowerPercent []float64 `json:"powerPercent"`
MemoryTotal []float64 `json:"memoryTotal"`
MemoryUsed []float64 `json:"memoryUsed"`
MemoryPercent []float64 `json:"memoryPercent"`
SpeedValue []int `json:"speedValue"`
GPUProcesses [][]GPUProcess `json:"gpuProcesses"`
}
type GPUProcess struct {
Pid string `json:"pid"`
Type string `json:"type"`
ProcessName string `json:"processName"`
UsedMemory string `json:"usedMemory"`
}
+1 -7
View File
@@ -33,16 +33,10 @@ type AppItem struct {
Key string `json:"key"`
ID uint `json:"id"`
Description string `json:"description"`
Icon string `json:"icon"`
Type string `json:"type"`
Status string `json:"status"`
Resource string `json:"resource"`
Installed bool `json:"installed"`
Versions []string `json:"versions"`
Limit int `json:"limit"`
Tags []TagDTO `json:"tags"`
Github string `json:"github"`
Website string `json:"website"`
Tags []string `json:"tags"`
GpuSupport bool `json:"gpuSupport"`
Recommend int `json:"recommend"`
}
+8
View File
@@ -81,3 +81,11 @@ type SystemProxy struct {
User string `json:"user"`
Password string `json:"password"`
}
type CommonDescription struct {
ID string `json:"id" validate:"required"`
Type string `json:"type" validate:"required"`
DetailType string `json:"detailType"`
IsPinned bool `json:"isPinned"`
Description string `json:"description"`
}
+1
View File
@@ -6,6 +6,7 @@ type DatabaseMysql struct {
From string `json:"from" gorm:"not null;default:local"`
MysqlName string `json:"mysqlName" gorm:"not null"`
Format string `json:"format" gorm:"not null"`
Collation string `json:"collation"`
Username string `json:"username" gorm:"not null"`
Password string `json:"password" gorm:"not null"`
Permission string `json:"permission" gorm:"not null"`
+13
View File
@@ -31,3 +31,16 @@ type MonitorNetwork struct {
Up float64 `json:"up"`
Down float64 `json:"down"`
}
type MonitorGPU struct {
BaseModel
ProductName string `json:"productName"`
GPUUtil float64 `json:"gpuUtil"`
Temperature float64 `json:"temperature"`
PowerDraw float64 `json:"powerDraw"`
MaxPowerLimit float64 `json:"maxPowerLimit"`
MemUsed float64 `json:"memUsed"`
MemTotal float64 `json:"memTotal"`
FanSpeed int `json:"fanSpeed"`
Processes string `json:"processes"`
}
+8
View File
@@ -7,6 +7,14 @@ type Setting struct {
About string `json:"about"`
}
type CommonDescription struct {
ID string `json:"id"`
Type string `json:"type"`
DetailType string `json:"detailType"`
IsPinned bool `json:"isPinned"`
Description string `json:"description"`
}
type NodeInfo struct {
Scope string `json:"scope"`
BaseDir string `json:"baseDir"`
+5
View File
@@ -77,6 +77,11 @@ func WithByType(tp string) DBOption {
return g.Where("`type` = ?", tp)
}
}
func WithByDetailType(tp string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("`detail_type` = ?", tp)
}
}
func WithTypes(types []string) DBOption {
return func(db *gorm.DB) *gorm.DB {
+27
View File
@@ -5,21 +5,27 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/global"
"gorm.io/gorm"
)
type MonitorRepo struct{}
type IMonitorRepo interface {
GetBase(opts ...DBOption) ([]model.MonitorBase, error)
GetGPU(opts ...DBOption) ([]model.MonitorGPU, error)
GetIO(opts ...DBOption) ([]model.MonitorIO, error)
GetNetwork(opts ...DBOption) ([]model.MonitorNetwork, error)
CreateMonitorBase(model model.MonitorBase) error
BatchCreateMonitorGPU(list []model.MonitorGPU) error
BatchCreateMonitorIO(ioList []model.MonitorIO) error
BatchCreateMonitorNet(ioList []model.MonitorNetwork) error
DelMonitorBase(timeForDelete time.Time) error
DelMonitorGPU(timeForDelete time.Time) error
DelMonitorIO(timeForDelete time.Time) error
DelMonitorNet(timeForDelete time.Time) error
WithByProductName(name string) DBOption
}
func NewIMonitorRepo() IMonitorRepo {
@@ -53,10 +59,22 @@ func (u *MonitorRepo) GetNetwork(opts ...DBOption) ([]model.MonitorNetwork, erro
err := db.Find(&data).Error
return data, err
}
func (u *MonitorRepo) GetGPU(opts ...DBOption) ([]model.MonitorGPU, error) {
var data []model.MonitorGPU
db := global.GPUMonitorDB
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&data).Error
return data, err
}
func (u *MonitorRepo) CreateMonitorBase(model model.MonitorBase) error {
return global.MonitorDB.Create(&model).Error
}
func (s *MonitorRepo) BatchCreateMonitorGPU(list []model.MonitorGPU) error {
return global.GPUMonitorDB.CreateInBatches(&list, len(list)).Error
}
func (u *MonitorRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
}
@@ -72,3 +90,12 @@ func (u *MonitorRepo) DelMonitorIO(timeForDelete time.Time) error {
func (u *MonitorRepo) DelMonitorNet(timeForDelete time.Time) error {
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}
func (s *MonitorRepo) DelMonitorGPU(timeForDelete time.Time) error {
return global.GPUMonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorGPU{}).Error
}
func (s *MonitorRepo) WithByProductName(name string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("product_name = ?", name)
}
}
+40 -26
View File
@@ -2,7 +2,6 @@ package repo
import (
"errors"
"time"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/global"
@@ -19,13 +18,14 @@ type ISettingRepo interface {
Update(key, value string) error
WithByKey(key string) DBOption
CreateMonitorBase(model model.MonitorBase) error
BatchCreateMonitorIO(ioList []model.MonitorIO) error
BatchCreateMonitorNet(ioList []model.MonitorNetwork) error
DelMonitorBase(timeForDelete time.Time) error
DelMonitorIO(timeForDelete time.Time) error
DelMonitorNet(timeForDelete time.Time) error
UpdateOrCreate(key, value string) error
GetDescription(opts ...DBOption) (model.CommonDescription, error)
GetDescriptionList(opts ...DBOption) ([]model.CommonDescription, error)
CreateDescription(data *model.CommonDescription) error
UpdateDescription(id string, val map[string]interface{}) error
DelDescription(id string) error
WithByDescriptionID(id string) DBOption
}
func NewISettingRepo() ISettingRepo {
@@ -78,25 +78,6 @@ func (s *SettingRepo) Update(key, value string) error {
return global.DB.Model(&model.Setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error
}
func (s *SettingRepo) CreateMonitorBase(model model.MonitorBase) error {
return global.MonitorDB.Create(&model).Error
}
func (s *SettingRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
}
func (s *SettingRepo) BatchCreateMonitorNet(ioList []model.MonitorNetwork) error {
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
}
func (s *SettingRepo) DelMonitorBase(timeForDelete time.Time) error {
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
}
func (s *SettingRepo) DelMonitorIO(timeForDelete time.Time) error {
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
}
func (s *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}
func (s *SettingRepo) UpdateOrCreate(key, value string) error {
var setting model.Setting
result := global.DB.Where("key = ?", key).First(&setting)
@@ -108,3 +89,36 @@ func (s *SettingRepo) UpdateOrCreate(key, value string) error {
}
return global.DB.Model(&setting).UpdateColumn("value", value).Error
}
func (s *SettingRepo) GetDescriptionList(opts ...DBOption) ([]model.CommonDescription, error) {
var lists []model.CommonDescription
db := global.DB.Model(&model.CommonDescription{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&lists).Error
return lists, err
}
func (s *SettingRepo) GetDescription(opts ...DBOption) (model.CommonDescription, error) {
var data model.CommonDescription
db := global.DB.Model(&model.CommonDescription{})
for _, opt := range opts {
db = opt(db)
}
err := db.First(&data).Error
return data, err
}
func (s *SettingRepo) CreateDescription(data *model.CommonDescription) error {
return global.DB.Create(data).Error
}
func (s *SettingRepo) UpdateDescription(id string, val map[string]interface{}) error {
return global.DB.Model(&model.CommonDescription{}).Where("id = ?", id).Updates(val).Error
}
func (s *SettingRepo) DelDescription(id string) error {
return global.DB.Where("id = ?", id).Delete(&model.CommonDescription{}).Error
}
func (s *SettingRepo) WithByDescriptionID(id string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("id = ?", id)
}
}
+3 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/global"
alertUtil "github.com/1Panel-dev/1Panel/agent/utils/alert"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/psutil"
versionUtil "github.com/1Panel-dev/1Panel/agent/utils/version"
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
"github.com/shirou/gopsutil/v4/cpu"
@@ -352,7 +353,7 @@ func loadLoadInfo(alert dto.AlertDTO) {
return
}
var loadValue float64
CPUTotal, _ := cpu.Counts(true)
CPUTotal, _ := psutil.CPUInfo.GetLogicalCores(false)
switch alert.Cycle {
case 1:
loadValue = avgStat.Load1 / (float64(CPUTotal*2) * 0.75) * 100
@@ -839,7 +840,7 @@ func processSingleDisk(alert dto.AlertDTO) error {
}
func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) (bool, error) {
usageStat, err := disk.Usage(path)
usageStat, err := psutil.DISK.GetUsage(path, false)
if err != nil {
global.LOG.Errorf("error getting disk usage for %s, err: %v", path, err)
return false, err
+25 -30
View File
@@ -37,7 +37,7 @@ type AppService struct {
}
type IAppService interface {
PageApp(ctx *gin.Context, req request.AppSearch) (interface{}, error)
PageApp(ctx *gin.Context, req request.AppSearch) (*response.AppRes, error)
GetAppTags(ctx *gin.Context) ([]response.TagDTO, error)
GetApp(ctx *gin.Context, key string) (*response.AppDTO, error)
GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error)
@@ -46,13 +46,14 @@ type IAppService interface {
GetAppUpdate() (*response.AppUpdateRes, error)
GetAppDetailByID(id uint) (*response.AppDetailDTO, error)
SyncAppListFromLocal(taskID string)
GetAppIcon(appID uint) ([]byte, error)
}
func NewIAppService() IAppService {
return &AppService{}
}
func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{}, error) {
func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (*response.AppRes, error) {
var opts []repo.DBOption
opts = append(opts, appRepo.OrderByRecommend())
if req.Name != "" {
@@ -98,7 +99,7 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{
}
opts = append(opts, repo.WithByIDs(appIds))
}
var res response.AppRes
res := &response.AppRes{}
total, apps, err := appRepo.Page(req.Page, req.PageSize, opts...)
if err != nil {
@@ -120,12 +121,7 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{
ID: ap.ID,
Name: ap.Name,
Key: ap.Key,
Type: ap.Type,
Icon: ap.Icon,
Resource: ap.Resource,
Limit: ap.Limit,
Website: ap.Website,
Github: ap.Github,
GpuSupport: ap.GpuSupport,
Recommend: ap.Recommend,
Description: ap.GetDescription(ctx),
@@ -135,7 +131,9 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (interface{
if err != nil {
continue
}
appDTO.Tags = tags
for _, tag := range tags {
appDTO.Tags = append(appDTO.Tags, tag.Name)
}
if ap.Type == constant.RuntimePHP || ap.Type == constant.RuntimeGo || ap.Type == constant.RuntimeNode || ap.Type == constant.RuntimePython || ap.Type == constant.RuntimeJava || ap.Type == constant.RuntimeDotNet {
details, _ := appDetailRepo.GetBy(appDetailRepo.WithAppId(ap.ID))
var ids []uint
@@ -195,24 +193,7 @@ func (a AppService) GetApp(ctx *gin.Context, key string) (*response.AppDTO, erro
if err != nil {
return nil, err
}
var versionsRaw []string
hasLatest := false
latestVersion := ""
for _, detail := range details {
if strings.Contains(detail.Version, "latest") {
hasLatest = true
latestVersion = detail.Version
continue
}
if key == "openresty" && !common.CompareAppVersion(detail.Version, "1.27") {
continue
}
versionsRaw = append(versionsRaw, detail.Version)
}
appDTO.Versions = common.GetSortedVersions(versionsRaw)
if hasLatest {
appDTO.Versions = append([]string{latestVersion}, appDTO.Versions...)
}
appDTO.Versions = getAppVersions(key, details)
tags, err := getAppTags(app.ID, strings.ToLower(common.GetLang(ctx)))
if err != nil {
return nil, err
@@ -864,13 +845,15 @@ func getAppList() (*dto.AppList, error) {
return nil, err
}
listFile := filepath.Join(global.Dir.ResourceDir, "1panel.json")
content, err := os.ReadFile(listFile)
file, err := os.Open(listFile)
if err != nil {
return nil, err
}
if err = json.Unmarshal(content, list); err != nil {
defer file.Close()
if err = json.NewDecoder(file).Decode(list); err != nil {
return nil, err
}
return list, nil
}
@@ -1153,7 +1136,7 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
}, nil)
go func() {
if err = syncTask.Execute(); err != nil {
if err := syncTask.Execute(); err != nil {
_ = NewISettingService().Update("AppStoreLastModified", "0")
_ = NewISettingService().Update("AppStoreSyncStatus", constant.StatusError)
}
@@ -1161,3 +1144,15 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
return nil
}
func (a AppService) GetAppIcon(appID uint) ([]byte, error) {
app, err := appRepo.GetFirst(repo.WithByID(appID))
if err != nil {
return nil, err
}
iconBytes, err := base64.StdEncoding.DecodeString(app.Icon)
if err != nil {
return nil, err
}
return iconBytes, nil
}
+40 -4
View File
@@ -300,10 +300,11 @@ func createLink(ctx context.Context, installTask *task.Task, app model.App, appI
createMysql.Name = dbConfig.DbName
createMysql.Username = dbConfig.DbUser
createMysql.Database = database.Name
createMysql.Format = "utf8mb4"
createMysql.Format = dbConfig.Format
createMysql.Permission = "%"
createMysql.Password = dbConfig.Password
createMysql.From = database.From
createMysql.Collation = dbConfig.Collation
mysqldb, err := NewIMysqlService().Create(ctx, createMysql)
if err != nil {
return err
@@ -540,8 +541,18 @@ func handleUpgradeCompose(install model.AppInstall, detail model.AppDetail) (map
if !ok || oldValue == nil {
return nil, buserr.New("ErrFileParse")
}
oldValueMap := oldValue.(map[string]interface{})
oldServiceValue := oldValueMap[install.ServiceName].(map[string]interface{})
oldValueMap, ok := oldValue.(map[string]interface{})
if !ok {
return nil, buserr.New("ErrFileParse")
}
oldServiceValueInterface, ok := oldValueMap[install.ServiceName]
if !ok || oldServiceValueInterface == nil {
return nil, buserr.New("ErrFileParse")
}
oldServiceValue, ok := oldServiceValueInterface.(map[string]interface{})
if !ok {
return nil, buserr.New("ErrFileParse")
}
if oldServiceValue["deploy"] != nil {
serviceValue["deploy"] = oldServiceValue["deploy"]
}
@@ -1414,6 +1425,7 @@ func handleLocalApp(appDir string) (app *model.App, err error) {
app.Key = "local" + appDefine.Key
app.Architectures = strings.Join(appDefine.Architectures, ",")
app.GpuSupport = appDefine.GpuSupport
app.MemoryRequired = appDefine.MemoryRequired
app.Resource = constant.AppResourceLocal
app.Status = constant.AppNormal
@@ -1555,7 +1567,6 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
Message: installed.Message,
HttpPort: installed.HttpPort,
HttpsPort: installed.HttpsPort,
Icon: installed.App.Icon,
AppName: installed.App.Name,
AppKey: installed.App.Key,
AppType: installed.App.Type,
@@ -2163,3 +2174,28 @@ func isEditCompose(installed model.AppInstall) bool {
}
return false
}
func getAppVersions(key string, details []model.AppDetail) []string {
var (
versionsRaw []string
versions []string
)
hasLatest := false
latestVersion := ""
for _, detail := range details {
if key != "mssql" && strings.Contains(detail.Version, "latest") {
hasLatest = true
latestVersion = detail.Version
continue
}
if key == "openresty" && !common.CompareAppVersion(detail.Version, "1.27") {
continue
}
versionsRaw = append(versionsRaw, detail.Version)
}
versions = common.GetSortedVersions(versionsRaw)
if hasLatest {
versions = append([]string{latestVersion}, versions...)
}
return versions
}
+6 -9
View File
@@ -8,17 +8,14 @@ import (
"strings"
"time"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/buserr"
"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/buserr"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/files"
"github.com/1Panel-dev/1Panel/agent/utils/mysql/client"
@@ -94,7 +91,7 @@ func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint,
if parentTask != nil {
return itemHandler()
}
backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour)
backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 0, 3*time.Hour)
go func() {
if err := backupTask.Execute(); err != nil {
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
@@ -196,7 +193,7 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback
return recoverDatabase(parentTask)
}
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 3, time.Hour)
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 0, 3*time.Hour)
go func() {
_ = itemTask.Execute()
}()
+12 -4
View File
@@ -82,11 +82,11 @@ func handlePostgresqlBackup(db DatabaseHelper, parentTask *task.Task, recordID u
}
}
itemHandler := func() error { return doPostgresqlgBackup(db, targetDir, fileName, secret) }
itemHandler := func() error { return doPostgresqlgBackup(db, targetDir, fileName, secret, backupTask) }
if parentTask != nil {
return itemHandler()
}
backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 3, time.Hour)
backupTask.AddSubTaskWithOps(task.GetTaskName(itemName, task.TaskBackup, task.TaskScopeBackup), func(t *task.Task) error { return itemHandler() }, nil, 0, 3*time.Hour)
go func() {
if err := backupTask.Execute(); err != nil {
backupRepo.UpdateRecordByMap(recordID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
@@ -130,10 +130,12 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
if !isRollback {
rollbackFile := path.Join(global.Dir.TmpDir, fmt.Sprintf("database/%s/%s_%s.sql.gz", req.Type, req.DetailName, time.Now().Format(constant.DateTimeSlimLayout)))
if err := cli.Backup(client.BackupInfo{
Database: req.Name,
Name: req.DetailName,
TargetDir: path.Dir(rollbackFile),
FileName: path.Base(rollbackFile),
Task: t,
Timeout: 300,
}); err != nil {
return fmt.Errorf("backup postgresql db %s for rollback before recover failed, err: %v", req.DetailName, err)
@@ -142,9 +144,11 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
if !isOk {
global.LOG.Info("recover failed, start to rollback now")
if err := cli.Recover(client.RecoverInfo{
Database: req.Name,
Name: req.DetailName,
SourceFile: rollbackFile,
Task: t,
Timeout: 300,
}); err != nil {
global.LOG.Errorf("rollback postgresql db %s from %s failed, err: %v", req.DetailName, rollbackFile, err)
@@ -167,9 +171,11 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
t.LogWithStatus(i18n.GetMsgByKey("Decrypt"), err)
}
if err := cli.Recover(client.RecoverInfo{
Database: req.Name,
Name: req.DetailName,
SourceFile: req.File,
Username: dbInfo.Username,
Task: t,
Timeout: 300,
}); err != nil {
global.LOG.Errorf("recover postgresql db %s from %s failed, err: %v", req.DetailName, req.File, err)
@@ -182,24 +188,26 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
return recoverDatabase(parentTask)
}
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 3, time.Hour)
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 0, 3*time.Hour)
go func() {
_ = itemTask.Execute()
}()
return nil
}
func doPostgresqlgBackup(db DatabaseHelper, targetDir, fileName, secret string) error {
func doPostgresqlgBackup(db DatabaseHelper, targetDir, fileName, secret string, task *task.Task) error {
cli, err := LoadPostgresqlClientByFrom(db.Database)
if err != nil {
return err
}
defer cli.Close()
backupInfo := pgclient.BackupInfo{
Database: db.Database,
Name: db.Name,
TargetDir: targetDir,
FileName: fileName,
Task: task,
Timeout: 300,
}
if err := cli.Backup(backupInfo); err != nil {
+198 -165
View File
@@ -70,6 +70,7 @@ type IContainerService interface {
ContainerUpgrade(req dto.ContainerUpgrade) error
ContainerInfo(req dto.OperationWithName) (*dto.ContainerOperate, error)
ContainerListStats() ([]dto.ContainerListStats, error)
ContainerItemStats(req dto.OperationWithName) (dto.ContainerItemStats, error)
LoadResourceLimit() (*dto.ResourceLimit, error)
ContainerRename(req dto.ContainerRename) error
ContainerCommit(req dto.ContainerCommit) error
@@ -96,19 +97,12 @@ func NewIContainerService() IContainerService {
}
func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, error) {
var (
records []container.Summary
list []container.Summary
)
client, err := docker.NewDockerClient()
if err != nil {
return 0, nil, err
}
defer client.Close()
options := container.ListOptions{
All: true,
Size: true,
}
options := container.ListOptions{All: true}
if len(req.Filters) != 0 {
options.Filters = filters.NewArgs()
options.Filters.Add("label", req.Filters)
@@ -117,114 +111,32 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
if err != nil {
return 0, nil, err
}
if req.ExcludeAppStore {
for _, item := range containers {
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" {
continue
}
list = append(list, item)
}
} else {
list = containers
}
records := searchWithFilter(req, containers)
if len(req.Name) != 0 {
length, count := len(list), 0
for count < length {
if !strings.Contains(list[count].Names[0][1:], req.Name) && !strings.Contains(list[count].Image, req.Name) {
list = append(list[:count], list[(count+1):]...)
length--
} else {
count++
}
}
}
if req.State != "all" {
length, count := len(list), 0
for count < length {
if list[count].State != req.State {
list = append(list[:count], list[(count+1):]...)
length--
} else {
count++
}
}
}
switch req.OrderBy {
case "name":
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].Names[0][1:] < list[j].Names[0][1:]
}
return list[i].Names[0][1:] > list[j].Names[0][1:]
})
default:
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].Created < list[j].Created
}
return list[i].Created > list[j].Created
})
}
total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize
var backData []dto.ContainerInfo
total, start, end := len(records), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total {
records = make([]container.Summary, 0)
backData = make([]dto.ContainerInfo, 0)
} else {
if end >= total {
end = total
}
records = list[start:end]
backData = records[start:end]
}
backDatas := make([]dto.ContainerInfo, len(records))
for i := 0; i < len(records); i++ {
item := records[i]
IsFromCompose := false
if _, ok := item.Labels[composeProjectLabel]; ok {
IsFromCompose = true
}
IsFromApp := false
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" {
IsFromApp = true
}
exposePorts := transPortToStr(records[i].Ports)
info := dto.ContainerInfo{
ContainerID: item.ID,
CreateTime: time.Unix(item.Created, 0).Format(constant.DateTimeLayout),
Name: item.Names[0][1:],
ImageId: strings.Split(item.ImageID, ":")[1],
ImageName: item.Image,
State: item.State,
RunTime: item.Status,
Ports: exposePorts,
IsFromApp: IsFromApp,
IsFromCompose: IsFromCompose,
SizeRw: item.SizeRw,
SizeRootFs: item.SizeRootFs,
}
install, _ := appInstallRepo.GetFirst(appInstallRepo.WithContainerName(info.Name))
for i := 0; i < len(backData); i++ {
install, _ := appInstallRepo.GetFirst(appInstallRepo.WithContainerName(backData[i].Name))
if install.ID > 0 {
info.AppInstallName = install.Name
info.AppName = install.App.Name
backData[i].AppInstallName = install.Name
backData[i].AppName = install.App.Name
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(install.ID))
for _, website := range websites {
info.Websites = append(info.Websites, website.PrimaryDomain)
backData[i].Websites = append(backData[i].Websites, website.PrimaryDomain)
}
}
backDatas[i] = info
if item.NetworkSettings != nil && len(item.NetworkSettings.Networks) > 0 {
networks := make([]string, 0, len(item.NetworkSettings.Networks))
for key := range item.NetworkSettings.Networks {
networks = append(networks, item.NetworkSettings.Networks[key].IPAddress)
}
sort.Strings(networks)
backDatas[i].Network = networks
}
}
return int64(total), backDatas, nil
return int64(total), backData, nil
}
func (u *ContainerService) List() []dto.ContainerOptions {
@@ -287,13 +199,60 @@ func (u *ContainerService) LoadStatus() (dto.ContainerStatus, error) {
defer client.Close()
c := context.Background()
usage, err := client.DiskUsage(c, types.DiskUsageOptions{})
images, _ := client.ImageList(c, image.ListOptions{All: true})
data.ImageCount = len(images)
repo, _ := imageRepoRepo.List()
data.RepoCount = len(repo)
templates, _ := composeRepo.List()
data.ComposeTemplateCount = len(templates)
networks, _ := client.NetworkList(c, network.ListOptions{})
data.NetworkCount = len(networks)
volumes, _ := client.VolumeList(c, volume.ListOptions{})
data.VolumeCount = len(volumes.Volumes)
data.ComposeCount = loadComposeCount(client)
containers, _ := client.ContainerList(c, container.ListOptions{All: true})
data.ContainerCount = len(containers)
for _, item := range containers {
switch item.State {
case "created":
data.Created++
case "running":
data.Running++
case "paused":
data.Paused++
case "restarting":
data.Restarting++
case "dead":
data.Dead++
case "exited":
data.Exited++
case "removing":
data.Removing++
}
}
return data, nil
}
func (u *ContainerService) ContainerItemStats(req dto.OperationWithName) (dto.ContainerItemStats, error) {
var data dto.ContainerItemStats
client, err := docker.NewDockerClient()
if err != nil {
return data, err
}
if req.Name != "system" {
defer client.Close()
containerInfo, _, err := client.ContainerInspectWithRaw(context.Background(), req.Name, true)
if err != nil {
return data, err
}
data.SizeRw = *containerInfo.SizeRw
data.SizeRootFs = *containerInfo.SizeRootFs
return data, nil
}
data.ImageCount = len(usage.Images)
data.VolumeCount = len(usage.Volumes)
usage, err := client.DiskUsage(context.Background(), types.DiskUsageOptions{})
if err != nil {
return data, err
}
for _, item := range usage.Images {
data.ImageUsage += item.Size
if item.Containers < 1 {
@@ -315,34 +274,6 @@ func (u *ContainerService) LoadStatus() (dto.ContainerStatus, error) {
for _, item := range usage.BuildCache {
data.BuildCacheUsage += item.Size
}
repo, _ := imageRepoRepo.List()
data.RepoCount = len(repo)
templates, _ := composeRepo.List()
data.ComposeTemplateCount = len(templates)
networks, _ := client.NetworkList(c, network.ListOptions{})
data.NetworkCount = len(networks)
volumes, _ := client.VolumeList(c, volume.ListOptions{})
data.VolumeCount = len(volumes.Volumes)
data.ComposeCount = loadComposeCount(client)
data.ContainerCount = len(usage.Containers)
for _, item := range usage.Containers {
switch item.State {
case "created":
data.Created++
case "running":
data.Running++
case "paused":
data.Paused++
case "restarting":
data.Restarting++
case "dead":
data.Dead++
case "exited":
data.Exited++
case "removing":
data.Removing++
}
}
return data, nil
}
func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error) {
@@ -667,27 +598,27 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
data.Name = strings.ReplaceAll(oldContainer.Name, "/", "")
data.Image = oldContainer.Config.Image
if oldContainer.NetworkSettings != nil {
for network := range oldContainer.NetworkSettings.Networks {
data.Network = network
break
for net, val := range oldContainer.NetworkSettings.Networks {
netItem := dto.ContainerNetwork{
Network: net,
MacAddr: val.MacAddress,
}
if val.IPAMConfig != nil {
if netItem.Network != "bridge" {
netItem.Ipv4 = val.IPAMConfig.IPv4Address
netItem.Ipv6 = val.IPAMConfig.IPv6Address
}
} else {
if netItem.Network != "bridge" {
netItem.Ipv4 = val.IPAddress
}
}
data.Networks = append(data.Networks, netItem)
}
}
exposePorts, _ := loadPortByInspect(oldContainer.ID, client)
data.ExposedPorts = loadContainerPortForInfo(exposePorts)
networkSettings := oldContainer.NetworkSettings
bridgeNetworkSettings := networkSettings.Networks[data.Network]
if bridgeNetworkSettings.IPAMConfig != nil {
data.MacAddr = bridgeNetworkSettings.MacAddress
if data.Network != "bridge" {
data.Ipv4 = bridgeNetworkSettings.IPAMConfig.IPv4Address
data.Ipv6 = bridgeNetworkSettings.IPAMConfig.IPv6Address
}
} else {
if data.Network != "bridge" {
data.Ipv4 = bridgeNetworkSettings.IPAddress
}
}
data.Hostname = oldContainer.Config.Hostname
data.DNS = oldContainer.HostConfig.DNS
data.DomainName = oldContainer.Config.Domainname
@@ -1505,25 +1436,25 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *conta
config.User = req.User
config.WorkingDir = req.WorkingDir
if len(req.Network) != 0 {
switch req.Network {
case "host", "none", "bridge":
hostConf.NetworkMode = container.NetworkMode(req.Network)
}
if req.Ipv4 != "" || req.Ipv6 != "" {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {
IPAMConfig: &network.EndpointIPAMConfig{
IPv4Address: req.Ipv4,
IPv6Address: req.Ipv6,
}, MacAddress: req.MacAddr}}
} else {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
if len(req.Networks) != 0 {
networkConf.EndpointsConfig = make(map[string]*network.EndpointSettings)
for _, item := range req.Networks {
switch item.Network {
case "host", "none", "bridge":
hostConf.NetworkMode = container.NetworkMode(item.Network)
}
if item.Ipv4 != "" || item.Ipv6 != "" {
networkConf.EndpointsConfig[item.Network] = &network.EndpointSettings{
IPAMConfig: &network.EndpointIPAMConfig{
IPv4Address: item.Ipv4,
IPv6Address: item.Ipv6,
}, MacAddress: item.MacAddr}
} else {
networkConf.EndpointsConfig[item.Network] = &network.EndpointSettings{}
}
}
} else {
if req.Ipv4 != "" || req.Ipv6 != "" {
return nil, nil, nil, fmt.Errorf("please set up the network")
}
networkConf = network.NetworkingConfig{}
return nil, nil, nil, fmt.Errorf("please set up the network")
}
hostConf.Privileged = req.Privileged
@@ -1771,3 +1702,105 @@ func loadContainerPortForInfo(itemPorts []container.Port) []dto.PortHelper {
}
return exposedPorts
}
func searchWithFilter(req dto.PageContainer, containers []container.Summary) []dto.ContainerInfo {
var (
records []dto.ContainerInfo
list []container.Summary
)
if req.ExcludeAppStore {
for _, item := range containers {
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" {
continue
}
list = append(list, item)
}
} else {
list = containers
}
if len(req.Name) != 0 {
length, count := len(list), 0
for count < length {
if !strings.Contains(list[count].Names[0][1:], req.Name) && !strings.Contains(list[count].Image, req.Name) {
list = append(list[:count], list[(count+1):]...)
length--
} else {
count++
}
}
}
if req.State != "all" {
length, count := len(list), 0
for count < length {
if list[count].State != req.State {
list = append(list[:count], list[(count+1):]...)
length--
} else {
count++
}
}
}
switch req.OrderBy {
case "name":
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].Names[0][1:] < list[j].Names[0][1:]
}
return list[i].Names[0][1:] > list[j].Names[0][1:]
})
default:
sort.Slice(list, func(i, j int) bool {
if req.Order == constant.OrderAsc {
return list[i].Created < list[j].Created
}
return list[i].Created > list[j].Created
})
}
for _, item := range list {
IsFromCompose := false
if _, ok := item.Labels[composeProjectLabel]; ok {
IsFromCompose = true
}
IsFromApp := false
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" {
IsFromApp = true
}
exposePorts := transPortToStr(item.Ports)
info := dto.ContainerInfo{
ContainerID: item.ID,
CreateTime: time.Unix(item.Created, 0).Format(constant.DateTimeLayout),
Name: item.Names[0][1:],
Ports: exposePorts,
ImageId: strings.Split(item.ImageID, ":")[1],
ImageName: item.Image,
State: item.State,
RunTime: item.Status,
IsFromApp: IsFromApp,
IsFromCompose: IsFromCompose,
}
if item.NetworkSettings != nil && len(item.NetworkSettings.Networks) > 0 {
networks := make([]string, 0, len(item.NetworkSettings.Networks))
for key := range item.NetworkSettings.Networks {
networks = append(networks, item.NetworkSettings.Networks[key].IPAddress)
}
sort.Strings(networks)
info.Network = networks
}
records = append(records, info)
}
descriptions, _ := settingRepo.GetDescriptionList(repo.WithByType("container"))
for i := 0; i < len(records); i++ {
for _, desc := range descriptions {
if desc.ID == records[i].ContainerID {
records[i].Description = desc.Description
records[i].IsPinned = desc.IsPinned
}
}
}
sort.Slice(records, func(i, j int) bool {
return records[i].IsPinned && !records[j].IsPinned
})
return records
}
+3 -4
View File
@@ -203,14 +203,13 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
}
go func() {
taskItem.AddSubTask(i18n.GetMsgByKey("ComposeCreate"), func(t *task.Task) error {
cmd := getComposeCmd(req.Path, "up")
out, err := cmd.CombinedOutput()
taskItem.Log(i18n.GetWithName("ComposeCreateRes", string(out)))
err := compose.UpWithTask(req.Path, t)
t.LogWithStatus(i18n.GetMsgByKey("ComposeCreate"), err)
if err != nil {
_, _ = compose.Down(req.Path)
return err
}
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name, Path: req.Path})
_ = composeRepo.CreateRecord(&model.Compose{Name: strings.ToLower(req.Name), Path: req.Path})
return nil
}, nil)
_ = taskItem.Execute()
+3 -6
View File
@@ -117,10 +117,8 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
return err
}
defer client.Close()
var (
ipams []network.IPAMConfig
enableV6 bool
)
var ipams []network.IPAMConfig
if req.Ipv4 {
var itemIpam network.IPAMConfig
if len(req.AuxAddress) != 0 {
@@ -141,7 +139,6 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
ipams = append(ipams, itemIpam)
}
if req.Ipv6 {
enableV6 = true
var itemIpam network.IPAMConfig
if len(req.AuxAddress) != 0 {
itemIpam.AuxAddress = make(map[string]string)
@@ -162,7 +159,7 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
}
options := network.CreateOptions{
EnableIPv6: &enableV6,
EnableIPv6: &req.Ipv6,
Driver: req.Driver,
Options: stringsToMap(req.Options),
Labels: stringsToMap(req.Labels),
+1 -15
View File
@@ -5,7 +5,6 @@ import (
"sort"
"strings"
"time"
"unicode"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/buserr"
@@ -57,7 +56,7 @@ func (u *ContainerService) PageVolume(req dto.SearchWithPage) (int64, interface{
var volume dto.Volume
volume.Driver = item.Driver
volume.Mountpoint = item.Mountpoint
volume.Name = simplifyVolumeName(item.Name)
volume.Name = item.Name
for key, val := range item.Labels {
volume.Labels = append(volume.Labels, dto.VolumeOption{Key: key, Value: val})
}
@@ -143,16 +142,3 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreate) error {
}
return nil
}
func simplifyVolumeName(name string) string {
if len(name) != 64 {
return name
}
for _, char := range name {
if !unicode.Is(unicode.ASCII_Hex_Digit, char) {
return name
}
}
return name[:12]
}
+8 -8
View File
@@ -13,6 +13,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/app/task"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/app/dto"
@@ -21,7 +22,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/files"
"github.com/pkg/errors"
)
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, taskItem *task.Task) error {
@@ -32,7 +32,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t
}
accountMap := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
if !accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
}
for _, app := range apps {
retry := 0
@@ -90,7 +90,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
}
accountMap := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
if !accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
}
for _, web := range webs {
retry := 0
@@ -149,7 +149,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
}
accountMap := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
if !accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
}
for _, dbInfo := range dbs {
retry := 0
@@ -178,7 +178,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
}
}
} else {
if err := doPostgresqlgBackup(dbInfo, backupDir, record.FileName, cronjob.Secret); err != nil {
if err := doPostgresqlgBackup(dbInfo, backupDir, record.FileName, cronjob.Secret, taskItem); err != nil {
if retry < int(cronjob.RetryTimes) || !cronjob.IgnoreErr {
retry++
return err
@@ -217,7 +217,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.Time, taskItem *task.Task) error {
accountMap := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
if !accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
}
taskItem.AddSubTaskWithOps(task.GetTaskName(cronjob.SourceDir, task.TaskBackup, task.TaskScopeCronjob), func(task *task.Task) error {
fileName := fmt.Sprintf("%s.tar.gz", startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(2))
@@ -267,7 +267,7 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.Time, taskItem *task.Task) error {
accountMap := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
if !accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
}
taskItem.AddSubTaskWithOps(task.GetTaskName(i18n.GetMsgByKey("SystemLog"), task.TaskBackup, task.TaskScopeCronjob), func(task *task.Task) error {
nameItem := startTime.Format(constant.DateTimeSlimLayout) + common.RandStrAndNum(5)
@@ -303,7 +303,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, jobRecord model.JobRecords, taskItem *task.Task) error {
accountMap := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
if !accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
}
var record model.BackupRecord
record.Status = constant.StatusSuccess
+19 -13
View File
@@ -8,14 +8,13 @@ import (
"io"
"net/http"
"os"
"path"
pathUtils "path"
"path/filepath"
"strings"
"time"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/utils/alert_push"
"github.com/pkg/errors"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
@@ -147,7 +146,7 @@ func (u *CronjobService) handleShell(cronjob model.Cronjob, taskItem *task.Task)
if len(cronjob.ContainerName) != 0 {
scriptItem := cronjob.Script
if cronjob.ScriptMode == "select" {
scriptItem = path.Join("/tmp", path.Base(cronjob.Script))
scriptItem = pathUtils.Join("/tmp", pathUtils.Base(cronjob.Script))
if err := cmdMgr.Run("docker", "cp", cronjob.Script, cronjob.ContainerName+":"+scriptItem); err != nil {
return err
}
@@ -195,10 +194,17 @@ func (u *CronjobService) handleShell(cronjob model.Cronjob, taskItem *task.Task)
}
func (u *CronjobService) handleCurl(cronjob model.Cronjob, taskItem *task.Task) {
taskItem.AddSubTaskWithOps(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error {
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem))
return cmdMgr.Run("curl", cronjob.URL)
}, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
urls := strings.Split(cronjob.URL, ",")
for _, url := range urls {
if len(strings.TrimSpace(url)) == 0 {
continue
}
taskItem.AddSubTaskWithOps(i18n.GetWithName("HandleCurl", url), func(t *task.Task) error {
taskItem.LogStart(i18n.GetWithName("HandleCurl", url))
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem))
return cmdMgr.Run("curl", url)
}, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
}
}
func (u *CronjobService) handleNtpSync(cronjob model.Cronjob, taskItem *task.Task) {
@@ -245,11 +251,11 @@ func (u *CronjobService) handleCleanLog(cronjob model.Cronjob, taskItem *task.Ta
if appInstall.ID > 0 {
curStr := i18n.GetWithName("CleanLogByName", "OpenResty")
t.LogStart(curStr)
accessLogPath := path.Join(appInstall.GetPath(), "log", "access.log")
accessLogPath := pathUtils.Join(appInstall.GetPath(), "log", "access.log")
if err := os.Truncate(accessLogPath, 0); err != nil {
t.LogFailedWithErr(curStr, err)
}
errLogPath := path.Join(appInstall.GetPath(), "log", "error.log")
errLogPath := pathUtils.Join(appInstall.GetPath(), "log", "error.log")
if err := os.Truncate(errLogPath, 0); err != nil {
t.LogFailedWithErr(curStr, err)
}
@@ -267,8 +273,8 @@ func (u *CronjobService) handleSyncIpGroup(cronjob model.Cronjob, taskItem *task
if err != nil {
return err
}
ipGroupDir := path.Join(appInstall.GetPath(), "1pwaf", "data", "rules", "ip_group")
urlDir := path.Join(ipGroupDir, "ip_group_url")
ipGroupDir := pathUtils.Join(appInstall.GetPath(), "1pwaf", "data", "rules", "ip_group")
urlDir := pathUtils.Join(ipGroupDir, "ip_group_url")
urlsFiles, err := os.ReadDir(urlDir)
if err != nil {
@@ -332,7 +338,7 @@ func (u *CronjobService) handleSyncIpGroup(cronjob model.Cronjob, taskItem *task
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time, taskItem *task.Task) error {
clientMap := NewBackupClientMap([]string{fmt.Sprintf("%v", cronjob.DownloadAccountID)})
if !clientMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
return errors.New(i18n.GetMsgWithDetail("LoadBackupFailed", clientMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", clientMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].message))
}
taskItem.AddSubTaskWithOps(i18n.GetWithName("CutWebsiteLog", cronjob.Name), func(t *task.Task) error {
websites := loadWebsForJob(*cronjob)
@@ -464,7 +470,7 @@ func (u *CronjobService) removeExpiredLog(cronjob model.Cronjob) {
}
_ = cronjobRepo.DeleteRecord(repo.WithByID(records[i].ID))
_ = taskRepo.Delete(taskRepo.WithByID(records[i].TaskID))
_ = os.Remove(path.Join(global.CONF.Base.InstallDir, "1panel/log/task/Cronjob", records[i].TaskID+".log"))
_ = os.Remove(pathUtils.Join(global.CONF.Base.InstallDir, "1panel/log/task/Cronjob", records[i].TaskID+".log"))
}
}
+85 -55
View File
@@ -1,6 +1,7 @@
package service
import (
"cmp"
"context"
"encoding/json"
"fmt"
@@ -23,10 +24,9 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/controller"
"github.com/1Panel-dev/1Panel/agent/utils/copier"
"github.com/1Panel-dev/1Panel/agent/utils/psutil"
"github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/disk"
"github.com/shirou/gopsutil/v4/host"
"github.com/shirou/gopsutil/v4/load"
"github.com/shirou/gopsutil/v4/mem"
"github.com/shirou/gopsutil/v4/net"
@@ -39,6 +39,8 @@ type IDashboardService interface {
LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error)
LoadCurrentInfoForNode() *dto.NodeCurrent
LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent
LoadTopCPU() []dto.Process
LoadTopMem() []dto.Process
LoadQuickOptions() []dto.QuickJump
ChangeQuick(req dto.ChangeQuicks) error
@@ -77,7 +79,7 @@ func (u *DashboardService) Restart(operation string) error {
func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
var baseInfo dto.OsInfo
hostInfo, err := host.Info()
hostInfo, err := psutil.HOST.GetHostInfo(false)
if err != nil {
return nil, err
}
@@ -86,8 +88,9 @@ func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
baseInfo.PlatformFamily = hostInfo.PlatformFamily
baseInfo.KernelArch = hostInfo.KernelArch
baseInfo.KernelVersion = hostInfo.KernelVersion
baseInfo.PrettyDistro = psutil.HOST.GetDistro()
diskInfo, err := disk.Usage(global.Dir.BaseDir)
diskInfo, err := psutil.DISK.GetUsage(global.Dir.BaseDir, false)
if err == nil {
baseInfo.DiskSize = int64(diskInfo.Free)
}
@@ -104,12 +107,17 @@ func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
func (u *DashboardService) LoadCurrentInfoForNode() *dto.NodeCurrent {
var currentInfo dto.NodeCurrent
currentInfo.CPUTotal, _ = cpu.Counts(true)
totalPercent, _ := cpu.Percent(100*time.Millisecond, false)
if len(totalPercent) == 1 {
currentInfo.CPUUsedPercent = totalPercent[0]
currentInfo.CPUUsed = currentInfo.CPUUsedPercent * 0.01 * float64(currentInfo.CPUTotal)
currentInfo.CPUTotal, _ = psutil.CPUInfo.GetLogicalCores(false)
cpuUsedPercent, perCore, cpuDetailedPercent := psutil.CPU.GetCPUUsage()
if len(perCore) == 0 {
currentInfo.CPUTotal = psutil.CPU.NumCPU()
} else {
currentInfo.CPUTotal = len(perCore)
}
currentInfo.CPUUsedPercent = cpuUsedPercent
currentInfo.CPUUsed = cpuUsedPercent * 0.01 * float64(currentInfo.CPUTotal)
currentInfo.CPUDetailedPercent = cpuDetailedPercent
loadInfo, _ := load.Avg()
currentInfo.Load1 = loadInfo.Load1
@@ -134,38 +142,39 @@ func (u *DashboardService) LoadCurrentInfoForNode() *dto.NodeCurrent {
func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error) {
var baseInfo dto.DashboardBase
hostInfo, err := host.Info()
hostInfo, err := psutil.HOST.GetHostInfo(false)
if err != nil {
return nil, err
}
baseInfo.Hostname = hostInfo.Hostname
baseInfo.OS = hostInfo.OS
baseInfo.Platform = hostInfo.Platform
baseInfo.PlatformFamily = hostInfo.PlatformFamily
baseInfo.PlatformVersion = hostInfo.PlatformVersion
baseInfo.KernelArch = hostInfo.KernelArch
baseInfo.KernelVersion = hostInfo.KernelVersion
ss, _ := json.Marshal(hostInfo)
baseInfo.VirtualizationSystem = string(ss)
baseInfo.IpV4Addr = loadOutboundIP()
httpProxy := os.Getenv("http_proxy")
if httpProxy == "" {
httpProxy = os.Getenv("HTTP_PROXY")
baseInfo = dto.DashboardBase{
Hostname: hostInfo.Hostname,
OS: hostInfo.OS,
Platform: hostInfo.Platform,
PlatformFamily: hostInfo.PlatformFamily,
PlatformVersion: hostInfo.PlatformVersion,
PrettyDistro: psutil.HOST.GetDistro(),
KernelArch: hostInfo.KernelArch,
KernelVersion: hostInfo.KernelVersion,
VirtualizationSystem: string(ss),
IpV4Addr: loadOutboundIP(),
SystemProxy: "noProxy",
}
if httpProxy != "" {
baseInfo.SystemProxy = httpProxy
if proxy := cmp.Or(os.Getenv("http_proxy"), os.Getenv("HTTP_PROXY")); proxy != "" {
baseInfo.SystemProxy = proxy
}
baseInfo.SystemProxy = "noProxy"
loadQuickJump(&baseInfo)
cpuInfo, err := cpu.Info()
if err == nil {
cpuInfo, err := psutil.CPUInfo.GetCPUInfo(false)
if err == nil && len(cpuInfo) > 0 {
baseInfo.CPUModelName = cpuInfo[0].ModelName
}
baseInfo.CPUCores, _ = cpu.Counts(false)
baseInfo.CPULogicalCores, _ = cpu.Counts(true)
baseInfo.CPUCores, _ = psutil.CPUInfo.GetPhysicalCores(false)
baseInfo.CPULogicalCores, _ = psutil.CPUInfo.GetLogicalCores(false)
baseInfo.CPUMhz = cpuInfo[0].Mhz
baseInfo.CurrentInfo = *u.LoadCurrentInfo(ioOption, netOption)
return &baseInfo, nil
@@ -173,18 +182,22 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent {
var currentInfo dto.DashboardCurrent
hostInfo, _ := host.Info()
hostInfo, _ := psutil.HOST.GetHostInfo(false)
currentInfo.Uptime = hostInfo.Uptime
currentInfo.TimeSinceUptime = time.Now().Add(-time.Duration(hostInfo.Uptime) * time.Second).Format(constant.DateTimeLayout)
currentInfo.TimeSinceUptime = time.Unix(int64(hostInfo.BootTime), 0).Format(constant.DateTimeLayout)
currentInfo.Procs = hostInfo.Procs
currentInfo.CPUTotal, _ = psutil.CPUInfo.GetLogicalCores(false)
currentInfo.CPUTotal, _ = cpu.Counts(true)
totalPercent, _ := cpu.Percent(100*time.Millisecond, false)
if len(totalPercent) == 1 {
currentInfo.CPUUsedPercent = totalPercent[0]
currentInfo.CPUUsed = currentInfo.CPUUsedPercent * 0.01 * float64(currentInfo.CPUTotal)
cpuUsedPercent, perCore, cpuDetailedPercent := psutil.CPU.GetCPUUsage()
if len(perCore) == 0 {
currentInfo.CPUTotal = psutil.CPU.NumCPU()
} else {
currentInfo.CPUTotal = len(perCore)
}
currentInfo.CPUPercent, _ = cpu.Percent(100*time.Millisecond, true)
currentInfo.CPUPercent = perCore
currentInfo.CPUUsedPercent = cpuUsedPercent
currentInfo.CPUUsed = cpuUsedPercent * 0.01 * float64(currentInfo.CPUTotal)
currentInfo.CPUDetailedPercent = cpuDetailedPercent
loadInfo, _ := load.Avg()
currentInfo.Load1 = loadInfo.Load1
@@ -211,9 +224,6 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
currentInfo.GPUData = loadGPUInfo()
currentInfo.XPUData = loadXpuInfo()
currentInfo.TopCPUItems = loadTopCPU()
currentInfo.TopMemItems = loadTopMem()
if ioOption == "all" {
diskInfo, _ := disk.IOCounters()
for _, state := range diskInfo {
@@ -246,6 +256,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
if state.Name == netOption {
currentInfo.NetBytesSent = state.BytesSent
currentInfo.NetBytesRecv = state.BytesRecv
break
}
}
}
@@ -254,6 +265,14 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
return &currentInfo
}
func (u *DashboardService) LoadTopCPU() []dto.Process {
return loadTopCPU()
}
func (u *DashboardService) LoadTopMem() []dto.Process {
return loadTopMem()
}
func (u *DashboardService) LoadAppLauncher(ctx *gin.Context) ([]dto.AppLauncher, error) {
var data []dto.AppLauncher
appInstalls, err := appInstallRepo.ListBy(context.Background())
@@ -455,41 +474,52 @@ func loadDiskInfo() []dto.DiskInfo {
)
wg.Add(len(mounts))
for i := 0; i < len(mounts); i++ {
go func(timeoutCh <-chan time.Time, mount diskInfo) {
go func(mount diskInfo) {
defer wg.Done()
var itemData dto.DiskInfo
itemData.Path = mount.Mount
itemData.Type = mount.Type
itemData.Device = mount.Device
type diskResult struct {
state *disk.UsageStat
err error
}
resultCh := make(chan diskResult, 1)
go func() {
state, err := psutil.DISK.GetUsage(mount.Mount, false)
resultCh <- diskResult{state: state, err: err}
}()
select {
case <-timeoutCh:
case <-time.After(5 * time.Second):
mu.Lock()
datas = append(datas, itemData)
mu.Unlock()
global.LOG.Errorf("load disk info from %s failed, err: timeout", mount.Mount)
default:
state, err := disk.Usage(mount.Mount)
if err != nil {
case result := <-resultCh:
if result.err != nil {
mu.Lock()
datas = append(datas, itemData)
mu.Unlock()
global.LOG.Errorf("load disk info from %s failed, err: %v", mount.Mount, err)
global.LOG.Errorf("load disk info from %s failed, err: %v", mount.Mount, result.err)
return
}
itemData.Total = state.Total
itemData.Free = state.Free
itemData.Used = state.Used
itemData.UsedPercent = state.UsedPercent
itemData.InodesTotal = state.InodesTotal
itemData.InodesUsed = state.InodesUsed
itemData.InodesFree = state.InodesFree
itemData.InodesUsedPercent = state.InodesUsedPercent
itemData.Total = result.state.Total
itemData.Free = result.state.Free
itemData.Used = result.state.Used
itemData.UsedPercent = result.state.UsedPercent
itemData.InodesTotal = result.state.InodesTotal
itemData.InodesUsed = result.state.InodesUsed
itemData.InodesFree = result.state.InodesFree
itemData.InodesUsedPercent = result.state.InodesUsedPercent
mu.Lock()
datas = append(datas, itemData)
mu.Unlock()
}
}(time.After(5*time.Second), mounts[i])
}(mounts[i])
}
wg.Wait()
+15 -1
View File
@@ -5,8 +5,10 @@ import (
"fmt"
"os"
"path"
"strings"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
@@ -51,7 +53,14 @@ func (u *DBCommonService) LoadDatabaseFile(req dto.OperationWithNameAndType) (st
case "mariadb-conf":
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/mariadb/%s/conf/my.cnf", req.Name))
case "postgresql-conf":
database, err := databaseRepo.Get(repo.WithByName(req.Name))
if err != nil {
return "", err
}
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/postgresql/%s/data/postgresql.conf", req.Name))
if strings.HasPrefix(database.Version, "18.") {
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/postgresql/%s/data/18/docker/postgresql.conf", req.Name))
}
case "redis-conf":
filePath = path.Join(global.Dir.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
case "redis-cluster-conf":
@@ -76,8 +85,13 @@ func (u *DBCommonService) UpdateConfByFile(req dto.DBConfUpdateByFile) error {
switch req.Type {
case constant.AppMariaDB, constant.AppMysql, constant.AppMysqlCluster:
path = fmt.Sprintf("%s/%s/%s/conf/my.cnf", global.Dir.AppInstallDir, req.Type, app.Name)
case constant.AppPostgresql, constant.AppPostgresqlCluster:
case constant.AppPostgresqlCluster:
path = fmt.Sprintf("%s/%s/%s/data/postgresql.conf", global.Dir.AppInstallDir, req.Type, app.Name)
case constant.AppPostgresql:
path = fmt.Sprintf("%s/%s/%s/data/postgresql.conf", global.Dir.AppInstallDir, req.Type, app.Name)
if strings.HasPrefix(app.Version, "18.") {
path = fmt.Sprintf("%s/%s/%s/data/18/docker/postgresql.conf", global.Dir.AppInstallDir, req.Type, app.Name)
}
case constant.AppRedis, constant.AppRedisCluster:
path = fmt.Sprintf("%s/%s/%s/conf/redis.conf", global.Dir.AppInstallDir, req.Type, app.Name)
}
+17 -2
View File
@@ -23,8 +23,8 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/compose"
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
"github.com/1Panel-dev/1Panel/agent/utils/mysql"
"github.com/1Panel-dev/1Panel/agent/utils/re"
"github.com/1Panel-dev/1Panel/agent/utils/mysql/client"
"github.com/1Panel-dev/1Panel/agent/utils/re"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
@@ -45,6 +45,7 @@ type IMysqlService interface {
DeleteCheck(req dto.MysqlDBDeleteCheck) ([]dto.DBResource, error)
Delete(ctx context.Context, req dto.MysqlDBDelete) error
LoadFormatOption(req dto.OperationWithName) []dto.MysqlFormatCollationOption
LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error)
LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error)
LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error)
@@ -99,7 +100,7 @@ func (u *MysqlService) ListDBOption() ([]dto.MysqlOption, error) {
}
func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) {
if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format, req.Permission) {
if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format, req.Collation, req.Permission) {
return nil, buserr.New("ErrCmdIllegal")
}
@@ -126,6 +127,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
if err := cli.Create(client.CreateInfo{
Name: req.Name,
Format: req.Format,
Collation: req.Collation,
Username: req.Username,
Password: req.Password,
Permission: req.Permission,
@@ -584,6 +586,19 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
return &info, nil
}
func (u *MysqlService) LoadFormatOption(req dto.OperationWithName) []dto.MysqlFormatCollationOption {
defaultList := []dto.MysqlFormatCollationOption{{Format: "utf8mb4"}, {Format: "utf8mb3"}, {Format: "gbk"}, {Format: "big5"}}
client, _, err := LoadMysqlClientByFrom(req.Name)
if err != nil {
return defaultList
}
options, err := client.LoadFormatCollation(3)
if err != nil {
return defaultList
}
return options
}
func executeSqlForMaps(containerName, dbType, password, command string) (map[string]string, error) {
if dbType == "mysql-cluster" {
dbType = "mysql"
+3 -3
View File
@@ -80,9 +80,9 @@ func (u *RedisService) CheckHasCli() bool {
func (u *RedisService) InstallCli() error {
item := dto.ContainerOperate{
Name: "1Panel-redis-cli-tools",
Image: "redis:7.4.4",
Network: "1panel-network",
Name: "1Panel-redis-cli-tools",
Image: "redis:7.4.4",
Networks: []dto.ContainerNetwork{{Network: "1panel-network"}},
}
return NewIContainerService().ContainerCreate(item, false)
}
+2
View File
@@ -20,6 +20,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/controller"
"github.com/1Panel-dev/1Panel/agent/utils/ntp"
"github.com/1Panel-dev/1Panel/agent/utils/psutil"
"github.com/shirou/gopsutil/v4/mem"
)
@@ -134,6 +135,7 @@ func (u *DeviceService) Update(key, value string) error {
if err := cmd.RunDefaultBashCf("%s hostnamectl set-hostname %s", cmd.SudoHandleCmd(), value); err != nil {
return err
}
_, _ = psutil.HOST.GetHostInfo(true)
case "Ntp", "LocalTime":
if cmd.CheckIllegal(value) {
return buserr.New("ErrCmdIllegal")
+2
View File
@@ -647,11 +647,13 @@ func dropTaskLog(logDir string) {
if err == nil {
_ = xpackDB.Table("tampers").Where("task_id != ?", "").Select("task_id").Find(&usedTasks).Error
}
defer common.CloseDB(xpackDB)
case "System":
xpackDB, err := common.LoadDBConnByPathWithErr(path.Join(global.CONF.Base.InstallDir, "1panel/db/xpack.db"), "xpack.db")
if err == nil {
_ = xpackDB.Model("nodes").Where("task_id != ?", "").Select("task_id").Find(&usedTasks).Error
}
defer common.CloseDB(xpackDB)
default:
dropFileOrDir(logDir)
_ = taskRepo.Delete(repo.WithByType(taskType))
+11 -12
View File
@@ -32,20 +32,19 @@ func (s *DiskService) GetCompleteDiskInfo() (*response.CompleteDiskInfo, error)
output, err := cmd.RunDefaultWithStdoutBashC("lsblk -J -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,MODEL,SERIAL,TRAN,ROTA")
if err == nil {
diskInfos, err = parseLsblkJsonOutput(output)
if err != nil {
return nil, fmt.Errorf("failed to parse lsblk output: %v", err)
}
} else {
output, err = cmd.RunDefaultWithStdoutBashC("lsblk -P -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,MODEL,SERIAL,TRAN,ROTA")
if err != nil {
return nil, fmt.Errorf("failed to run lsblk command: %v", err)
}
diskInfos, err = parseLsblkOutput(output)
if err != nil {
return nil, fmt.Errorf("failed to parse lsblk output: %v", err)
if err == nil {
result := organizeDiskInfo(diskInfos)
return &result, nil
}
}
output, err = cmd.RunDefaultWithStdoutBashC("lsblk -P -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,MODEL,SERIAL,TRAN,ROTA")
if err != nil {
return nil, fmt.Errorf("failed to run lsblk command: %v", err)
}
diskInfos, err = parseLsblkOutput(output)
if err != nil {
return nil, fmt.Errorf("failed to parse lsblk output: %v", err)
}
result := organizeDiskInfo(diskInfos)
return &result, nil
}
+8 -5
View File
@@ -5,10 +5,6 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/agent/app/task"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/utils/convert"
"github.com/1Panel-dev/1Panel/agent/utils/ini_conf"
"io"
"io/fs"
"os"
@@ -21,6 +17,11 @@ import (
"time"
"unicode/utf8"
"github.com/1Panel-dev/1Panel/agent/app/task"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/utils/convert"
"github.com/1Panel-dev/1Panel/agent/utils/ini_conf"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/jinzhu/copier"
"golang.org/x/text/encoding"
@@ -241,6 +242,8 @@ func (f *FileService) Create(op request.FileCreate) error {
if err := fo.LinkFile(op.LinkPath, op.Path, op.IsSymlink); err != nil {
return err
}
handleDefaultOwn(op.Path)
return nil
}
if err := fo.CreateFileWithMode(op.Path, fs.FileMode(mode)); err != nil {
return err
@@ -591,7 +594,7 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
scope string
logFileRes *dto.LogFileRes
)
if stat.Size() > 500*1024*1024 {
if stat.Size() > files.MaxReadFileSize {
lines, err = files.TailFromEnd(logFilePath, req.PageSize)
isEndOfFile = true
scope = "tail"
+1 -94
View File
@@ -68,7 +68,7 @@ func (u *FirewallService) LoadBaseInfo(tab string) (dto.FirewallBaseInfo, error)
go func() {
defer wg.Done()
baseInfo.IsActive, _ = client.Status()
baseInfo.IsInit, baseInfo.IsBind = loadInitStatus(baseInfo.Name, tab)
baseInfo.IsInit, baseInfo.IsBind = iptables.LoadInitStatus(baseInfo.Name, tab)
}()
wg.Wait()
return baseInfo, nil
@@ -826,96 +826,3 @@ func checkPortUsed(ports, proto string, apps []portOfApp) string {
}
return ""
}
func loadInitStatus(clientName, tab string) (bool, bool) {
if clientName == "firewalld" {
return true, true
}
if clientName == "ufw" && tab != "forward" {
return true, true
}
switch tab {
case "base":
if isExist, _ := iptables.CheckChainExist(iptables.FilterTab, iptables.Chain1PanelBasicBefore); !isExist {
return false, false
}
if exist := iptables.CheckRuleExist(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.IoRuleIn); !exist {
return false, false
}
if exist := iptables.CheckRuleExist(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.EstablishedRule); !exist {
return false, false
}
if exist, _ := iptables.CheckChainExist(iptables.FilterTab, iptables.Chain1PanelBasic); !exist {
return false, false
}
if exist, _ := iptables.CheckChainExist(iptables.FilterTab, iptables.Chain1PanelBasicAfter); !exist {
return false, false
}
if exist := iptables.CheckRuleExist(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.DropAllTcp); !exist {
return false, false
}
if exist := iptables.CheckRuleExist(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.DropAllUdp); !exist {
return false, false
}
if bind, _ := iptables.CheckChainBind(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicBefore); !bind {
return true, false
}
if bind, _ := iptables.CheckChainBind(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasic); !bind {
return true, false
}
if bind, _ := iptables.CheckChainBind(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter); !bind {
return true, false
}
return true, true
case "advance":
isExist, _ := iptables.CheckChainExist(iptables.FilterTab, iptables.Chain1PanelInput)
if !isExist {
return false, false
}
isExist, _ = iptables.CheckChainExist(iptables.FilterTab, iptables.Chain1PanelOutput)
if !isExist {
return false, false
}
isBind, _ := iptables.CheckChainBind(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelInput)
if !isBind {
return true, false
}
isBind, _ = iptables.CheckChainBind(iptables.FilterTab, iptables.ChainOutput, iptables.Chain1PanelOutput)
return true, isBind
case "forward":
stdout, err := cmd.RunDefaultWithStdoutBashC("cat /proc/sys/net/ipv4/ip_forward")
if err != nil {
global.LOG.Errorf("check /proc/sys/net/ipv4/ip_forward failed, err: %v", err)
return false, false
}
if strings.TrimSpace(stdout) == "0" {
return false, false
}
exist, _ := iptables.CheckChainExist(iptables.NatTab, iptables.Chain1PanelPreRouting)
if !exist {
return false, false
}
exist, _ = iptables.CheckChainExist(iptables.NatTab, iptables.Chain1PanelPostRouting)
if !exist {
return false, false
}
exist, _ = iptables.CheckChainExist(iptables.FilterTab, iptables.Chain1PanelForward)
if !exist {
return false, false
}
isBind, _ := iptables.CheckChainBind(iptables.NatTab, "PREROUTING", iptables.Chain1PanelPreRouting)
if !isBind {
return false, false
}
isBind, _ = iptables.CheckChainBind(iptables.NatTab, "POSTROUTING", iptables.Chain1PanelPostRouting)
if !isBind {
return false, false
}
isBind, _ = iptables.CheckChainBind(iptables.FilterTab, "FORWARD", iptables.Chain1PanelForward)
return true, isBind
default:
return false, false
}
}
+12
View File
@@ -128,6 +128,18 @@ func (u *ImageService) Page(req dto.PageImage) (int64, interface{}, error) {
})
}
imageDescriptions, _ := settingRepo.GetDescriptionList(repo.WithByType("image"))
for i := 0; i < len(list); i++ {
for _, desc := range imageDescriptions {
if "sha256:"+desc.ID == records[i].ID {
records[i].Description = desc.Description
records[i].IsPinned = desc.IsPinned
}
}
}
sort.Slice(records, func(i, j int) bool {
return records[i].IsPinned && !records[j].IsPinned
})
total, start, end := len(records), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total {
backDatas = make([]dto.ImageInfo, 0)
+61 -14
View File
@@ -8,6 +8,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
"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"
@@ -16,7 +17,7 @@ import (
type IIptablesService interface {
Search(req dto.SearchPageWithType) (int64, interface{}, error)
OperateRule(req dto.IptablesRuleOp) error
OperateRule(req dto.IptablesRuleOp, withSave bool) error
BatchOperate(req dto.IptablesBatchOperate) error
LoadChainStatus(req dto.OperationWithName) dto.IptablesChainStatus
@@ -63,7 +64,7 @@ func (s *IptablesService) Search(req dto.SearchPageWithType) (int64, interface{}
return int64(total), records, nil
}
func (s *IptablesService) OperateRule(req dto.IptablesRuleOp) error {
func (s *IptablesService) OperateRule(req dto.IptablesRuleOp, withSave bool) error {
action := "ACCEPT"
if req.Strategy == "drop" {
action = "DROP"
@@ -122,6 +123,9 @@ func (s *IptablesService) OperateRule(req dto.IptablesRuleOp) error {
}
}
if !withSave {
return nil
}
if err := iptables.SaveRulesToFile(iptables.FilterTab, req.Chain, name); err != nil {
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
}
@@ -129,11 +133,23 @@ func (s *IptablesService) OperateRule(req dto.IptablesRuleOp) error {
}
func (s *IptablesService) BatchOperate(req dto.IptablesBatchOperate) error {
if len(req.Rules) == 0 {
return errors.New("no rules to operate")
}
for _, rule := range req.Rules {
if err := s.OperateRule(rule); err != nil {
if err := s.OperateRule(rule, false); err != nil {
return err
}
}
chain := iptables.Chain1PanelInput
fileName := iptables.InputFileName
if req.Rules[0].Chain == iptables.Chain1PanelOutput {
chain = iptables.Chain1PanelOutput
fileName = iptables.OutputFileName
}
if err := iptables.SaveRulesToFile(iptables.FilterTab, chain, fileName); err != nil {
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
}
return nil
}
@@ -168,9 +184,20 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error {
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter, 3); err != nil {
return err
}
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.BasicBeforeFileName); err != nil {
return err
}
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.BasicAfterFileName); err != nil {
return err
}
_ = settingRepo.Update("IptablesStatus", constant.StatusEnable)
return nil
case "init-forward":
return client.EnableIptablesForward()
if err := client.EnableIptablesForward(); err != nil {
return err
}
_ = settingRepo.Update("IptablesForwardStatus", constant.StatusEnable)
return nil
case "init-advance":
if err := iptables.AddChain(iptables.FilterTab, iptables.Chain1PanelInput); err != nil {
return err
@@ -185,6 +212,8 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error {
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelInput, number); err != nil {
return err
}
_ = settingRepo.Update("IptablesInputStatus", constant.StatusEnable)
_ = settingRepo.Update("IptablesOutputStatus", constant.StatusEnable)
return nil
case "bind-base":
if err := initPreRules(); err != nil {
@@ -199,6 +228,7 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error {
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter, 3); err != nil {
return err
}
_ = settingRepo.Update("IptablesStatus", constant.StatusEnable)
return nil
case "unbind-base":
if err := iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter); err != nil {
@@ -210,16 +240,29 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error {
if err := iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasic); err != nil {
return err
}
_ = settingRepo.Update("IptablesStatus", constant.StatusDisable)
return nil
case "bind":
if err := iptables.BindChain(iptables.FilterTab, targetChain, req.Name, loadBindNumber(req.Name)); err != nil {
return err
}
if req.Name == iptables.Chain1PanelInput {
_ = settingRepo.Update("IptablesInputStatus", constant.StatusEnable)
}
if req.Name == iptables.Chain1PanelOutput {
_ = settingRepo.Update("IptablesOutputStatus", constant.StatusEnable)
}
return nil
case "unbind":
if err := iptables.UnbindChain(iptables.FilterTab, targetChain, req.Name); err != nil {
return err
}
if req.Name == iptables.Chain1PanelInput {
_ = settingRepo.Update("IptablesInputStatus", constant.StatusDisable)
}
if req.Name == iptables.Chain1PanelOutput {
_ = settingRepo.Update("IptablesOutputStatus", constant.StatusDisable)
}
return nil
}
return nil
@@ -310,16 +353,7 @@ func initPreRules() error {
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.EstablishedRule); err != nil {
return err
}
panelPort := ""
if !global.IsMaster {
panelPort = global.CONF.Base.Port
} else {
var portSetting model.Setting
_ = global.CoreDB.Where("key = ?", "ServerPort").First(&portSetting).Error
if len(portSetting.Value) != 0 {
panelPort = portSetting.Value
}
}
panelPort := LoadPanelPort()
if len(panelPort) == 0 {
return errors.New("find 1panel service port failed")
}
@@ -337,3 +371,16 @@ func initPreRules() error {
}
return nil
}
func LoadPanelPort() string {
if !global.IsMaster {
return global.CONF.Base.Port
} else {
var portSetting model.Setting
_ = global.CoreDB.Where("key = ?", "ServerPort").First(&portSetting).Error
if len(portSetting.Value) != 0 {
return portSetting.Value
}
}
return ""
}
+177 -7
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"sort"
"strconv"
"strings"
"time"
"github.com/1Panel-dev/1Panel/agent/app/repo"
@@ -15,7 +16,10 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/gpu"
"github.com/1Panel-dev/1Panel/agent/utils/ai_tools/xpu"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/psutil"
"github.com/robfig/cron/v3"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/disk"
@@ -35,6 +39,8 @@ var monitorCancel context.CancelFunc
type IMonitorService interface {
Run()
LoadMonitorData(req dto.MonitorSearch) ([]dto.MonitorData, error)
LoadGPUOptions() dto.MonitorGPUOptions
LoadGPUMonitorData(req dto.MonitorGPUSearch) (dto.MonitorGPUData, error)
LoadSetting() (*dto.MonitorSetting, error)
UpdateSetting(key, value string) error
CleanData() error
@@ -113,6 +119,78 @@ func (m *MonitorService) LoadMonitorData(req dto.MonitorSearch) ([]dto.MonitorDa
return data, nil
}
func (m *MonitorService) LoadGPUOptions() dto.MonitorGPUOptions {
var data dto.MonitorGPUOptions
gpuExist, gpuClient := gpu.New()
xpuExist, xpuClient := xpu.New()
if !gpuExist && !xpuExist {
return data
}
if gpuExist {
data.GPUType = "gpu"
gpuInfo, err := gpuClient.LoadGpuInfo()
if err != nil || len(gpuInfo.GPUs) == 0 {
global.LOG.Error("Load GPU info failed or no GPU found, err: ", err)
return data
}
sort.Slice(gpuInfo.GPUs, func(i, j int) bool {
return gpuInfo.GPUs[i].Index < gpuInfo.GPUs[j].Index
})
for _, item := range gpuInfo.GPUs {
data.Options = append(data.Options, fmt.Sprintf("%d - %s", item.Index, item.ProductName))
}
return data
} else {
data.GPUType = "xpu"
var err error
data.Options, err = xpuClient.LoadDeviceList()
if err != nil || len(data.Options) == 0 {
global.LOG.Error("Load XPU info failed or no XPU found, err: ", err)
}
return data
}
}
func (m *MonitorService) LoadGPUMonitorData(req dto.MonitorGPUSearch) (dto.MonitorGPUData, error) {
loc, _ := time.LoadLocation(common.LoadTimeZoneByCmd())
req.StartTime = req.StartTime.In(loc)
req.EndTime = req.EndTime.In(loc)
var data dto.MonitorGPUData
gpuList, err := monitorRepo.GetGPU(repo.WithByCreatedAt(req.StartTime, req.EndTime), monitorRepo.WithByProductName(req.ProductName))
if err != nil {
return data, err
}
for _, gpu := range gpuList {
data.Date = append(data.Date, gpu.CreatedAt)
data.GPUValue = append(data.GPUValue, gpu.GPUUtil)
data.TemperatureValue = append(data.TemperatureValue, gpu.Temperature)
data.PowerUsed = append(data.PowerUsed, gpu.PowerDraw)
data.PowerTotal = append(data.PowerTotal, gpu.MaxPowerLimit)
if gpu.MaxPowerLimit != 0 {
data.PowerPercent = append(data.PowerPercent, gpu.PowerDraw/gpu.MaxPowerLimit*100)
} else {
data.PowerPercent = append(data.PowerPercent, float64(0))
}
data.MemoryTotal = append(data.MemoryTotal, gpu.MemTotal)
data.MemoryUsed = append(data.MemoryUsed, gpu.MemUsed)
if gpu.MemTotal != 0 {
data.MemoryPercent = append(data.MemoryPercent, gpu.MemUsed/gpu.MemTotal*100)
} else {
data.MemoryPercent = append(data.MemoryPercent, float64(0))
}
var process []dto.GPUProcess
if err := json.Unmarshal([]byte(gpu.Processes), &process); err == nil {
data.GPUProcesses = append(data.GPUProcesses, process)
} else {
data.GPUProcesses = append(data.GPUProcesses, []dto.GPUProcess{})
}
data.SpeedValue = append(data.SpeedValue, gpu.FanSpeed)
}
return data, nil
}
func (m *MonitorService) LoadSetting() (*dto.MonitorSetting, error) {
setting, err := settingRepo.GetList()
if err != nil {
@@ -174,10 +252,13 @@ func (m *MonitorService) CleanData() error {
if err := global.MonitorDB.Exec("DELETE FROM monitor_networks").Error; err != nil {
return err
}
_ = global.GPUMonitorDB.Exec("DELETE FROM monitor_gpus").Error
return nil
}
func (m *MonitorService) Run() {
saveGPUDataToDB()
saveXPUDataToDB()
var itemModel model.MonitorBase
totalPercent, _ := cpu.Percent(3*time.Second, false)
if len(totalPercent) == 1 {
@@ -190,7 +271,7 @@ func (m *MonitorService) Run() {
itemModel.TopCPU = string(topItemCPU)
}
}
cpuCount, _ := cpu.Counts(false)
cpuCount, _ := psutil.CPUInfo.GetPhysicalCores(false)
loadInfo, _ := load.Avg()
itemModel.CpuLoad1 = loadInfo.Load1
itemModel.CpuLoad5 = loadInfo.Load5
@@ -207,7 +288,7 @@ func (m *MonitorService) Run() {
}
}
if err := settingRepo.CreateMonitorBase(itemModel); err != nil {
if err := monitorRepo.CreateMonitorBase(itemModel); err != nil {
global.LOG.Errorf("Insert basic monitoring data failed, err: %v", err)
}
@@ -220,9 +301,9 @@ func (m *MonitorService) Run() {
}
storeDays, _ := strconv.Atoi(MonitorStoreDays.Value)
timeForDelete := time.Now().AddDate(0, 0, -storeDays)
_ = settingRepo.DelMonitorBase(timeForDelete)
_ = settingRepo.DelMonitorIO(timeForDelete)
_ = settingRepo.DelMonitorNet(timeForDelete)
_ = monitorRepo.DelMonitorBase(timeForDelete)
_ = monitorRepo.DelMonitorIO(timeForDelete)
_ = monitorRepo.DelMonitorNet(timeForDelete)
}
func (m *MonitorService) loadDiskIO() {
@@ -302,7 +383,7 @@ func (m *MonitorService) saveIODataToDB(ctx context.Context, interval float64) {
}
}
}
if err := settingRepo.BatchCreateMonitorIO(ioList); err != nil {
if err := monitorRepo.BatchCreateMonitorIO(ioList); err != nil {
global.LOG.Errorf("Insert io monitoring data failed, err: %v", err)
}
m.DiskIO <- ioStat2
@@ -341,7 +422,7 @@ func (m *MonitorService) saveNetDataToDB(ctx context.Context, interval float64)
}
}
if err := settingRepo.BatchCreateMonitorNet(netList); err != nil {
if err := monitorRepo.BatchCreateMonitorNet(netList); err != nil {
global.LOG.Errorf("Insert network monitoring data failed, err: %v", err)
}
m.NetIO <- netStat2
@@ -482,3 +563,92 @@ func StartMonitor(removeBefore bool, interval string) error {
return nil
}
func saveGPUDataToDB() {
exist, client := gpu.New()
if !exist {
return
}
gpuInfo, err := client.LoadGpuInfo()
if err != nil {
return
}
var list []model.MonitorGPU
for _, gpuItem := range gpuInfo.GPUs {
item := model.MonitorGPU{
ProductName: fmt.Sprintf("%d - %s", gpuItem.Index, gpuItem.ProductName),
GPUUtil: loadGPUInfoFloat(gpuItem.GPUUtil),
Temperature: loadGPUInfoFloat(gpuItem.Temperature),
PowerDraw: loadGPUInfoFloat(gpuItem.PowerDraw),
MaxPowerLimit: loadGPUInfoFloat(gpuItem.MaxPowerLimit),
MemUsed: loadGPUInfoFloat(gpuItem.MemUsed),
MemTotal: loadGPUInfoFloat(gpuItem.MemTotal),
FanSpeed: loadGPUInfoInt(gpuItem.FanSpeed),
}
process, _ := json.Marshal(gpuItem.Processes)
if len(process) != 0 {
item.Processes = string(process)
}
list = append(list, item)
}
if err := repo.NewIMonitorRepo().BatchCreateMonitorGPU(list); err != nil {
global.LOG.Errorf("batch create gpu monitor data failed, err: %v", err)
return
}
}
func saveXPUDataToDB() {
exist, client := xpu.New()
if !exist {
return
}
xpuInfo, err := client.LoadGpuInfo()
if err != nil {
return
}
var list []model.MonitorGPU
for _, xpuItem := range xpuInfo.Xpu {
item := model.MonitorGPU{
ProductName: fmt.Sprintf("%d - %s", xpuItem.Basic.DeviceID, xpuItem.Basic.DeviceName),
Temperature: loadGPUInfoFloat(xpuItem.Stats.Temperature),
PowerDraw: loadGPUInfoFloat(xpuItem.Stats.Power),
MemUsed: loadGPUInfoFloat(xpuItem.Stats.MemoryUsed),
MemTotal: loadGPUInfoFloat(xpuItem.Basic.Memory),
}
if len(xpuItem.Processes) != 0 {
var processItem []dto.GPUProcess
for _, ps := range xpuItem.Processes {
processItem = append(processItem, dto.GPUProcess{
Pid: fmt.Sprintf("%v", ps.PID),
Type: ps.SHR,
ProcessName: ps.Command,
UsedMemory: ps.Memory,
})
}
process, _ := json.Marshal(processItem)
if len(process) != 0 {
item.Processes = string(process)
}
}
list = append(list, item)
}
if err := repo.NewIMonitorRepo().BatchCreateMonitorGPU(list); err != nil {
global.LOG.Errorf("batch create gpu monitor data failed, err: %v", err)
return
}
}
func loadGPUInfoInt(val string) int {
val = strings.TrimSuffix(val, "%")
val = strings.TrimSpace(val)
data, _ := strconv.Atoi(val)
return data
}
func loadGPUInfoFloat(val string) float64 {
val = strings.TrimSpace(val)
suffixes := []string{"W", "MB", "MiB", "°C", "C", "%"}
for _, suffix := range suffixes {
val = strings.TrimSuffix(val, suffix)
}
val = strings.TrimSpace(val)
data, _ := strconv.ParseFloat(val, 64)
return data
}
+167 -18
View File
@@ -1,11 +1,15 @@
package service
import (
"bufio"
"fmt"
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/websocket"
"github.com/shirou/gopsutil/v4/process"
"os"
"strconv"
"strings"
"time"
)
@@ -103,24 +107,20 @@ func (ps *ProcessService) GetProcessInfoByPID(pid int32) (*websocket.PsProcessDa
data.CmdLine = cmdline
}
if memInfo, err := p.MemoryInfo(); err == nil {
data.Rss = common.FormatBytes(memInfo.RSS)
data.VMS = common.FormatBytes(memInfo.VMS)
data.HWM = common.FormatBytes(memInfo.HWM)
data.Data = common.FormatBytes(memInfo.Data)
data.Stack = common.FormatBytes(memInfo.Stack)
data.Locked = common.FormatBytes(memInfo.Locked)
data.Swap = common.FormatBytes(memInfo.Swap)
data.RssValue = memInfo.RSS
} else {
data.Rss = "--"
data.Data = "--"
data.VMS = "--"
data.HWM = "--"
data.Stack = "--"
data.Locked = "--"
data.Swap = "--"
data.RssValue = 0
if memDetail, err := getMemoryDetail(p.Pid); err == nil {
data.Rss = common.FormatBytes(memDetail.RSS)
data.VMS = common.FormatBytes(memDetail.VMS)
data.HWM = common.FormatBytes(memDetail.HWM)
data.Data = common.FormatBytes(memDetail.Data)
data.Stack = common.FormatBytes(memDetail.Stack)
data.Locked = common.FormatBytes(memDetail.Locked)
data.Swap = common.FormatBytes(memDetail.Swap)
data.Dirty = common.FormatBytes(memDetail.Dirty)
data.RssValue = memDetail.RSS
data.PSS = common.FormatBytes(memDetail.PSS)
data.USS = common.FormatBytes(memDetail.USS)
data.Shared = common.FormatBytes(memDetail.Shared)
data.Text = common.FormatBytes(memDetail.Text)
}
if envs, err := p.Environ(); err == nil {
@@ -133,3 +133,152 @@ func (ps *ProcessService) GetProcessInfoByPID(pid int32) (*websocket.PsProcessDa
return data, nil
}
type MemoryDetail struct {
RSS uint64
VMS uint64
HWM uint64
Data uint64
Stack uint64
Locked uint64
Swap uint64
PSS uint64
USS uint64
Shared uint64
Text uint64
Dirty uint64
}
func getMemoryDetail(pid int32) (*MemoryDetail, error) {
mem := &MemoryDetail{}
if err := readStatus(pid, mem); err != nil {
return nil, err
}
if err := readSmapsRollup(pid, mem); err != nil {
if err := readSmaps(pid, mem); err != nil {
return nil, err
}
}
return mem, nil
}
func readStatus(pid int32, mem *MemoryDetail) error {
filePath := fmt.Sprintf("/proc/%d/status", pid)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}
key := strings.TrimSuffix(fields[0], ":")
value, _ := strconv.ParseUint(fields[1], 10, 64)
value *= 1024
switch key {
case "VmRSS":
mem.RSS = value
case "VmSize":
mem.VMS = value
case "VmData":
mem.Data = value
case "VmSwap":
mem.Swap = value
case "VmExe":
mem.Text = value
case "RssShmem":
mem.Shared = value
case "VmHWM":
mem.HWM = value
case "VmStk":
mem.Stack = value
case "VmLck":
mem.Locked = value
}
}
return scanner.Err()
}
func readSmapsRollup(pid int32, mem *MemoryDetail) error {
filePath := fmt.Sprintf("/proc/%d/smaps_rollup", pid)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}
key := strings.TrimSuffix(fields[0], ":")
value, _ := strconv.ParseUint(fields[1], 10, 64)
value *= 1024
switch key {
case "Pss":
mem.PSS = value
case "Private_Clean", "Private_Dirty":
mem.USS += value
case "Shared_Clean", "Shared_Dirty":
if mem.Shared == 0 {
mem.Shared = value
}
}
}
return scanner.Err()
}
func readSmaps(pid int32, mem *MemoryDetail) error {
filePath := fmt.Sprintf("/proc/%d/smaps", pid)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}
key := strings.TrimSuffix(fields[0], ":")
value, _ := strconv.ParseUint(fields[1], 10, 64)
value *= 1024
switch key {
case "Pss":
mem.PSS += value
case "Private_Clean", "Private_Dirty":
mem.USS += value
case "Shared_Clean", "Shared_Dirty":
if mem.Shared == 0 {
mem.Shared += value
}
}
}
return scanner.Err()
}
+3
View File
@@ -76,6 +76,9 @@ func (r RecycleBinService) Page(search dto.PageInfo) (int64, []response.RecycleB
}
func (r RecycleBinService) Create(create request.RecycleBinCreate) error {
if files.IsProtected(create.SourcePath) {
return buserr.New("ErrPathNotDelete")
}
op := files.NewFileOp()
if !op.Stat(create.SourcePath) {
return buserr.New("ErrLinkPathNotFound")
+1 -1
View File
@@ -722,7 +722,7 @@ func unInstallPHPExtension(runtime *model.Runtime, delExtensions []string) error
if ext.Name == del {
exist = true
delMap[ext.Check] = struct{}{}
delPHPExtensions(dir, phpExtensionDir, ext.Check, ext.Name)
delPHPExtensions(dir, phpExtensionDir, ext.File, ext.Name)
break
}
}
+24
View File
@@ -7,6 +7,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
"github.com/1Panel-dev/1Panel/agent/utils/ssh"
@@ -24,6 +25,8 @@ type ISettingService interface {
GetSystemProxy() (*dto.SystemProxy, error)
GetLocalConn() dto.SSHConnData
GetSettingByKey(key string) string
SaveDescription(req dto.CommonDescription) error
}
func NewISettingService() ISettingService {
@@ -170,3 +173,24 @@ func (u *SettingService) GetSettingByKey(key string) string {
return value
}
}
func (u *SettingService) SaveDescription(req dto.CommonDescription) error {
if len(req.Description) == 0 && !req.IsPinned {
_ = settingRepo.DelDescription(req.ID)
return nil
}
data, _ := settingRepo.GetDescription(settingRepo.WithByDescriptionID(req.ID), repo.WithByType(req.Type), repo.WithByDetailType(req.DetailType))
if data.ID == "" {
if err := copier.Copy(&data, &req); err != nil {
return err
}
return settingRepo.CreateDescription(&data)
}
valMap := make(map[string]interface{})
valMap["type"] = req.Type
valMap["detail_type"] = req.DetailType
valMap["is_pinned"] = req.IsPinned
valMap["description"] = req.Description
return settingRepo.UpdateDescription(data.ID, valMap)
}
+22 -3
View File
@@ -12,6 +12,8 @@ import (
"time"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/docker/docker/api/types/image"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
@@ -23,6 +25,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/controller"
"github.com/1Panel-dev/1Panel/agent/utils/copier"
"github.com/1Panel-dev/1Panel/agent/utils/docker"
"github.com/1Panel-dev/1Panel/agent/utils/files"
"gorm.io/gorm"
)
@@ -259,11 +262,12 @@ func loadDbConn(snap *snapHelper, targetDir string, req dto.SnapshotCreate) erro
return err
}
} else {
taskDB, err := common.LoadDBConnByPathWithErr(path.Join(targetDir, "db/task.db"), "core.db")
taskDB, err := common.LoadDBConnByPathWithErr(path.Join(targetDir, "db/task.db"), "task.db")
snap.Task.LogWithStatus(i18n.GetWithName("SnapNewDB", "task"), err)
if err != nil {
return err
}
defer common.CloseDB(taskDB)
_ = taskDB.Where("id = ?", req.TaskID).Delete(&model.Task{}).Error
}
if !req.WithOperationLog && global.IsMaster {
@@ -368,9 +372,21 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err
}
}
client, err := docker.NewDockerClient()
if err != nil {
snap.Task.Log("load docker client failed, skip save app images")
return nil
}
images, err := client.ImageList(context.Background(), image.ListOptions{})
if err != nil {
snap.Task.Log("list docker images failed, skip save app images")
return nil
}
var existImages []string
for _, img := range images {
existImages = append(existImages, img.RepoTags...)
}
var imageList []string
existStr, _ := cmd.RunDefaultWithStdoutBashC("docker images | awk '{print $1\":\"$2}' | grep -v REPOSITORY:TAG")
existImages := strings.Split(existStr, "\n")
for _, app := range req.AppData {
for _, item := range app.Children {
if item.Label == "appImage" && item.IsCheck {
@@ -546,5 +562,8 @@ func snapUpload(snap snapHelper, accounts string, downloadID, retry uint, file s
src := path.Join(global.Dir.LocalBackupDir, "tmp/system", path.Base(file))
dst := path.Join("system_snapshot", path.Base(file))
accountMap := NewBackupClientMap(strings.Split(accounts, ","))
if !accountMap[fmt.Sprintf("%d", downloadID)].isOk {
return buserr.New(i18n.GetMsgWithDetail("LoadBackupFailed", accountMap[fmt.Sprintf("%d", downloadID)].message))
}
return uploadWithMap(snap.Task, accountMap, src, dst, accounts, downloadID, retry)
}
-169
View File
@@ -1,169 +0,0 @@
package cmd
import (
"fmt"
"os"
"runtime"
"runtime/pprof"
"time"
"github.com/spf13/cobra"
)
var (
cpuProfile string
memProfile string
duration time.Duration
showMemStats bool
showGoroutine bool
)
func init() {
RootCmd.AddCommand(debugCmd)
debugCmd.Flags().StringVar(&cpuProfile, "cpuprofile", "", "write cpu profile to file")
debugCmd.Flags().StringVar(&memProfile, "memprofile", "", "write memory profile to file")
debugCmd.Flags().DurationVar(&duration, "duration", 30*time.Second, "duration for cpu profiling")
debugCmd.Flags().BoolVar(&showMemStats, "memstats", false, "show memory statistics")
debugCmd.Flags().BoolVar(&showGoroutine, "goroutine", false, "show goroutine profile")
}
var debugCmd = &cobra.Command{
Use: "debug",
Short: "Performance debugging with pprof",
Long: `Debug command provides CPU and memory profiling capabilities using pprof.
Examples:
# CPU profiling for 30 seconds
1panel-agent debug --cpuprofile=cpu.prof --duration=30s
# Memory profiling
1panel-agent debug --memprofile=mem.prof
# Show memory statistics
1panel-agent debug --memstats
# Show goroutine information
1panel-agent debug --goroutine
# Combined profiling
1panel-agent debug --cpuprofile=cpu.prof --memprofile=mem.prof --memstats`,
RunE: func(cmd *cobra.Command, args []string) error {
if cpuProfile != "" {
if err := startCPUProfile(cpuProfile); err != nil {
return fmt.Errorf("failed to start CPU profile: %v", err)
}
defer stopCPUProfile()
time.Sleep(duration)
fmt.Printf("CPU profile saved to: %s\n", cpuProfile)
}
if memProfile != "" {
if err := writeMemProfile(memProfile); err != nil {
return fmt.Errorf("failed to write memory profile: %v", err)
}
fmt.Printf("Memory profile saved to: %s\n", memProfile)
}
if showMemStats {
printMemStats()
}
if showGoroutine {
printGoroutineInfo()
}
if cpuProfile == "" && memProfile == "" && !showMemStats && !showGoroutine {
printBasicInfo()
}
return nil
},
}
func startCPUProfile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
if err := pprof.StartCPUProfile(f); err != nil {
f.Close()
return err
}
return nil
}
func stopCPUProfile() {
pprof.StopCPUProfile()
}
func writeMemProfile(filename string) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
runtime.GC()
if err := pprof.WriteHeapProfile(f); err != nil {
return err
}
return nil
}
func printMemStats() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Println("\n=== Memory Statistics ===")
fmt.Printf("Allocated memory: %d KB (%d MB)\n", m.Alloc/1024, m.Alloc/1024/1024)
fmt.Printf("Total allocated: %d KB (%d MB)\n", m.TotalAlloc/1024, m.TotalAlloc/1024/1024)
fmt.Printf("System memory: %d KB (%d MB)\n", m.Sys/1024, m.Sys/1024/1024)
fmt.Printf("Heap allocated: %d KB (%d MB)\n", m.HeapAlloc/1024, m.HeapAlloc/1024/1024)
fmt.Printf("Heap system: %d KB (%d MB)\n", m.HeapSys/1024, m.HeapSys/1024/1024)
fmt.Printf("Heap idle: %d KB (%d MB)\n", m.HeapIdle/1024, m.HeapIdle/1024/1024)
fmt.Printf("Heap in use: %d KB (%d MB)\n", m.HeapInuse/1024, m.HeapInuse/1024/1024)
fmt.Printf("Heap released: %d KB (%d MB)\n", m.HeapReleased/1024, m.HeapReleased/1024/1024)
fmt.Printf("Heap objects: %d\n", m.HeapObjects)
fmt.Printf("GC runs: %d\n", m.NumGC)
fmt.Printf("GC pause total: %d ns\n", m.PauseTotalNs)
fmt.Printf("Next GC: %d KB (%d MB)\n", m.NextGC/1024, m.NextGC/1024/1024)
fmt.Printf("Last GC: %s\n", time.Unix(0, int64(m.LastGC)).Format("2006-01-02 15:04:05"))
}
func printGoroutineInfo() {
fmt.Println("\n=== Goroutine Information ===")
fmt.Printf("Number of goroutines: %d\n", runtime.NumGoroutine())
fmt.Printf("Number of CPUs: %d\n", runtime.NumCPU())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
buf := make([]byte, 1024*1024)
stackSize := runtime.Stack(buf, true)
fmt.Printf("\nGoroutine stack trace (first 2048 bytes):\n")
if stackSize > 2048 {
fmt.Printf("%s...\n", buf[:2048])
fmt.Printf("(truncated, total size: %d bytes)\n", stackSize)
} else {
fmt.Printf("%s\n", buf[:stackSize])
}
}
func printBasicInfo() {
fmt.Println("=== Performance Debug Info ===")
fmt.Printf("Go version: %s\n", runtime.Version())
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
fmt.Printf("CPUs: %d\n", runtime.NumCPU())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine())
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Memory allocated: %d KB\n", m.Alloc/1024)
fmt.Printf("Total allocations: %d KB\n", m.TotalAlloc/1024)
fmt.Printf("GC runs: %d\n", m.NumGC)
fmt.Println("\nUse --help to see available profiling options.")
}
+6 -5
View File
@@ -13,11 +13,12 @@ import (
)
var (
DB *gorm.DB
MonitorDB *gorm.DB
TaskDB *gorm.DB
CoreDB *gorm.DB
AlertDB *gorm.DB
DB *gorm.DB
MonitorDB *gorm.DB
GPUMonitorDB *gorm.DB
TaskDB *gorm.DB
CoreDB *gorm.DB
AlertDB *gorm.DB
LOG *logrus.Logger
CONF ServerConfig
+40 -21
View File
@@ -4,22 +4,27 @@ go 1.24.9
require (
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/aws/aws-sdk-go v1.55.0
github.com/aws/aws-sdk-go-v2 v1.40.0
github.com/aws/aws-sdk-go-v2/config v1.32.2
github.com/aws/aws-sdk-go-v2/credentials v1.19.2
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.7
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1
github.com/aws/smithy-go v1.23.2
github.com/compose-spec/compose-go/v2 v2.9.0
github.com/creack/pty v1.1.24
github.com/docker/cli v28.5.1+incompatible
github.com/docker/compose/v2 v2.40.2
github.com/docker/docker v28.5.1+incompatible
github.com/docker/go-connections v0.6.0
github.com/fsnotify/fsnotify v1.9.0
github.com/gin-gonic/gin v1.10.0
github.com/glebarez/sqlite v1.11.0
github.com/go-acme/lego/v4 v4.27.0
github.com/go-acme/lego/v4 v4.29.0
github.com/go-gormigrate/gormigrate/v2 v2.1.2
github.com/go-playground/validator/v10 v10.26.0
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-resty/resty/v2 v2.16.5
github.com/go-sql-driver/mysql v1.8.1
github.com/goccy/go-yaml v1.9.8
github.com/goh-chunlin/go-onedrive v1.1.1
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674
@@ -47,11 +52,11 @@ require (
github.com/tencentyun/cos-go-sdk-v5 v0.7.54
github.com/tomasen/fcgi_client v0.0.0-20180423082037-2bb3d819fd19
github.com/upyun/go-sdk v2.1.0+incompatible
golang.org/x/crypto v0.43.0
golang.org/x/net v0.46.0
golang.org/x/oauth2 v0.32.0
golang.org/x/sys v0.37.0
golang.org/x/text v0.30.0
golang.org/x/crypto v0.45.0
golang.org/x/net v0.47.0
golang.org/x/oauth2 v0.33.0
golang.org/x/sys v0.38.0
golang.org/x/text v0.31.0
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
@@ -71,7 +76,22 @@ 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/baidubce/bce-sdk-go v0.9.248 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // 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.14 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 // indirect
github.com/baidubce/bce-sdk-go v0.9.252 // indirect
github.com/bodgit/plumbing v1.2.0 // indirect
github.com/bodgit/sevenzip v1.3.0 // indirect
github.com/bodgit/windows v1.0.0 // indirect
@@ -97,6 +117,7 @@ require (
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/buildx v0.29.1 // indirect
github.com/docker/cli v28.5.1+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dsnet/compress v0.0.1 // indirect
@@ -108,8 +129,9 @@ require (
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/go-acme/alidns-20150109/v4 v4.6.1 // indirect
github.com/go-acme/tencentclouddnspod v1.1.10 // indirect
github.com/go-acme/alidns-20150109/v4 v4.7.0 // indirect
github.com/go-acme/esa-20240910/v2 v2.40.1 // indirect
github.com/go-acme/tencentclouddnspod v1.1.25 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-logr/logr v1.4.3 // indirect
@@ -119,8 +141,7 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.9.8 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gofrs/flock v0.13.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
@@ -133,7 +154,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.172 // indirect
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.178 // indirect
github.com/in-toto/in-toto-golang v0.9.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
@@ -141,7 +162,6 @@ 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
@@ -178,7 +198,6 @@ require (
github.com/nrdcg/dnspod-go v0.4.0 // indirect
github.com/nrdcg/freemyip v0.3.0 // indirect
github.com/nrdcg/goacmedns v0.2.0 // indirect
github.com/nrdcg/mailinabox v0.2.0 // indirect
github.com/nrdcg/namesilo v0.5.0 // indirect
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -199,7 +218,7 @@ require (
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.41 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.3 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
@@ -212,7 +231,7 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/volcengine/volc-sdk-golang v1.0.223 // indirect
github.com/volcengine/volc-sdk-golang v1.0.229 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.mongodb.org/mongo-driver v1.13.1 // indirect
@@ -235,12 +254,12 @@ require (
golang.org/x/arch v0.8.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.37.0 // indirect
golang.org/x/tools v0.38.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect
google.golang.org/grpc v1.76.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
modernc.org/libc v1.66.1 // indirect
+88 -71
View File
@@ -48,9 +48,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.13.0 h1:/BcXOiS6Qi7N9XqUcv27vkIuVOkBEcWstd2pMlWSeaA=
github.com/Microsoft/hcsshim v0.13.0/go.mod h1:9KWJ/8DgU+QzYGupX4tzMhRQE8h6w90lH6HAaclpEok=
github.com/Microsoft/hcsshim v0.14.0-rc.1 h1:qAPXKwGOkVn8LlqgBN8GS0bxZ83hOJpcjxzmlQKxKsQ=
github.com/Microsoft/hcsshim v0.14.0-rc.1/go.mod h1:hTKFGbnDtQb1wHiOWv4v0eN+7boSWAHyK/tNAaYZL0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
@@ -79,7 +78,6 @@ github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.12/go.mod h1:f2wDpbM7hK9SvLIH09zSKVU1TsyemUNOqErMscMMl7c=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13 h1:Q00FU3H94Ts0ZIHDmY+fYGgB7dV9D/YX6FGsgorQPgw=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
@@ -102,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.12/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
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-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
@@ -130,13 +127,53 @@ 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/baidubce/bce-sdk-go v0.9.248 h1:vB5OMuEC2xnO197M6OWUi24C8mYOZHKXT/8HuKQJUhU=
github.com/baidubce/bce-sdk-go v0.9.248/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
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/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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -190,17 +227,12 @@ github.com/compose-spec/compose-go/v2 v2.9.0 h1:UHSv/QHlo6QJtrT4igF1rdORgIUhDo1g
github.com/compose-spec/compose-go/v2 v2.9.0/go.mod h1:Oky9AZGTRB4E+0VbTPZTUu4Kp+oEMMuwZXZtPPVT1iE=
github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEycw=
github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA=
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/cgroups/v3 v3.1.0 h1:azxYVj+91ZgSnIBp2eI3k9y2iYQSR/ZQIgh9vKO+HSY=
github.com/containerd/cgroups/v3 v3.1.0/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0=
github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI=
github.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o=
github.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM=
github.com/containerd/containerd/v2 v2.1.4 h1:/hXWjiSFd6ftrBOBGfAZ6T30LJcx1dBjdKEeI8xucKQ=
github.com/containerd/containerd/v2 v2.1.4/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM=
github.com/containerd/containerd/v2 v2.2.0 h1:K7TqcXy+LnFmZaui2DgHsnp2gAHhVNWYaHlx7HXfys8=
github.com/containerd/containerd/v2 v2.2.0/go.mod h1:YCMjKjA4ZA7egdHNi3/93bJR1+2oniYlnS+c0N62HdE=
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
@@ -215,8 +247,6 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/nydus-snapshotter v0.15.2 h1:qsHI4M+Wwrf6Jr4eBqhNx8qh+YU0dSiJ+WPmcLFWNcg=
github.com/containerd/nydus-snapshotter v0.15.2/go.mod h1:FfwH2KBkNYoisK/e+KsmNr7xTU53DmnavQHMFOcXwfM=
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4=
github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=
@@ -322,12 +352,14 @@ github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/go-acme/alidns-20150109/v4 v4.6.1 h1:Dch3aWRcw4U62+jKPjPQN3iW3TPvgIywATbvHzojXeo=
github.com/go-acme/alidns-20150109/v4 v4.6.1/go.mod h1:RBcqBA5IvUWtlpjx6dC6EkPVyBNLQ+mR18XoaP38BFY=
github.com/go-acme/lego/v4 v4.27.0 h1:cIhWd7Uj4BNFLEF3IpwuMkukVVRs5qjlp4KdUGa75yU=
github.com/go-acme/lego/v4 v4.27.0/go.mod h1:9FfNZHZmg6hf5CWOp4Lzo4gU8aBEvqZvrwdkBboa+4g=
github.com/go-acme/tencentclouddnspod v1.1.10 h1:ERVJ4mc3cT4Nb3+n6H/c1AwZnChGBqLoymE0NVYscKI=
github.com/go-acme/tencentclouddnspod v1.1.10/go.mod h1:Bo/0YQJ/99FM+44HmCQkByuptX1tJsJ9V14MGV/2Qco=
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/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/tencentclouddnspod v1.1.25 h1:7H3ZKshkaHzCXfRpAHVB5nvxeDDl2XLeNZfrNHiZj/s=
github.com/go-acme/tencentclouddnspod v1.1.25/go.mod h1:XXfzp0AYV7UAUsHKT6R0KAUJFhqAUXmWGF07Elpa5cE=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -386,8 +418,8 @@ github.com/goccy/go-yaml v1.9.8 h1:5gMyLUeU1/6zl+WFfR1hN7D2kf+1/eRGa7DFtToiBvQ=
github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -401,9 +433,9 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -486,8 +518,6 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafov/m3u8 v0.12.0/go.mod h1:nqzOkfBiZJENr52zTVd/Dcl03yzphIMbJqkXGu+u080=
@@ -533,8 +563,8 @@ 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.172 h1:68VUVbLKwBxPh8tjCXwnLO/d8/thdZ+ExpxdFMEdK5A=
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.172/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
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/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -568,9 +598,7 @@ 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=
@@ -593,8 +621,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@@ -711,7 +737,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
@@ -744,8 +769,6 @@ github.com/nrdcg/freemyip v0.3.0 h1:0D2rXgvLwe2RRaVIjyUcQ4S26+cIS2iFwnhzDsEuuwc=
github.com/nrdcg/freemyip v0.3.0/go.mod h1:c1PscDvA0ukBF0dwelU/IwOakNKnVxetpAQ863RMJoM=
github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0=
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
github.com/nrdcg/mailinabox v0.2.0 h1:IKq8mfKiVwNW2hQii/ng1dJ4yYMMv3HAP3fMFIq2CFk=
github.com/nrdcg/mailinabox v0.2.0/go.mod h1:0yxqeYOiGyxAu7Sb94eMxHPIOsPYXAjTeA9ZhePhGnc=
github.com/nrdcg/namesilo v0.5.0 h1:6QNxT/XxE+f5B+7QlfWorthNzOzcGlBLRQxqi6YeBrE=
github.com/nrdcg/namesilo v0.5.0/go.mod h1:4UkwlwQfDt74kSGmhLaDylnBrD94IfflnpoEaj6T2qw=
github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A=
@@ -813,33 +836,29 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
github.com/qiniu/go-sdk/v7 v7.21.1 h1:D/IjVOlg5pTw0jeDjqTo6H5QM73Obb1AYfPOHmIFN+Q=
github.com/qiniu/go-sdk/v7 v7.21.1/go.mod h1:8EM2awITynlem2VML2dXGHkMYP2UyECsGLOdp6yMpco=
@@ -928,9 +947,9 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD
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.10/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.41 h1:XQDGrLX6v4McMP+2myhgQcy5JaPqSgwpLM1qa7ngUII=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.41/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
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/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
github.com/tencentyun/cos-go-sdk-v5 v0.7.54 h1:FRamEhNBbSeggyYfWfzFejTLftgbICocSYFk4PKTSV4=
github.com/tencentyun/cos-go-sdk-v5 v0.7.54/go.mod h1:UN+VdbCl1hg+kKi5RXqZgaP+Boqfmk+D04GRc4XFk70=
@@ -970,8 +989,8 @@ 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.223 h1:1EEK6VOUaA2Tu0VBD4VC5iSTTFag+KuNo+Vix469Tz4=
github.com/volcengine/volc-sdk-golang v1.0.223/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
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/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
@@ -1043,6 +1062,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
@@ -1081,8 +1102,8 @@ 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.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1126,8 +1147,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.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
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/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1186,8 +1205,8 @@ 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.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1195,8 +1214,8 @@ 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.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
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/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1213,8 +1232,8 @@ 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.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
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/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1294,8 +1313,8 @@ 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.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
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/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1310,8 +1329,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.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
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/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=
@@ -1329,8 +1348,8 @@ 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.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1392,8 +1411,8 @@ 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1464,8 +1483,8 @@ google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOs
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/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
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/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1483,8 +1502,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.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
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/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+24 -12
View File
@@ -13,6 +13,19 @@ import (
"gopkg.in/yaml.v3"
)
var langFiles = map[string]string{
"zh": "lang/zh.yaml",
"en": "lang/en.yaml",
"zh-Hant": "lang/zh-Hant.yaml",
"pt-BR": "lang/pt-BR.yaml",
"ja": "lang/ja.yaml",
"ru": "lang/ru.yaml",
"ms": "lang/ms.yaml",
"ko": "lang/ko.yaml",
"tr": "lang/tr.yaml",
"es-ES": "lang/es-ES.yaml",
}
func GetMsgWithMap(key string, maps map[string]interface{}) string {
var content string
if maps == nil {
@@ -123,18 +136,17 @@ func UseI18n() gin.HandlerFunc {
func Init() {
bundle = i18n.NewBundle(language.Chinese)
bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)
_, _ = bundle.LoadMessageFileFS(fs, "lang/zh.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/en.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/zh-Hant.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/fa.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/pt.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/pt-BR.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/ja.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/ru.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/ms.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/ko.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/tr.yaml")
_, _ = bundle.LoadMessageFileFS(fs, "lang/es-ES.yaml")
isSuccess := true
for _, file := range langFiles {
if _, err := bundle.LoadMessageFileFS(fs, file); err != nil {
global.LOG.Errorf("[i18n] load language file %s failed: %v\n", file, err)
isSuccess = false
}
}
if !isSuccess {
panic("[i18n] failed to init language files, See log above for details")
}
lang := GetLanguageFromDB()
global.I18n = i18n.NewLocalizer(bundle, lang)
}
+4 -1
View File
@@ -197,6 +197,8 @@ ErrDatabaseIsExist: 'The current database already exists, please re-enter'
ErrExecTimeOut: 'SQL execution timed out, please check the database'
ErrRemoteExist: 'The remote database already exists with this name, please modify it and try again'
ErrLocalExist: 'The name already exists in the local database, please modify it and try again'
RemoteBackup: "To back up the remote database, the local container database service needs to be started first using the image {{ .name }}, please wait..."
RemoteRecover: "To restore the remote database, the local container database service needs to be started first using the image {{ .name }}, please wait..."
#redis
ErrTypeOfRedis: 'The recovery file type does not match the current persistence method, please modify it and try again'
@@ -239,6 +241,7 @@ ErrUserFindErr: 'User {{ .name }} search failed {{ .err }}'
#cronjob
CutWebsiteLogSuccess: '{{ .name }} website log cut successfully, backup path {{ .path }}'
HandleShell: 'Execute script {{ .name }}'
HandleCurl: "Access URL {{ .name }}"
HandleNtpSync: 'System time synchronization'
HandleSystemClean: 'System cache cleanup'
SystemLog: 'System Log'
@@ -251,7 +254,7 @@ IgnoreUploadErr: "Upload failed, error: {{ .detail }}, ignoring this error..."
LoadBackupFailed: "Failed to get backup account connection, error: {{ .detail }}"
InExecuting: "The current task is being executed, please do not repeat the execution!"
NoSuchResource: "No backup content found in the database, skipping..."
CleanLog: "Clean Log",
CleanLog: "Clean Log"
CleanLogByName: "Clean {{.name}} Log"
#toolbox
+3
View File
@@ -196,6 +196,8 @@ ErrDatabaseIsExist: 'La base de datos actual ya existe, intente con otro nombre'
ErrExecTimeOut: 'Tiempo de espera en la ejecución SQL, revise la base de datos'
ErrRemoteExist: 'La base de datos remota ya existe con ese nombre, modifíquelo e intente de nuevo'
ErrLocalExist: 'El nombre ya existe en la base de datos local, modifíquelo e intente de nuevo'
RemoteBackup: "Para hacer una copia de seguridad de la base de datos remota, primero debe iniciarse el servicio de base de datos del contenedor local utilizando la imagen {{ .name }}, espere por favor..."
RemoteRecover: "Para restaurar la base de datos remota, primero debe iniciarse el servicio de base de datos del contenedor local utilizando la imagen {{ .name }}, espere por favor..."
#redis
ErrTypeOfRedis: 'El tipo de archivo de recuperación no coincide con el método de persistencia actual, modifíquelo e intente'
@@ -238,6 +240,7 @@ ErrUserFindErr: 'Búsqueda del usuario {{ .name }} fallida {{ .err }}'
#cronjob
CutWebsiteLogSuccess: 'Log del sitio web {{ .name }} cortado con éxito, ruta de respaldo {{ .path }}'
HandleShell: 'Ejecutar script {{ .name }}'
HandleCurl: "URL {{ .name }} にアクセス"
HandleNtpSync: 'Sincronizar hora del sistema'
HandleSystemClean: 'Limpiar caché del sistema'
SystemLog: 'Log del sistema'
+3
View File
@@ -196,6 +196,8 @@ ErrDatabaseIsExist: '現在のデータベースは既に存在します。再
ErrExecTimeOut: 'SQL 実行がタイムアウトしました。データベースを確認してください'
ErrRemoteExist: 'この名前のリモート データベースは既に存在します。変更してもう一度お試しください'
ErrLocalExist: '名前はローカル データベースに既に存在します。変更してもう一度お試しください'
RemoteBackup: "リモートデータベースをバックアップするには、まずイメージ {{ .name }} を使用してローカルコンテナデータベースサービスを起動する必要があります。しばらくお待ちください..."
RemoteRecover: "リモートデータベースを復元するには、まずイメージ {{ .name }} を使用してローカルコンテナデータベースサービスを起動する必要があります。しばらくお待ちください..."
#redis
ErrTypeOfRedis: 'リカバリ ファイルの種類が現在の永続化方法と一致しません。変更して再試行してください'
@@ -238,6 +240,7 @@ ErrUserFindErr: 'ユーザー {{ .name }} の検索に失敗しました {{ .err
#cronjob
CutWebsiteLogSuccess: '{{ .name }} ウェブサイトのログが正常にカットされました。バックアップ パス {{ .path }}'
HandleShell: 'スクリプト {{ .name }} を実行します'
HandleCurl: "URL {{ .name }} にアクセス"
HandleNtpSync: 'システム時刻の同期'
HandleSystemClean: 'システム キャッシュのクリーンアップ'
SystemLog: 'システムログ'
+3
View File
@@ -197,6 +197,8 @@ ErrDatabaseIsExist: '현재 데이터베이스가 이미 존재합니다. 다시
ErrExecTimeOut: 'SQL 실행 시간이 초과되었습니다. 데이터베이스를 확인하십시오.'
ErrRemoteExist: '이 이름을 가진 원격 데이터베이스가 이미 존재합니다. 수정하고 다시 시도하세요'
ErrLocalExist: '이름이 로컬 데이터베이스에 이미 존재합니다. 이름을 수정하고 다시 시도하세요'
RemoteBackup: "원격 데이터베이스를 백업하려면 먼저 이미지 {{ .name }}을(를) 사용하여 로컬 컨테이너 데이터베이스 서비스를 시작해야 합니다. 잠시만 기다려 주세요..."
RemoteRecover: "원격 데이터베이스를 복원하려면 먼저 이미지 {{ .name }}을(를) 사용하여 로컬 컨테이너 데이터베이스 서비스를 시작해야 합니다. 잠시만 기다려 주세요..."
#레디스
ErrTypeOfRedis: '복구 파일 유형이 현재 지속성 방법과 일치하지 않습니다. 수정하고 다시 시도하세요'
@@ -239,6 +241,7 @@ ErrUserFindErr: '사용자 {{ .name }} 검색에 실패했습니다 {{ .err }}'
#크론잡
CutWebsiteLogSuccess: '{{ .name }} 웹사이트 로그가 성공적으로 잘렸습니다. 백업 경로 {{ .path }}'
HandleShell: '스크립트 {{ .name }} 실행'
HandleCurl: "URL {{ .name }} 접근"
HandleNtpSync: '시스템 시간 동기화'
HandleSystemClean: '시스템 캐시 정리'
SystemLog: '시스템 로그'
+3
View File
@@ -197,6 +197,8 @@ ErrDatabaseIsExist: 'Pangkalan data semasa sudah wujud, sila masukkan semula'
ErrExecTimeOut: 'Pelaksanaan SQL tamat masa, sila semak pangkalan data'
ErrRemoteExist: 'Pangkalan data jauh sudah wujud dengan nama ini, sila ubah suainya dan cuba lagi'
ErrLocalExist: 'Nama sudah wujud dalam pangkalan data tempatan, sila ubah suai dan cuba lagi'
RemoteBackup: "Untuk menyandarkan pangkalan data jauh, perkhidmatan pangkalan data bekas tempatan perlu dimulakan terlebih dahulu menggunakan imej {{ .name }}, sila tunggu..."
RemoteRecover: "Untuk memulihkan pangkalan data jauh, perkhidmatan pangkalan data bekas tempatan perlu dimulakan terlebih dahulu menggunakan imej {{ .name }}, sila tunggu..."
#redis
ErrTypeOfRedis: 'Jenis fail pemulihan tidak sepadan dengan kaedah kegigihan semasa, sila ubah suai dan cuba lagi'
@@ -239,6 +241,7 @@ ErrUserFindErr: 'Pengguna {{ .name }} carian gagal {{ .err }}'
#cronjob
CutWebsiteLogSuccess: '{{ .name }} log tapak web berjaya dipotong, laluan sandaran {{ .path }}'
HandleShell: 'Laksanakan skrip {{ .name }}'
HandleCurl: "Akses URL {{ .name }}"
HandleNtpSync: 'Penyegerakan masa sistem'
HandleSystemClean: 'Pembersihan cache sistem'
SystemLog: 'Log Sistem'
+3
View File
@@ -197,6 +197,8 @@ ErrDatabaseIsExist: 'O banco de dados atual já existe, digite novamente'
ErrExecTimeOut: 'Tempo limite de execução do SQL expirou, verifique o banco de dados'
ErrRemoteExist: 'O banco de dados remoto já existe com este nome, modifique-o e tente novamente'
ErrLocalExist: 'O nome já existe no banco de dados local, modifique-o e tente novamente'
RemoteBackup: "Para fazer backup do banco de dados remoto, o serviço de banco de dados do contêiner local precisa ser iniciado primeiro usando a imagem {{ .name }}, por favor aguarde..."
RemoteRecover: "Para restaurar o banco de dados remoto, o serviço de banco de dados do contêiner local precisa ser iniciado primeiro usando a imagem {{ .name }}, por favor aguarde..."
#redis
ErrTypeOfRedis: 'O tipo de arquivo de recuperação não corresponde ao método de persistência atual, modifique-o e tente novamente'
@@ -239,6 +241,7 @@ ErrUserFindErr: 'Falha na pesquisa do usuário {{ .name }} {{ .err }}'
#cronjob
CutWebsiteLogSuccess: '{{ .name }} registro do site cortado com sucesso, caminho de backup {{ .path }}'
HandleShell: 'Executar script {{ .name }}'
HandleCurl: "Acessar URL {{ .name }}"
HandleNtpSync: 'Sincronização de hora do sistema'
HandleSystemClean: 'Limpeza de cache do sistema'
SystemLog: 'Log do Sistema'
+3
View File
@@ -197,6 +197,8 @@ ErrDatabaseIsExist: 'Текущая база данных уже существ
ErrExecTimeOut: 'Время выполнения SQL истекло, проверьте базу данных'
ErrRemoteExist: 'Удаленная база данных с таким именем уже существует. Измените его и повторите попытку'
ErrLocalExist: 'Имя уже существует в локальной базе данных, измените его и повторите попытку'
RemoteBackup: "Для резервного копирования удаленной базы данных необходимо сначала запустить службу базы данных локального контейнера с помощью образа {{ .name }}, пожалуйста, подождите..."
RemoteRecover: "Для восстановления удаленной базы данных необходимо сначала запустить службу базы данных локального контейнера с помощью образа {{ .name }}, пожалуйста, подождите..."
#редис
ErrTypeOfRedis: 'Тип файла восстановления не соответствует текущему методу сохранения. Измените его и повторите попытку'
@@ -239,6 +241,7 @@ ErrUserFindErr: 'Поиск пользователя {{ .name }} не удалс
#cronjob
CutWebsiteLogSuccess: 'Журнал веб-сайта {{ .name }} успешно вырезан, путь к резервной копии {{ .path }}'
HandleShell: 'Выполнить скрипт {{ .name }}'
HandleCurl: "Доступ к URL {{ .name }}"
HandleNtpSync: 'Синхронизация системного времени'
HandleSystemClean: 'Очистка системного кэша'
SystemLog: 'Системный лог'
+6 -3
View File
@@ -112,14 +112,14 @@ ExportDate: "Zaman"
#file
ErrFileCanNotRead: 'Bu dosya önizlemeyi desteklemiyor'
ErrFileToLarge: 'Dosya 10M'dan büyük ve açılamıyor'
ErrFileToLarge: 'Dosya 10M dan büyük ve açılamıyor'
ErrPathNotFound: 'Dizin mevcut değil'
ErrMovePathFailed: 'Hedef yol orijinal yolu içeremez!'
ErrLinkPathNotFound: 'Hedef yol mevcut değil!'
ErrFileIsExist: 'Dosya veya klasör zaten mevcut!'
ErrFileUpload: '{{ .name }} dosya yükleme başarısız {{ .detail }}'
ErrFileDownloadDir: 'Klasör indirme desteklenmiyor'
ErrCmdNotFound: '{{ .name}} komutu mevcut değil, lütfen önce bu komutu host'a yükleyin'
ErrCmdNotFound: '{{ .name}} komutu mevcut değil, lütfen önce bu komutu host a yükleyin'
ErrSourcePathNotFound: 'Kaynak dizin mevcut değil'
ErrFavoriteExist: 'Bu yol zaten favorilere eklendi'
ErrInvalidChar: 'Yasak karakterlere izin verilmiyor'
@@ -198,6 +198,8 @@ ErrDatabaseIsExist: 'Mevcut veritabanı zaten mevcut, lütfen yeniden girin'
ErrExecTimeOut: 'SQL yürütme zaman aşımı, lütfen veritabanını kontrol edin'
ErrRemoteExist: 'Uzak veritabanında bu adla zaten mevcut, lütfen değiştirin ve tekrar deneyin'
ErrLocalExist: 'Yerel veritabanında bu ad zaten mevcut, lütfen değiştirin ve tekrar deneyin'
RemoteBackup: "Uzak veritabanını yedeklemek için önce {{ .name }} görüntüsü kullanılarak yerel konteyner veritabanı hizmetinin başlatılması gerekiyor, lütfen bekleyin..."
RemoteRecover: "Uzak veritabanını geri yüklemek için önce {{ .name }} görüntüsü kullanılarak yerel konteyner veritabanı hizmetinin başlatılması gerekiyor, lütfen bekleyin..."
#redis
ErrTypeOfRedis: 'Kurtarma dosyası türü mevcut kalıcılık yöntemiyle eşleşmiyor, lütfen değiştirin ve tekrar deneyin'
@@ -240,6 +242,7 @@ ErrUserFindErr: 'Kullanıcı {{ .name }} arama başarısız {{ .err }}'
#cronjob
CutWebsiteLogSuccess: '{{ .name }} web sitesi günlüğü başarıyla kesildi, yedekleme yolu {{ .path }}'
HandleShell: 'Betik {{ .name }} yürüt'
HandleCurl: "URL'ye Eriş {{ .name }}"
HandleNtpSync: 'Sistem zaman senkronizasyonu'
HandleSystemClean: 'Sistem önbellek temizliği'
SystemLog: 'Sistem Günlüğü'
@@ -405,7 +408,7 @@ SnapNewDB: 'Veritabanı {{ .name }} bağlantısını başlat'
SnapDeleteOperationLog: 'İşlem günlüğünü sil'
SnapDeleteLoginLog: 'Erişim günlüğünü sil'
SnapDeleteMonitor: 'İzleme verilerini sil'
SnapRemoveSystemIP: 'Sistem IP'sini kaldır'
SnapRemoveSystemIP: 'Sistem IP sini kaldır'
SnapBaseInfo: '1Panel temel bilgilerini yaz'
SnapInstallAppImageEmpty: 'Uygulama imageı seçilmedi, atlanıyor...'
SnapInstallApp: '1Panel yüklü uygulamaları yedekle'
+3
View File
@@ -196,6 +196,8 @@ ErrDatabaseIsExist: '目前資料庫已存在,請重新輸入'
ErrExecTimeOut: 'SQL 執行逾時,請檢查資料庫'
ErrRemoteExist: '遠端資料庫已存在該名稱,請修改後重試'
ErrLocalExist: '本機資料庫已存在該名稱,請修改後重試'
RemoteBackup: "備份遠端資料庫需要先使用映像 {{ .name }} 啟動本機容器資料庫服務,請稍候..."
RemoteRecover: "恢復遠端資料庫需要先使用映像 {{ .name }} 啟動本機容器資料庫服務,請稍候..."
#redis
ErrTypeOfRedis: '復原檔案類型與目前持久化方式不符,請修改後重試'
@@ -238,6 +240,7 @@ ErrUserFindErr: '使用者{{ .name }} 尋找失敗{{ .err }}'
#cronjob
CutWebsiteLogSuccess: '{{ .name }} 網站日誌切割成功,備份路徑{{ .path }}'
HandleShell: '執行腳本{{ .name }}'
HandleCurl: "存取 URL {{ .name }}"
HandleNtpSync: '系統時間同步'
HandleSystemClean: '系統快取清理'
SystemLog: '系統日誌'
+3
View File
@@ -197,6 +197,8 @@ ErrDatabaseIsExist: "当前数据库已存在,请重新输入"
ErrExecTimeOut: "SQL 执行超时,请检查数据库"
ErrRemoteExist: "远程数据库已存在该名称,请修改后重试"
ErrLocalExist: "本地数据库已存在该名称,请修改后重试"
RemoteBackup: "备份远程数据库需要先使用镜像 {{ .name }} 启动本地容器数据库服务,请稍候..."
RemoteRecover: "恢复远程数据库需要先使用镜像 {{ .name }} 启动本地容器数据库服务,请稍候..."
#redis
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
@@ -239,6 +241,7 @@ ErrUserFindErr: "用户 {{ .name }} 查找失败 {{ .err }}"
#cronjob
CutWebsiteLogSuccess: "{{ .name }} 网站日志切割成功,备份路径 {{ .path }}"
HandleShell: "执行脚本 {{ .name }}"
HandleCurl: "访问 URL {{ .name }}"
HandleNtpSync: "系统时间同步"
HandleSystemClean: "系统缓存清理"
SystemLog: "系统日志"
+3 -1
View File
@@ -1,6 +1,7 @@
package db
import (
"os"
"path"
"github.com/1Panel-dev/1Panel/agent/global"
@@ -11,9 +12,10 @@ func Init() {
global.DB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "agent.db"), "agent")
global.TaskDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "task.db"), "task")
global.MonitorDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "monitor.db"), "monitor")
global.GPUMonitorDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "gpu_monitor.db"), "gpu_monitor")
global.AlertDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "alert.db"), "alert")
if global.IsMaster {
if _, err := os.Stat("/usr/bin/1panel-core"); err == nil {
global.CoreDB = common.LoadDBConnByPath(path.Join(global.Dir.DbDir, "core.db"), "core")
}
}
+124
View File
@@ -0,0 +1,124 @@
package firewall
import (
"fmt"
"os"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/app/service"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
firewallClient "github.com/1Panel-dev/1Panel/agent/utils/firewall/client"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/client/iptables"
)
func Init() {
if !needInit() {
return
}
global.LOG.Info("initializing firewall settings...")
client, err := firewall.NewFirewallClient()
if err != nil {
return
}
clientName := client.Name()
settingRepo := repo.NewISettingRepo()
if clientName == "ufw" || clientName == "iptables" {
if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelForward, iptables.ForwardFileName); err != nil {
global.LOG.Errorf("load forward rules from file failed, err: %v", err)
return
}
if err := iptables.LoadRulesFromFile(iptables.NatTab, iptables.Chain1PanelPreRouting, iptables.ForwardFileName1); err != nil {
global.LOG.Errorf("load prerouting rules from file failed, err: %v", err)
return
}
if err := iptables.LoadRulesFromFile(iptables.NatTab, iptables.Chain1PanelPostRouting, iptables.ForwardFileName2); err != nil {
global.LOG.Errorf("load postrouting rules from file failed, err: %v", err)
return
}
global.LOG.Infof("loaded iptables rules for forward from file successfully")
iptablesForwardStatus, _ := settingRepo.GetValueByKey("IptablesForwardStatus")
if iptablesForwardStatus == constant.StatusEnable {
if err := firewallClient.EnableIptablesForward(); err != nil {
global.LOG.Errorf("enable iptables forward failed, err: %v", err)
return
}
}
}
if clientName != "iptables" {
return
}
if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.BasicBeforeFileName); err != nil {
global.LOG.Errorf("load basic before rules from file failed, err: %v", err)
return
}
if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName); err != nil {
global.LOG.Errorf("load basic rules from file failed, err: %v", err)
return
}
if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.BasicAfterFileName); err != nil {
global.LOG.Errorf("load basic after rules from file failed, err: %v", err)
return
}
panelPort := service.LoadPanelPort()
if len(panelPort) == 0 {
global.LOG.Errorf("find 1panel service port failed")
return
}
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, fmt.Sprintf("-p tcp -m tcp --dport %v -j ACCEPT", panelPort)); err != nil {
global.LOG.Errorf("add port accept rule %v failed, err: %v", panelPort, err)
return
}
global.LOG.Infof("loaded iptables rules for basic from file successfully")
iptablesService := service.IptablesService{}
iptablesStatus, _ := settingRepo.GetValueByKey("IptablesStatus")
if iptablesStatus == constant.StatusEnable {
if err := iptablesService.Operate(dto.IptablesOp{Operate: "bind-base"}); err != nil {
global.LOG.Errorf("bind base chains failed, err: %v", err)
return
}
}
if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelInput, iptables.InputFileName); err != nil {
global.LOG.Errorf("load input rules from file failed, err: %v", err)
return
}
if err := iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelOutput, iptables.OutputFileName); err != nil {
global.LOG.Errorf("load output rules from file failed, err: %v", err)
return
}
global.LOG.Infof("loaded iptables rules for input and output from file successfully")
iptablesInputStatus, _ := settingRepo.GetValueByKey("IptablesInputStatus")
if iptablesInputStatus == constant.StatusEnable {
if err := iptablesService.Operate(dto.IptablesOp{Name: iptables.Chain1PanelInput, Operate: "bind"}); err != nil {
global.LOG.Errorf("bind input chains failed, err: %v", err)
return
}
}
iptablesOutputStatus, _ := settingRepo.GetValueByKey("IptablesOutputStatus")
if iptablesOutputStatus == constant.StatusEnable {
if err := iptablesService.Operate(dto.IptablesOp{Name: iptables.Chain1PanelOutput, Operate: "bind"}); err != nil {
global.LOG.Errorf("bind output chains failed, err: %v", err)
return
}
}
}
func needInit() bool {
file, err := os.OpenFile("/run/1panel_boot_mark", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
if os.IsExist(err) {
return false
}
global.LOG.Errorf("check boot mark file failed: %v", err)
return true
}
defer file.Close()
fmt.Fprintf(file, "Boot Mark for 1panel\n")
return true
}
-24
View File
@@ -1,24 +0,0 @@
package firewall
import (
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/client/iptables"
)
func Init() {
client, err := firewall.NewFirewallClient()
if err != nil {
return
}
clientName := client.Name()
if clientName == "ufw" || clientName == "iptables" {
_ = iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelForward, iptables.ForwardFileName)
_ = iptables.LoadRulesFromFile(iptables.NatTab, iptables.Chain1PanelPreRouting, iptables.ForwardFileName1)
_ = iptables.LoadRulesFromFile(iptables.NatTab, iptables.Chain1PanelPostRouting, iptables.ForwardFileName2)
}
if clientName == "iptables" {
_ = iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName)
_ = iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelInput, iptables.InputFileName)
_ = iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelOutput, iptables.OutputFileName)
}
}
+4
View File
@@ -52,7 +52,11 @@ func InitAgentDB() {
migrations.UpdateCronJob,
migrations.UpdateTensorrtLLM,
migrations.AddIptablesFilterRuleTable,
migrations.AddCommonDescription,
migrations.UpdateDatabase,
migrations.AddGPUMonitor,
migrations.UpdateDatabaseMysql,
migrations.InitIptablesStatus,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
+63
View File
@@ -706,9 +706,72 @@ var UpdateTensorrtLLM = &gormigrate.Migration{
},
}
var AddCommonDescription = &gormigrate.Migration{
ID: "20251117-add-common-description",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&model.CommonDescription{})
},
}
var UpdateDatabase = &gormigrate.Migration{
ID: "20251117-update-database",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&model.Database{})
},
}
var AddGPUMonitor = &gormigrate.Migration{
ID: "20251122-add-gpu-monitor",
Migrate: func(tx *gorm.DB) error {
return global.GPUMonitorDB.AutoMigrate(&model.MonitorGPU{})
},
}
var UpdateDatabaseMysql = &gormigrate.Migration{
ID: "20251126-update-database-mysql",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.DatabaseMysql{}); err != nil {
return err
}
var data []model.DatabaseMysql
_ = tx.Where("1 = 1").Find(&data).Error
for _, item := range data {
if len(item.Collation) == 0 {
collation := ""
switch item.Format {
case "utf8":
collation = "utf8_general_ci"
case "utf8mb4":
collation = "utf8mb4_general_ci"
case "gbk":
collation = "gbk_chinese_ci"
case "big5":
collation = "big5_chinese_ci"
default:
collation = "utf8mb4_general_ci"
}
_ = tx.Model(&model.DatabaseMysql{}).Where("id = ?", item.ID).Updates(map[string]interface{}{"collation": collation}).Error
}
}
return nil
},
}
var InitIptablesStatus = &gormigrate.Migration{
ID: "20251201-init-iptables-status",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "IptablesStatus", Value: constant.StatusDisable}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "IptablesForwardStatus", Value: constant.StatusDisable}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "IptablesInputStatus", Value: constant.StatusDisable}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "IptablesOutputStatus", Value: constant.StatusDisable}).Error; err != nil {
return err
}
return nil
},
}
+1
View File
@@ -22,6 +22,7 @@ func (a *AppRouter) InitRouter(Router *gin.RouterGroup) {
appRouter.GET("/details/:id", baseApi.GetAppDetailByID)
appRouter.POST("/install", baseApi.InstallApp)
appRouter.GET("/tags", baseApi.GetAppTags)
appRouter.GET("/icon/:appID", baseApi.GetAppIcon)
appRouter.POST("/installed/check", baseApi.CheckAppInstalled)
appRouter.POST("/installed/loadport", baseApi.LoadPort)
+1
View File
@@ -24,6 +24,7 @@ func (s *ContainerRouter) InitRouter(Router *gin.RouterGroup) {
baRouter.POST("/list/byimage", baseApi.ListContainerByImage)
baRouter.GET("/status", baseApi.LoadContainerStatus)
baRouter.GET("/list/stats", baseApi.ContainerListStats)
baRouter.POST("/item/stats", baseApi.ContainerItemStats)
baRouter.GET("/search/log", baseApi.ContainerStreamLogs)
baRouter.POST("/download/log", baseApi.DownloadContainerLogs)
baRouter.GET("/limit", baseApi.LoadResourceLimit)
+2
View File
@@ -20,6 +20,8 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) {
cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo)
cmdRouter.GET("/current/node", baseApi.LoadCurrentInfoForNode)
cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo)
cmdRouter.GET("/current/top/cpu", baseApi.LoadDashboardTopCPU)
cmdRouter.GET("/current/top/mem", baseApi.LoadDashboardTopMem)
cmdRouter.POST("/system/restart/:operation", baseApi.SystemRestart)
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/variables", baseApi.LoadVariables)
cmdRouter.POST("/status", baseApi.LoadStatus)
cmdRouter.POST("/remote", baseApi.LoadRemoteAccess)
cmdRouter.GET("/options", baseApi.ListDBName)
cmdRouter.POST("/format/options", baseApi.ListDBFormatCollationOptions)
cmdRouter.POST("/redis/persistence/conf", baseApi.LoadPersistenceConf)
cmdRouter.POST("/redis/status", baseApi.LoadRedisStatus)
+2
View File
@@ -29,7 +29,9 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) {
hostRouter.POST("/firewall/filter/chain/status", baseApi.LoadChainStatus)
hostRouter.POST("/monitor/search", baseApi.LoadMonitor)
hostRouter.POST("/monitor/gpu/search", baseApi.LoadGPUMonitor)
hostRouter.POST("/monitor/clean", baseApi.CleanMonitor)
hostRouter.GET("/monitor/gpuoptions", baseApi.GetCPUOptions)
hostRouter.GET("/monitor/netoptions", baseApi.GetNetworkOptions)
hostRouter.GET("/monitor/iooptions", baseApi.GetIOOptions)
hostRouter.GET("/monitor/setting", baseApi.LoadMonitorSetting)
+2
View File
@@ -16,6 +16,8 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
settingRouter.POST("/update", baseApi.UpdateSetting)
settingRouter.GET("/get/:key", baseApi.GetSettingByKey)
settingRouter.POST("/description/save", baseApi.SaveDescription)
settingRouter.GET("/snapshot/load", baseApi.LoadSnapshotData)
settingRouter.POST("/snapshot", baseApi.CreateSnapshot)
settingRouter.POST("/snapshot/recreate", baseApi.RecreateSnapshot)
+1 -1
View File
@@ -42,11 +42,11 @@ func Start() {
i18n.Init()
cache.Init()
app.Init()
firewall.Init()
lang.Init()
validator.Init()
cron.Run()
hook.Init()
go firewall.Init()
InitOthers()
rootRouter := router.Routers()
+17
View File
@@ -120,6 +120,23 @@ func (x XpuSMI) LoadDashData() ([]XPUSimpleInfo, error) {
return res, nil
}
func (x XpuSMI) LoadDeviceList() ([]string, error) {
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(5 * time.Second))
data, err := cmdMgr.RunWithStdoutBashC("xpu-smi discovery -j")
if err != nil {
return nil, fmt.Errorf("calling xpu-smi failed, %v", err)
}
var deviceInfo DeviceInfo
if err := json.Unmarshal([]byte(data), &deviceInfo); err != nil {
return nil, fmt.Errorf("deviceInfo json unmarshal failed, err: %w", err)
}
var deviceNames []string
for _, device := range deviceInfo.DeviceList {
deviceNames = append(deviceNames, fmt.Sprintf("%d - %s", device.DeviceID, device.DeviceName))
}
return deviceNames, nil
}
func (x XpuSMI) LoadGpuInfo() (*XpuInfo, error) {
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(5 * time.Second))
data, err := cmdMgr.RunWithStdoutBashC("xpu-smi discovery -j")
+5 -5
View File
@@ -65,12 +65,12 @@ func AnalysisFromLog(pathItem string, record *model.ClamRecord) {
func StopAllClamJob(withCheck bool, clamRepo repo.IClamRepo) bool {
if withCheck {
isActive := false
isexist, _ := controller.CheckExist("clam")
if isexist {
isActive, _ = controller.CheckActive("clam")
isExist, _ := controller.CheckExist("clam")
if !isExist {
return false
}
if isActive {
isActive, _ := controller.CheckActive("clam")
if !isActive {
return false
}
}
@@ -72,16 +72,6 @@ func NewAutoAuth(login string, secret string) Authorizer {
return az
}
func NewEmptyAuth() Authorizer {
fmap := make([]authfactory, 0)
az := &authorizer{factories: fmap, defAuthMux: sync.Mutex{}, defAuth: &nullAuth{}}
return az
}
func NewPreemptiveAuth(auth Authenticator) Authorizer {
return &preemptiveAuthorizer{auth: auth}
}
func (a *authorizer) NewAuthenticator(body io.Reader) (Authenticator, io.Reader) {
var retryBuf io.Reader = body
if body != nil {
@@ -296,11 +286,3 @@ func (n *nullAuth) Clone() Authenticator {
func (n *nullAuth) String() string {
return "NullAuth"
}
func (b *preemptiveAuthorizer) NewAuthenticator(body io.Reader) (Authenticator, io.Reader) {
return b.auth.Clone(), body
}
func (b *preemptiveAuthorizer) AddAuthenticator(key string, fn AuthFactory) {
panic("You're funny! A preemptive authorizer may only have a single authentication method")
}
@@ -1,7 +1,6 @@
package webdav
import (
"bytes"
"encoding/xml"
"io"
"net/url"
@@ -63,13 +62,6 @@ func Join(path0 string, path1 string) string {
return strings.TrimSuffix(path0, "/") + "/" + strings.TrimPrefix(path1, "/")
}
func String(r io.Reader) string {
buf := new(bytes.Buffer)
// TODO - make String return an error as well
_, _ = buf.ReadFrom(r)
return buf.String()
}
func parseInt64(s *string) int64 {
if n, e := strconv.ParseInt(*s, 10, 64); e == nil {
return n
@@ -197,7 +197,7 @@ func (c *Client) MkdirAll(path string, _ os.FileMode) (err error) {
return fmt.Errorf("mkdir %s failed, err: %v", item, err)
}
defer rs.Body.Close()
if rs.StatusCode != 201 || rs.StatusCode == 200 {
if rs.StatusCode != 201 && rs.StatusCode != 200 {
return fmt.Errorf("mkdir %s failed, code: %d, err: %v", item, rs.StatusCode, rs.Status)
}
}
+72 -52
View File
@@ -1,20 +1,25 @@
package client
import (
"context"
"errors"
"os"
"strings"
"time"
"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"
"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"
)
type s3Client struct {
scType string
bucket string
Sess session.Session
client *s3.Client
}
func NewS3Client(vars map[string]interface{}) (*s3Client, error) {
@@ -31,22 +36,26 @@ func NewS3Client(vars map[string]interface{}) (*s3Client, error) {
if len(mode) == 0 {
mode = "virtual hosted"
}
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"),
})
cfg, err := config.LoadDefaultConfig(context.Background(),
config.WithRegion(region),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")),
)
if err != nil {
return nil, err
}
return &s3Client{scType: scType, bucket: bucket, Sess: *sess}, nil
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
}
func (s s3Client) ListBuckets() ([]interface{}, error) {
func (s *s3Client) ListBuckets() ([]interface{}, error) {
var result []interface{}
svc := s3.New(&s.Sess)
res, err := svc.ListBuckets(nil)
res, err := s.client.ListBuckets(context.Background(), &s3.ListBucketsInput{})
if err != nil {
return nil, err
}
@@ -56,50 +65,54 @@ func (s s3Client) ListBuckets() ([]interface{}, error) {
return result, nil
}
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 {
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":
return false, nil
}
} else {
return false, aerr
}
return false, err
}
return true, nil
}
func (s *s3Client) Size(path string) (int64, error) {
svc := s3.New(&s.Sess)
file, err := svc.GetObject(&s3.GetObjectInput{
Bucket: &s.bucket,
Key: &path,
file, err := s.client.GetObject(context.Background(), &s3.GetObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(path),
})
if err != nil {
return 0, err
}
return *file.ContentLength, nil
defer file.Body.Close()
return aws.ToInt64(file.ContentLength), nil
}
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{
func (s *s3Client) Delete(path string) (bool, error) {
if _, err := s.client.DeleteObject(context.Background(), &s3.DeleteObjectInput{
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
@@ -110,22 +123,23 @@ func (s s3Client) Upload(src, target string) (bool, error) {
}
defer file.Close()
uploader := s3manager.NewUploader(&s.Sess)
if fileInfo.Size() > s3manager.MaxUploadParts*s3manager.DefaultUploadPartSize {
uploader.PartSize = fileInfo.Size() / (s3manager.MaxUploadParts - 1)
uploader := manager.NewUploader(s.client)
maxUploadSize := int64(manager.MaxUploadParts) * manager.DefaultUploadPartSize
if fileInfo.Size() > maxUploadSize {
uploader.PartSize = fileInfo.Size() / (int64(manager.MaxUploadParts) - 1)
}
if _, err := uploader.Upload(&s3manager.UploadInput{
if _, err := uploader.Upload(context.Background(), &s3.PutObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(target),
Body: file,
StorageClass: &s.scType,
StorageClass: types.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)
}
@@ -134,8 +148,8 @@ func (s s3Client) Download(src, target string) (bool, error) {
return false, err
}
defer file.Close()
downloader := s3manager.NewDownloader(&s.Sess)
if _, err = downloader.Download(file, &s3.GetObjectInput{
downloader := manager.NewDownloader(s.client)
if _, err = downloader.Download(context.Background(), file, &s3.GetObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(src),
}); err != nil {
@@ -146,17 +160,23 @@ 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 := svc.ListObjects(&s3.ListObjectsInput{
Bucket: &s.bucket,
Prefix: &prefix,
outputs, err := s.client.ListObjectsV2(context.Background(), &s3.ListObjectsV2Input{
Bucket: aws.String(s.bucket),
Prefix: aws.String(prefix),
})
if err != nil {
return result, err
}
for _, item := range outputs.Contents {
result = append(result, *item.Key)
result = append(result, aws.ToString(item.Key))
}
return result, nil
}
func normalizeEndpoint(endpoint string) string {
if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") {
return endpoint
}
return "http://" + endpoint
}
+2 -2
View File
@@ -2,8 +2,8 @@ package client
import (
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
"os"
"path"
@@ -25,7 +25,7 @@ func NewWebDAVClient(vars map[string]interface{}) (*webDAVClient, error) {
username := loadParamFromVars("username", vars)
bucket := loadParamFromVars("bucket", vars)
url := net.JoinHostPort(address, port)
url := fmt.Sprintf("%s:%s", address, port)
if len(port) == 0 {
url = address
}
+3 -2
View File
@@ -71,8 +71,9 @@ func GetDBWithPath(dbPath string) (*gorm.DB, error) {
if dbError != nil {
return nil, dbError
}
sqlDB.SetConnMaxIdleTime(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetMaxOpenConns(4)
sqlDB.SetMaxIdleConns(1)
sqlDB.SetConnMaxIdleTime(15 * time.Minute)
sqlDB.SetConnMaxLifetime(time.Hour)
return db, nil
}
+63 -1
View File
@@ -1,11 +1,21 @@
package compose
import (
"errors"
"fmt"
"os"
"path"
"strings"
"time"
"github.com/1Panel-dev/1Panel/agent/app/task"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"time"
"github.com/1Panel-dev/1Panel/agent/utils/docker"
"github.com/goccy/go-yaml"
)
func checkCmd() error {
@@ -27,6 +37,58 @@ func Up(filePath string) (string, error) {
return stdout, err
}
func UpWithTask(filePath string, task *task.Task) error {
content, err := os.ReadFile(filePath)
if err != nil {
return err
}
env, _ := os.ReadFile(path.Join(path.Dir(filePath), ".env"))
var compose docker.ComposeProject
if err := yaml.Unmarshal(content, &compose); err != nil {
return fmt.Errorf("parse docker-compose file failed: %v", err)
}
images, err := docker.GetImagesFromDockerCompose(env, content)
if err != nil {
return err
}
dockerCLi, err := docker.NewClient()
if err != nil {
return err
}
errMsg := ""
for _, image := range images {
task.Log(i18n.GetWithName("PullImageStart", image))
if err = dockerCLi.PullImageWithProcess(task, image); err != nil {
errOur := err.Error()
if errOur != "" {
if strings.Contains(errOur, "no such host") {
errMsg = i18n.GetMsgByKey("ErrNoSuchHost") + ":"
}
if strings.Contains(errOur, "Error response from daemon") {
errMsg = i18n.GetMsgByKey("PullImageTimeout") + ":"
}
}
message := errMsg + errOur
installErr := errors.New(message)
task.LogFailedWithErr(i18n.GetMsgByKey("PullImage"), installErr)
if exist, _ := dockerCLi.ImageExists(image); !exist {
return installErr
} else {
task.Log(i18n.GetMsgByKey("UseExistImage"))
}
} else {
task.Log(i18n.GetMsgByKey("PullImageSuccess"))
}
}
dockerCommand := global.CONF.DockerConfig.Command
if dockerCommand == "docker-compose" {
return cmd.NewCommandMgr(cmd.WithTask(*task)).Run("docker-compose", "-f", filePath, "up", "-d")
} else {
return cmd.NewCommandMgr(cmd.WithTask(*task)).Run("docker", "compose", "-f", filePath, "up", "-d")
}
}
func Down(filePath string) (string, error) {
if err := checkCmd(); err != nil {
return "", err
+6 -6
View File
@@ -129,18 +129,18 @@ func RestartPanel(core, agent, reload bool) {
return
}
}
if agent {
if err := client.Operate("restart", "1panel-agent"); err != nil {
global.LOG.Errorf("restart 1panel agent service failed, err: %v", err)
return
}
}
if core {
if err := client.Operate("restart", "1panel-core"); err != nil {
global.LOG.Errorf("restart 1panel core service failed, err: %v", err)
return
}
}
if agent {
if err := client.Operate("restart", "1panel-agent"); err != nil {
global.LOG.Errorf("restart 1panel agent service failed, err: %v", err)
return
}
}
}
func LoadServiceName(keyword string) (string, error) {
+3 -3
View File
@@ -26,10 +26,10 @@ func (s *Systemd) IsActive(serviceName string) (bool, error) {
func (s *Systemd) IsEnable(serviceName string) (bool, error) {
out, err := run(s.toolCmd, "is-enabled", serviceName)
if out == "alias\n" && serviceName == "sshd.service" {
return s.IsEnable("ssh")
}
if err != nil && out != "disabled\n" {
if serviceName == "sshd" && out == "alias\n" {
return s.IsEnable("ssh")
}
if NewSnap().IsEnable(serviceName) {
return true, nil
}
+46
View File
@@ -33,6 +33,40 @@ import (
"github.com/spf13/afero"
)
var protectedPaths = []string{
"/",
"/bin",
"/sbin",
"/etc",
"/boot",
"/usr",
"/lib",
"/lib64",
"/dev",
"/proc",
"/sys",
"/root",
}
func IsProtected(path string) bool {
real, err := filepath.EvalSymlinks(path)
if err == nil {
path = real
}
abs, err := filepath.Abs(path)
if err == nil {
path = abs
}
for _, p := range protectedPaths {
if path == p {
return true
}
}
return false
}
type FileOp struct {
Fs afero.Fs
}
@@ -104,6 +138,9 @@ func (f FileOp) LinkFile(source string, dst string, isSymlink bool) error {
}
func (f FileOp) DeleteDir(dst string) error {
if IsProtected(dst) {
return buserr.New("ErrPathNotDelete")
}
return f.Fs.RemoveAll(dst)
}
@@ -113,14 +150,23 @@ func (f FileOp) Stat(dst string) bool {
}
func (f FileOp) DeleteFile(dst string) error {
if IsProtected(dst) {
return buserr.New("ErrPathNotDelete")
}
return f.Fs.Remove(dst)
}
func (f FileOp) CleanDir(dst string) error {
if IsProtected(dst) {
return buserr.New("ErrPathNotDelete")
}
return cmd.RunDefaultBashCf("rm -rf %s/*", dst)
}
func (f FileOp) RmRf(dst string) error {
if IsProtected(dst) {
return buserr.New("ErrPathNotDelete")
}
return cmd.RunDefaultBashCf("rm -rf %s", dst)
}
+143 -67
View File
@@ -3,6 +3,15 @@ package files
import (
"bufio"
"fmt"
"io"
"net/http"
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
"sync"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/1Panel-dev/1Panel/agent/constant"
@@ -14,13 +23,11 @@ import (
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/encoding/traditionalchinese"
"golang.org/x/text/encoding/unicode"
"io"
"net/http"
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
)
const (
MaxReadFileSize = 512 * 1024 * 1024
tailBufSize = int64(32768)
)
func IsSymlink(mode os.FileMode) bool {
@@ -78,27 +85,33 @@ func IsHidden(path string) bool {
return len(base) > 1 && base[0] == dotCharacter
}
func countLines(path string) (int, error) {
file, err := os.Open(path)
if err != nil {
return 0, err
}
defer file.Close()
reader := bufio.NewReader(file)
count := 0
for {
_, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
if count > 0 {
count++
}
return count, nil
}
return count, err
var readerPool = sync.Pool{
New: func() interface{} {
return bufio.NewReaderSize(nil, 8192)
},
}
var tailBufPool = sync.Pool{
New: func() interface{} {
buf := make([]byte, tailBufSize)
return &buf
},
}
func readLineTrimmed(reader *bufio.Reader) (string, error) {
line, err := reader.ReadString('\n')
if err == io.EOF {
if len(line) == 0 {
return "", io.EOF
}
count++
err = nil
}
if err != nil {
return "", err
}
line = strings.TrimSuffix(line, "\n")
line = strings.TrimSuffix(line, "\r")
return line, nil
}
func TailFromEnd(filename string, lines int) ([]string, error) {
@@ -114,24 +127,26 @@ func TailFromEnd(filename string, lines int) ([]string, error) {
}
fileSize := stat.Size()
bufSize := int64(4096)
bufPtr := tailBufPool.Get().(*[]byte)
buf := *bufPtr
defer tailBufPool.Put(bufPtr)
var result []string
var leftover string
for offset := fileSize; offset > 0 && len(result) < lines; {
readSize := bufSize
if offset < bufSize {
readSize := tailBufSize
if offset < tailBufSize {
readSize = offset
}
offset -= readSize
buf := make([]byte, readSize)
_, err := file.ReadAt(buf, offset)
_, err := file.ReadAt(buf[:readSize], offset)
if err != nil && err != io.EOF {
return nil, err
}
data := string(buf) + leftover
data := string(buf[:readSize]) + leftover
linesInChunk := strings.Split(data, "\n")
if offset > 0 {
@@ -142,20 +157,28 @@ func TailFromEnd(filename string, lines int) ([]string, error) {
}
for i := len(linesInChunk) - 1; i >= 0; i-- {
if len(result) < lines {
if !(i == len(linesInChunk)-1 && linesInChunk[i] == "" && len(result) == 0) {
result = append([]string{linesInChunk[i]}, result...)
}
if len(result) >= lines {
break
}
if i == len(linesInChunk)-1 && linesInChunk[i] == "" && len(result) == 0 {
continue
}
// 反插数据
result = append(result, linesInChunk[i])
}
}
if leftover != "" && len(result) < lines {
result = append([]string{leftover}, result...)
result = append(result, leftover)
}
if len(result) > lines {
result = result[len(result)-lines:]
result = result[:lines]
}
// 反转数据
for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
result[i], result[j] = result[j], result[i]
}
return result, nil
@@ -165,6 +188,10 @@ func ReadFileByLine(filename string, page, pageSize int, latest bool) (res *dto.
if !NewFileOp().Stat(filename) {
return
}
if pageSize <= 0 {
err = fmt.Errorf("pageSize must be positive")
return
}
file, err := os.Open(filename)
if err != nil {
return
@@ -176,43 +203,92 @@ func ReadFileByLine(filename string, page, pageSize int, latest bool) (res *dto.
return
}
if fi.Size() > 500*1024*1024 {
if fi.Size() > MaxReadFileSize {
err = buserr.New("ErrLogFileToLarge")
return
}
totalLines, err := countLines(filename)
if err != nil {
return
}
res = &dto.LogFileRes{}
total := (totalLines + pageSize - 1) / pageSize
res.TotalPages = total
res.TotalLines = totalLines
reader := bufio.NewReaderSize(file, 8192)
reader := readerPool.Get().(*bufio.Reader)
reader.Reset(file)
defer readerPool.Put(reader)
if latest {
page = total
ringBuf := make([]string, pageSize)
writeIdx := 0
totalLines := 0
for {
line, readErr := readLineTrimmed(reader)
if readErr == io.EOF {
break
}
if readErr != nil {
err = readErr
return
}
ringBuf[writeIdx%pageSize] = line
writeIdx++
totalLines++
}
if totalLines == 0 {
res.Lines = []string{}
res.TotalLines = 0
res.TotalPages = 0
res.IsEndOfFile = true
return
}
total := (totalLines + pageSize - 1) / pageSize
res.TotalPages = total
res.TotalLines = totalLines
lastPageSize := totalLines % pageSize
if lastPageSize == 0 {
lastPageSize = pageSize
}
if lastPageSize > totalLines {
lastPageSize = totalLines
}
result := make([]string, 0, lastPageSize)
startIdx := writeIdx - lastPageSize
for i := 0; i < lastPageSize; i++ {
idx := (startIdx + i) % pageSize
result = append(result, ringBuf[idx])
}
res.Lines = result
res.IsEndOfFile = true
} else {
startLine := (page - 1) * pageSize
endLine := startLine + pageSize
currentLine := 0
lines := make([]string, 0, pageSize)
for {
line, readErr := readLineTrimmed(reader)
if readErr == io.EOF {
break
}
if readErr != nil {
err = readErr
return
}
if currentLine >= startLine && currentLine < endLine {
lines = append(lines, line)
}
currentLine++
}
res.Lines = lines
res.TotalLines = currentLine
total := (currentLine + pageSize - 1) / pageSize
res.TotalPages = total
res.IsEndOfFile = page >= total
}
currentLine := 0
startLine := (page - 1) * pageSize
endLine := startLine + pageSize
lines := make([]string, 0, pageSize)
for {
line, _, err := reader.ReadLine()
if err == io.EOF {
break
}
if currentLine >= startLine && currentLine < endLine {
lines = append(lines, string(line))
}
currentLine++
if currentLine >= endLine {
break
}
}
res.Lines = lines
res.IsEndOfFile = currentLine < endLine
return
}

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