From 22d9bdacf68aba4f5843f3cbe1d8bd9f15ea64d0 Mon Sep 17 00:00:00 2001 From: zhengkunwang223 Date: Fri, 31 Mar 2023 14:02:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20runtime=20=E5=A2=9E=E5=8A=A0=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/helper/helper.go | 9 +++ backend/app/api/v1/runtime.go | 25 +++++++- backend/app/dto/request/runtime.go | 4 ++ backend/app/repo/runtime.go | 9 +++ backend/app/service/runtime.go | 45 ++++++++++---- backend/app/service/runtime_utils.go | 18 ++++++ backend/constant/errs.go | 8 +-- backend/constant/runtime.go | 10 ++-- backend/i18n/lang/en.yaml | 3 +- backend/i18n/lang/zh.yaml | 3 +- backend/router/ro_runtime.go | 1 + frontend/src/api/interface/runtime.ts | 4 ++ frontend/src/api/modules/runtime.ts | 4 ++ frontend/src/lang/modules/en.ts | 13 ++++- frontend/src/lang/modules/zh.ts | 5 +- frontend/src/utils/util.ts | 4 ++ .../views/website/runtime/create/index.vue | 13 ++++- frontend/src/views/website/runtime/index.vue | 58 +++++++++++++++++-- .../src/views/website/runtime/param/index.vue | 24 ++++---- 19 files changed, 217 insertions(+), 43 deletions(-) diff --git a/backend/app/api/v1/helper/helper.go b/backend/app/api/v1/helper/helper.go index 1afe5961044c..831d516e63d7 100644 --- a/backend/app/api/v1/helper/helper.go +++ b/backend/app/api/v1/helper/helper.go @@ -83,6 +83,15 @@ func SuccessWithData(ctx *gin.Context, data interface{}) { ctx.Abort() } +func SuccessWithOutData(ctx *gin.Context) { + res := dto.Response{ + Code: constant.CodeSuccess, + Message: "success", + } + ctx.JSON(http.StatusOK, res) + ctx.Abort() +} + func SuccessWithMsg(ctx *gin.Context, msg string) { res := dto.Response{ Code: constant.CodeSuccess, diff --git a/backend/app/api/v1/runtime.go b/backend/app/api/v1/runtime.go index 863582e7fdf9..19c285205553 100644 --- a/backend/app/api/v1/runtime.go +++ b/backend/app/api/v1/runtime.go @@ -52,5 +52,28 @@ func (b *BaseApi) CreateRuntime(c *gin.Context) { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return } - helper.SuccessWithData(c, nil) + helper.SuccessWithOutData(c) +} + +// @Tags Website +// @Summary Delete runtime +// @Description 删除运行环境 +// @Accept json +// @Param request body request.RuntimeDelete true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /runtimes/del [post] +// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除网站 [name]","formatEN":"Delete website [name]"} +func (b *BaseApi) DeleteRuntime(c *gin.Context) { + var req request.RuntimeDelete + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + err := runtimeService.Delete(req.ID) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithOutData(c) } diff --git a/backend/app/dto/request/runtime.go b/backend/app/dto/request/runtime.go index 6ed5f6dfd5ea..fa9d4522796d 100644 --- a/backend/app/dto/request/runtime.go +++ b/backend/app/dto/request/runtime.go @@ -17,3 +17,7 @@ type RuntimeCreate struct { Type string `json:"type"` Version string `json:"version"` } + +type RuntimeDelete struct { + ID uint `json:"Id"` +} diff --git a/backend/app/repo/runtime.go b/backend/app/repo/runtime.go index cda8f6b5c2d5..eadf2f535936 100644 --- a/backend/app/repo/runtime.go +++ b/backend/app/repo/runtime.go @@ -13,6 +13,7 @@ type IRuntimeRepo interface { Create(ctx context.Context, runtime *model.Runtime) error Save(runtime *model.Runtime) error DeleteBy(opts ...DBOption) error + GetFirst(opts ...DBOption) (*model.Runtime, error) } func NewIRunTimeRepo() IRuntimeRepo { @@ -40,3 +41,11 @@ func (r *RuntimeRepo) Save(runtime *model.Runtime) error { func (r *RuntimeRepo) DeleteBy(opts ...DBOption) error { return getDb(opts...).Delete(&model.Runtime{}).Error } + +func (r *RuntimeRepo) GetFirst(opts ...DBOption) (*model.Runtime, error) { + var runtime model.Runtime + if err := getDb(opts...).First(&runtime).Error; err != nil { + return nil, err + } + return &runtime, nil +} diff --git a/backend/app/service/runtime.go b/backend/app/service/runtime.go index e79f797f5c2b..6d28f09a92b1 100644 --- a/backend/app/service/runtime.go +++ b/backend/app/service/runtime.go @@ -2,6 +2,7 @@ package service import ( "context" + "fmt" "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/model" @@ -12,6 +13,8 @@ import ( "github.com/1Panel-dev/1Panel/backend/utils/files" "github.com/subosito/gotenv" "path" + "path/filepath" + "time" ) type RuntimeService struct { @@ -20,6 +23,7 @@ type RuntimeService struct { type IRuntimeService interface { Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) Create(create request.RuntimeCreate) error + Delete(id uint) error } func NewRuntimeService() IRuntimeService { @@ -50,21 +54,25 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) error { if !fileOp.Stat(buildDir) { return buserr.New(constant.ErrDirNotFound) } - tempDir := path.Join(constant.RuntimeDir, app.Key) + runtimeDir := path.Join(constant.RuntimeDir, create.Type) + tempDir := filepath.Join(runtimeDir, fmt.Sprintf("%d", time.Now().UnixNano())) if err := fileOp.CopyDir(buildDir, tempDir); err != nil { return err } oldDir := path.Join(tempDir, "build") - newNameDir := path.Join(tempDir, create.Name) - defer func(defErr *error) { - if defErr != nil { + newNameDir := path.Join(runtimeDir, create.Name) + defer func() { + if err != nil { _ = fileOp.DeleteDir(newNameDir) } - }(&err) + }() if oldDir != newNameDir { if err := fileOp.Rename(oldDir, newNameDir); err != nil { return err } + if err := fileOp.DeleteDir(tempDir); err != nil { + return err + } } composeFile, err := fileOp.GetContent(path.Join(newNameDir, "docker-compose.yml")) if err != nil { @@ -95,9 +103,6 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) error { return err } composeService.SetProject(project) - if err := composeService.ComposeBuild(); err != nil { - return err - } runtime := &model.Runtime{ Name: create.Name, DockerCompose: string(composeFile), @@ -106,9 +111,14 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) error { Type: create.Type, Image: create.Image, Resource: create.Resource, - Status: constant.RuntimeNormal, + Status: constant.RuntimeBuildIng, + Version: create.Version, } - return runtimeRepo.Create(context.Background(), runtime) + if err := runtimeRepo.Create(context.Background(), runtime); err != nil { + return err + } + go buildRuntime(runtime, composeService) + return nil } func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) { @@ -130,3 +140,18 @@ func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.Runt } return total, res, nil } + +func (r *RuntimeService) Delete(id uint) error { + runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id)) + if err != nil { + return err + } + //TODO 校验网站关联 + if runtime.Resource == constant.ResourceAppstore { + runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name) + if err := files.NewFileOp().DeleteDir(runtimeDir); err != nil { + return err + } + } + return runtimeRepo.DeleteBy(commonRepo.WithByID(id)) +} diff --git a/backend/app/service/runtime_utils.go b/backend/app/service/runtime_utils.go index 6d43c3366ca3..e96619b84388 100644 --- a/backend/app/service/runtime_utils.go +++ b/backend/app/service/runtime_utils.go @@ -1 +1,19 @@ package service + +import ( + "github.com/1Panel-dev/1Panel/backend/app/model" + "github.com/1Panel-dev/1Panel/backend/buserr" + "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/1Panel-dev/1Panel/backend/utils/docker" +) + +func buildRuntime(runtime *model.Runtime, service *docker.ComposeService) { + err := service.ComposeBuild() + if err != nil { + runtime.Status = constant.RuntimeError + runtime.Message = buserr.New(constant.ErrImageBuildErr).Error() + ":" + err.Error() + } else { + runtime.Status = constant.RuntimeNormal + } + _ = runtimeRepo.Save(runtime) +} diff --git a/backend/constant/errs.go b/backend/constant/errs.go index 4734c6b6be61..00ee9acac8f1 100644 --- a/backend/constant/errs.go +++ b/backend/constant/errs.go @@ -104,9 +104,9 @@ var ( ErrObjectInUsed = "ErrObjectInUsed" ) -//runtime - +// runtime var ( - ErrDirNotFound = "ErrDirNotFound" - ErrFileNotExist = "ErrFileNotExist" + ErrDirNotFound = "ErrDirNotFound" + ErrFileNotExist = "ErrFileNotExist" + ErrImageBuildErr = "ErrImageBuildErr" ) diff --git a/backend/constant/runtime.go b/backend/constant/runtime.go index 1363a0db715a..0f1fec67aab3 100644 --- a/backend/constant/runtime.go +++ b/backend/constant/runtime.go @@ -1,10 +1,10 @@ package constant const ( - ResourceLocal = "Local" - ResourceAppstore = "Appstore" + ResourceLocal = "local" + ResourceAppstore = "appstore" - RuntimeNormal = "Normal" - RuntimeBuildSuccess = "BuildSuccess" - RuntimeBuildFailed = "BuildFailed" + RuntimeNormal = "normal" + RuntimeError = "error" + RuntimeBuildIng = "building" ) diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml index 68d098ec0784..e6ffe7266f90 100644 --- a/backend/i18n/lang/en.yaml +++ b/backend/i18n/lang/en.yaml @@ -62,4 +62,5 @@ ErrObjectInUsed: "This object is in use and cannot be deleted" #runtime ErrDirNotFound: "The build folder does not exist! Please check file integrity!" -ErrFileNotExist: "{{ .detail }} file does not exist! Please check source file integrity!" \ No newline at end of file +ErrFileNotExist: "{{ .detail }} file does not exist! Please check source file integrity!" +ErrImageBuildErr: "Image build failed" \ No newline at end of file diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml index de2f02f1c6ea..82de943ad093 100644 --- a/backend/i18n/lang/zh.yaml +++ b/backend/i18n/lang/zh.yaml @@ -62,4 +62,5 @@ ErrObjectInUsed: "该对象正被使用,无法删除" #runtime ErrDirNotFound: "build 文件夹不存在!请检查文件完整性!" -ErrFileNotExist: "{{ .detail }} 文件不存在!请检查源文件完整性!" \ No newline at end of file +ErrFileNotExist: "{{ .detail }} 文件不存在!请检查源文件完整性!" +ErrImageBuildErr: "镜像 build 失败" \ No newline at end of file diff --git a/backend/router/ro_runtime.go b/backend/router/ro_runtime.go index d8755c36eac9..969b290f0560 100644 --- a/backend/router/ro_runtime.go +++ b/backend/router/ro_runtime.go @@ -17,5 +17,6 @@ func (r *RuntimeRouter) InitRuntimeRouter(Router *gin.RouterGroup) { { groupRouter.POST("/search", baseApi.SearchRuntimes) groupRouter.POST("", baseApi.CreateRuntime) + groupRouter.POST("/del", baseApi.DeleteRuntime) } } diff --git a/frontend/src/api/interface/runtime.ts b/frontend/src/api/interface/runtime.ts index bdaa52008a54..ada47e7b8299 100644 --- a/frontend/src/api/interface/runtime.ts +++ b/frontend/src/api/interface/runtime.ts @@ -29,4 +29,8 @@ export namespace Runtime { appId?: number; version?: string; } + + export interface RuntimeDelete { + id: number; + } } diff --git a/frontend/src/api/modules/runtime.ts b/frontend/src/api/modules/runtime.ts index 076cbadb451c..813bb8955cb3 100644 --- a/frontend/src/api/modules/runtime.ts +++ b/frontend/src/api/modules/runtime.ts @@ -9,3 +9,7 @@ export const SearchRuntimes = (req: Runtime.RuntimeReq) => { export const CreateRuntime = (req: Runtime.RuntimeCreate) => { return http.post(`/runtimes`, req); }; + +export const DeleteRuntime = (req: Runtime.RuntimeDelete) => { + return http.post(`/runtimes/del`, req); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index ff87b98148fa..c38c10c573df 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -199,6 +199,8 @@ const message = { exited: 'Exited', enabled: 'Enabled', disabled: 'Disabled', + normal: 'Normal', + building: 'Building', }, }, menu: { @@ -1237,7 +1239,16 @@ const message = { runtime: { runtime: 'Runtime', image: 'Image', - workDir: 'WorkDir', + workDir: 'working directory', + create: 'Create runtime', + name: 'Name', + resource: 'Source', + appstore: 'App Store', + local: 'Local', + app: 'Application', + localHelper: 'The local operating environment needs to be installed by itself', + version: 'Version', + status: 'Status', }, }; diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 0c1192b9a531..95260cf77f99 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -203,6 +203,8 @@ const message = { installing: '安装中', enabled: '已启用', disabled: '已停止', + normal: '正常', + building: '制作镜像中', }, }, menu: { @@ -1231,11 +1233,12 @@ const message = { create: '创建运行环境', name: '名称', resource: '来源', - appStore: '应用商店', + appstore: '应用商店', local: '本地', app: '应用', localHelper: '本地运行环境需要自行安装', version: '版本', + status: '状态', }, }; export default { diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index d66935d085c2..7f084482ea4e 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -226,3 +226,7 @@ export function isJson(str: string) { return false; } } + +export function toLowerCase(str: string) { + return str.toLowerCase(); +} diff --git a/frontend/src/views/website/runtime/create/index.vue b/frontend/src/views/website/runtime/create/index.vue index 635f3c6f2806..d0a0096456d5 100644 --- a/frontend/src/views/website/runtime/create/index.vue +++ b/frontend/src/views/website/runtime/create/index.vue @@ -22,7 +22,7 @@ @change="changeResource(runtimeCreate.resource)" > - {{ $t('runtime.appStore') }} + {{ $t('runtime.appstore') }} {{ $t('runtime.local') }} @@ -135,6 +135,7 @@ const changeResource = (resource: string) => { runtimeCreate.value.image = ''; } else { runtimeCreate.value.version = ''; + searchApp(); } }; @@ -179,7 +180,15 @@ const submit = async (formEl: FormInstance | undefined) => { }); }; -const acceptParams = async () => { +const acceptParams = async (type: string) => { + runtimeCreate.value = { + name: '', + appDetailId: undefined, + image: '', + params: {}, + type: type, + resource: 'AppStore', + }; searchApp(); open.value = true; }; diff --git a/frontend/src/views/website/runtime/index.vue b/frontend/src/views/website/runtime/index.vue index 2bb80a56ff1d..e369ef68a524 100644 --- a/frontend/src/views/website/runtime/index.vue +++ b/frontend/src/views/website/runtime/index.vue @@ -21,30 +21,64 @@ + + + + - + + + + - +