From fca928d609baffa87750d9de8b3d48e8746d64ce Mon Sep 17 00:00:00 2001 From: YoulongChen <30854794+YLChen-007@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:28:48 +0800 Subject: [PATCH 1/4] fix HMAC Signatures and API Keys Logged in Plaintext (#12021) Co-authored-by: chenyoulong20g@ict.ac.cn Co-authored-by: dahn --- .../java/com/cloud/storage/template/HttpTemplateDownloader.java | 2 +- .../schema/src/main/java/com/cloud/upgrade/DatabaseCreator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java b/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java index cf49217ef5b..6fe001de72c 100755 --- a/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java +++ b/core/src/main/java/com/cloud/storage/template/HttpTemplateDownloader.java @@ -151,7 +151,7 @@ public class HttpTemplateDownloader extends ManagedContextRunnable implements Te client.getParams().setAuthenticationPreemptive(true); Credentials defaultcreds = new UsernamePasswordCredentials(user, password); client.getState().setCredentials(new AuthScope(hostAndPort.first(), hostAndPort.second(), AuthScope.ANY_REALM), defaultcreds); - logger.info("Added username=" + user + ", password=" + password + "for host " + hostAndPort.first() + ":" + hostAndPort.second()); + logger.info("Added username={}, password=****** for host {}:{}", user, hostAndPort.first(), hostAndPort.second()); } else { logger.info("No credentials configured for host=" + hostAndPort.first() + ":" + hostAndPort.second()); } diff --git a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseCreator.java b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseCreator.java index 384826227af..cccfbe8a006 100644 --- a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseCreator.java +++ b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseCreator.java @@ -99,7 +99,7 @@ public class DatabaseCreator { String username = dbProperties.getProperty(String.format("db.%s.username", database)); String password = dbProperties.getProperty(String.format("db.%s.password", database)); String dbName = dbProperties.getProperty(String.format("db.%s.name", database)); - System.out.println(String.format("========> Initializing database=%s with host=%s port=%s username=%s password=%s", dbName, host, port, username, password)); + System.out.println(String.format("========> Initializing database=%s with host=%s port=%s username=%s password=******", dbName, host, port, username)); List queries = new ArrayList(); queries.add(String.format("drop database if exists `%s`", dbName)); From a29de0ed0665ea97a8bcdf35a2651b4f5df26494 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Mon, 5 Jan 2026 21:00:39 +0530 Subject: [PATCH 2/4] Retry cloneVM task when any file access issue while cloning from volume or template (#12335) --- .../vmware/mo/VirtualMachineMO.java | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 9802328827a..950ec9010cb 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -788,11 +788,8 @@ public class VirtualMachineMO extends BaseMO { cloneSpec.setMemory(false); cloneSpec.setConfig(vmConfigSpec); - ManagedObjectReference morTask = _context.getService().cloneVMTask(_mor, morFolder, cloneName, cloneSpec); - - boolean result = _context.getVimClient().waitForTask(morTask); + boolean result = cloneVM(cloneName, morFolder, cloneSpec); if (result) { - _context.waitForTaskProgressDone(morTask); VirtualMachineMO clonedVm = dcMo.findVm(cloneName); if (clonedVm == null) { logger.error(String.format("Failed to clone Instance %s", cloneName)); @@ -802,10 +799,9 @@ public class VirtualMachineMO extends BaseMO { clonedVm.tagAsWorkerVM(); makeSureVMHasOnlyRequiredDisk(clonedVm, requiredDisk, dsMo, dcMo); return clonedVm; - } else { - logger.error("VMware cloneVM_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask)); - return null; } + + return null; } private void makeSureVMHasOnlyRequiredDisk(VirtualMachineMO clonedVm, VirtualDisk requiredDisk, DatastoreMO dsMo, DatacenterMO dcMo) throws Exception { @@ -852,16 +848,42 @@ public class VirtualMachineMO extends BaseMO { setDiskProvisioningType(relocSpec, morDs, diskProvisioningType); - ManagedObjectReference morTask = _context.getService().cloneVMTask(_mor, morFolder, cloneName, cloneSpec); + return cloneVM(cloneName, morFolder, cloneSpec); + } + private boolean cloneVMTask(String cloneName, ManagedObjectReference morFolder, VirtualMachineCloneSpec cloneSpec) throws Exception { + ManagedObjectReference morTask = _context.getService().cloneVMTask(_mor, morFolder, cloneName, cloneSpec); boolean result = _context.getVimClient().waitForTask(morTask); if (result) { _context.waitForTaskProgressDone(morTask); return true; - } else { - logger.error("VMware cloneVM_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask)); } + logger.error("VMware cloneVM_Task failed due to {}", TaskMO.getTaskFailureInfo(_context, morTask)); + return false; + } + + private boolean cloneVM(final String cloneName, final ManagedObjectReference morFolder, final VirtualMachineCloneSpec cloneSpec) throws Exception { + final int retry = 20; + int retryAttempt = 0; + while (++retryAttempt <= retry) { + try { + logger.debug("Cloning VM {}, attempt #{}", cloneName, retryAttempt); + return cloneVMTask(cloneName, morFolder, cloneSpec); + } catch (Exception e) { + logger.info("Got exception while cloning VM {}", cloneName, e); + if (e.getMessage() != null && e.getMessage().contains("Unable to access file")) { + logger.debug("Failed to clone VM {}. Retrying", cloneName); + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + logger.debug("Waiting to clone VM {} been interrupted: ", cloneName); + } + } else { + throw e; + } + } + } return false; } @@ -925,17 +947,7 @@ public class VirtualMachineMO extends BaseMO { cloneSpec.setLocation(rSpec); cloneSpec.setSnapshot(morBaseSnapshot); - ManagedObjectReference morTask = _context.getService().cloneVMTask(_mor, morFolder, cloneName, cloneSpec); - - boolean result = _context.getVimClient().waitForTask(morTask); - if (result) { - _context.waitForTaskProgressDone(morTask); - return true; - } else { - logger.error("VMware cloneVM_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask)); - } - - return false; + return cloneVM(cloneName, morFolder, cloneSpec); } public VirtualMachineRuntimeInfo getRuntimeInfo() throws Exception { From 57331aca2fc4b0c7051a94a52b18969ac6920fd4 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 7 Jan 2026 09:25:11 +0530 Subject: [PATCH 3/4] Skip removal of offerings if in use during domain removal (#11780) This PR fixes #11502 - Prevent service offering update to specific domains if any instance for the offering are outside of those - Removal of offerings is skipped if it is in use by any Instance. --- .../java/com/cloud/storage/dao/VolumeDao.java | 2 + .../com/cloud/storage/dao/VolumeDaoImpl.java | 14 +++++++ .../java/com/cloud/vm/dao/VMInstanceDao.java | 3 ++ .../com/cloud/vm/dao/VMInstanceDaoImpl.java | 37 +++++++++++++++++++ .../ConfigurationManagerImpl.java | 8 +++- .../com/cloud/user/DomainManagerImpl.java | 25 +++++++++++-- 6 files changed, 84 insertions(+), 5 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java index e6ffca06f9e..4936af3caab 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java @@ -162,4 +162,6 @@ public interface VolumeDao extends GenericDao, StateDao searchRemovedByVms(List vmIds, Long batchSize); VolumeVO findOneByIScsiName(String iScsiName); + + int getVolumeCountByOfferingId(long diskOfferingId); } diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java index 750dbf2bee0..5ef64b04664 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java @@ -77,6 +77,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol protected GenericSearchBuilder primaryStorageSearch2; protected GenericSearchBuilder secondaryStorageSearch; private final SearchBuilder poolAndPathSearch; + final GenericSearchBuilder CountByOfferingId; @Inject ReservationDao reservationDao; @@ -504,6 +505,11 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol poolAndPathSearch.and("poolId", poolAndPathSearch.entity().getPoolId(), Op.EQ); poolAndPathSearch.and("path", poolAndPathSearch.entity().getPath(), Op.EQ); poolAndPathSearch.done(); + + CountByOfferingId = createSearchBuilder(Integer.class); + CountByOfferingId.select(null, Func.COUNT, CountByOfferingId.entity().getId()); + CountByOfferingId.and("diskOfferingId", CountByOfferingId.entity().getDiskOfferingId(), Op.EQ); + CountByOfferingId.done(); } @Override @@ -909,4 +915,12 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol sc.setParameters("iScsiName", iScsiName); return findOneIncludingRemovedBy(sc); } + + @Override + public int getVolumeCountByOfferingId(long diskOfferingId) { + SearchCriteria sc = CountByOfferingId.create(); + sc.setParameters("diskOfferingId", diskOfferingId); + List results = customSearch(sc, null); + return results.get(0); + } } diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java index 823642d8c3d..56e16ddd871 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java @@ -187,4 +187,7 @@ public interface VMInstanceDao extends GenericDao, StateDao< Map getNameIdMapForVmIds(Collection ids); + int getVmCountByOfferingId(Long serviceOfferingId); + + int getVmCountByOfferingNotInDomain(Long serviceOfferingId, List domainIds); } diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java index 29ab74dfbfd..518bc3cf497 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -104,6 +104,8 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected SearchBuilder LastHostAndStatesSearch; protected SearchBuilder VmsNotInClusterUsingPool; protected SearchBuilder IdsPowerStateSelectSearch; + GenericSearchBuilder CountByOfferingId; + GenericSearchBuilder CountUserVmNotInDomain; @Inject ResourceTagDao tagsDao; @@ -344,6 +346,18 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem IdsPowerStateSelectSearch.entity().getPowerStateUpdateCount(), IdsPowerStateSelectSearch.entity().getPowerStateUpdateTime()); IdsPowerStateSelectSearch.done(); + + CountByOfferingId = createSearchBuilder(Integer.class); + CountByOfferingId.select(null, Func.COUNT, CountByOfferingId.entity().getId()); + CountByOfferingId.and("serviceOfferingId", CountByOfferingId.entity().getServiceOfferingId(), Op.EQ); + CountByOfferingId.done(); + + CountUserVmNotInDomain = createSearchBuilder(Integer.class); + CountUserVmNotInDomain.select(null, Func.COUNT, CountUserVmNotInDomain.entity().getId()); + CountUserVmNotInDomain.and("serviceOfferingId", CountUserVmNotInDomain.entity().getServiceOfferingId(), Op.EQ); + CountUserVmNotInDomain.and("domainIdsNotIn", CountUserVmNotInDomain.entity().getDomainId(), Op.NIN); + CountUserVmNotInDomain.done(); + } @Override @@ -1224,4 +1238,27 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return vms.stream() .collect(Collectors.toMap(VMInstanceVO::getInstanceName, VMInstanceVO::getId)); } + + @Override + public int getVmCountByOfferingId(Long serviceOfferingId) { + if (serviceOfferingId == null) { + return 0; + } + SearchCriteria sc = CountByOfferingId.create(); + sc.setParameters("serviceOfferingId", serviceOfferingId); + List count = customSearch(sc, null); + return count.get(0); + } + + @Override + public int getVmCountByOfferingNotInDomain(Long serviceOfferingId, List domainIds) { + if (serviceOfferingId == null || CollectionUtils.isEmpty(domainIds)) { + return 0; + } + SearchCriteria sc = CountUserVmNotInDomain.create(); + sc.setParameters("serviceOfferingId", serviceOfferingId); + sc.setParameters("domainIdsNotIn", domainIds.toArray()); + List count = customSearch(sc, null); + return count.get(0); + } } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 246681f7585..62b3c23d27e 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -50,7 +50,7 @@ import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; - +import com.cloud.exception.UnsupportedServiceException; import com.cloud.network.as.AutoScaleManager; import com.cloud.user.AccountManagerImpl; import org.apache.cloudstack.acl.RoleType; @@ -3722,6 +3722,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati List filteredDomainIds = filterChildSubDomains(domainIds); Collections.sort(filteredDomainIds); + // avoid domain update of service offering if any instance is associated to it + int instanceCount = _vmInstanceDao.getVmCountByOfferingNotInDomain(offeringHandle.getId(), filteredDomainIds); + if (instanceCount > 0) { + throw new UnsupportedServiceException("There are Instances associated to this service offering outside of the specified domains."); + } + List filteredZoneIds = new ArrayList<>(); if (CollectionUtils.isNotEmpty(zoneIds)) { filteredZoneIds.addAll(zoneIds); diff --git a/server/src/main/java/com/cloud/user/DomainManagerImpl.java b/server/src/main/java/com/cloud/user/DomainManagerImpl.java index 6fc9c6f5ef5..28f9bd3ab39 100644 --- a/server/src/main/java/com/cloud/user/DomainManagerImpl.java +++ b/server/src/main/java/com/cloud/user/DomainManagerImpl.java @@ -34,6 +34,8 @@ import com.cloud.api.query.vo.NetworkOfferingJoinVO; import com.cloud.api.query.vo.VpcOfferingJoinVO; import com.cloud.configuration.Resource; import com.cloud.domain.dao.DomainDetailsDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcOfferingDao; import com.cloud.network.vpc.dao.VpcOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -85,6 +87,7 @@ import com.cloud.projects.dao.ProjectDao; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.user.dao.AccountDao; import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; @@ -101,6 +104,8 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContextImpl; +import com.cloud.vm.dao.VMInstanceDao; + import org.apache.commons.lang3.StringUtils; @Component @@ -141,6 +146,14 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom @Inject private ProjectDao _projectDao; @Inject + private VMInstanceDao vmInstanceDao; + @Inject + private NetworkDao networkDao; + @Inject + private VolumeDao volumeDao; + @Inject + private VpcDao vpcDao; + @Inject private ProjectManager _projectMgr; @Inject private RegionManager _regionMgr; @@ -543,7 +556,8 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom List vpcOfferingsDetailsToRemove = new ArrayList<>(); List vpcOfferingsForThisDomain = vpcOfferingJoinDao.findByDomainId(domainId); for (VpcOfferingJoinVO vpcOffering : vpcOfferingsForThisDomain) { - if (domainIdString.equals(vpcOffering.getDomainId())) { + int vpcCount = vpcDao.getVpcCountByOfferingId(vpcOffering.getId()); + if (vpcCount == 0) { vpcOfferingDao.remove(vpcOffering.getId()); } else { vpcOfferingsDetailsToRemove.add(vpcOffering.getId()); @@ -558,7 +572,8 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom List networkOfferingsDetailsToRemove = new ArrayList<>(); List networkOfferingsForThisDomain = networkOfferingJoinDao.findByDomainId(domainId, false); for (NetworkOfferingJoinVO networkOffering : networkOfferingsForThisDomain) { - if (domainIdString.equals(networkOffering.getDomainId())) { + int networkCount = networkDao.getNetworkCountByNetworkOffId(networkOffering.getId()); + if (networkCount == 0) { networkOfferingDao.remove(networkOffering.getId()); } else { networkOfferingsDetailsToRemove.add(networkOffering.getId()); @@ -573,7 +588,8 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom List serviceOfferingsDetailsToRemove = new ArrayList<>(); List serviceOfferingsForThisDomain = serviceOfferingJoinDao.findByDomainId(domainId); for (ServiceOfferingJoinVO serviceOffering : serviceOfferingsForThisDomain) { - if (domainIdString.equals(serviceOffering.getDomainId())) { + int vmCount = vmInstanceDao.getVmCountByOfferingId(serviceOffering.getId()); + if (vmCount == 0) { serviceOfferingDao.remove(serviceOffering.getId()); } else { serviceOfferingsDetailsToRemove.add(serviceOffering.getId()); @@ -588,7 +604,8 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom List diskOfferingsDetailsToRemove = new ArrayList<>(); List diskOfferingsForThisDomain = diskOfferingJoinDao.findByDomainId(domainId); for (DiskOfferingJoinVO diskOffering : diskOfferingsForThisDomain) { - if (domainIdString.equals(diskOffering.getDomainId())) { + int volumeCount = volumeDao.getVolumeCountByOfferingId(diskOffering.getId()); + if (volumeCount == 0) { diskOfferingDao.remove(diskOffering.getId()); } else { diskOfferingsDetailsToRemove.add(diskOffering.getId()); From 750290b8aede34c1da4012307ca8bc9ebfdb1343 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Wed, 7 Jan 2026 01:09:15 -0500 Subject: [PATCH 4/4] Prevent NPE when removing NIC from a stopped VM using service offering with CPU cap set (#12232) This PR fixes: #12225 --------- Co-authored-by: Abhisar Sinha <63767682+abh1sar@users.noreply.github.com> --- server/src/main/java/com/cloud/hypervisor/KVMGuru.java | 3 ++- server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java index 9edaa5e6d64..62063714b89 100644 --- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java +++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java @@ -132,7 +132,8 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru { VirtualMachine vm = vmProfile.getVirtualMachine(); HostVO host = hostDao.findById(vm.getHostId()); if (host == null) { - throw new CloudRuntimeException("Host with id: " + vm.getHostId() + " not found"); + logger.warn("Host is not available. Skipping setting CPU quota percentage for VM: {}", vm); + return; } logger.debug("Limiting CPU usage for VM: {} on host: {}", vm, host); double hostMaxSpeed = getHostCPUSpeed(host); diff --git a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java index eea8bb9de68..07e19d99f39 100644 --- a/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java +++ b/server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java @@ -32,7 +32,6 @@ import com.cloud.storage.GuestOSVO; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.GuestOSHypervisorDao; import com.cloud.utils.Pair; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import org.apache.cloudstack.api.ApiConstants; @@ -141,10 +140,11 @@ public class KVMGuruTest { Mockito.verify(vmTO).setCpuQuotaPercentage(Mockito.anyDouble()); } - @Test(expected = CloudRuntimeException.class) + @Test public void testSetVmQuotaPercentageNullHost() { Mockito.when(hostDao.findById(hostId)).thenReturn(null); guru.setVmQuotaPercentage(vmTO, vmProfile); + Mockito.verify(vmTO, Mockito.never()).setCpuQuotaPercentage(Mockito.anyDouble()); } @Test