mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-14 01:34:47 +08:00
feat: 计划任务脚本执行增加容器中选项 (#1474)
This commit is contained in:
parent
506d78cb00
commit
c403eb55b1
@ -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
|
// @Tags Container Compose
|
||||||
// @Summary Page composes
|
// @Summary Page composes
|
||||||
// @Description 获取编排列表分页
|
// @Description 获取编排列表分页
|
||||||
|
@ -13,6 +13,7 @@ type CronjobCreate struct {
|
|||||||
Second int `json:"second" validate:"number"`
|
Second int `json:"second" validate:"number"`
|
||||||
|
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
|
ContainerName string `json:"containerName"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
ExclusionRules string `json:"exclusionRules"`
|
ExclusionRules string `json:"exclusionRules"`
|
||||||
DBName string `json:"dbName"`
|
DBName string `json:"dbName"`
|
||||||
@ -34,6 +35,7 @@ type CronjobUpdate struct {
|
|||||||
Second int `json:"second" validate:"number"`
|
Second int `json:"second" validate:"number"`
|
||||||
|
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
|
ContainerName string `json:"containerName"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
ExclusionRules string `json:"exclusionRules"`
|
ExclusionRules string `json:"exclusionRules"`
|
||||||
DBName string `json:"dbName"`
|
DBName string `json:"dbName"`
|
||||||
@ -76,6 +78,7 @@ type CronjobInfo struct {
|
|||||||
Second int `json:"second"`
|
Second int `json:"second"`
|
||||||
|
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
|
ContainerName string `json:"containerName"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
ExclusionRules string `json:"exclusionRules"`
|
ExclusionRules string `json:"exclusionRules"`
|
||||||
DBName string `json:"dbName"`
|
DBName string `json:"dbName"`
|
||||||
|
@ -15,6 +15,7 @@ type Cronjob struct {
|
|||||||
Minute uint64 `gorm:"type:decimal" json:"minute"`
|
Minute uint64 `gorm:"type:decimal" json:"minute"`
|
||||||
Second uint64 `gorm:"type:decimal" json:"second"`
|
Second uint64 `gorm:"type:decimal" json:"second"`
|
||||||
|
|
||||||
|
ContainerName string `gorm:"type:varchar(64)" json:"containerName"`
|
||||||
Script string `gorm:"longtext" json:"script"`
|
Script string `gorm:"longtext" json:"script"`
|
||||||
Website string `gorm:"type:varchar(64)" json:"website"`
|
Website string `gorm:"type:varchar(64)" json:"website"`
|
||||||
DBName string `gorm:"type:varchar(64)" json:"dbName"`
|
DBName string `gorm:"type:varchar(64)" json:"dbName"`
|
||||||
|
@ -35,6 +35,7 @@ type ContainerService struct{}
|
|||||||
|
|
||||||
type IContainerService interface {
|
type IContainerService interface {
|
||||||
Page(req dto.PageContainer) (int64, interface{}, error)
|
Page(req dto.PageContainer) (int64, interface{}, error)
|
||||||
|
List() ([]string, error)
|
||||||
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
|
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
ListVolume() ([]dto.Options, error)
|
ListVolume() ([]dto.Options, error)
|
||||||
@ -150,6 +151,27 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
|||||||
return int64(total), backDatas, nil
|
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) {
|
func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -238,6 +238,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
|||||||
upMap["name"] = req.Name
|
upMap["name"] = req.Name
|
||||||
upMap["spec"] = cronjob.Spec
|
upMap["spec"] = cronjob.Spec
|
||||||
upMap["script"] = req.Script
|
upMap["script"] = req.Script
|
||||||
|
upMap["container_name"] = req.ContainerName
|
||||||
upMap["spec_type"] = req.SpecType
|
upMap["spec_type"] = req.SpecType
|
||||||
upMap["week"] = req.Week
|
upMap["week"] = req.Week
|
||||||
upMap["day"] = req.Day
|
upMap["day"] = req.Day
|
||||||
|
@ -32,7 +32,11 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
|||||||
if len(cronjob.Script) == 0 {
|
if len(cronjob.Script) == 0 {
|
||||||
return
|
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)
|
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
||||||
case "curl":
|
case "curl":
|
||||||
if len(cronjob.URL) == 0 {
|
if len(cronjob.URL) == 0 {
|
||||||
|
@ -394,7 +394,7 @@ var UpdateWebsite = &gormigrate.Migration{
|
|||||||
var AddBackupAccountDir = &gormigrate.Migration{
|
var AddBackupAccountDir = &gormigrate.Migration{
|
||||||
ID: "20200620-add-backup-dir",
|
ID: "20200620-add-backup-dir",
|
||||||
Migrate: func(tx *gorm.DB) error {
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -23,6 +23,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
|
|||||||
baRouter.POST("/upgrade", baseApi.ContainerUpgrade)
|
baRouter.POST("/upgrade", baseApi.ContainerUpgrade)
|
||||||
baRouter.POST("/info", baseApi.ContainerInfo)
|
baRouter.POST("/info", baseApi.ContainerInfo)
|
||||||
baRouter.POST("/search", baseApi.SearchContainer)
|
baRouter.POST("/search", baseApi.SearchContainer)
|
||||||
|
baRouter.POST("/list", baseApi.ListContainer)
|
||||||
baRouter.GET("/search/log", baseApi.ContainerLogs)
|
baRouter.GET("/search/log", baseApi.ContainerLogs)
|
||||||
baRouter.GET("/limit", baseApi.LoadResouceLimit)
|
baRouter.GET("/limit", baseApi.LoadResouceLimit)
|
||||||
baRouter.POST("/clean/log", baseApi.CleanContainerLog)
|
baRouter.POST("/clean/log", baseApi.CleanContainerLog)
|
||||||
|
@ -13,6 +13,8 @@ export namespace Cronjob {
|
|||||||
second: number;
|
second: number;
|
||||||
|
|
||||||
script: string;
|
script: string;
|
||||||
|
inContainer: boolean;
|
||||||
|
containerName: string;
|
||||||
website: string;
|
website: string;
|
||||||
exclusionRules: string;
|
exclusionRules: string;
|
||||||
dbName: string;
|
dbName: string;
|
||||||
|
@ -5,6 +5,9 @@ import { Container } from '../interface/container';
|
|||||||
export const searchContainer = (params: Container.ContainerSearch) => {
|
export const searchContainer = (params: Container.ContainerSearch) => {
|
||||||
return http.post<ResPage<Container.ContainerInfo>>(`/containers/search`, params, 400000);
|
return http.post<ResPage<Container.ContainerInfo>>(`/containers/search`, params, 400000);
|
||||||
};
|
};
|
||||||
|
export const listContainer = () => {
|
||||||
|
return http.post<Array<string>>(`/containers/list`, {});
|
||||||
|
};
|
||||||
export const loadResourceLimit = () => {
|
export const loadResourceLimit = () => {
|
||||||
return http.get<Container.ResourceLimit>(`/containers/limit`);
|
return http.get<Container.ResourceLimit>(`/containers/limit`);
|
||||||
};
|
};
|
||||||
|
@ -661,6 +661,8 @@ const message = {
|
|||||||
taskType: 'Task type',
|
taskType: 'Task type',
|
||||||
record: 'Records',
|
record: 'Records',
|
||||||
shell: 'Shell script',
|
shell: 'Shell script',
|
||||||
|
containerCheckBox: 'In container (no need to enter the container command)',
|
||||||
|
containerName: 'Container name',
|
||||||
ntp: 'Time synchronization',
|
ntp: 'Time synchronization',
|
||||||
website: 'Backup website',
|
website: 'Backup website',
|
||||||
rulesHelper:
|
rulesHelper:
|
||||||
|
@ -655,6 +655,8 @@ const message = {
|
|||||||
taskType: '任务类型',
|
taskType: '任务类型',
|
||||||
record: '报告',
|
record: '报告',
|
||||||
shell: 'Shell 脚本',
|
shell: 'Shell 脚本',
|
||||||
|
containerCheckBox: '在容器中执行(无需再输入进入容器命令)',
|
||||||
|
containerName: '容器名称',
|
||||||
ntp: '时间同步',
|
ntp: '时间同步',
|
||||||
website: '备份网站',
|
website: '备份网站',
|
||||||
rulesHelper: '当存在多个压缩排除规则时,需要换行显示,例:\n*.log \n*.sql',
|
rulesHelper: '当存在多个压缩排除规则时,需要换行显示,例:\n*.log \n*.sql',
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<el-option value="ntp" :label="$t('cronjob.ntp')" />
|
<el-option value="ntp" :label="$t('cronjob.ntp')" />
|
||||||
<el-option value="cutWebsiteLog" :label="$t('cronjob.cutWebsiteLog')" />
|
<el-option value="cutWebsiteLog" :label="$t('cronjob.cutWebsiteLog')" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-tag v-else>{{ dialogData.rowData!.type }}</el-tag>
|
<el-tag v-else>{{ $t('cronjob.' + dialogData.rowData!.type) }}</el-tag>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="$t('cronjob.taskName')" prop="name">
|
<el-form-item :label="$t('cronjob.taskName')" prop="name">
|
||||||
@ -75,6 +75,21 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="hasScript()">
|
||||||
|
<el-checkbox v-model="dialogData.rowData!.inContainer">
|
||||||
|
{{ $t('cronjob.containerCheckBox') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="hasScript() && dialogData.rowData!.inContainer"
|
||||||
|
:label="$t('cronjob.containerName')"
|
||||||
|
prop="containerName"
|
||||||
|
>
|
||||||
|
<el-select class="selectClass" v-model="dialogData.rowData!.containerName">
|
||||||
|
<el-option v-for="item in containerOptions" :key="item" :value="item" :label="item" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
|
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
|
||||||
<el-input
|
<el-input
|
||||||
clearable
|
clearable
|
||||||
@ -205,6 +220,7 @@ import { GetWebsiteOptions } from '@/api/modules/website';
|
|||||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { listContainer } from '@/api/modules/container';
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
interface DialogProps {
|
interface DialogProps {
|
||||||
@ -226,10 +242,14 @@ const acceptParams = (params: DialogProps): void => {
|
|||||||
if (dialogData.value?.rowData?.exclusionRules) {
|
if (dialogData.value?.rowData?.exclusionRules) {
|
||||||
dialogData.value.rowData.exclusionRules = dialogData.value.rowData.exclusionRules.replaceAll(',', '\n');
|
dialogData.value.rowData.exclusionRules = dialogData.value.rowData.exclusionRules.replaceAll(',', '\n');
|
||||||
}
|
}
|
||||||
|
if (dialogData.value?.rowData?.containerName) {
|
||||||
|
dialogData.value.rowData.inContainer = true;
|
||||||
|
}
|
||||||
drawerVisiable.value = true;
|
drawerVisiable.value = true;
|
||||||
checkMysqlInstalled();
|
checkMysqlInstalled();
|
||||||
loadBackups();
|
loadBackups();
|
||||||
loadWebsites();
|
loadWebsites();
|
||||||
|
loadContainers();
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
@ -243,6 +263,7 @@ const handleClose = () => {
|
|||||||
|
|
||||||
const localDirID = ref();
|
const localDirID = ref();
|
||||||
|
|
||||||
|
const containerOptions = ref();
|
||||||
const websiteOptions = ref();
|
const websiteOptions = ref();
|
||||||
const backupOptions = ref();
|
const backupOptions = ref();
|
||||||
|
|
||||||
@ -424,7 +445,12 @@ const loadBackups = async () => {
|
|||||||
|
|
||||||
const loadWebsites = async () => {
|
const loadWebsites = async () => {
|
||||||
const res = await GetWebsiteOptions();
|
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 () => {
|
const checkMysqlInstalled = async () => {
|
||||||
@ -487,6 +513,9 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
|||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
|
if (!dialogData.value.rowData.inContainer) {
|
||||||
|
dialogData.value.rowData.containerName = '';
|
||||||
|
}
|
||||||
if (dialogData.value?.rowData?.exclusionRules) {
|
if (dialogData.value?.rowData?.exclusionRules) {
|
||||||
dialogData.value.rowData.exclusionRules = dialogData.value.rowData.exclusionRules.replaceAll('\n', ',');
|
dialogData.value.rowData.exclusionRules = dialogData.value.rowData.exclusionRules.replaceAll('\n', ',');
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user