Skip to content

Commit d077b3e

Browse files
authored
Merge pull request apache#2004 from nuagenetworks/feature/vr_without_public_ip
CLOUDSTACK-9832: Do not assign public IP NIC to the VPC VR when the VPC offering does not contain VpcVirtualRouter as a SourceNat provider
2 parents 2139dbe + 1d382e0 commit d077b3e

11 files changed

Lines changed: 292 additions & 96 deletions

File tree

engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ NicProfile prepareNic(VirtualMachineProfile vmProfile, DeployDestination dest, R
189189
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException,
190190
ResourceUnavailableException;
191191

192+
/**
193+
* Removes the provided nic from the given vm
194+
* @param vm
195+
* @param nic
196+
*/
192197
void removeNic(VirtualMachineProfile vm, Nic nic);
193198

194199
/**

engine/components-api/src/com/cloud/network/vpc/VpcManager.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,11 @@ public interface VpcManager {
165165
validateNtwkOffForNtwkInVpc(Long networkId, long newNtwkOffId, String newCidr, String newNetworkDomain, Vpc vpc, String gateway, Account networkOwner, Long aclId);
166166

167167
List<PrivateGateway> getVpcPrivateGateways(long vpcId);
168+
169+
/**
170+
* Checks if the specified offering needs a public src nat ip or not.
171+
* @param vpcOfferingId
172+
* @return
173+
*/
174+
boolean isSrcNatIpRequired(long vpcOfferingId);
168175
}

server/src/com/cloud/network/router/VpcNetworkHelperImpl.java

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.Arrays;
2222
import java.util.LinkedHashMap;
2323
import java.util.List;
24+
import java.util.Map;
25+
import java.util.Set;
2426
import java.util.TreeSet;
2527

2628
import javax.annotation.PostConstruct;
@@ -83,7 +85,10 @@ public void reallocateRouterNetworks(final RouterDeploymentDefinition vpcRouterD
8385
throws ConcurrentOperationException, InsufficientCapacityException {
8486

8587
final TreeSet<String> publicVlans = new TreeSet<String>();
86-
publicVlans.add(vpcRouterDeploymentDefinition.getSourceNatIP().getVlanTag());
88+
if (vpcRouterDeploymentDefinition.isPublicNetwork()) {
89+
publicVlans.add(vpcRouterDeploymentDefinition.getSourceNatIP()
90+
.getVlanTag());
91+
}
8792

8893
//1) allocate nic for control and source nat public ip
8994
final LinkedHashMap<Network, List<? extends NicProfile>> networks = configureDefaultNics(vpcRouterDeploymentDefinition);
@@ -115,43 +120,51 @@ public void reallocateRouterNetworks(final RouterDeploymentDefinition vpcRouterD
115120
final List<IPAddressVO> ips = _ipAddressDao.listByAssociatedVpc(vpcId, false);
116121
final List<NicProfile> publicNics = new ArrayList<NicProfile>();
117122
Network publicNetwork = null;
123+
final Map<Network.Service, Set<Network.Provider>> vpcOffSvcProvidersMap = vpcMgr.getVpcOffSvcProvidersMap(vpcRouterDeploymentDefinition.getVpc().getVpcOfferingId());
124+
125+
boolean vpcIsStaticNatProvider = vpcOffSvcProvidersMap.get(Network.Service.StaticNat) != null &&
126+
vpcOffSvcProvidersMap.get(Network.Service.StaticNat).contains(Network.Provider.VPCVirtualRouter);
127+
128+
final ServiceOfferingVO routerOffering = _serviceOfferingDao.findById(vpcRouterDeploymentDefinition.getServiceOfferingId());
129+
118130
for (final IPAddressVO ip : ips) {
119-
final PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId()));
120-
if ((ip.getState() == IpAddress.State.Allocated || ip.getState() == IpAddress.State.Allocating) && vpcMgr.isIpAllocatedToVpc(ip) &&
121-
!publicVlans.contains(publicIp.getVlanTag())) {
122-
s_logger.debug("Allocating nic for router in vlan " + publicIp.getVlanTag());
123-
final NicProfile publicNic = new NicProfile();
124-
publicNic.setDefaultNic(false);
125-
publicNic.setIPv4Address(publicIp.getAddress().addr());
126-
publicNic.setIPv4Gateway(publicIp.getGateway());
127-
publicNic.setIPv4Netmask(publicIp.getNetmask());
128-
publicNic.setMacAddress(publicIp.getMacAddress());
129-
publicNic.setBroadcastType(BroadcastDomainType.Vlan);
130-
publicNic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(publicIp.getVlanTag()));
131-
publicNic.setIsolationUri(IsolationType.Vlan.toUri(publicIp.getVlanTag()));
132-
final NetworkOffering publicOffering = _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork).get(0);
133-
if (publicNetwork == null) {
134-
final List<? extends Network> publicNetworks = _networkMgr.setupNetwork(s_systemAccount, publicOffering, vpcRouterDeploymentDefinition.getPlan(), null, null, false);
135-
publicNetwork = publicNetworks.get(0);
131+
if (vpcIsStaticNatProvider || !ip.isOneToOneNat()) {
132+
final PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId()));
133+
if ((ip.getState() == IpAddress.State.Allocated || ip.getState() == IpAddress.State.Allocating)
134+
&& vpcMgr.isIpAllocatedToVpc(ip)
135+
&& !publicVlans.contains(publicIp.getVlanTag())) {
136+
s_logger.debug("Allocating nic for router in vlan " + publicIp.getVlanTag());
137+
final NicProfile publicNic = new NicProfile();
138+
publicNic.setDefaultNic(false);
139+
publicNic.setIPv4Address(publicIp.getAddress()
140+
.addr());
141+
publicNic.setIPv4Gateway(publicIp.getGateway());
142+
publicNic.setIPv4Netmask(publicIp.getNetmask());
143+
publicNic.setMacAddress(publicIp.getMacAddress());
144+
publicNic.setBroadcastType(BroadcastDomainType.Vlan);
145+
publicNic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(publicIp.getVlanTag()));
146+
publicNic.setIsolationUri(IsolationType.Vlan.toUri(publicIp.getVlanTag()));
147+
final NetworkOffering publicOffering = _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork)
148+
.get(0);
149+
if (publicNetwork == null) {
150+
final List<? extends Network> publicNetworks = _networkMgr.setupNetwork(s_systemAccount, publicOffering, vpcRouterDeploymentDefinition.getPlan(), null, null, false);
151+
publicNetwork = publicNetworks.get(0);
152+
}
153+
publicNics.add(publicNic);
154+
publicVlans.add(publicIp.getVlanTag());
136155
}
137-
publicNics.add(publicNic);
138-
publicVlans.add(publicIp.getVlanTag());
139156
}
140-
}
141-
if (publicNetwork != null) {
142-
if (networks.get(publicNetwork) != null) {
143-
@SuppressWarnings("unchecked")
144-
final
145-
List<NicProfile> publicNicProfiles = (List<NicProfile>)networks.get(publicNetwork);
146-
publicNicProfiles.addAll(publicNics);
147-
networks.put(publicNetwork, publicNicProfiles);
148-
} else {
149-
networks.put(publicNetwork, publicNics);
157+
if (publicNetwork != null) {
158+
if (networks.get(publicNetwork) != null) {
159+
@SuppressWarnings("unchecked") final List<NicProfile> publicNicProfiles = (List<NicProfile>)networks.get(publicNetwork);
160+
publicNicProfiles.addAll(publicNics);
161+
networks.put(publicNetwork, publicNicProfiles);
162+
} else {
163+
networks.put(publicNetwork, publicNics);
164+
}
150165
}
151166
}
152167

153-
final ServiceOfferingVO routerOffering = _serviceOfferingDao.findById(vpcRouterDeploymentDefinition.getServiceOfferingId());
154-
155168
_itMgr.allocate(router.getInstanceName(), template, routerOffering, networks, vpcRouterDeploymentDefinition.getPlan(), hType);
156169
}
157170

server/src/com/cloud/network/vpc/VpcManagerImpl.java

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,12 @@
4343
import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd;
4444
import org.apache.cloudstack.context.CallContext;
4545
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
46-
import org.apache.cloudstack.framework.config.ConfigDepot;
4746
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
4847
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
4948
import org.apache.commons.collections.CollectionUtils;
5049
import org.apache.log4j.Logger;
5150

5251
import com.cloud.configuration.Config;
53-
import com.cloud.configuration.ConfigurationManager;
5452
import com.cloud.configuration.Resource.ResourceType;
5553
import com.cloud.dc.DataCenter;
5654
import com.cloud.dc.DataCenterVO;
@@ -88,8 +86,6 @@
8886
import com.cloud.network.dao.IPAddressVO;
8987
import com.cloud.network.dao.NetworkDao;
9088
import com.cloud.network.dao.NetworkVO;
91-
import com.cloud.network.dao.PhysicalNetworkDao;
92-
import com.cloud.network.dao.Site2SiteVpnGatewayDao;
9389
import com.cloud.network.element.NetworkElement;
9490
import com.cloud.network.element.StaticNatServiceProvider;
9591
import com.cloud.network.element.VpcProvider;
@@ -108,7 +104,6 @@
108104
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
109105
import com.cloud.org.Grouping;
110106
import com.cloud.projects.Project.ListProjectResourcesCriteria;
111-
import com.cloud.server.ConfigurationServer;
112107
import com.cloud.server.ResourceTag.ResourceObjectType;
113108
import com.cloud.tags.ResourceTagVO;
114109
import com.cloud.tags.dao.ResourceTagDao;
@@ -140,7 +135,6 @@
140135
import com.cloud.utils.net.NetUtils;
141136
import com.cloud.vm.ReservationContext;
142137
import com.cloud.vm.ReservationContextImpl;
143-
import com.cloud.vm.dao.DomainRouterDao;
144138

145139
public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvisioningService, VpcService {
146140
private static final Logger s_logger = Logger.getLogger(VpcManagerImpl.class);
@@ -162,8 +156,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
162156
@Inject
163157
ConfigurationDao _configDao;
164158
@Inject
165-
ConfigurationManager _configMgr;
166-
@Inject
167159
AccountManager _accountMgr;
168160
@Inject
169161
NetworkDao _ntwkDao;
@@ -176,8 +168,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
176168
@Inject
177169
IPAddressDao _ipAddressDao;
178170
@Inject
179-
DomainRouterDao _routerDao;
180-
@Inject
181171
VpcGatewayDao _vpcGatewayDao;
182172
@Inject
183173
PrivateIpDao _privateIpDao;
@@ -188,14 +178,10 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
188178
@Inject
189179
VpcOfferingServiceMapDao _vpcOffServiceDao;
190180
@Inject
191-
PhysicalNetworkDao _pNtwkDao;
192-
@Inject
193181
ResourceTagDao _resourceTagDao;
194182
@Inject
195183
FirewallRulesDao _firewallDao;
196184
@Inject
197-
Site2SiteVpnGatewayDao _vpnGatewayDao;
198-
@Inject
199185
Site2SiteVpnManager _s2sVpnMgr;
200186
@Inject
201187
VlanDao _vlanDao = null;
@@ -206,17 +192,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
206192
@Inject
207193
DataCenterDao _dcDao;
208194
@Inject
209-
ConfigurationServer _configServer;
210-
@Inject
211195
NetworkACLDao _networkAclDao;
212196
@Inject
213-
NetworkACLItemDao _networkACLItemDao;
214-
@Inject
215197
NetworkACLManager _networkAclMgr;
216198
@Inject
217199
IpAddressManager _ipAddrMgr;
218-
@Inject
219-
ConfigDepot _configDepot;
220200

221201
@Inject
222202
private VpcPrivateGatewayTransactionCallable vpcTxCallable;
@@ -2266,14 +2246,9 @@ public IpAddress associateIPToVpc(final long ipId, final long vpcId) throws Reso
22662246
// check permissions
22672247
_accountMgr.checkAccess(caller, null, true, owner, vpc);
22682248

2269-
boolean isSourceNat = false;
2270-
if (getExistingSourceNatInVpc(owner.getId(), vpcId) == null) {
2271-
isSourceNat = true;
2272-
}
2273-
22742249
s_logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc);
22752250

2276-
final boolean isSourceNatFinal = isSourceNat;
2251+
final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(owner.getId(), vpcId) == null;
22772252
Transaction.execute(new TransactionCallbackNoReturn() {
22782253
@Override
22792254
public void doInTransactionWithoutResult(final TransactionStatus status) {
@@ -2449,4 +2424,10 @@ public boolean applyStaticRoute(final long routeId) throws ResourceUnavailableEx
24492424
final StaticRoute route = _staticRouteDao.findById(routeId);
24502425
return applyStaticRoutesForVpc(route.getVpcId());
24512426
}
2427+
2428+
@Override
2429+
public boolean isSrcNatIpRequired(long vpcOfferingId) {
2430+
final Map<Network.Service, Set<Network.Provider>> vpcOffSvcProvidersMap = getVpcOffSvcProvidersMap(vpcOfferingId);
2431+
return vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter);
2432+
}
24522433
}

server/src/org/cloud/network/router/deployment/VpcRouterDeploymentDefinition.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,6 @@ public boolean isVpcRouter() {
7272
return true;
7373
}
7474

75-
@Override
76-
public boolean isPublicNetwork() {
77-
return true;
78-
}
79-
8075
@Override
8176
protected void lock() {
8277
final Vpc vpcLock = vpcDao.acquireInLockTable(vpc.getId());
@@ -115,12 +110,19 @@ protected List<DeployDestination> findDestinations() {
115110
*/
116111
@Override
117112
protected boolean prepareDeployment() {
113+
//Check if the VR is the src NAT provider...
114+
isPublicNetwork = vpcMgr.isSrcNatIpRequired(vpc.getVpcOfferingId());
115+
116+
// Check if public network has to be set on VR
118117
return true;
119118
}
120119

121120
@Override
122121
protected void findSourceNatIP() throws InsufficientAddressCapacityException, ConcurrentOperationException {
123-
sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc);
122+
sourceNatIp = null;
123+
if (isPublicNetwork) {
124+
sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc);
125+
}
124126
}
125127

126128
@Override

server/test/org/cloud/network/router/deployment/VpcRouterDeploymentDefinitionTest.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,30 @@ public void testGetNumberOfRoutersToDeploy() {
168168
assertEquals("If there is already a router found, there is no need to deploy more", 0, deployment.getNumberOfRoutersToDeploy());
169169
}
170170

171+
protected void driveTestPrepareDeployment(final boolean isRedundant, final boolean isPublicNw) {
172+
// Prepare
173+
when(vpcMgr.isSrcNatIpRequired(mockVpc.getVpcOfferingId())).thenReturn(isPublicNw);
174+
175+
// Execute
176+
final boolean canProceedDeployment = deployment.prepareDeployment();
177+
// Assert
178+
assertTrue("There are no preconditions for Vpc Deployment, thus it should always pass", canProceedDeployment);
179+
assertEquals(isPublicNw, deployment.isPublicNetwork());
180+
}
181+
182+
@Test
183+
public void testPrepareDeploymentPublicNw() {
184+
driveTestPrepareDeployment(true, true);
185+
}
186+
187+
@Test
188+
public void testPrepareDeploymentNonRedundant() {
189+
driveTestPrepareDeployment(false, true);
190+
}
191+
171192
@Test
172-
public void testPrepareDeployment() {
173-
assertTrue("There are no preconditions for Vpc Deployment, thus it should always pass", deployment.prepareDeployment());
193+
public void testPrepareDeploymentRedundantNonPublicNw() {
194+
driveTestPrepareDeployment(true, false);
174195
}
175196

176197
@Test
@@ -246,6 +267,7 @@ public void testFindSourceNatIP() throws InsufficientAddressCapacityException, C
246267
// Prepare
247268
final PublicIp publicIp = mock(PublicIp.class);
248269
when(vpcMgr.assignSourceNatIpAddressToVpc(mockOwner, mockVpc)).thenReturn(publicIp);
270+
deployment.isPublicNetwork = true;
249271

250272
// Execute
251273
deployment.findSourceNatIP();

test/integration/plugins/nuagevsp/nuageTestCase.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,34 @@ def validate_PublicIPAddress(self, public_ip, network, static_nat=False,
849849
self.debug("Successfully validated the assignment and state of public "
850850
"IP address - %s" % public_ip.ipaddress.ipaddress)
851851

852+
# verify_VRWithoutPublicIPNIC - Verifies that the given Virtual Router has
853+
# no public IP and NIC
854+
def verify_VRWithoutPublicIPNIC(self, vr):
855+
"""Verifies VR without Public IP and NIC"""
856+
self.debug("Verifies that there is no public IP and NIC in Virtual "
857+
"Router - %s" % vr.name)
858+
self.assertEqual(vr.publicip, None,
859+
"Virtual router has public IP"
860+
)
861+
for nic in vr.nic:
862+
self.assertNotEqual(nic.traffictype, "Public",
863+
"Virtual router has public NIC"
864+
)
865+
self.debug("Successfully verified that there is no public IP and NIC "
866+
"in Virtual Router - %s" % vr.name)
867+
868+
def verify_vpc_has_no_src_nat(self, vpc, account=None):
869+
if not account:
870+
account = self.account
871+
self.debug("Verify that there is no src NAT ip address "
872+
"allocated for the vpc")
873+
src_nat_ip = PublicIPAddress.list(
874+
self.api_client,
875+
vpcid=vpc.id,
876+
issourcenat=True,
877+
account=account.name)
878+
self.assertEqual(src_nat_ip, None, "VPC has a source NAT ip!")
879+
852880
# VSD verifications; VSD is a programmable policy and analytics engine of
853881
# Nuage VSP SDN platform
854882

@@ -985,10 +1013,10 @@ def verify_vsd_object_status(self, cs_object, stopped):
9851013
expected_status = cs_object.state.upper() if not stopped \
9861014
else "DELETE_PENDING"
9871015
tries = 0
988-
while (vsd_object.status != expected_status) and (tries < 10):
1016+
while (vsd_object.status != expected_status) and (tries < 120):
9891017
self.debug("Waiting for the CloudStack object " + cs_object.name +
9901018
" to be fully resolved in VSD...")
991-
time.sleep(30)
1019+
time.sleep(5)
9921020
self.debug("Rechecking the CloudStack object " + cs_object.name +
9931021
" status in VSD...")
9941022
vsd_object = self.vsd.get_vm(

0 commit comments

Comments
 (0)