Browse Source

fix: 解决打开越权读取文件的问题 (#1810)

pull/1813/head
ssongliu 1 year ago committed by GitHub
parent
commit
6f6c836d9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 22
      backend/app/api/v1/container.go
  2. 22
      backend/app/api/v1/cronjob.go
  3. 22
      backend/app/api/v1/database_mysql.go
  4. 27
      backend/app/api/v1/file.go
  5. 16
      backend/app/api/v1/logs.go
  6. 15
      backend/app/api/v1/ssh.go
  7. 47
      backend/app/service/container.go
  8. 4
      backend/app/service/container_compose.go
  9. 18
      backend/app/service/cornjob.go
  10. 22
      backend/app/service/database_mysql.go
  11. 4
      backend/app/service/docker.go
  12. 24
      backend/app/service/image.go
  13. 19
      backend/app/service/logs.go
  14. 18
      backend/app/service/snapshot.go
  15. 13
      backend/app/service/ssh.go
  16. 2
      backend/init/migration/migrations/init.go
  17. 1
      backend/router/ro_container.go
  18. 1
      backend/router/ro_cronjob.go
  19. 1
      backend/router/ro_database.go
  20. 2
      backend/router/ro_file.go
  21. 1
      backend/router/ro_host.go
  22. 2
      backend/router/ro_log.go
  23. 3
      backend/utils/mysql/client/local.go
  24. 197
      cmd/server/docs/docs.go
  25. 193
      cmd/server/docs/swagger.json
  26. 117
      cmd/server/docs/swagger.yaml
  27. 3
      frontend/src/api/modules/container.ts
  28. 4
      frontend/src/api/modules/cronjob.ts
  29. 3
      frontend/src/api/modules/database.ts
  30. 4
      frontend/src/api/modules/files.ts
  31. 3
      frontend/src/api/modules/host.ts
  32. 4
      frontend/src/api/modules/log.ts
  33. 1
      frontend/src/components/backup/index.vue
  34. 7
      frontend/src/views/container/compose/create/index.vue
  35. 5
      frontend/src/views/container/compose/index.vue
  36. 5
      frontend/src/views/container/image/build/index.vue
  37. 5
      frontend/src/views/container/image/pull/index.vue
  38. 5
      frontend/src/views/container/image/push/index.vue
  39. 6
      frontend/src/views/cronjob/record/index.vue
  40. 16
      frontend/src/views/database/mysql/setting/index.vue
  41. 14
      frontend/src/views/database/mysql/setting/slow-log/index.vue
  42. 8
      frontend/src/views/database/redis/setting/index.vue
  43. 5
      frontend/src/views/host/ssh/ssh/index.vue
  44. 7
      frontend/src/views/log/system/index.vue

22
backend/app/api/v1/container.go

@ -355,6 +355,28 @@ func (b *BaseApi) CleanContainerLog(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Load container log
// @Description 获取容器操作日志
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/load/log [post]
func (b *BaseApi) LoadContainerLog(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content, err := containerService.LoadContainerLogs(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Container
// @Summary Operate Container
// @Description 容器操作

22
backend/app/api/v1/cronjob.go

@ -94,6 +94,28 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
})
}
// @Tags Cronjob
// @Summary Load Cronjob record log
// @Description 获取计划任务记录日志
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjob/record/log [post]
func (b *BaseApi) LoadRecordLog(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content, err := cronjobService.LoadRecordLog(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Cronjob
// @Summary Clean job records
// @Description 清空计划任务记录

22
backend/app/api/v1/database_mysql.go

@ -321,6 +321,28 @@ func (b *BaseApi) LoadBaseinfo(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Tags Database
// @Summary Load Database file
// @Description 获取数据库文件
// @Accept json
// @Param request body dto.OperationWithNameAndType true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/load/file [post]
func (b *BaseApi) LoadDatabaseFile(c *gin.Context) {
var req dto.OperationWithNameAndType
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content, err := mysqlService.LoadDatabaseFile(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, content)
}
// @Tags Database Mysql
// @Summary Load mysql remote access
// @Description 获取 mysql 远程访问权限

27
backend/app/api/v1/file.go

@ -589,33 +589,6 @@ func (b *BaseApi) Size(c *gin.Context) {
helper.SuccessWithData(c, res)
}
// @Tags File
// @Summary Read file
// @Description 读取文件
// @Accept json
// @Param request body dto.FilePath true "request"
// @Success 200 {string} content
// @Security ApiKeyAuth
// @Router /files/loadfile [post]
func (b *BaseApi) LoadFromFile(c *gin.Context) {
var req dto.FilePath
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
content, err := os.ReadFile(req.Path)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, string(content))
}
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
if _, err := os.Stat(path.Dir(dstDir)); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(dstDir), os.ModePerm); err != nil {

16
backend/app/api/v1/logs.go

@ -89,3 +89,19 @@ func (b *BaseApi) CleanLogs(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags Logs
// @Summary Load system logs
// @Description 获取系统日志
// @Success 200
// @Security ApiKeyAuth
// @Router /logs/system [get]
func (b *BaseApi) GetSystemLogs(c *gin.Context) {
data, err := logService.LoadSystemLog()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}

15
backend/app/api/v1/ssh.go

@ -183,3 +183,18 @@ func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
}
helper.SuccessWithData(c, data)
}
// @Tags SSH
// @Summary Load host ssh conf
// @Description 获取 ssh 配置文件
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/conf [get]
func (b *BaseApi) LoadSSHConf(c *gin.Context) {
data, err := sshService.LoadSSHConf()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}

47
backend/app/service/container.go

@ -7,6 +7,7 @@ import (
"io"
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strconv"
@ -63,6 +64,8 @@ type IContainerService interface {
TestCompose(req dto.ComposeCreate) (bool, error)
ComposeUpdate(req dto.ComposeUpdate) error
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
LoadContainerLogs(req dto.OperationWithNameAndType) (string, error)
}
func NewIContainerService() IContainerService {
@ -182,7 +185,7 @@ func (u *ContainerService) List() ([]string, error) {
for _, container := range containers {
for _, name := range container.Names {
if len(name) != 0 {
datas = append(datas, strings.TrimLeft(name, "/"))
datas = append(datas, strings.TrimPrefix(name, "/"))
}
}
}
@ -625,6 +628,48 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
return &data, nil
}
func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) (string, error) {
filePath := ""
switch req.Type {
case "image-pull", "image-push", "image-build":
filePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
case "compose-detail", "compose-create":
client, err := docker.NewDockerClient()
if err != nil {
return "", err
}
options := types.ContainerListOptions{All: true}
options.Filters = filters.NewArgs()
options.Filters.Add("label", fmt.Sprintf("%s=%s", composeProjectLabel, req.Name))
containers, err := client.ContainerList(context.Background(), options)
if err != nil {
return "", err
}
for _, container := range containers {
config := container.Labels[composeConfigLabel]
workdir := container.Labels[composeWorkdirLabel]
if len(config) != 0 && len(workdir) != 0 && strings.Contains(config, workdir) {
filePath = config
break
} else {
filePath = workdir
break
}
}
if req.Type == "compose-create" {
filePath = path.Join(path.Dir(filePath), "/compose.log")
}
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
func stringsToMap(list []string) map[string]string {
var lableMap = make(map[string]string)
for _, label := range list {

4
backend/app/service/container_compose.go

@ -157,7 +157,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
global.LOG.Infof("docker-compose.yml %s create successful, start to docker-compose up", req.Name)
if req.From == "path" {
req.Name = path.Base(strings.ReplaceAll(req.Path, "/"+path.Base(req.Path), ""))
req.Name = path.Base(path.Dir(req.Path))
}
logName := path.Dir(req.Path) + "/compose.log"
file, err := os.OpenFile(logName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
@ -181,7 +181,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
_, _ = file.WriteString("docker-compose up successful!")
}()
return logName, nil
return req.Name, nil
}
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {

18
backend/app/service/cornjob.go

@ -9,6 +9,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/jinzhu/copier"
@ -29,6 +30,8 @@ type ICronjobService interface {
Download(down dto.CronjobDownload) (string, error)
StartJob(cronjob *model.Cronjob) (int, error)
CleanRecord(req dto.CronjobClean) error
LoadRecordLog(req dto.OperateByID) (string, error)
}
func NewICronjobService() ICronjobService {
@ -80,6 +83,21 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
return total, dtoCronjobs, err
}
func (u *CronjobService) LoadRecordLog(req dto.OperateByID) (string, error) {
record, err := cronjobRepo.GetRecord(commonRepo.WithByID(req.ID))
if err != nil {
return "", err
}
if _, err := os.Stat(record.Records); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(record.Records)
if err != nil {
return "", err
}
return string(content), nil
}
func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
cronjob, err := cronjobRepo.Get(commonRepo.WithByID(req.CronjobID))
if err != nil {

22
backend/app/service/database_mysql.go

@ -46,6 +46,8 @@ type IMysqlService interface {
LoadVariables() (*dto.MysqlVariables, error)
LoadBaseInfo() (*dto.DBBaseInfo, error)
LoadRemoteAccess() (bool, error)
LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error)
}
func NewIMysqlService() IMysqlService {
@ -514,6 +516,26 @@ func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
return &info, nil
}
func (u *MysqlService) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) {
filePath := ""
switch req.Type {
case "mysql-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/conf/my.cnf", req.Name))
case "redis-conf":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/redis/%s/conf/redis.conf", req.Name))
case "slow-logs":
filePath = path.Join(global.CONF.System.DataDir, fmt.Sprintf("apps/mysql/%s/data/1Panel-slow.log", req.Name))
}
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput()

4
backend/app/service/docker.go

@ -136,14 +136,14 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
switch req.Key {
case "Registries":
req.Value = strings.TrimRight(req.Value, ",")
req.Value = strings.TrimSuffix(req.Value, ",")
if len(req.Value) == 0 {
delete(daemonMap, "insecure-registries")
} else {
daemonMap["insecure-registries"] = strings.Split(req.Value, ",")
}
case "Mirrors":
req.Value = strings.TrimRight(req.Value, ",")
req.Value = strings.TrimSuffix(req.Value, ",")
if len(req.Value) == 0 {
delete(daemonMap, "registry-mirrors")
} else {

24
backend/app/service/image.go

@ -123,6 +123,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
return "", err
}
fileName := "Dockerfile"
dockerLogDir := path.Join(global.CONF.System.TmpDir, "/docker_logs")
if req.From == "edit" {
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
@ -156,10 +157,9 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
Remove: true,
Labels: stringsToMap(req.Tags),
}
logName := fmt.Sprintf("%s/build.log", req.Dockerfile)
pathItem := logName
file, err := os.OpenFile(pathItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
}
@ -192,7 +192,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
_, _ = file.WriteString("image build successful!")
}()
return logName, nil
return path.Base(logItem), nil
}
func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
@ -200,15 +200,15 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
if err != nil {
return "", err
}
dockerLogDir := global.CONF.System.TmpDir + "/docker_logs"
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 {
return "", err
}
}
imageItemName := strings.ReplaceAll(path.Base(req.ImageName), ":", "_")
pathItem := fmt.Sprintf("%s/image_pull_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
file, err := os.OpenFile(pathItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
logItem := fmt.Sprintf("%s/image_pull_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
}
@ -224,7 +224,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
global.LOG.Infof("pull image %s successful!", req.ImageName)
_, _ = io.Copy(file, out)
}()
return pathItem, nil
return path.Base(logItem), nil
}
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
if err != nil {
@ -257,7 +257,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
_, _ = io.Copy(file, out)
_, _ = file.WriteString("image pull successful!")
}()
return pathItem, nil
return path.Base(logItem), nil
}
func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
@ -354,8 +354,8 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
}
}
imageItemName := strings.ReplaceAll(path.Base(req.Name), ":", "_")
pathItem := fmt.Sprintf("%s/image_push_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
file, err := os.OpenFile(pathItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
logItem := fmt.Sprintf("%s/image_push_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
}
@ -373,7 +373,7 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
_, _ = file.WriteString("image push successful!")
}()
return pathItem, nil
return path.Base(logItem), nil
}
func (u *ImageService) ImageRemove(req dto.BatchDelete) error {

19
backend/app/service/logs.go

@ -1,9 +1,14 @@
package service
import (
"os"
"path"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"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/jinzhu/copier"
"github.com/pkg/errors"
@ -20,6 +25,8 @@ type ILogService interface {
CreateOperationLog(operation model.OperationLog) error
PageOperationLog(search dto.SearchOpLogWithPage) (int64, interface{}, error)
LoadSystemLog() (string, error)
CleanLogs(logtype string) error
}
@ -74,6 +81,18 @@ func (u *LogService) PageOperationLog(req dto.SearchOpLogWithPage) (int64, inter
return total, dtoOps, err
}
func (u *LogService) LoadSystemLog() (string, error) {
filePath := path.Join(global.CONF.System.DataDir, "log/1Panel.log")
if _, err := os.Stat(filePath); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
func (u *LogService) CleanLogs(logtype string) error {
if logtype == "operation" {
return logRepo.CleanOperation()

18
backend/app/service/snapshot.go

@ -205,8 +205,8 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
global.LOG.Infof("start to upload snapshot to %s, please wait", backup.Type)
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusUploading})
localPath := path.Join(localDir, fmt.Sprintf("system/1panel_%s_%s.tar.gz", versionItem.Value, timeNow))
itemBackupPath := strings.TrimLeft(backup.BackupPath, "/")
itemBackupPath = strings.TrimRight(itemBackupPath, "/")
itemBackupPath := strings.TrimPrefix(backup.BackupPath, "/")
itemBackupPath = strings.TrimSuffix(itemBackupPath, "/")
if ok, err := backupAccount.Upload(localPath, fmt.Sprintf("%s/system_snapshot/1panel_%s_%s.tar.gz", itemBackupPath, versionItem.Value, timeNow)); err != nil || !ok {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
global.LOG.Errorf("upload snapshot to %s failed, err: %v", backup.Type, err)
@ -259,8 +259,8 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
operation = "re-recover"
}
if !isReTry || snap.InterruptStep == "Download" || (isReTry && req.ReDownload) {
itemBackupPath := strings.TrimLeft(backup.BackupPath, "/")
itemBackupPath = strings.TrimRight(itemBackupPath, "/")
itemBackupPath := strings.TrimPrefix(backup.BackupPath, "/")
itemBackupPath = strings.TrimSuffix(itemBackupPath, "/")
ok, err := client.Download(fmt.Sprintf("%s/system_snapshot/%s.tar.gz", itemBackupPath, snap.Name), fmt.Sprintf("%s/%s.tar.gz", baseDir, snap.Name))
if err != nil || !ok {
if req.ReDownload {
@ -947,7 +947,10 @@ func (u *SnapshotService) handleTar(sourceDir, targetDir, name, exclusionRules s
global.LOG.Debug(commands)
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
if err != nil {
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
if len(stdout) != 0 {
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
return fmt.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
}
}
return nil
}
@ -963,7 +966,10 @@ func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
global.LOG.Debug(commands)
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
if err != nil {
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
if len(stdout) != 0 {
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
return fmt.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
}
}
return nil
}

13
backend/app/service/ssh.go

@ -32,6 +32,8 @@ type ISSHService interface {
GenerateSSH(req dto.GenerateSSH) error
LoadSSHSecret(mode string) (string, error)
LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error)
LoadSSHConf() (string, error)
}
func NewISSHService() ISSHService {
@ -283,6 +285,17 @@ func (u *SSHService) LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error) {
return &data, nil
}
func (u *SSHService) LoadSSHConf() (string, error) {
if _, err := os.Stat("/etc/ssh/sshd_config"); err != nil {
return "", buserr.New("ErrHttpReqNotFound")
}
content, err := os.ReadFile("/etc/ssh/sshd_config")
if err != nil {
return "", err
}
return string(content), nil
}
func sortFileList(fileNames []sshFileItem) []sshFileItem {
if len(fileNames) < 2 {
return fileNames

2
backend/init/migration/migrations/init.go

@ -493,7 +493,7 @@ var AddRemoteDB = &gormigrate.Migration{
appInstall model.AppInstall
)
if err := global.DB.Where("key = ?", "mysql").First(&app).Error; err != nil {
return err
return nil
}
if err := global.DB.Where("app_id = ?", app.ID).First(&appInstall).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {

1
backend/router/ro_container.go

@ -28,6 +28,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
baRouter.GET("/search/log", baseApi.ContainerLogs)
baRouter.GET("/limit", baseApi.LoadResouceLimit)
baRouter.POST("/clean/log", baseApi.CleanContainerLog)
baRouter.POST("/load/log", baseApi.LoadContainerLog)
baRouter.POST("/inspect", baseApi.Inspect)
baRouter.POST("/operate", baseApi.ContainerOperation)
baRouter.POST("/prune", baseApi.ContainerPrune)

1
backend/router/ro_cronjob.go

@ -24,6 +24,7 @@ func (s *CronjobRouter) InitCronjobRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/download", baseApi.TargetDownload)
cmdRouter.POST("/search", baseApi.SearchCronjob)
cmdRouter.POST("/search/records", baseApi.SearchJobRecords)
cmdRouter.POST("/records/log", baseApi.LoadRecordLog)
cmdRouter.POST("/records/clean", baseApi.CleanRecord)
}
}

1
backend/router/ro_database.go

@ -26,6 +26,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
cmdRouter.POST("/conffile/update", baseApi.UpdateMysqlConfByFile)
cmdRouter.POST("/search", baseApi.SearchMysql)
cmdRouter.POST("/load/file", baseApi.LoadDatabaseFile)
cmdRouter.GET("/variables", baseApi.LoadVariables)
cmdRouter.GET("/status", baseApi.LoadStatus)
cmdRouter.GET("/baseinfo", baseApi.LoadBaseinfo)

2
backend/router/ro_file.go

@ -38,7 +38,5 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
fileRouter.POST("/size", baseApi.Size)
fileRouter.GET("/ws", baseApi.Ws)
fileRouter.GET("/keys", baseApi.Keys)
fileRouter.POST("/loadfile", baseApi.LoadFromFile)
}
}

1
backend/router/ro_host.go

@ -34,6 +34,7 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
hostRouter.POST("/firewall/update/port", baseApi.UpdatePortRule)
hostRouter.POST("/firewall/update/addr", baseApi.UpdateAddrRule)
hostRouter.GET("/ssh/conf", baseApi.LoadSSHConf)
hostRouter.POST("/ssh/search", baseApi.GetSSHInfo)
hostRouter.POST("/ssh/update", baseApi.UpdateSSH)
hostRouter.POST("/ssh/generate", baseApi.GenerateSSH)

2
backend/router/ro_log.go

@ -17,5 +17,7 @@ func (s *LogRouter) InitLogRouter(Router *gin.RouterGroup) {
operationRouter.POST("/login", baseApi.GetLoginLogs)
operationRouter.POST("/operation", baseApi.GetOperationLogs)
operationRouter.POST("/clean", baseApi.CleanLogs)
operationRouter.GET("/system", baseApi.GetSystemLogs)
}
}

3
backend/utils/mysql/client/local.go

@ -7,6 +7,7 @@ import (
"fmt"
"os"
"os/exec"
"path"
"strings"
"time"
@ -214,7 +215,7 @@ func (r *Local) Backup(info BackupInfo) error {
return fmt.Errorf("mkdir %s failed, err: %v", info.TargetDir, err)
}
}
outfile, _ := os.OpenFile(info.FileName, os.O_RDWR|os.O_CREATE, 0755)
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, info.Name)
gzipCmd := exec.Command("gzip", "-cf")

197
cmd/server/docs/docs.go

@ -1,5 +1,5 @@
// Package docs GENERATED BY SWAG; DO NOT EDIT
// This file was generated by swaggo/swag
// Code generated by swaggo/swag. DO NOT EDIT.
package docs
import "github.com/swaggo/swag"
@ -2005,6 +2005,39 @@ const docTemplate = `{
}
}
},
"/containers/load/log": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取容器操作日志",
"consumes": [
"application/json"
],
"tags": [
"Container"
],
"summary": "Load container log",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/containers/network": {
"get": {
"security": [
@ -3058,6 +3091,39 @@ const docTemplate = `{
}
}
},
"/cronjob/record/log": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取计划任务记录日志",
"consumes": [
"application/json"
],
"tags": [
"Cronjob"
],
"summary": "Load Cronjob record log",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperateByID"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/cronjobs": {
"post": {
"security": [
@ -3925,6 +3991,39 @@ const docTemplate = `{
"responses": {}
}
},
"/databases/load/file": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取数据库文件",
"consumes": [
"application/json"
],
"tags": [
"Database"
],
"summary": "Load Database file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/databases/options": {
"get": {
"security": [
@ -5036,42 +5135,6 @@ const docTemplate = `{
}
}
},
"/files/loadfile": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "读取文件",
"consumes": [
"application/json"
],
"tags": [
"File"
],
"summary": "Read file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.FilePath"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/files/mode": {
"post": {
"security": [
@ -5748,6 +5811,25 @@ const docTemplate = `{
}
}
},
"/host/ssh/conf": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 ssh 配置文件",
"tags": [
"SSH"
],
"summary": "Load host ssh conf",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/host/ssh/generate": {
"post": {
"security": [
@ -6251,7 +6333,7 @@ const docTemplate = `{
"bodyKeys": [
"operate"
],
"formatEN": "[operate] [operate] Supervisor 进程文件",
"formatEN": "[operate] Supervisor Process Config file",
"formatZH": "[operate] Supervisor 进程文件 ",
"paramKeys": []
}
@ -7188,6 +7270,25 @@ const docTemplate = `{
}
}
},
"/logs/system": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取系统日志",
"tags": [
"Logs"
],
"summary": "Load system logs",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/openResty": {
"get": {
"security": [
@ -13291,6 +13392,21 @@ const docTemplate = `{
}
}
},
"dto.OperationWithNameAndType": {
"type": "object",
"required": [
"name",
"type"
],
"properties": {
"name": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"dto.Options": {
"type": "object",
"properties": {
@ -15773,7 +15889,8 @@ const docTemplate = `{
"type": "string",
"enum": [
"out.log",
"err.log"
"err.log",
"config"
]
},
"name": {

193
cmd/server/docs/swagger.json

@ -1998,6 +1998,39 @@
}
}
},
"/containers/load/log": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取容器操作日志",
"consumes": [
"application/json"
],
"tags": [
"Container"
],
"summary": "Load container log",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/containers/network": {
"get": {
"security": [
@ -3051,6 +3084,39 @@
}
}
},
"/cronjob/record/log": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取计划任务记录日志",
"consumes": [
"application/json"
],
"tags": [
"Cronjob"
],
"summary": "Load Cronjob record log",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperateByID"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/cronjobs": {
"post": {
"security": [
@ -3918,6 +3984,39 @@
"responses": {}
}
},
"/databases/load/file": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取数据库文件",
"consumes": [
"application/json"
],
"tags": [
"Database"
],
"summary": "Load Database file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.OperationWithNameAndType"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/databases/options": {
"get": {
"security": [
@ -5029,42 +5128,6 @@
}
}
},
"/files/loadfile": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "读取文件",
"consumes": [
"application/json"
],
"tags": [
"File"
],
"summary": "Read file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.FilePath"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/files/mode": {
"post": {
"security": [
@ -5741,6 +5804,25 @@
}
}
},
"/host/ssh/conf": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 ssh 配置文件",
"tags": [
"SSH"
],
"summary": "Load host ssh conf",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/host/ssh/generate": {
"post": {
"security": [
@ -6244,7 +6326,7 @@
"bodyKeys": [
"operate"
],
"formatEN": "[operate] [operate] Supervisor 进程文件",
"formatEN": "[operate] Supervisor Process Config file",
"formatZH": "[operate] Supervisor 进程文件 ",
"paramKeys": []
}
@ -7181,6 +7263,25 @@
}
}
},
"/logs/system": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取系统日志",
"tags": [
"Logs"
],
"summary": "Load system logs",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/openResty": {
"get": {
"security": [
@ -13284,6 +13385,21 @@
}
}
},
"dto.OperationWithNameAndType": {
"type": "object",
"required": [
"name",
"type"
],
"properties": {
"name": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"dto.Options": {
"type": "object",
"properties": {
@ -15766,7 +15882,8 @@
"type": "string",
"enum": [
"out.log",
"err.log"
"err.log",
"config"
]
},
"name": {

117
cmd/server/docs/swagger.yaml

@ -1332,6 +1332,16 @@ definitions:
required:
- name
type: object
dto.OperationWithNameAndType:
properties:
name:
type: string
type:
type: string
required:
- name
- type
type: object
dto.Options:
properties:
option:
@ -2986,6 +2996,7 @@ definitions:
enum:
- out.log
- err.log
- config
type: string
name:
type: string
@ -5112,6 +5123,26 @@ paths:
security:
- ApiKeyAuth: []
summary: Load container stats
/containers/load/log:
post:
consumes:
- application/json
description: 获取容器操作日志
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OperationWithNameAndType'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Load container log
tags:
- Container
/containers/network:
get:
consumes:
@ -5781,6 +5812,26 @@ paths:
summary: Page volumes
tags:
- Container Volume
/cronjob/record/log:
post:
consumes:
- application/json
description: 获取计划任务记录日志
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OperateByID'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Load Cronjob record log
tags:
- Cronjob
/cronjobs:
post:
consumes:
@ -6336,6 +6387,26 @@ paths:
summary: Load mysql database from remote
tags:
- Database Mysql
/databases/load/file:
post:
consumes:
- application/json
description: 获取数据库文件
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.OperationWithNameAndType'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Load Database file
tags:
- Database
/databases/options:
get:
consumes:
@ -7038,28 +7109,6 @@ paths:
formatEN: Download file [path]
formatZH: 下载文件 [path]
paramKeys: []
/files/loadfile:
post:
consumes:
- application/json
description: 读取文件
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.FilePath'
responses:
"200":
description: OK
schema:
type: string
security:
- ApiKeyAuth: []
summary: Read file
tags:
- File
/files/mode:
post:
consumes:
@ -7495,6 +7544,17 @@ paths:
formatEN: update SSH conf
formatZH: 修改 SSH 配置文件
paramKeys: []
/host/ssh/conf:
get:
description: 获取 ssh 配置文件
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Load host ssh conf
tags:
- SSH
/host/ssh/generate:
post:
consumes:
@ -7814,7 +7874,7 @@ paths:
BeforeFuntions: []
bodyKeys:
- operate
formatEN: '[operate] [operate] Supervisor 进程文件'
formatEN: '[operate] Supervisor Process Config file'
formatZH: '[operate] Supervisor 进程文件 '
paramKeys: []
/hosts:
@ -8404,6 +8464,17 @@ paths:
summary: Page operation logs
tags:
- Logs
/logs/system:
get:
description: 获取系统日志
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Load system logs
tags:
- Logs
/openResty:
get:
description: 获取 OpenResty 配置信息

3
frontend/src/api/modules/container.ts

@ -26,6 +26,9 @@ export const loadContainerInfo = (name: string) => {
export const cleanContainerLog = (containerName: string) => {
return http.post(`/containers/clean/log`, { name: containerName });
};
export const loadContainerLog = (type: string, name: string) => {
return http.post<string>(`/containers/load/log`, { type: type, name: name });
};
export const containerListStats = () => {
return http.get<Array<Container.ContainerListStats>>(`/containers/list/stats`);
};

4
frontend/src/api/modules/cronjob.ts

@ -6,6 +6,10 @@ export const getCronjobPage = (params: SearchWithPage) => {
return http.post<ResPage<Cronjob.CronjobInfo>>(`/cronjobs/search`, params);
};
export const getRecordLog = (id: number) => {
return http.post<string>(`/cronjobs/records/log`, { id: id });
};
export const addCronjob = (params: Cronjob.CronjobCreate) => {
return http.post<Cronjob.CronjobCreate>(`/cronjobs`, params);
};

3
frontend/src/api/modules/database.ts

@ -7,6 +7,9 @@ import { Database } from '../interface/database';
export const searchMysqlDBs = (params: Database.SearchDBWithPage) => {
return http.post<ResPage<Database.MysqlDBInfo>>(`/databases/search`, params);
};
export const loadDatabaseFile = (type: string, name: string) => {
return http.post<string>(`/databases/load/file`, { type: type, name: name });
};
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
let reqest = deepCopy(params) as Database.MysqlDBCreate;

4
frontend/src/api/modules/files.ts

@ -31,10 +31,6 @@ export const ChangeFileMode = (form: File.FileCreate) => {
return http.post<File.File>('files/mode', form);
};
export const LoadFile = (form: File.FilePath) => {
return http.post<string>('files/loadfile', form);
};
export const CompressFile = (form: File.FileCompress) => {
return http.post<File.File>('files/compress', form);
};

3
frontend/src/api/modules/host.ts

@ -98,6 +98,9 @@ export const batchOperateRule = (params: Host.BatchRule) => {
export const getSSHInfo = () => {
return http.post<Host.SSHInfo>(`/hosts/ssh/search`);
};
export const getSSHConf = () => {
return http.get<string>(`/hosts/ssh/conf`);
};
export const operateSSH = (operation: string) => {
return http.post(`/hosts/ssh/operate`, { operation: operation });
};

4
frontend/src/api/modules/log.ts

@ -10,6 +10,10 @@ export const getLoginLogs = (info: Log.SearchLgLog) => {
return http.post<ResPage<Log.OperationLog>>(`/logs/login`, info);
};
export const getSystemLogs = () => {
return http.get<string>(`/logs/system`);
};
export const cleanLogs = (param: Log.CleanLog) => {
return http.post(`/logs/clean`, param);
};

1
frontend/src/components/backup/index.vue

@ -57,7 +57,6 @@ 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 { DownloadByPath } from '@/api/modules/files';
const selects = ref<any>([]);
const loading = ref();

7
frontend/src/views/container/compose/create/index.vue

@ -122,9 +122,8 @@ import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm, ElMessageBox } from 'element-plus';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { listComposeTemplate, testCompose, upCompose } from '@/api/modules/container';
import { listComposeTemplate, loadContainerLog, testCompose, upCompose } from '@/api/modules/container';
import { loadBaseDir } from '@/api/modules/setting';
import { LoadFile } from '@/api/modules/files';
import { formatImageStdout } from '@/utils/docker';
import { MsgError } from '@/utils/message';
@ -268,9 +267,9 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
});
};
const loadLogs = async (path: string) => {
const loadLogs = async (name: string) => {
timer = setInterval(async () => {
const res = await LoadFile({ path: path });
const res = await loadContainerLog('compose-create', name);
logInfo.value = formatImageStdout(res.data);
nextTick(() => {
const state = view.value.state;

5
frontend/src/views/container/compose/index.vue

@ -98,10 +98,9 @@ import EditDialog from '@/views/container/compose/edit/index.vue';
import CreateDialog from '@/views/container/compose/create/index.vue';
import DeleteDialog from '@/views/container/compose/delete/index.vue';
import ComposeDetial from '@/views/container/compose/detail/index.vue';
import { loadDockerStatus, searchCompose } from '@/api/modules/container';
import { loadContainerLog, loadDockerStatus, searchCompose } from '@/api/modules/container';
import i18n from '@/lang';
import { Container } from '@/api/interface/container';
import { LoadFile } from '@/api/modules/files';
import { loadBaseDir } from '@/api/modules/setting';
import router from '@/routers';
@ -198,7 +197,7 @@ const onDelete = async (row: Container.ComposeInfo) => {
const dialogEditRef = ref();
const onEdit = async (row: Container.ComposeInfo) => {
const res = await LoadFile({ path: row.path });
const res = await loadContainerLog('compose-detail', row.name);
let params = {
name: row.name,
path: row.path,

5
frontend/src/views/container/image/build/index.vue

@ -93,8 +93,7 @@ import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm, ElMessage } from 'element-plus';
import { imageBuild } from '@/api/modules/container';
import { LoadFile } from '@/api/modules/files';
import { imageBuild, loadContainerLog } from '@/api/modules/container';
import { formatImageStdout } from '@/utils/docker';
import DrawerHeader from '@/components/drawer-header/index.vue';
@ -163,7 +162,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
const loadLogs = async (path: string) => {
timer = setInterval(async () => {
if (logVisiable.value) {
const res = await LoadFile({ path: path });
const res = await loadContainerLog('image-build', path);
logInfo.value = formatImageStdout(res.data);
nextTick(() => {
const state = view.value.state;

5
frontend/src/views/container/image/pull/index.vue

@ -68,12 +68,11 @@ import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { imagePull } from '@/api/modules/container';
import { imagePull, loadContainerLog } from '@/api/modules/container';
import { Container } from '@/api/interface/container';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { formatImageStdout } from '@/utils/docker';
import { MsgSuccess } from '@/utils/message';
@ -133,7 +132,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
const loadLogs = async (path: string) => {
timer = setInterval(async () => {
if (logVisiable.value) {
const res = await LoadFile({ path: path });
const res = await loadContainerLog('image-pull', path);
logInfo.value = formatImageStdout(res.data);
nextTick(() => {
const state = view.value.state;

5
frontend/src/views/container/image/push/index.vue

@ -71,12 +71,11 @@ import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { imagePush } from '@/api/modules/container';
import { imagePush, loadContainerLog } from '@/api/modules/container';
import { Container } from '@/api/interface/container';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { formatImageStdout } from '@/utils/docker';
import { MsgSuccess } from '@/utils/message';
@ -138,7 +137,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
const loadLogs = async (path: string) => {
timer = setInterval(async () => {
if (logVisiable.value) {
const res = await LoadFile({ path: path });
const res = await loadContainerLog('image-push', path);
logInfo.value = formatImageStdout(res.data);
nextTick(() => {
const state = view.value.state;

6
frontend/src/views/cronjob/record/index.vue

@ -358,11 +358,11 @@
import { onBeforeUnmount, reactive, ref } from 'vue';
import { Cronjob } from '@/api/interface/cronjob';
import { loadZero } from '@/utils/util';
import { searchRecords, download, handleOnce, updateStatus, cleanRecords } from '@/api/modules/cronjob';
import { searchRecords, download, handleOnce, updateStatus, cleanRecords, getRecordLog } from '@/api/modules/cronjob';
import { dateFormat } from '@/utils/util';
import i18n from '@/lang';
import { ElMessageBox } from 'element-plus';
import { DownloadByPath, LoadFile } from '@/api/modules/files';
import { DownloadByPath } from '@/api/modules/files';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
@ -587,7 +587,7 @@ const loadRecord = async (row: Cronjob.Record) => {
return;
}
if (row.records) {
const res = await LoadFile({ path: row.records });
const res = await getRecordLog(row.id);
currentRecordDetail.value = res.data;
}
};

16
frontend/src/views/database/mysql/setting/index.vue

@ -119,17 +119,14 @@ import { reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import { loadMysqlBaseInfo, loadMysqlVariables, updateMysqlConfByFile } from '@/api/modules/database';
import { loadDatabaseFile, loadMysqlBaseInfo, loadMysqlVariables, updateMysqlConfByFile } from '@/api/modules/database';
import { ChangePort, GetAppDefaultConfig } from '@/api/modules/app';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { loadBaseDir } from '@/api/modules/setting';
import { MsgSuccess } from '@/utils/message';
const loading = ref(false);
const baseDir = ref();
const extensions = [javascript(), oneDark];
const activeName = ref('conf');
@ -179,8 +176,7 @@ const onClose = (): void => {
const jumpToConf = async () => {
activeName.value = 'conf';
const pathRes = await loadBaseDir();
loadMysqlConf(`${pathRes.data}/apps/mysql/${mysqlName.value}/conf/my.cnf`);
loadMysqlConf();
};
const jumpToSlowlog = async () => {
@ -271,9 +267,7 @@ const loadBaseInfo = async () => {
mysqlName.value = res.data?.name;
baseInfo.port = res.data?.port;
baseInfo.containerID = res.data?.containerName;
const pathRes = await loadBaseDir();
baseDir.value = pathRes.data;
loadMysqlConf(`${pathRes.data}/apps/mysql/${mysqlName.value}/conf/my.cnf`);
loadMysqlConf();
loadContainerLog(baseInfo.containerID);
};
@ -302,9 +296,9 @@ const loadSlowLogs = async () => {
slowLogRef.value!.acceptParams(param);
};
const loadMysqlConf = async (path: string) => {
const loadMysqlConf = async () => {
useOld.value = false;
const res = await LoadFile({ path: path });
const res = await loadDatabaseFile('mysql-conf', mysqlName.value);
loading.value = false;
mysqlConf.value = res.data;
};

14
frontend/src/views/database/mysql/setting/slow-log/index.vue

@ -51,12 +51,10 @@ import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { nextTick, onBeforeUnmount, reactive, ref, shallowRef } from 'vue';
import { Database } from '@/api/interface/database';
import { LoadFile } from '@/api/modules/files';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { updateMysqlVariables } from '@/api/modules/database';
import { loadDatabaseFile, updateMysqlVariables } from '@/api/modules/database';
import { dateFormatForName, downloadWithContent } from '@/utils/util';
import i18n from '@/lang';
import { loadBaseDir } from '@/api/modules/setting';
import { MsgError, MsgInfo, MsgSuccess } from '@/utils/message';
const extensions = [javascript(), oneDark];
@ -91,12 +89,10 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
if (variables.slow_query_log === 'ON') {
currentStatus.value = true;
detailShow.value = true;
const pathRes = await loadBaseDir();
let path = `${pathRes.data}/apps/mysql/${mysqlName.value}/data/1Panel-slow.log`;
loadMysqlSlowlogs(path);
loadMysqlSlowlogs();
timer = setInterval(() => {
if (variables.slow_query_log === 'ON' && isWatch.value) {
loadMysqlSlowlogs(path);
loadMysqlSlowlogs();
}
}, 1000 * 5);
} else {
@ -168,8 +164,8 @@ const onDownload = async () => {
downloadWithContent(slowLogs.value, mysqlName.value + '-slowlogs-' + dateFormatForName(new Date()) + '.log');
};
const loadMysqlSlowlogs = async (path: string) => {
const res = await LoadFile({ path: path });
const loadMysqlSlowlogs = async () => {
const res = await loadDatabaseFile('slow-logs', mysqlName.value);
slowLogs.value = res.data || '';
nextTick(() => {
const state = view.value.state;

8
frontend/src/views/database/redis/setting/index.vue

@ -132,15 +132,13 @@ import { nextTick, reactive, ref, shallowRef } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import Status from '@/views/database/redis/setting/status/index.vue';
import Persistence from '@/views/database/redis/setting/persistence/index.vue';
import { loadRedisConf, updateRedisConf, updateRedisConfByFile } from '@/api/modules/database';
import { loadDatabaseFile, loadRedisConf, updateRedisConf, updateRedisConfByFile } from '@/api/modules/database';
import i18n from '@/lang';
import { checkNumberRange, Rules } from '@/global/form-rules';
import { ChangePort, GetAppDefaultConfig } from '@/api/modules/app';
import { loadBaseDir } from '@/api/modules/setting';
import { MsgSuccess } from '@/utils/message';
const extensions = [javascript(), oneDark];
@ -335,11 +333,9 @@ const loadform = async () => {
};
const loadConfFile = async () => {
const pathRes = await loadBaseDir();
let path = `${pathRes.data}/apps/redis/${redisName.value}/conf/redis.conf`;
useOld.value = false;
loading.value = true;
await LoadFile({ path: path })
await loadDatabaseFile('redis-conf', redisName.value)
.then((res) => {
loading.value = false;
redisConf.value = res.data;

5
frontend/src/views/host/ssh/ssh/index.vue

@ -158,8 +158,7 @@ import Port from '@/views/host/ssh/ssh/port/index.vue';
import Address from '@/views/host/ssh/ssh/address/index.vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { getSSHInfo, operateSSH, updateSSH, updateSSHByfile } from '@/api/modules/host';
import { LoadFile } from '@/api/modules/files';
import { getSSHConf, getSSHInfo, operateSSH, updateSSH, updateSSHByfile } from '@/api/modules/host';
import { ElMessageBox, FormInstance } from 'element-plus';
const loading = ref(false);
@ -289,7 +288,7 @@ const changei18n = (value: string) => {
};
const loadSSHConf = async () => {
const res = await LoadFile({ path: '/etc/ssh/sshd_config' });
const res = await getSSHConf();
sshConf.value = res.data || '';
};

7
frontend/src/views/log/system/index.vue

@ -42,9 +42,8 @@ import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { nextTick, onMounted, ref, shallowRef } from 'vue';
import { LoadFile } from '@/api/modules/files';
import { loadBaseDir } from '@/api/modules/setting';
import { useRouter } from 'vue-router';
import { getSystemLogs } from '@/api/modules/log';
const router = useRouter();
const loading = ref();
@ -56,9 +55,7 @@ const handleReady = (payload) => {
};
const loadSystemlogs = async () => {
const pathRes = await loadBaseDir();
let logPath = pathRes.data + '/log';
await LoadFile({ path: `${logPath}/1Panel.log` })
await getSystemLogs()
.then((res) => {
loading.value = false;
logs.value = res.data;

Loading…
Cancel
Save