Skip to content

fix(ibm): respect configured zone for custom VPC subnets - #528

Open
Gisaldjo wants to merge 2 commits into
canonical:mainfrom
Gisaldjo:feat/filter-subnets-by-zone
Open

Gisaldjo wants to merge 2 commits into
canonical:mainfrom
Gisaldjo:feat/filter-subnets-by-zone

Conversation

@Gisaldjo

@Gisaldjo Gisaldjo commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Description

Custom IBM VPC discovery previously selected the first subnet in the VPC, regardless of the instance zone. Instance creation failed when the zones differed.

Select a subnet in the instance's current zone, creating one there if none exists. Initial zone resolution is unchanged: explicit argument, configuration, then <region>-1.

Default-VPC selection is unchanged and was already zone-aware.

Additional Context and Relevant Issues

Subnets created in existing VPCs use <vpc>-<zone>-subnet. This longer name can exceed IBM's subnet-name limit for VPC names whose previous <vpc>-subnet name fit. Name truncation is not addressed in this PR.

Creating a missing subnet requires subnet-creation permissions and available address space.

Updates IBM documentation and bumps the version to 1!11.1.9.

Test Steps

  • Previous default tox run passed Ruff, mypy, and all 323 Python 3.8 unit tests.
  • All 7 IBM instance unit tests passed.
  • Live custom-VPC subnet-selection regression test passed
  • Live instance launch and SSH access passed

@Gisaldjo
Gisaldjo marked this pull request as ready for review September 9, 2026 11:45
@Gisaldjo
Gisaldjo requested a review from blackboxsw September 9, 2026 11:47
Comment thread pycloudlib/ibm/instance.py Outdated
Comment thread pycloudlib/ibm/cloud.py Outdated
self.region = str(region or self.config.get("region")).lower()
zone = zone or self.config.get("zone") or f"{self.region}-1"
self.zone = str(zone).lower()
configured_zone = zone or self.config.get("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.

@blackboxsw I went back and forth on preserving the existing behavior where, without an explicit zone, pycloudlib selects the first available subnet. My current proposed change here would preserve existing behavior when no zone is explicitly provided by the user.

But I'm having second thoughts. I am leaning toward always filtering subnets based on self.zone. A subnet in a different zone cannot be used to create an instance in any case. When no zone is configured, pycloudlib already defaults self.zone to {region}-1; selecting a subnet in that zone seems more correct than selecting the first subnet returned by the API.

This would let us remove the _zone_provided / configured_zone workaround. What do you think?

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.

@Gisaldjo thank you for this discussion. I think your second proposal makes more sense. Tracking whether or not _zone_provided does add complexity and more 'magic' as to how subnets are filtered or created. Let's define the zone selection based on self.zone and default to {region}-1 if unset. The _select_subnet_by_zone parameter does feel like it makes the magic zone selection a bit more complicated and makes call signatures more complex than they need to be. I think just passing in self.zone which may default to {region}-1 if unset would make this logic simpler throughout. If we have overrides to provide during _Subnet.discover in the future, we can provide a specific zone value to that method to get alternative discovery needs met.

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.

If we need to break from existing magic detection behavior, I'm happy with us bumping the major version to account for that behavior change. As it is I don't think integration tests in cloud-init or ubuntu-advantage-client are specific enough to care. Our pycloudlib.toml files for both projects define a zone value, so changing how default selection behaves in absence of a configured zone shouldn't break any consumers I am aware of.

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.

One thing to confirm CPC-side is whether there are any supported test harnesses that expect to avoid providing a configured "zone" for pycloudlib test setup. In either case, if a major bump in version from 11 -> 12 is just a number if we want to be safe about behavior changes here with unspecified values.

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.

@blackboxsw I’ve updated the PR to always select a subnet in the instance’s resolved zone, including the existing -1 default.

I tested the pycloudlib changes against our test harness and validated that they work both in our current usage (default vpc, try instance launch on all zones) and in the case that would fail due to subnet selection (custom vpc, try on all zones).

Happy to do a major bump to keep it extra safe but it's likely not needed.

Comment thread pycloudlib/ibm/.kb/ibm.md Outdated
Subnet discovery for a custom VPC picked the first subnet in the VPC,
so instance creation failed when that subnet was in another zone.
Select a subnet in the instance zone (explicit, configured, or
<region>-1) instead, creating <vpc>-<zone>-subnet if none exists.
@Gisaldjo
Gisaldjo force-pushed the feat/filter-subnets-by-zone branch from f7635a7 to ce1a398 Compare September 30, 2026 15:59
@Gisaldjo
Gisaldjo requested a review from blackboxsw October 1, 2026 17:03

@blackboxsw blackboxsw 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.

Thank you for this update @Gisaldjo. this looks good, one nit is that we aren't cleaning up the created subnet when we are using pre-existing custom VPCs where we had to create a subnet in the right zone. Other than that, this looks very good.

subnet = _Subnet.discover(client, vpc_id=vpc["id"])
subnet = _Subnet.discover(client, vpc_id=vpc["id"], zone=zone)
except IBMException:
subnet = _Subnet.create(

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.

In cases where we have a pre-existing custom VPC, and we don't discover a subnet in the proper zone, we have created a new _Subnet, but we don't track self.subnets_created to ensure that pycloudlib-created resources are removed during "clean". We should probably track those created subnets that were created in the proper zone due to VPC.from_existing so that we can loop through any created subnets because pycloudlib isn't going to call vpc.delete() on pre-existing VPCs.

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.

Nice catch! I updated the PR to track the created subnets for existing VPCs.

When a custom VPC has no subnet in the instance zone, one is created
in it. That VPC is not tracked for deletion, so the subnet was left
behind after clean(). Track these subnets in created_subnets and
delete them in clean(), leaving the VPC and its other subnets intact.
@Gisaldjo
Gisaldjo requested a review from blackboxsw October 6, 2026 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants