mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 23:40:24 +08:00
feat: 容器操作优化等
This commit is contained in:
@@ -33,7 +33,7 @@ require (
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/veops/go-ansiterm v0.0.5
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.2 // mongo
|
||||
go.mongodb.org/mongo-driver/v2 v2.3.0 // mongo
|
||||
golang.org/x/crypto v0.41.0 // ssh
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.16.0
|
||||
@@ -41,7 +41,7 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
// gorm
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/gorm v1.30.2
|
||||
gorm.io/gorm v1.30.3
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
import "mayfly-go/pkg/ioc"
|
||||
|
||||
func InitIoc() {
|
||||
ioc.Register(new(ContainerConf))
|
||||
ioc.Register(new(Docker))
|
||||
ioc.Register(new(Container))
|
||||
ioc.Register(new(Image))
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"io"
|
||||
"mayfly-go/internal/docker/api/form"
|
||||
"mayfly-go/internal/docker/api/vo"
|
||||
"mayfly-go/internal/docker/dkm"
|
||||
"mayfly-go/internal/docker/imsg"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/errorx"
|
||||
@@ -52,12 +51,11 @@ func (d *Container) ReqConfs() *req.Confs {
|
||||
req.NewGet("/logs", d.ContainerLogs).NoRes(),
|
||||
}
|
||||
|
||||
return req.NewConfs("docker/containers", reqs[:]...)
|
||||
return req.NewConfs("docker/:id/containers", reqs[:]...)
|
||||
}
|
||||
|
||||
func (d *Container) GetContainers(rc *req.Ctx) {
|
||||
cli, err := dkm.GetCli(rc.Query("host"))
|
||||
biz.ErrIsNil(err)
|
||||
cli := GetCli(rc)
|
||||
cs, err := cli.ContainerList()
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
@@ -89,8 +87,7 @@ func (d *Container) GetContainers(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *Container) GetContainersStats(rc *req.Ctx) {
|
||||
cli, err := dkm.GetCli(rc.Query("host"))
|
||||
biz.ErrIsNil(err)
|
||||
cli := GetCli(rc)
|
||||
cs, err := cli.ContainerList()
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
@@ -141,8 +138,7 @@ func (d *Container) ContainerCreate(rc *req.Ctx) {
|
||||
|
||||
rc.ReqParam = containerCreate
|
||||
|
||||
cli, err := dkm.GetCli(containerCreate.Host)
|
||||
biz.ErrIsNil(err)
|
||||
cli := GetCli(rc)
|
||||
|
||||
config, hostConfig, networkConfig, err := loadConfigInfo(true, containerCreate, nil)
|
||||
biz.ErrIsNil(err)
|
||||
@@ -167,36 +163,30 @@ func (d *Container) ContainerStop(rc *req.Ctx) {
|
||||
containerOp := &form.ContainerOp{}
|
||||
biz.ErrIsNil(rc.BindJSON(containerOp))
|
||||
|
||||
rc.ReqParam = collx.Kvs("host", containerOp.Host, "containerId", containerOp.ContainerId)
|
||||
cli := GetCli(rc)
|
||||
rc.ReqParam = collx.Kvs("addr", cli.Server.Addr, "containerId", containerOp.ContainerId)
|
||||
|
||||
cli, err := dkm.GetCli(containerOp.Host)
|
||||
biz.ErrIsNil(err)
|
||||
err = cli.ContainerStop(containerOp.ContainerId)
|
||||
biz.ErrIsNil(err)
|
||||
biz.ErrIsNil(cli.ContainerStop(containerOp.ContainerId))
|
||||
}
|
||||
|
||||
func (d *Container) ContainerRemove(rc *req.Ctx) {
|
||||
containerOp := &form.ContainerOp{}
|
||||
biz.ErrIsNil(rc.BindJSON(containerOp))
|
||||
|
||||
rc.ReqParam = collx.Kvs("host", containerOp.Host, "containerId", containerOp.ContainerId)
|
||||
cli := GetCli(rc)
|
||||
rc.ReqParam = collx.Kvs("addr", cli.Server.Addr, "containerId", containerOp.ContainerId)
|
||||
|
||||
cli, err := dkm.GetCli(containerOp.Host)
|
||||
biz.ErrIsNil(err)
|
||||
err = cli.ContainerRemove(containerOp.ContainerId)
|
||||
biz.ErrIsNil(err)
|
||||
biz.ErrIsNil(cli.ContainerRemove(containerOp.ContainerId))
|
||||
}
|
||||
|
||||
func (d *Container) ContainerRestart(rc *req.Ctx) {
|
||||
containerOp := &form.ContainerOp{}
|
||||
biz.ErrIsNil(rc.BindJSON(containerOp))
|
||||
|
||||
rc.ReqParam = collx.Kvs("host", containerOp.Host, "containerId", containerOp.ContainerId)
|
||||
cli := GetCli(rc)
|
||||
rc.ReqParam = collx.Kvs("addr", cli.Server.Addr, "containerId", containerOp.ContainerId)
|
||||
|
||||
cli, err := dkm.GetCli(containerOp.Host)
|
||||
biz.ErrIsNil(err)
|
||||
err = cli.ContainerRestart(containerOp.ContainerId)
|
||||
biz.ErrIsNil(err)
|
||||
biz.ErrIsNil(cli.ContainerRestart(containerOp.ContainerId))
|
||||
}
|
||||
|
||||
func (d *Container) ContainerLogs(rc *req.Ctx) {
|
||||
@@ -211,9 +201,7 @@ func (d *Container) ContainerLogs(rc *req.Ctx) {
|
||||
}()
|
||||
biz.ErrIsNilAppendErr(err, "Upgrade websocket fail: %s")
|
||||
|
||||
cli, err := dkm.GetCli(rc.Query("host"))
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
cli := GetCli(rc)
|
||||
ctx, cancel := context.WithCancel(rc.MetaCtx)
|
||||
defer cancel()
|
||||
|
||||
@@ -288,9 +276,7 @@ func (d *Container) ContainerExecAttach(rc *req.Ctx) {
|
||||
biz.ErrIsNilAppendErr(err, "Upgrade websocket fail: %s")
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte("Connecting to container..."))
|
||||
|
||||
cli, err := dkm.GetCli(rc.Query("host"))
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
cli := GetCli(rc)
|
||||
cols := rc.QueryIntDefault("cols", 80)
|
||||
rows := rc.QueryIntDefault("rows", 32)
|
||||
|
||||
@@ -311,9 +297,7 @@ func (d *Container) ContainerProxy(rc *req.Ctx) {
|
||||
containerID := pathParts[2]
|
||||
remainingPath := strings.Join(pathParts[3:], "/")
|
||||
|
||||
cli, err := dkm.GetCli(rc.Query("host"))
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
cli := GetCli(rc)
|
||||
ctx := rc.MetaCtx
|
||||
containerJSON, err := cli.DockerClient.ContainerInspect(ctx, containerID)
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
96
server/internal/docker/api/container_conf.go
Normal file
96
server/internal/docker/api/container_conf.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/docker/api/form"
|
||||
"mayfly-go/internal/docker/api/vo"
|
||||
"mayfly-go/internal/docker/application"
|
||||
"mayfly-go/internal/docker/application/dto"
|
||||
"mayfly-go/internal/docker/dkm"
|
||||
"mayfly-go/internal/docker/domain/entity"
|
||||
"mayfly-go/internal/pkg/consts"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/req"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type ContainerConf struct {
|
||||
containerApp application.Container `inject:"T"`
|
||||
tagTreeApp tagapp.TagTree `inject:"T"`
|
||||
}
|
||||
|
||||
func (cc *ContainerConf) ReqConfs() *req.Confs {
|
||||
reqs := [...]*req.Conf{
|
||||
req.NewGet("/page", cc.GetContainerPage),
|
||||
req.NewPost("/save", cc.Save),
|
||||
req.NewDelete("/del/:ids", cc.Delete),
|
||||
}
|
||||
|
||||
return req.NewConfs("docker/container-conf", reqs[:]...)
|
||||
}
|
||||
|
||||
func (cc *ContainerConf) GetContainerPage(rc *req.Ctx) {
|
||||
condition := req.BindQuery[*entity.ContainerQuery](rc)
|
||||
|
||||
tags := cc.tagTreeApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
|
||||
TypePaths: collx.AsArray(tagentity.NewTypePaths(tagentity.TagTypeContainer)),
|
||||
CodePathLikes: collx.AsArray(condition.TagPath),
|
||||
})
|
||||
// 不存在,即没有可操作数据
|
||||
if len(tags) == 0 {
|
||||
rc.ResData = model.NewEmptyPageResult[any]()
|
||||
return
|
||||
}
|
||||
|
||||
tagCodePaths := tags.GetCodePaths()
|
||||
containerCodes := tagentity.GetCodesByCodePaths(tagentity.TagTypeContainer, tagCodePaths...)
|
||||
condition.Codes = collx.ArrayDeduplicate(containerCodes)
|
||||
|
||||
res, err := cc.containerApp.GetContainerPage(condition)
|
||||
biz.ErrIsNil(err)
|
||||
if res.Total == 0 {
|
||||
rc.ResData = res
|
||||
return
|
||||
}
|
||||
|
||||
resVo := model.PageResultConv[*entity.Container, *vo.ContainerConf](res)
|
||||
containerVos := resVo.List
|
||||
cc.tagTreeApp.FillTagInfo(tagentity.TagType(consts.ResourceTypeContainer), collx.ArrayMap(containerVos, func(cvo *vo.ContainerConf) tagentity.ITagResource {
|
||||
return cvo
|
||||
})...)
|
||||
|
||||
rc.ResData = resVo
|
||||
}
|
||||
|
||||
func (c *ContainerConf) Save(rc *req.Ctx) {
|
||||
machineForm, container := req.BindJsonAndCopyTo[*form.ContainerSave, *entity.Container](rc)
|
||||
rc.ReqParam = machineForm
|
||||
|
||||
biz.ErrIsNil(c.containerApp.SaveContainer(rc.MetaCtx, &dto.SaveContainer{
|
||||
Container: container,
|
||||
TagCodePaths: machineForm.TagCodePaths,
|
||||
}))
|
||||
}
|
||||
|
||||
func (c *ContainerConf) Delete(rc *req.Ctx) {
|
||||
idsStr := rc.PathParam("ids")
|
||||
rc.ReqParam = idsStr
|
||||
ids := strings.Split(idsStr, ",")
|
||||
|
||||
for _, v := range ids {
|
||||
biz.ErrIsNil(c.containerApp.DeleteContainer(rc.MetaCtx, cast.ToUint64(v)))
|
||||
}
|
||||
}
|
||||
|
||||
func GetCli(rc *req.Ctx) *dkm.Client {
|
||||
id := rc.PathParamInt("id")
|
||||
biz.IsTrue(id > 0, "id error")
|
||||
cli, err := application.GetContainerApp().GetContainerCli(rc.MetaCtx, uint64(id))
|
||||
biz.ErrIsNil(err)
|
||||
return cli
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/docker/dkm"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/req"
|
||||
)
|
||||
@@ -14,13 +13,11 @@ func (d *Docker) ReqConfs() *req.Confs {
|
||||
req.NewGet("/info", d.GetDockerInfo),
|
||||
}
|
||||
|
||||
return req.NewConfs("docker", reqs[:]...)
|
||||
return req.NewConfs("docker/:id", reqs[:]...)
|
||||
}
|
||||
|
||||
func (d *Docker) GetDockerInfo(rc *req.Ctx) {
|
||||
host := rc.Query("host")
|
||||
cli, err := dkm.GetCli(host)
|
||||
biz.ErrIsNil(err)
|
||||
cli := GetCli(rc)
|
||||
info, err := cli.DockerClient.Info(rc.MetaCtx)
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = info
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
package form
|
||||
|
||||
import "mayfly-go/pkg/model"
|
||||
|
||||
type ContainerSave struct {
|
||||
model.ExtraData
|
||||
|
||||
Id uint64 `json:"id"`
|
||||
Addr string `json:"addr" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
TagCodePaths []string `json:"tagCodePaths" binding:"required"`
|
||||
}
|
||||
|
||||
type ContainerOp struct {
|
||||
Host string `json:"host"`
|
||||
ContainerId string `json:"containerId" binding:"required"`
|
||||
}
|
||||
|
||||
type ContainerCreate struct {
|
||||
Host string `json:"host" binding:"required"`
|
||||
ContainerID string `json:"containerId"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Image string `json:"image" validate:"required"`
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package form
|
||||
|
||||
type ImageOp struct {
|
||||
Host string `json:"host" binding:"required"`
|
||||
ImageId string `json:"imageId" binding:"required"`
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"io"
|
||||
"mayfly-go/internal/docker/api/form"
|
||||
"mayfly-go/internal/docker/api/vo"
|
||||
"mayfly-go/internal/docker/dkm"
|
||||
"mayfly-go/internal/docker/imsg"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/req"
|
||||
@@ -32,12 +31,11 @@ func (d *Image) ReqConfs() *req.Confs {
|
||||
req.NewPost("/load", d.ImageLoad).Log(req.NewLogSaveI(imsg.LogDockerImageLoad)),
|
||||
}
|
||||
|
||||
return req.NewConfs("docker/images", reqs[:]...)
|
||||
return req.NewConfs("docker/:id/images", reqs[:]...)
|
||||
}
|
||||
|
||||
func (d *Image) GetImages(rc *req.Ctx) {
|
||||
cli, err := dkm.GetCli(rc.Query("host"))
|
||||
biz.ErrIsNil(err)
|
||||
cli := GetCli(rc)
|
||||
is, err := cli.ImageList()
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
@@ -62,18 +60,12 @@ func (d *Image) ImageRemove(rc *req.Ctx) {
|
||||
imageOp := &form.ImageOp{}
|
||||
biz.ErrIsNil(rc.BindJSON(imageOp))
|
||||
|
||||
rc.ReqParam = collx.Kvs("host", imageOp.Host, "imageId", imageOp.ImageId)
|
||||
cli, err := dkm.GetCli(imageOp.Host)
|
||||
biz.ErrIsNil(err)
|
||||
err = cli.ImageRemove(imageOp.ImageId)
|
||||
biz.ErrIsNil(err)
|
||||
rc.ReqParam = collx.Kvs("imageId", imageOp.ImageId)
|
||||
cli := GetCli(rc)
|
||||
biz.ErrIsNil(cli.ImageRemove(imageOp.ImageId))
|
||||
}
|
||||
|
||||
func (d *Image) ImageLoad(rc *req.Ctx) {
|
||||
host := rc.PostForm("host")
|
||||
biz.NotEmpty(host, "host cannot be empty")
|
||||
rc.ReqParam = host
|
||||
|
||||
fileheader, err := rc.FormFile("file")
|
||||
biz.ErrIsNilAppendErr(err, "read form file error: %s")
|
||||
|
||||
@@ -81,8 +73,9 @@ func (d *Image) ImageLoad(rc *req.Ctx) {
|
||||
biz.ErrIsNil(err)
|
||||
defer file.Close()
|
||||
|
||||
cli, err := dkm.GetCli(host)
|
||||
biz.ErrIsNil(err)
|
||||
cli := GetCli(rc)
|
||||
rc.ReqParam = cli.Server
|
||||
|
||||
resp, err := cli.DockerClient.ImageLoad(rc.MetaCtx, file)
|
||||
biz.ErrIsNil(err)
|
||||
defer resp.Body.Close()
|
||||
@@ -94,14 +87,10 @@ func (d *Image) ImageLoad(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *Image) ImageExport(rc *req.Ctx) {
|
||||
host := rc.Query("host")
|
||||
biz.NotEmpty(host, "host cannot be empty")
|
||||
tag := rc.Query("tag")
|
||||
biz.NotEmpty(tag, "tag cannot be empty")
|
||||
|
||||
cli, err := dkm.GetCli(host)
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
cli := GetCli(rc)
|
||||
reader, err := cli.DockerClient.ImageSave(rc.MetaCtx, []string{tag}, client.ImageSaveWithPlatforms())
|
||||
biz.ErrIsNil(err)
|
||||
defer reader.Close()
|
||||
|
||||
21
server/internal/docker/api/vo/container.go
Normal file
21
server/internal/docker/api/vo/container.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package vo
|
||||
|
||||
import (
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type ContainerConf struct {
|
||||
model.Model
|
||||
model.ExtraData
|
||||
tagentity.ResourceTags // 标签信息
|
||||
|
||||
Addr string `json:"addr"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (c *ContainerConf) GetCode() string {
|
||||
return c.Code
|
||||
}
|
||||
13
server/internal/docker/application/application.go
Normal file
13
server/internal/docker/application/application.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/ioc"
|
||||
)
|
||||
|
||||
func InitIoc() {
|
||||
ioc.Register(new(containerAppImpl), ioc.WithComponentName("ContainerApp"))
|
||||
}
|
||||
|
||||
func GetContainerApp() Container {
|
||||
return ioc.Get[Container]("ContainerApp")
|
||||
}
|
||||
144
server/internal/docker/application/container.go
Normal file
144
server/internal/docker/application/container.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/docker/application/dto"
|
||||
"mayfly-go/internal/docker/dkm"
|
||||
"mayfly-go/internal/docker/domain/entity"
|
||||
"mayfly-go/internal/docker/domain/repository"
|
||||
"mayfly-go/internal/docker/imsg"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagdto "mayfly-go/internal/tag/application/dto"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
)
|
||||
|
||||
type Container interface {
|
||||
base.App[*entity.Container]
|
||||
|
||||
GetContainerPage(condition *entity.ContainerQuery, orderBy ...string) (*model.PageResult[*entity.Container], error)
|
||||
|
||||
// SaveContainer 保存容器配置信息
|
||||
SaveContainer(context.Context, *dto.SaveContainer) error
|
||||
|
||||
// DeleteContainer 删除容器配置信息
|
||||
DeleteContainer(context.Context, uint64) error
|
||||
|
||||
// GetContaienrCli 获取容器客户端
|
||||
GetContainerCli(context.Context, uint64) (*dkm.Client, error)
|
||||
}
|
||||
|
||||
type containerAppImpl struct {
|
||||
base.AppImpl[*entity.Container, repository.Container]
|
||||
|
||||
tagApp tagapp.TagTree `inject:"T"`
|
||||
}
|
||||
|
||||
var _ (Container) = (*containerAppImpl)(nil)
|
||||
|
||||
func (c *containerAppImpl) GetContainerPage(condition *entity.ContainerQuery, orderBy ...string) (*model.PageResult[*entity.Container], error) {
|
||||
return c.Repo.GetContainerPage(condition, orderBy...)
|
||||
}
|
||||
|
||||
func (c *containerAppImpl) SaveContainer(ctx context.Context, saveContainer *dto.SaveContainer) error {
|
||||
container := saveContainer.Container
|
||||
tagCodePaths := saveContainer.TagCodePaths
|
||||
resourceType := tagentity.TagTypeContainer
|
||||
|
||||
oldContainer := &entity.Container{
|
||||
Addr: container.Addr,
|
||||
}
|
||||
|
||||
err := c.GetByCond(oldContainer)
|
||||
|
||||
if container.Id == 0 {
|
||||
if err == nil {
|
||||
return errorx.NewBizI(ctx, imsg.ErrContainerConfExist)
|
||||
}
|
||||
|
||||
// 生成随机编号
|
||||
container.Code = stringx.Rand(10)
|
||||
|
||||
return c.Tx(ctx, func(ctx context.Context) error {
|
||||
if err := c.Insert(ctx, container); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.tagApp.SaveResourceTag(ctx, &tagdto.SaveResourceTag{
|
||||
ResourceTag: &tagdto.ResourceTag{
|
||||
Code: container.Code,
|
||||
Name: container.Name,
|
||||
Type: resourceType,
|
||||
},
|
||||
ParentTagCodePaths: tagCodePaths,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if err == nil && container.Id != oldContainer.Id {
|
||||
return errorx.NewBizI(ctx, imsg.ErrContainerConfExist)
|
||||
}
|
||||
if oldContainer.Code == "" {
|
||||
oldContainer, _ = c.GetById(container.Id)
|
||||
}
|
||||
|
||||
dkm.CloseCli(oldContainer.Id)
|
||||
return c.Tx(ctx, func(ctx context.Context) error {
|
||||
if err := c.UpdateById(ctx, container); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if oldContainer.Name != container.Name {
|
||||
if err := c.tagApp.UpdateTagName(ctx, tagentity.TagTypeMachine, oldContainer.Code, container.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return c.tagApp.SaveResourceTag(ctx, &tagdto.SaveResourceTag{
|
||||
ResourceTag: &tagdto.ResourceTag{
|
||||
Code: oldContainer.Code,
|
||||
Name: container.Name,
|
||||
Type: resourceType,
|
||||
},
|
||||
ParentTagCodePaths: tagCodePaths,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (c *containerAppImpl) DeleteContainer(ctx context.Context, id uint64) error {
|
||||
container, err := c.GetById(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dkm.CloseCli(id)
|
||||
return c.Tx(ctx, func(ctx context.Context) error {
|
||||
if err := c.DeleteById(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.tagApp.SaveResourceTag(ctx, &tagdto.SaveResourceTag{
|
||||
ResourceTag: &tagdto.ResourceTag{
|
||||
Code: container.Code,
|
||||
Type: tagentity.TagTypeContainer,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (c *containerAppImpl) GetContainerCli(ctx context.Context, id uint64) (*dkm.Client, error) {
|
||||
return dkm.GetCli(id, func(u uint64) (*dkm.ContainerServer, error) {
|
||||
containerConf, err := c.GetById(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dkm.ContainerServer{
|
||||
Id: id,
|
||||
Addr: containerConf.Addr,
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
8
server/internal/docker/application/dto/container.go
Normal file
8
server/internal/docker/application/dto/container.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package dto
|
||||
|
||||
import "mayfly-go/internal/docker/domain/entity"
|
||||
|
||||
type SaveContainer struct {
|
||||
Container *entity.Container
|
||||
TagCodePaths []string
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package dkm
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mayfly-go/internal/machine/mcm"
|
||||
"mayfly-go/pkg/logx"
|
||||
@@ -26,13 +27,13 @@ const (
|
||||
DefaultServer = "unix:///var/run/docker.sock"
|
||||
)
|
||||
|
||||
type DockerServer struct {
|
||||
Host string
|
||||
|
||||
Client *client.Client
|
||||
type ContainerServer struct {
|
||||
Id uint64
|
||||
Addr string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Server *ContainerServer
|
||||
DockerClient *client.Client
|
||||
}
|
||||
|
||||
@@ -46,12 +47,13 @@ func (c *Client) Ping() error {
|
||||
}
|
||||
|
||||
// GetCli get docker cli
|
||||
func GetCli(host string) (*Client, error) {
|
||||
if host == "" {
|
||||
host = DefaultServer
|
||||
}
|
||||
pool, err := poolGroup.GetCachePool(host, func() (*Client, error) {
|
||||
return NewClient(&DockerServer{Host: host})
|
||||
func GetCli(id uint64, getContainer func(uint64) (*ContainerServer, error)) (*Client, error) {
|
||||
pool, err := poolGroup.GetCachePool(fmt.Sprintf("%d", id), func() (*Client, error) {
|
||||
containerServer, err := getContainer(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewClient(containerServer)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -59,18 +61,23 @@ func GetCli(host string) (*Client, error) {
|
||||
return pool.Get(context.Background())
|
||||
}
|
||||
|
||||
func CloseCli(id uint64) error {
|
||||
return poolGroup.Close(fmt.Sprintf("%d", id))
|
||||
}
|
||||
|
||||
// NewClient new docker client
|
||||
func NewClient(server *DockerServer) (*Client, error) {
|
||||
if server.Host == "" {
|
||||
server.Host = DefaultServer
|
||||
func NewClient(server *ContainerServer) (*Client, error) {
|
||||
if server.Addr == "" {
|
||||
server.Addr = DefaultServer
|
||||
}
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithHost(server.Host), client.WithAPIVersionNegotiation())
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithHost(server.Addr), client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
DockerClient: cli,
|
||||
Server: server,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
14
server/internal/docker/domain/entity/contrainer.go
Normal file
14
server/internal/docker/domain/entity/contrainer.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package entity
|
||||
|
||||
import "mayfly-go/pkg/model"
|
||||
|
||||
// 容器配置
|
||||
type Container struct {
|
||||
model.Model
|
||||
model.ExtraData
|
||||
|
||||
Code string `json:"code" gorm:"size:32;comment:code"` // code
|
||||
Name string `json:"name" gorm:"size:32"` // 名称
|
||||
Addr string `json:"addr" gorm:"size:64;not null;comment:地址"` // 地址
|
||||
Remark string `json:"remark" gorm:"comment:备注"` // 备注
|
||||
}
|
||||
16
server/internal/docker/domain/entity/query.go
Normal file
16
server/internal/docker/domain/entity/query.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package entity
|
||||
|
||||
import "mayfly-go/pkg/model"
|
||||
|
||||
type ContainerQuery struct {
|
||||
model.PageParam
|
||||
|
||||
Id uint64 `json:"id" form:"id"`
|
||||
Code string `json:"code" form:"code"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Addr string `json:"addr" form:"addr"`
|
||||
TagPath string `json:"tagPath" form:"tagPath"`
|
||||
|
||||
Keyword string `json:"keyword" form:"keyword"`
|
||||
Codes []string
|
||||
}
|
||||
14
server/internal/docker/domain/repository/container.go
Normal file
14
server/internal/docker/domain/repository/container.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/docker/domain/entity"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type Container interface {
|
||||
base.Repo[*entity.Container]
|
||||
|
||||
// 分页获取容器配置列表
|
||||
GetContainerPage(condition *entity.ContainerQuery, orderBy ...string) (*model.PageResult[*entity.Container], error)
|
||||
}
|
||||
@@ -5,4 +5,11 @@ import "mayfly-go/pkg/i18n"
|
||||
var En = map[i18n.MsgId]string{
|
||||
LogDockerContainerStop: "Container - Stop",
|
||||
LogDockerContainerRestart: "Container - Restart",
|
||||
LogDockerContainerRemove: "Container - Remove",
|
||||
LogDockerContainerCreate: "Container - Create",
|
||||
|
||||
LogDockerImageRemove: "Image - Remove",
|
||||
LogDockerImageLoad: "Image - Load",
|
||||
|
||||
ErrContainerConfExist: "Container conf already exists",
|
||||
}
|
||||
|
||||
@@ -18,4 +18,6 @@ const (
|
||||
|
||||
LogDockerImageRemove
|
||||
LogDockerImageLoad
|
||||
|
||||
ErrContainerConfExist
|
||||
)
|
||||
|
||||
@@ -10,4 +10,6 @@ var Zh_CN = map[i18n.MsgId]string{
|
||||
|
||||
LogDockerImageRemove: "镜像-删除",
|
||||
LogDockerImageLoad: "镜像-导入",
|
||||
|
||||
ErrContainerConfExist: "容器配置已存在",
|
||||
}
|
||||
|
||||
33
server/internal/docker/infra/persistence/container.go
Normal file
33
server/internal/docker/infra/persistence/container.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/docker/domain/entity"
|
||||
"mayfly-go/internal/docker/domain/repository"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type containerRepoImpl struct {
|
||||
base.RepoImpl[*entity.Container]
|
||||
}
|
||||
|
||||
func newContainerRepo() repository.Container {
|
||||
return &containerRepoImpl{}
|
||||
}
|
||||
|
||||
func (m *containerRepoImpl) GetContainerPage(condition *entity.ContainerQuery, orderBy ...string) (*model.PageResult[*entity.Container], error) {
|
||||
qd := model.NewCond().
|
||||
Eq("id", condition.Id).
|
||||
Like("addr", condition.Addr).
|
||||
Like("name", condition.Name).
|
||||
In("code", condition.Codes).
|
||||
Eq("code", condition.Code)
|
||||
|
||||
keyword := condition.Keyword
|
||||
if keyword != "" {
|
||||
keyword = "%" + keyword + "%"
|
||||
qd.And("addr like ? or name like ? or code like ?", keyword, keyword, keyword)
|
||||
}
|
||||
|
||||
return m.PageByCond(qd, condition.PageParam)
|
||||
}
|
||||
9
server/internal/docker/infra/persistence/persistence.go
Normal file
9
server/internal/docker/infra/persistence/persistence.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/ioc"
|
||||
)
|
||||
|
||||
func InitIoc() {
|
||||
ioc.Register(newContainerRepo(), ioc.WithComponentName("ContainerRepo"))
|
||||
}
|
||||
@@ -1,7 +1,16 @@
|
||||
package init
|
||||
|
||||
import "mayfly-go/internal/docker/api"
|
||||
import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/docker/api"
|
||||
"mayfly-go/internal/docker/application"
|
||||
"mayfly-go/internal/docker/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
api.InitIoc()
|
||||
initialize.AddInitIocFunc(func() {
|
||||
persistence.InitIoc()
|
||||
application.InitIoc()
|
||||
api.InitIoc()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import "fmt"
|
||||
|
||||
const (
|
||||
AppName = "mayfly-go"
|
||||
Version = "v1.10.2"
|
||||
Version = "v1.10.3"
|
||||
)
|
||||
|
||||
func GetAppInfo() string {
|
||||
|
||||
@@ -9,6 +9,7 @@ const (
|
||||
ResourceTypeMongo int8 = 4
|
||||
ResourceTypeAuthCert int8 = 5
|
||||
ResourceTypeEsInstance int8 = 6
|
||||
ResourceTypeContainer int8 = 7
|
||||
|
||||
// imsg起始编号
|
||||
ImsgNumSys = 10000
|
||||
|
||||
@@ -183,6 +183,10 @@ func (p *TagTree) CountTagResource(rc *req.Ctx) {
|
||||
Types: collx.AsArray(entity.TagTypeMongo),
|
||||
CodePathLikes: collx.AsArray(tagPath),
|
||||
}).GetCodes()),
|
||||
"container": len(p.tagTreeApp.GetAccountTags(accountId, &entity.TagTreeQuery{
|
||||
Types: collx.AsArray(entity.TagTypeContainer),
|
||||
CodePathLikes: collx.AsArray(tagPath),
|
||||
}).GetCodes()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ const (
|
||||
TagTypeRedis TagType = TagType(consts.ResourceTypeRedis)
|
||||
TagTypeMongo TagType = TagType(consts.ResourceTypeMongo)
|
||||
TagTypeAuthCert TagType = TagType(consts.ResourceTypeAuthCert) // 授权凭证类型
|
||||
TagTypeContainer TagType = TagType(consts.ResourceTypeContainer)
|
||||
|
||||
TagTypeDb TagType = 22 // 数据库名
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
dockerentity "mayfly-go/internal/docker/domain/entity"
|
||||
esentity "mayfly-go/internal/es/domain/entity"
|
||||
flowentity "mayfly-go/internal/flow/domain/entity"
|
||||
machineentity "mayfly-go/internal/machine/domain/entity"
|
||||
@@ -18,6 +19,7 @@ func V1_10() []*gormigrate.Migration {
|
||||
migrations = append(migrations, V1_10_0()...)
|
||||
migrations = append(migrations, V1_10_1()...)
|
||||
migrations = append(migrations, V1_10_2()...)
|
||||
migrations = append(migrations, V1_10_3()...)
|
||||
return migrations
|
||||
}
|
||||
|
||||
@@ -273,3 +275,54 @@ func V1_10_2() []*gormigrate.Migration {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func V1_10_3() []*gormigrate.Migration {
|
||||
return []*gormigrate.Migration{
|
||||
{
|
||||
ID: "20250904-v1.10.3",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
tx.AutoMigrate(&dockerentity.Container{})
|
||||
|
||||
// 删除容器菜单
|
||||
tx.Exec("update t_sys_resource set is_deleted = 1 where code = '/container'")
|
||||
|
||||
// 新增容器管理基本权限
|
||||
tx.Exec("INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES (1757145306, 94, 'Tag3fhad/glxajg23/Bbrte5UH/', 2, 1, 'menu.containerManageBase', 'container', 1757145306, 'null', 1, 'admin', 1, 'admin', '2025-09-06 15:55:06', '2025-09-06 15:56:10', 0, NULL)")
|
||||
|
||||
// 机器列表相关菜单权限
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Alw1Xkq3/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Alw1Xkq3/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Lsew24Kx/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Lsew24Kx/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Keiqkx4L/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Keiqkx4L/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Keal2Xke/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Keal2Xke/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Ihfs2xaw/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Ihfs2xaw/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/3ldkxJDx/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/3ldkxJDx/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Ljewix43/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Ljewix43/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/L12wix43/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/L12wix43/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Ljewisd3/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Ljewisd3/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Ljeew43/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Ljeew43/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/ODewix43/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/ODewix43/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/LIEwix43/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/LIEwix43/'")
|
||||
|
||||
// redis
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/IUlxia23/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/IUlxia23/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/Gxlagheg/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/Gxlagheg/'")
|
||||
|
||||
// db
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/TGFPA3Ez/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/TGFPA3Ez/'")
|
||||
|
||||
// es
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/SQNFhhhn/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/SQNFhhhn/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/XAgy5Uvp/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/XAgy5Uvp/'")
|
||||
|
||||
// mongo
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/xvpKk36u/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/xvpKk36u/'")
|
||||
tx.Exec("Update t_sys_resource set ui_path='ocdrUNaa/3sblw1Wb/', pid=1756122788 where ui_path = 'Tag3fhad/glxajg23/3sblw1Wb/'")
|
||||
|
||||
return nil
|
||||
},
|
||||
Rollback: func(tx *gorm.DB) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user