fix: 展示调整
parent
2d46aa7999
commit
309ec2e592
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="新增集群" width="40%" :close-on-click-modal="false" v-if="addData.dialog" :visible.sync="addData.dialog">
|
||||
<cb-form :model="addData.data" ref="data">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="地域:" prop="region" validate="required" required-message="请选择地域">
|
||||
<el-select v-model="addData.data.region" filterable>
|
||||
<el-option v-for="(item, index) in regions" :key="index" :label="item.regionName" :value="item.alias"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="addData.dialog = false">取消</el-button>
|
||||
<el-button type="primary" @click.native="ok">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import { modifyInstance, getTKERegions } from 'views/tce/services/tke.js'
|
||||
export default {
|
||||
props: {
|
||||
addData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
name: '',
|
||||
vendorId: -1
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
},
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
platformObject: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
regions: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getRegionList() {
|
||||
this.regions = []
|
||||
getTKERegions({
|
||||
tenantUuid: this.platformObject.tceTenantUuid,
|
||||
vendorId: this.vendorId
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.regions = data.data.regionInstanceSet
|
||||
}
|
||||
})
|
||||
},
|
||||
ok() {
|
||||
this.$refs.data.validate(valid => {
|
||||
if (valid) {
|
||||
const param = {
|
||||
id: this.addData.data.id,
|
||||
newName: this.addData.data.name
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
watch: {
|
||||
'addData.dialog': {
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.getRegionList()
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="绑定云主机" :visible.sync="addData.dialog" width="40%">
|
||||
<el-row>
|
||||
<el-form label-width="90px" :model="addData.data" ref="data">
|
||||
<cb-form-item label="云主机:" prop="serverId" validate="required" required-message="请选择云主机">
|
||||
<el-select v-model="addData.data.serverId">
|
||||
<el-option v-for="(item, index) in vmList" :label="item.name" :value="item.id" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click="addData.dialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="ok">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import { floatIpPorts } from 'views/tce/services/floatips.js'
|
||||
import { getVm } from 'views/tce/services/vms.js'
|
||||
export default {
|
||||
props: {
|
||||
addData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
labelIds: []
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
vmList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
this.$refs.data.validate(valid => {
|
||||
if (valid) {
|
||||
floatIpPorts(this.addData.data).then(data => {
|
||||
if (data.success) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: data.message
|
||||
})
|
||||
this.addData.dialog = false
|
||||
this.$parent.$parent.getData()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取可用域
|
||||
getVm() {
|
||||
getVm({
|
||||
simple: true,
|
||||
params: JSON.stringify([{ param: { vendorId: this.addData.data.vendorId, regionId: this.addData.data.regionId }, sign: 'EQ' }])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.vmList = data.data.rows
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getVm()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
<template>
|
||||
<div>
|
||||
<cb-advance-table @cell-click="handleCellClick" :data="clusterTableData" :params="params" :columns="Clustercolumns" :get-list="getClusterData" :total="total" :loading="loading">
|
||||
<template v-slot:action>
|
||||
<el-button type="primary" @click="addCluster()"> 新增 </el-button>
|
||||
</template>
|
||||
<template #name="val, record">
|
||||
<span class="detail-href" @click="getDetail(record)" v-if="record.clusterStatus !== 'Initializing'">{{ val }}</span>
|
||||
<span v-else>{{ val }}</span>
|
||||
</template>
|
||||
<template #clusterStatus="val">
|
||||
<cb-status-icon :type="val | tceClusterColor" v-if="val && val.toLowerCase() != 'stopped'">{{ val | tceClusterText }}</cb-status-icon>
|
||||
</template>
|
||||
<template #clusterOs="val">
|
||||
{{ val ? val : 'ubuntu16.04.1 LTSx86_64' }}
|
||||
</template>
|
||||
<template #clusterVersion="val">
|
||||
{{ val && val.length > 0 ? val : '1.10.5' }}
|
||||
</template>
|
||||
<template #operate="val, record">
|
||||
<AssignTenant :detail="record" type="TKE" @back="getClusterData"></AssignTenant>
|
||||
<div class="action-divider"></div>
|
||||
<el-button type="text" @click="edit(record)" :disabled="record.clusterStatus == 'Initializing'"> 编辑 </el-button>
|
||||
<div class="action-divider"></div>
|
||||
<el-button type="text" @click="handleOperate({ flag: 3, row: record })" :disabled="record.status === 'BIND' || record.tenantName"> 删除 </el-button>
|
||||
</template>
|
||||
</cb-advance-table>
|
||||
<detail v-if="detaildialogVisible" :detail="detail" @back="detaildialogVisible = false" :platform-object="platformObject"></detail>
|
||||
<bind :add-data="bindData" v-if="bindData.dialog"></bind>
|
||||
<service ref="serviceTable" v-if="serviceVisible" :vendorId="platformObject.vendorId" :clusterInfo="clusterInfo" @close="closeService"></service>
|
||||
<modify-cluster :add-data="modifyClusterData" :vendor-id="platformObject.vendorId" v-if="modifyClusterData.dialog"></modify-cluster>
|
||||
<delete-cluster :data="deleteClusterData" :vendor-id="platformObject.vendorId" v-if="deleteClusterData.dialog" :clusterInfo="clusterInfo"></delete-cluster>
|
||||
<add-cluster :add-data="addClusterData" :vendor-id="platformObject.vendorId" :platform-object="platformObject" v-if="addClusterData.dialog"></add-cluster>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import bind from './bind.vue'
|
||||
import { getClusterList } from 'views/tce/services/tke.js'
|
||||
import { removeFloatIp, detailFloatIp } from 'views/tce/services/floatips.js'
|
||||
import { getRegion } from 'views/tce/services/regions.js'
|
||||
import service from './service/index.vue'
|
||||
import modifyCluster from './modifyCluster.vue'
|
||||
import deleteCluster from './deleteCluster.vue'
|
||||
import addCluster from './addCluster.vue'
|
||||
import webSocket from '@cmp/cmp-common/mixins/getGlobalSocket'
|
||||
import detail from './detail'
|
||||
import AssignTenant from 'views/platform/assign/index.vue'
|
||||
const Clustercolumns = [
|
||||
{
|
||||
label: 'ID',
|
||||
prop: 'clusterId',
|
||||
disabled: true,
|
||||
scopedSlots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
label: '名称',
|
||||
prop: 'name'
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'clusterStatus',
|
||||
scopedSlots: { customRender: 'clusterStatus' }
|
||||
},
|
||||
{
|
||||
label: '版本',
|
||||
prop: 'clusterVersion',
|
||||
scopedSlots: { customRender: 'clusterVersion' }
|
||||
},
|
||||
{
|
||||
label: '类型',
|
||||
prop: 'clusterType',
|
||||
customRender(val) {
|
||||
const map = {
|
||||
INDEPENDENT_CLUSTER: '独立集群'
|
||||
}
|
||||
return map[val] || val
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '节点数量',
|
||||
prop: 'clusterNodeNum'
|
||||
},
|
||||
{
|
||||
label: '所属租户',
|
||||
prop: 'tenantName'
|
||||
},
|
||||
{
|
||||
label: '描述',
|
||||
prop: 'clusterDescription'
|
||||
},
|
||||
{
|
||||
label: '系统',
|
||||
prop: 'clusterOs',
|
||||
scopedSlots: { customRender: 'clusterOs' }
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'gmtCreate'
|
||||
},
|
||||
{
|
||||
label: '操作',
|
||||
scopedSlots: { customRender: 'operate' },
|
||||
width: '220px'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
mixins: [webSocket],
|
||||
components: {
|
||||
bind,
|
||||
service,
|
||||
modifyCluster,
|
||||
deleteCluster,
|
||||
addCluster,
|
||||
detail,
|
||||
AssignTenant
|
||||
},
|
||||
props: {
|
||||
platformObject: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
vendorId: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
clusterInfo: {},
|
||||
instanceVisible: false,
|
||||
secrectVisible: false,
|
||||
serviceVisible: false,
|
||||
flexibleVisible: false,
|
||||
Clustercolumns,
|
||||
clusterTableData: [],
|
||||
activeName: 'first', // 从这里开始
|
||||
loading: false,
|
||||
detaildialogVisible: false,
|
||||
detail: {},
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 10
|
||||
},
|
||||
total: 0,
|
||||
addData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
},
|
||||
regionList: [],
|
||||
bindData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
},
|
||||
modifyClusterData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
},
|
||||
addClusterData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
},
|
||||
deleteClusterData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onmessage(data) {
|
||||
const arr = ['tke.modify.cluster', 'tke.delete.instance', 'tke.add.instance', 'tce.sync', 'tce.cluster', 'tke.create.cluster', 'tke.delete.cluster']
|
||||
if (arr.includes(data.operate)) {
|
||||
this.getClusterData()
|
||||
}
|
||||
},
|
||||
addCluster() {
|
||||
this.$router.push({ name: 'tceCreateCluster', query: { vendorId: this.platformObject.vendorId } })
|
||||
},
|
||||
handleCellClick(data) {
|
||||
this.clusterInfo = data
|
||||
},
|
||||
edit(row) {
|
||||
this.modifyClusterData = {
|
||||
dialog: true,
|
||||
data: {
|
||||
name: row.name,
|
||||
id: row.id
|
||||
}
|
||||
}
|
||||
},
|
||||
handleOperate(command) {
|
||||
switch (command.flag) {
|
||||
case 1: // 密钥
|
||||
this.showSecrect(command.row)
|
||||
break
|
||||
case 2: // 服务
|
||||
this.showService(command.row)
|
||||
break
|
||||
case 3: // 删除
|
||||
this.deleteCluster(command.row)
|
||||
break
|
||||
case 4: // 添加已有节点
|
||||
this.addExistInstance(command.row)
|
||||
break
|
||||
case 5: // 伸缩组
|
||||
this.showFlexible(command.row)
|
||||
break
|
||||
case 'node':
|
||||
this.showInstance(command.row)
|
||||
break
|
||||
default:
|
||||
}
|
||||
},
|
||||
deleteCluster(row) {
|
||||
this.clusterInfo = row
|
||||
this.deleteClusterData = {
|
||||
dialog: true,
|
||||
mode: false,
|
||||
data: row
|
||||
}
|
||||
},
|
||||
closeService() {
|
||||
this.serviceVisible = false
|
||||
},
|
||||
showService(row) {
|
||||
this.serviceVisible = true
|
||||
this.clusterInfo = row
|
||||
},
|
||||
closeSecrect() {
|
||||
this.secrectVisible = false
|
||||
},
|
||||
showSecrect(row) {
|
||||
this.secrectVisible = true
|
||||
this.clusterInfo = row
|
||||
},
|
||||
showFlexible(row) {
|
||||
this.flexibleVisible = true
|
||||
this.clusterInfo = row
|
||||
},
|
||||
closeInstance() {
|
||||
this.instanceVisible = false
|
||||
},
|
||||
closeFlexible() {
|
||||
this.flexibleVisible = false
|
||||
},
|
||||
showInstance(row) {
|
||||
this.instanceVisible = true
|
||||
this.clusterInfo = row
|
||||
},
|
||||
getClusterData() {
|
||||
// if (this.instanceVisible) {
|
||||
// this.$refs.instanceTable.getData()
|
||||
// return
|
||||
// }
|
||||
this.loading = true
|
||||
this.clusterTableData = []
|
||||
this.total = 0
|
||||
const params = {
|
||||
page: this.params.page,
|
||||
rows: this.params.rows,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.platformObject.vendorId,
|
||||
tenantUuid: this.platformObject.tecTenantUuid,
|
||||
regionId: this.platformObject.tceRegionId
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}
|
||||
getClusterList(params).then(data => {
|
||||
if (data.success) {
|
||||
this.loading = false
|
||||
this.clusterTableData = data.data.rows
|
||||
this.total = data.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
createCluster() {
|
||||
this.$router.push({ name: 'tceClusterAdd', params: { id: this.platformObject.vendorId } })
|
||||
},
|
||||
// 详情
|
||||
getDetail(row) {
|
||||
this.detaildialogVisible = true
|
||||
this.detail = row
|
||||
},
|
||||
add() {
|
||||
this.addData = {
|
||||
dialog: true,
|
||||
data: {
|
||||
vendorId: this.platformObject.vendorId
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取域
|
||||
getRegion() {
|
||||
getRegion({ vendorId: this.platformObject.vendorId }).then(data => {
|
||||
if (data.success) {
|
||||
this.regionList = data.data
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$router.currentRoute.params.formCreateInstance) {
|
||||
this.showInstance(this.$router.currentRoute.params.clusterInfo)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
platformObject: {
|
||||
handler(newVal, oldVal) {
|
||||
this.getClusterData()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="分配IP" append-to-body :visible.sync="dialog.visible" width="400px" :close-on-click-modal="false">
|
||||
<div>
|
||||
<div>网段:{{ dialog.data.cidr }}</div>
|
||||
<div v-for="(item, index) in address" :key="index" class="m-t-md">
|
||||
<el-input v-model="address[index]"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click="dialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="ok">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { conditionSubnet } from 'views/tce/services/subnets.js'
|
||||
export default {
|
||||
props: {
|
||||
dialog: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
address: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
if (this.address.indexOf('') > -1) return this.$message.error('请输入IP')
|
||||
let flag = false
|
||||
const ary = []
|
||||
const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
|
||||
for (const a of this.address) {
|
||||
if (!reg.test(a)) {
|
||||
this.$message.error(`IP[${a}]输入有误`)
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
if (ary.indexOf(a) == -1) ary.push(a)
|
||||
if (this.dialog.data.allIpAddress.includes(a)) {
|
||||
this.$message.error(`IP[${a}]已经被其他节点占用,请选择其他可用IP`)
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (flag) return
|
||||
if (ary.length != this.address.length) return this.$message.error('IP输入重复')
|
||||
const { vendorId, SubnetId } = this.dialog.data
|
||||
conditionSubnet({
|
||||
condition: JSON.stringify({
|
||||
condition: 'ipCheck',
|
||||
vendorId,
|
||||
subnetUuid: SubnetId,
|
||||
ips: this.address
|
||||
})
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.$emit('setIp', this.address)
|
||||
this.dialog.visible = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const { InstanceCount, PrivateIpAddresses } = this.dialog.data
|
||||
for (let i = 0; i < InstanceCount; i++) {
|
||||
this.address.push(PrivateIpAddresses.length > i ? PrivateIpAddresses[i] : '')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
<template>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item :label="label">
|
||||
<div v-for="(node, index) in nodeList" :key="index" class="host-card">
|
||||
<el-row style="text-align: right" v-if="index != 0">
|
||||
<el-button type="text" style="padding-right: 30px !important" @click.native="deletNode(index)">删除</el-button>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="可用区:" :prop="type + 'List.' + index + '.zoneId'" validate="required" required-message="请选择可用域">
|
||||
<el-select v-model="node.zoneId" @change="handleZone(node)">
|
||||
<el-option v-for="(item, index) in zoneList" :label="item.name" :value="item.zoneId" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="节点网络:" :prop="type + 'List.' + index + '.SubnetId'" validate="required" required-message="请选择节点网络">
|
||||
<el-col :span="11" class="m-r-xs">
|
||||
<el-input v-model="addData.vpcName" disabled></el-input>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-select v-model="node.SubnetId" v-if="node.subnetList.length != 0" placeholder="请选择子网" @change="clearPrimaryIps(node)">
|
||||
<el-option v-for="(item, index) in node.subnetList" :label="item.name" :value="item.subnetUuid" :key="index"></el-option>
|
||||
</el-select>
|
||||
<span v-else style="color: red">此私有网络在该可用区无有效子网</span>
|
||||
</el-col>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="node.SubnetId">
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="分配IP:">
|
||||
<el-radio-group v-model="node.subentCreateType" class="m-r">
|
||||
<el-radio-button label="Automatic">自动分配</el-radio-button>
|
||||
<el-radio-button label="Manual">手动分配</el-radio-button>
|
||||
</el-radio-group>
|
||||
<template v-if="node.subentCreateType == 'Manual'">
|
||||
<el-button type="text" @click="openIpDialog(node)">指定IP</el-button>
|
||||
<el-tag v-for="item in node.PrivateIpAddresses" :key="item" class="m-l-sm">{{ item }}</el-tag>
|
||||
</template>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="机型:">
|
||||
{{ node.hostData.flavorUuid ? `${node.hostData.flavorUuid}(${node.hostData.cpu}核${node.hostData.memory}GB)` : '请先选择机型' }}
|
||||
<el-button type="text" icon="el-icon-edit" @click="openHostDialog(node)" :disabled="!node.zoneId"></el-button>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="系统盘:">
|
||||
{{ node.SystemDisk.DiskSize ? `${node.SystemDisk.diskCategory} ${node.SystemDisk.DiskSize}GB` : '暂不购买' }}
|
||||
<el-button type="text" :disabled="!node.zoneId" icon="el-icon-edit" @click="openDiskDialog('systemDisk', node)"></el-button>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="数据盘:">
|
||||
{{ node.DataDisks.DiskSize ? `${node.DataDisks.diskCategory} ${node.DataDisks.DiskSize}GB` : '暂不购买' }}
|
||||
<el-button type="text" :disabled="!node.zoneId" icon="el-icon-edit" @click="openDiskDialog('dataDisk', node)"></el-button>
|
||||
<el-button type="text" @click="cancelDiskData('DataDisks', node)" v-if="node.DataDisks.DiskSize">删除</el-button>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="数量:">
|
||||
<el-input-number :min="1" :max="100" v-model="node.InstanceCount"></el-input-number>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</cb-form-item>
|
||||
<cb-form-item label="">
|
||||
<el-button style="width: 100%" type="ghost" @click="addNode">添加机型</el-button>
|
||||
</cb-form-item>
|
||||
<HostDialog :dialog="hostDialog" v-if="hostDialog.visible" @getHostData="getHostData"></HostDialog>
|
||||
<DiskDialog :diskDialog="diskDialog" :platform-object="platformObject" v-if="diskDialog.visible" @getDiskData="getDiskData"></DiskDialog>
|
||||
<AssignIp v-if="assignIpDialog.visible" :dialog="assignIpDialog" @setIp="setIp"></AssignIp>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
<script>
|
||||
import { ref, computed } from 'vue'
|
||||
import { getSubnet } from 'views/tce/services/subnets.js'
|
||||
import HostDialog from './hostDialog.vue'
|
||||
import DiskDialog from './diskDialog.vue'
|
||||
import AssignIp from './AssignIpItem.vue'
|
||||
import { instanceParams } from './data'
|
||||
|
||||
export default {
|
||||
components: { HostDialog, DiskDialog, AssignIp },
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'master'
|
||||
},
|
||||
label: {
|
||||
type: String
|
||||
},
|
||||
zoneList: {},
|
||||
addData: {},
|
||||
nodeList: {
|
||||
type: Array
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const allIpAddress = computed(() => {
|
||||
const { masterList, nodeList } = props.addData
|
||||
const address = []
|
||||
;[...masterList, ...nodeList].forEach(item => {
|
||||
address.push(...item.PrivateIpAddresses)
|
||||
})
|
||||
return address
|
||||
})
|
||||
function deletNode(index) {
|
||||
props.nodeList.splice(index, 1)
|
||||
}
|
||||
function addNode() {
|
||||
props.nodeList.push({
|
||||
...instanceParams
|
||||
})
|
||||
}
|
||||
function cancelDiskData(type, node) {
|
||||
node[type] = {
|
||||
DiskType: '',
|
||||
DiskSize: ''
|
||||
}
|
||||
}
|
||||
const diskDialog = ref({})
|
||||
function getDiskData(data) {
|
||||
switch (data.type) {
|
||||
case 'systemDisk':
|
||||
currentNode.value.SystemDisk = data.data
|
||||
break
|
||||
case 'dataDisk':
|
||||
currentNode.value.DataDisks = data.data
|
||||
break
|
||||
default:
|
||||
}
|
||||
diskDialog.value.visible = false
|
||||
}
|
||||
function openDiskDialog(type, node) {
|
||||
currentNode.value = node
|
||||
diskDialog.value = {
|
||||
visible: true,
|
||||
type,
|
||||
regionId: this.addData.regionId,
|
||||
zoneId: node.zoneId,
|
||||
vendorId: this.addData.vendorId,
|
||||
data: type === 'systemDisk' ? node.SystemDisk : node.DataDisks
|
||||
}
|
||||
}
|
||||
// 选择主机
|
||||
function getHostData(data) {
|
||||
const item = currentNode.value
|
||||
item.hostData = data
|
||||
item.SystemDisk = {
|
||||
DiskType: 'CLOUD_SSD',
|
||||
DiskSize: 50,
|
||||
diskCategory: 'SSD云硬盘'
|
||||
}
|
||||
}
|
||||
const hostDialog = ref({
|
||||
visible: false,
|
||||
data: {}
|
||||
})
|
||||
const currentNode = ref({})
|
||||
function openHostDialog(node) {
|
||||
currentNode.value = node
|
||||
const { hostData } = node
|
||||
hostDialog.value = {
|
||||
visible: true,
|
||||
data: hostData,
|
||||
type: props.type,
|
||||
regionId: this.addData.regionId,
|
||||
zoneId: node.zoneId
|
||||
}
|
||||
}
|
||||
// IP分配
|
||||
const assignIpDialog = ref({})
|
||||
function openIpDialog(node) {
|
||||
currentNode.value = node
|
||||
const { SubnetId, PrivateIpAddresses, InstanceCount, subnetList } = node
|
||||
const obj = subnetList.find(item => item.subnetUuid == SubnetId)
|
||||
assignIpDialog.value = {
|
||||
visible: true,
|
||||
data: {
|
||||
cidr: obj.cidr,
|
||||
PrivateIpAddresses,
|
||||
InstanceCount,
|
||||
allIpAddress: allIpAddress.value.filter(item => !PrivateIpAddresses.includes(item)),
|
||||
SubnetId,
|
||||
vendorId: props.addData.vendorId
|
||||
}
|
||||
}
|
||||
}
|
||||
function setIp(data) {
|
||||
currentNode.value.PrivateIpAddresses = data
|
||||
}
|
||||
function clearPrimaryIps(node) {
|
||||
node.PrivateIpAddresses = []
|
||||
}
|
||||
// 子网
|
||||
function handleZone(node) {
|
||||
node.zoneName = props.zoneList.find(e => e.zoneId == node.zoneId).name
|
||||
// 数据清除
|
||||
node.SubnetId = ''
|
||||
cancelDiskData('SystemDisk', node)
|
||||
cancelDiskData('DataDisks', node)
|
||||
node.hostData = {}
|
||||
getSubnetList(node)
|
||||
}
|
||||
function getSubnetList(node) {
|
||||
getSubnet({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: props.addData.vendorId,
|
||||
networkId: props.addData.vpcNumberId,
|
||||
type: 0
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
node.subnetList = data.data.rows.filter(temp => temp.zone == node.zoneId)
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
deletNode,
|
||||
addNode,
|
||||
cancelDiskData,
|
||||
diskDialog,
|
||||
openDiskDialog,
|
||||
getDiskData,
|
||||
// 主机设置
|
||||
hostDialog,
|
||||
openHostDialog,
|
||||
getHostData,
|
||||
assignIpDialog,
|
||||
openIpDialog,
|
||||
setIp,
|
||||
clearPrimaryIps,
|
||||
handleZone
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.host-card {
|
||||
background-color: rgb(242, 242, 242) !important;
|
||||
padding: 18px 18px 0 18px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,509 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="地域:">
|
||||
<el-select v-model="region" @change="changeRegion">
|
||||
<el-option v-for="(item, index) in platformObject.tceRegionList" :label="item.name" :value="item.regionId" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="名称:" prop="name" validate="notZN,required" required-message="请输入名称">
|
||||
<el-input v-model="addData.name" maxlength="20" show-word-limit></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Kubernetes版本:" prop="kubernetes" validate="required" required-message="请选择Kubernetes版本">
|
||||
<el-select v-model="addData.kubernetes">
|
||||
<el-option v-for="(item, index) in kubernetesList" :label="item.version" :value="item.version" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器集群地域:" prop="regionId" validate="required" required-message="请选择地域">
|
||||
<el-select v-model="addData.regionId" @change="region">
|
||||
<el-option v-for="(item, index) in regionList" :label="item.regionName" :value="item.alias" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群网络:" prop="vpcId" validate="required" required-message="请选择集群网络">
|
||||
<el-select v-model="addData.vpcId" @change="handleVpc">
|
||||
<el-option v-for="(item, index) in vpcList" :key="index" :label="item.name" :value="item.vpcId"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器网络插件:" prop="networkPlug" validate="required" required-message="请选择容器网络插件">
|
||||
<el-radio-group v-model="addData.networkPlug" @change="handleNetwork">
|
||||
<el-radio-button label="router">Global Router</el-radio-button>
|
||||
<el-radio-button label="vpc">VPC-CNI</el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="addData.networkPlug == 'router'">
|
||||
<cb-form-item label="CIDR:">
|
||||
<el-select style="width: 100px" v-model="addData.one" @change="handleOne(1)">
|
||||
<el-option value="10"></el-option>
|
||||
<el-option value="172"></el-option>
|
||||
<el-option value="192"></el-option> </el-select
|
||||
> . <el-input-number @change="handleTwoValue" :disabled="addData.one === '192'" :title="title" v-model="addData.two" :min="twoMin" :max="twoMax" style="width: 100px" :controls="false"></el-input-number> . 0 . 0 /
|
||||
<el-select style="width: 100px" v-model="addData.end" @change="handleCIDR">
|
||||
<el-option value="14" v-if="addData.one == 10"></el-option>
|
||||
<el-option value="15" v-if="addData.one == 10"></el-option>
|
||||
<el-option value="16"></el-option>
|
||||
<el-option value="17"></el-option>
|
||||
<el-option value="18"></el-option>
|
||||
<el-option value="19"></el-option>
|
||||
<el-option value="20"></el-option>
|
||||
<el-option value="21"></el-option>
|
||||
<el-option value="22"></el-option>
|
||||
<el-option value="23"></el-option>
|
||||
<el-option value="24"></el-option>
|
||||
</el-select>
|
||||
<span style="color: red; display: block" v-if="!grIsOk && !addData.checkLoading && CIDRIndex">{{ grMessage }}</span>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.networkPlug == 'router'">
|
||||
<el-col :span="12">
|
||||
<cb-form-item label-width="200px" label="单节点Pod数量上限:" prop="podNum" validate="required" required-message="请选择单节点Pod数量上限">
|
||||
<el-select v-model="addData.podNum">
|
||||
<el-option value="16"></el-option>
|
||||
<el-option value="32"></el-option>
|
||||
<el-option value="64"></el-option>
|
||||
<el-option value="128"></el-option>
|
||||
<el-option value="256"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="addData.networkPlug == 'router'">
|
||||
<el-col :span="12">
|
||||
<cb-form-item label-width="200px" label="集群内Service数量上限:" prop="serviceNum" validate="required" required-message="请选择集群内Service数量上限">
|
||||
<el-select v-model="addData.serviceNum">
|
||||
<el-option value="32"></el-option>
|
||||
<el-option value="64"></el-option>
|
||||
<el-option value="128"></el-option>
|
||||
<el-option value="256"></el-option>
|
||||
<el-option value="512"></el-option>
|
||||
<el-option value="1024"></el-option>
|
||||
<el-option value="2048"></el-option>
|
||||
<el-option value="4096"></el-option>
|
||||
<el-option value="8192"></el-option>
|
||||
<el-option value="16384"></el-option>
|
||||
<el-option value="32768"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label=" " label-width="200px">
|
||||
<span class="tip">
|
||||
当前容器网络配置下,集群最多 <span class="text-danger">{{ maxNode }}</span> 个节点(含Master节点)。Master节点默认不支持部署业务POD,因此实际可用于部署业务的节点数为集群的节点数减去Master节点数。
|
||||
</span>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="addData.networkPlug == 'vpc'">
|
||||
<cb-form-item label="固定Pod IP:">
|
||||
<el-switch v-model="addData.podIpSwitch" @change="handlePodIpSwitch"></el-switch>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.networkPlug == 'vpc'">
|
||||
<cb-form-item label="容器子网:">
|
||||
<cb-advance-table ref="multipleTable" :data="subnetList" :columns="subnetColumns" :get-list="getSubnet" :loading="loading" @selection-change="handleSelectChange">
|
||||
<div slot="pagination"></div>
|
||||
</cb-advance-table>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.networkPlug == 'vpc'">
|
||||
<cb-form-item label="Service IP段:">
|
||||
<el-select style="width: 100px" v-model="addData.oneService" @change="handleOne(2)">
|
||||
<el-option value="10"></el-option>
|
||||
<el-option value="172"></el-option>
|
||||
<el-option value="192"></el-option> </el-select
|
||||
> . <el-input-number @change="handleTwoValue" :disabled="addData.oneService === '192'" :title="title" v-model="addData.twoService" :min="twoMin" :max="twoMax" style="width: 100px" :controls="false"></el-input-number> . 0 . 0 /
|
||||
<el-select style="width: 100px" v-model="addData.endService" @change="handleCIDR">
|
||||
<el-option value="14" v-if="addData.oneService == 10"></el-option>
|
||||
<el-option value="15" v-if="addData.oneService == 10"></el-option>
|
||||
<el-option value="16"></el-option>
|
||||
<el-option value="17"></el-option>
|
||||
<el-option value="18"></el-option>
|
||||
<el-option value="19"></el-option>
|
||||
<el-option value="20"></el-option>
|
||||
<el-option value="21"></el-option>
|
||||
<el-option value="22"></el-option>
|
||||
<el-option value="23"></el-option>
|
||||
<el-option value="24"></el-option>
|
||||
</el-select>
|
||||
<span style="color: red; display: block" v-if="!serveiceIpIsOk && !addData.checkLoading && CIDRIndex">{{ serveiceIpMessage }}</span>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="操作系统:" prop="system" validate="required" required-message="请选择操作系统">
|
||||
<el-select v-model="addData.system">
|
||||
<el-option v-for="(item, index) in systemList" :key="index" :label="item.alias" :value="item.osName"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群描述:">
|
||||
<el-input type="textarea" :rows="5" v-model="addData.ClusterDescription"></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<cb-form-item label="ipvs支持:" prop="ipvsSwitch" validate="required" required-message="请选择ipvs支持">
|
||||
<el-switch v-model="addData.ipvsSwitch"></el-switch>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getDescribeVersions, getTKERegions, createCluterImages, checkCIDR } from 'views/tce/services/tke.js'
|
||||
import { getVpc } from 'views/tce/services/vpcs.js'
|
||||
import { getSubnet } from 'views/tce/services/subnets.js'
|
||||
|
||||
const subnetColumns = [
|
||||
{
|
||||
type: 'selection',
|
||||
disabled: true,
|
||||
selectable: (row, index) => {
|
||||
return row.podIpSwitch ? row.vmNum == 0 : true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '子网',
|
||||
prop: 'subnetUuid'
|
||||
},
|
||||
{
|
||||
label: '子网名称',
|
||||
prop: 'name'
|
||||
},
|
||||
{
|
||||
label: '可用区',
|
||||
prop: 'zoneName'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
systemList: [],
|
||||
kubernetesList: [],
|
||||
vpcList: [],
|
||||
regionList: [],
|
||||
twoMin: 0,
|
||||
twoMax: 255,
|
||||
subnetList: [],
|
||||
loading: false,
|
||||
subnetColumns,
|
||||
selectionIds: [],
|
||||
zoneList: [],
|
||||
grTime: null,
|
||||
grMessage: '校验失败',
|
||||
grIsOk: true,
|
||||
serveiceIpTime: null,
|
||||
serveiceIpIsOk: false,
|
||||
serveiceIpMessage: '校验异常',
|
||||
CIDRIndex: 0,
|
||||
region: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
maxNode() {
|
||||
// (cidr IP数量 - 集群内Service数量上限) / 单节点Pod数量上限
|
||||
const { end, podNum, serviceNum } = this.addData
|
||||
return (Math.pow(2, 32 - end) - serviceNum) / podNum
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clearSubnet() {
|
||||
this.$refs.multipleTable.clearSelection()
|
||||
},
|
||||
getKubernetesList() {
|
||||
this.kubernetesList = []
|
||||
getDescribeVersions({
|
||||
tenantUuid: this.platformObject.tceTenantUuid,
|
||||
regionId: this.region
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.kubernetesList = data.data.versionInstanceSet
|
||||
}
|
||||
})
|
||||
},
|
||||
handleOne(type) {
|
||||
this.title = ''
|
||||
if (this.addData.one == '192') {
|
||||
this.addData.two = 168
|
||||
} else {
|
||||
this.addData.two = 0
|
||||
}
|
||||
if (this.addData.oneService == '192') {
|
||||
this.addData.twoService = 168
|
||||
} else {
|
||||
this.addData.twoService = 0
|
||||
}
|
||||
if ((this.addData.oneService == '10' && type == 2) || (this.addData.one == '10' && type == 1)) {
|
||||
this.title = '范围:0, 4, ... , 252'
|
||||
} else if ((this.addData.oneService == '172' && type == 2) || (this.addData.one == '172' && type == 1)) {
|
||||
this.title = '范围:16, 18, ... , 31'
|
||||
if (type == 1) {
|
||||
this.$set(this.addData, 'two', 16)
|
||||
}
|
||||
if (type == 2) {
|
||||
this.$set(this.addData, 'twoService', 16)
|
||||
}
|
||||
}
|
||||
this.handleCIDR()
|
||||
},
|
||||
handleTwoValue() {
|
||||
let value = 0
|
||||
if (this.addData.one == 10) {
|
||||
value = this.addData.two - (this.addData.two % 4)
|
||||
this.$set(this.addData, 'two', value)
|
||||
}
|
||||
if (this.addData.oneService == 10) {
|
||||
value = this.addData.twoService - (this.addData.twoService % 4)
|
||||
this.$set(this.addData, 'twoService', value)
|
||||
}
|
||||
if (this.addData.one == 172 && (this.addData.two == 17 || this.addData.two < 16 || this.addData.two > 31)) {
|
||||
this.$message.error('请按规则输入有效数字')
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.addData, 'two', 16)
|
||||
})
|
||||
}
|
||||
if (this.addData.oneService == 172 && (!this.addData.twoService || this.addData.twoService == 17 || this.addData.twoService < 16 || this.addData.twoService > 31)) {
|
||||
this.$message.error('请按规则输入有效数字')
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.addData, 'twoService', 16)
|
||||
})
|
||||
}
|
||||
this.handleCIDR()
|
||||
},
|
||||
handleCIDR() {
|
||||
this.grIsOk = false
|
||||
this.serveiceIpIsOk = false
|
||||
if (!this.addData.vpcId) {
|
||||
return
|
||||
}
|
||||
if (this.addData.networkPlug == 'vpc') {
|
||||
this.handleServiceIp()
|
||||
} else {
|
||||
this.handleCIDRgr()
|
||||
}
|
||||
},
|
||||
handleCIDRgr() {
|
||||
clearTimeout(this.grTime)
|
||||
this.grTime = setTimeout(() => {
|
||||
this.checkCIDRValue({
|
||||
vpcId: this.addData.vpcId,
|
||||
vendorId: this.vendorId,
|
||||
CIDR: `${this.addData.one}.${this.addData.two}.0.0/${this.addData.end}`
|
||||
})
|
||||
}, 500)
|
||||
},
|
||||
handleServiceIp() {
|
||||
clearTimeout(this.serveiceIpTime)
|
||||
this.serveiceIpTime = setTimeout(() => {
|
||||
this.checkCIDRValue({
|
||||
vpcId: this.addData.vpcId,
|
||||
vendorId: this.vendorId,
|
||||
CIDR: `${this.addData.oneService}.${this.addData.twoService}.0.0/${this.addData.endService}`
|
||||
})
|
||||
}, 500)
|
||||
},
|
||||
checkCIDRValue(params) {
|
||||
this.CIDRIndex++
|
||||
const index = this.CIDRIndex
|
||||
params.region = this.addData.regionId
|
||||
params.tenantUuid = this.platformObject.tceTenantUuid
|
||||
this.addData.checkLoading = true
|
||||
checkCIDR(params).then(data => {
|
||||
this.addData.checkLoading = false
|
||||
if (index == this.CIDRIndex) {
|
||||
if (data.success && data.data && !data.data.isConflict) {
|
||||
this.grIsOk = true
|
||||
this.serveiceIpIsOk = true
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: 'CIDR校验成功'
|
||||
})
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'CIDR校验失败,请重新填写'
|
||||
})
|
||||
this.grIsOk = false
|
||||
this.serveiceIpIsOk = false
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
getImages() {
|
||||
this.systemList = []
|
||||
createCluterImages({
|
||||
tenantUuid: this.platformObject.tceTenantUuid,
|
||||
vendorId: this.vendorId,
|
||||
regionId: this.region
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.systemList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
getData() {
|
||||
if (this.addData.checkLoading) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: '正在校验CIDR,请稍后'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.addData.networkPlug == 'vpc' && !this.serveiceIpIsOk && this.CIDRIndex) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'CIDR校验失败,请重新填写'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.addData.networkPlug == 'router' && !this.grIsOk && this.CIDRIndex) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'CIDR校验失败,请重新填写'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$refs.addData.validate(valid => {
|
||||
if (valid) {
|
||||
this.addData.kubernetesName = this.kubernetesList.find(item => item.version == this.addData.kubernetes).name
|
||||
this.addData.regionName = this.regionList.find(item => item.alias == this.addData.regionId).regionName
|
||||
this.addData.systemName = this.systemList.find(item => item.osName == this.addData.system).alias
|
||||
this.addData.imageId = this.systemList.find(item => item.osName == this.addData.system).imageId
|
||||
this.addData.vpcName = this.vpcList.find(item => item.vpcId == this.addData.vpcId).name
|
||||
this.addData.vpcNumberId = this.vpcList.find(item => item.vpcId == this.addData.vpcId).id
|
||||
this.addData.ClusterCIDR = this.addData.networkPlug == 'vpc' ? `${this.addData.oneService}.${this.addData.twoService}.0.0/${this.addData.endService}` : `${this.addData.one}.${this.addData.two}.0.0/${this.addData.end}`
|
||||
this.$emit('addStep')
|
||||
}
|
||||
})
|
||||
},
|
||||
handleZone() {
|
||||
this.handleSearchSpec()
|
||||
},
|
||||
// 搜索功能
|
||||
handleSelectChange(selection) {
|
||||
this.selectionIds = selection.map(item => item.id)
|
||||
this.addData.selectionSubnet = selection
|
||||
},
|
||||
handlePodIpSwitch() {
|
||||
this.clearSubnet()
|
||||
this.selectionIds = []
|
||||
this.addData.selectionSubnet = []
|
||||
this.initClick()
|
||||
},
|
||||
handleNetwork() {
|
||||
this.selectionIds = []
|
||||
this.addData.selectionSubnet = []
|
||||
},
|
||||
getRegionList() {
|
||||
this.regionList = []
|
||||
getTKERegions({
|
||||
tenantUuid: this.platformObject.tceTenantUuid,
|
||||
vendorId: this.vendorId,
|
||||
regionId: this.region
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.regionList = data.data.regionInstanceSet
|
||||
}
|
||||
})
|
||||
},
|
||||
handleVpc() {
|
||||
this.getSubnet()
|
||||
this.handleCIDR()
|
||||
},
|
||||
getSubnet() {
|
||||
this.loading = true
|
||||
getSubnet({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.vendorId,
|
||||
networkId: this.vpcList.find(item => item.vpcId == this.addData.vpcId).id,
|
||||
type: 0
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.loading = false
|
||||
this.subnetList = data.data.rows
|
||||
this.initClick()
|
||||
}
|
||||
})
|
||||
},
|
||||
initClick() {
|
||||
this.subnetList.forEach((item, index) => {
|
||||
item.podIpSwitch = this.addData.podIpSwitch
|
||||
})
|
||||
},
|
||||
getVpc() {
|
||||
getVpc({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([{ param: { vendorId: this.vendorId, tenantId: 0 }, sign: 'EQ' }])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.vpcList = data.data.rows
|
||||
if (this.addData.vpcId) this.getSubnet()
|
||||
}
|
||||
})
|
||||
},
|
||||
changeRegion() {
|
||||
this.getRegionList()
|
||||
this.getImages()
|
||||
this.getKubernetesList()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.handleOne(1)
|
||||
// this.getRegionList()
|
||||
this.getVpc()
|
||||
// this.getImages()
|
||||
// this.getKubernetesList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
export const instanceParams = {
|
||||
InstanceCount: 1,
|
||||
zoneName: '',
|
||||
zoneId: '',
|
||||
subnetList: [],
|
||||
SubnetId: '',
|
||||
hostType: '',
|
||||
flavorId: '',
|
||||
hostData: {},
|
||||
systemDiskCategory: '',
|
||||
rootSize: 50,
|
||||
subentCreateType: 'Automatic',
|
||||
PrivateIpAddresses: [],
|
||||
SystemDisk: {
|
||||
DiskType: '',
|
||||
DiskSize: ''
|
||||
},
|
||||
DataDisks: {
|
||||
DiskType: '',
|
||||
DiskSize: ''
|
||||
},
|
||||
publicIp: {
|
||||
type: '',
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<template>
|
||||
<el-dialog title="磁盘规格" width="40%" :close-on-click-modal="false" v-if="diskDialog.visible" :visible.sync="diskDialog.visible" append-to-body>
|
||||
<cb-form :model="configData" ref="diskDialog" label-width="160px" v-loading="loading">
|
||||
<el-alert type="warning" :closable="false" class="m-b-sm">SSD云硬盘为数据盘时不小于100G</el-alert>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="磁盘类型:" prop="categoryId" validate="required" required-message="该字段为必填字段">
|
||||
<el-radio-group v-model="configData.categoryId" @change="changeCategory()">
|
||||
<el-radio-button :label="item.id" v-for="(item, index) in diskTypeList" :key="index" :disabled="!item.available">
|
||||
<span v-if="!item.available">【售罄】</span>
|
||||
{{ item.name }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="磁盘大小(GB):" prop="DiskSize" validate="required,number" required-message="该字段为必填字段">
|
||||
<el-input-number step-strictly :step="configData.stepSize" :min="configData.minDiskSize" :max="configData.maxDiskSize" v-model.number="configData.DiskSize"> </el-input-number>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="diskDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click.native="ok">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCategoriesByCode } from 'views/tce/services/cloud.js'
|
||||
import { queryAvailable } from 'views/tce/services/cbs.js'
|
||||
export default {
|
||||
props: {
|
||||
diskDialog: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
diskTypeList: [],
|
||||
categoryMap: {},
|
||||
configData: {
|
||||
categoryId: '',
|
||||
DiskSize: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getCategoryList()
|
||||
},
|
||||
methods: {
|
||||
// 获取服务类型
|
||||
async getCategoryList() {
|
||||
const { vendorId, regionId, zoneId } = this.diskDialog
|
||||
const res = await queryAvailable({
|
||||
vendorId,
|
||||
regionId,
|
||||
diskChargeType: 'POSTPAID_BY_HOUR',
|
||||
zones: [zoneId],
|
||||
tenantUuid: this.platformObject.tceTenantUuid
|
||||
})
|
||||
if (!res.success) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
const map = {}
|
||||
res.data.forEach(item => {
|
||||
const { diskType } = item
|
||||
map[diskType] = item
|
||||
})
|
||||
const result = await getCategoriesByCode('tce.standard.volume')
|
||||
console.log(result)
|
||||
this.diskTypeList = result.data.map(item => {
|
||||
const { available, maxDiskSize, minDiskSize, stepSize } = map[item.code]
|
||||
const obj = {
|
||||
...item,
|
||||
available,
|
||||
maxDiskSize,
|
||||
minDiskSize,
|
||||
stepSize
|
||||
}
|
||||
this.categoryMap[item.code] = obj
|
||||
this.categoryMap[item.id] = obj
|
||||
return obj
|
||||
})
|
||||
const { DiskType, DiskSize } = this.diskDialog.data
|
||||
console.log('???', DiskType, DiskSize, this.diskDialog.data)
|
||||
console.log(this.diskTypeList)
|
||||
if (DiskType) {
|
||||
this.configData.categoryId = this.categoryMap[DiskType].id
|
||||
this.configData.DiskSize = DiskSize
|
||||
} else {
|
||||
this.configData.DiskSize = 50
|
||||
this.configData.categoryId = this.diskTypeList.find(item => item.available)?.id
|
||||
if (!this.configData.categoryId) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
}
|
||||
this.changeCategory()
|
||||
this.loading = false
|
||||
},
|
||||
ok() {
|
||||
this.$refs.diskDialog.validate(valid => {
|
||||
if (valid) {
|
||||
const { name: diskCategory, code: DiskType } = this.categoryMap[this.configData.categoryId]
|
||||
this.diskDialog.data = {
|
||||
diskCategory,
|
||||
DiskType,
|
||||
DiskSize: this.configData.DiskSize
|
||||
}
|
||||
this.$emit('getDiskData', this.diskDialog)
|
||||
}
|
||||
})
|
||||
},
|
||||
changeCategory() {
|
||||
const { maxDiskSize, minDiskSize, stepSize, code } = this.categoryMap[this.configData.categoryId]
|
||||
this.configData = {
|
||||
...this.configData,
|
||||
maxDiskSize,
|
||||
minDiskSize,
|
||||
stepSize
|
||||
}
|
||||
// SSD云硬盘为数据盘时必须不小于100
|
||||
const { type } = this.diskDialog
|
||||
if (code === 'CLOUD_SSD' && type === 'dataDisk') {
|
||||
this.configData.minDiskSize = 100
|
||||
if (this.configData.DiskSize < 100) this.configData.DiskSize = 100
|
||||
} else {
|
||||
this.configData.minDiskSize = minDiskSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<h1>已选配置</h1>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群名:" prop="name">
|
||||
{{ addData.name }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Kubernetes版本:" prop="name">
|
||||
{{ addData.kubernetes }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="所在地域:" prop="name">
|
||||
{{ addData.regionName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器网络:" prop="name">
|
||||
{{ addData.ClusterCIDR }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="操作系统:" prop="name">
|
||||
{{ addData.systemName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider></el-divider>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="数据盘挂载:" prop="system" validate="required" required-message="请选择操作系统">
|
||||
<el-checkbox v-model="addData.storeDiskSwitch">将容器和镜像存储在数据盘</el-checkbox>
|
||||
<div class="tip">将容器和镜像存储在数据盘将自动格式化数据盘成ext4且自动挂载到您指定的挂载点,并将容器存储到挂载点的docker目录,仅对购买数据盘的节点生效</div>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="addData.storeDiskSwitch">
|
||||
<cb-form-item label=" " prop="mountPath" validate="required" required-message="请选择挂载路径">
|
||||
<el-select v-model="addData.mountPath">
|
||||
<el-option v-for="(item, index) in mountList" :key="index" :label="item.name" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
<div class="tip">数据盘挂载点:{{ addData.mountPath }}, 容器目录:{{ addData.mountPath }}</div>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<cb-form-item label="安全组:" prop="group" validate="required" required-message="请选择安全组">
|
||||
<el-select v-model="addData.group">
|
||||
<el-option v-for="(item, index) in groupList" :key="index" :label="item.name" :value="item.groupUuid"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<cb-form-item label="登录方式:" prop="loginWay" validate="required" required-message="请选择登录方式">
|
||||
<el-radio-group v-model="addData.loginWay">
|
||||
<el-radio-button label="password">设置密码</el-radio-button>
|
||||
<el-radio-button label="secretKey">立即关联密钥</el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay != 'auto'">
|
||||
<cb-form-item label="用户名:">{{ username }}</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay == 'password'" key="password">
|
||||
<cb-form-item label="密码:" prop="password" validate="required,tceClusterPassword" required-message="请输入密码">
|
||||
<el-input type="password" v-model="addData.password"></el-input>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay == 'password'" key="password2">
|
||||
<cb-form-item label="确认密码:" prop="password2" validate="required,tceClusterPassword" required-message="请输入确认密码">
|
||||
<el-input type="password" v-model="addData.password2"></el-input>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay == 'secretKey'" key="ssh">
|
||||
<cb-form-item label="SSH密钥:" prop="ssh" validate="required" required-message="请选择SSH密钥">
|
||||
<el-select v-model="addData.ssh">
|
||||
<el-option v-for="(item, index) in keyList" :key="index" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="安全加固:">
|
||||
<el-checkbox v-model="addData.SecurityService">免费开通</el-checkbox>
|
||||
<div class="tip">安装组件免费开通DDoS防护、WAF和云镜主机防护</div>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="云监控:">
|
||||
<el-checkbox v-model="addData.MonitorService">免费开通</el-checkbox>
|
||||
<div class="tip">免费开通云产品监控、分析和实施告警,安装组件获取主机监控指标</div>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="自定义数据:">
|
||||
<el-input type="textarea" :rows="5" v-model="addData.selfDefining"></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="封锁(cordon):">
|
||||
<el-checkbox v-model="addData.cordon">开启封锁</el-checkbox>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getGroup } from 'views/tce/services/sgroups.js'
|
||||
import { getKey } from 'views/tce/services/keypairs.js'
|
||||
import { computed } from 'vue'
|
||||
const mountList = [
|
||||
{ name: '/var/lib/docker', value: '/var/lib/docker' },
|
||||
{ name: '/data', value: '/data' },
|
||||
{ name: '/opt', value: '/opt' }
|
||||
]
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
activeStep: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mountList,
|
||||
groupList: [],
|
||||
keyList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
// 校验数据
|
||||
this.$refs.addData.validate(valid => {
|
||||
if (valid) {
|
||||
if (this.addData.loginWay == 'password' && this.addData.password !== this.addData.password2) return this.$message.error('两次密码输入不一致')
|
||||
if (this.addData.loginWay == 'secretKey') {
|
||||
this.addData.sshId = this.keyList.find(item => item.id == this.addData.ssh).fingerprint
|
||||
}
|
||||
this.$emit('addStep')
|
||||
}
|
||||
})
|
||||
},
|
||||
getKey() {
|
||||
this.keyList = []
|
||||
getKey({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.vendorId
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.keyList = data.data.rows
|
||||
}
|
||||
})
|
||||
},
|
||||
getGroup() {
|
||||
this.groupList = []
|
||||
getGroup({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.vendorId
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.groupList = data.data.rows
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const username = computed(() => {
|
||||
const { system } = props.addData
|
||||
if (system.includes('ubuntu')) return 'ubuntu'
|
||||
return 'root'
|
||||
})
|
||||
return {
|
||||
username
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeStep: {
|
||||
handler(val) {
|
||||
if (val == 2) {
|
||||
this.getGroup()
|
||||
this.getKey()
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hostClass {
|
||||
background-color: rgb(242, 242, 242) !important;
|
||||
padding-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="主机规格" width="50%" :close-on-click-modal="false" v-if="dialog.visible" :visible.sync="dialog.visible">
|
||||
<el-alert v-if="dialog.type === 'master'" type="warning" :closable="false" class="m-b-sm">master节点要求主机规格必须大于等于4核4GB</el-alert>
|
||||
<table-search :configs="searchConfigs" :on-search="handleSearch" class="m-b-sm"></table-search>
|
||||
<cb-table :data="list" :get-list="getList" :params="params" :total="total" highlight-current-row tooltip-effect="dark" stripe border fit>
|
||||
<template slot="empty"> 请选择付费方式及区域 </template>
|
||||
<el-table-column label="名称">
|
||||
<template slot-scope="scope">
|
||||
<el-radio :label="scope.row.flavorUuid" v-model="flavorId" @change="handleHost(scope.row)" :disabled="getSkuDisabled(scope.row)">
|
||||
{{ scope.row.name }}
|
||||
</el-radio>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格编码" prop="flavorUuid"> </el-table-column>
|
||||
<el-table-column label="cpu" prop="cpu"> </el-table-column>
|
||||
<el-table-column label="内存(GB)" prop="memory"> </el-table-column>
|
||||
</cb-table>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="dialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click.native="ok">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFlavor, getFlavorType } from 'views/tce/services/flavors.js'
|
||||
import { getDictChildrenTree } from 'views/tce/services/dictionaries.js'
|
||||
|
||||
const searchConfigs = [
|
||||
{
|
||||
label: '实例族',
|
||||
type: 'Select',
|
||||
value: 'className',
|
||||
data: []
|
||||
},
|
||||
{
|
||||
label: '实例类型',
|
||||
type: 'Select',
|
||||
value: 'familyName',
|
||||
data: []
|
||||
},
|
||||
{
|
||||
type: 'Input',
|
||||
label: '名称',
|
||||
value: 'name'
|
||||
},
|
||||
{
|
||||
type: 'Const',
|
||||
value: 'regionId',
|
||||
initValue: ''
|
||||
},
|
||||
{
|
||||
type: 'Const',
|
||||
value: 'zone',
|
||||
initValue: ''
|
||||
}
|
||||
]
|
||||
export default {
|
||||
props: {
|
||||
dialog: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchConfigs,
|
||||
flavorId: '',
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 10
|
||||
},
|
||||
total: 0,
|
||||
list: [],
|
||||
hostData: {},
|
||||
typeData: {},
|
||||
dictList: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDict()
|
||||
this.flavorId = this.dialog.data.flavorUuid
|
||||
this.handleHost(this.dialog.data)
|
||||
const { regionId, zoneId } = this.dialog
|
||||
this.searchConfigs[3].initValue = regionId
|
||||
this.searchConfigs[4].initValue = zoneId
|
||||
this.searchConfigs[0].onChange = this.changeType
|
||||
},
|
||||
methods: {
|
||||
// master节点规格必须大于4c4g
|
||||
getSkuDisabled(record) {
|
||||
const { cpu, memory } = record
|
||||
return this.dialog.type === 'master' && (cpu < 4 || memory < 4)
|
||||
},
|
||||
changeType(val, listQuery) {
|
||||
if (listQuery.familyName) listQuery.familyName = ''
|
||||
const map = {}
|
||||
const children = this.dictList.find(item => item.value == val)?.children || []
|
||||
children.forEach(item => {
|
||||
map[item.value] = item.name
|
||||
})
|
||||
this.searchConfigs[1].data = this.typeData[val].map(item => {
|
||||
return {
|
||||
id: item,
|
||||
name: map[item]
|
||||
}
|
||||
})
|
||||
},
|
||||
async getType(dict) {
|
||||
const typeMap = {}
|
||||
dict.forEach(item => {
|
||||
typeMap[item.value] = item.name
|
||||
})
|
||||
const { regionId, zoneId } = this.dialog
|
||||
const res = await getFlavorType({
|
||||
region: regionId,
|
||||
zone: zoneId
|
||||
})
|
||||
if (res.success) {
|
||||
this.typeData = res.data
|
||||
this.searchConfigs[0].data = Object.keys(res.data).map(item => {
|
||||
return {
|
||||
id: item,
|
||||
name: typeMap[item]
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
async getDict() {
|
||||
const res = await getDictChildrenTree({ value: 'specFilter' })
|
||||
this.dictList = res.data
|
||||
this.getType(res.data)
|
||||
},
|
||||
handleHost(row) {
|
||||
this.hostData = row
|
||||
},
|
||||
// 获取规格列表
|
||||
getList() {
|
||||
getFlavor(this.params).then(data => {
|
||||
if (data.success) {
|
||||
this.list = data.data.rows
|
||||
this.total = data.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSearch(params) {
|
||||
this.params.page = 1
|
||||
this.params.params = params
|
||||
this.getList()
|
||||
},
|
||||
ok() {
|
||||
if (this.flavorId) {
|
||||
this.$emit('getHostData', this.hostData)
|
||||
this.dialog.visible = false
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: '您还未选择机型'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
<template>
|
||||
<div class="wrapper-container">
|
||||
<el-card>
|
||||
<el-steps :active="activeStep" finish-status="success" style="margin: 0 auto 20px; width: 70%">
|
||||
<el-step title="集群信息"></el-step>
|
||||
<el-step title="选择机型"></el-step>
|
||||
<el-step title="云主机配置"></el-step>
|
||||
<el-step title="信息确认"></el-step>
|
||||
</el-steps>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 0">
|
||||
<cluster-item ref="clusterItem" :addData="addData" :vendor-id="vendorId" :platform-object="platformObject" @addStep="addStep"></cluster-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 1">
|
||||
<type-item ref="typeItem" :addData="addData" :vendor-id="vendorId" :activeStep="activeStep" :platform-object="platformObject" @addStep="addStep"></type-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 2">
|
||||
<host-config-item ref="hostConfigItem" :addData="addData" :vendor-id="vendorId" :activeStep="activeStep" :platform-object="platformObject" @addStep="addStep"></host-config-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 3">
|
||||
<info-item ref="infoItem" :addData="addData" :vendor-id="vendorId" :activeStep="activeStep"></info-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="m-b-lg">
|
||||
<el-col :span="6" :offset="5" v-if="activeStep == 0">
|
||||
<el-button type="ghost" style="width: 100%" @click="goBack">取消</el-button>
|
||||
</el-col>
|
||||
<el-col :span="6" :offset="5" v-if="activeStep != 0">
|
||||
<el-button type="primary" style="width: 100%" @click="addLastStep()">上一步</el-button>
|
||||
</el-col>
|
||||
<el-col :span="6" :offset="1" v-if="activeStep == 3">
|
||||
<el-button type="primary" style="width: 100%" @click="ok" :loading="loading">确定</el-button>
|
||||
</el-col>
|
||||
<el-col :span="6" :offset="1" v-if="activeStep != 3">
|
||||
<el-button type="primary" style="width: 100%" :disabled="nextStepDisabled()" @click="addNextStep()">下一步</el-button>
|
||||
</el-col>
|
||||
<el-button type="ghost" v-if="activeStep == 1 && masterNumber()" style="margin-left: 20px">master节点最少选择3台</el-button>
|
||||
<el-button type="ghost" v-if="activeStep == 0 && addData.checkLoading" style="margin-left: 20px">正在校验CIDR,请稍后</el-button>
|
||||
</el-col>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import clusterItem from './clusterItem.vue'
|
||||
import typeItem from './typeItem.vue'
|
||||
import infoItem from './infoItem.vue'
|
||||
import hostConfigItem from './hostConfigItem.vue'
|
||||
import { createCluter } from 'views/tce/services/tke.js'
|
||||
import { instanceParams } from './data'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {
|
||||
clusterItem,
|
||||
typeItem,
|
||||
infoItem,
|
||||
hostConfigItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
activeStep: 0,
|
||||
vendorId: parseInt(this.$route.query.vendorId),
|
||||
addData: {
|
||||
vendorId: parseInt(this.$route.query.vendorId),
|
||||
selectionSubnet: [],
|
||||
zoneList: [],
|
||||
imageId: -1,
|
||||
checkLoading: false,
|
||||
ClusterDescription: '',
|
||||
hostDialog: false,
|
||||
name: '',
|
||||
regionId: '',
|
||||
kubernetes: '',
|
||||
networkPlug: 'router',
|
||||
one: 10,
|
||||
two: 0,
|
||||
end: 16,
|
||||
oneService: 10,
|
||||
twoService: 0,
|
||||
endService: 16,
|
||||
podNum: 64,
|
||||
serviceNum: 1024,
|
||||
podIpSwitch: false,
|
||||
vpcNumberId: -1,
|
||||
system: '',
|
||||
ipvsSwitch: false,
|
||||
zoneId: '',
|
||||
kubernetesName: '',
|
||||
regionName: '',
|
||||
systemName: '',
|
||||
deploy: 'deployNow',
|
||||
ClusterCIDR: '',
|
||||
vpcName: '',
|
||||
masterList: [{ ...instanceParams }],
|
||||
nodeList: [{ ...instanceParams }],
|
||||
RunInstancesForNode: [
|
||||
{
|
||||
NodeRole: 'MASTER_ETCD',
|
||||
RunInstancesPara: []
|
||||
},
|
||||
{
|
||||
NodeRole: 'WORKER',
|
||||
RunInstancesPara: []
|
||||
}
|
||||
],
|
||||
storeDiskSwitch: true,
|
||||
mountPath: '/var/lib/docker',
|
||||
group: '',
|
||||
loginWay: 'password',
|
||||
password: '',
|
||||
password2: '',
|
||||
ssh: '',
|
||||
sshId: '',
|
||||
SecurityService: true,
|
||||
MonitorService: true,
|
||||
selfDefining: '',
|
||||
cordon: false
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
masterNumber() {
|
||||
let len = 0
|
||||
this.addData.masterList.forEach(item => {
|
||||
len += item.InstanceCount
|
||||
})
|
||||
return len < 3
|
||||
},
|
||||
nextStepDisabled() {
|
||||
if (this.activeStep == 1) {
|
||||
return this.masterNumber()
|
||||
} else if (this.activeStep == 0) {
|
||||
return this.addData.checkLoading
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
addStep() {
|
||||
this.activeStep++
|
||||
},
|
||||
addNextStep() {
|
||||
switch (this.activeStep) {
|
||||
case 0:
|
||||
this.$refs.clusterItem.getData()
|
||||
break
|
||||
case 1:
|
||||
this.$refs.typeItem.getData()
|
||||
break
|
||||
case 2:
|
||||
this.$refs.hostConfigItem.getData()
|
||||
break
|
||||
case 3:
|
||||
break
|
||||
default:
|
||||
}
|
||||
},
|
||||
addLastStep() {
|
||||
this.activeStep--
|
||||
},
|
||||
goBack() {
|
||||
sessionStorage.setItem('platformId', this.vendorId)
|
||||
this.$router.back(-1)
|
||||
sessionStorage.setItem('needRefresh', 1)
|
||||
},
|
||||
handleInsParams(nodes, LoginSettings) {
|
||||
const { vpcId, SecurityService, MonitorService } = this.addData
|
||||
const insParams = []
|
||||
nodes.forEach(node => {
|
||||
const {
|
||||
hostData,
|
||||
DataDisks,
|
||||
SystemDisk: { diskCategory, ...systemOthers },
|
||||
SubnetId,
|
||||
PrivateIpAddresses,
|
||||
subentCreateType,
|
||||
InstanceCount
|
||||
} = node
|
||||
const VirtualPrivateCloud = {
|
||||
VpcId: vpcId,
|
||||
SubnetId
|
||||
}
|
||||
if (subentCreateType === 'Manual') {
|
||||
VirtualPrivateCloud.PrivateIpAddresses = PrivateIpAddresses
|
||||
}
|
||||
const temp = {
|
||||
Version: '2017-03-12', // 接口版本号 写死
|
||||
InstanceChargeType: 'POSTPAID_BY_HOUR',
|
||||
InstanceChargePrepaid: {
|
||||
Period: 1,
|
||||
RenewFlag: 'NOTIFY_AND_MANUAL_RENEW',
|
||||
TimeUnit: 'MONTH'
|
||||
},
|
||||
Placement: {
|
||||
Zone: hostData.zone,
|
||||
ProjectId: 0
|
||||
},
|
||||
InstanceType: hostData.flavorUuid,
|
||||
ImageId: this.addData.imageId,
|
||||
SystemDisk: systemOthers,
|
||||
VirtualPrivateCloud,
|
||||
InternetAccessible: {
|
||||
// 公网不做
|
||||
InternetChargeType: 'TRAFFIC_POSTPAID_BY_HOUR',
|
||||
InternetMaxBandwidthOut: 0,
|
||||
PublicIpAssigned: false
|
||||
},
|
||||
InstanceCount,
|
||||
InstanceName: '',
|
||||
LoginSettings,
|
||||
SecurityGroupIds: [this.addData.group],
|
||||
EnhancedService: {
|
||||
SecurityService: {
|
||||
Enabled: SecurityService
|
||||
},
|
||||
MonitorService: {
|
||||
Enabled: MonitorService
|
||||
}
|
||||
},
|
||||
PurchaseSource: 'ocker_dashboard',
|
||||
UserData: ''
|
||||
}
|
||||
|
||||
if (DataDisks.DiskType) {
|
||||
const { diskCategory, ...others } = DataDisks
|
||||
temp.DataDisks = [others]
|
||||
}
|
||||
insParams.push(JSON.stringify(temp))
|
||||
})
|
||||
return insParams
|
||||
},
|
||||
ok() {
|
||||
let ClusterCIDRSettings = {}
|
||||
switch (this.addData.networkPlug) {
|
||||
case 'router':
|
||||
ClusterCIDRSettings = {
|
||||
ClusterCIDR: this.addData.ClusterCIDR,
|
||||
IgnoreClusterCIDRConflict: false, // 是否忽略CIDR校验,写死
|
||||
MaxNodePodNum: this.addData.podNum,
|
||||
MaxClusterServiceNum: this.addData.serviceNum
|
||||
}
|
||||
break
|
||||
case 'vpc':
|
||||
ClusterCIDRSettings = {
|
||||
ServiceCIDR: this.addData.ClusterCIDR,
|
||||
EniSubnetIds: this.addData.selectionSubnet.map(item => item.subnetUuid),
|
||||
MaxNodePodNum: this.addData.podNum,
|
||||
MaxClusterServiceNum: this.addData.serviceNum
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
let LoginSettings = {}
|
||||
switch (this.addData.loginWay) {
|
||||
case 'password':
|
||||
LoginSettings = {
|
||||
Password: this.addData.password
|
||||
}
|
||||
break
|
||||
case 'secretKey':
|
||||
LoginSettings = {
|
||||
KeyIds: [this.addData.sshId]
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
const RunInstancesParaMater = this.handleInsParams(this.addData.masterList, LoginSettings)
|
||||
let RunInstancesParaNode = []
|
||||
if (this.addData.deploy == 'deployNow') {
|
||||
RunInstancesParaNode = this.handleInsParams(this.addData.nodeList, LoginSettings)
|
||||
}
|
||||
this.addData.RunInstancesForNode = [
|
||||
{
|
||||
NodeRole: 'MASTER_ETCD',
|
||||
RunInstancesPara: RunInstancesParaMater
|
||||
}
|
||||
]
|
||||
if (this.addData.deploy == 'deployNow') {
|
||||
this.addData.RunInstancesForNode.push({
|
||||
NodeRole: 'WORKER',
|
||||
RunInstancesPara: RunInstancesParaNode
|
||||
})
|
||||
}
|
||||
const { mountPath, storeDiskSwitch } = this.addData
|
||||
const mount = storeDiskSwitch ? mountPath : ''
|
||||
const params = {
|
||||
vendorId: this.vendorId,
|
||||
region: this.addData.regionId,
|
||||
ClusterType: 'INDEPENDENT_CLUSTER',
|
||||
ClusterBasicSettings: {
|
||||
ClusterOs: this.addData.system,
|
||||
ClusterVersion: this.addData.kubernetes,
|
||||
ClusterName: this.addData.name,
|
||||
ClusterDescription: this.addData.ClusterDescription,
|
||||
VpcId: this.addData.vpcId,
|
||||
ProjectId: 0,
|
||||
TagSpecification: [
|
||||
{
|
||||
ResourceType: 'cluster',
|
||||
Tags: []
|
||||
}
|
||||
]
|
||||
},
|
||||
ClusterCIDRSettings: ClusterCIDRSettings,
|
||||
ClusterAdvancedSettings: {
|
||||
AsEnabled: false,
|
||||
IPVS: this.addData.ipvsSwitch,
|
||||
NetworkType: this.addData.networkPlug == 'router' ? 'GR' : 'VPC-CNI'
|
||||
},
|
||||
InstanceAdvancedSettings: {
|
||||
MountTarget: mount,
|
||||
DockerGraphPath: mount,
|
||||
Unschedulable: this.addData.cordon ? 1 : 0,
|
||||
UserScript: btoa(this.addData.selfDefining)
|
||||
},
|
||||
Version: '2018-05-25', // 接口版本号,写死
|
||||
RunInstancesForNode: this.addData.RunInstancesForNode
|
||||
}
|
||||
this.loading = true
|
||||
createCluter(params)
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: data.message
|
||||
})
|
||||
this.goBack()
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<h1>已选配置</h1>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群名:" validate="required" required-message="请输入名称">
|
||||
{{ addData.name }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Kubernetes版本:">
|
||||
{{ addData.kubernetes }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="所在地域:">
|
||||
{{ addData.regionName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器网络:">
|
||||
{{ addData.ClusterCIDR }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="计费模式:"> 按量计费 </cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="操作系统:">
|
||||
{{ addData.systemName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Master&Etcd机型:">
|
||||
<div v-for="(master, index) in addData.masterList" :key="index">
|
||||
<p>可用区域:{{ master.zoneName }}</p>
|
||||
<p>机型:{{ `${master.hostData.flavorUuid}(${master.hostData.cpu}核${master.hostData.memory}GB)` }}</p>
|
||||
<p>系统盘:{{ master.SystemDisk.DiskSize ? `${master.SystemDisk.diskCategory} ${master.SystemDisk.DiskSize}GB` : '暂不购买' }}</p>
|
||||
<p>数据盘: {{ master.DataDisks.DiskSize ? `${master.DataDisks.diskCategory} ${master.DataDisks.DiskSize}GB` : '暂不购买' }}</p>
|
||||
<p>公网带宽: {{ master.publicIp.switch ? `${master.publicIp.name} ${master.publicIp.value}Mbps` : '不访问公网' }}</p>
|
||||
<p>数量: {{ master.InstanceCount }}</p>
|
||||
</div>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="addData.deploy == 'deployNow'">
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Node机型:">
|
||||
<div v-for="(master, index) in addData.nodeList" :key="index">
|
||||
<p>可用区域:{{ master.zoneName }}</p>
|
||||
<p>机型:{{ `${master.hostData.flavorUuid}(${master.hostData.cpu}核${master.hostData.memory}GB)` }}</p>
|
||||
<p>系统盘:{{ master.SystemDisk.DiskSize ? `${master.SystemDisk.diskCategory} ${master.SystemDisk.DiskSize}GB` : '暂不购买' }}</p>
|
||||
<p>数据盘: {{ master.DataDisks.DiskSize ? `${master.DataDisks.diskCategory} ${master.DataDisks.DiskSize}GB` : '暂不购买' }}</p>
|
||||
<p>公网带宽: {{ master.publicIp.switch ? `${master.publicIp.name} ${master.publicIp.value}Mbps` : '不访问公网' }}</p>
|
||||
<p>数量: {{ master.InstanceCount }}</p>
|
||||
</div>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: '',
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="公网带宽" width="40%" :close-on-click-modal="false" v-if="publicIpData.dialog" :visible.sync="publicIpData.dialog">
|
||||
<cb-form :model="publicIpData.data" ref="publicIpData" label-width="160px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="" prop="switch">
|
||||
<el-checkbox v-model="publicIpData.data.switch">分配免费公网IP</el-checkbox>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="publicIpData.data.switch">
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="计费方式:" prop="type" validate="required" required-message="该字段为必填字段">
|
||||
<el-select v-model="publicIpData.data.type" placeholder="请选择">
|
||||
<el-option v-for="(item, index) in ipList" :key="index" :label="item.name" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="" prop="type" label-width="0px"> <el-input-number :min="1" :max="100" v-model.number="publicIpData.data.value"></el-input-number>Mbps </cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="publicIpData.dialog = false">取消</el-button>
|
||||
<el-button type="primary" @click.native="ok">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
export default {
|
||||
props: {
|
||||
publicIpData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
name: '',
|
||||
vendorId: -1
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ipList: [
|
||||
{ name: '按带宽计费', value: 'bandwidth' },
|
||||
{ name: '按流量计费', value: 'flow' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
this.$refs.publicIpData.validate(valid => {
|
||||
if (valid) {
|
||||
this.publicIpData.data.name = this.ipList.find(item => item.value == this.publicIpData.data.type).name
|
||||
this.$emit('getPublicIpData', this.publicIpData)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
watch: {}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<h1>已选配置</h1>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群名:" prop="name">
|
||||
{{ addData.name }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Kubernetes版本:" prop="name">
|
||||
{{ addData.kubernetes }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="所在地域:" prop="name">
|
||||
{{ addData.regionName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器网络:" prop="name">
|
||||
{{ addData.ClusterCIDR }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="操作系统:" prop="name">
|
||||
{{ addData.systemName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider></el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Master:"> 独立部署 </cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Node:" prop="deploy">
|
||||
<el-radio-group v-model="addData.deploy">
|
||||
<el-radio-button label="deployNow">立即部署</el-radio-button>
|
||||
<el-radio-button label="deployLater">暂不部署</el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="计费模式:"> 按量计费 </cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<InstanceItem label="Master&Etcd机型:" :nodeList="addData.masterList" :addData="addData" :zoneList="zoneList" :platform-object="platformObject"></InstanceItem>
|
||||
<InstanceItem type="node" v-if="addData.deploy == 'deployNow'" label="Node机型:" :nodeList="addData.nodeList" :addData="addData" :zoneList="zoneList" :platform-object="platformObject"></InstanceItem>
|
||||
<el-row> </el-row>
|
||||
<hostDialog :addData="addData" v-if="addData.hostDialog" :zone="zone" :vendorId="vendorId" :flavorId="flavorId" :hostIndex="hostIndex" @getHostData="getHostData"></hostDialog>
|
||||
<diskDialog :diskDialog="diskDialog" v-if="diskDialog.dialog" @getDiskData="getDiskData"></diskDialog>
|
||||
<publicIpDialog :publicIpData="publicIpData" v-if="publicIpData.dialog" @getPublicIpData="getPublicIpData"></publicIpDialog>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getTKERegions } from 'views/tce/services/tke.js'
|
||||
import { getZone } from 'views/tce/services/regions.js'
|
||||
import { getVpc } from 'views/tce/services/vpcs.js'
|
||||
import { getSubnet } from 'views/tce/services/subnets.js'
|
||||
import { getFlavor } from 'views/tce/services/flavors.js'
|
||||
import hostDialog from './hostDialog.vue'
|
||||
import diskDialog from './diskDialog.vue'
|
||||
import publicIpDialog from './publicIpDialog.vue'
|
||||
import InstanceItem from './InstanceItem.vue'
|
||||
|
||||
export default {
|
||||
components: { hostDialog, diskDialog, publicIpDialog, InstanceItem },
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
activeStep: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hostType: '',
|
||||
diskType: '',
|
||||
zoneList: [],
|
||||
zone: '',
|
||||
flavorId: '',
|
||||
hostIndex: '',
|
||||
publicIpData: {
|
||||
hostType: '',
|
||||
dialog: false,
|
||||
index: -1,
|
||||
data: {
|
||||
switch: false
|
||||
}
|
||||
},
|
||||
diskDialog: {
|
||||
dialog: false,
|
||||
hostType: '',
|
||||
type: '',
|
||||
index: -1,
|
||||
data: {
|
||||
type: '',
|
||||
value: '',
|
||||
diskName: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
// 校验
|
||||
this.$refs.addData.validate(valid => {
|
||||
if (valid) {
|
||||
// 节点信息校验
|
||||
const { masterList, nodeList, deploy } = this.addData
|
||||
let nodeFlag = true
|
||||
const nodes = [...masterList]
|
||||
if (deploy === 'deployNow') nodes.push(...nodeList)
|
||||
for (const a of nodes) {
|
||||
const { hostData, InstanceCount, subentCreateType, PrivateIpAddresses } = a
|
||||
if (!hostData.flavorUuid) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: '请选择机型信息'
|
||||
})
|
||||
nodeFlag = false
|
||||
break
|
||||
}
|
||||
if (subentCreateType === 'Manual' && InstanceCount !== PrivateIpAddresses.length) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: '指定IP与申请数量不一致,请检查'
|
||||
})
|
||||
nodeFlag = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!nodeFlag) return
|
||||
// master节点数校验
|
||||
let len = 0
|
||||
this.addData.masterList.forEach(item => {
|
||||
len += item.InstanceCount
|
||||
})
|
||||
if (len < 3) {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'master节点最少选择3台'
|
||||
})
|
||||
return false
|
||||
}
|
||||
this.$emit('addStep')
|
||||
}
|
||||
})
|
||||
},
|
||||
getPublicIpData(data) {
|
||||
if (data.hostType == 'master') {
|
||||
this.addData.matserList[data.index].publicIp = data.data
|
||||
}
|
||||
if (data.hostType == 'node') {
|
||||
this.addData.nodeList[data.index].publicIp = data.data
|
||||
}
|
||||
this.publicIpData.dialog = false
|
||||
},
|
||||
openIpDialog(index, hostType) {
|
||||
this.publicIpData = {
|
||||
dialog: true,
|
||||
index: index,
|
||||
hostType: hostType,
|
||||
data: {
|
||||
switch: false,
|
||||
type: this.addData.matserList[index].publicIp.type,
|
||||
value: this.addData.matserList[index].publicIp.value
|
||||
}
|
||||
}
|
||||
},
|
||||
canceldataDiskData(type, cate, index) {
|
||||
this.addData[type][index][cate] = {
|
||||
type: '',
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
getDiskData(data) {
|
||||
switch (data.type) {
|
||||
case 'systemDisk':
|
||||
if (data.hostType == 'master') {
|
||||
this.addData.matserList[data.index].sysDiskData = data.data
|
||||
}
|
||||
if (data.hostType == 'node') {
|
||||
this.addData.nodeList[data.index].sysDiskData = data.data
|
||||
}
|
||||
break
|
||||
case 'dataDisk':
|
||||
if (data.hostType == 'master') {
|
||||
this.addData.matserList[data.index].dataDiskData = data.data
|
||||
}
|
||||
if (data.hostType == 'node') {
|
||||
this.addData.nodeList[data.index].dataDiskData = data.data
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
this.diskDialog.dialog = false
|
||||
},
|
||||
openDiskDialog(type, data, index, hostType) {
|
||||
this.diskType = type
|
||||
this.diskDialog = {
|
||||
dialog: true,
|
||||
type: type,
|
||||
hostType: hostType,
|
||||
index: index,
|
||||
data: {
|
||||
type: data.type,
|
||||
value: data.value,
|
||||
diskName: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
getHostData(data, index) {
|
||||
if (this.hostType == 'master') {
|
||||
this.addData.matserList[index].hostData = data
|
||||
this.addData.matserList[index].sysDiskData = {
|
||||
type: 'CLOUD_SSD',
|
||||
value: 50,
|
||||
diskName: 'SSD云硬盘'
|
||||
}
|
||||
}
|
||||
if (this.hostType == 'node') {
|
||||
this.addData.nodeList[index].hostData = data
|
||||
this.addData.nodeList[index].sysDiskData = {
|
||||
type: 'CLOUD_SSD',
|
||||
value: 50,
|
||||
diskName: 'SSD云硬盘'
|
||||
}
|
||||
}
|
||||
},
|
||||
openHostDialog(index, hostType) {
|
||||
this.zone = this.addData.matserList[index].zoneId
|
||||
this.flavorId = ''
|
||||
this.hostIndex = index
|
||||
this.addData.hostDialog = true
|
||||
this.hostType = hostType
|
||||
},
|
||||
// 获取可用域
|
||||
getZoomData() {
|
||||
getZone({ vendorId: this.vendorId, regionId: this.addData.regionId }).then(data => {
|
||||
if (data.success) {
|
||||
this.zoneList = data.data
|
||||
this.addData.zoneList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
// 搜索功能
|
||||
handleSearchSpec() {
|
||||
this.params.page = 1
|
||||
this.params.params = this.handleSearchParam({
|
||||
vendorId: this.vendorId,
|
||||
instanceChargeType: 'POSTPAID_BY_HOUR',
|
||||
zone: this.addData.zoneId,
|
||||
status: 'SELL',
|
||||
'name:LK': this.searchData.name
|
||||
})
|
||||
this.getSpecList()
|
||||
},
|
||||
// 获取规格列表
|
||||
getSpecList() {
|
||||
getFlavor(this.params).then(data => {
|
||||
if (data.success) {
|
||||
this.instanceTypeData = data.data.rows
|
||||
this.total1 = data.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSelectChange(selection) {
|
||||
this.selectionIds = selection.map(item => item.id)
|
||||
this.selectionSubnet = selection
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
watch: {
|
||||
activeStep: {
|
||||
handler(val) {
|
||||
if (val == 1) {
|
||||
this.getZoomData()
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hostClass {
|
||||
background-color: rgb(242, 242, 242) !important;
|
||||
padding-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="删除集群" width="40%" :close-on-click-modal="false" v-if="data.dialog" :visible.sync="data.dialog">
|
||||
<div v-loading="loading">
|
||||
<cb-advance-table :showTools="false" :title="`该集群下拥有${total}个节点`" :data="instanceList" :columns="instanceColumns" :get-list="getInstance" :loading="loading" :height="200">
|
||||
<div slot="pagination"></div>
|
||||
<template #status="val">
|
||||
<cb-status-icon :type="val | tceInstanceColor" v-if="val != 'STOPPED'">{{ val | tceInstanceText }}</cb-status-icon>
|
||||
</template>
|
||||
</cb-advance-table>
|
||||
</div>
|
||||
<div style="padding-top: 20px; padding-ledt: 10px">
|
||||
<el-checkbox disabled checked>销毁按量计费的节点(销毁后不可恢复,请谨慎操作,并提前备份好数据)</el-checkbox>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="data.dialog = false">取消</el-button>
|
||||
<el-button type="primary" @click.native="ok">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import { getInstanceList, deleteCluster } from 'views/tce/services/tke.js'
|
||||
const instanceColumns = [
|
||||
{
|
||||
label: '节点ID',
|
||||
prop: 'uuid'
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
}
|
||||
]
|
||||
export default {
|
||||
props: {
|
||||
clusterInfo: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
name: '',
|
||||
vendorId: -1
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
},
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
total: 0,
|
||||
instanceColumns,
|
||||
instanceList: [],
|
||||
loading: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
const param = {
|
||||
id: this.data.data.id,
|
||||
mode: 'terminate'
|
||||
}
|
||||
deleteCluster(param, param.mode).then(data => {
|
||||
if (data.success) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: data.message
|
||||
})
|
||||
this.$emit('back')
|
||||
this.data.dialog = false
|
||||
}
|
||||
})
|
||||
},
|
||||
getInstance() {
|
||||
this.loading = true
|
||||
const params = {
|
||||
page: 1,
|
||||
rows: 9999999,
|
||||
params: JSON.stringify([{ param: { vendorId: this.vendorId, clusterId: this.clusterInfo.clusterId }, sign: 'EQ' }])
|
||||
}
|
||||
getInstanceList(params).then(data => {
|
||||
if (data.success) {
|
||||
this.loading = false
|
||||
this.instanceList = data.data.rows
|
||||
this.total = data.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
watch: {
|
||||
'data.dialog': {
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.getInstance()
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
<template>
|
||||
<div class="detail">
|
||||
<cb-detail class="common" :title="detail.name" @goBack="goBack">
|
||||
<div slot="custom_content">
|
||||
<el-tabs ref="tab" tab-position="top" type="border-card" v-model="active">
|
||||
<el-tab-pane label="基本信息" name="detail">
|
||||
<el-form label-width="140px" label-position="left">
|
||||
<el-row>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="集群名称">{{ detail.name }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="操作系统">{{ detail.clusterOs }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="集群ID">{{ detail.clusterId }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="状态">{{ detail.clusterStatus | tceClusterText }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="k8s版本">{{ detail.clusterVersion }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="节点数量">{{ detail.clusterNodeNum }}个</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="所在地域">{{ detail.regionId }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="所属租户">{{ detail.tenantName }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="节点网络">{{ clusterNetWorkSetting.vpcId }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="容器网络">{{ clusterNetWorkSetting.clusterCIDR }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="创建时间">{{ detail.gmtCreate }}</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><el-form-item label="描述">{{ detail.clusterDescription }}</el-form-item></el-col
|
||||
>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="节点管理" name="instance">
|
||||
<instance :detail="detail"></instance>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="伸缩组" name="2">
|
||||
<flexible :clusterInfo="detail" :vendor-id="detail.vendorId"></flexible>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="地域列表" name="3">
|
||||
<region :detail="detail" :platform-object="platformObject"></region>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="密钥信息" name="4">
|
||||
<key :detail="detail"></key>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</cb-detail>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import instance from './instance/index.vue'
|
||||
import key from './secrect/index'
|
||||
import flexible from './flexible/index'
|
||||
import region from './region/index.vue'
|
||||
export default {
|
||||
components: { instance, key, flexible, region },
|
||||
props: {
|
||||
detail: {
|
||||
type: Object
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
active: 'detail',
|
||||
clusterNetWorkSetting: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
sessionStorage.setItem('containerClusterInfo', JSON.stringify(this.detail))
|
||||
this.clusterNetWorkSetting = this.detail.clusterNetWorkSetting ? JSON.parse(this.detail.clusterNetWorkSetting) : {}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$emit('back')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bill-table ::v-deep .search {
|
||||
display: none !important;
|
||||
}
|
||||
.order-table {
|
||||
::v-deep .pagination-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="新增" width="70%" :close-on-click-modal="false" v-if="addData.dialog" :visible.sync="addData.dialog" append-to-body>
|
||||
<el-steps :active="active" finish-status="success">
|
||||
<el-step title="启动配置"></el-step>
|
||||
<el-step title="伸缩组配置"></el-step>
|
||||
</el-steps>
|
||||
<addConfig ref="config" v-show="active == 0" :vendorId="vendorId" :regionId="addData.data.clusterInfo.regionId" :platform-object="platformObject"></addConfig>
|
||||
<addAs ref="as" v-show="active == 1" :vendorId="vendorId" :clusterInfo="clusterInfo"></addAs>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="addData.dialog = false">取消</el-button>
|
||||
<el-button v-show="active == 0" type="primary" @click="next(1)">下一步</el-button>
|
||||
<el-button v-show="active == 1" type="primary" @click="next(0)">上一步</el-button>
|
||||
<el-button v-show="active == 1" type="primary" @click.native="ok" :loading="submitLoading">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addAsByCluster } from 'views/tce/services/as.js'
|
||||
import addConfig from './components/addConfig'
|
||||
import addAs from './components/addAs'
|
||||
export default {
|
||||
components: { addConfig, addAs },
|
||||
props: {
|
||||
clusterInfo: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
active: 0,
|
||||
configData: {},
|
||||
asData: {},
|
||||
submitLoading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
this.asData = this.$refs.as.getPostData()
|
||||
if (this.asData.subnetIds.length == 0) {
|
||||
this.$message.error('请选择子网')
|
||||
return
|
||||
}
|
||||
if (this.asData) {
|
||||
const str1 = this.asData.autoScalingGroupName
|
||||
const str2 = this.configData.launchConfigurationName
|
||||
this.asData.autoScalingGroupName = str2
|
||||
this.configData.launchConfigurationName = str1
|
||||
const params = {
|
||||
vendorId: this.vendorId,
|
||||
region: this.addData.data.clusterInfo.regionId,
|
||||
clusterId: this.addData.data.clusterInfo.clusterId,
|
||||
autoScalingGroupPara: JSON.stringify(this.asData),
|
||||
launchConfigurePara: JSON.stringify(this.configData),
|
||||
instanceAdvancedSettings: {
|
||||
mountTarget: '',
|
||||
dockerGraphPath: '/var/lib/docker',
|
||||
userScript: '',
|
||||
unschedulable: 0,
|
||||
labels: []
|
||||
}
|
||||
}
|
||||
this.submitLoading = true
|
||||
addAsByCluster(params).then(res => {
|
||||
this.submitLoading = false
|
||||
if (res.success) {
|
||||
this.$message.success(res.message)
|
||||
this.$emit('back')
|
||||
this.addData.dialog = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
next(n) {
|
||||
if (n == 1) {
|
||||
this.configData = this.$refs.config.getPostData()
|
||||
if (this.configData && this.configData.keypair == '设置密码' && this.configData.password != this.configData.endPassword) {
|
||||
this.$message.error('两次输入密码不一致!')
|
||||
return
|
||||
}
|
||||
if (this.configData) {
|
||||
this.active = n
|
||||
}
|
||||
} else if (n == 0) {
|
||||
this.active = n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
<template>
|
||||
<div>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="节点范围">
|
||||
<cb-form-item label="最小节点数">
|
||||
<el-input-number :min="0" :max="200" v-model.number="addData.minSize" @change="handleMinSize" placeholder="最小节点数"></el-input-number>
|
||||
</cb-form-item>
|
||||
<cb-form-item label="最大节点数">
|
||||
<el-input-number :min="addData.minSize" :max="200" v-model.number="addData.maxSize" placeholder="最大节点数"> </el-input-number>
|
||||
</cb-form-item>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="活动重试策略">
|
||||
<el-select v-model="addData.retryPolicy" placeholder="请选择">
|
||||
<el-option v-for="(item, index) in retryPolicyList" :key="index" :label="item.name" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="VPC">
|
||||
<el-select v-model="addData.vpcId" placeholder="请选择" @change="handleVpc" disabled>
|
||||
<el-option v-for="(item, index) in vpcList" :key="index" :label="`${item.vpcId} | ${item.name}`" :value="item.vpcId"> </el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="支持子网">
|
||||
<cb-advance-table ref="subnetList" :showTools="false" :data="subnetList" :columns="subnetColumns" :get-list="getVpc" :loading="tableLoading" @selection-change="handleSelectChange">
|
||||
<div slot="pagination"></div>
|
||||
</cb-advance-table>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getVpc } from 'views/tce/services/vpcs.js'
|
||||
import { getSubnet } from 'views/tce/services/subnets.js'
|
||||
const retryPolicyList = [
|
||||
{ name: '立即重试', value: 'IMMEDIATE_RETRY' },
|
||||
{ name: '间隔递增重试', value: 'INCREMENTAL_INTERVALS' }
|
||||
]
|
||||
const subnetColumns = [
|
||||
{
|
||||
type: 'selection',
|
||||
disabled: true,
|
||||
selectable: (row, index) => {
|
||||
return true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '子网',
|
||||
prop: 'subnetUuid'
|
||||
},
|
||||
{
|
||||
label: '子网名称',
|
||||
prop: 'name'
|
||||
},
|
||||
{
|
||||
label: '可用区',
|
||||
prop: 'zoneName'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
clusterInfo: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
addData: {
|
||||
autoScalingGroupName: '',
|
||||
maxSize: 0,
|
||||
minSize: 0,
|
||||
vpcId: '',
|
||||
subnetIds: [],
|
||||
retryPolicy: 'INCREMENTAL_INTERVALS'
|
||||
},
|
||||
subnetColumns,
|
||||
tableLoading: false,
|
||||
subnetList: [],
|
||||
loading: false,
|
||||
retryPolicyList,
|
||||
vpcList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getVpc() {
|
||||
this.tableLoading = true
|
||||
getVpc({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([{ param: { vendorId: this.vendorId }, sign: 'EQ' }])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.vpcList = data.data.rows
|
||||
this.addData.vpcId = JSON.parse(this.clusterInfo.clusterNetWorkSetting).vpcId
|
||||
this.getSubnetList(data.data.rows.find(item => item.vpcId == this.addData.vpcId).id)
|
||||
}
|
||||
})
|
||||
},
|
||||
handleVpc() {
|
||||
this.getSubnetList(this.vpcList.find(item => item.vpcId == this.addData.vpcId).id)
|
||||
},
|
||||
getSubnetList(vpcId) {
|
||||
getSubnet({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.vendorId,
|
||||
networkId: vpcId
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.tableLoading = false
|
||||
this.subnetList = data.data.rows
|
||||
}
|
||||
})
|
||||
},
|
||||
handleMinSize() {
|
||||
if (this.addData.maxSize < this.addData.minSize) {
|
||||
this.addData.maxSize = this.addData.minSize
|
||||
}
|
||||
},
|
||||
handleSelectChange(selection) {
|
||||
this.selectionIds = selection.map(item => item.id)
|
||||
this.addData.subnetIds = selection.map(item => item.subnetUuid)
|
||||
},
|
||||
getPostData() {
|
||||
let addData = ''
|
||||
this.$refs.addData.validate(valid => {
|
||||
if (valid) {
|
||||
addData = JSON.parse(JSON.stringify(this.addData))
|
||||
addData.vendorId = this.vendorId
|
||||
}
|
||||
})
|
||||
return addData
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getVpc()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,343 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="140px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="计费方式:">
|
||||
<el-radio-group v-model="addData.instanceChargeType">
|
||||
<el-radio-button label="POSTPAID_BY_HOUR">按量计费</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="可用地域:" prop="regionId" validate="required" required-message="请选择地域">
|
||||
<el-select v-model="addData.regionId" @change="region" disabled>
|
||||
<el-option v-for="(item, index) in regionList" :label="item.name" :value="item.regionId" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="可用区域:" prop="zoneId" validate="required" required-message="请选择可用域">
|
||||
<el-select v-model="addData.zoneId" @change="handleZone">
|
||||
<el-option v-for="(item, index) in zoneList" :label="item.name" :value="item.zoneId" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="启动配置名称:" prop="launchConfigurationName" validate="required,tceConfigName" required-message="请输入名称" maxlength="25">
|
||||
<el-input v-model="addData.launchConfigurationName"></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="镜像类型:">
|
||||
<el-radio-group v-model="addData.imageType" @change="chooseWay">
|
||||
<el-radio-button :disabled="!addData.regionId" :label="item.value" :key="index" v-for="(item, index) in typeList"> {{ item.name }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="系统类型:" required>
|
||||
<el-select filterable v-model="addData.imageName" @change="setImageId">
|
||||
<el-option v-for="(value, name, index) in imageList" :key="index" :label="name" :value="name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label-width="10px" label="" prop="imageId" validate="required" required-message="该字段为必填字段">
|
||||
<el-select filterable v-model="addData.imageId" @change="setOsCategory">
|
||||
<el-option v-for="(item, index) in imageList[addData.imageName]" :key="index" :label="item.name" :value="item.imageUuid"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" v-if="addData.zoneId">
|
||||
<!-- <flavor :add-data="addData" :vendor-id="vendorId" :az="addData.zoneId" :region="addData.regionId"></flavor> -->
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="登录方式:" validate="required">
|
||||
<el-radio-group v-model="keypair" @change="chooseLoginWay">
|
||||
<el-radio-button label="关联密钥"></el-radio-button>
|
||||
<el-radio-button label="设置密码"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="keypair == '关联密钥'">
|
||||
<cb-form-item label="云主机密钥:" prop="keypairName" validate="required" required-message="该字段为必填字段">
|
||||
<el-select v-model="addData.keypairName">
|
||||
<el-option v-for="item in keypairList" :key="item.id" :label="item.name" :value="item.fingerprint"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-else-if="keypair == '设置密码'">
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="登录密码:" prop="password" validate="required,tceClusterAsPassword" required-message="该字段为必填字段">
|
||||
<el-input type="password" v-model="addData.password" show-password></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="确认密码:" prop="endPassword" validate="required,tceClusterAsPassword" required-message="该字段为必填字段">
|
||||
<el-input type="password" v-model="addData.endPassword" show-password></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-col>
|
||||
<el-col v-else></el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="系统磁盘类型:" prop="systemDisk.diskType" validate="required" required-message="该字段为必填字段">
|
||||
<el-select v-model="addData.systemDisk.diskType" placeholder="请选择">
|
||||
<el-option :disabled="!item.available" v-for="(item, index) in diskTypeList" :key="index" :label="item.diskType | diskType" :value="item.diskType"> </el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="系统磁盘(GB):" prop="systemDisk.diskSize" validate="required,number" required-message="该字段为必填字段">
|
||||
<el-input-number :min="50" :max="1024" v-model.number="addData.systemDisk.diskSize" style="width: 100%"> </el-input-number>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="公网IP:">
|
||||
<el-radio-group v-model="addData.internetAccessible.publicIpAssigned">
|
||||
<el-radio-button :label="true">现在分配</el-radio-button>
|
||||
<el-radio-button :label="false">暂不分配</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="addData.internetAccessible.publicIpAssigned == true">
|
||||
<cb-form-item label="目标带宽" prop="internetAccessible.internetMaxBandwidthOut" validate="required">
|
||||
<el-slider v-model="addData.internetAccessible.internetMaxBandwidthOut" :min="0" :max="100"></el-slider>
|
||||
<el-input-number v-model="addData.internetAccessible.internetMaxBandwidthOut" :min="0" :max="100"></el-input-number> Mbps
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="安全组:" prop="securityGroupIds" validate="required" required-message="该字段为必填字段">
|
||||
<el-select v-model="addData.securityGroupIds" multiple placeholder="请选择">
|
||||
<el-option v-for="item in groupList" :key="item.id" :label="item.name" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRegion, getZone } from 'views/tce/services/regions.js'
|
||||
import { getGroup } from 'views/tce/services/sgroups.js'
|
||||
import { getKey } from 'views/tce/services/keypairs.js'
|
||||
import { conditionImage } from 'views/tce/services/images.js'
|
||||
import { queryAvailable } from 'views/tce/services/cbs.js'
|
||||
// import flavor from '../../../components/flavor'
|
||||
export default {
|
||||
// components: { flavor },
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
regionId: {
|
||||
// 容错处理
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
addData: {
|
||||
regionId: this.regionId,
|
||||
zoneId: '',
|
||||
imageId: '',
|
||||
imageName: '',
|
||||
imageType: 'PUBLIC',
|
||||
launchConfigurationName: '',
|
||||
instanceType: '',
|
||||
systemDisk: {
|
||||
diskType: '',
|
||||
diskSize: 50
|
||||
},
|
||||
internetAccessible: {
|
||||
internetChargeType: 'TRAFFIC_POSTPAID_BY_HOUR',
|
||||
internetMaxBandwidthOut: 0,
|
||||
publicIpAssigned: true
|
||||
},
|
||||
loginSettings: {},
|
||||
securityGroupIds: [],
|
||||
enhancedService: {
|
||||
securityService: {
|
||||
enabled: true
|
||||
},
|
||||
monitorService: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
instanceChargeType: 'POSTPAID_BY_HOUR'
|
||||
},
|
||||
diskTypeList: [],
|
||||
zoneList: [],
|
||||
tagList: [],
|
||||
searchData: {
|
||||
name: ''
|
||||
},
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 5
|
||||
},
|
||||
instanceTypeData: [],
|
||||
total1: 0,
|
||||
groupList: [],
|
||||
keypair: '关联密钥',
|
||||
keypairList: [],
|
||||
regionList: [],
|
||||
typeList: [
|
||||
{ name: '公共镜像', value: 'PUBLIC' },
|
||||
{ name: '私有镜像', value: 'PRIVATE' }
|
||||
],
|
||||
imageList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
region() {
|
||||
this.addData.zoneId = ''
|
||||
this.addData.imageId = this.imageId || ''
|
||||
this.addData.securityGroupIds = []
|
||||
this.getZoomData()
|
||||
this.getGroupData()
|
||||
},
|
||||
handleZone() {
|
||||
this.getDisk()
|
||||
},
|
||||
getDisk() {
|
||||
queryAvailable({
|
||||
vendorId: this.vendorId,
|
||||
regionId: this.addData.regionId,
|
||||
diskChargeType: 'POSTPAID_BY_HOUR',
|
||||
zones: [this.addData.zoneId],
|
||||
tenantUuid: this.platformObject.tceTenantUuid
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.diskTypeList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取区域
|
||||
getRegion() {
|
||||
getRegion({ vendorId: this.vendorId }).then(data => {
|
||||
if (data.success) {
|
||||
this.regionList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取可用域
|
||||
getZoomData() {
|
||||
getZone({ vendorId: this.vendorId, regionId: this.addData.regionId }).then(data => {
|
||||
if (data.success) {
|
||||
this.zoneList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取安全组
|
||||
getGroupData() {
|
||||
getGroup({
|
||||
simple: true,
|
||||
params: JSON.stringify([{ param: { vendorId: this.vendorId, regionId: this.addData.regionId, tenantId: 0 }, sign: 'EQ' }])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.groupList = data.data.rows
|
||||
}
|
||||
})
|
||||
},
|
||||
// 切换登录方式
|
||||
chooseLoginWay(item) {
|
||||
if (this.keypair == '自动生成') {
|
||||
this.addData.loginType = 'auto'
|
||||
} else if (this.keypair == '关联密钥') {
|
||||
this.addData.loginType = 'keyIds'
|
||||
} else if (this.keypair == '设置密码') {
|
||||
this.addData.loginType = 'password'
|
||||
}
|
||||
},
|
||||
// 获取密钥
|
||||
getKeypair() {
|
||||
getKey({
|
||||
page: 1,
|
||||
rows: 99999,
|
||||
params: JSON.stringify([{ param: { vendorId: this.vendorId }, sign: 'EQ' }])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.keypairList = data.data.rows
|
||||
}
|
||||
})
|
||||
},
|
||||
setOsCategory() {
|
||||
this.imageList[this.addData.imageName].forEach(item => {
|
||||
if (item.id == this.addData.imageId) {
|
||||
this.$emit('setOsCategory', item)
|
||||
}
|
||||
})
|
||||
},
|
||||
chooseWay() {
|
||||
this.addData.imageName = ''
|
||||
this.addData.imageId = ''
|
||||
this.getImageData()
|
||||
},
|
||||
setImageId() {
|
||||
this.addData.imageId = ''
|
||||
if (this.vendorType == 'TENCENT') {
|
||||
this.addData.imageId = this.imageList[this.addData.imageName].length ? this.imageList[this.addData.imageName][0].id : ''
|
||||
this.setOsCategory()
|
||||
}
|
||||
},
|
||||
getImageData() {
|
||||
conditionImage({
|
||||
condition: 'listByImageType',
|
||||
vendorId: this.vendorId,
|
||||
status: 'ACTIVE',
|
||||
tenantId: 0,
|
||||
regionId: this.addData.regionId,
|
||||
imageType: this.addData.imageType
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.imageList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
getPostData() {
|
||||
let addData = ''
|
||||
if (!this.addData.instanceType) {
|
||||
this.$message.error('请选择规格')
|
||||
return ''
|
||||
}
|
||||
this.$refs.addData.validate(valid => {
|
||||
if (valid) {
|
||||
addData = JSON.parse(JSON.stringify(this.addData))
|
||||
addData.vendorId = this.vendorId
|
||||
addData.keypair = this.keypair
|
||||
}
|
||||
})
|
||||
return addData
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getRegion()
|
||||
this.getKeypair()
|
||||
this.getImageData()
|
||||
this.region()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,424 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card v-if="tableData.length != 0 && wholeAllocationData">
|
||||
<div class="top-text">
|
||||
<h4>全局配置</h4>
|
||||
<el-button type="text" @click="wholeAllocatioEidt">编辑</el-button>
|
||||
</div>
|
||||
<el-form label-position="left" label-width="150px" :model="wholeAllocationData" class="top-form">
|
||||
<el-form-item label="自动伸容">
|
||||
{{ wholeAllocationData.isScaleDownEnabled ? '开启' : '已关闭' }}
|
||||
</el-form-item>
|
||||
<el-form-item label="最大并发缩容数" v-if="wholeAllocationData.isScaleDownEnabled">
|
||||
{{ wholeAllocationData.maxEmptyBulkDelete }}
|
||||
<el-tooltip class="item" effect="dark" content="只缩容符合完全空闲的空节点。如果存在Pod, 每次缩容最多一个节点" placement="top-start">
|
||||
<i class="el-icon-info"></i>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="缩容计算方法" v-if="wholeAllocationData.isScaleDownEnabled">
|
||||
Pod占用资源/可分配资源小于{{ wholeAllocationData.scaleDownUtilizationThreshold }}%开始判断缩容条件 <br />
|
||||
{{ wholeAllocationData.ignoreDaemonSetsUtilization ? 'DaemonSet类型不计入pod占用资源' : '' }}
|
||||
</el-form-item>
|
||||
<el-form-item label="节点连续空闲" v-if="wholeAllocationData.isScaleDownEnabled"> {{ wholeAllocationData.scaleDownUnneededTime }}分钟后被缩容 </el-form-item>
|
||||
<el-form-item label="集群扩容" v-if="wholeAllocationData.isScaleDownEnabled"> {{ wholeAllocationData.scaleDownDelay }}分钟后开始判断缩容条件 </el-form-item>
|
||||
<el-form-item label="不缩容节点" v-if="wholeAllocationData.isScaleDownEnabled">
|
||||
{{ wholeAllocationData.skipNodesWithLocalStorage ? '含有本地存储Pod的节点' : '' }} <br />
|
||||
{{ wholeAllocationData.skipNodesWithSystemPods ? '含有kube-system namespace下非DaemonSet管理的Pod的节点' : '' }}
|
||||
</el-form-item>
|
||||
<el-form-item label="扩容算法">
|
||||
{{ wholeAllocationData.expander == 'random' ? '随机' : wholeAllocationData.expander }}
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<cb-advance-table @selection-change="handleSelectChange" :data="tableData" :params="params" :columns="column" :get-list="getData" :total="total" :loading="loading">
|
||||
<template v-slot:action>
|
||||
<el-button type="primary" @click="addAsByCluster"> 新增伸缩组 </el-button>
|
||||
</template>
|
||||
<template #status="val">
|
||||
<cb-status-icon :type="val | tceInstanceColor" v-if="val != 'STOPPED'">{{ val | tceInstanceText }}</cb-status-icon>
|
||||
</template>
|
||||
<template #stretchGroup="val">
|
||||
{{ val.launchConfigurationId }}<br />
|
||||
{{ val.launchConfigurationName }}
|
||||
</template>
|
||||
<template #operate="val, record">
|
||||
<el-button type="text" @click="moreOperate({ flag: 1, row: record })">调整配置</el-button>
|
||||
<el-button type="text" @click="moreOperate({ flag: 2, row: record })">删除</el-button>
|
||||
</template>
|
||||
</cb-advance-table>
|
||||
<el-dialog title="删除伸缩组" v-if="delectVisible" :visible.sync="delectVisible" width="600px" center append-to-body>
|
||||
<p>
|
||||
<strong>确定要删除ID为{{ delectPrams.autoScalingGroupId }}的伸缩组么?</strong>
|
||||
</p>
|
||||
<el-checkbox v-model="delectPrams.keepInstance" :true-label="1" :false-label="0">销毁按量计费的节点(销毁后不可恢复,请谨慎操作,并提前备份好数据)</el-checkbox>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="delectVisible = false">取 消</el-button>
|
||||
<el-button type="primary" v-loading="loading" @click="deleteData">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog title="调整伸缩组配置" v-if="allocationVisible" :visible.sync="allocationVisible" width="600px" :close-on-click-modal="false" center append-to-body>
|
||||
<el-form :model="allocationParams" class="demo-form-inline" label-width="80px">
|
||||
<el-form-item label="伸缩组ID">
|
||||
{{ allocationParams.AutoScalingGroupId }}
|
||||
</el-form-item>
|
||||
<el-form-item label="实例范围">
|
||||
<el-input-number size="mini" :precision="0" :min="0" v-model="allocationParams.MinSize"></el-input-number> ~
|
||||
<el-input-number size="mini" :precision="0" :min="allocationParams.MinSize" v-model="allocationParams.MaxSize"></el-input-number>
|
||||
<p>在设定的实例范围内自动调节,不会超出该设定范围</p>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="sumbit(null)">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog title="设置集群伸缩全局配置" v-if="wholeAllocationVisible" :visible.sync="wholeAllocationVisible" width="60%" :close-on-click-modal="false" append-to-body>
|
||||
<el-form :model="wholeAllocationForm" class="demo-form-inline" label-width="100px">
|
||||
<el-form-item label="自动伸缩">
|
||||
<el-checkbox v-model="wholeAllocationForm.isScaleDownEnabled">开启自动伸缩</el-checkbox> <br />
|
||||
<span>集群中节点空闲资源较多时将触发缩容</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="缩容配置" v-if="wholeAllocationForm.isScaleDownEnabled">
|
||||
<div class="info">
|
||||
<span
|
||||
>最大并发缩容数
|
||||
<el-tooltip class="item" effect="dark" content="只缩容符合完全空闲的空节点。如果存在Pod, 每次缩容最多一个节点" placement="top-start">
|
||||
<i class="el-icon-info"></i>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-input-number size="mini" :min="0" :max="200" v-model="wholeAllocationForm.maxEmptyBulkDelete"></el-input-number>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span>Pod占用资源/可分配资源小于</span>
|
||||
<el-input-number size="mini" :min="0" :max="80" v-model="wholeAllocationForm.scaleDownUtilizationThreshold"></el-input-number>
|
||||
<span>%时开始判断缩容条件</span>
|
||||
<p><span></span> 占比范围为0-80。</p>
|
||||
<p>
|
||||
<span></span>
|
||||
<el-checkbox v-model="wholeAllocationForm.ignoreDaemonSetsUtilization">DaemonSet类型不计入pod占用资源</el-checkbox>
|
||||
</p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span>节点连续空闲</span>
|
||||
<el-input-number size="mini" :min="0" v-model="wholeAllocationForm.scaleDownUnneededTime"></el-input-number>
|
||||
<span>分钟后被缩容</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span>集群扩容</span>
|
||||
<el-input-number size="mini" :min="0" v-model="wholeAllocationForm.scaleDownDelay"></el-input-number>
|
||||
<span>分钟后开始判断缩容条件</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span>不缩容节点</span>
|
||||
<el-checkbox v-model="wholeAllocationForm.skipNodesWithLocalStorage">含有本地存储Pod的节点</el-checkbox>
|
||||
<p>
|
||||
<span></span>
|
||||
<el-checkbox v-model="wholeAllocationForm.skipNodesWithSystemPods">含有kube-system namespace下非DaemonSet管理的Pod的节点</el-checkbox>
|
||||
</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="扩容算法">
|
||||
<el-radio-group v-model="wholeAllocationForm.expander">
|
||||
<el-radio label="random">随机</el-radio>
|
||||
<el-radio label="most-pods">most-pods</el-radio>
|
||||
<el-radio label="least-waste">least-waste</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" :loading="loading" @click="sumbit('wholeAllocationForm')">提交</el-button>
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<addAsDialog
|
||||
v-if="addAsByClusterData.dialog"
|
||||
:addData="addAsByClusterData"
|
||||
:vendorId="vendorId"
|
||||
:clusterInfo="clusterInfo"
|
||||
:platform-object="platformObject"
|
||||
@back="
|
||||
cancel()
|
||||
getData()
|
||||
"
|
||||
></addAsDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref, reactive, watch } from 'vue'
|
||||
import { getFlexibleList, delectFlexible, editFlexibleAllocation, getWholeAllocation, editWholeAllocation } from '../../../services/tke.js'
|
||||
import { Message } from 'element-ui'
|
||||
|
||||
import addAsDialog from './addAsDialog.vue'
|
||||
const columns = [
|
||||
{
|
||||
label: '伸缩组ID',
|
||||
prop: 'autoScalingGroupId'
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
label: '子机数量',
|
||||
prop: 'stretchGroup.instanceCount'
|
||||
},
|
||||
{
|
||||
label: '最小伸缩数',
|
||||
prop: 'stretchGroup.minSize'
|
||||
},
|
||||
{
|
||||
label: '最大伸缩数',
|
||||
prop: 'stretchGroup.maxSize'
|
||||
},
|
||||
{
|
||||
label: '启动配置ID/名称',
|
||||
prop: 'stretchGroup',
|
||||
scopedSlots: { customRender: 'stretchGroup' }
|
||||
},
|
||||
{
|
||||
label: '操作',
|
||||
prop: 'id',
|
||||
width: '160px',
|
||||
disabled: true,
|
||||
showOverflowTooltip: false,
|
||||
scopedSlots: { customRender: 'operate' }
|
||||
}
|
||||
]
|
||||
export default defineComponent({
|
||||
components: {
|
||||
addAsDialog
|
||||
},
|
||||
props: {
|
||||
clusterInfo: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
vendorId: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
setup(props, context) {
|
||||
const selectionIds = ref([])
|
||||
const column = ref(columns)
|
||||
const selection = ref([])
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const loading = ref(false)
|
||||
const delectVisible = ref(false)
|
||||
const allocationVisible = ref(false)
|
||||
const wholeAllocationVisible = ref(false)
|
||||
const wholeAllocationData = ref({})
|
||||
const wholeAllocationForm = ref({})
|
||||
const allocationParams = ref({
|
||||
MinSize: 0,
|
||||
MaxSize: 0
|
||||
})
|
||||
const addAsByClusterData = reactive({
|
||||
dialog: false,
|
||||
data: {}
|
||||
})
|
||||
const delectPrams = reactive({
|
||||
keepInstance: 1
|
||||
})
|
||||
const params = reactive({
|
||||
page: 1,
|
||||
rows: 10
|
||||
})
|
||||
function addAsByCluster() {
|
||||
addAsByClusterData.dialog = true
|
||||
addAsByClusterData.data = {
|
||||
clusterInfo: props.clusterInfo
|
||||
}
|
||||
}
|
||||
function goBack() {
|
||||
context.emit('close')
|
||||
}
|
||||
function handleSelectChange(selection) {
|
||||
selectionIds.value = selection.map(item => item.id)
|
||||
selection.value = selection
|
||||
}
|
||||
async function getData() {
|
||||
try {
|
||||
loading.value = true
|
||||
const listPrams = {
|
||||
...params,
|
||||
params: JSON.stringify([{ param: { vendorId: props.vendorId, clusterId: props.clusterInfo.clusterId }, sign: 'EQ' }])
|
||||
}
|
||||
const { data } = await getFlexibleList(listPrams)
|
||||
tableData.value = data.rows
|
||||
total.value = data.total
|
||||
const WholeParams = {
|
||||
...params,
|
||||
params: JSON.stringify([{ param: { clusterId: props.clusterInfo.clusterId }, sign: 'EQ' }])
|
||||
}
|
||||
const {
|
||||
data: { rows }
|
||||
} = await getWholeAllocation(WholeParams)
|
||||
wholeAllocationData.value = rows[0]
|
||||
cancel()
|
||||
} catch {
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
function moreOperate(command) {
|
||||
if (command.flag === 1) {
|
||||
allocationParams.value.id = command.row.id
|
||||
allocationParams.value.vendorId = command.row.vendorId
|
||||
allocationParams.value.ClusterId = command.row.clusterId
|
||||
allocationParams.value.AutoScalingGroupId = command.row.autoScalingGroupId
|
||||
allocationParams.value.MinSize = command.row.stretchGroup.minSize
|
||||
allocationParams.value.MaxSize = command.row.stretchGroup.maxSize
|
||||
allocationParams.value.name = command.row.stretchGroup.autoScalingGroupName
|
||||
allocationVisible.value = true
|
||||
} else {
|
||||
delectPrams.id = command.row.id
|
||||
delectPrams.name = command.row.stretchGroup.autoScalingGroupName
|
||||
delectPrams.autoScalingGroupId = command.row.autoScalingGroupId
|
||||
delectVisible.value = true
|
||||
}
|
||||
}
|
||||
async function deleteData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const { success } = await delectFlexible(delectPrams)
|
||||
if (success) {
|
||||
Message.success('删除成功')
|
||||
delectVisible.value = false
|
||||
getData()
|
||||
}
|
||||
} catch {
|
||||
delectVisible.value = false
|
||||
}
|
||||
}
|
||||
async function sumbit(type) {
|
||||
if (type) {
|
||||
loading.value = true
|
||||
try {
|
||||
const { success } = await editWholeAllocation(wholeAllocationForm.value)
|
||||
loading.value = false
|
||||
if (success) {
|
||||
Message.success('修改成功')
|
||||
cancel()
|
||||
getData()
|
||||
}
|
||||
} catch {
|
||||
loading.value = false
|
||||
}
|
||||
} else {
|
||||
if (allocationParams.value.MinSize > allocationParams.value.MaxSize) {
|
||||
Message.error('实例范围最大值不能小于最小值')
|
||||
} else {
|
||||
loading.value = true
|
||||
try {
|
||||
const { success } = await editFlexibleAllocation(allocationParams.value)
|
||||
loading.value = false
|
||||
if (success) {
|
||||
Message.success('修改成功')
|
||||
cancel()
|
||||
getData()
|
||||
} else {
|
||||
loading.value = false
|
||||
}
|
||||
} catch {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function wholeAllocatioEidt() {
|
||||
wholeAllocationVisible.value = true
|
||||
wholeAllocationForm.value = {
|
||||
...wholeAllocationData.value
|
||||
}
|
||||
}
|
||||
function cancel() {
|
||||
allocationVisible.value = false
|
||||
wholeAllocationVisible.value = false
|
||||
loading.value = false
|
||||
}
|
||||
watch(
|
||||
props.clusterInfo,
|
||||
() => {
|
||||
getData()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
return {
|
||||
addAsByCluster,
|
||||
addAsByClusterData,
|
||||
goBack,
|
||||
handleSelectChange,
|
||||
tableData,
|
||||
selectionIds,
|
||||
params,
|
||||
column,
|
||||
getData,
|
||||
total,
|
||||
loading,
|
||||
moreOperate,
|
||||
delectVisible,
|
||||
deleteData,
|
||||
delectPrams,
|
||||
allocationVisible,
|
||||
allocationParams,
|
||||
sumbit,
|
||||
cancel,
|
||||
wholeAllocationVisible,
|
||||
wholeAllocationData,
|
||||
wholeAllocatioEidt,
|
||||
wholeAllocationForm
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
div,
|
||||
p,
|
||||
h4 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.el-card {
|
||||
margin-bottom: 30px;
|
||||
.top-text {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.top-form .el-form-item {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
h4 {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
::v-deep .el-dialog {
|
||||
.info {
|
||||
color: #9e9e9e;
|
||||
margin-bottom: 10px;
|
||||
.el-input-number {
|
||||
margin-right: 3%;
|
||||
}
|
||||
p .el-checkbox .el-checkbox__label {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.info span {
|
||||
display: inline-block;
|
||||
width: 30%;
|
||||
margin-right: 5%;
|
||||
}
|
||||
.item {
|
||||
margin-left: 20px;
|
||||
color: #e4e464;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div>
|
||||
<cluster ref="containerTab" :platform-object="platformObject"></cluster>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import cluster from './cluster.vue'
|
||||
// 从 TCE 复制过来
|
||||
export default {
|
||||
props: {
|
||||
platformObject: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
vendorId: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cluster
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: 'containerTab'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
switch (this.activeName) {
|
||||
case 'containerTab':
|
||||
this.$refs.containerTab.getClusterData()
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.handleClick()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="添加已有节点" width="40%" :close-on-click-modal="false" v-if="addData.dialog" :visible.sync="addData.dialog" append-to-body>
|
||||
<div v-loading="loading">
|
||||
<cb-form :model="addData.data" ref="data">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="可用节点:" prop="instances" validate="required" required-message="请选择">
|
||||
<el-select v-model="addData.data.instances" filterable multiple>
|
||||
<el-option v-for="(item, index) in instanceList" :key="index" :label="`${item.instanceId}(${item.instanceName})`" :value="item.instanceId" :disabled="!item.usable"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="addData.dialog = false">取消</el-button>
|
||||
<el-button type="primary" @click.native="ok">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import { postAddInstance, getExistInstance } from 'views/tce/services/tke.js'
|
||||
export default {
|
||||
props: {
|
||||
addData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
name: '',
|
||||
vendorId: -1
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
},
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
clusterInfo: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
instanceList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getExistInstanceList() {
|
||||
this.loading = true
|
||||
this.instanceList = []
|
||||
const temp = JSON.parse(this.clusterInfo.clusterNetWorkSetting)
|
||||
const param = {
|
||||
vpcId: temp.vpcId,
|
||||
vendorId: this.vendorId,
|
||||
id: this.clusterInfo.id
|
||||
}
|
||||
getExistInstance(param, this.clusterInfo.id).then(data => {
|
||||
if (data.success) {
|
||||
this.loading = false
|
||||
this.instanceList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
ok() {
|
||||
this.$refs.data.validate(async valid => {
|
||||
if (valid) {
|
||||
const param = {
|
||||
vendorId: this.vendorId,
|
||||
ClusterId: this.addData.data.id,
|
||||
InstanceIds: this.addData.data.instances
|
||||
}
|
||||
const { success, message } = await postAddInstance(param)
|
||||
if (success) {
|
||||
this.$message.success(message)
|
||||
this.$emit('back')
|
||||
this.addData.dialog = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
watch: {
|
||||
'addData.dialog': {
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.getExistInstanceList()
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<h1>已选配置</h1>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群名:" prop="name">
|
||||
{{ addData.name }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Kubernetes版本:" prop="name">
|
||||
{{ addData.kubernetesName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="所在地域:" prop="name">
|
||||
{{ addData.regionName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器网络:" prop="name">
|
||||
{{ addData.clusterCIDR }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="操作系统:" prop="name">
|
||||
{{ addData.systemName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider></el-divider>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<cb-form-item label="系统盘:" prop="SystemDisk.DiskType" validate="required" required-message="请选择">
|
||||
<el-select v-model="addData.SystemDisk.DiskType" @change="changeDiskCategory('system')">
|
||||
<el-option v-for="(item, index) in diskTypeList" :key="index" :value="item.diskType" :label="item.diskType | diskTypeFilter(item)" :disabled="!item.available"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<cb-form-item label="" label-width="40px" prop="SystemDisk.DiskSize" validate="required" required-message="请选择">
|
||||
<el-slider :min="50" :max="1024" v-model="addData.SystemDisk.DiskSize" show-input>G </el-slider>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<cb-form-item label="数据盘:" prop="DataDiskFlag" validate="required" required-message="请选择">
|
||||
<el-radio-group v-model="addData.DataDiskFlag">
|
||||
<el-radio-button label="0">暂不购买</el-radio-button>
|
||||
<el-radio-button label="1">立即购买</el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="addData.DataDiskFlag == 1">
|
||||
<el-col :span="6">
|
||||
<cb-form-item label="数据盘:" prop="DataDisks.DiskType" validate="required" required-message="请选择">
|
||||
<el-select v-model="addData.DataDisks.DiskType" @change="changeDiskCategory('data')">
|
||||
<el-option v-for="(item, index) in diskTypeList" :key="index" :value="item.diskType" :label="item.diskType | diskTypeFilter(item)" :disabled="!item.available"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<cb-form-item label="" label-width="40px" prop="DataDisks.DiskSize" validate="required" required-message="请选择">
|
||||
<el-slider :min="addData.DataDisks.minDiskSize" :max="32000" v-model="addData.DataDisks.DiskSize" show-input>G </el-slider>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="addData.DataDiskFlag == 1">
|
||||
<el-col :span="8">
|
||||
<cb-form-item label="数据盘挂载:">
|
||||
<el-checkbox v-model="addData.storeDiskSwitch">将容器和镜像存储在数据盘</el-checkbox>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6" v-if="addData.storeDiskSwitch">
|
||||
<cb-form-item label="" label-width="0px" prop="mountPath" validate="required" required-message="请选择挂载路径">
|
||||
<el-select v-model="addData.mountPath">
|
||||
<el-option v-for="(item, index) in mountList" :key="index" :label="item.name" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<cb-form-item label="登录方式:" prop="loginWay" validate="required" required-message="请选择登录方式">
|
||||
<el-radio-group v-model="addData.loginWay">
|
||||
<el-radio-button label="password">设置密码</el-radio-button>
|
||||
<el-radio-button label="secretKey">立即关联密钥</el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay != 'auto'">
|
||||
<cb-form-item label="用户名:">
|
||||
{{ username }}
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay == 'password'" key="password">
|
||||
<cb-form-item label="密码:" prop="password" validate="required,tceClusterPassword" required-message="请输入密码">
|
||||
<el-input type="password" v-model="addData.password"></el-input>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay == 'password'" key="password2">
|
||||
<cb-form-item label="确认密码:" prop="password2" validate="required,tceClusterPassword" required-message="请输入确认密码">
|
||||
<el-input type="password" v-model="addData.password2"></el-input>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.loginWay == 'secretKey'" key="ssh">
|
||||
<cb-form-item label="SSH密钥:" prop="ssh" validate="required" required-message="请选择SSH密钥">
|
||||
<el-select v-model="addData.ssh">
|
||||
<el-option v-for="(item, index) in keyList" :key="index" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<cb-form-item label="主机名:" prop="instanceFlag" validate="required" required-message="请选择">
|
||||
<el-radio-group v-model="addData.instanceFlag">
|
||||
<el-radio-button label="0">自动命名</el-radio-button>
|
||||
<el-radio-button label="1">手动命名</el-radio-button>
|
||||
</el-radio-group>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="addData.instanceFlag == 1">
|
||||
<cb-form-item label="主机名:" prop="InstanceName" validate="required" required-message="请输入" maxlength="60">
|
||||
<el-input v-model="addData.InstanceName"></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<cb-form-item label="安全组:" prop="group" validate="required" required-message="请选择安全组">
|
||||
<el-select v-model="addData.group">
|
||||
<el-option v-for="(item, index) in groupList" :key="index" :label="item.name" :value="item.groupUuid"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="安全加固:">
|
||||
<el-checkbox v-model="addData.SecurityService">免费开通</el-checkbox>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="云监控:">
|
||||
<el-checkbox v-model="addData.MonitorService">免费开通</el-checkbox>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="自定义数据:">
|
||||
<el-input type="textarea" :rows="5" v-model="addData.selfDefining"></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="封锁(cordon):">
|
||||
<el-checkbox v-model="addData.cordon">开启封锁</el-checkbox>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getGroup } from 'views/tce/services/sgroups.js'
|
||||
import { getKey } from 'views/tce/services/keypairs.js'
|
||||
import { queryAvailable } from 'views/tce/services/cbs.js'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const mountList = [
|
||||
{ name: '/var/lib/docker', value: '/var/lib/docker' },
|
||||
{ name: '/data', value: '/data' },
|
||||
{ name: '/opt', value: '/opt' }
|
||||
]
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
activeStep: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mountList,
|
||||
groupList: [],
|
||||
keyList: [],
|
||||
diskTypeList: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'addData.zoneId'(val) {
|
||||
this.getDiskType(val)
|
||||
},
|
||||
activeStep: {
|
||||
handler(val) {
|
||||
if (val == 2) {
|
||||
this.getGroup()
|
||||
this.getKey()
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
diskTypeFilter(val, item) {
|
||||
const map = {
|
||||
CLOUD_BASIC: '普通云硬盘',
|
||||
CLOUD_PREMIUM: '高性能云硬盘',
|
||||
CLOUD_SSD: 'SSD云硬盘'
|
||||
}
|
||||
return `${!item.available ? '【售罄】' : ''}${map[val]}`
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const username = computed(() => {
|
||||
const { systemName } = props.addData
|
||||
if (systemName.includes('ubuntu')) return 'ubuntu'
|
||||
return 'root'
|
||||
})
|
||||
return {
|
||||
username
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeDiskCategory(type) {
|
||||
const {
|
||||
DataDisks,
|
||||
DataDisks: { DiskSize, DiskType }
|
||||
} = this.addData
|
||||
// SSD云硬盘为数据盘时必须不小于100
|
||||
if (DiskType === 'CLOUD_SSD' && type === 'data') {
|
||||
DataDisks.minDiskSize = 100
|
||||
if (DiskSize < 100) this.addData.DataDisks.DiskSize = 100
|
||||
} else {
|
||||
DataDisks.minDiskSize = 50
|
||||
}
|
||||
},
|
||||
getDiskType(az) {
|
||||
queryAvailable({
|
||||
vendorId: this.vendorId,
|
||||
diskChargeType: 'POSTPAID_BY_HOUR',
|
||||
zones: [az],
|
||||
regionId: this.addData.data.regionId,
|
||||
tenantUuid: this.platformObject.tceTenantUuid
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.diskTypeList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
getData() {
|
||||
// 校验数据
|
||||
if (this.addData.loginWay == 'password' && this.addData.password !== this.addData.password2) return this.$message.error('两次密码输入不一致')
|
||||
this.$refs.addData.validate(valid => {
|
||||
if (valid) {
|
||||
if (this.addData.loginWay == 'secretKey') {
|
||||
this.addData.sshId = this.keyList.find(item => item.id == this.addData.ssh).fingerprint
|
||||
}
|
||||
this.$emit('addStep')
|
||||
}
|
||||
})
|
||||
},
|
||||
getKey() {
|
||||
this.keyList = []
|
||||
getKey({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.vendorId
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.keyList = data.data.rows
|
||||
}
|
||||
})
|
||||
},
|
||||
getGroup() {
|
||||
this.groupList = []
|
||||
getGroup({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.vendorId
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.groupList = data.data.rows
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hostClass {
|
||||
background-color: rgb(242, 242, 242) !important;
|
||||
padding-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
<template>
|
||||
<div class="wrapper-container" v-loading="loading">
|
||||
<el-card>
|
||||
<el-steps :active="activeStep" finish-status="success" style="margin: 0 auto 20px; width: 70%">
|
||||
<el-step title="集群信息"></el-step>
|
||||
<el-step title="选择机型"></el-step>
|
||||
<el-step title="云主机配置"></el-step>
|
||||
<el-step title="信息确认"></el-step>
|
||||
</el-steps>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 0"> </el-col>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 1">
|
||||
<type-item v-if="vendorId && addData.regionId" ref="typeItem" :addData="addData" :vendor-id="vendorId" :platform-object="platformObject" :activeStep="activeStep" @addStep="addStep"></type-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 2">
|
||||
<host-config-item v-if="vendorId" ref="hostConfigItem" :addData="addData" :vendor-id="vendorId" :activeStep="activeStep" @addStep="addStep"></host-config-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="panel-body" v-show="activeStep == 3">
|
||||
<info-item ref="infoItem" :addData="addData" :vendor-id="vendorId" :activeStep="activeStep"></info-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="m-b-lg">
|
||||
<el-col :span="6" :offset="5" v-if="activeStep == 1">
|
||||
<el-button type="ghost" style="width: 100%" @click="goBack">取消</el-button>
|
||||
</el-col>
|
||||
<el-col :span="6" :offset="5" v-if="activeStep > 1">
|
||||
<el-button type="primary" style="width: 100%" @click="addLastStep()">上一步</el-button>
|
||||
</el-col>
|
||||
<el-col :span="6" :offset="1" v-if="activeStep == 3">
|
||||
<el-button type="primary" style="width: 100%" @click="ok" :loading="loading">确定</el-button>
|
||||
</el-col>
|
||||
<el-col :span="6" :offset="1" v-if="activeStep != 3">
|
||||
<el-button type="primary" style="width: 100%" @click="addNextStep()">下一步</el-button>
|
||||
</el-col>
|
||||
</el-col>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import typeItem from './typeItem.vue'
|
||||
import { getTKERegions, createInstance, getClusterDetail } from 'views/tce/services/tke.js'
|
||||
import { getVpc } from 'views/tce/services/vpcs.js'
|
||||
import hostConfigItem from './hostConfigItem.vue'
|
||||
import infoItem from './infoItem.vue'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {
|
||||
typeItem,
|
||||
hostConfigItem,
|
||||
infoItem
|
||||
},
|
||||
name: '',
|
||||
data() {
|
||||
return {
|
||||
vpcList: [],
|
||||
activeStep: 1,
|
||||
vendorId: 0,
|
||||
clusterInfo: {},
|
||||
loading: true,
|
||||
addData: {
|
||||
vpcName: '',
|
||||
vpcNumberId: '',
|
||||
InstanceCount: 1,
|
||||
name: '',
|
||||
kubernetesName: '',
|
||||
regionId: '', // 集群没有地域信息
|
||||
clusterCIDR: '',
|
||||
vpcId: '',
|
||||
systemName: '',
|
||||
hostDialog: false,
|
||||
SystemDisk: {
|
||||
DiskType: '',
|
||||
name: '',
|
||||
DiskSize: 50
|
||||
},
|
||||
DataDisks: {
|
||||
DiskType: '',
|
||||
name: '',
|
||||
DiskSize: 50
|
||||
},
|
||||
DataDiskFlag: 0,
|
||||
storeDiskSwitch: true,
|
||||
mountPath: '/var/lib/docker',
|
||||
group: '',
|
||||
cordon: '',
|
||||
selfDefining: '',
|
||||
ssh: '',
|
||||
sshId: '',
|
||||
password: '',
|
||||
password2: '',
|
||||
loginWay: 'password',
|
||||
instanceFlag: 0,
|
||||
InstanceName: '',
|
||||
subentCreateType: 'Automatic',
|
||||
PrivateIpAddresses: [],
|
||||
SecurityService: true,
|
||||
MonitorService: true,
|
||||
SubnetId: '',
|
||||
specData: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.vendorId = this.$route.query.vendorId / 1
|
||||
await this.getClusterInfo()
|
||||
this.getVpc()
|
||||
},
|
||||
methods: {
|
||||
async getRegionName(regionId) {
|
||||
const res = await getTKERegions({
|
||||
tenantUuid: this.platformObject.tceTenantUuid,
|
||||
vendorId: this.vendorId
|
||||
})
|
||||
if (res.success) {
|
||||
return res.data.regionInstanceSet.find(item => item.alias === regionId).regionName
|
||||
}
|
||||
},
|
||||
async getClusterInfo() {
|
||||
const res = await getClusterDetail(this.$route.query.clusterId)
|
||||
const { clusterName, clusterVersion, clusterId, imageId, region: regionId, clusterNetWorkSetting, clusterOs, vendorId } = res.data
|
||||
const { clusterCIDR, vpcId } = clusterNetWorkSetting
|
||||
this.addData = {
|
||||
...this.addData,
|
||||
name: clusterName,
|
||||
kubernetesName: clusterVersion,
|
||||
regionId,
|
||||
regionName: await this.getRegionName(regionId),
|
||||
systemName: clusterOs,
|
||||
clusterCIDR,
|
||||
vpcId,
|
||||
clusterId,
|
||||
vendorId,
|
||||
imageId
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
getVpc() {
|
||||
getVpc({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([{ param: { vendorId: this.vendorId }, sign: 'EQ' }])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.vpcList = data.data.rows
|
||||
const item = data.data.rows.find(item => item.vpcId == this.addData.vpcId)
|
||||
this.addData.vpcName = item.name
|
||||
this.addData.vpcNumberId = item.id
|
||||
}
|
||||
})
|
||||
},
|
||||
goBack() {
|
||||
this.$router.push({
|
||||
name: 'tceContainer'
|
||||
})
|
||||
},
|
||||
ok() {
|
||||
let LoginSettings = {}
|
||||
switch (this.addData.loginWay) {
|
||||
case 'password':
|
||||
LoginSettings = {
|
||||
Password: this.addData.password
|
||||
}
|
||||
break
|
||||
case 'secretKey':
|
||||
LoginSettings = {
|
||||
KeyIds: [this.addData.sshId]
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
const { SubnetId, PrivateIpAddresses, clusterId, subentCreateType, vpcId, zoneId, SystemDisk, group, DataDisks, DataDiskFlag, specData, InstanceCount, imageId, SecurityService, MonitorService } = this.addData
|
||||
const VirtualPrivateCloud = {
|
||||
VpcId: vpcId,
|
||||
SubnetId,
|
||||
AsVpcGateway: false
|
||||
}
|
||||
if (subentCreateType === 'Manual') {
|
||||
VirtualPrivateCloud.PrivateIpAddresses = PrivateIpAddresses
|
||||
}
|
||||
const RunInstancePara = {
|
||||
InstanceChargeType: 'POSTPAID_BY_HOUR',
|
||||
Placement: {
|
||||
Zone: zoneId,
|
||||
ProjectId: 0
|
||||
},
|
||||
InstanceType: specData.flavorUuid,
|
||||
SystemDisk: {
|
||||
DiskType: SystemDisk.DiskType,
|
||||
DiskSize: SystemDisk.DiskSize
|
||||
},
|
||||
DataDisks: [
|
||||
{
|
||||
DiskType: DataDisks.DiskType || 'CLOUD_SSD',
|
||||
DiskSize: DataDiskFlag == 1 ? DataDisks.DiskSize : 0
|
||||
}
|
||||
],
|
||||
VirtualPrivateCloud,
|
||||
InternetAccessible: {
|
||||
// 公网不做
|
||||
InternetChargeType: 'TRAFFIC_POSTPAID_BY_HOUR',
|
||||
InternetMaxBandwidthOut: 0,
|
||||
PublicIpAssigned: false
|
||||
},
|
||||
InstanceCount,
|
||||
ImageId: imageId,
|
||||
InstanceName: this.addData.instanceFlag == 1 ? this.addData.InstanceName : clusterId + '_worker',
|
||||
LoginSettings: LoginSettings,
|
||||
SecurityGroupIds: [group],
|
||||
EnhancedService: {
|
||||
SecurityService: {
|
||||
Enabled: SecurityService
|
||||
},
|
||||
MonitorService: {
|
||||
Enabled: MonitorService
|
||||
}
|
||||
}
|
||||
}
|
||||
const params = {
|
||||
vendorId: this.vendorId,
|
||||
ClusterId: clusterId,
|
||||
InstanceAdvancedSettings: {
|
||||
MountTarget: this.addData.mountPath,
|
||||
DockerGraphPath: this.addData.mountPath,
|
||||
UserScript: btoa(this.addData.selfDefining),
|
||||
Unschedulable: this.addData.cordon ? 1 : 0
|
||||
},
|
||||
RunInstancePara: JSON.stringify(RunInstancePara)
|
||||
}
|
||||
this.loading = true
|
||||
createInstance(params)
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: data.message
|
||||
})
|
||||
this.$router.push({
|
||||
name: 'tceContainer'
|
||||
})
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
addNextStep() {
|
||||
switch (this.activeStep) {
|
||||
case 1:
|
||||
this.$refs.typeItem.getData()
|
||||
break
|
||||
case 2:
|
||||
this.$refs.hostConfigItem.getData()
|
||||
break
|
||||
case 3:
|
||||
break
|
||||
default:
|
||||
}
|
||||
},
|
||||
addLastStep() {
|
||||
this.activeStep--
|
||||
},
|
||||
addStep() {
|
||||
this.activeStep++
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<h1>已选配置</h1>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群名:" validate="required" required-message="请输入名称">
|
||||
{{ addData.name }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Kubernetes版本:">
|
||||
{{ addData.kubernetesName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="所在地域:">
|
||||
{{ addData.regionName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器网络:">
|
||||
{{ addData.clusterCIDR }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="计费模式:"> 按量计费 </cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="规格:">
|
||||
{{ `${addData.specData.flavorUuid}(${addData.specData.cpu}核${addData.specData.memory}GB)` }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="系统盘:"> {{ diskTypeFilter(addData.SystemDisk.DiskType) }}({{ addData.SystemDisk.DiskSize }}G) </cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="数据盘:">
|
||||
{{ addData.DataDiskFlag == 1 ? `${diskTypeFilter(addData.DataDisks.DiskType)}(${addData.DataDisks.DiskSize})G` : `暂不购买` }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="操作系统:">
|
||||
{{ addData.systemName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
function diskTypeFilter(val) {
|
||||
const map = {
|
||||
CLOUD_BASIC: '普通云硬盘',
|
||||
CLOUD_PREMIUM: '高性能云硬盘',
|
||||
CLOUD_SSD: 'SSD云硬盘'
|
||||
}
|
||||
return map[val]
|
||||
}
|
||||
return {
|
||||
diskTypeFilter
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
<template>
|
||||
<cb-form :model="addData" ref="addData" label-width="160px">
|
||||
<h1>已选配置</h1>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="集群名:" prop="name">
|
||||
{{ addData.name }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="Kubernetes版本:" prop="name">
|
||||
{{ addData.kubernetesName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="所在地域:" prop="name">
|
||||
{{ addData.regionName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="容器网络:" prop="name">
|
||||
{{ addData.clusterCIDR }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="操作系统:" prop="name">
|
||||
{{ addData.systemName }}
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-divider></el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="计费模式:"> 按量计费 </cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="可用区:" prop="zoneId" validate="required" required-message="请选择可用域">
|
||||
<el-select v-model="addData.zoneId" @change="handleZone()">
|
||||
<el-option v-for="(item, index) in zoneList" :label="item.name" :value="item.zoneId" :key="index"></el-option>
|
||||
</el-select>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<cb-form-item label="节点网络:" prop="SubnetId" validate="required" required-message="请选择节点网络">
|
||||
<el-col :span="11" class="m-r-xs">
|
||||
<el-input v-model="addData.vpcName" disabled></el-input>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-select v-model="addData.SubnetId" v-if="subnetList.length != 0" placeholder="请选择子网" @change="setIp([])">
|
||||
<el-option v-for="(item, index) in subnetList" :label="item.name" :value="item.subnetUuid" :key="index"></el-option>
|
||||
</el-select>
|
||||
<span v-else style="color: red">此私有网络在该可用区无有效子网</span>
|
||||
</el-col>
|
||||
</cb-form-item>
|
||||
</el-row>
|
||||
<el-row v-if="addData.SubnetId">
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="分配IP:">
|
||||
<el-radio-group v-model="addData.subentCreateType" class="m-r">
|
||||
<el-radio-button label="Automatic">自动分配</el-radio-button>
|
||||
<el-radio-button label="Manual">手动分配</el-radio-button>
|
||||
</el-radio-group>
|
||||
<template v-if="addData.subentCreateType == 'Manual'">
|
||||
<el-button type="text" @click="openIpDialog()">指定IP</el-button>
|
||||
<el-tag v-for="item in addData.PrivateIpAddresses" :key="item" class="m-l-sm">{{ item }}</el-tag>
|
||||
</template>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<cb-form-item label="数量:">
|
||||
<el-input-number :min="1" :max="100" v-model="addData.InstanceCount"></el-input-number>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<SpecList :add-data="addData" :vendor-id="vendorId" :az="addData.zoneId" :region="addData.regionId" v-if="addData.zoneId" category="container"></SpecList>
|
||||
<AssignIp v-if="assignIpDialog.visible" :dialog="assignIpDialog" @setIp="setIp"></AssignIp>
|
||||
</cb-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SpecList from 'views/platform/components/abcstack/flavor.vue'
|
||||
import AssignIp from '../../creatCluster/AssignIpItem.vue'
|
||||
import { getSubnet } from 'views/tce/services/subnets.js'
|
||||
import { getZone } from 'views/tce/services/regions.js'
|
||||
|
||||
export default {
|
||||
components: { SpecList, AssignIp },
|
||||
name: '',
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
activeStep: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
subnetList: [],
|
||||
zoneList: [],
|
||||
assignIpDialog: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
// 校验
|
||||
this.$refs.addData.validate(valid => {
|
||||
if (valid) {
|
||||
if (!this.addData.specData.flavorUuid) {
|
||||
return this.$message.error('请选择主机规格')
|
||||
}
|
||||
const { PrivateIpAddresses, InstanceCount } = this.addData
|
||||
if (this.addData.subentCreateType === 'Manual' && InstanceCount !== PrivateIpAddresses.length) {
|
||||
return this.$message.error('指定IP与申请数量不一致,请检查')
|
||||
}
|
||||
this.$emit('addStep')
|
||||
}
|
||||
})
|
||||
},
|
||||
openIpDialog() {
|
||||
const { SubnetId, PrivateIpAddresses, InstanceCount } = this.addData
|
||||
const obj = this.subnetList.find(item => item.subnetUuid == SubnetId)
|
||||
this.assignIpDialog = {
|
||||
visible: true,
|
||||
data: {
|
||||
cidr: obj.cidr,
|
||||
PrivateIpAddresses,
|
||||
InstanceCount,
|
||||
allIpAddress: [],
|
||||
SubnetId,
|
||||
vendorId: this.vendorId
|
||||
}
|
||||
}
|
||||
},
|
||||
setIp(data) {
|
||||
this.addData.PrivateIpAddresses = data
|
||||
},
|
||||
// 获取可用域
|
||||
getZoomData() {
|
||||
getZone({ vendorId: this.vendorId, regionId: this.addData.regionId }).then(data => {
|
||||
if (data.success) {
|
||||
this.zoneList = data.data
|
||||
this.addData.zoneList = data.data
|
||||
}
|
||||
})
|
||||
},
|
||||
handleZone() {
|
||||
this.addData.SubnetId = ''
|
||||
this.getSubnet()
|
||||
},
|
||||
getSubnet() {
|
||||
getSubnet({
|
||||
page: 1,
|
||||
rows: 9999,
|
||||
params: JSON.stringify([
|
||||
{
|
||||
param: {
|
||||
vendorId: this.vendorId,
|
||||
networkId: this.addData.vpcNumberId,
|
||||
type: 0
|
||||
},
|
||||
sign: 'EQ'
|
||||
}
|
||||
])
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.subnetList = data.data.rows.filter(temp => temp.zone == this.addData.zoneId)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeStep: {
|
||||
handler(val) {
|
||||
if (val == 1) {
|
||||
this.getZoomData()
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hostClass {
|
||||
background-color: rgb(242, 242, 242) !important;
|
||||
padding-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="提示" :visible.sync="deleteData.dialog" width="30%" append-to-body>
|
||||
<p style="font-size: 18px">是否删除节点?</p>
|
||||
<el-checkbox v-model="deleteData.data.mode">销毁实例,仅支持按量计费云主机实例</el-checkbox>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click="deleteData.dialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="ok">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import { deleteInstance } from 'views/tce/services/tke.js'
|
||||
export default {
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
clusterInfo: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
deleteData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
labelIds: []
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
vmList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
const params = {
|
||||
vendorId: this.deleteData.data.vendorId,
|
||||
id: this.deleteData.data.id,
|
||||
instanceId: this.deleteData.data.instanceId,
|
||||
mode: this.deleteData.data.mode ? 'terminate' : 'retain'
|
||||
}
|
||||
deleteInstance(params, {
|
||||
instanceId: params.instanceId,
|
||||
mode: params.mode
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: data.message
|
||||
})
|
||||
this.deleteData.dialog = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="提示" :visible.sync="addData.dialog" width="30%" append-to-body>
|
||||
<p style="font-size: 18px">是否驱逐节点?</p>
|
||||
<span style="display: block">节点驱逐后,将会把节点内的所有Pod(不包含DaemonSet管理的Pod)从节点中驱逐到集群内其他节点,并将节点设置为封锁状态。</span>
|
||||
<span style="color: red; display: block">注意:本地存储的Pod被驱逐后数据将丢失,请谨慎操作</span>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click="addData.dialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="ok">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import { drain } from 'views/tce/services/tke.js'
|
||||
export default {
|
||||
props: {
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
addData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
labelIds: []
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
vmList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
const { instanceId, clusterId } = this.addData.data
|
||||
const params = {
|
||||
vendorId: this.vendorId,
|
||||
id: clusterId,
|
||||
instanceId
|
||||
}
|
||||
drain(params).then(data => {
|
||||
if (data.success) {
|
||||
this.$message.success(data.message)
|
||||
this.$emit('back')
|
||||
this.addData.dialog = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
<template>
|
||||
<div>
|
||||
<cb-advance-table @selection-change="handleSelectChange" :data="tableData" :params="params" :columns="columns" :get-list="getData" :total="total" :loading="loading">
|
||||
<template v-slot:action>
|
||||
<el-button type="primary" @click="creatInstance()"> 新增 </el-button>
|
||||
<el-button type="primary" @click="addExistInstance()"> 新增已有节点 </el-button>
|
||||
<el-button type="ghost" @click="handleDelete()" :disabled="selectionIds.length == 0"> 批量删除 </el-button>
|
||||
</template>
|
||||
<template #status="val">
|
||||
<cb-status-icon :type="val | tceInstanceColor" v-if="val != 'STOPPED'">{{ val | tceInstanceText }}</cb-status-icon>
|
||||
</template>
|
||||
<template #operate="val, record">
|
||||
<el-button type="text" @click="drain(record)" :disabled="record.instanceRole == 'MASTER_ETCD'"> 驱逐 </el-button>
|
||||
<div class="action-divider"></div>
|
||||
<el-button type="text" @click="remove([record.instanceId])" :disabled="record.instanceRole == 'MASTER_ETCD' || detail.tenantName"> 删除 </el-button>
|
||||
<div class="action-divider"></div>
|
||||
<el-button type="text" :disabled="record.instanceRole == 'MASTER_ETCD'" v-if="record.drainStatus === 'false'" @click.native="handleOperate('block', record)"> 封锁 </el-button>
|
||||
<el-button type="text" :disabled="record.instanceRole == 'MASTER_ETCD'" v-else @click.native="handleOperate('unblock', record)"> 解封 </el-button>
|
||||
</template>
|
||||
</cb-advance-table>
|
||||
<drain-instance :add-data="drainData" :vendorId="detail.vendorId" v-if="drainData.dialog" :detail="detail"></drain-instance>
|
||||
<delete-instance :delete-data="deleteData" v-if="deleteData.dialog"></delete-instance>
|
||||
<add-exist-instance :add-data="addExistInstanceData" :vendor-id="detail.vendorId" :clusterInfo="detail" v-if="addExistInstanceData.dialog"></add-exist-instance>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import drainInstance from './drainInstance.vue'
|
||||
import deleteInstance from './deleteInstance.vue'
|
||||
import { getInstanceList, operateInstance } from 'views/tce/services/tke.js'
|
||||
import addExistInstance from './addExistInstance.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
type: 'selection',
|
||||
disabled: true,
|
||||
selectable: (row, index) => {
|
||||
if (['MASTER_ETCD'].indexOf(row.instanceRole) == -1) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '节点ID',
|
||||
prop: 'instanceId'
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
scopedSlots: { customRender: 'status' }
|
||||
},
|
||||
{
|
||||
label: '角色',
|
||||
prop: 'instanceRole'
|
||||
},
|
||||
{
|
||||
label: '云盘类型',
|
||||
prop: 'usageType'
|
||||
},
|
||||
{
|
||||
label: '内网ip',
|
||||
prop: 'privateIpAddresses'
|
||||
},
|
||||
{
|
||||
label: '外网ip',
|
||||
prop: 'publicIpAddresses'
|
||||
},
|
||||
{
|
||||
label: '云盘类型',
|
||||
prop: 'diskType'
|
||||
},
|
||||
{
|
||||
label: '云盘大小',
|
||||
prop: 'diskSize'
|
||||
},
|
||||
{
|
||||
label: 'cpu核数',
|
||||
prop: 'cpu'
|
||||
},
|
||||
{
|
||||
label: '内存',
|
||||
prop: 'memory'
|
||||
},
|
||||
{
|
||||
label: '是否封锁',
|
||||
prop: 'drainStatus',
|
||||
customRender(value) {
|
||||
if (value === 'true') return '是'
|
||||
else return '否'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime'
|
||||
},
|
||||
{
|
||||
label: '操作',
|
||||
prop: 'id',
|
||||
width: '200px',
|
||||
disabled: true,
|
||||
showOverflowTooltip: false,
|
||||
scopedSlots: { customRender: 'operate' }
|
||||
}
|
||||
]
|
||||
export default {
|
||||
components: {
|
||||
drainInstance,
|
||||
deleteInstance,
|
||||
addExistInstance
|
||||
},
|
||||
props: {
|
||||
detail: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
name: '',
|
||||
data() {
|
||||
return {
|
||||
selectionIds: [],
|
||||
selection: [],
|
||||
columns,
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 10
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
loading: false,
|
||||
drainData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
},
|
||||
deleteData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
},
|
||||
addExistInstanceData: {
|
||||
dialog: false,
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onmessage(data) {
|
||||
const arr = ['tke.drain.instance', 'tke.delete.instance']
|
||||
if (arr.indexOf(data.operate) != -1) {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
async handleOperate(action, record) {
|
||||
const { clusterId, vendorId, privateIpAddresses: instanceIps } = record
|
||||
this.$confirm(`您确定要${action === 'block' ? '封锁' : '解封'}【${record.instanceId}】吗?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
confirmButtonClass: 'el-button--danger',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const res = await operateInstance({
|
||||
action,
|
||||
clusterId,
|
||||
vendorId,
|
||||
instanceIps
|
||||
})
|
||||
if (res.success) {
|
||||
this.$message.success(res.message)
|
||||
this.getData()
|
||||
}
|
||||
})
|
||||
},
|
||||
creatInstance() {
|
||||
this.$router.push({ name: 'tceInstanceAdd', query: { clusterId: this.detail.id, vendorId: this.detail.vendorId } })
|
||||
},
|
||||
addExistInstance() {
|
||||
this.addExistInstanceData = {
|
||||
dialog: true,
|
||||
data: {
|
||||
name: this.detail.name,
|
||||
id: this.detail.clusterId,
|
||||
instances: []
|
||||
}
|
||||
}
|
||||
},
|
||||
drain(row) {
|
||||
this.drainData = {
|
||||
dialog: true,
|
||||
data: {
|
||||
clusterId: this.detail.id,
|
||||
instanceId: row.instanceId
|
||||
}
|
||||
}
|
||||
},
|
||||
handleSelectChange(selection) {
|
||||
this.selectionIds = selection.map(item => item.id)
|
||||
this.selection = selection
|
||||
},
|
||||
handleDelete() {
|
||||
const arr = this.selection.map(item => item.instanceId)
|
||||
this.remove(arr)
|
||||
},
|
||||
remove(instanceId) {
|
||||
this.deleteData = {
|
||||
dialog: true,
|
||||
data: {
|
||||
vendorId: this.detail.vendorId,
|
||||
id: this.detail.id,
|
||||
instanceId: instanceId,
|
||||
mode: false
|
||||
}
|
||||
}
|
||||
},
|
||||
goBack() {
|
||||
this.$emit('close')
|
||||
},
|
||||
getData() {
|
||||
this.loading = true
|
||||
const params = {
|
||||
page: this.params.page,
|
||||
rows: this.params.rows,
|
||||
params: JSON.stringify([{ param: { vendorId: this.detail.vendorId, clusterId: this.detail.clusterId }, sign: 'EQ' }])
|
||||
}
|
||||
getInstanceList(params).then(data => {
|
||||
if (data.success) {
|
||||
this.loading = false
|
||||
this.tableData = data.data.rows
|
||||
this.total = data.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
detail: {
|
||||
handler(newVal, oldVal) {
|
||||
this.getData()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div>
|
||||
<cb-advance-table title="" :data="data" :params="params" :columns="columns" :get-list="getList" :total="total" :loading="loading" :search-configs="searchConfigs"> </cb-advance-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLogList } from 'views/tce/services/tke.js'
|
||||
const columns = [
|
||||
{
|
||||
label: 'ID',
|
||||
prop: 'clusterId',
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
label: '名称',
|
||||
prop: 'name',
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: ''
|
||||
},
|
||||
{
|
||||
label: '类型',
|
||||
prop: 'inputType'
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'gmtCreate'
|
||||
},
|
||||
{
|
||||
label: '集群',
|
||||
prop: 'clusterName'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
props: ['vendorId'],
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
columns,
|
||||
loading: false,
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 10
|
||||
},
|
||||
data: [],
|
||||
total: 0,
|
||||
searchConfigs: [{ type: 'Const', value: 'vendorId', initValue: this.vendorId }]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true
|
||||
getLogList(this.params).then(res => {
|
||||
this.loading = false
|
||||
if (res.success) {
|
||||
this.data = res.data.rows
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
vendorId: {
|
||||
handler(newVal, oldVal) {
|
||||
this.getList()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="编辑集群" width="40%" :close-on-click-modal="false" v-if="addData.dialog" :visible.sync="addData.dialog">
|
||||
<cb-form :model="addData.data" ref="data">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="24">
|
||||
<cb-form-item label="名称:" prop="name" validate="required" required-message="请输入名称" maxlength="60">
|
||||
<el-input v-model="addData.data.name"></el-input>
|
||||
</cb-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</cb-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="ghost" @click.native="addData.dialog = false">取消</el-button>
|
||||
<el-button type="primary" @click.native="ok">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global $ */
|
||||
import { modifyInstance } from 'views/tce/services/tke.js'
|
||||
export default {
|
||||
props: {
|
||||
addData: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {
|
||||
data: {
|
||||
name: '',
|
||||
vendorId: -1
|
||||
},
|
||||
dialog: false
|
||||
}
|
||||
}
|
||||
},
|
||||
vendorId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
ok() {
|
||||
this.$refs.data.validate(valid => {
|
||||
if (valid) {
|
||||
const param = {
|
||||
id: this.addData.data.id,
|
||||
newName: this.addData.data.name
|
||||
}
|
||||
modifyInstance(param).then(data => {
|
||||
if (data.success) {
|
||||
this.$message.success(data.message)
|
||||
this.$emit('back')
|
||||
this.addData.dialog = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<div>
|
||||
<cb-advance-table :data="tableData" :params="params" :columns="columns" :get-list="getData" :total="total" :loading="loading">
|
||||
<template #instanceState="val">
|
||||
<cb-status-icon :type="val | tceInstanceColor">{{ val | tceInstanceText }}</cb-status-icon>
|
||||
</template>
|
||||
<div slot="pagination"></div>
|
||||
</cb-advance-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getTKERegions } from 'views/tce/services/tke.js'
|
||||
const columns = [
|
||||
{
|
||||
label: '名称',
|
||||
prop: 'regionName'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
props: {
|
||||
detail: {
|
||||
type: Object
|
||||
},
|
||||
platformObject: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
name: '',
|
||||
data() {
|
||||
return {
|
||||
columns,
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 10
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$emit('close')
|
||||
},
|
||||
getData() {
|
||||
getTKERegions({
|
||||
tenantUuid: this.platformObject.tceTenantUuid,
|
||||
vendorId: this.detail.vendorId
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
this.tableData = data.data.regionInstanceSet
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
detail: {
|
||||
handler(newVal, oldVal) {
|
||||
this.getData()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<div>
|
||||
<cb-advance-table :data="tableData" :params="params" :columns="columns" :get-list="getData" :total="total" :loading="loading">
|
||||
<template #instanceState="val">
|
||||
<cb-status-icon :type="val | tceInstanceColor">{{ val | tceInstanceText }}</cb-status-icon>
|
||||
</template>
|
||||
</cb-advance-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getsecrectList } from 'views/tce/services/tke.js'
|
||||
const columns = [
|
||||
{
|
||||
label: '名称',
|
||||
prop: 'name'
|
||||
},
|
||||
{
|
||||
label: '类型',
|
||||
prop: 'type'
|
||||
},
|
||||
{
|
||||
label: 'lables',
|
||||
prop: 'lables'
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'creationTimestamp'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
props: {
|
||||
detail: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
name: '',
|
||||
data() {
|
||||
return {
|
||||
columns,
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 10
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$emit('close')
|
||||
},
|
||||
getData() {
|
||||
const params = {
|
||||
page: this.params.page,
|
||||
rows: this.params.rows,
|
||||
params: JSON.stringify([{ param: { vendorId: this.detail.vendorId, clusterId: this.detail.clusterId }, sign: 'EQ' }])
|
||||
}
|
||||
getsecrectList(params).then(data => {
|
||||
if (data.success) {
|
||||
this.loading = false
|
||||
this.tableData = data.data.rows
|
||||
this.total = data.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
detail: {
|
||||
handler(newVal, oldVal) {
|
||||
this.getData()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div>
|
||||
<cb-detail :title="clusterInfo.name + ' 服务'" @goBack="goBack">
|
||||
<template v-slot:item_container>
|
||||
<cb-advance-table :data="tableData" :params="params" :columns="columns" :get-list="getData" :total="total" :loading="loading">
|
||||
<template v-slot:action> </template>
|
||||
<template #instanceState="val">
|
||||
<cb-status-icon :type="val | tceInstanceColor">{{ val | tceInstanceText }}</cb-status-icon>
|
||||
</template>
|
||||
<template #operate="val, record">
|
||||
<div class="action-divider"></div>
|
||||
<el-button type="text" @click="remove(record.id)" :disabled="record.status === 'BIND'"> 删除 </el-button>
|
||||
<div class="action-divider"></div>
|
||||
</template>
|
||||
</cb-advance-table>
|
||||
</template>
|
||||
</cb-detail>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getServiceList } from 'views/tce/services/tke.js'
|
||||
const columns = [
|
||||
{
|
||||
label: '名称',
|
||||
prop: 'serviceName'
|
||||
},
|
||||
{
|
||||
label: '类型',
|
||||
prop: 'type'
|
||||
},
|
||||
{
|
||||
label: 'ip',
|
||||
prop: 'ipAddress'
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'createTime'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
props: ['vendorId', 'clusterInfo'],
|
||||
name: '',
|
||||
data() {
|
||||
return {
|
||||
searchConfigs: [{ type: 'Input', label: '名称', value: 'serviceName' }],
|
||||
searchData: {
|
||||
serviceName: ''
|
||||
},
|
||||
columns,
|
||||
params: {
|
||||
page: 1,
|
||||
rows: 10
|
||||
},
|
||||
total: 0,
|
||||
tableData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$emit('close')
|
||||
},
|
||||
getData() {
|
||||
const params = {
|
||||
page: this.params.page,
|
||||
rows: this.params.rows,
|
||||
params: JSON.stringify([{ param: { vendorId: this.vendorId, clusterId: this.clusterInfo.clusterId }, sign: 'EQ' }])
|
||||
}
|
||||
getServiceList(params).then(data => {
|
||||
if (data.success) {
|
||||
this.loading = false
|
||||
this.tableData = data.data.rows
|
||||
this.total = data.data.total
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
clusterInfo: {
|
||||
handler(newVal, oldVal) {
|
||||
this.getData()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -11,5 +11,7 @@ export default {
|
|||
ctstackKey: () => import('views/resource/ctstack/page/secretKey.vue'),
|
||||
ctstackServer: () => import('views/resource/ctstack/page/serverAdd.vue'),
|
||||
ctstackFloatIp: () => import('views/resource/ctstack/page/floatIp/index.vue'),
|
||||
ctstackSnapshot: () => import('views/resource/ctstack/page/snapshot/index.vue')
|
||||
ctstackSnapshot: () => import('views/resource/ctstack/page/snapshot/index.vue'),
|
||||
ctstackContainer: () => import('views/resource/ctstack/page/container/index.vue'),
|
||||
ctstackCreateCluster: () => import('views/resource/ctstack/page/container/creatCluster/index.vue')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
import { request } from '@cmp/cmp-element'
|
||||
import { wrapperParams, downloadFile } from 'utils'
|
||||
|
||||
const createCluterUrl = '/cmp/plugins/tce/v1/tke'
|
||||
export function createCluter(params) {
|
||||
return request.post(createCluterUrl, wrapperParams(params))
|
||||
}
|
||||
|
||||
const describeVersionsUrl = '/cmp/plugins/tce/v1/tke/describeVersions'
|
||||
export function getDescribeVersions(params) {
|
||||
return request.get(`${describeVersionsUrl}`, { params })
|
||||
}
|
||||
|
||||
// 集群 查询地域
|
||||
const regionsUrl = '/cmp/plugins/tce/v1/tke/describe/regions'
|
||||
export function getTKERegions(params) {
|
||||
return request.get(regionsUrl, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 创建 查询镜像信息
|
||||
const createCluterImagesUrl = '/cmp/plugins/tce/v1/tke/describe/images'
|
||||
export function createCluterImages(params) {
|
||||
return request.get(createCluterImagesUrl, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 创建 校验CIDR
|
||||
const checkCIDRUrl = '/cmp/plugins/tce/v1/tke/check/CIDR'
|
||||
export function checkCIDR(params) {
|
||||
return request.get(checkCIDRUrl, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
const clusterListUrl = '/cmp/plugins/tce/v1/tke'
|
||||
// 获取伸缩组
|
||||
export function getFlexibleList(params) {
|
||||
return request.get(`${clusterListUrl}/group/list`, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 删除伸缩组
|
||||
export function delectFlexible(params) {
|
||||
return request.get(`${clusterListUrl}/group/del/${params.id}`, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 修改伸缩组配置
|
||||
export function editFlexibleAllocation(params) {
|
||||
return request.post(`${clusterListUrl}/group/update/${params.id}`, wrapperParams(params))
|
||||
}
|
||||
|
||||
// 查询全局配置
|
||||
export function getWholeAllocation(params) {
|
||||
return request.get(`${clusterListUrl}/option/list`, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function editWholeAllocation(params) {
|
||||
return request.post(`${clusterListUrl}/option/update/${params.id}`, wrapperParams(params))
|
||||
}
|
||||
|
||||
export function getClusterDetail(id) {
|
||||
return request.get(`${clusterListUrl}/${id}`)
|
||||
}
|
||||
|
||||
export function postAddInstance(params) {
|
||||
return request.post(`${clusterListUrl}/add/instance`, wrapperParams(params))
|
||||
}
|
||||
|
||||
// 集群 节点 创建
|
||||
const createInstanceUrl = '/cmp/plugins/tce/v1/tke/instance '
|
||||
export function createInstance(params) {
|
||||
return request.post(createInstanceUrl, wrapperParams(params))
|
||||
}
|
||||
|
||||
// 集群 已存在节点
|
||||
const existInstanceUrl = '/cmp/plugins/tce/v1/tke/exist/instance'
|
||||
export function getExistInstance(params, id) {
|
||||
return request.get(`${existInstanceUrl}/${params.vendorId}/${id}`, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 节点
|
||||
const instanceListUrl = '/cmp/plugins/tce/v1/tke/instance'
|
||||
|
||||
export function getInstanceList(params) {
|
||||
return request.get(instanceListUrl, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 节点 删除
|
||||
export function deleteInstance(params, data) {
|
||||
return request.delete(`${instanceListUrl}/${params.vendorId}/${params.id}`, {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 节点 驱逐
|
||||
const drainUrl = '/cmp/plugins/tce/v1/tke/drain'
|
||||
export function drain(params) {
|
||||
return request.delete(`${drainUrl}/${params.vendorId}/${params.id}`, {
|
||||
data: { instanceId: params.instanceId }
|
||||
})
|
||||
}
|
||||
|
||||
export function operateInstance(params) {
|
||||
return request.post('/cmp/plugins/tce/v1/tke/block/operation', wrapperParams(params))
|
||||
}
|
||||
|
||||
const secrectListUrl = '/cmp/plugins/tce/v1/tke/cluster'
|
||||
export function getsecrectList(params) {
|
||||
return request.get(secrectListUrl, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 服务
|
||||
const serviceListUrl = '/cmp/plugins/tce/v1/tke/service'
|
||||
export function getServiceList(params) {
|
||||
return request.get(serviceListUrl, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 编辑
|
||||
export function modifyInstance({ id, newName }) {
|
||||
return request.put(`${clusterListUrl}/${id}`, {
|
||||
newName
|
||||
})
|
||||
}
|
||||
|
||||
// 集群 删除
|
||||
export function deleteCluster(params, mode) {
|
||||
const formData = new FormData()
|
||||
formData.append('mode', mode)
|
||||
return request.delete(`${clusterListUrl}/${params.id}`, {
|
||||
data: formData
|
||||
})
|
||||
}
|
||||
|
||||
// 容器服务 日志列表
|
||||
export function getLogList(params) {
|
||||
return request.get('/cmp/plugins/tce/v1/tke/logCollectorController', { params })
|
||||
}
|
||||
|
||||
export function getClusterList(params) {
|
||||
return request.get(clusterListUrl, {
|
||||
params
|
||||
})
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ export default {
|
|||
const leftConfigs = ref([])
|
||||
const rightConfigs = ref([])
|
||||
const loading = ref(true)
|
||||
const leftKeys = ['企业微信配置', '钉钉配置', 'LDAP配置']
|
||||
const leftKeys = ['企业微信配置', '钉钉配置', 'LDAP配置', '邮箱配置', '短信配置']
|
||||
async function getConfigs() {
|
||||
loading.value = true
|
||||
const res = await getSystemTreeConfigs({ category: '系统对接' })
|
||||
|
|
@ -39,7 +39,7 @@ export default {
|
|||
}
|
||||
getConfigs()
|
||||
const showTest = name => {
|
||||
return !['短信配置', '阵地信息', '大屏展示配置'].includes(name)
|
||||
return !['短信配置', '阵地信息', '大屏展示配置', '运控系统地址'].includes(name)
|
||||
}
|
||||
return {
|
||||
leftConfigs,
|
||||
|
|
|
|||
Loading…
Reference in New Issue