This commit is contained in:
jhnine 2022-11-30 09:47:57 +08:00
parent 9ea949fd5c
commit f11b772ed5
8 changed files with 273 additions and 249 deletions

View File

@ -19,7 +19,7 @@ export function deleteCluster(params) {
})
}
// 集群创建
// 集群注册
export function joinCluster(data) {
return request({
url: '/jcc-schedule/api/v1/cluster/join',
@ -309,7 +309,7 @@ export function proxyJoinCluster(data) {
})
}
// 集群创建-集群注册
// 集群注册-集群注册
export function createCluster(data) {
return request({
url: '/jcc-schedule/api/v1/cluster/createCluster',

View File

@ -38,7 +38,7 @@ const scheduleRouter = {
path: 'clusterCreate',
component: () => import('@/views/jccSchedule/clusterSetting/clusterCreate/index'),
name: 'clusterCreate',
meta: { title: '集群创建', affix: true }
meta: { title: '集群注册', affix: true }
},
{
path: 'clusterDiscovery',

View File

@ -88,7 +88,7 @@ export default {
value: '-'
},
{
name: '纳管算力总计',
name: '纳管算力总计(Pflops)',
src: 'dataIcon-3',
value: '-'
}
@ -251,6 +251,7 @@ export default {
background: #333333;
box-shadow: 0px 3px 7px 0px rgba(51, 51, 51, 0.35);
border-radius: 3px;
white-space: nowrap;
}
.researth{
padding: 8px;

View File

@ -1,5 +1,5 @@
<template>
<el-dialog v-if="createFormVisible" :close-on-click-modal="false" width="60%" title="集群创建" :visible.sync="createFormVisible">
<el-dialog v-if="createFormVisible" :close-on-click-modal="false" width="60%" title="集群注册" :visible.sync="createFormVisible">
<el-steps :active="stepNum" finish-status="success" simple>
<el-step title="基本信息" />
<el-step title="节点创建" />
@ -24,7 +24,7 @@
<el-button @click="createFormVisible = false;transformYaml()"> </el-button>
<el-button v-if="stepNum!==0" type="primary" @click="prev">上一步</el-button>
<el-button v-if="stepNum!==1" type="primary" @click="next">下一步</el-button>
<el-button v-else type="primary" @click="createWorkload">创建</el-button>
<el-button v-else type="primary" :loading="loading" @click="createWorkload">创建</el-button>
</div>
</el-dialog>
</template>
@ -43,6 +43,7 @@ export default {
},
data() {
return {
loading: false,
stepNum: 0,
editInfoForm: {},
rules: {
@ -86,12 +87,16 @@ export default {
this.$refs.editInfoForm.validate((valid) => {
if (valid) {
if (this.editInfoForm.masterNodes && this.editInfoForm.memberNodes) {
this.loading = true
createCluster(this.editInfoForm).then(res => {
this.loading = false
if (res.code === 200) {
this.$message.success('操作成功')
this.createFormVisible = false
this.$emit('getList')
}
}).catch(() => {
this.loading = false
})
} else {
this.$message.warning('Master配置和Worker配置不能为空')

View File

@ -4,7 +4,7 @@
<el-row>
<el-card class="basicInfo">
<img src="@/assets/images/node.png" class="sidebar-logo" alt="集群发现">
<h4>集群创建</h4>
<h4>集群注册</h4>
<span class="tips title-tips">
集群创建描述</span>
</el-card>
@ -50,20 +50,20 @@ export default {
columns: [
{ prop: 'clusterName', label: '集群名称' },
{ prop: 'version', label: 'K8S版本' },
{ prop: 'userName', label: '关联用户' },
{ prop: 'more', width: '80', label: '操作', formatter: (row) => {
return <div>
<el-dropdown>
<el-button size='mini' className='el-dropdown-link' icon='el-icon-more' circle>
</el-button>
<el-dropdown-menu slot='dropdown'>
<span> <el-dropdown-item> 修改</el-dropdown-item> </span>
<span> <el-dropdown-item> 删除</el-dropdown-item> </span>
<span> <el-dropdown-item> 查询</el-dropdown-item> </span>
</el-dropdown-menu>
</el-dropdown>
</div>
} }
{ prop: 'userName', label: '关联用户' }
// { prop: 'more', width: '80', label: '', formatter: (row) => {
// return <div>
// <el-dropdown>
// <el-button size='mini' className='el-dropdown-link' icon='el-icon-more' circle>
// </el-button>
// <el-dropdown-menu slot='dropdown'>
// <span> <el-dropdown-item> </el-dropdown-item> </span>
// <span> <el-dropdown-item> </el-dropdown-item> </span>
// <span> <el-dropdown-item> </el-dropdown-item> </span>
// </el-dropdown-menu>
// </el-dropdown>
// </div>
// } }
]
}
},

View File

@ -3,6 +3,7 @@
<el-page-header :content="$route.query.clone ? '克隆' : $route.query.name ? '编辑' : '创建'" @back="goBack" />
<h2>虚拟机 </h2>
<el-form
ref="virtualFormData"
:model="virtualFormData"
:rules="rules"
>
@ -237,243 +238,247 @@ export default {
this.virtualDetailData = e
},
saveVirtualMachine() {
var formData = this.$refs['child'].formData
const baseTemp = {
'type': 'kubevirt.io.virtualmachine',
'metadata': {
'namespace': '',
'annotations': {
'harvesterhci.io/volumeClaimTemplates': '',
'field.cattle.io/description': '',
'networks.harvesterhci.io/ips': '[]'
},
'labels': {
'harvesterhci.io/creator': 'harvester',
'harvesterhci.io/os': ''//
},
'name': ''
},
'spec': {
'running': '', //
'template': {
this.$refs.virtualFormData.validate((valid) => {
if (valid) {
var formData = this.$refs['child'].formData
const baseTemp = {
'type': 'kubevirt.io.virtualmachine',
'metadata': {
'namespace': '',
'annotations': {
'harvesterhci.io/sshNames': '[]'// sshList
'harvesterhci.io/volumeClaimTemplates': '',
'field.cattle.io/description': '',
'networks.harvesterhci.io/ips': '[]'
},
'labels': {
'harvesterhci.io/vmName': ''
}
'harvesterhci.io/creator': 'harvester',
'harvesterhci.io/os': ''//
},
'name': ''
},
'spec': {
'domain': {
'machine': {
'type': ''//
},
'cpu': {
'cores': 0,
'sockets': 1,
'threads': 1
},
'devices': {
'inputs': [], // tablet
'interfaces': [], //
'disks': [] //
},
'resources': {
'limits': {
'cpu': '',
'memory': ''
'running': '', //
'template': {
'metadata': {
'annotations': {
'harvesterhci.io/sshNames': '[]'// sshList
},
'labels': {
'harvesterhci.io/vmName': ''
}
},
'spec': {
'domain': {
'machine': {
'type': ''//
},
'cpu': {
'cores': 0,
'sockets': 1,
'threads': 1
},
'devices': {
'inputs': [], // tablet
'interfaces': [], //
'disks': [] //
},
'resources': {
'limits': {
'cpu': '1',
'memory': '2'
}
}
},
'evictionStrategy': 'LiveMigrate',
'networks': [],
'volumes': [], //
'hostname': '' //
}
},
'evictionStrategy': 'LiveMigrate',
'networks': [],
'volumes': [], //
'hostname': '' //
}
}
}
}
const tempYAML = this.isEdit ? deepClone(this.virtualDetailData) : baseTemp
set(tempYAML, 'metadata.namespace', this.virtualFormData.namespace)
set(tempYAML, "metadata.annotations['field.cattle.io/description']", this.virtualFormData.description)
set(tempYAML, "metadata.labels['harvesterhci.io/os']", formData.osSystem)
set(tempYAML, 'metadata.name', this.virtualFormData.name)
set(tempYAML, 'spec.running', this.virtualFormData.isRunning)
set(tempYAML, "spec.template.metadata.labels['harvesterhci.io/vmName']", this.virtualFormData.name)
set(tempYAML, 'spec.template.spec.domain.machine.type', formData.machineType || '')
set(tempYAML, 'spec.template.spec.domain.cpu.cores', Number(formData.cpu) || 0)
set(tempYAML, 'spec.template.spec.domain.devices.inputs', formData.usbTablet ? [
{
'bus': 'usb',
'name': 'tablet',
'type': 'tablet'
}
] : [])
set(tempYAML, 'spec.template.spec.domain.resources.limits.cpu', formData.cpu)
set(tempYAML, 'spec.template.spec.domain.resources.limits.memory', (formData.memory || 4) + 'Gi')
set(tempYAML, 'spec.template.spec.hostname', formData.hostname || this.virtualFormData.name)
//
// nodeSelector: {kubernetes.io/hostname: "zhejianglab-node"}
//
var volumes = this.$refs['child'].$refs['volume']
const volumeClaimTemplates = []
tempYAML.spec.template.spec.volumes = []
tempYAML.spec.template.spec.domain.devices.disks = []
for (let i = 0; i < volumes.length; i++) {
var volumeType = volumes[i].$options['_componentTag']
const { name, bus, size, type, imageId, image, currentVolume, claimName: claimNameData } = volumes[i].formData
// claimName
const claimName = claimNameData || volumeType === 'ExistingVolume' ? currentVolume : this.virtualFormData.name + '-' + name + '-' + generate('0123456789abcdefghijklmnopqrstuvwxyz', 5)
tempYAML.spec.template.spec.volumes.push(
volumeType === 'Container' ? {
'name': name,
'containerDisk': {
'image': image
}
} : {
'name': name,
'persistentVolumeClaim': {
'claimName': claimName
}
}
)
tempYAML.spec.template.spec.domain.devices.disks.push({
'name': name,
[type]: {
'bus': bus
},
'bootOrder': i + 1
})
if (volumeType === 'VMImage') {
volumeClaimTemplates.push({
'metadata': {
'name': claimName,
'annotations': {
'harvesterhci.io/imageId': imageId
}
},
'spec': {
'accessModes': [
'ReadWriteMany'
],
'resources': {
'requests': {
'storage': size + 'Gi'
}
},
'volumeMode': 'Block',
'storageClassName': 'longhorn-' + imageId.split('/')[1]
}
})
}
if (volumeType === 'Volume') {
volumeClaimTemplates.push({
'metadata': {
'name': claimName
},
'spec': {
'accessModes': [
'ReadWriteMany'
],
'resources': {
'requests': {
'storage': size + 'Gi'
}
},
'volumeMode': 'Block',
'storageClassName': 'longhorn'
}
})
}
}
tempYAML.spec.template.spec.domain.devices.disks.push({
name: 'cloudinitdisk',
disk: { bus: 'virtio' }
})
const secretName = this.isEdit ? this.virtualDetailData.spec.template.spec.volumes.filter(e => e.name === 'cloudinitdisk')[0].cloudInitNoCloud.secretRef.name : (this.virtualFormData.name + '-' + generate('0123456789abcdefghijklmnopqrstuvwxyz', 5))
tempYAML.spec.template.spec.volumes.push({
name: 'cloudinitdisk',
cloudInitNoCloud: {
secretRef: { name: secretName },
networkDataSecretRef: { name: secretName }
}
})
// set volumeClaimTemplates
set(tempYAML, "metadata.annotations['harvesterhci.io/volumeClaimTemplates']", JSON.stringify(volumeClaimTemplates))
//
var networksData = this.$refs['child'].$refs['network']
tempYAML.spec.template.spec.networks = []
tempYAML.spec.template.spec.domain.devices.interfaces = []
for (let i = 0; i < networksData.length; i++) {
const { name, model, networkName, type, mac } = networksData[i].formData
// default
const interfaces = {
[type]: {
},
'model': model,
'name': name
}
if (networkName === 'management Network') {
set(interfaces, 'macAddress', mac)
tempYAML.spec.template.spec.networks.push({
'pod': {},
'name': name
})
} else {
tempYAML.spec.template.spec.networks.push({
'multus': {
'networkName': networkName
},
'name': name
})
}
tempYAML.spec.template.spec.domain.devices.interfaces.push(interfaces)
}
if (!this.isEdit) {
postVirtualMachine(tempYAML).then((res) => {
// secret
const secretData = {
'metadata': {
'name': secretName,
'namespace': this.virtualFormData.namespace,
'labels': {
'harvesterhci.io/cloud-init-template': 'harvester'
},
'ownerReferences': [
{
'name': this.virtualFormData.name,
'kind': 'VirtualMachine',
'uid': res.metadata.uid,
'apiVersion': 'kubevirt.io/v1'
}
]
},
'type': 'secret',
'data': {
networkData: base64Encode(formData.networkData) || null,
userData: base64Encode(formData.userData) || this.initUserData
}
}
postSecret(this.virtualFormData.namespace, secretData).then(e => {
this.$message.success('创建成功')
this.goBack()
const tempYAML = this.isEdit ? deepClone(this.virtualDetailData) : baseTemp
set(tempYAML, 'metadata.namespace', this.virtualFormData.namespace)
set(tempYAML, "metadata.annotations['field.cattle.io/description']", this.virtualFormData.description)
set(tempYAML, "metadata.labels['harvesterhci.io/os']", formData.osSystem)
set(tempYAML, 'metadata.name', this.virtualFormData.name)
set(tempYAML, 'spec.running', this.virtualFormData.isRunning)
set(tempYAML, "spec.template.metadata.labels['harvesterhci.io/vmName']", this.virtualFormData.name)
set(tempYAML, 'spec.template.spec.domain.machine.type', formData.machineType || '')
set(tempYAML, 'spec.template.spec.domain.cpu.cores', Number(formData.cpu) || 0)
set(tempYAML, 'spec.template.spec.domain.devices.inputs', formData.usbTablet ? [
{
'bus': 'usb',
'name': 'tablet',
'type': 'tablet'
}
] : [])
set(tempYAML, 'spec.template.spec.domain.resources.limits.cpu', formData.cpu)
set(tempYAML, 'spec.template.spec.domain.resources.limits.memory', (formData.memory || 4) + 'Gi')
set(tempYAML, 'spec.template.spec.hostname', formData.hostname || this.virtualFormData.name)
//
// nodeSelector: {kubernetes.io/hostname: "zhejianglab-node"}
//
var volumes = this.$refs['child'].$refs['volume']
const volumeClaimTemplates = []
tempYAML.spec.template.spec.volumes = []
tempYAML.spec.template.spec.domain.devices.disks = []
for (let i = 0; i < volumes.length; i++) {
var volumeType = volumes[i].$options['_componentTag']
const { name, bus, size, type, imageId, image, currentVolume, claimName: claimNameData } = volumes[i].formData
// claimName
const claimName = claimNameData || volumeType === 'ExistingVolume' ? currentVolume : this.virtualFormData.name + '-' + name + '-' + generate('0123456789abcdefghijklmnopqrstuvwxyz', 5)
tempYAML.spec.template.spec.volumes.push(
volumeType === 'Container' ? {
'name': name,
'containerDisk': {
'image': image
}
} : {
'name': name,
'persistentVolumeClaim': {
'claimName': claimName
}
}
)
tempYAML.spec.template.spec.domain.devices.disks.push({
'name': name,
[type]: {
'bus': bus
},
'bootOrder': i + 1
})
if (volumeType === 'VMImage') {
volumeClaimTemplates.push({
'metadata': {
'name': claimName,
'annotations': {
'harvesterhci.io/imageId': imageId
}
},
'spec': {
'accessModes': [
'ReadWriteMany'
],
'resources': {
'requests': {
'storage': size + 'Gi'
}
},
'volumeMode': 'Block',
'storageClassName': 'longhorn-' + imageId.split('/')[1]
}
})
}
if (volumeType === 'Volume') {
volumeClaimTemplates.push({
'metadata': {
'name': claimName
},
'spec': {
'accessModes': [
'ReadWriteMany'
],
'resources': {
'requests': {
'storage': size + 'Gi'
}
},
'volumeMode': 'Block',
'storageClassName': 'longhorn'
}
})
}
}
tempYAML.spec.template.spec.domain.devices.disks.push({
name: 'cloudinitdisk',
disk: { bus: 'virtio' }
})
})
} else {
putVirtualMachine(tempYAML).then(res => {
const secretData = deepClone(this.secretTemp)
set(secretData, 'data.networkData', base64Encode(formData.networkData) || null)
set(secretData, 'data.userData', base64Encode(formData.userData) || this.initUserData)
putSecret(this.virtualFormData.namespace, secretData.metadata.name, secretData).then(e => {
this.$message.success('修改成功')
this.goBack()
const secretName = this.isEdit ? this.virtualDetailData.spec.template.spec.volumes.filter(e => e.name === 'cloudinitdisk')[0].cloudInitNoCloud.secretRef.name : (this.virtualFormData.name + '-' + generate('0123456789abcdefghijklmnopqrstuvwxyz', 5))
tempYAML.spec.template.spec.volumes.push({
name: 'cloudinitdisk',
cloudInitNoCloud: {
secretRef: { name: secretName },
networkDataSecretRef: { name: secretName }
}
})
})
}
// set volumeClaimTemplates
set(tempYAML, "metadata.annotations['harvesterhci.io/volumeClaimTemplates']", JSON.stringify(volumeClaimTemplates))
//
var networksData = this.$refs['child'].$refs['network']
tempYAML.spec.template.spec.networks = []
tempYAML.spec.template.spec.domain.devices.interfaces = []
for (let i = 0; i < networksData.length; i++) {
const { name, model, networkName, type, mac } = networksData[i].formData
// default
const interfaces = {
[type]: {
},
'model': model,
'name': name
}
if (networkName === 'management Network') {
set(interfaces, 'macAddress', mac)
tempYAML.spec.template.spec.networks.push({
'pod': {},
'name': name
})
} else {
tempYAML.spec.template.spec.networks.push({
'multus': {
'networkName': networkName
},
'name': name
})
}
tempYAML.spec.template.spec.domain.devices.interfaces.push(interfaces)
}
if (!this.isEdit) {
postVirtualMachine(tempYAML).then((res) => {
// secret
const secretData = {
'metadata': {
'name': secretName,
'namespace': this.virtualFormData.namespace,
'labels': {
'harvesterhci.io/cloud-init-template': 'harvester'
},
'ownerReferences': [
{
'name': this.virtualFormData.name,
'kind': 'VirtualMachine',
'uid': res.metadata.uid,
'apiVersion': 'kubevirt.io/v1'
}
]
},
'type': 'secret',
'data': {
networkData: base64Encode(formData.networkData) || null,
userData: base64Encode(formData.userData) || this.initUserData
}
}
postSecret(this.virtualFormData.namespace, secretData).then(e => {
this.$message.success('创建成功')
this.goBack()
})
})
} else {
putVirtualMachine(tempYAML).then(res => {
const secretData = deepClone(this.secretTemp)
set(secretData, 'data.networkData', base64Encode(formData.networkData) || null)
set(secretData, 'data.userData', base64Encode(formData.userData) || this.initUserData)
putSecret(this.virtualFormData.namespace, secretData.metadata.name, secretData).then(e => {
this.$message.success('修改成功')
this.goBack()
})
})
}
}
})
},
goBack() {
this.$router.push({ path: '/virtual/virtual-machine' })

View File

@ -208,8 +208,8 @@ export default {
osSystem: '',
usbTablet: true,
qumeAgent: true,
cpu: '',
memory: '',
cpu: '1',
memory: '2',
userData: null,
networkData: '',
selectSshkeyList: []

View File

@ -3,7 +3,7 @@
<div @click="deleteCard"> <i class="el-icon-close show-icon" /></div>
<h5>镜像卷</h5>
<el-row :gutter="20">
<el-form>
<el-form :rules="rules">
<el-col :span="8">
<el-form-item label="名称" prop="name"><el-input
v-model="formData.name"
@ -89,7 +89,17 @@ export default {
isEdit: false,
imageList: [],
vmImageTypeList: ['disk', 'cd-rom'],
busList: ['virtio', 'sata', 'scsi']
busList: ['virtio', 'sata', 'scsi'],
//
rules: {
imageId: [
{
required: true,
message: '镜像不能为空',
trigger: 'blur'
}
]
}
}
},
mounted() {
@ -101,6 +111,9 @@ export default {
}
getImages().then(res => {
this.imageList = res.data
if (this.formData.imageId === '') {
this.formData.imageId = res.data?.[0].id || ''
}
})
},
methods: {