Skip to content

fix(network): relax constraints for resizing dynamic range reservations - #280

Open
bryanfraschetti wants to merge 6 commits into
canonical:masterfrom
bryanfraschetti:fix_dynamic_range_resizing
Open

fix(network): relax constraints for resizing dynamic range reservations#280
bryanfraschetti wants to merge 6 commits into
canonical:masterfrom
bryanfraschetti:fix_dynamic_range_resizing

Conversation

@bryanfraschetti

@bryanfraschetti bryanfraschetti commented May 27, 2026

Copy link
Copy Markdown

When an IP is allocated inside a dynamic range reservation, the validation performed during a resize sees the range as discontinuous, since an allocated IP splits the available space into separate contiguous blocks. As a result, both shrinking and expanding the reservation are rejected with "Requested dynamic range conflicts with an existing IP address or range", even when the requested change is otherwise valid.

This commit addresses the issue by comparing the requested range against the previously persisted range and requiring only the newly added segments (i.e., the expanded portions) to be contained within an unused range. Pure shrinks add no segments and are always allowed.

Resolves LP:2143090

@bryanfraschetti
bryanfraschetti requested a review from a team May 27, 2026 11:30
@maas-lander

Copy link
Copy Markdown
Collaborator

Check where you would like a Mattermost message to be sent to when CI completes and this PR is merged

  • Direct message
  • ~maas

@bryanfraschetti
bryanfraschetti force-pushed the fix_dynamic_range_resizing branch 2 times, most recently from 735e40e to fc872ef Compare May 27, 2026 13:15
r00ta

This comment was marked as outdated.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes validation for resizing existing dynamic IP ranges when there are already allocated IPs inside the current range, which previously caused the “Requested dynamic range conflicts…” error by treating the range as discontinuous.

Changes:

  • Updates dynamic range overlap validation to permit resizing when only the newly-added segments are within unused space.
  • Adds regression tests ensuring an existing dynamic range can shrink/expand even with an allocated IP inside the original range.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/maasserver/models/iprange.py Adjusts overlap/duplicate validation to allow certain dynamic-range resizes with in-range allocations.
src/maasserver/models/tests/test_iprange.py Adds tests covering shrink/expand of an existing dynamic range when an IP inside it is allocated.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/maasserver/models/iprange.py Outdated
Comment thread src/maasserver/models/tests/test_iprange.py
@tanzin8r

tanzin8r commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for the fix.

Implementation

  • Consider caching the original start, end, and subnet when the model is loaded from the database using from_db, so validation does not need an extra query on every clean().
  • The same overlap check exists in the v3 ipranges API. I can help with that part if you want.
  • When the range is moved to another subnet, the resize exception should not apply. Use full validation on the new subnet instead.

Testing

I ran additional cases on top of the PR tests, including the subnet-change guard.

Expected to pass on resize:

  1. Shrink end with lease inside pool
    Range 10–50, lease at .30, end changed to .49.
    Expected: clean() and save() succeed. Only addresses at the tail are removed; nothing new is claimed.

  2. Expand end with lease inside pool
    Range 10–50, lease at .30, end changed to .60.
    Expected: succeed. Only 51–60 is new and should be free. The lease inside the old range should not block this.
    I also checked on master without the fix: this fails with error from the bug report. With the PR it passes.

  3. Shrink start with lease inside pool
    Range 10–50, lease at .30, start changed to .15.
    Expected: succeed. Same idea as shrinking the end, but on the start boundary.

  4. Expand start into free space on the left
    Range 20–50, lease at .30, start changed to .10 with free space below 20.
    Expected: succeed. Only the new strip on the left must be free.

  5. Shrink end so lease ends up outside pool
    Range 10–50, lease at .30, end changed to .25.
    Expected: succeed. The lease is no longer inside the range after the change.

All of the above passed.

Expected to fail on resize:

  1. Expand end over a lease outside the old pool
    Range 10–20, lease at .25, end changed to .30.
    Expected: rejected. The new strip 21–30 includes an address that is already in use.

  2. Expand start over a lease outside the old pool
    Range 20–50, lease at .15, start changed to .10.
    Expected: rejected. The new strip 10–19 includes an address that is already in use.

  3. Move pool to another subnet over a busy IP
    Range moved to another subnet where the new bounds overlap a busy address.
    Expected: rejected. The resize exception should not apply; validation should run on the new subnet.

  4. Create new pool spanning an already-assigned IP
    New dynamic range 10–50 while .30 is already assigned on the subnet.
    Expected: rejected. The fix is for editing an existing range, not for creating one over a split gap.

All of the above were rejected as expected.

@tanzin8r

tanzin8r commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Nice work on the caching and subnet guard! Could you rebase onto upstream master when you get a chance? Some of the tests were failing are fixed there now.
On tests, I think you have the main bug covered already. The ones I would still add are the failure cases: expanding over a busy IP just outside the old pool on both start and end, a full clean() test when moving the range to another subnet that already has a clash, and one create-path test to make sure new ranges still get rejected if they span an already-assigned IP.

On v3 side, the logic lives in src/maasapiserver/v3/api/public/models/requests/ipranges.py inside to_builder(), called from update_fabric_vlan_subnet_iprange() in the handler. Subnet move is less of an issue there since the URL pins the subnet, but the resize-with-lease-inside-pool bug will still show up. We can create a seperate PR for that.

@bryanfraschetti
bryanfraschetti force-pushed the fix_dynamic_range_resizing branch from 22860a9 to 34b548d Compare June 10, 2026 12:20
@bryanfraschetti

bryanfraschetti commented Jun 10, 2026

Copy link
Copy Markdown
Author

Thanks for the review!

Good idea to add tests for the failure cases. I just rebased and added some tests to cover the ones you mentioned: resizing, moving, or creating dynamic ranges over a busy IP.

I'll look into the v3 API and put up changes in a separate PR. Thank you for the pointers regarding that

@tanzin8r

tanzin8r commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

lgtm. Thank you for the edits. Just one last test to make this concrete.

    def test_modify_existing_dynamic_range_can_expand_start_with_allocated_ip(
        self,
    ):
        subnet = make_plain_subnet()
        iprange = IPRange(
            subnet=subnet,
            type=IPRANGE_TYPE.DYNAMIC,
            start_ip="192.168.0.20",
            end_ip="192.168.0.50",
        )
        iprange.save()
        factory.make_StaticIPAddress(
            subnet=subnet,
            alloc_type=IPADDRESS_TYPE.AUTO,
            ip="192.168.0.30",
        )
        iprange.start_ip = "192.168.0.10"
        iprange.clean()
        iprange.save()

@tanzin8r tanzin8r left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

+1

@r00ta r00ta left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

questions inline

Comment thread src/maasserver/models/iprange.py
Comment thread src/maasserver/models/iprange.py
@bryanfraschetti
bryanfraschetti requested a review from r00ta July 27, 2026 14:05
@r00ta r00ta changed the title fix(network): Relax Constraints for Resizing Dynamic Range Reservations LP: #2143090 fix(network): relax constraints for resizing dynamic range reservations Jul 28, 2026

@r00ta r00ta left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

+1, thank you!

@r00ta
r00ta added this pull request to the merge queue Jul 28, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 28, 2026
@r00ta
r00ta enabled auto-merge July 28, 2026 09:52
@r00ta

r00ta commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

@bryanfraschetti there are test failures

…ns LP: #2143090

When an IP is allocated in a dynamic range reservation, the resize operation
validator views the range as discontinuous and instead sees multiple contiguous
blocks separated by each allocated IP. As a result, shrinking and expanding the
reservation are both rejected with "Requested dynamic range conflicts with an
existing IP address or range" despite the requested action being otherwise
sensible (LP: #2143090)

This commit addresses the issue by making sure the new boundaries are contained
by an unused range
…ging Subnets

Add tests to cover the expected failure of a resize over a busy IP, ensure that
moving a dynamic range to a new subnet with a busy IP fails validation, and
finally ensure that creation of a range over a busy IP is also disallowed
auto-merge was automatically disabled July 29, 2026 19:42

Head branch was pushed to by a user without write access

@bryanfraschetti
bryanfraschetti force-pushed the fix_dynamic_range_resizing branch from 1fe7d0f to df687ea Compare July 29, 2026 19:42
@bryanfraschetti

Copy link
Copy Markdown
Author

Thanks @r00ta! I fixed the failing tests by rebasing

@skatsaounis
skatsaounis requested a review from r00ta July 30, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants