Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 41 additions & 37 deletions server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines +1211 to 1212
Copy link

Copilot AI Mar 24, 2026

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.

Copilot uses AI. Check for mistakes.
} finally {
if (logger.isInfoEnabled()) {
Expand Down Expand Up @@ -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());
}

Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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());
Expand All @@ -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 ->
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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.");
}
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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);

Expand All @@ -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());
Expand All @@ -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");
}
}
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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");
}
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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");
}

Expand Down Expand Up @@ -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");
}

Expand Down Expand Up @@ -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);
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new log line only prints the hostId; when debugging restore/re-image issues it would be helpful to include the VM and root volume identifiers (e.g., vm UUID/id and root volume UUID/id) in the warning so operators can correlate the skip with the affected resources.

Suggested change
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 uses AI. Check for mistakes.
return;
}
Comment on lines 9221 to +9227
Copy link

Copilot AI Mar 24, 2026

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).

Copilot uses AI. Check for mistakes.

VolumeInfo volumeInfo = volFactory.getVolume(root.getId());

final Command cmd;

Expand Down Expand Up @@ -9978,7 +9982,7 @@ private void collectVmDiskAndNetworkStatistics(UserVm vm, State expectedState) {
}
}

public Boolean getDestroyRootVolumeOnVmDestruction(Long domainId){
public Boolean getDestroyRootVolumeOnVmDestruction(Long domainId) {
return DestroyRootVolumeOnVmDestruction.valueIn(domainId);
}

Expand Down
Loading