From c403eb55b18ee8a9454f71987504677654a06c04 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:30:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=A1=E5=88=92=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E6=89=A7=E8=A1=8C=E5=A2=9E=E5=8A=A0=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=E4=B8=AD=E9=80=89=E9=A1=B9=20(#1474)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/container.go | 17 ++++++++++ backend/app/dto/cronjob.go | 3 ++ backend/app/model/cronjob.go | 1 + backend/app/service/container.go | 22 +++++++++++++ backend/app/service/cornjob.go | 1 + backend/app/service/cronjob_helper.go | 6 +++- backend/init/migration/migrations/init.go | 2 +- backend/router/ro_container.go | 1 + frontend/src/api/interface/cronjob.ts | 2 ++ frontend/src/api/modules/container.ts | 3 ++ frontend/src/lang/modules/en.ts | 2 ++ frontend/src/lang/modules/zh.ts | 2 ++ frontend/src/views/cronjob/operate/index.vue | 33 ++++++++++++++++++-- 13 files changed, 91 insertions(+), 4 deletions(-) diff --git a/backend/app/api/v1/container.go b/backend/app/api/v1/container.go index 9e96a884f..0be334b41 100644 --- a/backend/app/api/v1/container.go +++ b/backend/app/api/v1/container.go @@ -40,6 +40,23 @@ func (b *BaseApi) SearchContainer(c *gin.Context) { }) } +// @Tags Container +// @Summary List containers +// @Description 获取容器名称 +// @Accept json +// @Produce json +// @Success 200 +// @Security ApiKeyAuth +// @Router /containers/list [post] +func (b *BaseApi) ListContainer(c *gin.Context) { + list, err := containerService.List() + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, list) +} + // @Tags Container Compose // @Summary Page composes // @Description 获取编排列表分页 diff --git a/backend/app/dto/cronjob.go b/backend/app/dto/cronjob.go index d016e41bb..803560e3f 100644 --- a/backend/app/dto/cronjob.go +++ b/backend/app/dto/cronjob.go @@ -13,6 +13,7 @@ type CronjobCreate struct { Second int `json:"second" validate:"number"` Script string `json:"script"` + ContainerName string `json:"containerName"` Website string `json:"website"` ExclusionRules string `json:"exclusionRules"` DBName string `json:"dbName"` @@ -34,6 +35,7 @@ type CronjobUpdate struct { Second int `json:"second" validate:"number"` Script string `json:"script"` + ContainerName string `json:"containerName"` Website string `json:"website"` ExclusionRules string `json:"exclusionRules"` DBName string `json:"dbName"` @@ -76,6 +78,7 @@ type CronjobInfo struct { Second int `json:"second"` Script string `json:"script"` + ContainerName string `json:"containerName"` Website string `json:"website"` ExclusionRules string `json:"exclusionRules"` DBName string `json:"dbName"` diff --git a/backend/app/model/cronjob.go b/backend/app/model/cronjob.go index befacb5cb..3bc2ca30f 100644 --- a/backend/app/model/cronjob.go +++ b/backend/app/model/cronjob.go @@ -15,6 +15,7 @@ type Cronjob struct { Minute uint64 `gorm:"type:decimal" json:"minute"` Second uint64 `gorm:"type:decimal" json:"second"` + ContainerName string `gorm:"type:varchar(64)" json:"containerName"` Script string `gorm:"longtext" json:"script"` Website string `gorm:"type:varchar(64)" json:"website"` DBName string `gorm:"type:varchar(64)" json:"dbName"` diff --git a/backend/app/service/container.go b/backend/app/service/container.go index 79f43cf7a..7701c4c9c 100644 --- a/backend/app/service/container.go +++ b/backend/app/service/container.go @@ -35,6 +35,7 @@ type ContainerService struct{} type IContainerService interface { Page(req dto.PageContainer) (int64, interface{}, error) + List() ([]string, error) PageNetwork(req dto.SearchWithPage) (int64, interface{}, error) PageVolume(req dto.SearchWithPage) (int64, interface{}, error) ListVolume() ([]dto.Options, error) @@ -150,6 +151,27 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro return int64(total), backDatas, nil } +func (u *ContainerService) List() ([]string, error) { + client, err := docker.NewDockerClient() + if err != nil { + return nil, err + } + containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{All: true}) + if err != nil { + return nil, err + } + var datas []string + for _, container := range containers { + for _, name := range container.Names { + if len(name) != 0 { + datas = append(datas, strings.TrimLeft(name, "/")) + } + } + } + + return datas, nil +} + func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) { client, err := docker.NewDockerClient() if err != nil { diff --git a/backend/app/service/cornjob.go b/backend/app/service/cornjob.go index 7a6285b77..0458efbc3 100644 --- a/backend/app/service/cornjob.go +++ b/backend/app/service/cornjob.go @@ -238,6 +238,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error { upMap["name"] = req.Name upMap["spec"] = cronjob.Spec upMap["script"] = req.Script + upMap["container_name"] = req.ContainerName upMap["spec_type"] = req.SpecType upMap["week"] = req.Week upMap["day"] = req.Day diff --git a/backend/app/service/cronjob_helper.go b/backend/app/service/cronjob_helper.go index d6e4cec3b..52b0d1ee3 100644 --- a/backend/app/service/cronjob_helper.go +++ b/backend/app/service/cronjob_helper.go @@ -32,7 +32,11 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) { if len(cronjob.Script) == 0 { return } - message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script) + if len(cronjob.ContainerName) != 0 { + message, err = u.handleShell(cronjob.Type, cronjob.Name, fmt.Sprintf("docker exec %s %s", cronjob.ContainerName, cronjob.Script)) + } else { + message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script) + } u.HandleRmExpired("LOCAL", "", "", cronjob, nil) case "curl": if len(cronjob.URL) == 0 { diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index f590e1864..346e9dfc1 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -394,7 +394,7 @@ var UpdateWebsite = &gormigrate.Migration{ var AddBackupAccountDir = &gormigrate.Migration{ ID: "20200620-add-backup-dir", Migrate: func(tx *gorm.DB) error { - if err := tx.AutoMigrate(&model.BackupAccount{}); err != nil { + if err := tx.AutoMigrate(&model.BackupAccount{}, &model.Cronjob{}); err != nil { return err } return nil diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index f99fbda3b..df5fc4cbb 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -23,6 +23,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { baRouter.POST("/upgrade", baseApi.ContainerUpgrade) baRouter.POST("/info", baseApi.ContainerInfo) baRouter.POST("/search", baseApi.SearchContainer) + baRouter.POST("/list", baseApi.ListContainer) baRouter.GET("/search/log", baseApi.ContainerLogs) baRouter.GET("/limit", baseApi.LoadResouceLimit) baRouter.POST("/clean/log", baseApi.CleanContainerLog) diff --git a/frontend/src/api/interface/cronjob.ts b/frontend/src/api/interface/cronjob.ts index 08837c358..f6e6e13f7 100644 --- a/frontend/src/api/interface/cronjob.ts +++ b/frontend/src/api/interface/cronjob.ts @@ -13,6 +13,8 @@ export namespace Cronjob { second: number; script: string; + inContainer: boolean; + containerName: string; website: string; exclusionRules: string; dbName: string; diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index f1c7c89f2..dac6b8612 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -5,6 +5,9 @@ import { Container } from '../interface/container'; export const searchContainer = (params: Container.ContainerSearch) => { return http.post>(`/containers/search`, params, 400000); }; +export const listContainer = () => { + return http.post>(`/containers/list`, {}); +}; export const loadResourceLimit = () => { return http.get(`/containers/limit`); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 043d4d73f..aeee34ace 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -661,6 +661,8 @@ const message = { taskType: 'Task type', record: 'Records', shell: 'Shell script', + containerCheckBox: 'In container (no need to enter the container command)', + containerName: 'Container name', ntp: 'Time synchronization', website: 'Backup website', rulesHelper: diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index df5211b77..5aeeb0fc3 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -655,6 +655,8 @@ const message = { taskType: '任务类型', record: '报告', shell: 'Shell 脚本', + containerCheckBox: '在容器中执行(无需再输入进入容器命令)', + containerName: '容器名称', ntp: '时间同步', website: '备份网站', rulesHelper: '当存在多个压缩排除规则时,需要换行显示,例:\n*.log \n*.sql', diff --git a/frontend/src/views/cronjob/operate/index.vue b/frontend/src/views/cronjob/operate/index.vue index 35a049c55..4f70875be 100644 --- a/frontend/src/views/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/operate/index.vue @@ -21,7 +21,7 @@ - {{ dialogData.rowData!.type }} + {{ $t('cronjob.' + dialogData.rowData!.type) }} @@ -75,6 +75,21 @@ + + + {{ $t('cronjob.containerCheckBox') }} + + + + + + + + { if (dialogData.value?.rowData?.exclusionRules) { dialogData.value.rowData.exclusionRules = dialogData.value.rowData.exclusionRules.replaceAll(',', '\n'); } + if (dialogData.value?.rowData?.containerName) { + dialogData.value.rowData.inContainer = true; + } drawerVisiable.value = true; checkMysqlInstalled(); loadBackups(); loadWebsites(); + loadContainers(); }; const emit = defineEmits<{ (e: 'search'): void }>(); @@ -243,6 +263,7 @@ const handleClose = () => { const localDirID = ref(); +const containerOptions = ref(); const websiteOptions = ref(); const backupOptions = ref(); @@ -424,7 +445,12 @@ const loadBackups = async () => { const loadWebsites = async () => { const res = await GetWebsiteOptions(); - websiteOptions.value = res.data; + websiteOptions.value = res.data || []; +}; + +const loadContainers = async () => { + const res = await listContainer(); + containerOptions.value = res.data || []; }; const checkMysqlInstalled = async () => { @@ -487,6 +513,9 @@ const onSubmit = async (formEl: FormInstance | undefined) => { if (!formEl) return; formEl.validate(async (valid) => { if (!valid) return; + if (!dialogData.value.rowData.inContainer) { + dialogData.value.rowData.containerName = ''; + } if (dialogData.value?.rowData?.exclusionRules) { dialogData.value.rowData.exclusionRules = dialogData.value.rowData.exclusionRules.replaceAll('\n', ','); }