Visitar URL original
Netris: Improvements and fixes to the Netris plugin by Pearl1594 · Pull Request #13591 · apache/cloudstack · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4b817d8
Netris CloudStack Integration Enhancements
Pearl1594 Jun 18, 2026
1618383
Add a check to prevent re-adding existing ACLs
Pearl1594 Jun 24, 2026
b66eb66
Add check for vnet name length and cleanup vpc and vnet resources on …
Pearl1594 Jul 6, 2026
34a15b5
Add support to the VPC response to display if redundant routers are s…
Pearl1594 Jul 6, 2026
f73bbdd
Hide VPN sections and prevent enabling it when service isn't enabled …
Pearl1594 Jul 6, 2026
98ae1c4
Fix issue with adding external node to a CKS cluster with Netris offe…
Pearl1594 Jul 8, 2026
4ac23ee
Update upgrade path to reclaim vnets of deleted netris networks, impr…
Pearl1594 Jul 9, 2026
0c0f22c
Allocate IP from Netris (Provider) range when IP is not specified dur…
Pearl1594 Jul 10, 2026
049f9e9
Fix VRRP gateway IP conflict on redundant VPC routers with external n…
Pearl1594 Jul 24, 2026
ab80f11
Merge branch '4.22' of github.com:apache/cloudstack into netris-impro…
Pearl1594 Sep 15, 2026
227122c
VPN: Reconfigure static nat and static route on fail over to backup V…
Pearl1594 Jul 30, 2026
71f6299
Fix issue with deletion of vpn connection for DualStack redundant VPCs
Pearl1594 Jul 30, 2026
5d8727b
fix precommit ci issue
Pearl1594 Sep 15, 2026
811c21b
Merge branch '4.22' of github.com:apache/cloudstack into netris-impro…
Pearl1594 Sep 28, 2026
c5ee6d1
Merge branch '4.22' into netris-improvements
nvazquez Sep 30, 2026
f8669aa
Add Netris to the range limit check (#129)
Pearl1594 Jul 14, 2026
40e804f
Netris: address review comments on static NAT, L2 and offering form
Pearl1594 Oct 2, 2026
2423fe9
Update Netris SDK version to 1.0.1
nvazquez Oct 8, 2026
8490722
Merge branch '4.22' into netris-improvements
nvazquez Oct 9, 2026
411fb9a
Move to the correct schema file
nvazquez Oct 9, 2026
e008445
systemvm: bind dnsmasq and password server to router IP when external…
Pearl1594 Oct 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Netris: address review comments on static NAT, L2 and offering form
- Match the legacy static NAT rule only when it was created for the
  requested public IP, on both create and delete
- Roll back the dedicated L2 VPC if vNet creation fails
- Hide the L2 guest type for Netris in the add offering form
- Add VPN to the external provider service map for Netris only
- Fix the L2 offering services javadoc
  • Loading branch information
Pearl1594 committed Oct 2, 2026
commit 40e804f4cf2f513950be32bcbcafbfaedb65f15e
Original file line number Diff line number Diff line change
Expand Up @@ -3182,10 +3182,9 @@ private boolean hasGuestBypassVlanOverlapCheck(final boolean bypassVlanOverlapCh
}

/**
* Checks for L2 network offering services. Only 3 cases allowed:
* Checks for L2 network offering services. Only 2 cases allowed:
* - No services
* - UserData service only, provided by ConfigDrive
* - Connectivity service only, provided by Netris
*
* @param ntwkOff network offering
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,9 @@ public boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd) {
NatGetBody existingNatRule = netrisNatRuleExists(natRuleName);
// Backward compatibility: rules created before the public-IP suffix was added use the legacy name
if (existingNatRule == null && "STATICNAT".equals(cmd.getNatRuleType())) {
String legacyName = getLegacyStaticNatRuleName(natRuleName);
if (legacyName != null) {
logger.debug("Static NAT rule not found with name '{}', falling back to legacy name '{}'", natRuleName, legacyName);
existingNatRule = netrisNatRuleExists(legacyName);
if (existingNatRule != null) {
natRuleName = legacyName;
}
existingNatRule = findLegacyStaticNatRule(natRuleName, cmd.getNatIp());
if (existingNatRule != null) {
natRuleName = existingNatRule.getName();
}
}
boolean ruleExists = Objects.nonNull(existingNatRule);
Expand Down Expand Up @@ -1170,6 +1166,14 @@ private VPCListing getOrCreateL2Vpc(NetrisCommand cmd) {
return getVpcByNameAndTenant(l2VpcName);
}

private void rollbackL2Vpc(VPCListing l2Vpc) {
try {
deleteVpcInternal(l2Vpc);
} catch (Exception e) {
logger.error("Failed to rollback L2 VPC {} after vNet creation failure - manual cleanup may be required: {}", l2Vpc.getName(), e.getMessage());
}
}

private VPCListing getVpcByNameAndTenant(String vpcName) {
try {
List<VPCListing> vpcListings = listVPCs();
Expand Down Expand Up @@ -1256,9 +1260,11 @@ public boolean createVnet(CreateNetrisVnetCommand cmd) {
String netrisV6IpamAllocationName = null;
String netrisV6SubnetName = null;
boolean createdIpv6Allocation = false;
boolean createdL2Vpc = false;

try {
if (isL2) {
createdL2Vpc = getVpcByNameAndTenant(getL2VpcName(cmd, cmd.getName())) == null;
associatedVpc = getOrCreateL2Vpc(cmd);
if (associatedVpc == null) {
logger.error("Failed to get or create dedicated L2 VPC to create the corresponding vNet for L2 network {}", networkName);
Expand Down Expand Up @@ -1309,13 +1315,17 @@ public boolean createVnet(CreateNetrisVnetCommand cmd) {
if (!isL2) {
rollbackVnetResources(associatedVpc, netrisSubnetName, netrisV6SubnetName,
createdIpv6Allocation ? netrisV6IpamAllocationName : null, networkName);
} else if (createdL2Vpc) {
rollbackL2Vpc(associatedVpc);
}
Comment thread
Pearl1594 marked this conversation as resolved.
return false;
}
} catch (Exception e) {
if (!isL2 && associatedVpc != null) {
rollbackVnetResources(associatedVpc, netrisSubnetName, netrisV6SubnetName,
createdIpv6Allocation ? netrisV6IpamAllocationName : null, networkName);
} else if (isL2 && createdL2Vpc && associatedVpc != null) {
rollbackL2Vpc(associatedVpc);
}
throw new CloudRuntimeException(String.format("Failed to create Netris vNet %s", networkName), e);
}
Expand Down Expand Up @@ -1710,9 +1720,9 @@ public boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd) {
return true;
}
// Backward compatibility: rule with legacy naming convention (no public IP post-fixed) exists - don't create a duplicate
String legacyName = getLegacyStaticNatRuleName(staticNatRuleName);
if (legacyName != null && netrisNatRuleExists(legacyName) != null) {
logger.debug("Legacy static NAT rule '{}' already exists on Netris, skipping creation of '{}'", legacyName, staticNatRuleName);
NatGetBody legacyRule = findLegacyStaticNatRule(staticNatRuleName, cmd.getNatIp());
if (legacyRule != null) {
logger.debug("Legacy static NAT rule '{}' already exists on Netris, skipping creation of '{}'", legacyRule.getName(), staticNatRuleName);
return true;
Comment thread
Pearl1594 marked this conversation as resolved.
}
// Create a /32 subnet for the DNAT IP
Expand Down Expand Up @@ -2194,6 +2204,21 @@ private String getLegacyStaticNatRuleName(String newName) {
return newName.substring(0, idx + "-STATICNAT".length());
}

/**
* Returns the legacy-named static NAT rule only if it was created for the given public IP.
*/
private NatGetBody findLegacyStaticNatRule(String newName, String natIp) {
String legacyName = getLegacyStaticNatRuleName(newName);
if (legacyName == null) {
return null;
}
NatGetBody legacyRule = netrisNatRuleExists(legacyName);
if (legacyRule == null || !(natIp + "/32").equals(legacyRule.getDestinationAddress())) {
return null;
}
return legacyRule;
}

private VPCListing getNetrisVpcResource(String netrisVpcName) {
VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName);
if (vpcResource == null) {
Expand Down
4 changes: 2 additions & 2 deletions ui/src/views/offering/AddNetworkOffering.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<a-radio-button value="isolated">
{{ $t('label.isolated') }}
</a-radio-button>
<a-radio-button value="l2" v-if="form.provider !== 'NSX'">
<a-radio-button value="l2" v-if="form.provider !== 'NSX' && form.provider !== 'Netris'">
{{ $t('label.l2') }}
</a-radio-button>
<a-radio-button value="shared" v-if="form.provider !== 'NSX' && form.provider !== 'Netris'">
Expand Down Expand Up @@ -1021,7 +1021,7 @@ export default {
SourceNat: externalProvider,
StaticNat: externalProvider,
PortForwarding: externalProvider,
Vpn: this.forVpc ? this.VPCVR : this.VR,
...(!isNsxProvider && { Vpn: this.forVpc ? this.VPCVR : this.VR }),
...((!isNsxProvider || this.form.nsxsupportlb) && { Lb: externalProvider })
}

Expand Down
Loading