mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 16:29:17 +08:00
feat: 应用安装增加日志展示 (#5996)
This commit is contained in:
parent
82d8997217
commit
636e149b29
@ -19,6 +19,7 @@ type AppInstallCreate struct {
|
|||||||
Params map[string]interface{} `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Services map[string]string `json:"services"`
|
Services map[string]string `json:"services"`
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
AppContainerConfig
|
AppContainerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@ type FileReadByLineReq struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Latest bool `json:"latest"`
|
Latest bool `json:"latest"`
|
||||||
TaskID string `json:"taskID"`
|
TaskID string `json:"taskID"`
|
||||||
|
TaskType string `json:"taskType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileExistReq struct {
|
type FileExistReq struct {
|
||||||
|
@ -16,6 +16,8 @@ type ITaskRepo interface {
|
|||||||
Update(ctx context.Context, task *model.Task) error
|
Update(ctx context.Context, task *model.Task) error
|
||||||
|
|
||||||
WithByID(id string) DBOption
|
WithByID(id string) DBOption
|
||||||
|
WithType(taskType string) DBOption
|
||||||
|
WithResourceID(id uint) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewITaskRepo() ITaskRepo {
|
func NewITaskRepo() ITaskRepo {
|
||||||
@ -28,6 +30,18 @@ func (t TaskRepo) WithByID(id string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t TaskRepo) WithType(taskType string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("type = ?", taskType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TaskRepo) WithResourceID(id uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("resource_id = ?", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t TaskRepo) Create(ctx context.Context, task *model.Task) error {
|
func (t TaskRepo) Create(ctx context.Context, task *model.Task) error {
|
||||||
return getTx(ctx).Create(&task).Error
|
return getTx(ctx).Create(&task).Error
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
http2 "github.com/1Panel-dev/1Panel/agent/utils/http"
|
http2 "github.com/1Panel-dev/1Panel/agent/utils/http"
|
||||||
httpUtil "github.com/1Panel-dev/1Panel/agent/utils/http"
|
httpUtil "github.com/1Panel-dev/1Panel/agent/utils/http"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||||
"github.com/google/uuid"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -442,8 +441,7 @@ func (a AppService) Install(req request.AppInstallCreate) (appInstall *model.App
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
taskID := uuid.New().String()
|
installTask, err := task.NewTaskWithOps(appInstall.Name, task.TaskCreate, task.TaskScopeApp, req.TaskID, appInstall.ID)
|
||||||
installTask, err := task.NewTaskWithOps(appInstall.Name, task.TaskCreate, task.TaskScopeApp, taskID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
@ -467,11 +468,17 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case constant.TypeTask:
|
case constant.TypeTask:
|
||||||
task, err := taskRepo.GetFirst(taskRepo.WithByID(req.TaskID))
|
var opts []repo.DBOption
|
||||||
|
if req.TaskID != "" {
|
||||||
|
opts = append(opts, taskRepo.WithByID(req.TaskID))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, taskRepo.WithType(req.TaskType), taskRepo.WithResourceID(req.ID))
|
||||||
|
}
|
||||||
|
taskModel, err := taskRepo.GetFirst(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logFilePath = task.LogFile
|
logFilePath = taskModel.LogFile
|
||||||
case constant.TypeImagePull, constant.TypeImagePush, constant.TypeImageBuild, constant.TypeComposeCreate:
|
case constant.TypeImagePull, constant.TypeImagePush, constant.TypeImageBuild, constant.TypeComposeCreate:
|
||||||
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
logFilePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
|||||||
runtime *model.Runtime
|
runtime *model.Runtime
|
||||||
)
|
)
|
||||||
|
|
||||||
createTask, err := task.NewTaskWithOps(create.PrimaryDomain, task.TaskCreate, task.TaskScopeWebsite, create.TaskID)
|
createTask, err := task.NewTaskWithOps(create.PrimaryDomain, task.TaskCreate, task.TaskScopeWebsite, create.TaskID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -370,6 +370,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
|||||||
if err = websiteRepo.Create(ctx, website); err != nil {
|
if err = websiteRepo.Create(ctx, website); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
t.Task.ResourceID = website.ID
|
||||||
for i := range domains {
|
for i := range domains {
|
||||||
domains[i].WebsiteID = website.ID
|
domains[i].WebsiteID = website.ID
|
||||||
}
|
}
|
||||||
|
@ -66,20 +66,20 @@ func GetTaskName(resourceName, operate, scope string) string {
|
|||||||
return fmt.Sprintf("%s%s [%s]", i18n.GetMsgByKey(operate), i18n.GetMsgByKey(scope), resourceName)
|
return fmt.Sprintf("%s%s [%s]", i18n.GetMsgByKey(operate), i18n.GetMsgByKey(scope), resourceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTaskWithOps(resourceName, operate, scope, taskID string) (*Task, error) {
|
func NewTaskWithOps(resourceName, operate, scope, taskID string, resourceID uint) (*Task, error) {
|
||||||
return NewTask(GetTaskName(resourceName, operate, scope), scope, taskID)
|
return NewTask(GetTaskName(resourceName, operate, scope), scope, taskID, resourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChildTask(name, taskType, parentTaskID string) (*Task, error) {
|
//func NewChildTask(name, taskType, parentTaskID string) (*Task, error) {
|
||||||
task, err := NewTask(name, taskType, "")
|
// task, err := NewTask(name, taskType, "")
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
task.ParentID = parentTaskID
|
// task.ParentID = parentTaskID
|
||||||
return task, nil
|
// return task, nil
|
||||||
}
|
//}
|
||||||
|
|
||||||
func NewTask(name, taskType, taskID string) (*Task, error) {
|
func NewTask(name, taskType, taskID string, resourceID uint) (*Task, error) {
|
||||||
if taskID == "" {
|
if taskID == "" {
|
||||||
taskID = uuid.New().String()
|
taskID = uuid.New().String()
|
||||||
}
|
}
|
||||||
@ -101,6 +101,7 @@ func NewTask(name, taskType, taskID string) (*Task, error) {
|
|||||||
Type: taskType,
|
Type: taskType,
|
||||||
LogFile: logPath,
|
LogFile: logPath,
|
||||||
Status: constant.StatusRunning,
|
Status: constant.StatusRunning,
|
||||||
|
ResourceID: resourceID,
|
||||||
}
|
}
|
||||||
taskRepo := repo.NewITaskRepo()
|
taskRepo := repo.NewITaskRepo()
|
||||||
task := &Task{Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: taskModel}
|
task := &Task{Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: taskModel}
|
||||||
|
@ -276,7 +276,7 @@ var InitPHPExtensions = &gormigrate.Migration{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var AddTask = &gormigrate.Migration{
|
var AddTask = &gormigrate.Migration{
|
||||||
ID: "20240724-add-task",
|
ID: "20240801-add-task",
|
||||||
Migrate: func(tx *gorm.DB) error {
|
Migrate: func(tx *gorm.DB) error {
|
||||||
return tx.AutoMigrate(
|
return tx.AutoMigrate(
|
||||||
&model.Task{})
|
&model.Task{})
|
||||||
|
@ -94,6 +94,7 @@ export namespace App {
|
|||||||
export interface AppInstall {
|
export interface AppInstall {
|
||||||
appDetailId: number;
|
appDetailId: number;
|
||||||
params: any;
|
params: any;
|
||||||
|
taskID: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppInstallSearch extends ReqPage {
|
export interface AppInstallSearch extends ReqPage {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
:show-close="showClose"
|
:show-close="showClose"
|
||||||
:before-close="handleClose"
|
:before-close="handleClose"
|
||||||
class="task-log-dialog"
|
:width="width"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<highlightjs ref="editorRef" language="JavaScript" :autodetect="false" :code="content"></highlightjs>
|
<highlightjs ref="editorRef" language="JavaScript" :autodetect="false" :code="content"></highlightjs>
|
||||||
@ -19,6 +19,17 @@ import { ReadByLine } from '@/api/modules/files';
|
|||||||
|
|
||||||
const editorRef = ref();
|
const editorRef = ref();
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
showClose: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '30%',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const data = ref({
|
const data = ref({
|
||||||
enable: false,
|
enable: false,
|
||||||
content: '',
|
content: '',
|
||||||
@ -34,8 +45,6 @@ const scrollerElement = ref<HTMLElement | null>(null);
|
|||||||
const minPage = ref(1);
|
const minPage = ref(1);
|
||||||
const maxPage = ref(1);
|
const maxPage = ref(1);
|
||||||
const open = ref(false);
|
const open = ref(false);
|
||||||
const taskID = ref('');
|
|
||||||
const showClose = ref(false);
|
|
||||||
|
|
||||||
const readReq = reactive({
|
const readReq = reactive({
|
||||||
taskID: '',
|
taskID: '',
|
||||||
@ -43,22 +52,30 @@ const readReq = reactive({
|
|||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 500,
|
pageSize: 500,
|
||||||
latest: false,
|
latest: false,
|
||||||
|
taskType: '',
|
||||||
|
id: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const stopSignals = ['[TASK-END]'];
|
const stopSignals = ['[TASK-END]'];
|
||||||
|
|
||||||
const acceptParams = (id: string, closeShow: boolean) => {
|
const initData = () => {
|
||||||
if (closeShow) {
|
|
||||||
showClose.value = closeShow;
|
|
||||||
}
|
|
||||||
taskID.value = id;
|
|
||||||
open.value = true;
|
open.value = true;
|
||||||
initCodemirror();
|
initCodemirror();
|
||||||
init();
|
init();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openWithTaskID = (id: string) => {
|
||||||
|
readReq.taskID = id;
|
||||||
|
initData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const openWithResourceID = (taskType: string, resourceID: number) => {
|
||||||
|
readReq.taskType = taskType;
|
||||||
|
readReq.id = resourceID;
|
||||||
|
initData();
|
||||||
|
};
|
||||||
|
|
||||||
const getContent = (pre: boolean) => {
|
const getContent = (pre: boolean) => {
|
||||||
readReq.taskID = taskID.value;
|
|
||||||
if (readReq.page < 1) {
|
if (readReq.page < 1) {
|
||||||
readReq.page = 1;
|
readReq.page = 1;
|
||||||
}
|
}
|
||||||
@ -182,7 +199,7 @@ onUnmounted(() => {
|
|||||||
onCloseLog();
|
onCloseLog();
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({ acceptParams, handleClose });
|
defineExpose({ openWithResourceID, openWithTaskID });
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.task-log-dialog {
|
.task-log-dialog {
|
||||||
|
@ -106,6 +106,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</DrawerPro>
|
</DrawerPro>
|
||||||
|
<TaskLog ref="taskLogRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup name="appInstall">
|
<script lang="ts" setup name="appInstall">
|
||||||
@ -121,6 +122,8 @@ import { MsgError } from '@/utils/message';
|
|||||||
import { Container } from '@/api/interface/container';
|
import { Container } from '@/api/interface/container';
|
||||||
import { loadResourceLimit } from '@/api/modules/container';
|
import { loadResourceLimit } from '@/api/modules/container';
|
||||||
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
|
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
|
||||||
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@ -159,6 +162,7 @@ const initData = () => ({
|
|||||||
version: '',
|
version: '',
|
||||||
appID: '',
|
appID: '',
|
||||||
pullImage: true,
|
pullImage: true,
|
||||||
|
taskID: '',
|
||||||
});
|
});
|
||||||
const req = reactive(initData());
|
const req = reactive(initData());
|
||||||
const limits = ref<Container.ResourceLimit>({
|
const limits = ref<Container.ResourceLimit>({
|
||||||
@ -176,6 +180,7 @@ const handleClose = () => {
|
|||||||
};
|
};
|
||||||
const paramKey = ref(1);
|
const paramKey = ref(1);
|
||||||
const isHostMode = ref(false);
|
const isHostMode = ref(false);
|
||||||
|
const taskLogRef = ref();
|
||||||
|
|
||||||
const changeUnit = () => {
|
const changeUnit = () => {
|
||||||
if (req.memoryUnit == 'M') {
|
if (req.memoryUnit == 'M') {
|
||||||
@ -258,12 +263,20 @@ const submit = async (formEl: FormInstance | undefined) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openTaskLog = (taskID: string) => {
|
||||||
|
taskLogRef.value.openWithTaskID(taskID);
|
||||||
|
};
|
||||||
|
|
||||||
const install = () => {
|
const install = () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
const taskID = uuidv4();
|
||||||
|
console.log(taskID);
|
||||||
|
req.taskID = taskID;
|
||||||
|
console.log(req);
|
||||||
InstallApp(req)
|
InstallApp(req)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
handleClose();
|
handleClose();
|
||||||
router.push({ path: '/apps/installed' });
|
openTaskLog(taskID);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -102,7 +102,7 @@
|
|||||||
<el-card class="e-card">
|
<el-card class="e-card">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4">
|
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4">
|
||||||
<div class="icon" @click.stop="openDetail(installed.appKey)">
|
<div class="icon">
|
||||||
<el-avatar
|
<el-avatar
|
||||||
shape="square"
|
shape="square"
|
||||||
:size="66"
|
:size="66"
|
||||||
@ -313,7 +313,7 @@
|
|||||||
<PortJumpDialog ref="dialogPortJumpRef" />
|
<PortJumpDialog ref="dialogPortJumpRef" />
|
||||||
<AppIgnore ref="ignoreRef" @close="search" />
|
<AppIgnore ref="ignoreRef" @close="search" />
|
||||||
<ComposeLogs ref="composeLogRef" />
|
<ComposeLogs ref="composeLogRef" />
|
||||||
<AppDetail ref="appDetail" />
|
<TaskLog ref="taskLogRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -335,7 +335,6 @@ import AppDelete from './delete/index.vue';
|
|||||||
import AppParams from './detail/index.vue';
|
import AppParams from './detail/index.vue';
|
||||||
import AppUpgrade from './upgrade/index.vue';
|
import AppUpgrade from './upgrade/index.vue';
|
||||||
import AppIgnore from './ignore/index.vue';
|
import AppIgnore from './ignore/index.vue';
|
||||||
import AppDetail from '../detail/index.vue';
|
|
||||||
import ComposeLogs from '@/components/compose-log/index.vue';
|
import ComposeLogs from '@/components/compose-log/index.vue';
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
import Status from '@/components/status/index.vue';
|
import Status from '@/components/status/index.vue';
|
||||||
@ -343,6 +342,7 @@ import { getAge, getLanguage } from '@/utils/util';
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
import { toFolder } from '@/global/business';
|
import { toFolder } from '@/global/business';
|
||||||
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
|
|
||||||
const data = ref<any>();
|
const data = ref<any>();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
@ -369,6 +369,7 @@ const upgradeRef = ref();
|
|||||||
const ignoreRef = ref();
|
const ignoreRef = ref();
|
||||||
const dialogPortJumpRef = ref();
|
const dialogPortJumpRef = ref();
|
||||||
const composeLogRef = ref();
|
const composeLogRef = ref();
|
||||||
|
const taskLogRef = ref();
|
||||||
const tags = ref<App.Tag[]>([]);
|
const tags = ref<App.Tag[]>([]);
|
||||||
const activeTag = ref('all');
|
const activeTag = ref('all');
|
||||||
const searchReq = reactive({
|
const searchReq = reactive({
|
||||||
@ -384,7 +385,6 @@ const activeName = ref(i18n.global.t('app.installed'));
|
|||||||
const mode = ref('installed');
|
const mode = ref('installed');
|
||||||
const moreTag = ref('');
|
const moreTag = ref('');
|
||||||
const language = getLanguage();
|
const language = getLanguage();
|
||||||
const appDetail = ref();
|
|
||||||
const options = {
|
const options = {
|
||||||
modifiers: [
|
modifiers: [
|
||||||
{
|
{
|
||||||
@ -453,10 +453,6 @@ const goDashboard = async (port: any, protocol: string) => {
|
|||||||
dialogPortJumpRef.value.acceptParams({ port: port, protocol: protocol });
|
dialogPortJumpRef.value.acceptParams({ port: port, protocol: protocol });
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDetail = (appKey: string) => {
|
|
||||||
appDetail.value.acceptParams(appKey, 'detail');
|
|
||||||
};
|
|
||||||
|
|
||||||
const openOperate = (row: any, op: string) => {
|
const openOperate = (row: any, op: string) => {
|
||||||
operateReq.installId = row.id;
|
operateReq.installId = row.id;
|
||||||
operateReq.operate = op;
|
operateReq.operate = op;
|
||||||
@ -623,7 +619,13 @@ const quickJump = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openLog = (row: any) => {
|
const openLog = (row: any) => {
|
||||||
|
switch (row.status) {
|
||||||
|
case 'Installing':
|
||||||
|
taskLogRef.value.openWithResourceID('App', row.id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
composeLogRef.value.acceptParams({ compose: row.path + '/docker-compose.yml', resource: row.name });
|
composeLogRef.value.acceptParams({ compose: row.path + '/docker-compose.yml', resource: row.name });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user