Skip to content

Commit 9aee625

Browse files
authored
orchestration: fix error on deleted template vm start (#7327)
* server: fix error on deleted template vm start When a VM is deployed with start flag as false and the template is deleted before the VM start, NPE is obeserved it is started for the first time. Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> * fix Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com> --------- Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
1 parent 9fb2005 commit 9aee625

File tree

3 files changed

+99
-7
lines changed

3 files changed

+99
-7
lines changed

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
package com.cloud.vm;
1919

20+
import static com.cloud.configuration.ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS;
21+
2022
import java.net.URI;
2123
import java.sql.PreparedStatement;
2224
import java.sql.ResultSet;
@@ -204,6 +206,7 @@
204206
import com.cloud.storage.StorageManager;
205207
import com.cloud.storage.StoragePool;
206208
import com.cloud.storage.VMTemplateVO;
209+
import com.cloud.storage.VMTemplateZoneVO;
207210
import com.cloud.storage.Volume;
208211
import com.cloud.storage.Volume.Type;
209212
import com.cloud.storage.VolumeApiService;
@@ -213,6 +216,7 @@
213216
import com.cloud.storage.dao.GuestOSDao;
214217
import com.cloud.storage.dao.StoragePoolHostDao;
215218
import com.cloud.storage.dao.VMTemplateDao;
219+
import com.cloud.storage.dao.VMTemplateZoneDao;
216220
import com.cloud.storage.dao.VolumeDao;
217221
import com.cloud.template.VirtualMachineTemplate;
218222
import com.cloud.user.Account;
@@ -253,8 +257,6 @@
253257
import com.cloud.vm.snapshot.VMSnapshotVO;
254258
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
255259

256-
import static com.cloud.configuration.ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS;
257-
258260
public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable {
259261
private static final Logger s_logger = Logger.getLogger(VirtualMachineManagerImpl.class);
260262

@@ -281,6 +283,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
281283
@Inject
282284
private VMTemplateDao _templateDao;
283285
@Inject
286+
private VMTemplateZoneDao templateZoneDao;
287+
@Inject
284288
private ItWorkDao _workDao;
285289
@Inject
286290
private UserVmDao _userVmDao;
@@ -1005,6 +1009,25 @@ private void setupAgentSecurity(final Host vmHost, final Map<String, String> ssh
10051009
}
10061010
}
10071011

1012+
protected void checkIfTemplateNeededForCreatingVmVolumes(VMInstanceVO vm) {
1013+
final List<VolumeVO> existingRootVolumes = _volsDao.findReadyRootVolumesByInstance(vm.getId());
1014+
if (CollectionUtils.isNotEmpty(existingRootVolumes)) {
1015+
return;
1016+
}
1017+
final VMTemplateVO template = _templateDao.findById(vm.getTemplateId());
1018+
if (template == null) {
1019+
String msg = "Template for the VM instance can not be found, VM instance configuration needs to be updated";
1020+
s_logger.error(String.format("%s. Template ID: %d seems to be removed", msg, vm.getTemplateId()));
1021+
throw new CloudRuntimeException(msg);
1022+
}
1023+
final VMTemplateZoneVO templateZoneVO = templateZoneDao.findByZoneTemplate(vm.getDataCenterId(), template.getId());
1024+
if (templateZoneVO == null) {
1025+
String msg = "Template for the VM instance can not be found in the zone ID: %s, VM instance configuration needs to be updated";
1026+
s_logger.error(String.format("%s. %s", msg, template));
1027+
throw new CloudRuntimeException(msg);
1028+
}
1029+
}
1030+
10081031
@Override
10091032
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
10101033
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
@@ -1068,6 +1091,8 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
10681091
boolean reuseVolume = true;
10691092
final DataCenterDeployment originalPlan = plan;
10701093

1094+
checkIfTemplateNeededForCreatingVmVolumes(vm);
1095+
10711096
int retry = StartRetry.value();
10721097
while (retry-- != 0) {
10731098
s_logger.debug("VM start attempt #" + (StartRetry.value() - retry));

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import javax.inject.Inject;
3838
import javax.naming.ConfigurationException;
3939

40-
import com.cloud.storage.StorageUtil;
4140
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
4241
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
4342
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
@@ -69,6 +68,7 @@
6968
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
7069
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
7170
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
71+
import org.apache.cloudstack.snapshot.SnapshotHelper;
7272
import org.apache.cloudstack.storage.command.CommandResult;
7373
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
7474
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
@@ -79,6 +79,7 @@
7979
import org.apache.commons.collections.MapUtils;
8080
import org.apache.commons.lang3.StringUtils;
8181
import org.apache.log4j.Logger;
82+
import org.jetbrains.annotations.Nullable;
8283

8384
import com.cloud.agent.api.to.DataTO;
8485
import com.cloud.agent.api.to.DatadiskTO;
@@ -114,6 +115,7 @@
114115
import com.cloud.storage.Storage.ImageFormat;
115116
import com.cloud.storage.StorageManager;
116117
import com.cloud.storage.StoragePool;
118+
import com.cloud.storage.StorageUtil;
117119
import com.cloud.storage.VMTemplateStorageResourceAssoc;
118120
import com.cloud.storage.Volume;
119121
import com.cloud.storage.Volume.Type;
@@ -161,9 +163,6 @@
161163
import com.cloud.vm.dao.UserVmDao;
162164
import com.cloud.vm.dao.UserVmDetailsDao;
163165

164-
import org.apache.cloudstack.snapshot.SnapshotHelper;
165-
import org.jetbrains.annotations.Nullable;
166-
167166
public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrationService, Configurable {
168167

169168
public enum UserVmCloneType {
@@ -1546,6 +1545,11 @@ private Pair<VolumeVO, DataStore> recreateVolume(VolumeVO vol, VirtualMachinePro
15461545

15471546
future = volService.createVolumeAsync(volume, destPool);
15481547
} else {
1548+
final VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId);
1549+
if (template == null) {
1550+
s_logger.error(String.format("Failed to find template: %d for %s", templateId, volume));
1551+
throw new CloudRuntimeException(String.format("Failed to find template for volume ID: %s", volume.getUuid()));
1552+
}
15491553
TemplateInfo templ = tmplFactory.getReadyTemplateOnImageStore(templateId, dest.getDataCenter().getId());
15501554
PrimaryDataStore primaryDataStore = (PrimaryDataStore)destPool;
15511555

engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.List;
3232
import java.util.Map;
3333

34-
import com.cloud.exception.InvalidParameterValueException;
3534
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
3635
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
3736
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
@@ -54,6 +53,7 @@
5453
import com.cloud.deploy.DeploymentPlan;
5554
import com.cloud.deploy.DeploymentPlanner;
5655
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
56+
import com.cloud.exception.InvalidParameterValueException;
5757
import com.cloud.host.HostVO;
5858
import com.cloud.hypervisor.Hypervisor.HypervisorType;
5959
import com.cloud.hypervisor.HypervisorGuru;
@@ -64,10 +64,14 @@
6464
import com.cloud.storage.ScopeType;
6565
import com.cloud.storage.StoragePool;
6666
import com.cloud.storage.StoragePoolHostVO;
67+
import com.cloud.storage.VMTemplateVO;
68+
import com.cloud.storage.VMTemplateZoneVO;
6769
import com.cloud.storage.Volume;
6870
import com.cloud.storage.VolumeVO;
6971
import com.cloud.storage.dao.DiskOfferingDao;
7072
import com.cloud.storage.dao.StoragePoolHostDao;
73+
import com.cloud.storage.dao.VMTemplateDao;
74+
import com.cloud.storage.dao.VMTemplateZoneDao;
7175
import com.cloud.storage.dao.VolumeDao;
7276
import com.cloud.utils.exception.CloudRuntimeException;
7377
import com.cloud.vm.VirtualMachine.State;
@@ -124,6 +128,10 @@ public class VirtualMachineManagerImplTest {
124128

125129
@Mock
126130
private DiskOfferingDao diskOfferingDaoMock;
131+
@Mock
132+
VMTemplateDao templateDao;
133+
@Mock
134+
VMTemplateZoneDao templateZoneDao;
127135

128136
@Before
129137
public void setup() {
@@ -693,4 +701,59 @@ private void prepareAndRunCheckIfNewOfferingStorageScopeMatchesStoragePool(boole
693701
Mockito.doReturn(isOfferingUsingLocal).when(diskOfferingMock).isUseLocalStorage();
694702
virtualMachineManagerImpl.checkIfNewOfferingStorageScopeMatchesStoragePool(vmInstanceMock, diskOfferingMock);
695703
}
704+
705+
@Test
706+
public void checkIfTemplateNeededForCreatingVmVolumesExistingRootVolumes() {
707+
long vmId = 1L;
708+
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
709+
Mockito.when(vm.getId()).thenReturn(vmId);
710+
Mockito.when(volumeDaoMock.findReadyRootVolumesByInstance(vmId)).thenReturn(List.of(Mockito.mock(VolumeVO.class)));
711+
virtualMachineManagerImpl.checkIfTemplateNeededForCreatingVmVolumes(vm);
712+
}
713+
714+
@Test(expected = CloudRuntimeException.class)
715+
public void checkIfTemplateNeededForCreatingVmVolumesMissingTemplate() {
716+
long vmId = 1L;
717+
long templateId = 1L;
718+
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
719+
Mockito.when(vm.getId()).thenReturn(vmId);
720+
Mockito.when(vm.getTemplateId()).thenReturn(templateId);
721+
Mockito.when(volumeDaoMock.findReadyRootVolumesByInstance(vmId)).thenReturn(null);
722+
Mockito.when(templateDao.findById(templateId)).thenReturn(null);
723+
virtualMachineManagerImpl.checkIfTemplateNeededForCreatingVmVolumes(vm);
724+
}
725+
726+
@Test(expected = CloudRuntimeException.class)
727+
public void checkIfTemplateNeededForCreatingVmVolumesMissingZoneTemplate() {
728+
long vmId = 1L;
729+
long templateId = 1L;
730+
long dcId = 1L;
731+
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
732+
Mockito.when(vm.getId()).thenReturn(vmId);
733+
Mockito.when(vm.getTemplateId()).thenReturn(templateId);
734+
Mockito.when(vm.getDataCenterId()).thenReturn(dcId);
735+
Mockito.when(volumeDaoMock.findReadyRootVolumesByInstance(vmId)).thenReturn(null);
736+
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
737+
Mockito.when(vm.getId()).thenReturn(templateId);
738+
Mockito.when(templateDao.findById(templateId)).thenReturn(template);
739+
Mockito.when(templateZoneDao.findByZoneTemplate(dcId, templateId)).thenReturn(null);
740+
virtualMachineManagerImpl.checkIfTemplateNeededForCreatingVmVolumes(vm);
741+
}
742+
743+
@Test
744+
public void checkIfTemplateNeededForCreatingVmVolumesTemplateAvailable() {
745+
long vmId = 1L;
746+
long templateId = 1L;
747+
long dcId = 1L;
748+
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
749+
Mockito.when(vm.getId()).thenReturn(vmId);
750+
Mockito.when(vm.getTemplateId()).thenReturn(templateId);
751+
Mockito.when(vm.getDataCenterId()).thenReturn(dcId);
752+
Mockito.when(volumeDaoMock.findReadyRootVolumesByInstance(vmId)).thenReturn(new ArrayList<>());
753+
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
754+
Mockito.when(template.getId()).thenReturn(templateId);
755+
Mockito.when(templateDao.findById(templateId)).thenReturn(template);
756+
Mockito.when(templateZoneDao.findByZoneTemplate(dcId, templateId)).thenReturn(Mockito.mock(VMTemplateZoneVO.class));
757+
virtualMachineManagerImpl.checkIfTemplateNeededForCreatingVmVolumes(vm);
758+
}
696759
}

0 commit comments

Comments
 (0)