mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-11 21:06:08 +08:00
feat: 镜像拉取、推送、构建改为任务方式实现 (#6598)
Co-authored-by: ssonglius11 <ssonglius11@163.com>
This commit is contained in:
parent
c101dfb694
commit
157fff8481
18 changed files with 488 additions and 563 deletions
|
|
@ -54,7 +54,6 @@ func (b *BaseApi) ListContainer(c *gin.Context) {
|
||||||
helper.SuccessWithData(c, list)
|
helper.SuccessWithData(c, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @Tags Container
|
// @Tags Container
|
||||||
// @Summary Load containers status
|
// @Summary Load containers status
|
||||||
// @Description 获取容器状态
|
// @Description 获取容器状态
|
||||||
|
|
@ -135,12 +134,11 @@ func (b *BaseApi) CreateCompose(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log, err := containerService.CreateCompose(req)
|
if err := containerService.CreateCompose(req); err != nil {
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, log)
|
helper.SuccessWithOutData(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container Compose
|
// @Tags Container Compose
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,12 @@ func (b *BaseApi) ImageBuild(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log, err := imageService.ImageBuild(req)
|
if err := imageService.ImageBuild(req); err != nil {
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.SuccessWithData(c, log)
|
helper.SuccessWithOutData(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container Image
|
// @Tags Container Image
|
||||||
|
|
@ -105,13 +104,12 @@ func (b *BaseApi) ImagePull(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logPath, err := imageService.ImagePull(req)
|
if err := imageService.ImagePull(req); err != nil {
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.SuccessWithData(c, logPath)
|
helper.SuccessWithOutData(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container Image
|
// @Tags Container Image
|
||||||
|
|
@ -129,13 +127,12 @@ func (b *BaseApi) ImagePush(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logPath, err := imageService.ImagePush(req)
|
if err := imageService.ImagePush(req); err != nil {
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.SuccessWithData(c, logPath)
|
helper.SuccessWithOutData(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Container Image
|
// @Tags Container Image
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ type ResourceLimit struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerOperate struct {
|
type ContainerOperate struct {
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
ContainerID string `json:"containerID"`
|
ContainerID string `json:"containerID"`
|
||||||
ForcePull bool `json:"forcePull"`
|
ForcePull bool `json:"forcePull"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
|
|
@ -218,6 +219,7 @@ type ComposeContainer struct {
|
||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
}
|
}
|
||||||
type ComposeCreate struct {
|
type ComposeCreate struct {
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
From string `json:"from" validate:"required,oneof=edit path template"`
|
From string `json:"from" validate:"required,oneof=edit path template"`
|
||||||
File string `json:"file"`
|
File string `json:"file"`
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ type ImageLoad struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageBuild struct {
|
type ImageBuild struct {
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
From string `json:"from" validate:"required"`
|
From string `json:"from" validate:"required"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Dockerfile string `json:"dockerfile" validate:"required"`
|
Dockerfile string `json:"dockerfile" validate:"required"`
|
||||||
|
|
@ -22,6 +23,7 @@ type ImageBuild struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImagePull struct {
|
type ImagePull struct {
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
RepoID uint `json:"repoID"`
|
RepoID uint `json:"repoID"`
|
||||||
ImageName string `json:"imageName" validate:"required"`
|
ImageName string `json:"imageName" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +34,7 @@ type ImageTag struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImagePush struct {
|
type ImagePush struct {
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
RepoID uint `json:"repoID" validate:"required"`
|
RepoID uint `json:"repoID" validate:"required"`
|
||||||
TagName string `json:"tagName" validate:"required"`
|
TagName string `json:"tagName" validate:"required"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,11 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||||
|
|
@ -57,7 +59,7 @@ type IContainerService interface {
|
||||||
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
ListVolume() ([]dto.Options, error)
|
ListVolume() ([]dto.Options, error)
|
||||||
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
CreateCompose(req dto.ComposeCreate) (string, error)
|
CreateCompose(req dto.ComposeCreate) error
|
||||||
ComposeOperation(req dto.ComposeOperation) error
|
ComposeOperation(req dto.ComposeOperation) error
|
||||||
ContainerCreate(req dto.ContainerOperate) error
|
ContainerCreate(req dto.ContainerOperate) error
|
||||||
ContainerUpdate(req dto.ContainerOperate) error
|
ContainerUpdate(req dto.ContainerOperate) error
|
||||||
|
|
@ -412,39 +414,64 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
||||||
return buserr.New(constant.ErrContainerName)
|
return buserr.New(constant.ErrContainerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !checkImageExist(client, req.Image) || req.ForcePull {
|
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskCreate, task.TaskScopeContainer, req.TaskID, 1)
|
||||||
if err := pullImages(ctx, client, req.Image); err != nil {
|
if err != nil {
|
||||||
if !req.ForcePull {
|
global.LOG.Errorf("new task for create container failed, err: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
taskItem.AddSubTask(i18n.GetWithName("ContainerImagePull", req.Image), func(t *task.Task) error {
|
||||||
|
if !checkImageExist(client, req.Image) || req.ForcePull {
|
||||||
|
if err := pullImages(ctx, client, req.Image); err != nil {
|
||||||
|
if !req.ForcePull {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
taskItem.AddSubTask(i18n.GetMsgByKey("ContainerImageCheck"), func(t *task.Task) error {
|
||||||
|
imageInfo, _, err := client.ImageInspectWithRaw(ctx, req.Image)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err)
|
if len(req.Entrypoint) == 0 {
|
||||||
|
req.Entrypoint = imageInfo.Config.Entrypoint
|
||||||
|
}
|
||||||
|
if len(req.Cmd) == 0 {
|
||||||
|
req.Cmd = imageInfo.Config.Cmd
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
taskItem.AddSubTask(i18n.GetWithName("ContainerCreate", req.Name), func(t *task.Task) error {
|
||||||
|
config, hostConf, networkConf, err := loadConfigInfo(true, req, nil)
|
||||||
|
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerLoadInfo"), err)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
con, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
|
||||||
|
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerCreate"), err)
|
||||||
|
if err != nil {
|
||||||
|
taskItem.Log(i18n.GetMsgByKey("ContainerCreateFailed"))
|
||||||
|
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = client.ContainerStart(ctx, con.ID, container.StartOptions{})
|
||||||
|
taskItem.LogWithStatus(i18n.GetMsgByKey("ContainerStartCheck"), err)
|
||||||
|
if err != nil {
|
||||||
|
taskItem.Log(i18n.GetMsgByKey("ContainerCreateFailed"))
|
||||||
|
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
||||||
|
return fmt.Errorf("create successful but start failed, err: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
if err := taskItem.Execute(); err != nil {
|
||||||
|
global.LOG.Error(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
imageInfo, _, err := client.ImageInspectWithRaw(ctx, req.Image)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(req.Entrypoint) == 0 {
|
|
||||||
req.Entrypoint = imageInfo.Config.Entrypoint
|
|
||||||
}
|
|
||||||
if len(req.Cmd) == 0 {
|
|
||||||
req.Cmd = imageInfo.Config.Cmd
|
|
||||||
}
|
|
||||||
config, hostConf, networkConf, err := loadConfigInfo(true, req, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
|
|
||||||
con, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
|
|
||||||
if err != nil {
|
|
||||||
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
global.LOG.Infof("create container %s successful! now check if the container is started and delete the container information if it is not.", req.Name)
|
|
||||||
if err := client.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
|
|
||||||
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
|
|
||||||
return fmt.Errorf("create successful but start failed, err: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
|
@ -16,9 +15,11 @@ import (
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/compose"
|
"github.com/1Panel-dev/1Panel/agent/utils/compose"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||||
|
|
@ -149,48 +150,36 @@ func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error) {
|
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
|
||||||
if cmd.CheckIllegal(req.Name, req.Path) {
|
if cmd.CheckIllegal(req.Name, req.Path) {
|
||||||
return "", buserr.New(constant.ErrCmdIllegal)
|
return buserr.New(constant.ErrCmdIllegal)
|
||||||
}
|
}
|
||||||
if err := u.loadPath(&req); err != nil {
|
if err := u.loadPath(&req); err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
global.LOG.Infof("docker-compose.yml %s create successful, start to docker-compose up", req.Name)
|
|
||||||
|
|
||||||
if req.From == "path" {
|
if req.From == "path" {
|
||||||
req.Name = path.Base(path.Dir(req.Path))
|
req.Name = path.Base(path.Dir(req.Path))
|
||||||
}
|
}
|
||||||
|
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskCreate, task.TaskScopeCompose, req.TaskID, 1)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logItem := fmt.Sprintf("%s/compose_create_%s_%s.log", dockerLogDir, req.Name, time.Now().Format(constant.DateTimeSlimLayout))
|
|
||||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return fmt.Errorf("new task for image build failed, err: %v", err)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
defer file.Close()
|
taskItem.AddSubTask(i18n.GetMsgByKey("ComposeCreate"), func(t *task.Task) error {
|
||||||
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
|
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
|
||||||
multiWriter := io.MultiWriter(os.Stdout, file)
|
out, err := cmd.CombinedOutput()
|
||||||
cmd.Stdout = multiWriter
|
taskItem.Log(i18n.GetWithName("ComposeCreateRes", string(out)))
|
||||||
cmd.Stderr = multiWriter
|
if err != nil {
|
||||||
if err := cmd.Run(); err != nil {
|
_, _ = compose.Down(req.Path)
|
||||||
global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err)
|
return err
|
||||||
_, _ = compose.Down(req.Path)
|
}
|
||||||
_, _ = file.WriteString("docker-compose up failed!")
|
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name})
|
||||||
return
|
return nil
|
||||||
}
|
}, nil)
|
||||||
global.LOG.Infof("docker-compose up %s successful!", req.Name)
|
_ = taskItem.Execute()
|
||||||
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name})
|
|
||||||
_, _ = file.WriteString("docker-compose up successful!")
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return path.Base(logItem), nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ const (
|
||||||
uploadPath = "1panel/uploads"
|
uploadPath = "1panel/uploads"
|
||||||
downloadPath = "1panel/download"
|
downloadPath = "1panel/download"
|
||||||
logPath = "1panel/log"
|
logPath = "1panel/log"
|
||||||
dockerLogPath = "1panel/tmp/docker_logs"
|
|
||||||
taskPath = "1panel/task"
|
taskPath = "1panel/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -252,8 +251,6 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||||
} else {
|
} else {
|
||||||
dropFileOrDir(path.Join(global.CONF.System.BaseDir, logPath, item.Name))
|
dropFileOrDir(path.Join(global.CONF.System.BaseDir, logPath, item.Name))
|
||||||
}
|
}
|
||||||
case "docker_log":
|
|
||||||
dropFileOrDir(path.Join(global.CONF.System.BaseDir, dockerLogPath, item.Name))
|
|
||||||
case "task_log":
|
case "task_log":
|
||||||
pathItem := path.Join(global.CONF.System.BaseDir, taskPath, item.Name)
|
pathItem := path.Join(global.CONF.System.BaseDir, taskPath, item.Name)
|
||||||
dropFileOrDir(path.Join(global.CONF.System.BaseDir, taskPath, item.Name))
|
dropFileOrDir(path.Join(global.CONF.System.BaseDir, taskPath, item.Name))
|
||||||
|
|
@ -344,7 +341,6 @@ func (u *DeviceService) CleanForCronjob() (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timeNow := time.Now().Format(constant.DateTimeLayout)
|
timeNow := time.Now().Format(constant.DateTimeLayout)
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, dockerLogPath), &logs, &size, &fileCount)
|
|
||||||
logs += fmt.Sprintf("\n%s: total clean: %s, total count: %d", timeNow, common.LoadSizeUnit2F(float64(size)), fileCount)
|
logs += fmt.Sprintf("\n%s: total clean: %s, total count: %d", timeNow, common.LoadSizeUnit2F(float64(size)), fileCount)
|
||||||
|
|
||||||
_ = settingRepo.Update("LastCleanTime", timeNow)
|
_ = settingRepo.Update("LastCleanTime", timeNow)
|
||||||
|
|
@ -501,15 +497,10 @@ func loadLogTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||||
}
|
}
|
||||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "system_log", Size: uint64(size), Children: list1, Type: "system_log", IsRecommend: true})
|
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "system_log", Size: uint64(size), Children: list1, Type: "system_log", IsRecommend: true})
|
||||||
|
|
||||||
path2 := path.Join(global.CONF.System.BaseDir, dockerLogPath)
|
path2 := path.Join(global.CONF.System.BaseDir, taskPath)
|
||||||
list2 := loadTreeWithAllFile(true, path2, "docker_log", path2, fileOp)
|
list2 := loadTreeWithAllFile(false, path2, "task_log", path2, fileOp)
|
||||||
size2, _ := fileOp.GetDirSize(path2)
|
size2, _ := fileOp.GetDirSize(path2)
|
||||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "docker_log", Size: uint64(size2), Children: list2, Type: "docker_log", IsRecommend: true})
|
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "task_log", Size: uint64(size2), Children: list2, Type: "task_log"})
|
||||||
|
|
||||||
path3 := path.Join(global.CONF.System.BaseDir, taskPath)
|
|
||||||
list3 := loadTreeWithAllFile(false, path3, "task_log", path3, fileOp)
|
|
||||||
size3, _ := fileOp.GetDirSize(path3)
|
|
||||||
treeData = append(treeData, dto.CleanTree{ID: uuid.NewString(), Label: "task_log", Size: uint64(size3), Children: list3, Type: "task_log"})
|
|
||||||
return treeData
|
return treeData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -475,8 +475,6 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logFilePath = taskModel.LogFile
|
logFilePath = taskModel.LogFile
|
||||||
case constant.TypeImagePull, constant.TypeImagePush, constant.TypeImageBuild, constant.TypeComposeCreate:
|
|
||||||
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
|
lines, isEndOfFile, total, err := files.ReadFileByLine(logFilePath, req.Page, req.PageSize, req.Latest)
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,11 @@ import (
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
|
|
@ -33,11 +35,11 @@ type IImageService interface {
|
||||||
Page(req dto.SearchWithPage) (int64, interface{}, error)
|
Page(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
List() ([]dto.Options, error)
|
List() ([]dto.Options, error)
|
||||||
ListAll() ([]dto.ImageInfo, error)
|
ListAll() ([]dto.ImageInfo, error)
|
||||||
ImageBuild(req dto.ImageBuild) (string, error)
|
ImageBuild(req dto.ImageBuild) error
|
||||||
ImagePull(req dto.ImagePull) (string, error)
|
ImagePull(req dto.ImagePull) error
|
||||||
ImageLoad(req dto.ImageLoad) error
|
ImageLoad(req dto.ImageLoad) error
|
||||||
ImageSave(req dto.ImageSave) error
|
ImageSave(req dto.ImageSave) error
|
||||||
ImagePush(req dto.ImagePush) (string, error)
|
ImagePush(req dto.ImagePush) error
|
||||||
ImageRemove(req dto.BatchDelete) error
|
ImageRemove(req dto.BatchDelete) error
|
||||||
ImageTag(req dto.ImageTag) error
|
ImageTag(req dto.ImageTag) error
|
||||||
}
|
}
|
||||||
|
|
@ -152,10 +154,10 @@ func (u *ImageService) List() ([]dto.Options, error) {
|
||||||
return backDatas, nil
|
return backDatas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
func (u *ImageService) ImageBuild(req dto.ImageBuild) error {
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
fileName := "Dockerfile"
|
fileName := "Dockerfile"
|
||||||
|
|
@ -163,14 +165,14 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
||||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathItem := fmt.Sprintf("%s/Dockerfile", dir)
|
pathItem := fmt.Sprintf("%s/Dockerfile", dir)
|
||||||
file, err := os.OpenFile(pathItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
file, err := os.OpenFile(pathItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
write := bufio.NewWriter(file)
|
write := bufio.NewWriter(file)
|
||||||
|
|
@ -183,7 +185,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||||
}
|
}
|
||||||
tar, err := archive.TarWithOptions(req.Dockerfile+"/", &archive.TarOptions{})
|
tar, err := archive.TarWithOptions(req.Dockerfile+"/", &archive.TarOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := types.ImageBuildOptions{
|
opts := types.ImageBuildOptions{
|
||||||
|
|
@ -192,118 +194,89 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||||
Remove: true,
|
Remove: true,
|
||||||
Labels: stringsToMap(req.Tags),
|
Labels: stringsToMap(req.Tags),
|
||||||
}
|
}
|
||||||
|
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskBuild, task.TaskScopeImage, req.TaskID, 1)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format(constant.DateTimeSlimLayout))
|
|
||||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return fmt.Errorf("new task for image build failed, err: %v", err)
|
||||||
}
|
}
|
||||||
go func() {
|
|
||||||
defer file.Close()
|
|
||||||
defer tar.Close()
|
|
||||||
res, err := client.ImageBuild(context.Background(), tar, opts)
|
|
||||||
if err != nil {
|
|
||||||
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
|
||||||
_, _ = file.WriteString("image build failed!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
|
||||||
_, _ = file.WriteString(fmt.Sprintf("build image %s failed, err: %v", req.Name, err))
|
|
||||||
_, _ = file.WriteString("image build failed!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(string(body), "errorDetail") || strings.Contains(string(body), "error:") {
|
go func() {
|
||||||
global.LOG.Errorf("build image %s failed", req.Name)
|
defer tar.Close()
|
||||||
_, _ = file.Write(body)
|
taskItem.AddSubTask(i18n.GetMsgByKey("ImageBuild"), func(t *task.Task) error {
|
||||||
_, _ = file.WriteString("image build failed!")
|
res, err := client.ImageBuild(context.Background(), tar, opts)
|
||||||
return
|
taskItem.LogWithStatus(i18n.GetMsgByKey("TaskBuild"), err)
|
||||||
}
|
if err != nil {
|
||||||
global.LOG.Infof("build image %s successful!", req.Name)
|
return err
|
||||||
_, _ = file.Write(body)
|
}
|
||||||
_, _ = file.WriteString("image build successful!")
|
defer res.Body.Close()
|
||||||
|
body, _ := io.ReadAll(res.Body)
|
||||||
|
if strings.Contains(string(body), "errorDetail") || strings.Contains(string(body), "error:") {
|
||||||
|
taskItem.LogWithStatus(i18n.GetMsgByKey("ImageBuildStdoutCheck"), fmt.Errorf("build image %s failed", req.Name))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
taskItem.LogSuccess(i18n.GetWithName("ImaegBuildRes", "\n"+string(body)))
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
_ = taskItem.Execute()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return path.Base(logItem), nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
|
func (u *ImageService) ImagePull(req dto.ImagePull) error {
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
defer client.Close()
|
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 {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imageItemName := strings.ReplaceAll(path.Base(req.ImageName), ":", "_")
|
imageItemName := strings.ReplaceAll(path.Base(req.ImageName), ":", "_")
|
||||||
logItem := fmt.Sprintf("%s/image_pull_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format(constant.DateTimeSlimLayout))
|
taskItem, err := task.NewTaskWithOps(imageItemName, task.TaskPull, task.TaskScopeImage, req.TaskID, 1)
|
||||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return fmt.Errorf("new task for image pull failed, err: %v", err)
|
||||||
}
|
}
|
||||||
options := image.PullOptions{}
|
go func() {
|
||||||
if req.RepoID == 0 {
|
taskItem.AddSubTask(i18n.GetWithName("ImagePull", req.ImageName), func(t *task.Task) error {
|
||||||
hasAuth, authStr := loadAuthInfo(req.ImageName)
|
options := image.PullOptions{}
|
||||||
if hasAuth {
|
imageName := req.ImageName
|
||||||
options.RegistryAuth = authStr
|
if req.RepoID == 0 {
|
||||||
}
|
hasAuth, authStr := loadAuthInfo(req.ImageName)
|
||||||
go func() {
|
if hasAuth {
|
||||||
defer file.Close()
|
options.RegistryAuth = authStr
|
||||||
out, err := client.ImagePull(context.TODO(), req.ImageName, options)
|
}
|
||||||
|
} else {
|
||||||
|
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
|
||||||
|
taskItem.LogWithStatus(i18n.GetMsgByKey("ImageRepoAuthFromDB"), err)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
imageName = repo.DownloadUrl + "/" + req.ImageName
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := client.ImagePull(context.TODO(), imageName, options)
|
||||||
|
taskItem.LogWithStatus(i18n.GetMsgByKey("TaskPull"), err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("image %s pull failed, err: %v", req.ImageName, err)
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
global.LOG.Infof("pull image %s successful!", req.ImageName)
|
body, _ := io.ReadAll(out)
|
||||||
_, _ = io.Copy(file, out)
|
taskItem.LogSuccess(i18n.GetWithName("ImaegPullRes", "\n"+string(body)))
|
||||||
}()
|
return nil
|
||||||
return path.Base(logItem), nil
|
}, nil)
|
||||||
}
|
_ = taskItem.Execute()
|
||||||
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
image := repo.DownloadUrl + "/" + req.ImageName
|
|
||||||
go func() {
|
|
||||||
defer file.Close()
|
|
||||||
out, err := client.ImagePull(context.TODO(), image, options)
|
|
||||||
if err != nil {
|
|
||||||
_, _ = file.WriteString("image pull failed!")
|
|
||||||
global.LOG.Errorf("image %s pull failed, err: %v", image, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer out.Close()
|
|
||||||
global.LOG.Infof("pull image %s successful!", req.ImageName)
|
|
||||||
_, _ = io.Copy(file, out)
|
|
||||||
_, _ = file.WriteString("image pull successful!")
|
|
||||||
}()
|
}()
|
||||||
return path.Base(logItem), nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
|
func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
|
||||||
|
|
@ -368,61 +341,62 @@ func (u *ImageService) ImageTag(req dto.ImageTag) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
|
func (u *ImageService) ImagePush(req dto.ImagePush) error {
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
|
|
||||||
|
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskPush, task.TaskScopeImage, req.TaskID, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return fmt.Errorf("new task for image push failed, err: %v", err)
|
||||||
}
|
|
||||||
options := image.PushOptions{All: true}
|
|
||||||
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
|
|
||||||
newName := fmt.Sprintf("%s/%s", repo.DownloadUrl, req.Name)
|
|
||||||
if newName != req.TagName {
|
|
||||||
if err := client.ImageTag(context.TODO(), req.TagName, newName); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerLogDir := 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.Name), ":", "_")
|
|
||||||
logItem := fmt.Sprintf("%s/image_push_%s_%s.log", dockerLogDir, imageItemName, time.Now().Format(constant.DateTimeSlimLayout))
|
|
||||||
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
go func() {
|
go func() {
|
||||||
defer file.Close()
|
options := image.PushOptions{All: true}
|
||||||
out, err := client.ImagePush(context.TODO(), newName, options)
|
var repo model.ImageRepo
|
||||||
if err != nil {
|
newName := ""
|
||||||
global.LOG.Errorf("image %s push failed, err: %v", req.TagName, err)
|
taskItem.AddSubTask(i18n.GetMsgByKey("ImagePush"), func(t *task.Task) error {
|
||||||
_, _ = file.WriteString("image push failed!")
|
repo, err = imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
|
||||||
return
|
newName = fmt.Sprintf("%s/%s", repo.DownloadUrl, req.Name)
|
||||||
}
|
taskItem.LogWithStatus(i18n.GetMsgByKey("ImageRepoAuthFromDB"), err)
|
||||||
defer out.Close()
|
if err != nil {
|
||||||
global.LOG.Infof("push image %s successful!", req.Name)
|
return err
|
||||||
_, _ = io.Copy(file, out)
|
}
|
||||||
_, _ = file.WriteString("image push successful!")
|
options = image.PushOptions{All: true}
|
||||||
|
authConfig := registry.AuthConfig{
|
||||||
|
Username: repo.Username,
|
||||||
|
Password: repo.Password,
|
||||||
|
}
|
||||||
|
encodedJSON, _ := json.Marshal(authConfig)
|
||||||
|
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
|
||||||
|
options.RegistryAuth = authStr
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
taskItem.AddSubTask(i18n.GetMsgByKey("ImageRenameTag"), func(t *task.Task) error {
|
||||||
|
taskItem.Log(i18n.GetWithName("ImageNewTag", newName))
|
||||||
|
if newName != req.TagName {
|
||||||
|
if err := client.ImageTag(context.TODO(), req.TagName, newName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
taskItem.AddSubTask(i18n.GetMsgByKey("TaskPush"), func(t *task.Task) error {
|
||||||
|
out, err := client.ImagePush(context.TODO(), newName, options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
body, _ := io.ReadAll(out)
|
||||||
|
taskItem.Log(i18n.GetWithName("ImaegPushRes", "\n"+string(body)))
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
_ = taskItem.Execute()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return path.Base(logItem), nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ const (
|
||||||
TaskRollback = "TaskRollback"
|
TaskRollback = "TaskRollback"
|
||||||
TaskSync = "TaskSync"
|
TaskSync = "TaskSync"
|
||||||
TaskBuild = "TaskBuild"
|
TaskBuild = "TaskBuild"
|
||||||
|
TaskPull = "TaskPull"
|
||||||
|
TaskPush = "TaskPush"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -65,6 +67,9 @@ const (
|
||||||
TaskScopeDatabase = "Database"
|
TaskScopeDatabase = "Database"
|
||||||
TaskScopeAppStore = "AppStore"
|
TaskScopeAppStore = "AppStore"
|
||||||
TaskScopeSnapshot = "Snapshot"
|
TaskScopeSnapshot = "Snapshot"
|
||||||
|
TaskScopeContainer = "Container"
|
||||||
|
TaskScopeCompose = "Compose"
|
||||||
|
TaskScopeImage = "Image"
|
||||||
TaskScopeRuntimeExtension = "RuntimeExtension"
|
TaskScopeRuntimeExtension = "RuntimeExtension"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ ErrNameIsExist: "Name is already exist"
|
||||||
ErrDemoEnvironment: "Demo server, prohibit this operation!"
|
ErrDemoEnvironment: "Demo server, prohibit this operation!"
|
||||||
ErrCmdTimeout: "Command execution timed out!"
|
ErrCmdTimeout: "Command execution timed out!"
|
||||||
ErrCmdIllegal: "The command contains illegal characters. Please modify and try again!"
|
ErrCmdIllegal: "The command contains illegal characters. Please modify and try again!"
|
||||||
ErrPortExist: '{{ .port }} port is already occupied by {{ .type }} [{{ .name }}]'
|
ErrPortExist: "{{ .port }} port is already occupied by {{ .type }} [{{ .name }}]"
|
||||||
TYPE_APP: "Application"
|
TYPE_APP: "Application"
|
||||||
TYPE_RUNTIME: "Runtime environment"
|
TYPE_RUNTIME: "Runtime environment"
|
||||||
TYPE_DOMAIN: "Domain name"
|
TYPE_DOMAIN: "Domain name"
|
||||||
ErrTypePort: 'Port {{ .name }} format error'
|
ErrTypePort: "Port {{ .name }} format error"
|
||||||
Success: "Success"
|
Success: "Success"
|
||||||
Failed: "Failed"
|
Failed: "Failed"
|
||||||
SystemRestart: "System restart causes task interruption"
|
SystemRestart: "System restart causes task interruption"
|
||||||
|
|
@ -27,16 +27,16 @@ ErrNotInstall: "App not installed"
|
||||||
ErrPortInOtherApp: "{{ .port }} port already in use by app {{ .apps }}"
|
ErrPortInOtherApp: "{{ .port }} port already in use by app {{ .apps }}"
|
||||||
ErrDbUserNotValid: "Stock database, username and password do not match!"
|
ErrDbUserNotValid: "Stock database, username and password do not match!"
|
||||||
ErrDockerComposeNotValid: "docker-compose file format error!"
|
ErrDockerComposeNotValid: "docker-compose file format error!"
|
||||||
ErrUpdateBuWebsite: 'The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!'
|
ErrUpdateBuWebsite: "The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!"
|
||||||
Err1PanelNetworkFailed: 'Default container network creation failed! {{ .detail }}'
|
Err1PanelNetworkFailed: "Default container network creation failed! {{ .detail }}"
|
||||||
ErrFileParse: 'Application docker-compose file parsing failed!'
|
ErrFileParse: "Application docker-compose file parsing failed!"
|
||||||
ErrInstallDirNotFound: 'installation directory does not exist'
|
ErrInstallDirNotFound: "installation directory does not exist"
|
||||||
AppStoreIsUpToDate: 'The app store is already up to date!'
|
AppStoreIsUpToDate: "The app store is already up to date!"
|
||||||
LocalAppVersionNull: 'The {{.name}} app is not synced to version! Could not add to application list'
|
LocalAppVersionNull: "The {{.name}} app is not synced to version! Could not add to application list"
|
||||||
LocalAppVersionErr: '{{.name}} failed to sync version {{.version}}! {{.err}}'
|
LocalAppVersionErr: "{{.name}} failed to sync version {{.version}}! {{.err}}"
|
||||||
ErrFileNotFound: '{{.name}} file does not exist'
|
ErrFileNotFound: "{{.name}} file does not exist"
|
||||||
ErrFileParseApp: 'Failed to parse {{.name}} file {{.err}}'
|
ErrFileParseApp: "Failed to parse {{.name}} file {{.err}}"
|
||||||
ErrAppDirNull: 'version folder does not exist'
|
ErrAppDirNull: "version folder does not exist"
|
||||||
LocalAppErr: "App {{.name}} sync failed! {{.err}}"
|
LocalAppErr: "App {{.name}} sync failed! {{.err}}"
|
||||||
ErrContainerName: "ContainerName is already exist"
|
ErrContainerName: "ContainerName is already exist"
|
||||||
ErrAppSystemRestart: "1Panel restart causes the task to terminate"
|
ErrAppSystemRestart: "1Panel restart causes the task to terminate"
|
||||||
|
|
@ -45,14 +45,14 @@ ErrHttpReqTimeOut: "Request timed out {{.err}}"
|
||||||
ErrHttpReqFailed: "Request failed {{.err}}"
|
ErrHttpReqFailed: "Request failed {{.err}}"
|
||||||
ErrHttpReqNotFound: "The file does not exist"
|
ErrHttpReqNotFound: "The file does not exist"
|
||||||
ErrNoSuchHost: "Network connection failed"
|
ErrNoSuchHost: "Network connection failed"
|
||||||
ErrImagePullTimeOut: 'Image pull timeout'
|
ErrImagePullTimeOut: "Image pull timeout"
|
||||||
ErrContainerNotFound: '{{ .name }} container does not exist'
|
ErrContainerNotFound: "{{ .name }} container does not exist"
|
||||||
ErrContainerMsg: '{{ .name }} container is abnormal, please check the log on the container page for details'
|
ErrContainerMsg: "{{ .name }} container is abnormal, please check the log on the container page for details"
|
||||||
ErrAppBackup: '{{ .name }} application backup failed err {{.err}}'
|
ErrAppBackup: "{{ .name }} application backup failed err {{.err}}"
|
||||||
ErrImagePull: '{{ .name }} image pull failed err {{.err}}'
|
ErrImagePull: "{{ .name }} image pull failed err {{.err}}"
|
||||||
ErrVersionTooLow: 'The current 1Panel version is too low to update the app store, please upgrade the version'
|
ErrVersionTooLow: "The current 1Panel version is too low to update the app store, please upgrade the version"
|
||||||
ErrAppNameExist: 'App name is already exist'
|
ErrAppNameExist: "App name is already exist"
|
||||||
AppStoreIsSyncing: 'The App Store is syncing, please try again later'
|
AppStoreIsSyncing: "The App Store is syncing, please try again later"
|
||||||
ErrGetCompose: "Failed to obtain docker-compose.yml file! {{ .detail }}"
|
ErrGetCompose: "Failed to obtain docker-compose.yml file! {{ .detail }}"
|
||||||
ErrAppWarn: "Abnormal status, please check the log"
|
ErrAppWarn: "Abnormal status, please check the log"
|
||||||
ErrAppParamKey: "Parameter {{ .name }} field exception"
|
ErrAppParamKey: "Parameter {{ .name }} field exception"
|
||||||
|
|
@ -89,12 +89,12 @@ ErrInvalidChar: "Illegal characters are prohibited"
|
||||||
#website
|
#website
|
||||||
ErrDomainIsExist: "Domain is already exist"
|
ErrDomainIsExist: "Domain is already exist"
|
||||||
ErrAliasIsExist: "Alias is already exist"
|
ErrAliasIsExist: "Alias is already exist"
|
||||||
ErrAppDelete: 'Other Website use this App'
|
ErrAppDelete: "Other Website use this App"
|
||||||
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
|
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}}'
|
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}}'
|
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!'
|
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 an Access denied error when accessing the website. Please click the save button above"
|
||||||
ErrDomainIsUsed: "Domain is already used by website {{ .name }}"
|
ErrDomainIsUsed: "Domain is already used by website {{ .name }}"
|
||||||
ErrDomainFormat: "{{ .name }} domain format error"
|
ErrDomainFormat: "{{ .name }} domain format error"
|
||||||
ErrDefaultAlias: "default is a reserved code name, please use another code name"
|
ErrDefaultAlias: "default is a reserved code name, please use another code name"
|
||||||
|
|
@ -105,21 +105,21 @@ ErrBuildDirNotFound: "Build directory does not exist"
|
||||||
ErrSSLCannotDelete: "The certificate {{ .name }} is being used by the website and cannot be removed"
|
ErrSSLCannotDelete: "The certificate {{ .name }} is being used by the website and cannot be removed"
|
||||||
ErrAccountCannotDelete: "The certificate associated with the account cannot be deleted"
|
ErrAccountCannotDelete: "The certificate associated with the account cannot be deleted"
|
||||||
ErrSSLApply: "The certificate continues to be signed successfully, but openresty reload fails, please check the configuration!"
|
ErrSSLApply: "The certificate continues to be signed successfully, but openresty reload fails, please check the configuration!"
|
||||||
ErrEmailIsExist: 'Email is already exist'
|
ErrEmailIsExist: "Email is already exist"
|
||||||
ErrSSLKeyNotFound: 'The private key file does not exist'
|
ErrSSLKeyNotFound: "The private key file does not exist"
|
||||||
ErrSSLCertificateNotFound: 'The certificate file does not exist'
|
ErrSSLCertificateNotFound: "The certificate file does not exist"
|
||||||
ErrSSLKeyFormat: 'Private key file verification error'
|
ErrSSLKeyFormat: "Private key file verification error"
|
||||||
ErrSSLCertificateFormat: 'Certificate file format error, please use pem format'
|
ErrSSLCertificateFormat: "Certificate file format error, please use pem format"
|
||||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid or EabHmacKey cannot be empty'
|
ErrEabKidOrEabHmacKeyCannotBlank: "EabKid or EabHmacKey cannot be empty"
|
||||||
ErrOpenrestyNotFound: 'Http mode requires Openresty to be installed first'
|
ErrOpenrestyNotFound: "Http mode requires Openresty to be installed first"
|
||||||
ApplySSLStart: 'Start applying for certificate, domain name [{{ .domain }}] application method [{{ .type }}] '
|
ApplySSLStart: "Start applying for certificate, domain name [{{ .domain }}] application method [{{ .type }}] "
|
||||||
dnsAccount: "DNS Automatic"
|
dnsAccount: "DNS Automatic"
|
||||||
dnsManual: "DNS Manual"
|
dnsManual: "DNS Manual"
|
||||||
http: "HTTP"
|
http: "HTTP"
|
||||||
ApplySSLFailed: 'Application for [{{ .domain }}] certificate failed, {{.detail}} '
|
ApplySSLFailed: "Application for [{{ .domain }}] certificate failed, {{.detail}} "
|
||||||
ApplySSLSuccess: 'Application for [{{ .domain }}] certificate successful! ! '
|
ApplySSLSuccess: "Application for [{{ .domain }}] certificate successful! ! "
|
||||||
DNSAccountName: 'DNS account [{{ .name }}] manufacturer [{{.type}}]'
|
DNSAccountName: "DNS account [{{ .name }}] manufacturer [{{.type}}]"
|
||||||
PushDirLog: 'Certificate pushed to directory [{{ .path }}] {{ .status }}'
|
PushDirLog: "Certificate pushed to directory [{{ .path }}] {{ .status }}"
|
||||||
ErrDeleteCAWithSSL: "There is an issued certificate under the current organization and cannot be deleted"
|
ErrDeleteCAWithSSL: "There is an issued certificate under the current organization and cannot be deleted"
|
||||||
ErrDeleteWithPanelSSL: "Panel SSL configuration uses this certificate and cannot be deleted"
|
ErrDeleteWithPanelSSL: "Panel SSL configuration uses this certificate and cannot be deleted"
|
||||||
ErrDefaultCA: "The default organization cannot be deleted"
|
ErrDefaultCA: "The default organization cannot be deleted"
|
||||||
|
|
@ -220,6 +220,9 @@ TaskUpgrade: "Upgrade"
|
||||||
TaskUpdate: "Update"
|
TaskUpdate: "Update"
|
||||||
TaskRestart: "Restart"
|
TaskRestart: "Restart"
|
||||||
TaskRollback: "Rollback"
|
TaskRollback: "Rollback"
|
||||||
|
TaskPull: "Pull"
|
||||||
|
TaskBuild: "Build"
|
||||||
|
TaskPush: "Push"
|
||||||
Website: "Website"
|
Website: "Website"
|
||||||
App: "App"
|
App: "App"
|
||||||
Runtime: "Runtime"
|
Runtime: "Runtime"
|
||||||
|
|
@ -237,9 +240,11 @@ ExecShell: "Execute {{ .name }} Script"
|
||||||
PullImage: "Pull Image"
|
PullImage: "Pull Image"
|
||||||
Start: "Start"
|
Start: "Start"
|
||||||
Run: "Run"
|
Run: "Run"
|
||||||
Stop: 'Stop',
|
Stop: "Stop"
|
||||||
Image: 'Image',
|
Image: "Image"
|
||||||
AppLink: 'Associated Application'
|
Container: "Container"
|
||||||
|
Compose: "Compose"
|
||||||
|
AppLink: "Associated Application"
|
||||||
EnableSSL: "Enable HTTPS"
|
EnableSSL: "Enable HTTPS"
|
||||||
AppStore: "App Store"
|
AppStore: "App Store"
|
||||||
TaskSync: "Sync"
|
TaskSync: "Sync"
|
||||||
|
|
@ -272,4 +277,27 @@ SnapCompressSize: "Snapshot file size {{ .name }}"
|
||||||
SnapUpload: "Upload snapshot file"
|
SnapUpload: "Upload snapshot file"
|
||||||
SnapLoadBackup: "Get backup account information"
|
SnapLoadBackup: "Get backup account information"
|
||||||
SnapUploadTo: "Upload snapshot file to {{ .name }}"
|
SnapUploadTo: "Upload snapshot file to {{ .name }}"
|
||||||
SnapUploadRes: "Upload snapshot file to {{ .name }}"
|
SnapUploadRes: "Upload snapshot file to {{ .name }}"
|
||||||
|
|
||||||
|
# task - container
|
||||||
|
ContainerNewCliet: "Initialize Docker Client"
|
||||||
|
ContainerImagePull: "Pull container image {{ .name }}"
|
||||||
|
ContainerImageCheck: "Check if the image is pulled successfully"
|
||||||
|
ContainerLoadInfo: "Get basic information of the container"
|
||||||
|
ContainerCreate: "Create new container {{ .name }}"
|
||||||
|
ContainerCreateFailed: "Container creation failed, delete the failed container"
|
||||||
|
ContainerStartCheck: "Check if the container has started"
|
||||||
|
|
||||||
|
# task - image
|
||||||
|
ImageBuild: "Image build"
|
||||||
|
ImageBuildStdoutCheck: "Parse image output"
|
||||||
|
ImaegBuildRes: "Image build output: {{ .name }}"
|
||||||
|
ImagePull: "Pull image"
|
||||||
|
ImageRepoAuthFromDB: "Get repository authentication information from database"
|
||||||
|
ImaegPullRes: "Image pull output: {{ .name }}"
|
||||||
|
ImagePush: "Push image"
|
||||||
|
ImageRenameTag: "Rename image tag"
|
||||||
|
ImageNewTag: "New image tag {{ .name }}"
|
||||||
|
ImaegPushRes: "Image push output: {{ .name }}"
|
||||||
|
ComposeCreate: "Create compose"
|
||||||
|
ComposeCreateRes: "Compose creation output: {{ .name }}"
|
||||||
|
|
@ -10,11 +10,11 @@ ErrNameIsExist: "名稱已存在"
|
||||||
ErrDemoEnvironment: "演示伺服器,禁止此操作!"
|
ErrDemoEnvironment: "演示伺服器,禁止此操作!"
|
||||||
ErrCmdTimeout: "指令執行超時!"
|
ErrCmdTimeout: "指令執行超時!"
|
||||||
ErrCmdIllegal: "執行命令中存在不合法字符,請修改後重試!"
|
ErrCmdIllegal: "執行命令中存在不合法字符,請修改後重試!"
|
||||||
ErrPortExist: '{{ .port }} 埠已被 {{ .type }} [{{ .name }}] 佔用'
|
ErrPortExist: "{{ .port }} 埠已被 {{ .type }} [{{ .name }}] 佔用"
|
||||||
TYPE_APP: "應用"
|
TYPE_APP: "應用"
|
||||||
TYPE_RUNTIME: "運作環境"
|
TYPE_RUNTIME: "運作環境"
|
||||||
TYPE_DOMAIN: "網域名稱"
|
TYPE_DOMAIN: "網域名稱"
|
||||||
ErrTypePort: '埠 {{ .name }} 格式錯誤'
|
ErrTypePort: "埠 {{ .name }} 格式錯誤"
|
||||||
Success: "成功"
|
Success: "成功"
|
||||||
Failed: "失敗"
|
Failed: "失敗"
|
||||||
SystemRestart: "系統重啟導致任務中斷"
|
SystemRestart: "系統重啟導致任務中斷"
|
||||||
|
|
@ -28,16 +28,16 @@ ErrNotInstall: "應用未安裝"
|
||||||
ErrPortInOtherApp: "{{ .port }} 端口已被應用 {{ .apps }} 佔用!"
|
ErrPortInOtherApp: "{{ .port }} 端口已被應用 {{ .apps }} 佔用!"
|
||||||
ErrDbUserNotValid: "儲存資料庫,用戶名密碼不匹配!"
|
ErrDbUserNotValid: "儲存資料庫,用戶名密碼不匹配!"
|
||||||
ErrDockerComposeNotValid: "docker-compose 文件格式錯誤"
|
ErrDockerComposeNotValid: "docker-compose 文件格式錯誤"
|
||||||
ErrUpdateBuWebsite: '應用更新成功,但是網站配置文件修改失敗,請檢查配置!'
|
ErrUpdateBuWebsite: "應用更新成功,但是網站配置文件修改失敗,請檢查配置!"
|
||||||
Err1PanelNetworkFailed: '默認容器網絡創建失敗!{{ .detail }}'
|
Err1PanelNetworkFailed: "默認容器網絡創建失敗!{{ .detail }}"
|
||||||
ErrFileParse: '應用 docker-compose 文件解析失敗!'
|
ErrFileParse: "應用 docker-compose 文件解析失敗!"
|
||||||
ErrInstallDirNotFound: '安裝目錄不存在'
|
ErrInstallDirNotFound: "安裝目錄不存在"
|
||||||
AppStoreIsUpToDate: '應用商店已經是最新版本'
|
AppStoreIsUpToDate: "應用商店已經是最新版本"
|
||||||
LocalAppVersionNull: '{{.name}} 應用未同步到版本!無法添加到應用列表'
|
LocalAppVersionNull: "{{.name}} 應用未同步到版本!無法添加到應用列表"
|
||||||
LocalAppVersionErr: '{{.name}} 同步版本 {{.version}} 失敗!{{.err}}'
|
LocalAppVersionErr: "{{.name}} 同步版本 {{.version}} 失敗!{{.err}}"
|
||||||
ErrFileNotFound: '{{.name}} 文件不存在'
|
ErrFileNotFound: "{{.name}} 文件不存在"
|
||||||
ErrFileParseApp: '{{.name}} 文件解析失敗 {{.err}}'
|
ErrFileParseApp: "{{.name}} 文件解析失敗 {{.err}}"
|
||||||
ErrAppDirNull: '版本資料夾不存在'
|
ErrAppDirNull: "版本資料夾不存在"
|
||||||
LocalAppErr: "應用 {{.name}} 同步失敗!{{.err}}"
|
LocalAppErr: "應用 {{.name}} 同步失敗!{{.err}}"
|
||||||
ErrContainerName: "容器名稱已存在"
|
ErrContainerName: "容器名稱已存在"
|
||||||
ErrAppSystemRestart: "1Panel 重啟導致任務中斷"
|
ErrAppSystemRestart: "1Panel 重啟導致任務中斷"
|
||||||
|
|
@ -47,13 +47,13 @@ ErrHttpReqFailed: "請求失敗 {{.err}}"
|
||||||
ErrHttpReqNotFound: "文件不存在"
|
ErrHttpReqNotFound: "文件不存在"
|
||||||
ErrNoSuchHost: "網路連接失敗"
|
ErrNoSuchHost: "網路連接失敗"
|
||||||
ErrImagePullTimeOut: "鏡像拉取超時"
|
ErrImagePullTimeOut: "鏡像拉取超時"
|
||||||
ErrContainerNotFound: '{{ .name }} 容器不存在'
|
ErrContainerNotFound: "{{ .name }} 容器不存在"
|
||||||
ErrContainerMsg: '{{ .name }} 容器異常,具體請在容器頁面查看日誌'
|
ErrContainerMsg: "{{ .name }} 容器異常,具體請在容器頁面查看日誌"
|
||||||
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{.err}}'
|
ErrAppBackup: "{{ .name }} 應用備份失敗 err {{.err}}"
|
||||||
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{.err}}'
|
ErrImagePull: "{{ .name }} 鏡像拉取失敗 err {{.err}}"
|
||||||
ErrVersionTooLow: '當前 1Panel 版本過低,無法更新應用商店,請升級版本之後操作'
|
ErrVersionTooLow: "當前 1Panel 版本過低,無法更新應用商店,請升級版本之後操作"
|
||||||
ErrAppNameExist: '應用名稱已存在'
|
ErrAppNameExist: "應用名稱已存在"
|
||||||
AppStoreIsSyncing: '應用程式商店正在同步中,請稍後再試'
|
AppStoreIsSyncing: "應用程式商店正在同步中,請稍後再試"
|
||||||
ErrGetCompose: "docker-compose.yml 檔案取得失敗!{{ .detail }}"
|
ErrGetCompose: "docker-compose.yml 檔案取得失敗!{{ .detail }}"
|
||||||
ErrAppWarn: "狀態異常,請查看日誌"
|
ErrAppWarn: "狀態異常,請查看日誌"
|
||||||
ErrAppParamKey: "參數 {{ .name }} 欄位異常"
|
ErrAppParamKey: "參數 {{ .name }} 欄位異常"
|
||||||
|
|
@ -89,12 +89,12 @@ ErrFavoriteExist: "已收藏此路徑"
|
||||||
#website
|
#website
|
||||||
ErrDomainIsExist: "域名已存在"
|
ErrDomainIsExist: "域名已存在"
|
||||||
ErrAliasIsExist: "代號已存在"
|
ErrAliasIsExist: "代號已存在"
|
||||||
ErrAppDelete: '其他網站使用此應用,無法刪除'
|
ErrAppDelete: "其他網站使用此應用,無法刪除"
|
||||||
ErrGroupIsUsed: '分組正在使用中,無法刪除'
|
ErrGroupIsUsed: "分組正在使用中,無法刪除"
|
||||||
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}'
|
ErrBackupMatch: "該備份文件與當前網站部分數據不匹配: {{ .detail}}"
|
||||||
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}'
|
ErrBackupExist: "該備份文件對應部分原數據不存在: {{ .detail}}"
|
||||||
ErrPHPResource: '本地運行環境不支持切換!'
|
ErrPHPResource: "本地運行環境不支持切換!"
|
||||||
ErrPathPermission: 'index 目錄下偵測到非 1000:1000 權限資料夾,可能導致網站存取 Access denied 錯誤,請點擊上方儲存按鈕'
|
ErrPathPermission: "index 目錄下偵測到非 1000:1000 權限資料夾,可能導致網站存取 Access denied 錯誤,請點擊上方儲存按鈕"
|
||||||
ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
|
ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
|
||||||
ErrDomainFormat: "{{ .name }} 域名格式不正確"
|
ErrDomainFormat: "{{ .name }} 域名格式不正確"
|
||||||
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
|
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
|
||||||
|
|
@ -105,21 +105,21 @@ ErrBuildDirNotFound: "編譯目錄不存在"
|
||||||
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
|
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
|
||||||
ErrAccountCannotDelete: "帳號關聯證書,無法刪除"
|
ErrAccountCannotDelete: "帳號關聯證書,無法刪除"
|
||||||
ErrSSLApply: "證書續簽成功,openresty reload失敗,請檢查配置!"
|
ErrSSLApply: "證書續簽成功,openresty reload失敗,請檢查配置!"
|
||||||
ErrEmailIsExist: '郵箱已存在'
|
ErrEmailIsExist: "郵箱已存在"
|
||||||
ErrSSLKeyNotFound: '私鑰文件不存在'
|
ErrSSLKeyNotFound: "私鑰文件不存在"
|
||||||
ErrSSLCertificateNotFound: '證書文件不存在'
|
ErrSSLCertificateNotFound: "證書文件不存在"
|
||||||
ErrSSLKeyFormat: '私鑰文件校驗錯誤'
|
ErrSSLKeyFormat: "私鑰文件校驗錯誤"
|
||||||
ErrSSLCertificateFormat: '證書文件格式錯誤,請使用 pem 格式'
|
ErrSSLCertificateFormat: "證書文件格式錯誤,請使用 pem 格式"
|
||||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid 或 EabHmacKey 不能為空'
|
ErrEabKidOrEabHmacKeyCannotBlank: "EabKid 或 EabHmacKey 不能為空"
|
||||||
ErrOpenrestyNotFound: 'Http 模式需要先安裝 Openresty'
|
ErrOpenrestyNotFound: "Http 模式需要先安裝 Openresty"
|
||||||
ApplySSLStart: '開始申請憑證,網域 [{{ .domain }}] 申請方式 [{{ .type }}] '
|
ApplySSLStart: "開始申請憑證,網域 [{{ .domain }}] 申請方式 [{{ .type }}] "
|
||||||
dnsAccount: "DNS 自動"
|
dnsAccount: "DNS 自動"
|
||||||
dnsManual: "DNS 手排"
|
dnsManual: "DNS 手排"
|
||||||
http: "HTTP"
|
http: "HTTP"
|
||||||
ApplySSLFailed: '申請 [{{ .domain }}] 憑證失敗, {{.detail}} '
|
ApplySSLFailed: "申請 [{{ .domain }}] 憑證失敗, {{.detail}} "
|
||||||
ApplySSLSuccess: '申請 [{{ .domain }}] 憑證成功! ! '
|
ApplySSLSuccess: "申請 [{{ .domain }}] 憑證成功! ! "
|
||||||
DNSAccountName: 'DNS 帳號 [{{ .name }}] 廠商 [{{.type}}]'
|
DNSAccountName: "DNS 帳號 [{{ .name }}] 廠商 [{{.type}}]"
|
||||||
PushDirLog: '憑證推送到目錄 [{{ .path }}] {{ .status }}'
|
PushDirLog: "憑證推送到目錄 [{{ .path }}] {{ .status }}"
|
||||||
ErrDeleteCAWithSSL: "目前機構下存在已簽發證書,無法刪除"
|
ErrDeleteCAWithSSL: "目前機構下存在已簽發證書,無法刪除"
|
||||||
ErrDeleteWithPanelSSL: "面板 SSL 配置使用此證書,無法刪除"
|
ErrDeleteWithPanelSSL: "面板 SSL 配置使用此證書,無法刪除"
|
||||||
ErrDefaultCA: "默認機構不能刪除"
|
ErrDefaultCA: "默認機構不能刪除"
|
||||||
|
|
@ -222,6 +222,9 @@ TaskUpgrade: "升級"
|
||||||
TaskUpdate: "更新"
|
TaskUpdate: "更新"
|
||||||
TaskRestart: "重啟"
|
TaskRestart: "重啟"
|
||||||
TaskRollback: "回滚"
|
TaskRollback: "回滚"
|
||||||
|
TaskPull: "拉取"
|
||||||
|
TaskBuild: "建構"
|
||||||
|
TaskPush: "推送"
|
||||||
Website: "網站"
|
Website: "網站"
|
||||||
App: "應用"
|
App: "應用"
|
||||||
Runtime: "運行環境"
|
Runtime: "運行環境"
|
||||||
|
|
@ -239,9 +242,11 @@ ExecShell: "執行 {{ .name }} 腳本"
|
||||||
PullImage: "拉取鏡像"
|
PullImage: "拉取鏡像"
|
||||||
Start: "開始"
|
Start: "開始"
|
||||||
Run: "啟動"
|
Run: "啟動"
|
||||||
Stop: '停止',
|
Stop: "停止"
|
||||||
Image: '鏡像',
|
Image: "鏡像"
|
||||||
AppLink: '關聯應用'
|
Container: "容器"
|
||||||
|
Compose: "編排"
|
||||||
|
AppLink: "關聯應用"
|
||||||
EnableSSL: "開啟 HTTPS"
|
EnableSSL: "開啟 HTTPS"
|
||||||
AppStore: "應用商店"
|
AppStore: "應用商店"
|
||||||
TaskSync: "同步"
|
TaskSync: "同步"
|
||||||
|
|
@ -275,4 +280,27 @@ SnapCompressSize: "快照檔案大小 {{ .name }}"
|
||||||
SnapUpload: "上傳快照檔案"
|
SnapUpload: "上傳快照檔案"
|
||||||
SnapLoadBackup: "獲取備份帳號資訊"
|
SnapLoadBackup: "獲取備份帳號資訊"
|
||||||
SnapUploadTo: "上傳快照檔案到 {{ .name }}"
|
SnapUploadTo: "上傳快照檔案到 {{ .name }}"
|
||||||
SnapUploadRes: "上傳快照檔案到 {{ .name }}"
|
SnapUploadRes: "上傳快照檔案到 {{ .name }}"
|
||||||
|
|
||||||
|
# task - container
|
||||||
|
ContainerNewCliet: "初始化 Docker 客戶端"
|
||||||
|
ContainerImagePull: "拉取容器鏡像 {{ .name }}"
|
||||||
|
ContainerImageCheck: "檢查鏡像是否正常拉取"
|
||||||
|
ContainerLoadInfo: "獲取容器基本信息"
|
||||||
|
ContainerCreate: "創建新容器 {{ .name }}"
|
||||||
|
ContainerCreateFailed: "容器創建失敗,刪除失敗容器"
|
||||||
|
ContainerStartCheck: "檢查容器是否已啟動"
|
||||||
|
|
||||||
|
# task - image
|
||||||
|
ImageBuild: "鏡像構建"
|
||||||
|
ImageBuildStdoutCheck: "解析鏡像輸出內容"
|
||||||
|
ImaegBuildRes: "鏡像構建輸出:{{ .name }}"
|
||||||
|
ImagePull: "拉取鏡像"
|
||||||
|
ImageRepoAuthFromDB: "從數據庫獲取倉庫認證信息"
|
||||||
|
ImaegPullRes: "鏡像拉取輸出:{{ .name }}"
|
||||||
|
ImagePush: "推送鏡像"
|
||||||
|
ImageRenameTag: "修改鏡像 Tag"
|
||||||
|
ImageNewTag: "新鏡像 Tag {{ .name }}"
|
||||||
|
ImaegPushRes: "鏡像推送輸出:{{ .name }}"
|
||||||
|
ComposeCreate: "創建編排"
|
||||||
|
ComposeCreateRes: "編排創建輸出:{{ .name }}"
|
||||||
|
|
@ -10,11 +10,11 @@ ErrNameIsExist: "名称已存在"
|
||||||
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
ErrDemoEnvironment: "演示服务器,禁止此操作!"
|
||||||
ErrCmdTimeout: "命令执行超时!"
|
ErrCmdTimeout: "命令执行超时!"
|
||||||
ErrCmdIllegal: "执行命令中存在不合法字符,请修改后重试!"
|
ErrCmdIllegal: "执行命令中存在不合法字符,请修改后重试!"
|
||||||
ErrPortExist: '{{ .port }} 端口已被 {{ .type }} [{{ .name }}] 占用'
|
ErrPortExist: "{{ .port }} 端口已被 {{ .type }} [{{ .name }}] 占用"
|
||||||
TYPE_APP: "应用"
|
TYPE_APP: "应用"
|
||||||
TYPE_RUNTIME: "运行环境"
|
TYPE_RUNTIME: "运行环境"
|
||||||
TYPE_DOMAIN: "域名"
|
TYPE_DOMAIN: "域名"
|
||||||
ErrTypePort: '端口 {{ .name }} 格式错误'
|
ErrTypePort: "端口 {{ .name }} 格式错误"
|
||||||
Success: "成功"
|
Success: "成功"
|
||||||
Failed: "失败"
|
Failed: "失败"
|
||||||
SystemRestart: "系统重启导致任务中断"
|
SystemRestart: "系统重启导致任务中断"
|
||||||
|
|
@ -27,16 +27,16 @@ ErrNotInstall: "应用未安装"
|
||||||
ErrPortInOtherApp: "{{ .port }} 端口已被应用 {{ .apps }} 占用!"
|
ErrPortInOtherApp: "{{ .port }} 端口已被应用 {{ .apps }} 占用!"
|
||||||
ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
|
ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
|
||||||
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
|
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
|
||||||
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
|
ErrUpdateBuWebsite: "应用更新成功,但是网站配置文件修改失败,请检查配置!"
|
||||||
Err1PanelNetworkFailed: '默认容器网络创建失败!{{ .detail }}'
|
Err1PanelNetworkFailed: "默认容器网络创建失败!{{ .detail }}"
|
||||||
ErrFileParse: '应用 docker-compose 文件解析失败!'
|
ErrFileParse: "应用 docker-compose 文件解析失败!"
|
||||||
ErrInstallDirNotFound: '安装目录不存在'
|
ErrInstallDirNotFound: "安装目录不存在"
|
||||||
AppStoreIsUpToDate: '应用商店已经是最新版本'
|
AppStoreIsUpToDate: "应用商店已经是最新版本"
|
||||||
LocalAppVersionNull: '{{.name}} 应用未同步到版本!无法添加到应用列表'
|
LocalAppVersionNull: "{{.name}} 应用未同步到版本!无法添加到应用列表"
|
||||||
LocalAppVersionErr: '{{.name}} 同步版本 {{.version}} 失败!{{.err}}'
|
LocalAppVersionErr: "{{.name}} 同步版本 {{.version}} 失败!{{.err}}"
|
||||||
ErrFileNotFound: '{{.name}} 文件不存在'
|
ErrFileNotFound: "{{.name}} 文件不存在"
|
||||||
ErrFileParseApp: '{{.name}} 文件解析失败 {{.err}}'
|
ErrFileParseApp: "{{.name}} 文件解析失败 {{.err}}"
|
||||||
ErrAppDirNull: '版本文件夹不存在'
|
ErrAppDirNull: "版本文件夹不存在"
|
||||||
LocalAppErr: "应用 {{.name}} 同步失败!{{.err}}"
|
LocalAppErr: "应用 {{.name}} 同步失败!{{.err}}"
|
||||||
ErrContainerName: "容器名称已存在"
|
ErrContainerName: "容器名称已存在"
|
||||||
ErrAppSystemRestart: "1Panel 重启导致任务终止"
|
ErrAppSystemRestart: "1Panel 重启导致任务终止"
|
||||||
|
|
@ -45,14 +45,14 @@ ErrHttpReqTimeOut: "请求超时 {{.err}}"
|
||||||
ErrHttpReqFailed: "请求失败 {{.err}}"
|
ErrHttpReqFailed: "请求失败 {{.err}}"
|
||||||
ErrHttpReqNotFound: "文件不存在"
|
ErrHttpReqNotFound: "文件不存在"
|
||||||
ErrNoSuchHost: "网络连接失败"
|
ErrNoSuchHost: "网络连接失败"
|
||||||
ErrImagePullTimeOut: '镜像拉取超时'
|
ErrImagePullTimeOut: "镜像拉取超时"
|
||||||
ErrContainerNotFound: '{{ .name }} 容器不存在'
|
ErrContainerNotFound: "{{ .name }} 容器不存在"
|
||||||
ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日志'
|
ErrContainerMsg: "{{ .name }} 容器异常,具体请在容器页面查看日志"
|
||||||
ErrAppBackup: '{{ .name }} 应用备份失败 err {{.err}}'
|
ErrAppBackup: "{{ .name }} 应用备份失败 err {{.err}}"
|
||||||
ErrImagePull: '镜像拉取失败 {{.err}}'
|
ErrImagePull: "镜像拉取失败 {{.err}}"
|
||||||
ErrVersionTooLow: '当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作'
|
ErrVersionTooLow: "当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作"
|
||||||
ErrAppNameExist: '应用名称已存在'
|
ErrAppNameExist: "应用名称已存在"
|
||||||
AppStoreIsSyncing: '应用商店正在同步中,请稍后再试'
|
AppStoreIsSyncing: "应用商店正在同步中,请稍后再试"
|
||||||
ErrGetCompose: "docker-compose.yml 文件获取失败!{{ .detail }}"
|
ErrGetCompose: "docker-compose.yml 文件获取失败!{{ .detail }}"
|
||||||
ErrAppWarn: "状态异常,请查看日志"
|
ErrAppWarn: "状态异常,请查看日志"
|
||||||
ErrAppParamKey: "参数 {{ .name }} 字段异常"
|
ErrAppParamKey: "参数 {{ .name }} 字段异常"
|
||||||
|
|
@ -89,12 +89,12 @@ ErrInvalidChar: "禁止使用非法字符"
|
||||||
#website
|
#website
|
||||||
ErrDomainIsExist: "域名已存在"
|
ErrDomainIsExist: "域名已存在"
|
||||||
ErrAliasIsExist: "代号已存在"
|
ErrAliasIsExist: "代号已存在"
|
||||||
ErrAppDelete: '其他网站使用此应用,无法删除'
|
ErrAppDelete: "其他网站使用此应用,无法删除"
|
||||||
ErrGroupIsUsed: '分组正在使用中,无法删除'
|
ErrGroupIsUsed: "分组正在使用中,无法删除"
|
||||||
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}'
|
ErrBackupMatch: "该备份文件与当前网站部分数据不匹配 {{ .detail}}"
|
||||||
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}'
|
ErrBackupExist: "该备份文件对应部分源数据不存在 {{ .detail}}"
|
||||||
ErrPHPResource: '本地运行环境不支持切换!'
|
ErrPHPResource: "本地运行环境不支持切换!"
|
||||||
ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误,请点击上方保存按钮'
|
ErrPathPermission: "index 目录下检测到非 1000:1000 权限文件夹,可能导致网站访问 Access denied 错误,请点击上方保存按钮"
|
||||||
ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
|
ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
|
||||||
ErrDomainFormat: "{{ .name }} 域名格式不正确"
|
ErrDomainFormat: "{{ .name }} 域名格式不正确"
|
||||||
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
|
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
|
||||||
|
|
@ -105,21 +105,21 @@ ErrBuildDirNotFound: "构建目录不存在"
|
||||||
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
|
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
|
||||||
ErrAccountCannotDelete: "账号关联证书,无法删除"
|
ErrAccountCannotDelete: "账号关联证书,无法删除"
|
||||||
ErrSSLApply: "证书续签成功,openresty reload失败,请检查配置!"
|
ErrSSLApply: "证书续签成功,openresty reload失败,请检查配置!"
|
||||||
ErrEmailIsExist: '邮箱已存在'
|
ErrEmailIsExist: "邮箱已存在"
|
||||||
ErrSSLKeyNotFound: '私钥文件不存在'
|
ErrSSLKeyNotFound: "私钥文件不存在"
|
||||||
ErrSSLCertificateNotFound: '证书文件不存在'
|
ErrSSLCertificateNotFound: "证书文件不存在"
|
||||||
ErrSSLKeyFormat: '私钥文件校验失败'
|
ErrSSLKeyFormat: "私钥文件校验失败"
|
||||||
ErrSSLCertificateFormat: '证书文件格式错误,请使用 pem 格式'
|
ErrSSLCertificateFormat: "证书文件格式错误,请使用 pem 格式"
|
||||||
ErrEabKidOrEabHmacKeyCannotBlank: 'EabKid 或 EabHmacKey 不能为空'
|
ErrEabKidOrEabHmacKeyCannotBlank: "EabKid 或 EabHmacKey 不能为空"
|
||||||
ErrOpenrestyNotFound: 'Http 模式需要首先安装 Openresty'
|
ErrOpenrestyNotFound: "Http 模式需要首先安装 Openresty"
|
||||||
ApplySSLStart: '开始申请证书,域名 [{{ .domain }}] 申请方式 [{{ .type }}] '
|
ApplySSLStart: "开始申请证书,域名 [{{ .domain }}] 申请方式 [{{ .type }}] "
|
||||||
dnsAccount: "DNS 自动"
|
dnsAccount: "DNS 自动"
|
||||||
dnsManual: "DNS 手动"
|
dnsManual: "DNS 手动"
|
||||||
http: "HTTP"
|
http: "HTTP"
|
||||||
ApplySSLFailed: '申请 [{{ .domain }}] 证书失败, {{.detail}} '
|
ApplySSLFailed: "申请 [{{ .domain }}] 证书失败, {{.detail}} "
|
||||||
ApplySSLSuccess: '申请 [{{ .domain }}] 证书成功!!'
|
ApplySSLSuccess: "申请 [{{ .domain }}] 证书成功!!"
|
||||||
DNSAccountName: 'DNS 账号 [{{ .name }}] 厂商 [{{.type}}]'
|
DNSAccountName: "DNS 账号 [{{ .name }}] 厂商 [{{.type}}]"
|
||||||
PushDirLog: '证书推送到目录 [{{ .path }}] {{ .status }}'
|
PushDirLog: "证书推送到目录 [{{ .path }}] {{ .status }}"
|
||||||
ErrDeleteCAWithSSL: "当前机构下存在已签发证书,无法删除"
|
ErrDeleteCAWithSSL: "当前机构下存在已签发证书,无法删除"
|
||||||
ErrDeleteWithPanelSSL: "面板 SSL 配置使用此证书,无法删除"
|
ErrDeleteWithPanelSSL: "面板 SSL 配置使用此证书,无法删除"
|
||||||
ErrDefaultCA: "默认机构不能删除"
|
ErrDefaultCA: "默认机构不能删除"
|
||||||
|
|
@ -225,6 +225,9 @@ TaskRestart: "重启"
|
||||||
TaskBackup: "备份"
|
TaskBackup: "备份"
|
||||||
TaskRecover: "恢复"
|
TaskRecover: "恢复"
|
||||||
TaskRollback: "回滚"
|
TaskRollback: "回滚"
|
||||||
|
TaskPull: "拉取"
|
||||||
|
TaskBuild: "构建"
|
||||||
|
TaskPush: "推送"
|
||||||
Website: "网站"
|
Website: "网站"
|
||||||
App: "应用"
|
App: "应用"
|
||||||
Runtime: "运行环境"
|
Runtime: "运行环境"
|
||||||
|
|
@ -244,6 +247,8 @@ Start: "开始"
|
||||||
Run: "启动"
|
Run: "启动"
|
||||||
Stop: "停止"
|
Stop: "停止"
|
||||||
Image: "镜像"
|
Image: "镜像"
|
||||||
|
Compose: "编排"
|
||||||
|
Container: "容器"
|
||||||
AppLink: "关联应用"
|
AppLink: "关联应用"
|
||||||
EnableSSL: "开启 HTTPS"
|
EnableSSL: "开启 HTTPS"
|
||||||
AppStore: "应用商店"
|
AppStore: "应用商店"
|
||||||
|
|
@ -303,3 +308,25 @@ RecoverDBData: "恢复数据库数据"
|
||||||
RecoverBackups: "恢复本地备份目录"
|
RecoverBackups: "恢复本地备份目录"
|
||||||
RecoverPanelData: "恢复数据目录"
|
RecoverPanelData: "恢复数据目录"
|
||||||
|
|
||||||
|
# task - container
|
||||||
|
ContainerNewCliet: "初始化 Docker Client"
|
||||||
|
ContainerImagePull: "拉取容器镜像 {{ .name }}"
|
||||||
|
ContainerImageCheck: "检查镜像是否正常拉取"
|
||||||
|
ContainerLoadInfo: "获取容器基本信息"
|
||||||
|
ContainerCreate: "创建新容器 {{ .name }}"
|
||||||
|
ContainerCreateFailed: "容器创建失败,删除失败容器"
|
||||||
|
ContainerStartCheck: "检查容器是否已启动"
|
||||||
|
|
||||||
|
# task - image
|
||||||
|
ImageBuild: "镜像构建"
|
||||||
|
ImageBuildStdoutCheck: "解析镜像输出内容"
|
||||||
|
ImaegBuildRes: "镜像构建输出:{{ .name }}"
|
||||||
|
ImagePull: "拉取镜像"
|
||||||
|
ImageRepoAuthFromDB: "从数据库获取仓库认证信息"
|
||||||
|
ImaegPullRes: "镜像拉取输出:{{ .name }}"
|
||||||
|
ImagePush: "推送镜像"
|
||||||
|
ImageRenameTag: "修改镜像 Tag"
|
||||||
|
ImageNewTag: "新镜像 Tag {{ .name }}"
|
||||||
|
ImaegPushRes: "镜像推送输出:{{ .name }}"
|
||||||
|
ComposeCreate: "创建编排"
|
||||||
|
ComposeCreateRes: "编排创建输出:{{ .name }}"
|
||||||
|
|
@ -143,12 +143,14 @@ export namespace Container {
|
||||||
isUsed: boolean;
|
isUsed: boolean;
|
||||||
}
|
}
|
||||||
export interface ImageBuild {
|
export interface ImageBuild {
|
||||||
|
taskID: string;
|
||||||
from: string;
|
from: string;
|
||||||
name: string;
|
name: string;
|
||||||
dockerfile: string;
|
dockerfile: string;
|
||||||
tags: Array<string>;
|
tags: Array<string>;
|
||||||
}
|
}
|
||||||
export interface ImagePull {
|
export interface ImagePull {
|
||||||
|
taskID: string;
|
||||||
repoID: number;
|
repoID: number;
|
||||||
imageName: string;
|
imageName: string;
|
||||||
}
|
}
|
||||||
|
|
@ -157,6 +159,7 @@ export namespace Container {
|
||||||
targetName: string;
|
targetName: string;
|
||||||
}
|
}
|
||||||
export interface ImagePush {
|
export interface ImagePush {
|
||||||
|
taskID: string;
|
||||||
repoID: number;
|
repoID: number;
|
||||||
tagName: string;
|
tagName: string;
|
||||||
}
|
}
|
||||||
|
|
@ -259,6 +262,7 @@ export namespace Container {
|
||||||
state: string;
|
state: string;
|
||||||
}
|
}
|
||||||
export interface ComposeCreate {
|
export interface ComposeCreate {
|
||||||
|
taskID: string;
|
||||||
name: string;
|
name: string;
|
||||||
from: string;
|
from: string;
|
||||||
file: string;
|
file: string;
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<div v-if="form.from === 'edit' || form.from === 'template'" class="w-full">
|
<div v-if="form.from === 'edit' || form.from === 'template'" class="w-full">
|
||||||
<el-radio-group v-model="mode" size="small">
|
|
||||||
<el-radio-button label="edit">{{ $t('commons.button.edit') }}</el-radio-button>
|
|
||||||
<el-radio-button label="log">{{ $t('commons.button.log') }}</el-radio-button>
|
|
||||||
</el-radio-group>
|
|
||||||
<CodemirrorPro
|
<CodemirrorPro
|
||||||
v-if="mode === 'edit'"
|
|
||||||
v-model="form.file"
|
v-model="form.file"
|
||||||
placeholder="#Define or paste the content of your docker-compose file here"
|
placeholder="#Define or paste the content of your docker-compose file here"
|
||||||
mode="yaml"
|
mode="yaml"
|
||||||
|
|
@ -50,60 +45,44 @@
|
||||||
></CodemirrorPro>
|
></CodemirrorPro>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="w-full h-32">
|
|
||||||
<LogFile
|
|
||||||
ref="logRef"
|
|
||||||
v-model:is-reading="isReading"
|
|
||||||
:config="logConfig"
|
|
||||||
:default-button="false"
|
|
||||||
v-if="mode === 'log' && showLog"
|
|
||||||
:height-diff="370"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="drawerVisible = false">
|
<el-button @click="drawerVisible = false">
|
||||||
{{ $t('commons.button.cancel') }}
|
{{ $t('commons.button.cancel') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" :disabled="isStartReading || isReading" @click="onSubmit(formRef)">
|
<el-button type="primary" @click="onSubmit(formRef)">
|
||||||
{{ $t('commons.button.confirm') }}
|
{{ $t('commons.button.confirm') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</DrawerPro>
|
</DrawerPro>
|
||||||
|
<TaskLog ref="taskLogRef" width="70%" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onBeforeUnmount, reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import FileList from '@/components/file-list/index.vue';
|
import FileList from '@/components/file-list/index.vue';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElForm, ElMessageBox } from 'element-plus';
|
import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { loadBaseDir } from '@/api/modules/setting';
|
import { loadBaseDir } from '@/api/modules/setting';
|
||||||
import { MsgError } from '@/utils/message';
|
import { MsgError } from '@/utils/message';
|
||||||
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
|
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
|
||||||
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
import { listComposeTemplate, testCompose, upCompose } from '@/api/modules/container';
|
import { listComposeTemplate, testCompose, upCompose } from '@/api/modules/container';
|
||||||
|
import { newUUID } from '@/utils/util';
|
||||||
|
|
||||||
const showLog = ref(false);
|
|
||||||
const loading = ref();
|
const loading = ref();
|
||||||
const mode = ref('edit');
|
|
||||||
const oldFrom = ref('edit');
|
const oldFrom = ref('edit');
|
||||||
const drawerVisible = ref(false);
|
const drawerVisible = ref(false);
|
||||||
const templateOptions = ref();
|
const templateOptions = ref();
|
||||||
const baseDir = ref();
|
const baseDir = ref();
|
||||||
const composeFile = ref();
|
const composeFile = ref();
|
||||||
let timer: NodeJS.Timer | null = null;
|
const taskLogRef = ref();
|
||||||
const logRef = ref();
|
|
||||||
const isStartReading = ref(false);
|
|
||||||
const isReading = ref();
|
|
||||||
|
|
||||||
const logConfig = reactive({
|
|
||||||
type: 'compose-create',
|
|
||||||
name: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
|
taskID: '',
|
||||||
name: '',
|
name: '',
|
||||||
from: 'edit',
|
from: 'edit',
|
||||||
path: '',
|
path: '',
|
||||||
|
|
@ -122,7 +101,6 @@ const loadTemplates = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const acceptParams = (): void => {
|
const acceptParams = (): void => {
|
||||||
mode.value = 'edit';
|
|
||||||
drawerVisible.value = true;
|
drawerVisible.value = true;
|
||||||
form.name = '';
|
form.name = '';
|
||||||
form.from = 'edit';
|
form.from = 'edit';
|
||||||
|
|
@ -131,7 +109,6 @@ const acceptParams = (): void => {
|
||||||
form.template = null;
|
form.template = null;
|
||||||
loadTemplates();
|
loadTemplates();
|
||||||
loadPath();
|
loadPath();
|
||||||
isStartReading.value = false;
|
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
|
|
@ -171,8 +148,6 @@ const changeFrom = () => {
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
emit('search');
|
emit('search');
|
||||||
clearInterval(Number(timer));
|
|
||||||
timer = null;
|
|
||||||
drawerVisible.value = false;
|
drawerVisible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -196,9 +171,6 @@ const onEdit = (item: string) => {
|
||||||
if (item === 'form') {
|
if (item === 'form') {
|
||||||
changeFrom();
|
changeFrom();
|
||||||
}
|
}
|
||||||
if (!isReading.value && isStartReading.value) {
|
|
||||||
isStartReading.value = false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
|
|
@ -213,16 +185,10 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
mode.value = 'log';
|
form.taskID = newUUID();
|
||||||
await upCompose(form)
|
await upCompose(form);
|
||||||
.then((res) => {
|
openTaskLog(form.taskID);
|
||||||
logConfig.name = res.data;
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
loadLogs();
|
|
||||||
isStartReading.value = true;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|
@ -230,26 +196,14 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const openTaskLog = (taskID: string) => {
|
||||||
const loadLogs = () => {
|
taskLogRef.value.openWithTaskID(taskID);
|
||||||
showLog.value = false;
|
|
||||||
nextTick(() => {
|
|
||||||
showLog.value = true;
|
|
||||||
nextTick(() => {
|
|
||||||
logRef.value.changeTail(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadDir = async (path: string) => {
|
const loadDir = async (path: string) => {
|
||||||
form.path = path;
|
form.path = path;
|
||||||
};
|
};
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
clearInterval(Number(timer));
|
|
||||||
timer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
acceptParams,
|
acceptParams,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<el-input :placeholder="$t('container.imageNameHelper')" v-model.trim="form.name" clearable />
|
<el-input :placeholder="$t('container.imageNameHelper')" v-model.trim="form.name" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Dockerfile" prop="from">
|
<el-form-item label="Dockerfile" prop="from">
|
||||||
<el-radio-group @change="onEdit()" v-model="form.from">
|
<el-radio-group v-model="form.from">
|
||||||
<el-radio value="edit">{{ $t('commons.button.edit') }}</el-radio>
|
<el-radio value="edit">{{ $t('commons.button.edit') }}</el-radio>
|
||||||
<el-radio value="path">{{ $t('container.pathSelect') }}</el-radio>
|
<el-radio value="path">{{ $t('container.pathSelect') }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
|
@ -18,62 +18,44 @@
|
||||||
></CodemirrorPro>
|
></CodemirrorPro>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-else :rules="Rules.requiredSelect" prop="dockerfile">
|
<el-form-item v-else :rules="Rules.requiredSelect" prop="dockerfile">
|
||||||
<el-input @change="onEdit()" clearable v-model="form.dockerfile">
|
<el-input clearable v-model="form.dockerfile">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<FileList @choose="loadBuildDir"></FileList>
|
<FileList @choose="loadBuildDir"></FileList>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('container.tag')">
|
<el-form-item :label="$t('container.tag')">
|
||||||
<el-input
|
<el-input :placeholder="$t('container.tagHelper')" type="textarea" :rows="3" v-model="form.tagStr" />
|
||||||
@change="onEdit()"
|
|
||||||
:placeholder="$t('container.tagHelper')"
|
|
||||||
type="textarea"
|
|
||||||
:rows="3"
|
|
||||||
v-model="form.tagStr"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<LogFile
|
|
||||||
ref="logRef"
|
|
||||||
:config="logConfig"
|
|
||||||
:default-button="false"
|
|
||||||
v-model:is-reading="isReading"
|
|
||||||
v-if="logVisible"
|
|
||||||
:height-diff="370"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
<el-button :disabled="isStartReading || isReading" type="primary" @click="onSubmit(formRef)">
|
<el-button type="primary" @click="onSubmit(formRef)">
|
||||||
{{ $t('commons.button.confirm') }}
|
{{ $t('commons.button.confirm') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</DrawerPro>
|
</DrawerPro>
|
||||||
|
<TaskLog ref="taskLogRef" width="70%" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import FileList from '@/components/file-list/index.vue';
|
import FileList from '@/components/file-list/index.vue';
|
||||||
import { nextTick, reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElForm, ElMessage } from 'element-plus';
|
import { ElForm, ElMessage } from 'element-plus';
|
||||||
import { imageBuild } from '@/api/modules/container';
|
import { imageBuild } from '@/api/modules/container';
|
||||||
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
|
import { newUUID } from '@/utils/util';
|
||||||
|
|
||||||
const logVisible = ref<boolean>(false);
|
|
||||||
const drawerVisible = ref(false);
|
const drawerVisible = ref(false);
|
||||||
const logRef = ref();
|
const taskLogRef = ref();
|
||||||
const isStartReading = ref(false);
|
|
||||||
const isReading = ref(false);
|
|
||||||
|
|
||||||
const logConfig = reactive({
|
|
||||||
type: 'image-build',
|
|
||||||
name: '',
|
|
||||||
});
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
|
taskID: '',
|
||||||
from: 'path',
|
from: 'path',
|
||||||
dockerfile: '',
|
dockerfile: '',
|
||||||
name: '',
|
name: '',
|
||||||
|
|
@ -87,13 +69,11 @@ const rules = reactive({
|
||||||
dockerfile: [Rules.requiredInput],
|
dockerfile: [Rules.requiredInput],
|
||||||
});
|
});
|
||||||
const acceptParams = async () => {
|
const acceptParams = async () => {
|
||||||
logVisible.value = false;
|
|
||||||
drawerVisible.value = true;
|
drawerVisible.value = true;
|
||||||
form.from = 'path';
|
form.from = 'path';
|
||||||
form.dockerfile = '';
|
form.dockerfile = '';
|
||||||
form.tagStr = '';
|
form.tagStr = '';
|
||||||
form.name = '';
|
form.name = '';
|
||||||
isStartReading.value = false;
|
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
|
|
@ -105,11 +85,6 @@ const handleClose = () => {
|
||||||
type FormInstance = InstanceType<typeof ElForm>;
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
const onEdit = () => {
|
|
||||||
if (!isReading.value && isStartReading.value) {
|
|
||||||
isStartReading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
|
|
@ -117,22 +92,14 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (form.tagStr !== '') {
|
if (form.tagStr !== '') {
|
||||||
form.tags = form.tagStr.split('\n');
|
form.tags = form.tagStr.split('\n');
|
||||||
}
|
}
|
||||||
const res = await imageBuild(form);
|
form.taskID = newUUID();
|
||||||
isStartReading.value = true;
|
await imageBuild(form);
|
||||||
logConfig.name = res.data;
|
openTaskLog(form.taskID);
|
||||||
loadLogs();
|
|
||||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const openTaskLog = (taskID: string) => {
|
||||||
const loadLogs = () => {
|
taskLogRef.value.openWithTaskID(taskID);
|
||||||
logVisible.value = false;
|
|
||||||
nextTick(() => {
|
|
||||||
logVisible.value = true;
|
|
||||||
nextTick(() => {
|
|
||||||
logRef.value.changeTail(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadBuildDir = async (path: string) => {
|
const loadBuildDir = async (path: string) => {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<DrawerPro v-model="drawerVisible" :header="$t('container.imagePull')" :back="onCloseLog" size="large">
|
<DrawerPro v-model="drawerVisible" :header="$t('container.imagePull')" :back="onCloseLog" size="large">
|
||||||
<el-form ref="formRef" label-position="top" :model="form">
|
<el-form ref="formRef" label-position="top" :model="form">
|
||||||
<el-form-item :label="$t('container.from')">
|
<el-form-item :label="$t('container.from')">
|
||||||
<el-checkbox @change="onEdit()" v-model="form.fromRepo">
|
<el-checkbox v-model="form.fromRepo">
|
||||||
{{ $t('container.imageRepo') }}
|
{{ $t('container.imageRepo') }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -12,62 +12,49 @@
|
||||||
:rules="Rules.requiredSelect"
|
:rules="Rules.requiredSelect"
|
||||||
prop="repoID"
|
prop="repoID"
|
||||||
>
|
>
|
||||||
<el-select @change="onEdit()" clearable style="width: 100%" filterable v-model="form.repoID">
|
<el-select clearable style="width: 100%" filterable v-model="form.repoID">
|
||||||
<el-option v-for="item in repos" :key="item.id" :value="item.id" :label="item.name" />
|
<el-option v-for="item in repos" :key="item.id" :value="item.id" :label="item.name" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('container.imageName')" :rules="Rules.imageName" prop="imageName">
|
<el-form-item :label="$t('container.imageName')" :rules="Rules.imageName" prop="imageName">
|
||||||
<el-input @change="onEdit()" v-model.trim="form.imageName">
|
<el-input v-model.trim="form.imageName">
|
||||||
<template v-if="form.fromRepo" #prepend>{{ loadDetailInfo(form.repoID) }}/</template>
|
<template v-if="form.fromRepo" #prepend>{{ loadDetailInfo(form.repoID) }}/</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<LogFile
|
|
||||||
ref="logRef"
|
|
||||||
:config="logConfig"
|
|
||||||
:default-button="false"
|
|
||||||
v-model:is-reading="isReading"
|
|
||||||
v-if="showLog"
|
|
||||||
:height-diff="420"
|
|
||||||
/>
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="drawerVisible = false">
|
<el-button @click="drawerVisible = false">
|
||||||
{{ $t('commons.button.cancel') }}
|
{{ $t('commons.button.cancel') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button :disabled="isStartReading || isReading" type="primary" @click="onSubmit(formRef)">
|
<el-button type="primary" @click="onSubmit(formRef)">
|
||||||
{{ $t('container.pull') }}
|
{{ $t('container.pull') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</DrawerPro>
|
</DrawerPro>
|
||||||
|
<TaskLog ref="taskLogRef" width="70%" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElForm } from 'element-plus';
|
import { ElForm } from 'element-plus';
|
||||||
import { imagePull } from '@/api/modules/container';
|
import { imagePull } from '@/api/modules/container';
|
||||||
import { Container } from '@/api/interface/container';
|
import { Container } from '@/api/interface/container';
|
||||||
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
import { newUUID } from '@/utils/util';
|
||||||
|
|
||||||
const drawerVisible = ref(false);
|
const drawerVisible = ref(false);
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
|
taskID: '',
|
||||||
fromRepo: true,
|
fromRepo: true,
|
||||||
repoID: null as number,
|
repoID: null as number,
|
||||||
imageName: '',
|
imageName: '',
|
||||||
});
|
});
|
||||||
const logConfig = reactive({
|
const taskLogRef = ref();
|
||||||
type: 'image-pull',
|
|
||||||
name: '',
|
|
||||||
});
|
|
||||||
const showLog = ref(false);
|
|
||||||
const logRef = ref();
|
|
||||||
const logVisible = ref(false);
|
|
||||||
const logInfo = ref();
|
|
||||||
const isStartReading = ref(false);
|
|
||||||
const isReading = ref(false);
|
|
||||||
|
|
||||||
interface DialogProps {
|
interface DialogProps {
|
||||||
repos: Array<Container.RepoOptions>;
|
repos: Array<Container.RepoOptions>;
|
||||||
|
|
@ -75,7 +62,6 @@ interface DialogProps {
|
||||||
const repos = ref();
|
const repos = ref();
|
||||||
|
|
||||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||||
logVisible.value = false;
|
|
||||||
drawerVisible.value = true;
|
drawerVisible.value = true;
|
||||||
form.fromRepo = true;
|
form.fromRepo = true;
|
||||||
form.imageName = '';
|
form.imageName = '';
|
||||||
|
|
@ -87,20 +73,12 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isStartReading.value = false;
|
|
||||||
logInfo.value = '';
|
|
||||||
showLog.value = false;
|
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
type FormInstance = InstanceType<typeof ElForm>;
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
const onEdit = () => {
|
|
||||||
if (!isReading.value && isStartReading.value) {
|
|
||||||
isStartReading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
|
|
@ -108,23 +86,14 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!form.fromRepo) {
|
if (!form.fromRepo) {
|
||||||
form.repoID = 0;
|
form.repoID = 0;
|
||||||
}
|
}
|
||||||
const res = await imagePull(form);
|
form.taskID = newUUID();
|
||||||
logVisible.value = true;
|
await imagePull(form);
|
||||||
isStartReading.value = true;
|
openTaskLog(form.taskID);
|
||||||
logConfig.name = res.data;
|
|
||||||
search();
|
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const openTaskLog = (taskID: string) => {
|
||||||
const search = () => {
|
taskLogRef.value.openWithTaskID(taskID);
|
||||||
showLog.value = false;
|
|
||||||
nextTick(() => {
|
|
||||||
showLog.value = true;
|
|
||||||
nextTick(() => {
|
|
||||||
logRef.value.changeTail(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCloseLog = async () => {
|
const onCloseLog = async () => {
|
||||||
|
|
|
||||||
|
|
@ -2,73 +2,57 @@
|
||||||
<DrawerPro v-model="drawerVisible" :header="$t('container.imagePush')" :back="onCloseLog" size="large">
|
<DrawerPro v-model="drawerVisible" :header="$t('container.imagePush')" :back="onCloseLog" size="large">
|
||||||
<el-form ref="formRef" label-position="top" :model="form" label-width="80px">
|
<el-form ref="formRef" label-position="top" :model="form" label-width="80px">
|
||||||
<el-form-item :label="$t('container.tag')" :rules="Rules.requiredSelect" prop="tagName">
|
<el-form-item :label="$t('container.tag')" :rules="Rules.requiredSelect" prop="tagName">
|
||||||
<el-select @change="onEdit(true)" filterable v-model="form.tagName">
|
<el-select filterable v-model="form.tagName">
|
||||||
<el-option v-for="item in form.tags" :key="item" :value="item" :label="item" />
|
<el-option v-for="item in form.tags" :key="item" :value="item" :label="item" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('container.repoName')" :rules="Rules.requiredSelect" prop="repoID">
|
<el-form-item :label="$t('container.repoName')" :rules="Rules.requiredSelect" prop="repoID">
|
||||||
<el-select @change="onEdit()" clearable style="width: 100%" filterable v-model="form.repoID">
|
<el-select clearable style="width: 100%" filterable v-model="form.repoID">
|
||||||
<el-option v-for="item in dialogData.repos" :key="item.id" :value="item.id" :label="item.name" />
|
<el-option v-for="item in dialogData.repos" :key="item.id" :value="item.id" :label="item.name" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('container.image')" :rules="Rules.imageName" prop="name">
|
<el-form-item :label="$t('container.image')" :rules="Rules.imageName" prop="name">
|
||||||
<el-input @change="onEdit()" v-model.trim="form.name">
|
<el-input v-model.trim="form.name">
|
||||||
<template #prepend>{{ loadDetailInfo(form.repoID) }}/</template>
|
<template #prepend>{{ loadDetailInfo(form.repoID) }}/</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<LogFile
|
|
||||||
ref="logRef"
|
|
||||||
:config="logConfig"
|
|
||||||
:default-button="false"
|
|
||||||
v-model:is-reading="isReading"
|
|
||||||
v-if="logVisible"
|
|
||||||
:height-diff="420"
|
|
||||||
v-model:loading="loading"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="drawerVisible = false">
|
<el-button @click="drawerVisible = false">
|
||||||
{{ $t('commons.button.cancel') }}
|
{{ $t('commons.button.cancel') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button :disabled="isStartReading || isReading" type="primary" @click="onSubmit(formRef)">
|
<el-button type="primary" @click="onSubmit(formRef)">
|
||||||
{{ $t('container.push') }}
|
{{ $t('container.push') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</DrawerPro>
|
</DrawerPro>
|
||||||
|
<TaskLog ref="taskLogRef" width="70%" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElForm } from 'element-plus';
|
import { ElForm } from 'element-plus';
|
||||||
import { imagePush } from '@/api/modules/container';
|
import { imagePush } from '@/api/modules/container';
|
||||||
import { Container } from '@/api/interface/container';
|
import { Container } from '@/api/interface/container';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
|
import { newUUID } from '@/utils/util';
|
||||||
|
|
||||||
const drawerVisible = ref(false);
|
const drawerVisible = ref(false);
|
||||||
|
const taskLogRef = ref();
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
|
taskID: '',
|
||||||
tags: [] as Array<string>,
|
tags: [] as Array<string>,
|
||||||
tagName: '',
|
tagName: '',
|
||||||
repoID: 1,
|
repoID: 1,
|
||||||
name: '',
|
name: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const logVisible = ref(false);
|
|
||||||
const loading = ref(false);
|
|
||||||
const isStartReading = ref(false);
|
|
||||||
const isReading = ref(false);
|
|
||||||
|
|
||||||
const logRef = ref();
|
|
||||||
const logConfig = reactive({
|
|
||||||
type: 'image-push',
|
|
||||||
name: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
interface DialogProps {
|
interface DialogProps {
|
||||||
repos: Array<Container.RepoOptions>;
|
repos: Array<Container.RepoOptions>;
|
||||||
tags: Array<string>;
|
tags: Array<string>;
|
||||||
|
|
@ -79,50 +63,30 @@ const dialogData = ref<DialogProps>({
|
||||||
});
|
});
|
||||||
|
|
||||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||||
logVisible.value = false;
|
|
||||||
loading.value = false;
|
|
||||||
drawerVisible.value = true;
|
drawerVisible.value = true;
|
||||||
form.tags = params.tags;
|
form.tags = params.tags;
|
||||||
form.repoID = 1;
|
form.repoID = 1;
|
||||||
form.tagName = form.tags.length !== 0 ? form.tags[0] : '';
|
form.tagName = form.tags.length !== 0 ? form.tags[0] : '';
|
||||||
form.name = form.tags.length !== 0 ? form.tags[0] : '';
|
form.name = form.tags.length !== 0 ? form.tags[0] : '';
|
||||||
dialogData.value.repos = params.repos;
|
dialogData.value.repos = params.repos;
|
||||||
isStartReading.value = false;
|
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
type FormInstance = InstanceType<typeof ElForm>;
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
const onEdit = (isName?: boolean) => {
|
|
||||||
if (!isReading.value && isStartReading.value) {
|
|
||||||
isStartReading.value = false;
|
|
||||||
}
|
|
||||||
if (isName) {
|
|
||||||
form.name = form.tagName;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
const res = await imagePush(form);
|
form.taskID = newUUID();
|
||||||
logVisible.value = true;
|
await imagePush(form);
|
||||||
isStartReading.value = true;
|
openTaskLog(form.taskID);
|
||||||
logConfig.name = res.data;
|
|
||||||
loadLogs();
|
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const openTaskLog = (taskID: string) => {
|
||||||
const loadLogs = () => {
|
taskLogRef.value.openWithTaskID(taskID);
|
||||||
logVisible.value = false;
|
|
||||||
nextTick(() => {
|
|
||||||
logVisible.value = true;
|
|
||||||
nextTick(() => {
|
|
||||||
logRef.value.changeTail(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCloseLog = async () => {
|
const onCloseLog = async () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue