-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Check for null host before proceeding with VM volume operations in managed storage while restoring VM #12879
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 4.22
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1194,21 +1194,21 @@ private UserVm rebootVirtualMachine(long userId, long vmId, boolean enterSetup, | |||||
| List<Long> vmNetworks = _vmNetworkMapDao.getNetworks(vmId); | ||||||
| List<DomainRouterVO> routers = new ArrayList<DomainRouterVO>(); | ||||||
| //List the stopped routers | ||||||
| for(long vmNetworkId : vmNetworks) { | ||||||
| for (long vmNetworkId : vmNetworks) { | ||||||
| List<DomainRouterVO> router = _routerDao.listStopped(vmNetworkId); | ||||||
| routers.addAll(router); | ||||||
| } | ||||||
| //A vm may not have many nics attached and even fewer routers might be stopped (only in exceptional cases) | ||||||
| //Safe to start the stopped router serially, this is consistent with the way how multiple networks are added to vm during deploy | ||||||
| //and routers are started serially ,may revisit to make this process parallel | ||||||
| for(DomainRouterVO routerToStart : routers) { | ||||||
| for (DomainRouterVO routerToStart : routers) { | ||||||
| logger.warn("Trying to start router {} as part of vm: {} reboot", routerToStart, vm); | ||||||
| _virtualNetAppliance.startRouter(routerToStart.getId(),true); | ||||||
| } | ||||||
| } | ||||||
| } catch (ConcurrentOperationException e) { | ||||||
| throw new CloudRuntimeException("Concurrent operations on starting router. " + e); | ||||||
| } catch (Exception ex){ | ||||||
| } catch (Exception ex) { | ||||||
| throw new CloudRuntimeException("Router start failed due to" + ex); | ||||||
| } finally { | ||||||
| if (logger.isInfoEnabled()) { | ||||||
|
|
@@ -1493,7 +1493,7 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV | |||||
|
|
||||||
| macAddress = validateOrReplaceMacAddress(macAddress, network); | ||||||
|
|
||||||
| if(_nicDao.findByNetworkIdAndMacAddress(networkId, macAddress) != null) { | ||||||
| if (_nicDao.findByNetworkIdAndMacAddress(networkId, macAddress) != null) { | ||||||
| throw new CloudRuntimeException("A NIC with this MAC address exists for network: " + network.getUuid()); | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -1519,7 +1519,7 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV | |||||
| vmInstance, dc, network, dataCenterDao.findById(network.getDataCenterId()))); | ||||||
| } | ||||||
|
|
||||||
| if(_networkModel.getNicInNetwork(vmInstance.getId(),network.getId()) != null){ | ||||||
| if (_networkModel.getNicInNetwork(vmInstance.getId(),network.getId()) != null) { | ||||||
| logger.debug("Instance {} already in network {} going to add another NIC", vmInstance, network); | ||||||
| } else { | ||||||
| //* get all vms hostNames in the network | ||||||
|
|
@@ -1547,7 +1547,7 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV | |||||
| } catch (ConcurrentOperationException e) { | ||||||
| throw new CloudRuntimeException("Concurrent operations on adding NIC to " + vmInstance + ": " + e); | ||||||
| } finally { | ||||||
| if(cleanUp) { | ||||||
| if (cleanUp) { | ||||||
| try { | ||||||
| _itMgr.removeVmFromNetwork(vmInstance, network, null); | ||||||
| } catch (ResourceUnavailableException e) { | ||||||
|
|
@@ -2295,7 +2295,7 @@ public HashMap<String, VolumeStatsEntry> getVolumeStatistics(long clusterId, Str | |||||
| answer = _agentMgr.easySend(neighbor.getId(), cmd); | ||||||
| } | ||||||
|
|
||||||
| if (answer != null && answer instanceof GetVolumeStatsAnswer){ | ||||||
| if (answer != null && answer instanceof GetVolumeStatsAnswer) { | ||||||
| GetVolumeStatsAnswer volstats = (GetVolumeStatsAnswer)answer; | ||||||
| if (volstats.getVolumeStats() != null) { | ||||||
| volumeStatsByUuid.putAll(volstats.getVolumeStats()); | ||||||
|
|
@@ -2306,7 +2306,7 @@ public HashMap<String, VolumeStatsEntry> getVolumeStatistics(long clusterId, Str | |||||
| return volumeStatsByUuid.size() > 0 ? volumeStatsByUuid : null; | ||||||
| } | ||||||
|
|
||||||
| private List<String> getVolumesByHost(HostVO host, StoragePool pool){ | ||||||
| private List<String> getVolumesByHost(HostVO host, StoragePool pool) { | ||||||
| List<VMInstanceVO> vmsPerHost = _vmInstanceDao.listByHostId(host.getId()); | ||||||
| return vmsPerHost.stream() | ||||||
| .flatMap(vm -> _volsDao.findNonDestroyedVolumesByInstanceIdAndPoolId(vm.getId(),pool.getId()).stream().map(vol -> | ||||||
|
|
@@ -2602,7 +2602,7 @@ private void transitionExpungingToError(long vmId) { | |||||
| */ | ||||||
| private void releaseNetworkResourcesOnExpunge(long id) throws ConcurrentOperationException, ResourceUnavailableException { | ||||||
| final VMInstanceVO vmInstance = _vmDao.findById(id); | ||||||
| if (vmInstance != null){ | ||||||
| if (vmInstance != null) { | ||||||
| final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vmInstance); | ||||||
| _networkMgr.release(profile, false); | ||||||
| } | ||||||
|
|
@@ -2867,17 +2867,17 @@ private void adjustVmLimits(Account owner, UserVmVO vmInstance, ServiceOfferingV | |||||
| ) { | ||||||
| if (newCpu > currentCpu) { | ||||||
| _resourceLimitMgr.incrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newCpu - currentCpu); | ||||||
| } else if (newCpu > 0 && currentCpu > newCpu){ | ||||||
| } else if (newCpu > 0 && currentCpu > newCpu) { | ||||||
| _resourceLimitMgr.decrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentCpu - newCpu); | ||||||
| } | ||||||
| if (newMemory > currentMemory) { | ||||||
| _resourceLimitMgr.incrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newMemory - currentMemory); | ||||||
| } else if (newMemory > 0 && currentMemory > newMemory){ | ||||||
| } else if (newMemory > 0 && currentMemory > newMemory) { | ||||||
| _resourceLimitMgr.decrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentMemory - newMemory); | ||||||
| } | ||||||
| if (newGpu > currentGpu) { | ||||||
| _resourceLimitMgr.incrementVmGpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newGpu - currentGpu); | ||||||
| } else if (newGpu > 0 && currentGpu > newGpu){ | ||||||
| } else if (newGpu > 0 && currentGpu > newGpu) { | ||||||
| _resourceLimitMgr.decrementVmGpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentGpu - newGpu); | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -2931,7 +2931,7 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx | |||||
| .map(item -> (item).trim()) | ||||||
| .collect(Collectors.toList()); | ||||||
| List<VMInstanceDetailVO> existingDetails = vmInstanceDetailsDao.listDetails(id); | ||||||
| if (cleanupDetails){ | ||||||
| if (cleanupDetails) { | ||||||
| if (template != null && template.isDeployAsIs()) { | ||||||
| throw new InvalidParameterValueException("Detail settings are read from OVA, it cannot be cleaned up by API call."); | ||||||
| } | ||||||
|
|
@@ -2991,7 +2991,7 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx | |||||
| if (userReadOnlySettings.contains(detailName)) { | ||||||
| throw new InvalidParameterValueException("You're not allowed to add or edit the read-only setting: " + detailName); | ||||||
| } | ||||||
| if (existingDetails.stream().anyMatch(d -> Objects.equals(d.getName(), detailName) && !d.isDisplay())){ | ||||||
| if (existingDetails.stream().anyMatch(d -> Objects.equals(d.getName(), detailName) && !d.isDisplay())) { | ||||||
| throw new InvalidParameterValueException("You're not allowed to add or edit the non-displayable setting: " + detailName); | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -3090,25 +3090,24 @@ protected void validateGuestOsIdForUpdateVirtualMachineCommand(UpdateVMCmd cmd) | |||||
| private void saveUsageEvent(UserVmVO vm) { | ||||||
|
|
||||||
| // If vm not destroyed | ||||||
| if( vm.getState() != State.Destroyed && vm.getState() != State.Expunging && vm.getState() != State.Error){ | ||||||
| if (vm.getState() != State.Destroyed && vm.getState() != State.Expunging && vm.getState() != State.Error) { | ||||||
|
|
||||||
| if(vm.isDisplayVm()){ | ||||||
| if (vm.isDisplayVm()) { | ||||||
| //1. Allocated VM Usage Event | ||||||
| generateUsageEvent(vm, true, EventTypes.EVENT_VM_CREATE); | ||||||
|
|
||||||
| if(vm.getState() == State.Running || vm.getState() == State.Stopping){ | ||||||
| if (vm.getState() == State.Running || vm.getState() == State.Stopping) { | ||||||
| //2. Running VM Usage Event | ||||||
| generateUsageEvent(vm, true, EventTypes.EVENT_VM_START); | ||||||
|
|
||||||
| // 3. Network offering usage | ||||||
| generateNetworkUsageForVm(vm, true, EventTypes.EVENT_NETWORK_OFFERING_ASSIGN); | ||||||
| } | ||||||
|
|
||||||
| }else { | ||||||
| } else { | ||||||
| //1. Allocated VM Usage Event | ||||||
| generateUsageEvent(vm, true, EventTypes.EVENT_VM_DESTROY); | ||||||
|
|
||||||
| if(vm.getState() == State.Running || vm.getState() == State.Stopping){ | ||||||
| if (vm.getState() == State.Running || vm.getState() == State.Stopping) { | ||||||
| //2. Running VM Usage Event | ||||||
| generateUsageEvent(vm, true, EventTypes.EVENT_VM_STOP); | ||||||
|
|
||||||
|
|
@@ -3120,8 +3119,7 @@ private void saveUsageEvent(UserVmVO vm) { | |||||
|
|
||||||
| } | ||||||
|
|
||||||
| private void generateNetworkUsageForVm(VirtualMachine vm, boolean isDisplay, String eventType){ | ||||||
|
|
||||||
| private void generateNetworkUsageForVm(VirtualMachine vm, boolean isDisplay, String eventType) { | ||||||
| List<NicVO> nics = _nicDao.listByVmId(vm.getId()); | ||||||
| for (NicVO nic : nics) { | ||||||
| NetworkVO network = _networkDao.findById(nic.getNetworkId()); | ||||||
|
|
@@ -3146,9 +3144,9 @@ public UserVm updateVirtualMachine(long id, String displayName, String group, Bo | |||||
| throw new CloudRuntimeException("Unable to find virtual machine with id " + id); | ||||||
| } | ||||||
|
|
||||||
| if(instanceName != null){ | ||||||
| if (instanceName != null) { | ||||||
| VMInstanceVO vmInstance = _vmInstanceDao.findVMByInstanceName(instanceName); | ||||||
| if(vmInstance != null && vmInstance.getId() != id){ | ||||||
| if (vmInstance != null && vmInstance.getId() != id) { | ||||||
| throw new CloudRuntimeException("Instance name : " + instanceName + " is not unique"); | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -3290,7 +3288,7 @@ private void checkAndUpdateSecurityGroupForVM(List<Long> securityGroupIdList, Us | |||||
| networkIds = networks.stream().map(Network::getId).collect(Collectors.toList()); | ||||||
| } | ||||||
| } catch (InvalidParameterValueException e) { | ||||||
| if(logger.isDebugEnabled()) { | ||||||
| if (logger.isDebugEnabled()) { | ||||||
| logger.debug(e.getMessage(),e); | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -5152,7 +5150,7 @@ public void validateRootDiskResize(final HypervisorType hypervisorType, Long roo | |||||
|
|
||||||
|
|
||||||
| @Override | ||||||
| public void generateUsageEvent(VirtualMachine vm, boolean isDisplay, String eventType){ | ||||||
| public void generateUsageEvent(VirtualMachine vm, boolean isDisplay, String eventType) { | ||||||
| ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId()); | ||||||
| if (!serviceOffering.isDynamic()) { | ||||||
| UsageEventUtils.publishUsageEvent(eventType, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), | ||||||
|
|
@@ -5408,7 +5406,7 @@ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, Depl | |||||
| } | ||||||
| // add userdata info into vm profile | ||||||
| Nic defaultNic = _networkModel.getDefaultNic(vm.getId()); | ||||||
| if(defaultNic != null) { | ||||||
| if (defaultNic != null) { | ||||||
| Network network = _networkModel.getNetwork(defaultNic.getNetworkId()); | ||||||
| if (_networkModel.isSharedNetworkWithoutServices(network.getId())) { | ||||||
| final String serviceOffering = serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText(); | ||||||
|
|
@@ -5659,7 +5657,7 @@ public UserVm stopVirtualMachine(long vmId, boolean forced) throws ConcurrentOpe | |||||
| try { | ||||||
| VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid()); | ||||||
|
|
||||||
| if(forced) { | ||||||
| if (forced) { | ||||||
| status = vmEntity.stopForced(Long.toString(userId)); | ||||||
| } else { | ||||||
| status = vmEntity.stop(Long.toString(userId)); | ||||||
|
|
@@ -5839,7 +5837,7 @@ public Pair<UserVmVO, Map<VirtualMachineProfile.Param, Object>> startVirtualMach | |||||
| params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.VmPassword, password); | ||||||
| } | ||||||
|
|
||||||
| if(additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) { | ||||||
| if (additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) { | ||||||
| if (! HypervisorType.VMware.equals(vm.getHypervisorType())) { | ||||||
| throw new InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense for " + vm.getHypervisorType()); | ||||||
| } | ||||||
|
|
@@ -6317,8 +6315,8 @@ private void verifyServiceOffering(BaseDeployVMCmd cmd, ServiceOffering serviceO | |||||
| } | ||||||
|
|
||||||
| if (!serviceOffering.isDynamic()) { | ||||||
| for(String detail: cmd.getDetails().keySet()) { | ||||||
| if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) { | ||||||
| for (String detail: cmd.getDetails().keySet()) { | ||||||
| if (detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) { | ||||||
| throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -6537,8 +6535,8 @@ private UserVm createVirtualMachine(BaseDeployVMCmd cmd, DataCenter zone, Accoun | |||||
|
|
||||||
| // check if this templateId has a child ISO | ||||||
| List<VMTemplateVO> child_templates = _templateDao.listByParentTemplatetId(template.getId()); | ||||||
| for (VMTemplateVO tmpl: child_templates){ | ||||||
| if (tmpl.getFormat() == Storage.ImageFormat.ISO){ | ||||||
| for (VMTemplateVO tmpl: child_templates) { | ||||||
| if (tmpl.getFormat() == Storage.ImageFormat.ISO) { | ||||||
| logger.info("MDOV trying to attach disk {} to the VM {}", tmpl, vm); | ||||||
| _tmplService.attachIso(tmpl.getId(), vm.getId(), true); | ||||||
| } | ||||||
|
|
@@ -7195,7 +7193,7 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr | |||||
|
|
||||||
| checkIfHostOfVMIsInPrepareForMaintenanceState(vm, "Migrate"); | ||||||
|
|
||||||
| if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { | ||||||
| if (serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { | ||||||
| throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported"); | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -7810,7 +7808,7 @@ public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinatio | |||||
| throw ex; | ||||||
| } | ||||||
|
|
||||||
| if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { | ||||||
| if (serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) { | ||||||
| throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported"); | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -9221,8 +9219,14 @@ private void handleManagedStorage(UserVmVO vm, VolumeVO root) { | |||||
| Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId(); | ||||||
|
|
||||||
| if (hostId != null) { | ||||||
| VolumeInfo volumeInfo = volFactory.getVolume(root.getId()); | ||||||
| // default findById() won't search entries with removed field not null | ||||||
| Host host = _hostDao.findById(hostId); | ||||||
| if (host == null) { | ||||||
| logger.warn("Host {} not found", hostId); | ||||||
|
||||||
| logger.warn("Host {} not found", hostId); | |
| logger.warn("Host {} not found for vm id: {}, uuid: {}, root volume id: {}, uuid: {}", hostId, vm.getId(), vm.getUuid(), root.getId(), root.getUuid()); |
Copilot
AI
Mar 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are unit tests for restoreVirtualMachine() in server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java, but none appear to cover the managed-storage restore path where vm.getLastHostId() is set and _hostDao.findById(hostId) returns null (deleted host). Adding a test for this scenario would help prevent regressions (e.g., ensure restore proceeds without leaving an extra ROOT volume in Allocated state).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exception message concatenation is missing a space ("due to" + ex) and the thrown CloudRuntimeException drops the original cause/stack trace. Consider including a separating space and passing the caught exception as the cause so callers/logs preserve details.