This is an automated email from the ASF dual-hosted git repository.
DaanHoogland pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.22 by this push:
new f493d993dbf sharedfs: skip hypervisors without system templates
(#13830)
f493d993dbf is described below
commit f493d993dbf786a06f13222ff37ecce69a6cc8e5
Author: Brad <[email protected]>
AuthorDate: Tue Sep 8 13:12:26 2026 +0100
sharedfs: skip hypervisors without system templates (#13830)
---
.../lifecycle/StorageVmSharedFSLifeCycle.java | 5 ++-
.../lifecycle/StorageVmSharedFSLifeCycleTest.java | 41 ++++++++++++++++++++++
2 files changed, 45 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 ac8d6a58f0c..15c45226e00 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 @@ public class StorageVmSharedFSLifeCycle implements
SharedFSLifeCycle {
for (final Iterator<Hypervisor.HypervisorType> 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 c64e8c05c99..dd7f873998e 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.VirtualMachineManager;
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;
@@ -273,6 +274,46 @@ public class StorageVmSharedFSLifeCycleTest {
Assert.assertEquals(Optional.ofNullable(result.second()),
Optional.ofNullable(s_vmId));
}
+ @Test
+ public void
testDeploySharedFSContinuesWhenTemplateIsMissingForNonLastHypervisor() throws
ResourceUnavailableException, InsufficientCapacityException,
ResourceAllocationException, IOException, OperationTimedoutException {
+ SharedFS sharedFS = prepareDeploySharedFS();
+ when(resourceMgr.getSupportedHypervisorTypes(s_zoneId, false,
null)).thenReturn(new ArrayList<>(List.of(Hypervisor.HypervisorType.External,
Hypervisor.HypervisorType.KVM)) {
+ @Override
+ public Hypervisor.HypervisorType set(int index,
Hypervisor.HypervisorType element) {
+ // Keep the test order stable while exercising the production
shuffle call.
+ return get(index);
+ }
+ });
+ when(templateDao.findSystemVMReadyTemplate(s_zoneId,
Hypervisor.HypervisorType.External,
ResourceManager.SystemVmPreferredArchitecture.defaultValue())).thenReturn(null);
+
+ Account owner = mock(Account.class);
+ when(owner.getId()).thenReturn(s_ownerId);
+ when(accountMgr.getActiveAccountById(s_ownerId)).thenReturn(owner);
+
+ UserVm vm = mock(UserVm.class);
+ when(vm.getId()).thenReturn(s_vmId);
+ when(userVmService.createAdvancedVirtualMachine(
+ any(DataCenter.class), any(ServiceOffering.class),
any(VirtualMachineTemplate.class), anyList(), any(Account.class), anyString(),
+ anyString(), anyLong(), anyLong(), any(), isNull(),
any(Hypervisor.HypervisorType.class), any(BaseCmd.HTTPMethod.class),
anyString(),
+ isNull(), isNull(), anyList(), isNull(),
any(Network.IpAddresses.class), isNull(), isNull(), isNull(),
+ anyMap(), isNull(), isNull(), isNull(), isNull(),
+ anyBoolean(), anyString(), isNull(), isNull(),
isNull())).thenReturn(vm);
+
+ VolumeVO rootVol = mock(VolumeVO.class);
+ when(rootVol.getVolumeType()).thenReturn(Volume.Type.ROOT);
+ when(rootVol.getName()).thenReturn("ROOT-1");
+ VolumeVO dataVol = mock(VolumeVO.class);
+ when(dataVol.getId()).thenReturn(s_volumeId);
+ when(dataVol.getName()).thenReturn("DATA-1");
+ when(dataVol.getVolumeType()).thenReturn(Volume.Type.DATADISK);
+ when(volumeDao.findByInstance(s_vmId)).thenReturn(List.of(rootVol,
dataVol));
+
+ Pair<Long, Long> result = lifeCycle.deploySharedFS(sharedFS,
s_networkId, s_diskOfferingId, s_size, s_minIops, s_maxIops);
+
+ Assert.assertEquals(Optional.ofNullable(result.first()),
Optional.ofNullable(s_volumeId));
+ Assert.assertEquals(Optional.ofNullable(result.second()),
Optional.ofNullable(s_vmId));
+ }
+
@Test(expected = CloudRuntimeException.class)
public void testDeploySharedFSHypervisorNotFound() throws
ResourceUnavailableException, InsufficientCapacityException,
ResourceAllocationException, IOException, OperationTimedoutException {
SharedFS sharedFS = mock(SharedFS.class);