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
This commit is contained in:
Nicolas Vazquez 2024-11-07 11:05:20 -03:00 committed by GitHub
parent 6e41063808
commit 9b4d95780a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 305 additions and 48 deletions

View File

@ -35,5 +35,10 @@
<artifactId>netris-java-sdk</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.github.seancfoley</groupId>
<artifactId>ipaddress</artifactId>
<version>5.5.1</version>
</dependency>
</dependencies>
</project>

View File

@ -20,13 +20,13 @@ import com.cloud.agent.api.Command;
public class NetrisCommand extends Command {
private final long zoneId;
private final long accountId;
private final long domainId;
private final Long accountId;
private final Long domainId;
private final String name;
private final long id;
private final boolean isVpc;
public NetrisCommand(long zoneId, long accountId, long domainId, String name, long id, boolean isVpc) {
public NetrisCommand(long zoneId, Long accountId, Long domainId, String name, long id, boolean isVpc) {
this.zoneId = zoneId;
this.accountId = accountId;
this.domainId = domainId;
@ -48,11 +48,11 @@ public class NetrisCommand extends Command {
return zoneId;
}
public long getAccountId() {
public Long getAccountId() {
return accountId;
}
public long getDomainId() {
public Long getDomainId() {
return domainId;
}

View File

@ -0,0 +1,37 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.agent.api;
public class SetupNetrisPublicRangeCommand extends NetrisCommand {
private final String superCidr;
private final String exactCidr;
public SetupNetrisPublicRangeCommand(long zoneId, String superCidr, String exactCidr) {
super(zoneId, null, null, null, zoneId, false);
this.superCidr = superCidr;
this.exactCidr = exactCidr;
}
public String getSuperCidr() {
return superCidr;
}
public String getExactCidr() {
return exactCidr;
}
}

View File

@ -34,6 +34,7 @@ import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
import org.apache.cloudstack.agent.api.NetrisAnswer;
import org.apache.cloudstack.StartupNetrisCommand;
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
import org.apache.cloudstack.service.NetrisApiClient;
import org.apache.cloudstack.service.NetrisApiClientImpl;
import org.apache.logging.log4j.LogManager;
@ -94,6 +95,8 @@ public class NetrisResource implements ServerResource {
return executeRequest((CreateNetrisVnetCommand) cmd);
} else if (cmd instanceof DeleteNetrisVnetCommand) {
return executeRequest((DeleteNetrisVnetCommand) cmd);
} else if (cmd instanceof SetupNetrisPublicRangeCommand) {
return executeRequest((SetupNetrisPublicRangeCommand) cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
@ -250,6 +253,14 @@ public class NetrisResource implements ServerResource {
return new NetrisAnswer(cmd, true, "OK");
}
private Answer executeRequest(SetupNetrisPublicRangeCommand cmd) {
boolean result = netrisApiClient.setupZoneLevelPublicRange(cmd);
if (!result) {
return new NetrisAnswer(cmd, false, "Netris Setup for Public Range failed");
}
return new NetrisAnswer(cmd, true, "OK");
}
@Override
public boolean start() {
return true;

View File

@ -27,14 +27,19 @@ public class NetrisResourceObjectUtils {
public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, NetrisObjectType netrisObjectType, String... suffixes) {
long zoneId = cmd.getZoneId();
long accountId = cmd.getAccountId();
long domainId = cmd.getDomainId();
Long accountId = cmd.getAccountId();
Long domainId = cmd.getDomainId();
long objectId = cmd.getId();
String objectName = cmd.getName();
boolean isVpc = cmd.isVpc();
boolean isZoneLevel = accountId == null && domainId == null;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(String.format("D%s-A%s-Z%s", domainId, accountId, zoneId));
if (isZoneLevel) {
stringBuilder.append(String.format("Z%s", zoneId));
} else {
stringBuilder.append(String.format("D%s-A%s-Z%s", domainId, accountId, zoneId));
}
String prefix = isVpc ? "-V" : "-N";
switch (netrisObjectType) {
case VPC:
@ -46,10 +51,14 @@ public class NetrisResourceObjectUtils {
}
break;
case IPAM_ALLOCATION:
stringBuilder.append(String.format("%s%s", prefix, objectId));
if (!isZoneLevel) {
stringBuilder.append(String.format("%s%s", prefix, objectId));
}
break;
case IPAM_SUBNET:
stringBuilder.append(String.format("-N%s", objectId));
if (!isZoneLevel) {
stringBuilder.append(String.format("-N%s", objectId));
}
break;
case VNET:
break;

View File

@ -24,6 +24,7 @@ import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
import java.util.List;
@ -50,4 +51,11 @@ public interface NetrisApiClient {
boolean createVnet(CreateNetrisVnetCommand cmd);
boolean deleteVnet(DeleteNetrisVnetCommand cmd);
/**
* Check and create zone level Netris Public range in the following manner:
* - Check the IPAM allocation for the zone super CIDR. In case it doesn't exist, create it
* - Check the IPAM subnet for NAT purpose for the range start-end. In case it doesn't exist, create it
*/
boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd);
}

View File

@ -33,6 +33,9 @@ import io.netris.model.FilterBySites;
import io.netris.model.FilterByVpc;
import io.netris.model.GetSiteBody;
import io.netris.model.InlineResponse2004;
import io.netris.model.InlineResponse2004Data;
import io.netris.model.IpTree;
import io.netris.model.IpTreeAllocation;
import io.netris.model.IpTreeAllocationTenant;
import io.netris.model.IpTreeSubnet;
import io.netris.model.IpTreeSubnetSites;
@ -63,6 +66,7 @@ import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand;
import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand;
import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand;
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
import org.apache.cloudstack.resource.NetrisResourceObjectUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.LogManager;
@ -196,25 +200,31 @@ public class NetrisApiClientImpl implements NetrisApiClient {
return response;
}
private InlineResponse2004 createVpcAllocationInternal(VPCResponseObjectOK createdVpc, String cidr, int adminTenantId,
String adminTenantName, String netrisIpamAllocationName) {
logger.debug(String.format("Creating Netris VPC Allocation %s for VPC %s", cidr, createdVpc.getData().getName()));
private InlineResponse2004Data createIpamAllocationInternal(String ipamName, String ipamPrefix, VPCListing vpc) {
logger.debug(String.format("Creating Netris IPAM Allocation %s for VPC %s", ipamPrefix, vpc.getName()));
try {
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
AllocationBody body = new AllocationBody();
AllocationBodyVpc allocationBodyVpc = new AllocationBodyVpc();
allocationBodyVpc.setId(createdVpc.getData().getId());
allocationBodyVpc.setName(createdVpc.getData().getName());
allocationBodyVpc.setId(vpc.getId());
allocationBodyVpc.setName(vpc.getName());
body.setVpc(allocationBodyVpc);
body.setName(netrisIpamAllocationName);
body.setPrefix(cidr);
body.setName(ipamName);
body.setPrefix(ipamPrefix);
IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant();
allocationTenant.setId(new BigDecimal(adminTenantId));
allocationTenant.setName(adminTenantName);
allocationTenant.setId(new BigDecimal(tenantId));
allocationTenant.setName(tenantName);
body.setTenant(allocationTenant);
return ipamApi.apiV2IpamAllocationPost(body);
InlineResponse2004 ipamResponse = ipamApi.apiV2IpamAllocationPost(body);
if (ipamResponse == null || !ipamResponse.isIsSuccess()) {
String reason = ipamResponse == null ? "Empty response" : "Operation failed on Netris";
logger.debug("The Netris Allocation {} for VPC {} creation failed: {}", ipamPrefix, vpc.getName(), reason);
return null;
}
logger.debug(String.format("Successfully created VPC %s and its IPAM Allocation %s on Netris", vpc.getName(), ipamPrefix));
return ipamResponse.getData();
} catch (ApiException e) {
logAndThrowException(String.format("Error creating Netris Allocation %s for VPC %s", cidr, createdVpc.getData().getName()), e);
logAndThrowException(String.format("Error creating Netris IPAM Allocation %s for VPC %s", ipamPrefix, vpc.getName()), e);
return null;
}
}
@ -231,14 +241,8 @@ public class NetrisApiClientImpl implements NetrisApiClient {
String netrisIpamAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, cmd.getCidr());
String vpcCidr = cmd.getCidr();
InlineResponse2004 ipamResponse = createVpcAllocationInternal(createdVpc, vpcCidr, tenantId, tenantName, netrisIpamAllocationName);
if (ipamResponse == null || !ipamResponse.isIsSuccess()) {
String reason = ipamResponse == null ? "Empty response" : "Operation failed on Netris";
logger.debug("The Netris Allocation {} for VPC {} creation failed: {}", vpcCidr, cmd.getName(), reason);
return false;
}
logger.debug(String.format("Successfully created VPC %s and its IPAM Allocation %s on Netris", cmd.getName(), vpcCidr));
return true;
InlineResponse2004Data createdIpamAllocation = createIpamAllocationInternal(netrisIpamAllocationName, vpcCidr, createdVpc.getData());
return createdIpamAllocation != null;
}
private void deleteVpcIpamAllocationInternal(VPCListing vpcResource, String vpcCidr) {
@ -334,12 +338,7 @@ public class NetrisApiClientImpl implements NetrisApiClient {
String netrisVnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VNET, vNetName) ;
String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, vnetCidr) ;
InlineResponse2004 subnetResponse = createVpcSubnetInternal(associatedVpc, vNetName, vnetCidr, netrisSubnetName);
if (subnetResponse == null || !subnetResponse.isIsSuccess()) {
String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris";
logger.debug("The Netris Subnet {} for network {} creation failed: {}", vnetCidr, networkName, reason);
return false;
}
createIpamSubnetInternal(netrisSubnetName, vnetCidr, SubnetBody.PurposeEnum.COMMON, associatedVpc);
logger.debug("Successfully created IPAM Subnet {} for network {} on Netris", netrisSubnetName, networkName);
VnetResAddBody vnetResponse = createVnetInternal(associatedVpc, netrisVnetName, vnetCidr);
@ -392,6 +391,71 @@ public class NetrisApiClientImpl implements NetrisApiClient {
return true;
}
protected VPCListing getSystemVpc() throws ApiException {
List<VPCListing> systemVpcList = listVPCs().stream().filter(VPCListing::isIsSystem).collect(Collectors.toList());
if (CollectionUtils.isEmpty(systemVpcList)) {
String msg = "Cannot find any system VPC";
logger.error(msg);
throw new CloudRuntimeException(msg);
}
return systemVpcList.get(0);
}
private BigDecimal getIpamAllocationIdByPrefixAndVpc(String superCidrPrefix, VPCListing vpc) throws ApiException {
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
FilterBySites filterBySites = new FilterBySites();
filterBySites.add(siteId);
FilterByVpc filterByVpc = new FilterByVpc();
filterByVpc.add(vpc.getId());
IpTree ipamTree = ipamApi.apiV2IpamGet(filterBySites, filterByVpc);
List<IpTreeAllocation> superCidrList = ipamTree.getData().stream()
.filter(x -> x.getPrefix().equals(superCidrPrefix))
.collect(Collectors.toList());
return CollectionUtils.isEmpty(superCidrList) ? null : superCidrList.get(0).getId();
}
private IpTreeSubnet getIpamSubnetByAllocationAndPrefixAndPurposeAndVpc(BigDecimal ipamAllocationId, String exactCidr, IpTreeSubnet.PurposeEnum purpose, VPCListing vpc) throws ApiException {
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
FilterByVpc filterByVpc = new FilterByVpc();
filterByVpc.add(vpc.getId());
SubnetResBody subnetResBody = ipamApi.apiV2IpamSubnetsGet(filterByVpc);
List<IpTreeSubnet> exactSubnetList = subnetResBody.getData().stream()
.filter(x -> x.getAllocationID().equals(ipamAllocationId) && x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose)
.collect(Collectors.toList());
return CollectionUtils.isEmpty(exactSubnetList) ? null : exactSubnetList.get(0);
}
@Override
public boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd) {
String superCidr = cmd.getSuperCidr();
String exactCidr = cmd.getExactCidr();
try {
VPCListing systemVpc = getSystemVpc();
logger.debug("Checking if the Netris Public Super CIDR {} exists", superCidr);
BigDecimal ipamAllocationId = getIpamAllocationIdByPrefixAndVpc(superCidr, systemVpc);
if (ipamAllocationId == null) {
String ipamName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, superCidr);
InlineResponse2004Data ipamAllocation = createIpamAllocationInternal(ipamName, superCidr, systemVpc);
if (ipamAllocation == null) {
String msg = String.format("Could not create the zone level super CIDR %s for the system VPC", superCidr);
logger.error(msg);
throw new CloudRuntimeException(msg);
}
ipamAllocationId = new BigDecimal(ipamAllocation.getId());
}
IpTreeSubnet exactSubnet = getIpamSubnetByAllocationAndPrefixAndPurposeAndVpc(ipamAllocationId, exactCidr, IpTreeSubnet.PurposeEnum.NAT, systemVpc);
if (exactSubnet == null) {
String ipamSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, exactCidr);
createIpamSubnetInternal(ipamSubnetName, exactCidr, SubnetBody.PurposeEnum.NAT, systemVpc);
}
} catch (ApiException e) {
String msg = String.format("Error setting up the Netris Public Range %s on super CIDR %s", exactCidr, superCidr);
logAndThrowException(msg, e);
return false;
}
return true;
}
private void deleteVnetInternal(VPCListing associatedVpc, FilterBySites siteFilter, FilterByVpc vpcFilter, String netrisVnetName, String vNetName) {
try {
VNetApi vNetApi = apiClient.getApiStubForMethod(VNetApi.class);
@ -433,16 +497,16 @@ public class NetrisApiClientImpl implements NetrisApiClient {
}
}
private InlineResponse2004 createVpcSubnetInternal(VPCListing associatedVpc, String vNetName, String vNetCidr, String netrisSubnetName) {
logger.debug("Creating Netris VPC Subnet {} for VPC {} for vNet {}", vNetCidr, associatedVpc.getName(), vNetName);
private InlineResponse2004Data createIpamSubnetInternal(String subnetName, String subnetPrefix, SubnetBody.PurposeEnum purpose, VPCListing vpc) {
logger.debug("Creating Netris IPAM Subnet {} for VPC {}", subnetPrefix, vpc.getName());
try {
SubnetBody subnetBody = new SubnetBody();
subnetBody.setName(netrisSubnetName);
subnetBody.setName(subnetName);
AllocationBodyVpc vpcAllocationBody = new AllocationBodyVpc();
vpcAllocationBody.setName(associatedVpc.getName());
vpcAllocationBody.setId(associatedVpc.getId());
vpcAllocationBody.setName(vpc.getName());
vpcAllocationBody.setId(vpc.getId());
subnetBody.setVpc(vpcAllocationBody);
IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant();
@ -455,12 +519,18 @@ public class NetrisApiClientImpl implements NetrisApiClient {
subnetSites.setName(siteName);
subnetBody.setSites(List.of(subnetSites));
subnetBody.setPurpose(SubnetBody.PurposeEnum.COMMON);
subnetBody.setPrefix(vNetCidr);
subnetBody.setPurpose(purpose);
subnetBody.setPrefix(subnetPrefix);
IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class);
return ipamApi.apiV2IpamSubnetPost(subnetBody);
InlineResponse2004 subnetResponse = ipamApi.apiV2IpamSubnetPost(subnetBody);
if (subnetResponse == null || !subnetResponse.isIsSuccess()) {
String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris";
logger.debug("The Netris IPAM Subnet {} creation failed: {}", subnetName, reason);
throw new CloudRuntimeException(reason);
}
return subnetResponse.getData();
} catch (ApiException e) {
logAndThrowException(String.format("Error creating Netris Subnet %s for VPC %s", vNetCidr, associatedVpc.getName()), e);
logAndThrowException(String.format("Error creating Netris IPAM Subnet %s for VPC %s", subnetPrefix, vpc.getName()), e);
return null;
}
}

View File

@ -16,15 +16,19 @@
// under the License.
package org.apache.cloudstack.service;
import com.amazonaws.util.CollectionUtils;
import com.cloud.agent.api.Answer;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
import com.cloud.host.dao.HostDetailsDao;
import com.cloud.network.Network;
import com.cloud.network.Networks;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.NetrisProviderDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
@ -36,7 +40,11 @@ import com.cloud.resource.ResourceManager;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.google.common.annotations.VisibleForTesting;
import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressString;
import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.command.AddNetrisProviderCmd;
import org.apache.cloudstack.api.command.DeleteNetrisProviderCmd;
@ -44,6 +52,10 @@ import org.apache.cloudstack.api.command.ListNetrisProvidersCmd;
import org.apache.cloudstack.api.response.NetrisProviderResponse;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.resource.NetrisResource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
@ -53,9 +65,12 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
public class NetrisProviderServiceImpl implements NetrisProviderService {
protected Logger logger = LogManager.getLogger(getClass());
@Inject
DataCenterDao dataCenterDao;
@Inject
@ -68,6 +83,10 @@ public class NetrisProviderServiceImpl implements NetrisProviderService {
PhysicalNetworkDao physicalNetworkDao;
@Inject
NetworkDao networkDao;
@Inject
private IPAddressDao ipAddressDao;
@Inject
private VlanDao vlanDao;
@Override
public NetrisProvider addProvider(AddNetrisProviderCmd cmd) {
@ -123,12 +142,77 @@ public class NetrisProviderServiceImpl implements NetrisProviderService {
} else {
throw new CloudRuntimeException("Failed to add Netris controller due to internal error.");
}
createNetrisPublicIpRangesOnNetrisProvider(zoneId, netrisResource);
} catch (ConfigurationException e) {
throw new CloudRuntimeException(e.getMessage());
}
return netrisProvider;
}
/**
* Calculate the minimum CIDR subnet containing the IP range (using the library: <a href="https://github.com/seancfoley/IPAddress">IPAddress</a>)
* From: <a href="https://github.com/seancfoley/IPAddress/wiki/Code-Examples-3:-Subnetting-and-Other-Subnet-Operations#from-start-and-end-address-get-single-cidr-block-covering-both">Example</a>
* @param ipRange format: startIP-endIP
* @return the minimum CIDR containing the IP range
*/
protected String calculateSubnetCidrFromIpRange(String ipRange) {
if (StringUtils.isBlank(ipRange) || !ipRange.contains("-")) {
return null;
}
String[] rangeArray = ipRange.split("-");
String startIp = rangeArray[0];
String endIp = rangeArray[1];
IPAddress startIpAddress = new IPAddressString(startIp).getAddress();
IPAddress endIpAddress = new IPAddressString(endIp).getAddress();
return startIpAddress.coverWithPrefixBlock(endIpAddress).toPrefixLengthString();
}
/**
* Prepare the Netris Public Range to be used by CloudStack after the zone is created and the Netris provider is added
*/
public SetupNetrisPublicRangeCommand createSetupPublicRangeCommand(long zoneId, String gateway, String netmask, String ipRange) {
String superCidr = NetUtils.getCidrFromGatewayAndNetmask(gateway, netmask);
String subnetNatCidr = calculateSubnetCidrFromIpRange(ipRange);
return new SetupNetrisPublicRangeCommand(zoneId, superCidr, subnetNatCidr);
}
protected void createNetrisPublicIpRangesOnNetrisProvider(long zoneId, NetrisResource netrisResource) {
List<PhysicalNetworkVO> physicalNetworks = physicalNetworkDao.listByZoneAndTrafficType(zoneId, Networks.TrafficType.Public);
physicalNetworks = physicalNetworks.stream().filter(x -> x.getIsolationMethods().contains(Network.Provider.Netris.getName())).collect(Collectors.toList());
if (CollectionUtils.isEmpty(physicalNetworks)) {
return;
}
for (PhysicalNetworkVO physicalNetwork : physicalNetworks) {
List<IPAddressVO> publicIps = ipAddressDao.listByPhysicalNetworkId(physicalNetwork.getId());
List<Long> vlanDbIds = publicIps.stream()
.filter(x -> !x.isForSystemVms())
.map(IPAddressVO::getVlanId)
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(vlanDbIds)) {
String msg = "Cannot find a public IP range VLAN range for the Netris Public traffic";
logger.error(msg);
throw new CloudRuntimeException(msg);
}
if (vlanDbIds.size() > 1) {
logger.warn("Expected one Netris Public IP range but found {}. Using the first one to create the Netris IPAM allocation and NAT subnet", vlanDbIds.size());
}
VlanVO vlanRecord = vlanDao.findById(vlanDbIds.get(0));
if (vlanRecord == null) {
logger.error("Cannot set up the Netris Public IP range as it cannot find the public range on database");
return;
}
String gateway = vlanRecord.getVlanGateway();
String netmask = vlanRecord.getVlanNetmask();
String ipRange = vlanRecord.getIpRange();
SetupNetrisPublicRangeCommand cmd = createSetupPublicRangeCommand(zoneId, gateway, netmask, ipRange);
Answer answer = netrisResource.executeRequest(cmd);
boolean result = answer != null && answer.getResult();
if (!result) {
throw new CloudRuntimeException("Netris Public IP Range setup failed, please check the logs");
}
}
}
@Override
public List<BaseResponse> listNetrisProviders(Long zoneId) {
List<BaseResponse> netrisControllersResponseList = new ArrayList<>();
@ -158,7 +242,7 @@ public class NetrisProviderServiceImpl implements NetrisProviderService {
List<PhysicalNetworkVO> physicalNetworks = physicalNetworkDao.listByZone(zoneId);
for (PhysicalNetworkVO physicalNetwork : physicalNetworks) {
List<NetworkVO> networkList = networkDao.listByPhysicalNetwork(physicalNetwork.getId());
if (!CollectionUtils.isNullOrEmpty(networkList)) {
if (!CollectionUtils.isEmpty(networkList)) {
validateNetworkState(networkList);
}
}

View File

@ -0,0 +1,33 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.service;
import org.junit.Assert;
import org.junit.Test;
public class NetrisProviderServiceImplTest {
private NetrisProviderServiceImpl service = new NetrisProviderServiceImpl();
@Test
public void testCalculateSubnetCidrFromIpRange() {
String ipRange = "100.99.18.140-100.99.18.159";
String expectedCidr = "100.99.18.128/27";
String cidr = service.calculateSubnetCidrFromIpRange(ipRange);
Assert.assertEquals(expectedCidr, cidr);
}
}

View File

@ -4450,7 +4450,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
if (network.getIsolationMethods().contains("GRE")) {
minVnet = MIN_GRE_KEY;
maxVnet = MAX_GRE_KEY;
} else if (network.getIsolationMethods().contains("VXLAN")) {
} else if (network.getIsolationMethods().contains("VXLAN") || network.getIsolationMethods().contains("Netris")) {
minVnet = MIN_VXLAN_VNI;
maxVnet = MAX_VXLAN_VNI;
// fail if zone already contains VNI, need to be unique per zone.

View File

@ -1772,7 +1772,7 @@
"label.public.ips": "Public IP addresses",
"label.public.lb": "Public LB",
"label.public.traffic": "Public traffic",
"label.public.traffic.netris": "Netris Public traffic",
"label.public.traffic.netris": "Netris Public IP Pool",
"label.public.traffic.nsx": "NSX Public traffic",
"label.publicinterface": "Public interface",
"label.publicip": "IP address",