feat: 裸金属列表/修改/创建

develop
时启龙 2024-09-03 17:56:02 +08:00
parent e01feb840d
commit e5551d64a9
10 changed files with 482 additions and 252 deletions

View File

@ -2091,29 +2091,73 @@ export function physicalLineProider(value) {
}
return obj[value]
}
export function bareMetalState(value, type) {
const obj = {
RUNNING: '运行中',
STOPPING: '关机中',
CREATING: '创建中',
STOPPED: '已关机',
STARTING: '开机中',
REBOOTING: '重启中',
PENDING: '生产中',
CREATE_FAILED: '创建失败'
CREATE_FAILED: '创建失败',
RESIZING: '变配中',
VERIFY_RESIZE: '确认变配中',
RESTARTING: '正在重启',
WAITING: '等待其他资源创建中',
DELETING: '退订中',
DELETE: '退订完成',
ERROR: '异常',
EXPIRED: '已过期',
REBUILD: '重装中',
CREATING_IMAGE: '创建镜像中',
SUSPENDED: '挂起',
SUSPENDING: '挂起中',
MIGRATING: '迁移中',
BUILD_BACKUP: '创建备份中',
EXPORT_IMAGE: '裸金属创建镜像中',
REINSTALLING: '重装中',
MODIFY_NETWORK: '裸金属重置网络中',
RESTORING: '恢复中',
BACKUPING: '创建备份中',
MOUNT_FILE_SYSTEM: '挂载文件系统中',
UNMOUNT_FILE_SYSTEM: '卸载文件系统中',
Rebuilding: '重建中'
}
return obj[value]
}
export function bareMetalColor(value) {
const obj = {
RUNNING: 'success',
STOPPING: 'warning',
CREATING: 'warning',
STOPPED: 'danger',
STARTING: 'warning',
REBOOTING: 'warning',
PENDING: 'info',
CREATE_FAILED: 'danger'
CREATE_FAILED: 'danger',
RESIZING: 'info',
VERIFY_RESIZE: 'info',
RESTARTING: 'info',
WAITING: 'info',
DELETING: 'danger',
DELETE: 'info',
ERROR: 'danger',
EXPIRED: 'warning',
REBUILD: 'info',
CREATING_IMAGE: 'info',
SUSPENDED: 'danger',
SUSPENDING: 'warning',
MIGRATING: 'info',
BUILD_BACKUP: 'info',
EXPORT_IMAGE: 'info',
REINSTALLING: 'info',
MODIFY_NETWORK: 'info',
RESTORING: 'info',
BACKUPING: 'info',
MOUNT_FILE_SYSTEM: 'info',
UNMOUNT_FILE_SYSTEM: 'info',
Rebuilding: 'info'
}
return obj[value]
}

View File

@ -942,5 +942,58 @@ export default {
}
},
trigger: trigger
},
ctstackBMSName: {
// 长度6到15位可以为字母数字和中划线首字符不能为中划线和数字不能以中划线结尾
validator: (rule, value, callback) => {
const reg = /^[a-zA-Z][a-zA-Z0-9\-]{4,13}[a-zA-Z0-9]$/
if (reg.test(value)) {
callback()
} else {
callback(new Error('长度6到15位可以为字母数字和中划线首字符不能为中划线和数字不能以中划线结尾'))
}
},
trigger: trigger
},
ctstackBMSPassword: {
// 密码校验830 个字符,必须包含大小写字母,同时必须包含一个数字或者特殊字符,且不能以斜线号(/)开头,不能包含连续字符
validator: (rule, value, callback) => {
const message = new Error('密码校验830 个字符,必须包含大小写字母,同时必须包含一个数字或者特殊字符,且不能以斜线号(/)开头,不能包含连续字符')
// 检查长度要求
if (value.length < 8 || value.length > 30) {
callback(message)
return
}
// 检查不能以斜线 / 开头
if (value.startsWith('/')) {
callback(message)
return
}
// 检查是否包含大小写字母
const hasUpperCase = /[A-Z]/.test(value)
const hasLowerCase = /[a-z]/.test(value)
if (!(hasUpperCase && hasLowerCase)) {
callback(message)
return
}
// 检查是否包含数字或特殊字符
const hasNumberOrSpecialChar = /[\d()~`!@#$%^&*_=|{}\[\]:;'"<>,.?/-]/.test(value)
if (!hasNumberOrSpecialChar) {
callback(message)
return
}
// 检查是否含有连续字符
for (let i = 0; i < value.length - 1; i++) {
if (value.charCodeAt(i) + 1 === value.charCodeAt(i + 1)) {
callback(message)
}
}
callback()
},
trigger: trigger
}
}

View File

@ -11,19 +11,44 @@
</el-col>
<el-col :span="12">
<cb-form-item label="可用区域:" prop="zoneId" :rules="[required]">
<el-select v-model="addData.zoneId" @change="getSizeData">
<el-select v-model="addData.zoneId" @change="getFlavorList">
<el-option v-for="item in zoneData" :key="item.id" :label="item.name" :value="item.zoneId"></el-option>
</el-select>
</cb-form-item>
</el-col>
<el-col :span="12">
<cb-form-item label="实例规格:" prop="flavorId" :rules="[required]">
<el-select v-model="addData.flavorId">
<el-option v-for="item in flavorList" :key="item.id" :label="item.name + '(' + item.cpu + 'C/' + item.memory + 'GB' + ')'" :value="item.id"></el-option>
</el-select>
<el-col :span="20">
<cb-form-item label="实例规格:" prop="deviceType" :rules="[required]">
<cb-table :data="flavorList" max-height="400px" :loading="flavorLoading" :rows="99999">
<el-table-column label="名称">
<template slot-scope="scope">
<el-radio :label="scope.row.deviceType" v-model="addData.deviceType" @input="flavorChange">
{{ scope.row.deviceType }}
</el-radio>
</template>
</el-table-column>
<el-table-column label="CPU">
<template slot-scope="scope">
<span>{{ scope.row.cpuSockets }}{{ scope.row.cpuAmount }}{{ scope.row.cpuThreadAmount }}线程 </span>
</template>
</el-table-column>
<el-table-column label="内存GB" prop="memSize"> </el-table-column>
<el-table-column label="本地磁盘">
<template slot-scope="scope">
<div>系统盘:{{ scope.row.systemVolumeAmount ? `${scope.row.systemVolumeAmount} * ${scope.row.systemVolumeSize}GB(${scope.row.systemVolumeType})` : '--' }}</div>
<div>数据盘:{{ scope.row.dataVolumeAmount ? `${scope.row.dataVolumeAmount} * ${scope.row.dataVolumeSize}GB(${scope.row.dataVolumeType})` : '--' }}</div>
</template>
</el-table-column>
<el-table-column label="网卡">
<template slot-scope="scope">
<div>个数:{{ scope.row.nicAmount }}</div>
<div>传输速率:{{ scope.row.nicRate }}(GE)</div>
</template>
</el-table-column>
<span slot="pagination"></span>
</cb-table>
</cb-form-item>
</el-col>
<images :add-data="addData" :vendor-id="vendorId" :region-id="addData.regionId"></images>
<images :add-data="addData" :vendor-id="vendorId"></images>
<el-col :span="24">
<el-col :span="12">
<cb-form-item label="所属VPC" prop="vpcUuid" :rules="[required]">
@ -33,14 +58,18 @@
</cb-form-item>
</el-col>
<el-col :span="12">
<cb-form-item label="所属子网:" prop="subnetId" :rules="[required]">
<el-select v-model="addData.subnetId">
<el-option v-for="item in subnetList" :label="item.name" :value="item.id" :key="item.id"></el-option>
<cb-form-item label="所属子网:" prop="subnetUuid" :rules="[required]">
<el-select v-model="addData.subnetUuid">
<el-option v-for="item in subnetList" :label="item.name" :value="item.value" :key="item.value"></el-option>
</el-select>
</cb-form-item>
</el-col>
</el-col>
<!-- <flavor :add-data="addData" :list="flavorList" v-if="flavorList.length" :zone-id="addData.zoneId" vendorType='TIANYI'></flavor> -->
<el-col :span="12">
<cb-form-item label="物理机名称:" prop="name" :rules="[required, ctstackBMSName]">
<el-input v-model="addData.name"></el-input>
</cb-form-item>
</el-col>
<!-- <el-col :span="24">
<cb-form-item label="登录方式:">
<el-radio-group v-model="keypair" @change="chooseLoginWay">
@ -57,31 +86,41 @@
</el-col>
<el-col :span="24" v-else-if="keypair == ''">
<el-col :span="12">
<cb-form-item label="登录密码:" prop="password" :rules="[required, tyVmPassword]">
<cb-form-item label="登录密码:" prop="password" :rules="[required, ctstackBMSPassword]">
<el-input type="password" v-model="addData.password" @blur="PswBlur" show-password></el-input>
</cb-form-item>
</el-col>
<el-col :span="12">
<cb-form-item label="确认密码:" prop="endPassword" :rules="[required, tyVmPassword]">
<cb-form-item label="确认密码:" prop="endPassword" :rules="[required, ctstackBMSPassword]">
<el-input type="password" v-model="addData.endPassword" @blur="PswBlur"></el-input>
</cb-form-item>
</el-col>
</el-col>
<el-col :span="12">
<cb-form-item label="物理机名称:" prop="name" :rules="[required, noChinese]">
<el-input v-model="addData.name"></el-input>
<cb-form-item label="数量:" prop="orderCount" :rules="[required]">
<el-input-number v-model="addData.orderCount"></el-input-number>
</cb-form-item>
</el-col>
<el-col :span="12">
<cb-form-item label="安全组:" prop="groups" :rules="[required]">
<el-select v-model="addData.groups" 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 label=" 描述:" prop="remark" :rules="[required]">
<el-input v-model="addData.remark"></el-input>
</cb-form-item>
</el-col>
<el-col :span="12">
<cb-form-item label="数量:" prop="count" :rules="[required]">
<el-input-number v-model="addData.count" style="width: 100%" :min="1"></el-input-number>
<el-col :span="24">
<cb-form-item label="本地磁盘:" v-if="systemVolumeLabel || dataVolumeLabel">
<div v-if="systemVolumeLabel">
{{ systemVolumeLabel }}
<el-select v-model="addData.systemVolumeRaidUuid" class="w m-l">
<el-option v-for="row in systemRaidList" :label="row.nameZh" :value="row.uuid" :key="row.uuid"></el-option>
</el-select>
</div>
<div v-if="dataVolumeLabel">
{{ dataVolumeLabel }}
<el-select v-model="addData.dataVolumeRaidUuid" class="w m-l">
<el-option v-for="row in dataRaidList" :label="row.nameZh" :value="row.uuid" :key="row.uuid"></el-option>
</el-select>
</div>
</cb-form-item>
</el-col>
<el-col :span="24" v-for="(item, index) in addData.diskDevices" :key="index">
@ -110,6 +149,7 @@
</cb-form-item>
</el-col>
<!-- <el-col :span="24">
暂不做数据盘
<cb-form-item>
<el-button type="primary" @click="addDiskDevices" v-if="addData.diskDevices.length <= 9"></el-button>
</cb-form-item>
@ -131,12 +171,12 @@
import validate from '@/validate'
import { getRegion, getZone } from 'services/platform/index'
import { getVpc } from 'views/resource/ctstack/services/vpcs'
import { getFlavor } from 'views/resource/ctstack/services/flavors'
import { getBMSFlavor } from 'views/resource/ctstack/services/flavors'
import { getRaids } from 'views/resource/ctstack/services/volume'
import { getSubnet } from 'views/resource/ctstack/services/subnet'
import { getGroup } from 'views/resource/ctstack/services/group'
import { getKey } from 'views/resource/ctstack/services/key'
import { typeData, dataTypeData } from 'views/resource/ctstack/page/hardDisk/config'
import images from 'views/platform/components/image.vue'
import images from './image.vue'
import { encrypt } from '@cmp/cmp-element'
import { addBMS } from 'views/resource/ctstack/services/bms.js'
@ -147,64 +187,79 @@ export default {
type: Object
}
},
computed: {
pwdRule() {
return this.$store.state.app.systemConfig.pwdStrength + ',required'
}
},
data() {
return {
vendorId: parseInt(this.$router.currentRoute.query.vendorId),
required: validate.required,
noChinese: validate.noChinese,
ctstackBMSName: validate.ctstackBMSName,
ctstackBMSPassword: validate.ctstackBMSPassword,
addData: {
regionId: '',
zoneId: '',
flavorId: '',
name: '',
password: '',
endPassword: '',
keypairName: '',
imageId: '',
vpcUuid: '',
subnetId: '',
count: 1,
groups: [],
networks: [],
diskDevices: []
},
tyVmPassword: {
validator: (rule, value, callback) => {
const users = ['admin', 'adminstartor', 'root', 'nimda', 'rotratsnimda', 'toor']
const pattern = '^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\\W_]+$)(?![a-z0-9]+$)(?![a-z\\W_]+$)(?![0-9\\W_]+$)[a-zA-Z0-9\\W_]{8,26}$'
users.forEach(item => {
if (value.indexOf(item) != -1) {
callback(new Error('密码不能包含用户名或用户名的逆序'))
}
})
if (!value.match(pattern)) {
callback(new Error('只能包含大写字母、小写字母、数字和特殊字符(!@$%^-_=+[{}]:,./?~#*)且至少包含四种字符中的三种,密码不能包含用户名或用户名的逆序,长度介于8-26字符'))
} else {
callback()
}
},
trigger: null
vendorId: 1, // id
regionId: '', //
zoneId: '', //
name: '', // (615线线线
hostname: '', // name
remark: '', //
deviceType: '', // deviceType
imageUuid: '', // imageUUID
password: '', // -830,^
vpcUuid: '', // vpcvpcId
extIp: '0', // IP0
systemVolumeRaidUuid: '', // raiduuid
dataVolumeRaidUuid: '', // raiduuid
vpcName: '', // vpcname
master: true, // true
subnetUuid: '', // subnetUuid
cycleCount: 0, // 0
cycleType: 'ondemand', // :[MONTH=,YEAR=,ondemand=]
orderCount: 1 //
},
regionData: [],
typeData,
dataTypeData,
routerList: [],
flavorList: [],
flavorLoading: false,
loginWays: [{ name: '密码' }, { name: '密钥' }],
groupList: [],
keypairList: [],
keypair: '密码',
zoneData: [],
subnetList: [],
loading: false
loading: false,
systemVolumeLabel: '',
dataVolumeLabel: '',
systemRaidList: [],
dataRaidList: []
}
},
methods: {
flavorChange() {
const find = this.flavorList.find(({ deviceType }) => this.addData.deviceType)
this.systemVolumeLabel = find?.systemVolumeAmount ? `系统盘:${find.systemVolumeAmount}*${find.systemVolumeSize}GB(${find.systemVolumeType})` : ''
this.dataVolumeLabel = find?.dataVolumeAmount ? `数据盘:${find.dataVolumeAmount}*${find.dataVolumeSize}GB(${find.dataVolumeType})` : ''
this.addData.systemVolumeRaidUuid = ''
this.addData.dataVolumeRaidUuid = ''
this.systemRaidList = []
this.dataRaidList = []
if (this.systemVolumeLabel) this.getRaidList('system')
if (this.dataVolumeLabel) this.getRaidList('data')
},
getRaidList(volumeType) {
const { regionId, zoneId, deviceType } = this.addData
if (!deviceType) return
getRaids({
vendorId: this.vendorId,
regionId,
zoneId,
deviceType, // deviceType
volumeType // systemdata
}).then(res => {
if (res.success) {
if (volumeType === 'system') this.systemRaidList = res.data
if (volumeType === 'data') this.dataRaidList = res.data
}
})
},
goBack() {
this.$router.back(-1)
},
@ -235,13 +290,12 @@ export default {
regionChange() {
if (this.addData.zoneId) this.addData.zoneId = ''
if (this.addData.vpcUuid) this.addData.vpcUuid = ''
if (this.addData.imageId) this.addData.imageId = ''
if (this.addData.subnetId) this.addData.subnetId = ''
if (this.addData.imageUuid) this.addData.imageUuid = ''
if (this.addData.subnetUuid) this.addData.subnetUuid = ''
this.subnetList = []
this.addData.groups = []
this.getZone()
this.getVpcData()
this.getKeypair()
// this.getKeypair()
},
//
diskDevicesRemove(index) {
@ -264,7 +318,7 @@ export default {
},
//
getSubnet() {
this.addData.subnetId = ''
this.addData.subnetUuid = ''
const params = JSON.stringify([
{
param: {
@ -298,38 +352,27 @@ export default {
})
},
changeVpc() {
this.addData.subnetId = ''
this.addData.groups = []
this.addData.vpcName = this.routerList.find(item => item.vpcId === this.addData.vpcUuid)?.name
this.addData.subnetUuid = ''
this.getSubnet()
this.getGroupData()
},
//
getSizeData() {
getFlavorList() {
const params = {
simple: true
vendorId: this.vendorId,
regionId: this.addData.regionId,
zoneId: this.addData.zoneId
}
const searchParam = [
{ param: { vendorId: this.vendorId, regionId: this.addData.regionId }, sign: 'EQ' },
{ param: { zone: this.addData.zoneId }, sign: 'LK' }
]
params.params = JSON.stringify(searchParam)
getFlavor(params).then(data => {
if (data.success) {
this.flavorList = data.data.rows
}
})
},
//
getGroupData() {
const vpcId = this.routerList.find(item => item.vpcId === this.addData.vpcUuid)?.id
getGroup({
simple: true,
params: JSON.stringify([{ param: { vendorId: this.vendorId, regionId: this.addData.regionId, tenantId: 0, vpcId }, sign: 'EQ' }])
}).then(data => {
if (data.success) {
this.groupList = data.data.rows
}
})
this.flavorLoading = true
getBMSFlavor(params)
.then(data => {
if (data.success) {
this.flavorList = data.data
}
})
.finally(() => {
this.flavorLoading = false
})
},
chooseLoginWay(item) {
if (this.keypair == '密钥') {
@ -366,8 +409,8 @@ export default {
let addData = ''
this.$refs.addData.validate(valid => {
if (valid) {
this.addData.hostname = this.addData.name
this.addData.vendorId = this.vendorId
this.addData.networks = []
if (this.addData.password != this.addData.endPassword && this.keypair == '密码') {
this.$notify({
title: '提示',
@ -375,9 +418,6 @@ export default {
})
return
}
if (this.addData.content) {
this.addData.name = this.addData.content + this.addData.name
}
addData = JSON.parse(JSON.stringify(this.addData))
}
})

View File

@ -0,0 +1,66 @@
<template>
<el-col :span="24">
<el-form-item label="镜像" prop="imageUuid" :rules="[required]">
<el-radio-group v-model="type" @change="chooseWay" class="m-r">
<el-radio disabled :label="item.value" :key="index" v-for="(item, index) in typeList" border> {{ item.name }}</el-radio>
</el-radio-group>
<el-select filterable v-model="addData.imageUuid" class="w-lg">
<el-option v-for="item in imageList" :key="item.imageUUID" :label="`${item.nameZh} ${item.version} ${item.os[0].bits}位`" :value="item.imageUUID"></el-option>
</el-select>
</el-form-item>
</el-col>
</template>
<script>
import { getBMSImage } from 'views/resource/ctstack/services/image'
import validate from '@/validate'
export default {
props: {
addData: {
type: Object,
default: () => {
return {}
}
},
vendorId: {
type: [Number, String]
}
},
data() {
return {
required: validate.required,
type: 'PUBLIC',
typeList: [{ name: '公共镜像', value: 'PUBLIC' }],
imageList: []
}
},
watch: {
'addData.deviceType': {
handler(newVal) {
this.chooseWay()
},
deep: true
}
},
methods: {
chooseWay() {
this.addData.imageUuid = ''
this.getImageData()
},
getImageData() {
if (!this.addData.deviceType) return
getBMSImage({
vendorId: this.vendorId,
regionId: this.addData.regionId,
zoneId: this.addData.zoneId,
deviceType: this.addData.deviceType //deviceType
}).then(data => {
if (data.success) {
this.imageList = data.data
if (data.data.length) this.addData.imageUuid = data.data[0].imageUUID
}
})
}
}
}
</script>

View File

@ -1,16 +1,19 @@
<template>
<div>
<cb-advance-table title="" :data="data" :params="params" :columns="columns" :get-list="getList" :total="total" @select="handleSelectItem" @select-all="handleSelectAll" :loading="loading" :search-configs="searchConfigs">
<cb-advance-table title="" :data="data" :params="params" :columns="columns" :get-list="getList" :total="total" :loading="loading" :search-configs="searchConfigs">
<template v-slot:action>
<el-button type="primary" @click="handleAdd()"> </el-button>
</template>
<template #instanceId="val, record">
<template #instanceUuid="val, record">
<span class="detail-href" @click="getDiskList(record)">{{ val }}</span>
</template>
<template #state="val">
<template #ebmState="val">
<cb-status-icon :type="val | bareMetalColor">{{ val | bareMetalState }}</cb-status-icon>
</template>
<template #operate="val, record">
<el-button type="text" @click="handleEdit(record)"> </el-button>
<el-button type="text" @click="handleDelete(record)"> </el-button>
<!-- <div class="action-divider"></div>
<el-button type="text" @click="reboot(record)"> </el-button>
<div class="action-divider"></div>
<el-button type="text" @click="bootup(record)"> </el-button>
@ -20,27 +23,12 @@
<el-dropdown trigger="click">
<span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="edt(record)" :disabled="record.status == 'PENDING'"> 退还 </el-dropdown-item>
<el-dropdown-item @click.native="edt(record)" :disabled="record.ebmState == 'CREATING'"> 退还 </el-dropdown-item>
<el-dropdown-item @click.native="reload(record)"> 重装 </el-dropdown-item>
<el-dropdown-item @click.native="edit(record)"> 改名 </el-dropdown-item>
<el-dropdown-item @click.native="edit(record)" disabled> 分配 </el-dropdown-item>
<el-dropdown-item @click.native="edit(record)" disabled> 回收 </el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown> -->
</template>
</cb-advance-table>
<!-- 更改名称 -->
<el-dialog width="30%" title="更改名称" :close-on-click-modal="false" v-if="editData.dialog" :visible.sync="editData.dialog">
<cb-form :model="editData.data" ref="editData" label-width="50px">
<cb-form-item label="名称" prop="newName">
<el-input v-model="editData.data.newName"></el-input>
</cb-form-item>
</cb-form>
<div slot="footer" class="dialog-footer">
<el-button type="ghost" @click.native="editData.dialog = false">取消</el-button>
<el-button type="primary" @click.native="editSubmit">确定</el-button>
</div>
</el-dialog>
<!-- 硬盘列表 -->
<el-dialog width="50%" title="硬盘列表" :close-on-click-modal="false" v-if="diskSign" :visible.sync="diskSign">
<cb-smart-table ref="list" :data="diskData" :rows="5" style="margin-top: 10px">
@ -59,20 +47,14 @@
<el-dialog width="45%" title="重装" :close-on-click-modal="false" v-if="Reloading" :visible.sync="Reloading" :append-to-body="true">
<cb-form :model="reloadData.data" ref="reloadData" label-width="140px">
<h3>当前配置</h3>
<cb-form-item label="镜像名称">{{ reloadData.row.operatingSystemType }}</cb-form-item>
<cb-form-item label="RAID类型">{{ reloadData.row.raidType }}</cb-form-item>
<cb-form-item label="镜像名称">{{ reloadData.row.osTypeName }}</cb-form-item>
<h3>重装为</h3>
<cb-form-item label="镜像类型">{{ reloadData.row.operatingSystemType }}</cb-form-item>
<cb-form-item label="镜像类型">{{ reloadData.row.osTypeName }}</cb-form-item>
<cb-form-item label="镜像">
<el-select v-model="reloadData.data.operatingSystem" placeholder="请选择镜像">
<el-option v-for="item in selectCombo.operatingSystem.linux" :key="item" :label="item" :value="item"> </el-option>
</el-select>
</cb-form-item>
<cb-form-item label="RAID类型" prop="raidType">
<el-select v-model="reloadData.data.raidType" placeholder="请选择类型">
<el-option v-for="item in selectCombo.raidType" :key="item" :label="item" :value="item"> </el-option>
</el-select>
</cb-form-item>
<cb-form-item label="主机安全agent">
<el-radio v-model="reloadData.data.enhancedService.SecurityService.Enabled" label="true"></el-radio>
<el-radio v-model="reloadData.data.enhancedService.SecurityService.Enabled" label="false"></el-radio>
@ -90,75 +72,69 @@
<el-button type="primary" :loading="subLoading" @click.native="ok">确定</el-button>
</div>
</el-dialog>
<modifyName :add-data="modifyDialog" @back="getList" v-if="modifyDialog.dialog"></modifyName>
</div>
</template>
<script>
import { bareMetalState, bareMetalColor } from 'filters'
import { getBareMetalList, modifyBareMetal, bmsReboot, bmsBootUp, bmsStop, bmsedt, getDisk, getCombo, bmsReload } from 'views/resource/ctstack/services/bms.js'
import { removeVmUsers } from 'views/resource/ctstack/services/vm.js'
import { getBareMetalList, modifyBareMetal, bmsReboot, bmsBootUp, bmsStop, bmsedt, getDisk, getCombo, bmsReload, bmsDelete } from 'views/resource/ctstack/services/bms.js'
import { getRegion } from 'services/platform/index'
import modifyName from './modifyName.vue'
const columns = [
{
type: 'selection'
},
{
label: 'ID',
prop: 'instanceId',
prop: 'instanceUuid',
disabled: true,
scopedSlots: { customRender: 'instanceId' }
scopedSlots: { customRender: 'instanceUuid' }
},
{
label: '名称',
prop: 'instanceName',
prop: 'name',
disabled: true
},
{
label: '状态',
prop: 'status',
scopedSlots: { customRender: 'state' }
},
{
label: '机型',
prop: 'flavorName'
prop: 'ebmState',
scopedSlots: { customRender: 'ebmState' }
},
{
label: '可用区',
prop: 'zone'
prop: 'zoneName'
},
{
label: '私有网络',
prop: 'vpcId'
prop: 'vpcName'
},
{
label: '子网',
prop: 'subnetId'
prop: 'subnetName'
},
{
label: '公网IP',
prop: ''
prop: 'publicIP'
},
{
label: '内网IP',
prop: ''
prop: 'privateIP'
},
{
label: '操作系统',
prop: 'operatingSystemType'
prop: 'osTypeName'
},
{
label: 'RAID类型',
prop: 'raidType'
label: '描述',
prop: 'remark'
},
{
label: '操作',
disabled: true,
width: '220px',
width: '160px',
scopedSlots: { customRender: 'operate' }
}
]
export default {
components: {},
components: { modifyName },
props: {
platformObject: {
type: Object,
@ -201,11 +177,6 @@ export default {
{ type: 'Select', label: '所属地域', data: [], value: 'regionId', props: { value: 'regionId' } },
{ type: 'Const', value: 'vendorId', initValue: this.platformObject.vendorId }
],
//
editData: {
dialog: false,
data: {}
},
diskSign: false,
diskData: [],
//
@ -213,9 +184,8 @@ export default {
ruleForm: {},
reloadData: {
data: {
instanceId: '',
raidType: '',
operatingSystemType: '',
instanceUuid: '',
osTypeName: '',
operatingSystem: '',
loginSettings: {
Password: '',
@ -230,10 +200,46 @@ export default {
row: {}
},
comboData: '',
selectCombo: {}
selectCombo: {},
modifyDialog: {
dialog: false,
data: {}
}
}
},
methods: {
//
handleEdit(row) {
const { id, name, regionId, zoneId, remark = '' } = row
this.modifyDialog = {
dialog: true,
data: {
id,
displayName: name,
regionId,
zoneId,
remark
}
}
},
//
handleDelete(row) {
this.$confirm('此操作将删除该实例, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
bmsDelete({ id: row.id }).then(data => {
if (data.success) {
this.$message({
type: 'success',
message: data.message
})
this.getList()
}
})
})
},
//
ok() {
this.$refs.reloadData.validate(valid => {
@ -257,16 +263,15 @@ export default {
},
reload(row) {
const params = {
zone: ['yfm14az1']
zoneName: ['yfm14az1']
}
getCombo(this.platformObject.vendorId, params).then(res => {
this.comboData = res.data.flavorSet
this.Reloading = true
this.reloadData.row = row
this.reloadData.data = {
instanceId: row.instanceId,
raidType: row.raidType,
operatingSystemType: row.operatingSystemType,
instanceUuid: row.instanceUuid,
osTypeName: row.osTypeName,
operatingSystem: row.operatingSystem,
loginSettings: {
Password: ''
@ -288,7 +293,7 @@ export default {
getArea() {
//
const params = {
zone: ['yfm14az1']
zoneName: ['yfm14az1']
}
getCombo(this.platformObject.vendorId, params).then(res => {
this.comboData = res.data.flavorSet
@ -312,7 +317,7 @@ export default {
type: 'warning'
}).then(() => {
this.$cmpDelete(close => {
bmsedt([row.instanceId]).then(data => {
bmsedt([row.instanceUuid]).then(data => {
if (data.success) {
this.$message({
type: 'success',
@ -375,66 +380,8 @@ export default {
}, 45000)
})
},
edit(row) {
this.editData = {
dialog: true,
data: {
id: row.id,
instanceId: row.instanceId,
newName: row.instanceName
}
}
},
editSubmit() {
this.$refs.editData.validate(valid => {
if (valid) {
modifyBareMetal(this.editData.data).then(res => {
if (res.success) {
this.$message.success(res.message)
this.editData.dialog = false
this.getList()
}
})
}
})
},
//
handleSelectAll(selection) {
this.refreshId()
if (selection.length) {
//
selection.forEach(item => {
if (this.idList.indexOf(item.id) == -1) {
this.selectList.push(item)
}
})
} else {
//
this.list.forEach(item => {
if (this.idList.indexOf(item.id) > -1) {
for (let j = 0; j < this.selectList.length; j++) {
const row = this.selectList[j]
if (item.id == row.id) {
this.selectList.splice(j, 1)
break
}
}
}
})
}
},
getList() {
this.loading = true
// const params = {
// page: this.params.page,
// rows: this.params.rows,
// params: JSON.stringify([{
// param: {
// vendorId: this.platformObject.vendorId,
// },
// sign: 'EQ'
// }])
// }
getBareMetalList(this.params)
.then(res => {
if (res.success) {

View File

@ -0,0 +1,65 @@
<template>
<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="displayName" :rules="[required]" required-message="">
<el-input v-model="addData.data.displayName"></el-input>
</cb-form-item>
</el-col>
<el-col :span="24">
<cb-form-item label="备注:" prop="remark" :rules="[required]" required-message="">
<el-input v-model="addData.data.remark"></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" :loading="loading">确定</el-button>
</div>
</el-dialog>
</template>
<script>
import { modifyBareMetal } from 'views/resource/ctstack/services/bms'
import validate from '@/validate'
export default {
props: {
addData: {
type: Object,
default: function () {
return {
data: {
labelIds: []
},
dialog: false
}
}
}
},
data() {
return { required: validate.required, loading: false }
},
methods: {
ok() {
this.$refs.data.validate(valid => {
if (valid) {
this.loading = true
modifyBareMetal(this.addData.data)
.then(data => {
if (data.success) {
this.$message.success(data.message)
this.$emit('back')
this.addData.dialog = false
}
})
.finally(() => {
this.loading = false
})
}
})
}
}
}
</script>

View File

@ -1,61 +1,59 @@
import { request } from '@cmp/cmp-element'
import { wrapperParams } from 'utils'
const baseUrl = '/cmp/plugins/ctstack/v1/physical/servers'
export function getBareMetalList(params) {
return request.get('/cmp/plugins/ctstack/v1/bms', {
return request.get(baseUrl, {
params
})
}
// 新建 获取套餐列表
export function getCombo(id, params) {
return request.post(`/cmp/plugins/ctstack/v1/bms/describeFlavors/${id}`, wrapperParams(params))
// 修改BMS名称
export function modifyBareMetal(params) {
return request.put(`${baseUrl}/${params.id}`, wrapperParams(params))
}
// 获取运营商
export function getOperator(params) {
return request.post('/cmp/plugins/ctstack/v1/bms/describeEIPIspInfo', wrapperParams(params))
}
// 获取子网
export function getBareSubnet(id, params) {
return request.post(`/cmp/plugins/ctstack/v1/bms/describeSubnets/${id}`, wrapperParams(params))
export function bmsDelete(params) {
return request.delete(`${baseUrl}/${params.id}`)
}
// 新建BMS
export function addBMS(id, params) {
return request.post(`/cmp/plugins/ctstack/v1/bms/runInstances/${id}`, wrapperParams(params))
export function addBMS(params) {
return request.post(baseUrl, wrapperParams(params))
}
// 修改BMS名称
export function modifyBareMetal(params) {
return request.post(`/cmp/plugins/ctstack/v1/bms/modifyAttribute/${params.id}`, wrapperParams(params))
// 假的
export function getCombo(params) {
return request.get(baseUrl, {
params
})
}
// 重启
export function bmsReboot(params) {
return request.patch(`/cmp/plugins/ctstack/v1/bms/reboot/${params.id}`)
return request.patch(`${baseUrl}/reboot/${params.id}`)
}
// 开机
export function bmsBootUp(params) {
return request.patch(`/cmp/plugins/ctstack/v1/bms/start/${params.id}`)
return request.patch(`${baseUrl}/start/${params.id}`)
}
// 关机
export function bmsStop(params) {
return request.patch(`/cmp/plugins/ctstack/v1/bms/stop/${params.id}`)
return request.patch(`${baseUrl}/stop/${params.id}`)
}
// 退还实例
export function bmsedt(params) {
return request.post('/cmp/plugins/ctstack/v1/bms/terminateInstances', wrapperParams(params))
return request.post('${baseUrl}/terminateInstances', wrapperParams(params))
}
// 获取硬盘列表
export function getDisk(params) {
return request.get(`/cmp/plugins/ctstack/v1/bms/disks/${params.id}`)
return request.get(`${baseUrl}/disks/${params.id}`)
}
// 重装
export function bmsReload(id, params) {
return request.post(`/cmp/plugins/ctstack/v1/bms/resetInstance/${id}`, wrapperParams(params))
return request.post(`${baseUrl}/resetInstance/${id}`, wrapperParams(params))
}

View File

@ -45,3 +45,9 @@ export function unbindFlavor(params) {
export function getFlavorListZone(id) {
return request.get(`${url}/listZone/${id}`)
}
export function getBMSFlavor(params) {
return request.get(`${url}/listPhysical`, {
params
})
}

View File

@ -84,3 +84,8 @@ export function patchImage(action, params) {
export function volumeImage(id) {
return request.get(`${imageUrl}/${id}/volumes`)
}
export function getBMSImage(params) {
return request.get(`${imageUrl}/listPhysical`, {
params
})
}

View File

@ -45,3 +45,9 @@ export function getVolumeVms(params) {
params: wrapperParams(params)
})
}
export function getRaids(params) {
return request.get(`${volumeUrl}/raids`, {
params: wrapperParams(params)
})
}