From 6cb5e27db454bbe36a8cca2ceb594dac197e4ab1 Mon Sep 17 00:00:00 2001 From: Vishesh Date: Mon, 20 Jan 2025 15:25:30 +0530 Subject: [PATCH 1/2] Check for unique hostnames for all networks in the vpc --- .../com/cloud/network/dao/NetworkDao.java | 6 ++ .../com/cloud/network/dao/NetworkDaoImpl.java | 30 ++++++++ .../main/java/com/cloud/vm/UserVmManager.java | 6 ++ .../java/com/cloud/vm/UserVmManagerImpl.java | 74 ++++++++++++++++--- .../com/cloud/vpc/dao/MockNetworkDaoImpl.java | 14 ++++ 5 files changed, 119 insertions(+), 11 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java index 0861a424ebb6..c50d6f899bd1 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java @@ -47,6 +47,12 @@ public interface NetworkDao extends GenericDao, StateDao listByNetworkDomains(List uniqueNtwkDomains); + + List listByNetworkDomainsAndAccountIds(List uniqueNtwkDomains, List accountIds); + + List listByNetworkDomainsAndDomainIds(List uniqueNtwkDomains, List domainIds); + /** * Retrieves the next available mac address in this network configuration. * diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java index 0aae532eac57..39ad5fcb36a5 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java @@ -86,6 +86,7 @@ public class NetworkDaoImpl extends GenericDaoBaseimplements Ne GenericSearchBuilder GarbageCollectedSearch; SearchBuilder PrivateNetworkSearch; + SearchBuilder NetworkDomainSearch; @Inject ResourceTagDao _tagsDao; @@ -198,6 +199,12 @@ protected void init() { PersistentNetworkSearch.join("persistent", persistentNtwkOffJoin, PersistentNetworkSearch.entity().getNetworkOfferingId(), persistentNtwkOffJoin.entity().getId(), JoinType.INNER); PersistentNetworkSearch.done(); + NetworkDomainSearch = createSearchBuilder(); + NetworkDomainSearch.and("networkDomains", NetworkDomainSearch.entity().getNetworkDomain(), Op.IN); + NetworkDomainSearch.and("accounts", NetworkDomainSearch.entity().getAccountId(), Op.IN); + NetworkDomainSearch.and("domains", NetworkDomainSearch.entity().getDomainId(), Op.IN); + NetworkDomainSearch.done(); + PhysicalNetworkSearch = createSearchBuilder(); PhysicalNetworkSearch.and("physicalNetworkId", PhysicalNetworkSearch.entity().getPhysicalNetworkId(), Op.EQ); PhysicalNetworkSearch.done(); @@ -428,6 +435,29 @@ public List getAllPersistentNetworksFromZone(long dataCenterId) { return search(sc, null); } + @Override + public List listByNetworkDomains(List uniqueNtwkDomains) { + SearchCriteria sc = NetworkDomainSearch.create(); + sc.setParameters("networkDomains", uniqueNtwkDomains.toArray()); + return search(sc, null); + } + + @Override + public List listByNetworkDomainsAndAccountIds(List uniqueNtwkDomains, List accountIds) { + SearchCriteria sc = NetworkDomainSearch.create(); + sc.setParameters("networkDomains", uniqueNtwkDomains.toArray()); + sc.setParameters("accounts", accountIds.toArray()); + return search(sc, null); + } + + @Override + public List listByNetworkDomainsAndDomainIds(List uniqueNtwkDomains, List domainIds) { + SearchCriteria sc = NetworkDomainSearch.create(); + sc.setParameters("networkDomains", uniqueNtwkDomains.toArray()); + sc.setParameters("domains", domainIds.toArray()); + return search(sc, null); + } + @Override public String getNextAvailableMacAddress(final long networkConfigId, Integer zoneMacIdentifier) { final SequenceFetcher fetch = SequenceFetcher.getInstance(); diff --git a/server/src/main/java/com/cloud/vm/UserVmManager.java b/server/src/main/java/com/cloud/vm/UserVmManager.java index f2a8a672d42a..a902b1d260ee 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManager.java +++ b/server/src/main/java/com/cloud/vm/UserVmManager.java @@ -83,6 +83,12 @@ public interface UserVmManager extends UserVmService { "If set to true, tags specified in `resource.limit.host.tags` are also included in vm.strict.host.tags.", true); + ConfigKey VmDistinctHostNameScope = new ConfigKey<>(String.class, "vm.distinct.hostname.scope", ConfigKey.CATEGORY_ADVANCED, + "network", + "Scope of resources to check while checking if the hostname is unique. Possible values are global, domain, subdomain, account, network.", + true, ConfigKey.Scope.Global, null, "VM distinct hostname scope", null, null, null, ConfigKey.Kind.Select, + "global,domain,subdomain,account,network"); + static final int MAX_USER_DATA_LENGTH_BYTES = 2048; public static final String CKS_NODE = "cksnode"; diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 854886d233e0..4583b1c9e22d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4691,23 +4691,75 @@ protected void verifyIfHypervisorSupportsRootdiskSizeOverride(HypervisorType hyp } } - private void checkIfHostNameUniqueInNtwkDomain(String hostName, List networkList) { - // Check that hostName is unique in the network domain - Map> ntwkDomains = new HashMap>(); + private List getNetworksWithSameNetworkDomainInDomains(List networkList, boolean checkSubDomains) { + List uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toList()); + List domainIdList = new ArrayList<>(); for (Network network : networkList) { + domainIdList.add(network.getDomainId()); + } + Set finalDomainIdList = new HashSet<>(domainIdList); + if (checkSubDomains) { + for (Long domainId : domainIdList) { + DomainVO domain = _domainDao.findById(domainId); + List childDomainIds = _domainDao.getDomainChildrenIds(domain.getPath()); + finalDomainIdList.addAll(childDomainIds); + } + } + return _networkDao.listByNetworkDomainsAndDomainIds(uniqueNtwkDomains, finalDomainIdList.stream().collect(Collectors.toList())); + } + + private List getNetworksForCheckUniqueHostName(List networkList) { + List finalNetworkList; + List uniqueNtwkDomains; + switch (VmDistinctHostNameScope.value()) { + case "global": + uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toList()); + finalNetworkList = _networkDao.listByNetworkDomains(uniqueNtwkDomains); + break; + case "domain": + finalNetworkList = getNetworksWithSameNetworkDomainInDomains(networkList, false); + break; + case "subdomain": + finalNetworkList = getNetworksWithSameNetworkDomainInDomains(networkList, true); + break; + case "account": + uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toList()); + List accountIds = networkList.stream().map(Network::getAccountId).collect(Collectors.toList()); + finalNetworkList = _networkDao.listByNetworkDomainsAndAccountIds(uniqueNtwkDomains, accountIds); + break; + default: + Set vpcIds = networkList.stream().map(Network::getVpcId).filter(Objects::nonNull).collect(Collectors.toSet()); + finalNetworkList = new ArrayList<>(networkList); + for (Long vpcId : vpcIds) { + finalNetworkList.addAll(_networkDao.listByVpc(vpcId)); + } + break; + } + return finalNetworkList; + } + + private Map> getNetworkIdPerNetworkDomain(List networkList) { + Map> ntwkDomains = new HashMap<>(); + + List updatedNetworkList = getNetworksForCheckUniqueHostName(networkList); + for (Network network : updatedNetworkList) { String ntwkDomain = network.getNetworkDomain(); + Set ntwkIds; if (!ntwkDomains.containsKey(ntwkDomain)) { - List ntwkIds = new ArrayList(); - ntwkIds.add(network.getId()); - ntwkDomains.put(ntwkDomain, ntwkIds); + ntwkIds = new HashSet<>(); } else { - List ntwkIds = ntwkDomains.get(ntwkDomain); - ntwkIds.add(network.getId()); - ntwkDomains.put(ntwkDomain, ntwkIds); + ntwkIds = ntwkDomains.get(ntwkDomain); } + ntwkIds.add(network.getId()); + ntwkDomains.put(ntwkDomain, ntwkIds); } + return ntwkDomains; + } - for (Entry> ntwkDomain : ntwkDomains.entrySet()) { + private void checkIfHostNameUniqueInNtwkDomain(String hostName, List networkList) { + // Check that hostName is unique + Map> ntwkDomains = getNetworkIdPerNetworkDomain(networkList); + for (Entry> ntwkDomain : ntwkDomains.entrySet()) { for (Long ntwkId : ntwkDomain.getValue()) { // * get all vms hostNames in the network List hostNames = _vmInstanceDao.listDistinctHostNames(ntwkId); @@ -9244,7 +9296,7 @@ public ConfigKey[] getConfigKeys() { return new ConfigKey[] {EnableDynamicallyScaleVm, AllowDiskOfferingChangeDuringScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers, AllowDeployVmIfGivenHostFails, EnableAdditionalVmConfig, DisplayVMOVFProperties, KvmAdditionalConfigAllowList, XenServerAdditionalConfigAllowList, VmwareAdditionalConfigAllowList, DestroyRootVolumeOnVmDestruction, - EnforceStrictResourceLimitHostTagCheck, StrictHostTags, AllowUserForceStopVm}; + EnforceStrictResourceLimitHostTagCheck, StrictHostTags, AllowUserForceStopVm, VmDistinctHostNameScope}; } @Override diff --git a/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java b/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java index 490f2ccba46b..1b74edc2acbe 100644 --- a/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java +++ b/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java @@ -265,4 +265,18 @@ public List getAllPersistentNetworksFromZone(long dataCenterId) { return null; } + @Override + public List listByNetworkDomains(List uniqueNtwkDomains) { + return List.of(); + } + + @Override + public List listByNetworkDomainsAndAccountIds(List uniqueNtwkDomains, List accountIds) { + return List.of(); + } + + @Override + public List listByNetworkDomainsAndDomainIds(List uniqueNtwkDomains, List domainIds) { + return List.of(); + } } From 6f2136e8aaf5c39bed3a245eba9e9f73da359a82 Mon Sep 17 00:00:00 2001 From: vishesh92 Date: Wed, 1 Oct 2025 14:40:38 +0530 Subject: [PATCH 2/2] Address comments --- .../java/com/cloud/network/dao/NetworkDao.java | 7 ++++--- .../com/cloud/network/dao/NetworkDaoImpl.java | 6 +++--- .../main/java/com/cloud/vm/UserVmManager.java | 2 +- .../java/com/cloud/vm/UserVmManagerImpl.java | 18 +++++++++--------- .../com/cloud/vpc/dao/MockNetworkDaoImpl.java | 7 ++++--- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java index c50d6f899bd1..fdca6e43f00f 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; +import java.util.Set; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; @@ -47,11 +48,11 @@ public interface NetworkDao extends GenericDao, StateDao listByNetworkDomains(List uniqueNtwkDomains); + List listByNetworkDomains(Set uniqueNtwkDomains); - List listByNetworkDomainsAndAccountIds(List uniqueNtwkDomains, List accountIds); + List listByNetworkDomainsAndAccountIds(Set uniqueNtwkDomains, Set accountIds); - List listByNetworkDomainsAndDomainIds(List uniqueNtwkDomains, List domainIds); + List listByNetworkDomainsAndDomainIds(Set uniqueNtwkDomains, Set domainIds); /** * Retrieves the next available mac address in this network configuration. diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java index 39ad5fcb36a5..4b299085612c 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java @@ -436,14 +436,14 @@ public List getAllPersistentNetworksFromZone(long dataCenterId) { } @Override - public List listByNetworkDomains(List uniqueNtwkDomains) { + public List listByNetworkDomains(Set uniqueNtwkDomains) { SearchCriteria sc = NetworkDomainSearch.create(); sc.setParameters("networkDomains", uniqueNtwkDomains.toArray()); return search(sc, null); } @Override - public List listByNetworkDomainsAndAccountIds(List uniqueNtwkDomains, List accountIds) { + public List listByNetworkDomainsAndAccountIds(Set uniqueNtwkDomains, Set accountIds) { SearchCriteria sc = NetworkDomainSearch.create(); sc.setParameters("networkDomains", uniqueNtwkDomains.toArray()); sc.setParameters("accounts", accountIds.toArray()); @@ -451,7 +451,7 @@ public List listByNetworkDomainsAndAccountIds(List uniqueNtwk } @Override - public List listByNetworkDomainsAndDomainIds(List uniqueNtwkDomains, List domainIds) { + public List listByNetworkDomainsAndDomainIds(Set uniqueNtwkDomains, Set domainIds) { SearchCriteria sc = NetworkDomainSearch.create(); sc.setParameters("networkDomains", uniqueNtwkDomains.toArray()); sc.setParameters("domains", domainIds.toArray()); diff --git a/server/src/main/java/com/cloud/vm/UserVmManager.java b/server/src/main/java/com/cloud/vm/UserVmManager.java index a902b1d260ee..34fc37a2bbcd 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManager.java +++ b/server/src/main/java/com/cloud/vm/UserVmManager.java @@ -85,7 +85,7 @@ public interface UserVmManager extends UserVmService { ConfigKey VmDistinctHostNameScope = new ConfigKey<>(String.class, "vm.distinct.hostname.scope", ConfigKey.CATEGORY_ADVANCED, "network", - "Scope of resources to check while checking if the hostname is unique. Possible values are global, domain, subdomain, account, network.", + "Defines the scope for enforcing unique VM hostnames which determines the resource boundary within which VM hostnames must be unique. Possible values: global, domain, subdomain, account, network.", true, ConfigKey.Scope.Global, null, "VM distinct hostname scope", null, null, null, ConfigKey.Kind.Select, "global,domain,subdomain,account,network"); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 4583b1c9e22d..093258f98b47 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4692,28 +4692,28 @@ protected void verifyIfHypervisorSupportsRootdiskSizeOverride(HypervisorType hyp } private List getNetworksWithSameNetworkDomainInDomains(List networkList, boolean checkSubDomains) { - List uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toList()); - List domainIdList = new ArrayList<>(); + Set uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toSet()); + Set domainIdList = new HashSet<>(); for (Network network : networkList) { domainIdList.add(network.getDomainId()); } - Set finalDomainIdList = new HashSet<>(domainIdList); + Set finalDomainIdSet = new HashSet<>(domainIdList); if (checkSubDomains) { for (Long domainId : domainIdList) { DomainVO domain = _domainDao.findById(domainId); List childDomainIds = _domainDao.getDomainChildrenIds(domain.getPath()); - finalDomainIdList.addAll(childDomainIds); + finalDomainIdSet.addAll(childDomainIds); } } - return _networkDao.listByNetworkDomainsAndDomainIds(uniqueNtwkDomains, finalDomainIdList.stream().collect(Collectors.toList())); + return _networkDao.listByNetworkDomainsAndDomainIds(uniqueNtwkDomains, finalDomainIdSet); } private List getNetworksForCheckUniqueHostName(List networkList) { List finalNetworkList; - List uniqueNtwkDomains; + Set uniqueNtwkDomains; switch (VmDistinctHostNameScope.value()) { case "global": - uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toList()); + uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toSet()); finalNetworkList = _networkDao.listByNetworkDomains(uniqueNtwkDomains); break; case "domain": @@ -4723,8 +4723,8 @@ private List getNetworksForCheckUniqueHostName(List networ finalNetworkList = getNetworksWithSameNetworkDomainInDomains(networkList, true); break; case "account": - uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toList()); - List accountIds = networkList.stream().map(Network::getAccountId).collect(Collectors.toList()); + uniqueNtwkDomains = networkList.stream().map(NetworkVO::getNetworkDomain).collect(Collectors.toSet()); + Set accountIds = networkList.stream().map(Network::getAccountId).collect(Collectors.toSet()); finalNetworkList = _networkDao.listByNetworkDomainsAndAccountIds(uniqueNtwkDomains, accountIds); break; default: diff --git a/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java b/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java index 1b74edc2acbe..8a0bec56df7b 100644 --- a/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java +++ b/server/src/test/java/com/cloud/vpc/dao/MockNetworkDaoImpl.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; @DB() public class MockNetworkDaoImpl extends GenericDaoBase implements NetworkDao { @@ -266,17 +267,17 @@ public List getAllPersistentNetworksFromZone(long dataCenterId) { } @Override - public List listByNetworkDomains(List uniqueNtwkDomains) { + public List listByNetworkDomains(Set uniqueNtwkDomains) { return List.of(); } @Override - public List listByNetworkDomainsAndAccountIds(List uniqueNtwkDomains, List accountIds) { + public List listByNetworkDomainsAndAccountIds(Set uniqueNtwkDomains, Set accountIds) { return List.of(); } @Override - public List listByNetworkDomainsAndDomainIds(List uniqueNtwkDomains, List domainIds) { + public List listByNetworkDomainsAndDomainIds(Set uniqueNtwkDomains, Set domainIds) { return List.of(); } }