Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 增加扫描执行集群配置管理页面 #2762 #2773

Merged
merged 3 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/frontend/devops-op/src/api/executionClusters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import request from '@/utils/request'

const PREFIX_SERVICES = 'analyst/api/execution/clusters'

export function clusters() {
return request({
url: `${PREFIX_SERVICES}`,
method: 'get'
})
}

export function update(body) {
return request({
url: `${PREFIX_SERVICES}/${body.name}`,
method: 'put',
data: body
})
}

export function create(body) {
return request({
url: `${PREFIX_SERVICES}`,
method: 'post',
data: body
})
}

export function remove(name) {
return request({
url: `${PREFIX_SERVICES}/${name}`,
method: 'delete'
})
}
25 changes: 13 additions & 12 deletions src/frontend/devops-op/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const ROUTER_NAME_FILE_SYSTEM_RECORD = 'FileSystemRecord'
export const ROUTER_NAME_REPO_CONFIG = 'RepoConfig'
export const ROUTER_NAME_RATE_LIMITER_CONFIG = 'RateLimiterConfig'
export const ROUTER_NAME_PRELOAD_CONFIG = 'PreloadConfig'
export const ROUTER_NAME_EXECUTION_CLUSTERS_CONFIG = 'ExecutionClustersConfig'

Vue.use(Router)

Expand Down Expand Up @@ -174,6 +175,12 @@ export const asyncRoutes = [
name: ROUTER_NAME_PROJECT_METRICS,
meta: { title: '仓库大小统计', icon: 'file' },
component: () => import('@/views/node/ProjectMetrics')
},
{
path: 'preloadConfig',
name: ROUTER_NAME_PRELOAD_CONFIG,
meta: { title: '制品预加载配置', icon: 'service-config' },
component: () => import('@/views/preload/index')
}
]
},
Expand Down Expand Up @@ -261,6 +268,12 @@ export const asyncRoutes = [
name: ROUTER_NAME_PROJECT_SCAN_CONFIGURATIONS,
component: () => import('@/views/scan/ProjectScanConfiguration'),
meta: { title: '项目配置', icon: 'setting' }
},
{
path: 'executionClustersConfig',
name: ROUTER_NAME_EXECUTION_CLUSTERS_CONFIG,
meta: { title: '扫描执行集群配置', icon: 'service-config' },
component: () => import('@/views/execution-clusters/index')
}
]
},
Expand Down Expand Up @@ -327,18 +340,6 @@ export const asyncRoutes = [
}
]
},
{
path: '/preload-config',
component: Layout,
children: [
{
path: '/',
name: ROUTER_NAME_PRELOAD_CONFIG,
meta: { title: '制品预加载配置', icon: 'service-config' },
component: () => import('@/views/preload/index')
}
]
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
<template>
<el-dialog :title="showMode? '详情': (createMode?'创建扫描执行集群配置':'更新扫描执行集群配置')" :visible.sync="showDialog" :before-close="close">
<el-form ref="form" :rules="rules" :model="executionCluster" status-icon label-position="left" label-width="185px">
<el-form-item ref="project-form-item" label="执行集群名" prop="name" :rules="[{ required: true, message: '执行集群名不能为空'}]">
<el-input v-model="executionCluster.name" style="height: 40px ; width: 500px;" :disabled="!createMode" />
</el-form-item>
<el-form-item ref="project-form-item" label="描述" prop="description">
<el-input v-model="executionCluster.description" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item label="集群类型" prop="type">
<el-select
v-model="executionCluster.type"
placeholder="请选择"
:disabled="showMode"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="命名空间" prop="kubernetesProperties.namespace" :rules="[{ required: true, message: '命名空间不能为空'}]">
<el-input v-model="executionCluster.kubernetesProperties.namespace" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="apiServer" prop="apiServer">
<el-input v-model="executionCluster.kubernetesProperties.apiServer" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="certificateAuthorityData" prop="certificateAuthorityData">
<el-input v-model="executionCluster.kubernetesProperties.certificateAuthorityData" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="token" prop="token">
<el-input v-model="executionCluster.kubernetesProperties.token" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="clientCertificateData" prop="clientCertificateData">
<el-input v-model="executionCluster.kubernetesProperties.clientCertificateData" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="clientKeyData" prop="clientCertificateData">
<el-input v-model="executionCluster.kubernetesProperties.clientKeyData" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="最大使用内存(B)" prop="kubernetesProperties.limitMem" :rules="[{ required: true, message: '最大使用内存不能为空'}]">
<el-input-number v-model="executionCluster.kubernetesProperties.limitMem" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="最大临时内存(B)" prop="kubernetesProperties.limitStorage" :rules="[{ required: true, message: '最大临时内存不能为空'}]">
<el-input-number v-model="executionCluster.kubernetesProperties.limitStorage" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type !== 'docker'" label="最大cpu" prop="kubernetesProperties.limitCpu" :rules="[{ required: true, message: '最大cpu不能为空'}]">
<el-input-number v-model="executionCluster.kubernetesProperties.limitCpu" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'k8s_job'" label="最大保留时间(秒)" prop="jobTtlSecondsAfterFinished">
<el-input-number v-model="executionCluster.jobTtlSecondsAfterFinished" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'k8s_job'" label="执行完是否删除" prop="cleanJobAfterSuccess">
<el-switch
v-model="executionCluster.cleanJobAfterSuccess"
active-color="#13ce66"
inactive-color="#ff4949"
:disabled="showMode"
/>
</el-form-item>
<el-form-item v-if="executionCluster.type === 'k8s_deployment'" label="扫描器" prop="scanner" :rules="[{ required: true, message: '扫描器不能为空'}]">
<el-select
v-model="executionCluster.scanner"
placeholder="请选择"
:disabled="showMode"
>
<el-option
v-for="item in scannerOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="executionCluster.type === 'k8s_deployment'" label="最大副本数" prop="maxReplicas" :rules="[{ required: true, message: '最大副本数不能为空'}]">
<el-input-number v-model="executionCluster.maxReplicas" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'k8s_deployment'" label="最小副本数" prop="minReplicas" :rules="[{ required: true, message: '最小副本数不能为空'}]">
<el-input-number v-model="executionCluster.minReplicas" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'k8s_deployment'" label="扩容阈值" prop="scaleThreshold" :rules="[{ required: true, message: '扩容阈值不能为空'}]">
<el-input-number v-model="executionCluster.scaleThreshold" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'k8s_deployment'" label="扫描器重试次数" prop="pullRetry" :rules="[{ required: true, message: '扫描器重试次数不能为空'}]">
<el-input-number v-model="executionCluster.pullRetry" style="height: 40px ; width: 200px;" controls-position="right" :min="1" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'docker'" label="host" prop="host" :rules="[{ required: true, message: 'host不能为空'}]">
<el-input v-model="executionCluster.host" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'docker'" label="版本" prop="version" :rules="[{ required: true, message: '版本不能为空'}]">
<el-input v-model="executionCluster.version" style="height: 40px ; width: 500px;" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'docker'" label="连接超时时长(毫秒)" prop="connectTimeout" :rules="[{ required: true, message: '连接超时时长不能为空'}]">
<el-input-number v-model="executionCluster.connectTimeout" style="height: 40px ; width: 200px;" controls-position="right" :min="0" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'docker'" label="读取超时时长(毫秒)" prop="readTimeout" :rules="[{ required: true, message: '读取超时时长不能为空'}]">
<el-input-number v-model="executionCluster.readTimeout" style="height: 40px ; width: 200px;" controls-position="right" :min="0" :disabled="showMode" />
</el-form-item>
<el-form-item v-if="executionCluster.type === 'docker'" label="最大任务数" prop="maxTaskCount" :rules="[{ required: true, message: '最大任务数不能为空'}]">
<el-input-number v-model="executionCluster.maxTaskCount" style="height: 40px ; width: 200px;" controls-position="right" :min="0" :disabled="showMode" />
</el-form-item>
</el-form>
<div v-if="!showMode" slot="footer">
<el-button @click="close">取 消</el-button>
<el-button type="primary" @click="handleUpdate()">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
import _ from 'lodash'
import { scanners } from '@/api/scan'
import { create, update } from '@/api/executionClusters'

export default {
name: 'EditClusterConfigDialog',
props: {
visible: Boolean,
createMode: {
type: Boolean,
default: false
},
showMode: {
type: Boolean,
default: false
},
/**
* 仅在更新模式时有值
*/
updatingClusterConfig: {
type: Object,
default: undefined
}
},
data() {
return {
repoCache: {},
showDialog: this.visible,
executionCluster: this.newCluster(),
data: '',
rules: {},
options: [
{ value: 'k8s_job',
label: 'k8s_job' },
{ value: 'k8s_deployment',
label: 'k8s_deployment'
},
{ value: 'docker',
label: 'docker' }
],
scannerOptions: []
}
},
watch: {
visible: function(newVal) {
if (newVal) {
this.resetStrategy()
this.showDialog = true
} else {
this.close()
}
}
},
created() {
scanners().then(res => {
res.data.forEach(item => {
const scanner = {
label: item.name,
value: item.name
}
this.scannerOptions.push(scanner)
})
})
},
methods: {
resetStrategy() {
if (this.createMode) {
this.executionCluster = this.newCluster()
} else {
this.executionCluster = _.cloneDeep(this.updatingClusterConfig)
if (!this.executionCluster.kubernetesProperties) {
this.executionCluster.kubernetesProperties = {
namespace: '',
apiServer: '',
certificateAuthorityData: '',
token: '',
clientCertificateData: '',
clientKeyData: '',
limitMem: 1,
limitStorage: 1,
limitCpu: 1
}
}
}
this.$nextTick(() => {
this.$refs['form'].clearValidate()
})
},
newCluster() {
const Cluster = {
name: '',
type: 'k8s_job',
description: '',
kubernetesProperties: {
namespace: '',
apiServer: '',
certificateAuthorityData: '',
token: '',
clientCertificateData: '',
clientKeyData: '',
limitMem: 1,
limitStorage: 1,
limitCpu: 1
},
jobTtlSecondsAfterFinished: 1,
cleanJobAfterSuccess: true,
scanner: '',
maxReplicas: 1,
minReplicas: 1,
scaleThreshold: 1,
pullRetry: 1,
host: 'unix://var/run/docker.sock',
version: '1.23',
connectTimeout: 5000,
readTimeout: 0,
maxTaskCount: 1
}
return Cluster
},
close(changed) {
this.showDialog = false
this.$refs['form'].resetFields()
if (changed === true) {
this.$emit('updated')
}
this.$emit('update:visible', false)
},
handleUpdate() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.executionCluster.kubernetesProperties.apiServer === '') {
this.executionCluster.kubernetesProperties.apiServer === null
}
if (this.executionCluster.kubernetesProperties.certificateAuthorityData === '') {
this.executionCluster.kubernetesProperties.certificateAuthorityData === null
}
if (this.executionCluster.kubernetesProperties.token === '') {
this.executionCluster.kubernetesProperties.token === null
}
if (this.executionCluster.kubernetesProperties.clientCertificateData === '') {
this.executionCluster.kubernetesProperties.clientCertificateData === null
}
if (this.executionCluster.kubernetesProperties.clientKeyData === '') {
this.executionCluster.kubernetesProperties.clientKeyData === null
}
if (this.createMode) {
create(this.executionCluster).then(() => {
this.$message.success('新建配置成功')
this.close(true)
})
} else {
update(this.executionCluster).then(() => {
this.$message.success('更新配置成功')
this.close(true)
})
}
}
})
}
}
}
</script>

<style scoped>

</style>
Loading
Loading