mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 08:00:27 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c826525e3 | ||
|
|
3f0fd48cf3 | ||
|
|
211dbfdead | ||
|
|
aafec142cc | ||
|
|
384ff57df7 | ||
|
|
01ddd203ea | ||
|
|
29aed616ac | ||
|
|
83f0df9d84 | ||
|
|
7aa16c8142 | ||
|
|
3bd505954f | ||
|
|
275c0522a3 | ||
|
|
85dec6815b | ||
|
|
5e4e9f762e | ||
|
|
7ae3722997 |
+2
-2
@@ -3,9 +3,9 @@
|
||||
## Create pull request
|
||||
PR are always welcome, even if they only contain small fixes like typos or a few lines of code. If there will be a significant effort, please document it as an issue and get a discussion going before starting to work on it.
|
||||
|
||||
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot of features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
|
||||
Please submit a PR broken down into small changes bit by bit. A PR consisting of a lot features and code changes may be hard to review. It is recommended to submit PRs in an incremental fashion.
|
||||
|
||||
This [development guideline](https://1panel.cn/docs/dev_manual/dev_manual/) contains information about repository structure, how to set up development environment, how to run it, and more.
|
||||
This [development guideline](https://1panel.cn/docs/dev_manual/dev_manual/) contains information about repository structure, how to setup development environment, how to run it, and more.
|
||||
|
||||
Note: If you split your pull request to small changes, please make sure any of the changes goes to master will not break anything. Otherwise, it can not be merged until this feature complete.
|
||||
|
||||
|
||||
@@ -21,8 +21,18 @@
|
||||
|
||||
1Panel 三分钟速览:https://www.bilibili.com/video/BV1Mt421n7LZ/
|
||||
|
||||
## UI 展示
|
||||
|
||||

|
||||
|
||||
## 快速开始
|
||||
|
||||
**在线体验**
|
||||
|
||||
- 环境地址:<https://demo.1panel.cn/>
|
||||
- 用户名:demo
|
||||
- 密码:1panel
|
||||
|
||||
**一键安装**
|
||||
|
||||
执行如下命令一键安装 1Panel:
|
||||
@@ -34,24 +44,30 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
**学习资料**
|
||||
|
||||
- [在线文档](https://1panel.cn/docs/)
|
||||
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
|
||||
- [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)
|
||||
|
||||
## UI 展示
|
||||
## 安全说明
|
||||
|
||||

|
||||
如果您在使用过程中发现任何安全问题,请通过以下方式直接联系我们:
|
||||
|
||||
- 邮箱:wanghe@fit2cloud.com
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||
|
||||
## 我们的其他明星项目
|
||||
|
||||
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统
|
||||
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
|
||||
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
|
||||
- [DataEase](https://github.com/dataease/dataease/) - 人人可用的开源数据可视化分析工具
|
||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - 开源自动化测试平台
|
||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - 一站式开源自动化测试平台
|
||||
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
|
||||
|
||||
|
||||
## FOSSA Status
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_large)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -323,7 +323,7 @@ func (b *BaseApi) Backup(c *gin.Context) {
|
||||
|
||||
switch req.Type {
|
||||
case "app":
|
||||
if _, err := backupService.AppBackup(req); err != nil {
|
||||
if err := backupService.AppBackup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
}
|
||||
dir := path.Dir(paths[0])
|
||||
|
||||
_, err = os.Stat(dir)
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
mode, err := files.GetParentMode(dir)
|
||||
if err != nil {
|
||||
@@ -330,7 +330,7 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
info, err := os.Stat(dir)
|
||||
info, err = os.Stat(dir)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -486,7 +486,6 @@ func (b *BaseApi) Download(c *gin.Context) {
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
}
|
||||
defer file.Close()
|
||||
info, _ := file.Stat()
|
||||
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
|
||||
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
|
||||
@@ -609,7 +608,7 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer targetFile.Close()
|
||||
|
||||
for i := 0; i < chunkCount; i++ {
|
||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
||||
chunkData, err := os.ReadFile(chunkPath)
|
||||
@@ -644,7 +643,6 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
defer uploadFile.Close()
|
||||
chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
|
||||
@@ -76,20 +76,6 @@ func (b *BaseApi) DeleteRuntime(c *gin.Context) {
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteRuntimeCheck(c *gin.Context) {
|
||||
runTimeId, err := helper.GetIntParamByKey(c, "runTimeId")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
checkData, err := runtimeService.DeleteCheck(runTimeId)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, checkData)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Update runtime
|
||||
// @Description 更新运行环境
|
||||
|
||||
@@ -3,6 +3,7 @@ package v1
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -92,17 +93,16 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
||||
}
|
||||
|
||||
defer wsConn.Close()
|
||||
commands := []string{"redis-cli"}
|
||||
commands := "redis-cli"
|
||||
if len(redisConf.Requirepass) != 0 {
|
||||
commands = []string{"redis-cli", "-a", redisConf.Requirepass, "--no-auth-warning"}
|
||||
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass)
|
||||
}
|
||||
pidMap := loadMapFromDockerTop(redisConf.ContainerName)
|
||||
itemCmds := append([]string{"exec", "-it", redisConf.ContainerName}, commands...)
|
||||
slave, err := terminal.NewCommand(itemCmds)
|
||||
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(redisConf.ContainerName, strings.Join(commands, " "), pidMap)
|
||||
defer killBash(redisConf.ContainerName, pidMap)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
|
||||
@@ -161,16 +161,16 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
commands := []string{"exec", "-it", containerID, command}
|
||||
commands := fmt.Sprintf("docker exec -it %s %s", containerID, command)
|
||||
if len(user) != 0 {
|
||||
commands = []string{"exec", "-it", "-u", user, containerID, command}
|
||||
commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command)
|
||||
}
|
||||
pidMap := loadMapFromDockerTop(containerID)
|
||||
slave, err := terminal.NewCommand(commands)
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
defer killBash(containerID, command, pidMap)
|
||||
defer killBash(containerID, pidMap)
|
||||
defer slave.Close()
|
||||
|
||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, true)
|
||||
@@ -221,26 +221,26 @@ func loadMapFromDockerTop(containerID string) map[string]string {
|
||||
lines := strings.Split(stdout, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
if len(parts) == 0 {
|
||||
continue
|
||||
}
|
||||
pidMap[parts[0]] = strings.Join(parts[1:], " ")
|
||||
pidMap[parts[0]] = strings.Join(parts, " ")
|
||||
}
|
||||
return pidMap
|
||||
}
|
||||
|
||||
func killBash(containerID, comm string, pidMap map[string]string) {
|
||||
func killBash(containerID string, pidMap map[string]string) {
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
newPidMap := loadMapFromDockerTop(containerID)
|
||||
for pid, command := range newPidMap {
|
||||
for pid, newCmd := range newPidMap {
|
||||
isOld := false
|
||||
for pid2 := range pidMap {
|
||||
if pid == pid2 {
|
||||
for pid2, oldCmd := range pidMap {
|
||||
if pid == pid2 && oldCmd == newCmd {
|
||||
isOld = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isOld && command == comm {
|
||||
if !isOld {
|
||||
_, _ = cmd.Execf("%s kill -9 %s", sudo, pid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,6 @@ type WebsiteSSLCreate struct {
|
||||
Dir string `json:"dir"`
|
||||
ID uint `json:"id"`
|
||||
Description string `json:"description"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
}
|
||||
|
||||
type WebsiteDNSReq struct {
|
||||
@@ -36,9 +32,8 @@ type WebsiteSSLRenew struct {
|
||||
}
|
||||
|
||||
type WebsiteSSLApply struct {
|
||||
ID uint `json:"ID" validate:"required"`
|
||||
SkipDNSCheck bool `json:"skipDNSCheck"`
|
||||
Nameservers []string `json:"nameservers"`
|
||||
ID uint `json:"ID" validate:"required"`
|
||||
SkipDNSCheck bool `json:"SkipDNSCheck"`
|
||||
}
|
||||
|
||||
type WebsiteAcmeAccountCreate struct {
|
||||
@@ -71,22 +66,9 @@ type WebsiteBatchDelReq struct {
|
||||
}
|
||||
|
||||
type WebsiteSSLUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
Description string `json:"description"`
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
OtherDomains string `json:"otherDomains"`
|
||||
Provider string `json:"provider" validate:"required"`
|
||||
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
KeyType string `json:"keyType"`
|
||||
Apply bool `json:"apply"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type WebsiteSSLUpload struct {
|
||||
|
||||
@@ -8,7 +8,6 @@ type SettingInfo struct {
|
||||
SystemIP string `json:"systemIP"`
|
||||
SystemVersion string `json:"systemVersion"`
|
||||
DockerSockPath string `json:"dockerSockPath"`
|
||||
DeveloperMode string `json:"developerMode"`
|
||||
|
||||
SessionTimeout string `json:"sessionTimeout"`
|
||||
LocalTime string `json:"localTime"`
|
||||
@@ -141,7 +140,6 @@ type SnapshotInfo struct {
|
||||
}
|
||||
|
||||
type UpgradeInfo struct {
|
||||
TestVersion string `json:"testVersion"`
|
||||
NewVersion string `json:"newVersion"`
|
||||
LatestVersion string `json:"latestVersion"`
|
||||
ReleaseNote string `json:"releaseNote"`
|
||||
|
||||
@@ -9,30 +9,26 @@ import (
|
||||
|
||||
type WebsiteSSL struct {
|
||||
BaseModel
|
||||
PrimaryDomain string `json:"primaryDomain"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Pem string `json:"pem"`
|
||||
Domains string `json:"domains"`
|
||||
CertURL string `json:"certURL"`
|
||||
Type string `json:"type"`
|
||||
Provider string `json:"provider"`
|
||||
Organization string `json:"organization"`
|
||||
DnsAccountID uint `json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"column:acme_account_id" json:"acmeAccountId" `
|
||||
CaID uint `json:"caId"`
|
||||
AutoRenew bool `json:"autoRenew"`
|
||||
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
|
||||
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
||||
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
||||
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
|
||||
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
|
||||
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
|
||||
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
||||
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
|
||||
CaID uint `gorm:"type:integer;not null;default:0" json:"caId"`
|
||||
AutoRenew bool `gorm:"type:varchar(64);not null" json:"autoRenew"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
StartDate time.Time `json:"startDate"`
|
||||
Status string `json:"status"`
|
||||
Status string `gorm:"not null;default:ready" json:"status"`
|
||||
Message string `json:"message"`
|
||||
KeyType string `json:"keyType"`
|
||||
PushDir bool `json:"pushDir"`
|
||||
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
||||
PushDir bool `gorm:"not null;default:0" json:"pushDir"`
|
||||
Dir string `json:"dir"`
|
||||
Description string `json:"description"`
|
||||
SkipDNS bool `json:"skipDNS"`
|
||||
Nameserver1 string `json:"nameserver1"`
|
||||
Nameserver2 string `json:"nameserver2"`
|
||||
DisableCNAME bool `json:"disableCNAME"`
|
||||
|
||||
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
|
||||
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
|
||||
|
||||
@@ -21,7 +21,6 @@ type ISSLRepo interface {
|
||||
Create(ctx context.Context, ssl *model.WebsiteSSL) error
|
||||
Save(ssl *model.WebsiteSSL) error
|
||||
DeleteBy(opts ...DBOption) error
|
||||
SaveByMap(ssl *model.WebsiteSSL, params map[string]interface{}) error
|
||||
}
|
||||
|
||||
type WebsiteSSLRepo struct {
|
||||
@@ -83,15 +82,7 @@ func (w WebsiteSSLRepo) Create(ctx context.Context, ssl *model.WebsiteSSL) error
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) Save(ssl *model.WebsiteSSL) error {
|
||||
return getDb().Model(&model.WebsiteSSL{BaseModel: model.BaseModel{
|
||||
ID: ssl.ID,
|
||||
}}).Save(&ssl).Error
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) SaveByMap(ssl *model.WebsiteSSL, params map[string]interface{}) error {
|
||||
return getDb().Model(&model.WebsiteSSL{BaseModel: model.BaseModel{
|
||||
ID: ssl.ID,
|
||||
}}).Updates(params).Error
|
||||
return getDb().Save(&ssl).Error
|
||||
}
|
||||
|
||||
func (w WebsiteSSLRepo) DeleteBy(opts ...DBOption) error {
|
||||
|
||||
@@ -230,7 +230,6 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
|
||||
if err != nil {
|
||||
return appDetailDTO, buserr.WithDetail("ErrGetCompose", err.Error(), err)
|
||||
}
|
||||
defer composeRes.Body.Close()
|
||||
bodyContent, err := io.ReadAll(composeRes.Body)
|
||||
if err != nil {
|
||||
return appDetailDTO, buserr.WithDetail("ErrGetCompose", err.Error(), err)
|
||||
@@ -728,14 +727,6 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||
res.CanUpdate = true
|
||||
return res, err
|
||||
}
|
||||
apps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
|
||||
for _, app := range apps {
|
||||
if app.Icon == "" {
|
||||
res.CanUpdate = true
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
list, err := getAppList()
|
||||
if err != nil {
|
||||
return res, err
|
||||
@@ -848,12 +839,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
iconStr := ""
|
||||
if !strings.Contains(string(body), "<xml>") {
|
||||
iconStr = base64.StdEncoding.EncodeToString(body)
|
||||
}
|
||||
_ = iconRes.Body.Close()
|
||||
|
||||
iconStr := base64.StdEncoding.EncodeToString(body)
|
||||
app.Icon = iconStr
|
||||
app.TagsKey = l.AppProperty.Tags
|
||||
if l.AppProperty.Recommend > 0 {
|
||||
@@ -876,7 +862,6 @@ func (a AppService) SyncAppListFromRemote() (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer composeRes.Body.Close()
|
||||
bodyContent, err := io.ReadAll(composeRes.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -712,7 +712,6 @@ func syncAppInstallStatus(appInstall *model.AppInstall) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err := cli.ListContainersByName(containerNames)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -15,9 +17,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
@@ -451,40 +450,23 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
install.Status = constant.Upgrading
|
||||
|
||||
go func() {
|
||||
var (
|
||||
upErr error
|
||||
backupFile string
|
||||
)
|
||||
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppStart", install.Name, nil))
|
||||
if backup {
|
||||
backupRecord, err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name})
|
||||
if err == nil {
|
||||
localDir, err := loadLocalDir()
|
||||
if err == nil {
|
||||
backupFile = path.Join(localDir, backupRecord.FileDir, backupRecord.FileName)
|
||||
} else {
|
||||
global.LOG.Errorf(i18n.GetMsgWithName("ErrAppBackup", install.Name, err))
|
||||
}
|
||||
} else {
|
||||
global.LOG.Errorf(i18n.GetMsgWithName("ErrAppBackup", install.Name, err))
|
||||
if err = NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
|
||||
global.LOG.Errorf(i18n.GetMsgWithMap("ErrAppBackup", map[string]interface{}{"name": install.Name, "err": err.Error()}))
|
||||
}
|
||||
}
|
||||
var upErr error
|
||||
|
||||
defer func() {
|
||||
if upErr != nil {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("ErrAppUpgrade", install.Name, upErr))
|
||||
if backup {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("AppRecover", install.Name, nil))
|
||||
if err := NewIBackupService().AppRecover(dto.CommonRecover{Name: install.App.Key, DetailName: install.Name, Type: "app", Source: constant.ResourceLocal, File: backupFile}); err != nil {
|
||||
if err := NewIBackupService().AppRecover(dto.CommonRecover{Name: install.App.Key, DetailName: install.Name, Type: "app", Source: constant.ResourceLocal}); err != nil {
|
||||
global.LOG.Errorf("recover app [%s] [%s] failed %v", install.App.Key, install.Name, err)
|
||||
}
|
||||
}
|
||||
existInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(installID))
|
||||
if existInstall.ID > 0 {
|
||||
existInstall.Status = constant.UpgradeErr
|
||||
existInstall.Message = upErr.Error()
|
||||
_ = appInstallRepo.Save(context.Background(), &existInstall)
|
||||
}
|
||||
install.Status = constant.UpgradeErr
|
||||
install.Message = upErr.Error()
|
||||
_ = appInstallRepo.Save(context.Background(), &install)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -564,15 +546,13 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
if upErr = addDockerComposeCommonParam(composeMap, install.ServiceName, config, envs); upErr != nil {
|
||||
return
|
||||
}
|
||||
paramByte, err := json.Marshal(envs)
|
||||
if err != nil {
|
||||
upErr = err
|
||||
paramByte, upErr := json.Marshal(envs)
|
||||
if upErr != nil {
|
||||
return
|
||||
}
|
||||
install.Env = string(paramByte)
|
||||
composeByte, err := yaml.Marshal(composeMap)
|
||||
if err != nil {
|
||||
upErr = err
|
||||
composeByte, upErr := yaml.Marshal(composeMap)
|
||||
if upErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -580,6 +560,23 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
install.Version = detail.Version
|
||||
install.AppDetailId = detailID
|
||||
|
||||
if out, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
if out != "" {
|
||||
upErr = errors.New(out)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
envParams := make(map[string]string, len(envs))
|
||||
handleMap(envs, envParams)
|
||||
if err = env.Write(envParams, install.GetEnvPath()); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = runScript(&install, "upgrade"); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := fileOp.GetContent(install.GetEnvPath())
|
||||
if err != nil {
|
||||
upErr = err
|
||||
@@ -587,8 +584,7 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
}
|
||||
|
||||
if pullImage {
|
||||
projectName := strings.ToLower(install.Name)
|
||||
images, err := composeV2.GetDockerComposeImages(projectName, content, []byte(detail.DockerCompose))
|
||||
images, err := composeV2.GetDockerComposeImages(install.Name, content, []byte(detail.DockerCompose))
|
||||
if err != nil {
|
||||
upErr = err
|
||||
return
|
||||
@@ -598,36 +594,14 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
defer dockerCli.Close()
|
||||
for _, image := range images {
|
||||
global.LOG.Infof(i18n.GetMsgWithName("PullImageStart", image, nil))
|
||||
if err = dockerCli.PullImage(image, true); err != nil {
|
||||
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
|
||||
return
|
||||
} else {
|
||||
global.LOG.Infof(i18n.GetMsgByKey("PullImageSuccess"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if out, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
if out != "" {
|
||||
upErr = errors.New(out)
|
||||
return
|
||||
}
|
||||
upErr = err
|
||||
return
|
||||
}
|
||||
envParams := make(map[string]string, len(envs))
|
||||
handleMap(envs, envParams)
|
||||
if upErr = env.Write(envParams, install.GetEnvPath()); upErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if upErr = runScript(&install, "upgrade"); upErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if upErr = fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); upErr != nil {
|
||||
return
|
||||
}
|
||||
@@ -641,7 +615,6 @@ func upgradeInstall(installID uint, detailID uint, backup, pullImage bool) error
|
||||
}
|
||||
install.Status = constant.Running
|
||||
_ = appInstallRepo.Save(context.Background(), &install)
|
||||
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppSuccess", install.Name, nil))
|
||||
}()
|
||||
|
||||
return appInstallRepo.Save(context.Background(), &install)
|
||||
@@ -856,7 +829,6 @@ func checkContainerNameIsExist(containerName, appDir string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer client.Close()
|
||||
var options container.ListOptions
|
||||
list, err := client.ContainerList(context.Background(), options)
|
||||
if err != nil {
|
||||
|
||||
@@ -55,7 +55,7 @@ type IBackupService interface {
|
||||
WebsiteBackup(db dto.CommonBackup) error
|
||||
WebsiteRecover(req dto.CommonRecover) error
|
||||
|
||||
AppBackup(db dto.CommonBackup) (*model.BackupRecord, error)
|
||||
AppBackup(db dto.CommonBackup) error
|
||||
AppRecover(req dto.CommonRecover) error
|
||||
|
||||
Run()
|
||||
|
||||
@@ -22,26 +22,26 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, error) {
|
||||
func (u *BackupService) AppBackup(req dto.CommonBackup) error {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
app, err := appRepo.GetFirst(appRepo.WithKey(req.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByName(req.DetailName), appInstallRepo.WithAppId(app.ID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
itemDir := fmt.Sprintf("app/%s/%s", req.Name, req.DetailName)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow+common.RandStrAndNum(5))
|
||||
if err := handleAppBackup(&install, backupDir, fileName, ""); err != nil {
|
||||
return nil, err
|
||||
if err := handleAppBackup(&install, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record := &model.BackupRecord{
|
||||
@@ -56,9 +56,9 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) (*model.BackupRecord, er
|
||||
|
||||
if err := backupRepo.CreateRecord(record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
return record, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
@@ -84,7 +84,7 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excludes string) error {
|
||||
func handleAppBackup(install *model.AppInstall, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
@@ -103,7 +103,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string, excl
|
||||
}
|
||||
|
||||
appPath := install.GetPath()
|
||||
if err := handleTar(appPath, tmpDir, "app.tar.gz", excludes); err != nil {
|
||||
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format("20060102150405")))
|
||||
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil {
|
||||
if err := handleAppBackup(install, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
return fmt.Errorf("backup app %s for rollback before recover failed, err: %v", install.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
|
||||
@@ -4,19 +4,18 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, excludes string) error {
|
||||
func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
@@ -35,7 +34,7 @@ func handleRuntimeBackup(runtime *model.Runtime, backupDir, fileName string, exc
|
||||
}
|
||||
|
||||
appPath := runtime.GetPath()
|
||||
if err := handleTar(appPath, tmpDir, "runtime.tar.gz", excludes); err != nil {
|
||||
if err := handleTar(appPath, tmpDir, "runtime.tar.gz", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil {
|
||||
@@ -73,7 +72,7 @@ func handleRuntimeRecover(runtime *model.Runtime, recoverFile string, isRollback
|
||||
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("runtime/%s_%s.tar.gz", runtime.Name, time.Now().Format("20060102150405")))
|
||||
if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil {
|
||||
if err := handleRuntimeBackup(runtime, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
return fmt.Errorf("backup runtime %s for rollback before recover failed, err: %v", runtime.Name, err)
|
||||
}
|
||||
defer func() {
|
||||
|
||||
@@ -35,7 +35,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||
itemDir := fmt.Sprintf("website/%s", req.Name)
|
||||
backupDir := path.Join(localDir, itemDir)
|
||||
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow+common.RandStrAndNum(5))
|
||||
if err := handleWebsiteBackup(&website, backupDir, fileName, ""); err != nil {
|
||||
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
isOk := false
|
||||
if !isRollback {
|
||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
|
||||
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil {
|
||||
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil {
|
||||
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
|
||||
}
|
||||
defer func() {
|
||||
@@ -182,7 +182,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleWebsiteBackup(website *model.Website, backupDir, fileName string, excludes string) error {
|
||||
func handleWebsiteBackup(website *model.Website, backupDir, fileName string) error {
|
||||
fileOp := files.NewFileOp()
|
||||
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
|
||||
if !fileOp.Stat(tmpDir) {
|
||||
@@ -216,7 +216,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias), excludes); err != nil {
|
||||
if err := handleAppBackup(&app, tmpDir, fmt.Sprintf("%s.app.tar.gz", website.Alias)); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put app.tar.gz into tmp dir successful")
|
||||
@@ -226,7 +226,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
|
||||
return err
|
||||
}
|
||||
if runtime.Type == constant.RuntimeNode {
|
||||
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias), excludes); err != nil {
|
||||
if err := handleRuntimeBackup(runtime, tmpDir, fmt.Sprintf("%s.runtime.tar.gz", website.Alias)); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put runtime.tar.gz into tmp dir successful")
|
||||
@@ -234,7 +234,7 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string, exc
|
||||
}
|
||||
|
||||
websiteDir := fmt.Sprintf("%s/openresty/%s/www/sites/%s", constant.AppInstallDir, nginxInfo.Name, website.Alias)
|
||||
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), excludes); err != nil {
|
||||
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
global.LOG.Info("put web.tar.gz into tmp dir successful, now start to tar tmp dir")
|
||||
@@ -250,18 +250,18 @@ func checkValidOfWebsite(oldWebsite, website *model.Website) error {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, fmt.Sprintf("oldName: %s, oldType: %v", oldWebsite.Alias, oldWebsite.Type), nil)
|
||||
}
|
||||
if oldWebsite.AppInstallID != 0 {
|
||||
_, err := appInstallRepo.GetFirst(commonRepo.WithByID(oldWebsite.AppInstallID))
|
||||
_, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, "app", nil)
|
||||
}
|
||||
}
|
||||
if oldWebsite.RuntimeID != 0 {
|
||||
if _, err := runtimeRepo.GetFirst(commonRepo.WithByID(oldWebsite.RuntimeID)); err != nil {
|
||||
if _, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID)); err != nil {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, "runtime", nil)
|
||||
}
|
||||
}
|
||||
if oldWebsite.WebsiteSSLID != 0 {
|
||||
if _, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(oldWebsite.WebsiteSSLID)); err != nil {
|
||||
if _, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID)); err != nil {
|
||||
return buserr.WithDetail(constant.ErrBackupMatch, "ssl", nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,6 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
options := container.ListOptions{
|
||||
All: true,
|
||||
}
|
||||
@@ -220,7 +219,6 @@ func (u *ContainerService) List() ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
containers, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -242,7 +240,6 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -265,7 +262,6 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
var inspectInfo interface{}
|
||||
switch req.Type {
|
||||
case "container":
|
||||
@@ -293,7 +289,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
defer client.Close()
|
||||
pruneFilters := filters.NewArgs()
|
||||
if req.WithTagAll {
|
||||
pruneFilters.Add("dangling", "false")
|
||||
@@ -323,13 +318,6 @@ func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneRepo
|
||||
}
|
||||
report.DeletedNumber = len(rep.NetworksDeleted)
|
||||
case "volume":
|
||||
versions, err := client.ServerVersion(context.Background())
|
||||
if err != nil {
|
||||
return report, err
|
||||
}
|
||||
if common.ComparePanelVersion(versions.APIVersion, "1.42") {
|
||||
pruneFilters.Add("all", "true")
|
||||
}
|
||||
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
|
||||
if err != nil {
|
||||
return report, err
|
||||
@@ -362,7 +350,6 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
newContainer, _ := client.ContainerInspect(ctx, req.Name)
|
||||
if newContainer.ContainerJSONBase != nil {
|
||||
@@ -410,7 +397,6 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
oldContainer, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
@@ -481,7 +467,6 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
newContainer, _ := client.ContainerInspect(ctx, req.Name)
|
||||
if newContainer.ContainerJSONBase != nil && newContainer.ID != req.ContainerID {
|
||||
@@ -530,7 +515,6 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
oldContainer, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
@@ -578,7 +562,6 @@ func (u *ContainerService) ContainerRename(req dto.ContainerRename) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
newContainer, _ := client.ContainerInspect(ctx, req.NewName)
|
||||
if newContainer.ContainerJSONBase != nil {
|
||||
@@ -594,7 +577,6 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, item := range req.Names {
|
||||
global.LOG.Infof("start container %s operation %s", item, req.Operation)
|
||||
switch req.Operation {
|
||||
@@ -622,7 +604,6 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
ctx := context.Background()
|
||||
containerItem, err := client.ContainerInspect(ctx, req.Name)
|
||||
if err != nil {
|
||||
@@ -741,7 +722,6 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
res, err := client.ContainerStats(context.TODO(), id, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -777,7 +757,6 @@ func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) s
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer cli.Close()
|
||||
options := container.ListOptions{All: true}
|
||||
options.Filters = filters.NewArgs()
|
||||
options.Filters.Add("label", fmt.Sprintf("%s=%s", composeProjectLabel, req.Name))
|
||||
@@ -918,11 +897,12 @@ func loadCpuAndMem(client *client.Client, container string) dto.ContainerListSta
|
||||
return data
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
res.Body.Close()
|
||||
return data
|
||||
}
|
||||
res.Body.Close()
|
||||
var stats *types.StatsJSON
|
||||
if err := json.Unmarshal(body, &stats); err != nil {
|
||||
return data
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -12,8 +13,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
@@ -40,7 +39,6 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
options := container.ListOptions{All: true}
|
||||
options.Filters = filters.NewArgs()
|
||||
|
||||
@@ -19,7 +19,6 @@ func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
@@ -82,7 +81,6 @@ func (u *ContainerService) ListNetwork() ([]dto.Options, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -102,7 +100,6 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, id := range req.Names {
|
||||
if err := client.NetworkRemove(context.TODO(), id); err != nil {
|
||||
if strings.Contains(err.Error(), "has active endpoints") {
|
||||
@@ -118,7 +115,6 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
var (
|
||||
ipams []network.IPAMConfig
|
||||
enableV6 bool
|
||||
|
||||
@@ -82,7 +82,6 @@ func (u *ContainerService) ListVolume() ([]dto.Options, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.VolumeList(context.TODO(), volume.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -103,7 +102,6 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, id := range req.Names {
|
||||
if err := client.VolumeRemove(context.TODO(), id, true); err != nil {
|
||||
if strings.Contains(err.Error(), "volume is in use") {
|
||||
@@ -119,7 +117,6 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
arg := filters.NewArgs()
|
||||
arg.Add("name", req.Name)
|
||||
vos, _ := client.VolumeList(context.TODO(), volume.ListOptions{Filters: arg})
|
||||
|
||||
@@ -41,7 +41,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
||||
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err := handleAppBackup(&app, backupDir, record.FileName, cronjob.ExclusionRules); err != nil {
|
||||
if err := handleAppBackup(&app, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
@@ -74,7 +74,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
|
||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain))
|
||||
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405")+common.RandStrAndNum(5))
|
||||
if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules); err != nil {
|
||||
if err := handleWebsiteBackup(&web, backupDir, record.FileName); err != nil {
|
||||
return err
|
||||
}
|
||||
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
|
||||
|
||||
@@ -456,7 +456,7 @@ func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool,
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
hosts, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "select host from mysql.user where user='root';")
|
||||
hosts, err := executeSqlForRows(app.ContainerName, app.Password, "select host from mysql.user where user='root';")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -474,7 +474,7 @@ func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.Mys
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
variableMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global variables;")
|
||||
variableMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global variables;")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -493,7 +493,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statusMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global status;")
|
||||
statusMap, err := executeSqlForMaps(app.ContainerName, app.Password, "show global status;")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -517,7 +517,7 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
|
||||
info.File = "OFF"
|
||||
info.Position = "OFF"
|
||||
rows, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "show master status;")
|
||||
rows, err := executeSqlForRows(app.ContainerName, app.Password, "show master status;")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -532,8 +532,8 @@ func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlS
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func executeSqlForMaps(containerName, dbType, password, command string) (map[string]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||
func executeSqlForMaps(containerName, password, command string) (map[string]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||
@@ -551,8 +551,8 @@ func executeSqlForMaps(containerName, dbType, password, command string) (map[str
|
||||
return rowMap, nil
|
||||
}
|
||||
|
||||
func executeSqlForRows(containerName, dbType, password, command string) ([]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
||||
func executeSqlForRows(containerName, password, command string) ([]string, error) {
|
||||
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||
@@ -614,7 +614,6 @@ func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
dbInfo.Type = databaseItem.Type
|
||||
dbInfo.From = databaseItem.From
|
||||
dbInfo.Database = database
|
||||
if dbInfo.From != "local" {
|
||||
|
||||
@@ -55,7 +55,6 @@ func (u *DockerService) LoadDockerStatus() string {
|
||||
if err != nil {
|
||||
return constant.Stopped
|
||||
}
|
||||
defer client.Close()
|
||||
if _, err := client.Ping(context.Background()); err != nil {
|
||||
return constant.Stopped
|
||||
}
|
||||
@@ -73,7 +72,6 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
||||
if err != nil {
|
||||
data.Status = constant.Stopped
|
||||
} else {
|
||||
defer client.Close()
|
||||
if _, err := client.Ping(ctx); err != nil {
|
||||
data.Status = constant.Stopped
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -313,32 +312,12 @@ func (f *FileService) FileDownload(d request.FileDownload) (string, error) {
|
||||
}
|
||||
|
||||
func (f *FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) {
|
||||
var (
|
||||
res response.DirSizeRes
|
||||
)
|
||||
if req.Path == "/proc" {
|
||||
return res, nil
|
||||
}
|
||||
cmd := exec.Command("du", "-s", req.Path)
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
fields := strings.Fields(string(output))
|
||||
if len(fields) == 2 {
|
||||
var cmdSize int64
|
||||
_, err = fmt.Sscanf(fields[0], "%d", &cmdSize)
|
||||
if err == nil {
|
||||
res.Size = float64(cmdSize * 1024)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
fo := files.NewFileOp()
|
||||
size, err := fo.GetDirSize(req.Path)
|
||||
if err != nil {
|
||||
return res, err
|
||||
return response.DirSizeRes{}, err
|
||||
}
|
||||
res.Size = size
|
||||
return res, nil
|
||||
return response.DirSizeRes{Size: size}, nil
|
||||
}
|
||||
|
||||
func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) {
|
||||
|
||||
@@ -307,7 +307,7 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = section.NewKey("command", strings.TrimSpace(req.Command))
|
||||
_, _ = section.NewKey("command", req.Command)
|
||||
_, _ = section.NewKey("directory", req.Dir)
|
||||
_, _ = section.NewKey("autorestart", "true")
|
||||
_, _ = section.NewKey("startsecs", "3")
|
||||
@@ -338,7 +338,7 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
|
||||
}
|
||||
|
||||
commandKey := section.Key("command")
|
||||
commandKey.SetValue(strings.TrimSpace(req.Command))
|
||||
commandKey.SetValue(req.Command)
|
||||
directoryKey := section.Key("directory")
|
||||
directoryKey.SetValue(req.Dir)
|
||||
userKey := section.Key("user")
|
||||
|
||||
@@ -7,15 +7,14 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -54,7 +53,6 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err = client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
@@ -108,7 +106,6 @@ func (u *ImageService) ListAll() ([]dto.ImageInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err := client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -136,7 +133,6 @@ func (u *ImageService) List() ([]dto.Options, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
list, err = client.ImageList(context.Background(), image.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -156,7 +152,6 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
fileName := "Dockerfile"
|
||||
if req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
||||
@@ -240,7 +235,6 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
|
||||
if _, err := os.Stat(dockerLogDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dockerLogDir, os.ModePerm); err != nil {
|
||||
@@ -271,7 +265,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options := image.PullOptions{}
|
||||
options := types.ImagePullOptions{}
|
||||
if repo.Auth {
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
@@ -311,12 +305,10 @@ func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
res, err := client.ImageLoad(context.TODO(), file, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
content, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -332,7 +324,6 @@ func (u *ImageService) ImageSave(req dto.ImageSave) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
out, err := client.ImageSave(context.TODO(), []string{req.TagName})
|
||||
if err != nil {
|
||||
@@ -355,7 +346,6 @@ func (u *ImageService) ImageTag(req dto.ImageTag) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if err := client.ImageTag(context.TODO(), req.SourceID, req.TargetName); err != nil {
|
||||
return err
|
||||
@@ -368,22 +358,23 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options := image.PushOptions{All: true}
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
Password: repo.Password,
|
||||
options := types.ImagePushOptions{}
|
||||
if repo.Auth {
|
||||
authConfig := registry.AuthConfig{
|
||||
Username: repo.Username,
|
||||
Password: repo.Password,
|
||||
}
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||
options.RegistryAuth = authStr
|
||||
newName := fmt.Sprintf("%s/%s", repo.DownloadUrl, req.Name)
|
||||
if newName != req.TagName {
|
||||
if err := client.ImageTag(context.TODO(), req.TagName, newName); err != nil {
|
||||
@@ -425,7 +416,6 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
for _, id := range req.Names {
|
||||
if _, err := client.ImageRemove(context.TODO(), id, types.ImageRemoveOptions{Force: req.Force, PruneChildren: true}); err != nil {
|
||||
if strings.Contains(err.Error(), "image is being used") || strings.Contains(err.Error(), "is using") {
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -9,8 +10,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
|
||||
@@ -77,7 +76,6 @@ func (n NginxService) GetStatus() (response.NginxStatus, error) {
|
||||
if err != nil {
|
||||
return response.NginxStatus{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
content, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return response.NginxStatus{}, err
|
||||
|
||||
@@ -4,14 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
@@ -27,6 +19,13 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/subosito/gotenv"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RuntimeService struct {
|
||||
@@ -44,7 +43,6 @@ type IRuntimeService interface {
|
||||
OperateNodeModules(req request.NodeModuleOperateReq) error
|
||||
SyncForRestart() error
|
||||
SyncRuntimeStatus() error
|
||||
DeleteCheck(installID uint) ([]dto.AppResource, error)
|
||||
}
|
||||
|
||||
func NewRuntimeService() IRuntimeService {
|
||||
@@ -178,18 +176,6 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt
|
||||
return total, res, nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) DeleteCheck(runTimeId uint) ([]dto.AppResource, error) {
|
||||
var res []dto.AppResource
|
||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithRuntimeID(runTimeId))
|
||||
for _, website := range websites {
|
||||
res = append(res, dto.AppResource{
|
||||
Type: "website",
|
||||
Name: website.PrimaryDomain,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(runtimeDelete.ID))
|
||||
if err != nil {
|
||||
@@ -207,7 +193,6 @@ func (r *RuntimeService) Delete(runtimeDelete request.RuntimeDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
imageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -435,7 +420,6 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
imageID, err := client.GetImageIDByName(oldImage)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,15 +3,6 @@ package service
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
@@ -22,6 +13,14 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/subosito/gotenv"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
|
||||
@@ -54,12 +53,7 @@ func handleNode(create request.RuntimeCreate, runtime *model.Runtime, fileOp fil
|
||||
}
|
||||
|
||||
go func() {
|
||||
res, err := http.Get(nodeDetail.DownloadCallBackUrl)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("http request failed(handleNode), err: %v", err)
|
||||
return
|
||||
}
|
||||
res.Body.Close()
|
||||
_, _ = http.Get(nodeDetail.DownloadCallBackUrl)
|
||||
}()
|
||||
go startRuntime(runtime)
|
||||
|
||||
@@ -150,7 +144,6 @@ func runComposeCmdWithLog(operate string, composePath string, logPath string) er
|
||||
global.LOG.Errorf("Failed to open log file: %v", err)
|
||||
return err
|
||||
}
|
||||
defer logFile.Close()
|
||||
multiWriterStdout := io.MultiWriter(os.Stdout, logFile)
|
||||
cmd.Stdout = multiWriterStdout
|
||||
var stderrBuf bytes.Buffer
|
||||
@@ -179,7 +172,6 @@ func SyncRuntimeContainerStatus(runtime *model.Runtime) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err := cli.ListContainersByName(containerNames)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -236,7 +228,6 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
|
||||
if oldImageID != "" {
|
||||
client, err := docker.NewClient()
|
||||
if err == nil {
|
||||
defer client.Close()
|
||||
newImageID, err := client.GetImageIDByName(runtime.Image)
|
||||
if err == nil && newImageID != oldImageID {
|
||||
global.LOG.Infof("delete imageID [%s] ", oldImageID)
|
||||
@@ -399,7 +390,6 @@ func checkContainerName(name string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dockerCli.Close()
|
||||
names, err := dockerCli.ListContainersByName([]string{name})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+47
-133
@@ -7,11 +7,12 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
@@ -36,43 +37,45 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
DeveloperMode, err := settingRepo.Get(settingRepo.WithByKey("DeveloperMode"))
|
||||
|
||||
latestVersion, err := u.loadVersion(true, currentVersion.Value)
|
||||
if err != nil {
|
||||
global.LOG.Infof("load latest version failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
upgrade.TestVersion, upgrade.NewVersion, upgrade.LatestVersion = u.loadVersionByMode(DeveloperMode.Value, currentVersion.Value)
|
||||
var itemVersion string
|
||||
if len(upgrade.LatestVersion) != 0 {
|
||||
itemVersion = upgrade.LatestVersion
|
||||
if !common.ComparePanelVersion(string(latestVersion), currentVersion.Value) {
|
||||
return nil, err
|
||||
}
|
||||
if len(upgrade.NewVersion) != 0 {
|
||||
upgrade.LatestVersion = latestVersion
|
||||
if latestVersion[0:4] == currentVersion.Value[0:4] {
|
||||
upgrade.NewVersion = ""
|
||||
} else {
|
||||
newerVersion, err := u.loadVersion(false, currentVersion.Value)
|
||||
if err != nil {
|
||||
global.LOG.Infof("load newer version failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if newerVersion == currentVersion.Value {
|
||||
upgrade.NewVersion = ""
|
||||
} else {
|
||||
upgrade.NewVersion = newerVersion
|
||||
}
|
||||
}
|
||||
itemVersion := upgrade.LatestVersion
|
||||
if upgrade.NewVersion != "" {
|
||||
itemVersion = upgrade.NewVersion
|
||||
}
|
||||
if (global.CONF.System.Mode == "dev" || DeveloperMode.Value == "enable") && len(upgrade.TestVersion) != 0 {
|
||||
itemVersion = upgrade.TestVersion
|
||||
}
|
||||
if len(itemVersion) == 0 {
|
||||
return &upgrade, nil
|
||||
}
|
||||
mode := global.CONF.System.Mode
|
||||
if strings.Contains(itemVersion, "beta") {
|
||||
mode = "beta"
|
||||
}
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, mode, itemVersion, itemVersion))
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, itemVersion, itemVersion))
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", itemVersion, err)
|
||||
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", latestVersion, err)
|
||||
}
|
||||
upgrade.ReleaseNote = notes
|
||||
return &upgrade, nil
|
||||
}
|
||||
|
||||
func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
|
||||
mode := global.CONF.System.Mode
|
||||
if strings.Contains(req.Version, "beta") {
|
||||
mode = "beta"
|
||||
}
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, mode, req.Version, req.Version))
|
||||
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version, req.Version))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load releases-notes of version %s failed, err: %v", req.Version, err)
|
||||
}
|
||||
@@ -96,11 +99,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
return err
|
||||
}
|
||||
|
||||
mode := global.CONF.System.Mode
|
||||
if strings.Contains(req.Version, "beta") {
|
||||
mode = "beta"
|
||||
}
|
||||
downloadPath := fmt.Sprintf("%s/%s/%s/release", global.CONF.System.RepoUrl, mode, req.Version)
|
||||
downloadPath := fmt.Sprintf("%s/%s/%s/release", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version)
|
||||
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", itemArch)
|
||||
_ = settingRepo.Update("SystemStatus", "Upgrading")
|
||||
go func() {
|
||||
@@ -174,8 +173,8 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
|
||||
if err := fileOp.Copy("/etc/systemd/system/1panel.service", originalDir); err != nil {
|
||||
return err
|
||||
}
|
||||
checkPointOfWal()
|
||||
if err := handleTar(path.Join(global.CONF.System.BaseDir, "1panel/db"), originalDir, "db.tar.gz", "db/1Panel.db-*"); err != nil {
|
||||
dbPath := global.CONF.System.DbPath + "/" + global.CONF.System.DbFile
|
||||
if err := fileOp.Copy(dbPath, originalDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -183,17 +182,8 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
|
||||
|
||||
func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
|
||||
checkPointOfWal()
|
||||
if _, err := os.Stat(path.Join(originalDir, "1Panel.db")); err == nil {
|
||||
if err := common.CopyFile(path.Join(originalDir, "1Panel.db"), global.CONF.System.DbPath); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel db failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path.Join(originalDir, "db.tar.gz")); err == nil {
|
||||
if err := handleUnTar(path.Join(originalDir, "db.tar.gz"), global.CONF.System.DbPath); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel db failed, err: %v", err)
|
||||
}
|
||||
if err := common.CopyFile(path.Join(originalDir, "1Panel.db"), global.CONF.System.DbPath); err != nil {
|
||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||
}
|
||||
if err := common.CopyFile(path.Join(originalDir, "1panel"), "/usr/local/bin"); err != nil {
|
||||
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
|
||||
@@ -212,112 +202,36 @@ func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UpgradeService) loadVersionByMode(developer, currentVersion string) (string, string, string) {
|
||||
var current, latest string
|
||||
if global.CONF.System.Mode == "dev" {
|
||||
betaVersionLatest := u.loadVersion(true, currentVersion, "beta")
|
||||
devVersionLatest := u.loadVersion(true, currentVersion, "dev")
|
||||
if common.ComparePanelVersion(betaVersionLatest, devVersionLatest) {
|
||||
return betaVersionLatest, "", ""
|
||||
}
|
||||
return devVersionLatest, "", ""
|
||||
}
|
||||
|
||||
betaVersionLatest := ""
|
||||
latest = u.loadVersion(true, currentVersion, "stable")
|
||||
current = u.loadVersion(false, currentVersion, "stable")
|
||||
if developer == "enable" {
|
||||
betaVersionLatest = u.loadVersion(true, currentVersion, "beta")
|
||||
}
|
||||
if current != latest {
|
||||
return betaVersionLatest, current, latest
|
||||
}
|
||||
|
||||
versionPart := strings.Split(current, ".")
|
||||
if len(versionPart) < 3 {
|
||||
return betaVersionLatest, current, latest
|
||||
}
|
||||
num, _ := strconv.Atoi(versionPart[1])
|
||||
if num == 0 {
|
||||
return betaVersionLatest, current, latest
|
||||
}
|
||||
if num >= 10 {
|
||||
if current[:6] == currentVersion[:6] {
|
||||
return betaVersionLatest, current, ""
|
||||
}
|
||||
return betaVersionLatest, "", latest
|
||||
}
|
||||
if current[:5] == currentVersion[:5] {
|
||||
return betaVersionLatest, current, ""
|
||||
}
|
||||
return betaVersionLatest, "", latest
|
||||
}
|
||||
|
||||
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion, mode string) string {
|
||||
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, mode)
|
||||
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (string, error) {
|
||||
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode)
|
||||
if !isLatest {
|
||||
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, mode)
|
||||
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, global.CONF.System.Mode)
|
||||
}
|
||||
latestVersionRes, err := http.Get(path)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load latest version from oss failed, err: %v", err)
|
||||
return ""
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
defer latestVersionRes.Body.Close()
|
||||
versionByte, err := io.ReadAll(latestVersionRes.Body)
|
||||
version := string(versionByte)
|
||||
if err != nil || strings.Contains(version, "<") {
|
||||
global.LOG.Errorf("load latest version from oss failed, err: %v", version)
|
||||
return ""
|
||||
version, err := io.ReadAll(latestVersionRes.Body)
|
||||
if err != nil {
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
if isLatest {
|
||||
return u.checkVersion(version, currentVersion)
|
||||
return string(version), nil
|
||||
}
|
||||
|
||||
versionMap := make(map[string]string)
|
||||
if err := json.Unmarshal(versionByte, &versionMap); err != nil {
|
||||
global.LOG.Errorf("load latest version from oss failed (error unmarshal), err: %v", err)
|
||||
return ""
|
||||
if err := json.Unmarshal(version, &versionMap); err != nil {
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
|
||||
versionPart := strings.Split(currentVersion, ".")
|
||||
if len(versionPart) < 3 {
|
||||
global.LOG.Errorf("current version is error format: %s", currentVersion)
|
||||
return ""
|
||||
}
|
||||
num, _ := strconv.Atoi(versionPart[1])
|
||||
if num == 0 {
|
||||
global.LOG.Errorf("current version is error format: %s", currentVersion)
|
||||
return ""
|
||||
}
|
||||
if num >= 10 {
|
||||
if version, ok := versionMap[currentVersion[0:5]]; ok {
|
||||
return u.checkVersion(version, currentVersion)
|
||||
}
|
||||
return ""
|
||||
if len(currentVersion) < 4 {
|
||||
return "", fmt.Errorf("current version is error format: %s", currentVersion)
|
||||
}
|
||||
if version, ok := versionMap[currentVersion[0:4]]; ok {
|
||||
return u.checkVersion(version, currentVersion)
|
||||
return version, nil
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (u *UpgradeService) checkVersion(v2, v1 string) string {
|
||||
addSuffix := false
|
||||
if !strings.Contains(v1, "-") {
|
||||
v1 = v1 + "-lts"
|
||||
}
|
||||
if !strings.Contains(v2, "-") {
|
||||
addSuffix = true
|
||||
v2 = v2 + "-lts"
|
||||
}
|
||||
if common.ComparePanelVersion(v2, v1) {
|
||||
if addSuffix {
|
||||
return strings.TrimSuffix(v2, "-lts")
|
||||
}
|
||||
return v2
|
||||
}
|
||||
return ""
|
||||
return "", buserr.New(constant.ErrOSSConn)
|
||||
}
|
||||
|
||||
func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
|
||||
|
||||
@@ -180,9 +180,6 @@ func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
|
||||
|
||||
func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error) {
|
||||
alias := create.Alias
|
||||
if alias == "default" {
|
||||
return buserr.New("ErrDefaultAlias")
|
||||
}
|
||||
if common.ContainsChinese(alias) {
|
||||
alias, err = common.PunycodeEncode(alias)
|
||||
if err != nil {
|
||||
@@ -296,7 +293,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
install *model.AppInstall
|
||||
)
|
||||
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
|
||||
req.Name = reg.ReplaceAllString(strings.ToLower(alias), "")
|
||||
req.Name = reg.ReplaceAllString(strings.ToLower(create.PrimaryDomain), "")
|
||||
req.AppDetailId = create.AppInstall.AppDetailId
|
||||
req.Params = create.AppInstall.Params
|
||||
req.Params["IMAGE_NAME"] = runtime.Image
|
||||
|
||||
@@ -82,7 +82,7 @@ func (w WebsiteCAService) Create(create request.WebsiteCACreate) (*request.Websi
|
||||
}
|
||||
|
||||
rootCA := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(time.Now().Unix() + 1),
|
||||
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||
Subject: pkixName,
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
@@ -279,7 +279,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
notAfter = notAfter.AddDate(0, 0, req.Time)
|
||||
}
|
||||
interCsr := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(time.Now().Unix() + 2),
|
||||
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||
Subject: rootCsr.Subject,
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: notAfter,
|
||||
@@ -315,7 +315,7 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
subject := rootCsr.Subject
|
||||
subject.CommonName = commonName
|
||||
csr := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(time.Now().Unix() + 3),
|
||||
SerialNumber: big.NewInt(time.Now().Unix()),
|
||||
Subject: subject,
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: notAfter,
|
||||
@@ -346,7 +346,6 @@ func (w WebsiteCAService) ObtainSSL(req request.WebsiteCAObtain) (*model.Website
|
||||
websiteSSL.StartDate = cert.NotBefore
|
||||
websiteSSL.Type = cert.Issuer.CommonName
|
||||
websiteSSL.Organization = rootCsr.Subject.Organization[0]
|
||||
websiteSSL.Status = constant.SSLReady
|
||||
|
||||
if req.Renew {
|
||||
if err := websiteSSLRepo.Save(websiteSSL); err != nil {
|
||||
|
||||
@@ -102,12 +102,6 @@ func (w WebsiteSSLService) Search(search request.WebsiteSSLSearch) ([]response.W
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error) {
|
||||
if create.Nameserver1 != "" && !common.IsValidIP(create.Nameserver1) {
|
||||
return create, buserr.New("ErrParseIP")
|
||||
}
|
||||
if create.Nameserver2 != "" && !common.IsValidIP(create.Nameserver2) {
|
||||
return create, buserr.New("ErrParseIP")
|
||||
}
|
||||
var res request.WebsiteSSLCreate
|
||||
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(create.AcmeAccountID))
|
||||
if err != nil {
|
||||
@@ -122,10 +116,6 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
||||
KeyType: create.KeyType,
|
||||
PushDir: create.PushDir,
|
||||
Description: create.Description,
|
||||
Nameserver1: create.Nameserver1,
|
||||
Nameserver2: create.Nameserver2,
|
||||
SkipDNS: create.SkipDNS,
|
||||
DisableCNAME: create.DisableCNAME,
|
||||
}
|
||||
if create.PushDir {
|
||||
if !files.NewFileOp().Stat(create.Dir) {
|
||||
@@ -201,7 +191,7 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, *websiteSSL); err != nil {
|
||||
if err = client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization, apply.SkipDNSCheck); err != nil {
|
||||
return err
|
||||
}
|
||||
case constant.Http:
|
||||
@@ -378,60 +368,15 @@ func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams := make(map[string]interface{})
|
||||
updateParams["primary_domain"] = update.PrimaryDomain
|
||||
updateParams["description"] = update.Description
|
||||
updateParams["provider"] = update.Provider
|
||||
updateParams["key_type"] = update.KeyType
|
||||
updateParams["push_dir"] = update.PushDir
|
||||
updateParams["disable_cname"] = update.DisableCNAME
|
||||
updateParams["skip_dns"] = update.SkipDNS
|
||||
updateParams["nameserver1"] = update.Nameserver1
|
||||
updateParams["nameserver2"] = update.Nameserver2
|
||||
|
||||
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(update.AcmeAccountID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams["acme_account_id"] = acmeAccount.ID
|
||||
|
||||
if update.PushDir {
|
||||
if !files.NewFileOp().Stat(update.Dir) {
|
||||
return buserr.New(constant.ErrLinkPathNotFound)
|
||||
}
|
||||
updateParams["dir"] = update.Dir
|
||||
}
|
||||
var domains []string
|
||||
if update.OtherDomains != "" {
|
||||
otherDomainArray := strings.Split(update.OtherDomains, "\n")
|
||||
for _, domain := range otherDomainArray {
|
||||
if !common.IsValidDomain(domain) {
|
||||
return buserr.WithName("ErrDomainFormat", domain)
|
||||
}
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
}
|
||||
updateParams["domains"] = strings.Join(domains, ",")
|
||||
if update.Provider == constant.DNSAccount || update.Provider == constant.Http {
|
||||
updateParams["auto_renew"] = update.AutoRenew
|
||||
} else {
|
||||
updateParams["auto_renew"] = false
|
||||
}
|
||||
if update.Provider == constant.DNSAccount {
|
||||
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(update.DnsAccountID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams["dns_account_id"] = dnsAccount.ID
|
||||
}
|
||||
return websiteSSLRepo.SaveByMap(websiteSSL, updateParams)
|
||||
websiteSSL.AutoRenew = update.AutoRenew
|
||||
websiteSSL.Description = update.Description
|
||||
return websiteSSLRepo.Save(websiteSSL)
|
||||
}
|
||||
|
||||
func (w WebsiteSSLService) Upload(req request.WebsiteSSLUpload) error {
|
||||
websiteSSL := &model.WebsiteSSL{
|
||||
Provider: constant.Manual,
|
||||
Description: req.Description,
|
||||
Status: constant.SSLReady,
|
||||
}
|
||||
var err error
|
||||
if req.SSLID > 0 {
|
||||
|
||||
@@ -362,11 +362,11 @@ func createWafConfig(website *model.Website, domains []model.WebsiteDomain) erro
|
||||
return err
|
||||
}
|
||||
}
|
||||
defaultRulesName := []string{"acl", "args", "cookie", "defaultUaBlack", "defaultUrlBlack", "fileExt", "header", "methodWhite", "cdn"}
|
||||
defaultRulesName := []string{"acl", "args", "cookie", "defaultUaBlack", "defaultUrlBlack", "fileExt", "header", "methodWhite"}
|
||||
for _, ruleName := range defaultRulesName {
|
||||
srcPath := path.Join(defaultRuleDir, ruleName+".json")
|
||||
if fileOp.Stat(srcPath) {
|
||||
_ = fileOp.Copy(srcPath, websiteRuleDir)
|
||||
if err = fileOp.Copy(srcPath, websiteRuleDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
mathRand "math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -43,7 +41,7 @@ func Run() {
|
||||
if _, err := global.Cron.AddJob("@daily", job.NewSSLJob()); err != nil {
|
||||
global.LOG.Errorf("can not add ssl corn job: %s", err.Error())
|
||||
}
|
||||
if _, err := global.Cron.AddJob(fmt.Sprintf("%v %v * * *", mathRand.Intn(60), mathRand.Intn(3)), job.NewAppStoreJob()); err != nil {
|
||||
if _, err := global.Cron.AddJob("@daily", job.NewAppStoreJob()); err != nil {
|
||||
global.LOG.Errorf("can not add appstore corn job: %s", err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -31,27 +31,6 @@ func GetMsgWithMap(key string, maps map[string]interface{}) string {
|
||||
}
|
||||
}
|
||||
|
||||
func GetMsgWithName(key string, name string, err error) string {
|
||||
var (
|
||||
content string
|
||||
dataMap = make(map[string]interface{})
|
||||
)
|
||||
dataMap["name"] = name
|
||||
if err != nil {
|
||||
dataMap["err"] = err.Error()
|
||||
}
|
||||
content, _ = global.I18n.Localize(&i18n.LocalizeConfig{
|
||||
MessageID: key,
|
||||
TemplateData: dataMap,
|
||||
})
|
||||
content = strings.ReplaceAll(content, "<no value>", "")
|
||||
if content == "" {
|
||||
return key
|
||||
} else {
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
||||
func GetErrMsg(key string, maps map[string]interface{}) string {
|
||||
var content string
|
||||
if maps == nil {
|
||||
|
||||
@@ -61,12 +61,6 @@ AppStoreIsSyncing: 'The App Store is syncing, please try again later'
|
||||
ErrGetCompose: "Failed to obtain docker-compose.yml file! {{ .detail }}"
|
||||
ErrAppWarn: "Abnormal status, please check the log"
|
||||
ErrAppParamKey: "Parameter {{ .name }} field exception"
|
||||
ErrAppUpgrade: "Failed to upgrade application {{ .name }} {{ .err }}"
|
||||
AppRecover: "App {{ .name }} rolled back "
|
||||
PullImageStart: "Start pulling image {{ .name }}"
|
||||
PullImageSuccess: "Image pulled successfully"
|
||||
UpgradeAppStart: "Start upgrading application {{ .name }}"
|
||||
UpgradeAppSuccess: "App {{ .name }} upgraded successfully"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "File can not read"
|
||||
@@ -87,13 +81,12 @@ ErrDomainIsExist: "Domain is already exist"
|
||||
ErrAliasIsExist: "Alias is already exist"
|
||||
ErrAppDelete: 'Other Website use this App'
|
||||
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
|
||||
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}'
|
||||
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}'
|
||||
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}"'
|
||||
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}"'
|
||||
ErrPHPResource: 'The local runtime does not support switching!'
|
||||
ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the index directory, which may cause an Access denied error when accessing the website. Please click the save button above'
|
||||
ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the index directory, which may cause Access denied errors when accessing the website.'
|
||||
ErrDomainIsUsed: "Domain is already used by website {{ .name }}"
|
||||
ErrDomainFormat: "{{ .name }} domain format error"
|
||||
ErrDefaultAlias: "default is a reserved code name, please use another code name"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "The certificate {{ .name }} is being used by the website and cannot be removed"
|
||||
@@ -185,7 +178,6 @@ ErrDefaultIP: "default is a reserved name, please change it to another name"
|
||||
ErrGroupInUse: "The IP group is used by the black/white list and cannot be deleted"
|
||||
ErrGroupExist: "IP group name already exists"
|
||||
ErrIPRange: "Wrong IP range"
|
||||
ErrIPExist: "IP is exit"
|
||||
|
||||
#license
|
||||
ErrLicense: "License format error, please check and try again!"
|
||||
|
||||
@@ -62,12 +62,6 @@ AppStoreIsSyncing: '應用程式商店正在同步中,請稍後再試'
|
||||
ErrGetCompose: "docker-compose.yml 檔案取得失敗!{{ .detail }}"
|
||||
ErrAppWarn: "狀態異常,請查看日誌"
|
||||
ErrAppParamKey: "參數 {{ .name }} 欄位異常"
|
||||
ErrAppUpgrade: "應用程式 {{ .name }} 升級失敗 {{ .err }}"
|
||||
AppRecover: "應用程式 {{ .name }} 回滾 "
|
||||
PullImageStart: "開始拉取鏡像 {{ .name }}"
|
||||
PullImageSuccess: "鏡像拉取成功"
|
||||
UpgradeAppStart: "開始升級應用程式 {{ .name }}"
|
||||
UpgradeAppSuccess: "應用程式 {{ .name }} 升級成功"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持預覽"
|
||||
@@ -87,13 +81,12 @@ ErrDomainIsExist: "域名已存在"
|
||||
ErrAliasIsExist: "代號已存在"
|
||||
ErrAppDelete: '其他網站使用此應用,無法刪除'
|
||||
ErrGroupIsUsed: '分組正在使用中,無法刪除'
|
||||
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}'
|
||||
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}'
|
||||
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}"'
|
||||
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}"'
|
||||
ErrPHPResource: '本地運行環境不支持切換!'
|
||||
ErrPathPermission: 'index 目錄下偵測到非 1000:1000 權限資料夾,可能導致網站存取 Access denied 錯誤,請點擊上方儲存按鈕'
|
||||
ErrPathPermission: 'index 目錄下檢測到非 1000:1000 權限文件夾,可能導致網站訪問 Access denied 錯誤'
|
||||
ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正確"
|
||||
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
|
||||
@@ -179,15 +172,13 @@ ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後
|
||||
#waf
|
||||
ErrScope: "不支援修改此配置"
|
||||
ErrStateChange: "狀態修改失敗"
|
||||
ErrRuleExist: "規則已存在"
|
||||
ErrRuleExist: "規則名稱已存在"
|
||||
ErrRuleNotExist: "規則不存在"
|
||||
ErrParseIP: "IP 格式錯誤"
|
||||
ErrDefaultIP: "default 為保留名稱,請更換其他名稱"
|
||||
ErrGroupInUse: "IP 群組被黑/白名單使用,無法刪除"
|
||||
ErrGroupExist: "IP 群組名稱已存在"
|
||||
ErrIPRange: "IP 範圍錯誤"
|
||||
ErrIPExist: "IP 已存在"
|
||||
|
||||
|
||||
#license
|
||||
ErrLicense: "許可證格式錯誤,請檢查後重試!"
|
||||
|
||||
@@ -61,12 +61,6 @@ AppStoreIsSyncing: '应用商店正在同步中,请稍后再试'
|
||||
ErrGetCompose: "docker-compose.yml 文件获取失败!{{ .detail }}"
|
||||
ErrAppWarn: "状态异常,请查看日志"
|
||||
ErrAppParamKey: "参数 {{ .name }} 字段异常"
|
||||
ErrAppUpgrade: "应用 {{ .name }} 升级失败 {{ .err }}"
|
||||
AppRecover: "应用 {{ .name }} 回滚 "
|
||||
PullImageStart: "开始拉取镜像 {{ .name }}"
|
||||
PullImageSuccess: "镜像拉取成功"
|
||||
UpgradeAppStart: "开始升级应用 {{ .name }}"
|
||||
UpgradeAppSuccess: "应用 {{ .name }} 升级成功"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持预览"
|
||||
@@ -87,13 +81,12 @@ ErrDomainIsExist: "域名已存在"
|
||||
ErrAliasIsExist: "代号已存在"
|
||||
ErrAppDelete: '其他网站使用此应用,无法删除'
|
||||
ErrGroupIsUsed: '分组正在使用中,无法删除'
|
||||
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}'
|
||||
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}'
|
||||
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}"'
|
||||
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}"'
|
||||
ErrPHPResource: '本地运行环境不支持切换!'
|
||||
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误,请点击上方保存按钮'
|
||||
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误'
|
||||
ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正确"
|
||||
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
|
||||
@@ -178,14 +171,13 @@ ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后
|
||||
#waf
|
||||
ErrScope: "不支持修改此配置"
|
||||
ErrStateChange: "状态修改失败"
|
||||
ErrRuleExist: "规则已存在"
|
||||
ErrRuleExist: "规则名称已存在"
|
||||
ErrRuleNotExist: "规则不存在"
|
||||
ErrParseIP: "IP 格式错误"
|
||||
ErrDefaultIP: "default 为保留名称,请更换其他名称"
|
||||
ErrGroupInUse: "IP 组被黑/白名单使用,无法删除"
|
||||
ErrGroupExist: "IP 组名称已存在"
|
||||
ErrIPRange: "IP 范围错误"
|
||||
ErrIPExist: "IP 已存在"
|
||||
|
||||
#license
|
||||
ErrLicense: "许可证格式错误,请检查后重试!"
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -64,7 +63,6 @@ func Init() {
|
||||
handleCronjobStatus()
|
||||
handleSnapStatus()
|
||||
loadLocalDir()
|
||||
initDir()
|
||||
}
|
||||
|
||||
func handleSnapStatus() {
|
||||
@@ -200,13 +198,3 @@ func handleUserInfo(tags string, settingRepo repo.ISettingRepo) {
|
||||
sudo := cmd.SudoHandleCmd()
|
||||
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=%v/d' /usr/local/bin/1pctl", sudo, global.CONF.System.ChangeUserInfo)
|
||||
}
|
||||
|
||||
func initDir() {
|
||||
composePath := path.Join(global.CONF.System.BaseDir, "1panel/docker/compose/")
|
||||
if _, err := os.Stat(composePath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(composePath, os.ModePerm); err != nil {
|
||||
global.LOG.Errorf("mkdir %s failed, err: %v", composePath, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,9 +81,6 @@ func Init() {
|
||||
migrations.AddNoAuthSetting,
|
||||
migrations.UpdateXpackHideMenu,
|
||||
migrations.AddMenuTabsSetting,
|
||||
migrations.AddDeveloperSetting,
|
||||
|
||||
migrations.AddWebsiteSSLColumn,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -144,23 +144,3 @@ var AddMenuTabsSetting = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddDeveloperSetting = &gormigrate.Migration{
|
||||
ID: "20240423-add-developer-setting",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&model.Setting{Key: "DeveloperMode", Value: "disable"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddWebsiteSSLColumn = &gormigrate.Migration{
|
||||
ID: "20240508-update-website-ssl",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -124,9 +124,6 @@ var AddTablePHPExtensions = &gormigrate.Migration{
|
||||
if err := tx.Create(&model.PHPExtensions{Name: "默认", Extensions: "bcmath,gd,gettext,intl,pcntl,shmop,soap,sockets,sysvsem,xmlrpc,zip"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.PHPExtensions{Name: "WordPress", Extensions: "exif,igbinary,imagick,intl,zip,apcu,memcached,opcache,redis,bc,image,shmop,mysqli,pdo_mysql"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.PHPExtensions{Name: "苹果CMS-V10", Extensions: "mysqli,pdo_mysql,zip,gd,redis,memcache,memcached"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -27,9 +27,6 @@ var whiteUrlList = map[string]struct{}{
|
||||
"/api/v1/databases/variables": {},
|
||||
"/api/v1/databases/status": {},
|
||||
"/api/v1/databases/baseinfo": {},
|
||||
|
||||
"/api/v1/waf/attack/stat": {},
|
||||
"/api/v1/waf/config/website": {},
|
||||
}
|
||||
|
||||
func DemoHandle() gin.HandlerFunc {
|
||||
|
||||
@@ -15,7 +15,6 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
groupRouter.GET("/installed/delete/check/:runTimeId", baseApi.DeleteRuntimeCheck)
|
||||
groupRouter.POST("/search", baseApi.SearchRuntimes)
|
||||
groupRouter.POST("", baseApi.CreateRuntime)
|
||||
groupRouter.POST("/del", baseApi.DeleteRuntime)
|
||||
|
||||
@@ -223,11 +223,11 @@ func RefreshToken(grantType string, varMap map[string]interface{}) (string, stri
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("request for access token failed, err: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("read data from response body failed, err: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
tokenMap := map[string]interface{}{}
|
||||
if err := json.Unmarshal(respBody, &tokenMap); err != nil {
|
||||
@@ -387,9 +387,9 @@ func (o *oneDriveClient) upBig(ctx context.Context, srcPath, folderID string, fi
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
res.Body.Close()
|
||||
if res.StatusCode != 201 && res.StatusCode != 202 && res.StatusCode != 200 {
|
||||
data, _ := io.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
return false, errors.New(string(data))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ func (s sftpClient) Upload(src, target string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
client, err := sftp.NewClient(sshClient)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer client.Close()
|
||||
defer sshClient.Close()
|
||||
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
|
||||
@@ -49,8 +49,8 @@ func ComparePanelVersion(version1, version2 string) bool {
|
||||
if version1 == version2 {
|
||||
return false
|
||||
}
|
||||
version1s := SplitStr(version1, ".", "-")
|
||||
version2s := SplitStr(version2, ".", "-")
|
||||
version1s := strings.Split(version1, ".")
|
||||
version2s := strings.Split(version2, ".")
|
||||
|
||||
if len(version2s) > len(version1s) {
|
||||
for i := 0; i < len(version2s)-len(version1s); i++ {
|
||||
@@ -68,15 +68,7 @@ func ComparePanelVersion(version1, version2 string) bool {
|
||||
if version1s[i] == version2s[i] {
|
||||
continue
|
||||
} else {
|
||||
v1, err1 := strconv.Atoi(version1s[i])
|
||||
if err1 != nil {
|
||||
return version1s[i] > version2s[i]
|
||||
}
|
||||
v2, err2 := strconv.Atoi(version2s[i])
|
||||
if err2 != nil {
|
||||
return version1s[i] > version2s[i]
|
||||
}
|
||||
return v1 > v2
|
||||
return version1s[i] > version2s[i]
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -304,20 +296,3 @@ func PunycodeEncode(text string) (string, error) {
|
||||
}
|
||||
return ascii, nil
|
||||
}
|
||||
|
||||
func SplitStr(str string, spi ...string) []string {
|
||||
lists := []string{str}
|
||||
var results []string
|
||||
for _, s := range spi {
|
||||
results = []string{}
|
||||
for _, list := range lists {
|
||||
results = append(results, strings.Split(list, s)...)
|
||||
}
|
||||
lists = results
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func IsValidIP(ip string) bool {
|
||||
return net.ParseIP(ip) != nil
|
||||
}
|
||||
|
||||
@@ -33,10 +33,6 @@ func NewClient() (Client, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c Client) Close() {
|
||||
_ = c.cli.Close()
|
||||
}
|
||||
|
||||
func NewDockerClient() (*client.Client, error) {
|
||||
var settingItem model.Setting
|
||||
_ = global.DB.Where("key = ?", "DockerSockPath").First(&settingItem).Error
|
||||
@@ -154,7 +150,6 @@ func CreateDefaultDockerNetwork() error {
|
||||
global.LOG.Errorf("init docker client error %s", err.Error())
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
if !cli.NetworkExist("1panel-network") {
|
||||
if err := cli.CreateNetwork("1panel-network"); err != nil {
|
||||
global.LOG.Errorf("create default docker network error %s", err.Error())
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
@@ -435,20 +436,20 @@ func (f FileOp) CopyFile(src, dst string) error {
|
||||
}
|
||||
|
||||
func (f FileOp) GetDirSize(path string) (float64, error) {
|
||||
var size int64
|
||||
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
size += info.Size()
|
||||
}
|
||||
return nil
|
||||
var m sync.Map
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
go ScanDir(f.Fs, path, &m, &wg)
|
||||
wg.Wait()
|
||||
|
||||
var dirSize float64
|
||||
m.Range(func(k, v interface{}) bool {
|
||||
dirSize = dirSize + v.(float64)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float64(size), nil
|
||||
|
||||
return dirSize, nil
|
||||
}
|
||||
|
||||
func getFormat(cType CompressType) archiver.CompressedArchive {
|
||||
|
||||
@@ -10,6 +10,9 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func IsSymlink(mode os.FileMode) bool {
|
||||
@@ -60,6 +63,22 @@ func GetGroup(gid uint32) string {
|
||||
return usr.Name
|
||||
}
|
||||
|
||||
func ScanDir(fs afero.Fs, path string, dirMap *sync.Map, wg *sync.WaitGroup) {
|
||||
afs := &afero.Afero{Fs: fs}
|
||||
files, _ := afs.ReadDir(path)
|
||||
for _, f := range files {
|
||||
if f.IsDir() {
|
||||
wg.Add(1)
|
||||
go ScanDir(fs, filepath.Join(path, f.Name()), dirMap, wg)
|
||||
} else {
|
||||
if f.Size() > 0 {
|
||||
dirMap.Store(filepath.Join(path, f.Name()), float64(f.Size()))
|
||||
}
|
||||
}
|
||||
}
|
||||
defer wg.Done()
|
||||
}
|
||||
|
||||
const dotCharacter = 46
|
||||
|
||||
func IsHidden(path string) bool {
|
||||
|
||||
@@ -4,12 +4,11 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
)
|
||||
|
||||
func GetHttpRes(url string) (*http.Response, error) {
|
||||
|
||||
@@ -30,8 +30,8 @@ type MysqlClient interface {
|
||||
|
||||
func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
|
||||
if conn.From == "local" {
|
||||
connArgs := []string{"exec", conn.Address, conn.Type, "-u" + conn.Username, "-p" + conn.Password, "-e"}
|
||||
return client.NewLocal(connArgs, conn.Type, conn.Address, conn.Password, conn.Database), nil
|
||||
connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.Username, "-p" + conn.Password, "-e"}
|
||||
return client.NewLocal(connArgs, conn.Address, conn.Password, conn.Database), nil
|
||||
}
|
||||
|
||||
if strings.Contains(conn.Address, ":") {
|
||||
@@ -59,7 +59,6 @@ func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
|
||||
}
|
||||
|
||||
return client.NewRemote(client.Remote{
|
||||
Type: conn.Type,
|
||||
Client: db,
|
||||
Database: conn.Database,
|
||||
User: conn.Username,
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
)
|
||||
|
||||
type DBInfo struct {
|
||||
Type string `json:"type"`
|
||||
From string `json:"from"`
|
||||
Database string `json:"database"`
|
||||
Address string `json:"address"`
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"errors"
|
||||
@@ -19,15 +18,14 @@ import (
|
||||
)
|
||||
|
||||
type Local struct {
|
||||
Type string
|
||||
PrefixCommand []string
|
||||
Database string
|
||||
Password string
|
||||
ContainerName string
|
||||
}
|
||||
|
||||
func NewLocal(command []string, dbType, containerName, password, database string) *Local {
|
||||
return &Local{Type: dbType, PrefixCommand: command, ContainerName: containerName, Password: password, Database: database}
|
||||
func NewLocal(command []string, containerName, password, database string) *Local {
|
||||
return &Local{PrefixCommand: command, ContainerName: containerName, Password: password, Database: database}
|
||||
}
|
||||
|
||||
func (r *Local) Create(info CreateInfo) error {
|
||||
@@ -224,27 +222,14 @@ func (r *Local) Backup(info BackupInfo) error {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", info.TargetDir, err)
|
||||
}
|
||||
}
|
||||
outfile, err := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||
if err == nil {
|
||||
defer outfile.Close()
|
||||
}
|
||||
dumpCmd := "mysqldump"
|
||||
if r.Type == constant.AppMariaDB {
|
||||
dumpCmd = "mariadb-dump"
|
||||
}
|
||||
global.LOG.Infof("start to %s | gzip > %s.gzip", dumpCmd, info.TargetDir+"/"+info.FileName)
|
||||
cmd := exec.Command("docker", "exec", r.ContainerName, dumpCmd, "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
outfile, _ := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||
global.LOG.Infof("start to mysqldump | gzip > %s.gzip", info.TargetDir+"/"+info.FileName)
|
||||
cmd := exec.Command("docker", "exec", r.ContainerName, "mysqldump", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
|
||||
gzipCmd := exec.Command("gzip", "-cf")
|
||||
gzipCmd.Stdin, _ = cmd.StdoutPipe()
|
||||
gzipCmd.Stdout = outfile
|
||||
_ = gzipCmd.Start()
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("handle backup database failed, err: %v", stderr.String())
|
||||
}
|
||||
_ = cmd.Run()
|
||||
_ = gzipCmd.Wait()
|
||||
return nil
|
||||
}
|
||||
@@ -252,7 +237,7 @@ func (r *Local) Backup(info BackupInfo) error {
|
||||
func (r *Local) Recover(info RecoverInfo) error {
|
||||
fi, _ := os.Open(info.SourceFile)
|
||||
defer fi.Close()
|
||||
cmd := exec.Command("docker", "exec", "-i", r.ContainerName, r.Type, "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
|
||||
cmd := exec.Command("docker", "exec", "-i", r.ContainerName, "mysql", "-uroot", "-p"+r.Password, "--default-character-set="+info.Format, info.Name)
|
||||
if strings.HasSuffix(info.SourceFile, ".gz") {
|
||||
gzipFile, err := os.Open(info.SourceFile)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"database/sql"
|
||||
@@ -22,7 +21,6 @@ import (
|
||||
)
|
||||
|
||||
type Remote struct {
|
||||
Type string
|
||||
Client *sql.DB
|
||||
Database string
|
||||
User string
|
||||
@@ -235,35 +233,23 @@ func (r *Remote) Backup(info BackupInfo) error {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", info.TargetDir, err)
|
||||
}
|
||||
}
|
||||
outfile, err := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||
if err == nil {
|
||||
defer outfile.Close()
|
||||
}
|
||||
dumpCmd := "mysqldump"
|
||||
if r.Type == constant.AppMariaDB {
|
||||
dumpCmd = "mariadb-dump"
|
||||
}
|
||||
global.LOG.Infof("start to %s | gzip > %s.gzip", dumpCmd, info.TargetDir+"/"+info.FileName)
|
||||
outfile, _ := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||
global.LOG.Infof("start to mysqldump | gzip > %s.gzip", info.TargetDir+"/"+info.FileName)
|
||||
image, err := loadImage(info.Type, info.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
backupCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c '%s -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
|
||||
image, dumpCmd, r.Address, r.Port, r.User, r.Password, sslSkip(info.Version, r.Type), info.Format, info.Name)
|
||||
backupCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c 'mysqldump -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
|
||||
image, r.Address, r.Port, r.User, r.Password, sslSkip(info.Version), info.Format, info.Name)
|
||||
|
||||
global.LOG.Debug(backupCmd)
|
||||
cmd := exec.Command("bash", "-c", backupCmd)
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
gzipCmd := exec.Command("gzip", "-cf")
|
||||
gzipCmd.Stdin, _ = cmd.StdoutPipe()
|
||||
gzipCmd.Stdout = outfile
|
||||
|
||||
_ = gzipCmd.Start()
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("handle backup database failed, err: %v", stderr.String())
|
||||
}
|
||||
_ = cmd.Run()
|
||||
_ = gzipCmd.Wait()
|
||||
return nil
|
||||
}
|
||||
@@ -277,8 +263,8 @@ func (r *Remote) Recover(info RecoverInfo) error {
|
||||
return err
|
||||
}
|
||||
|
||||
recoverCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c '%s -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
|
||||
image, r.Type, r.Address, r.Port, r.User, r.Password, sslSkip(info.Version, r.Type), info.Format, info.Name)
|
||||
recoverCmd := fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c 'mysql -h %s -P %d -u%s -p%s %s --default-character-set=%s %s'",
|
||||
image, r.Address, r.Port, r.User, r.Password, sslSkip(info.Version), info.Format, info.Name)
|
||||
|
||||
global.LOG.Debug(recoverCmd)
|
||||
cmd := exec.Command("bash", "-c", recoverCmd)
|
||||
@@ -450,8 +436,8 @@ func loadImage(dbType, version string) (string, error) {
|
||||
return "mysql:" + version, nil
|
||||
}
|
||||
|
||||
func sslSkip(version, dbType string) string {
|
||||
if dbType == constant.AppMariaDB || strings.HasPrefix(version, "5.6") || strings.HasPrefix(version, "5.7") {
|
||||
func sslSkip(version string) string {
|
||||
if strings.HasPrefix(version, "5.6") || strings.HasPrefix(version, "5.7") {
|
||||
return "--skip-ssl"
|
||||
}
|
||||
return "--ssl-mode=DISABLED"
|
||||
|
||||
@@ -129,10 +129,7 @@ func (r *Local) Backup(info BackupInfo) error {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", info.TargetDir, err)
|
||||
}
|
||||
}
|
||||
outfile, err := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||
if err == nil {
|
||||
defer outfile.Close()
|
||||
}
|
||||
outfile, _ := os.OpenFile(path.Join(info.TargetDir, info.FileName), os.O_RDWR|os.O_CREATE, 0755)
|
||||
global.LOG.Infof("start to pg_dump | gzip > %s.gzip", info.TargetDir+"/"+info.FileName)
|
||||
cmd := exec.Command("docker", "exec", r.ContainerName, "pg_dump", "-F", "c", "-U", r.Username, "-d", info.Name)
|
||||
gzipCmd := exec.Command("gzip", "-cf")
|
||||
|
||||
@@ -269,7 +269,6 @@ func loadImageTag() (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer client.Close()
|
||||
images, err := client.ImageList(context.Background(), types.ImageListOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
+18
-34
@@ -3,7 +3,6 @@ package ssl
|
||||
import (
|
||||
"crypto"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
@@ -85,7 +84,7 @@ type DNSParam struct {
|
||||
SecretID string `json:"secretID"`
|
||||
}
|
||||
|
||||
func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.WebsiteSSL) error {
|
||||
func (c *AcmeClient) UseDns(dnsType DnsType, params string, skipDNSCheck bool) error {
|
||||
var (
|
||||
param DNSParam
|
||||
p challenge.Provider
|
||||
@@ -100,15 +99,15 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.Web
|
||||
case DnsPod:
|
||||
dnsPodConfig := dnspod.NewDefaultConfig()
|
||||
dnsPodConfig.LoginToken = param.ID + "," + param.Token
|
||||
dnsPodConfig.PropagationTimeout = 15 * time.Minute
|
||||
dnsPodConfig.PollingInterval = 10 * time.Second
|
||||
dnsPodConfig.PropagationTimeout = 60 * time.Minute
|
||||
dnsPodConfig.PollingInterval = 5 * time.Second
|
||||
dnsPodConfig.TTL = 3600
|
||||
p, err = dnspod.NewDNSProviderConfig(dnsPodConfig)
|
||||
case AliYun:
|
||||
alidnsConfig := alidns.NewDefaultConfig()
|
||||
alidnsConfig.SecretKey = param.SecretKey
|
||||
alidnsConfig.APIKey = param.AccessKey
|
||||
alidnsConfig.PropagationTimeout = 15 * time.Minute
|
||||
alidnsConfig.PropagationTimeout = 60 * time.Minute
|
||||
alidnsConfig.PollingInterval = 5 * time.Second
|
||||
alidnsConfig.TTL = 3600
|
||||
p, err = alidns.NewDNSProviderConfig(alidnsConfig)
|
||||
@@ -116,73 +115,58 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string, websiteSSL model.Web
|
||||
cloudflareConfig := cloudflare.NewDefaultConfig()
|
||||
cloudflareConfig.AuthEmail = param.Email
|
||||
cloudflareConfig.AuthToken = param.APIkey
|
||||
cloudflareConfig.PropagationTimeout = 15 * time.Minute
|
||||
cloudflareConfig.PollingInterval = 10 * time.Second
|
||||
cloudflareConfig.PropagationTimeout = 60 * time.Minute
|
||||
cloudflareConfig.PollingInterval = 5 * time.Second
|
||||
cloudflareConfig.TTL = 3600
|
||||
p, err = cloudflare.NewDNSProviderConfig(cloudflareConfig)
|
||||
case NameCheap:
|
||||
namecheapConfig := namecheap.NewDefaultConfig()
|
||||
namecheapConfig.APIKey = param.APIkey
|
||||
namecheapConfig.APIUser = param.APIUser
|
||||
namecheapConfig.PropagationTimeout = 15 * time.Minute
|
||||
namecheapConfig.PropagationTimeout = 60 * time.Minute
|
||||
namecheapConfig.PollingInterval = 5 * time.Second
|
||||
namecheapConfig.TTL = 3600
|
||||
p, err = namecheap.NewDNSProviderConfig(namecheapConfig)
|
||||
case NameSilo:
|
||||
nameSiloConfig := namesilo.NewDefaultConfig()
|
||||
nameSiloConfig.APIKey = param.APIkey
|
||||
nameSiloConfig.PropagationTimeout = 15 * time.Minute
|
||||
nameSiloConfig.PollingInterval = 10 * time.Second
|
||||
nameSiloConfig.PropagationTimeout = 60 * time.Minute
|
||||
nameSiloConfig.PollingInterval = 5 * time.Second
|
||||
nameSiloConfig.TTL = 3600
|
||||
p, err = namesilo.NewDNSProviderConfig(nameSiloConfig)
|
||||
case Godaddy:
|
||||
godaddyConfig := godaddy.NewDefaultConfig()
|
||||
godaddyConfig.APIKey = param.APIkey
|
||||
godaddyConfig.APISecret = param.APISecret
|
||||
godaddyConfig.PropagationTimeout = 15 * time.Minute
|
||||
godaddyConfig.PollingInterval = 10 * time.Second
|
||||
godaddyConfig.PropagationTimeout = 60 * time.Minute
|
||||
godaddyConfig.PollingInterval = 5 * time.Second
|
||||
godaddyConfig.TTL = 3600
|
||||
p, err = godaddy.NewDNSProviderConfig(godaddyConfig)
|
||||
case NameCom:
|
||||
nameComConfig := namedotcom.NewDefaultConfig()
|
||||
nameComConfig.APIToken = param.Token
|
||||
nameComConfig.Username = param.APIUser
|
||||
nameComConfig.PropagationTimeout = 15 * time.Minute
|
||||
nameComConfig.PollingInterval = 10 * time.Second
|
||||
nameComConfig.PropagationTimeout = 30 * time.Minute
|
||||
nameComConfig.PollingInterval = 30 * time.Second
|
||||
nameComConfig.TTL = 3600
|
||||
p, err = namedotcom.NewDNSProviderConfig(nameComConfig)
|
||||
case TencentCloud:
|
||||
tencentCloudConfig := tencentcloud.NewDefaultConfig()
|
||||
tencentCloudConfig.SecretID = param.SecretID
|
||||
tencentCloudConfig.SecretKey = param.SecretKey
|
||||
tencentCloudConfig.PropagationTimeout = 15 * time.Minute
|
||||
tencentCloudConfig.PollingInterval = 10 * time.Second
|
||||
tencentCloudConfig.PropagationTimeout = 30 * time.Minute
|
||||
tencentCloudConfig.PollingInterval = 30 * time.Second
|
||||
tencentCloudConfig.TTL = 3600
|
||||
p, err = tencentcloud.NewDNSProviderConfig(tencentCloudConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var nameservers []string
|
||||
if websiteSSL.Nameserver1 != "" {
|
||||
nameservers = append(nameservers, websiteSSL.Nameserver1)
|
||||
}
|
||||
if websiteSSL.Nameserver2 != "" {
|
||||
nameservers = append(nameservers, websiteSSL.Nameserver2)
|
||||
}
|
||||
if websiteSSL.DisableCNAME {
|
||||
_ = os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true")
|
||||
} else {
|
||||
_ = os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "false")
|
||||
if skipDNSCheck {
|
||||
return c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(10*time.Minute), dns01.DisableCompletePropagationRequirement())
|
||||
}
|
||||
|
||||
return c.Client.Challenge.SetDNS01Provider(p,
|
||||
dns01.CondOption(len(nameservers) > 0,
|
||||
dns01.AddRecursiveNameservers(nameservers)),
|
||||
dns01.CondOption(websiteSSL.SkipDNS,
|
||||
dns01.DisableCompletePropagationRequirement()),
|
||||
dns01.AddDNSTimeout(10*time.Minute),
|
||||
)
|
||||
return c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(10*time.Minute))
|
||||
}
|
||||
|
||||
func (c *AcmeClient) UseManualDns() error {
|
||||
|
||||
@@ -25,8 +25,8 @@ type LocalCommand struct {
|
||||
pty *os.File
|
||||
}
|
||||
|
||||
func NewCommand(commands []string) (*LocalCommand, error) {
|
||||
cmd := exec.Command("docker", commands...)
|
||||
func NewCommand(commands string) (*LocalCommand, error) {
|
||||
cmd := exec.Command("sh", "-c", commands)
|
||||
|
||||
pty, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
|
||||
@@ -70,11 +70,6 @@ func (sws *LocalWsSession) masterWrite(data []byte) error {
|
||||
}
|
||||
|
||||
func (sws *LocalWsSession) receiveWsMsg(exitCh chan bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
global.LOG.Errorf("[xpack] A panic occurred during receive ws message, error message: %v", r)
|
||||
}
|
||||
}()
|
||||
wsConn := sws.wsConn
|
||||
defer setQuit(exitCh)
|
||||
defer global.LOG.Debug("thread of receive ws msg has exited now")
|
||||
|
||||
@@ -116,11 +116,6 @@ func (sws *LogicSshWsSession) Start(quitChan chan bool) {
|
||||
}
|
||||
|
||||
func (sws *LogicSshWsSession) receiveWsMsg(exitCh chan bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
global.LOG.Errorf("[xpack] A panic occurred during receive ws message, error message: %v", r)
|
||||
}
|
||||
}()
|
||||
wsConn := sws.wsConn
|
||||
defer setQuit(exitCh)
|
||||
for {
|
||||
|
||||
@@ -6,11 +6,9 @@ import (
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cmdUtils "github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -57,16 +55,8 @@ var restoreCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
fmt.Println("(3/4) 1panel 服务回滚成功")
|
||||
checkPointOfWal()
|
||||
if _, err := os.Stat(path.Join(tmpPath, "1Panel.db")); err == nil {
|
||||
if err := common.CopyFile(path.Join(tmpPath, "1Panel.db"), path.Join(baseDir, "1panel/db")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path.Join(tmpPath, "db.tar.gz")); err == nil {
|
||||
if err := handleUnTar(path.Join(tmpPath, "db.tar.gz"), path.Join(baseDir, "1panel")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := common.CopyFile(path.Join(tmpPath, "1Panel.db"), path.Join(baseDir, "1panel", "db")); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("(4/4) 1panel 数据回滚成功 \n\n")
|
||||
|
||||
@@ -75,14 +65,6 @@ var restoreCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func checkPointOfWal() {
|
||||
db, err := loadDBConn()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = db.Exec("PRAGMA wal_checkpoint(TRUNCATE);").Error
|
||||
}
|
||||
|
||||
func loadRestorePath(upgradeDir string) (string, error) {
|
||||
if _, err := os.Stat(upgradeDir); err != nil && os.IsNotExist(err) {
|
||||
return "暂无可回滚文件", nil
|
||||
@@ -105,18 +87,3 @@ func loadRestorePath(upgradeDir string) (string, error) {
|
||||
})
|
||||
return folders[0], nil
|
||||
}
|
||||
|
||||
func handleUnTar(sourceFile, targetDir string) error {
|
||||
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
commands := fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir)
|
||||
stdout, err := cmdUtils.ExecWithTimeOut(commands, 20*time.Second)
|
||||
if err != nil {
|
||||
return errors.New(stdout)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14675,12 +14675,6 @@ const docTemplate = `{
|
||||
"image": {
|
||||
"type": "string"
|
||||
},
|
||||
"ipv4": {
|
||||
"type": "string"
|
||||
},
|
||||
"ipv6": {
|
||||
"type": "string"
|
||||
},
|
||||
"labels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -17781,9 +17775,6 @@ const docTemplate = `{
|
||||
"defaultNetwork": {
|
||||
"type": "string"
|
||||
},
|
||||
"developerMode": {
|
||||
"type": "string"
|
||||
},
|
||||
"dingVars": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -17823,9 +17814,6 @@ const docTemplate = `{
|
||||
"localTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"menuTabs": {
|
||||
"type": "string"
|
||||
},
|
||||
"messageType": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -18088,9 +18076,6 @@ const docTemplate = `{
|
||||
},
|
||||
"releaseNote": {
|
||||
"type": "string"
|
||||
},
|
||||
"testVersion": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14668,12 +14668,6 @@
|
||||
"image": {
|
||||
"type": "string"
|
||||
},
|
||||
"ipv4": {
|
||||
"type": "string"
|
||||
},
|
||||
"ipv6": {
|
||||
"type": "string"
|
||||
},
|
||||
"labels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -17774,9 +17768,6 @@
|
||||
"defaultNetwork": {
|
||||
"type": "string"
|
||||
},
|
||||
"developerMode": {
|
||||
"type": "string"
|
||||
},
|
||||
"dingVars": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -17816,9 +17807,6 @@
|
||||
"localTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"menuTabs": {
|
||||
"type": "string"
|
||||
},
|
||||
"messageType": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -18081,9 +18069,6 @@
|
||||
},
|
||||
"releaseNote": {
|
||||
"type": "string"
|
||||
},
|
||||
"testVersion": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -444,10 +444,6 @@ definitions:
|
||||
type: boolean
|
||||
image:
|
||||
type: string
|
||||
ipv4:
|
||||
type: string
|
||||
ipv6:
|
||||
type: string
|
||||
labels:
|
||||
items:
|
||||
type: string
|
||||
@@ -2545,8 +2541,6 @@ definitions:
|
||||
type: string
|
||||
defaultNetwork:
|
||||
type: string
|
||||
developerMode:
|
||||
type: string
|
||||
dingVars:
|
||||
type: string
|
||||
dockerSockPath:
|
||||
@@ -2573,8 +2567,6 @@ definitions:
|
||||
type: string
|
||||
localTime:
|
||||
type: string
|
||||
menuTabs:
|
||||
type: string
|
||||
messageType:
|
||||
type: string
|
||||
mfaInterval:
|
||||
@@ -2748,8 +2740,6 @@ definitions:
|
||||
type: string
|
||||
releaseNote:
|
||||
type: string
|
||||
testVersion:
|
||||
type: string
|
||||
type: object
|
||||
dto.UserLoginInfo:
|
||||
properties:
|
||||
|
||||
@@ -13,7 +13,7 @@ server {
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
|
||||
access_log /www/sites/domain/log/access.log main;
|
||||
access_log /www/sites/domain/log/access.log;
|
||||
error_log /www/sites/domain/log/error.log;
|
||||
|
||||
location ^~ /.well-known/acme-challenge {
|
||||
|
||||
+3
-2
@@ -51,16 +51,17 @@ If you have any questions or suggestions, please submit a GitHub Issue or join o
|
||||
|
||||
If you discover any security issues, please contact us through:
|
||||
|
||||
- email: wanghe@fit2cloud.com
|
||||
- Email: support@fit2cloud.com
|
||||
- Phone: 400-052-0755
|
||||
|
||||
## Our Other Star Projects
|
||||
|
||||
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - Open-Source Knowledge Base Question-Answering System Based on LLM Large Language Model
|
||||
- [JumpServer](https://github.com/jumpserver/jumpserver/) - A popular open-source PAM system
|
||||
- [DataEase](https://github.com/dataease/dataease/) - An open-source data visualization and analysis tool for everyone
|
||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - An all-in-one open-source automated testing platform
|
||||
- [Halo](https://github.com/halo-dev/halo/) - A powerful and user-friendly open-source website building tool
|
||||
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||
|
||||
+2
-2
@@ -51,11 +51,11 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
|
||||
セキュリティ上の問題を発見された場合は、下記までご連絡ください:
|
||||
|
||||
- メール: wanghe@fit2cloud.com
|
||||
- メール: support@fit2cloud.com
|
||||
- 電話番号: 400-052-0755
|
||||
|
||||
## その他の主要プロジェクト
|
||||
|
||||
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - LLMベースのオープンソース知識ベースの質問応答システム
|
||||
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 人気のあるオープンソースのバスチョンホスト管理ツール
|
||||
- [DataEase](https://github.com/dataease/dataease/) - 誰でも利用できるオープンソースのデータ可視化および分析ツール
|
||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - オールインワンのオープンソース自動化テストプラットフォーム
|
||||
|
||||
+2
-2
@@ -49,11 +49,11 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
|
||||
如果您在使用過程中發現任何安全問題,請通過以下方式直接聯繫我們:
|
||||
|
||||
- 郵箱:wanghe@fit2cloud.com
|
||||
- 郵箱:support@fit2cloud.com
|
||||
- 電話:400-052-0755
|
||||
|
||||
## 我們的其他明星專案
|
||||
|
||||
- [MaxKB](https://github.com/1Panel-dev/MaxKB/) - 基於 LLM 大語言模型的開源知識庫問答系統
|
||||
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 受歡迎的開源堡壘機管理工具
|
||||
- [DataEase](https://github.com/dataease/dataease/) - 開源的數據可視化和分析工具,適用於所有人
|
||||
- [MeterSphere](https://github.com/metersphere/metersphere/) - 一站式開源自動化測試平台
|
||||
|
||||
@@ -8,7 +8,6 @@ export namespace Setting {
|
||||
systemIP: string;
|
||||
systemVersion: string;
|
||||
dockerSockPath: string;
|
||||
developerMode: string;
|
||||
|
||||
sessionTimeout: number;
|
||||
localTime: string;
|
||||
@@ -152,7 +151,6 @@ export namespace Setting {
|
||||
productPro: string;
|
||||
trial: boolean;
|
||||
status: string;
|
||||
message: string;
|
||||
}
|
||||
export interface LicenseStatus {
|
||||
productPro: string;
|
||||
|
||||
@@ -165,18 +165,10 @@ export namespace Website {
|
||||
provider: string;
|
||||
websites?: Website.Website[];
|
||||
autoRenew: boolean;
|
||||
acmeAccountId: number;
|
||||
acmeAccountId?: number;
|
||||
status: string;
|
||||
domains: string;
|
||||
description: string;
|
||||
dnsAccountId?: number;
|
||||
pushDir: boolean;
|
||||
dir: string;
|
||||
keyType: string;
|
||||
nameserver1: string;
|
||||
nameserver2: string;
|
||||
disableCNAME: boolean;
|
||||
skipDNS: boolean;
|
||||
}
|
||||
|
||||
export interface SSLDTO extends SSL {
|
||||
@@ -206,14 +198,6 @@ export namespace Website {
|
||||
id: number;
|
||||
autoRenew: boolean;
|
||||
description: string;
|
||||
primaryDomain: string;
|
||||
otherDomains: string;
|
||||
acmeAccountId: number;
|
||||
provider: string;
|
||||
dnsAccountId?: number;
|
||||
keyType: string;
|
||||
pushDir: boolean;
|
||||
dir: string;
|
||||
}
|
||||
|
||||
export interface AcmeAccount extends CommonModel {
|
||||
@@ -456,6 +440,7 @@ export namespace Website {
|
||||
|
||||
export interface SSLObtain {
|
||||
ID: number;
|
||||
skipDNSCheck: boolean;
|
||||
}
|
||||
|
||||
export interface CA extends CommonModel {
|
||||
|
||||
@@ -2,7 +2,6 @@ import http from '@/api';
|
||||
import { ResPage, ReqPage } from '../interface';
|
||||
import { Runtime } from '../interface/runtime';
|
||||
import { TimeoutEnum } from '@/enums/http-enum';
|
||||
import { App } from '@/api/interface/app';
|
||||
|
||||
export const SearchRuntimes = (req: Runtime.RuntimeReq) => {
|
||||
return http.post<ResPage<Runtime.RuntimeDTO>>(`/runtimes/search`, req);
|
||||
@@ -16,10 +15,6 @@ export const DeleteRuntime = (req: Runtime.RuntimeDelete) => {
|
||||
return http.post<any>(`/runtimes/del`, req);
|
||||
};
|
||||
|
||||
export const RuntimeDeleteCheck = (runTimeId: number) => {
|
||||
return http.get<App.AppInstallResource[]>(`runtimes/installed/delete/check/${runTimeId}`);
|
||||
};
|
||||
|
||||
export const GetRuntime = (id: number) => {
|
||||
return http.get<Runtime.RuntimeDTO>(`/runtimes/${id}`);
|
||||
};
|
||||
|
||||
@@ -10,19 +10,6 @@
|
||||
/>
|
||||
<DrawerHeader v-else :header="$t('commons.button.backup')" :resource="name" :back="handleClose" />
|
||||
</template>
|
||||
|
||||
<div class="mb-5" v-if="type === 'app'">
|
||||
<el-alert :closable="false" type="warning">
|
||||
<div class="mt-2 text-xs">
|
||||
<span>{{ $t('setting.backupJump') }}</span>
|
||||
<span class="jump" @click="goFile()">
|
||||
<el-icon class="ml-2"><Position /></el-icon>
|
||||
{{ $t('firewall.quickJump') }}
|
||||
</span>
|
||||
</div>
|
||||
</el-alert>
|
||||
</div>
|
||||
|
||||
<ComplexTable
|
||||
v-loading="loading"
|
||||
:pagination-config="paginationConfig"
|
||||
@@ -31,7 +18,7 @@
|
||||
:data="data"
|
||||
>
|
||||
<template #toolbar>
|
||||
<el-button type="primary" :disabled="status && status != 'Running'" @click="onBackup()">
|
||||
<el-button type="primary" @click="onBackup()">
|
||||
{{ $t('commons.button.backup') }}
|
||||
</el-button>
|
||||
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
|
||||
@@ -73,13 +60,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { computeSize, dateFormat, downloadFile } from '@/utils/util';
|
||||
import { getBackupList, handleBackup, handleRecover } from '@/api/modules/setting';
|
||||
import { handleBackup, handleRecover } from '@/api/modules/setting';
|
||||
import i18n from '@/lang';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { deleteBackupRecord, downloadBackupRecord, searchBackupRecords } from '@/api/modules/setting';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import router from '@/routers';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const loading = ref();
|
||||
@@ -97,50 +83,23 @@ const backupVisible = ref(false);
|
||||
const type = ref();
|
||||
const name = ref();
|
||||
const detailName = ref();
|
||||
const backupPath = ref();
|
||||
const status = ref();
|
||||
|
||||
interface DialogProps {
|
||||
type: string;
|
||||
name: string;
|
||||
detailName: string;
|
||||
status: string;
|
||||
}
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
type.value = params.type;
|
||||
if (type.value === 'app') {
|
||||
loadBackupDir();
|
||||
}
|
||||
name.value = params.name;
|
||||
detailName.value = params.detailName;
|
||||
backupVisible.value = true;
|
||||
status.value = params.status;
|
||||
search();
|
||||
};
|
||||
const handleClose = () => {
|
||||
backupVisible.value = false;
|
||||
};
|
||||
|
||||
const loadBackupDir = () => {
|
||||
getBackupList().then((res) => {
|
||||
let backupList = res.data || [];
|
||||
for (const bac of backupList) {
|
||||
if (bac.type !== 'LOCAL') {
|
||||
continue;
|
||||
}
|
||||
if (bac.id !== 0) {
|
||||
bac.varsJson = JSON.parse(bac.vars);
|
||||
}
|
||||
backupPath.value = bac.varsJson['dir'];
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const goFile = async () => {
|
||||
router.push({ name: 'File', query: { path: `${backupPath.value}/app/${name.value}/${detailName.value}` } });
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
@@ -282,13 +241,3 @@ defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jump {
|
||||
color: $primary-color;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: #74a4f3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
</span>
|
||||
<el-button type="primary" link @click="toHalo">
|
||||
{{ isProductPro ? $t('license.pro') : $t('license.community') }}
|
||||
<span class="version">{{ version }}</span>
|
||||
</el-button>
|
||||
<span class="version">{{ version }}</span>
|
||||
<el-badge is-dot style="margin-top: -3px" v-if="version !== 'Waiting' && globalStore.hasNewVersion">
|
||||
<el-badge is-dot style="margin-left: -3px" v-if="version !== 'Waiting' && globalStore.hasNewVersion">
|
||||
<el-button type="primary" link @click="onLoadUpgradeInfo">
|
||||
<span>({{ $t('setting.hasNewVersion') }})</span>
|
||||
</el-button>
|
||||
@@ -48,13 +48,10 @@
|
||||
</div>
|
||||
<el-radio-group class="inline-block tag" v-model="upgradeVersion" @change="changeOption">
|
||||
<el-radio v-if="upgradeInfo.newVersion" :value="upgradeInfo.newVersion">
|
||||
{{ upgradeInfo.newVersion }}
|
||||
{{ upgradeInfo.newVersion }} {{ $t('setting.newVersion') }}
|
||||
</el-radio>
|
||||
<el-radio v-if="upgradeInfo.latestVersion" :value="upgradeInfo.latestVersion">
|
||||
{{ upgradeInfo.latestVersion }}
|
||||
</el-radio>
|
||||
<el-radio v-if="upgradeInfo.testVersion" :value="upgradeInfo.testVersion">
|
||||
{{ upgradeInfo.testVersion }}
|
||||
<el-radio :value="upgradeInfo.latestVersion">
|
||||
{{ upgradeInfo.latestVersion }} {{ $t('setting.latestVersion') }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<MdEditor
|
||||
@@ -127,25 +124,13 @@ const onLoadUpgradeInfo = async () => {
|
||||
await loadUpgradeInfo()
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
if (res.data.testVersion || res.data.newVersion || res.data.latestVersion) {
|
||||
upgradeInfo.value = res.data;
|
||||
drawerVisible.value = true;
|
||||
if (upgradeInfo.value.newVersion) {
|
||||
upgradeVersion.value = upgradeInfo.value.newVersion;
|
||||
return;
|
||||
}
|
||||
if (upgradeInfo.value.latestVersion) {
|
||||
upgradeVersion.value = upgradeInfo.value.latestVersion;
|
||||
return;
|
||||
}
|
||||
if (upgradeInfo.value.testVersion) {
|
||||
upgradeVersion.value = upgradeInfo.value.testVersion;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!res.data) {
|
||||
MsgSuccess(i18n.global.t('setting.noUpgrade'));
|
||||
return;
|
||||
}
|
||||
upgradeInfo.value = res.data;
|
||||
upgradeVersion.value = upgradeInfo.value.newVersion || upgradeInfo.value.latestVersion;
|
||||
drawerVisible.value = true;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<div class="mb-4" v-if="type === 'mysql' || type === 'mariadb'">
|
||||
<el-alert type="error" :title="$t('database.formatHelper', [remark])" />
|
||||
</div>
|
||||
<div class="mb-4" v-if="type === 'website'">
|
||||
<el-alert :closable="false" type="warning" :title="$t('website.websiteBackupWarn')"></el-alert>
|
||||
</div>
|
||||
<el-upload ref="uploadRef" drag :on-change="fileOnChange" class="upload-demo" :auto-upload="false">
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
|
||||
@@ -22,20 +22,6 @@ const checkIp = (rule: any, value: any, callback: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
const checkIpv4 = (rule: any, value: any, callback: any) => {
|
||||
if (value === '' || typeof value === 'undefined' || value == null) {
|
||||
callback();
|
||||
} else {
|
||||
const reg =
|
||||
/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
|
||||
if (!reg.test(value) && value !== '') {
|
||||
callback(new Error(i18n.global.t('commons.rule.ip')));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const checkIpV6 = (rule: any, value: any, callback: any) => {
|
||||
if (value === '' || typeof value === 'undefined' || value == null) {
|
||||
callback(new Error(i18n.global.t('commons.rule.requiredInput')));
|
||||
@@ -237,7 +223,7 @@ const checkSupervisorName = (rule: any, value: any, callback: any) => {
|
||||
if (value === '' || typeof value === 'undefined' || value == null) {
|
||||
callback(new Error(i18n.global.t('commons.rule.supervisorName')));
|
||||
} else {
|
||||
const reg = /^[a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,127}$/;
|
||||
const reg = /^[a-zA-Z0-9]{1}[a-zA-Z0-9_-]{1,128}$/;
|
||||
if (!reg.test(value) && value !== '') {
|
||||
callback(new Error(i18n.global.t('commons.rule.supervisorName')));
|
||||
} else {
|
||||
@@ -547,7 +533,6 @@ interface CommonRule {
|
||||
floatNumber: FormItemRule;
|
||||
ip: FormItemRule;
|
||||
ipV6: FormItemRule;
|
||||
ipv4: FormItemRule;
|
||||
ipV4V6OrDomain: FormItemRule;
|
||||
host: FormItemRule;
|
||||
illegal: FormItemRule;
|
||||
@@ -783,8 +768,4 @@ export const Rules: CommonRule = {
|
||||
validator: checkHttpOrHttps,
|
||||
trigger: 'blur',
|
||||
},
|
||||
ipv4: {
|
||||
validator: checkIpv4,
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -161,7 +161,7 @@ export const DNSTypes = [
|
||||
value: 'DnsPod',
|
||||
},
|
||||
{
|
||||
label: 'Cloudflare',
|
||||
label: 'CloudFlare',
|
||||
value: 'CloudFlare',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -837,7 +837,6 @@ const message = {
|
||||
allOptionHelper:
|
||||
'The current task plan is to back up all [{0}]. Direct download is not supported at the moment. You can check the backup list of [{0}] menu.',
|
||||
exclusionRules: 'Exclusive rule',
|
||||
exclusionRulesHelper: 'The exclusion rules will apply to all compression operations of this backup.',
|
||||
default_download_path: 'Default Download Link',
|
||||
saveLocal: 'Retain local backups (the same as the number of cloud storage copies)',
|
||||
url: 'URL Address',
|
||||
@@ -1156,10 +1155,6 @@ const message = {
|
||||
clashDitNotSupport: 'File names are prohibited from containing .1panel_clash',
|
||||
clashDeleteAlert: 'The Recycle Bin folder cannot be deleted',
|
||||
clashOpenAlert: 'Please click the [Recycle Bin] button to open the recycle bin directory',
|
||||
right: 'Forward',
|
||||
back: 'Back',
|
||||
top: 'Go Back',
|
||||
refresh: 'Refresh',
|
||||
},
|
||||
ssh: {
|
||||
autoStart: 'Auto Start',
|
||||
@@ -1273,8 +1268,6 @@ const message = {
|
||||
noSpace: 'Input information cannot include space characters',
|
||||
duplicatePassword: 'The new password cannot be the same as the original password, please re-enter!',
|
||||
diskClean: 'Cache Clean',
|
||||
developerMode: 'Preview Experience Program',
|
||||
developerModeHelper: 'Get a preview version of 1Panel to provide feedback on new features and updates',
|
||||
|
||||
thirdParty: 'Third-party account',
|
||||
createBackupAccount: 'Add {0}',
|
||||
@@ -1437,8 +1430,6 @@ const message = {
|
||||
rootCrtDownload: 'Root certificate download',
|
||||
primaryKey: 'Primary key',
|
||||
certificate: 'Certificate',
|
||||
backupJump:
|
||||
'Backup files not in the current backup list, please try downloading from the file directory and importing for backup.',
|
||||
|
||||
snapshot: 'Snapshot',
|
||||
status: 'Snapshot status',
|
||||
@@ -1477,6 +1468,8 @@ const message = {
|
||||
'Name rules: [major version].[functional version].[Bug fix version], as shown in the following example:',
|
||||
versionHelper1: 'v1.0.1 is a Bug fix after v1.0.0',
|
||||
versionHelper2: 'v1.1.0 is a feature release after v1.0.0',
|
||||
newVersion: '(Bug fix version)',
|
||||
latestVersion: '(Functional version)',
|
||||
upgradeCheck: 'Check for updates',
|
||||
upgradeNotes: 'Release note',
|
||||
upgradeNow: 'Upgrade now',
|
||||
@@ -1488,7 +1481,7 @@ const message = {
|
||||
issue: 'Feedback',
|
||||
doc: 'Official document',
|
||||
star: 'Star',
|
||||
description: 'Linux Server Panel',
|
||||
description: 'Linux server operation and maintenance management panel',
|
||||
forum: 'Forum Help',
|
||||
doc2: 'User Manual',
|
||||
currentVersion: 'Version',
|
||||
@@ -1695,8 +1688,6 @@ const message = {
|
||||
'The current application network mode is host mode. If you need to open the port, please open it manually on the firewall page.',
|
||||
showLocal: 'Show Local Application',
|
||||
reload: 'Reload',
|
||||
upgradeWarn:
|
||||
'Upgrading the application will replace the docker-compose.yml file. If there is any change, please replace it after upgrading',
|
||||
},
|
||||
website: {
|
||||
website: 'Website',
|
||||
@@ -1948,8 +1939,6 @@ const message = {
|
||||
containWarn: 'The domain name contains the main domain, please re-enter',
|
||||
rewriteHelper2:
|
||||
'Applications such as WordPress installed from the app store have pseudo-static configuration by default. Repeated configuration may result in errors',
|
||||
websiteBackupWarn:
|
||||
'Only supports importing local backups, importing backups from other machines may cause recovery failure',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: 'Short tag support',
|
||||
@@ -2059,11 +2048,6 @@ const message = {
|
||||
deprecated: 'will be deprecated',
|
||||
deprecatedHelper:
|
||||
'Maintenance has been stopped and may be abandoned in a future version. Please use Tencent Cloud method for analysis',
|
||||
disableCNAME: 'Disable CNAME',
|
||||
disableCNAMEHelper: 'Domain name with CNAME configuration, if the application fails, you can check here',
|
||||
nameserver: 'DNS server',
|
||||
nameserverHelper: 'Use a custom DNS server to verify domain names',
|
||||
edit: 'Edit certificate',
|
||||
},
|
||||
firewall: {
|
||||
create: 'Create rule',
|
||||
|
||||
@@ -797,7 +797,6 @@ const message = {
|
||||
snapshot: '系統快照',
|
||||
allOptionHelper: '當前計劃任務為備份所有【{0}】,暫不支持直接下載,可在【{0}】備份列表中查看',
|
||||
exclusionRules: '排除規則',
|
||||
exclusionRulesHelper: '排除規則將對此次備份的所有壓縮操作生效',
|
||||
default_download_path: '默認下載地址',
|
||||
saveLocal: '同時保留本地備份(和雲存儲保留份數一致)',
|
||||
url: 'URL 地址',
|
||||
@@ -1100,10 +1099,6 @@ const message = {
|
||||
clashDitNotSupport: '檔名禁止包含 .1panel_clash',
|
||||
clashDleteAlert: '回收站資料夾不能刪除',
|
||||
clashOpenAlert: '回收站目錄請點選【回收站】按鈕開啟',
|
||||
right: '前進',
|
||||
back: '後退',
|
||||
top: '返回上一層',
|
||||
refresh: '重新整理',
|
||||
},
|
||||
ssh: {
|
||||
autoStart: '開機自啟',
|
||||
@@ -1196,8 +1191,6 @@ const message = {
|
||||
noSpace: '輸入信息不能包括空格符號',
|
||||
duplicatePassword: '新密碼不能與原始密碼一致,請重新輸入!',
|
||||
diskClean: '缓存清理',
|
||||
developerMode: '預覽體驗計劃',
|
||||
developerModeHelper: '獲取 1Panel 的預覽版本,以分享有關新功能和更新的反饋',
|
||||
|
||||
thirdParty: '第三方賬號',
|
||||
createBackupAccount: '添加 {0}',
|
||||
@@ -1267,7 +1260,6 @@ const message = {
|
||||
accountKey: '賬戶密鑰',
|
||||
address: '地址',
|
||||
path: '路徑',
|
||||
backupJump: '未在當前備份列表中的備份檔案,請嘗試從檔案目錄中下載後導入備份。',
|
||||
|
||||
snapshot: '快照',
|
||||
status: '快照狀態',
|
||||
@@ -1304,6 +1296,8 @@ const message = {
|
||||
versionHelper: '1Panel 版本號命名規則為: [大版本].[功能版本].[Bug 修復版本],例:',
|
||||
versionHelper1: 'v1.0.1 是 v1.0.0 之後的 Bug 修復版本',
|
||||
versionHelper2: 'v1.1.0 是 v1.0.0 之後的功能版本',
|
||||
newVersion: '(Bug 修復版本)',
|
||||
latestVersion: '(功能版本)',
|
||||
upgradeCheck: '檢查更新',
|
||||
upgradeNotes: '更新內容',
|
||||
upgradeNow: '立即更新',
|
||||
@@ -1581,7 +1575,6 @@ const message = {
|
||||
hostModeHelper: '目前應用網路模式為 host 模式,如需放開端口,請在防火牆頁面手動放開',
|
||||
showLocal: '顯示本機應用程式',
|
||||
reload: '重載',
|
||||
upgradeWarn: '升級應用程式會取代 docker-compose.yml 文件,如有更改,請升級之後替換',
|
||||
},
|
||||
website: {
|
||||
website: '網站',
|
||||
@@ -1821,7 +1814,6 @@ const message = {
|
||||
tencentCloud: '騰訊雲',
|
||||
containWarn: '其他域名中包含主域名,请重新輸入',
|
||||
rewriteHelper2: '從應用程式商店安裝的 WordPress 等應用,預設已經配置好偽靜態,重複配置可能會報錯',
|
||||
websiteBackupWarn: '僅支援導入本機備份,導入其他機器備份可能會恢復失敗',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短標簽支持',
|
||||
@@ -1926,11 +1918,6 @@ const message = {
|
||||
cfHelper: '請勿使用 Global API Key',
|
||||
deprecated: '即將廢棄',
|
||||
deprecatedHelper: '已經停止維護,可能會在以後的某個版本廢棄,請使用騰訊雲方式解析',
|
||||
disableCNAME: '停用 CNAME',
|
||||
disableCNAMEHelper: '有 CNAME 配置的域名,如果申請失敗,可以勾選此處',
|
||||
nameserver: 'DNS 伺服器',
|
||||
nameserverHelper: '使用自訂的 DNS 伺服器來校驗網域名稱',
|
||||
edit: '編輯證書',
|
||||
},
|
||||
firewall: {
|
||||
create: '創建規則',
|
||||
|
||||
@@ -798,7 +798,6 @@ const message = {
|
||||
snapshot: '系统快照',
|
||||
allOptionHelper: '当前计划任务为备份所有【{0}】,暂不支持直接下载,可在【{0}】备份列表中查看',
|
||||
exclusionRules: '排除规则',
|
||||
exclusionRulesHelper: '排除规则将对此次备份的所有压缩操作生效',
|
||||
default_download_path: '默认下载地址',
|
||||
saveLocal: '同时保留本地备份(和云存储保留份数一致)',
|
||||
url: 'URL 地址',
|
||||
@@ -1101,10 +1100,6 @@ const message = {
|
||||
clashDitNotSupport: '文件名禁止包含 .1panel_clash',
|
||||
clashDleteAlert: '回收站文件夹不能删除',
|
||||
clashOpenAlert: '回收站目录请点击【回收站】按钮打开',
|
||||
right: '前进',
|
||||
back: '后退',
|
||||
top: '返回上一级',
|
||||
refresh: '刷新',
|
||||
},
|
||||
ssh: {
|
||||
autoStart: '开机自启',
|
||||
@@ -1197,8 +1192,6 @@ const message = {
|
||||
noSpace: '输入信息不能包含空格符',
|
||||
duplicatePassword: '新密码不能与原始密码一致,请重新输入!',
|
||||
diskClean: '缓存清理',
|
||||
developerMode: '预览体验计划',
|
||||
developerModeHelper: '获取 1Panel 的预览版本,以分享有关新功能和更新的反馈',
|
||||
|
||||
thirdParty: '第三方账号',
|
||||
createBackupAccount: '添加 {0}',
|
||||
@@ -1268,7 +1261,6 @@ const message = {
|
||||
accountKey: '账户密钥',
|
||||
address: '地址',
|
||||
path: '路径',
|
||||
backupJump: '未在当前备份列表中的备份文件,请尝试从文件目录中下载后导入备份。',
|
||||
|
||||
snapshot: '快照',
|
||||
ignoreRule: '排除规则',
|
||||
@@ -1305,6 +1297,8 @@ const message = {
|
||||
versionHelper: '1Panel 版本号命名规则为: [大版本].[功能版本].[Bug 修复版本],例:',
|
||||
versionHelper1: 'v1.0.1 是 v1.0.0 之后的 Bug 修复版本',
|
||||
versionHelper2: 'v1.1.0 是 v1.0.0 之后的功能版本',
|
||||
newVersion: '(Bug 修复版本)',
|
||||
latestVersion: '(功能版本)',
|
||||
upgradeCheck: '检查更新',
|
||||
upgradeNotes: '更新内容',
|
||||
upgradeNow: '立即更新',
|
||||
@@ -1581,7 +1575,6 @@ const message = {
|
||||
hostModeHelper: '当前应用网络模式为 host 模式,如需放开端口,请在防火墙页面手动放开',
|
||||
showLocal: '显示本地应用',
|
||||
reload: '重载',
|
||||
upgradeWarn: '升级应用会替换 docker-compose.yml 文件,如有更改,请升级之后替换',
|
||||
},
|
||||
website: {
|
||||
website: '网站',
|
||||
@@ -1821,7 +1814,6 @@ const message = {
|
||||
tencentCloud: '腾讯云',
|
||||
containWarn: '其他域名中包含主域名,请重新输入',
|
||||
rewriteHelper2: '从应用商店安装的 WordPress 等应用,默认已经配置好伪静态,重复配置可能会报错',
|
||||
websiteBackupWarn: '仅支持导入本机备份,导入其他机器备份可能会恢复失败',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短标签支持',
|
||||
@@ -1926,11 +1918,6 @@ const message = {
|
||||
cfHelper: '请勿使用 Global API Key',
|
||||
deprecated: '即将废弃',
|
||||
deprecatedHelper: '已经停止维护,可能会在以后的某个版本废弃,请使用腾讯云方式解析',
|
||||
disableCNAME: '禁用 CNAME',
|
||||
disableCNAMEHelper: '有 CNAME 配置的域名,如果申请失败,可以勾选此处',
|
||||
nameserver: 'DNS 服务器',
|
||||
nameserverHelper: '使用自定义的 DNS 服务器来校验域名',
|
||||
edit: '编辑证书',
|
||||
},
|
||||
firewall: {
|
||||
create: '创建规则',
|
||||
|
||||
@@ -41,6 +41,11 @@ const { switchDark } = useTheme();
|
||||
|
||||
let timer: NodeJS.Timer | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
if (!tabsStore.activeTabPath) {
|
||||
handleMenuClick('/');
|
||||
}
|
||||
});
|
||||
const classObj = computed(() => {
|
||||
return {
|
||||
fullScreen: globalStore.isFullScreen,
|
||||
@@ -158,10 +163,6 @@ onBeforeUnmount(() => {
|
||||
timer = null;
|
||||
});
|
||||
onMounted(() => {
|
||||
if (globalStore.openMenuTabs && !tabsStore.activeTabPath) {
|
||||
handleMenuClick('/');
|
||||
}
|
||||
|
||||
loadStatus();
|
||||
initFavicon();
|
||||
loadDataFromDB();
|
||||
|
||||
@@ -125,16 +125,12 @@
|
||||
:width="400"
|
||||
trigger="hover"
|
||||
:content="installed.message"
|
||||
:popper-options="options"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button link type="danger">
|
||||
<el-icon><Warning /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
<div class="app-error">
|
||||
{{ installed.message }}
|
||||
</div>
|
||||
</el-popover>
|
||||
</span>
|
||||
<span class="ml-1">
|
||||
@@ -168,6 +164,10 @@
|
||||
plain
|
||||
round
|
||||
size="small"
|
||||
:disabled="
|
||||
installed.status !== 'Running' ||
|
||||
installed.app.status === 'TakeDown'
|
||||
"
|
||||
@click="openUploads(installed.app.key, installed.name)"
|
||||
v-if="mode === 'installed'"
|
||||
>
|
||||
@@ -178,9 +178,11 @@
|
||||
plain
|
||||
round
|
||||
size="small"
|
||||
@click="
|
||||
openBackups(installed.app.key, installed.name, installed.status)
|
||||
:disabled="
|
||||
installed.status !== 'Running' ||
|
||||
installed.app.status === 'TakeDown'
|
||||
"
|
||||
@click="openBackups(installed.app.key, installed.name)"
|
||||
v-if="mode === 'installed'"
|
||||
>
|
||||
{{ $t('commons.button.backup') }}
|
||||
@@ -360,17 +362,6 @@ const mode = ref('installed');
|
||||
const moreTag = ref('');
|
||||
const language = getLanguage();
|
||||
const appDetail = ref();
|
||||
const options = {
|
||||
modifiers: [
|
||||
{
|
||||
name: 'flip',
|
||||
options: {
|
||||
padding: 5,
|
||||
fallbackPlacements: ['bottom-start', 'top-start', 'right', 'left'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const sync = () => {
|
||||
ElMessageBox.confirm(i18n.global.t('app.syncAllAppHelper'), i18n.global.t('app.sync'), {
|
||||
@@ -569,12 +560,11 @@ const buttons = [
|
||||
},
|
||||
];
|
||||
|
||||
const openBackups = (key: string, name: string, status: string) => {
|
||||
const openBackups = (key: string, name: string) => {
|
||||
let params = {
|
||||
type: 'app',
|
||||
name: key,
|
||||
detailName: name,
|
||||
status: status,
|
||||
};
|
||||
backupRef.value.acceptParams(params);
|
||||
};
|
||||
@@ -631,9 +621,4 @@ onUnmounted(() => {
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.app-error {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
<el-checkbox v-model="operateReq.pullImage" :label="$t('container.forcePull')" size="large" />
|
||||
<span class="input-help">{{ $t('container.forcePullHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-text type="warning">{{ $t('app.upgradeWarn') }}</el-text>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="22" :offset="1">
|
||||
|
||||
@@ -69,8 +69,6 @@ export function loadDefaultSpec(type: string) {
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'directory':
|
||||
case 'cutWebsiteLog':
|
||||
case 'ntp':
|
||||
item.specType = 'perDay';
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
|
||||
@@ -320,7 +320,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
v-if="hasExclusionRules()"
|
||||
v-if="dialogData.rowData!.type === 'directory'"
|
||||
:label="$t('cronjob.exclusionRules')"
|
||||
prop="exclusionRules"
|
||||
>
|
||||
@@ -331,7 +331,6 @@
|
||||
clearable
|
||||
v-model="dialogData.rowData!.exclusionRules"
|
||||
/>
|
||||
<span class="input-help">{{ $t('cronjob.exclusionRulesHelper') }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -682,14 +681,6 @@ function isBackup() {
|
||||
);
|
||||
}
|
||||
|
||||
function hasExclusionRules() {
|
||||
return (
|
||||
dialogData.value.rowData!.type === 'app' ||
|
||||
dialogData.value.rowData!.type === 'website' ||
|
||||
dialogData.value.rowData!.type === 'directory'
|
||||
);
|
||||
}
|
||||
|
||||
function hasScript() {
|
||||
return dialogData.value.rowData!.type === 'shell';
|
||||
}
|
||||
|
||||
@@ -154,9 +154,14 @@
|
||||
<template #label>
|
||||
<span class="status-label">{{ $t('commons.table.status') }}</span>
|
||||
</template>
|
||||
<el-tag type="danger" v-if="currentRecord?.status === 'Failed'">
|
||||
{{ $t('commons.table.statusFailed') }}
|
||||
</el-tag>
|
||||
<el-tooltip v-if="currentRecord?.status === 'Failed'" placement="top">
|
||||
<template #content>
|
||||
<div style="width: 300px; word-break: break-all">
|
||||
{{ currentRecord?.message }}
|
||||
</div>
|
||||
</template>
|
||||
<el-tag type="danger">{{ $t('commons.table.statusFailed') }}</el-tag>
|
||||
</el-tooltip>
|
||||
<el-tag type="success" v-if="currentRecord?.status === 'Success'">
|
||||
{{ $t('commons.table.statusSuccess') }}
|
||||
</el-tag>
|
||||
@@ -165,14 +170,6 @@
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="currentRecord?.status === 'Failed'">
|
||||
<el-form-item class="w-full">
|
||||
<template #label>
|
||||
<span class="status-label">{{ $t('commons.table.message') }}</span>
|
||||
</template>
|
||||
{{ currentRecord?.message }}
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="currentRecord?.records">
|
||||
<span>{{ $t('commons.table.records') }}</span>
|
||||
<codemirror
|
||||
|
||||
@@ -32,10 +32,7 @@
|
||||
<el-radio label="5.7" value="5.7" />
|
||||
<el-radio label="5.6" value="5.6" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-radio label="10.x" value="10.x" />
|
||||
<el-radio label="11.x" value="11.x" />
|
||||
</div>
|
||||
<el-radio v-else label="10.x" value="10.x" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('database.address')" prop="address">
|
||||
|
||||
@@ -125,12 +125,8 @@
|
||||
<template #body>
|
||||
<div style="position: relative; margin-top: 20px">
|
||||
<div class="monitor-tags" v-if="chartOption === 'network'">
|
||||
<el-tag>
|
||||
{{ $t('monitor.up') }}: {{ computeSizeFromKBs(currentChartInfo.netBytesSent) }}
|
||||
</el-tag>
|
||||
<el-tag>
|
||||
{{ $t('monitor.down') }}: {{ computeSizeFromKBs(currentChartInfo.netBytesRecv) }}
|
||||
</el-tag>
|
||||
<el-tag>{{ $t('monitor.up') }}: {{ currentChartInfo.netBytesSent }} KB/s</el-tag>
|
||||
<el-tag>{{ $t('monitor.down') }}: {{ currentChartInfo.netBytesRecv }} KB/s</el-tag>
|
||||
<el-tag>{{ $t('home.totalSend') }}: {{ computeSize(currentInfo.netBytesSent) }}</el-tag>
|
||||
<el-tag>{{ $t('home.totalRecv') }}: {{ computeSize(currentInfo.netBytesRecv) }}</el-tag>
|
||||
</div>
|
||||
@@ -251,7 +247,7 @@ import LicenseImport from '@/components/license-import/index.vue';
|
||||
import CardWithHeader from '@/components/card-with-header/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import { Dashboard } from '@/api/interface/dashboard';
|
||||
import { dateFormatForSecond, computeSize, computeSizeFromKBs } from '@/utils/util';
|
||||
import { dateFormatForSecond, computeSize } from '@/utils/util';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { loadBaseInfo, loadCurrentInfo } from '@/api/modules/dashboard';
|
||||
import { getIOOptions, getNetworkOptions } from '@/api/modules/host';
|
||||
@@ -546,7 +542,7 @@ const hideEntrance = () => {
|
||||
|
||||
const loadUpgradeStatus = async () => {
|
||||
const res = await loadUpgradeInfo();
|
||||
if (res.data.testVersion || res.data.newVersion || res.data.latestVersion) {
|
||||
if (res.data) {
|
||||
globalStore.hasNewVersion = true;
|
||||
} else {
|
||||
globalStore.hasNewVersion = false;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<el-dialog v-model="open" :title="$t('app.delete')" width="30%" :close-on-click-modal="false">
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="22" :offset="1">
|
||||
<el-col :span="20" :offset="2">
|
||||
<el-alert
|
||||
class="mt-2"
|
||||
:show-icon="true"
|
||||
@@ -15,11 +15,8 @@
|
||||
</div>
|
||||
</el-alert>
|
||||
<div class="mt-4" v-if="recycleStatus === 'enable'">
|
||||
<el-checkbox v-model="forceDelete" class="force-delete">
|
||||
<span>{{ $t('file.forceDeleteHelper') }}</span>
|
||||
</el-checkbox>
|
||||
<el-checkbox v-model="forceDelete">{{ $t('file.forceDeleteHelper') }}</el-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="file-list">
|
||||
<div class="flx-align-center mb-1" v-for="(row, index) in files" :key="index">
|
||||
<div>
|
||||
@@ -132,10 +129,4 @@ defineExpose({
|
||||
line-height: 20px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.force-delete {
|
||||
white-space: pre-line;
|
||||
word-wrap: break-word;
|
||||
line-height: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,18 +2,8 @@
|
||||
<div>
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 flex items-center mr-4">
|
||||
<el-tooltip :content="$t('file.back')" placement="top">
|
||||
<el-button :icon="Back" @click="back" circle />
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('file.right')" placement="top">
|
||||
<el-button :icon="Right" @click="right" circle />
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('file.top')" placement="top">
|
||||
<el-button :icon="Top" @click="top" circle :disabled="paths.length == 0" />
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('file.refresh')" placement="top">
|
||||
<el-button :icon="Refresh" circle @click="search" />
|
||||
</el-tooltip>
|
||||
<el-button :icon="Back" @click="back" circle :disabled="paths.length == 0" />
|
||||
<el-button :icon="Refresh" circle @click="search" />
|
||||
</div>
|
||||
<div
|
||||
v-show="!searchableStatus"
|
||||
@@ -244,7 +234,7 @@
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('file.group')" prop="group" show-overflow-tooltip>
|
||||
<el-table-column :label="$t('file.group')" prop="group">
|
||||
<template #default="{ row }">
|
||||
<el-link :underline="false" @click="openChown(row)">
|
||||
{{ row.group ? row.group : '-' }} ({{ row.gid }})
|
||||
@@ -315,7 +305,7 @@ import {
|
||||
SearchFavorite,
|
||||
} from '@/api/modules/files';
|
||||
import { computeSize, copyText, dateFormat, downloadFile, getIcon, getRandomStr } from '@/utils/util';
|
||||
import { StarFilled, Star, Top, Right } from '@element-plus/icons-vue';
|
||||
import { StarFilled, Star } from '@element-plus/icons-vue';
|
||||
import { File } from '@/api/interface/file';
|
||||
import { Mimetypes, Languages } from '@/global/mimetype';
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -372,8 +362,6 @@ let req = reactive(initData());
|
||||
let loading = ref(false);
|
||||
const paths = ref<FilePaths[]>([]);
|
||||
let pathWidth = ref(0);
|
||||
const history: string[] = [];
|
||||
let pointer = -1;
|
||||
|
||||
const fileCreate = reactive({ path: '/', isDir: false, mode: 0o755 });
|
||||
const fileCompress = reactive({ files: [''], name: '', dst: '', operate: 'compress' });
|
||||
@@ -473,6 +461,7 @@ const open = async (row: File.File) => {
|
||||
url: req.path,
|
||||
name: name,
|
||||
});
|
||||
|
||||
jump(req.path);
|
||||
} else {
|
||||
openCodeEditor(row.path, row.extension);
|
||||
@@ -502,23 +491,7 @@ const handlePath = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const right = () => {
|
||||
if (pointer < history.length - 1) {
|
||||
pointer++;
|
||||
let url = history[pointer];
|
||||
backForwardJump(url);
|
||||
}
|
||||
};
|
||||
|
||||
const back = () => {
|
||||
if (pointer > 0) {
|
||||
pointer--;
|
||||
let url = history[pointer];
|
||||
backForwardJump(url);
|
||||
}
|
||||
};
|
||||
|
||||
const top = () => {
|
||||
if (paths.value.length > 0) {
|
||||
let url = '/';
|
||||
if (paths.value.length >= 2) {
|
||||
@@ -529,10 +502,6 @@ const top = () => {
|
||||
};
|
||||
|
||||
const jump = async (url: string) => {
|
||||
history.splice(pointer + 1);
|
||||
history.push(url);
|
||||
pointer = history.length - 1;
|
||||
|
||||
const oldUrl = req.path;
|
||||
const oldPageSize = req.pageSize;
|
||||
// reset search params before exec jump
|
||||
@@ -557,22 +526,6 @@ const jump = async (url: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
const backForwardJump = async (url: string) => {
|
||||
const oldPageSize = req.pageSize;
|
||||
// reset search params before exec jump
|
||||
Object.assign(req, initData());
|
||||
req.path = url;
|
||||
req.containSub = false;
|
||||
req.search = '';
|
||||
req.pageSize = oldPageSize;
|
||||
let searchResult = await searchFile();
|
||||
handleSearchResult(searchResult);
|
||||
getPaths(req.path);
|
||||
nextTick(function () {
|
||||
handlePath();
|
||||
});
|
||||
};
|
||||
|
||||
const getPaths = (reqPath: string) => {
|
||||
const pathArray = reqPath.split('/');
|
||||
paths.value = [];
|
||||
@@ -863,9 +816,7 @@ const buttons = [
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('file.mode'),
|
||||
click: (row: File.File) => {
|
||||
openBatchRole([row]);
|
||||
},
|
||||
click: openMode,
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('file.compress'),
|
||||
|
||||
@@ -48,9 +48,6 @@
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item class="descriptions" :label="$t('commons.table.message')">
|
||||
{{ license.message }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
@@ -129,7 +126,6 @@ const license = reactive({
|
||||
productName: '',
|
||||
|
||||
status: '',
|
||||
message: '',
|
||||
});
|
||||
|
||||
const toHalo = () => {
|
||||
@@ -201,7 +197,6 @@ const search = async () => {
|
||||
globalStore.productProExpires = Number(res.data.productPro);
|
||||
}
|
||||
license.licenseName = res.data.licenseName;
|
||||
license.message = res.data.message;
|
||||
license.assigneeName = res.data.assigneeName;
|
||||
license.trial = res.data.trial;
|
||||
if (res.data.productPro) {
|
||||
@@ -239,11 +234,4 @@ onMounted(() => {
|
||||
background-color: rgba(0, 94, 235, 0.03);
|
||||
}
|
||||
}
|
||||
:deep(.el-descriptions__content) {
|
||||
max-width: 300px;
|
||||
}
|
||||
.descriptions {
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -113,21 +113,6 @@
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('setting.developerMode')" prop="developerMode">
|
||||
<el-radio-group
|
||||
@change="onSave('DeveloperMode', form.developerMode)"
|
||||
v-model="form.developerMode"
|
||||
>
|
||||
<el-radio-button value="enable">
|
||||
<span>{{ $t('commons.button.enable') }}</span>
|
||||
</el-radio-button>
|
||||
<el-radio-button value="disable">
|
||||
<span>{{ $t('commons.button.disable') }}</span>
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
<span class="input-help">{{ $t('setting.developerModeHelper') }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('setting.advancedMenuHide')">
|
||||
<el-input disabled v-model="form.proHideMenus">
|
||||
<template #append>
|
||||
@@ -191,7 +176,6 @@ const form = reactive({
|
||||
complexityVerification: '',
|
||||
defaultNetwork: '',
|
||||
defaultNetworkVal: '',
|
||||
developerMode: '',
|
||||
|
||||
proHideMenus: ref(i18n.t('setting.unSetting')),
|
||||
hideMenuList: '',
|
||||
@@ -235,7 +219,6 @@ const search = async () => {
|
||||
form.defaultNetworkVal = res.data.defaultNetwork === 'all' ? i18n.t('commons.table.all') : res.data.defaultNetwork;
|
||||
form.proHideMenus = res.data.xpackHideMenu;
|
||||
form.hideMenuList = res.data.xpackHideMenu;
|
||||
form.developerMode = res.data.developerMode;
|
||||
|
||||
// 提取隐藏节点的 title 并显示
|
||||
const json: Node = JSON.parse(res.data.xpackHideMenu);
|
||||
|
||||
@@ -33,11 +33,13 @@
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
></el-table-column>
|
||||
<el-table-column :label="$t('tool.supervisor.dir')" prop="dir" min-width="100px" fix>
|
||||
<template #default="{ row }">
|
||||
<Tooltip @click="toFolder(row.dir)" :text="row.dir" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('tool.supervisor.dir')"
|
||||
prop="dir"
|
||||
min-width="100px"
|
||||
fix
|
||||
show-overflow-tooltip
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('tool.supervisor.user')"
|
||||
prop="user"
|
||||
@@ -159,7 +161,6 @@ import i18n from '@/lang';
|
||||
import { HostTool } from '@/api/interface/host-tool';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { VideoPlay, VideoPause, RefreshRight } from '@element-plus/icons-vue';
|
||||
import router from '@/routers';
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
const loading = ref(false);
|
||||
@@ -185,10 +186,6 @@ const getStatus = (status: any) => {
|
||||
search();
|
||||
};
|
||||
|
||||
const toFolder = (folder: string) => {
|
||||
router.push({ path: '/hosts/files', query: { path: folder } });
|
||||
};
|
||||
|
||||
const showStopped = computed((): boolean => {
|
||||
if (supervisorStatus.value.init || setSuperVisor.value) {
|
||||
return false;
|
||||
|
||||
@@ -84,14 +84,13 @@
|
||||
<ComposeLogs ref="composeLogRef" />
|
||||
<PortJumpDialog ref="dialogPortJumpRef" />
|
||||
<Modules ref="moduleRef" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||
import { Runtime } from '@/api/interface/runtime';
|
||||
import { OperateRuntime, RuntimeDeleteCheck, SearchRuntimes, SyncRuntime } from '@/api/modules/runtime';
|
||||
import { OperateRuntime, SearchRuntimes, SyncRuntime } from '@/api/modules/runtime';
|
||||
import { dateFormat } from '@/utils/util';
|
||||
import OperateNode from '@/views/website/runtime/node/operate/index.vue';
|
||||
import Status from '@/components/status/index.vue';
|
||||
@@ -103,7 +102,6 @@ import router from '@/routers/router';
|
||||
import ComposeLogs from '@/components/compose-log/index.vue';
|
||||
import { Promotion } from '@element-plus/icons-vue';
|
||||
import PortJumpDialog from '@/components/port-jump/index.vue';
|
||||
import AppResources from '@/views/website/runtime/php/check/index.vue';
|
||||
|
||||
let timer: NodeJS.Timer | null = null;
|
||||
const loading = ref(false);
|
||||
@@ -113,7 +111,6 @@ const deleteRef = ref();
|
||||
const dialogPortJumpRef = ref();
|
||||
const composeLogRef = ref();
|
||||
const moduleRef = ref();
|
||||
const checkRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
@@ -212,14 +209,7 @@ const openDetail = (row: Runtime.Runtime) => {
|
||||
};
|
||||
|
||||
const openDelete = async (row: Runtime.Runtime) => {
|
||||
RuntimeDeleteCheck(row.id).then(async (res) => {
|
||||
const items = res.data;
|
||||
if (res.data && res.data.length > 0) {
|
||||
checkRef.value.acceptParams({ items: items, key: 'website', installID: row.id });
|
||||
} else {
|
||||
deleteRef.value.acceptParams(row.id, row.name);
|
||||
}
|
||||
});
|
||||
deleteRef.value.acceptParams(row.id, row.name);
|
||||
};
|
||||
|
||||
const openLog = (row: any) => {
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :title="$t('app.checkTitle')" width="50%" :close-on-click-modal="false">
|
||||
<el-row>
|
||||
<el-col :span="20" :offset="2" v-if="open">
|
||||
<el-alert
|
||||
type="error"
|
||||
:description="$t('app.deleteHelper', [$t('runtime.runtime')])"
|
||||
center
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
<br />
|
||||
<el-descriptions border :column="1">
|
||||
<el-descriptions-item v-for="(item, key) in map" :key="key">
|
||||
<template #label>
|
||||
<a href="javascript:void(0);" @click="toPage(item[0])">{{ $t('app.' + item[0]) }}</a>
|
||||
</template>
|
||||
<span class="resources">
|
||||
{{ map.get(item[0]).toString() }}
|
||||
</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div v-if="installData.key === 'openresty'" class="mt-5">
|
||||
<el-checkbox v-model="forceDelete" label="true">{{ $t('app.forceDelete') }}</el-checkbox>
|
||||
<ErrPrompt :title="$t('app.openrestyDeleteHelper')" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<template #footer v-if="forceDelete">
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="open = false">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="onConfirm">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { App } from '@/api/interface/app';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { DeleteRuntime } from '@/api/modules/runtime';
|
||||
const router = useRouter();
|
||||
|
||||
interface CheckRrops {
|
||||
items: App.AppInstallResource[];
|
||||
installID: Number;
|
||||
key: string;
|
||||
}
|
||||
const installData = ref<CheckRrops>({
|
||||
items: [],
|
||||
installID: 0,
|
||||
key: '',
|
||||
});
|
||||
const open = ref(false);
|
||||
const map = new Map();
|
||||
const forceDelete = ref(false);
|
||||
const em = defineEmits(['close']);
|
||||
|
||||
const acceptParams = (props: CheckRrops) => {
|
||||
map.clear();
|
||||
forceDelete.value = false;
|
||||
installData.value.installID = props.installID;
|
||||
installData.value.key = props.key;
|
||||
installData.value.items = [];
|
||||
installData.value.items = props.items;
|
||||
installData.value.items.forEach((item) => {
|
||||
if (map.has(item.type)) {
|
||||
const array = map.get(item.type);
|
||||
array.push(item.name);
|
||||
map.set(item.type, array);
|
||||
} else {
|
||||
map.set(item.type, [item.name]);
|
||||
}
|
||||
});
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const toPage = (key: string) => {
|
||||
if (key === 'website') {
|
||||
router.push({ name: 'Website' });
|
||||
}
|
||||
};
|
||||
|
||||
const onConfirm = () => {
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('app.operatorHelper', [i18n.global.t('app.delete')]),
|
||||
i18n.global.t('app.delete'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
).then(() => {
|
||||
const params = {
|
||||
id: installData.value.installID.valueOf(),
|
||||
forceDelete: true,
|
||||
};
|
||||
DeleteRuntime(params).then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
open.value = false;
|
||||
em('close', open);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resources {
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -9,7 +9,6 @@
|
||||
allow-create
|
||||
default-first-option
|
||||
@change="updateParam"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="service in p.values"
|
||||
|
||||
@@ -79,14 +79,13 @@
|
||||
<OpDialog ref="opRef" @search="search" />
|
||||
<Log ref="logRef" @close="search" />
|
||||
<Extensions ref="extensionsRef" @close="search" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||
import { Runtime } from '@/api/interface/runtime';
|
||||
import { DeleteRuntime, RuntimeDeleteCheck, SearchRuntimes } from '@/api/modules/runtime';
|
||||
import { DeleteRuntime, SearchRuntimes } from '@/api/modules/runtime';
|
||||
import { dateFormat, toLowerCase } from '@/utils/util';
|
||||
import CreateRuntime from '@/views/website/runtime/php/create/index.vue';
|
||||
import Status from '@/components/status/index.vue';
|
||||
@@ -94,7 +93,6 @@ import i18n from '@/lang';
|
||||
import RouterMenu from '../index.vue';
|
||||
import Log from '@/components/log-dialog/index.vue';
|
||||
import Extensions from './extensions/index.vue';
|
||||
import AppResources from '@/views/website/runtime/php/check/index.vue';
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
@@ -113,8 +111,6 @@ const opRef = ref();
|
||||
const logRef = ref();
|
||||
const extensionsRef = ref();
|
||||
|
||||
const checkRef = ref();
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.edit'),
|
||||
@@ -171,22 +167,15 @@ const openExtensions = () => {
|
||||
};
|
||||
|
||||
const openDelete = async (row: Runtime.Runtime) => {
|
||||
RuntimeDeleteCheck(row.id).then(async (res) => {
|
||||
const items = res.data;
|
||||
if (res.data && res.data.length > 0) {
|
||||
checkRef.value.acceptParams({ items: items, key: 'website', installID: row.id });
|
||||
} else {
|
||||
opRef.value.acceptParams({
|
||||
title: i18n.global.t('commons.msg.deleteTitle'),
|
||||
names: [row.name],
|
||||
msg: i18n.global.t('commons.msg.operatorHelper', [
|
||||
i18n.global.t('website.runtime'),
|
||||
i18n.global.t('commons.button.delete'),
|
||||
]),
|
||||
api: DeleteRuntime,
|
||||
params: { id: row.id, forceDelete: true },
|
||||
});
|
||||
}
|
||||
opRef.value.acceptParams({
|
||||
title: i18n.global.t('commons.msg.deleteTitle'),
|
||||
names: [row.name],
|
||||
msg: i18n.global.t('commons.msg.operatorHelper', [
|
||||
i18n.global.t('website.runtime'),
|
||||
i18n.global.t('commons.button.delete'),
|
||||
]),
|
||||
api: DeleteRuntime,
|
||||
params: { id: row.id, forceDelete: true },
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<el-checkbox v-model="skipDNSCheck">{{ $t('ssl.skipDNSCheck') }}</el-checkbox>
|
||||
<span class="input-help">{{ $t('ssl.skipDNSCheckHelper') }}</span>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
@@ -62,11 +67,13 @@ const handleClose = () => {
|
||||
open.value = false;
|
||||
em('close', false);
|
||||
};
|
||||
const skipDNSCheck = ref(false);
|
||||
|
||||
const acceptParams = async (props: RenewProps) => {
|
||||
open.value = true;
|
||||
dnsResolve.value = [];
|
||||
sslID.value = props.ssl.id;
|
||||
skipDNSCheck.value = false;
|
||||
getDnsResolve(props.ssl);
|
||||
};
|
||||
|
||||
@@ -89,7 +96,7 @@ const getDnsResolve = async (row: Website.SSL) => {
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
ObtainSSL({ ID: sslID.value })
|
||||
ObtainSSL({ ID: sslID.value, skipDNSCheck: skipDNSCheck.value })
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('ssl.applyStart'));
|
||||
handleClose();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user