From 1e5b7687267f54b0330a8502427bf90b0fc6d960 Mon Sep 17 00:00:00 2001 From: Ramgopal Nagaboina Date: Tue, 8 Sep 2026 19:31:18 -0400 Subject: [PATCH] sharedfs: skip hypervisors with no systemvm template deploySharedFSVM iterates the zone's supported hypervisors looking for one with a systemvm template. It only threw when the template was missing on the last hypervisor, so a missing template on any earlier one fell through to template.getId() and hit a NullPointerException. In a zone with more than one hypervisor type where one has no systemvm template this failed the shared filesystem VM deployment at random depending on the shuffled order. Skip a hypervisor that has no template and move to the next, and throw only when none of them has one, mirroring the existing continue-on-hasNext handling further down the same loop. Fixes: #13825 --- .../lifecycle/StorageVmSharedFSLifeCycle.java | 5 ++++- .../StorageVmSharedFSLifeCycleTest.java | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/plugins/storage/sharedfs/storagevm/src/main/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycle.java b/plugins/storage/sharedfs/storagevm/src/main/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycle.java index ed799e9030be..96c24c1c0ed1 100644 --- a/plugins/storage/sharedfs/storagevm/src/main/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycle.java +++ b/plugins/storage/sharedfs/storagevm/src/main/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycle.java @@ -180,7 +180,10 @@ private UserVm deploySharedFSVM(Long zoneId, Account owner, List networkId for (final Iterator iter = hypervisors.iterator(); iter.hasNext();) { final Hypervisor.HypervisorType hypervisor = iter.next(); VMTemplateVO template = templateDao.findSystemVMReadyTemplate(zoneId, hypervisor, preferredArchitecture); - if (template == null && !iter.hasNext()) { + if (template == null) { + if (iter.hasNext()) { + continue; + } throw new CloudRuntimeException(String.format("Unable to find the systemvm template for %s or it was not downloaded in %s.", hypervisor.toString(), zone.toString())); } diff --git a/plugins/storage/sharedfs/storagevm/src/test/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycleTest.java b/plugins/storage/sharedfs/storagevm/src/test/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycleTest.java index 82d055b9a359..ff0a023e9b6d 100644 --- a/plugins/storage/sharedfs/storagevm/src/test/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycleTest.java +++ b/plugins/storage/sharedfs/storagevm/src/test/java/org/apache/cloudstack/storage/sharedfs/lifecycle/StorageVmSharedFSLifeCycleTest.java @@ -53,6 +53,7 @@ import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.apache.cloudstack.api.ApiCommandResourceType; @@ -305,6 +306,23 @@ public void testDeploySharedFSTemplateNotFound() throws ResourceUnavailableExcep lifeCycle.deploySharedFS(sharedFS, s_networkId, s_diskOfferingId, s_size, s_minIops, s_maxIops); } + @Test(expected = CloudRuntimeException.class) + public void testDeploySharedFSTemplateNotFoundWithMultipleHypervisors() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException, IOException, OperationTimedoutException { + SharedFS sharedFS = mock(SharedFS.class); + when(sharedFS.getDataCenterId()).thenReturn(s_zoneId); + when(sharedFS.getName()).thenReturn(s_name); + when(sharedFS.getServiceOfferingId()).thenReturn(s_serviceOfferingId); + when(sharedFS.getFsType()).thenReturn(SharedFS.FileSystemType.valueOf(s_fsFormat)); + when(sharedFS.getAccountId()).thenReturn(s_ownerId); + + when(accountMgr.getActiveAccountById(s_ownerId)).thenReturn(null); + DataCenterVO zone = mock(DataCenterVO.class); + when(dataCenterDao.findById(s_zoneId)).thenReturn(zone); + when(resourceMgr.getSupportedHypervisorTypes(s_zoneId, false, null)).thenReturn(new ArrayList<>(List.of(Hypervisor.HypervisorType.KVM, Hypervisor.HypervisorType.VMware))); + + lifeCycle.deploySharedFS(sharedFS, s_networkId, s_diskOfferingId, s_size, s_minIops, s_maxIops); + } + @Test public void testDeleteSharedFS() throws ResourceUnavailableException { SharedFS sharedFS = mock(SharedFS.class);