Skip to content

Commit a27eca3

Browse files
nvazquezPearl1594
authored andcommitted
Set up Netris Public range on new zone addition (#15)
* Set up Netris Public range on new zone addition * Add dependency to calculate subnet containing a start and end IP * Remove unused import * Move dependency to the netris module * Rename Netris IP range * Refactor logic * Revert "Refactor logic" This reverts commit 7ec36a81320444c37e7bb914dd895060b663411b. * Fix setup range after adding Netris Provider * Fix VXLAN range adding on zone creation
1 parent 4610d10 commit a27eca3

File tree

11 files changed

+305
-48
lines changed

11 files changed

+305
-48
lines changed

plugins/network-elements/netris/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,10 @@
3535
<artifactId>netris-java-sdk</artifactId>
3636
<version>1.0.0</version>
3737
</dependency>
38+
<dependency>
39+
<groupId>com.github.seancfoley</groupId>
40+
<artifactId>ipaddress</artifactId>
41+
<version>5.5.1</version>
42+
</dependency>
3843
</dependencies>
3944
</project>

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020

2121
public class NetrisCommand extends Command {
2222
private final long zoneId;
23-
private final long accountId;
24-
private final long domainId;
23+
private final Long accountId;
24+
private final Long domainId;
2525
private final String name;
2626
private final long id;
2727
private final boolean isVpc;
2828

29-
public NetrisCommand(long zoneId, long accountId, long domainId, String name, long id, boolean isVpc) {
29+
public NetrisCommand(long zoneId, Long accountId, Long domainId, String name, long id, boolean isVpc) {
3030
this.zoneId = zoneId;
3131
this.accountId = accountId;
3232
this.domainId = domainId;
@@ -48,11 +48,11 @@ public long getZoneId() {
4848
return zoneId;
4949
}
5050

51-
public long getAccountId() {
51+
public Long getAccountId() {
5252
return accountId;
5353
}
5454

55-
public long getDomainId() {
55+
public Long getDomainId() {
5656
return domainId;
5757
}
5858

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.agent.api;
18+
19+
public class SetupNetrisPublicRangeCommand extends NetrisCommand {
20+
21+
private final String superCidr;
22+
private final String exactCidr;
23+
24+
public SetupNetrisPublicRangeCommand(long zoneId, String superCidr, String exactCidr) {
25+
super(zoneId, null, null, null, zoneId, false);
26+
this.superCidr = superCidr;
27+
this.exactCidr = exactCidr;
28+
}
29+
30+
public String getSuperCidr() {
31+
return superCidr;
32+
}
33+
34+
public String getExactCidr() {
35+
return exactCidr;
36+
}
37+
}

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
3535
import org.apache.cloudstack.agent.api.NetrisAnswer;
3636
import org.apache.cloudstack.StartupNetrisCommand;
37+
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
3738
import org.apache.cloudstack.service.NetrisApiClient;
3839
import org.apache.cloudstack.service.NetrisApiClientImpl;
3940
import org.apache.logging.log4j.LogManager;
@@ -94,6 +95,8 @@ public Answer executeRequest(Command cmd) {
9495
return executeRequest((CreateNetrisVnetCommand) cmd);
9596
} else if (cmd instanceof DeleteNetrisVnetCommand) {
9697
return executeRequest((DeleteNetrisVnetCommand) cmd);
98+
} else if (cmd instanceof SetupNetrisPublicRangeCommand) {
99+
return executeRequest((SetupNetrisPublicRangeCommand) cmd);
97100
} else {
98101
return Answer.createUnsupportedCommandAnswer(cmd);
99102
}
@@ -250,6 +253,14 @@ private Answer executeRequest(DeleteNetrisVpcCommand cmd) {
250253
return new NetrisAnswer(cmd, true, "OK");
251254
}
252255

256+
private Answer executeRequest(SetupNetrisPublicRangeCommand cmd) {
257+
boolean result = netrisApiClient.setupZoneLevelPublicRange(cmd);
258+
if (!result) {
259+
return new NetrisAnswer(cmd, false, "Netris Setup for Public Range failed");
260+
}
261+
return new NetrisAnswer(cmd, true, "OK");
262+
}
263+
253264
@Override
254265
public boolean start() {
255266
return true;

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,19 @@ public enum NetrisObjectType {
2727

2828
public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, NetrisObjectType netrisObjectType, String... suffixes) {
2929
long zoneId = cmd.getZoneId();
30-
long accountId = cmd.getAccountId();
31-
long domainId = cmd.getDomainId();
30+
Long accountId = cmd.getAccountId();
31+
Long domainId = cmd.getDomainId();
3232
long objectId = cmd.getId();
3333
String objectName = cmd.getName();
3434
boolean isVpc = cmd.isVpc();
35+
boolean isZoneLevel = accountId == null && domainId == null;
3536

3637
StringBuilder stringBuilder = new StringBuilder();
37-
stringBuilder.append(String.format("D%s-A%s-Z%s", domainId, accountId, zoneId));
38+
if (isZoneLevel) {
39+
stringBuilder.append(String.format("Z%s", zoneId));
40+
} else {
41+
stringBuilder.append(String.format("D%s-A%s-Z%s", domainId, accountId, zoneId));
42+
}
3843
String prefix = isVpc ? "-V" : "-N";
3944
switch (netrisObjectType) {
4045
case VPC:
@@ -46,10 +51,14 @@ public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, NetrisO
4651
}
4752
break;
4853
case IPAM_ALLOCATION:
49-
stringBuilder.append(String.format("%s%s", prefix, objectId));
54+
if (!isZoneLevel) {
55+
stringBuilder.append(String.format("%s%s", prefix, objectId));
56+
}
5057
break;
5158
case IPAM_SUBNET:
52-
stringBuilder.append(String.format("-N%s", objectId));
59+
if (!isZoneLevel) {
60+
stringBuilder.append(String.format("-N%s", objectId));
61+
}
5362
break;
5463
case VNET:
5564
break;

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
2525
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
2626
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
27+
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
2728

2829
import java.util.List;
2930

@@ -50,4 +51,11 @@ public interface NetrisApiClient {
5051
boolean createVnet(CreateNetrisVnetCommand cmd);
5152

5253
boolean deleteVnet(DeleteNetrisVnetCommand cmd);
54+
55+
/**
56+
* Check and create zone level Netris Public range in the following manner:
57+
* - Check the IPAM allocation for the zone super CIDR. In case it doesn't exist, create it
58+
* - Check the IPAM subnet for NAT purpose for the range start-end. In case it doesn't exist, create it
59+
*/
60+
boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd);
5361
}

plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java

Lines changed: 104 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
import io.netris.model.FilterByVpc;
3434
import io.netris.model.GetSiteBody;
3535
import io.netris.model.InlineResponse2004;
36+
import io.netris.model.InlineResponse2004Data;
37+
import io.netris.model.IpTree;
38+
import io.netris.model.IpTreeAllocation;
3639
import io.netris.model.IpTreeAllocationTenant;
3740
import io.netris.model.IpTreeSubnet;
3841
import io.netris.model.IpTreeSubnetSites;
@@ -63,6 +66,7 @@
6366
import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
6467
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
6568
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
69+
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
6670
import org.apache.cloudstack.resource.NetrisResourceObjectUtils;
6771
import org.apache.commons.collections.CollectionUtils;
6872
import org.apache.logging.log4j.LogManager;
@@ -196,25 +200,31 @@ private VPCResponseObjectOK createVpcInternal(String vpcName, int adminTenantId,
196200
return response;
197201
}
198202

199-
private InlineResponse2004 createVpcAllocationInternal(VPCResponseObjectOK createdVpc, String cidr, int adminTenantId,
200-
String adminTenantName, String netrisIpamAllocationName) {
201-
logger.debug(String.format("Creating Netris VPC Allocation %s for VPC %s", cidr, createdVpc.getData().getName()));
203+
private InlineResponse2004Data createIpamAllocationInternal(String ipamName, String ipamPrefix, VPCListing vpc) {
204+
logger.debug(String.format("Creating Netris IPAM Allocation %s for VPC %s", ipamPrefix, vpc.getName()));
202205
try {
203206
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
204207
AllocationBody body = new AllocationBody();
205208
AllocationBodyVpc allocationBodyVpc = new AllocationBodyVpc();
206-
allocationBodyVpc.setId(createdVpc.getData().getId());
207-
allocationBodyVpc.setName(createdVpc.getData().getName());
209+
allocationBodyVpc.setId(vpc.getId());
210+
allocationBodyVpc.setName(vpc.getName());
208211
body.setVpc(allocationBodyVpc);
209-
body.setName(netrisIpamAllocationName);
210-
body.setPrefix(cidr);
212+
body.setName(ipamName);
213+
body.setPrefix(ipamPrefix);
211214
IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant();
212-
allocationTenant.setId(new BigDecimal(adminTenantId));
213-
allocationTenant.setName(adminTenantName);
215+
allocationTenant.setId(new BigDecimal(tenantId));
216+
allocationTenant.setName(tenantName);
214217
body.setTenant(allocationTenant);
215-
return ipamApi.apiV2IpamAllocationPost(body);
218+
InlineResponse2004 ipamResponse = ipamApi.apiV2IpamAllocationPost(body);
219+
if (ipamResponse == null || !ipamResponse.isIsSuccess()) {
220+
String reason = ipamResponse == null ? "Empty response" : "Operation failed on Netris";
221+
logger.debug("The Netris Allocation {} for VPC {} creation failed: {}", ipamPrefix, vpc.getName(), reason);
222+
return null;
223+
}
224+
logger.debug(String.format("Successfully created VPC %s and its IPAM Allocation %s on Netris", vpc.getName(), ipamPrefix));
225+
return ipamResponse.getData();
216226
} catch (ApiException e) {
217-
logAndThrowException(String.format("Error creating Netris Allocation %s for VPC %s", cidr, createdVpc.getData().getName()), e);
227+
logAndThrowException(String.format("Error creating Netris IPAM Allocation %s for VPC %s", ipamPrefix, vpc.getName()), e);
218228
return null;
219229
}
220230
}
@@ -231,14 +241,8 @@ public boolean createVpc(CreateNetrisVpcCommand cmd) {
231241

232242
String netrisIpamAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, cmd.getCidr());
233243
String vpcCidr = cmd.getCidr();
234-
InlineResponse2004 ipamResponse = createVpcAllocationInternal(createdVpc, vpcCidr, tenantId, tenantName, netrisIpamAllocationName);
235-
if (ipamResponse == null || !ipamResponse.isIsSuccess()) {
236-
String reason = ipamResponse == null ? "Empty response" : "Operation failed on Netris";
237-
logger.debug("The Netris Allocation {} for VPC {} creation failed: {}", vpcCidr, cmd.getName(), reason);
238-
return false;
239-
}
240-
logger.debug(String.format("Successfully created VPC %s and its IPAM Allocation %s on Netris", cmd.getName(), vpcCidr));
241-
return true;
244+
InlineResponse2004Data createdIpamAllocation = createIpamAllocationInternal(netrisIpamAllocationName, vpcCidr, createdVpc.getData());
245+
return createdIpamAllocation != null;
242246
}
243247

244248
private void deleteVpcIpamAllocationInternal(VPCListing vpcResource, String vpcCidr) {
@@ -334,12 +338,7 @@ public boolean createVnet(CreateNetrisVnetCommand cmd) {
334338
String netrisVnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VNET, vNetName) ;
335339
String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, vnetCidr) ;
336340

337-
InlineResponse2004 subnetResponse = createVpcSubnetInternal(associatedVpc, vNetName, vnetCidr, netrisSubnetName);
338-
if (subnetResponse == null || !subnetResponse.isIsSuccess()) {
339-
String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris";
340-
logger.debug("The Netris Subnet {} for network {} creation failed: {}", vnetCidr, networkName, reason);
341-
return false;
342-
}
341+
createIpamSubnetInternal(netrisSubnetName, vnetCidr, SubnetBody.PurposeEnum.COMMON, associatedVpc);
343342
logger.debug("Successfully created IPAM Subnet {} for network {} on Netris", netrisSubnetName, networkName);
344343

345344
VnetResAddBody vnetResponse = createVnetInternal(associatedVpc, netrisVnetName, vnetCidr);
@@ -392,6 +391,71 @@ public boolean deleteVnet(DeleteNetrisVnetCommand cmd) {
392391
return true;
393392
}
394393

394+
protected VPCListing getSystemVpc() throws ApiException {
395+
List<VPCListing> systemVpcList = listVPCs().stream().filter(VPCListing::isIsSystem).collect(Collectors.toList());
396+
if (CollectionUtils.isEmpty(systemVpcList)) {
397+
String msg = "Cannot find any system VPC";
398+
logger.error(msg);
399+
throw new CloudRuntimeException(msg);
400+
}
401+
return systemVpcList.get(0);
402+
}
403+
404+
private BigDecimal getIpamAllocationIdByPrefixAndVpc(String superCidrPrefix, VPCListing vpc) throws ApiException {
405+
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
406+
FilterBySites filterBySites = new FilterBySites();
407+
filterBySites.add(siteId);
408+
FilterByVpc filterByVpc = new FilterByVpc();
409+
filterByVpc.add(vpc.getId());
410+
IpTree ipamTree = ipamApi.apiV2IpamGet(filterBySites, filterByVpc);
411+
List<IpTreeAllocation> superCidrList = ipamTree.getData().stream()
412+
.filter(x -> x.getPrefix().equals(superCidrPrefix))
413+
.collect(Collectors.toList());
414+
return CollectionUtils.isEmpty(superCidrList) ? null : superCidrList.get(0).getId();
415+
}
416+
417+
private IpTreeSubnet getIpamSubnetByAllocationAndPrefixAndPurposeAndVpc(BigDecimal ipamAllocationId, String exactCidr, IpTreeSubnet.PurposeEnum purpose, VPCListing vpc) throws ApiException {
418+
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
419+
FilterByVpc filterByVpc = new FilterByVpc();
420+
filterByVpc.add(vpc.getId());
421+
SubnetResBody subnetResBody = ipamApi.apiV2IpamSubnetsGet(filterByVpc);
422+
List<IpTreeSubnet> exactSubnetList = subnetResBody.getData().stream()
423+
.filter(x -> x.getAllocationID().equals(ipamAllocationId) && x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose)
424+
.collect(Collectors.toList());
425+
return CollectionUtils.isEmpty(exactSubnetList) ? null : exactSubnetList.get(0);
426+
}
427+
428+
@Override
429+
public boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd) {
430+
String superCidr = cmd.getSuperCidr();
431+
String exactCidr = cmd.getExactCidr();
432+
try {
433+
VPCListing systemVpc = getSystemVpc();
434+
logger.debug("Checking if the Netris Public Super CIDR {} exists", superCidr);
435+
BigDecimal ipamAllocationId = getIpamAllocationIdByPrefixAndVpc(superCidr, systemVpc);
436+
if (ipamAllocationId == null) {
437+
String ipamName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, superCidr);
438+
InlineResponse2004Data ipamAllocation = createIpamAllocationInternal(ipamName, superCidr, systemVpc);
439+
if (ipamAllocation == null) {
440+
String msg = String.format("Could not create the zone level super CIDR %s for the system VPC", superCidr);
441+
logger.error(msg);
442+
throw new CloudRuntimeException(msg);
443+
}
444+
ipamAllocationId = new BigDecimal(ipamAllocation.getId());
445+
}
446+
IpTreeSubnet exactSubnet = getIpamSubnetByAllocationAndPrefixAndPurposeAndVpc(ipamAllocationId, exactCidr, IpTreeSubnet.PurposeEnum.NAT, systemVpc);
447+
if (exactSubnet == null) {
448+
String ipamSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, exactCidr);
449+
createIpamSubnetInternal(ipamSubnetName, exactCidr, SubnetBody.PurposeEnum.NAT, systemVpc);
450+
}
451+
} catch (ApiException e) {
452+
String msg = String.format("Error setting up the Netris Public Range %s on super CIDR %s", exactCidr, superCidr);
453+
logAndThrowException(msg, e);
454+
return false;
455+
}
456+
return true;
457+
}
458+
395459
private void deleteVnetInternal(VPCListing associatedVpc, FilterBySites siteFilter, FilterByVpc vpcFilter, String netrisVnetName, String vNetName) {
396460
try {
397461
VNetApi vNetApi = apiClient.getApiStubForMethod(VNetApi.class);
@@ -433,16 +497,16 @@ private void deleteSubnetInternal(FilterByVpc vpcFilter, String netrisVnetName,
433497
}
434498
}
435499

436-
private InlineResponse2004 createVpcSubnetInternal(VPCListing associatedVpc, String vNetName, String vNetCidr, String netrisSubnetName) {
437-
logger.debug("Creating Netris VPC Subnet {} for VPC {} for vNet {}", vNetCidr, associatedVpc.getName(), vNetName);
500+
private InlineResponse2004Data createIpamSubnetInternal(String subnetName, String subnetPrefix, SubnetBody.PurposeEnum purpose, VPCListing vpc) {
501+
logger.debug("Creating Netris IPAM Subnet {} for VPC {}", subnetPrefix, vpc.getName());
438502
try {
439503

440504
SubnetBody subnetBody = new SubnetBody();
441-
subnetBody.setName(netrisSubnetName);
505+
subnetBody.setName(subnetName);
442506

443507
AllocationBodyVpc vpcAllocationBody = new AllocationBodyVpc();
444-
vpcAllocationBody.setName(associatedVpc.getName());
445-
vpcAllocationBody.setId(associatedVpc.getId());
508+
vpcAllocationBody.setName(vpc.getName());
509+
vpcAllocationBody.setId(vpc.getId());
446510
subnetBody.setVpc(vpcAllocationBody);
447511

448512
IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant();
@@ -455,12 +519,18 @@ private InlineResponse2004 createVpcSubnetInternal(VPCListing associatedVpc, Str
455519
subnetSites.setName(siteName);
456520
subnetBody.setSites(List.of(subnetSites));
457521

458-
subnetBody.setPurpose(SubnetBody.PurposeEnum.COMMON);
459-
subnetBody.setPrefix(vNetCidr);
522+
subnetBody.setPurpose(purpose);
523+
subnetBody.setPrefix(subnetPrefix);
460524
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
461-
return ipamApi.apiV2IpamSubnetPost(subnetBody);
525+
InlineResponse2004 subnetResponse = ipamApi.apiV2IpamSubnetPost(subnetBody);
526+
if (subnetResponse == null || !subnetResponse.isIsSuccess()) {
527+
String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris";
528+
logger.debug("The Netris IPAM Subnet {} creation failed: {}", subnetName, reason);
529+
throw new CloudRuntimeException(reason);
530+
}
531+
return subnetResponse.getData();
462532
} catch (ApiException e) {
463-
logAndThrowException(String.format("Error creating Netris Subnet %s for VPC %s", vNetCidr, associatedVpc.getName()), e);
533+
logAndThrowException(String.format("Error creating Netris IPAM Subnet %s for VPC %s", subnetPrefix, vpc.getName()), e);
464534
return null;
465535
}
466536
}

0 commit comments

Comments
 (0)