diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java index f0a82ccb9a6..087bf21784c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java @@ -153,8 +153,8 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd { return (Map) (paramsCollection.toArray())[0]; } - public boolean isCleanupDetails(){ - return cleanupDetails == null ? false : cleanupDetails.booleanValue(); + public boolean isCleanupDetails() { + return cleanupDetails != null && cleanupDetails; } public CPU.CPUArch getCPUArch() { diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java index 7d46aa9f225..4127ce8dc87 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -460,7 +460,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem if (detailsStr == null) { return; } - List details = new ArrayList(); + List details = new ArrayList<>(); for (String key : detailsStr.keySet()) { VMTemplateDetailVO detail = new VMTemplateDetailVO(tmpl.getId(), key, detailsStr.get(key), true); details.add(detail); @@ -482,7 +482,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem } if (tmplt.getDetails() != null) { - List details = new ArrayList(); + List details = new ArrayList<>(); for (String key : tmplt.getDetails().keySet()) { details.add(new VMTemplateDetailVO(tmplt.getId(), key, tmplt.getDetails().get(key), true)); } diff --git a/pom.xml b/pom.xml index e56c8b96c54..b4e2ec57f81 100644 --- a/pom.xml +++ b/pom.xml @@ -63,20 +63,20 @@ 1.8 3.0.0 - 3.1.0 + 3.6.0 0.8.11 3.8.1 - 3.1.1 + 3.9.0 2.22.2 3.1.12 3.1.12.2 3.2.0 - 3.12.0 + 3.28.0 3.0.0 7.4.4 2.5.3 3.1.0 - 3.8.2 + 3.21.0 2.22.2 4.4.1 3.2.0 diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 4699be65888..a5180c05b19 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -2256,7 +2256,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, templateTag == null && forCks == null && arch == null && - (! cleanupDetails && details == null) //update details in every case except this one + (!cleanupDetails && details == null) //update details in every case except this one ); if (!updateNeeded) { return template; @@ -2360,8 +2360,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if (cleanupDetails) { template.setDetails(null); _tmpltDetailsDao.removeDetails(id); - } - else if (details != null && !details.isEmpty()) { + } else if (details != null && !details.isEmpty()) { template.setDetails(details); _tmpltDao.saveDetails(template); } diff --git a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index 617a4e54a6e..6f7b96453ac 100644 --- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -23,6 +23,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -182,6 +183,11 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme Long.class, "vm.job.check.interval", "3000", "Interval in milliseconds to check if the job is complete", false); + private static final Set VM_SNAPSHOT_CUSTOM_SERVICE_OFFERING_DETAILS = Set.of( + VmDetailConstants.CPU_NUMBER.toLowerCase(), + VmDetailConstants.CPU_SPEED.toLowerCase(), + VmDetailConstants.MEMORY.toLowerCase()); + @Override public boolean configure(String name, Map params) throws ConfigurationException { _name = name; @@ -471,7 +477,8 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme } /** - * Add entries on vm_snapshot_details if service offering is dynamic. This will allow setting details when revert to vm snapshot + * Add entries about cpu, cpu_speed and memory in vm_snapshot_details if service offering is dynamic. + * This will allow setting details when revert to vm snapshot. * @param vmId vm id * @param serviceOfferingId service offering id * @param vmSnapshotId vm snapshot id @@ -482,7 +489,7 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme List vmDetails = _vmInstanceDetailsDao.listDetails(vmId); List vmSnapshotDetails = new ArrayList(); for (VMInstanceDetailVO detail : vmDetails) { - if(detail.getName().equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.getName().equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.getName().equalsIgnoreCase(VmDetailConstants.MEMORY)) { + if (VM_SNAPSHOT_CUSTOM_SERVICE_OFFERING_DETAILS.contains(detail.getName().toLowerCase())) { vmSnapshotDetails.add(new VMSnapshotDetailsVO(vmSnapshotId, detail.getName(), detail.getValue(), detail.isDisplay())); } } @@ -935,7 +942,7 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) throws CloudRuntimeException { - revertUserVmDetailsFromVmSnapshot(userVm, vmSnapshotVo); + revertCustomServiceOfferingDetailsFromVmSnapshot(userVm, vmSnapshotVo); updateUserVmServiceOffering(userVm, vmSnapshotVo); } }); @@ -947,19 +954,19 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme } /** - * Update or add user vm details from vm snapshot for vms with custom service offerings + * Update or add user vm details (cpu, cpu_speed and memory) from vm snapshot for vms with custom service offerings * @param userVm user vm * @param vmSnapshotVo vm snapshot */ - protected void revertUserVmDetailsFromVmSnapshot(UserVmVO userVm, VMSnapshotVO vmSnapshotVo) { + protected void revertCustomServiceOfferingDetailsFromVmSnapshot(UserVmVO userVm, VMSnapshotVO vmSnapshotVo) { ServiceOfferingVO serviceOfferingVO = _serviceOfferingDao.findById(vmSnapshotVo.getServiceOfferingId()); if (serviceOfferingVO.isDynamic()) { List vmSnapshotDetails = _vmSnapshotDetailsDao.listDetails(vmSnapshotVo.getId()); - List userVmDetails = new ArrayList(); for (VMSnapshotDetailsVO detail : vmSnapshotDetails) { - userVmDetails.add(new VMInstanceDetailVO(userVm.getId(), detail.getName(), detail.getValue(), detail.isDisplay())); + if (VM_SNAPSHOT_CUSTOM_SERVICE_OFFERING_DETAILS.contains(detail.getName().toLowerCase())) { + _vmInstanceDetailsDao.addDetail(userVm.getId(), detail.getName(), detail.getValue(), detail.isDisplay()); + } } - _vmInstanceDetailsDao.saveDetails(userVmDetails); } } diff --git a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java index a0f09981a40..38f1680af6a 100644 --- a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java +++ b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java @@ -51,6 +51,7 @@ import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VmDetailConstants; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDetailsDao; import com.cloud.vm.dao.VMInstanceDao; @@ -67,7 +68,6 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Captor; -import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -79,13 +79,18 @@ import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -225,13 +230,13 @@ public class VMSnapshotManagerTest { when(_serviceOfferingDao.findById(SERVICE_OFFERING_ID)).thenReturn(serviceOffering); for (ResourceDetail detail : Arrays.asList(userVmDetailCpuNumber, vmSnapshotDetailCpuNumber)) { - when(detail.getName()).thenReturn("cpuNumber"); + when(detail.getName()).thenReturn(VmDetailConstants.CPU_NUMBER); when(detail.getValue()).thenReturn("2"); when(detail.isDisplay()).thenReturn(true); } for (ResourceDetail detail : Arrays.asList(userVmDetailMemory, vmSnapshotDetailMemory)) { - when(detail.getName()).thenReturn("memory"); + when(detail.getName()).thenReturn(VmDetailConstants.MEMORY); when(detail.getValue()).thenReturn("2048"); when(detail.isDisplay()).thenReturn(true); } @@ -348,12 +353,12 @@ public class VMSnapshotManagerTest { @Test public void testUpdateUserVmServiceOfferingDifferentServiceOffering() throws ConcurrentOperationException, ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException { when(userVm.getServiceOfferingId()).thenReturn(SERVICE_OFFERING_DIFFERENT_ID); - when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true); + when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true); _vmSnapshotMgr.updateUserVmServiceOffering(userVm, vmSnapshotVO); verify(_vmSnapshotMgr).changeUserVmServiceOffering(userVm, vmSnapshotVO); verify(_vmSnapshotMgr).getVmMapDetails(userVm); - verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture()); + verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture()); } @Test @@ -368,18 +373,18 @@ public class VMSnapshotManagerTest { @Test public void testChangeUserVmServiceOffering() throws ConcurrentOperationException, ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException { - when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true); + when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(true); _vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO); verify(_vmSnapshotMgr).getVmMapDetails(userVm); - verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture()); + verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture()); } @Test(expected=CloudRuntimeException.class) public void testChangeUserVmServiceOfferingFailOnUpgradeVMServiceOffering() throws ConcurrentOperationException, ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException { - when(_userVmManager.upgradeVirtualMachine(ArgumentMatchers.eq(TEST_VM_ID), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(false); + when(_userVmManager.upgradeVirtualMachine(eq(TEST_VM_ID), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture())).thenReturn(false); _vmSnapshotMgr.changeUserVmServiceOffering(userVm, vmSnapshotVO); verify(_vmSnapshotMgr).getVmMapDetails(userVm); - verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(ArgumentMatchers.eq(userVm), ArgumentMatchers.eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture()); + verify(_vmSnapshotMgr).upgradeUserVmServiceOffering(eq(userVm), eq(SERVICE_OFFERING_ID), mapDetailsCaptor.capture()); } @Test @@ -396,16 +401,27 @@ public class VMSnapshotManagerTest { @Test public void testRevertUserVmDetailsFromVmSnapshotNotDynamicServiceOffering() { - _vmSnapshotMgr.revertUserVmDetailsFromVmSnapshot(vmMock, vmSnapshotVO); + _vmSnapshotMgr.revertCustomServiceOfferingDetailsFromVmSnapshot(vmMock, vmSnapshotVO); verify(_vmSnapshotDetailsDao, never()).listDetails(anyLong()); } @Test public void testRevertUserVmDetailsFromVmSnapshotDynamicServiceOffering() { when(serviceOffering.isDynamic()).thenReturn(true); - _vmSnapshotMgr.revertUserVmDetailsFromVmSnapshot(vmMock, vmSnapshotVO); - verify(_vmSnapshotDetailsDao).listDetails(VM_SNAPSHOT_ID); - verify(_vmInstanceDetailsDao).saveDetails(listUserVmDetailsCaptor.capture()); - } + VMSnapshotDetailsVO uefiSnapshotDetail = new VMSnapshotDetailsVO(VM_SNAPSHOT_ID, "UEFI", "SECURE", true); + List snapshotDetailsWithUefi = Arrays.asList( + vmSnapshotDetailCpuNumber, vmSnapshotDetailMemory, uefiSnapshotDetail); + when(_vmSnapshotDetailsDao.listDetails(VM_SNAPSHOT_ID)).thenReturn(snapshotDetailsWithUefi); + _vmSnapshotMgr.revertCustomServiceOfferingDetailsFromVmSnapshot(vmMock, vmSnapshotVO); + + verify(_vmSnapshotDetailsDao).listDetails(VM_SNAPSHOT_ID); + verify(_vmInstanceDetailsDao, never()).saveDetails(any()); + ArgumentCaptor detailNameCaptor = ArgumentCaptor.forClass(String.class); + verify(_vmInstanceDetailsDao, times(2)).addDetail(eq(TEST_VM_ID), detailNameCaptor.capture(), anyString(), anyBoolean()); + List appliedNames = detailNameCaptor.getAllValues(); + assertTrue(appliedNames.contains(VmDetailConstants.CPU_NUMBER)); + assertTrue(appliedNames.contains(VmDetailConstants.MEMORY)); + assertFalse("UEFI must not be applied from snapshot so that existing UEFI setting is preserved", appliedNames.contains("UEFI")); + } } diff --git a/tools/checkstyle/src/main/resources/cloud-pmd.xml b/tools/checkstyle/src/main/resources/cloud-pmd.xml index 66a4ec08294..78d394ea15e 100644 --- a/tools/checkstyle/src/main/resources/cloud-pmd.xml +++ b/tools/checkstyle/src/main/resources/cloud-pmd.xml @@ -19,11 +19,8 @@ under the License. --> - + Ruleset that brings all the rulesets we want from the pmd jar, because @@ -31,16 +28,16 @@ to add our own future rulesets, if any. - - - - - + + + + + - + @@ -50,35 +47,35 @@ - + - + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 300b8b3f9f0..82fa22b5333 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1017,6 +1017,7 @@ "label.endpoint": "Endpoint", "label.endport": "End port", "label.enter.account.name": "Enter the account name", +"label.enter.domain.name": "Enter the domain name", "label.enter.code": "Enter 2FA code to verify", "label.enter.static.pin": "Enter static PIN to verify", "label.enter.token": "Enter token", @@ -3270,6 +3271,9 @@ "message.delete.account.processing": "Deleting account", "message.delete.account.success": "Successfully deleted account", "message.delete.account.warning": "Deleting this account will delete all of the instances, volumes and snapshots associated with the account.", +"message.delete.domain.confirm": "Please confirm that you want to delete this domain by entering the name of the domain below.", +"message.delete.domain.warning": "All associated accounts, users, VMs, and sub-domains will be permanently deleted. This action cannot be undone.", +"message.delete.domain.failed": "Delete domain failed", "message.delete.acl.processing": "Removing ACL rule...", "message.delete.acl.rule": "Remove ACL rule", "message.delete.acl.rule.failed": "Failed to remove ACL rule.", diff --git a/ui/src/components/view/DomainDeleteConfirm.vue b/ui/src/components/view/DomainDeleteConfirm.vue new file mode 100644 index 00000000000..4fdb9b658ad --- /dev/null +++ b/ui/src/components/view/DomainDeleteConfirm.vue @@ -0,0 +1,155 @@ +// 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. + + + + + diff --git a/ui/src/views/iam/DomainView.vue b/ui/src/views/iam/DomainView.vue index 2d414950456..966554c0f64 100644 --- a/ui/src/views/iam/DomainView.vue +++ b/ui/src/views/iam/DomainView.vue @@ -74,6 +74,11 @@ :resource="resource" :action="action"/> + @@ -87,6 +92,7 @@ import ActionButton from '@/components/view/ActionButton' import TreeView from '@/components/view/TreeView' import DomainActionForm from '@/views/iam/DomainActionForm' import ResourceView from '@/components/view/ResourceView' +import DomainDeleteConfirm from '@/components/view/DomainDeleteConfirm' import eventBus from '@/config/eventBus' export default { @@ -96,7 +102,8 @@ export default { ActionButton, TreeView, DomainActionForm, - ResourceView + ResourceView, + DomainDeleteConfirm }, mixins: [mixinDevice], data () { @@ -111,7 +118,9 @@ export default { action: {}, dataView: false, domainStore: {}, - treeDeletedKey: null + treeDeletedKey: null, + showDeleteConfirm: false, + deleteDomainResource: null } }, computed: { @@ -205,7 +214,12 @@ export default { }) }, execAction (action) { - this.treeDeletedKey = action.api === 'deleteDomain' ? this.resource.key : null + if (action.api === 'deleteDomain') { + this.deleteDomainResource = this.resource + this.showDeleteConfirm = true + return + } + this.treeDeletedKey = null this.actionData = [] this.action = action this.action.params = store.getters.apis[this.action.api].params @@ -316,6 +330,42 @@ export default { closeAction () { this.showAction = false }, + confirmDeleteDomain () { + const domain = this.deleteDomainResource + const params = { id: domain.id, cleanup: true } + + api('deleteDomain', params).then(json => { + const jobId = json.deletedomainresponse.jobid + + this.$pollJob({ + jobId, + title: this.$t('label.action.delete.domain'), + description: domain.name, + loadingMessage: `${this.$t('label.action.delete.domain')} ${domain.name}`, + successMessage: `${this.$t('label.action.delete.domain')} ${domain.name}`, + catchMessage: this.$t('error.fetching.async.job.result'), + successMethod: () => { + this.$router.replace({ path: '/domain' }) + this.resource = {} + this.treeSelected = {} + this.treeDeletedKey = null + this.treeViewKey += 1 + this.$nextTick(() => { + this.fetchData() + }) + } + }) + }).catch(error => { + this.$notification.error({ + message: this.$t('message.request.failed'), + description: error.response?.headers['x-description'] || this.$t('message.request.failed') + }) + }).finally(() => { + this.showDeleteConfirm = false + this.deleteDomainResource = null + this.treeDeletedKey = null + }) + }, forceRerender () { this.treeViewKey += 1 } diff --git a/ui/src/views/image/UpdateTemplate.vue b/ui/src/views/image/UpdateTemplate.vue index 9f52eededd3..326cabc1f74 100644 --- a/ui/src/views/image/UpdateTemplate.vue +++ b/ui/src/views/image/UpdateTemplate.vue @@ -261,6 +261,8 @@ export default { userdatapolicylist: {}, architectureTypes: {}, originalOstypeid: null + detailsFields: [], + details: {} } }, beforeCreate () { @@ -315,17 +317,10 @@ export default { } } } - const resourceDetailsFields = [] if (this.resource.hypervisor === 'KVM') { - resourceDetailsFields.push('rootDiskController') + this.detailsFields.push('rootDiskController') } else if (this.resource.hypervisor === 'VMware' && !this.resource.deployasis) { - resourceDetailsFields.push(...['rootDiskController', 'nicAdapter', 'keyboard']) - } - for (var detailsField of resourceDetailsFields) { - var detailValue = this.resource?.details?.[detailsField] || null - if (detailValue) { - this.form[detailValue] = fieldValue - } + this.detailsFields.push(...['rootDiskController', 'nicAdapter', 'keyboard']) } }, fetchData () { @@ -336,6 +331,7 @@ export default { this.fetchKeyboardTypes() this.fetchUserdata() this.fetchUserdataPolicy() + this.fetchDetails() }, isValidValueForKey (obj, key) { if (this.emptyAllowedFields.includes(key) && obj[key] === '') { @@ -380,6 +376,10 @@ export default { id: 'virtio', description: 'virtio' }) + controller.push({ + id: 'virtio-blk', + description: 'virtio-blk' + }) } else if (hyperVisor === 'VMware') { controller.push({ id: '', @@ -506,6 +506,25 @@ export default { this.userdata.loading = false }) }, + fetchDetails () { + const params = {} + params.id = this.resource.id + params.templatefilter = 'all' + + api('listTemplates', params).then(response => { + if (response?.listtemplatesresponse?.template?.length > 0) { + this.details = response.listtemplatesresponse.template[0].details + if (this.details) { + for (var detailsField of this.detailsFields) { + var detailValue = this.details?.[detailsField] || null + if (detailValue) { + this.form[detailsField] = detailValue + } + } + } + } + }) + }, handleSubmit (e) { e.preventDefault() if (this.loading) return @@ -515,10 +534,14 @@ export default { const params = { id: this.resource.id } - const detailsField = ['rootDiskController', 'nicAdapter', 'keyboard'] + if (this.details) { + Object.keys(this.details).forEach((detail, index) => { + params['details[0].' + detail] = this.details[detail] + }) + } for (const key in values) { if (!this.isValidValueForKey(values, key)) continue - if (detailsField.includes(key)) { + if (this.detailsFields.includes(key)) { params['details[0].' + key] = values[key] continue }