From 6e3495f535c86c1d3e1e0f3971335aef796d824f Mon Sep 17 00:00:00 2001 From: niteshsarda Date: Tue, 19 Dec 2017 14:39:34 +0530 Subject: [PATCH] CLOUDSTACK-10190: Duplicate public VLAN for two different admin accounts (#2361) ISSUE : Duplicate public VLAN for two different admin accounts. STEPS TO REPRODUCE : Start multiple threads for executing createVlanIpRange API. Make sure multiple threads run in parallel. Verify vlan table in DB, duplicate entry for same VLAN and IP address range will be encountered, just id and uuid will be different, rest all fields will have similar value. Following entry will be observed in vlan table : `mysql> select * from vlan where vlan_id like 'vlan://77' and removed is null; +----+--------------------------------------+-----------+--------------+-----------------+---------------------------+----------------+----------------+------------+---------------------+-------------+----------+-----------+---------+---------------------+ | id | uuid | vlan_id | vlan_gateway | vlan_netmask | description | vlan_type | data_center_id | network_id | physical_network_id | ip6_gateway | ip6_cidr | ip6_range | removed | created | +----+--------------------------------------+-----------+--------------+-----------------+---------------------------+----------------+----------------+------------+---------------------+-------------+----------+-----------+---------+---------------------+ | 15 | 6a205b78-d162-43e3-8da9-86a3ff60f40e | vlan://77 | 10.112.63.65 | 255.255.255.192 | 10.112.63.66-10.112.63.70 | VirtualNetwork | 1 | 200 | 200 | NULL | NULL | NULL | NULL | 2017-12-13 12:55:51 | | 17 | ff8b5175-b247-45a5-b8d3-feb6a1ca64d0 | vlan://77 | 10.112.63.65 | 255.255.255.192 | 10.112.63.66-10.112.63.70 | VirtualNetwork | 1 | 200 | 200 | NULL | NULL | NULL | NULL | 2017-12-13 12:55:51 | +----+--------------------------------------+-----------+--------------+-----------------+---------------------------+----------------+----------------+------------+---------------------+-------------+----------+-----------+---------+---------------------+ --- .../ConfigurationManagerImpl.java | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 6dab97ae1ed..1bf807af7ea 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2859,35 +2859,42 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal, final String vlanId, final Boolean forVirtualNetwork, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6, final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair> sameSubnet) { - return Transaction.execute(new TransactionCallback() { - @Override - public Vlan doInTransaction(final TransactionStatus status) { - String newVlanNetmask = newVlanNetmaskFinal; - String newVlanGateway = newVlanGatewayFinal; + final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan"); + commitVlanLock.lock(5); + s_logger.debug("Acquiring lock for committing vlan"); + try { + return Transaction.execute(new TransactionCallback() { + @Override + public Vlan doInTransaction(final TransactionStatus status) { + String newVlanNetmask = newVlanNetmaskFinal; + String newVlanGateway = newVlanGatewayFinal; - if ((sameSubnet == null || !sameSubnet.first()) && network.getTrafficType() == TrafficType.Guest && network.getGuestType() == GuestType.Shared - && _vlanDao.listVlansByNetworkId(networkId) != null) { - final Map dhcpCapabilities = _networkSvc.getNetworkOfferingServiceCapabilities(_networkOfferingDao.findById(network.getNetworkOfferingId()), + if ((sameSubnet == null || !sameSubnet.first()) && network.getTrafficType() == TrafficType.Guest && network.getGuestType() == GuestType.Shared + && _vlanDao.listVlansByNetworkId(networkId) != null) { + final Map dhcpCapabilities = _networkSvc.getNetworkOfferingServiceCapabilities(_networkOfferingDao.findById(network.getNetworkOfferingId()), Service.Dhcp); - final String supportsMultipleSubnets = dhcpCapabilities.get(Capability.DhcpAccrossMultipleSubnets); - if (supportsMultipleSubnets == null || !Boolean.valueOf(supportsMultipleSubnets)) { - throw new InvalidParameterValueException("The dhcp service provider for this network does not support dhcp across multiple subnets"); + final String supportsMultipleSubnets = dhcpCapabilities.get(Capability.DhcpAccrossMultipleSubnets); + if (supportsMultipleSubnets == null || !Boolean.valueOf(supportsMultipleSubnets)) { + throw new InvalidParameterValueException("The dhcp service provider for this network does not support dhcp across multiple subnets"); + } + s_logger.info("adding a new subnet to the network " + network.getId()); + } else if (sameSubnet != null) { + // if it is same subnet the user might not send the vlan and the + // netmask details. so we are + // figuring out while validation and setting them here. + newVlanGateway = sameSubnet.second().first(); + newVlanNetmask = sameSubnet.second().second(); } - s_logger.info("adding a new subnet to the network " + network.getId()); - } else if (sameSubnet != null) { - // if it is same subnet the user might not send the vlan and the - // netmask details. so we are - // figuring out while validation and setting them here. - newVlanGateway = sameSubnet.second().first(); - newVlanNetmask = sameSubnet.second().second(); + final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, + false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr); + // create an entry in the nic_secondary table. This will be the new + // gateway that will be configured on the corresponding routervm. + return vlan; } - final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, - false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr); - // create an entry in the nic_secondary table. This will be the new - // gateway that will be configured on the corresponding routervm. - return vlan; - } - }); + }); + } finally { + commitVlanLock.unlock(); + } } public NetUtils.SupersetOrSubset checkIfSubsetOrSuperset(String vlanGateway, String vlanNetmask, String newVlanGateway, String newVlanNetmask, final String newStartIP, final String newEndIP) {