Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ui/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@
"label.app.name": "CloudStack",
"label.application.policy.set": "Application Policy Set",
"label.apply": "Apply",
"label.apply.to.all": "Apply to all",
"label.apply.tungsten.firewall.policy": "Apply Firewall Policy",
"label.apply.tungsten.network.policy": "Apply Network Policy",
"label.apply.tungsten.tag": "Apply tag",
Expand Down Expand Up @@ -3686,6 +3687,7 @@
"message.vnf.nic.move.down.fail": "Failed to move down this NIC",
"message.vnf.no.credentials": "No credentials found for the VNF appliance.",
"message.vnf.select.networks": "Please select the relevant network for each VNF NIC.",
"message.volume.pool.apply.to.all": "Selected storage pool will be applied to all existing volumes of the instance.",
"message.volume.state.allocated": "The volume is allocated but has not been created yet.",
"message.volume.state.attaching": "The volume is attaching to a volume from Ready state.",
"message.volume.state.copying": "The volume is being copied from the image store to primary storage, in case it's an uploaded volume.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,19 @@ export default {
closeVolumeStoragePoolSelector () {
this.selectedVolumeForStoragePoolSelection = {}
},
handleVolumeStoragePoolSelection (volumeId, storagePool) {
handleVolumeStoragePoolSelection (volumeId, storagePool, applyToAll) {
for (const volume of this.volumes) {
if (volume.id === volumeId) {
if (applyToAll) {
volume.selectedstorageid = storagePool.id
volume.selectedstoragename = storagePool.name
volume.selectedstorageclusterid = storagePool.clusterid
break
} else {
if (volume.id === volumeId) {
volume.selectedstorageid = storagePool.id
volume.selectedstoragename = storagePool.name
volume.selectedstorageclusterid = storagePool.clusterid
break
}
}
}
this.updateVolumeToStoragePoolSelection()
Expand Down
16 changes: 14 additions & 2 deletions ui/src/components/view/VolumeStoragePoolSelectForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
:autoAssignAllowed="autoAssignAllowed"
@select="handleSelect" />

<a-form-item
class="top-spaced">
<template #label>
<tooltip-label :title="$t('label.apply.to.all')" :tooltip="$t('message.volume.pool.apply.to.all')"/>
</template>
<a-switch
v-model:checked="applyToAll" />
</a-form-item>

<a-divider />

<div class="actions">
Expand All @@ -36,11 +45,13 @@
</template>

<script>
import TooltipLabel from '@/components/widgets/TooltipLabel'
import StoragePoolSelectView from '@/components/view/StoragePoolSelectView'

export default {
name: 'VolumeStoragePoolSelectionForm',
components: {
TooltipLabel,
StoragePoolSelectView
},
props: {
Expand Down Expand Up @@ -70,7 +81,8 @@ export default {
},
data () {
return {
selectedStoragePool: null
selectedStoragePool: null,
applyToAll: false
}
},
watch: {
Expand All @@ -95,7 +107,7 @@ export default {
}
},
submitForm () {
this.$emit('select', this.resource.id, this.selectedStoragePool)
this.$emit('select', this.resource.id, this.selectedStoragePool, this.applyToAll)
this.closeModal()
}
}
Expand Down
60 changes: 50 additions & 10 deletions ui/src/views/compute/MigrateWizard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
class="top-spaced"
:placeholder="$t('label.search')"
v-model:value="searchQuery"
@search="fetchData"
@search="fetchHostsForMigration"
v-focus="true" />
<a-table
class="top-spaced"
Expand Down Expand Up @@ -97,7 +97,7 @@
</a-pagination>

<a-form-item
v-if="isUserVm"
v-if="isUserVm && hasVolumes"
class="top-spaced">
<template #label>
<tooltip-label :title="$t('label.migrate.with.storage')" :tooltip="$t('message.migrate.with.storage')"/>
Expand All @@ -106,9 +106,29 @@
v-model:checked="migrateWithStorage"
:disabled="!selectedHost || !selectedHost.id || selectedHost.id === -1" />
</a-form-item>

<a-radio-group
v-if="migrateWithStorage"
v-model:value="migrateMode"
@change="e => { handleMigrateModeChange(e.target.value) }">
<a-radio class="radio-style" :value="1">
{{ $t('label.migrate.instance.single.storage') }}
</a-radio>
<a-radio class="radio-style" :value="2">
{{ $t('label.migrate.instance.specific.storages') }}
</a-radio>
</a-radio-group>

<div v-if="migrateWithStorage && migrateMode == 1">
<storage-pool-select-view
ref="storagePoolSelection"
:autoAssignAllowed="false"
:resource="resource"
@select="handleStoragePoolChange" />
</div>
<instance-volumes-storage-pool-select-list-view
ref="volumeToPoolSelect"
v-if="migrateWithStorage"
v-if="migrateWithStorage && migrateMode !== 1"
class="top-spaced"
:resource="resource"
:clusterId="selectedHost.id ? selectedHost.clusterid : null"
Expand All @@ -118,20 +138,22 @@

<div class="actions">
<a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
<a-button type="primary" ref="submit" :disabled="!selectedHost.id" @click="submitForm">{{ $t('label.ok') }}</a-button>
<a-button type="primary" ref="submit" :disabled="!selectedHost.id || (migrateWithStorage && migrateMode === 1 && !volumeToPoolSelection.length)" @click="submitForm">{{ $t('label.ok') }}</a-button>
</div>
</div>
</template>

<script>
import { api } from '@/api'
import TooltipLabel from '@/components/widgets/TooltipLabel'
import StoragePoolSelectView from '@/components/view/StoragePoolSelectView'
import InstanceVolumesStoragePoolSelectListView from '@/components/view/InstanceVolumesStoragePoolSelectListView'

export default {
name: 'VMMigrateWizard',
components: {
TooltipLabel,
StoragePoolSelectView,
InstanceVolumesStoragePoolSelectListView
},
props: {
Expand Down Expand Up @@ -188,6 +210,7 @@ export default {
}
],
migrateWithStorage: false,
migrateMode: 1,
volumeToPoolSelection: [],
volumes: []
}
Expand All @@ -198,6 +221,9 @@ export default {
computed: {
isUserVm () {
return this.$route.meta.resourceType === 'UserVm'
},
hasVolumes () {
return this.volumes && this.volumes.length > 0
}
},
watch: {
Expand All @@ -212,6 +238,10 @@ export default {
return array !== null && array !== undefined && Array.isArray(array) && array.length > 0
},
fetchData () {
this.fetchHostsForMigration()
this.fetchVolumes()
},
fetchHostsForMigration () {
this.loading = true
api('findHostsForMigration', {
virtualmachineid: this.resource.id,
Expand Down Expand Up @@ -239,17 +269,16 @@ export default {
handleChangePage (page, pageSize) {
this.page = page
this.pageSize = pageSize
this.fetchData()
this.fetchHostsForMigration()
},
handleChangePageSize (currentPage, pageSize) {
this.page = currentPage
this.pageSize = pageSize
this.fetchData()
this.fetchHostsForMigration()
},
handleSelectedHostChange (host) {
if (host.id === -1) {
this.migrateWithStorage = false
this.fetchVolumes()
}
this.selectedHost = host
this.selectedVolumeForStoragePoolSelection = {}
Expand All @@ -258,6 +287,17 @@ export default {
this.$refs.volumeToPoolSelect.resetSelection()
}
},
handleMigrateModeChange () {
this.volumeToPoolSelection = []
},
handleStoragePoolChange (storagePool) {
this.volumeToPoolSelection = []
for (const volume of this.volumes) {
if (storagePool && storagePool.id && storagePool.id !== -1) {
this.volumeToPoolSelection.push({ volume: volume.id, pool: storagePool.id })
}
}
},
handleVolumeToPoolChange (volumeToPool) {
this.volumeToPoolSelection = volumeToPool
},
Expand All @@ -268,7 +308,7 @@ export default {
listAll: true,
virtualmachineid: this.resource.id
}).then(response => {
this.volumes = response.listvolumesresponse.volume
this.volumes = response?.listvolumesresponse?.volume || []
}).finally(() => {
this.loading = false
})
Expand All @@ -277,7 +317,7 @@ export default {
if (this.selectedHost.requiresStorageMotion || this.volumeToPoolSelection.length > 0) {
return true
}
if (this.selectedHost.id === -1 && this.volumes && this.volumes.length > 0) {
if (this.selectedHost.id === -1 && this.hasVolumes) {
for (var volume of this.volumes) {
if (volume.storagetype === 'local') {
return true
Expand Down Expand Up @@ -305,7 +345,7 @@ export default {
var params = this.selectedHost.id === -1
? { autoselect: true, virtualmachineid: this.resource.id }
: { hostid: this.selectedHost.id, virtualmachineid: this.resource.id }
if (this.migrateWithStorage) {
if (this.migrateWithStorage && this.volumeToPoolSelection && this.volumeToPoolSelection.length > 0) {
for (var i = 0; i < this.volumeToPoolSelection.length; i++) {
const mapping = this.volumeToPoolSelection[i]
params['migrateto[' + i + '].volume'] = mapping.volume
Expand Down
Loading
Loading