mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 11:27:17 +08:00
feat: compose接口
This commit is contained in:
@@ -97,6 +97,8 @@ func initWeb() (*app.Web, error) {
|
||||
sshService := service.NewSSHService(sshRepo)
|
||||
containerRepo := data.NewContainerRepo()
|
||||
containerService := service.NewContainerService(containerRepo)
|
||||
containerComposeRepo := data.NewContainerComposeRepo()
|
||||
containerComposeService := service.NewContainerComposeService(containerComposeRepo)
|
||||
containerNetworkRepo := data.NewContainerNetworkRepo()
|
||||
containerNetworkService := service.NewContainerNetworkService(containerNetworkRepo)
|
||||
containerImageRepo := data.NewContainerImageRepo()
|
||||
@@ -132,7 +134,7 @@ func initWeb() (*app.Web, error) {
|
||||
supervisorApp := supervisor.NewApp()
|
||||
toolboxApp := toolbox.NewApp()
|
||||
loader := bootstrap.NewLoader(benchmarkApp, dockerApp, fail2banApp, frpApp, giteaApp, memcachedApp, mysqlApp, nginxApp, php74App, php80App, php81App, php82App, php83App, php84App, phpmyadminApp, podmanApp, postgresqlApp, pureftpdApp, redisApp, rsyncApp, s3fsApp, supervisorApp, toolboxApp)
|
||||
http := route.NewHttp(userService, dashboardService, taskService, websiteService, databaseService, databaseServerService, databaseUserService, backupService, certService, certDNSService, certAccountService, appService, cronService, processService, safeService, firewallService, sshService, containerService, containerNetworkService, containerImageService, containerVolumeService, fileService, monitorService, settingService, systemctlService, loader)
|
||||
http := route.NewHttp(userService, dashboardService, taskService, websiteService, databaseService, databaseServerService, databaseUserService, backupService, certService, certDNSService, certAccountService, appService, cronService, processService, safeService, firewallService, sshService, containerService, containerComposeService, containerNetworkService, containerImageService, containerVolumeService, fileService, monitorService, settingService, systemctlService, loader)
|
||||
wsService := service.NewWsService(koanf, sshRepo)
|
||||
ws := route.NewWs(wsService)
|
||||
mux, err := bootstrap.NewRouter(middlewares, http, ws)
|
||||
|
||||
10
internal/biz/container_compose.go
Normal file
10
internal/biz/container_compose.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package biz
|
||||
|
||||
type ContainerComposeRepo interface {
|
||||
List() ([]string, error)
|
||||
Get(name string) (string, error)
|
||||
Create(name, compose string) error
|
||||
Up(name string, force bool) error
|
||||
Down(name string) error
|
||||
Remove(name string) error
|
||||
}
|
||||
83
internal/data/container_compose.go
Normal file
83
internal/data/container_compose.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/app"
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
"github.com/tnb-labs/panel/pkg/shell"
|
||||
)
|
||||
|
||||
type containerComposeRepo struct{}
|
||||
|
||||
func NewContainerComposeRepo() biz.ContainerComposeRepo {
|
||||
return &containerComposeRepo{}
|
||||
}
|
||||
|
||||
// List 列出所有编排文件名
|
||||
func (r *containerComposeRepo) List() ([]string, error) {
|
||||
dir := filepath.Join(app.Root, "server", "compose")
|
||||
var files []string
|
||||
err := filepath.Walk(dir, func(path string, d fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if ext := filepath.Ext(path); ext == ".yml" || ext == ".yaml" {
|
||||
files = append(files, strings.TrimSuffix(filepath.Base(path), ext))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// Get 获取编排文件内容
|
||||
func (r *containerComposeRepo) Get(name string) (string, error) {
|
||||
dir := filepath.Join(app.Root, "server", "compose")
|
||||
path := filepath.Join(dir, name+".yml")
|
||||
content, err := os.ReadFile(path)
|
||||
return string(content), err
|
||||
}
|
||||
|
||||
// Create 创建编排文件
|
||||
func (r *containerComposeRepo) Create(name, compose string) error {
|
||||
dir := filepath.Join(app.Root, "server", "compose")
|
||||
path := filepath.Join(dir, name+".yml")
|
||||
return os.WriteFile(path, []byte(compose), 0644)
|
||||
}
|
||||
|
||||
// Up 启动编排
|
||||
func (r *containerComposeRepo) Up(name string, force bool) error {
|
||||
dir := filepath.Join(app.Root, "server", "compose")
|
||||
path := filepath.Join(dir, name+".yml")
|
||||
cmd := "docker compose -f %s up -d"
|
||||
if force {
|
||||
cmd += " --pull always" // 强制拉取镜像
|
||||
}
|
||||
_, err := shell.Execf(cmd, path)
|
||||
return err
|
||||
}
|
||||
|
||||
// Down 停止编排
|
||||
func (r *containerComposeRepo) Down(name string) error {
|
||||
dir := filepath.Join(app.Root, "server", "compose")
|
||||
path := filepath.Join(dir, name+".yml")
|
||||
_, err := shell.Execf("docker compose -f %s down", path)
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove 删除编排
|
||||
func (r *containerComposeRepo) Remove(name string) error {
|
||||
dir := filepath.Join(app.Root, "server", "compose")
|
||||
path := filepath.Join(dir, name+".yml")
|
||||
return os.Remove(path)
|
||||
}
|
||||
@@ -11,6 +11,7 @@ var ProviderSet = wire.NewSet(
|
||||
NewCertAccountRepo,
|
||||
NewCertDNSRepo,
|
||||
NewContainerRepo,
|
||||
NewContainerComposeRepo,
|
||||
NewContainerImageRepo,
|
||||
NewContainerNetworkRepo,
|
||||
NewContainerVolumeRepo,
|
||||
|
||||
23
internal/http/request/container_compose.go
Normal file
23
internal/http/request/container_compose.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package request
|
||||
|
||||
type ContainerComposeGet struct {
|
||||
Name string `uri:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type ContainerComposeCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Compose string `json:"compose" validate:"required"`
|
||||
}
|
||||
|
||||
type ContainerComposeUp struct {
|
||||
Name string `uri:"name" validate:"required"`
|
||||
Force bool `json:"force"`
|
||||
}
|
||||
|
||||
type ContainerComposeDown struct {
|
||||
Name string `uri:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type ContainerComposeRemove struct {
|
||||
Name string `uri:"name" validate:"required"`
|
||||
}
|
||||
@@ -33,6 +33,7 @@ type Http struct {
|
||||
firewall *service.FirewallService
|
||||
ssh *service.SSHService
|
||||
container *service.ContainerService
|
||||
containerCompose *service.ContainerComposeService
|
||||
containerNetwork *service.ContainerNetworkService
|
||||
containerImage *service.ContainerImageService
|
||||
containerVolume *service.ContainerVolumeService
|
||||
@@ -62,6 +63,7 @@ func NewHttp(
|
||||
firewall *service.FirewallService,
|
||||
ssh *service.SSHService,
|
||||
container *service.ContainerService,
|
||||
containerCompose *service.ContainerComposeService,
|
||||
containerNetwork *service.ContainerNetworkService,
|
||||
containerImage *service.ContainerImageService,
|
||||
containerVolume *service.ContainerVolumeService,
|
||||
@@ -90,6 +92,7 @@ func NewHttp(
|
||||
firewall: firewall,
|
||||
ssh: ssh,
|
||||
container: container,
|
||||
containerCompose: containerCompose,
|
||||
containerNetwork: containerNetwork,
|
||||
containerImage: containerImage,
|
||||
containerVolume: containerVolume,
|
||||
@@ -284,6 +287,14 @@ func (route *Http) Register(r *chi.Mux) {
|
||||
r.Get("/{id}/logs", route.container.Logs)
|
||||
r.Post("/prune", route.container.Prune)
|
||||
})
|
||||
r.Route("/compose", func(r chi.Router) {
|
||||
r.Get("/", route.containerCompose.List)
|
||||
r.Get("/{name}", route.containerCompose.Get)
|
||||
r.Post("/", route.containerCompose.Create)
|
||||
r.Post("/{name}/up", route.containerCompose.Up)
|
||||
r.Post("/{name}/down", route.containerCompose.Down)
|
||||
r.Delete("/{name}", route.containerCompose.Remove)
|
||||
})
|
||||
r.Route("/network", func(r chi.Router) {
|
||||
r.Get("/", route.containerNetwork.List)
|
||||
r.Post("/", route.containerNetwork.Create)
|
||||
|
||||
111
internal/service/container_compose.go
Normal file
111
internal/service/container_compose.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-rat/chix"
|
||||
|
||||
"github.com/tnb-labs/panel/internal/biz"
|
||||
"github.com/tnb-labs/panel/internal/http/request"
|
||||
)
|
||||
|
||||
type ContainerComposeService struct {
|
||||
containerComposeRepo biz.ContainerComposeRepo
|
||||
}
|
||||
|
||||
func NewContainerComposeService(containerCompose biz.ContainerComposeRepo) *ContainerComposeService {
|
||||
return &ContainerComposeService{
|
||||
containerComposeRepo: containerCompose,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ContainerComposeService) List(w http.ResponseWriter, r *http.Request) {
|
||||
files, err := s.containerComposeRepo.List()
|
||||
if err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
paged, total := Paginate(r, files)
|
||||
|
||||
Success(w, chix.M{
|
||||
"total": total,
|
||||
"items": paged,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ContainerComposeService) Get(w http.ResponseWriter, r *http.Request) {
|
||||
req, err := Bind[request.ContainerComposeGet](r)
|
||||
if err != nil {
|
||||
Error(w, http.StatusUnprocessableEntity, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
content, err := s.containerComposeRepo.Get(req.Name)
|
||||
if err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Success(w, content)
|
||||
}
|
||||
|
||||
func (s *ContainerComposeService) Create(w http.ResponseWriter, r *http.Request) {
|
||||
req, err := Bind[request.ContainerComposeCreate](r)
|
||||
if err != nil {
|
||||
Error(w, http.StatusUnprocessableEntity, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.containerComposeRepo.Create(req.Name, req.Compose); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Success(w, nil)
|
||||
}
|
||||
|
||||
func (s *ContainerComposeService) Up(w http.ResponseWriter, r *http.Request) {
|
||||
req, err := Bind[request.ContainerComposeUp](r)
|
||||
if err != nil {
|
||||
Error(w, http.StatusUnprocessableEntity, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.containerComposeRepo.Up(req.Name, req.Force); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Success(w, nil)
|
||||
}
|
||||
|
||||
func (s *ContainerComposeService) Down(w http.ResponseWriter, r *http.Request) {
|
||||
req, err := Bind[request.ContainerComposeDown](r)
|
||||
if err != nil {
|
||||
Error(w, http.StatusUnprocessableEntity, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.containerComposeRepo.Down(req.Name); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Success(w, nil)
|
||||
}
|
||||
|
||||
func (s *ContainerComposeService) Remove(w http.ResponseWriter, r *http.Request) {
|
||||
req, err := Bind[request.ContainerComposeRemove](r)
|
||||
if err != nil {
|
||||
Error(w, http.StatusUnprocessableEntity, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.containerComposeRepo.Remove(req.Name); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Success(w, nil)
|
||||
}
|
||||
@@ -11,6 +11,7 @@ var ProviderSet = wire.NewSet(
|
||||
NewCertDNSService,
|
||||
NewCliService,
|
||||
NewContainerService,
|
||||
NewContainerComposeService,
|
||||
NewContainerImageService,
|
||||
NewContainerNetworkService,
|
||||
NewContainerVolumeService,
|
||||
|
||||
Reference in New Issue
Block a user