From 485733b9e71b7708e2dbf799ba67b12c81b70c74 Mon Sep 17 00:00:00 2001 From: alena Date: Fri, 4 Mar 2011 22:40:30 -0800 Subject: [PATCH] bug 8821: Domain specific Direct Vlans --- api.log | 0 client/tomcatconf/components.xml.in | 1 + core/src/com/cloud/dc/AccountVlanMapVO.java | 14 +- .../cloud/dc/dao/AccountVlanMapDaoImpl.java | 4 +- core/src/com/cloud/dc/dao/VlanDao.java | 4 +- core/src/com/cloud/dc/dao/VlanDaoImpl.java | 44 ++++- .../com/cloud/server/ManagementServer.java | 36 ++-- deps/.project | 17 ++ .../api/commands/CreateVlanIpRangeCmd.java | 34 ++-- .../api/commands/ListVlanIpRangesCmd.java | 21 ++- .../configuration/ConfigurationManager.java | 12 +- .../ConfigurationManagerImpl.java | 73 ++++++--- .../cloud/server/ManagementServerImpl.java | 43 ++++- .../src/com/cloud/vm/UserVmManagerImpl.java | 154 +++++++++++++----- setup/db/create-index-fk.sql | 3 + setup/db/create-schema.sql | 3 +- 16 files changed, 345 insertions(+), 118 deletions(-) create mode 100644 api.log create mode 100644 deps/.project diff --git a/api.log b/api.log new file mode 100644 index 00000000000..e69de29bb2d diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index 6404055551b..612f6747277 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -206,6 +206,7 @@ + diff --git a/core/src/com/cloud/dc/AccountVlanMapVO.java b/core/src/com/cloud/dc/AccountVlanMapVO.java index a5fbb105e1d..6e10073e05e 100644 --- a/core/src/com/cloud/dc/AccountVlanMapVO.java +++ b/core/src/com/cloud/dc/AccountVlanMapVO.java @@ -35,14 +35,18 @@ public class AccountVlanMapVO { private Long id; @Column(name="account_id") - private long accountId; + private Long accountId; @Column(name="vlan_db_id") private long vlanDbId; - public AccountVlanMapVO(long accountId, long vlanDbId) { + @Column(name="domain_id") + private Long domainId; + + public AccountVlanMapVO(Long accountId, long vlanDbId, Long domainId) { this.accountId = accountId; this.vlanDbId = vlanDbId; + this.domainId = domainId; } public AccountVlanMapVO() { @@ -53,11 +57,15 @@ public class AccountVlanMapVO { return id; } - public long getAccountId() { + public Long getAccountId() { return accountId; } public long getVlanDbId() { return vlanDbId; } + + public Long getDomainId() { + return domainId; + } } diff --git a/core/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java b/core/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java index ccbc195f77b..fbf54901edc 100644 --- a/core/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java +++ b/core/src/com/cloud/dc/dao/AccountVlanMapDaoImpl.java @@ -69,6 +69,6 @@ public class AccountVlanMapDaoImpl extends GenericDaoBase { boolean zoneHasDirectAttachUntaggedVlans(long zoneId); List searchForZoneWideVlans(long dcId, String vlanType,String vlanId); + + List listVlansForDomainByTypeAndZone(Long zoneId, long domainId, VlanType vlanType); } diff --git a/core/src/com/cloud/dc/dao/VlanDaoImpl.java b/core/src/com/cloud/dc/dao/VlanDaoImpl.java index 4a2005f1f7f..6e7c283b804 100644 --- a/core/src/com/cloud/dc/dao/VlanDaoImpl.java +++ b/core/src/com/cloud/dc/dao/VlanDaoImpl.java @@ -28,13 +28,12 @@ import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; - import com.cloud.dc.AccountVlanMapVO; +import com.cloud.dc.DataCenterVO; import com.cloud.dc.PodVlanMapVO; import com.cloud.dc.Vlan; -import com.cloud.dc.VlanVO; import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; import com.cloud.network.dao.IPAddressDao; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLocator; @@ -42,6 +41,7 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @@ -55,7 +55,8 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao protected SearchBuilder ZoneTypeSearch; protected SearchBuilder ZoneTypeAllPodsSearch; protected SearchBuilder ZoneTypePodSearch; - + protected SearchBuilder DomainZoneVlanSearch; + protected SearchBuilder DomainVlanSearch; protected PodVlanMapDaoImpl _podVlanMapDao = new PodVlanMapDaoImpl(); protected AccountVlanMapDao _accountVlanMapDao = new AccountVlanMapDaoImpl(); @@ -290,7 +291,42 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao } catch (SQLException e) { throw new CloudRuntimeException("Unable to execute " + pstmt.toString(), e); } + } + + @Override + public List listVlansForDomainByTypeAndZone(Long zoneId, long domainId, VlanType vlanType) { + + if (DomainZoneVlanSearch == null) { + + DataCenterDao _dcDao = ComponentLocator.getLocator("management-server").getDao(DataCenterDao.class); + AccountVlanMapDao _accountVlanMap = ComponentLocator.getLocator("management-server").getDao(AccountVlanMapDao.class); + + SearchBuilder ZoneSearch = _dcDao.createSearchBuilder(); + ZoneSearch.and("id", ZoneSearch.entity().getId(), SearchCriteria.Op.EQ); + + SearchBuilder DomainSearch = _accountVlanMap.createSearchBuilder(); + DomainSearch.and("accountId", DomainSearch.entity().getAccountId(), Op.NULL); + DomainSearch.and("domainId", DomainSearch.entity().getDomainId(), Op.EQ); + + DomainZoneVlanSearch = createSearchBuilder(); + DomainZoneVlanSearch.and("vlanType", DomainZoneVlanSearch.entity().getVlanType(), Op.EQ); + DomainZoneVlanSearch.join("zoneSearch", ZoneSearch, DomainZoneVlanSearch.entity().getDataCenterId(), ZoneSearch.entity().getId()); + DomainZoneVlanSearch.join("domainVlanSearch", DomainSearch, DomainZoneVlanSearch.entity().getId(), DomainSearch.entity().getVlanDbId()); + DomainZoneVlanSearch.done(); + ZoneSearch.done(); + DomainSearch.done(); + + } + + SearchCriteria sc = DomainZoneVlanSearch.create(); + sc.setParameters("vlanType", vlanType); + if (zoneId != null) { + sc.setJoinParameters("zoneSearch", "id", zoneId); + } + sc.setJoinParameters("domainVlanSearch", "domainId", domainId); + + return listBy(sc); } } diff --git a/core/src/com/cloud/server/ManagementServer.java b/core/src/com/cloud/server/ManagementServer.java index 9dc8eb3f20f..5cc55ae1f34 100644 --- a/core/src/com/cloud/server/ManagementServer.java +++ b/core/src/com/cloud/server/ManagementServer.java @@ -17,33 +17,26 @@ */ package com.cloud.server; -import java.io.IOException; import java.net.URISyntaxException; import java.net.UnknownHostException; -import java.rmi.ServerException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; -import netapp.manage.NaAPIFailedException; -import netapp.manage.NaAuthenticationException; -import netapp.manage.NaException; -import netapp.manage.NaProtocolException; - import com.cloud.alert.AlertVO; import com.cloud.async.AsyncJobResult; import com.cloud.async.AsyncJobVO; import com.cloud.capacity.CapacityVO; import com.cloud.configuration.ConfigurationVO; -import com.cloud.configuration.ResourceLimitVO; import com.cloud.configuration.ResourceCount.ResourceType; +import com.cloud.configuration.ResourceLimitVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.dc.VlanVO; import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; import com.cloud.domain.DomainVO; import com.cloud.event.EventVO; import com.cloud.exception.ConcurrentOperationException; @@ -95,7 +88,6 @@ import com.cloud.user.UserAccount; import com.cloud.user.UserAccountVO; import com.cloud.user.UserStatisticsVO; import com.cloud.utils.Pair; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.DomainRouter; @@ -420,19 +412,20 @@ public interface ManagementServer { /** * Adds a VLAN to the database, along with an IP address range. Can add three types of VLANs: (1) zone-wide VLANs on the virtual network (2) pod-wide direct attached VLANs (3) account-specific direct attached VLANs * @param userId - * @param vlanType - either "DomR" (VLAN for a virtual network) or "DirectAttached" (VLAN for IPs that will be directly attached to UserVMs) - * @param zoneId - * @param accountId - * @param podId - * @param add - * @param vlanId - * @param gateway - * @param startIP - * @param endIP + * @param vlanType - either "DomR" (VLAN for a virtual network) or "DirectAttached" (VLAN for IPs that will be directly attached to UserVMs) + * @param zoneId + * @param accountId + * @param podId + * @param vlanId + * @param startIP + * @param endIP + * @param domainId TODO + * @param add + * @param gateway * @return The new VlanVO object * @throws Exception */ - VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP) throws Exception; + VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP, Long domainId) throws Exception; /** * Deletes a VLAN from the database, along with all of its IP addresses. Will not delete VLANs that have allocated IP addresses. @@ -2191,5 +2184,8 @@ public interface ManagementServer { */ String getHostTags(long hostId); VolumeVO findVolumeByIdIncludingRemoved(long id); + + + Long getDomainIdForVlan(long vlanDbId); } diff --git a/deps/.project b/deps/.project new file mode 100644 index 00000000000..901f15e089b --- /dev/null +++ b/deps/.project @@ -0,0 +1,17 @@ + + + deps + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/server/src/com/cloud/api/commands/CreateVlanIpRangeCmd.java b/server/src/com/cloud/api/commands/CreateVlanIpRangeCmd.java index a22f35f2d95..f352b0d5096 100644 --- a/server/src/com/cloud/api/commands/CreateVlanIpRangeCmd.java +++ b/server/src/com/cloud/api/commands/CreateVlanIpRangeCmd.java @@ -18,19 +18,19 @@ package com.cloud.api.commands; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.log4j.Logger; - +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; import com.cloud.dc.HostPodVO; import com.cloud.dc.Vlan; -import com.cloud.dc.VlanVO; import com.cloud.dc.Vlan.VlanType; -import com.cloud.exception.InvalidParameterValueException; +import com.cloud.dc.VlanVO; +import com.cloud.domain.DomainVO; import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.utils.Pair; @@ -99,14 +99,28 @@ public class CreateVlanIpRangeCmd extends BaseCmd { } else { accountId = account.getId(); } - } + } + + //if only domain id is specified, create domain specific vlan + if (domainId != null) { + DomainVO domain = getManagementServer().findDomainIdById(domainId); + if (domain == null) { + throw new ServerApiException(BaseCmd.PARAM_ERROR, "Please specify a valid domain"); + } + } + + //pass only accountId or domainId to createVlanIpRange command, but never both + Long domainIdForVlan = null; + if (accountId == null && domainId != null) { + domainIdForVlan = domainId; + } VlanType vlanType = forVirtualNetwork ? VlanType.VirtualNetwork : VlanType.DirectAttached; // Create a VLAN and public IP addresses VlanVO vlan = null; try { - vlan = getManagementServer().createVlanAndPublicIpRange(userId, vlanType, zoneId, accountId, podId, vlanId, vlanGateway, vlanNetmask, startIp, endIp); + vlan = getManagementServer().createVlanAndPublicIpRange(userId, vlanType, zoneId, accountId, podId, vlanId, vlanGateway, vlanNetmask, startIp, endIp, domainIdForVlan); } catch (Exception e) { s_logger.error("Error adding VLAN: ", e); throw new ServerApiException (BaseCmd.INTERNAL_ERROR, e.getMessage()); diff --git a/server/src/com/cloud/api/commands/ListVlanIpRangesCmd.java b/server/src/com/cloud/api/commands/ListVlanIpRangesCmd.java index 5e50421003e..07480065a77 100644 --- a/server/src/com/cloud/api/commands/ListVlanIpRangesCmd.java +++ b/server/src/com/cloud/api/commands/ListVlanIpRangesCmd.java @@ -18,20 +18,19 @@ package com.cloud.api.commands; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.log4j.Logger; - +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; import com.cloud.dc.HostPodVO; -import com.cloud.dc.VlanVO; import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; import com.cloud.server.Criteria; import com.cloud.user.Account; -import com.cloud.user.AccountVO; import com.cloud.utils.Pair; public class ListVlanIpRangesCmd extends BaseCmd { @@ -118,6 +117,7 @@ public class ListVlanIpRangesCmd extends BaseCmd { for (VlanVO vlan : vlans) { accountId = getManagementServer().getAccountIdForVlan(vlan.getId()); + Long vlanDomainId = getManagementServer().getDomainIdForVlan(vlan.getId()); podId = getManagementServer().getPodIdForVlan(vlan.getId()); List> vlanData = new ArrayList>(); @@ -132,6 +132,11 @@ public class ListVlanIpRangesCmd extends BaseCmd { vlanData.add(new Pair(BaseCmd.Properties.DOMAIN_ID.getName(), account.getDomainId())); vlanData.add(new Pair(BaseCmd.Properties.DOMAIN.getName(), getManagementServer().findDomainIdById(account.getDomainId()).getName())); } + + if (vlanDomainId != null) { + vlanData.add(new Pair(BaseCmd.Properties.DOMAIN_ID.getName(), vlanDomainId)); + vlanData.add(new Pair(BaseCmd.Properties.DOMAIN.getName(), getManagementServer().findDomainIdById(vlanDomainId).getName())); + } if (podId != null) { HostPodVO pod = getManagementServer().findHostPodById(podId); diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index 8080000591b..5e0b153a004 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -18,11 +18,12 @@ package com.cloud.configuration; import java.util.List; +import java.util.Map; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.dc.VlanVO; import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; import com.cloud.exception.InternalErrorException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.service.ServiceOfferingVO; @@ -175,15 +176,16 @@ public interface ConfigurationManager extends Manager { * @param zoneId * @param accountId * @param podId - * @param add * @param vlanId - * @param gateway * @param startIP * @param endIP + * @param domainId TODO + * @param add + * @param gateway * @throws InvalidParameterValueException * @return The new VlanVO object */ - VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP) throws InvalidParameterValueException, InternalErrorException; + VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP, Long domainId) throws InvalidParameterValueException, InternalErrorException; /** * Deletes a VLAN from the database, along with all of its IP addresses. Will not delete VLANs that have allocated IP addresses. @@ -209,5 +211,7 @@ public interface ConfigurationManager extends Manager { * @return true for Premium, false for not */ boolean isPremium(); + + Map> listDomainDirectVlans(long domainId, long zoneId); } diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 846d633d28e..78f4736e1e4 100644 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -45,6 +45,8 @@ import com.cloud.dc.dao.DataCenterIpAddressDaoImpl; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.PodVlanMapDao; import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventTypes; import com.cloud.event.EventVO; import com.cloud.event.dao.EventDao; @@ -56,7 +58,6 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.user.AccountVO; import com.cloud.user.UserVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; @@ -88,6 +89,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager { @Inject DataCenterIpAddressDaoImpl _privateIpAddressDao; @Inject VMInstanceDao _vmInstanceDao; @Inject AccountDao _accountDao; + @Inject DomainDao _domainDao; @Inject EventDao _eventDao; @Inject UserDao _userDao; public boolean _premium; @@ -973,8 +975,9 @@ public class ConfigurationManagerImpl implements ConfigurationManager { } } - public VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP) throws InvalidParameterValueException, InternalErrorException { - + public VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP, Long domainId) throws InvalidParameterValueException, InternalErrorException { + + //check for hypervisor type to be xenserver String hypervisorType = _configDao.getValue("hypervisor.type"); @@ -988,7 +991,6 @@ public class ConfigurationManagerImpl implements ConfigurationManager { throw new InternalErrorException("For adding an untagged vlan, please set up xen.public.network.device"); } } - } DataCenterVO zone; @@ -1015,8 +1017,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager { } // Check that the pod ID is valid - HostPodVO pod = null; - if (podId != null && ((pod = _podDao.findById(podId)) == null)) { + if (podId != null && ((_podDao.findById(podId)) == null)) { throw new InvalidParameterValueException("Please specify a valid pod."); } @@ -1032,19 +1033,22 @@ public class ConfigurationManagerImpl implements ConfigurationManager { } else { - // VLANs for an account must be tagged + // VLANs for an account/domain must be tagged if (vlanId.equals(Vlan.UNTAGGED)) { throw new InvalidParameterValueException("Direct Attached VLANs for an account must be tagged."); } - if(accountId!=null) - { + if(accountId != null || domainId != null) { // Check that the account ID is valid - AccountVO account; - if ((account = _accountDao.findById(accountId)) == null) { + if (accountId != null && _accountDao.findById(accountId) == null) { throw new InvalidParameterValueException("Please specify a valid account."); } + //Check that domainId is valid + if (domainId != null && _domainDao.findById(domainId) == null) { + throw new InvalidParameterValueException("Please specify a valid domain"); + } + // Make sure there aren't any pod VLANs in this zone List podsInZone = _podDao.listByDataCenterId(zone.getId()); for (HostPodVO pod : podsInZone) { @@ -1052,15 +1056,6 @@ public class ConfigurationManagerImpl implements ConfigurationManager { throw new InvalidParameterValueException("Zone " + zone.getName() + " already has pod VLANs. A zone may contain either pod VLANs or account VLANs, but not both."); } } - - // Make sure the specified account isn't already assigned to a VLAN in this zone -// List accountVlanMaps = _accountVlanMapDao.listAccountVlanMapsByAccount(accountId); -// for (AccountVlanMapVO accountVlanMap : accountVlanMaps) { -// VlanVO vlan = _vlanDao.findById(accountVlanMap.getVlanDbId()); -// if (vlan.getDataCenterId() == zone.getId().longValue()) { -// throw new InvalidParameterValueException("The account " + account.getAccountName() + " is already assigned to the VLAN with ID " + vlan.getVlanId() + " in zone " + zone.getName() + "."); -// } -// } } } } @@ -1166,7 +1161,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager { _vlanDao.delete(vlan.getId()); throw new InternalErrorException("Failed to save IP range. Please contact Cloud Support."); //It can be Direct IP or Public IP. } - }else if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId())) { + } else if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId())) { deletePublicIPRange(vlan.getId()); _vlanDao.delete(vlan.getId()); throw new InternalErrorException("Failed to save IP range. Please contact Cloud Support."); //It can be Direct IP or Public IP. @@ -1174,8 +1169,12 @@ public class ConfigurationManagerImpl implements ConfigurationManager { if (accountId != null) { // This VLAN is account-specific, so create an AccountVlanMapVO entry - AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(accountId, vlan.getId()); + AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(accountId, vlan.getId(), null); _accountVlanMapDao.persist(accountVlanMapVO); + } else if (domainId != null) { + // This VLAN is domain-specific, so create an AccountVlanMapVO entry + AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(null, vlan.getId(), domainId); + _accountVlanMapDao.persist(accountVlanMapVO); } else if (podId != null) { // This VLAN is pod-wide, so create a PodVlanMapVO entry PodVlanMapVO podVlanMapVO = new PodVlanMapVO(podId, vlan.getId()); @@ -1191,7 +1190,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager { "accountId=" + accountId, "podId=" + podId, "vlanId=" + vlanId, "vlanGateway=" + vlanGateway, "vlanNetmask=" + vlanNetmask, "startIP=" + startIP, - "endIP=" + endIP); + "endIP=" + endIP, "domainId=" + domainId); return vlan; } @@ -1690,4 +1689,32 @@ public class ConfigurationManagerImpl implements ConfigurationManager { return ipRanges; } + @Override + public Map> listDomainDirectVlans(long domainId, long zoneId) { + Map> vlansForDomain = new HashMap>(); + getDomainDirectVlans(vlansForDomain, domainId, zoneId); + return vlansForDomain; + } + + private void getDomainDirectVlans(Map> vlans, long domainId, long zoneId) { + //Domain level vlans include: + //* vlans belonging to this domain + //* vlans belonging to all domain + + DomainVO domain = _domainDao.findById(domainId); + if (domain == null) { + return; + } + + List vlan = _vlanDao.listVlansForDomainByTypeAndZone(zoneId, domainId, VlanType.DirectAttached); + if (vlan != null && !vlan.isEmpty()) { + vlans.put(domain.getLevel(), vlan); + } + + if (domain.getParent() != null) { + getDomainDirectVlans(vlans, domain.getParent(), zoneId); + } else { + return; + } + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 5f5c7d1b704..98c43faf04e 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -1716,7 +1716,7 @@ public class ManagementServerImpl implements ManagementServer { @DB @Override - public VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP) throws Exception{ + public VlanVO createVlanAndPublicIpRange(long userId, VlanType vlanType, Long zoneId, Long accountId, Long podId, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP, Long domainId) throws Exception{ if(accountId != null && vlanType == VlanType.VirtualNetwork){ long ipResourceLimit = _accountMgr.findCorrectResourceLimit( _accountDao.findById(accountId), ResourceType.public_ip); @@ -1729,7 +1729,7 @@ public class ManagementServerImpl implements ManagementServer { Transaction txn = Transaction.currentTxn(); try{ txn.start(); - VlanVO vlan = _configMgr.createVlanAndPublicIpRange(userId, vlanType, zoneId, accountId, podId, vlanId, vlanGateway, vlanNetmask, startIP, endIP); + VlanVO vlan = _configMgr.createVlanAndPublicIpRange(userId, vlanType, zoneId, accountId, podId, vlanId, vlanGateway, vlanNetmask, startIP, endIP, null); associateIpAddressListToAccount(userId, accountId, zoneId, vlan.getId()); txn.commit(); return vlan; @@ -1744,7 +1744,7 @@ public class ManagementServerImpl implements ManagementServer { throw new Exception(e.getMessage()); } } - return _configMgr.createVlanAndPublicIpRange(userId, vlanType, zoneId, accountId, podId, vlanId, vlanGateway, vlanNetmask, startIP, endIP); + return _configMgr.createVlanAndPublicIpRange(userId, vlanType, zoneId, accountId, podId, vlanId, vlanGateway, vlanNetmask, startIP, endIP, domainId); } @Override @@ -3820,6 +3820,7 @@ public class ManagementServerImpl implements ManagementServer { //if account doesn't have direct ip addresses and there are no direct Zone wide vlans, return virtual service offerings only //If untagged network is enabled, return only direct service offerings List accountDirectVlans = new ArrayList(); + Map> domainDirectVlans = new HashMap>(); List zoneDirectVlans = new ArrayList(); boolean isDirectUntaggedNetworkEnabled = new Boolean(_configDao.getValue("direct.attach.untagged.vlan.enabled")); @@ -3828,9 +3829,11 @@ public class ManagementServerImpl implements ManagementServer { sc.addAnd("guestIpType", SearchCriteria.Op.EQ, GuestIpType.DirectSingle); } else { if (accountId != null && zoneId != null) { - accountDirectVlans = _vlanDao.listVlansForAccountByType(null, ((Long)accountId).longValue(), VlanType.DirectAttached); + AccountVO account = _accountDao.findById((Long)accountId); + accountDirectVlans = _vlanDao.listVlansForAccountByType((Long)zoneId, ((Long)accountId).longValue(), VlanType.DirectAttached); + domainDirectVlans = _configMgr.listDomainDirectVlans(account.getDomainId(), (Long)zoneId); zoneDirectVlans = listZoneWideVlansByType(VlanType.DirectAttached, (Long)zoneId); - if (accountDirectVlans.isEmpty() && zoneDirectVlans.isEmpty()) { + if (accountDirectVlans.isEmpty() && domainDirectVlans.isEmpty() && zoneDirectVlans.isEmpty()) { sc.addAnd("guestIpType", SearchCriteria.Op.EQ, GuestIpType.Virtualized); } } else if (zoneId != null) { @@ -6243,6 +6246,26 @@ public class ManagementServerImpl implements ManagementServer { } } } + + //delete domain specific vlans + List domainVlans = _vlanDao.listVlansForDomainByTypeAndZone(null, domainId, VlanType.DirectAttached); + s_logger.debug("Found " + domainVlans.size() + " vlans to cleanup as a part of domain id=" + domainId + " cleanup."); + boolean allVlansDeleted = true; + for (VlanVO vlan : domainVlans) { + try { + allVlansDeleted = _configMgr.deleteVlanAndPublicIpRange(User.UID_SYSTEM, vlan.getId()); + } catch (Exception e) { + s_logger.warn("Failed to delete vlan id=" + vlan.getId() + " as a part of domain cleanup due to exception: ", e); + allVlansDeleted = false; + } + } + + if (!allVlansDeleted) { + s_logger.warn("Failed to cleanup domain specific vlans as a part of domain cleanup"); + success = false; + } else { + s_logger.debug("Successfully deleted vlans as a part of domain id=" + domainId + " cleanup."); + } // delete the domain itself boolean deleteDomainSuccess = _domainDao.remove(domainId); @@ -8433,5 +8456,15 @@ public class ManagementServerImpl implements ManagementServer { } return _hashKey; } + + @Override + public Long getDomainIdForVlan(long vlanDbId) { + List accountVlanMaps = _accountVlanMapDao.listAccountVlanMapsByVlan(vlanDbId); + if (accountVlanMaps.isEmpty()) { + return null; + } else { + return accountVlanMaps.get(0).getDomainId(); + } + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 9b8cf2a61b1..cdbf4c7d976 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -77,6 +77,7 @@ import com.cloud.async.executor.VMOperationListener; import com.cloud.async.executor.VMOperationParam; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; +import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ResourceLimitDao; @@ -88,6 +89,7 @@ import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventState; import com.cloud.event.EventTypes; @@ -227,6 +229,7 @@ public class UserVmManagerImpl implements UserVmManager { @Inject StoragePoolDao _storagePoolDao; @Inject VMTemplateHostDao _vmTemplateHostDao; @Inject NetworkGroupManager _networkGroupManager; + @Inject ConfigurationManager _configMgr; @Inject ServiceOfferingDao _serviceOfferingDao; @Inject EventDao _eventDao = null; private IpAddrAllocator _IpAllocator; @@ -2485,28 +2488,37 @@ public class UserVmManagerImpl implements UserVmManager { Set avoids = new HashSet(); VlanVO guestVlan = null; List vlansForAccount = _vlanDao.listVlansForAccountByType(dc.getId(), account.getId(), VlanType.DirectAttached); + Map> vlansForDomain = _configMgr.listDomainDirectVlans(account.getDomainId(), dc.getId()); List vlansForPod = null; List zoneWideVlans = null; int freeIpCount = 0; boolean forAccount = false; + boolean forDomain = false; if (vlansForAccount.size() > 0) { //iterate over the vlan to see if there are actually addresses available - for(VlanVO vlan:vlansForAccount) - { + for(VlanVO vlan : vlansForAccount) { freeIpCount = (_ipAddressDao.countIPs(dc.getId(), vlan.getId(), false) - _ipAddressDao.countIPs(dc.getId(), vlan.getId(), true)); - if(freeIpCount>0) - { + if(freeIpCount>0) { forAccount = true; guestVlan = vlan; + s_logger.debug("Found account specific guest vlan id=" + guestVlan.getId() + " for vm deployment"); break; } } - + } + + if (!forAccount && vlansForDomain != null && !vlansForDomain.isEmpty()) { + guestVlan = getDomainDirectVlan(account.getDomainId(), dc); + + if (guestVlan != null) { + s_logger.debug("Found domain level vlan id=" + guestVlan.getId() + " for vm deployment"); + forDomain = true; + } } - if(!forAccount) + if(!forAccount && !forDomain) { //list zone wide vlans that are direct attached and tagged //if exists pick random one @@ -2537,7 +2549,7 @@ public class UserVmManagerImpl implements UserVmManager { s_logger.debug("Attempting to create direct attached vm in pod " + pod.first().getName()); } avoids.add(pod.first().getId()); - if (!forAccount && !forZone) { + if (!forAccount && !forDomain && !forZone) { vlansForPod = _vlanDao.listVlansForPodByType(pod.first().getId(), VlanType.DirectAttached); if (vlansForPod.size() < 1) { if (s_logger.isDebugEnabled()) { @@ -2548,6 +2560,11 @@ public class UserVmManagerImpl implements UserVmManager { guestVlan = vlansForPod.get(0);//FIXME: iterate over all vlans } + if (guestVlan == null) { + s_logger.debug("Unable to find Direct IP address in the pod id=" + pod.first().getId() + " to use for vm deployment for account id=" + account.getId() + "; checking other pods"); + continue; + } + List rtrs = _routerDao.listByVlanDbId(guestVlan.getId()); assert rtrs.size() < 2 : "How did we get more than one router per vlan?"; if (rtrs.size() > 0) { @@ -2564,43 +2581,56 @@ public class UserVmManagerImpl implements UserVmManager { routerId = router.getId(); } - String guestIp = null; - if(forAccount) - { - for(VlanVO vlanForAcc : vlansForAccount) - { - guestIp = _ipAddressDao.assignIpAddress(accountId, account.getDomainId(), vlanForAcc.getId(), false); - if(guestIp!=null) - break; //got an ip - } - } - else if(!forAccount && !forZone) - { - //i.e. for pod - for(VlanVO vlanForPod : vlansForPod) - { - guestIp = _ipAddressDao.assignIpAddress(accountId, account.getDomainId(), vlanForPod.getId(), false); - if(guestIp!=null) - break;//got an ip - } - } - else - { - //for zone - for(VlanVO vlanForZone : zoneWideVlans) - { - guestIp = _ipAddressDao.assignIpAddress(accountId, account.getDomainId().longValue(), vlanForZone.getId(), false); - if(guestIp!=null) - break;//found an ip - } + //First try to get guest ip address from the guest vlan; if the operation fails, go through account/domain/pod/zone specific vlans again + guestIp = _ipAddressDao.assignIpAddress(accountId, account.getDomainId(), guestVlan.getId(), false); + if (guestIp == null) { + + if (forAccount) { + for(VlanVO vlanForAcc : vlansForAccount) { + guestIp = _ipAddressDao.assignIpAddress(accountId, account.getDomainId(), vlanForAcc.getId(), false); + if(guestIp != null) + break; //got an ip + } + } else if (forDomain) { + if (vlansForDomain != null && !vlansForDomain.isEmpty()) { + guestIp = getDomainDirectIp(account.getDomainId(), dc, account); + + if(guestIp != null) { + break; //got an ip + } + + } + + } else if(!forAccount && !forDomain && !forZone) { + //i.e. for pod + for(VlanVO vlanForPod : vlansForPod) + { + guestIp = _ipAddressDao.assignIpAddress(accountId, account.getDomainId(), vlanForPod.getId(), false); + if(guestIp!=null) + break;//got an ip + } + } else { + //for zone + for(VlanVO vlanForZone : zoneWideVlans) + { + guestIp = _ipAddressDao.assignIpAddress(accountId, account.getDomainId().longValue(), vlanForZone.getId(), false); + if(guestIp!=null) + break;//found an ip + } + } } + VlanVO guestIpVlan = null; if (guestIp == null) { s_logger.debug("No guest IP available in pod id=" + pod.first().getId()); continue; + } else { + IPAddressVO ip = _ipAddressDao.findById(guestIp); + guestIpVlan = _vlanDao.findById(ip.getVlanDbId()); } + s_logger.debug("Acquired a guest IP, ip=" + guestIp); String guestMacAddress = macAddresses[0]; String externalMacAddress = macAddresses[1]; @@ -2621,7 +2651,7 @@ public class UserVmManagerImpl implements UserVmManager { vm = _vmDao.persist(vm); */ vm.setDomainRouterId(routerId); - vm.setGuestNetmask(guestVlan.getVlanNetmask()); + vm.setGuestNetmask(guestIpVlan.getVlanNetmask()); vm.setGuestIpAddress(guestIp); vm.setGuestMacAddress(guestMacAddress); vm.setPodId(pod.first().getId()); @@ -3010,6 +3040,56 @@ public class UserVmManagerImpl implements UserVmManager { return usedCapacity; } + + + protected VlanVO getDomainDirectVlan(long domainId, DataCenterVO dc) { + //Domain level vlans include: + //* vlans belonging to this domain + //* vlans belonging to all parent domains + + DomainVO domain = _domainDao.findById(domainId); + VlanVO guestVlan = null; + + List vlansForDomain = _vlanDao.listVlansForDomainByTypeAndZone(dc.getId(), domainId, VlanType.DirectAttached); + for(VlanVO vlan : vlansForDomain) { + long freeIpCount = (_ipAddressDao.countIPs(dc.getId(), vlan.getId(), false) - _ipAddressDao.countIPs(dc.getId(), vlan.getId(), true)); + + if(freeIpCount>0) { + guestVlan = vlan; + break; + } + } + + if (guestVlan == null && domain.getParent() != null) { + guestVlan = getDomainDirectVlan(domain.getParent(), dc); + } + + return guestVlan; + } + + protected String getDomainDirectIp(long domainId, DataCenterVO dc, AccountVO account) { + //Domain level ips include: + //* ips belonging to vlans of this domain + //* ips belonging to vlans belonging to all parent domains + + DomainVO domain = _domainDao.findById(domainId); + String guestIp = null; + + List vlansForDomain = _vlanDao.listVlansForDomainByTypeAndZone(dc.getId(), domainId, VlanType.DirectAttached); + for(VlanVO vlan : vlansForDomain) { + guestIp = _ipAddressDao.assignIpAddress(account.getId(), account.getDomainId(), vlan.getId(), false); + if(guestIp != null) { + s_logger.debug("Got direct ip address " + guestIp + " from domain level vlan id=" + vlan.getId() + " for vm deployment"); + break; //got an ip + } + } + + if (guestIp == null && domain.getParent() != null) { + guestIp = getDomainDirectIp(domain.getParent(), dc, account); + } + + return guestIp; + } } diff --git a/setup/db/create-index-fk.sql b/setup/db/create-index-fk.sql index fb73534b192..09115189dcf 100644 --- a/setup/db/create-index-fk.sql +++ b/setup/db/create-index-fk.sql @@ -167,6 +167,9 @@ ALTER TABLE `cloud`.`pod_vlan_map` ADD INDEX `i_pod_vlan_map__vlan_id`(`vlan_db_ ALTER TABLE `cloud`.`account_vlan_map` ADD CONSTRAINT `fk_account_vlan_map__account_id` FOREIGN KEY `fk_account_vlan_map__account_id` (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE; ALTER TABLE `cloud`.`account_vlan_map` ADD INDEX `i_account_vlan_map__account_id`(`account_id`); +ALTER TABLE `cloud`.`account_vlan_map` ADD CONSTRAINT `fk_account_vlan_map__domain_id` FOREIGN KEY `fk_account_vlan_map__domain_id` (`domain_id`) REFERENCES `domain` (`id`) ON DELETE CASCADE; +ALTER TABLE `cloud`.`account_vlan_map` ADD INDEX `i_account_vlan_map__domain_id`(`domain_id`); + ALTER TABLE `cloud`.`account_vlan_map` ADD CONSTRAINT `fk_account_vlan_map__vlan_id` FOREIGN KEY `fk_account_vlan_map__vlan_id` (`vlan_db_id`) REFERENCES `vlan` (`id`) ON DELETE CASCADE; ALTER TABLE `cloud`.`account_vlan_map` ADD INDEX `i_account_vlan_map__vlan_id`(`vlan_db_id`); diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 36c193498c9..f8eecfe6bb5 100644 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -242,8 +242,9 @@ CREATE TABLE `cloud`.`pod_vlan_map` ( CREATE TABLE `cloud`.`account_vlan_map` ( `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, - `account_id` bigint unsigned NOT NULL COMMENT 'account id. foreign key to account table', + `account_id` bigint unsigned COMMENT 'account id. foreign key to account table', `vlan_db_id` bigint unsigned NOT NULL COMMENT 'database id of vlan. foreign key to vlan table', + `domain_id` bigint unsigned COMMENT 'domain id. foreign key to domain table', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;