Skip to content

network: scope routed network/VPC subnets to a zone - #14421

Open
prashanthr2 wants to merge 2 commits into
apache:4.22from
prashanthr2:routed-vpc-cidr-per-zone
Open

prashanthr2 wants to merge 2 commits into
apache:4.22from
prashanthr2:routed-vpc-cidr-per-zone

Conversation

@prashanthr2

Copy link
Copy Markdown
Contributor

Description

Fixes #14419.

ip4_guest_subnet_network_map has no zone column, so the subnet bookkeeping for routed networks and VPCs is global. Creating a routed VPC or network with a CIDR that is already used in another zone fails with The subnet is in use, even though the two zones are independent.

This adds a nullable data_center_id to the table and scopes both the subnet lookup (findBySubnetAndDataCenterId) and the parentless overlap check (listAllNoParentByDataCenterId) by zone, so the same CIDR can be used once per zone. Existing rows are backfilled from their parent zone subnet, their VPC's zone_id, or their network's data_center_id.

Notes for reviewers:

  • The new FK gets ON DELETE CASCADE because IDEMPOTENT_ADD_FOREIGN_KEY hardcodes it. That matches networks, vpc, user_ip_address and most of the schema, though the sibling table dc_ip4_guest_subnets uses a plain FK.
  • Rows with no parent, no VPC and no network cannot be attributed to a zone and keep data_center_id = NULL. Those are leftovers from failed network/VPC creates (state = Free, unreferenced) and no longer take part in any zone's overlap check, which is the intended direction.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (improves an existing feature and functionality)
  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • build/CI
  • test (unit or integration test code)

Feature/Enhancement Scale or Bug Severity

Bug Severity

  • BLOCKER
  • Critical
  • Major
  • Minor
  • Trivial

How Has This Been Tested?

Unit tests in RoutedIpv4ManagerImplTest updated for the new DAO signatures, plus a new testGetOrCreateIpv4SubnetForGuestNetworkOrVpcInternalByCidrInAnotherZone covering the cross-zone case.

Manual: create a routed VPC with 10.0.0.0/8 in zone 1, then a second routed VPC with the same CIDR in zone 2. Before this change the second create fails with "The subnet is in use"; after it, both succeed and each row in ip4_guest_subnet_network_map carries its own data_center_id.

🤖 Generated with Claude Code

https://claude.ai/code/session_017rnv8vT6LQSKfwkzp8tvg9

The ip4_guest_subnet_network_map table had no zone column, so the subnet
bookkeeping for routed networks and VPCs was global. Creating a routed VPC
or network with a CIDR already used in another zone failed with
"The subnet is in use", even though the two zones are independent.

Add a nullable data_center_id column to ip4_guest_subnet_network_map and
scope the subnet lookup and the parentless overlap check by zone, so the
same CIDR can be used once per zone. Existing rows are backfilled from
their parent zone subnet, VPC or network.

Fixes apache#14419

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017rnv8vT6LQSKfwkzp8tvg9
@vladimirpetrov vladimirpetrov added this to the 4.22.2 milestone Oct 16, 2026

@weizhouapache weizhouapache left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm
the SQL may be applied to 423to24.sql too

@codecov

codecov Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 45.83333% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 18.02%. Comparing base (c7667d8) to head (cc80ffe).

Files with missing lines Patch % Lines
.../network/dao/Ipv4GuestSubnetNetworkMapDaoImpl.java 0.00% 6 Missing ⚠️
...loudstack/network/Ipv4GuestSubnetNetworkMapVO.java 37.50% 5 Missing ⚠️
...ache/cloudstack/network/RoutedIpv4ManagerImpl.java 80.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               4.22   #14421      +/-   ##
============================================
- Coverage     18.03%   18.02%   -0.01%     
+ Complexity    16286    16282       -4     
============================================
  Files          5937     5937              
  Lines        536771   536782      +11     
  Branches      65782    65782              
============================================
- Hits          96787    96762      -25     
- Misses       428932   428968      +36     
  Partials      11052    11052              
Flag Coverage Δ
uitests 4.04% <ø> (ø)
unittests 19.10% <45.83%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

private Long parentId;

@Column(name = "data_center_id")
private Long dataCenterId;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should listing subnets by zone use this column too? right now it only matches through the zone subnet, so ones made without a zone subnet dont show up when you filter by zone

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thanks @Damans227 and it’s a bit worse than parentless rows. The zoneid filter resolves the zone through dc_ip4_guest_subnets:

List<DataCenterIpv4GuestSubnetVO> subnets = dataCenterIpv4GuestSubnetDao.listByDataCenterId(zoneId);
if (CollectionUtils.isEmpty(subnets)) {
    return new ArrayList<>();
}
sc.addAnd("parentId", SearchCriteria.Op.IN, parentIds.toArray());

So if the zone has no zone-level subnet configured at all, the list returns empty even when routed VPCs exist there , which is exactly the setup in #14419. createIpv4SubnetForGuestNetworkResponse has the same gap: zoneId is only derived from the network, VPC or parent, so a parentless unassigned row reports no zone.

Now that the row carries the zone, I’ll replace the parent-id lookup with a direct data_center_id filter and add it as a fallback in the response (that needs getDataCenterId() on the Ipv4GuestSubnetNetworkMap interface). Rows that predate the upgrade and can’t be attributed to a zone keep data_center_id = NULL and still won’t show under a zone filter same as today, so no regression. Pushing shortly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed in d98069c , filter now uses data_center_id, and the response falls back to it for parentless subnets.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that covers it, thanks

@vladimirpetrov

Copy link
Copy Markdown
Contributor

@blueorangutan package

@blueorangutan

Copy link
Copy Markdown

@vladimirpetrov a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan

Copy link
Copy Markdown

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 19588

@prashanthr2

Copy link
Copy Markdown
Contributor Author

lgtm the SQL may be applied to 423to24.sql too

@weizhouapache Agreed. schema-42300to2400.sql only exists on main, so I can’t add it here , do you want me to raise a separate PR against main for it or will it be picked up in the forward-merge?

listIpv4SubnetsForGuestNetwork resolved the zoneid filter through
dc_ip4_guest_subnets, so a subnet with no parent never matched, and a zone
with no zone-level subnet returned an empty list. The response derived the
zone the same way, leaving parentless subnets with no zone at all.

Now that the record carries its zone, filter on data_center_id directly and
fall back to it when building the response.

Addresses review feedback on apache#14419.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017rnv8vT6LQSKfwkzp8tvg9

@Damans227 Damans227 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @prashanthr2, fix looks right. LGTM

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants