From 1949be249007702eab3e96581ca1d9b603a8b338 Mon Sep 17 00:00:00 2001 From: zhengkunwang223 Date: Wed, 29 Mar 2023 14:58:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=8F=9C=E5=8D=95=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E7=8E=AF=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/runtime.go | 34 +++++++++ backend/app/dto/request/runtime.go | 9 +++ backend/app/dto/response/runtime.go | 7 ++ backend/app/model/runtime.go | 13 ++++ backend/app/repo/runtime.go | 42 +++++++++++ backend/app/service/app_utils.go | 19 ++++- backend/app/service/runtime.go | 42 +++++++++++ backend/constant/dir.go | 1 + backend/init/migration/migrate.go | 1 + backend/init/migration/migrations/init.go | 7 ++ backend/init/router/router.go | 1 + backend/router/entry.go | 1 + backend/router/ro_runtime.go | 20 ++++++ frontend/src/api/interface/runtime.ts | 21 ++++++ frontend/src/api/modules/runtime.ts | 7 ++ frontend/src/lang/modules/en.ts | 6 ++ frontend/src/lang/modules/zh.ts | 6 ++ frontend/src/routers/modules/website.ts | 9 +++ frontend/src/views/website/runtime/index.vue | 73 ++++++++++++++++++++ 19 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 backend/app/api/v1/runtime.go create mode 100644 backend/app/dto/request/runtime.go create mode 100644 backend/app/dto/response/runtime.go create mode 100644 backend/app/model/runtime.go create mode 100644 backend/app/repo/runtime.go create mode 100644 backend/app/service/runtime.go create mode 100644 backend/router/ro_runtime.go create mode 100644 frontend/src/api/interface/runtime.ts create mode 100644 frontend/src/api/modules/runtime.ts create mode 100644 frontend/src/views/website/runtime/index.vue diff --git a/backend/app/api/v1/runtime.go b/backend/app/api/v1/runtime.go new file mode 100644 index 000000000..c72398c0e --- /dev/null +++ b/backend/app/api/v1/runtime.go @@ -0,0 +1,34 @@ +package v1 + +import ( + "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" + "github.com/1Panel-dev/1Panel/backend/app/dto" + "github.com/1Panel-dev/1Panel/backend/app/dto/request" + "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/gin-gonic/gin" +) + +// @Tags Runtime +// @Summary List runtimes +// @Description 获取运行环境列表 +// @Accept json +// @Param request body request.RuntimeSearch true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /runtimes/search [post] +func (b *BaseApi) SearchRuntimes(c *gin.Context) { + var req request.RuntimeSearch + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + total, items, err := runtimeService.Page(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, dto.PageResult{ + Total: total, + Items: items, + }) +} diff --git a/backend/app/dto/request/runtime.go b/backend/app/dto/request/runtime.go new file mode 100644 index 000000000..3fac16d0f --- /dev/null +++ b/backend/app/dto/request/runtime.go @@ -0,0 +1,9 @@ +package request + +import "github.com/1Panel-dev/1Panel/backend/app/dto" + +type RuntimeSearch struct { + dto.PageInfo + Type string `json:"type"` + Name string `json:"name"` +} diff --git a/backend/app/dto/response/runtime.go b/backend/app/dto/response/runtime.go new file mode 100644 index 000000000..90b9d65bb --- /dev/null +++ b/backend/app/dto/response/runtime.go @@ -0,0 +1,7 @@ +package response + +import "github.com/1Panel-dev/1Panel/backend/app/model" + +type RuntimeRes struct { + model.Runtime +} diff --git a/backend/app/model/runtime.go b/backend/app/model/runtime.go new file mode 100644 index 000000000..3892623fe --- /dev/null +++ b/backend/app/model/runtime.go @@ -0,0 +1,13 @@ +package model + +type Runtime struct { + BaseModel + Name string `gorm:"type:varchar;not null" json:"name"` + AppDetailID uint `gorm:"type:integer" json:"appDetailId"` + Image string `gorm:"type:varchar;not null" json:"image"` + WorkDir string `gorm:"type:varchar;not null" json:"workDir"` + DockerCompose string `gorm:"type:varchar;not null" json:"dockerCompose"` + Env string `gorm:"type:varchar;not null" json:"env"` + Params string `gorm:"type:varchar;not null" json:"params"` + Type string `gorm:"type:varchar;not null" json:"type"` +} diff --git a/backend/app/repo/runtime.go b/backend/app/repo/runtime.go new file mode 100644 index 000000000..cda8f6b5c --- /dev/null +++ b/backend/app/repo/runtime.go @@ -0,0 +1,42 @@ +package repo + +import ( + "context" + "github.com/1Panel-dev/1Panel/backend/app/model" +) + +type RuntimeRepo struct { +} + +type IRuntimeRepo interface { + Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error) + Create(ctx context.Context, runtime *model.Runtime) error + Save(runtime *model.Runtime) error + DeleteBy(opts ...DBOption) error +} + +func NewIRunTimeRepo() IRuntimeRepo { + return &RuntimeRepo{} +} + +func (r *RuntimeRepo) Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error) { + var runtimes []model.Runtime + db := getDb(opts...).Model(&model.Runtime{}) + count := int64(0) + db = db.Count(&count) + err := db.Limit(size).Offset(size * (page - 1)).Find(&runtimes).Error + return count, runtimes, err +} + +func (r *RuntimeRepo) Create(ctx context.Context, runtime *model.Runtime) error { + db := getTx(ctx).Model(&model.Runtime{}) + return db.Create(&runtime).Error +} + +func (r *RuntimeRepo) Save(runtime *model.Runtime) error { + return getDb().Save(&runtime).Error +} + +func (r *RuntimeRepo) DeleteBy(opts ...DBOption) error { + return getDb(opts...).Delete(&model.Runtime{}).Error +} diff --git a/backend/app/service/app_utils.go b/backend/app/service/app_utils.go index a1efea3bb..6c488207d 100644 --- a/backend/app/service/app_utils.go +++ b/backend/app/service/app_utils.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/subosito/gotenv" "math" "os" "path" @@ -224,7 +225,11 @@ func updateInstall(installId uint, detailId uint) error { } func getContainerNames(install model.AppInstall) ([]string, error) { - project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(install.Env)) + envStr, err := coverEnvJsonToStr(install.Env) + if err != nil { + return nil, err + } + project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(envStr)) if err != nil { return nil, err } @@ -238,6 +243,18 @@ func getContainerNames(install model.AppInstall) ([]string, error) { return containerNames, nil } +func coverEnvJsonToStr(envJson string) (string, error) { + envMap := make(map[string]interface{}) + _ = json.Unmarshal([]byte(envJson), &envMap) + newEnvMap := make(map[string]string, len(envMap)) + handleMap(envMap, newEnvMap) + envStr, err := gotenv.Marshal(newEnvMap) + if err != nil { + return "", err + } + return envStr, nil +} + func checkLimit(app model.App) error { if app.Limit > 0 { installs, err := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID)) diff --git a/backend/app/service/runtime.go b/backend/app/service/runtime.go new file mode 100644 index 000000000..e2908e040 --- /dev/null +++ b/backend/app/service/runtime.go @@ -0,0 +1,42 @@ +package service + +import ( + "github.com/1Panel-dev/1Panel/backend/app/dto/request" + "github.com/1Panel-dev/1Panel/backend/app/dto/response" + "github.com/1Panel-dev/1Panel/backend/app/repo" +) + +type RuntimeService struct { +} + +type IRuntimeService interface { + Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) +} + +func NewRuntimeService() IRuntimeService { + return &RuntimeService{} +} + +func (r *RuntimeService) Create() { + +} + +func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) { + var ( + opts []repo.DBOption + res []response.RuntimeRes + ) + if req.Name != "" { + opts = append(opts, commonRepo.WithLikeName(req.Name)) + } + total, runtimes, err := runtimeRepo.Page(req.Page, req.PageSize, opts...) + if err != nil { + return 0, nil, err + } + for _, runtime := range runtimes { + res = append(res, response.RuntimeRes{ + Runtime: runtime, + }) + } + return total, res, nil +} diff --git a/backend/constant/dir.go b/backend/constant/dir.go index d9024992e..aa5da639c 100644 --- a/backend/constant/dir.go +++ b/backend/constant/dir.go @@ -11,4 +11,5 @@ var ( ResourceDir = path.Join(DataDir, "resource") AppResourceDir = path.Join(ResourceDir, "apps") AppInstallDir = path.Join(DataDir, "apps") + RuntimeDir = path.Join(DataDir, "runtime") ) diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index f79a8f435..29c50c0c5 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -21,6 +21,7 @@ func Init() { migrations.AddTableDatabaseMysql, migrations.AddTableSnap, migrations.AddDefaultGroup, + migrations.AddTableRuntime, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index bb8c2fd64..6329fdaee 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -247,3 +247,10 @@ var AddDefaultGroup = &gormigrate.Migration{ return tx.Migrator().DropTable("website_groups") }, } + +var AddTableRuntime = &gormigrate.Migration{ + ID: "20230328-add-table-runtime", + Migrate: func(tx *gorm.DB) error { + return tx.AutoMigrate(&model.Runtime{}) + }, +} diff --git a/backend/init/router/router.go b/backend/init/router/router.go index 5d01407a1..f501153fb 100644 --- a/backend/init/router/router.go +++ b/backend/init/router/router.go @@ -96,6 +96,7 @@ func Routers() *gin.Engine { systemRouter.InitWebsiteSSLRouter(PrivateGroup) systemRouter.InitWebsiteAcmeAccountRouter(PrivateGroup) systemRouter.InitNginxRouter(PrivateGroup) + systemRouter.InitRuntimeRouter(PrivateGroup) } return Router diff --git a/backend/router/entry.go b/backend/router/entry.go index 07febf122..9898932e6 100644 --- a/backend/router/entry.go +++ b/backend/router/entry.go @@ -19,6 +19,7 @@ type RouterGroup struct { WebsiteSSLRouter DatabaseRouter NginxRouter + RuntimeRouter } var RouterGroupApp = new(RouterGroup) diff --git a/backend/router/ro_runtime.go b/backend/router/ro_runtime.go new file mode 100644 index 000000000..6d2928aec --- /dev/null +++ b/backend/router/ro_runtime.go @@ -0,0 +1,20 @@ +package router + +import ( + v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1" + "github.com/1Panel-dev/1Panel/backend/middleware" + "github.com/gin-gonic/gin" +) + +type RuntimeRouter struct { +} + +func (r *RuntimeRouter) InitRuntimeRouter(Router *gin.RouterGroup) { + groupRouter := Router.Group("runtimes") + groupRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.PasswordExpired()) + + baseApi := v1.ApiGroupApp.BaseApi + { + groupRouter.POST("/search", baseApi.SearchRuntimes) + } +} diff --git a/frontend/src/api/interface/runtime.ts b/frontend/src/api/interface/runtime.ts new file mode 100644 index 000000000..aa7721482 --- /dev/null +++ b/frontend/src/api/interface/runtime.ts @@ -0,0 +1,21 @@ +import { CommonModel, ReqPage } from '.'; +export namespace Runtime { + export interface Runtime extends CommonModel { + name: string; + appDetailId: string; + image: string; + workDir: string; + dockerCompose: string; + env: string; + params: string; + type: string; + } + + export interface RuntimeReq extends ReqPage { + name: string; + } + + export interface RuntimeDTO extends Runtime { + websites: string[]; + } +} diff --git a/frontend/src/api/modules/runtime.ts b/frontend/src/api/modules/runtime.ts new file mode 100644 index 000000000..319410b28 --- /dev/null +++ b/frontend/src/api/modules/runtime.ts @@ -0,0 +1,7 @@ +import http from '@/api'; +import { ResPage } from '../interface'; +import { Runtime } from '../interface/runtime'; + +export const SearchRuntimes = (req: Runtime.RuntimeReq) => { + return http.post>(`/runtimes/search`, req); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 3a5507e43..ff87b9814 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -220,6 +220,7 @@ const message = { toolbox: 'Toolbox', logs: 'Log', ssl: 'Certificate', + runtime: 'Runtime', }, home: { overview: 'Overview', @@ -1233,6 +1234,11 @@ const message = { portRule: 'Port rule', ipRule: 'IP rule', }, + runtime: { + runtime: 'Runtime', + image: 'Image', + workDir: 'WorkDir', + }, }; export default { diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index bbcc88037..13f4002ab 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -223,6 +223,7 @@ const message = { settings: '面板设置', toolbox: '工具箱', logs: '面板日志', + runtime: '运行环境', }, home: { overview: '概览', @@ -1223,6 +1224,11 @@ const message = { portRule: '端口规则', ipRule: 'IP 规则', }, + runtime: { + runtime: '运行环境', + image: '镜像', + workDir: '工作目录', + }, }; export default { ...fit2cloudZhLocale, diff --git a/frontend/src/routers/modules/website.ts b/frontend/src/routers/modules/website.ts index 967aa2386..e48dbcf66 100644 --- a/frontend/src/routers/modules/website.ts +++ b/frontend/src/routers/modules/website.ts @@ -39,6 +39,15 @@ const webSiteRouter = { requiresAuth: false, }, }, + { + path: '/websites/runtime', + name: 'Runtime', + component: () => import('@/views/website/runtime/index.vue'), + meta: { + title: 'menu.runtime', + requiresAuth: false, + }, + }, ], }; diff --git a/frontend/src/views/website/runtime/index.vue b/frontend/src/views/website/runtime/index.vue new file mode 100644 index 000000000..9595b3296 --- /dev/null +++ b/frontend/src/views/website/runtime/index.vue @@ -0,0 +1,73 @@ + + +