diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index bdba1569ffa..43436501e11 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -108,6 +108,7 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDomainDao; +import com.cloud.network.dao.NetworkDomainVO; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.OvsProviderDao; @@ -140,13 +141,13 @@ import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.org.Grouping; import com.cloud.projects.Project; -import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.projects.ProjectManager; import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; import com.cloud.user.DomainManager; import com.cloud.user.ResourceLimitService; import com.cloud.user.User; @@ -156,7 +157,6 @@ import com.cloud.user.dao.UserDao; import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.EntityManager; @@ -1391,10 +1391,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { String trafficType = cmd.getTrafficType(); Boolean isSystem = cmd.getIsSystem(); String aclType = cmd.getAclType(); + Long projectId = cmd.getProjectId(); + List permittedAccounts = new ArrayList(); + String path = null; Long physicalNetworkId = cmd.getPhysicalNetworkId(); List supportedServicesStr = cmd.getSupportedServices(); Boolean restartRequired = cmd.getRestartRequired(); boolean listAll = cmd.listAll(); + boolean isRecursive = cmd.isRecursive(); Boolean specifyIpRanges = cmd.getSpecifyIpRanges(); Long vpcId = cmd.getVpcId(); Boolean canUseForDeploy = cmd.canUseForDeploy(); @@ -1413,16 +1417,66 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { throw new InvalidParameterValueException("System network belongs to system, account and domainId parameters can't be specified"); } - List permittedDomains = new ArrayList(); - List permittedAccounts = new ArrayList(); - List permittedResources = new ArrayList(); - Ternary domainIdRecursiveListProject = new Ternary(cmd.getDomainId(), - cmd.isRecursive(), null); - _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedDomains, permittedAccounts, permittedResources, - domainIdRecursiveListProject, cmd.listAll(), false, "listNetworks"); - Boolean isRecursive = domainIdRecursiveListProject.second(); - ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + if (domainId != null) { + DomainVO domain = _domainDao.findById(domainId); + if (domain == null) { + // see DomainVO.java + throw new InvalidParameterValueException("Specified domain id doesn't exist in the system"); + } + _accountMgr.checkAccess(caller, domain); + if (accountName != null) { + Account owner = _accountMgr.getActiveAccountByName(accountName, domainId); + if (owner == null) { + // see DomainVO.java + throw new InvalidParameterValueException("Unable to find account " + accountName + " in specified domain"); + } + + _accountMgr.checkAccess(caller, null, true, owner); + permittedAccounts.add(owner.getId()); + } + } + + if (!_accountMgr.isAdmin(caller.getId()) || (projectId != null && projectId.longValue() != -1 && domainId == null)) { + permittedAccounts.add(caller.getId()); + domainId = caller.getDomainId(); + } + + // set project information + boolean skipProjectNetworks = true; + if (projectId != null) { + if (projectId.longValue() == -1) { + if (!_accountMgr.isAdmin(caller.getId())) { + permittedAccounts.addAll(_projectMgr.listPermittedProjectAccounts(caller.getId())); + } + } else { + permittedAccounts.clear(); + Project project = _projectMgr.getProject(projectId); + if (project == null) { + throw new InvalidParameterValueException("Unable to find project by specified id"); + } + if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) { + // getProject() returns type ProjectVO. + InvalidParameterValueException ex = new InvalidParameterValueException("Account " + caller + " cannot access specified project id"); + ex.addProxyObject(project.getUuid(), "projectId"); + throw ex; + } + + //add project account + permittedAccounts.add(project.getProjectAccountId()); + //add caller account (if admin) + if (_accountMgr.isAdmin(caller.getId())) { + permittedAccounts.add(caller.getId()); + } + } + skipProjectNetworks = false; + } + + if (domainId != null) { + path = _domainDao.findById(domainId).getPath(); + } else { + path = _domainDao.findById(caller.getDomainId()).getPath(); + } if (listAll && domainId == null) { isRecursive = true; @@ -1430,7 +1484,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { Filter searchFilter = new Filter(NetworkVO.class, "id", false, null, null); SearchBuilder sb = _networksDao.createSearchBuilder(); - _accountMgr.buildACLSearchBuilder(sb, isRecursive, permittedDomains, permittedAccounts, permittedResources, listProjectResourcesCriteria); if (forVpc != null) { if (forVpc) { @@ -1465,9 +1518,122 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); } - // build network search criteria + if (permittedAccounts.isEmpty()) { + SearchBuilder domainSearch = _domainDao.createSearchBuilder(); + domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE); + sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.entity().getId(), JoinBuilder.JoinType.INNER); + } + + SearchBuilder accountSearch = _accountDao.createSearchBuilder(); + accountSearch.and("typeNEQ", accountSearch.entity().getType(), SearchCriteria.Op.NEQ); + accountSearch.and("typeEQ", accountSearch.entity().getType(), SearchCriteria.Op.EQ); + + sb.join("accountSearch", accountSearch, sb.entity().getAccountId(), accountSearch.entity().getId(), JoinBuilder.JoinType.INNER); + + List networksToReturn = new ArrayList(); + + if (isSystem == null || !isSystem) { + if (!permittedAccounts.isEmpty()) { + //get account level networks + networksToReturn.addAll(listAccountSpecificNetworks( + buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, skipProjectNetworks, restartRequired, + specifyIpRanges, vpcId, tags, display), searchFilter, permittedAccounts)); + //get domain level networks + if (domainId != null) { + networksToReturn.addAll(listDomainLevelNetworks( + buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, true, restartRequired, + specifyIpRanges, vpcId, tags, display), searchFilter, domainId, false)); + } + } else { + //add account specific networks + networksToReturn.addAll(listAccountSpecificNetworksByDomainPath( + buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, skipProjectNetworks, restartRequired, + specifyIpRanges, vpcId, tags, display), searchFilter, path, isRecursive)); + //add domain specific networks of domain + parent domains + networksToReturn.addAll(listDomainSpecificNetworksByDomainPath( + buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, skipProjectNetworks, restartRequired, + specifyIpRanges, vpcId, tags, display), searchFilter, path, isRecursive)); + //add networks of subdomains + if (domainId == null) { + networksToReturn.addAll(listDomainLevelNetworks( + buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, aclType, true, restartRequired, + specifyIpRanges, vpcId, tags, display), searchFilter, caller.getDomainId(), true)); + } + } + } else { + networksToReturn = _networksDao.search( + buildNetworkSearchCriteria(sb, keyword, id, isSystem, zoneId, guestIpType, trafficType, physicalNetworkId, null, skipProjectNetworks, restartRequired, + specifyIpRanges, vpcId, tags, display), searchFilter); + } + + if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.isEmpty()) { + List supportedNetworks = new ArrayList(); + Service[] suppportedServices = new Service[supportedServicesStr.size()]; + int i = 0; + for (String supportedServiceStr : supportedServicesStr) { + Service service = Service.getService(supportedServiceStr); + if (service == null) { + throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr); + } else { + suppportedServices[i] = service; + } + i++; + } + + for (NetworkVO network : networksToReturn) { + if (areServicesSupportedInNetwork(network.getId(), suppportedServices)) { + supportedNetworks.add(network); + } + } + + networksToReturn = supportedNetworks; + } + + if (canUseForDeploy != null) { + List networksForDeploy = new ArrayList(); + for (NetworkVO network : networksToReturn) { + if (_networkModel.canUseForDeploy(network) == canUseForDeploy) { + networksForDeploy.add(network); + } + } + + networksToReturn = networksForDeploy; + } + + //Now apply pagination + //Most likely pageSize will never exceed int value, and we need integer to partition the listToReturn + boolean notNull = cmd.getStartIndex() != null && cmd.getPageSizeVal() != null; + if (notNull && cmd.getStartIndex() <= Integer.MAX_VALUE && cmd.getStartIndex() >= Integer.MIN_VALUE && cmd.getPageSizeVal() <= Integer.MAX_VALUE + && cmd.getPageSizeVal() >= Integer.MIN_VALUE) { + int index = cmd.getStartIndex().intValue() == 0 ? 0 : cmd.getStartIndex().intValue() / cmd.getPageSizeVal().intValue(); + List wPagination = new ArrayList(); + List> partitions = partitionNetworks(networksToReturn, cmd.getPageSizeVal().intValue()); + if (index < partitions.size()) { + wPagination = partitions.get(index); + } + return new Pair, Integer>(wPagination, networksToReturn.size()); + } + + return new Pair, Integer>(networksToReturn, networksToReturn.size()); + } + + private static List> partitionNetworks(List originalList, int chunkSize) { + List> listOfChunks = new ArrayList>(); + for (int i = 0; i < originalList.size() / chunkSize; i++) { + listOfChunks.add(originalList.subList(i * chunkSize, i * chunkSize + chunkSize)); + } + if (originalList.size() % chunkSize != 0) { + listOfChunks.add(originalList.subList(originalList.size() - originalList.size() % chunkSize, originalList.size())); + } + return listOfChunks; + } + + private SearchCriteria buildNetworkSearchCriteria(SearchBuilder sb, String keyword, Long id, Boolean isSystem, Long zoneId, String guestIpType, + String trafficType, Long physicalNetworkId, String aclType, boolean skipProjectNetworks, Boolean restartRequired, Boolean specifyIpRanges, Long vpcId, + Map tags, Boolean display) { + SearchCriteria sc = sb.create(); - _accountMgr.buildACLSearchCriteria(sc, isRecursive, permittedDomains, permittedAccounts, permittedResources, listProjectResourcesCriteria); + if (isSystem != null) { sc.setJoinParameters("networkOfferingSearch", "systemOnly", isSystem); } @@ -1506,6 +1672,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { sc.addAnd("physicalNetworkId", SearchCriteria.Op.EQ, physicalNetworkId); } + if (skipProjectNetworks) { + sc.setJoinParameters("accountSearch", "typeNEQ", Account.ACCOUNT_TYPE_PROJECT); + } else { + sc.setJoinParameters("accountSearch", "typeEQ", Account.ACCOUNT_TYPE_PROJECT); + } + if (restartRequired != null) { sc.addAnd("restartRequired", SearchCriteria.Op.EQ, restartRequired); } @@ -1528,70 +1700,94 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } } - List networksToReturn = _networksDao.search(sc, searchFilter); - - // filter by supported services - if (supportedServicesStr != null && !supportedServicesStr.isEmpty() && !networksToReturn.isEmpty()) { - List supportedNetworks = new ArrayList(); - Service[] suppportedServices = new Service[supportedServicesStr.size()]; - int i = 0; - for (String supportedServiceStr : supportedServicesStr) { - Service service = Service.getService(supportedServiceStr); - if (service == null) { - throw new InvalidParameterValueException("Invalid service specified " + supportedServiceStr); - } else { - suppportedServices[i] = service; - } - i++; - } - - for (NetworkVO network : networksToReturn) { - if (areServicesSupportedInNetwork(network.getId(), suppportedServices)) { - supportedNetworks.add(network); - } - } - - networksToReturn = supportedNetworks; - } - - // filter by usability to deploy - if (canUseForDeploy != null) { - List networksForDeploy = new ArrayList(); - for (NetworkVO network : networksToReturn) { - if (_networkModel.canUseForDeploy(network) == canUseForDeploy) { - networksForDeploy.add(network); - } - } - - networksToReturn = networksForDeploy; - } - - //Now apply pagination - //Most likely pageSize will never exceed int value, and we need integer to partition the listToReturn - boolean notNull = cmd.getStartIndex() != null && cmd.getPageSizeVal() != null; - if (notNull && cmd.getStartIndex() <= Integer.MAX_VALUE && cmd.getStartIndex() >= Integer.MIN_VALUE && cmd.getPageSizeVal() <= Integer.MAX_VALUE - && cmd.getPageSizeVal() >= Integer.MIN_VALUE) { - int index = cmd.getStartIndex().intValue() == 0 ? 0 : cmd.getStartIndex().intValue() / cmd.getPageSizeVal().intValue(); - List wPagination = new ArrayList(); - List> partitions = partitionNetworks(networksToReturn, cmd.getPageSizeVal().intValue()); - if (index < partitions.size()) { - wPagination = partitions.get(index); - } - return new Pair, Integer>(wPagination, networksToReturn.size()); - } - - return new Pair, Integer>(networksToReturn, networksToReturn.size()); + return sc; } - private static List> partitionNetworks(List originalList, int chunkSize) { - List> listOfChunks = new ArrayList>(); - for (int i = 0; i < originalList.size() / chunkSize; i++) { - listOfChunks.add(originalList.subList(i * chunkSize, i * chunkSize + chunkSize)); + private List listDomainLevelNetworks(SearchCriteria sc, Filter searchFilter, long domainId, boolean parentDomainsOnly) { + List networkIds = new ArrayList(); + Set allowedDomains = _domainMgr.getDomainParentIds(domainId); + List maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray()); + + for (NetworkDomainVO map : maps) { + if (map.getDomainId() == domainId && parentDomainsOnly) { + continue; + } + boolean subdomainAccess = (map.isSubdomainAccess() != null) ? map.isSubdomainAccess() : getAllowSubdomainAccessGlobal(); + if (map.getDomainId() == domainId || subdomainAccess) { + networkIds.add(map.getNetworkId()); + } } - if (originalList.size() % chunkSize != 0) { - listOfChunks.add(originalList.subList(originalList.size() - originalList.size() % chunkSize, originalList.size())); + + if (!networkIds.isEmpty()) { + SearchCriteria domainSC = _networksDao.createSearchCriteria(); + domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray()); + domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString()); + + sc.addAnd("id", SearchCriteria.Op.SC, domainSC); + return _networksDao.search(sc, searchFilter); + } else { + return new ArrayList(); + } + } + + private List listAccountSpecificNetworks(SearchCriteria sc, Filter searchFilter, List permittedAccounts) { + SearchCriteria accountSC = _networksDao.createSearchCriteria(); + if (!permittedAccounts.isEmpty()) { + accountSC.addAnd("accountId", SearchCriteria.Op.IN, permittedAccounts.toArray()); + } + + accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString()); + + sc.addAnd("id", SearchCriteria.Op.SC, accountSC); + return _networksDao.search(sc, searchFilter); + } + + private List listAccountSpecificNetworksByDomainPath(SearchCriteria sc, Filter searchFilter, String path, boolean isRecursive) { + SearchCriteria accountSC = _networksDao.createSearchCriteria(); + accountSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Account.toString()); + + if (path != null) { + if (isRecursive) { + sc.setJoinParameters("domainSearch", "path", path + "%"); + } else { + sc.setJoinParameters("domainSearch", "path", path); + } + } + + sc.addAnd("id", SearchCriteria.Op.SC, accountSC); + return _networksDao.search(sc, searchFilter); + } + + private List listDomainSpecificNetworksByDomainPath(SearchCriteria sc, Filter searchFilter, String path, boolean isRecursive) { + + Set allowedDomains = new HashSet(); + if (path != null) { + if (isRecursive) { + allowedDomains = _domainMgr.getDomainChildrenIds(path); + } else { + Domain domain = _domainDao.findDomainByPath(path); + allowedDomains.add(domain.getId()); + } + } + + List networkIds = new ArrayList(); + + List maps = _networkDomainDao.listDomainNetworkMapByDomain(allowedDomains.toArray()); + + for (NetworkDomainVO map : maps) { + networkIds.add(map.getNetworkId()); + } + + if (!networkIds.isEmpty()) { + SearchCriteria domainSC = _networksDao.createSearchCriteria(); + domainSC.addAnd("id", SearchCriteria.Op.IN, networkIds.toArray()); + domainSC.addAnd("aclType", SearchCriteria.Op.EQ, ACLType.Domain.toString()); + + sc.addAnd("id", SearchCriteria.Op.SC, domainSC); + return _networksDao.search(sc, searchFilter); + } else { + return new ArrayList(); } - return listOfChunks; } @Override