From 555e6b36cab54ac20d625c5b471178015dd7d681 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Mon, 29 Dec 2025 14:44:01 +0530 Subject: [PATCH] Add copy template flag in zone wizard and remove NFS checks --- ui/public/locales/en.json | 3 ++- ui/src/views/infra/AddSecondaryStorage.vue | 23 ++++------------- .../infra/zone/ZoneWizardAddResources.vue | 25 ++++++++++++++++++- .../views/infra/zone/ZoneWizardLaunchZone.vue | 5 ++++ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index efa06c60e3c..aad2f6c7d43 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -590,6 +590,7 @@ "label.copyid": "Copy ID", "label.copy.password": "Copy password", "label.copy.templates.from.other.secondary.storages": "Copy templates from other storages instead of fetching from URLs", +"label.copy.templates.from.other.secondary.storages.add.zone": "Copy templates from other storages", "label.core": "Core", "label.core.zone.type": "Core Zone type", "label.counter": "Counter", @@ -3017,7 +3018,7 @@ "message.desc.importmigratefromvmwarewizard": "By selecting an existing or external VMware Datacenter and an instance to import, CloudStack migrates the selected instance from VMware to KVM on a conversion host using virt-v2v and imports it into a KVM Cluster", "message.desc.primary.storage": "Each Cluster must contain one or more primary storage servers. We will add the first one now. Primary storage contains the disk volumes for all the Instances running on hosts in the cluster. Use any standards-compliant protocol that is supported by the underlying hypervisor.", "message.desc.reset.ssh.key.pair": "Please specify a ssh key pair that you would like to add to this Instance.", -"message.desc.secondary.storage": "Each Zone must have at least one NFS or secondary storage server. We will add the first one now. Secondary storage stores Instance Templates, ISO images, and Instance disk volume Snapshots. This server must be available to all hosts in the zone.

Provide the IP address and exported path.", +"message.desc.secondary.storage": "Each Zone must have at least one NFS or secondary storage server. We will add the first one now. Secondary storage stores Instance Templates, ISO images, and Instance disk volume Snapshots. This server must be available to all hosts in the zone.

Provide the IP address and exported path.

\"Copy templates from other secondary storages\" checkbox can be used to automatically copy existing templates from secondary storages in other zones instead of fetching from their URLs.", "message.desc.register.user.data": "Please fill in the following to register new User Data.", "message.desc.registered.user.data": "Registered a User Data.", "message.desc.zone": "A Zone is the largest organizational unit in CloudStack, and it typically corresponds to a single datacenter. Zones provide physical isolation and redundancy. A zone consists of one or more Pods (each of which contains hosts and primary storage servers) and a secondary storage server which is shared by all pods in the zone.", diff --git a/ui/src/views/infra/AddSecondaryStorage.vue b/ui/src/views/infra/AddSecondaryStorage.vue index fa8cb2194ed..fcfb35c9d27 100644 --- a/ui/src/views/infra/AddSecondaryStorage.vue +++ b/ui/src/views/infra/AddSecondaryStorage.vue @@ -48,10 +48,6 @@ -
+
0) { this.form.zone = this.zones[0].id || '' - this.fetchCopyTemplatesConfig() - this.checkOtherSecondaryStorages() } } }) }, checkOtherSecondaryStorages () { - api('listImageStores', { - listall: true - }).then(json => { + api('listImageStores', { listall: true }).then(json => { const stores = json?.listimagestoresresponse?.imagestore || [] - this.showCopyTemplatesToggle = stores.some(store => { - if (store.providername !== 'NFS') { - return false - } - - return store.zoneid !== this.form.zone || store.zoneid === this.form.zone - }) + this.showCopyTemplatesToggle = stores.length > 0 }) }, onCopyTemplatesToggleChanged (val) { @@ -422,7 +410,6 @@ export default { } if ( - provider === 'NFS' && this.showCopyTemplatesToggle && this.copyTemplatesTouched ) { diff --git a/ui/src/views/infra/zone/ZoneWizardAddResources.vue b/ui/src/views/infra/zone/ZoneWizardAddResources.vue index 4bd602f0aca..24c0238bd2e 100644 --- a/ui/src/views/infra/zone/ZoneWizardAddResources.vue +++ b/ui/src/views/infra/zone/ZoneWizardAddResources.vue @@ -840,6 +840,13 @@ export default { display: { secondaryStorageProvider: ['Swift'] } + }, + { + title: 'label.copy.templates.from.other.secondary.storages.add.zone', + key: 'copyTemplatesFromOtherSecondaryStorages', + required: false, + switch: true, + checked: this.copytemplate, } ] } @@ -860,7 +867,8 @@ export default { }], storageProviders: [], currentStep: null, - options: ['primaryStorageScope', 'primaryStorageProtocol', 'provider', 'primaryStorageProvider'] + options: ['primaryStorageScope', 'primaryStorageProtocol', 'provider', 'primaryStorageProvider'], + copytemplate: true } }, created () { @@ -885,6 +893,7 @@ export default { primaryStorageScope: null }) } + this.applyCopyTemplatesOptionFromGlobalSettingDuringSecondaryStorageAddition() } }, watch: { @@ -1108,6 +1117,20 @@ export default { this.storageProviders = storageProviders }) }, + applyCopyTemplatesOptionFromGlobalSettingDuringSecondaryStorageAddition () { + api('listConfigurations', { + name: 'copy.templates.from.other.secondary.storages' + }).then(json => { + const config = json?.listconfigurationsresponse?.configuration?.[0] + + if (!config || config.value === undefined) { + return + } + + const value = String(config.value).toLowerCase() === 'true' + this.copytemplate = value + }) + }, fetchPrimaryStorageProvider () { this.primaryStorageProviders = [] api('listStorageProviders', { type: 'primary' }).then(json => { diff --git a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue index a787ad839cd..fbf5e6f5c20 100644 --- a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue +++ b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue @@ -1580,6 +1580,11 @@ export default { params.provider = this.prefillContent.secondaryStorageProvider params.zoneid = this.stepData.zoneReturned.id params.url = url + if (this.prefillContent.copyTemplatesFromOtherSecondaryStorages !== undefined) { + params['details[0].key'] = 'copytemplatesfromothersecondarystorages' + params['details[0].value'] = + this.prefillContent.copyTemplatesFromOtherSecondaryStorages + } } else if (this.prefillContent.secondaryStorageProvider === 'SMB') { const nfsServer = this.prefillContent.secondaryStorageServer const path = this.prefillContent.secondaryStoragePath