764 lines
29 KiB
Vue
764 lines
29 KiB
Vue
|
<template>
|
|||
|
<basic-form :model="formData" ref="addForm" label-width="0" :disabled="disabled">
|
|||
|
<basic-table :data="showParamList" ref="addTable">
|
|||
|
<el-table-column label="序号" show-overflow-tooltip width="60px">
|
|||
|
<template slot-scope="{ $index }">
|
|||
|
<basic-form-item label="">
|
|||
|
{{ $index + 1 }}
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="命名规则" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" :prop="`showParamList.${$index}.configs.nameRuleId`">
|
|||
|
<el-select v-model="row.configs.nameRuleId" placeholder="请选择命名规则" clearable filterable>
|
|||
|
<el-option v-for="(item, index) in nameruleList" :key="index" :label="item.name" :value="item.id"> </el-option>
|
|||
|
</el-select>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="主机名" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required,vmHostName" :prop="`showParamList.${$index}.configs.vmHostName`">
|
|||
|
<el-input v-model="row.configs.vmHostName"> </el-input>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<!-- <el-table-column label="云平台类型" show-overflow-tooltip>
|
|||
|
<template slot-scope="{ row,$index }">
|
|||
|
<basic-form-item label="">
|
|||
|
<el-select v-model="row.subLocation.vendorType">
|
|||
|
<el-option :label="item | vendorName" :value="item" v-for="item in vendorTypelist" :key="item"></el-option>
|
|||
|
</el-select>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column> -->
|
|||
|
<el-table-column label="区域" show-overflow-tooltip width="180px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.subLocation.region`">
|
|||
|
<el-select v-model="row.subLocation.region" @change="changeRegion(row, true)">
|
|||
|
<el-option :label="item.regionName" :value="item.region" v-for="item in regionList" :key="item.region"></el-option>
|
|||
|
</el-select>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="可用区" show-overflow-tooltip width="180px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.subLocation.az`">
|
|||
|
<el-select v-model="row.subLocation.az" @change="changeAz(row, true)">
|
|||
|
<el-option :label="item.azName" :value="item.availablitiyZone" v-for="item in getZoneListByRegion(row)" :key="item.availablitiyZone"></el-option>
|
|||
|
</el-select>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="镜像类型" show-overflow-tooltip width="180px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.osCategory`">
|
|||
|
<el-select v-model="row.configs.osCategory" placeholder="请选择" @change="getVersionList(row, true)">
|
|||
|
<el-option v-for="(item, index) in row.osList" :key="index" :label="item" :value="item"> </el-option>
|
|||
|
</el-select>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="镜像版本" show-overflow-tooltip width="180px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.osVersion`">
|
|||
|
<el-select v-model="row.configs.osVersion" placeholder="请选择" @change="getImage(row, true)">
|
|||
|
<el-option v-for="(item, index) in row.versionList" :key="index" :label="item" :value="item"> </el-option>
|
|||
|
</el-select>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="CPU(核)" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.cpu`">
|
|||
|
<el-input-number :min="1" :max="500" v-model="row.configs.cpu" @change="(val) => changeCpu(val, row)"> </el-input-number>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="内存(GB)" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.memory`">
|
|||
|
<el-input-number :min="row.configs.templateRam" :max="500" v-model="row.configs.memory" @change="(val) => changeMemory(val, row)"> </el-input-number>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="磁盘(GB)" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.sysDisk.disk`">
|
|||
|
<span class="detail-href" @click="handleOpenDiskDialog(row, $index)">
|
|||
|
<template v-if="getDiskTotalSize(row) > 0">{{ getDiskTotalSize(row) }}</template>
|
|||
|
<template v-else>配置</template>
|
|||
|
</span>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="网络" show-overflow-tooltip width="180px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" :prop="`showParamList.${$index}`" :rules="rules.networkCardConfigsRule">
|
|||
|
<span class="detail-href" @click="handleOpenNetworkDialog(row, $index)">
|
|||
|
<template v-if="!row.configs.networkCardConfigs.length || row.configs.networkCardConfigs[0].ipPoolId">
|
|||
|
<div v-for="(item, index) in row.configs.networkCardConfigs" :key="index">
|
|||
|
{{ item.ipPoolName }} <span v-if="item.address.length">-{{ item.address.join('、') }}</span>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
<template v-else>配置</template>
|
|||
|
</span>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="密码" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required,vmPassword" :prop="`showParamList.${$index}.configs.password`">
|
|||
|
<el-input v-model="row.configs.password" placeholder="请输入密码" show-password></el-input>
|
|||
|
</basic-form-item>
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.confirm_password`">
|
|||
|
<el-input v-model="row.configs.confirm_password" placeholder="请再次输入密码" show-password></el-input>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="用途" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.subLocation.purpose`">
|
|||
|
<el-input v-model="row.subLocation.purpose"> </el-input>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="软件配置" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="">
|
|||
|
<span class="detail-href" @click="openGraph(row, $index)"> {{ getGraphConfigLabel(row) }} </span>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="数量" show-overflow-tooltip width="160px">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.emption.count`">
|
|||
|
<el-input-number v-model="row.emption.count"> </el-input-number>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<el-table-column label="操作" width="160px" fixed="right">
|
|||
|
<template slot-scope="{ row, $index }">
|
|||
|
<basic-form-item label="">
|
|||
|
<el-button type="text" @click="handleClone(row)">复制</el-button>
|
|||
|
<el-button type="text" @click="handleSub($index)">删除</el-button>
|
|||
|
</basic-form-item>
|
|||
|
</template>
|
|||
|
</el-table-column>
|
|||
|
<span slot="pagination"></span>
|
|||
|
</basic-table>
|
|||
|
<DataDisk v-if="addDiskDialog.visible" :dialog="addDiskDialog" @success="changeDisk"></DataDisk>
|
|||
|
<Ippool v-if="addNetworkDialog.visible" :dialog="addNetworkDialog" :disabled="disabled"></Ippool>
|
|||
|
<el-dialog :visible.sync="graphDialog.visible" title="作业编排" width="1200px" append-to-body top="5vh" :closeOnClickModal="false">
|
|||
|
<Graph v-if="graphDialog.visible" :addData="addData" :graphDialog="graphDialog" @back="graphDialog.visible = false" :disabled="disabled"></Graph>
|
|||
|
</el-dialog>
|
|||
|
</basic-form>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
import { conditionService, conditionImage, getNameRule } from 'services/platform/index'
|
|||
|
import { generateSpec, getSpecValue } from 'views/resource-apply/utils/index'
|
|||
|
import { getPoolCondition } from 'services/platform/pool'
|
|||
|
import { uniqBy, cloneDeep } from 'lodash-es'
|
|||
|
import { transformNetworkConfig } from './ImageItem'
|
|||
|
import { subApplicationParam, GEN_UUID, ServiceCodeMap, defaultTask } from '../data/EFCInit'
|
|||
|
import Ippool, { CECSTACK_DEFAULT_CONFIG, CLOUDTOWER_DEFAULT_CONFIG } from './EFCIppool'
|
|||
|
import DataDisk from './EFCDataDisk'
|
|||
|
import sku from '../mixins/EFCsku'
|
|||
|
import Graph from '../graph/graph.vue'
|
|||
|
import { getVolumeTpl } from 'services/platform/smart.js'
|
|||
|
export default {
|
|||
|
name: 'VmList',
|
|||
|
mixins: [sku],
|
|||
|
components: {
|
|||
|
Ippool,
|
|||
|
DataDisk,
|
|||
|
Graph
|
|||
|
},
|
|||
|
props: {
|
|||
|
itemData: {
|
|||
|
type: [Object, Boolean]
|
|||
|
},
|
|||
|
showParamList: {
|
|||
|
type: Array,
|
|||
|
required: true,
|
|||
|
default: () => []
|
|||
|
},
|
|||
|
addData: {
|
|||
|
type: Object,
|
|||
|
required: true,
|
|||
|
default: () => {}
|
|||
|
},
|
|||
|
disabled: {
|
|||
|
type: Boolean
|
|||
|
}
|
|||
|
},
|
|||
|
provide() {
|
|||
|
// 使用函数的形式,可以访问到 `this`
|
|||
|
return {
|
|||
|
getSubApplicationParamsForTaskServer: () => this.addData.subApplicationParams.filter((item) => item.taskGroupUuid === this.graphDialog.task.taskGroupUuid)
|
|||
|
}
|
|||
|
},
|
|||
|
computed: {
|
|||
|
formData() {
|
|||
|
return { showParamList: this.showParamList }
|
|||
|
},
|
|||
|
regionList() {
|
|||
|
return this.allPoolList.reduce((pre, cur) => {
|
|||
|
if (!pre.find((item) => item.region == cur.region)) {
|
|||
|
pre.push({
|
|||
|
regionName: cur.regionName,
|
|||
|
region: cur.region
|
|||
|
})
|
|||
|
}
|
|||
|
return pre
|
|||
|
}, [])
|
|||
|
}
|
|||
|
},
|
|||
|
data() {
|
|||
|
return {
|
|||
|
nameruleList: [],
|
|||
|
vendorTypelist: [],
|
|||
|
allPoolList: [],
|
|||
|
addDiskDialog: {
|
|||
|
visible: false,
|
|||
|
index: '',
|
|||
|
row: {}
|
|||
|
},
|
|||
|
addNetworkDialog: {
|
|||
|
visible: false,
|
|||
|
row: {},
|
|||
|
cb: () => {}
|
|||
|
},
|
|||
|
rules: {
|
|||
|
networkCardConfigsRule: [
|
|||
|
{
|
|||
|
required: true,
|
|||
|
validator: (rule, value, callback) => {
|
|||
|
const validateNetworkCard = this.validateNetworkCard(value)
|
|||
|
if (validateNetworkCard.valid) {
|
|||
|
callback()
|
|||
|
} else {
|
|||
|
callback(new Error(validateNetworkCard.message))
|
|||
|
}
|
|||
|
},
|
|||
|
trigger: null
|
|||
|
}
|
|||
|
]
|
|||
|
},
|
|||
|
graphDialog: {
|
|||
|
visible: false,
|
|||
|
task: {},
|
|||
|
cb: () => {}
|
|||
|
},
|
|||
|
CTDataDisktemplateData: []
|
|||
|
}
|
|||
|
},
|
|||
|
created() {
|
|||
|
getNameRule({
|
|||
|
page: 1,
|
|||
|
rows: 9999
|
|||
|
}).then((data) => {
|
|||
|
if (data.success) {
|
|||
|
this.nameruleList = data.data.rows
|
|||
|
}
|
|||
|
})
|
|||
|
this.getAllPool()
|
|||
|
// 获取云平台类型
|
|||
|
conditionService('server').then((data) => {
|
|||
|
if (data.success) {
|
|||
|
this.vendorTypelist = data.data
|
|||
|
}
|
|||
|
})
|
|||
|
},
|
|||
|
methods: {
|
|||
|
getGraphConfigLabel(row) {
|
|||
|
const task = this.addData.tasks.find(({ taskGroupUuid }) => taskGroupUuid === row.taskGroupUuid)
|
|||
|
if (!task) return '配置'
|
|||
|
return `${task.taskName}`
|
|||
|
},
|
|||
|
openGraph(row) {
|
|||
|
if (!this.addData.location.name) return this.$message.error('请填写业务信息')
|
|||
|
if (!row.configs.vmHostName) return this.$message.error('请填写主机名')
|
|||
|
if (!row.configs.password) return this.$message.error('请填写密码')
|
|||
|
this.$emit('handleUpdateParamList')
|
|||
|
this.graphDialog.visible = true
|
|||
|
this.graphDialog.task = cloneDeep(
|
|||
|
this.addData.tasks.find((item) => item.taskGroupUuid === row.taskGroupUuid) || {
|
|||
|
...defaultTask,
|
|||
|
taskGroupUuid: row.taskGroupUuid
|
|||
|
}
|
|||
|
)
|
|||
|
this.graphDialog.cb = () => {
|
|||
|
this.graphDialog.task.taskName = `${this.addData.location.name}_${this.graphDialog.task.name}`
|
|||
|
const findIndex = this.addData.tasks.findIndex((item) => item.taskGroupUuid === row.taskGroupUuid)
|
|||
|
if (findIndex > -1) {
|
|||
|
this.addData.tasks[findIndex] = this.graphDialog.task
|
|||
|
} else {
|
|||
|
this.addData.tasks.push(this.graphDialog.task)
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
changeCpu(val, row) {
|
|||
|
row.elements[0].specs[0].cpu = val
|
|||
|
},
|
|||
|
changeMemory(val, row) {
|
|||
|
row.elements[0].specs[1].memory = val
|
|||
|
},
|
|||
|
// 将磁盘配置保存到 elements 中
|
|||
|
async changeDisk(index = -1, row) {
|
|||
|
row = index > -1 ? this.showParamList[index] : row
|
|||
|
// 系统盘
|
|||
|
row.elements[1].specs = [{ disk: row.configs.sysDisk.disk }]
|
|||
|
row.configs.sysDisk.categoryId = row.elements[1].categoryId
|
|||
|
// 数据盘
|
|||
|
row.elements.splice(2)
|
|||
|
if (row.configs.addDiskList.length) {
|
|||
|
const dataDiskElementClone = cloneDeep(row.elements[1])
|
|||
|
row.configs.addDiskList.map((item) => {
|
|||
|
row.elements.push({ ...dataDiskElementClone, specs: [{ disk: item.disk }] })
|
|||
|
})
|
|||
|
}
|
|||
|
// 设置各个云平台的默认磁盘配置
|
|||
|
const vendorType = row.subLocation.vendorType
|
|||
|
const vendorId = row.subLocation.vendorId
|
|||
|
switch (vendorType) {
|
|||
|
case 'VMWARE':
|
|||
|
row.configs.sysDisk.diskType = 'thin'
|
|||
|
// 设置磁盘默认数据
|
|||
|
row.configs.addDiskList.forEach((item) => {
|
|||
|
item.createLvm = false
|
|||
|
item.diskType = 'thin'
|
|||
|
item.fileSystem = 'ext3'
|
|||
|
item.forceMount = false
|
|||
|
})
|
|||
|
break
|
|||
|
case 'INSPURRAIL':
|
|||
|
row.configs.sysDisk.diskType = 'thin'
|
|||
|
// 设置磁盘默认数据
|
|||
|
row.configs.addDiskList.forEach((item) => {
|
|||
|
item.createLvm = false
|
|||
|
item.diskType = 'thin'
|
|||
|
item.fileSystem = 'ext3'
|
|||
|
item.forceMount = false
|
|||
|
})
|
|||
|
break
|
|||
|
case 'CLOUDTOWER':
|
|||
|
const busData = [
|
|||
|
{ name: 'VIRTIO', value: 'VIRTIO' },
|
|||
|
{ name: 'SCSI', value: 'SCSI' },
|
|||
|
{ name: 'IDE', value: 'IDE' }
|
|||
|
]
|
|||
|
// 设置磁盘默认数据
|
|||
|
if (!this.CTDataDisktemplateData.length || this.CTDataDisktemplateData[0].vendorId !== vendorId) {
|
|||
|
await getVolumeTpl({
|
|||
|
simple: true,
|
|||
|
params: this.$tools.handleSearchParam({ vendorId })
|
|||
|
}).then((data) => {
|
|||
|
if (data.success) {
|
|||
|
if (!data.data.rows.length) {
|
|||
|
row.configs.addDiskList = []
|
|||
|
return this.$message.error('获取CLOUDTOWER存储策略数据为空,请联系管理员')
|
|||
|
}
|
|||
|
this.CTDataDisktemplateData = data.data.rows
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
row.configs.addDiskList.forEach((item) => {
|
|||
|
item.type = 'newDisk'
|
|||
|
item.bus = busData[0].value
|
|||
|
item.volumeTemplateId = this.CTDataDisktemplateData[0].id // 存储策略
|
|||
|
item.volumeTemplateName = this.CTDataDisktemplateData[0].name
|
|||
|
})
|
|||
|
break
|
|||
|
case 'CECSTACK':
|
|||
|
row.configs.addDiskList.forEach((item) => {
|
|||
|
item.deleteWithInstance = true
|
|||
|
item.bootVolume = false
|
|||
|
// item.size = ''
|
|||
|
// item.volumeType = ''
|
|||
|
item.volumeUnit = 'GiB'
|
|||
|
// item.bootIndex = ''
|
|||
|
})
|
|||
|
break
|
|||
|
default:
|
|||
|
break
|
|||
|
}
|
|||
|
},
|
|||
|
handleClone(row = subApplicationParam) {
|
|||
|
const cloneData = cloneDeep(row)
|
|||
|
cloneData.taskGroupUuid = GEN_UUID()
|
|||
|
cloneData.taskTargetUuid = GEN_UUID()
|
|||
|
cloneData.configs.name = ''
|
|||
|
this.showParamList.push(cloneData)
|
|||
|
},
|
|||
|
handleSub(index) {
|
|||
|
this.showParamList.splice(index, 1)
|
|||
|
},
|
|||
|
handleOpenNetworkDialog(row, index) {
|
|||
|
this.addNetworkDialog.visible = true
|
|||
|
this.addNetworkDialog.row = row
|
|||
|
this.addNetworkDialog.cb = () => {
|
|||
|
this.$refs.addForm && this.$refs.addForm.$refs.formRef.validateField(`showParamList.${index}`)
|
|||
|
}
|
|||
|
},
|
|||
|
getDiskTotalSize(row) {
|
|||
|
return row.configs.sysDisk.disk + row.configs.addDiskList.reduce((pre, cur) => pre + cur.disk, 0)
|
|||
|
},
|
|||
|
handleOpenDiskDialog(row, index) {
|
|||
|
this.addDiskDialog.visible = true
|
|||
|
this.addDiskDialog.row = row
|
|||
|
this.addDiskDialog.index = index
|
|||
|
},
|
|||
|
getOsList(row) {
|
|||
|
if (!row.subLocation.vendorId) return
|
|||
|
let params
|
|||
|
if (row.subLocation.vendorType === 'CECSTACK') {
|
|||
|
params = {
|
|||
|
condition: 'listByImageType',
|
|||
|
vendorId: row.subLocation.vendorId,
|
|||
|
status: 'ACTIVE',
|
|||
|
tenantId: 0,
|
|||
|
regionId: row.subLocation.region,
|
|||
|
imageType: 'PUBLIC'
|
|||
|
}
|
|||
|
} else {
|
|||
|
params = {
|
|||
|
condition: 'listTenantImages',
|
|||
|
vendorId: row.subLocation.vendorId
|
|||
|
}
|
|||
|
if (row.subLocation.vendorType === 'SANGFOR') {
|
|||
|
if (!row.subLocation.azUuid) return
|
|||
|
params.azUuid = row.subLocation.azUuid
|
|||
|
}
|
|||
|
}
|
|||
|
conditionImage(params).then((data) => {
|
|||
|
if (data.success) {
|
|||
|
row.imageData = data.data
|
|||
|
this.$set(row, 'osList', Object.keys(row.imageData))
|
|||
|
if (!this.itemData) {
|
|||
|
row.configs.osCategory = row.osList[0]
|
|||
|
row.configs.osVersion = ''
|
|||
|
}
|
|||
|
this.$set(row, 'versionList', [])
|
|||
|
this.getVersionList(row, !row.configs.osVersion)
|
|||
|
}
|
|||
|
})
|
|||
|
return row.osList
|
|||
|
},
|
|||
|
|
|||
|
getVersionList(row, flag) {
|
|||
|
if (row.subLocation.vendorType === 'CECSTACK') {
|
|||
|
row.versionList = row.imageData[row.configs.osCategory].map(({ name }) => name)
|
|||
|
} else {
|
|||
|
row.versionList = Object.keys(row.imageData[row.configs.osCategory])
|
|||
|
}
|
|||
|
if (flag) {
|
|||
|
row.configs.osVersion = row.versionList[0]
|
|||
|
this.getImage(row, true)
|
|||
|
} else {
|
|||
|
this.getImage(row, false)
|
|||
|
}
|
|||
|
},
|
|||
|
getImage(row, flag) {
|
|||
|
let obj
|
|||
|
if (row.subLocation.vendorType === 'CECSTACK') {
|
|||
|
obj = row.imageData[row.configs.osCategory].find(({ name }) => row.configs.osVersion === name)
|
|||
|
} else {
|
|||
|
obj = row.imageData[row.configs.osCategory][row.configs.osVersion]?.[0]
|
|||
|
}
|
|||
|
if (!obj) return
|
|||
|
if (flag) {
|
|||
|
row.configs.imageId = obj.id
|
|||
|
// 电子云为 minDisk
|
|||
|
// cloudtower 镜像中可能没系统盘大小
|
|||
|
row.configs.templateDisk = obj.templateDisk || obj.minDisk || 50
|
|||
|
row.configs.templateRam = obj.minRam / 1024 || 1
|
|||
|
if (row.configs.memory < row.configs.templateRam) row.configs.memory = row.configs.templateRam
|
|||
|
row.configs.sysDisk.disk = row.configs.templateDisk
|
|||
|
}
|
|||
|
if (row.subLocation.vendorType == 'CECSTACK') {
|
|||
|
if (flag) {
|
|||
|
this.$set(row.configs, 'networkCardConfigs', [
|
|||
|
{
|
|||
|
networkId: obj.networkId,
|
|||
|
ipPolicy: 'Auto',
|
|||
|
ipPoolId: '',
|
|||
|
ipPoolName: '',
|
|||
|
address: [],
|
|||
|
portGroupId: '',
|
|||
|
loading: false,
|
|||
|
// 电子云特殊参数
|
|||
|
...CECSTACK_DEFAULT_CONFIG
|
|||
|
}
|
|||
|
])
|
|||
|
}
|
|||
|
} else if (row.subLocation.vendorType == 'SANGFOR') {
|
|||
|
row.configs.vmUuid = obj.imageUuid
|
|||
|
if (flag && row.configs.networkCardConfigs.length == 0) {
|
|||
|
const hardware_status = JSON.parse(obj.detail || '{}')?.hardware_status
|
|||
|
if (!hardware_status) return this.$message.error('镜像缺少网卡,请检查镜像是否正确')
|
|||
|
const configs = transformNetworkConfig(hardware_status).map((item) => ({
|
|||
|
ipPolicy: 'Auto',
|
|||
|
ipPoolId: '',
|
|||
|
ipPoolName: '',
|
|||
|
address: [],
|
|||
|
portGroupId: '',
|
|||
|
loading: false
|
|||
|
}))
|
|||
|
this.$set(row.configs, 'networkCardConfigs', configs)
|
|||
|
}
|
|||
|
} else if (row.subLocation.vendorType == 'VMWARE') {
|
|||
|
if (flag && (row.configs.networkCardConfigs.length == 0 || row.configs.networkCardConfigs[0].networkCardId != obj.networkCards?.[0]?.id)) {
|
|||
|
if (!obj.networkCards?.length) this.$message.error('镜像缺少网卡,请检查镜像是否正确')
|
|||
|
this.$set(
|
|||
|
row.configs,
|
|||
|
'networkCardConfigs',
|
|||
|
obj.networkCards.map((item) => {
|
|||
|
return {
|
|||
|
networkCardId: item.id,
|
|||
|
ipPolicy: 'Auto',
|
|||
|
ipPoolId: '',
|
|||
|
ipPoolName: '',
|
|||
|
address: [],
|
|||
|
portGroupId: '',
|
|||
|
loading: false
|
|||
|
}
|
|||
|
})
|
|||
|
)
|
|||
|
}
|
|||
|
} else if (row.subLocation.vendorType == 'INSPURRAIL') {
|
|||
|
if (flag) {
|
|||
|
if (row.configs.networkCardConfigs.length == 0 || row.configs.networkCardConfigs[0].networkCardId != obj.networkCards?.[0]?.id) {
|
|||
|
if (!obj.networkCards?.length) this.$message.error('镜像缺少网卡,请检查镜像是否正确')
|
|||
|
this.$set(
|
|||
|
row.configs,
|
|||
|
'networkCardConfigs',
|
|||
|
obj.networkCards.map((item) => {
|
|||
|
return {
|
|||
|
networkCardId: item.id,
|
|||
|
ipPolicy: 'Auto',
|
|||
|
ipPoolId: '',
|
|||
|
ipPoolName: '',
|
|||
|
address: [],
|
|||
|
portGroupId: '',
|
|||
|
loading: false
|
|||
|
}
|
|||
|
})
|
|||
|
)
|
|||
|
}
|
|||
|
// 模板里面的磁盘配置
|
|||
|
const volumes = obj.volumes || []
|
|||
|
volumes.map(({ bootVolume, size }) => {
|
|||
|
if (bootVolume) {
|
|||
|
row.configs.templateDisk = size
|
|||
|
row.configs.sysDisk.disk = size
|
|||
|
} else {
|
|||
|
row.configs.addDiskList.push({ disk: size, templateDisk: size })
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
} else if (row.subLocation.vendorType == 'CLOUDTOWER') {
|
|||
|
if (flag) {
|
|||
|
this.$set(row.configs, 'networkCardConfigs', [
|
|||
|
{
|
|||
|
networkId: obj.networkId,
|
|||
|
ipPolicy: 'Auto',
|
|||
|
ipPoolId: '',
|
|||
|
ipPoolName: '',
|
|||
|
address: [],
|
|||
|
portGroupId: '',
|
|||
|
loading: false,
|
|||
|
// CLOUDTOWER特殊参数
|
|||
|
...CLOUDTOWER_DEFAULT_CONFIG
|
|||
|
}
|
|||
|
])
|
|||
|
}
|
|||
|
} else if (row.subLocation.vendorType === 'CNWARE') {
|
|||
|
const res = JSON.parse(obj.configuration).devices.map((d) => {
|
|||
|
if (d.capacity) {
|
|||
|
const size = Number(d.capacity) / 1024 / 1024 / 1024
|
|||
|
// 系统盘大小
|
|||
|
row.configs.templateDisk = size
|
|||
|
}
|
|||
|
return {
|
|||
|
...d
|
|||
|
}
|
|||
|
})
|
|||
|
if (flag) {
|
|||
|
row.configs.sysDiskList = res.flat()
|
|||
|
}
|
|||
|
}
|
|||
|
// 设置硬盘参数
|
|||
|
if (flag) this.changeDisk(-1, row)
|
|||
|
},
|
|||
|
setVendor(row, manual = true) {
|
|||
|
const findVendorList = this.getVendorListByRegionZone(row)
|
|||
|
const pool = findVendorList.filter((item) => item.vendorId == row.subLocation.vendorId)[0]
|
|||
|
if (!pool) return this.$message.error('当前可用区下不存在资源池')
|
|||
|
console.log('当前资源池:', pool.vendorType, pool.name)
|
|||
|
const { vendorType, id, azUuid } = pool
|
|||
|
row.subLocation.poolGroupId = id
|
|||
|
row.subLocation.azUuid = azUuid
|
|||
|
row.subLocation.vendorType = vendorType
|
|||
|
row.networkRelations = pool.networkRelations || []
|
|||
|
row.service = ServiceCodeMap.server[vendorType]
|
|||
|
row.elements.map((item, index) => {
|
|||
|
item.serviceCode = index === 0 ? ServiceCodeMap.server[vendorType] : ServiceCodeMap.disk[vendorType]
|
|||
|
})
|
|||
|
switch (vendorType) {
|
|||
|
case 'VMWARE':
|
|||
|
row.configs.isAddShterm = false
|
|||
|
break
|
|||
|
case 'INSPURRAIL':
|
|||
|
row.configs.isAddShterm = false
|
|||
|
break
|
|||
|
case 'CLOUDTOWER':
|
|||
|
row.configs.serverId = 0
|
|||
|
row.configs.ha = true
|
|||
|
row.configs.firmware = 'BIOS'
|
|||
|
row.configs.status = 'running'
|
|||
|
row.configs.fullClone = false
|
|||
|
break
|
|||
|
default:
|
|||
|
break
|
|||
|
}
|
|||
|
// 根据云平台类型设置默认磁盘配置
|
|||
|
this.changeDisk(-1, row)
|
|||
|
this.getData(row, manual)
|
|||
|
},
|
|||
|
getData(row, manual = true) {
|
|||
|
// 加载服务目录
|
|||
|
if (!this.itemData || !this.disabled) this.loadSku(row)
|
|||
|
this.getOsList(row)
|
|||
|
},
|
|||
|
|
|||
|
getZoneListByRegion(row) {
|
|||
|
const filterPools = this.allPoolList.filter((item) => item.region == row.subLocation.region)
|
|||
|
if (!filterPools.length) return []
|
|||
|
// 同一地域下可能会存在重复可用区,去重处理
|
|||
|
if (filterPools[0].vendorType === 'CECSTACK') {
|
|||
|
const formatPools = []
|
|||
|
// 将多个可用区扁平化放在资源池中
|
|||
|
filterPools.map((pool) => {
|
|||
|
pool.regionRelations.map((zone) => {
|
|||
|
formatPools.push({ ...pool, availablitiyZone: zone.zoneId, azName: zone.zoneName })
|
|||
|
})
|
|||
|
})
|
|||
|
return uniqBy(formatPools, 'availablitiyZone')
|
|||
|
} else {
|
|||
|
return uniqBy(filterPools, 'availablitiyZone')
|
|||
|
}
|
|||
|
},
|
|||
|
getVendorListByRegionZone(row) {
|
|||
|
const zoneList = this.getZoneListByRegion(row)
|
|||
|
return zoneList.filter((item) => item.availablitiyZone == row.subLocation.az)
|
|||
|
},
|
|||
|
// 地域变化
|
|||
|
// manual 手动切换
|
|||
|
changeRegion(row, manual = true) {
|
|||
|
this.setZone(row, manual)
|
|||
|
},
|
|||
|
// 设置可用区
|
|||
|
setZone(row, manual = true) {
|
|||
|
const zoneList = this.getZoneListByRegion(row)
|
|||
|
// 手动切换才需要置空
|
|||
|
if (manual && !zoneList.length) return (row.subLocation.az = '')
|
|||
|
if (!zoneList.find((item) => item.availablitiyZone === row.subLocation.az)) {
|
|||
|
row.subLocation.az = zoneList[0].availablitiyZone
|
|||
|
}
|
|||
|
this.changeAz(row, manual)
|
|||
|
},
|
|||
|
// 可用区改变
|
|||
|
changeAz(row, manual = true) {
|
|||
|
const findVendorList = this.getVendorListByRegionZone(row)
|
|||
|
if (manual && !findVendorList.length) return (row.subLocation.vendorId = '')
|
|||
|
if (!findVendorList.find((item) => item.vendorId === row.subLocation.vendorId)) {
|
|||
|
row.subLocation.vendorId = findVendorList[0].vendorId
|
|||
|
}
|
|||
|
this.setVendor(row, manual)
|
|||
|
},
|
|||
|
// 所有资源池
|
|||
|
async getAllPool() {
|
|||
|
const res = await getPoolCondition({
|
|||
|
condition: 'listPoolGroups',
|
|||
|
tenantId: this.addData.location.tenantId
|
|||
|
})
|
|||
|
if (!res.success) return
|
|||
|
this.allPoolList = res.data
|
|||
|
if (!this.regionList.length) return
|
|||
|
const [{ region }] = this.regionList
|
|||
|
if (!this.showParamList[0].subLocation.region) {
|
|||
|
this.showParamList[0].subLocation.region = region
|
|||
|
}
|
|||
|
this.changeRegion(this.showParamList[0], false)
|
|||
|
},
|
|||
|
validateNetworkCard(param) {
|
|||
|
const res = {
|
|||
|
valid: true,
|
|||
|
message: ''
|
|||
|
}
|
|||
|
let flag = false
|
|||
|
let addressLenFlag = false
|
|||
|
let cecstackFlag = false
|
|||
|
param.configs.networkCardConfigs.forEach((item) => {
|
|||
|
if (!item.ipPoolId || (item.ipPolicy == 'Manual' && item.address.length == 0) || (item.checkIpv6 && (!item.ipv6PoolId || (item.ipv6Policy == 'Manual' && item.ipv6Address.length == 0)))) flag = true
|
|||
|
if (item.ipPolicy == 'Manual' && item.address.length !== param.emption.count) {
|
|||
|
addressLenFlag = true
|
|||
|
}
|
|||
|
if (param.subLocation.vendorType === 'CECSTACK' && !(item.vpcUuid || item.subnetUuid)) {
|
|||
|
cecstackFlag = true
|
|||
|
}
|
|||
|
})
|
|||
|
if (flag) {
|
|||
|
res.valid = false
|
|||
|
res.message = '网卡信息配置不完善'
|
|||
|
return res
|
|||
|
}
|
|||
|
if (addressLenFlag) {
|
|||
|
res.valid = false
|
|||
|
res.message = 'IP数量与云主机订购数量不一致'
|
|||
|
return res
|
|||
|
}
|
|||
|
if (cecstackFlag) {
|
|||
|
res.valid = false
|
|||
|
res.message = '缺少 VPC 和子网信息'
|
|||
|
}
|
|||
|
return res
|
|||
|
},
|
|||
|
getParams() {
|
|||
|
let data = false
|
|||
|
this.$refs.addForm.validate((valid) => {
|
|||
|
if (valid) {
|
|||
|
const result = []
|
|||
|
this.showParamList.forEach((param) => {
|
|||
|
const validateNetworkCard = this.validateNetworkCard(param)
|
|||
|
if (!validateNetworkCard.valid) {
|
|||
|
data = false
|
|||
|
return
|
|||
|
}
|
|||
|
const { password, confirm_password, ...other } = param.configs
|
|||
|
if (password !== confirm_password) {
|
|||
|
data = false
|
|||
|
this.$message.error('两次密码输入不一致')
|
|||
|
return
|
|||
|
}
|
|||
|
result.push({
|
|||
|
...other,
|
|||
|
categoryId: param.elements[0].categoryId
|
|||
|
})
|
|||
|
})
|
|||
|
if (result.length === this.showParamList.length) data = result
|
|||
|
} else {
|
|||
|
this.$message.error('虚拟机信息未填写完整')
|
|||
|
}
|
|||
|
})
|
|||
|
return data
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped lang="scss"></style>
|