feat: 逃生通道

This commit is contained in:
feng626
2022-01-10 19:03:57 +08:00
committed by Jiangjie.Bai
parent aa94c1792c
commit 03031e94c1
12 changed files with 716 additions and 0 deletions

View File

@@ -1326,6 +1326,13 @@
"TimerPeriod": "定时执行周期",
"Username": "用户名"
},
"EscapeRoutePlan": {
"EscapeRoutePlan": "逃生通道",
"EscapeRoutePlanCreate": "创建逃生通道",
"EscapeRoutePlanUpdate": "更新逃生通道",
"ExecutionDetail": "执行详情",
"MailRecipient": "邮件收件人"
},
"Cloud": {
"ServerAccountKey": "服务账号密钥",
"IPNetworkSegment": "IP网段",

View File

@@ -161,5 +161,54 @@ export default [
hidden: true
}
]
},
{
path: 'escape',
component: empty,
redirect: '',
meta: { title: i18n.t('xpack.EscapeRoutePlan.EscapeRoutePlan') },
children: [
{
path: '',
component: () => import('@/views/accounts/EscapeRoutePlan/index.vue'),
name: 'EscapeRoutePlanIndex',
meta: { title: i18n.t('xpack.EscapeRoutePlan.EscapeRoutePlan'), activeMenu: '/accounts/escape' }
},
{
path: '',
component: () => import('@/views/accounts/EscapeRoutePlan/EscapeRoutePlanList.vue'),
name: 'EscapeRoutePlanList',
meta: { title: i18n.t('xpack.EscapeRoutePlan.EscapeRoutePlan'), activeMenu: '/accounts/escape' },
hidden: true
},
{
path: 'create',
component: () => import('@/views/accounts/EscapeRoutePlan/EscapeRoutePlanCreateUpdate.vue'),
name: 'EscapeRoutePlanCreate',
meta: { title: i18n.t('xpack.EscapeRoutePlan.EscapeRoutePlanCreate'), activeMenu: '/accounts/escape', action: 'create' },
hidden: true
},
{
path: ':id/update',
component: () => import('@/views/accounts/EscapeRoutePlan/EscapeRoutePlanCreateUpdate.vue'),
name: 'EscapeRoutePlanUpdate',
meta: { title: i18n.t('xpack.EscapeRoutePlan.EscapeRoutePlanUpdate'), activeMenu: '/accounts/escape', action: 'update' },
hidden: true
},
{
path: ':id',
component: () => import('@/views/accounts/EscapeRoutePlan/EscapeRoutePlanDetail/index.vue'),
name: 'EscapeRoutePlanDetail',
meta: { title: i18n.t('xpack.EscapeRoutePlan.EscapeRoutePlan'), activeMenu: '/accounts/escape' },
hidden: true
},
{
path: 'plan-execution/:id',
component: () => import('@/views/accounts/EscapeRoutePlan/EscapeRoutePlanDetail/EscapeRoutePlanExecution/EscapeRoutePlanExecutionDetail/index.vue'),
name: 'EscapeRoutePlanExecutionDetail',
meta: { title: i18n.t('xpack.EscapeRoutePlan.ExecutionDetail'), activeMenu: '/accounts/escape' },
hidden: true
}
]
}
]

View File

@@ -0,0 +1,48 @@
<template>
<GenericCreateUpdatePage v-bind="$data" />
</template>
<script>
import { GenericCreateUpdatePage } from '@/layout/components'
import getFields from '@/views/accounts/EscapeRoutePlan/fields'
export default {
name: 'EscapeRoutePlanreateUpdate',
components: {
GenericCreateUpdatePage
},
data() {
const fields = getFields.bind(this)()
return {
url: '/api/v1/assets/escape/',
fields: [
[this.$t('common.Basic'), ['name']],
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
[this.$t('common.Other'), ['recipients', 'comment']]
],
initial: {
is_periodic: true,
interval: 24
},
fieldsMeta: {
is_periodic: fields.is_periodic,
crontab: fields.crontab,
interval: fields.interval,
recipients: fields.recipients
},
createSuccessNextRoute: { name: 'EscapeRoutePlanIndex' },
updateSuccessNextRoute: { name: 'EscapeRoutePlanIndex' },
cleanFormValue(data) {
if (data['interval'] === '') {
delete data['interval']
}
return data
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,52 @@
<template>
<el-row :gutter="20">
<el-col :md="14" :sm="24">
<DetailCard :items="detailItems" />
</el-col>
</el-row>
</template>
<script>
import DetailCard from '@/components/DetailCard'
import { toSafeLocalDateStr } from '@/utils/common'
export default {
name: 'EscapeRoutePlanExecutionInfo',
components: {
DetailCard
},
props: {
object: {
type: Object,
default: () => ({})
}
},
data() {
return {
}
},
computed: {
detailItems() {
return [
{
key: this.$t('xpack.ChangeAuthPlan.TimeDelta'),
value: this.object.timedelta.toFixed(2) + 's'
},
{
key: this.$t('xpack.ChangeAuthPlan.DateStart'),
value: toSafeLocalDateStr(this.object.date_start)
},
{
key: this.$t('xpack.ChangeAuthPlan.MailRecipient'),
value: this.object.recipients ? this.object.recipients.map(
i => `${i[0]}` + `${i[1] ? ': ' + this.$t('xpack.ChangeAuthPlan.ContainAttachment') : ''}`).join(', ') : ''
}
]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,79 @@
<template>
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import GenericListTable from '@/layout/components/GenericListTable'
export default {
name: 'EscapeRoutePlanExecutionTaskList',
components: {
GenericListTable
},
props: {
object: {
type: Object,
required: true,
default: () => ({})
}
},
data() {
return {
tableConfig: {
url: `/api/v1/xpack/assets/escape-execution-subtask/?plan_execution_id=${this.object.id}`,
columns: [
'is_success', 'reason', 'timedelta', 'date_start', 'actions'
],
columnsMeta: {
is_success: {
label: this.$t('xpack.ChangeAuthPlan.Success')
},
timedelta: {
label: this.$t('xpack.ChangeAuthPlan.TimeDelta'),
width: '90px',
formatter: function(row) {
return row.timedelta.toFixed(2) + 's'
}
},
actions: {
formatterArgs: {
hasDelete: false,
hasUpdate: false,
hasClone: false,
extraActions: [
{
name: 'retry',
type: 'info',
title: this.$t('xpack.ChangeAuthPlan.Retry'),
callback: function({ row, tableData }) {
this.$axios.put(
`/api/v1/assets/escape-execution-subtask/${row.id}/`,
).then(res => {
window.open(`/#/ops/celery/task/${res.task}/log/`, '_blank', 'toolbar=yes, width=900, height=600')
})
}.bind(this)
}
]
}
}
}
},
headerActions: {
hasSearch: true,
hasRefresh: true,
hasLeftActions: true,
hasRightActions: true,
hasExport: false,
hasImport: false,
hasCreate: false,
hasBulkDelete: false,
hasBulkUpdate: false
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,54 @@
<template>
<GenericDetailPage :object.sync="execution" :active-menu.sync="config.activeMenu" v-bind="config" v-on="$listeners">
<keep-alive>
<component :is="config.activeMenu" :object="execution" />
</keep-alive>
</GenericDetailPage>
</template>
<script>
import { GenericDetailPage } from '@/layout/components'
import EscapeRoutePlanExecutionInfo from './EscapeRoutePlanExecutionInfo'
import EscapeRoutePlanExecutionTaskList from './EscapeRoutePlanExecutionTaskList'
export default {
components: {
GenericDetailPage,
EscapeRoutePlanExecutionInfo,
EscapeRoutePlanExecutionTaskList
},
data() {
return {
execution: { id: '' },
config: {
activeMenu: 'EscapeRoutePlanExecutionInfo',
actions: {
hasUpdate: false,
hasDelete: false
},
submenu: [
{
title: this.$t('common.BasicInfo'),
name: 'EscapeRoutePlanExecutionInfo'
},
{
title: this.$t('xpack.ChangeAuthPlan.TaskList'),
name: 'EscapeRoutePlanExecutionTaskList'
}
],
getTitle: this.getExecutionTitle
}
}
},
methods: {
getExecutionTitle() {
return `${this.$route.meta.title}: ${this.execution.id}`
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,102 @@
<template>
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import GenericListTable from '@/layout/components/GenericListTable'
export default {
name: 'EscapeRoutePlanExecution',
components: {
GenericListTable
},
props: {
object: {
type: Object,
required: true,
default: () => ({})
}
},
data() {
return {
tableConfig: {
url: `/api/v1/assets/escape-execution/?plan_id=${this.object.id}`,
columns: [
'username', 'result_summary', 'timedelta', 'trigger_display', 'date_start', 'actions'
],
columnsMeta: {
result_summary: {
label: this.$t('xpack.ChangeAuthPlan.Result'),
width: '80px',
showOverflowTooltip: true,
formatter: function(row) {
const summary = <div>
<span class='text-primary'>{row.result_summary.succeed}</span>/
<span class='text-danger'>{row.result_summary.failed}</span>/
<span>{row.result_summary.total}</span>
</div>
return summary
}
},
password_strategy_display: {
label: this.$t('xpack.ChangeAuthPlan.PasswordStrategy'),
width: '220px',
showOverflowTooltip: true
},
timedelta: {
label: this.$t('xpack.ChangeAuthPlan.TimeDelta'),
width: '90px',
formatter: function(row) {
return row.timedelta.toFixed(2) + 's'
}
},
date_start: {
showOverflowTooltip: true
},
actions: {
formatterArgs: {
hasDelete: false,
hasUpdate: false,
hasClone: false,
extraActions: [
{
name: 'log',
type: 'primary',
title: this.$t('xpack.ChangeAuthPlan.Log'),
callback: function({ row }) {
window.open(`/#/ops/celery/task/${row.id}/log/`, '_blank', 'toolbar=yes, width=900, height=600')
}
},
{
name: 'detail',
title: this.$t('xpack.ChangeAuthPlan.Detail'),
type: 'info',
callback: function({ row }) {
return this.$router.push({ name: 'EscapeRoutePlanExecutionDetail', params: { id: row.id }})
}
}
]
}
}
}
},
headerActions: {
hasSearch: true,
hasRefresh: true,
hasRightActions: true,
hasLeftActions: true,
hasMoreActions: false,
hasExport: false,
hasImport: false,
hasCreate: false,
hasBulkDelete: false,
hasBulkUpdate: false
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,94 @@
<template>
<el-row :gutter="20">
<el-col :md="14" :sm="24">
<DetailCard :items="detailItems" />
</el-col>
<el-col :md="10" :sm="24">
<QuickActions :actions="quickActions" type="primary" />
</el-col>
</el-row>
</template>
<script>
import { DetailCard, QuickActions } from '@/components'
import { toSafeLocalDateStr } from '@/utils/common'
export default {
name: 'EscapeRoutePlanInfo',
components: {
DetailCard,
QuickActions
},
props: {
object: {
type: Object,
required: true,
default: () => ({})
}
},
data() {
return {
url: '/api/v1/assets/escape/',
quickActions: [
{
title: this.$t('xpack.ChangeAuthPlan.ManualExecutePlan'),
attrs: {
type: 'primary',
label: this.$t('xpack.ChangeAuthPlan.Execute')
},
callbacks: {
click: function() {
this.$axios.post(
`/api/v1/assets/escape-execution/`,
{ plan: this.object.id }
).then(res => {
window.open(`/#/ops/celery/task/${res.task}/log/`, '_blank', 'toolbar=yes, width=900, height=600')
})
}.bind(this)
}
}
]
}
},
computed: {
detailItems() {
return [
{
key: this.$t('xpack.ChangeAuthPlan.Name'),
value: this.object.name
},
{
key: this.$t('xpack.ChangeAuthPlan.RegularlyPerform'),
value: this.object.crontab,
formatter: (item, val) => {
return <span>{this.object.is_periodic ? val : ''}</span>
}
},
{
key: this.$t('xpack.ChangeAuthPlan.CyclePerform'),
value: this.object.interval,
formatter: (item, val) => {
return <span>{this.object.is_periodic ? val : ''}</span>
}
},
{
key: this.$t('xpack.ChangeAuthPlan.DateJoined'),
value: toSafeLocalDateStr(this.object.date_created)
},
{
key: this.$t('xpack.ChangeAuthPlan.DateUpdated'),
value: toSafeLocalDateStr(this.object.date_updated)
},
{
key: this.$t('common.Comment'),
value: this.object.comment
}
]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,43 @@
<template>
<GenericDetailPage :object.sync="plan" :active-menu.sync="config.activeMenu" v-bind="config">
<keep-alive>
<component :is="config.activeMenu" :object="plan" />
</keep-alive>
</GenericDetailPage>
</template>
<script>
import { GenericDetailPage } from '@/layout/components'
import EscapeRoutePlanInfo from './EscapeRoutePlanInfo'
import EscapeRoutePlanExecutionList from './EscapeRoutePlanExecution/EscapeRoutePlanExecutionList'
export default {
components: {
GenericDetailPage,
EscapeRoutePlanInfo,
EscapeRoutePlanExecutionList
},
data() {
return {
plan: { name: '', comment: '' },
config: {
activeMenu: 'EscapeRoutePlanInfo',
submenu: [
{
title: this.$t('common.BasicInfo'),
name: 'EscapeRoutePlanInfo'
},
{
title: this.$t('xpack.ChangeAuthPlan.ExecutionList'),
name: 'EscapeRoutePlanExecutionList'
}
]
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,95 @@
<template>
<GenericListTable :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import { GenericListTable } from '@/layout/components'
import { DetailFormatter } from '@/components/TableFormatters'
import { openTaskPage } from '@/utils/jms'
export default {
name: 'EscapeRoutePlanList',
components: {
GenericListTable
},
data() {
const vm = this
return {
tableConfig: {
url: '/api/v1/assets/escape/',
columns: [
'name', 'is_periodic', 'periodic_display', 'comment', 'org_name', 'actions'
],
columnsShow: {
min: ['name', 'actions'],
default: ['name', 'org_name', 'is_periodic', 'periodic_display', 'actions']
},
columnsMeta: {
name: {
formatter: DetailFormatter,
formatterArgs: {
route: 'EscapeRoutePlanDetail'
}
},
is_periodic: {
label: vm.$t('xpack.ChangeAuthPlan.Timer'),
formatterArgs: {
showFalse: false
},
width: '80px'
},
periodic_display: {
label: vm.$t('xpack.ChangeAuthPlan.TimerPeriod'),
showOverflowTooltip: true,
width: '150px'
},
comment: {
width: '90px'
},
actions: {
width: '164px',
formatterArgs: {
onClone: ({ row }) => {
vm.$router.push({ name: 'EscapeRoutePlanCreate', query: { clone_from: row.id }})
},
onUpdate: ({ row }) => {
vm.$router.push({ name: 'EscapeRoutePlanUpdate', params: { id: row.id }})
},
extraActions: [
{
title: vm.$t('xpack.Execute'),
name: 'execute',
type: 'info',
callback: function({ row }) {
this.$axios.post(
`/api/v1/assets/escape-execution/`,
{ plan: row.id }
).then(res => {
openTaskPage(res['task'])
})
}.bind(this)
}
]
}
}
}
},
headerActions: {
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: false,
createRoute: () => {
return {
name: 'EscapeRoutePlanCreate'
}
}
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,57 @@
import i18n from '@/i18n/i18n'
import { CronTab } from '@/components'
var validatorInterval = (rule, value, callback) => {
if (parseInt(value) < 1) {
return callback(new Error(i18n.t('xpack.ChangeAuthPlan.validatorMessage.EnsureThisValueIsGreaterThanOrEqualTo1')))
}
callback()
}
function getFields() {
const recipients = {
el: {
value: [],
ajax: {
url: '/api/v1/users/users/?fields_size=mini',
transformOption: (item) => {
return { label: item.name + '(' + item.username + ')', value: item.id }
}
}
}
}
const is_periodic = {
type: 'switch'
}
const crontab = {
type: 'cronTab',
component: CronTab,
label: i18n.t('xpack.RegularlyPerform'),
hidden: (formValue) => {
return formValue.is_periodic === false
},
helpText: i18n.t('xpack.HelpText.CrontabOfCreateUpdatePage')
}
const interval = {
label: i18n.t('xpack.CyclePerform'),
hidden: (formValue) => {
return formValue.is_periodic === false
},
helpText: i18n.t('xpack.HelpText.IntervalOfCreateUpdatePage'),
rules: [
{ validator: validatorInterval }
]
}
return {
is_periodic: is_periodic,
crontab: crontab,
interval: interval,
recipients: recipients
}
}
export default getFields

View File

@@ -0,0 +1,36 @@
<template>
<TabPage :active-menu.sync="config.activeMenu" :submenu="config.submenu">
<keep-alive>
<component :is="config.activeMenu" />
</keep-alive>
</TabPage>
</template>
<script>
import { TabPage } from '@/layout/components'
import EscapeRoutePlanList from './EscapeRoutePlanList'
export default {
name: 'Index',
components: {
TabPage,
EscapeRoutePlanList
},
data() {
return {
config: {
activeMenu: 'EscapeRoutePlanList',
submenu: [
{
title: this.$t('xpack.EscapeRoutePlan.EscapeRoutePlan'),
name: 'EscapeRoutePlanList'
}
]
}
}
}
}
</script>
<style scoped>
</style>