mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 16:00:29 +00:00
Compare commits
174
Commits
release-2.0.16
...
v2.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c3f56516f | ||
|
|
4833cf2d3c | ||
|
|
b5ca015632 | ||
|
|
1c82034111 | ||
|
|
e45d723f3d | ||
|
|
627e6852db | ||
|
|
1725767789 | ||
|
|
3e1f2b4934 | ||
|
|
140d20a21d | ||
|
|
6e933fc83c | ||
|
|
79ff565995 | ||
|
|
39691698c9 | ||
|
|
4bedddb557 | ||
|
|
f9547752f5 | ||
|
|
96b37cb024 | ||
|
|
30d874bc91 | ||
|
|
32bc8d922b | ||
|
|
a95d9aa27a | ||
|
|
7f4f5a0a47 | ||
|
|
65a7193bc6 | ||
|
|
64f79b4fdd | ||
|
|
31d2af554e | ||
|
|
e0f2910710 | ||
|
|
f89ab607b4 | ||
|
|
61fa07b8f2 | ||
|
|
9653df185a | ||
|
|
8f7d3df76d | ||
|
|
2aa89699c1 | ||
|
|
46b8d3bd80 | ||
|
|
8a7be481b0 | ||
|
|
21bd94d3a3 | ||
|
|
d337190b59 | ||
|
|
7073e83d94 | ||
|
|
537ff49c0b | ||
|
|
4b1f643c70 | ||
|
|
b8b873836d | ||
|
|
021334c2c8 | ||
|
|
635d86a1a5 | ||
|
|
607eae3ca8 | ||
|
|
66428c0a8e | ||
|
|
c0404a4ec5 | ||
|
|
77ef3b7096 | ||
|
|
498052f4c9 | ||
|
|
958c55eab8 | ||
|
|
d3cddd175a | ||
|
|
6cd130677e | ||
|
|
33b90e3979 | ||
|
|
e1e2b97e88 | ||
|
|
8e4e1dc749 | ||
|
|
1eb5830238 | ||
|
|
5db2ccbb22 | ||
|
|
47e04a14ad | ||
|
|
a13c58eb18 | ||
|
|
15d77ceb46 | ||
|
|
af8fa6763f | ||
|
|
ed66d22bdb | ||
|
|
5209db3abc | ||
|
|
35ea1a1d6c | ||
|
|
b0a053b397 | ||
|
|
a8b3390ce9 | ||
|
|
4266e39d84 | ||
|
|
5620b6e736 | ||
|
|
289e4190ff | ||
|
|
9250412296 | ||
|
|
9c5370508e | ||
|
|
a145bfdc5b | ||
|
|
db2b38eedb | ||
|
|
9303ee399f | ||
|
|
d64cb3dc58 | ||
|
|
62871acfbb | ||
|
|
7401906b03 | ||
|
|
5aa3c29684 | ||
|
|
91745f592f | ||
|
|
564333ea03 | ||
|
|
7b543ea5fe | ||
|
|
fc5e583481 | ||
|
|
1767b1a9c1 | ||
|
|
930c340e37 | ||
|
|
58531d3995 | ||
|
|
4b7c1390fb | ||
|
|
2337d6f13a | ||
|
|
cb8ecd55ed | ||
|
|
33ad31dba2 | ||
|
|
294c3f128b | ||
|
|
0899f4e9db | ||
|
|
788f4d8307 | ||
|
|
2451d6bed2 | ||
|
|
c547de875a | ||
|
|
ffead783aa | ||
|
|
d742c7d333 | ||
|
|
1025cd3535 | ||
|
|
de402ea724 | ||
|
|
3af07a42d6 | ||
|
|
e5b7e99cce | ||
|
|
365936bf57 | ||
|
|
2b7562f546 | ||
|
|
e7f4e312b9 | ||
|
|
98d3870477 | ||
|
|
b1ceb2e53d | ||
|
|
075d2468ea | ||
|
|
8b9e7aef4a | ||
|
|
15e499c1e9 | ||
|
|
55ccb9fe61 | ||
|
|
a5816f1dc9 | ||
|
|
95a613f59f | ||
|
|
6777941dee | ||
|
|
e55128b7fa | ||
|
|
9ac11002f8 | ||
|
|
1cc7bfb4a9 | ||
|
|
e59534e54f | ||
|
|
8c2368c1d2 | ||
|
|
8e8f181cae | ||
|
|
2fcab77565 | ||
|
|
d29f0c6c31 | ||
|
|
79f1b1458b | ||
|
|
b279ee6b82 | ||
|
|
c64a58d814 | ||
|
|
57c60ab3f8 | ||
|
|
e37d90d6e1 | ||
|
|
22055ed99a | ||
|
|
e263331b94 | ||
|
|
eb3d613e3d | ||
|
|
cc23444776 | ||
|
|
1931d3f262 | ||
|
|
79cbbbdf0a | ||
|
|
38cd785aa3 | ||
|
|
dabec3f87a | ||
|
|
6c94cb2bdf | ||
|
|
f67bdf0c22 | ||
|
|
6c51b31270 | ||
|
|
ef6e342737 | ||
|
|
ac0ef98dde | ||
|
|
523775e56b | ||
|
|
b6e741a150 | ||
|
|
54357fbe2b | ||
|
|
040dda5bec | ||
|
|
77b4d58fb8 | ||
|
|
0c9e551492 | ||
|
|
2ba1e2e22e | ||
|
|
d8a08a6c0c | ||
|
|
2c92226f88 | ||
|
|
cd9cb9b9c9 | ||
|
|
b2777055bc | ||
|
|
c8673b60bb | ||
|
|
21975dff2d | ||
|
|
6ab14185e0 | ||
|
|
1f70646952 | ||
|
|
c90ed9e873 | ||
|
|
e4ee07d36b | ||
|
|
8fb3e78554 | ||
|
|
01ab004876 | ||
|
|
6205eac51c | ||
|
|
d9a5418029 | ||
|
|
74a8e61f3e | ||
|
|
e18472f1a3 | ||
|
|
e3dea80cb7 | ||
|
|
50947f4ddc | ||
|
|
d302bc07b3 | ||
|
|
c6df20e565 | ||
|
|
6f9a1321d1 | ||
|
|
eb4eb31578 | ||
|
|
f8f5fcfca2 | ||
|
|
4e7b654090 | ||
|
|
e8059d3676 | ||
|
|
ffadc6721b | ||
|
|
e2e774d215 | ||
|
|
f23d3678fb | ||
|
|
dfade50bd8 | ||
|
|
d25b5f4f2a | ||
|
|
9a17bc74b0 | ||
|
|
015605526d | ||
|
|
099896dc96 | ||
|
|
aa1bc6fa8e | ||
|
|
f27a429fc5 |
+13
-2
@@ -44,12 +44,17 @@ frontend/src/xpack
|
||||
agent/xpack
|
||||
agent/router/entry_xpack.go
|
||||
agent/server/init_xpack.go
|
||||
agent/utils/xpack/xpack.go
|
||||
agent/utils/xpack/xpack_xpack.go
|
||||
core/xpack
|
||||
core/router/entry_xpack.go
|
||||
core/server/init_xpack.go
|
||||
core/utils/xpack/xpack.go
|
||||
core/utils/xpack/xpack_xpack.go
|
||||
xpack
|
||||
core/xpack-ee
|
||||
core/router/entry_xpackee.go
|
||||
core/server/init_xpackee.go
|
||||
core/utils/xpack/xpack_xpackee.go
|
||||
|
||||
.history/
|
||||
dist/
|
||||
@@ -62,4 +67,10 @@ cmd/server/fileList.txt
|
||||
1Panel.code-workspace
|
||||
|
||||
core/.golangci.yml
|
||||
agent/.golangci.yml
|
||||
agent/.golangci.yml
|
||||
|
||||
.opencode
|
||||
openspec
|
||||
CLAUDE.md
|
||||
AGENTS.md
|
||||
opencode.json
|
||||
@@ -1,5 +1,4 @@
|
||||
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
|
||||
<p align="center"><b>Top-Rated Web-based Linux Server Management Tool</b><br>Best VPS control panel<br>新一代的 Linux 服务器运维管理面板</p>
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 240px; height: auto;" /></a>
|
||||
</p>
|
||||
@@ -30,27 +29,38 @@
|
||||
</p>
|
||||
|
||||
------------------------------
|
||||
## What is 1Panel?
|
||||
|
||||
1Panel is an open-source, modern web-based control panel for Linux server management.
|
||||
1Panel is a modern, open-source Linux server management panel that streamlines administration through an intuitive, clean web interface.
|
||||
|
||||
- **Efficient Management**: Through a user-friendly web graphical interface, 1Panel enables users to effortlessly manage their Linux servers. Key features include host monitoring, file management, database administration, container management, LLMs management.
|
||||
- **Rapid Website Deployment**: With deep integration of the popular open-source website building software WordPress, 1Panel streamlines the process of domain binding and SSL certificate configuration, all achievable with just one click.
|
||||
- **Application Store**: 1Panel curates a wide range of high-quality open-source tools and applications, facilitating easy installation and updates for its users.
|
||||
- **Security and Reliability**: By leveraging containerization and secure application deployment practices, 1Panel minimizes vulnerability exposure. It further enhances security through integrated firewall management and log auditing capabilities.
|
||||
- **One-Click Backup & Restore**: Data protection is made simple with 1Panel's one-click backup and restore functionality, supporting various cloud storage solutions to ensure data integrity and availability.
|
||||
## Key Features
|
||||
|
||||
🔹 **AI Integration**
|
||||
Seamlessly deploy OpenClaw agents, host local LLMs via Ollama, and monitor GPU utilization—all within a unified workspace engineered for efficient AI development and inference.
|
||||
|
||||
🔹 **One-Click Website Deployment**
|
||||
Launch production-ready websites instantly with automatic domain binding, SSL certificate provisioning, and configuration—zero manual setup required.
|
||||
|
||||
🔹 **Curated App Marketplace**
|
||||
Discover, install, and update trusted open-source applications (WordPress, MySQL, Redis, and more) with a single click.
|
||||
|
||||
🔹 **Centralized Server Management**
|
||||
Monitor system resources and manage files, databases, containers, and services effortlessly through a unified, intuitive dashboard.
|
||||
|
||||
🔹 **Enterprise-Grade Security**
|
||||
Strengthen defenses with container isolation, firewall controls, audit logging, and secure deployment practices—ensuring compliance and peace of mind.
|
||||
|
||||
🔹 **Intelligent Backup & Restore**
|
||||
Schedule automated backups or perform instant restores to local storage or leading cloud platforms (AWS S3, Cloudflare R2, and more), with flexible retention and destination options.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Execute the script below and follow the prompts to install 1Panel:
|
||||
|
||||
```bash
|
||||
curl -sSL https://resource.1panel.pro/quick_start.sh -o quick_start.sh && bash quick_start.sh
|
||||
bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)"
|
||||
```
|
||||
|
||||
Please refer to our [documentation](https://docs.1panel.pro/quick_start/) for more details.
|
||||
|
||||
中国用户请使用这个 [安装脚本](https://1panel.cn/docs/installation/online_installation/),其应用数量比国际版本更丰富。
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||
@@ -73,4 +83,4 @@ Licensed under The GNU General Public License version 3 (GPLv3) (the "License")
|
||||
|
||||
<https://www.gnu.org/licenses/gpl-3.0.html>
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Create Agent
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentCreateReq true "request"
|
||||
// @Success 200 {object} dto.AgentItem
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents [post]
|
||||
func (b *BaseApi) CreateAgent(c *gin.Context) {
|
||||
var req dto.AgentCreateReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
res, err := agentService.Create(req)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Page Agents
|
||||
// @Accept json
|
||||
// @Param request body dto.SearchWithPage true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/search [post]
|
||||
func (b *BaseApi) PageAgents(c *gin.Context) {
|
||||
var req dto.SearchWithPage
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
total, list, err := agentService.Page(req)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Delete Agent
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/delete [post]
|
||||
func (b *BaseApi) DeleteAgent(c *gin.Context) {
|
||||
var req dto.AgentDeleteReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.Delete(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Reset Agent token
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentTokenResetReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/token/reset [post]
|
||||
func (b *BaseApi) ResetAgentToken(c *gin.Context) {
|
||||
var req dto.AgentTokenResetReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.ResetToken(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Update Agent model config
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentModelConfigUpdateReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/model/update [post]
|
||||
func (b *BaseApi) UpdateAgentModelConfig(c *gin.Context) {
|
||||
var req dto.AgentModelConfigUpdateReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.UpdateModelConfig(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Get Providers
|
||||
// @Success 200 {object} []dto.ProviderInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/providers [get]
|
||||
func (b *BaseApi) GetAgentProviders(c *gin.Context) {
|
||||
list, err := agentService.GetProviders()
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Create Agent account
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentAccountCreateReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/accounts [post]
|
||||
func (b *BaseApi) CreateAgentAccount(c *gin.Context) {
|
||||
var req dto.AgentAccountCreateReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.CreateAccount(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Update Agent account
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentAccountUpdateReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/accounts/update [post]
|
||||
func (b *BaseApi) UpdateAgentAccount(c *gin.Context) {
|
||||
var req dto.AgentAccountUpdateReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.UpdateAccount(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Page Agent accounts
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentAccountSearch true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/accounts/search [post]
|
||||
func (b *BaseApi) PageAgentAccounts(c *gin.Context) {
|
||||
var req dto.AgentAccountSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
total, list, err := agentService.PageAccounts(req)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Verify Agent account
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentAccountVerifyReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/accounts/verify [post]
|
||||
func (b *BaseApi) VerifyAgentAccount(c *gin.Context) {
|
||||
var req dto.AgentAccountVerifyReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.VerifyAccount(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Delete Agent account
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentAccountDeleteReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/accounts/delete [post]
|
||||
func (b *BaseApi) DeleteAgentAccount(c *gin.Context) {
|
||||
var req dto.AgentAccountDeleteReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.DeleteAccount(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Get Agent Feishu channel config
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentFeishuConfigReq true "request"
|
||||
// @Success 200 {object} dto.AgentFeishuConfig
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/channel/feishu/get [post]
|
||||
func (b *BaseApi) GetAgentFeishuConfig(c *gin.Context) {
|
||||
var req dto.AgentFeishuConfigReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
data, err := agentService.GetFeishuConfig(req)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Update Agent Feishu channel config
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentFeishuConfigUpdateReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/channel/feishu/update [post]
|
||||
func (b *BaseApi) UpdateAgentFeishuConfig(c *gin.Context) {
|
||||
var req dto.AgentFeishuConfigUpdateReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.UpdateFeishuConfig(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags AI
|
||||
// @Summary Approve Agent Feishu pairing code
|
||||
// @Accept json
|
||||
// @Param request body dto.AgentFeishuPairingApproveReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /ai/agents/channel/feishu/approve [post]
|
||||
func (b *BaseApi) ApproveAgentFeishuPairing(c *gin.Context) {
|
||||
var req dto.AgentFeishuPairingApproveReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agentService.ApproveFeishuPairing(req); err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
+42
-9
@@ -2,12 +2,12 @@ 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"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/appicon"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -164,7 +164,7 @@ func (b *BaseApi) InstallApp(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
install, err := appService.Install(req)
|
||||
install, err := appService.Install(req, true)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
@@ -203,20 +203,53 @@ func (b *BaseApi) GetAppListUpdate(c *gin.Context) {
|
||||
// @Success 200 {file} file "app icon"
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /apps/icon/:appId [get]
|
||||
// @Router /apps/icon/:key [get]
|
||||
func (b *BaseApi) GetAppIcon(c *gin.Context) {
|
||||
appID, err := helper.GetIntParamByKey(c, "appID")
|
||||
appKey, err := helper.GetStrParamByKey(c, "key")
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
iconBytes, err := appService.GetAppIcon(appID)
|
||||
iconBytes, filename, etag, err := appService.GetAppIcon(appKey)
|
||||
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)
|
||||
|
||||
if len(iconBytes) == 0 {
|
||||
c.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Cache-Control", "public, max-age=2592000")
|
||||
|
||||
if etag != "" && filename != "" {
|
||||
c.Header("ETag", etag)
|
||||
if c.GetHeader("If-None-Match") == etag {
|
||||
c.Status(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Data(http.StatusOK, appicon.ContentTypePNG, iconBytes)
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Search app detail by appkey and version
|
||||
// @Accept json
|
||||
// @Param appId path integer true "app key"
|
||||
// @Param version path string true "app version"
|
||||
// @Success 200 {object} response.AppDetailSimpleDTO
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /apps/detail/node/:appKey/:version [get]
|
||||
func (b *BaseApi) GetAppDetailForNode(c *gin.Context) {
|
||||
appKey := c.Param("appKey")
|
||||
version := c.Param("version")
|
||||
appDetailDTO, err := appService.GetAppDetailByKey(appKey, version)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, appDetailDTO)
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ func (b *BaseApi) GetParams(c *gin.Context) {
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /apps/installed/params/update [post]
|
||||
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"应用参数修改 [installId]","formatEN":"Application param update [installId]"}
|
||||
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"name","output_value":"name"}],"formatZH":"应用参数修改 [name]","formatEN":"Application param update [name]"}
|
||||
func (b *BaseApi) UpdateInstalled(c *gin.Context) {
|
||||
var req request.AppInstalledUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
|
||||
@@ -529,7 +529,7 @@ func (b *BaseApi) DownloadContainerLogs(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := containerService.DownloadContainerLogs(req.ContainerType, req.Container, req.Since, strconv.Itoa(int(req.Tail)), c)
|
||||
err := containerService.DownloadContainerLogs(req.ContainerType, req.Container, req.Since, strconv.Itoa(int(req.Tail)), req.Timestamp, c)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
}
|
||||
@@ -731,12 +731,33 @@ func (b *BaseApi) ComposeUpdate(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Container Compose
|
||||
// @Summary Load compose environment variables
|
||||
// @Accept json
|
||||
// @Param request body dto.FilePath true "request"
|
||||
// @Success 200 {array} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /containers/compose/env [post]
|
||||
func (b *BaseApi) LoadComposeEnv(c *gin.Context) {
|
||||
var req dto.FilePath
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
data, err := containerService.LoadComposeEnv(req.Path)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Container
|
||||
// @Summary Container logs
|
||||
// @Param container query string false "容器名称"
|
||||
// @Param since query string false "时间筛选"
|
||||
// @Param follow query string false "是否追踪"
|
||||
// @Param tail query string false "显示行号"
|
||||
// @Param timestamp query string false "是否显示时间"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
@@ -750,6 +771,7 @@ func (b *BaseApi) ContainerStreamLogs(c *gin.Context) {
|
||||
since := c.Query("since")
|
||||
follow := c.Query("follow") == "true"
|
||||
tail := c.Query("tail")
|
||||
timestamp := c.Query("timestamp") == "true"
|
||||
|
||||
container := c.Query("container")
|
||||
compose := c.Query("compose")
|
||||
@@ -759,6 +781,7 @@ func (b *BaseApi) ContainerStreamLogs(c *gin.Context) {
|
||||
Since: since,
|
||||
Follow: follow,
|
||||
Tail: tail,
|
||||
Timestamp: timestamp,
|
||||
Type: "container",
|
||||
}
|
||||
if compose != "" {
|
||||
|
||||
@@ -20,6 +20,7 @@ var (
|
||||
aiToolService = service.NewIAIToolService()
|
||||
mcpServerService = service.NewIMcpServerService()
|
||||
tensorrtLLMService = service.NewITensorRTLLMService()
|
||||
agentService = service.NewIAgentService()
|
||||
|
||||
containerService = service.NewIContainerService()
|
||||
composeTemplateService = service.NewIComposeTemplateService()
|
||||
|
||||
@@ -978,3 +978,40 @@ func (b *BaseApi) ConvertLog(c *gin.Context) {
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Batch get file remarks
|
||||
// @Accept json
|
||||
// @Param request body request.FileRemarkBatch true "request"
|
||||
// @Success 200 {object} response.FileRemarksRes
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /files/remarks [post]
|
||||
func (b *BaseApi) BatchGetFileRemarks(c *gin.Context) {
|
||||
var req request.FileRemarkBatch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
remarks := fileService.BatchGetRemarks(req)
|
||||
helper.SuccessWithData(c, response.FileRemarksRes{Remarks: remarks})
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Set file remark
|
||||
// @Accept json
|
||||
// @Param request body request.FileRemarkUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /files/remark [post]
|
||||
func (b *BaseApi) SetFileRemark(c *gin.Context) {
|
||||
var req request.FileRemarkUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := fileService.SetRemark(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
@@ -57,3 +57,18 @@ func (b *BaseApi) GetProcessInfoByPID(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Process
|
||||
// @Summary Get Listening Process
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /process/listening [post]
|
||||
func (b *BaseApi) GetListeningProcess(c *gin.Context) {
|
||||
procs, err := processService.GetListeningProcess(c)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, procs)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,10 @@ func (b *BaseApi) LoadLocalConn(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (b *BaseApi) CheckLocalConn(c *gin.Context) {
|
||||
_, err := loadLocalConn()
|
||||
client, err := loadLocalConn()
|
||||
if err == nil && client != nil {
|
||||
client.Close()
|
||||
}
|
||||
helper.SuccessWithData(c, err == nil)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
@@ -26,27 +25,39 @@ import (
|
||||
// @Router /websites/ssl/search [post]
|
||||
func (b *BaseApi) PageWebsiteSSL(c *gin.Context) {
|
||||
var req request.WebsiteSSLSearch
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
total, accounts, err := websiteSSLService.Page(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithDataGzipped(c, dto.PageResult{
|
||||
Total: total,
|
||||
Items: accounts,
|
||||
})
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
// @Summary List website ssl
|
||||
// @Accept json
|
||||
// @Param request body request.WebsiteSSLListReq true "request"
|
||||
// @Success 200 {array} response.WebsiteSSLDTO
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /websites/ssl/list [post]
|
||||
func (b *BaseApi) ListWebsiteSSL(c *gin.Context) {
|
||||
var req request.WebsiteSSLListReq
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(req.PageInfo, dto.PageInfo{}) {
|
||||
total, accounts, err := websiteSSLService.Page(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithDataGzipped(c, dto.PageResult{
|
||||
Total: total,
|
||||
Items: accounts,
|
||||
})
|
||||
} else {
|
||||
list, err := websiteSSLService.Search(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithDataGzipped(c, list)
|
||||
list, err := websiteSSLService.Search(req)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithDataGzipped(c, list)
|
||||
}
|
||||
|
||||
// @Tags Website SSL
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
package dto
|
||||
|
||||
import "time"
|
||||
|
||||
type AgentCreateReq struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
AppVersion string `json:"appVersion" validate:"required"`
|
||||
WebUIPort int `json:"webUIPort" validate:"required"`
|
||||
BridgePort int `json:"bridgePort" validate:"required"`
|
||||
Provider string `json:"provider" validate:"required"`
|
||||
Model string `json:"model" validate:"required"`
|
||||
AccountID uint `json:"accountId"`
|
||||
APIKey string `json:"apiKey"`
|
||||
BaseURL string `json:"baseURL"`
|
||||
Token string `json:"token"`
|
||||
TaskID string `json:"taskID"`
|
||||
Advanced bool `json:"advanced"`
|
||||
ContainerName string `json:"containerName"`
|
||||
AllowPort bool `json:"allowPort"`
|
||||
SpecifyIP string `json:"specifyIP"`
|
||||
RestartPolicy string `json:"restartPolicy"`
|
||||
CpuQuota float64 `json:"cpuQuota"`
|
||||
MemoryLimit float64 `json:"memoryLimit"`
|
||||
MemoryUnit string `json:"memoryUnit"`
|
||||
PullImage bool `json:"pullImage"`
|
||||
EditCompose bool `json:"editCompose"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
}
|
||||
|
||||
type AgentItem struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderName string `json:"providerName"`
|
||||
Model string `json:"model"`
|
||||
BaseURL string `json:"baseUrl"`
|
||||
APIKey string `json:"apiKey"`
|
||||
Token string `json:"token"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
AppInstallID uint `json:"appInstallId"`
|
||||
AccountID uint `json:"accountId"`
|
||||
AppVersion string `json:"appVersion"`
|
||||
Container string `json:"containerName"`
|
||||
WebUIPort int `json:"webUIPort"`
|
||||
BridgePort int `json:"bridgePort"`
|
||||
Path string `json:"path"`
|
||||
ConfigPath string `json:"configPath"`
|
||||
Upgradable bool `json:"upgradable"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
type AgentDeleteReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
TaskID string `json:"taskID"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
}
|
||||
|
||||
type AgentTokenResetReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type AgentModelConfigUpdateReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
AccountID uint `json:"accountId" validate:"required"`
|
||||
Model string `json:"model" validate:"required"`
|
||||
}
|
||||
|
||||
type AgentAccountCreateReq struct {
|
||||
Provider string `json:"provider" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
APIKey string `json:"apiKey" validate:"required"`
|
||||
BaseURL string `json:"baseURL"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type AgentAccountUpdateReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
APIKey string `json:"apiKey" validate:"required"`
|
||||
BaseURL string `json:"baseURL"`
|
||||
Remark string `json:"remark"`
|
||||
SyncAgents bool `json:"syncAgents"`
|
||||
}
|
||||
|
||||
type AgentAccountVerifyReq struct {
|
||||
Provider string `json:"provider" validate:"required"`
|
||||
APIKey string `json:"apiKey" validate:"required"`
|
||||
BaseURL string `json:"baseURL"`
|
||||
}
|
||||
|
||||
type AgentAccountDeleteReq struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type AgentAccountSearch struct {
|
||||
PageInfo
|
||||
Provider string `json:"provider"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type AgentAccountInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderName string `json:"providerName"`
|
||||
Name string `json:"name"`
|
||||
APIKey string `json:"apiKey"`
|
||||
BaseURL string `json:"baseUrl"`
|
||||
Verified bool `json:"verified"`
|
||||
Remark string `json:"remark"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
type ProviderModelInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ProviderInfo struct {
|
||||
Sort uint `json:"-"`
|
||||
Provider string `json:"provider"`
|
||||
DisplayName string `json:"displayName"`
|
||||
BaseURL string `json:"baseUrl"`
|
||||
Models []ProviderModelInfo `json:"models"`
|
||||
}
|
||||
|
||||
type AgentFeishuConfigReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
}
|
||||
|
||||
type AgentFeishuConfigUpdateReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
BotName string `json:"botName" validate:"required"`
|
||||
AppID string `json:"appId" validate:"required"`
|
||||
AppSecret string `json:"appSecret" validate:"required"`
|
||||
Enabled bool `json:"enabled"`
|
||||
DmPolicy string `json:"dmPolicy" validate:"required"`
|
||||
}
|
||||
|
||||
type AgentFeishuPairingApproveReq struct {
|
||||
AgentID uint `json:"agentId" validate:"required"`
|
||||
PairingCode string `json:"pairingCode" validate:"required"`
|
||||
}
|
||||
|
||||
type AgentFeishuConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
DmPolicy string `json:"dmPolicy"`
|
||||
BotName string `json:"botName"`
|
||||
AppID string `json:"appId"`
|
||||
AppSecret string `json:"appSecret"`
|
||||
}
|
||||
@@ -330,3 +330,13 @@ type AlertEmailConfig struct {
|
||||
Encryption string `json:"encryption"` // "ssl" / "tls" / "none"
|
||||
Recipient string `json:"recipient"`
|
||||
}
|
||||
|
||||
type AgentInfo struct {
|
||||
NodeName string `json:"nodeName"`
|
||||
NodeAddr string `json:"nodeAddr"`
|
||||
}
|
||||
|
||||
type AlertWebhookConfig struct {
|
||||
DisplayName string `json:"displayName"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
+20
-19
@@ -84,25 +84,26 @@ type ExtraProperties struct {
|
||||
}
|
||||
|
||||
type AppProperty struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Tags []string `json:"tags"`
|
||||
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh"`
|
||||
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn"`
|
||||
Description Locale `json:"description"`
|
||||
Key string `json:"key"`
|
||||
Required []string `json:"Required"`
|
||||
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
|
||||
Limit int `json:"limit" yaml:"limit"`
|
||||
Recommend int `json:"recommend" yaml:"recommend"`
|
||||
Website string `json:"website"`
|
||||
Github string `json:"github"`
|
||||
Document string `json:"document"`
|
||||
Architectures []string `json:"architectures"`
|
||||
MemoryRequired int `json:"memoryRequired" yaml:"memoryRequired"`
|
||||
GpuSupport bool `json:"gpuSupport" yaml:"gpuSupport"`
|
||||
Version float64 `json:"version"`
|
||||
Deprecated float64 `json:"deprecated"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Tags []string `json:"tags"`
|
||||
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh"`
|
||||
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn"`
|
||||
Description Locale `json:"description"`
|
||||
Key string `json:"key"`
|
||||
Required []string `json:"Required"`
|
||||
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
|
||||
Limit int `json:"limit" yaml:"limit"`
|
||||
Recommend int `json:"recommend" yaml:"recommend"`
|
||||
Website string `json:"website"`
|
||||
Github string `json:"github"`
|
||||
Document string `json:"document"`
|
||||
Architectures []string `json:"architectures"`
|
||||
MemoryRequired int `json:"memoryRequired" yaml:"memoryRequired"`
|
||||
GpuSupport bool `json:"gpuSupport" yaml:"gpuSupport"`
|
||||
Version float64 `json:"version"`
|
||||
Deprecated float64 `json:"deprecated"`
|
||||
BatchInstallSupport bool `json:"batchInstallSupport"`
|
||||
}
|
||||
|
||||
type AppConfigVersion struct {
|
||||
|
||||
@@ -65,12 +65,13 @@ type UploadForRecover struct {
|
||||
}
|
||||
|
||||
type CommonBackup struct {
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
Type string `json:"type" validate:"required,oneof=app mysql mariadb redis website postgresql mysql-cluster postgresql-cluster redis-cluster"`
|
||||
Name string `json:"name"`
|
||||
DetailName string `json:"detailName"`
|
||||
Secret string `json:"secret"`
|
||||
TaskID string `json:"taskID"`
|
||||
FileName string `json:"fileName"`
|
||||
Args []string `json:"args"`
|
||||
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
@@ -272,13 +272,14 @@ type ComposeContainer struct {
|
||||
Ports []string `json:"ports"`
|
||||
}
|
||||
type ComposeCreate struct {
|
||||
TaskID string `json:"taskID"`
|
||||
Name string `json:"name"`
|
||||
From string `json:"from" validate:"required,oneof=edit path template"`
|
||||
File string `json:"file"`
|
||||
Path string `json:"path"`
|
||||
Template uint `json:"template"`
|
||||
Env string `json:"env"`
|
||||
TaskID string `json:"taskID"`
|
||||
Name string `json:"name"`
|
||||
From string `json:"from" validate:"required,oneof=edit path template"`
|
||||
File string `json:"file"`
|
||||
Path string `json:"path"`
|
||||
Template uint `json:"template"`
|
||||
Env string `json:"env"`
|
||||
ForcePull bool `json:"forcePull"`
|
||||
}
|
||||
type ComposeOperation struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
@@ -288,11 +289,13 @@ type ComposeOperation struct {
|
||||
Force bool `json:"force"`
|
||||
}
|
||||
type ComposeUpdate struct {
|
||||
TaskID string `json:"taskID"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
DetailPath string `json:"detailPath"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
Env string `json:"env"`
|
||||
ForcePull bool `json:"forcePull"`
|
||||
}
|
||||
type ComposeLogClean struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
@@ -304,6 +307,7 @@ type ContainerLog struct {
|
||||
Container string `json:"container" validate:"required"`
|
||||
Since string `json:"since"`
|
||||
Tail uint `json:"tail"`
|
||||
Timestamp bool `json:"timestamp"`
|
||||
ContainerType string `json:"containerType"`
|
||||
}
|
||||
|
||||
@@ -313,5 +317,6 @@ type StreamLog struct {
|
||||
Since string
|
||||
Follow bool
|
||||
Tail string
|
||||
Timestamp bool
|
||||
Type string
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type CronjobOperate struct {
|
||||
Timeout uint `json:"timeout" validate:"number,min=1"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
@@ -123,6 +124,7 @@ type CronjobInfo struct {
|
||||
LastRecordTime string `json:"lastRecordTime"`
|
||||
Status string `json:"status"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
AlertCount uint `json:"alertCount"`
|
||||
}
|
||||
@@ -162,6 +164,7 @@ type CronjobTrans struct {
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
SnapshotRule SnapshotTransHelper `json:"snapshotRule"`
|
||||
Secret string `json:"secret"`
|
||||
Args string `json:"args"`
|
||||
|
||||
SourceAccounts []string `json:"sourceAccounts"`
|
||||
DownloadAccount string `json:"downloadAccount"`
|
||||
|
||||
@@ -19,7 +19,7 @@ type RuleSearch struct {
|
||||
}
|
||||
|
||||
type FirewallOperation struct {
|
||||
Operation string `json:"operation" validate:"required,oneof=start stop restart disablePing enablePing"`
|
||||
Operation string `json:"operation" validate:"required,oneof=start stop restart disableBanPing enableBanPing"`
|
||||
WithDockerRestart bool `json:"withDockerRestart"`
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ type ImageInfo struct {
|
||||
}
|
||||
|
||||
type ImageLoad struct {
|
||||
TaskID string `json:"taskID"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
TaskID string `json:"taskID"`
|
||||
Paths []string `json:"paths" validate:"required,dive,required"`
|
||||
}
|
||||
|
||||
type ImageBuild struct {
|
||||
|
||||
@@ -22,7 +22,16 @@ type AppInstallCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Services map[string]string `json:"services"`
|
||||
TaskID string `json:"taskID"`
|
||||
|
||||
AppContainerConfig
|
||||
NodePushConfig
|
||||
}
|
||||
|
||||
type NodePushConfig struct {
|
||||
Nodes []string `json:"nodes"`
|
||||
PushNode bool `json:"pushNode"`
|
||||
AppKey string `json:"appKey"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type AppContainerConfig struct {
|
||||
@@ -45,13 +54,14 @@ type AppContainerConfig struct {
|
||||
|
||||
type AppInstalledSearch struct {
|
||||
dto.PageInfo
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
Update bool `json:"update"`
|
||||
Unused bool `json:"unused"`
|
||||
All bool `json:"all"`
|
||||
Sync bool `json:"sync"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
Update bool `json:"update"`
|
||||
Unused bool `json:"unused"`
|
||||
All bool `json:"all"`
|
||||
Sync bool `json:"sync"`
|
||||
CheckUpdate bool `json:"checkUpdate"`
|
||||
}
|
||||
|
||||
type AppInstalledInfo struct {
|
||||
|
||||
@@ -13,6 +13,7 @@ type DiskMountRequest struct {
|
||||
MountPoint string `json:"mountPoint" validate:"required"`
|
||||
Filesystem string `json:"filesystem" validate:"required,oneof=ext4 xfs"`
|
||||
AutoMount bool `json:"autoMount"`
|
||||
NoFail bool `json:"noFail"`
|
||||
}
|
||||
|
||||
type DiskUnmountRequest struct {
|
||||
|
||||
@@ -163,3 +163,12 @@ type FileConvertRequest struct {
|
||||
DeleteSource bool `json:"deleteSource"`
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
||||
type FileRemarkBatch struct {
|
||||
Paths []string `json:"paths" validate:"required"`
|
||||
}
|
||||
|
||||
type FileRemarkUpdate struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ type StreamConfig struct {
|
||||
StreamPorts string `json:"streamPorts"`
|
||||
Name string `json:"name"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
UDP bool `json:"udp"`
|
||||
|
||||
Servers []dto.NginxUpstreamServer `json:"servers"`
|
||||
}
|
||||
@@ -310,6 +311,7 @@ type WebsiteHtmlReq struct {
|
||||
type WebsiteHtmlUpdate struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
Content string `json:"content" validate:"required"`
|
||||
Sync bool `json:"sync"`
|
||||
}
|
||||
|
||||
type WebsiteLBCreate struct {
|
||||
|
||||
@@ -10,6 +10,10 @@ type WebsiteSSLSearch struct {
|
||||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
}
|
||||
|
||||
type WebsiteSSLListReq struct {
|
||||
AcmeAccountID string `json:"acmeAccountID"`
|
||||
}
|
||||
|
||||
type WebsiteSSLCreate struct {
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
OtherDomains string `json:"otherDomains"`
|
||||
@@ -63,6 +67,7 @@ type WebsiteAcmeAccountCreate struct {
|
||||
EabHmacKey string `json:"eabHmacKey"`
|
||||
UseProxy bool `json:"useProxy"`
|
||||
CaDirURL string `json:"caDirURL"`
|
||||
UseEAB bool `json:"useEAB"`
|
||||
}
|
||||
|
||||
type WebsiteAcmeAccountUpdate struct {
|
||||
|
||||
@@ -29,17 +29,18 @@ type AppDTO struct {
|
||||
}
|
||||
|
||||
type AppItem struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
ID uint `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Installed bool `json:"installed"`
|
||||
Limit int `json:"limit"`
|
||||
Tags []string `json:"tags"`
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
Recommend int `json:"recommend"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
ID uint `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Installed bool `json:"installed"`
|
||||
Limit int `json:"limit"`
|
||||
Tags []string `json:"tags"`
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
Recommend int `json:"recommend"`
|
||||
Type string `json:"type"`
|
||||
BatchInstallSupport bool `json:"batchInstallSupport"`
|
||||
}
|
||||
|
||||
type TagDTO struct {
|
||||
@@ -75,6 +76,10 @@ type AppDetailDTO struct {
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
}
|
||||
|
||||
type AppDetailSimpleDTO struct {
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
||||
type IgnoredApp struct {
|
||||
Icon string `json:"icon"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -81,3 +81,7 @@ type FileConvertLog struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type FileRemarksRes struct {
|
||||
Remarks map[string]string `json:"remarks"`
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ type WebsiteDTO struct {
|
||||
SiteDir string `json:"siteDir"`
|
||||
OpenBaseDir bool `json:"openBaseDir"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
UDP bool `json:"udp"`
|
||||
|
||||
Servers []dto.NginxUpstreamServer `json:"servers"`
|
||||
}
|
||||
@@ -39,6 +40,7 @@ type WebsiteRes struct {
|
||||
SSLStatus string `json:"sslStatus"`
|
||||
AppInstallID uint `json:"appInstallId"`
|
||||
ChildSites []string `json:"childSites"`
|
||||
ParentSite string `json:"parentSite"`
|
||||
RuntimeType string `json:"runtimeType"`
|
||||
Favorite bool `json:"favorite"`
|
||||
IPV6 bool `json:"IPV6"`
|
||||
|
||||
@@ -37,6 +37,7 @@ type SyncTime struct {
|
||||
|
||||
type CleanData struct {
|
||||
SystemClean []CleanTree `json:"systemClean"`
|
||||
BackupClean []CleanTree `json:"backupClean"`
|
||||
UploadClean []CleanTree `json:"uploadClean"`
|
||||
DownloadClean []CleanTree `json:"downloadClean"`
|
||||
SystemLogClean []CleanTree `json:"systemLogClean"`
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package model
|
||||
|
||||
type Agent struct {
|
||||
BaseModel
|
||||
Name string `json:"name" gorm:"not null;unique"`
|
||||
Provider string `json:"provider"`
|
||||
Model string `json:"model"`
|
||||
BaseURL string `json:"baseUrl"`
|
||||
APIKey string `json:"apiKey"`
|
||||
Token string `json:"token"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
AppInstallID uint `json:"appInstallId"`
|
||||
AccountID uint `json:"accountId"`
|
||||
ConfigPath string `json:"configPath"`
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
type AgentAccount struct {
|
||||
BaseModel
|
||||
Provider string `json:"provider"`
|
||||
Name string `json:"name"`
|
||||
APIKey string `json:"apiKey"`
|
||||
BaseURL string `json:"baseUrl"`
|
||||
Verified bool `json:"verified"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (AgentAccount) TableName() string {
|
||||
return "agent_provider_accounts"
|
||||
}
|
||||
@@ -11,7 +11,7 @@ type Alert struct {
|
||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
||||
Method string `gorm:"type:varchar(64);not null" json:"method"`
|
||||
SendCount uint `gorm:"type:integer" json:"sendCount"`
|
||||
AdvancedParams string `gorm:"type:longText" json:"advancedParam"`
|
||||
AdvancedParams string `gorm:"type:longText" json:"advancedParams"`
|
||||
}
|
||||
|
||||
type AlertTask struct {
|
||||
|
||||
@@ -34,6 +34,7 @@ type App struct {
|
||||
MemoryRequired int `json:"memoryRequired"`
|
||||
GpuSupport bool `json:"gpuSupport"`
|
||||
RequiredPanelVersion float64 `json:"requiredPanelVersion"`
|
||||
BatchInstallSupport bool `json:"batchInstallSupport" yaml:"batchInstallSupport"`
|
||||
|
||||
Details []AppDetail `json:"-" gorm:"-:migration"`
|
||||
TagsKey []string `json:"tags" yaml:"tags" gorm:"-"`
|
||||
|
||||
@@ -37,6 +37,7 @@ type Cronjob struct {
|
||||
Timeout uint `json:"timeout"`
|
||||
IgnoreErr bool `json:"ignoreErr"`
|
||||
RetainCopies uint64 `json:"retainCopies"`
|
||||
Args string `json:"args"`
|
||||
|
||||
IsExecuting bool `json:"isExecuting"`
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -11,6 +11,7 @@ type WebsiteAcmeAccount struct {
|
||||
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
||||
UseProxy bool `gorm:"default:false" json:"useProxy"`
|
||||
CaDirURL string `json:"caDirURL"`
|
||||
UseEAB bool `json:"useEAB"`
|
||||
}
|
||||
|
||||
func (w WebsiteAcmeAccount) TableName() string {
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
package provider
|
||||
|
||||
import "strings"
|
||||
|
||||
type Model struct {
|
||||
ID string
|
||||
Name string
|
||||
}
|
||||
|
||||
type Meta struct {
|
||||
Key string
|
||||
DisplayName string
|
||||
Sort uint
|
||||
DefaultBaseURL string
|
||||
EnvKey string
|
||||
Models []Model
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
var catalog = map[string]Meta{
|
||||
"ollama": {
|
||||
Key: "ollama",
|
||||
DisplayName: "Ollama",
|
||||
Sort: 1,
|
||||
Enabled: true,
|
||||
},
|
||||
"deepseek": {
|
||||
Key: "deepseek",
|
||||
DisplayName: "DeepSeek",
|
||||
Sort: 2,
|
||||
DefaultBaseURL: "https://api.deepseek.com/v1",
|
||||
EnvKey: "DEEPSEEK_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "deepseek/deepseek-chat", Name: "DeepSeek Chat"},
|
||||
{ID: "deepseek/deepseek-reasoner", Name: "DeepSeek Reasoner"},
|
||||
{ID: "deepseek/deepseek-r1:1.5b", Name: "DeepSeek R1 1.5B"},
|
||||
},
|
||||
},
|
||||
"openai": {
|
||||
Key: "openai",
|
||||
DisplayName: "OpenAI",
|
||||
Sort: 3,
|
||||
DefaultBaseURL: "https://api.openai.com/v1",
|
||||
EnvKey: "OPENAI_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "openai/codex-mini-latest", Name: "Codex Mini"},
|
||||
{ID: "openai/gpt-4.1", Name: "GPT-4.1"},
|
||||
{ID: "openai/gpt-4o", Name: "GPT-4o"},
|
||||
{ID: "openai/gpt-4o-mini", Name: "GPT-4o Mini"},
|
||||
{ID: "openai/gpt-5", Name: "GPT-5"},
|
||||
{ID: "openai/gpt-5-mini", Name: "GPT-5 Mini"},
|
||||
},
|
||||
},
|
||||
"anthropic": {
|
||||
Key: "anthropic",
|
||||
DisplayName: "Anthropic",
|
||||
Sort: 4,
|
||||
DefaultBaseURL: "https://api.anthropic.com",
|
||||
EnvKey: "ANTHROPIC_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "anthropic/claude-3-haiku-20240307", Name: "Claude 3 Haiku"},
|
||||
{ID: "anthropic/claude-3-5-haiku-latest", Name: "Claude 3.5 Haiku"},
|
||||
{ID: "anthropic/claude-3-5-sonnet-20241022", Name: "Claude 3.5 Sonnet"},
|
||||
{ID: "anthropic/claude-3-7-sonnet-20250219", Name: "Claude 3.7 Sonnet"},
|
||||
{ID: "anthropic/claude-opus-4-1", Name: "Claude Opus 4.1"},
|
||||
},
|
||||
},
|
||||
"gemini": {
|
||||
Key: "gemini",
|
||||
DisplayName: "Gemini",
|
||||
Sort: 5,
|
||||
DefaultBaseURL: "https://generativelanguage.googleapis.com",
|
||||
EnvKey: "GEMINI_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "google/gemini-1.5-flash", Name: "Gemini 1.5 Flash"},
|
||||
{ID: "google/gemini-1.5-pro", Name: "Gemini 1.5 Pro"},
|
||||
{ID: "google/gemini-2.0-flash", Name: "Gemini 2.0 Flash"},
|
||||
{ID: "google/gemini-2.5-flash", Name: "Gemini 2.5 Flash"},
|
||||
{ID: "google/gemini-2.5-pro", Name: "Gemini 2.5 Pro"},
|
||||
{ID: "google/gemini-3-flash-preview", Name: "Gemini 3 Flash Preview"},
|
||||
},
|
||||
},
|
||||
"minimax": {
|
||||
Key: "minimax",
|
||||
DisplayName: "MiniMax (CN)",
|
||||
Sort: 6,
|
||||
DefaultBaseURL: "https://api.minimaxi.com/anthropic",
|
||||
EnvKey: "MINIMAX_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "minimax/MiniMax-M2.1", Name: "MiniMax M2.1"},
|
||||
{ID: "minimax/MiniMax-M2.1-lightning", Name: "MiniMax M2.1 Lightning"},
|
||||
},
|
||||
},
|
||||
"moonshot": {
|
||||
Key: "moonshot",
|
||||
DisplayName: "Moonshot (Global)",
|
||||
Sort: 7,
|
||||
DefaultBaseURL: "https://api.moonshot.ai/v1",
|
||||
EnvKey: "MOONSHOT_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "moonshot/kimi-k2.5", Name: "Kimi K2.5"},
|
||||
{ID: "moonshot/kimi-k2-0905-preview", Name: "Kimi K2 0905 Preview"},
|
||||
{ID: "moonshot/kimi-k2-thinking", Name: "Kimi K2 Thinking"},
|
||||
},
|
||||
},
|
||||
"kimi": {
|
||||
Key: "kimi",
|
||||
DisplayName: "Kimi (CN)",
|
||||
Sort: 8,
|
||||
DefaultBaseURL: "https://api.moonshot.cn/v1",
|
||||
EnvKey: "KIMI_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "kimi/kimi-k2.5", Name: "Kimi K2.5"},
|
||||
{ID: "kimi/kimi-k2-0905-preview", Name: "Kimi K2 0905 Preview"},
|
||||
{ID: "kimi/kimi-k2-thinking", Name: "Kimi K2 Thinking"},
|
||||
},
|
||||
},
|
||||
"kimi-coding": {
|
||||
Key: "kimi-coding",
|
||||
DisplayName: "Kimi Coding",
|
||||
Sort: 9,
|
||||
DefaultBaseURL: "https://api.moonshot.cn/anthropic/v1",
|
||||
EnvKey: "KIMI_API_KEY",
|
||||
Enabled: true,
|
||||
Models: []Model{
|
||||
{ID: "kimi-coding/k2p5", Name: "Kimi K2.5"},
|
||||
},
|
||||
},
|
||||
"qwen": {
|
||||
Key: "qwen",
|
||||
DisplayName: "Qwen",
|
||||
Sort: 10,
|
||||
DefaultBaseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
EnvKey: "QWEN_API_KEY",
|
||||
Enabled: false,
|
||||
},
|
||||
}
|
||||
|
||||
func Get(key string) (Meta, bool) {
|
||||
meta, ok := catalog[strings.ToLower(strings.TrimSpace(key))]
|
||||
if !ok {
|
||||
return Meta{}, false
|
||||
}
|
||||
return cloneMeta(meta), true
|
||||
}
|
||||
|
||||
func All() map[string]Meta {
|
||||
result := make(map[string]Meta, len(catalog))
|
||||
for key, meta := range catalog {
|
||||
result[key] = cloneMeta(meta)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func IsEnabled(key string) bool {
|
||||
meta, ok := catalog[strings.ToLower(strings.TrimSpace(key))]
|
||||
return ok && meta.Enabled
|
||||
}
|
||||
|
||||
func DefaultBaseURL(key string) (string, bool) {
|
||||
meta, ok := catalog[strings.ToLower(strings.TrimSpace(key))]
|
||||
if !ok || strings.TrimSpace(meta.DefaultBaseURL) == "" {
|
||||
return "", false
|
||||
}
|
||||
return meta.DefaultBaseURL, true
|
||||
}
|
||||
|
||||
func EnvKey(key string) string {
|
||||
meta, ok := catalog[strings.ToLower(strings.TrimSpace(key))]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return meta.EnvKey
|
||||
}
|
||||
|
||||
func DisplayName(key string) string {
|
||||
meta, ok := catalog[strings.ToLower(strings.TrimSpace(key))]
|
||||
if !ok {
|
||||
return key
|
||||
}
|
||||
if strings.TrimSpace(meta.DisplayName) == "" {
|
||||
return key
|
||||
}
|
||||
return meta.DisplayName
|
||||
}
|
||||
|
||||
func cloneMeta(meta Meta) Meta {
|
||||
clone := meta
|
||||
if len(meta.Models) > 0 {
|
||||
clone.Models = make([]Model, len(meta.Models))
|
||||
copy(clone.Models, meta.Models)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
)
|
||||
|
||||
type AgentRepo struct{}
|
||||
|
||||
type IAgentRepo interface {
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.Agent, error)
|
||||
GetFirst(opts ...DBOption) (*model.Agent, error)
|
||||
Create(agent *model.Agent) error
|
||||
Save(agent *model.Agent) error
|
||||
DeleteByID(id uint) error
|
||||
DeleteByAppInstallID(appInstallID uint) error
|
||||
DeleteByAppInstallIDWithCtx(ctx context.Context, appInstallID uint) error
|
||||
List(opts ...DBOption) ([]model.Agent, error)
|
||||
}
|
||||
|
||||
func NewIAgentRepo() IAgentRepo {
|
||||
return &AgentRepo{}
|
||||
}
|
||||
|
||||
func (a AgentRepo) Page(page, size int, opts ...DBOption) (int64, []model.Agent, error) {
|
||||
var agents []model.Agent
|
||||
db := getDb(opts...).Model(&model.Agent{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&agents).Error
|
||||
return count, agents, err
|
||||
}
|
||||
|
||||
func (a AgentRepo) GetFirst(opts ...DBOption) (*model.Agent, error) {
|
||||
var agent model.Agent
|
||||
if err := getDb(opts...).First(&agent).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &agent, nil
|
||||
}
|
||||
|
||||
func (a AgentRepo) Create(agent *model.Agent) error {
|
||||
return getDb().Create(agent).Error
|
||||
}
|
||||
|
||||
func (a AgentRepo) Save(agent *model.Agent) error {
|
||||
return getDb().Save(agent).Error
|
||||
}
|
||||
|
||||
func (a AgentRepo) DeleteByID(id uint) error {
|
||||
return getDb().Delete(&model.Agent{}, id).Error
|
||||
}
|
||||
|
||||
func (a AgentRepo) DeleteByAppInstallID(appInstallID uint) error {
|
||||
if appInstallID == 0 {
|
||||
return nil
|
||||
}
|
||||
return getDb().Where("app_install_id = ?", appInstallID).Delete(&model.Agent{}).Error
|
||||
}
|
||||
|
||||
func (a AgentRepo) DeleteByAppInstallIDWithCtx(ctx context.Context, appInstallID uint) error {
|
||||
if appInstallID == 0 {
|
||||
return nil
|
||||
}
|
||||
return getTx(ctx).Where("app_install_id = ?", appInstallID).Delete(&model.Agent{}).Error
|
||||
}
|
||||
|
||||
func (a AgentRepo) List(opts ...DBOption) ([]model.Agent, error) {
|
||||
var agents []model.Agent
|
||||
if err := getDb(opts...).Find(&agents).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agents, nil
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package repo
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
|
||||
type AgentAccountRepo struct{}
|
||||
|
||||
type IAgentAccountRepo interface {
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.AgentAccount, error)
|
||||
GetFirst(opts ...DBOption) (*model.AgentAccount, error)
|
||||
Create(account *model.AgentAccount) error
|
||||
Save(account *model.AgentAccount) error
|
||||
DeleteByID(id uint) error
|
||||
List(opts ...DBOption) ([]model.AgentAccount, error)
|
||||
}
|
||||
|
||||
func NewIAgentAccountRepo() IAgentAccountRepo {
|
||||
return &AgentAccountRepo{}
|
||||
}
|
||||
|
||||
func (a AgentAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.AgentAccount, error) {
|
||||
var accounts []model.AgentAccount
|
||||
db := getDb(opts...).Model(&model.AgentAccount{})
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&accounts).Error
|
||||
return count, accounts, err
|
||||
}
|
||||
|
||||
func (a AgentAccountRepo) GetFirst(opts ...DBOption) (*model.AgentAccount, error) {
|
||||
var account model.AgentAccount
|
||||
if err := getDb(opts...).First(&account).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &account, nil
|
||||
}
|
||||
|
||||
func (a AgentAccountRepo) Create(account *model.AgentAccount) error {
|
||||
return getDb().Create(account).Error
|
||||
}
|
||||
|
||||
func (a AgentAccountRepo) Save(account *model.AgentAccount) error {
|
||||
return getDb().Save(account).Error
|
||||
}
|
||||
|
||||
func (a AgentAccountRepo) DeleteByID(id uint) error {
|
||||
return getDb().Delete(&model.AgentAccount{}, id).Error
|
||||
}
|
||||
|
||||
func (a AgentAccountRepo) List(opts ...DBOption) ([]model.AgentAccount, error) {
|
||||
var accounts []model.AgentAccount
|
||||
if err := getDb(opts...).Find(&accounts).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return accounts, nil
|
||||
}
|
||||
@@ -20,6 +20,7 @@ type IAppRepo interface {
|
||||
WithResource(resource string) DBOption
|
||||
WithNotLocal() DBOption
|
||||
WithByLikeName(name string) DBOption
|
||||
WithKeyIn(keys []string) DBOption
|
||||
WithArch(arch string) DBOption
|
||||
WithPanelVersion(panelVersion string) DBOption
|
||||
|
||||
@@ -55,6 +56,12 @@ func (a AppRepo) WithKey(key string) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppRepo) WithKeyIn(keys []string) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("`key` in (?)", keys)
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppRepo) WithType(typeStr string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("type = ?", typeStr)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/re"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -72,6 +73,33 @@ func WithByDetailName(detailName string) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithByProvider(provider string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if len(provider) == 0 {
|
||||
return g
|
||||
}
|
||||
return g.Where("provider = ?", provider)
|
||||
}
|
||||
}
|
||||
|
||||
func WithByModel(model string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if len(model) == 0 {
|
||||
return g
|
||||
}
|
||||
return g.Where("model = ?", model)
|
||||
}
|
||||
}
|
||||
|
||||
func WithByAccountID(accountID uint) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
if accountID == 0 {
|
||||
return g
|
||||
}
|
||||
return g.Where("account_id = ?", accountID)
|
||||
}
|
||||
}
|
||||
|
||||
func WithByType(tp string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("`type` = ?", tp)
|
||||
@@ -124,23 +152,30 @@ func WithByCreatedAt(startTime, endTime time.Time) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithOrderBy(orderStr string) DBOption {
|
||||
if orderStr == "createdAt" {
|
||||
orderStr = "created_at"
|
||||
}
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Order(orderStr)
|
||||
}
|
||||
func WithOrderDesc(orderBy string) DBOption {
|
||||
return WithOrderRuleBy(orderBy, constant.Desc)
|
||||
}
|
||||
|
||||
func WithOrderAsc(orderBy string) DBOption {
|
||||
return WithOrderRuleBy(orderBy, constant.Asc)
|
||||
}
|
||||
|
||||
func WithOrderRuleBy(orderBy, order string) DBOption {
|
||||
if orderBy == "createdAt" {
|
||||
orderBy = "created_at"
|
||||
}
|
||||
if !re.GetRegex(re.OrderByValidationPattern).MatchString(orderBy) {
|
||||
orderBy = "created_at"
|
||||
}
|
||||
switch order {
|
||||
case constant.OrderDesc:
|
||||
order = "desc"
|
||||
case constant.OrderAsc:
|
||||
order = "asc"
|
||||
case constant.Desc:
|
||||
order = "desc"
|
||||
case constant.Asc:
|
||||
order = "asc"
|
||||
default:
|
||||
orderBy = "created_at"
|
||||
order = "desc"
|
||||
|
||||
@@ -73,28 +73,13 @@ func (u *MonitorRepo) CreateMonitorBase(model model.MonitorBase) error {
|
||||
return global.MonitorDB.Create(&model).Error
|
||||
}
|
||||
func (s *MonitorRepo) BatchCreateMonitorGPU(list []model.MonitorGPU) error {
|
||||
for _, item := range list {
|
||||
if err := global.GPUMonitorDB.Create(&item).Error; err != nil {
|
||||
global.LOG.Errorf("create Monitor GPU record failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return global.GPUMonitorDB.CreateInBatches(&list, len(list)).Error
|
||||
}
|
||||
func (u *MonitorRepo) BatchCreateMonitorIO(list []model.MonitorIO) error {
|
||||
for _, item := range list {
|
||||
if err := global.MonitorDB.Create(&item).Error; err != nil {
|
||||
global.LOG.Errorf("create Monitor IO record failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (u *MonitorRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
|
||||
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
|
||||
}
|
||||
func (u *MonitorRepo) BatchCreateMonitorNet(list []model.MonitorNetwork) error {
|
||||
for _, item := range list {
|
||||
if err := global.MonitorDB.Create(&item).Error; err != nil {
|
||||
global.LOG.Errorf("create Monitor Network record failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (u *MonitorRepo) BatchCreateMonitorNet(ioList []model.MonitorNetwork) error {
|
||||
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
|
||||
}
|
||||
func (u *MonitorRepo) DelMonitorBase(timeForDelete time.Time) error {
|
||||
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,7 @@ func (a AlertService) PageAlert(search dto.AlertSearch) (int64, []dto.AlertDTO,
|
||||
if search.Type != "" {
|
||||
opts = append(opts, alertRepo.WithByType(search.Type))
|
||||
}
|
||||
opts = append(opts, repo.WithOrderBy("created_at desc"))
|
||||
opts = append(opts, repo.WithOrderDesc("created_at"))
|
||||
|
||||
total, alerts, err := alertRepo.Page(search.Page, search.PageSize, opts...)
|
||||
if err != nil {
|
||||
@@ -343,7 +343,7 @@ func (a AlertService) PageAlertLogs(search dto.AlertLogSearch) (int64, []dto.Ale
|
||||
if search.Count != 0 {
|
||||
opts = append(opts, alertRepo.WithByCount(search.Count))
|
||||
}
|
||||
opts = append(opts, repo.WithOrderBy("created_at desc"))
|
||||
opts = append(opts, repo.WithOrderDesc("created_at"))
|
||||
|
||||
total, alerts, err := alertRepo.PageLog(search.Page, search.PageSize, opts...)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
@@ -110,7 +111,7 @@ func (m *AlertTaskHelper) getClassifiedAlerts() (baseAlerts, resourceAlerts []dt
|
||||
|
||||
func handleBaseAlerts(baseAlerts []dto.AlertDTO) {
|
||||
if len(baseAlerts) == 0 {
|
||||
stopResourceJob()
|
||||
stopBaseJob()
|
||||
return
|
||||
}
|
||||
if global.AlertBaseJobID == 0 {
|
||||
@@ -227,11 +228,30 @@ func loadSSLInfo(alert dto.AlertDTO) {
|
||||
return
|
||||
}
|
||||
sender := NewAlertSender(alert, projectJSON)
|
||||
minDays := math.MaxInt
|
||||
maxDays := 0
|
||||
allDomains := make([]string, 0)
|
||||
for daysDiff, domains := range daysDiffMap {
|
||||
domainStr := strings.Join(domains, ",")
|
||||
params := createAlertBaseParams(strconv.Itoa(len(domains)), strconv.Itoa(daysDiff))
|
||||
sender.Send(domainStr, params)
|
||||
allDomains = append(allDomains, domains...)
|
||||
if daysDiff < minDays {
|
||||
minDays = daysDiff
|
||||
}
|
||||
if daysDiff > maxDays {
|
||||
maxDays = daysDiff
|
||||
}
|
||||
}
|
||||
if len(allDomains) == 0 {
|
||||
return
|
||||
}
|
||||
var daysStr string
|
||||
if len(allDomains) == 1 {
|
||||
daysStr = strconv.Itoa(minDays)
|
||||
} else {
|
||||
daysStr = strconv.Itoa(minDays) + "-" + strconv.Itoa(maxDays)
|
||||
}
|
||||
domainStr := strings.Join(allDomains, ",")
|
||||
params := createAlertBaseParams(strconv.Itoa(len(daysDiffMap)), daysStr)
|
||||
sender.Send(domainStr, params)
|
||||
}
|
||||
|
||||
func loadWebsiteInfo(alert dto.AlertDTO) {
|
||||
@@ -247,11 +267,30 @@ func loadWebsiteInfo(alert dto.AlertDTO) {
|
||||
return
|
||||
}
|
||||
sender := NewAlertSender(alert, projectJSON)
|
||||
minDays := math.MaxInt
|
||||
maxDays := 0
|
||||
allDomains := make([]string, 0)
|
||||
for daysDiff, domains := range daysDiffMap {
|
||||
domainStr := strings.Join(domains, ",")
|
||||
params := createAlertBaseParams(strconv.Itoa(len(domains)), strconv.Itoa(daysDiff))
|
||||
sender.Send(domainStr, params)
|
||||
allDomains = append(allDomains, domains...)
|
||||
if daysDiff < minDays {
|
||||
minDays = daysDiff
|
||||
}
|
||||
if daysDiff > maxDays {
|
||||
maxDays = daysDiff
|
||||
}
|
||||
}
|
||||
if len(allDomains) == 0 {
|
||||
return
|
||||
}
|
||||
var daysStr string
|
||||
if len(allDomains) == 1 {
|
||||
daysStr = strconv.Itoa(minDays)
|
||||
} else {
|
||||
daysStr = strconv.Itoa(minDays) + "-" + strconv.Itoa(maxDays)
|
||||
}
|
||||
domainStr := strings.Join(allDomains, ",")
|
||||
params := createAlertBaseParams(strconv.Itoa(len(daysDiffMap)), daysStr)
|
||||
sender.Send(domainStr, params)
|
||||
}
|
||||
|
||||
func loadPanelPwd(alert dto.AlertDTO) {
|
||||
@@ -580,10 +619,12 @@ func sendAlerts(alert dto.AlertDTO, alertType, quota, quotaType string, params [
|
||||
AlertId: alert.ID,
|
||||
Count: todayCount + 1,
|
||||
}
|
||||
_ = xpack.CreateSMSAlertLog(alertType, alert, create, quotaType, params, constant.SMS)
|
||||
alertErr := xpack.CreateSMSAlertLog(alertType, alert, create, quotaType, params, constant.SMS)
|
||||
if alertErr != nil {
|
||||
global.LOG.Infof("%s alert sms push faild, err: %v", alertType, alertErr.Error())
|
||||
continue
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, alertType, quotaType, constant.SMS)
|
||||
global.LOG.Infof("%s alert sms push successful", alertType)
|
||||
|
||||
case constant.Email:
|
||||
todayCount, isValid := canSendAlertToday(alertType, quotaType, alert.SendCount, constant.Email)
|
||||
if !isValid {
|
||||
@@ -599,9 +640,32 @@ func sendAlerts(alert dto.AlertDTO, alertType, quota, quotaType string, params [
|
||||
create.AlertRule = alertUtil.ProcessAlertRule(alert)
|
||||
create.AlertDetail = alertUtil.ProcessAlertDetail(alertInfo, quotaType, params, constant.Email)
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, alertInfo, params, transport)
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
alertErr := alertUtil.CreateEmailAlertLog(create, alertInfo, params, transport, agentInfo)
|
||||
if alertErr != nil {
|
||||
global.LOG.Infof("%s alert email push faild, err: %v", alertType, alertErr.Error())
|
||||
continue
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, alertType, quotaType, constant.Email)
|
||||
global.LOG.Infof("%s alert email push successful", alertType)
|
||||
case constant.WeCom, constant.DingTalk, constant.FeiShu:
|
||||
todayCount, isValid := canSendAlertToday(alertType, quotaType, alert.SendCount, m)
|
||||
if !isValid {
|
||||
continue
|
||||
}
|
||||
var create = dto.AlertLogCreate{
|
||||
Type: alertUtil.GetCronJobType(alert.Type),
|
||||
AlertId: alert.ID,
|
||||
Count: todayCount + 1,
|
||||
}
|
||||
transport := xpack.LoadRequestTransport()
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
err := xpack.CreateWebhookAlertLog(alertType, alert, create, quotaType, params, m, transport, agentInfo)
|
||||
if err != nil {
|
||||
global.LOG.Infof("%s alert webhook %s push faild, err: %v", alertType, m, err)
|
||||
continue
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, alertType, quotaType, m)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -641,7 +705,9 @@ func calculateSSLExpiryDays(sslList []model.WebsiteSSL, cycle uint) (map[int][]s
|
||||
projectMap := make(map[uint][]time.Time)
|
||||
|
||||
for _, ssl := range sslList {
|
||||
daysDiff := int(ssl.ExpireDate.Sub(currentDate).Hours() / 24)
|
||||
daysDiff := int(math.Ceil(
|
||||
ssl.ExpireDate.Sub(currentDate).Hours() / 24,
|
||||
))
|
||||
if daysDiff > 0 && int(cycle) >= daysDiff {
|
||||
daysDiffMap[daysDiff] = append(daysDiffMap[daysDiff], ssl.PrimaryDomain)
|
||||
projectMap[ssl.ID] = append(projectMap[ssl.ID], ssl.ExpireDate)
|
||||
@@ -656,7 +722,9 @@ func calculateWebsiteExpiryDays(websites []model.Website, cycle uint) (map[int][
|
||||
projectMap := make(map[uint][]time.Time)
|
||||
|
||||
for _, website := range websites {
|
||||
daysDiff := int(website.ExpireDate.Sub(currentDate).Hours() / 24)
|
||||
daysDiff := int(math.Ceil(
|
||||
website.ExpireDate.Sub(currentDate).Hours() / 24,
|
||||
))
|
||||
if daysDiff > 0 && int(cycle) >= daysDiff {
|
||||
daysDiffMap[daysDiff] = append(daysDiffMap[daysDiff], website.PrimaryDomain)
|
||||
projectMap[website.ID] = append(projectMap[website.ID], website.ExpireDate)
|
||||
@@ -820,30 +888,36 @@ func processAllDisks(alert dto.AlertDTO) error {
|
||||
global.LOG.Errorf("error getting disk list, err: %v", err)
|
||||
return err
|
||||
}
|
||||
var errMsgs []string
|
||||
for _, item := range diskList {
|
||||
if success, err := checkAndCreateDiskAlert(alert, item.Path); err == nil && success {
|
||||
global.LOG.Infof("disk alert pushed successfully for %s", item.Path)
|
||||
err := checkAndCreateDiskAlert(alert, item.Path)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("disk path %s process failed: %v", item.Path, err)
|
||||
errMsgs = append(errMsgs, errMsg)
|
||||
global.LOG.Errorf(errMsg)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(errMsgs) > 0 {
|
||||
return fmt.Errorf("batch process disks failed, error count: %d, details: %s", len(errMsgs), strings.Join(errMsgs, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processSingleDisk(alert dto.AlertDTO) error {
|
||||
success, err := checkAndCreateDiskAlert(alert, alert.Project)
|
||||
err := checkAndCreateDiskAlert(alert, alert.Project)
|
||||
if err != nil {
|
||||
global.LOG.Errorf(err.Error())
|
||||
return err
|
||||
}
|
||||
if success {
|
||||
global.LOG.Infof("disk alert pushed successfully for %s", alert.Project)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) (bool, error) {
|
||||
func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) error {
|
||||
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
|
||||
return err
|
||||
}
|
||||
|
||||
usedTotal, usedStr := calculateUsedTotal(alert.Cycle, usageStat)
|
||||
@@ -852,13 +926,12 @@ func checkAndCreateDiskAlert(alert dto.AlertDTO, path string) (bool, error) {
|
||||
commonTotal *= 1024 * 1024 * 1024
|
||||
}
|
||||
if usedTotal < commonTotal {
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
global.LOG.Infof("disk「 %s 」usage: %s", path, usedStr)
|
||||
params := createAlertDiskParams(path, usedStr)
|
||||
sender := NewAlertSender(alert, alert.Project)
|
||||
sender.ResourceSend(path, params)
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func calculateUsedTotal(cycle uint, usageStat *disk.UsageStat) (float64, string) {
|
||||
|
||||
@@ -30,6 +30,8 @@ func (s *AlertSender) Send(quota string, params []dto.Param) {
|
||||
s.sendSMS(quota, params)
|
||||
case constant.Email:
|
||||
s.sendEmail(quota, params)
|
||||
case constant.WeCom, constant.DingTalk, constant.FeiShu:
|
||||
s.sendWebhook(quota, params, method)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +45,8 @@ func (s *AlertSender) ResourceSend(quota string, params []dto.Param) {
|
||||
s.sendResourceSMS(quota, params)
|
||||
case constant.Email:
|
||||
s.sendResourceEmail(quota, params)
|
||||
case constant.WeCom, constant.DingTalk, constant.FeiShu:
|
||||
s.sendResourceWebhook(quota, params, method)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,9 +68,12 @@ func (s *AlertSender) sendSMS(quota string, params []dto.Param) {
|
||||
Type: s.alert.Type,
|
||||
}
|
||||
|
||||
_ = xpack.CreateSMSAlertLog(s.alert.Type, s.alert, create, quota, params, constant.SMS)
|
||||
err := xpack.CreateSMSAlertLog(s.alert.Type, s.alert, create, quota, params, constant.SMS)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("%s alert sms push failed: %v", s.alert.Type, err)
|
||||
return
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.SMS)
|
||||
global.LOG.Infof("%s alert sms push successful", s.alert.Type)
|
||||
}
|
||||
|
||||
func (s *AlertSender) sendEmail(quota string, params []dto.Param) {
|
||||
@@ -85,9 +92,35 @@ func (s *AlertSender) sendEmail(quota string, params []dto.Param) {
|
||||
}
|
||||
|
||||
transport := xpack.LoadRequestTransport()
|
||||
_ = alertUtil.CreateEmailAlertLog(create, s.alert, params, transport)
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
err := alertUtil.CreateEmailAlertLog(create, s.alert, params, transport, agentInfo)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("%s alert email push failed: %v", s.alert.Type, err)
|
||||
return
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.Email)
|
||||
global.LOG.Infof("%s alert email push successful", s.alert.Type)
|
||||
}
|
||||
|
||||
func (s *AlertSender) sendWebhook(quota string, params []dto.Param, method string) {
|
||||
totalCount, isValid := s.canSendAlert(method)
|
||||
if !isValid {
|
||||
return
|
||||
}
|
||||
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: totalCount + 1,
|
||||
AlertId: s.alert.ID,
|
||||
Type: s.alert.Type,
|
||||
}
|
||||
transport := xpack.LoadRequestTransport()
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
err := xpack.CreateWebhookAlertLog(s.alert.Type, s.alert, create, quota, params, method, transport, agentInfo)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("%s alert %s webhook push failed: %v", s.alert.Type, method, err)
|
||||
return
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, method)
|
||||
}
|
||||
|
||||
func (s *AlertSender) sendResourceSMS(quota string, params []dto.Param) {
|
||||
@@ -112,7 +145,6 @@ func (s *AlertSender) sendResourceSMS(quota string, params []dto.Param) {
|
||||
return
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.SMS)
|
||||
global.LOG.Infof("%s alert sms push successful", s.alert.Type)
|
||||
}
|
||||
|
||||
func (s *AlertSender) sendResourceEmail(quota string, params []dto.Param) {
|
||||
@@ -131,12 +163,33 @@ func (s *AlertSender) sendResourceEmail(quota string, params []dto.Param) {
|
||||
}
|
||||
|
||||
transport := xpack.LoadRequestTransport()
|
||||
if err := alertUtil.CreateEmailAlertLog(create, s.alert, params, transport); err != nil {
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
if err := alertUtil.CreateEmailAlertLog(create, s.alert, params, transport, agentInfo); err != nil {
|
||||
global.LOG.Errorf("failed to send Email alert: %v", err)
|
||||
return
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, constant.Email)
|
||||
global.LOG.Infof("%s alert email push successful", s.alert.Type)
|
||||
}
|
||||
|
||||
func (s *AlertSender) sendResourceWebhook(quota string, params []dto.Param, method string) {
|
||||
todayCount, isValid := s.canResourceSendAlert(method)
|
||||
if !isValid {
|
||||
return
|
||||
}
|
||||
|
||||
create := dto.AlertLogCreate{
|
||||
Status: constant.AlertSuccess,
|
||||
Count: todayCount + 1,
|
||||
AlertId: s.alert.ID,
|
||||
Type: s.alert.Type,
|
||||
}
|
||||
transport := xpack.LoadRequestTransport()
|
||||
agentInfo, _ := xpack.GetAgentInfo()
|
||||
if err := xpack.CreateWebhookAlertLog(s.alert.Type, s.alert, create, quota, params, method, transport, agentInfo); err != nil {
|
||||
global.LOG.Errorf("%s alert %s webhook push failed: %v", s.alert.Type, method, err)
|
||||
return
|
||||
}
|
||||
alertUtil.CreateNewAlertTask(quota, s.alert.Type, s.quotaType, method)
|
||||
}
|
||||
|
||||
func (s *AlertSender) canSendAlert(method string) (uint, bool) {
|
||||
|
||||
+132
-264
@@ -12,6 +12,7 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"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/appicon"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
@@ -33,6 +35,11 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
appStoreSyncMu sync.Mutex
|
||||
appStoreSyncing bool
|
||||
)
|
||||
|
||||
type AppService struct {
|
||||
}
|
||||
|
||||
@@ -41,12 +48,13 @@ type IAppService interface {
|
||||
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)
|
||||
Install(req request.AppInstallCreate) (*model.AppInstall, error)
|
||||
Install(req request.AppInstallCreate, executeScript bool) (*model.AppInstall, error)
|
||||
SyncAppListFromRemote(taskID string) error
|
||||
GetAppUpdate() (*response.AppUpdateRes, error)
|
||||
GetAppDetailByID(id uint) (*response.AppDetailDTO, error)
|
||||
SyncAppListFromLocal(taskID string)
|
||||
GetAppIcon(appID uint) ([]byte, error)
|
||||
GetAppIcon(key string) ([]byte, string, string, error)
|
||||
GetAppDetailByKey(appKey, version string) (response.AppDetailSimpleDTO, error)
|
||||
}
|
||||
|
||||
func NewIAppService() IAppService {
|
||||
@@ -118,14 +126,15 @@ func (a AppService) PageApp(ctx *gin.Context, req request.AppSearch) (*response.
|
||||
}
|
||||
}
|
||||
appDTO := &response.AppItem{
|
||||
ID: ap.ID,
|
||||
Name: ap.Name,
|
||||
Key: ap.Key,
|
||||
Limit: ap.Limit,
|
||||
GpuSupport: ap.GpuSupport,
|
||||
Recommend: ap.Recommend,
|
||||
Description: ap.GetDescription(ctx),
|
||||
Type: ap.Type,
|
||||
ID: ap.ID,
|
||||
Name: ap.Name,
|
||||
Key: ap.Key,
|
||||
Limit: ap.Limit,
|
||||
GpuSupport: ap.GpuSupport,
|
||||
Recommend: ap.Recommend,
|
||||
Description: ap.GetDescription(ctx),
|
||||
Type: ap.Type,
|
||||
BatchInstallSupport: ap.BatchInstallSupport,
|
||||
}
|
||||
appDTOs = append(appDTOs, appDTO)
|
||||
tags, err := getAppTags(ap.ID, lang)
|
||||
@@ -203,6 +212,20 @@ func (a AppService) GetApp(ctx *gin.Context, key string) (*response.AppDTO, erro
|
||||
return &appDTO, nil
|
||||
}
|
||||
|
||||
func (a AppService) GetAppDetailByKey(appKey, version string) (response.AppDetailSimpleDTO, error) {
|
||||
var appDetailDTO response.AppDetailSimpleDTO
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(appKey))
|
||||
if err != nil {
|
||||
return appDetailDTO, err
|
||||
}
|
||||
appDetail, err := appDetailRepo.GetFirst(appDetailRepo.WithAppId(app.ID), appDetailRepo.WithVersion(version))
|
||||
if err != nil {
|
||||
return appDetailDTO, err
|
||||
}
|
||||
appDetailDTO.ID = appDetail.ID
|
||||
return appDetailDTO, nil
|
||||
}
|
||||
|
||||
func (a AppService) GetAppDetail(appID uint, version, appType string) (response.AppDetailDTO, error) {
|
||||
var (
|
||||
appDetailDTO response.AppDetailDTO
|
||||
@@ -316,7 +339,7 @@ func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a AppService) Install(req request.AppInstallCreate) (appInstall *model.AppInstall, err error) {
|
||||
func (a AppService) Install(req request.AppInstallCreate, executeScript bool) (appInstall *model.AppInstall, err error) {
|
||||
if err = docker.CreateDefaultDockerNetwork(); err != nil {
|
||||
err = buserr.WithDetail("Err1PanelNetworkFailed", err.Error(), nil)
|
||||
return
|
||||
@@ -386,11 +409,21 @@ func (a AppService) Install(req request.AppInstallCreate) (appInstall *model.App
|
||||
App: app,
|
||||
}
|
||||
composeMap := make(map[string]interface{})
|
||||
var composeRes []byte
|
||||
if req.EditCompose {
|
||||
if err = yaml.Unmarshal([]byte(req.DockerCompose), &composeMap); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if appDetail.DockerCompose == "" {
|
||||
dockerComposeUrl := fmt.Sprintf("%s/%s/1panel/%s/%s/docker-compose.yml", global.CONF.RemoteURL.AppRepo, global.CONF.Base.Mode, app.Key, appDetail.Version)
|
||||
_, composeRes, err = req_helper.HandleRequest(dockerComposeUrl, http.MethodGet, constant.TimeOut20s)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appDetail.DockerCompose = string(composeRes)
|
||||
_ = appDetailRepo.Update(context.Background(), appDetail)
|
||||
}
|
||||
if err = yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -500,8 +533,10 @@ func (a AppService) Install(req request.AppInstallCreate) (appInstall *model.App
|
||||
if err = copyData(t, app, appDetail, appInstall, req); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = runScript(t, appInstall, "init"); err != nil {
|
||||
return err
|
||||
if executeScript {
|
||||
if err = runScript(t, appInstall, "init"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if app.Key == "openresty" {
|
||||
if err = handleSiteDir(app, appDetail, req, t); err != nil {
|
||||
@@ -776,6 +811,11 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||
res := &response.AppUpdateRes{
|
||||
CanUpdate: false,
|
||||
}
|
||||
mysql, _ := appRepo.GetFirst(appRepo.WithKey("mysql"))
|
||||
if !mysql.BatchInstallSupport {
|
||||
res.CanUpdate = true
|
||||
return res, nil
|
||||
}
|
||||
|
||||
versionUrl := fmt.Sprintf("%s/%s/1panel.json.version.txt", global.CONF.RemoteURL.AppRepo, global.CONF.Base.Mode)
|
||||
_, versionRes, err := req_helper.HandleRequest(versionUrl, http.MethodGet, constant.TimeOut20s)
|
||||
@@ -808,6 +848,13 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||
res.CanUpdate = true
|
||||
return res, err
|
||||
}
|
||||
if appicon.IsIconFile(app.Icon) {
|
||||
fileName, _ := appicon.ParseIconField(app.Icon)
|
||||
if fileName == "" || !appicon.IconFileExists(fileName) {
|
||||
res.CanUpdate = true
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list, err := getAppList()
|
||||
@@ -865,295 +912,116 @@ var InitTypes = map[string]struct{}{
|
||||
}
|
||||
|
||||
func deleteCustomApp() {
|
||||
installs, err := appInstallRepo.ListBy(context.Background())
|
||||
if err != nil {
|
||||
global.LOG.Errorf("[AppStore] deleteCustomApp: failed to list installs, skipping: %v", err)
|
||||
return
|
||||
}
|
||||
var appIDS []uint
|
||||
installs, _ := appInstallRepo.ListBy(context.Background())
|
||||
for _, install := range installs {
|
||||
appIDS = append(appIDS, install.AppId)
|
||||
}
|
||||
var ops []repo.DBOption
|
||||
ops = append(ops, repo.WithByIDNotIn(appIDS))
|
||||
if len(appIDS) > 0 {
|
||||
ops = append(ops, repo.WithByIDNotIn(appIDS))
|
||||
}
|
||||
apps, _ := appRepo.GetBy(ops...)
|
||||
apps, err := appRepo.GetBy(ops...)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("[AppStore] deleteCustomApp: failed to get apps, skipping: %v", err)
|
||||
return
|
||||
}
|
||||
var deleteIDS []uint
|
||||
for _, app := range apps {
|
||||
if app.Resource == constant.AppResourceCustom {
|
||||
deleteIDS = append(deleteIDS, app.ID)
|
||||
}
|
||||
}
|
||||
_ = appRepo.DeleteByIDs(context.Background(), deleteIDS)
|
||||
_ = appDetailRepo.DeleteByAppIds(context.Background(), deleteIDS)
|
||||
if len(deleteIDS) == 0 {
|
||||
return
|
||||
}
|
||||
if err = appRepo.DeleteByIDs(context.Background(), deleteIDS); err != nil {
|
||||
global.LOG.Errorf("[AppStore] deleteCustomApp: failed to delete apps: %v", err)
|
||||
}
|
||||
if err = appDetailRepo.DeleteByAppIds(context.Background(), deleteIDS); err != nil {
|
||||
global.LOG.Errorf("[AppStore] deleteCustomApp: failed to delete app details: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
|
||||
if xpack.IsUseCustomApp() {
|
||||
return nil
|
||||
}
|
||||
|
||||
appStoreSyncMu.Lock()
|
||||
global.LOG.Info("[AppStore] sync app from remote task create start")
|
||||
if appStoreSyncing {
|
||||
appStoreSyncMu.Unlock()
|
||||
global.LOG.Info("[AppStore] sync already in progress, skipping")
|
||||
return nil
|
||||
}
|
||||
appStoreSyncing = true
|
||||
appStoreSyncMu.Unlock()
|
||||
|
||||
syncTask, err := task.NewTaskWithOps(i18n.GetMsgByKey("App"), task.TaskSync, task.TaskScopeAppStore, taskID, 0)
|
||||
if err != nil {
|
||||
appStoreSyncMu.Lock()
|
||||
appStoreSyncing = false
|
||||
appStoreSyncMu.Unlock()
|
||||
return err
|
||||
}
|
||||
syncTask.AddSubTask(task.GetTaskName(i18n.GetMsgByKey("App"), task.TaskSync, task.TaskScopeAppStore), func(t *task.Task) (err error) {
|
||||
updateRes, err := a.GetAppUpdate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !updateRes.CanUpdate {
|
||||
if updateRes.IsSyncing {
|
||||
t.Log(i18n.GetMsgByKey("AppStoreIsSyncing"))
|
||||
return nil
|
||||
}
|
||||
t.Log(i18n.GetMsgByKey("AppStoreIsUpToDate"))
|
||||
return nil
|
||||
}
|
||||
list := &dto.AppList{}
|
||||
if updateRes.AppList == nil {
|
||||
list, err = getAppList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
list = updateRes.AppList
|
||||
}
|
||||
settingService := NewISettingService()
|
||||
_ = settingService.Update("AppStoreSyncStatus", constant.StatusSyncing)
|
||||
|
||||
setting, err := settingService.GetSettingInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
appTags []*model.AppTag
|
||||
oldAppIds []uint
|
||||
)
|
||||
if err = SyncTags(list.Extra); err != nil {
|
||||
return err
|
||||
}
|
||||
deleteCustomApp()
|
||||
oldApps, err := appRepo.GetBy(appRepo.WithNotLocal())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, old := range oldApps {
|
||||
oldAppIds = append(oldAppIds, old.ID)
|
||||
}
|
||||
var sharedCtx *appSyncContext
|
||||
|
||||
baseRemoteUrl := fmt.Sprintf("%s/%s/1panel", global.CONF.RemoteURL.AppRepo, global.CONF.Base.Mode)
|
||||
|
||||
appsMap := getApps(oldApps, list.Apps, setting.SystemVersion, t)
|
||||
|
||||
t.LogStart(i18n.GetMsgByKey("SyncAppDetail"))
|
||||
for _, l := range list.Apps {
|
||||
app, ok := appsMap[l.AppProperty.Key]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
iconStr := ""
|
||||
_, iconRes, err := req_helper.HandleRequest(l.Icon, http.MethodGet, constant.TimeOut20s)
|
||||
if err == nil {
|
||||
if !strings.Contains(string(iconRes), "<xml>") {
|
||||
iconStr = base64.StdEncoding.EncodeToString(iconRes)
|
||||
}
|
||||
}
|
||||
app.Icon = iconStr
|
||||
app.TagsKey = l.AppProperty.Tags
|
||||
if l.AppProperty.Recommend > 0 {
|
||||
app.Recommend = l.AppProperty.Recommend
|
||||
} else {
|
||||
app.Recommend = 9999
|
||||
}
|
||||
app.ReadMe = l.ReadMe
|
||||
app.LastModified = l.LastModified
|
||||
versions := l.Versions
|
||||
detailsMap := getAppDetails(app.Details, versions)
|
||||
for _, v := range versions {
|
||||
version := v.Name
|
||||
detail := detailsMap[version]
|
||||
versionUrl := fmt.Sprintf("%s/%s/%s", baseRemoteUrl, app.Key, version)
|
||||
paramByte, _ := json.Marshal(v.AppForm)
|
||||
var appForm dto.AppForm
|
||||
_ = json.Unmarshal(paramByte, &appForm)
|
||||
if appForm.SupportVersion > 0 && common.CompareVersion(strconv.FormatFloat(appForm.SupportVersion, 'f', -1, 64), setting.SystemVersion) {
|
||||
delete(detailsMap, version)
|
||||
continue
|
||||
}
|
||||
if _, ok := InitTypes[app.Type]; ok {
|
||||
dockerComposeUrl := fmt.Sprintf("%s/%s", versionUrl, "docker-compose.yml")
|
||||
_, composeRes, err := req_helper.HandleRequest(dockerComposeUrl, http.MethodGet, constant.TimeOut20s)
|
||||
if err == nil {
|
||||
detail.DockerCompose = string(composeRes)
|
||||
}
|
||||
} else {
|
||||
detail.DockerCompose = ""
|
||||
}
|
||||
|
||||
detail.Params = string(paramByte)
|
||||
detail.DownloadUrl = fmt.Sprintf("%s/%s", versionUrl, app.Key+"-"+version+".tar.gz")
|
||||
detail.DownloadCallBackUrl = v.DownloadCallBackUrl
|
||||
detail.Update = true
|
||||
detail.LastModified = v.LastModified
|
||||
detailsMap[version] = detail
|
||||
}
|
||||
var newDetails []model.AppDetail
|
||||
for _, detail := range detailsMap {
|
||||
newDetails = append(newDetails, detail)
|
||||
}
|
||||
app.Details = newDetails
|
||||
appsMap[l.AppProperty.Key] = app
|
||||
}
|
||||
t.LogSuccess(i18n.GetMsgByKey("SyncAppDetail"))
|
||||
|
||||
tags, _ := tagRepo.All()
|
||||
var (
|
||||
addAppArray []model.App
|
||||
updateAppArray []model.App
|
||||
deleteAppArray []model.App
|
||||
deleteIds []uint
|
||||
tagMap = make(map[string]uint, len(tags))
|
||||
)
|
||||
|
||||
for _, v := range appsMap {
|
||||
if v.ID == 0 {
|
||||
addAppArray = append(addAppArray, v)
|
||||
} else {
|
||||
if v.Status == constant.AppTakeDown {
|
||||
installs, _ := appInstallRepo.ListBy(context.Background(), appInstallRepo.WithAppId(v.ID))
|
||||
if len(installs) > 0 {
|
||||
updateAppArray = append(updateAppArray, v)
|
||||
continue
|
||||
}
|
||||
deleteAppArray = append(deleteAppArray, v)
|
||||
deleteIds = append(deleteIds, v.ID)
|
||||
} else {
|
||||
updateAppArray = append(updateAppArray, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tx, ctx := getTxAndContext()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
}()
|
||||
if len(addAppArray) > 0 {
|
||||
if err = appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(deleteAppArray) > 0 {
|
||||
if err = appRepo.BatchDelete(ctx, deleteAppArray); err != nil {
|
||||
return
|
||||
}
|
||||
if err = appDetailRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, tag := range tags {
|
||||
tagMap[tag.Key] = tag.ID
|
||||
}
|
||||
for _, update := range updateAppArray {
|
||||
if err = appRepo.Save(ctx, &update); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
apps := append(addAppArray, updateAppArray...)
|
||||
|
||||
var (
|
||||
addDetails []model.AppDetail
|
||||
updateDetails []model.AppDetail
|
||||
deleteDetails []model.AppDetail
|
||||
)
|
||||
for _, app := range apps {
|
||||
for _, tag := range app.TagsKey {
|
||||
tagId, ok := tagMap[tag]
|
||||
if ok {
|
||||
exist, _ := appTagRepo.GetFirst(ctx, appTagRepo.WithByTagID(tagId), appTagRepo.WithByAppID(app.ID))
|
||||
if exist == nil {
|
||||
appTags = append(appTags, &model.AppTag{
|
||||
AppId: app.ID,
|
||||
TagId: tagId,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, d := range app.Details {
|
||||
d.AppId = app.ID
|
||||
if d.ID == 0 {
|
||||
addDetails = append(addDetails, d)
|
||||
} else {
|
||||
if d.Status == constant.AppTakeDown {
|
||||
runtime, _ := runtimeRepo.GetFirst(ctx, runtimeRepo.WithDetailId(d.ID))
|
||||
if runtime != nil {
|
||||
updateDetails = append(updateDetails, d)
|
||||
continue
|
||||
}
|
||||
installs, _ := appInstallRepo.ListBy(ctx, appInstallRepo.WithDetailIdsIn([]uint{d.ID}))
|
||||
if len(installs) > 0 {
|
||||
updateDetails = append(updateDetails, d)
|
||||
continue
|
||||
}
|
||||
deleteDetails = append(deleteDetails, d)
|
||||
} else {
|
||||
updateDetails = append(updateDetails, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(addDetails) > 0 {
|
||||
if err = appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(deleteDetails) > 0 {
|
||||
if err = appDetailRepo.BatchDelete(ctx, deleteDetails); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, u := range updateDetails {
|
||||
if err = appDetailRepo.Update(ctx, u); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(oldAppIds) > 0 {
|
||||
if err = appTagRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(appTags) > 0 {
|
||||
if err = appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
|
||||
_ = settingService.Update("AppStoreSyncStatus", constant.StatusSyncSuccess)
|
||||
_ = settingService.Update("AppStoreLastModified", strconv.Itoa(list.LastModified))
|
||||
return nil
|
||||
}, nil)
|
||||
syncTask.AddSubTask(task.GetTaskName(i18n.GetMsgByKey("App"), task.TaskSync, task.TaskScopeAppStore), a.createSyncAppStoreTask(&sharedCtx), nil)
|
||||
syncTask.AddSubTask(i18n.GetMsgByKey("SyncAppDetail"), a.createSyncAppStoreMetaTask(&sharedCtx), nil)
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
global.LOG.Errorf("[AppStore] sync goroutine recovered from panic: %v", r)
|
||||
if updateErr := NewISettingService().Update("AppStoreSyncStatus", constant.StatusError); updateErr != nil {
|
||||
global.LOG.Warnf("[AppStore] failed to update sync status after panic: %v", updateErr)
|
||||
}
|
||||
}
|
||||
appStoreSyncMu.Lock()
|
||||
appStoreSyncing = false
|
||||
appStoreSyncMu.Unlock()
|
||||
}()
|
||||
if err := syncTask.Execute(); err != nil {
|
||||
_ = NewISettingService().Update("AppStoreLastModified", "0")
|
||||
_ = NewISettingService().Update("AppStoreSyncStatus", constant.StatusError)
|
||||
if updateErr := NewISettingService().Update("AppStoreLastModified", "0"); updateErr != nil {
|
||||
global.LOG.Warnf("[AppStore] failed to reset last modified: %v", updateErr)
|
||||
}
|
||||
if updateErr := NewISettingService().Update("AppStoreSyncStatus", constant.StatusError); updateErr != nil {
|
||||
global.LOG.Warnf("[AppStore] failed to update sync status to error: %v", updateErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
global.LOG.Info("[AppStore] sync app from remote task create ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppService) GetAppIcon(appID uint) ([]byte, error) {
|
||||
app, err := appRepo.GetFirst(repo.WithByID(appID))
|
||||
func (a AppService) GetAppIcon(key string) ([]byte, string, string, error) {
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
if appicon.IsIconFile(app.Icon) {
|
||||
fileName, etag := appicon.ParseIconField(app.Icon)
|
||||
iconBytes, err := appicon.ReadIconFile(fileName)
|
||||
if err != nil {
|
||||
global.LOG.Warnf("[AppIcon] read icon file failed key=%s, file=%s, err=%v", key, fileName, err)
|
||||
return nil, "", "", nil
|
||||
}
|
||||
return iconBytes, fileName, etag, nil
|
||||
}
|
||||
|
||||
iconBytes, err := base64.StdEncoding.DecodeString(app.Icon)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
global.LOG.Warnf("[AppIcon] decode base64 icon failed key=%s, err=%v", key, err)
|
||||
return nil, "", "", nil
|
||||
}
|
||||
return iconBytes, nil
|
||||
return iconBytes, "", "", nil
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []respo
|
||||
}
|
||||
}
|
||||
|
||||
installDTOs, _ := handleInstalled(installs, req.Update, req.Sync)
|
||||
installDTOs, _ := handleInstalled(installs, req.Update, req.Sync, req.CheckUpdate)
|
||||
if req.Update {
|
||||
total = int64(len(installDTOs))
|
||||
}
|
||||
@@ -238,7 +238,7 @@ func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]
|
||||
}
|
||||
}
|
||||
|
||||
return handleInstalled(installs, false, true)
|
||||
return handleInstalled(installs, false, true, false)
|
||||
}
|
||||
|
||||
func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/appicon"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
)
|
||||
|
||||
type appSyncContext struct {
|
||||
task *task.Task
|
||||
httpClient http.Client
|
||||
baseRemoteUrl string
|
||||
systemVersion string
|
||||
appsMap map[string]model.App
|
||||
settingService ISettingService
|
||||
list *dto.AppList
|
||||
oldAppIds []uint
|
||||
appTags []*model.AppTag
|
||||
skipMetaSync bool
|
||||
pendingIcons map[string]string
|
||||
}
|
||||
|
||||
func (a AppService) createSyncAppStoreTask(sharedCtx **appSyncContext) func(t *task.Task) error {
|
||||
return func(t *task.Task) (err error) {
|
||||
t.LogStart(i18n.GetMsgByKey("AppStore") + " " + i18n.GetMsgByKey("TaskSync"))
|
||||
|
||||
updateRes, err := a.GetAppUpdate()
|
||||
if err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("CheckAppStoreUpdate"), err)
|
||||
return err
|
||||
}
|
||||
if !updateRes.CanUpdate {
|
||||
if updateRes.IsSyncing {
|
||||
t.Log(i18n.GetMsgByKey("AppStoreIsSyncing"))
|
||||
return nil
|
||||
}
|
||||
global.LOG.Infof("[AppStore] Appstore is up to date")
|
||||
t.Log(i18n.GetMsgByKey("AppStoreIsUpToDate"))
|
||||
*sharedCtx = &appSyncContext{skipMetaSync: true}
|
||||
t.LogSuccess(i18n.GetMsgByKey("AppStore") + " " + i18n.GetMsgByKey("TaskSync"))
|
||||
return nil
|
||||
}
|
||||
|
||||
list := &dto.AppList{}
|
||||
if updateRes.AppList == nil {
|
||||
list, err = getAppList()
|
||||
if err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("DownloadAppList"), err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
list = updateRes.AppList
|
||||
}
|
||||
|
||||
settingService := NewISettingService()
|
||||
if err := settingService.Update("AppStoreSyncStatus", constant.StatusSyncing); err != nil {
|
||||
global.LOG.Warnf("[AppStore] failed to update sync status to syncing: %v", err)
|
||||
}
|
||||
|
||||
setting, err := settingService.GetSettingInfo()
|
||||
if err != nil {
|
||||
t.LogFailedWithErr("GetSettingInfo", err)
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := &appSyncContext{
|
||||
task: t,
|
||||
httpClient: http.Client{Timeout: time.Duration(constant.TimeOut20s) * time.Second, Transport: xpack.LoadRequestTransport()},
|
||||
baseRemoteUrl: fmt.Sprintf("%s/%s/1panel", global.CONF.RemoteURL.AppRepo, global.CONF.Base.Mode),
|
||||
systemVersion: setting.SystemVersion,
|
||||
settingService: settingService,
|
||||
list: list,
|
||||
appTags: make([]*model.AppTag, 0),
|
||||
pendingIcons: make(map[string]string),
|
||||
}
|
||||
|
||||
if err = SyncTags(list.Extra); err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("SyncTags"), err)
|
||||
return err
|
||||
}
|
||||
deleteCustomApp()
|
||||
|
||||
oldApps, err := appRepo.GetBy(appRepo.WithNotLocal())
|
||||
if err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("LoadLocalApps"), err)
|
||||
return err
|
||||
}
|
||||
ctx.oldAppIds = make([]uint, 0, len(oldApps))
|
||||
for _, old := range oldApps {
|
||||
ctx.oldAppIds = append(ctx.oldAppIds, old.ID)
|
||||
}
|
||||
|
||||
ctx.appsMap, ctx.pendingIcons = getApps(oldApps, list.Apps, setting.SystemVersion, t)
|
||||
|
||||
var addCount, updateCount, deleteCount int
|
||||
if err = ctx.classifyAndPersistAppsWithStats(&addCount, &updateCount, &deleteCount); err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("PersistApps"), err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := settingService.Update("AppStoreSyncStatus", constant.StatusSyncSuccess); err != nil {
|
||||
global.LOG.Warnf("[AppStore] failed to update sync status to success: %v", err)
|
||||
}
|
||||
if err := settingService.Update("AppStoreLastModified", strconv.Itoa(list.LastModified)); err != nil {
|
||||
global.LOG.Warnf("[AppStore] failed to update last modified: %v", err)
|
||||
}
|
||||
global.LOG.Infof("[AppStore] Appstore sync completed")
|
||||
|
||||
*sharedCtx = ctx
|
||||
t.LogSuccess(i18n.GetMsgByKey("AppStore") + " " + i18n.GetMsgByKey("TaskSync"))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *appSyncContext) syncAppIconsAndDetails() error {
|
||||
total := len(c.list.Apps)
|
||||
global.LOG.Infof("[AppStore] sync app detail start, total apps: %d", total)
|
||||
|
||||
var (
|
||||
icon200Count = 0
|
||||
icon304Count = 0
|
||||
iconFailCount = 0
|
||||
)
|
||||
|
||||
for i, l := range c.list.Apps {
|
||||
if (i+1)%10 == 0 {
|
||||
c.task.LogWithProgress(i18n.GetMsgByKey("SyncAppDetail"), i+1, total)
|
||||
}
|
||||
|
||||
app, ok := c.appsMap[l.AppProperty.Key]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
iconUrl, hasPending := c.pendingIcons[l.AppProperty.Key]
|
||||
if hasPending {
|
||||
status, iconField := c.downloadAppIcon(iconUrl, l.AppProperty.Key, app.Icon)
|
||||
switch status {
|
||||
case http.StatusOK:
|
||||
app.Icon = iconField
|
||||
icon200Count++
|
||||
case http.StatusNotModified:
|
||||
icon304Count++
|
||||
default:
|
||||
global.LOG.Warnf("[AppStore] download icon failed url=%s, appKey=%s", iconUrl, l.AppProperty.Key)
|
||||
iconFailCount++
|
||||
}
|
||||
}
|
||||
|
||||
app.TagsKey = l.AppProperty.Tags
|
||||
if l.AppProperty.Recommend > 0 {
|
||||
app.Recommend = l.AppProperty.Recommend
|
||||
} else {
|
||||
app.Recommend = 9999
|
||||
}
|
||||
app.ReadMe = l.ReadMe
|
||||
app.LastModified = l.LastModified
|
||||
|
||||
versions := l.Versions
|
||||
detailsMap := getAppDetails(app.Details, versions)
|
||||
for _, v := range versions {
|
||||
version := v.Name
|
||||
detail := detailsMap[version]
|
||||
versionUrl := fmt.Sprintf("%s/%s/%s", c.baseRemoteUrl, app.Key, version)
|
||||
|
||||
paramByte, _ := json.Marshal(v.AppForm)
|
||||
var appForm dto.AppForm
|
||||
_ = json.Unmarshal(paramByte, &appForm)
|
||||
|
||||
if appForm.SupportVersion > 0 && common.CompareVersion(strconv.FormatFloat(appForm.SupportVersion, 'f', -1, 64), c.systemVersion) {
|
||||
delete(detailsMap, version)
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := InitTypes[app.Type]; ok {
|
||||
dockerComposeUrl := fmt.Sprintf("%s/%s", versionUrl, "docker-compose.yml")
|
||||
_, composeRes, err := req_helper.HandleRequestWithClient(&c.httpClient, dockerComposeUrl, http.MethodGet, constant.TimeOut20s)
|
||||
if err == nil {
|
||||
detail.DockerCompose = string(composeRes)
|
||||
}
|
||||
} else {
|
||||
detail.DockerCompose = ""
|
||||
}
|
||||
|
||||
detail.Params = string(paramByte)
|
||||
detail.DownloadUrl = fmt.Sprintf("%s/%s", versionUrl, app.Key+"-"+version+".tar.gz")
|
||||
detail.DownloadCallBackUrl = v.DownloadCallBackUrl
|
||||
detail.Update = true
|
||||
detail.LastModified = v.LastModified
|
||||
detailsMap[version] = detail
|
||||
}
|
||||
|
||||
var newDetails []model.AppDetail
|
||||
for _, detail := range detailsMap {
|
||||
newDetails = append(newDetails, detail)
|
||||
}
|
||||
app.Details = newDetails
|
||||
c.appsMap[l.AppProperty.Key] = app
|
||||
}
|
||||
|
||||
global.LOG.Infof("[AppStore] icon download completed - total: %d, success(200): %d, cached(304): %d, failed: %d",
|
||||
total, icon200Count, icon304Count, iconFailCount)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *appSyncContext) downloadAppIcon(iconUrl, appKey, oldIcon string) (status int, iconField string) {
|
||||
iconFileName, existingEtag := appicon.ParseIconField(oldIcon)
|
||||
|
||||
reqHeaders := make(map[string]string)
|
||||
if existingEtag != "" && iconFileName != "" && appicon.IconFileExists(iconFileName) {
|
||||
reqHeaders["If-None-Match"] = existingEtag
|
||||
}
|
||||
|
||||
resp, err := req_helper.HandleRequestWithHeaders(&c.httpClient, iconUrl, http.MethodGet, constant.TimeOut20s, reqHeaders)
|
||||
if err != nil {
|
||||
global.LOG.Warnf("[AppStore] request icon failed url=%s, err=%v", iconUrl, err)
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotModified {
|
||||
return http.StatusNotModified, ""
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
global.LOG.Warnf("[AppStore] download icon failed url=%s, status=%d", iconUrl, resp.StatusCode)
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
if len(resp.Body) == 0 {
|
||||
global.LOG.Warnf("[AppStore] download icon empty body url=%s", iconUrl)
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
if resp.Body[0] == '<' {
|
||||
global.LOG.Warnf("[AppStore] download icon got HTML response url=%s", iconUrl)
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
ct := strings.TrimSpace(strings.Split(contentType, ";")[0])
|
||||
if strings.ToLower(ct) != "image/png" {
|
||||
global.LOG.Warnf("[AppStore] unexpected icon content-type: %s, expected image/png, url=%s", ct, iconUrl)
|
||||
}
|
||||
|
||||
fileName, err := appicon.WriteIconFile(appKey, resp.Body)
|
||||
if err != nil {
|
||||
global.LOG.Warnf("[AppStore] write icon file failed appKey=%s, err=%v", appKey, err)
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
newEtag := resp.Header.Get("ETag")
|
||||
iconField = appicon.BuildIconField(fileName, newEtag)
|
||||
|
||||
return http.StatusOK, iconField
|
||||
}
|
||||
|
||||
func (a AppService) createSyncAppStoreMetaTask(sharedCtx **appSyncContext) func(t *task.Task) error {
|
||||
return func(t *task.Task) (err error) {
|
||||
t.LogStart(i18n.GetMsgByKey("SyncAppDetail"))
|
||||
ctx := *sharedCtx
|
||||
if ctx == nil {
|
||||
global.LOG.Warnf("[AppStore] meta sync skipped: shared context is nil")
|
||||
t.Log(i18n.GetMsgByKey("SyncAppDetail") + " skipped: shared context is nil")
|
||||
return nil
|
||||
}
|
||||
|
||||
if ctx.skipMetaSync {
|
||||
global.LOG.Infof("[AppStore] meta sync skipped: no update needed")
|
||||
t.Log(i18n.GetMsgByKey("SyncAppDetail") + " skipped: no update needed")
|
||||
return nil
|
||||
}
|
||||
|
||||
if ctx.list == nil || ctx.appsMap == nil {
|
||||
global.LOG.Errorf("[AppStore] meta sync failed: shared context data not initialized")
|
||||
err := fmt.Errorf("shared context data not initialized")
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("SyncAppDetail"), err)
|
||||
return err
|
||||
}
|
||||
|
||||
t.Logf("%s: %d apps", i18n.GetMsgByKey("SyncAppDetail"), len(ctx.list.Apps))
|
||||
|
||||
ctx.task = t
|
||||
ctx.appTags = make([]*model.AppTag, 0)
|
||||
|
||||
if err = ctx.syncAppIconsAndDetails(); err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("SyncAppDetail"), err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ctx.classifyAndPersistApps(); err != nil {
|
||||
t.LogFailedWithErr(i18n.GetMsgByKey("PersistAppDetails"), err)
|
||||
return err
|
||||
}
|
||||
|
||||
global.LOG.Infof("[AppStore] Appstore meta sync completed")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *appSyncContext) classifyAndPersistApps() (err error) {
|
||||
var addCount, updateCount, deleteCount int
|
||||
return c.classifyAndPersistAppsWithStats(&addCount, &updateCount, &deleteCount)
|
||||
}
|
||||
|
||||
func (c *appSyncContext) classifyAndPersistAppsWithStats(addCount, updateCount, deleteCount *int) (err error) {
|
||||
tags, _ := tagRepo.All()
|
||||
var (
|
||||
addAppArray []model.App
|
||||
updateAppArray []model.App
|
||||
deleteAppArray []model.App
|
||||
deleteIds []uint
|
||||
tagMap = make(map[string]uint, len(tags))
|
||||
)
|
||||
|
||||
for _, v := range c.appsMap {
|
||||
if v.ID == 0 {
|
||||
addAppArray = append(addAppArray, v)
|
||||
} else {
|
||||
if v.Status == constant.AppTakeDown {
|
||||
installs, _ := appInstallRepo.ListBy(context.Background(), appInstallRepo.WithAppId(v.ID))
|
||||
if len(installs) > 0 {
|
||||
updateAppArray = append(updateAppArray, v)
|
||||
continue
|
||||
}
|
||||
deleteAppArray = append(deleteAppArray, v)
|
||||
deleteIds = append(deleteIds, v.ID)
|
||||
} else {
|
||||
updateAppArray = append(updateAppArray, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(addAppArray) > 0 {
|
||||
addKeys := make([]string, 0, len(addAppArray))
|
||||
for _, app := range addAppArray {
|
||||
addKeys = append(addKeys, app.Key)
|
||||
}
|
||||
existingApps, _ := appRepo.GetBy(appRepo.WithKeyIn(addKeys))
|
||||
if len(existingApps) > 0 {
|
||||
existingMap := make(map[string]model.App, len(existingApps))
|
||||
for _, e := range existingApps {
|
||||
existingMap[e.Key] = e
|
||||
}
|
||||
filteredAdd := make([]model.App, 0, len(addAppArray))
|
||||
for _, app := range addAppArray {
|
||||
if existing, ok := existingMap[app.Key]; ok {
|
||||
app.ID = existing.ID
|
||||
if len(app.Details) == 0 {
|
||||
app.Details = existing.Details
|
||||
}
|
||||
updateAppArray = append(updateAppArray, app)
|
||||
} else {
|
||||
filteredAdd = append(filteredAdd, app)
|
||||
}
|
||||
}
|
||||
addAppArray = filteredAdd
|
||||
}
|
||||
}
|
||||
|
||||
*addCount = len(addAppArray)
|
||||
*updateCount = len(updateAppArray)
|
||||
*deleteCount = len(deleteAppArray)
|
||||
|
||||
tx, ctx := getTxAndContext()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
if len(addAppArray) > 0 {
|
||||
if err = appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(deleteAppArray) > 0 {
|
||||
if err = appRepo.BatchDelete(ctx, deleteAppArray); err != nil {
|
||||
return
|
||||
}
|
||||
if err = appDetailRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
tagMap[tag.Key] = tag.ID
|
||||
}
|
||||
|
||||
if len(updateAppArray) > 0 {
|
||||
for _, update := range updateAppArray {
|
||||
if err = appRepo.Save(ctx, &update); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apps := append(addAppArray, updateAppArray...)
|
||||
|
||||
var (
|
||||
addDetails []model.AppDetail
|
||||
updateDetails []model.AppDetail
|
||||
deleteDetails []model.AppDetail
|
||||
)
|
||||
|
||||
totalDetails := 0
|
||||
for _, app := range apps {
|
||||
for _, tag := range app.TagsKey {
|
||||
tagId, ok := tagMap[tag]
|
||||
if ok {
|
||||
exist, _ := appTagRepo.GetFirst(ctx, appTagRepo.WithByTagID(tagId), appTagRepo.WithByAppID(app.ID))
|
||||
if exist == nil {
|
||||
c.appTags = append(c.appTags, &model.AppTag{
|
||||
AppId: app.ID,
|
||||
TagId: tagId,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, d := range app.Details {
|
||||
totalDetails++
|
||||
d.AppId = app.ID
|
||||
if d.ID == 0 {
|
||||
addDetails = append(addDetails, d)
|
||||
} else {
|
||||
if d.Status == constant.AppTakeDown {
|
||||
runtime, _ := runtimeRepo.GetFirst(ctx, runtimeRepo.WithDetailId(d.ID))
|
||||
if runtime != nil {
|
||||
updateDetails = append(updateDetails, d)
|
||||
continue
|
||||
}
|
||||
installs, _ := appInstallRepo.ListBy(ctx, appInstallRepo.WithDetailIdsIn([]uint{d.ID}))
|
||||
if len(installs) > 0 {
|
||||
updateDetails = append(updateDetails, d)
|
||||
continue
|
||||
}
|
||||
deleteDetails = append(deleteDetails, d)
|
||||
} else {
|
||||
updateDetails = append(updateDetails, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(addDetails) > 0 {
|
||||
if err = appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(deleteDetails) > 0 {
|
||||
if err = appDetailRepo.BatchDelete(ctx, deleteDetails); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(updateDetails) > 0 {
|
||||
for _, u := range updateDetails {
|
||||
if err = appDetailRepo.Update(ctx, u); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.oldAppIds) > 0 {
|
||||
if err = appTagRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.appTags) > 0 {
|
||||
if err = appTagRepo.BatchCreate(ctx, c.appTags); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = tx.Commit().Error; err != nil {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -392,6 +392,10 @@ func deleteAppInstall(deleteReq request.AppInstallDelete) error {
|
||||
if err = appInstallRepo.Delete(ctx, install); err != nil {
|
||||
return err
|
||||
}
|
||||
appKey := install.App.Key
|
||||
if appKey == constant.AppOpenclaw {
|
||||
_ = agentRepo.DeleteByAppInstallIDWithCtx(ctx, install.ID)
|
||||
}
|
||||
|
||||
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if len(resources) > 0 {
|
||||
@@ -764,6 +768,30 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
|
||||
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
|
||||
_, _ = command.CombinedOutput()
|
||||
if install.App.Key == constant.AppOpenresty {
|
||||
installBuildDir := path.Join(install.GetPath(), "build")
|
||||
detailBuildDir := path.Join(detailDir, "build")
|
||||
if !fileOp.Stat(installBuildDir) {
|
||||
if err := fileOp.CreateDir(installBuildDir, constant.DirPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := fileOp.DeleteDir(path.Join(installBuildDir, "tmp")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CopyDir(path.Join(detailBuildDir, "tmp"), installBuildDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CopyFile(path.Join(detailBuildDir, "Dockerfile"), installBuildDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CopyFile(path.Join(detailBuildDir, "nginx.conf"), installBuildDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.CopyFile(path.Join(detailBuildDir, "nginx.vh.default.conf"), installBuildDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sourceScripts := path.Join(detailDir, "scripts")
|
||||
if fileOp.Stat(sourceScripts) {
|
||||
dstScripts := path.Join(install.GetPath(), "scripts")
|
||||
@@ -1271,8 +1299,9 @@ func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) m
|
||||
return appDetails
|
||||
}
|
||||
|
||||
func getApps(oldApps []model.App, items []dto.AppDefine, systemVersion string, task *task.Task) map[string]model.App {
|
||||
func getApps(oldApps []model.App, items []dto.AppDefine, systemVersion string, task *task.Task) (map[string]model.App, map[string]string) {
|
||||
apps := make(map[string]model.App, len(oldApps))
|
||||
pendingIcons := make(map[string]string, len(items))
|
||||
for _, old := range oldApps {
|
||||
old.Status = constant.AppTakeDown
|
||||
apps[old.Key] = old
|
||||
@@ -1312,9 +1341,13 @@ func getApps(oldApps []model.App, items []dto.AppDefine, systemVersion string, t
|
||||
app.MemoryRequired = config.MemoryRequired
|
||||
app.Architectures = strings.Join(config.Architectures, ",")
|
||||
app.GpuSupport = config.GpuSupport
|
||||
app.BatchInstallSupport = config.BatchInstallSupport
|
||||
if item.Icon != "" {
|
||||
pendingIcons[key] = item.Icon
|
||||
}
|
||||
apps[key] = app
|
||||
}
|
||||
return apps
|
||||
return apps, pendingIcons
|
||||
}
|
||||
|
||||
func handleLocalAppDetail(versionDir string, appDetail *model.AppDetail) error {
|
||||
@@ -1530,7 +1563,7 @@ func synAppInstall(containers map[string]container.Summary, appInstall *model.Ap
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
}
|
||||
|
||||
func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool) ([]response.AppInstallDTO, error) {
|
||||
func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpdate bool) ([]response.AppInstallDTO, error) {
|
||||
var (
|
||||
res []response.AppInstallDTO
|
||||
containersMap map[string]container.Summary
|
||||
@@ -1553,6 +1586,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
||||
if updated && ignoreUpdate(installed) {
|
||||
continue
|
||||
}
|
||||
|
||||
if sync && !doNotNeedSync(installed) {
|
||||
synAppInstall(containersMap, &installed, false)
|
||||
}
|
||||
@@ -1582,20 +1616,30 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
||||
Container: installed.ContainerName,
|
||||
ServiceName: strings.ToLower(installed.ServiceName),
|
||||
}
|
||||
if !updated {
|
||||
|
||||
if !updated && !checkUpdate {
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
res = append(res, installDTO)
|
||||
continue
|
||||
}
|
||||
|
||||
if installed.Version == "latest" {
|
||||
if checkUpdate {
|
||||
installDTO.CanUpdate = false
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
installDTO.DockerCompose = installed.DockerCompose
|
||||
installDTO.IsEdit = isEditCompose(installed)
|
||||
|
||||
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(installed.App.ID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var versions []string
|
||||
for _, appDetail := range details {
|
||||
ignores, _ := appIgnoreUpgradeRepo.List(runtimeRepo.WithDetailId(appDetail.ID), appIgnoreUpgradeRepo.WithScope("version"))
|
||||
@@ -1607,11 +1651,19 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
||||
}
|
||||
versions = append(versions, appDetail.Version)
|
||||
}
|
||||
|
||||
if len(versions) == 0 {
|
||||
if checkUpdate {
|
||||
installDTO.CanUpdate = false
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
versions = common.GetSortedVersions(versions)
|
||||
lastVersion := versions[0]
|
||||
|
||||
if installed.App.Key == constant.AppMysql || installed.App.Key == constant.AppMysqlCluster {
|
||||
for _, version := range versions {
|
||||
majorVersion := getMajorVersion(installed.Version)
|
||||
@@ -1623,15 +1675,23 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if common.IsCrossVersion(installed.Version, lastVersion) {
|
||||
installDTO.CanUpdate = installed.App.CrossVersionUpdate
|
||||
} else {
|
||||
installDTO.CanUpdate = common.CompareVersion(lastVersion, installed.Version)
|
||||
}
|
||||
if installDTO.CanUpdate {
|
||||
|
||||
if updated {
|
||||
if installDTO.CanUpdate {
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
} else if checkUpdate {
|
||||
installDTO.LinkDB = hasLinkDB(installed.ID)
|
||||
res = append(res, installDTO)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -1960,23 +2020,26 @@ func handleSiteDir(app model.App, appDetail model.AppDetail, req request.AppInst
|
||||
req.Params["WEBSITE_DIR"] = siteDir
|
||||
oldWebStePath, _ := settingRepo.GetValueByKey("WEBSITE_DIR")
|
||||
fileOp := files.NewFileOp()
|
||||
movePath := func(src, dst string) error {
|
||||
return cmd.NewCommandMgr().Run("mv", src, dst)
|
||||
}
|
||||
if oldWebStePath != "" && oldWebStePath != siteDir && fileOp.Stat(oldWebStePath) {
|
||||
t.Log(i18n.GetWithName("MoveSiteDir", siteDir))
|
||||
if fileOp.Stat(siteDir) {
|
||||
if fileOp.Stat(path.Join(siteDir, "conf.d")) {
|
||||
_ = fileOp.Rename(path.Join(siteDir, "conf.d"), path.Join(siteDir, "conf.d.bak"))
|
||||
_ = movePath(path.Join(siteDir, "conf.d"), path.Join(siteDir, "conf.d.bak"))
|
||||
}
|
||||
if fileOp.Stat(path.Join(siteDir, "sites")) {
|
||||
_ = fileOp.Rename(path.Join(siteDir, "sites"), path.Join(siteDir, "sites.bak"))
|
||||
_ = movePath(path.Join(siteDir, "sites"), path.Join(siteDir, "sites.bak"))
|
||||
}
|
||||
if err := fileOp.Rename(path.Join(oldWebStePath, "sites"), path.Join(siteDir, "sites")); err != nil {
|
||||
if err := movePath(path.Join(oldWebStePath, "sites"), path.Join(siteDir, "sites")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fileOp.Rename(path.Join(oldWebStePath, "conf.d"), path.Join(siteDir, "conf.d")); err != nil {
|
||||
if err := movePath(path.Join(oldWebStePath, "conf.d"), path.Join(siteDir, "conf.d")); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := fileOp.Rename(oldWebStePath, siteDir)
|
||||
err := movePath(oldWebStePath, siteDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2091,15 +2154,21 @@ func handleSSLConfig(appInstall *model.AppInstall, hasDefaultWebsite bool, sslRe
|
||||
return nil
|
||||
}
|
||||
|
||||
func SyncTags(remoteProperties dto.ExtraProperties) error {
|
||||
func SyncTags(remoteProperties dto.ExtraProperties) (err error) {
|
||||
tx, ctx := getTxAndContext()
|
||||
defer tx.Rollback()
|
||||
localTags, _ := tagRepo.All()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
localTags, err := tagRepo.All()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
localTagsMap := make(map[string]*model.Tag)
|
||||
for i := range localTags {
|
||||
localTagsMap[localTags[i].Key] = &localTags[i]
|
||||
}
|
||||
var err error
|
||||
remoteTagsMap := make(map[string]*dto.Tag)
|
||||
for i := range remoteProperties.Tags {
|
||||
remoteTagsMap[remoteProperties.Tags[i].Key] = &remoteProperties.Tags[i]
|
||||
@@ -2107,7 +2176,9 @@ func SyncTags(remoteProperties dto.ExtraProperties) error {
|
||||
|
||||
for key, localTag := range localTagsMap {
|
||||
if _, exists := remoteTagsMap[key]; !exists {
|
||||
_ = tagRepo.DeleteByID(ctx, localTag.ID)
|
||||
if err = tagRepo.DeleteByID(ctx, localTag.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2137,7 +2208,9 @@ func SyncTags(remoteProperties dto.ExtraProperties) error {
|
||||
}
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
if err = tx.Commit().Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ func (u *BackupService) GetLocalDir() (string, error) {
|
||||
}
|
||||
|
||||
func (u *BackupService) SearchWithPage(req dto.SearchPageWithType) (int64, interface{}, error) {
|
||||
options := []repo.DBOption{repo.WithOrderBy("created_at desc")}
|
||||
options := []repo.DBOption{repo.WithOrderDesc("created_at")}
|
||||
if len(req.Type) != 0 {
|
||||
options = append(options, repo.WithByType(req.Type))
|
||||
}
|
||||
@@ -372,7 +372,7 @@ func (u *BackupService) checkBackupConn(backup *model.BackupAccount) (bool, erro
|
||||
}
|
||||
|
||||
func (u *BackupService) LoadBackupOptions() ([]dto.BackupOption, error) {
|
||||
accounts, err := backupRepo.List(repo.WithOrderBy("created_at desc"))
|
||||
accounts, err := backupRepo.List(repo.WithOrderDesc("created_at"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -535,7 +535,7 @@ func loadRefreshTokenByCode(backup *model.BackupAccount) (string, error) {
|
||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
||||
return "", fmt.Errorf("unmarshal backup vars failed, err: %v", err)
|
||||
}
|
||||
if _, ok := varMap["refresh_token"]; ok {
|
||||
if token, ok := varMap["refresh_token"]; ok && len(token.(string)) != 0 {
|
||||
return "", nil
|
||||
}
|
||||
refreshToken := ""
|
||||
|
||||
@@ -44,7 +44,7 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error {
|
||||
return err
|
||||
}
|
||||
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName}
|
||||
databaseHelper := DatabaseHelper{Database: req.Name, DBType: req.Type, Name: req.DetailName, Args: req.Args}
|
||||
if err := handleMysqlBackup(databaseHelper, nil, record.ID, targetDir, fileName, req.TaskID, req.Secret); err != nil {
|
||||
backupRepo.UpdateRecordByMap(record.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
return err
|
||||
@@ -87,7 +87,12 @@ func handleMysqlBackup(db DatabaseHelper, parentTask *task.Task, recordID uint,
|
||||
}
|
||||
}
|
||||
|
||||
itemHandler := func() error { return doMysqlBackup(db, targetDir, fileName, secret) }
|
||||
itemHandler := func() error {
|
||||
if len(db.Args) != 0 {
|
||||
backupTask.Logf("%s: %v", i18n.GetMsgByKey("Arg"), db.Args)
|
||||
}
|
||||
return doMysqlBackup(db, targetDir, fileName, secret)
|
||||
}
|
||||
if parentTask != nil {
|
||||
return itemHandler()
|
||||
}
|
||||
@@ -225,6 +230,7 @@ func doMysqlBackup(db DatabaseHelper, targetDir, fileName, secret string) error
|
||||
Format: dbInfo.Format,
|
||||
TargetDir: targetDir,
|
||||
FileName: fileName,
|
||||
Args: db.Args,
|
||||
}
|
||||
if err := cli.Backup(backupInfo); err != nil {
|
||||
return err
|
||||
|
||||
@@ -38,7 +38,7 @@ func NewIBackupRecordService() IBackupRecordService {
|
||||
func (u *BackupRecordService) SearchRecordsWithPage(search dto.RecordSearch) (int64, []dto.BackupRecords, error) {
|
||||
total, records, err := backupRepo.PageRecord(
|
||||
search.Page, search.PageSize,
|
||||
repo.WithOrderBy("created_at desc"),
|
||||
repo.WithOrderDesc("created_at"),
|
||||
repo.WithByName(search.Name),
|
||||
repo.WithByType(search.Type),
|
||||
repo.WithByDetailName(search.DetailName),
|
||||
@@ -69,7 +69,7 @@ func (u *BackupRecordService) SearchRecordsWithPage(search dto.RecordSearch) (in
|
||||
func (u *BackupRecordService) SearchRecordsByCronjobWithPage(search dto.RecordSearchByCronjob) (int64, []dto.BackupRecords, error) {
|
||||
total, records, err := backupRepo.PageRecord(
|
||||
search.Page, search.PageSize,
|
||||
repo.WithOrderBy("created_at desc"),
|
||||
repo.WithOrderDesc("created_at"),
|
||||
backupRepo.WithByCronID(search.CronjobID),
|
||||
)
|
||||
if err != nil {
|
||||
@@ -166,7 +166,7 @@ func (u *BackupRecordService) BatchDeleteRecord(ids []uint) error {
|
||||
|
||||
func (u *BackupRecordService) ListAppRecords(name, detailName, fileName string) ([]model.BackupRecord, error) {
|
||||
records, err := backupRepo.ListRecord(
|
||||
repo.WithOrderBy("created_at asc"),
|
||||
repo.WithOrderAsc("created_at"),
|
||||
repo.WithByName(name),
|
||||
repo.WithByType("app"),
|
||||
backupRepo.WithFileNameStartWith(fileName),
|
||||
@@ -221,7 +221,7 @@ func (u *BackupRecordService) LoadRecordSize(req dto.SearchForSize) ([]dto.Recor
|
||||
list = append(list, backupSizeHelper{ID: item.ID, DownloadID: item.DownloadAccountID, FilePath: fmt.Sprintf("system_snapshot/%s.tar.gz", item.Name)})
|
||||
}
|
||||
case "cronjob":
|
||||
_, records, err := backupRepo.PageRecord(req.Page, req.PageSize, repo.WithOrderBy("created_at desc"), backupRepo.WithByCronID(req.CronjobID))
|
||||
_, records, err := backupRepo.PageRecord(req.Page, req.PageSize, repo.WithOrderDesc("created_at"), backupRepo.WithByCronID(req.CronjobID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -231,7 +231,7 @@ func (u *BackupRecordService) LoadRecordSize(req dto.SearchForSize) ([]dto.Recor
|
||||
default:
|
||||
_, records, err := backupRepo.PageRecord(
|
||||
req.Page, req.PageSize,
|
||||
repo.WithOrderBy("created_at desc"),
|
||||
repo.WithOrderDesc("created_at"),
|
||||
repo.WithByName(req.Name),
|
||||
repo.WithByType(req.Type),
|
||||
repo.WithByDetailName(req.DetailName),
|
||||
|
||||
@@ -96,7 +96,7 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_ = clam.StopAllClamJob(false, clamRepo)
|
||||
_ = clam.CheckWithStopAll(false, clamRepo)
|
||||
}
|
||||
if baseInfo.FreshIsActive {
|
||||
version, err := cmd.RunDefaultWithStdoutBashC("freshclam --version")
|
||||
@@ -313,7 +313,7 @@ func (c *ClamService) Delete(req dto.ClamDelete) error {
|
||||
}
|
||||
|
||||
func (c *ClamService) HandleOnce(id uint) error {
|
||||
if active := clam.StopAllClamJob(true, clamRepo); !active {
|
||||
if active := clam.CheckWithStopAll(true, clamRepo); !active {
|
||||
return buserr.New("ErrClamdscanNotFound")
|
||||
}
|
||||
clamItem, _ := clamRepo.Get(repo.WithByID(id))
|
||||
@@ -337,9 +337,9 @@ func (c *ClamService) HandleOnce(id uint) error {
|
||||
clamRepo.EndRecords(record, constant.StatusFailed, err.Error())
|
||||
return
|
||||
}
|
||||
handleAlert(record.InfectedFiles, clamItem.Name, clamItem.ID)
|
||||
clam.AnalysisFromLog(taskItem.LogFile, &record)
|
||||
clamRepo.EndRecords(record, constant.StatusDone, "")
|
||||
handleAlert(record.InfectedFiles, clamItem.Name, clamItem.ID)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -59,9 +59,15 @@ type IContainerService interface {
|
||||
ListNetwork() ([]dto.Options, error)
|
||||
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
ListVolume() ([]dto.Options, error)
|
||||
|
||||
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
LoadComposeEnv(name string) (string, error)
|
||||
CreateCompose(req dto.ComposeCreate) error
|
||||
ComposeOperation(req dto.ComposeOperation) error
|
||||
TestCompose(req dto.ComposeCreate) (bool, error)
|
||||
ComposeUpdate(req dto.ComposeUpdate) error
|
||||
ComposeLogClean(req dto.ComposeLogClean) error
|
||||
|
||||
ContainerCreate(req dto.ContainerOperate, inThread bool) error
|
||||
ContainerCreateByCommand(req dto.ContainerCreateByCommand) error
|
||||
ContainerUpdate(req dto.ContainerOperate) error
|
||||
@@ -74,16 +80,14 @@ type IContainerService interface {
|
||||
ContainerCommit(req dto.ContainerCommit) error
|
||||
ContainerLogClean(req dto.OperationWithName) error
|
||||
ContainerOperation(req dto.ContainerOperation) error
|
||||
DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error
|
||||
DownloadContainerLogs(containerType, container, since, tail string, timestamp bool, c *gin.Context) error
|
||||
ContainerStats(id string) (*dto.ContainerStats, error)
|
||||
|
||||
Inspect(req dto.InspectReq) (string, error)
|
||||
DeleteNetwork(req dto.BatchDelete) error
|
||||
CreateNetwork(req dto.NetworkCreate) error
|
||||
DeleteVolume(req dto.BatchDelete) error
|
||||
CreateVolume(req dto.VolumeCreate) error
|
||||
TestCompose(req dto.ComposeCreate) (bool, error)
|
||||
ComposeUpdate(req dto.ComposeUpdate) error
|
||||
ComposeLogClean(req dto.ComposeLogClean) error
|
||||
Prune(req dto.ContainerPrune) error
|
||||
|
||||
LoadUsers(req dto.OperationWithName) []string
|
||||
@@ -435,7 +439,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
}
|
||||
}
|
||||
taskItem.Log(i18n.GetMsgByKey("PruneStart"))
|
||||
DeletedNumber := 0
|
||||
SpaceReclaimed := 0
|
||||
switch req.PruneType {
|
||||
case "container":
|
||||
@@ -443,21 +446,18 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DeletedNumber = len(rep.ContainersDeleted)
|
||||
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
case "image":
|
||||
rep, err := client.ImagesPrune(context.Background(), pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DeletedNumber = len(rep.ImagesDeleted)
|
||||
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
case "network":
|
||||
rep, err := client.NetworksPrune(context.Background(), pruneFilters)
|
||||
_, err := client.NetworksPrune(context.Background(), pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DeletedNumber = len(rep.NetworksDeleted)
|
||||
case "volume":
|
||||
versions, err := client.ServerVersion(context.Background())
|
||||
if err != nil {
|
||||
@@ -470,7 +470,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DeletedNumber = len(rep.VolumesDeleted)
|
||||
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
case "buildcache":
|
||||
opts := build.CachePruneOptions{}
|
||||
@@ -479,10 +478,9 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DeletedNumber = len(rep.CachesDeleted)
|
||||
SpaceReclaimed = int(rep.SpaceReclaimed)
|
||||
}
|
||||
taskItem.Log(i18n.GetMsgWithMap("PruneHelper", map[string]interface{}{"name": i18n.GetMsgByKey(name), "count": DeletedNumber, "size": common.LoadSizeUnit2F(float64(SpaceReclaimed))}))
|
||||
taskItem.Log(i18n.GetMsgWithMap("PruneHelper", map[string]interface{}{"name": i18n.GetMsgByKey(name), "size": common.LoadSizeUnit2F(float64(SpaceReclaimed))}))
|
||||
return nil
|
||||
}, nil)
|
||||
go func() {
|
||||
@@ -958,6 +956,9 @@ func collectLogs(done <-chan struct{}, params dto.StreamLog, messageChan chan<-
|
||||
if params.Follow {
|
||||
cmdArgs = append(cmdArgs, "-f")
|
||||
}
|
||||
if params.Timestamp {
|
||||
cmdArgs = append(cmdArgs, "-t")
|
||||
}
|
||||
if params.Tail != "0" {
|
||||
cmdArgs = append(cmdArgs, "--tail", params.Tail)
|
||||
}
|
||||
@@ -1054,7 +1055,7 @@ func collectLogs(done <-chan struct{}, params dto.StreamLog, messageChan chan<-
|
||||
_ = dockerCmd.Wait()
|
||||
}
|
||||
|
||||
func (u *ContainerService) DownloadContainerLogs(containerType, container, since, tail string, c *gin.Context) error {
|
||||
func (u *ContainerService) DownloadContainerLogs(containerType, container, since, tail string, timestamp bool, c *gin.Context) error {
|
||||
if cmd.CheckIllegal(container, since, tail) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
@@ -1082,6 +1083,9 @@ func (u *ContainerService) DownloadContainerLogs(containerType, container, since
|
||||
commandArg = append(commandArg, "--since")
|
||||
commandArg = append(commandArg, since)
|
||||
}
|
||||
if timestamp {
|
||||
commandArg = append(commandArg, "-t")
|
||||
}
|
||||
var dockerCmd *exec.Cmd
|
||||
if containerType == "compose" && dockerCommand == "docker-compose" {
|
||||
dockerCmd = exec.Command("docker-compose", commandArg...)
|
||||
|
||||
@@ -205,7 +205,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
|
||||
}
|
||||
go func() {
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("ComposeCreate"), func(t *task.Task) error {
|
||||
err := compose.UpWithTask(req.Path, t)
|
||||
err := compose.UpWithTask(req.Path, t, req.ForcePull)
|
||||
t.LogWithStatus(i18n.GetMsgByKey("ComposeCreate"), err)
|
||||
if err != nil {
|
||||
_, _ = compose.Down(req.Path)
|
||||
@@ -258,31 +258,43 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
||||
if cmd.CheckIllegal(req.Name, req.Path) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
oldFile, err := os.ReadFile(req.DetailPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load file with path %s failed, %v", req.DetailPath, err)
|
||||
}
|
||||
file, err := os.OpenFile(req.DetailPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskUpdate, task.TaskScopeCompose, req.TaskID, 1)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("new task for update compose failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.Content)
|
||||
write.Flush()
|
||||
go func() {
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("TaskUpdate"), func(t *task.Task) error {
|
||||
oldFile, err := os.ReadFile(req.DetailPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load file with path %s failed, %v", req.DetailPath, err)
|
||||
}
|
||||
file, err := os.OpenFile(req.DetailPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.Content)
|
||||
write.Flush()
|
||||
|
||||
global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.DetailPath)
|
||||
if err := newComposeEnv(req.DetailPath, req.Env); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.DetailPath)
|
||||
if err := newComposeEnv(req.DetailPath, req.Env); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if stdout, err := compose.Up(req.Path); err != nil {
|
||||
global.LOG.Errorf("update failed when handle compose up, std: %s, err: %s, now try to recreate the old compose file", stdout, err)
|
||||
if err := recreateCompose(string(oldFile), req.Path); err != nil {
|
||||
return fmt.Errorf("update failed and recreate old compose file also failed, err: %v", err)
|
||||
}
|
||||
return fmt.Errorf("update failed when handle compose up, std: %v, err: %s", stdout, err)
|
||||
}
|
||||
if err := compose.UpWithTask(req.Path, t, req.ForcePull); err != nil {
|
||||
global.LOG.Errorf("update failed when handle compose up, err: %s, now try to recreate the old compose file", err)
|
||||
if err := recreateCompose(string(oldFile), req.Path); err != nil {
|
||||
return fmt.Errorf("update failed and recreate old compose file also failed, err: %v", err)
|
||||
}
|
||||
return fmt.Errorf("update failed when handle compose up, err: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, nil)
|
||||
_ = taskItem.Execute()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -338,6 +350,15 @@ func (u *ContainerService) ComposeLogClean(req dto.ComposeLogClean) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ContainerService) LoadComposeEnv(name string) (string, error) {
|
||||
envFilePath := path.Join(path.Dir(name), ".env")
|
||||
file, err := os.ReadFile(envFilePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(file), nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
|
||||
if req.From == "template" || req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/compose/%s", global.Dir.DataDir, req.Name)
|
||||
|
||||
@@ -143,6 +143,7 @@ func (u *CronjobService) Export(req dto.OperateByIDs) (string, error) {
|
||||
Timeout: cronjob.Timeout,
|
||||
IgnoreErr: cronjob.IgnoreErr,
|
||||
Secret: cronjob.Secret,
|
||||
Args: cronjob.Args,
|
||||
}
|
||||
switch cronjob.Type {
|
||||
case "app":
|
||||
@@ -237,6 +238,7 @@ func (u *CronjobService) Import(req []dto.CronjobTrans) error {
|
||||
Timeout: item.Timeout,
|
||||
IgnoreErr: item.IgnoreErr,
|
||||
Secret: item.Secret,
|
||||
Args: item.Args,
|
||||
}
|
||||
hasNotFound := false
|
||||
switch item.Type {
|
||||
@@ -733,6 +735,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
|
||||
upMap["timeout"] = req.Timeout
|
||||
upMap["ignore_err"] = req.IgnoreErr
|
||||
upMap["secret"] = req.Secret
|
||||
upMap["args"] = req.Args
|
||||
err = cronjobRepo.Update(id, upMap)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -762,7 +765,7 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
|
||||
)
|
||||
|
||||
if status == constant.StatusEnable {
|
||||
entryIDs, err = u.StartJob(&cronjob, false)
|
||||
entryIDs, err = u.StartJob(&cronjob, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -379,6 +379,7 @@ type DatabaseHelper struct {
|
||||
DBType string
|
||||
Database string
|
||||
Name string
|
||||
Args []string
|
||||
}
|
||||
|
||||
func addSkipTask(source string, taskItem *task.Task) {
|
||||
@@ -400,6 +401,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysql.Database,
|
||||
Name: mysql.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@@ -410,6 +412,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: pg.PostgresqlName,
|
||||
Name: pg.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -425,6 +428,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: mysqlItem.MysqlName,
|
||||
Name: mysqlItem.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
} else {
|
||||
pgItem, _ := postgresqlRepo.Get(repo.WithByID(uint(itemID)))
|
||||
@@ -433,6 +437,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
|
||||
DBType: cronjob.DBType,
|
||||
Database: pgItem.PostgresqlName,
|
||||
Name: pgItem.Name,
|
||||
Args: strings.Split(cronjob.Args, ","),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap m
|
||||
var opts []repo.DBOption
|
||||
opts = append(opts, repo.WithByFrom("cronjob"))
|
||||
opts = append(opts, backupRepo.WithByCronID(cronjob.ID))
|
||||
opts = append(opts, repo.WithOrderBy("created_at desc"))
|
||||
opts = append(opts, repo.WithOrderDesc("created_at"))
|
||||
if record.ID != 0 {
|
||||
opts = append(opts, repo.WithByType(record.Type))
|
||||
opts = append(opts, repo.WithByName(record.Name))
|
||||
@@ -461,7 +461,7 @@ func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap m
|
||||
}
|
||||
|
||||
func (u *CronjobService) removeExpiredLog(cronjob model.Cronjob) {
|
||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), repo.WithOrderBy("created_at desc"))
|
||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), repo.WithOrderDesc("created_at"))
|
||||
if len(records) <= int(cronjob.RetainCopies) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ func (u *DashboardService) LoadCurrentInfoForNode() *dto.NodeCurrent {
|
||||
|
||||
func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error) {
|
||||
var baseInfo dto.DashboardBase
|
||||
hostInfo, err := psutil.HOST.GetHostInfo(false)
|
||||
hostInfo, err := psutil.HOST.GetHostInfo(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+527
-124
@@ -11,36 +11,27 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/controller"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
fileUtils "github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
upgradePath = "1panel/tmp/upgrade"
|
||||
snapshotTmpPath = "1panel/tmp/system"
|
||||
rollbackPath = "1panel/tmp"
|
||||
cachePath = "1panel/cache"
|
||||
oldOriginalPath = "original"
|
||||
oldAppBackupPath = "1panel/resource/apps_bak"
|
||||
oldDownloadPath = "1panel/tmp/download"
|
||||
oldUpgradePath = "1panel/tmp"
|
||||
tmpUploadPath = "1panel/tmp/upload"
|
||||
uploadPath = "1panel/uploads"
|
||||
downloadPath = "1panel/download"
|
||||
rollbackPath = "1panel/tmp"
|
||||
upgradePath = "1panel/tmp/upgrade"
|
||||
uploadPath = "1panel/uploads"
|
||||
downloadPath = "1panel/download"
|
||||
)
|
||||
|
||||
func (u *DeviceService) Scan() dto.CleanData {
|
||||
@@ -61,54 +52,10 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
Type: "1panel_original",
|
||||
Children: loadTreeWithDir(true, "1panel_original", originalPath, fileOp),
|
||||
})
|
||||
treeData = append(treeData, loadUpgradeTree(fileOp))
|
||||
treeData = append(treeData, loadAgentPackage(fileOp))
|
||||
|
||||
upgradePath := path.Join(global.Dir.BaseDir, upgradePath)
|
||||
upgradeSize, _ := fileOp.GetDirSize(upgradePath)
|
||||
upgradeTree := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "upgrade",
|
||||
Size: uint64(upgradeSize),
|
||||
IsCheck: false,
|
||||
IsRecommend: true,
|
||||
Type: "upgrade",
|
||||
Children: loadTreeWithDir(true, "upgrade", upgradePath, fileOp),
|
||||
}
|
||||
if len(upgradeTree.Children) != 0 {
|
||||
sort.Slice(upgradeTree.Children, func(i, j int) bool {
|
||||
return common.CompareVersion(upgradeTree.Children[i].Label, upgradeTree.Children[j].Label)
|
||||
})
|
||||
if global.IsMaster {
|
||||
var copiesSetting model.Setting
|
||||
_ = global.CoreDB.Where("key = ?", "UpgradeBackupCopies").First(&copiesSetting).Error
|
||||
copies, _ := strconv.Atoi(copiesSetting.Value)
|
||||
if copies == 0 || copies > len(upgradeTree.Children) {
|
||||
copies = len(upgradeTree.Children)
|
||||
}
|
||||
for i := 0; i < copies; i++ {
|
||||
upgradeTree.Children[i].IsCheck = false
|
||||
upgradeTree.Children[i].IsRecommend = false
|
||||
}
|
||||
} else {
|
||||
upgradeTree.Children[0].IsCheck = false
|
||||
upgradeTree.Children[0].IsRecommend = false
|
||||
}
|
||||
}
|
||||
treeData = append(treeData, upgradeTree)
|
||||
|
||||
tmpBackupTree := loadTmpBackupTree(fileOp)
|
||||
tmpBackupSize := uint64(0)
|
||||
for _, tmp := range tmpBackupTree {
|
||||
tmpBackupSize += tmp.Size
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "backup",
|
||||
Size: tmpBackupSize,
|
||||
IsCheck: tmpBackupSize > 0,
|
||||
IsRecommend: true,
|
||||
Type: "backup",
|
||||
Children: tmpBackupTree,
|
||||
})
|
||||
SystemClean.BackupClean = loadBackupTree(fileOp)
|
||||
|
||||
rollBackTree := loadRollBackTree(fileOp)
|
||||
rollbackSize := uint64(0)
|
||||
@@ -124,17 +71,6 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
Type: "rollback",
|
||||
Children: rollBackTree,
|
||||
})
|
||||
|
||||
cachePath := path.Join(global.Dir.BaseDir, cachePath)
|
||||
cacheSize, _ := fileOp.GetDirSize(cachePath)
|
||||
treeData = append(treeData, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "cache",
|
||||
Size: uint64(cacheSize),
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "cache",
|
||||
})
|
||||
SystemClean.SystemClean = treeData
|
||||
|
||||
uploadTreeData := loadUploadTree(fileOp)
|
||||
@@ -154,7 +90,6 @@ func (u *DeviceService) Scan() dto.CleanData {
|
||||
|
||||
func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
size := uint64(0)
|
||||
restart := false
|
||||
for _, item := range req {
|
||||
size += item.Size
|
||||
switch item.TreeType {
|
||||
@@ -164,13 +99,17 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
case "upgrade":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, upgradePath, item.Name))
|
||||
|
||||
case "backup":
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/app"))
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/database"))
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/website"))
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/directory"))
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/log"))
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp/system"))
|
||||
case "agent":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, "1panel/agent/package", item.Name))
|
||||
|
||||
case "tmp_backup":
|
||||
dropFileOrDir(path.Join(global.Dir.LocalBackupDir, "tmp"))
|
||||
case "unknown_backup":
|
||||
if strings.HasPrefix(item.Name, path.Join(global.Dir.LocalBackupDir, "log/website")) {
|
||||
dropFileOrDir(item.Name)
|
||||
} else {
|
||||
dropFile(item.Name)
|
||||
}
|
||||
|
||||
case "rollback":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, rollbackPath, "app"))
|
||||
@@ -183,25 +122,14 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
case "rollback_website":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, rollbackPath, "website", item.Name))
|
||||
|
||||
case "cache":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, cachePath, item.Name))
|
||||
restart = true
|
||||
|
||||
case "upload":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, item.Name))
|
||||
if len(item.Name) == 0 {
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, tmpUploadPath))
|
||||
}
|
||||
case "upload_tmp":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, tmpUploadPath, item.Name))
|
||||
case "upload_app":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "app", item.Name))
|
||||
case "upload_database":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "database", item.Name))
|
||||
case "upload_website":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "website", item.Name))
|
||||
case "upload_directory":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, uploadPath, "directory", item.Name))
|
||||
case "download":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, item.Name))
|
||||
case "download_app":
|
||||
@@ -210,8 +138,6 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, "database", item.Name))
|
||||
case "download_website":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, "website", item.Name))
|
||||
case "download_directory":
|
||||
dropFileOrDir(path.Join(global.Dir.BaseDir, downloadPath, "directory", item.Name))
|
||||
|
||||
case "system_log":
|
||||
if len(item.Name) == 0 {
|
||||
@@ -243,6 +169,8 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
} else {
|
||||
dropTaskLog(path.Join(global.Dir.TaskDir, item.Name))
|
||||
}
|
||||
case "website_log":
|
||||
dropWebsiteLog(item.Name)
|
||||
case "script":
|
||||
dropFileOrDir(path.Join(global.Dir.TmpDir, "script", item.Name))
|
||||
case "images":
|
||||
@@ -253,16 +181,15 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||
_, _ = dropVolumes()
|
||||
case "build_cache":
|
||||
_, _ = dropBuildCache()
|
||||
case "app_tmp_download_version":
|
||||
dropFileOrDir(path.Join(global.Dir.RemoteAppResourceDir, item.Name))
|
||||
}
|
||||
}
|
||||
|
||||
_ = cleanEmptyDirs(global.Dir.LocalBackupDir)
|
||||
_ = settingRepo.Update("LastCleanTime", time.Now().Format(constant.DateTimeLayout))
|
||||
_ = settingRepo.Update("LastCleanSize", fmt.Sprintf("%v", size))
|
||||
_ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", len(req)))
|
||||
|
||||
if restart {
|
||||
go controller.RestartPanel(false, true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func doSystemClean(taskItem *task.Task) func(t *task.Task) error {
|
||||
@@ -284,25 +211,20 @@ func doSystemClean(taskItem *task.Task) func(t *task.Task) error {
|
||||
}
|
||||
}
|
||||
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, snapshotTmpPath), taskItem, &size, &fileCount)
|
||||
dropWithTask(path.Join(global.Dir.LocalBackupDir, "tmp/system"), taskItem, &size, &fileCount)
|
||||
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, rollbackPath, "app"), taskItem, &size, &fileCount)
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, rollbackPath, "website"), taskItem, &size, &fileCount)
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, rollbackPath, "database"), taskItem, &size, &fileCount)
|
||||
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, oldOriginalPath), taskItem, &size, &fileCount)
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, oldAppBackupPath), taskItem, &size, &fileCount)
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, oldDownloadPath), taskItem, &size, &fileCount)
|
||||
oldUpgradePath := path.Join(global.Dir.BaseDir, oldUpgradePath)
|
||||
oldUpgradeFiles, _ := os.ReadDir(oldUpgradePath)
|
||||
upgrades := path.Join(global.Dir.BaseDir, upgradePath)
|
||||
oldUpgradeFiles, _ := os.ReadDir(upgrades)
|
||||
if len(oldUpgradeFiles) != 0 {
|
||||
for i := 0; i < len(oldUpgradeFiles); i++ {
|
||||
dropWithTask(path.Join(oldUpgradePath, oldUpgradeFiles[i].Name()), taskItem, &size, &fileCount)
|
||||
dropWithTask(path.Join(upgrades, oldUpgradeFiles[i].Name()), taskItem, &size, &fileCount)
|
||||
}
|
||||
}
|
||||
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, tmpUploadPath), taskItem, &size, &fileCount)
|
||||
dropWithExclude(path.Join(global.Dir.BaseDir, uploadPath), []string{"theme"}, taskItem, &size, &fileCount)
|
||||
dropWithTask(path.Join(global.Dir.BaseDir, downloadPath), taskItem, &size, &fileCount)
|
||||
|
||||
@@ -338,17 +260,340 @@ func doSystemClean(taskItem *task.Task) func(t *task.Task) error {
|
||||
}
|
||||
}
|
||||
|
||||
func loadTmpBackupTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
func loadUpgradeTree(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
upgradePath := path.Join(global.Dir.BaseDir, upgradePath)
|
||||
upgradeSize, _ := fileOp.GetDirSize(upgradePath)
|
||||
upgradeTree := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "upgrade",
|
||||
Size: uint64(upgradeSize),
|
||||
IsCheck: false,
|
||||
IsRecommend: true,
|
||||
Type: "upgrade",
|
||||
Children: loadTreeWithDir(true, "upgrade", upgradePath, fileOp),
|
||||
}
|
||||
if len(upgradeTree.Children) != 0 {
|
||||
sort.Slice(upgradeTree.Children, func(i, j int) bool {
|
||||
return common.CompareVersion(upgradeTree.Children[i].Label, upgradeTree.Children[j].Label)
|
||||
})
|
||||
if global.IsMaster {
|
||||
var copiesSetting model.Setting
|
||||
_ = global.CoreDB.Where("key = ?", "UpgradeBackupCopies").First(&copiesSetting).Error
|
||||
copies, _ := strconv.Atoi(copiesSetting.Value)
|
||||
if copies == 0 || copies > len(upgradeTree.Children) {
|
||||
copies = len(upgradeTree.Children)
|
||||
}
|
||||
for i := 0; i < copies; i++ {
|
||||
upgradeTree.Children[i].IsCheck = false
|
||||
upgradeTree.Children[i].IsRecommend = false
|
||||
}
|
||||
} else {
|
||||
upgradeTree.Children[0].IsCheck = false
|
||||
upgradeTree.Children[0].IsRecommend = false
|
||||
}
|
||||
}
|
||||
return upgradeTree
|
||||
}
|
||||
|
||||
func loadAgentPackage(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
pathItem := path.Join(global.Dir.BaseDir, "1panel/agent/package")
|
||||
itemTree := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "agent_packages",
|
||||
IsCheck: false,
|
||||
IsRecommend: true,
|
||||
Type: "agent",
|
||||
}
|
||||
files, _ := os.ReadDir(pathItem)
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
itemSize, _ := fileOp.GetDirSize(path.Join(pathItem, file.Name()))
|
||||
itemTree.Size += uint64(itemSize)
|
||||
itemTree.Children = append(itemTree.Children, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: file.Name(),
|
||||
Name: file.Name(),
|
||||
Size: uint64(itemSize),
|
||||
IsCheck: true,
|
||||
IsRecommend: true,
|
||||
Type: "agent",
|
||||
})
|
||||
} else {
|
||||
itemSize, _ := file.Info()
|
||||
itemName := file.Name()
|
||||
isCurrentVersion := strings.HasPrefix(itemName, fmt.Sprintf("1panel-agent_%s_", global.CONF.Base.Version))
|
||||
if isCurrentVersion {
|
||||
continue
|
||||
}
|
||||
itemTree.Size += uint64(itemSize.Size())
|
||||
itemTree.Children = append(itemTree.Children, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: itemName,
|
||||
Name: itemName,
|
||||
Size: uint64(itemSize.Size()),
|
||||
IsCheck: !isCurrentVersion,
|
||||
IsRecommend: true,
|
||||
Type: "agent",
|
||||
})
|
||||
}
|
||||
}
|
||||
if itemTree.Size == 0 {
|
||||
itemTree.IsCheck = false
|
||||
}
|
||||
return itemTree
|
||||
}
|
||||
|
||||
func loadBackupTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
var treeData []dto.CleanTree
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/app"), "tmp_backup_app", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/website"), "tmp_backup_website", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/database"), "tmp_backup_database", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/system"), "tmp_backup_snapshot", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/directory"), "tmp_backup_directory", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.LocalBackupDir, "tmp/log"), "tmp_backup_log", fileOp)
|
||||
|
||||
tmpSize, _ := fileOp.GetDirSize(path.Join(global.Dir.LocalBackupDir, "tmp"))
|
||||
treeData = append(treeData, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "tmp_backup",
|
||||
Size: uint64(tmpSize),
|
||||
IsCheck: tmpSize != 0,
|
||||
IsRecommend: true,
|
||||
Type: "tmp_backup",
|
||||
})
|
||||
backupRecords, _ := backupRepo.ListRecord()
|
||||
var recordMap = make(map[string][]string)
|
||||
for _, record := range backupRecords {
|
||||
if val, ok := recordMap[record.FileDir]; ok {
|
||||
val = append(val, record.FileName)
|
||||
recordMap[record.FileDir] = val
|
||||
} else {
|
||||
recordMap[record.FileDir] = []string{record.FileName}
|
||||
}
|
||||
}
|
||||
|
||||
treeData = append(treeData, loadUnknownApps(fileOp, recordMap))
|
||||
treeData = append(treeData, loadUnknownDbs(fileOp, recordMap))
|
||||
treeData = append(treeData, loadUnknownWebsites(fileOp, recordMap))
|
||||
treeData = append(treeData, loadUnknownSnapshot(fileOp))
|
||||
treeData = append(treeData, loadUnknownWebsiteLog(fileOp))
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadUnknownApps(fileOp fileUtils.FileOp, recordMap map[string][]string) dto.CleanTree {
|
||||
apps, _ := appInstallRepo.ListBy(context.Background())
|
||||
var excludePaths []string
|
||||
for _, app := range apps {
|
||||
itemName := fmt.Sprintf("app/%s/%s", app.App.Key, app.Name)
|
||||
if val, ok := recordMap[itemName]; ok {
|
||||
for _, item := range val {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, itemName, item))
|
||||
}
|
||||
}
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "app")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_app",
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Name: backupPath,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, backupPath, &treeData, excludePaths)
|
||||
return treeData
|
||||
}
|
||||
func loadUnknownDbs(fileOp fileUtils.FileOp, recordMap map[string][]string) dto.CleanTree {
|
||||
dbs, _ := databaseRepo.GetList()
|
||||
var excludePaths []string
|
||||
dbMap := make(map[string]struct{})
|
||||
for _, db := range dbs {
|
||||
dbMap[fmt.Sprintf("database/%s/%s", db.Type, db.Name)] = struct{}{}
|
||||
}
|
||||
for key, val := range recordMap {
|
||||
itemName := path.Dir(key)
|
||||
if _, ok := dbMap[itemName]; ok {
|
||||
for _, item := range val {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, key, item))
|
||||
}
|
||||
}
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "database")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_database",
|
||||
Name: backupPath,
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, backupPath, &treeData, excludePaths)
|
||||
return treeData
|
||||
}
|
||||
func loadUnknownWebsites(fileOp fileUtils.FileOp, recordMap map[string][]string) dto.CleanTree {
|
||||
websites, _ := websiteRepo.List()
|
||||
var excludePaths []string
|
||||
for _, website := range websites {
|
||||
itemName := fmt.Sprintf("website/%s", website.Alias)
|
||||
if val, ok := recordMap[itemName]; ok {
|
||||
for _, item := range val {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, itemName, item))
|
||||
}
|
||||
}
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "website")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_website",
|
||||
Name: backupPath,
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
_ = loadFileOrDirWithExclude(fileOp, 0, backupPath, &treeData, excludePaths)
|
||||
return treeData
|
||||
}
|
||||
func loadUnknownSnapshot(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
snaps, _ := snapshotRepo.GetList()
|
||||
var excludePaths []string
|
||||
for _, item := range snaps {
|
||||
excludePaths = append(excludePaths, path.Join(global.Dir.LocalBackupDir, "system_snapshot", item.Name+".tar.gz"))
|
||||
}
|
||||
backupPath := path.Join(global.Dir.LocalBackupDir, "system_snapshot")
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_snapshot",
|
||||
Name: backupPath,
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
entries, _ := os.ReadDir(backupPath)
|
||||
for _, entry := range entries {
|
||||
childPath := filepath.Join(backupPath, entry.Name())
|
||||
if isExactPathMatch(childPath, excludePaths) {
|
||||
continue
|
||||
}
|
||||
childNode := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: entry.Name(),
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Name: childPath,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
if entry.IsDir() {
|
||||
itemSize, _ := fileOp.GetDirSize(childPath)
|
||||
childNode.Size = uint64(itemSize)
|
||||
childNode.IsCheck = true
|
||||
childNode.IsRecommend = true
|
||||
treeData.Size += childNode.Size
|
||||
} else {
|
||||
info, _ := entry.Info()
|
||||
childNode.Size = uint64(info.Size())
|
||||
treeData.Size += childNode.Size
|
||||
}
|
||||
|
||||
treeData.Children = append(treeData.Children, childNode)
|
||||
}
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadUnknownWebsiteLog(fileOp fileUtils.FileOp) dto.CleanTree {
|
||||
treeData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "unknown_website_log",
|
||||
IsCheck: false,
|
||||
IsRecommend: true,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
dir := path.Join(global.Dir.LocalBackupDir, "log/website")
|
||||
websites, _ := websiteRepo.List()
|
||||
websiteMap := make(map[string]struct{})
|
||||
for _, website := range websites {
|
||||
websiteMap[website.Alias] = struct{}{}
|
||||
}
|
||||
|
||||
entries, _ := os.ReadDir(dir)
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
dirName := entry.Name()
|
||||
if _, ok := websiteMap[dirName]; !ok {
|
||||
dirPath := path.Join(dir, dirName)
|
||||
itemSize, _ := fileOp.GetDirSize(dirPath)
|
||||
childData := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: dirName,
|
||||
IsCheck: true,
|
||||
IsRecommend: true,
|
||||
Name: dirPath,
|
||||
Type: "unknown_backup",
|
||||
Size: uint64(itemSize),
|
||||
}
|
||||
treeData.Size += uint64(itemSize)
|
||||
treeData.Children = append(treeData.Children, childData)
|
||||
}
|
||||
}
|
||||
if treeData.Size > 0 {
|
||||
treeData.IsCheck = true
|
||||
}
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadFileOrDirWithExclude(fileOp fileUtils.FileOp, index uint, dir string, rootTree *dto.CleanTree, excludes []string) error {
|
||||
index++
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
childPath := filepath.Join(dir, entry.Name())
|
||||
if isExactPathMatch(childPath, excludes) {
|
||||
continue
|
||||
}
|
||||
childNode := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: entry.Name(),
|
||||
IsCheck: false,
|
||||
IsRecommend: false,
|
||||
Name: childPath,
|
||||
Type: "unknown_backup",
|
||||
}
|
||||
if entry.IsDir() {
|
||||
if index < 4 {
|
||||
if err = loadFileOrDirWithExclude(fileOp, index, childPath, &childNode, excludes); err != nil {
|
||||
return err
|
||||
}
|
||||
childNode.Size = 0
|
||||
for _, child := range childNode.Children {
|
||||
childNode.Size += child.Size
|
||||
}
|
||||
rootTree.Size += childNode.Size
|
||||
} else {
|
||||
itemSize, _ := fileOp.GetDirSize(childPath)
|
||||
childNode.Size = uint64(itemSize)
|
||||
rootTree.Size += childNode.Size
|
||||
}
|
||||
} else {
|
||||
info, _ := entry.Info()
|
||||
childNode.Size = uint64(info.Size())
|
||||
rootTree.Size += childNode.Size
|
||||
}
|
||||
|
||||
rootTree.Children = append(rootTree.Children, childNode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isExactPathMatch(path string, excludePaths []string) bool {
|
||||
cleanPath := filepath.Clean(path)
|
||||
|
||||
for _, excludePath := range excludePaths {
|
||||
cleanExclude := filepath.Clean(excludePath)
|
||||
if cleanPath == cleanExclude {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func loadRollBackTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
var treeData []dto.CleanTree
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, rollbackPath, "app"), "rollback_app", fileOp)
|
||||
@@ -360,7 +605,6 @@ func loadRollBackTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
|
||||
func loadUploadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
var treeData []dto.CleanTree
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, tmpUploadPath), "upload_tmp", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, uploadPath, "app"), "upload_app", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, uploadPath, "website"), "upload_website", fileOp)
|
||||
treeData = loadTreeWithCheck(treeData, path.Join(global.Dir.BaseDir, uploadPath, "database"), "upload_database", fileOp)
|
||||
@@ -382,6 +626,22 @@ func loadDownloadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
uploadTreeData := loadTreeWithAllFile(true, path5, "download", path5, fileOp)
|
||||
treeData = append(treeData, uploadTreeData...)
|
||||
|
||||
appTmpDownloadTree := loadAppTmpDownloadTree(fileOp)
|
||||
if len(appTmpDownloadTree) > 0 {
|
||||
parentTree := dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: "app_tmp_download",
|
||||
IsCheck: true,
|
||||
IsRecommend: true,
|
||||
Type: "app_tmp_download",
|
||||
Name: "apps",
|
||||
}
|
||||
for _, child := range appTmpDownloadTree {
|
||||
parentTree.Size += child.Size
|
||||
}
|
||||
parentTree.Children = appTmpDownloadTree
|
||||
treeData = append(treeData, parentTree)
|
||||
}
|
||||
return treeData
|
||||
}
|
||||
|
||||
@@ -393,20 +653,106 @@ func loadLogTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
for _, file := range list1 {
|
||||
size += file.Size
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "system_log", Size: uint64(size), Children: list1, Type: "system_log", IsRecommend: true})
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "system_log", Size: size, Children: list1, Type: "system_log", IsRecommend: true})
|
||||
|
||||
path2 := path.Join(global.Dir.TaskDir)
|
||||
list2 := loadTreeWithDir(false, "task_log", path2, fileOp)
|
||||
size2, _ := fileOp.GetDirSize(path2)
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "task_log", Size: uint64(size2), Children: list2, Type: "task_log"})
|
||||
|
||||
path3 := path.Join(global.Dir.TmpDir, "script")
|
||||
list3 := loadTreeWithAllFile(true, path3, "script", path3, fileOp)
|
||||
size3, _ := fileOp.GetDirSize(path3)
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "script", Size: uint64(size3), Children: list3, Type: "script", IsRecommend: true})
|
||||
websiteLogList := loadWebsiteLogTree(fileOp)
|
||||
logTotalSize := uint64(0)
|
||||
for _, websiteLog := range websiteLogList {
|
||||
logTotalSize += websiteLog.Size
|
||||
}
|
||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "website_log", Size: logTotalSize, Children: websiteLogList, Type: "website_log", IsRecommend: false})
|
||||
|
||||
return treeData
|
||||
}
|
||||
|
||||
func loadWebsiteLogTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
websites, _ := websiteRepo.List()
|
||||
if len(websites) == 0 {
|
||||
return nil
|
||||
}
|
||||
var res []dto.CleanTree
|
||||
for _, website := range websites {
|
||||
size3, _ := fileOp.GetDirSize(path.Join(GetSiteDir(website.Alias), "log"))
|
||||
res = append(res, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: website.PrimaryDomain,
|
||||
Size: uint64(size3),
|
||||
Type: "website_log",
|
||||
Name: website.Alias,
|
||||
})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func loadAppTmpDownloadTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||
appDirs, err := os.ReadDir(global.Dir.RemoteAppResourceDir)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var res []dto.CleanTree
|
||||
for _, appDir := range appDirs {
|
||||
if !appDir.IsDir() {
|
||||
continue
|
||||
}
|
||||
appKey := appDir.Name()
|
||||
app, _ := appRepo.GetFirst(appRepo.WithKey(appKey))
|
||||
if app.ID == 0 {
|
||||
continue
|
||||
}
|
||||
appPath := filepath.Join(global.Dir.RemoteAppResourceDir, appKey)
|
||||
versionDirs, err := os.ReadDir(appPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
appDetails, _ := appDetailRepo.GetBy(appDetailRepo.WithAppId(app.ID))
|
||||
existingVersions := make(map[string]bool)
|
||||
for _, appDetail := range appDetails {
|
||||
existingVersions[appDetail.Version] = true
|
||||
}
|
||||
var missingVersions []string
|
||||
for _, versionDir := range versionDirs {
|
||||
if !versionDir.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
version := versionDir.Name()
|
||||
if !existingVersions[version] {
|
||||
missingVersions = append(missingVersions, version)
|
||||
}
|
||||
}
|
||||
if len(missingVersions) > 0 {
|
||||
var appTree dto.CleanTree
|
||||
appTree.ID = uuid.NewString()
|
||||
appTree.Label = app.Name
|
||||
appTree.Type = "app_tmp_download"
|
||||
appTree.Name = appKey
|
||||
appTree.IsRecommend = true
|
||||
appTree.IsCheck = true
|
||||
for _, version := range missingVersions {
|
||||
versionPath := filepath.Join(appPath, version)
|
||||
size, _ := fileOp.GetDirSize(versionPath)
|
||||
appTree.Size += uint64(size)
|
||||
appTree.Children = append(appTree.Children, dto.CleanTree{
|
||||
ID: uuid.NewString(),
|
||||
Label: version,
|
||||
Size: uint64(size),
|
||||
IsCheck: true,
|
||||
IsRecommend: true,
|
||||
Type: "app_tmp_download_version",
|
||||
Name: path.Join(appKey, version),
|
||||
})
|
||||
}
|
||||
res = append(res, appTree)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func loadContainerTree() []dto.CleanTree {
|
||||
var treeData []dto.CleanTree
|
||||
client, err := docker.NewDockerClient()
|
||||
@@ -528,7 +874,7 @@ func loadTreeWithAllFile(isCheck bool, originalPath, treeType, pathItem string,
|
||||
ID: uuid.NewString(),
|
||||
Label: file.Name(),
|
||||
Type: treeType,
|
||||
Size: uint64(size),
|
||||
Size: size,
|
||||
Name: name,
|
||||
IsCheck: isCheck,
|
||||
IsRecommend: isCheck,
|
||||
@@ -546,6 +892,18 @@ func dropFileOrDir(itemPath string) {
|
||||
global.LOG.Errorf("drop file %s failed, err %v", itemPath, err)
|
||||
}
|
||||
}
|
||||
func dropFile(itemPath string) {
|
||||
info, err := os.Stat(itemPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if info.IsDir() {
|
||||
return
|
||||
}
|
||||
if err := os.Remove(itemPath); err != nil {
|
||||
global.LOG.Errorf("drop file %s failed, err %v", itemPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropBuildCache() (int, int) {
|
||||
client, err := docker.NewDockerClient()
|
||||
@@ -621,6 +979,18 @@ func dropVolumes() (int, int) {
|
||||
return len(res.VolumesDeleted), int(res.SpaceReclaimed)
|
||||
}
|
||||
|
||||
func dropWebsiteLog(alias string) {
|
||||
accessLogPath := path.Join(GetSiteDir(alias), "log", "access.log")
|
||||
errorLogPath := path.Join(GetSiteDir(alias), "log", "error.log")
|
||||
if err := os.Truncate(accessLogPath, 0); err != nil {
|
||||
global.LOG.Errorf("truncate access log %s failed, err %v", accessLogPath, err)
|
||||
}
|
||||
|
||||
if err := os.Truncate(errorLogPath, 0); err != nil {
|
||||
global.LOG.Errorf("truncate error log %s failed, err %v", errorLogPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
func dropTaskLog(logDir string) {
|
||||
files, err := os.ReadDir(logDir)
|
||||
if err != nil {
|
||||
@@ -732,3 +1102,36 @@ func scanFile(pathItem string, size *int64, count *int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanEmptyDirs(root string) error {
|
||||
dirsToCheck := make([]string, 0)
|
||||
err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() {
|
||||
dirsToCheck = append(dirsToCheck, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := len(dirsToCheck) - 1; i >= 0; i-- {
|
||||
dir := dirsToCheck[i]
|
||||
if dir == root {
|
||||
continue
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
_ = os.Remove(dir)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ func (s *DiskService) GetCompleteDiskInfo() (*response.CompleteDiskInfo, error)
|
||||
}
|
||||
|
||||
func (s *DiskService) PartitionDisk(req request.DiskPartitionRequest) (string, error) {
|
||||
if cmd.CheckIllegal(req.Device, req.Filesystem, req.MountPoint, req.Label) {
|
||||
return "", buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
if !strings.HasPrefix("/dev", req.Device) {
|
||||
req.Device = "/dev/" + req.Device
|
||||
}
|
||||
@@ -104,6 +107,9 @@ func (s *DiskService) PartitionDisk(req request.DiskPartitionRequest) (string, e
|
||||
}
|
||||
|
||||
func (s *DiskService) MountDisk(req request.DiskMountRequest) error {
|
||||
if cmd.CheckIllegal(req.Device, req.MountPoint, req.Filesystem) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
if !deviceExists(req.Device) {
|
||||
return buserr.WithName("DeviceNotFound", req.Device)
|
||||
}
|
||||
@@ -131,7 +137,11 @@ func (s *DiskService) MountDisk(req request.DiskMountRequest) error {
|
||||
return buserr.WithErr("MountDiskErr", err)
|
||||
}
|
||||
if req.AutoMount {
|
||||
if err := addToFstabWithOptions(req.Device, req.MountPoint, req.Filesystem, ""); err != nil {
|
||||
options := ""
|
||||
if req.NoFail {
|
||||
options = "defaults,nofail"
|
||||
}
|
||||
if err := addToFstabWithOptions(req.Device, req.MountPoint, req.Filesystem, options); err != nil {
|
||||
return buserr.WithErr("MountDiskErr", err)
|
||||
}
|
||||
}
|
||||
@@ -140,6 +150,9 @@ func (s *DiskService) MountDisk(req request.DiskMountRequest) error {
|
||||
}
|
||||
|
||||
func (s *DiskService) UnmountDisk(req request.DiskUnmountRequest) error {
|
||||
if cmd.CheckIllegal(req.MountPoint) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
if !isPointMounted(req.MountPoint) {
|
||||
return buserr.New("MountDiskErr")
|
||||
}
|
||||
|
||||
@@ -463,6 +463,11 @@ func isPointMounted(mountPoint string) bool {
|
||||
}
|
||||
|
||||
func addToFstabWithOptions(device, mountPoint, filesystem, options string) error {
|
||||
uuid, err := getDeviceUUID(device)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get UUID for device %s: %v", device, err)
|
||||
}
|
||||
|
||||
if filesystem == "" {
|
||||
fsType, err := getFilesystemType(device)
|
||||
if err != nil {
|
||||
@@ -476,7 +481,7 @@ func addToFstabWithOptions(device, mountPoint, filesystem, options string) error
|
||||
options = "defaults"
|
||||
}
|
||||
|
||||
entry := fmt.Sprintf("%s %s %s %s 0 2\n", device, mountPoint, filesystem, options)
|
||||
entry := fmt.Sprintf("UUID=%s %s %s %s 0 2\n", uuid, mountPoint, filesystem, options)
|
||||
|
||||
file, err := os.OpenFile("/etc/fstab", os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
@@ -568,3 +573,15 @@ func parseSizeToBytes(sizeStr string) int64 {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
func getDeviceUUID(device string) (string, error) {
|
||||
output, err := cmd.RunDefaultWithStdoutBashC(fmt.Sprintf("blkid -s UUID -o value %s", device))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
uuid := strings.TrimSpace(output)
|
||||
if uuid == "" {
|
||||
return "", fmt.Errorf("no UUID found for device %s", device)
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ var (
|
||||
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
|
||||
appIgnoreUpgradeRepo = repo.NewIAppIgnoreUpgradeRepo()
|
||||
|
||||
aiRepo = repo.NewIAiRepo()
|
||||
mcpServerRepo = repo.NewIMcpServerRepo()
|
||||
tensorrtLLMRepo = repo.NewITensorRTLLMRepo()
|
||||
aiRepo = repo.NewIAiRepo()
|
||||
mcpServerRepo = repo.NewIMcpServerRepo()
|
||||
tensorrtLLMRepo = repo.NewITensorRTLLMRepo()
|
||||
agentRepo = repo.NewIAgentRepo()
|
||||
agentAccountRepo = repo.NewIAgentAccountRepo()
|
||||
|
||||
mysqlRepo = repo.NewIMysqlRepo()
|
||||
postgresqlRepo = repo.NewIPostgresqlRepo()
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -75,12 +76,19 @@ type IFileService interface {
|
||||
GetUsersAndGroups() (*response.UserGroupResponse, error)
|
||||
Convert(req request.FileConvertRequest)
|
||||
ConvertLog(req dto.PageInfo) (int64, []response.FileConvertLog, error)
|
||||
BatchGetRemarks(req request.FileRemarkBatch) map[string]string
|
||||
SetRemark(req request.FileRemarkUpdate) error
|
||||
}
|
||||
|
||||
var filteredPaths = []string{
|
||||
"/.1panel_clash",
|
||||
}
|
||||
|
||||
const (
|
||||
fileRemarkXattr = "user.1panel.remark"
|
||||
fileRemarkEncodedMaxLen = 256
|
||||
)
|
||||
|
||||
func NewIFileService() IFileService {
|
||||
return &FileService{}
|
||||
}
|
||||
@@ -307,19 +315,18 @@ func (f *FileService) ChangeMode(op request.FileCreate) error {
|
||||
|
||||
func (f *FileService) BatchChangeModeAndOwner(op request.FileRoleReq) error {
|
||||
fo := files.NewFileOp()
|
||||
for _, path := range op.Paths {
|
||||
if !fo.Stat(path) {
|
||||
for _, p := range op.Paths {
|
||||
if !fo.Stat(p) {
|
||||
return buserr.New("ErrPathNotFound")
|
||||
}
|
||||
if err := fo.ChownR(path, op.User, op.Group, op.Sub); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fo.ChmodR(path, op.Mode, op.Sub); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := fo.ChownRPaths(op.Paths, op.User, op.Group, op.Sub); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fo.ChmodRPaths(op.Paths, op.Mode, op.Sub); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (f *FileService) ChangeOwner(req request.FileRoleUpdate) error {
|
||||
@@ -658,6 +665,9 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||
configPath = pathSet.Value
|
||||
}
|
||||
logFilePath, _ = ini_conf.GetIniValue(configPath, "supervisord", "logfile")
|
||||
case constant.Supervisor:
|
||||
logDir := path.Join(global.Dir.DataDir, "tools", "supervisord", "log")
|
||||
logFilePath = path.Join(logDir, req.Name)
|
||||
}
|
||||
|
||||
file, err := os.Open(logFilePath)
|
||||
@@ -757,6 +767,52 @@ func (f *FileService) GetUsersAndGroups() (*response.UserGroupResponse, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *FileService) BatchGetRemarks(req request.FileRemarkBatch) map[string]string {
|
||||
remarks := make(map[string]string)
|
||||
for _, filePath := range req.Paths {
|
||||
remark, err := getFileRemark(filePath)
|
||||
if err != nil {
|
||||
if isXattrNotSupported(err) {
|
||||
return map[string]string{}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if remark == "" {
|
||||
continue
|
||||
}
|
||||
remarks[filePath] = remark
|
||||
}
|
||||
|
||||
return remarks
|
||||
}
|
||||
|
||||
func (f *FileService) SetRemark(req request.FileRemarkUpdate) error {
|
||||
if req.Remark == "" {
|
||||
if err := unix.Lremovexattr(req.Path, fileRemarkXattr); err != nil {
|
||||
if isXattrNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
if isXattrNotSupported(err) {
|
||||
return buserr.WithDetail("ErrInvalidParams", "xattr not supported", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(req.Remark))
|
||||
if len(encoded) >= fileRemarkEncodedMaxLen {
|
||||
return buserr.WithDetail("ErrInvalidParams", "remark length must be less than 256", nil)
|
||||
}
|
||||
if err := unix.Lsetxattr(req.Path, fileRemarkXattr, []byte(encoded), 0); err != nil {
|
||||
if isXattrNotSupported(err) {
|
||||
return buserr.WithDetail("ErrInvalidParams", "xattr not supported", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getValidGroups() (map[string]bool, error) {
|
||||
groupFile, err := os.Open("/etc/group")
|
||||
if err != nil {
|
||||
@@ -783,6 +839,37 @@ func getValidGroups() (map[string]bool, error) {
|
||||
return groupMap, nil
|
||||
}
|
||||
|
||||
func getFileRemark(filePath string) (string, error) {
|
||||
size, err := unix.Lgetxattr(filePath, fileRemarkXattr, nil)
|
||||
if err != nil {
|
||||
if isXattrNotFound(err) {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
if size == 0 {
|
||||
return "", nil
|
||||
}
|
||||
buf := make([]byte, size)
|
||||
n, err := unix.Lgetxattr(filePath, fileRemarkXattr, buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
decoded, err := base64.StdEncoding.DecodeString(string(buf[:n]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(decoded), nil
|
||||
}
|
||||
|
||||
func isXattrNotSupported(err error) bool {
|
||||
return errors.Is(err, unix.ENOTSUP) || errors.Is(err, unix.EOPNOTSUPP)
|
||||
}
|
||||
|
||||
func isXattrNotFound(err error) bool {
|
||||
return errors.Is(err, unix.ENODATA)
|
||||
}
|
||||
|
||||
func getValidUsers(validGroups map[string]bool) ([]response.UserInfo, map[string]struct{}, error) {
|
||||
passwdFile, err := os.Open("/etc/passwd")
|
||||
if err != nil {
|
||||
|
||||
+17
-134
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -14,7 +13,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/controller"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
@@ -23,9 +21,6 @@ import (
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
const confPath = "/etc/sysctl.conf"
|
||||
const panelSysctlPath = "/etc/sysctl.d/98-onepanel.conf"
|
||||
|
||||
type FirewallService struct{}
|
||||
|
||||
type IFirewallService interface {
|
||||
@@ -62,7 +57,7 @@ func (u *FirewallService) LoadBaseInfo(tab string) (dto.FirewallBaseInfo, error)
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
baseInfo.PingStatus = u.pingStatus()
|
||||
baseInfo.PingStatus = firewall.LoadPingStatus()
|
||||
baseInfo.Version, _ = client.Version()
|
||||
}()
|
||||
go func() {
|
||||
@@ -117,29 +112,15 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}
|
||||
}
|
||||
}
|
||||
|
||||
var datasFilterStatus []fireClient.FireInfo
|
||||
if len(req.Status) != 0 {
|
||||
for _, data := range datas {
|
||||
if req.Status == "free" && len(data.UsedStatus) == 0 {
|
||||
datasFilterStatus = append(datasFilterStatus, data)
|
||||
}
|
||||
if req.Status == "used" && len(data.UsedStatus) != 0 {
|
||||
datasFilterStatus = append(datasFilterStatus, data)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
datasFilterStatus = datas
|
||||
}
|
||||
|
||||
var datasFilterStrategy []fireClient.FireInfo
|
||||
if len(req.Strategy) != 0 {
|
||||
for _, data := range datasFilterStatus {
|
||||
for _, data := range datas {
|
||||
if req.Strategy == data.Strategy {
|
||||
datasFilterStrategy = append(datasFilterStrategy, data)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
datasFilterStrategy = datasFilterStatus
|
||||
datasFilterStrategy = datas
|
||||
}
|
||||
|
||||
total, start, end := len(datasFilterStrategy), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
@@ -206,10 +187,18 @@ func (u *FirewallService) OperateFirewall(req dto.FirewallOperation) error {
|
||||
return err
|
||||
}
|
||||
needRestartDocker = true
|
||||
case "disablePing":
|
||||
return u.updatePingStatus("0")
|
||||
case "enablePing":
|
||||
return u.updatePingStatus("1")
|
||||
case "disableBanPing":
|
||||
if err := firewall.UpdatePingStatus("0"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = settingRepo.Update("BanPing", constant.StatusDisable)
|
||||
return nil
|
||||
case "enableBanPing":
|
||||
if err := firewall.UpdatePingStatus("1"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = settingRepo.Update("BanPing", constant.StatusEnable)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("not supported operation: %s", req.Operation)
|
||||
}
|
||||
@@ -589,105 +578,6 @@ func (u *FirewallService) cleanUnUsedData(client firewall.FirewallClient) {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *FirewallService) pingStatus() string {
|
||||
data, err := os.ReadFile("/proc/sys/net/ipv4/icmp_echo_ignore_all")
|
||||
if err != nil {
|
||||
return constant.StatusNone
|
||||
}
|
||||
v6Data, v6err := os.ReadFile("/proc/sys/net/ipv6/icmp/echo_ignore_all")
|
||||
if v6err != nil {
|
||||
if strings.TrimSpace(string(data)) == "1" {
|
||||
return constant.StatusEnable
|
||||
}
|
||||
return constant.StatusDisable
|
||||
} else {
|
||||
if strings.TrimSpace(string(data)) == "1" && strings.TrimSpace(string(v6Data)) == "1" {
|
||||
return constant.StatusEnable
|
||||
}
|
||||
return constant.StatusDisable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (u *FirewallService) updatePingStatus(enable string) error {
|
||||
var targetPath string
|
||||
var applyCmd string
|
||||
|
||||
if _, err := os.Stat(confPath); os.IsNotExist(err) {
|
||||
// Debian 13
|
||||
targetPath = panelSysctlPath
|
||||
applyCmd = fmt.Sprintf("%s sysctl --system", cmd.SudoHandleCmd())
|
||||
if err := cmd.RunDefaultBashCf("%s mkdir -p /etc/sysctl.d", cmd.SudoHandleCmd()); err != nil {
|
||||
return fmt.Errorf("failed to create directory /etc/sysctl.d: %v", err)
|
||||
}
|
||||
} else {
|
||||
targetPath = confPath
|
||||
applyCmd = fmt.Sprintf("%s sysctl -p", cmd.SudoHandleCmd())
|
||||
}
|
||||
|
||||
lineBytes, err := os.ReadFile(targetPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("failed to read %s: %v", targetPath, err)
|
||||
}
|
||||
|
||||
if err := cmd.RunDefaultBashCf("echo %s | %s tee /proc/sys/net/ipv4/icmp_echo_ignore_all > /dev/null", enable, cmd.SudoHandleCmd()); err != nil {
|
||||
return fmt.Errorf("failed to apply ipv4 ping status temporarily: %v", err)
|
||||
}
|
||||
|
||||
var hasIpv6 bool
|
||||
if _, err := os.Stat("/proc/sys/net/ipv6/icmp/echo_ignore_all"); err == nil {
|
||||
hasIpv6 = true
|
||||
if err := cmd.RunDefaultBashCf("echo %s | %s tee /proc/sys/net/ipv6/icmp/echo_ignore_all > /dev/null", enable, cmd.SudoHandleCmd()); err != nil {
|
||||
global.LOG.Warnf("failed to apply ipv6 ping status temporarily: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var files []string
|
||||
if err == nil {
|
||||
files = strings.Split(string(lineBytes), "\n")
|
||||
}
|
||||
|
||||
var newFiles []string
|
||||
hasIPv4Line, hasIPv6Line := false, false
|
||||
|
||||
for _, line := range files {
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "net.ipv4.icmp_echo_ignore_all") {
|
||||
newFiles = append(newFiles, "net.ipv4.icmp_echo_ignore_all="+enable)
|
||||
hasIPv4Line = true
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "net.ipv6.icmp.echo_ignore_all") {
|
||||
newFiles = append(newFiles, "net.ipv6.icmp.echo_ignore_all="+enable)
|
||||
hasIPv6Line = true
|
||||
continue
|
||||
}
|
||||
newFiles = append(newFiles, line)
|
||||
}
|
||||
|
||||
if !hasIPv4Line {
|
||||
newFiles = append(newFiles, "net.ipv4.icmp_echo_ignore_all="+enable)
|
||||
}
|
||||
if hasIpv6 && !hasIPv6Line {
|
||||
newFiles = append(newFiles, "net.ipv6.icmp.echo_ignore_all="+enable)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(targetPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, constant.FilePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open %s: %v", targetPath, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err = file.WriteString(strings.Join(newFiles, "\n")); err != nil {
|
||||
return fmt.Errorf("failed to write to %s: %v", targetPath, err)
|
||||
}
|
||||
|
||||
if err := cmd.RunDefaultBashC(applyCmd); err != nil {
|
||||
global.LOG.Warnf("failed to apply persistent config with '%s': %v", applyCmd, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) error {
|
||||
if !global.IsMaster {
|
||||
if err := client.Port(fireClient.FireInfo{Port: global.CONF.Base.Port, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||
@@ -816,16 +706,9 @@ func checkPortUsed(ports, proto string, apps []portOfApp) string {
|
||||
|
||||
for _, app := range apps {
|
||||
if app.HttpPort == ports || app.HttpsPort == ports {
|
||||
return fmt.Sprintf("(%s)", app.AppName)
|
||||
return app.AppName
|
||||
}
|
||||
}
|
||||
port, err := strconv.Atoi(ports)
|
||||
if err != nil {
|
||||
global.LOG.Errorf(" convert string %v to int failed, err: %v", port, err)
|
||||
return ""
|
||||
}
|
||||
if common.ScanPortWithProto(port, proto) {
|
||||
return "inUsed"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func (u *FtpService) Operate(operation string) error {
|
||||
}
|
||||
|
||||
func (f *FtpService) SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error) {
|
||||
total, lists, err := ftpRepo.Page(req.Page, req.PageSize, ftpRepo.WithLikeUser(req.Info), repo.WithOrderBy("created_at desc"))
|
||||
total, lists, err := ftpRepo.Page(req.Page, req.PageSize, ftpRepo.WithLikeUser(req.Info), repo.WithOrderDesc("created_at"))
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ func NewIGroupService() IGroupService {
|
||||
|
||||
func (u *GroupService) List(req dto.OperateByType) ([]dto.GroupInfo, error) {
|
||||
options := []repo.DBOption{
|
||||
repo.WithOrderBy("is_default desc"),
|
||||
repo.WithOrderBy("created_at desc"),
|
||||
repo.WithOrderDesc("is_default"),
|
||||
repo.WithOrderDesc("created_at"),
|
||||
}
|
||||
if len(req.Type) != 0 {
|
||||
options = append(options, repo.WithByType(req.Type))
|
||||
|
||||
+30
-22
@@ -321,36 +321,44 @@ func (u *ImageService) ImagePull(req dto.ImagePull) error {
|
||||
}
|
||||
|
||||
func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
|
||||
taskItem, err := task.NewTaskWithOps(req.Path, task.TaskImport, task.TaskScopeImage, req.TaskID, 1)
|
||||
taskItem, err := task.NewTaskWithOps(strings.Join(req.Paths, ","), task.TaskImport, task.TaskScopeImage, req.TaskID, 1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("new task for image import failed, err: %v", err)
|
||||
}
|
||||
taskItem.AddSubTask(i18n.GetWithName("TaskImport", req.Path), func(t *task.Task) error {
|
||||
file, err := os.Open(req.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
go func() {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
taskItem.Log("Failed to create Docker client: " + err.Error())
|
||||
return
|
||||
}
|
||||
defer client.Close()
|
||||
res, err := client.ImageLoad(context.TODO(), file)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
for _, itemPath := range req.Paths {
|
||||
currentPath := itemPath
|
||||
itemName := path.Base(currentPath)
|
||||
taskItem.AddSubTask(i18n.GetWithName("TaskImport", itemName), func(t *task.Task) error {
|
||||
taskItem.Logf("----------------- %s -----------------", itemName)
|
||||
file, err := os.Open(currentPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
res, err := client.ImageLoad(context.TODO(), file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
content, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(string(content), "Error") {
|
||||
return errors.New(string(content))
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
content, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(string(content), "Error") {
|
||||
return errors.New(string(content))
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
go func() {
|
||||
_ = taskItem.Execute()
|
||||
}()
|
||||
return nil
|
||||
|
||||
@@ -37,7 +37,7 @@ func NewIImageRepoService() IImageRepoService {
|
||||
}
|
||||
|
||||
func (u *ImageRepoService) Page(req dto.SearchWithPage) (int64, interface{}, error) {
|
||||
total, ops, err := imageRepoRepo.Page(req.Page, req.PageSize, repo.WithByLikeName(req.Info), repo.WithOrderBy("created_at desc"))
|
||||
total, ops, err := imageRepoRepo.Page(req.Page, req.PageSize, repo.WithByLikeName(req.Info), repo.WithOrderDesc("created_at"))
|
||||
var dtoOps []dto.ImageRepoInfo
|
||||
for _, op := range ops {
|
||||
var item dto.ImageRepoInfo
|
||||
@@ -65,7 +65,7 @@ func (u *ImageRepoService) Login(req dto.OperateByID) error {
|
||||
}
|
||||
|
||||
func (u *ImageRepoService) List() ([]dto.ImageRepoOption, error) {
|
||||
ops, err := imageRepoRepo.List(repo.WithOrderBy("created_at desc"))
|
||||
ops, err := imageRepoRepo.List(repo.WithOrderDesc("created_at"))
|
||||
var dtoOps []dto.ImageRepoOption
|
||||
for _, op := range ops {
|
||||
if op.Status == constant.StatusSuccess {
|
||||
|
||||
@@ -230,6 +230,18 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error {
|
||||
}
|
||||
_ = settingRepo.Update("IptablesStatus", constant.StatusEnable)
|
||||
return nil
|
||||
case "bind-base-without-init":
|
||||
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicBefore, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasic, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = settingRepo.Update("IptablesStatus", constant.StatusEnable)
|
||||
return nil
|
||||
case "unbind-base":
|
||||
if err := iptables.UnbindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter); err != nil {
|
||||
return err
|
||||
|
||||
@@ -2,15 +2,19 @@ package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"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"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"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/net"
|
||||
"github.com/shirou/gopsutil/v4/process"
|
||||
)
|
||||
|
||||
type ProcessService struct{}
|
||||
@@ -18,6 +22,7 @@ type ProcessService struct{}
|
||||
type IProcessService interface {
|
||||
StopProcess(req request.ProcessReq) error
|
||||
GetProcessInfoByPID(pid int32) (*websocket.PsProcessData, error)
|
||||
GetListeningProcess(c context.Context) ([]ListeningProcess, error)
|
||||
}
|
||||
|
||||
func NewIProcessService() IProcessService {
|
||||
@@ -35,6 +40,55 @@ func (ps *ProcessService) StopProcess(req request.ProcessReq) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListeningProcess struct {
|
||||
PID int32
|
||||
Port map[uint32]struct{}
|
||||
Protocol uint32
|
||||
Name string
|
||||
}
|
||||
|
||||
func (ps *ProcessService) GetListeningProcess(c context.Context) ([]ListeningProcess, error) {
|
||||
conn, err := net.ConnectionsMaxWithContext(c, "inet", 32768)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
procCache := make(map[int32]ListeningProcess, 64)
|
||||
|
||||
for _, conn := range conn {
|
||||
if conn.Pid == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if (conn.Status == "LISTEN" && conn.Type == syscall.SOCK_STREAM) || (conn.Type == syscall.SOCK_DGRAM && conn.Raddr.Port == 0) {
|
||||
if _, exists := procCache[conn.Pid]; !exists {
|
||||
proc, err := process.NewProcess(conn.Pid)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
procData := ListeningProcess{
|
||||
PID: conn.Pid,
|
||||
}
|
||||
procData.Name, _ = proc.Name()
|
||||
procData.Port = make(map[uint32]struct{})
|
||||
procData.Port[conn.Laddr.Port] = struct{}{}
|
||||
procData.Protocol = conn.Type
|
||||
procCache[conn.Pid] = procData
|
||||
} else {
|
||||
p := procCache[conn.Pid]
|
||||
p.Port[conn.Laddr.Port] = struct{}{}
|
||||
procCache[conn.Pid] = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
procs := make([]ListeningProcess, 0, len(procCache))
|
||||
for _, proc := range procCache {
|
||||
procs = append(procs, proc)
|
||||
}
|
||||
|
||||
return procs, nil
|
||||
}
|
||||
|
||||
func (ps *ProcessService) GetProcessInfoByPID(pid int32) (*websocket.PsProcessData, error) {
|
||||
p, err := process.NewProcess(pid)
|
||||
if err != nil {
|
||||
|
||||
@@ -405,7 +405,7 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err
|
||||
if len(imageList) != 0 {
|
||||
snap.Task.Log(strings.Join(imageList, " "))
|
||||
snap.Task.Logf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz"))
|
||||
if err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")); err != nil {
|
||||
if err := cmd.RunDefaultBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")); err != nil {
|
||||
snap.Task.LogFailedWithErr(i18n.GetMsgByKey("SnapDockerSave"), err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -101,15 +101,15 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
}()
|
||||
|
||||
if req.IsNew || snap.InterruptStep == "RecoverDownload" || req.ReDownload {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDownload",
|
||||
func(t *task.Task) error { return handleDownloadSnapshot(&itemHelper, snap, rootDir) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverDecompress" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDecompress",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 2 / 11 ----------------------")
|
||||
@@ -118,54 +118,54 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "BackupBeforeRecover" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"BackupBeforeRecover",
|
||||
func(t *task.Task) error { return backupBeforeRecover(snap.Name, &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
|
||||
var snapJson SnapshotJson
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"Readjson",
|
||||
func(t *task.Task) error {
|
||||
snapJson, err = readFromJson(path.Join(rootDir, snap.Name), &itemHelper)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
if req.IsNew || snap.InterruptStep == "RecoverApp" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverApp",
|
||||
func(t *task.Task) error { return recoverAppData(path.Join(rootDir, snap.Name), &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverBaseData" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverBaseData",
|
||||
func(t *task.Task) error { return recoverBaseData(path.Join(rootDir, snap.Name, "base"), &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverDBData" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDBData",
|
||||
func(t *task.Task) error { return recoverDBData(path.Join(rootDir, snap.Name, "db"), &itemHelper) },
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverBackups" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverBackups",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 8 / 11 ----------------------")
|
||||
@@ -174,12 +174,12 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverWebsite" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverWebsite",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 9 / 11 ----------------------")
|
||||
@@ -193,12 +193,12 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
itemHelper.Task.LogWithStatus(i18n.GetMsgByKey("Decompress"), err)
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
if req.IsNew || snap.InterruptStep == "RecoverPanelData" {
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverPanelData",
|
||||
func(t *task.Task) error {
|
||||
itemHelper.Task.Log("---------------------- 10 / 11 ----------------------")
|
||||
@@ -218,16 +218,16 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
}
|
||||
return err
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
req.IsNew = true
|
||||
}
|
||||
taskItem.AddSubTaskWithAlias(
|
||||
taskItem.AddSubTaskWithAliasAndOps(
|
||||
"RecoverDBData",
|
||||
func(t *task.Task) error {
|
||||
return restartCompose(path.Join(snapJson.BaseDir, "1panel/docker/compose"), &itemHelper)
|
||||
},
|
||||
nil,
|
||||
nil, 0, 90*time.Minute,
|
||||
)
|
||||
|
||||
if err := taskItem.Execute(); err != nil {
|
||||
@@ -277,14 +277,15 @@ func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := itemHelper.FileOp.CopyDirWithExclude(global.Dir.DataDir, rootDir, []string{"cache", "tmp"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", global.Dir.DataDir), err)
|
||||
dataDir := global.Dir.DataDir
|
||||
err := itemHelper.FileOp.CopyDirWithExclude(dataDir, rootDir, []string{"cache", "tmp", "backup"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", dataDir), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
openrestyDir, _ := settingRepo.GetValueByKey("WEBSITE_DIR")
|
||||
if len(openrestyDir) != 0 && !strings.Contains(openrestyDir, global.Dir.DataDir) {
|
||||
if len(openrestyDir) != 0 && !strings.Contains(openrestyDir, dataDir) {
|
||||
err := itemHelper.FileOp.CopyDirWithExclude(openrestyDir, rootDir, nil)
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", openrestyDir), err)
|
||||
if err != nil {
|
||||
@@ -292,9 +293,10 @@ func backupBeforeRecover(name string, itemHelper *snapRecoverHelper) error {
|
||||
}
|
||||
}
|
||||
|
||||
if len(global.Dir.LocalBackupDir) != 0 && !strings.Contains(global.Dir.LocalBackupDir, global.Dir.DataDir) {
|
||||
err = itemHelper.FileOp.CopyDirWithExclude(global.Dir.LocalBackupDir, rootDir, []string{"system_snapshot"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", global.Dir.LocalBackupDir), err)
|
||||
backupDir := global.Dir.LocalBackupDir
|
||||
if len(backupDir) != 0 && (backupDir == dataDir+"/backup" || !strings.HasPrefix(backupDir, dataDir)) {
|
||||
err = itemHelper.FileOp.CopyDirWithExclude(backupDir, rootDir, []string{"system_snapshot", "tmp"})
|
||||
itemHelper.Task.LogWithStatus(i18n.GetWithName("SnapCopy", backupDir), err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
|
||||
@@ -88,7 +89,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
||||
taskItem.AddSubTask(
|
||||
i18n.GetWithName("SnapCopy", global.Dir.LocalBackupDir),
|
||||
func(t *task.Task) error {
|
||||
return FileOp.CopyDir(path.Join(rootDir, "backup"), global.Dir.LocalBackupDir)
|
||||
return FileOp.CopyDir(path.Join(rootDir, "backup"), strings.TrimSuffix(global.Dir.LocalBackupDir, "/backup"))
|
||||
},
|
||||
nil,
|
||||
)
|
||||
@@ -97,7 +98,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
||||
taskItem.AddSubTask(
|
||||
i18n.GetWithName("SnapCopy", openrestyDir),
|
||||
func(t *task.Task) error {
|
||||
return FileOp.CopyDir(path.Join(rootDir, "www"), openrestyDir)
|
||||
return FileOp.CopyDir(path.Join(rootDir, "www"), strings.TrimSuffix(openrestyDir, "/www"))
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
@@ -465,6 +465,9 @@ func (u *SSHService) LoadLog(ctx *gin.Context, req dto.SearchSSHLog) (int64, []d
|
||||
|
||||
command := ""
|
||||
if len(req.Info) != 0 {
|
||||
if cmd.CheckIllegal(req.Info) {
|
||||
return 0, data, buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
command = fmt.Sprintf(" | grep '%s'", req.Info)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ func NewITaskService() ITaskLogService {
|
||||
|
||||
func (u *TaskLogService) Page(req dto.SearchTaskLogReq) (int64, []dto.TaskDTO, error) {
|
||||
opts := []repo.DBOption{
|
||||
repo.WithOrderBy("created_at desc"),
|
||||
repo.WithOrderDesc("created_at"),
|
||||
}
|
||||
if req.Status != "" {
|
||||
opts = append(opts, repo.WithByStatus(req.Status))
|
||||
|
||||
@@ -208,6 +208,13 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
|
||||
IPV6: web.IPV6,
|
||||
}
|
||||
|
||||
if siteDTO.Type == constant.Subsite {
|
||||
parentWeb, _ := websiteRepo.GetFirst(repo.WithByID(web.ParentWebsiteID))
|
||||
if parentWeb.ID != 0 {
|
||||
siteDTO.ParentSite = parentWeb.PrimaryDomain
|
||||
}
|
||||
}
|
||||
|
||||
sites, _ := websiteRepo.List(websiteRepo.WithParentID(web.ID))
|
||||
if len(sites) > 0 {
|
||||
for _, site := range sites {
|
||||
@@ -376,7 +383,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
req.AppDetailId = create.AppInstall.AppDetailId
|
||||
req.Params = create.AppInstall.Params
|
||||
req.AppContainerConfig = create.AppInstall.AppContainerConfig
|
||||
install, err = NewIAppService().Install(req)
|
||||
install, err = NewIAppService().Install(req, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -617,6 +624,13 @@ func (w WebsiteService) GetWebsite(id uint) (response.WebsiteDTO, error) {
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
listens := config.FindDirectives("listen")
|
||||
for _, listen := range listens {
|
||||
params := listen.GetParameters()
|
||||
if len(params) > 1 && params[1] == "udp" {
|
||||
res.UDP = true
|
||||
}
|
||||
}
|
||||
upstreams := config.FindUpstreams()
|
||||
for _, up := range upstreams {
|
||||
directives := up.GetDirectives()
|
||||
@@ -1773,7 +1787,7 @@ func (w WebsiteService) GetRedirect(id uint) (res []response.NginxRedirectConfig
|
||||
continue
|
||||
}
|
||||
fileName := entry.Name()
|
||||
if !strings.HasSuffix(fileName, ".conf") && !strings.HasSuffix(fileName, ".conf.bak") {
|
||||
if !strings.HasSuffix(fileName, ".conf") && !strings.HasSuffix(fileName, ".bak") {
|
||||
continue
|
||||
}
|
||||
redirectConfig := response.NginxRedirectConfig{
|
||||
@@ -1929,25 +1943,40 @@ func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*res
|
||||
return nil, err
|
||||
}
|
||||
res.Dirs = []string{"/"}
|
||||
for _, file := range indexFiles {
|
||||
if !file.IsDir() || file.Name() == "node_modules" || file.Name() == "vendor" {
|
||||
continue
|
||||
}
|
||||
res.Dirs = append(res.Dirs, fmt.Sprintf("/%s", file.Name()))
|
||||
fileInfo, _ := file.Info()
|
||||
if fileInfo.Sys().(*syscall.Stat_t).Uid != 1000 || fileInfo.Sys().(*syscall.Stat_t).Gid != 1000 {
|
||||
res.Msg = i18n.GetMsgByKey("ErrPathPermission")
|
||||
}
|
||||
childFiles, _ := os.ReadDir(absoluteIndexPath + "/" + file.Name())
|
||||
for _, childFile := range childFiles {
|
||||
if !childFile.IsDir() {
|
||||
checkAndAppendDirs := func(relPath string, entries []os.DirEntry) {
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() || entry.Name() == "node_modules" || entry.Name() == "vendor" {
|
||||
continue
|
||||
}
|
||||
childInfo, _ := childFile.Info()
|
||||
if childInfo.Sys().(*syscall.Stat_t).Uid != 1000 || childInfo.Sys().(*syscall.Stat_t).Gid != 1000 {
|
||||
res.Msg = i18n.GetMsgByKey("ErrPathPermission")
|
||||
nextRelPath := path.Join(relPath, entry.Name())
|
||||
res.Dirs = append(res.Dirs, "/"+strings.TrimPrefix(nextRelPath, "/"))
|
||||
entryInfo, _ := entry.Info()
|
||||
if entryInfo != nil {
|
||||
if stat, ok := entryInfo.Sys().(*syscall.Stat_t); ok {
|
||||
if stat.Uid != 1000 || stat.Gid != 1000 {
|
||||
res.Msg = i18n.GetMsgByKey("ErrPathPermission")
|
||||
}
|
||||
}
|
||||
}
|
||||
res.Dirs = append(res.Dirs, fmt.Sprintf("/%s/%s", file.Name(), childFile.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
checkAndAppendDirs("", indexFiles)
|
||||
for _, firstDir := range indexFiles {
|
||||
if !firstDir.IsDir() || firstDir.Name() == "node_modules" || firstDir.Name() == "vendor" {
|
||||
continue
|
||||
}
|
||||
secondLevelPath := path.Join(absoluteIndexPath, firstDir.Name())
|
||||
secondLevelDirs, _ := os.ReadDir(secondLevelPath)
|
||||
checkAndAppendDirs(firstDir.Name(), secondLevelDirs)
|
||||
|
||||
for _, secondDir := range secondLevelDirs {
|
||||
if !secondDir.IsDir() || secondDir.Name() == "node_modules" || secondDir.Name() == "vendor" {
|
||||
continue
|
||||
}
|
||||
thirdLevelPath := path.Join(secondLevelPath, secondDir.Name())
|
||||
thirdLevelDirs, _ := os.ReadDir(thirdLevelPath)
|
||||
checkAndAppendDirs(path.Join(firstDir.Name(), secondDir.Name()), thirdLevelDirs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2028,6 +2057,15 @@ func (w WebsiteService) UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error {
|
||||
switch req.Type {
|
||||
case "404":
|
||||
resourcePath = path.Join(defaultPath, "404.html")
|
||||
if req.Sync {
|
||||
websites, _ := websiteRepo.GetBy(repo.WithTypes([]string{constant.Static, constant.Runtime}))
|
||||
for _, website := range websites {
|
||||
filePath := path.Join(GetSitePath(website, SiteIndexDir), "404.html")
|
||||
if fileOp.Stat(filePath) {
|
||||
_ = fileOp.SaveFile(filePath, req.Content, constant.DirPerm)
|
||||
}
|
||||
}
|
||||
}
|
||||
case "php":
|
||||
resourcePath = path.Join(defaultPath, "index.php")
|
||||
case "index":
|
||||
@@ -2259,6 +2297,9 @@ func (w WebsiteService) OperateCrossSiteAccess(req request.CrossSiteAccessOp) er
|
||||
}
|
||||
|
||||
func (w WebsiteService) ExecComposer(req request.ExecComposerReq) error {
|
||||
if cmd.CheckIllegal(req.User, req.Mirror, req.Command, req.ExtCommand) {
|
||||
return buserr.New("ErrCmdIllegal")
|
||||
}
|
||||
website, err := websiteRepo.GetFirst(repo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -2333,10 +2374,14 @@ func (w WebsiteService) UpdateStream(req request.StreamUpdate) error {
|
||||
}
|
||||
server := servers[0]
|
||||
server.Listens = []*components.ServerListen{}
|
||||
var params []string
|
||||
if req.UDP {
|
||||
params = []string{"udp"}
|
||||
}
|
||||
for _, port := range ports {
|
||||
server.UpdateListen(port, false)
|
||||
server.UpdateListen(port, false, params...)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:"+port, false)
|
||||
server.UpdateListen("[::]:"+port, false, params...)
|
||||
}
|
||||
}
|
||||
upstream := components.Upstream{
|
||||
|
||||
@@ -25,7 +25,7 @@ func NewIWebsiteAcmeAccountService() IWebsiteAcmeAccountService {
|
||||
}
|
||||
|
||||
func (w WebsiteAcmeAccountService) Page(search dto.PageInfo) (int64, []response.WebsiteAcmeAccountDTO, error) {
|
||||
total, accounts, err := websiteAcmeRepo.Page(search.Page, search.PageSize, repo.WithOrderBy("created_at desc"))
|
||||
total, accounts, err := websiteAcmeRepo.Page(search.Page, search.PageSize, repo.WithOrderDesc("created_at"))
|
||||
var accountDTOs []response.WebsiteAcmeAccountDTO
|
||||
for _, account := range accounts {
|
||||
accountDTOs = append(accountDTOs, response.WebsiteAcmeAccountDTO{
|
||||
@@ -45,9 +45,10 @@ func (w WebsiteAcmeAccountService) Create(create request.WebsiteAcmeAccountCreat
|
||||
Type: create.Type,
|
||||
KeyType: create.KeyType,
|
||||
UseProxy: create.UseProxy,
|
||||
UseEAB: create.UseEAB,
|
||||
}
|
||||
|
||||
if create.Type == "google" || create.Type == "freessl" {
|
||||
if create.Type == "google" || create.Type == "freessl" || (create.Type == "custom" && create.UseEAB) {
|
||||
if create.EabKid == "" || create.EabHmacKey == "" {
|
||||
return nil, buserr.New("ErrEabKidOrEabHmacKeyCannotBlank")
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func NewIWebsiteCAService() IWebsiteCAService {
|
||||
}
|
||||
|
||||
func (w WebsiteCAService) Page(search request.WebsiteCASearch) (int64, []response.WebsiteCADTO, error) {
|
||||
total, cas, err := websiteCARepo.Page(search.Page, search.PageSize, repo.WithOrderBy("created_at desc"))
|
||||
total, cas, err := websiteCARepo.Page(search.Page, search.PageSize, repo.WithOrderDesc("created_at"))
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func NewIWebsiteDnsAccountService() IWebsiteDnsAccountService {
|
||||
}
|
||||
|
||||
func (w WebsiteDnsAccountService) Page(search dto.PageInfo) (int64, []response.WebsiteDnsAccountDTO, error) {
|
||||
total, accounts, err := websiteDnsRepo.Page(search.Page, search.PageSize, repo.WithOrderBy("created_at desc"))
|
||||
total, accounts, err := websiteDnsRepo.Page(search.Page, search.PageSize, repo.WithOrderDesc("created_at"))
|
||||
var accountDTOs []response.WebsiteDnsAccountDTO
|
||||
for _, account := range accounts {
|
||||
auth := make(map[string]string)
|
||||
|
||||
@@ -4,6 +4,10 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
@@ -17,9 +21,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx/components"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/nginx/parser"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/re"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error) {
|
||||
@@ -119,8 +120,13 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
location.RemoveServerCache(fmt.Sprintf("proxy_cache_zone_of_%s", website.Alias))
|
||||
}
|
||||
// Browser Cache Settings
|
||||
if req.CacheTime != 0 {
|
||||
// cacheTime > 0: enable expires;
|
||||
// cacheTime == 0: use upstream cache-control, remove self-set;
|
||||
// cacheTime < 0: force no-cache
|
||||
if req.CacheTime > 0 {
|
||||
location.AddBrowserCache(req.CacheTime, req.CacheUnit)
|
||||
} else if req.CacheTime < 0 {
|
||||
location.AddBroswerNoCache()
|
||||
} else {
|
||||
location.RemoveBrowserCache()
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ type WebsiteSSLService struct {
|
||||
type IWebsiteSSLService interface {
|
||||
Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error)
|
||||
GetSSL(id uint) (*response.WebsiteSSLDTO, error)
|
||||
Search(req request.WebsiteSSLSearch) ([]response.WebsiteSSLDTO, error)
|
||||
Search(req request.WebsiteSSLListReq) ([]response.WebsiteSSLDTO, error)
|
||||
Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error)
|
||||
GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error)
|
||||
GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error)
|
||||
@@ -62,7 +62,7 @@ func (w WebsiteSSLService) Page(search request.WebsiteSSLSearch) (int64, []respo
|
||||
if search.OrderBy != "" && search.Order != "null" {
|
||||
opts = append(opts, repo.WithOrderRuleBy(search.OrderBy, search.Order))
|
||||
} else {
|
||||
opts = append(opts, repo.WithOrderBy("created_at desc"))
|
||||
opts = append(opts, repo.WithOrderDesc("created_at"))
|
||||
}
|
||||
if search.Domain != "" {
|
||||
opts = append(opts, websiteSSLRepo.WithByDomain(search.Domain))
|
||||
@@ -90,12 +90,12 @@ func (w WebsiteSSLService) GetSSL(id uint) (*response.WebsiteSSLDTO, error) {
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) Search(search request.WebsiteSSLSearch) ([]response.WebsiteSSLDTO, error) {
|
||||
func (w WebsiteSSLService) Search(search request.WebsiteSSLListReq) ([]response.WebsiteSSLDTO, error) {
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
result []response.WebsiteSSLDTO
|
||||
)
|
||||
opts = append(opts, repo.WithOrderBy("created_at desc"))
|
||||
opts = append(opts, repo.WithOrderDesc("created_at"))
|
||||
if search.AcmeAccountID != "" {
|
||||
acmeAccountID, err := strconv.ParseUint(search.AcmeAccountID, 10, 64)
|
||||
if err != nil {
|
||||
|
||||
@@ -131,7 +131,7 @@ func createProxyFile(website *model.Website) error {
|
||||
}
|
||||
|
||||
func createWebsiteFolder(website *model.Website, runtime *model.Runtime) error {
|
||||
siteFolder := GteSiteDir(website.Alias)
|
||||
siteFolder := GetSiteDir(website.Alias)
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(siteFolder) {
|
||||
if err := fileOp.CreateDir(siteFolder, constant.DirPerm); err != nil {
|
||||
@@ -206,10 +206,14 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
}
|
||||
server := servers[0]
|
||||
ports := strings.Split(streamConfig.StreamPorts, ",")
|
||||
var params []string
|
||||
if streamConfig.UDP {
|
||||
params = []string{"udp"}
|
||||
}
|
||||
for _, port := range ports {
|
||||
server.UpdateListen(port, false)
|
||||
server.UpdateListen(port, false, params...)
|
||||
if website.IPV6 {
|
||||
server.UpdateListen("[::]:"+port, false)
|
||||
server.UpdateListen("[::]:"+port, false, params...)
|
||||
}
|
||||
}
|
||||
siteFolder := path.Join("/www", "sites", website.Alias)
|
||||
@@ -491,7 +495,7 @@ func delNginxConfig(website model.Website, force bool) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sitePath := GteSiteDir(website.Alias)
|
||||
sitePath := GetSiteDir(website.Alias)
|
||||
if fileOp.Stat(sitePath) {
|
||||
xpack.RemoveTamper(website.Alias)
|
||||
_ = fileOp.DeleteDir(sitePath)
|
||||
@@ -845,6 +849,17 @@ func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.W
|
||||
nginxParams[i].Params = []string{"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED"}
|
||||
}
|
||||
}
|
||||
if param.Name == "error_page" {
|
||||
if len(param.Params) < 2 {
|
||||
continue
|
||||
}
|
||||
code := param.Params[0]
|
||||
if code == "497" {
|
||||
if sslPort != 443 && param.Params[1] == "https://$host$request_uri" {
|
||||
param.Params[1] = fmt.Sprintf("https://$host:%d$request_uri", sslPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if req.Hsts {
|
||||
var hstsValue string
|
||||
@@ -962,6 +977,8 @@ func opWebsite(website *model.Website, operate string) error {
|
||||
server.RemoveDirective("include", []string{proxyInclude})
|
||||
rewriteInclude := fmt.Sprintf("/www/sites/%s/rewrite/%s.conf", website.Alias, website.Alias)
|
||||
server.RemoveDirective("include", []string{rewriteInclude})
|
||||
redirectInclude := fmt.Sprintf("/www/sites/%s/redirect/%s.conf", website.Alias, website.Alias)
|
||||
server.RemoveDirective("include", []string{redirectInclude})
|
||||
|
||||
switch website.Type {
|
||||
case constant.Deployment:
|
||||
@@ -992,6 +1009,11 @@ func opWebsite(website *model.Website, operate string) error {
|
||||
if fileOp.Stat(absoluteRewritePath) {
|
||||
server.UpdateDirective("include", []string{rewriteInclude})
|
||||
}
|
||||
redirectInclude := fmt.Sprintf("/www/sites/%s/redirect/%s.conf", website.Alias, website.Alias)
|
||||
absoluteRedirectPath := GetSitePath(*website, SiteRedirectDir)
|
||||
if fileOp.Stat(absoluteRedirectPath) {
|
||||
server.UpdateDirective("include", []string{redirectInclude})
|
||||
}
|
||||
rootIndex := path.Join("/www/sites", website.Alias, "index")
|
||||
if website.SiteDir != "/" {
|
||||
rootIndex = path.Join(rootIndex, website.SiteDir)
|
||||
@@ -1111,7 +1133,7 @@ func getWebsiteDomains(domains []request.WebsiteDomain, defaultHTTPPort, default
|
||||
if domain.Domain == "" {
|
||||
continue
|
||||
}
|
||||
if !common.IsValidNginxServerName(domain.Domain) {
|
||||
if !(common.IsValidNginxServerName(domain.Domain) || common.IsValidIP(domain.Domain)) {
|
||||
err = buserr.WithName("ErrDomainFormat", domain.Domain)
|
||||
return
|
||||
}
|
||||
@@ -1222,7 +1244,7 @@ func saveCertificateFile(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
|
||||
func GetSystemSSL() (bool, uint) {
|
||||
var sslSetting model.Setting
|
||||
_ = global.CoreDB.Model(&model.Setting{}).Where("key = ?", "SSL").First(&sslSetting).Error
|
||||
if sslSetting.Value == "Enable" {
|
||||
if sslSetting.Value == "Enable" || sslSetting.Value == "Mux" {
|
||||
var sslIDSetting model.Setting
|
||||
_ = global.CoreDB.Model(&model.Setting{}).Where("key = ?", "SSLID").First(&sslIDSetting).Error
|
||||
idValue, _ := strconv.Atoi(sslIDSetting.Value)
|
||||
@@ -1357,7 +1379,7 @@ func GetWebSiteRootDir() string {
|
||||
return dir
|
||||
}
|
||||
|
||||
func GteSiteDir(alias string) string {
|
||||
func GetSiteDir(alias string) string {
|
||||
return path.Join(GetWebSiteRootDir(), "sites", alias)
|
||||
}
|
||||
|
||||
@@ -1399,31 +1421,31 @@ func GetSitePath(website model.Website, confType string) string {
|
||||
case StreamConf:
|
||||
return path.Join(GetWebSiteRootDir(), "stream.d", website.Alias+".conf")
|
||||
case SiteAccessLog:
|
||||
return path.Join(GteSiteDir(website.Alias), "log", "access.log")
|
||||
return path.Join(GetSiteDir(website.Alias), "log", "access.log")
|
||||
case SiteErrorLog:
|
||||
return path.Join(GteSiteDir(website.Alias), "log", "error.log")
|
||||
return path.Join(GetSiteDir(website.Alias), "log", "error.log")
|
||||
case SiteDir:
|
||||
return GteSiteDir(website.Alias)
|
||||
return GetSiteDir(website.Alias)
|
||||
case SiteIndexDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "index")
|
||||
return path.Join(GetSiteDir(website.Alias), "index")
|
||||
case SiteCacheDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "cache")
|
||||
return path.Join(GetSiteDir(website.Alias), "cache")
|
||||
case SiteProxyDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "proxy")
|
||||
return path.Join(GetSiteDir(website.Alias), "proxy")
|
||||
case SiteSSLDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "ssl")
|
||||
return path.Join(GetSiteDir(website.Alias), "ssl")
|
||||
case SiteReWritePath:
|
||||
return path.Join(GteSiteDir(website.Alias), "rewrite", website.Alias+".conf")
|
||||
return path.Join(GetSiteDir(website.Alias), "rewrite", website.Alias+".conf")
|
||||
case SiteRedirectDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "redirect")
|
||||
return path.Join(GetSiteDir(website.Alias), "redirect")
|
||||
case SiteRootAuthBasicPath:
|
||||
return path.Join(GteSiteDir(website.Alias), "auth_basic", "auth.pass")
|
||||
return path.Join(GetSiteDir(website.Alias), "auth_basic", "auth.pass")
|
||||
case SitePathAuthBasicDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "path_auth")
|
||||
return path.Join(GetSiteDir(website.Alias), "path_auth")
|
||||
case SiteUpstreamDir:
|
||||
return path.Join(GteSiteDir(website.Alias), "upstream")
|
||||
return path.Join(GetSiteDir(website.Alias), "upstream")
|
||||
case SiteCorsPath:
|
||||
return path.Join(GteSiteDir(website.Alias), "cors", "cors.conf")
|
||||
return path.Join(GetSiteDir(website.Alias), "cors", "cors.conf")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
+16
-1
@@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
@@ -96,6 +97,7 @@ const (
|
||||
TaskScopeCustomAppstore = "CustomAppstore"
|
||||
TaskScopeTamper = "Tamper"
|
||||
TaskScopeFileConvert = "Convert"
|
||||
TaskScopeTask = "Task"
|
||||
)
|
||||
|
||||
func GetTaskName(resourceName, operate, scope string) string {
|
||||
@@ -352,7 +354,20 @@ func (t *Task) LogSuccessWithOps(operate, msg string) {
|
||||
}
|
||||
|
||||
func (t *Task) LogFailedWithOps(operate, msg string, err error) {
|
||||
t.Logger.Printf("%s%s%s : %s ", i18n.GetMsgByKey(operate), msg, i18n.GetMsgByKey("Failed"), err.Error())
|
||||
t.Logger.Printf("%s%s : %s ", msg, i18n.GetMsgByKey("Failed"), err.Error())
|
||||
}
|
||||
|
||||
func (t *Task) LogWithProgress(msg string, current int, total int) {
|
||||
const barWidth = 10
|
||||
filled := int(float64(current) / float64(total) * 100 / 10)
|
||||
if filled > barWidth {
|
||||
filled = barWidth
|
||||
}
|
||||
if filled < 0 {
|
||||
filled = 0
|
||||
}
|
||||
bar := strings.Repeat("=", filled) + strings.Repeat("-", barWidth-filled)
|
||||
t.Logger.Printf("%s [%s] %.2f%%", msg, bar, float64(current)/float64(total)*100)
|
||||
}
|
||||
|
||||
type SimpleFormatter struct{}
|
||||
|
||||
@@ -24,4 +24,5 @@ const (
|
||||
WeCom = "weCom"
|
||||
DingTalk = "dingTalk"
|
||||
FeiShu = "feiShu"
|
||||
Custom = "custom"
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ const (
|
||||
AppTakeDown = "TakeDown"
|
||||
|
||||
AppOpenresty = "openresty"
|
||||
AppOpenclaw = "openclaw"
|
||||
AppMysql = "mysql"
|
||||
AppMariaDB = "mariadb"
|
||||
AppPostgresql = "postgresql"
|
||||
|
||||
@@ -40,4 +40,6 @@ const (
|
||||
|
||||
OrderDesc = "descending"
|
||||
OrderAsc = "ascending"
|
||||
Desc = "desc"
|
||||
Asc = "asc"
|
||||
)
|
||||
|
||||
@@ -34,6 +34,7 @@ type SystemDir struct {
|
||||
|
||||
AppDir string
|
||||
ResourceDir string
|
||||
IconCacheDir string
|
||||
AppResourceDir string
|
||||
AppInstallDir string
|
||||
LocalAppResourceDir string
|
||||
|
||||
+8
-11
@@ -4,12 +4,7 @@ go 1.24.9
|
||||
|
||||
require (
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.7
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0
|
||||
github.com/aws/smithy-go v1.24.0
|
||||
github.com/aws/aws-sdk-go v1.55.0
|
||||
github.com/compose-spec/compose-go/v2 v2.9.0
|
||||
github.com/creack/pty v1.1.24
|
||||
github.com/docker/compose/v2 v2.40.2
|
||||
@@ -33,6 +28,7 @@ require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/klauspost/compress v1.18.1
|
||||
github.com/mholt/archiver/v4 v4.0.0-alpha.8
|
||||
github.com/miekg/dns v1.1.69
|
||||
github.com/minio/minio-go/v7 v7.0.74
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||
github.com/opencontainers/image-spec v1.1.1
|
||||
@@ -75,21 +71,21 @@ require (
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect
|
||||
github.com/aliyun/credentials-go v1.4.7 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.254 // indirect
|
||||
github.com/bodgit/plumbing v1.2.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.3.0 // indirect
|
||||
@@ -162,6 +158,7 @@ require (
|
||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
@@ -174,7 +171,6 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/miekg/dns v1.1.69 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
@@ -199,6 +195,7 @@ require (
|
||||
github.com/nrdcg/freemyip v0.3.0 // indirect
|
||||
github.com/nrdcg/goacmedns v0.2.0 // indirect
|
||||
github.com/nrdcg/namesilo v0.5.0 // indirect
|
||||
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/ovh/go-ovh v1.9.0 // indirect
|
||||
|
||||
+9
-117
@@ -100,7 +100,6 @@ github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/Ke
|
||||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||
github.com/alibabacloud-go/tea v1.3.13 h1:WhGy6LIXaMbBM6VBYcsDCz6K/TPsT1Ri2hPmmZffZ94=
|
||||
github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||
github.com/alibabacloud-go/tea v1.3.14 h1:/Uzj5ZCFPpbPR+Bs7jfzsyXkYIVsi5TOIuQNOWwc/9c=
|
||||
github.com/alibabacloud-go/tea v1.3.14/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||
@@ -129,91 +128,41 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go v1.55.0 h1:hVALKPjXz33kP1R9nTyJpUK7qF59dO2mleQxUW9mCVE=
|
||||
github.com/aws/aws-sdk-go v1.55.0/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.2 h1:4liUsdEpUUPZs5WVapsJLx5NPmQhQdez7nYFcovrytk=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.2/go.mod h1:l0hs06IFz1eCT+jTacU/qZtC33nvcnLADAPL/XyrkZI=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5 h1:pz3duhAfUgnxbtVhIK39PGF/AHYyrzGEyRD9Og0QrE8=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.5/go.mod h1:xmDjzSUs/d0BB7ClzYPAZMmgQdrodNjPPhd6bGASwoE=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.2 h1:qZry8VUyTK4VIo5aEdUcBjPZHL2v4FyQ3QEOaWcFLu4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.2/go.mod h1:YUqm5a1/kBnoK+/NY5WEiMocZihKSo15/tJdmdXnM5g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 h1:xMo63RlqP3ZZydpJDMBsH9uJ10hgHYfQFIk1cHDXrR4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5/go.mod h1:hhbH6oRcou+LpXfA/0vPElh/e0M3aFeOblE1sssAAEk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 h1:WZVR5DbDgxzA0BJeudId89Kmgy6DIU4ORpxwsVHz0qA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14/go.mod h1:Dadl9QO0kHgbrH1GRqGiZdYtW5w+IXXaBNCHTIaheM4=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.7 h1:u8danF+A2Zv//pFZvj5V23v/6XG4AxuSVup5s6nxSnI=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.7/go.mod h1:uvLIvU8iJPEU5so7b6lLDNArWpOX6sRBfL5wBABmlfc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 h1:ITi7qiDSv/mSGDSWNpZ4k4Ve0DQR6Ug2SJQ8zEHoDXg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14/go.mod h1:k1xtME53H1b6YpZt74YmwlONMWf4ecM+lut1WQLAF/U=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 h1:Hjkh7kE6D81PgrHlE/m9gx+4TyyeLHuY8xJs7yXN5C4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5/go.mod h1:nPRXgyCfAurhyaTMoBMwRBYBhaHI4lNPAnJmjM0Tslc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 h1:FIouAnCE46kyYqyhs0XEBDFFSREtdnr8HQuLPQPLCrY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14/go.mod h1:UTwDc5COa5+guonQU8qBikJo1ZJ4ln2r1MkF7Dqag1E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 h1:FzQE21lNtUor0Fb7QNgnEyiRCBlolLTX/Z1j65S7teM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14/go.mod h1:s1ydyWG9pm3ZwmmYN21HKyG9WzAZhYVW85wMHs5FV6w=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0 h1:W3+0Cbc9awFBr9Yt7nFUkvB4N4e7vVIGtKD1qDttXn4=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.61.0/go.mod h1:Wa3q5R2uwIfIL3HZH+vG1/P9y7CjjfzTgcz5IWXlsZs=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 h1:80pDB3Tpmb2RCSZORrK9/3iQxsd+w6vSzVqpT1FGiwE=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0/go.mod h1:6EZUGGNLPLh5Unt30uEoA+KQcByERfXIkax9qrc80nA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1 h1:OgQy/+0+Kc3khtqiEOk23xQAglXi3Tj0y5doOxbi5tg=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1/go.mod h1:wYNqY3L02Z3IgRYxOBPH9I1zD9Cjh9hI5QOy/eOjQvw=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0 h1:SWTxh/EcUCDVqi/0s26V6pVUq0BBG7kx0tDTmF/hCgA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 h1:MxMBdKTYBjPQChlJhi4qlEueqB1p1KcbTEa7tD5aqPs=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 h1:ksUT5KtgpZd3SAiFJNJ0AFEJVva3gjBmN7eXUZjzUwQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 h1:eYnlt6QxnFINKzwxP5/Ucs1vkG7VT3Iezmvfgc2waUw=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 h1:GtsxyiF3Nd3JahRBJbxLCCdYW9ltGQYrFWg8XdkGDd8=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 h1:a5UTtD4mHBU3t0o6aHQZFJTNKVfxFWfPX7J0Lr7G+uY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
||||
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
||||
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/baidubce/bce-sdk-go v0.9.252 h1:TONS/utgfEkDjvHllVZFBrTsjsNhk51rhWuj3ppcL4s=
|
||||
github.com/baidubce/bce-sdk-go v0.9.252/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/baidubce/bce-sdk-go v0.9.254 h1:A7GtBOt7z2lnV7fqlZPZefhcBFg7z6iliUAhEOiIhoE=
|
||||
github.com/baidubce/bce-sdk-go v0.9.254/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@@ -350,8 +299,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
|
||||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
@@ -398,12 +345,8 @@ github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GM
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-acme/alidns-20150109/v4 v4.7.0 h1:PqJ/wR0JTpL4v0Owu1uM7bPQ1Yww0eQLAuuSdLjjQaQ=
|
||||
github.com/go-acme/alidns-20150109/v4 v4.7.0/go.mod h1:btQvB6xZoN6ykKB74cPhiR+uvhrEE2AFVXm6RDmCHm0=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.1 h1:pog3UlF5d+3LPoo1L8u8PqB189recIXX8T7pGoEz18A=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.1/go.mod h1:ZYdN9EN9ikn26SNapxCVjZ65pHT/1qm4fzuJ7QGVX6g=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.3 h1:xXOMRex148wKEHbv7Izn73/HdAxSmz5GOaF4HdnqN+M=
|
||||
github.com/go-acme/esa-20240910/v2 v2.40.3/go.mod h1:ZYdN9EN9ikn26SNapxCVjZ65pHT/1qm4fzuJ7QGVX6g=
|
||||
github.com/go-acme/lego/v4 v4.29.0 h1:vKMEtvoKb0gOO9rWO9zMBwE4CgI5A5CWDsK4QEeBqzo=
|
||||
github.com/go-acme/lego/v4 v4.29.0/go.mod h1:rnYyDj1NdDd9y1dHkVuUS97j7bfe9I61+oY9odKaHM8=
|
||||
github.com/go-acme/lego/v4 v4.30.1 h1:tmb6U0lvy8Mc3lQbqKwTat7oAhE8FUYNJ3D0gSg6pJU=
|
||||
github.com/go-acme/lego/v4 v4.30.1/go.mod h1:V7m/Ip+EeFkjOe028+zeH+SwWtESxw1LHelwMIfAjm4=
|
||||
github.com/go-acme/tencentclouddnspod v1.1.25 h1:7H3ZKshkaHzCXfRpAHVB5nvxeDDl2XLeNZfrNHiZj/s=
|
||||
@@ -450,8 +393,6 @@ github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-resty/resty/v2 v2.17.0 h1:pW9DeXcaL4Rrym4EZ8v7L19zZiIlWPg5YXAcVmt+gN0=
|
||||
github.com/go-resty/resty/v2 v2.17.0/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
@@ -601,8 +542,6 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
|
||||
github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@@ -615,8 +554,6 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg
|
||||
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.178 h1:eNVkjzdPMgM2qih9aECiFUI8S9zgpOwXxeBPAwQqtvU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.178/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.180 h1:uia+R3K1izQRGpxTV+bS4q3/ueMW7ProAMWqM6OlqOU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.180/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
|
||||
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
|
||||
@@ -652,7 +589,9 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
@@ -741,8 +680,6 @@ github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60V
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
|
||||
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/miekg/dns v1.1.69 h1:Kb7Y/1Jo+SG+a2GtfoFUfDkG//csdRPwRLkCsxDG9Sc=
|
||||
github.com/miekg/dns v1.1.69/go.mod h1:7OyjD9nEba5OkqQ/hB4fy3PIoxafSZJtducccIelz3g=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
@@ -827,6 +764,8 @@ github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0
|
||||
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
|
||||
github.com/nrdcg/namesilo v0.5.0 h1:6QNxT/XxE+f5B+7QlfWorthNzOzcGlBLRQxqi6YeBrE=
|
||||
github.com/nrdcg/namesilo v0.5.0/go.mod h1:4UkwlwQfDt74kSGmhLaDylnBrD94IfflnpoEaj6T2qw=
|
||||
github.com/nrdcg/porkbun v0.4.0 h1:rWweKlwo1PToQ3H+tEO9gPRW0wzzgmI/Ob3n2Guticw=
|
||||
github.com/nrdcg/porkbun v0.4.0/go.mod h1:/QMskrHEIM0IhC/wY7iTCUgINsxdT2WcOphktJ9+Q54=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A=
|
||||
github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
@@ -885,8 +824,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
@@ -933,8 +870,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -952,8 +889,6 @@ github.com/secure-systems-lab/go-securesystemslib v0.6.0 h1:T65atpAVCJQK14UA57LM
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.6.0/go.mod h1:8Mtpo9JKks/qhPG4HGZ2LGMvrPbzuxwfz/f/zLfEWkk=
|
||||
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
|
||||
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
@@ -1008,8 +943,6 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.25/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.3 h1:r05ohLc0LVEpiEQeOJ5QwCiKk6XM9kjTca6+UAbNR/8=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.3/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.12 h1:/ABtv4x4FSGxGW0d6Sc88iQn6Up2LalWKwt/Tj7Dtz8=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.12/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
|
||||
@@ -1022,12 +955,8 @@ github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnH
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
|
||||
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
|
||||
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||
github.com/tomasen/fcgi_client v0.0.0-20180423082037-2bb3d819fd19 h1:ZCmSnT6CLGhfoQ2lPEhL4nsJstKDCw1F1RfN8/smTCU=
|
||||
@@ -1055,8 +984,6 @@ github.com/upyun/go-sdk v2.1.0+incompatible/go.mod h1:eu3F5Uz4b9ZE5bE5QsCL6mgSNW
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
|
||||
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.229 h1:gOkDltTS6Fta8OyfYrbeY9bqCHHyiJuGYNJpR5MR+Fo=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.229/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.230 h1:84/MOF0zUPtAHt3e1+MsFq5qrnQRC+e3XzTUwIOzZxw=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.230/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
@@ -1090,8 +1017,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
@@ -1100,8 +1025,6 @@ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
|
||||
@@ -1112,20 +1035,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
@@ -1182,8 +1097,6 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1229,8 +1142,6 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1289,8 +1200,6 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1300,8 +1209,6 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
|
||||
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1320,8 +1227,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1403,8 +1308,6 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
@@ -1421,9 +1324,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1441,8 +1343,6 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1506,8 +1406,6 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1578,12 +1476,8 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
|
||||
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -1603,8 +1497,6 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
||||
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
||||
+29
-15
@@ -38,6 +38,19 @@ ErrGroupIsDefault: 'Default group, cannot be deleted'
|
||||
ErrGroupIsInWebsiteUse: 'The group is being used by another website and cannot be deleted.'
|
||||
Decrypt: "Decrypt"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: 'This account is bound to an agent and cannot be deleted. Please check and try again!'
|
||||
ErrAgentAccountUnavailable: 'The account connection information is unavailable. Error: {{ .err }}. Please check and try again!'
|
||||
ErrAgentProviderNotSupported: 'This agent provider is not supported. Please check and try again!'
|
||||
ErrAgentAccountRequired: 'Please select an agent account and try again.'
|
||||
ErrAgentAccountNotVerified: 'The account has not been verified. Please check and try again!'
|
||||
ErrAgentProviderMismatch: 'The account provider does not match. Please check and try again!'
|
||||
ErrAgentBaseURLRequired: 'Base URL cannot be empty. Please check and try again!'
|
||||
ErrAgentApiKeyRequired: 'API Key cannot be empty. Please check and try again!'
|
||||
ErrAgentComposeRequired: 'Custom compose content cannot be empty. Please check and try again!'
|
||||
ErrAgentIDRequired: 'Agent ID cannot be empty. Please check and try again!'
|
||||
ErrAgentAccountIDRequired: 'Account ID cannot be empty. Please check and try again!'
|
||||
|
||||
#backup
|
||||
Localhost: 'Local Machine'
|
||||
ErrBackupInUsed: 'The backup account has been used in the scheduled task and cannot be deleted.'
|
||||
@@ -201,6 +214,7 @@ ErrRemoteExist: 'The remote database already exists with this name, please modif
|
||||
ErrLocalExist: 'The name already exists in the local database, please modify it and try again'
|
||||
RemoteBackup: "To back up the remote database, the local container database service needs to be started first using the image {{ .name }}, please wait..."
|
||||
RemoteRecover: "To restore the remote database, the local container database service needs to be started first using the image {{ .name }}, please wait..."
|
||||
Arg: "Argument"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'The recovery file type does not match the current persistence method, please modify it and try again'
|
||||
@@ -211,7 +225,7 @@ ErrObjectInUsed: "This object is in use and cannot be deleted!"
|
||||
ErrObjectBeDependent: "This image is depended on by other images and cannot be deleted!"
|
||||
ErrPortRules: 'Port number does not match, please re-enter!'
|
||||
ErrPgImagePull: 'Image pull timed out, please configure image acceleration or manually pull the {{ .name }} image and try again'
|
||||
PruneHelper: "This cleanup removed {{ .name }} {{ .count }} items, freeing {{ .size }} disk space"
|
||||
PruneHelper: "This cleanup {{ .name }} freed disk space {{ .size }}"
|
||||
ImageRemoveHelper: "Deleted image {{ .name }}, freeing {{ .size }} disk space"
|
||||
BuildCache: "Build cache"
|
||||
Volume: "Storage volume"
|
||||
@@ -505,19 +519,19 @@ ErrInstallExtension: "An installation task is already in progress, please wait f
|
||||
PanelAlertTitle: "Panel Alert Notification"
|
||||
TestAlertTitle: "Test Email - Verify Email Connectivity"
|
||||
TestAlert: "This is a test email to verify that your email sending configuration is correct."
|
||||
LicenseExpirationAlert: "Your 1Panel license will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
CronJobFailedAlert: "Your 1Panel scheduled task '{{ .name }}' has failed. Please log in to the panel for details."
|
||||
ClamAlert: "Your 1Panel virus scan task has detected {{ .num }} infected files. Please log in to the panel for details."
|
||||
WebSiteAlert: "There are {{ .num }} websites on your 1Panel that will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
SSLAlert: "There are {{ .num }} SSL certificates on your 1Panel that will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
DiskUsedAlert: "Your 1Panel disk '{{ .name }}' has used {{ .used }}. Please log in to the panel for details."
|
||||
ResourceAlert: "The average {{ .name }} usage over {{ .time }} minutes on your 1Panel is {{ .used }}. Please log in to the panel for details."
|
||||
PanelVersionAlert: "A new version of 1Panel is available. Please log in to the panel to upgrade."
|
||||
PanelPwdExpirationAlert: "Your 1Panel password will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
CommonAlert: "Your 1Panel, {{ .msg }}, please log in to the panel for details."
|
||||
NodeExceptionAlert: "Your 1Panel, {{ .num }} nodes are abnormal, please log in to the panel for details."
|
||||
LicenseExceptionAlert: "Your 1Panel, {{ .num }} licenses are abnormal, please log in to the panel for details."
|
||||
SSHAndPanelLoginAlert: "Your 1Panel, abnormal panel {{ .name }} login from {{ .ip }}, please log in to the panel for details."
|
||||
LicenseExpirationAlert: "Your {{ .node }}{{ .ip }} Panel, the license will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
CronJobFailedAlert: "Your {{ .node }}{{ .ip }} Panel, scheduled task - {{ .name }} execution failed. Please log in to the panel for details."
|
||||
ClamAlert: "Your {{ .node }}{{ .ip }} Panel, the virus scan task detected {{ .num }} infected files. Please log in to the panel for details."
|
||||
WebSiteAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} websites will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
SSLAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} SSL certificates will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
DiskUsedAlert: "Your {{ .node }}{{ .ip }} Panel, disk {{ .name }} usage has reached {{ .used }}. Please log in to the panel for details."
|
||||
ResourceAlert: "Your {{ .node }}{{ .ip }} Panel, the average {{ .name }} usage rate in {{ .time }} minutes is {{ .used }}. Please log in to the panel for details."
|
||||
PanelVersionAlert: "Your {{ .node }}{{ .ip }} Panel, the latest panel version is available for upgrade. Please log in to the panel for details."
|
||||
PanelPwdExpirationAlert: "Your {{ .node }}{{ .ip }} Panel, the panel password will expire in {{ .day }} days. Please log in to the panel for details."
|
||||
CommonAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .msg }}. Please log in to the panel for details."
|
||||
NodeExceptionAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} nodes are abnormal. Please log in to the panel for details."
|
||||
LicenseExceptionAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .num }} licenses are abnormal. Please log in to the panel for details."
|
||||
SSHAndPanelLoginAlert: "Your {{ .node }}{{ .ip }} Panel, {{ .name }} login from {{ .loginIp }} is abnormal. Please log in to the panel for details."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Device {{ .name }} not found"
|
||||
@@ -526,4 +540,4 @@ PartitionDiskErr: "Failed to partition, {{ .err }}"
|
||||
FormatDiskErr: "Failed to format disk, {{ .err }}"
|
||||
MountDiskErr: "Failed to mount disk, {{ .err }}"
|
||||
UnMountDiskErr: "Failed to unmount disk, {{ .err }}"
|
||||
XfsNotFound: "xfs filesystem not detected, please install xfsprogs first"
|
||||
XfsNotFound: "xfs filesystem not detected, please install xfsprogs first"
|
||||
|
||||
+28
-14
@@ -38,6 +38,19 @@ ErrGroupIsDefault: 'Grupo predeterminado, no se puede eliminar'
|
||||
ErrGroupIsInWebsiteUse: 'El grupo está siendo usado por otro sitio web y no se puede eliminar.'
|
||||
Decrypt: "Descifrar"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: 'Esta cuenta está vinculada a un agente y no se puede eliminar. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentAccountUnavailable: 'La información de conexión de la cuenta no está disponible. Error: {{ .err }}. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentProviderNotSupported: 'Este proveedor de agente no es compatible. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentAccountRequired: 'Seleccione una cuenta de agente y vuelva a intentarlo.'
|
||||
ErrAgentAccountNotVerified: 'La cuenta no está verificada. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentProviderMismatch: 'El proveedor de la cuenta no coincide. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentBaseURLRequired: 'Base URL no puede estar vacío. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentApiKeyRequired: 'API Key no puede estar vacío. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentComposeRequired: 'El contenido personalizado de compose no puede estar vacío. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentIDRequired: 'El ID del agente no puede estar vacío. Verifique e inténtelo de nuevo!'
|
||||
ErrAgentAccountIDRequired: 'El ID de la cuenta no puede estar vacío. Verifique e inténtelo de nuevo!'
|
||||
|
||||
#backup
|
||||
ErrBackupInUsed: 'La cuenta de respaldo está siendo utilizada en una tarea programada y no se puede eliminar.'
|
||||
ErrBackupCheck: 'Error al probar la conexión de la cuenta de respaldo {{ .err }}'
|
||||
@@ -200,6 +213,7 @@ ErrRemoteExist: 'La base de datos remota ya existe con ese nombre, modifíquelo
|
||||
ErrLocalExist: 'El nombre ya existe en la base de datos local, modifíquelo e intente de nuevo'
|
||||
RemoteBackup: "Para hacer una copia de seguridad de la base de datos remota, primero debe iniciarse el servicio de base de datos del contenedor local utilizando la imagen {{ .name }}, espere por favor..."
|
||||
RemoteRecover: "Para restaurar la base de datos remota, primero debe iniciarse el servicio de base de datos del contenedor local utilizando la imagen {{ .name }}, espere por favor..."
|
||||
Arg: "Argumento"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'El tipo de archivo de recuperación no coincide con el método de persistencia actual, modifíquelo e intente'
|
||||
@@ -210,7 +224,7 @@ ErrObjectInUsed: "Este objeto está en uso y no se puede eliminar!"
|
||||
ErrObjectBeDependent: "Esta imagen es dependida por otras imágenes y no se puede eliminar!"
|
||||
ErrPortRules: 'El número de puerto no coincide, ingrese de nuevo'
|
||||
ErrPgImagePull: 'Tiempo de espera al descargar la imagen, configure la aceleración o descárguela manualmente ({{ .name }}) e intente de nuevo'
|
||||
PruneHelper: "Esta limpieza eliminó {{ .name }} {{ .count }} elementos, liberando {{ .size }} de espacio en disco"
|
||||
PruneHelper: "Esta limpieza {{ .name }} liberó espacio en disco {{ .size }}"
|
||||
ImageRemoveHelper: "Imagen {{ .name }} eliminada, liberando {{ .size }} de espacio en disco"
|
||||
BuildCache: "Caché de compilación"
|
||||
Volume: "Volumen de almacenamiento"
|
||||
@@ -495,10 +509,6 @@ ErrAlertPush: 'Error al enviar la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertSave: 'Error al guardar la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertSync: 'Error en la sincronización de la alerta, ¡revise e intente de nuevo!'
|
||||
ErrAlertRemote: 'Error remoto de alerta, ¡revise e intente de nuevo!'
|
||||
CommonAlert: "Su 1Panel: {{ .msg }}, por favor inicie sesión en el panel para más detalles."
|
||||
NodeExceptionAlert: "Su 1Panel tiene {{ .num }} nodos anómalos, inicie sesión para más detalles."
|
||||
LicenseExceptionAlert: "Su 1Panel tiene {{ .num }} licencias anómalas, inicie sesión para más detalles."
|
||||
SSHAndPanelLoginAlert: "Su 1Panel detectó un inicio de sesión anómalo en el panel {{ .name }} desde {{ .ip }}, revise en el panel para más detalles."
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "Ya hay una tarea de instalación en curso, espere a que termine"
|
||||
@@ -507,15 +517,19 @@ ErrInstallExtension: "Ya hay una tarea de instalación en curso, espere a que te
|
||||
PanelAlertTitle: "Notificación de alerta del panel"
|
||||
TestAlertTitle: "Correo de prueba - Verificar conectividad de correo"
|
||||
TestAlert: "Este es un correo de prueba para verificar que la configuración de envío de correos es correcta."
|
||||
LicenseExpirationAlert: "Su licencia de 1Panel expirará en {{ .day }} días. Inicie sesión para más detalles."
|
||||
CronJobFailedAlert: "Su tarea programada '{{ .name }}' ha fallado. Inicie sesión en el panel para más detalles."
|
||||
ClamAlert: "La tarea de escaneo de virus detectó {{ .num }} archivos infectados. Inicie sesión para detalles."
|
||||
WebSiteAlert: "Hay {{ .num }} sitios web en su 1Panel que expirarán en {{ .day }} días. Inicie sesión para más detalles."
|
||||
SSLAlert: "Hay {{ .num }} certificados SSL en su 1Panel que expirarán en {{ .day }} días. Inicie sesión para detalles."
|
||||
DiskUsedAlert: "El disco '{{ .name }}' de su 1Panel ha utilizado {{ .used }}. Inicie sesión para más detalles."
|
||||
ResourceAlert: "El uso promedio de {{ .name }} en {{ .time }} minutos es de {{ .used }}. Inicie sesión para más detalles."
|
||||
PanelVersionAlert: "Hay una nueva versión de 1Panel disponible. Inicie sesión para actualizar."
|
||||
PanelPwdExpirationAlert: "Su contraseña de 1Panel expirará en {{ .day }} días. Inicie sesión para más detalles."
|
||||
LicenseExpirationAlert: "Su Panel {{ .node }}{{ .ip }}, la licencia expirará en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
CronJobFailedAlert: "Su Panel {{ .node }}{{ .ip }}, la ejecución de la tarea programada {{ .name }} falló. Inicie sesión en el panel para ver los detalles."
|
||||
ClamAlert: "Su Panel {{ .node }}{{ .ip }}, la tarea de escaneo antivirus detectó {{ .num }} archivos infectados. Inicie sesión en el panel para ver los detalles."
|
||||
WebSiteAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} sitios web expirarán en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
SSLAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} certificados SSL expirarán en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
DiskUsedAlert: "Su Panel {{ .node }}{{ .ip }}, el uso del disco {{ .name }} ha alcanzado {{ .used }}. Inicie sesión en el panel para ver los detalles."
|
||||
ResourceAlert: "Su Panel {{ .node }}{{ .ip }}, la tasa de uso promedio de {{ .name }} en {{ .time }} minutos es {{ .used }}. Inicie sesión en el panel para ver los detalles."
|
||||
PanelVersionAlert: "Su Panel {{ .node }}{{ .ip }}, está disponible la última versión del panel para actualizar. Inicie sesión en el panel para ver los detalles."
|
||||
PanelPwdExpirationAlert: "Su Panel {{ .node }}{{ .ip }}, la contraseña del panel expirará en {{ .day }} días. Inicie sesión en el panel para ver los detalles."
|
||||
CommonAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .msg }}. Inicie sesión en el panel para ver los detalles."
|
||||
NodeExceptionAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} nodos son anómalos. Inicie sesión en el panel para ver los detalles."
|
||||
LicenseExceptionAlert: "Su Panel {{ .node }}{{ .ip }}, {{ .num }} licencias son anómalas. Inicie sesión en el panel para ver los detalles."
|
||||
SSHAndPanelLoginAlert: "Su Panel {{ .node }}{{ .ip }}, el inicio de sesión {{ .name }} desde {{ .loginIp }} es anómalo. Inicie sesión en el panel para ver los detalles."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Dispositivo {{ .name }} no encontrado"
|
||||
|
||||
+29
-15
@@ -37,6 +37,19 @@ ErrGroupIsDefault: 'デフォルト グループ、削除できません'
|
||||
ErrGroupIsInWebsiteUse: 'グループは別の Web サイトで使用されているため、削除できません。'
|
||||
Decrypt: "復号化"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: 'このアカウントはエージェントに紐付いているため削除できません。確認して再試行してください!'
|
||||
ErrAgentAccountUnavailable: 'アカウント接続情報を利用できません。エラー: {{ .err }}。確認して再試行してください!'
|
||||
ErrAgentProviderNotSupported: 'このエージェント提供元はサポートされていません。確認して再試行してください!'
|
||||
ErrAgentAccountRequired: 'エージェントアカウントを選択して再試行してください。'
|
||||
ErrAgentAccountNotVerified: 'アカウントの検証が完了していません。確認して再試行してください!'
|
||||
ErrAgentProviderMismatch: 'アカウントの提供元が一致しません。確認して再試行してください!'
|
||||
ErrAgentBaseURLRequired: 'Base URL を空にできません。確認して再試行してください!'
|
||||
ErrAgentApiKeyRequired: 'API Key を空にできません。確認して再試行してください!'
|
||||
ErrAgentComposeRequired: 'カスタム compose 内容を空にできません。確認して再試行してください!'
|
||||
ErrAgentIDRequired: 'エージェント ID を空にできません。確認して再試行してください!'
|
||||
ErrAgentAccountIDRequired: 'アカウント ID を空にできません。確認して再試行してください!'
|
||||
|
||||
#backup
|
||||
Localhost: 'ローカルマシン'
|
||||
ErrBackupInUsed: 'バックアップ アカウントはスケジュールされたタスクで使用されているため、削除できません。'
|
||||
@@ -200,6 +213,7 @@ ErrRemoteExist: 'この名前のリモート データベースは既に存在
|
||||
ErrLocalExist: '名前はローカル データベースに既に存在します。変更してもう一度お試しください'
|
||||
RemoteBackup: "リモートデータベースをバックアップするには、まずイメージ {{ .name }} を使用してローカルコンテナデータベースサービスを起動する必要があります。しばらくお待ちください..."
|
||||
RemoteRecover: "リモートデータベースを復元するには、まずイメージ {{ .name }} を使用してローカルコンテナデータベースサービスを起動する必要があります。しばらくお待ちください..."
|
||||
Arg: "引数"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'リカバリ ファイルの種類が現在の永続化方法と一致しません。変更して再試行してください'
|
||||
@@ -210,7 +224,7 @@ ErrObjectInUsed: "このオブジェクトは使用中であり、削除でき
|
||||
ErrObjectBeDependent: "このイメージは他のイメージに依存されているため、削除できません!"
|
||||
ErrPortRules: 'ポート番号が一致しません。再入力してください。'
|
||||
ErrPgImagePull: 'イメージのプルがタイムアウトしました。イメージのアクセラレーションを設定するか、{{ .name }} イメージを手動でプルして再試行してください'
|
||||
PruneHelper: "今回のクリーンアップで{{ .name }} {{ .count }}個を削除し、{{ .size }}のディスク領域を解放しました"
|
||||
PruneHelper: "今回のクリーンアップ {{ .name }} でディスク領域 {{ .size }} を解放しました"
|
||||
ImageRemoveHelper: "イメージ{{ .name }}を削除し、{{ .size }}のディスク領域を解放しました"
|
||||
BuildCache: "ビルドキャッシュ"
|
||||
Volume: "ストレージボリューム"
|
||||
@@ -504,19 +518,19 @@ ErrInstallExtension: "インストールタスクが進行中です、タスク
|
||||
PanelAlertTitle: "パネルアラート通知"
|
||||
TestAlertTitle: "テストメール - メール接続の確認"
|
||||
TestAlert: "これはテストメールです。メール送信設定が正しく構成されているかを確認します。"
|
||||
LicenseExpirationAlert: "お使いの 1Panel ライセンスは {{ .day }} 日後に有効期限が切れます。詳細はパネルにログインしてご確認ください。"
|
||||
CronJobFailedAlert: "1Panel のスケジュールタスク '{{ .name }}' の実行に失敗しました。詳細はパネルでご確認ください。"
|
||||
ClamAlert: "1Panel のウイルススキャンで {{ .num }} 件の感染ファイルが検出されました。詳細はパネルでご確認ください。"
|
||||
WebSiteAlert: "1Panel にある {{ .num }} 件のウェブサイトが {{ .day }} 日後に有効期限を迎えます。詳細はパネルでご確認ください。"
|
||||
SSLAlert: "1Panel にある {{ .num }} 枚のSSL証明書が {{ .day }} 日後に有効期限を迎えます。詳細はパネルでご確認ください。"
|
||||
DiskUsedAlert: "1Panel のディスク '{{ .name }}' は {{ .used }} 使用されています。詳細はパネルでご確認ください。"
|
||||
ResourceAlert: "1Panel の {{ .time }} 分間の平均 {{ .name }} 使用率は {{ .used }} です。詳細はパネルでご確認ください。"
|
||||
PanelVersionAlert: "1Panel に新しいバージョンが利用可能です。アップグレードはパネルから行ってください。"
|
||||
PanelPwdExpirationAlert: "1Panel のパスワードは {{ .day }} 日後に期限切れとなります。詳細はパネルでご確認ください。"
|
||||
CommonAlert: "お使いの1Panel、{{ .msg }}、詳細はパネルにログインしてご確認ください。"
|
||||
NodeExceptionAlert: "お使いの1Panel、{{ .num }}個のノードに異常があります。詳細はパネルにログインしてご確認ください。"
|
||||
LicenseExceptionAlert: "お使いの1Panel、{{ .num }}個のライセンスに異常があります。詳細はパネルにログインしてご確認ください。"
|
||||
SSHAndPanelLoginAlert: "お使いの1Panel、パネル{{ .name }}が{{ .ip }}から異常ログインしました。詳細はパネルにログインしてご確認ください。"
|
||||
LicenseExpirationAlert: "あなたの {{ .node }}{{ .ip }} パネル、ライセンスは {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
CronJobFailedAlert: "あなたの {{ .node }}{{ .ip }} パネル、スケジュールタスク {{ .name }} の実行に失敗しました。詳細はパネルにログインしてご確認ください。"
|
||||
ClamAlert: "あなたの {{ .node }}{{ .ip }} パネル、ウイルススキャンタスクで {{ .num }} 個の感染ファイルを検出しました。詳細はパネルにログインしてご確認ください。"
|
||||
WebSiteAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 個のウェブサイトが {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
SSLAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 枚のSSL証明書が {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
DiskUsedAlert: "あなたの {{ .node }}{{ .ip }} パネル、ディスク {{ .name }} の使用率が {{ .used }} に達しました。詳細はパネルにログインしてご確認ください。"
|
||||
ResourceAlert: "あなたの {{ .node }}{{ .ip }} パネル、過去 {{ .time }} 分間の {{ .name }} 平均使用率は {{ .used }} です。詳細はパネルにログインしてご確認ください。"
|
||||
PanelVersionAlert: "あなたの {{ .node }}{{ .ip }} パネル、最新バージョンがアップグレード可能です。詳細はパネルにログインしてご確認ください。"
|
||||
PanelPwdExpirationAlert: "あなたの {{ .node }}{{ .ip }} パネル、パネルパスワードは {{ .day }} 日後に期限切れになります。詳細はパネルにログインしてご確認ください。"
|
||||
CommonAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .msg }}。詳細はパネルにログインしてご確認ください。"
|
||||
NodeExceptionAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 個のノードに異常が発生しています。詳細はパネルにログインしてご確認ください。"
|
||||
LicenseExceptionAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .num }} 個のライセンスに異常が発生しています。詳細はパネルにログインしてご確認ください。"
|
||||
SSHAndPanelLoginAlert: "あなたの {{ .node }}{{ .ip }} パネル、{{ .loginIp }} からの {{ .name }} ログインに異常があります。詳細はパネルにログインしてご確認ください。"
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "デバイス {{ .name }} が見つかりません"
|
||||
@@ -525,4 +539,4 @@ PartitionDiskErr: "パーティションに失敗しました、{{ .err }}"
|
||||
FormatDiskErr: "ディスクのフォーマットに失敗しました、{{ .err }}"
|
||||
MountDiskErr: "ディスクのマウントに失敗しました、{{ .err }}"
|
||||
UnMountDiskErr: "ディスクのアンマウントに失敗しました、{{ .err }}"
|
||||
XfsNotFound: "xfs ファイルシステムが検出されませんでした、最初に xfsprogs をインストールしてください"
|
||||
XfsNotFound: "xfs ファイルシステムが検出されませんでした、最初に xfsprogs をインストールしてください"
|
||||
|
||||
+29
-15
@@ -38,6 +38,19 @@ ErrGroupIsDefault: '기본 그룹, 삭제할 수 없습니다'
|
||||
ErrGroupIsInWebsiteUse: '그룹이 다른 웹사이트에서 사용 중이므로 삭제할 수 없습니다.'
|
||||
Decrypt: "복호화"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: '이 계정은 에이전트에 바인딩되어 있어 삭제할 수 없습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentAccountUnavailable: '계정 연결 정보를 사용할 수 없습니다. 오류: {{ .err }}. 확인 후 다시 시도하세요!'
|
||||
ErrAgentProviderNotSupported: '이 에이전트 제공자는 지원되지 않습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentAccountRequired: '에이전트 계정을 선택한 후 다시 시도하세요.'
|
||||
ErrAgentAccountNotVerified: '계정이 검증되지 않았습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentProviderMismatch: '계정 제공자가 일치하지 않습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentBaseURLRequired: 'Base URL은 비워 둘 수 없습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentApiKeyRequired: 'API Key는 비워 둘 수 없습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentComposeRequired: '사용자 정의 compose 내용은 비워 둘 수 없습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentIDRequired: '에이전트 ID는 비워 둘 수 없습니다. 확인 후 다시 시도하세요!'
|
||||
ErrAgentAccountIDRequired: '계정 ID는 비워 둘 수 없습니다. 확인 후 다시 시도하세요!'
|
||||
|
||||
#지원
|
||||
Localhost: '로컬 머신'
|
||||
ErrBackupInUsed: '백업 계정이 예약된 작업에 사용되었으므로 삭제할 수 없습니다.'
|
||||
@@ -201,6 +214,7 @@ ErrRemoteExist: '이 이름을 가진 원격 데이터베이스가 이미 존재
|
||||
ErrLocalExist: '이름이 로컬 데이터베이스에 이미 존재합니다. 이름을 수정하고 다시 시도하세요'
|
||||
RemoteBackup: "원격 데이터베이스를 백업하려면 먼저 이미지 {{ .name }}을(를) 사용하여 로컬 컨테이너 데이터베이스 서비스를 시작해야 합니다. 잠시만 기다려 주세요..."
|
||||
RemoteRecover: "원격 데이터베이스를 복원하려면 먼저 이미지 {{ .name }}을(를) 사용하여 로컬 컨테이너 데이터베이스 서비스를 시작해야 합니다. 잠시만 기다려 주세요..."
|
||||
Arg: "인수"
|
||||
|
||||
#레디스
|
||||
ErrTypeOfRedis: '복구 파일 유형이 현재 지속성 방법과 일치하지 않습니다. 수정하고 다시 시도하세요'
|
||||
@@ -211,7 +225,7 @@ ErrObjectInUsed: "이 객체는 사용 중이어서 삭제할 수 없습니다!"
|
||||
ErrObjectBeDependent: "이 이미지는 다른 이미지에 의존되어 있어 삭제할 수 없습니다!"
|
||||
ErrPortRules: '포트 번호가 일치하지 않습니다. 다시 입력하세요!'
|
||||
ErrPgImagePull: '이미지 풀링 시간이 초과되었습니다. 이미지 가속을 구성하거나 {{ .name }} 이미지를 수동으로 풀링한 다음 다시 시도하세요.'
|
||||
PruneHelper: "이번 정리에서 {{ .name }} {{ .count }}개를 제거하여 {{ .size }} 디스크 공간을 확보했습니다"
|
||||
PruneHelper: "이번 정리 {{ .name }}가 디스크 공간 {{ .size }}을(를) 확보했습니다"
|
||||
ImageRemoveHelper: "이미지 {{ .name }} 삭제, {{ .size }} 디스크 공간 확보"
|
||||
BuildCache: "빌드 캐시"
|
||||
Volume: "스토리지 볼륨"
|
||||
@@ -505,19 +519,19 @@ ErrInstallExtension: "이미 설치 작업이 진행 중입니다. 작업이 완
|
||||
PanelAlertTitle: "패널 알림 통지"
|
||||
TestAlertTitle: "테스트 이메일 - 이메일 연결 확인"
|
||||
TestAlert: "이것은 테스트 이메일이며 이메일 발송 설정이 올바른지 확인합니다."
|
||||
LicenseExpirationAlert: "귀하의 1Panel 라이선스는 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하세요."
|
||||
CronJobFailedAlert: "1Panel 예약 작업 '{{ .name }}' 실행에 실패했습니다. 자세한 내용은 패널에서 확인하세요."
|
||||
ClamAlert: "1Panel 바이러스 검사에서 {{ .num }}개의 감염된 파일이 발견되었습니다. 자세한 내용은 패널에서 확인하세요."
|
||||
WebSiteAlert: "1Panel 에 있는 {{ .num }}개의 웹사이트가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||
SSLAlert: "1Panel 에 있는 {{ .num }}개의 SSL 인증서가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||
DiskUsedAlert: "1Panel 디스크 '{{ .name }}'의 사용량은 {{ .used }}입니다. 자세한 내용은 패널에서 확인하세요."
|
||||
ResourceAlert: "1Panel 의 평균 {{ .time }}분 동안 {{ .name }} 사용률은 {{ .used }}입니다. 자세한 내용은 패널에서 확인하세요."
|
||||
PanelVersionAlert: "1Panel 의 새로운 버전이 이용 가능합니다. 패널에 로그인하여 업그레이드하세요."
|
||||
PanelPwdExpirationAlert: "1Panel 비밀번호가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에서 확인하세요."
|
||||
CommonAlert: "귀하의 1Panel, {{ .msg }}. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
NodeExceptionAlert: "귀하의 1Panel, {{ .num }}개의 노드에 이상이 있습니다. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
LicenseExceptionAlert: "귀하의 1Panel, {{ .num }}개의 라이선스에 이상이 있습니다. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
SSHAndPanelLoginAlert: "귀하의 1Panel, 패널 {{ .name }}이(가) {{ .ip }}에서 비정상 로그인했습니다. 자세한 내용은 패널에 로그인하여 확인하세요."
|
||||
LicenseExpirationAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 라이센스가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
CronJobFailedAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 예약 작업 {{ .name }} 실행에 실패했습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
ClamAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 바이러스 스캔 작업에서 {{ .num }}개의 감염 파일이 감지되었습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
WebSiteAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 웹사이트가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
SSLAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 SSL 인증서가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
DiskUsedAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 디스크 {{ .name }} 사용률이 {{ .used }}에 도달했습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
ResourceAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 최근 {{ .time }}분간 {{ .name }} 평균 사용률은 {{ .used }}입니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
PanelVersionAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 최신 버전으로 업그레이드할 수 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
PanelPwdExpirationAlert: "귀하의 {{ .node }}{{ .ip }} 패널, 패널 비밀번호가 {{ .day }}일 후에 만료됩니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
CommonAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .msg }}。자세한 내용은 패널에 로그인하십시오."
|
||||
NodeExceptionAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 노드에 이상이 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
LicenseExceptionAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .num }}개의 라이센스에 이상이 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
SSHAndPanelLoginAlert: "귀하의 {{ .node }}{{ .ip }} 패널, {{ .loginIp }}에서의 {{ .name }} 로그인에 이상이 있습니다. 자세한 내용은 패널에 로그인하십시오."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "장치 {{ .name }} 을(를) 찾을 수 없습니다"
|
||||
@@ -526,4 +540,4 @@ PartitionDiskErr: "파티션 분할에 실패했습니다, {{ .err }}"
|
||||
FormatDiskErr: "디스크 포맷에 실패했습니다, {{ .err }}"
|
||||
MountDiskErr: "디스크 마운트에 실패했습니다, {{ .err }}"
|
||||
UnMountDiskErr: "디스크 마운트 해제에 실패했습니다, {{ .err }}"
|
||||
XfsNotFound: "xfs 파일 시스템이 감지되지 않았습니다, 먼저 xfsprogs 를 설치하세요"
|
||||
XfsNotFound: "xfs 파일 시스템이 감지되지 않았습니다, 먼저 xfsprogs 를 설치하세요"
|
||||
|
||||
+29
-15
@@ -41,6 +41,19 @@ ErrGroupIsDefault: 'Kumpulan lalai, tidak boleh dipadamkan'
|
||||
ErrGroupIsInWebsiteUse: 'Kumpulan sedang digunakan oleh tapak web lain dan tidak boleh dipadamkan.'
|
||||
Decrypt: "Dekripsi"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: 'Akaun ini telah dipautkan kepada ejen dan tidak boleh dipadam. Sila semak dan cuba lagi!'
|
||||
ErrAgentAccountUnavailable: 'Maklumat sambungan akaun tidak tersedia. Ralat: {{ .err }}. Sila semak dan cuba lagi!'
|
||||
ErrAgentProviderNotSupported: 'Penyedia ejen ini tidak disokong. Sila semak dan cuba lagi!'
|
||||
ErrAgentAccountRequired: 'Sila pilih akaun ejen dan cuba lagi.'
|
||||
ErrAgentAccountNotVerified: 'Akaun belum disahkan. Sila semak dan cuba lagi!'
|
||||
ErrAgentProviderMismatch: 'Penyedia akaun tidak sepadan. Sila semak dan cuba lagi!'
|
||||
ErrAgentBaseURLRequired: 'Base URL tidak boleh kosong. Sila semak dan cuba lagi!'
|
||||
ErrAgentApiKeyRequired: 'API Key tidak boleh kosong. Sila semak dan cuba lagi!'
|
||||
ErrAgentComposeRequired: 'Kandungan compose tersuai tidak boleh kosong. Sila semak dan cuba lagi!'
|
||||
ErrAgentIDRequired: 'ID ejen tidak boleh kosong. Sila semak dan cuba lagi!'
|
||||
ErrAgentAccountIDRequired: 'ID akaun tidak boleh kosong. Sila semak dan cuba lagi!'
|
||||
|
||||
#sandaran
|
||||
Localhost: 'Mesin Tempatan'
|
||||
ErrBackupInUsed: 'Akaun sandaran telah digunakan dalam tugas yang dijadualkan dan tidak boleh dipadamkan.'
|
||||
@@ -201,6 +214,7 @@ ErrRemoteExist: 'Pangkalan data jauh sudah wujud dengan nama ini, sila ubah suai
|
||||
ErrLocalExist: 'Nama sudah wujud dalam pangkalan data tempatan, sila ubah suai dan cuba lagi'
|
||||
RemoteBackup: "Untuk menyandarkan pangkalan data jauh, perkhidmatan pangkalan data bekas tempatan perlu dimulakan terlebih dahulu menggunakan imej {{ .name }}, sila tunggu..."
|
||||
RemoteRecover: "Untuk memulihkan pangkalan data jauh, perkhidmatan pangkalan data bekas tempatan perlu dimulakan terlebih dahulu menggunakan imej {{ .name }}, sila tunggu..."
|
||||
Arg: "Hujah"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'Jenis fail pemulihan tidak sepadan dengan kaedah kegigihan semasa, sila ubah suai dan cuba lagi'
|
||||
@@ -211,7 +225,7 @@ ErrObjectInUsed: "Objek ini sedang digunakan dan tidak boleh dipadam!"
|
||||
ErrObjectBeDependent: "Imej ini digantungkan oleh imej lain dan tidak boleh dipadam!"
|
||||
ErrPortRules: 'Nombor port tidak sepadan, sila masukkan semula!'
|
||||
ErrPgImagePull: 'Tarikh imej tamat masa, sila konfigurasikan pecutan imej atau tarik imej {{ .name }} secara manual dan cuba lagi'
|
||||
PruneHelper: "Pembersihan ini membuang {{ .name }} {{ .count }} item, membebaskan {{ .size }} ruang cakera"
|
||||
PruneHelper: "Pembersihan ini {{ .name }} membebaskan ruang cakera {{ .size }}"
|
||||
ImageRemoveHelper: "Padam imej {{ .name }}, membebaskan {{ .size }} ruang cakera"
|
||||
BuildCache: "Cache binaan"
|
||||
Volume: "Jilid storan"
|
||||
@@ -505,19 +519,19 @@ ErrInstallExtension: "Tugas pemasangan sudah sedang berjalan, silakan tunggu tug
|
||||
PanelAlertTitle: "Notifikasi Amaran Panel"
|
||||
TestAlertTitle: "E-mel Ujian - Sahkan Sambungan E-mel"
|
||||
TestAlert: "Ini adalah e-mel ujian untuk mengesahkan konfigurasi penghantaran e-mel anda betul."
|
||||
LicenseExpirationAlert: "Lesen 1Panel anda akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
CronJobFailedAlert: "Tugas berjadual 1Panel '{{ .name }}' gagal dilaksanakan. Sila log masuk ke panel untuk butiran lanjut."
|
||||
ClamAlert: "Tugas imbasan virus 1Panel menemui {{ .num }} fail yang dijangkiti. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
WebSiteAlert: "Terdapat {{ .num }} laman web dalam 1Panel anda yang akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
SSLAlert: "Terdapat {{ .num }} sijil SSL dalam 1Panel anda yang akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
DiskUsedAlert: "Cakera '{{ .name }}' dalam 1Panel anda telah menggunakan {{ .used }}. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
ResourceAlert: "Penggunaan purata {{ .name }} selama {{ .time }} minit dalam 1Panel anda ialah {{ .used }}. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
PanelVersionAlert: "Versi baru 1Panel tersedia. Sila log masuk ke panel untuk menaik taraf."
|
||||
PanelPwdExpirationAlert: "Kata laluan 1Panel anda akan tamat dalam {{ .day }} hari. Sila log masuk ke panel untuk maklumat lanjut."
|
||||
CommonAlert: "1Panel anda, {{ .msg }}, sila log masuk ke panel untuk maklumat lanjut."
|
||||
NodeExceptionAlert: "1Panel anda, {{ .num }} nod bermasalah, sila log masuk ke panel untuk maklumat lanjut."
|
||||
LicenseExceptionAlert: "1Panel anda, {{ .num }} lesen bermasalah, sila log masuk ke panel untuk maklumat lanjut."
|
||||
SSHAndPanelLoginAlert: "1Panel anda, log masuk panel {{ .name }} yang tidak normal dari {{ .ip }}, sila log masuk ke panel untuk maklumat lanjut."
|
||||
LicenseExpirationAlert: "Panel {{ .node }}{{ .ip }} Anda, lesen akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
CronJobFailedAlert: "Panel {{ .node }}{{ .ip }} Anda, tugas jadual {{ .name }} gagal dilaksanakan. Sila log masuk ke panel untuk butiran lanjut."
|
||||
ClamAlert: "Panel {{ .node }}{{ .ip }} Anda, tugas imbasan virus mengesan {{ .num }} fail yang dijangkiti. Sila log masuk ke panel untuk butiran lanjut."
|
||||
WebSiteAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} laman web akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
SSLAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} sijil SSL akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
DiskUsedAlert: "Panel {{ .node }}{{ .ip }} Anda, penggunaan cakera {{ .name }} telah mencapai {{ .used }}. Sila log masuk ke panel untuk butiran lanjut."
|
||||
ResourceAlert: "Panel {{ .node }}{{ .ip }} Anda, kadar penggunaan purata {{ .name }} dalam tempoh {{ .time }} minit ialah {{ .used }}. Sila log masuk ke panel untuk butiran lanjut."
|
||||
PanelVersionAlert: "Panel {{ .node }}{{ .ip }} Anda, versi panel terkini tersedia untuk dinaik taraf. Sila log masuk ke panel untuk butiran lanjut."
|
||||
PanelPwdExpirationAlert: "Panel {{ .node }}{{ .ip }} Anda, kata laluan panel akan tamat tempoh dalam {{ .day }} hari. Sila log masuk ke panel untuk butiran lanjut."
|
||||
CommonAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .msg }}. Sila log masuk ke panel untuk butiran lanjut."
|
||||
NodeExceptionAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} nod tidak normal. Sila log masuk ke panel untuk butiran lanjut."
|
||||
LicenseExceptionAlert: "Panel {{ .node }}{{ .ip }} Anda, {{ .num }} lesen tidak normal. Sila log masuk ke panel untuk butiran lanjut."
|
||||
SSHAndPanelLoginAlert: "Panel {{ .node }}{{ .ip }} Anda, log masuk {{ .name }} dari {{ .loginIp }} tidak normal. Sila log masuk ke panel untuk butiran lanjut."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Peranti {{ .name }} tidak ditemui"
|
||||
@@ -526,4 +540,4 @@ PartitionDiskErr: "Gagal membahagikan, {{ .err }}"
|
||||
FormatDiskErr: "Gagal memformat cakera, {{ .err }}"
|
||||
MountDiskErr: "Gagal mengkaitkan cakera, {{ .err }}"
|
||||
UnMountDiskErr: "Gagal nyahkaitkan cakera, {{ .err }}"
|
||||
XfsNotFound: "Sistem fail xfs tidak dikesan, sila pasang xfsprogs terlebih dahulu"
|
||||
XfsNotFound: "Sistem fail xfs tidak dikesan, sila pasang xfsprogs terlebih dahulu"
|
||||
|
||||
+29
-15
@@ -41,6 +41,19 @@ ErrGroupIsDefault: 'Grupo padrão, não pode ser excluído'
|
||||
ErrGroupIsInWebsiteUse: 'O grupo está sendo usado por outro site e não pode ser excluído.'
|
||||
Decrypt: "Descriptografar"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: 'Esta conta está vinculada a um agente e não pode ser excluída. Verifique e tente novamente!'
|
||||
ErrAgentAccountUnavailable: 'As informações de conexão da conta não estão disponíveis. Erro: {{ .err }}. Verifique e tente novamente!'
|
||||
ErrAgentProviderNotSupported: 'Este provedor de agente não é suportado. Verifique e tente novamente!'
|
||||
ErrAgentAccountRequired: 'Selecione uma conta de agente e tente novamente.'
|
||||
ErrAgentAccountNotVerified: 'A conta não foi verificada. Verifique e tente novamente!'
|
||||
ErrAgentProviderMismatch: 'O provedor da conta não corresponde. Verifique e tente novamente!'
|
||||
ErrAgentBaseURLRequired: 'Base URL não pode estar vazio. Verifique e tente novamente!'
|
||||
ErrAgentApiKeyRequired: 'API Key não pode estar vazio. Verifique e tente novamente!'
|
||||
ErrAgentComposeRequired: 'O conteúdo personalizado do compose não pode estar vazio. Verifique e tente novamente!'
|
||||
ErrAgentIDRequired: 'ID do agente não pode estar vazio. Verifique e tente novamente!'
|
||||
ErrAgentAccountIDRequired: 'ID da conta não pode estar vazio. Verifique e tente novamente!'
|
||||
|
||||
#backup
|
||||
Localhost: 'Máquina Local'
|
||||
ErrBackupInUsed: 'A conta de backup foi usada na tarefa agendada e não pode ser excluída.'
|
||||
@@ -201,6 +214,7 @@ ErrRemoteExist: 'O banco de dados remoto já existe com este nome, modifique-o e
|
||||
ErrLocalExist: 'O nome já existe no banco de dados local, modifique-o e tente novamente'
|
||||
RemoteBackup: "Para fazer backup do banco de dados remoto, o serviço de banco de dados do contêiner local precisa ser iniciado primeiro usando a imagem {{ .name }}, por favor aguarde..."
|
||||
RemoteRecover: "Para restaurar o banco de dados remoto, o serviço de banco de dados do contêiner local precisa ser iniciado primeiro usando a imagem {{ .name }}, por favor aguarde..."
|
||||
Arg: "Argumento"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'O tipo de arquivo de recuperação não corresponde ao método de persistência atual, modifique-o e tente novamente'
|
||||
@@ -211,7 +225,7 @@ ErrObjectInUsed: "Este objeto está em uso e não pode ser excluído!"
|
||||
ErrObjectBeDependent: "Esta imagem é dependida por outras imagens e não pode ser excluída!"
|
||||
ErrPortRules: 'O número da porta não corresponde, digite novamente!'
|
||||
ErrPgImagePull: 'Tempo limite para extração de imagem. Configure a aceleração de imagem ou extraia manualmente a imagem {{ .name }} e tente novamente'
|
||||
PruneHelper: "Esta limpeza removeu {{ .name }} {{ .count }} itens, liberando {{ .size }} de espaço em disco"
|
||||
PruneHelper: "Esta limpeza {{ .name }} liberou espaço em disco {{ .size }}"
|
||||
ImageRemoveHelper: "Excluída a imagem {{ .name }}, liberando {{ .size }} de espaço em disco"
|
||||
BuildCache: "Cache de construção"
|
||||
Volume: "Volume de armazenamento"
|
||||
@@ -505,19 +519,19 @@ ErrInstallExtension: "Já existe uma tarefa de instalação em andamento, aguard
|
||||
PanelAlertTitle: "Notificação de Alerta do Painel"
|
||||
TestAlertTitle: "E-mail de Teste - Verificar Conectividade de E-mail"
|
||||
TestAlert: "Este é um e-mail de teste para verificar se sua configuração de envio de e-mails está correta."
|
||||
LicenseExpirationAlert: "A licença do seu 1Panel expirará em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
CronJobFailedAlert: "A tarefa agendada '{{ .name }}' do seu 1Panel falhou. Acesse o painel para mais detalhes."
|
||||
ClamAlert: "A verificação de vírus do 1Panel detectou {{ .num }} arquivos infectados. Acesse o painel para mais detalhes."
|
||||
WebSiteAlert: "{{ .num }} sites do seu 1Panel expirarão em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
SSLAlert: "{{ .num }} certificados SSL do seu 1Panel expirarão em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
DiskUsedAlert: "O disco '{{ .name }}' do seu 1Panel está com uso de {{ .used }}. Acesse o painel para mais detalhes."
|
||||
ResourceAlert: "O uso médio de {{ .name }} em {{ .time }} minutos no seu 1Panel é de {{ .used }}. Acesse o painel para mais detalhes."
|
||||
PanelVersionAlert: "Uma nova versão do 1Panel está disponível. Acesse o painel para atualizá-lo."
|
||||
PanelPwdExpirationAlert: "A senha do 1Panel expirará em {{ .day }} dias. Acesse o painel para mais detalhes."
|
||||
CommonAlert: "Seu 1Panel, {{ .msg }}. Para mais detalhes, faça login no painel."
|
||||
NodeExceptionAlert: "Seu 1Panel, {{ .num }} nós estão com problemas. Para mais detalhes, faça login no painel."
|
||||
LicenseExceptionAlert: "Seu 1Panel, {{ .num }} licenças estão com problemas. Para mais detalhes, faça login no painel."
|
||||
SSHAndPanelLoginAlert: "Seu 1Panel, login anormal no painel {{ .name }} a partir de {{ .ip }}. Para mais detalhes, faça login no painel."
|
||||
LicenseExpirationAlert: "Seu Painel {{ .node }}{{ .ip }}, a licença expirará em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
CronJobFailedAlert: "Seu Painel {{ .node }}{{ .ip }}, a execução da tarefa agendada {{ .name }} falhou. Faça login no painel para obter detalhes."
|
||||
ClamAlert: "Seu Painel {{ .node }}{{ .ip }}, a tarefa de verificação de vírus detectou {{ .num }} arquivos infectados. Faça login no painel para obter detalhes."
|
||||
WebSiteAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} sites expirarão em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
SSLAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} certificados SSL expirarão em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
DiskUsedAlert: "Seu Painel {{ .node }}{{ .ip }}, o uso do disco {{ .name }} atingiu {{ .used }}. Faça login no painel para obter detalhes."
|
||||
ResourceAlert: "Seu Painel {{ .node }}{{ .ip }}, a taxa de uso médio do {{ .name }} nos últimos {{ .time }} minutos é {{ .used }}. Faça login no painel para obter detalhes."
|
||||
PanelVersionAlert: "Seu Painel {{ .node }}{{ .ip }}, a versão mais recente do painel está disponível para atualização. Faça login no painel para obter detalhes."
|
||||
PanelPwdExpirationAlert: "Seu Painel {{ .node }}{{ .ip }}, a senha do painel expirará em {{ .day }} dias. Faça login no painel para obter detalhes."
|
||||
CommonAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .msg }}. Faça login no painel para obter detalhes."
|
||||
NodeExceptionAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} nós estão anormais. Faça login no painel para obter detalhes."
|
||||
LicenseExceptionAlert: "Seu Painel {{ .node }}{{ .ip }}, {{ .num }} licenças estão anormais. Faça login no painel para obter detalhes."
|
||||
SSHAndPanelLoginAlert: "Seu Painel {{ .node }}{{ .ip }}, o login {{ .name }} a partir de {{ .loginIp }} é anormal. Faça login no painel para obter detalhes."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Dispositivo {{ .name }} não encontrado"
|
||||
@@ -526,4 +540,4 @@ PartitionDiskErr: "Falha ao particionar, {{ .err }}"
|
||||
FormatDiskErr: "Falha ao formatar disco, {{ .err }}"
|
||||
MountDiskErr: "Falha ao montar disco, {{ .err }}"
|
||||
UnMountDiskErr: "Falha ao desmontar disco, {{ .err }}"
|
||||
XfsNotFound: "Sistema de arquivos xfs não detectado, por favor instale xfsprogs primeiro"
|
||||
XfsNotFound: "Sistema de arquivos xfs não detectado, por favor instale xfsprogs primeiro"
|
||||
|
||||
+29
-15
@@ -41,6 +41,19 @@ ErrGroupIsDefault: 'Группа по умолчанию, не может быт
|
||||
ErrGroupIsInWebsiteUse: 'Группа используется другим веб-сайтом и не может быть удалена.'
|
||||
Decrypt: "Расшифровать"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: 'Эта учетная запись привязана к агенту и не может быть удалена. Проверьте и повторите попытку!'
|
||||
ErrAgentAccountUnavailable: 'Информация о подключении учетной записи недоступна. Ошибка: {{ .err }}. Проверьте и повторите попытку!'
|
||||
ErrAgentProviderNotSupported: 'Этот провайдер агента не поддерживается. Проверьте и повторите попытку!'
|
||||
ErrAgentAccountRequired: 'Выберите учетную запись агента и повторите попытку.'
|
||||
ErrAgentAccountNotVerified: 'Учетная запись не прошла проверку. Проверьте и повторите попытку!'
|
||||
ErrAgentProviderMismatch: 'Провайдер учетной записи не совпадает. Проверьте и повторите попытку!'
|
||||
ErrAgentBaseURLRequired: 'Base URL не может быть пустым. Проверьте и повторите попытку!'
|
||||
ErrAgentApiKeyRequired: 'API Key не может быть пустым. Проверьте и повторите попытку!'
|
||||
ErrAgentComposeRequired: 'Пользовательское содержимое compose не может быть пустым. Проверьте и повторите попытку!'
|
||||
ErrAgentIDRequired: 'ID агента не может быть пустым. Проверьте и повторите попытку!'
|
||||
ErrAgentAccountIDRequired: 'ID учетной записи не может быть пустым. Проверьте и повторите попытку!'
|
||||
|
||||
#резервное копирование
|
||||
Localhost: 'Локальная машина'
|
||||
ErrBackupInUsed: 'Учетная запись резервного копирования использовалась в запланированной задаче и не может быть удалена.'
|
||||
@@ -201,6 +214,7 @@ ErrRemoteExist: 'Удаленная база данных с таким имен
|
||||
ErrLocalExist: 'Имя уже существует в локальной базе данных, измените его и повторите попытку'
|
||||
RemoteBackup: "Для резервного копирования удаленной базы данных необходимо сначала запустить службу базы данных локального контейнера с помощью образа {{ .name }}, пожалуйста, подождите..."
|
||||
RemoteRecover: "Для восстановления удаленной базы данных необходимо сначала запустить службу базы данных локального контейнера с помощью образа {{ .name }}, пожалуйста, подождите..."
|
||||
Arg: "Аргумент"
|
||||
|
||||
#редис
|
||||
ErrTypeOfRedis: 'Тип файла восстановления не соответствует текущему методу сохранения. Измените его и повторите попытку'
|
||||
@@ -211,7 +225,7 @@ ErrObjectInUsed: "Этот объект используется и не мож
|
||||
ErrObjectBeDependent: "Этот образ зависит от других образов и не может быть удален!"
|
||||
ErrPortRules: 'Номер порта не совпадает, введите заново!'
|
||||
ErrPgImagePull: 'Время извлечения изображения истекло. Настройте ускорение изображения или вручную извлеките изображение {{ .name }} и повторите попытку'
|
||||
PruneHelper: "Очистка удалила {{ .name }} в количестве {{ .count }}, освободив {{ .size }} дискового пространства"
|
||||
PruneHelper: "Эта очистка {{ .name }} освободила дисковое пространство {{ .size }}"
|
||||
ImageRemoveHelper: "Удалён образ {{ .name }}, освобождено {{ .size }} дискового пространства"
|
||||
BuildCache: "Кэш сборки"
|
||||
Volume: "Том хранилища"
|
||||
@@ -505,19 +519,19 @@ ErrInstallExtension: "Уже выполняется задача установ
|
||||
PanelAlertTitle: "Уведомление панели"
|
||||
TestAlertTitle: "Тестовое письмо - проверка подключения"
|
||||
TestAlert: "Это тестовое письмо для проверки правильности настройки отправки писем."
|
||||
LicenseExpirationAlert: "Срок действия лицензии на 1Panel истекает через {{ .day }} дней. Подробности смотрите в панели."
|
||||
CronJobFailedAlert: "Запланированное задание '{{ .name }}' на вашем 1Panel завершилось с ошибкой. Подробности в панели."
|
||||
ClamAlert: "Антивирусная проверка 1Panel обнаружила {{ .num }} заражённых файлов. Подробности смотрите в панели."
|
||||
WebSiteAlert: "На вашем 1Panel {{ .num }} веб-сайтов истекают через {{ .day }} дней. Подробности смотрите в панели."
|
||||
SSLAlert: "На вашем 1Panel {{ .num }} SSL-сертификатов истекают через {{ .day }} дней. Подробности смотрите в панели."
|
||||
DiskUsedAlert: "Диск '{{ .name }}' на вашем 1Panel использует {{ .used }}. Подробности смотрите в панели."
|
||||
ResourceAlert: "Средняя загрузка {{ .name }} за {{ .time }} минут составляет {{ .used }}. Подробности смотрите в панели."
|
||||
PanelVersionAlert: "Доступна новая версия 1Panel. Обновитесь через панель."
|
||||
PanelPwdExpirationAlert: "Пароль для 1Panel истекает через {{ .day }} дней. Подробности смотрите в панели."
|
||||
CommonAlert: "Ваш 1Panel, {{ .msg }}. Подробности смотрите, войдя в панель."
|
||||
NodeExceptionAlert: "Ваш 1Panel, {{ .num }} узлов работают неправильно. Подробности смотрите, войдя в панель."
|
||||
LicenseExceptionAlert: "Ваш 1Panel, {{ .num }} лицензий работают неправильно. Подробности смотрите, войдя в панель."
|
||||
SSHAndPanelLoginAlert: "Ваш 1Panel, обнаружен аномальный вход в панель {{ .name }} с {{ .ip }}. Подробности смотрите, войдя в панель."
|
||||
LicenseExpirationAlert: "Ваш панель {{ .node }}{{ .ip }}, лицензия истечет через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
CronJobFailedAlert: "Ваш панель {{ .node }}{{ .ip }}, выполнение запланированной задачи {{ .name }} не удалось. Войдите в панель для получения деталей."
|
||||
ClamAlert: "Ваш панель {{ .node }}{{ .ip }}, задача сканирования на вирусы обнаружила {{ .num }} зараженных файлов. Войдите в панель для получения деталей."
|
||||
WebSiteAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} веб-сайтов истечут через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
SSLAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} сертификатов SSL истечут через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
DiskUsedAlert: "Ваш панель {{ .node }}{{ .ip }}, использование диска {{ .name }} достигло {{ .used }}. Войдите в панель для получения деталей."
|
||||
ResourceAlert: "Ваш панель {{ .node }}{{ .ip }}, средний уровень использования {{ .name }} за {{ .time }} минут составляет {{ .used }}. Войдите в панель для получения деталей."
|
||||
PanelVersionAlert: "Ваш панель {{ .node }}{{ .ip }}, доступна последняя версия панели для обновления. Войдите в панель для получения деталей."
|
||||
PanelPwdExpirationAlert: "Ваш панель {{ .node }}{{ .ip }}, пароль панели истечет через {{ .day }} дней. Войдите в панель для получения деталей."
|
||||
CommonAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .msg }}. Войдите в панель для получения деталей."
|
||||
NodeExceptionAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} узлов работают с ошибками. Войдите в панель для получения деталей."
|
||||
LicenseExceptionAlert: "Ваш панель {{ .node }}{{ .ip }}, {{ .num }} лицензий имеют ошибки. Войдите в панель для получения деталей."
|
||||
SSHAndPanelLoginAlert: "Ваш панель {{ .node }}{{ .ip }}, вход {{ .name }} с адреса {{ .loginIp }} является аномальным. Войдите в панель для получения деталей."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Устройство {{ .name }} не найдено"
|
||||
@@ -526,4 +540,4 @@ PartitionDiskErr: "Не удалось разделить, {{ .err }}"
|
||||
FormatDiskErr: "Не удалось отформатировать диск, {{ .err }}"
|
||||
MountDiskErr: "Не удалось подключить диск, {{ .err }}"
|
||||
UnMountDiskErr: "Не удалось отключить диск, {{ .err }}"
|
||||
XfsNotFound: "Файловая система xfs не обнаружена, сначала установите xfsprogs"
|
||||
XfsNotFound: "Файловая система xfs не обнаружена, сначала установите xfsprogs"
|
||||
|
||||
+28
-14
@@ -41,6 +41,19 @@ ErrGroupIsDefault: 'Varsayılan grup, silinemez'
|
||||
ErrGroupIsInWebsiteUse: 'Grup başka bir web sitesi tarafından kullanılıyor ve silinemez.'
|
||||
Decrypt: "Şifre Çöz"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: 'Bu hesap bir ajana bağlı ve silinemez. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentAccountUnavailable: 'Hesap bağlantı bilgileri kullanılamıyor. Hata: {{ .err }}. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentProviderNotSupported: 'Bu ajan sağlayıcısı desteklenmiyor. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentAccountRequired: 'Lütfen bir ajan hesabı seçip tekrar deneyin.'
|
||||
ErrAgentAccountNotVerified: 'Hesap doğrulanmadı. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentProviderMismatch: 'Hesap sağlayıcısı eşleşmiyor. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentBaseURLRequired: 'Base URL boş olamaz. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentApiKeyRequired: 'API Key boş olamaz. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentComposeRequired: 'Özel compose içeriği boş olamaz. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentIDRequired: 'Ajan ID boş olamaz. Kontrol edip tekrar deneyin!'
|
||||
ErrAgentAccountIDRequired: 'Hesap ID boş olamaz. Kontrol edip tekrar deneyin!'
|
||||
|
||||
#backup
|
||||
Localhost: 'Yerel Makine'
|
||||
ErrBackupInUsed: 'Yedekleme hesabı zamanlanmış görevde kullanıldı ve silinemez.'
|
||||
@@ -202,6 +215,7 @@ ErrRemoteExist: 'Uzak veritabanında bu adla zaten mevcut, lütfen değiştirin
|
||||
ErrLocalExist: 'Yerel veritabanında bu ad zaten mevcut, lütfen değiştirin ve tekrar deneyin'
|
||||
RemoteBackup: "Uzak veritabanını yedeklemek için önce {{ .name }} görüntüsü kullanılarak yerel konteyner veritabanı hizmetinin başlatılması gerekiyor, lütfen bekleyin..."
|
||||
RemoteRecover: "Uzak veritabanını geri yüklemek için önce {{ .name }} görüntüsü kullanılarak yerel konteyner veritabanı hizmetinin başlatılması gerekiyor, lütfen bekleyin..."
|
||||
Arg: "Argüman"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: 'Kurtarma dosyası türü mevcut kalıcılık yöntemiyle eşleşmiyor, lütfen değiştirin ve tekrar deneyin'
|
||||
@@ -212,7 +226,7 @@ ErrObjectInUsed: "Bu nesne kullanımda ve silinemez!"
|
||||
ErrObjectBeDependent: "Bu görüntü diğer görüntüler tarafından bağımlıdır ve silinemez!"
|
||||
ErrPortRules: 'Port numarası eşleşmiyor, lütfen yeniden girin!'
|
||||
ErrPgImagePull: 'Image çekme zaman aşımı, lütfen image hızlandırma yapılandırın veya manuel olarak {{ .name }} imageını çekin ve tekrar deneyin'
|
||||
PruneHelper: "Bu temizleme {{ .name }} {{ .count }} öğe kaldırdı, {{ .size }} disk alanı boşalttı"
|
||||
PruneHelper: "Bu temizlik {{ .name }} disk alanı {{ .size }} boşalttı"
|
||||
ImageRemoveHelper: "{{ .name }} imajı silindi, {{ .size }} disk alanı boşalttı"
|
||||
BuildCache: "Derleme önbelleği"
|
||||
Volume: "Depolama hacmi"
|
||||
@@ -506,19 +520,19 @@ ErrInstallExtension: "Zaten devam eden bir kurulum görevi var, görevin bitmesi
|
||||
PanelAlertTitle: "Panel Uyarı Bildirimi"
|
||||
TestAlertTitle: "Test E-postası - E-posta Bağlantısını Doğrula"
|
||||
TestAlert: "Bu, e-posta gönderim ayarlarınızın doğru yapılandırıldığını doğrulamak için gönderilen bir test e-postasıdır."
|
||||
LicenseExpirationAlert: "1Panel lisansınız {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
CronJobFailedAlert: "1Panel zamanlanmış görevi '{{ .name }}' başarısız oldu. Detaylar için panele giriş yapın."
|
||||
ClamAlert: "1Panel virüs taraması {{ .num }} enfekte dosya tespit etti. Detaylar için panele giriş yapın."
|
||||
WebSiteAlert: "1Panel üzerindeki {{ .num }} web sitesi {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
SSLAlert: "1Panel üzerindeki {{ .num }} SSL sertifikası {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
DiskUsedAlert: "1Panel diski '{{ .name }}' {{ .used }} kullanıldı. Detaylar için panele giriş yapın."
|
||||
ResourceAlert: "1Panel üzerinde ortalama {{ .time }} dakikalık {{ .name }} kullanım oranı {{ .used }}. Detaylar için panele giriş yapın."
|
||||
PanelVersionAlert: "1Panel için yeni bir sürüm mevcut. Güncellemek için panele giriş yapın."
|
||||
PanelPwdExpirationAlert: "1Panel şifreniz {{ .day }} gün içinde sona erecek. Detaylar için panele giriş yapın."
|
||||
CommonAlert: "1Panel'iniz, {{ .msg }}. Detaylar için panele giriş yapınız."
|
||||
NodeExceptionAlert: "1Panel'iniz, {{ .num }} düğümde sorun var. Detaylar için panele giriş yapınız."
|
||||
LicenseExceptionAlert: "1Panel'iniz, {{ .num }} lisansda sorun var. Detaylar için panele giriş yapınız."
|
||||
SSHAndPanelLoginAlert: "1Panel'iniz, {{ .ip }} adresinden {{ .name }} paneline anormal giriş tespit edildi. Detaylar için panele giriş yapınız."
|
||||
LicenseExpirationAlert: "Paneliniz {{ .node }}{{ .ip }}, lisans {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
CronJobFailedAlert: "Paneliniz {{ .node }}{{ .ip }}, zamanlanmış görev {{ .name }} çalıştırma başarısız oldu. Detaylar için paneline giriş yapın."
|
||||
ClamAlert: "Paneliniz {{ .node }}{{ .ip }}, virüs tarama görevi {{ .num }} enfekte dosya tespit etti. Detaylar için paneline giriş yapın."
|
||||
WebSiteAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} web sitesi {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
SSLAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} SSL sertifikası {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
DiskUsedAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .name }} diski kullanımı {{ .used }}'a ulaştı. Detaylar için paneline giriş yapın."
|
||||
ResourceAlert: "Paneliniz {{ .node }}{{ .ip }}, son {{ .time }} dakika içindeki ortalama {{ .name }} kullanım oranı {{ .used }}'dır. Detaylar için paneline giriş yapın."
|
||||
PanelVersionAlert: "Paneliniz {{ .node }}{{ .ip }}, en son panel sürümü yükseltme için mevcut. Detaylar için paneline giriş yapın."
|
||||
PanelPwdExpirationAlert: "Paneliniz {{ .node }}{{ .ip }}, panel şifresi {{ .day }} gün içinde süresi dolacak. Detaylar için paneline giriş yapın."
|
||||
CommonAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .msg }}. Detaylar için paneline giriş yapın."
|
||||
NodeExceptionAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} düğüm anormal durumda. Detaylar için paneline giriş yapın."
|
||||
LicenseExceptionAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .num }} lisans anormal durumda. Detaylar için paneline giriş yapın."
|
||||
SSHAndPanelLoginAlert: "Paneliniz {{ .node }}{{ .ip }}, {{ .loginIp }} adresinden {{ .name }} girişi anormal. Detaylar için paneline giriş yapın."
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "Cihaz {{ .name }} bulunamadı"
|
||||
|
||||
@@ -38,6 +38,19 @@ ErrGroupIsDefault: '預設分組,無法刪除'
|
||||
ErrGroupIsInWebsiteUse: '分組正在被其他網站使用,無法刪除'
|
||||
Decrypt: "解密"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: '該帳號已綁定到智能體,無法刪除,請檢查後重試!!'
|
||||
ErrAgentAccountUnavailable: '帳號連線資訊不可用,錯誤:{{ .err }},請檢查後重試!'
|
||||
ErrAgentProviderNotSupported: '暫不支援該智能體提供商,請檢查後重試!'
|
||||
ErrAgentAccountRequired: '請選擇智能體帳號後重試'
|
||||
ErrAgentAccountNotVerified: '帳號未驗證通過,請檢查後重試!'
|
||||
ErrAgentProviderMismatch: '帳號提供商不匹配,請檢查後重試!'
|
||||
ErrAgentBaseURLRequired: 'Base URL 不能為空,請檢查後重試!'
|
||||
ErrAgentApiKeyRequired: 'API Key 不能為空,請檢查後重試!'
|
||||
ErrAgentComposeRequired: '自訂編排內容不能為空,請檢查後重試!'
|
||||
ErrAgentIDRequired: '智能體 ID 不能為空,請檢查後重試!'
|
||||
ErrAgentAccountIDRequired: '帳號 ID 不能為空,請檢查後重試!'
|
||||
|
||||
#backup
|
||||
Localhost: '本機'
|
||||
ErrBackupInUsed: '此備份帳號已在排程任務中使用,無法刪除'
|
||||
@@ -124,7 +137,7 @@ ErrLogFileToLarge: "日誌檔案超過 500M,無法打開"
|
||||
FileDropFailed: "清理文件 {{ .name }} 失敗: {{ .err }}"
|
||||
FileDropSuccess: "清理文件 {{ .name }} 成功,清理 {{ .count }} 個文件,釋放 {{ .size }} 磁碟空間"
|
||||
FileDropSum: "文件清理完成,共清理 {{ .count }} 個文件,共釋放 {{ .size }} 磁碟空間"
|
||||
ErrBadDecrypt: "壓縮檔解壓密碼錯誤,解壓失敗,請檢查後重試!"
|
||||
ErrBadDecrypt: "壓縮檔解壓密碼錯誤,解壓失敗,請檢查後重試!!"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: '代號已存在'
|
||||
@@ -200,6 +213,7 @@ ErrRemoteExist: '遠端資料庫已存在該名稱,請修改後重試'
|
||||
ErrLocalExist: '本機資料庫已存在該名稱,請修改後重試'
|
||||
RemoteBackup: "備份遠端資料庫需要先使用映像 {{ .name }} 啟動本機容器資料庫服務,請稍候..."
|
||||
RemoteRecover: "恢復遠端資料庫需要先使用映像 {{ .name }} 啟動本機容器資料庫服務,請稍候..."
|
||||
Arg: "參數"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: '復原檔案類型與目前持久化方式不符,請修改後重試'
|
||||
@@ -210,7 +224,7 @@ ErrObjectInUsed: "該對象正被使用,無法刪除!"
|
||||
ErrObjectBeDependent: "該映像正被其他映像所依賴,無法刪除!"
|
||||
ErrPortRules: '連接埠數目不匹配,請重新輸入!'
|
||||
ErrPgImagePull: '鏡像拉取逾時,請配置鏡像加速或手動拉取{{ .name }} 鏡像後重試'
|
||||
PruneHelper: "本次清理 {{ .name }} {{ .count }} 個,釋放磁碟空間 {{ .size }}"
|
||||
PruneHelper: "本次清理 {{ .name }} 釋放磁碟空間 {{ .size }}"
|
||||
ImageRemoveHelper: "刪除鏡像 {{ .name }} ,釋放磁碟空間 {{ .size }}"
|
||||
BuildCache: "構建快取"
|
||||
Volume: "磁碟區"
|
||||
@@ -491,11 +505,11 @@ AppBackupFileIncomplete: '備份檔案不完整缺少 app.json 或 app.tar.gz
|
||||
AppAttributesNotMatch: '應用程式類型或名稱不一致'
|
||||
|
||||
#alert
|
||||
ErrAlert: '警告訊息格式錯誤,請檢查後重試!'
|
||||
ErrAlertPush: '警告訊息推送錯誤,請檢查後重試!'
|
||||
ErrAlertSave: '警告訊息儲存錯誤,請檢查後重試!'
|
||||
ErrAlertSync: '警告訊息同步錯誤,請檢查後重試!'
|
||||
ErrAlertRemote: '警告訊息遠端錯誤,請檢查後重試!'
|
||||
ErrAlert: '警告訊息格式錯誤,請檢查後重試!!'
|
||||
ErrAlertPush: '警告訊息推送錯誤,請檢查後重試!!'
|
||||
ErrAlertSave: '警告訊息儲存錯誤,請檢查後重試!!'
|
||||
ErrAlertSync: '警告訊息同步錯誤,請檢查後重試!!'
|
||||
ErrAlertRemote: '警告訊息遠端錯誤,請檢查後重試!!'
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "已有安裝任務正在進行,請等待任務結束"
|
||||
@@ -504,19 +518,19 @@ ErrInstallExtension: "已有安裝任務正在進行,請等待任務結束"
|
||||
PanelAlertTitle: "面板警示通知"
|
||||
TestAlertTitle: "測試郵件 - 驗證信箱連通性"
|
||||
TestAlert: "這是一封測試郵件,用於確認您的郵件發送設定是否正確。"
|
||||
LicenseExpirationAlert: "您的 1Panel 授權將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CronJobFailedAlert: "您的 1Panel 面板中,計畫任務 '{{ .name }}' 執行失敗,詳情請登入面板查看。"
|
||||
ClamAlert: "您的 1Panel 面板病毒掃描任務發現 {{ .num }} 個受感染的檔案,詳情請登入面板查看。"
|
||||
WebSiteAlert: "您的 1Panel 面板中有 {{ .num }} 個網站將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
SSLAlert: "您的 1Panel 面板中有 {{ .num }} 張 SSL 憑證將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
DiskUsedAlert: "您的 1Panel 面板磁碟 '{{ .name }}' 已使用 {{ .used }},詳情請登入面板查看。"
|
||||
ResourceAlert: "您的 1Panel 面板於 {{ .time }} 分鐘內的平均 {{ .name }} 使用率為 {{ .used }},詳情請登入面板查看。"
|
||||
PanelVersionAlert: "您的 1Panel 面板有可升級的新版本,詳情請登入面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 1Panel 面板密碼將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CommonAlert: "您的 1Panel 面板,{{ .msg }},詳情請登入面板查看。"
|
||||
NodeExceptionAlert: "您的 1Panel 面板,{{ .num }} 個節點存在異常,詳情請登入面板查看。"
|
||||
LicenseExceptionAlert: "您的 1Panel 面板,{{ .num }} 個許可證存在異常,詳情請登入面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 1Panel 面板,面板{{ .name }}從 {{ .ip }} 登入異常,詳情請登入面板查看。"
|
||||
LicenseExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,授權將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CronJobFailedAlert: "您的 {{ .node }}{{ .ip }} 面板,排程任務{{ .name }}執行失敗,詳情請登入面板查看。"
|
||||
ClamAlert: "您的 {{ .node }}{{ .ip }} 面板,病毒掃描任務偵測到 {{ .num }} 個感染檔案,詳情請登入面板查看。"
|
||||
WebSiteAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 個網站將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
SSLAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 張SSL憑證將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
DiskUsedAlert: "您的 {{ .node }}{{ .ip }} 面板,磁碟 {{ .name }} 使用率已達 {{ .used }},詳情請登入面板查看。"
|
||||
ResourceAlert: "您的 {{ .node }}{{ .ip }} 面板,過去 {{ .time }} 分鐘內 {{ .name }} 平均使用率為 {{ .used }},詳情請登入面板查看。"
|
||||
PanelVersionAlert: "您的 {{ .node }}{{ .ip }} 面板,已有最新版本可供升級,詳情請登入面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,面板密碼將於 {{ .day }} 天後到期,詳情請登入面板查看。"
|
||||
CommonAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .msg }},詳情請登入面板查看。"
|
||||
NodeExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 個節點出現異常,詳情請登入面板查看。"
|
||||
LicenseExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 個授權出現異常,詳情請登入面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 {{ .node }}{{ .ip }} 面板,來自 {{ .loginIp }} 的 {{ .name }} 登入出現異常,詳情請登入面板查看。"
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "裝置 {{ .name }} 未找到"
|
||||
|
||||
+36
-22
@@ -38,6 +38,19 @@ ErrGroupIsDefault: "默认分组,无法删除"
|
||||
ErrGroupIsInWebsiteUse: "分组正在被其他网站使用,无法删除"
|
||||
Decrypt: "解密"
|
||||
|
||||
#agent
|
||||
ErrAgentAccountBound: "该账号已经绑定到智能体,无法删除,请检查后重试!!"
|
||||
ErrAgentAccountUnavailable: "账号连接信息不可用,错误:{{ .err }},请检查后重试!"
|
||||
ErrAgentProviderNotSupported: "暂不支持该智能体提供商,请检查后重试!"
|
||||
ErrAgentAccountRequired: "请选择智能体账号后重试"
|
||||
ErrAgentAccountNotVerified: "账号未验证通过,请检查后重试!"
|
||||
ErrAgentProviderMismatch: "账号提供商不匹配,请检查后重试!"
|
||||
ErrAgentBaseURLRequired: "Base URL 不能为空,请检查后重试!"
|
||||
ErrAgentApiKeyRequired: "API Key 不能为空,请检查后重试!"
|
||||
ErrAgentComposeRequired: "自定义编排内容不能为空,请检查后重试!"
|
||||
ErrAgentIDRequired: "智能体 ID 不能为空,请检查后重试!"
|
||||
ErrAgentAccountIDRequired: "账号 ID 不能为空,请检查后重试!"
|
||||
|
||||
#backup
|
||||
Localhost: '本机'
|
||||
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
|
||||
@@ -125,7 +138,7 @@ ErrLogFileToLarge: "日志文件超过 500M,无法打开"
|
||||
FileDropFailed: "清理文件 {{ .name }} 失败 {{ .err }}"
|
||||
FileDropSuccess: "清理文件 {{ .name }} 成功,清理文件 {{ .count }},释放磁盘空间 {{ .size }}"
|
||||
FileDropSum: "文件清理成功,清理文件共计 {{ .count }},释放磁盘空间共计 {{ .size }}"
|
||||
ErrBadDecrypt: "压缩包解压密码错误,解压失败,请检查后重试!"
|
||||
ErrBadDecrypt: "压缩包解压密码错误,解压失败,请检查后重试!!"
|
||||
|
||||
#website
|
||||
ErrAliasIsExist: "代号已存在"
|
||||
@@ -201,6 +214,7 @@ ErrRemoteExist: "远程数据库已存在该名称,请修改后重试"
|
||||
ErrLocalExist: "本地数据库已存在该名称,请修改后重试"
|
||||
RemoteBackup: "备份远程数据库需要先使用镜像 {{ .name }} 启动本地容器数据库服务,请稍候..."
|
||||
RemoteRecover: "恢复远程数据库需要先使用镜像 {{ .name }} 启动本地容器数据库服务,请稍候..."
|
||||
Arg: "参数"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
|
||||
@@ -211,7 +225,7 @@ ErrObjectInUsed: "该对象正被使用,无法删除!"
|
||||
ErrObjectBeDependent: "该镜像正被其他镜像所依赖,无法删除!"
|
||||
ErrPortRules: "端口数目不匹配,请重新输入!"
|
||||
ErrPgImagePull: "镜像拉取超时,请配置镜像加速或手动拉取 {{ .name }} 镜像后重试"
|
||||
PruneHelper: "本次清理 {{ .name }} {{ .count }} 个,释放磁盘空间 {{ .size }}"
|
||||
PruneHelper: "本次清理 {{ .name }} 释放磁盘空间 {{ .size }}"
|
||||
ImageRemoveHelper: "删除镜像 {{ .name }} ,释放磁盘空间 {{ .size }}"
|
||||
BuildCache: "构建缓存"
|
||||
Volume: "存储卷"
|
||||
@@ -262,7 +276,7 @@ WafIpGroupNotFound: "WAF IP组未找到,请先到【高级功能-WAF-黑白名
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
||||
ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!"
|
||||
ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!!"
|
||||
ErrClamdscanNotFound: "未检测到 clamdscan 命令,请参考文档安装!"
|
||||
TaskSwapSet: "设置 Swap"
|
||||
SetSwap: "设置 Swap {{ .path }} - {{ .size }}"
|
||||
@@ -493,11 +507,11 @@ AppBackupFileIncomplete: "备份文件不完整 缺少 app.json 或者 app.tar.
|
||||
AppAttributesNotMatch: "应用类型或者名称不一致"
|
||||
|
||||
#alert
|
||||
ErrAlert: "告警信息格式错误,请检查后重试!"
|
||||
ErrAlertPush: "告警信息推送错误,请检查后重试!"
|
||||
ErrAlertSave: "告警信息保存错误,请检查后重试!"
|
||||
ErrAlertSync: "告警信息同步错误,请检查后重试!"
|
||||
ErrAlertRemote: "告警信息远端错误,请检查后重试!"
|
||||
ErrAlert: "告警信息格式错误,请检查后重试!!"
|
||||
ErrAlertPush: "告警信息推送错误,请检查后重试!!"
|
||||
ErrAlertSave: "告警信息保存错误,请检查后重试!!"
|
||||
ErrAlertSync: "告警信息同步错误,请检查后重试!!"
|
||||
ErrAlertRemote: "告警信息远端错误,请检查后重试!!"
|
||||
|
||||
#task - runtime
|
||||
ErrInstallExtension: "已有安装任务正在进行,请等待任务结束"
|
||||
@@ -506,19 +520,19 @@ ErrInstallExtension: "已有安装任务正在进行,请等待任务结束"
|
||||
PanelAlertTitle: "面板告警通知"
|
||||
TestAlertTitle: "测试邮件 - 验证邮箱连通性"
|
||||
TestAlert: "这是一封测试邮件,旨在验证您的邮箱发件配置是否正确。"
|
||||
LicenseExpirationAlert: "您的 1Panel 面板,许可证将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
CronJobFailedAlert: "您的 1Panel 面板,计划任务-{{ .name }}执行失败,详情请登录面板查看。"
|
||||
ClamAlert: "您的 1Panel 面板,病毒扫描任务发现 {{ .num }} 个感染文件,详情请登录面板查看。"
|
||||
WebSiteAlert: "您的 1Panel 面板,有 {{ .num }} 个网站将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
SSLAlert: "您的 1Panel 面板,有 {{ .num }} 张SSL证书将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
DiskUsedAlert: "您的 1Panel 面板,磁盘 {{ .name }} 已使用 {{ .used }},详情请登录面板查看。"
|
||||
ResourceAlert: "您的 1Panel 面板,平均 {{ .time }} 分钟内的 {{ .name }} 使用率为 {{ .used }},详情请登录面板查看。"
|
||||
PanelVersionAlert: "您的 1Panel 面板,有最新面板版本可供升级,详情请登录面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 1Panel 面板,面板密码将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
CommonAlert: "您的 1Panel 面板,{{ .msg }},详情请登录面板查看。"
|
||||
NodeExceptionAlert: "您的 1Panel 面板,{{ .num }} 个节点存在异常,详情请登录面板查看。"
|
||||
LicenseExceptionAlert: "您的 1Panel 面板,{{ .num }} 个许可证存在异常,详情请登录面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 1Panel 面板,面板{{ .name }}登录{{ .ip }}异常,详情请登录面板查看。"
|
||||
LicenseExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,许可证将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
CronJobFailedAlert: "您的 {{ .node }}{{ .ip }} 面板,计划任务-{{ .name }}执行失败,详情请登录面板查看。"
|
||||
ClamAlert: "您的 {{ .node }}{{ .ip }} 面板,病毒扫描任务发现 {{ .num }} 个感染文件,详情请登录面板查看。"
|
||||
WebSiteAlert: "您的 {{ .node }}{{ .ip }} 面板,有 {{ .num }} 个网站将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
SSLAlert: "您的 {{ .node }}{{ .ip }} 面板,有 {{ .num }} 张SSL证书将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
DiskUsedAlert: "您的 {{ .node }}{{ .ip }} 面板,磁盘 {{ .name }} 已使用 {{ .used }},详情请登录面板查看。"
|
||||
ResourceAlert: "您的 {{ .node }}{{ .ip }} 面板,平均 {{ .time }} 分钟内的 {{ .name }} 使用率为 {{ .used }},详情请登录面板查看。"
|
||||
PanelVersionAlert: "您的 {{ .node }}{{ .ip }} 面板,有最新面板版本可供升级,详情请登录面板查看。"
|
||||
PanelPwdExpirationAlert: "您的 {{ .node }}{{ .ip }} 面板,面板密码将在 {{ .day }} 天后到期,详情请登录面板查看。"
|
||||
CommonAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .msg }},详情请登录面板查看。"
|
||||
NodeExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 个节点存在异常,详情请登录面板查看。"
|
||||
LicenseExceptionAlert: "您的 {{ .node }}{{ .ip }} 面板,{{ .num }} 个许可证存在异常,详情请登录面板查看。"
|
||||
SSHAndPanelLoginAlert: "您的 {{ .node }}{{ .ip }} 面板,面板{{ .name }}登录{{ .loginIp }}异常,详情请登录面板查看。"
|
||||
|
||||
#disk
|
||||
DeviceNotFound: "设备 {{ .name }} 未找到"
|
||||
@@ -527,4 +541,4 @@ PartitionDiskErr: "分区失败,{{ .err }}"
|
||||
FormatDiskErr: "格式化磁盘失败,{{ .err }}"
|
||||
MountDiskErr: "挂载磁盘失败,{{ .err }}"
|
||||
UnMountDiskErr: "卸载磁盘失败,{{ .err }}"
|
||||
XfsNotFound: "未检测到 xfs 文件系统,请先安装 xfsprogs"
|
||||
XfsNotFound: "未检测到 xfs 文件系统,请先安装 xfsprogs"
|
||||
|
||||
@@ -23,7 +23,10 @@ func syncApp() {
|
||||
if global.CONF.Base.IsOffLine {
|
||||
return
|
||||
}
|
||||
_ = service.NewISettingService().Update("AppStoreSyncStatus", constant.StatusSyncSuccess)
|
||||
setting, err := service.NewISettingService().GetSettingInfo()
|
||||
if err == nil && setting.AppStoreSyncStatus == constant.StatusSyncing {
|
||||
_ = service.NewISettingService().Update("AppStoreSyncStatus", constant.StatusSyncSuccess)
|
||||
}
|
||||
if err := service.NewIAppService().SyncAppListFromRemote(""); err != nil {
|
||||
global.LOG.Errorf("App Store synchronization failed")
|
||||
return
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user