Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
This repository was archived by the owner on Jan 20, 2021. It is now read-only.
8 changes: 8 additions & 0 deletions 8 public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,10 @@
"label.action.migrate.instance.processing": "Migrating Instance....",
"label.action.migrate.router": "Migrate Router",
"label.action.migrate.router.processing": "Migrating Router....",
"label.action.migrate.router.to.ps": "Migrate router to another primary storage",
"label.action.migrate.systemvm": "Migrate System VM",
"label.action.migrate.systemvm.processing": "Migrating System VM....",
"label.action.migrate.systemvm.to.ps": "Migrate system VM to another primary storage",
"label.action.project.add.account": "Add Account to Project",
"label.action.project.add.user": "Add User to Project",
"label.action.reboot.instance": "Reboot Instance",
Expand Down Expand Up @@ -1358,6 +1360,7 @@
"label.migrate.instance.to.host": "Migrate instance to another host",
"label.migrate.instance.to.ps": "Migrate instance to another primary storage",
"label.migrate.lb.vm": "Migrate LB VM",
"label.migrate.lb.vm.to.ps": "Migrate LB VM to another primary storage",
"label.migrate.router.to": "Migrate Router to",
"label.migrate.systemvm.to": "Migrate System VM to",
"label.migrate.to.host": "Migrate to host",
Expand Down Expand Up @@ -2030,6 +2033,7 @@
"label.storage.tags": "Storage Tags",
"label.storage.traffic": "Storage Traffic",
"label.storageid": "Primary Storage",
"label.storage.migration.required": "Storage Migration Required",
"label.storagemotionenabled": "Storage Motion Enabled",
"label.storagepolicy": "Storage policy",
"label.storagepool": "Storage Pool",
Expand Down Expand Up @@ -2929,6 +2933,9 @@
"message.migrate.instance.select.host": "Please select a host for migration",
"message.migrate.instance.to.host": "Please confirm that you want to migrate instance to another host.",
"message.migrate.instance.to.ps": "Please confirm that you want to migrate instance to another primary storage.",
"message.migrate.lb.vm.to.ps": "Please confirm that you want to migrate LB VM to another primary storage.",
"message.migrate.router.to.ps": "Please confirm that you want to migrate router to another primary storage.",
"message.migrate.system.vm.to.ps": "Please confirm that you want to migrate system VM to another primary storage.",
"message.migrate.router.confirm": "Please confirm the host you wish to migrate the router to:",
"message.migrate.systemvm.confirm": "Please confirm the host you wish to migrate the system VM to:",
"message.migrate.volume": "Please confirm that you want to migrate volume to another primary storage.",
Expand All @@ -2937,6 +2944,7 @@
"message.migrating.failed": "Migration failed",
"message.migrating.processing": "Migration in progress for",
"message.migrating.vm.to.host.failed": "Failed to migrate VM to host",
"message.migrating.vm.to.storage.failed": "Failed to migrate VM to storage",
"message.move.acl.order": "Move ACL rule order",
"message.move.acl.order.failed": "Failed to move ACL rule",
"message.move.acl.order.processing": "Moving ACL rule...",
Expand Down
12 changes: 2 additions & 10 deletions 12 src/config/section/compute.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,16 +299,8 @@ export default {
docHelp: 'adminguide/virtual_machines.html#moving-vms-between-hosts-manual-live-migration',
dataView: true,
show: (record, store) => { return ['Stopped'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
args: ['storageid', 'virtualmachineid'],
mapping: {
storageid: {
api: 'listStoragePools',
params: (record) => { return { zoneid: record.zoneid } }
},
virtualmachineid: {
value: (record) => { return record.id }
}
}
component: () => import('@/views/compute/MigrateVMStorage'),
popup: true
},
{
api: 'resetPasswordForVirtualMachine',
Expand Down
19 changes: 12 additions & 7 deletions 19 src/config/section/infra/ilbvms.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,18 @@ export default {
icon: 'drag',
label: 'label.action.migrate.router',
dataView: true,
show: (record) => { return record.state === 'Running' },
args: ['virtualmachineid', 'hostid'],
mapping: {
virtualmachineid: {
value: (record) => { return record.id }
}
}
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
component: () => import('@/views/compute/MigrateWizard'),
popup: true
},
{
api: 'migrateSystemVm',
icon: 'drag',
label: 'label.action.migrate.systemvm.to.ps',
dataView: true,
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
component: () => import('@/views/compute/MigrateVMStorage'),
popup: true
}
]
}
23 changes: 12 additions & 11 deletions 23 src/config/section/infra/routers.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,18 @@ export default {
icon: 'drag',
label: 'label.action.migrate.router',
dataView: true,
show: (record, store) => { return ['Running'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
args: ['virtualmachineid', 'hostid'],
mapping: {
virtualmachineid: {
value: (record) => { return record.id }
},
hostid: {
api: 'findHostsForMigration',
params: (record) => { return { virtualmachineid: record.id } }
}
}
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
component: () => import('@/views/compute/MigrateWizard'),
popup: true
},
{
api: 'migrateSystemVm',
icon: 'drag',
label: 'label.action.migrate.systemvm.to.ps',
dataView: true,
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
component: () => import('@/views/compute/MigrateVMStorage'),
popup: true
},
{
api: 'runDiagnostics',
Expand Down
23 changes: 12 additions & 11 deletions 23 src/config/section/infra/systemVms.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,18 @@ export default {
icon: 'drag',
label: 'label.action.migrate.systemvm',
dataView: true,
show: (record) => { return record.state === 'Running' },
args: ['virtualmachineid', 'hostid'],
mapping: {
virtualmachineid: {
value: (record) => { return record.id }
},
hostid: {
api: 'findHostsForMigration',
params: (record) => { return { virtualmachineid: record.id } }
}
}
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
component: () => import('@/views/compute/MigrateWizard'),
popup: true
},
{
api: 'migrateSystemVm',
icon: 'drag',
label: 'label.action.migrate.systemvm.to.ps',
dataView: true,
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
component: () => import('@/views/compute/MigrateVMStorage'),
popup: true
},
{
api: 'runDiagnostics',
Expand Down
228 changes: 228 additions & 0 deletions 228 src/views/compute/MigrateVMStorage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

<template>
<div class="form-layout">
<a-spin :spinning="loading">
<a-form
:form="form"
@submit="handleSubmit"
layout="vertical">
<a-form-item>
<span slot="label">
{{ $t('label.storageid') }}
<a-tooltip :title="apiParams.storageid.description" v-if="!(apiParams.hostid && apiParams.hostid.required === false)">
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
</a-tooltip>
</span>
<a-select
:loading="loading"
v-decorator="['storageid', {
rules: [{ required: true, message: `${this.$t('message.error.required.input')}` }]
}]">
<a-select-option v-for="storagePool in storagePools" :key="storagePool.id">
{{ storagePool.name || storagePool.id }}
</a-select-option>
</a-select>
</a-form-item>

<div :span="24" class="action-button">
<a-button @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
<a-button :loading="loading" type="primary" @click="handleSubmit">{{ this.$t('label.ok') }}</a-button>
</div>
</a-form>
</a-spin>
</div>
</template>

<script>
import { api } from '@/api'

export default {
name: 'MigrateVMStorage',
props: {
resource: {
type: Object,
required: true
}
},
data () {
return {
loading: false,
storagePools: []
}
},
beforeCreate () {
this.form = this.$form.createForm(this)
this.apiParams = {}
if (this.$route.meta.name === 'vm') {
this.apiConfig = this.$store.getters.apis.migrateVirtualMachineWithVolume || {}
this.apiConfig.params.forEach(param => {
this.apiParams[param.name] = param
})
this.apiConfig = this.$store.getters.apis.migrateVirtualMachine || {}
this.apiConfig.params.forEach(param => {
if (!(param.name in this.apiParams)) {
this.apiParams[param.name] = param
}
})
} else {
this.apiConfig = this.$store.getters.apis.migrateSystemVm || {}
this.apiConfig.params.forEach(param => {
if (!(param.name in this.apiParams)) {
this.apiParams[param.name] = param
}
})
}
},
created () {
},
mounted () {
this.fetchData()
},
methods: {
fetchData () {
this.loading = true
api('listStoragePools', {
zoneid: this.resource.zoneid
}).then(response => {
if (this.arrayHasItems(response.liststoragepoolsresponse.storagepool)) {
this.storagePools = response.liststoragepoolsresponse.storagepool
}
}).finally(() => {
this.loading = false
})
},
isValidValueForKey (obj, key) {
return key in obj && obj[key] != null
},
arrayHasItems (array) {
return array !== null && array !== undefined && Array.isArray(array) && array.length > 0
},
isObjectEmpty (obj) {
return !(obj !== null && obj !== undefined && Object.keys(obj).length > 0 && obj.constructor === Object)
},
handleSubmit (e) {
e.preventDefault()
this.form.validateFields((err, values) => {
if (err) {
return
}
this.loading = true
var isUserVm = true
if (this.$route.meta.name !== 'vm') {
isUserVm = false
}
var migrateApi = isUserVm ? 'migrateVirtualMachine' : 'migrateSystemVm'
if (isUserVm && this.apiParams.hostid && this.apiParams.hostid.required === false) {
migrateApi = 'migrateVirtualMachineWithVolume'
var rootVolume = null
api('listVolumes', {
listAll: true,
virtualmachineid: this.resource.id
}).then(response => {
var volumes = response.listvolumesresponse.volume
if (volumes && volumes.length > 0) {
volumes = volumes.filter(item => item.type === 'ROOT')
if (volumes && volumes.length > 0) {
rootVolume = volumes[0]
}
if (rootVolume == null) {
this.$message.error('Failed to find ROOT volume for the VM ' + this.resource.id)
this.closeAction()
}
this.migrateVm(migrateApi, values.storageid, rootVolume.id)
}
})
return
}
this.migrateVm(migrateApi, values.storageid, null)
})
},
migrateVm (migrateApi, storageId, rootVolumeId) {
var params = {
virtualmachineid: this.resource.id,
storageid: storageId
}
if (rootVolumeId !== null) {
params = {
virtualmachineid: this.resource.id,
'migrateto[0].volume': rootVolumeId,
'migrateto[0].pool': storageId
}
}
api(migrateApi, params).then(response => {
var jobId = ''
if (migrateApi === 'migrateVirtualMachineWithVolume') {
jobId = response.migratevirtualmachinewithvolumeresponse.jobid
} else if (migrateApi === 'migrateSystemVm') {
jobId = response.migratesystemvmresponse.jobid
} else {
jobId = response.migratevirtualmachine.jobid
}
this.$store.dispatch('AddAsyncJob', {
title: `${this.$t('label.migrating')} ${this.resource.name}`,
jobid: jobId,
description: this.resource.name,
status: 'progress'
})
this.$pollJob({
jobId: jobId,
successMessage: `${this.$t('message.success.migrating')} ${this.resource.name}`,
successMethod: () => {
this.$parent.$parent.close()
},
errorMessage: this.$t('message.migrating.failed'),
errorMethod: () => {
this.$parent.$parent.close()
},
loadingMessage: `${this.$t('message.migrating.processing')} ${this.resource.name}`,
catchMessage: this.$t('error.fetching.async.job.result'),
catchMethod: () => {
this.$parent.$parent.close()
}
})
this.$parent.$parent.close()
}).catch(error => {
console.error(error)
this.$message.error(`${this.$t('message.migrating.vm.to.storage.failed')} ${storageId}`)
})
},
closeAction () {
this.$emit('close-action')
}
}
}
</script>

<style scoped lang="less">
.form-layout {
width: 60vw;

@media (min-width: 500px) {
width: 450px;
}
}

.action-button {
text-align: right;

button {
margin-right: 5px;
}
}
</style>
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.