storage: Allow creating snapshot from VM snapshot (#587)

In old UI we support creating snapshot from
VM snapshot by selecting one of the volume
belonging to VM. Allow the same in new UI

Co-authored-by: Rakesh Venkatesh <r.venkatesh@global.leaseweb.com>
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rakesh 2020-08-20 10:44:24 +02:00 committed by Rohit Yadav
parent 3a81c55932
commit 2bc239fa76
3 changed files with 168 additions and 1 deletions

View File

@ -256,6 +256,7 @@ export default {
columns: () => { columns: () => {
var fields = ['name', 'state', 'volumename', 'intervaltype', 'created'] var fields = ['name', 'state', 'volumename', 'intervaltype', 'created']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) { if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
fields.push('domain')
fields.push('account') fields.push('account')
} }
return fields return fields
@ -315,7 +316,7 @@ export default {
permission: ['listVMSnapshot'], permission: ['listVMSnapshot'],
resourceType: 'VMSnapshot', resourceType: 'VMSnapshot',
columns: () => { columns: () => {
var fields = ['displayname', 'state', 'name', 'type', 'current', 'parentName', 'created'] const fields = ['displayname', 'state', 'name', 'type', 'current', 'parentName', 'created']
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) { if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
fields.push('domain') fields.push('domain')
fields.push('account') fields.push('account')
@ -325,6 +326,16 @@ export default {
details: ['name', 'id', 'displayname', 'description', 'type', 'current', 'parentName', 'virtualmachineid', 'account', 'domain', 'created'], details: ['name', 'id', 'displayname', 'description', 'type', 'current', 'parentName', 'virtualmachineid', 'account', 'domain', 'created'],
searchFilters: ['name', 'domainid', 'account', 'tags'], searchFilters: ['name', 'domainid', 'account', 'tags'],
actions: [ actions: [
{
api: 'createSnapshotFromVMSnapshot',
icon: 'camera',
label: 'label.action.create.snapshot.from.vmsnapshot',
message: 'message.action.create.snapshot.from.vmsnapshot',
dataView: true,
popup: true,
show: (record) => { return (record.state === 'Ready' && record.hypervisor === 'KVM') },
component: () => import('@/views/storage/CreateSnapshotFromVMSnapshot.vue')
},
{ {
api: 'revertToVMSnapshot', api: 'revertToVMSnapshot',
icon: 'sync', icon: 'sync',

View File

@ -83,6 +83,7 @@
"label.action.create.template.from.vm": "Create Template from VM", "label.action.create.template.from.vm": "Create Template from VM",
"label.action.create.template.from.volume": "Create Template from Volume", "label.action.create.template.from.volume": "Create Template from Volume",
"label.action.create.template.processing": "Creating Template....", "label.action.create.template.processing": "Creating Template....",
"label.action.create.snapshot.from.vmsnapshot": "Create Snapshot from VM Snapshot",
"label.action.create.vm": "Create VM", "label.action.create.vm": "Create VM",
"label.action.create.vm.processing": "Creating VM....", "label.action.create.vm.processing": "Creating VM....",
"label.action.create.volume": "Create Volume", "label.action.create.volume": "Create Volume",
@ -2341,6 +2342,7 @@
"message.action.cancel.maintenance.mode": "Please confirm that you want to cancel this maintenance.", "message.action.cancel.maintenance.mode": "Please confirm that you want to cancel this maintenance.",
"message.action.change.service.warning.for.instance": "Your instance must be stopped before attempting to change its current service offering.", "message.action.change.service.warning.for.instance": "Your instance must be stopped before attempting to change its current service offering.",
"message.action.change.service.warning.for.router": "Your router must be stopped before attempting to change its current service offering.", "message.action.change.service.warning.for.router": "Your router must be stopped before attempting to change its current service offering.",
"message.action.create.snapshot.from.vmsnapshot": "Please confirm that you want to create snapshot from VM Snapshot",
"message.action.delete.backup.offering": "Please confirm that you want to delete this backup offering?", "message.action.delete.backup.offering": "Please confirm that you want to delete this backup offering?",
"message.action.delete.cluster": "Please confirm that you want to delete this cluster.", "message.action.delete.cluster": "Please confirm that you want to delete this cluster.",
"message.action.delete.disk.offering": "Please confirm that you want to delete this disk offering.", "message.action.delete.disk.offering": "Please confirm that you want to delete this disk offering.",
@ -2595,6 +2597,8 @@
"message.create.internallb.failed": "Failed to create Internal LB", "message.create.internallb.failed": "Failed to create Internal LB",
"message.create.internallb.processing": "Creation of Internal LB is in progress", "message.create.internallb.processing": "Creation of Internal LB is in progress",
"message.create.service.offering": "Service offering created", "message.create.service.offering": "Service offering created",
"message.create.snapshot.from.vmsnapshot.failed": "Failed to create Snapshot from VM Snapshot",
"message.create.snapshot.from.vmsnapshot.progress": "Snapshot Creation in progress",
"message.create.template": "Are you sure you want to create template?", "message.create.template": "Are you sure you want to create template?",
"message.create.template.vm": "Create VM from template <b id=\"p_name\"></b>", "message.create.template.vm": "Create VM from template <b id=\"p_name\"></b>",
"message.create.template.volume": "Please specify the following information before creating a template of your disk volume: <b><span id=\"volume_name\"></span></b>. Creation of the template can range from several minutes to longer depending on the size of the volume.", "message.create.template.volume": "Please specify the following information before creating a template of your disk volume: <b><span id=\"volume_name\"></span></b>. Creation of the template can range from several minutes to longer depending on the size of the volume.",
@ -3064,6 +3068,7 @@
"message.success.create.keypair": "Successfully created SSH key pair", "message.success.create.keypair": "Successfully created SSH key pair",
"message.success.create.kubernetes.cluter": "Successfully created Kubernetes cluster", "message.success.create.kubernetes.cluter": "Successfully created Kubernetes cluster",
"message.success.create.l2.network": "Successfully created L2 network", "message.success.create.l2.network": "Successfully created L2 network",
"message.success.create.snapshot.from.vmsnapshot": "Successfully created Snapshot from VM snapshot",
"message.success.create.volume": "Successfully created volume", "message.success.create.volume": "Successfully created volume",
"message.success.delete": "Delete success", "message.success.delete": "Delete success",
"message.success.delete.acl.rule": "Successfully removed ACL rule", "message.success.delete.acl.rule": "Successfully removed ACL rule",

View File

@ -0,0 +1,151 @@
// 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>
<a-spin :spinning="loading">
<a-form class="form" :form="form" @submit="handleSubmit" layout="vertical">
<a-form-item :label="$t('label.name')">
<a-input
v-decorator="['name', {
rules: [{ required: true, message: $t('message.error.name') }]
}]"
:placeholder="$t('label.snapshot.name')"/>
</a-form-item>
<a-form-item :label="$t('label.volume')">
<a-select
v-decorator="['volumeid', {
initialValue: selectedVolumeId,
rules: [{ required: true, message: $t('message.error.select') }]}]"
:loading="loading"
@change="id => (volumes.filter(x => x.id === id))"
>
<a-select-option
v-for="(volume, index) in volumes"
:value="volume.id"
:key="index">
{{ volume.displaytext || volume.name }}
</a-select-option>
</a-select>
</a-form-item>
<div :span="24" class="action-button">
<a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
<a-button type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
</div>
</a-form>
</a-spin>
</template>
<script>
import { api } from '@/api'
export default {
name: 'CreateSnapshotFromVMSnapshot',
props: {
resource: {
type: Object,
required: true
}
},
data () {
return {
volumes: [],
selectedVolumeId: '',
loading: false
}
},
beforeCreate () {
this.form = this.$form.createForm(this)
},
mounted () {
this.fetchData()
},
methods: {
fetchData () {
this.loading = true
api('listVolumes', {
virtualmachineid: this.resource.virtualmachineid,
listall: true
}).then(json => {
this.volumes = json.listvolumesresponse.volume || []
this.selectedVolumeId = this.volumes[0].id || ''
}).finally(() => {
this.loading = false
})
},
handleSubmit (e) {
this.form.validateFields((err, values) => {
if (err) {
return
}
this.loading = true
api('createSnapshotFromVMSnapshot', {
name: values.name,
volumeid: values.volumeid,
vmsnapshotid: this.resource.id
}).then(response => {
this.$pollJob({
jobId: response.createsnapshotfromvmsnapshotresponse.jobid,
successMessage: this.$t('message.success.create.snapshot.from.vmsnapshot'),
successMethod: () => {
this.$store.dispatch('AddAsyncJob', {
title: this.$t('message.success.create.snapshot.from.vmsnapshot'),
jobid: response.createsnapshotfromvmsnapshotresponse.jobid,
description: values.name,
status: 'progress'
})
this.$emit('refresh-data')
},
errorMessage: this.$t('message.create.snapshot.from.vmsnapshot.failed'),
errorMethod: () => {
this.$emit('refresh-data')
},
loadingMessage: this.$t('message.create.snapshot.from.vmsnapshot.progress'),
catchMessage: this.$t('error.fetching.async.job.result')
})
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
this.$emit('refresh-data')
this.closeModal()
})
})
},
closeModal () {
this.$emit('close-action')
}
}
}
</script>
<style lang="scss" scoped>
.form {
width: 80vw;
@media (min-width: 500px) {
width: 400px;
}
}
.action-button {
text-align: right;
button {
margin-right: 5px;
}
}
</style>