mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
ui: allow provisioning backups during instance deploy (#11612)
* ui: allow assigning backup offring during instance deploy Add backup offering selection to Deploy VM wizard and assign selected backup offering to the VM after successful deployment. This enables users to choose a backup offering during VM creation, and the VM is automatically associated with the selected offering post-deployment. Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * changes for schedules Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * Update ui/public/locales/pt_BR.json * Update ui/src/views/compute/wizard/DeployInstanceBackupSelection.vue Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * address review Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix * allow only one schdeule per interval type Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * show message same internaltype schedule * show backup step only when zone has offering --------- Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
d9abc078cf
commit
4884f52c90
@ -259,6 +259,7 @@
|
||||
"label.available": "Verfügbar",
|
||||
"label.back": "Zurück",
|
||||
"label.backup": "Backup",
|
||||
"label.backups": "Backup",
|
||||
"label.backup.attach.restore": "Backup-Volume wiederherstellen und anhängen",
|
||||
"label.backup.offering.assign": "VM zum Backup-Angebot zuordnen",
|
||||
"label.backup.offering.remove": "VM vom Backup-Angebot entfernen",
|
||||
|
||||
@ -317,6 +317,7 @@
|
||||
"label.availableprocessors": "Διαθέσιμοι πυρήνες επεξεργαστή",
|
||||
"label.back": "Πίσω",
|
||||
"label.backup": "Αντίγραφα ασφαλείας",
|
||||
"label.backups": "Αντίγραφα ασφαλείας",
|
||||
"label.backup.attach.restore": "Επαναφορά και επισύναψη τόμου αντιγράφου ασφαλείας",
|
||||
"label.backup.offering.assign": "Αντιστοίχιση εικονικής μηχανής με προσφορά δημιουργίας αντιγράφων ασφαλείας",
|
||||
"label.backup.offering.remove": "Κατάργηση εικονικής μηχανής από την προσφορά δημιουργίας αντιγράφων ασφαλείας",
|
||||
|
||||
@ -252,6 +252,7 @@
|
||||
"label.add.acl.rule": "Add ACL rule",
|
||||
"label.add.acl": "Add ACL",
|
||||
"label.add.affinity.group": "Add new Affinity Group",
|
||||
"label.add.backup.schedule": "Add Backup Schedule",
|
||||
"label.add.baremetal.dhcp.device": "Add bare metal DHCP device",
|
||||
"label.add.bgp.peer": "Add BGP Peer",
|
||||
"label.add.bigswitchbcf.device": "Add BigSwitch BCF Controller",
|
||||
@ -442,14 +443,17 @@
|
||||
"label.availablevirtualmachinecount": "Available Instances",
|
||||
"label.back": "Back",
|
||||
"label.back.login": "Back to login",
|
||||
"label.backup": "Backups",
|
||||
"label.backup": "Backup",
|
||||
"label.backups": "Backups",
|
||||
"label.backup.attach.restore": "Restore and attach backup volume",
|
||||
"label.backup.configure.schedule": "Configure Backup Schedule",
|
||||
"label.backup.offering.assign": "Assign Instance to backup offering",
|
||||
"label.backup.offering.remove": "Remove Instance from backup offering",
|
||||
"label.backup.offerings": "Backup Offerings",
|
||||
"label.backup.offering.assign.failed": "Failed to assign Backup Offering",
|
||||
"label.backup.repository": "Backup Repository",
|
||||
"label.backup.restore": "Restore Instance backup",
|
||||
"label.backup.schedule.create.failed": "Failed to create Backup Schedule",
|
||||
"label.backuplimit": "Backup Limits",
|
||||
"label.backup.storage": "Backup Storage",
|
||||
"label.backupstoragelimit": "Backup Storage Limits (GiB)",
|
||||
@ -2194,6 +2198,7 @@
|
||||
"label.select.all": "Select all",
|
||||
"label.select.columns": "Select columns",
|
||||
"label.select.a.zone": "Select a Zone",
|
||||
"label.select.backup.offering": "Select Backup Offering",
|
||||
"label.select.deployment.infrastructure": "Select deployment infrastructure",
|
||||
"label.select.guest.os.type": "Please select the guest OS type",
|
||||
"label.select.network": "Select Network",
|
||||
@ -3075,7 +3080,9 @@
|
||||
"message.backup.attach.restore": "Please confirm that you want to restore and attach the volume from the backup?",
|
||||
"message.backup.create": "Are you sure you want to create an Instance backup?",
|
||||
"message.backup.offering.remove": "Are you sure you want to remove Instance from backup offering and delete the backup chain?",
|
||||
"message.backup.provision.instance": "Select a backup offering to assign to the Instance. You can also add one or more backup schedules for different interval types to automate backups for this Instance. Assigning a backup offering and schedules helps protect your data by enabling automated and scheduled backups.",
|
||||
"message.backup.restore": "Please confirm that you want to restore the Instance backup?",
|
||||
"message.backup.update.existing.schedule": "Updating existing backup schedule for the same interval type",
|
||||
"message.cancel.shutdown": "Please confirm that you would like to cancel the shutdown on this Management Server. It will resume accepting any new Async Jobs.",
|
||||
"message.cancel.maintenance": "Please confirm that you would like to cancel the maintenance on this Management Server. It will resume accepting any new Async Jobs.",
|
||||
"message.certificate.upload.processing": "Certificate upload in progress",
|
||||
|
||||
@ -222,6 +222,7 @@
|
||||
"label.available": "Disponible",
|
||||
"label.back": "Volver",
|
||||
"label.backup": "Respaldos",
|
||||
"label.backups": "Respaldos",
|
||||
"label.backup.attach.restore": "Restaurar y conectar un Volumen de Respaldo",
|
||||
"label.backup.offering.assign": "Asignar instancia a una oferta de respaldo",
|
||||
"label.backup.offering.remove": "remover instancia de una oferta de respaldo",
|
||||
|
||||
@ -485,6 +485,7 @@
|
||||
"label.available.public.ips": "使用できるパブリックIPアドレス",
|
||||
"label.back": "戻る",
|
||||
"label.backup": "バックアップ",
|
||||
"label.backups": "バックアップ",
|
||||
"label.backup.attach.restore": "復元とバックアップボリュームをアタッチ",
|
||||
"label.backup.offering.assign": "VMをバックアップオファリングに割り当て",
|
||||
"label.backup.offering.remove": "VMバックアップオファリングから削除",
|
||||
|
||||
@ -269,6 +269,7 @@
|
||||
"label.available": "\uc0ac\uc6a9 \uac00\ub2a5",
|
||||
"label.back": "\ub4a4\ub85c",
|
||||
"label.backup": "\ubc31\uc5c5",
|
||||
"label.backups": "\ubc31\uc5c5",
|
||||
"label.backup.attach.restore": "\ubc31\uc5c5 \ubcfc\ub968 \ubcf5\uc6d0 \ubc0f \uc5f0\uacb0",
|
||||
"label.backup.offering.assign": "\uac00\uc0c1\uba38\uc2e0\uc5d0 \ubc31\uc5c5 \uc624\ud37c\ub9c1 \ud560\ub2f9",
|
||||
"label.backup.offering.remove": "\uac00\uc0c1\uba38\uc2e0\uc5d0 \ubc31\uc5c5 \uc624\ud37c\ub9c1 \uc81c\uac70",
|
||||
|
||||
@ -292,7 +292,8 @@
|
||||
"label.availability": "Disponibilidade",
|
||||
"label.available": "Dispon\u00edvel",
|
||||
"label.back": "Voltar",
|
||||
"label.backup": "Backups",
|
||||
"label.backup": "Backup",
|
||||
"label.backups": "Backups",
|
||||
"label.backup.attach.restore": "Restaurar e anexar volume de backup",
|
||||
"label.backup.offering.assign": "Atribuir VM a oferta de backup",
|
||||
"label.backup.offering.remove": "Remover VM de oferta de backup",
|
||||
|
||||
@ -419,6 +419,7 @@
|
||||
"label.back": "వెనుకకు",
|
||||
"label.back.login": "తిరిగి లాగిన్కి",
|
||||
"label.backup": "బ్యాకప్లు",
|
||||
"label.backups": "బ్యాకప్లు",
|
||||
"label.backup.attach.restore": "బ్యాకప్ వాల్యూమ్ను పునరుద్ధరించండి మరియు అటాచ్ చేయండి",
|
||||
"label.backup.configure.schedule": "బ్యాకప్ షెడ్యూల్ను కాన్ఫిగర్ చేయండి",
|
||||
"label.backup.offering.assign": "బ్యాకప్ సమర్పణకు ఉదాహరణను కేటాయించండి",
|
||||
|
||||
@ -561,6 +561,7 @@
|
||||
|
||||
"label.back": "\u540E\u9000",
|
||||
"label.backup": "\u5907\u4EFD",
|
||||
"label.backups": "\u5907\u4EFD",
|
||||
"label.backup.attach.restore": "\u6062\u590D\u5E76\u8FDE\u63A5\u5907\u4EFD\u5377",
|
||||
"label.backup.offering.assign": "\u5C06\u865A\u62DF\u673A\u5206\u914D\u7ED9\u5907\u4EFD\u4EA7\u54C1",
|
||||
"label.backup.offering.remove": "\u4ECE\u5907\u4EFD\u4EA7\u54C1\u4E2D\u5220\u9664\u865A\u62DF\u673A",
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
</template>
|
||||
<a-select-option v-for="option in options" :key="option.id" :value="option[optionValueKey]">
|
||||
<span>
|
||||
<span v-if="showIcon">
|
||||
<span v-if="showIcon && option.showicon !== false">
|
||||
<resource-icon v-if="option.icon && option.icon.base64image" :image="option.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||
<render-icon v-else :icon="defaultIcon" style="margin-right: 5px" />
|
||||
</span>
|
||||
|
||||
@ -415,7 +415,7 @@ export default {
|
||||
},
|
||||
{
|
||||
name: 'backup',
|
||||
title: 'label.backup',
|
||||
title: 'label.backups',
|
||||
icon: 'cloud-upload-outlined',
|
||||
permission: ['listBackups'],
|
||||
params: { listvmdetails: 'true' },
|
||||
|
||||
@ -40,7 +40,8 @@ import {
|
||||
dialogUtilPlugin,
|
||||
cpuArchitectureUtilPlugin,
|
||||
imagesUtilPlugin,
|
||||
extensionsUtilPlugin
|
||||
extensionsUtilPlugin,
|
||||
backupUtilPlugin
|
||||
} from './utils/plugins'
|
||||
import { VueAxios } from './utils/request'
|
||||
import directives from './utils/directives'
|
||||
@ -63,6 +64,7 @@ vueApp.use(dialogUtilPlugin)
|
||||
vueApp.use(cpuArchitectureUtilPlugin)
|
||||
vueApp.use(imagesUtilPlugin)
|
||||
vueApp.use(extensionsUtilPlugin)
|
||||
vueApp.use(backupUtilPlugin)
|
||||
vueApp.use(extensions)
|
||||
vueApp.use(directives)
|
||||
|
||||
|
||||
@ -597,3 +597,14 @@ export const extensionsUtilPlugin = {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const backupUtilPlugin = {
|
||||
install (app) {
|
||||
app.config.globalProperties.$isBackupProviderSupportsQuiesceVm = function (provider) {
|
||||
if (!provider && typeof provider !== 'string') {
|
||||
return false
|
||||
}
|
||||
return ['nas'].includes(provider.toLowerCase())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,13 +21,11 @@
|
||||
<a-tab-pane :tab="$t('label.schedule')" key="1">
|
||||
<FormSchedule
|
||||
:loading="loading"
|
||||
:resource="resource"
|
||||
:dataSource="dataSource"/>
|
||||
:resource="resource"/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane :tab="$t('label.scheduled.backups')" key="2">
|
||||
<BackupSchedule
|
||||
:loading="loading"
|
||||
:resource="resource"
|
||||
:dataSource="dataSource" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
||||
@ -540,6 +540,25 @@
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
<a-step
|
||||
v-if="zoneAllowsBackupOperations"
|
||||
:title="$t('label.backup')"
|
||||
:status="zoneSelected ? 'process' : 'wait'">
|
||||
<template #description>
|
||||
<div v-if="zoneSelected" style="margin-top: 15px">
|
||||
<deploy-instance-backup-selection
|
||||
:zoneId="zoneId"
|
||||
v-model:backupOfferingId="form.backupofferingid"
|
||||
:backupSchedules="backupSchedules"
|
||||
@change-backup-offering="onChangeBackupOffering"
|
||||
@add-backup-schedule="onAddBackupSchedule"
|
||||
@delete-backup-schedule="backupSchedules = backupSchedules.filter(schedule => schedule.id !== $event.id)" />
|
||||
<a-form-item class="form-item-hidden">
|
||||
<a-input v-model:value="form.backupofferingid" />
|
||||
</a-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
<a-step
|
||||
:title="$t('label.advanced.mode')"
|
||||
:status="zoneSelected ? 'process' : 'wait'">
|
||||
@ -901,7 +920,7 @@
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw, nextTick, h } from 'vue'
|
||||
import { Button } from 'ant-design-vue'
|
||||
import { Button, message } from 'ant-design-vue'
|
||||
import { getAPI, postAPI } from '@/api'
|
||||
import _ from 'lodash'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
@ -930,6 +949,7 @@ import SecurityGroupSelection from '@views/compute/wizard/SecurityGroupSelection
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
import InstanceNicsNetworkSelectListView from '@/components/view/InstanceNicsNetworkSelectListView'
|
||||
import DetailsInput from '@/components/widgets/DetailsInput'
|
||||
import DeployInstanceBackupSelection from '@views/compute/wizard/DeployInstanceBackupSelection'
|
||||
|
||||
export default {
|
||||
name: 'Wizard',
|
||||
@ -955,7 +975,8 @@ export default {
|
||||
SecurityGroupSelection,
|
||||
TooltipLabel,
|
||||
InstanceNicsNetworkSelectListView,
|
||||
DetailsInput
|
||||
DetailsInput,
|
||||
DeployInstanceBackupSelection
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
@ -1135,7 +1156,10 @@ export default {
|
||||
opts: []
|
||||
},
|
||||
externalDetailsEnabled: false,
|
||||
selectedExtensionId: null
|
||||
selectedExtensionId: null,
|
||||
zoneAllowsBackupOperations: false,
|
||||
selectedBackupOffering: null,
|
||||
backupSchedules: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -1672,6 +1696,13 @@ export default {
|
||||
if (this.leaseduration < 1) {
|
||||
this.vm.leaseduration = undefined
|
||||
}
|
||||
|
||||
delete this.vm.backupofferingid
|
||||
delete this.vm.backupofferingname
|
||||
if (this.form.backupofferingid && this.selectedBackupOffering) {
|
||||
this.vm.backupofferingid = this.selectedBackupOffering.id
|
||||
this.vm.backupofferingname = this.selectedBackupOffering.name
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2507,6 +2538,7 @@ export default {
|
||||
duration: 0
|
||||
})
|
||||
}
|
||||
this.performPostDeployBackupActions(vm)
|
||||
eventBus.emit('vm-refresh-data')
|
||||
},
|
||||
loadingMessage: `${title} ${this.$t('label.in.progress')}`,
|
||||
@ -2979,6 +3011,31 @@ export default {
|
||||
this.updateTemplateKey()
|
||||
this.formModel = toRaw(this.form)
|
||||
},
|
||||
async updateZoneAllowsBackupOperations () {
|
||||
this.zoneAllowsBackupOperations = false
|
||||
if (!this.zoneId) {
|
||||
return
|
||||
}
|
||||
if (!('listBackupOfferings' in this.$store.getters.apis) ||
|
||||
!('assignVirtualMachineToBackupOffering' in this.$store.getters.apis)) {
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
zoneid: this.zoneId,
|
||||
issystem: false,
|
||||
listall: true,
|
||||
page: 1,
|
||||
pageSize: 1
|
||||
}
|
||||
try {
|
||||
const response = await getAPI('listBackupOfferings', params)
|
||||
const backupOfferings = response.listbackupofferingsresponse.backupoffering || []
|
||||
this.zoneAllowsBackupOperations = backupOfferings.length > 0
|
||||
} catch (error) {
|
||||
console.error('Error fetching backup offerings:', error)
|
||||
this.zoneAllowsBackupOperations = false
|
||||
}
|
||||
},
|
||||
onSelectZoneId (value) {
|
||||
if (this.dataPreFill.zoneid !== value) {
|
||||
this.dataPreFill = {}
|
||||
@ -3004,7 +3061,10 @@ export default {
|
||||
this.resetTemplatesList()
|
||||
this.resetIsosList()
|
||||
this.imageType = this.queryIsoId ? 'isoid' : 'templateid'
|
||||
this.form.backupofferingid = undefined
|
||||
this.selectedBackupOffering = null
|
||||
this.fetchZoneOptions()
|
||||
this.updateZoneAllowsBackupOperations()
|
||||
},
|
||||
onSelectPodId (value) {
|
||||
this.podId = value
|
||||
@ -3395,6 +3455,113 @@ export default {
|
||||
return
|
||||
}
|
||||
this.form.externaldetails = undefined
|
||||
},
|
||||
onChangeBackupOffering (val) {
|
||||
if (!val || !val.id) {
|
||||
this.selectedBackupOffering = null
|
||||
this.backupSchedules = []
|
||||
return
|
||||
}
|
||||
this.selectedBackupOffering = val
|
||||
if (this.backupSchedules && this.backupSchedules.length > 0 && !this.$isBackupProviderSupportsQuiesceVm(val.provider)) {
|
||||
this.backupSchedules = this.backupSchedules.filter(item => !item.quiescevm)
|
||||
}
|
||||
},
|
||||
onAddBackupSchedule (schedule) {
|
||||
if (!schedule) {
|
||||
return
|
||||
}
|
||||
// This is in accordance with the API behavior that only one schedule per intervaltype is allowed
|
||||
const existingIndex = this.backupSchedules.findIndex(item => item.intervaltype === schedule.intervaltype)
|
||||
if (existingIndex !== -1) {
|
||||
message.warning({
|
||||
content: this.$t('message.backup.update.existing.schedule') + ' ' + schedule.intervaltype,
|
||||
duration: 2
|
||||
})
|
||||
this.backupSchedules.splice(existingIndex, 1, schedule)
|
||||
return
|
||||
}
|
||||
this.backupSchedules.push(schedule)
|
||||
},
|
||||
async performPostDeployBackupActions (vm) {
|
||||
if (!this.zoneAllowsBackupOperations) {
|
||||
return
|
||||
}
|
||||
const assigned = await this.assignVirtualMachineToBackupOfferingIfNeeded(vm)
|
||||
if (assigned) {
|
||||
await this.createVirtualMachineBackupSchedulesIfNeeded(vm)
|
||||
}
|
||||
},
|
||||
assignVirtualMachineToBackupOfferingIfNeeded (vm) {
|
||||
if (!this.form.backupofferingid || !vm || !vm.id) {
|
||||
return Promise.resolve(false)
|
||||
}
|
||||
const params = {
|
||||
virtualmachineid: vm.id,
|
||||
backupofferingid: this.form.backupofferingid
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
postAPI('assignVirtualMachineToBackupOffering', params).then(json => {
|
||||
const jobId = json.assignvirtualmachinetobackupofferingresponse?.jobid
|
||||
if (!jobId) {
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
this.$pollJob({
|
||||
jobId,
|
||||
loadingMessage: `${this.$t('label.backup.offering.assign')} ${this.$t('label.in.progress')}`,
|
||||
successMethod: () => {
|
||||
resolve(true)
|
||||
},
|
||||
errorMethod: (result) => {
|
||||
this.$notification.error({
|
||||
message: this.$t('label.backup.offering.assign.failed'),
|
||||
description: result?.jobresult?.errortext || this.$t('error.fetching.async.job.result')
|
||||
})
|
||||
resolve(false)
|
||||
},
|
||||
catchMessage: this.$t('error.fetching.async.job.result')
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notification.error({
|
||||
message: this.$t('label.backup.offering.assign.failed'),
|
||||
description: error.message || error
|
||||
})
|
||||
resolve(false)
|
||||
})
|
||||
})
|
||||
},
|
||||
createVirtualMachineBackupSchedulesIfNeeded (vm) {
|
||||
if (!vm || !vm.id || !this.backupSchedules) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
const promises = (this.backupSchedules || []).map(item =>
|
||||
this.createVirtualMachineBackupSchedule(vm, item)
|
||||
)
|
||||
return Promise.all(promises)
|
||||
},
|
||||
createVirtualMachineBackupSchedule (vm, item) {
|
||||
const params = {
|
||||
virtualmachineid: vm.id,
|
||||
intervaltype: item.intervaltype,
|
||||
maxbackups: item.maxbackups,
|
||||
timezone: item.timezone,
|
||||
schedule: item.schedule
|
||||
}
|
||||
if (item.quiescevm) {
|
||||
params.quiescevm = item.quiescevm
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
postAPI('createBackupSchedule', params).then(response => {
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
this.$notification.error({
|
||||
message: this.$t('label.backup.schedule.create.failed'),
|
||||
description: error.message || error
|
||||
})
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,9 +102,9 @@ export default {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
deleteFn: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -183,6 +183,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
handleClickDelete (record) {
|
||||
if (this.deleteFn) {
|
||||
this.deleteFn(record)
|
||||
return
|
||||
}
|
||||
const params = {}
|
||||
params.id = record.id
|
||||
this.actionLoading = true
|
||||
|
||||
@ -133,7 +133,7 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item v-if="backupProvider === 'nas'" name="quiescevm" ref="quiescevm">
|
||||
<a-form-item v-if="isQuiesceVmSupported" name="quiescevm" ref="quiescevm">
|
||||
<a-switch v-model:checked="form.quiescevm"/>
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.quiescevm')" :tooltip="apiParams.quiescevm.description"/>
|
||||
@ -180,13 +180,13 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dataSource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
submitFn: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -211,6 +211,11 @@ export default {
|
||||
this.fetchBackupOffering()
|
||||
},
|
||||
inject: ['refreshSchedule', 'closeSchedule'],
|
||||
computed: {
|
||||
isQuiesceVmSupported () {
|
||||
return this.$isBackupProviderSupportsQuiesceVm(this.backupProvider)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
@ -226,6 +231,10 @@ export default {
|
||||
})
|
||||
},
|
||||
fetchBackupOffering () {
|
||||
if ('backupoffering' in this.resource) {
|
||||
this.backupProvider = this.resource.backupoffering.provider
|
||||
return
|
||||
}
|
||||
getAPI('listBackupOfferings', { id: this.resource.backupofferingid }).then(json => {
|
||||
if (json.listbackupofferingsresponse && json.listbackupofferingsresponse.backupoffering) {
|
||||
const backupoffering = json.listbackupofferingsresponse.backupoffering[0]
|
||||
@ -305,6 +314,11 @@ export default {
|
||||
params.schedule = [values.timeSelect.format('mm:HH'), values['day-of-month']].join(':')
|
||||
break
|
||||
}
|
||||
if (this.submitFn) {
|
||||
this.submitFn(params)
|
||||
this.resetForm()
|
||||
return
|
||||
}
|
||||
this.actionLoading = true
|
||||
postAPI('createBackupSchedule', params).then(json => {
|
||||
this.$notification.success({
|
||||
|
||||
154
ui/src/views/compute/wizard/DeployInstanceBackupSelection.vue
Normal file
154
ui/src/views/compute/wizard/DeployInstanceBackupSelection.vue
Normal file
@ -0,0 +1,154 @@
|
||||
// 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>
|
||||
<div>{{ $t('message.backup.provision.instance') }}</div>
|
||||
<infinite-scroll-select
|
||||
style="margin-top: 10px; width: 100%;"
|
||||
v-model:value="localBackupOfferingId"
|
||||
placeholder="Select backup offering"
|
||||
api="listBackupOfferings"
|
||||
:apiParams="listBackupOfferingApiParams"
|
||||
resourceType="backupoffering"
|
||||
defaultIcon="cloud-upload-outlined"
|
||||
:defaultOption="backupOfferingDefaultOption"
|
||||
@change-option="handleChangeBackupOffering" />
|
||||
|
||||
<div v-if="backupOfferingId && 'createBackupSchedule' in $store.getters.apis" style="margin-top: 15px">
|
||||
<a-form-item :label="$t('label.schedule')">
|
||||
<a-button
|
||||
type="dashed"
|
||||
style="width: 100%"
|
||||
@click="onShowAddBackupSchedule">
|
||||
<template #icon><plus-outlined /></template>
|
||||
{{ $t('label.add.backup.schedule') }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
<backup-schedule
|
||||
style="margin-top: 10px;"
|
||||
:dataSource="backupSchedules"
|
||||
:deleteFn="handleDeleteBackupSchedule" />
|
||||
</div>
|
||||
|
||||
<a-modal
|
||||
style="min-width: 400px;"
|
||||
:visible="showAddBackupSchedule"
|
||||
:title="$t('label.add.backup.schedule')"
|
||||
:maskClosable="false"
|
||||
:closable="true"
|
||||
:footer="null"
|
||||
@cancel="closeModals">
|
||||
<form-schedule
|
||||
:resource="addFormResource"
|
||||
:submitFn="handleAddBackupSchedule" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import InfiniteScrollSelect from '@/components/widgets/InfiniteScrollSelect'
|
||||
import BackupSchedule from '@views/compute/backup/BackupSchedule'
|
||||
import FormSchedule from '@views/compute/backup/FormSchedule'
|
||||
|
||||
export default {
|
||||
name: 'DeployInstanceBackupSelection',
|
||||
components: {
|
||||
InfiniteScrollSelect,
|
||||
BackupSchedule,
|
||||
FormSchedule
|
||||
},
|
||||
props: {
|
||||
zoneId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
backupOfferingId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
backupSchedules: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
backupOffering: null,
|
||||
showAddBackupSchedule: false,
|
||||
localBackupOfferingId: this.backupOfferingId
|
||||
}
|
||||
},
|
||||
provide () {
|
||||
return {
|
||||
refreshSchedule: null,
|
||||
closeSchedule: this.closeModals
|
||||
}
|
||||
},
|
||||
emits: ['change-backup-offering', 'add-backup-schedule', 'delete-backup-schedule', 'update:backupOfferingId'],
|
||||
computed: {
|
||||
listBackupOfferingApiParams () {
|
||||
return {
|
||||
zoneid: this.zoneId
|
||||
}
|
||||
},
|
||||
backupOfferingDefaultOption () {
|
||||
return { id: null, name: this.$t('label.noselect'), showicon: false }
|
||||
},
|
||||
addFormResource () {
|
||||
return {
|
||||
id: 'NEW',
|
||||
backupofferingid: this.backupOfferingId,
|
||||
backupoffering: this.backupOffering
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
localBackupOfferingId (val) {
|
||||
if (val !== this.backupOfferingId) {
|
||||
this.$emit('update:backupOfferingId', val)
|
||||
}
|
||||
},
|
||||
backupOfferingId (val) {
|
||||
if (val !== this.localBackupOfferingId) {
|
||||
this.localBackupOfferingId = val
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChangeBackupOffering (offering) {
|
||||
this.$emit('change-backup-offering', offering)
|
||||
this.backupOffering = offering
|
||||
},
|
||||
onShowAddBackupSchedule () {
|
||||
this.showAddBackupSchedule = true
|
||||
},
|
||||
handleAddBackupSchedule (schedule) {
|
||||
schedule.id = 'SCH_' + new Date().getTime()
|
||||
schedule.intervaltype = schedule.intervaltype?.toUpperCase()
|
||||
this.$emit('add-backup-schedule', schedule)
|
||||
this.closeModals()
|
||||
},
|
||||
handleDeleteBackupSchedule (schedule) {
|
||||
this.$emit('delete-backup-schedule', schedule)
|
||||
},
|
||||
closeModals () {
|
||||
this.showAddBackupSchedule = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Loading…
x
Reference in New Issue
Block a user