Skip to content

Conversation

@stephenfin
Copy link
Contributor

@stephenfin stephenfin commented Nov 18, 2025

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • New Features

    • Automatic OpenStack infrastructure discovery and configuration for clusters (networking primitives and identity wiring).
  • Improvements

    • Stronger OpenStack validation with default subnet/router inference and clearer, consistent platform error handling; stricter PowerVS platform-status checks and unified error messages.
  • Tests

    • Added end-to-end OpenStack MachineSet tests for provisioning and template validation.
  • Chores

    • Updated project dependencies and simplified e2e test invocation.

✏️ Tip: You can customize this high-level summary in your review settings.

@openshift-ci-robot
Copy link

Pipeline controller notification
This repository is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. Review these jobs and use /test <job> to manually trigger optional jobs most likely to be impacted by the proposed changes.

@coderabbitai
Copy link

coderabbitai bot commented Nov 18, 2025

Walkthrough

Adds OpenStack infra discovery/creation logic and helpers, delegates OpenStack handling from the InfraCluster controller, infers default subnet/router from control-plane machines, adjusts PowerVS error handling, adds OpenStack e2e MachineSet test, and updates module dependencies.

Changes

Cohort / File(s) Summary
Dependency management
go.mod, e2e/go.mod
Added direct dependency github.com/gophercloud/gophercloud/v2 v2.9.0; added indirects github.com/gofrs/uuid/v5 v5.3.0, go.uber.org/mock v0.5.2; replaced an indirect reference and added github.com/gophercloud/utils/v2 v2.0.0-...; e2e/go.mod adds sigs.k8s.io/cluster-api-provider-openstack v0.12.4.
Infra controller
pkg/controllers/infracluster/infracluster_controller.go
Replaced inline OpenStackCluster retrieval with call to new ensureOpenStackCluster(ctx, log); removed unused OpenStack import alias; standardized PowerVS error message text.
OpenStack infra logic (new)
pkg/controllers/infracluster/openstack.go
New file implementing ensureOpenStackCluster(ctx, log) to validate platform status and LB type, discover Network/Router/ExternalNetwork and IdentityRef, create/update OpenStackCluster; added getDefaultSubnetFromMachines(...), getDefaultRouterFromSubnet(...), error variables, and structured logging.
PowerVS error constant
pkg/controllers/infracluster/powervs.go
Added package-level errInvalidPlatformStatus and replaced inline PlatformStatus nil error with this constant.
End-to-end tests & script
e2e/openstack_test.go, hack/e2e-openstack.sh
Added OpenStack e2e MachineSet test (provider spec extraction, OpenStackMachineTemplate creation, MachineSet lifecycle and cleanup); simplified hack/e2e-openstack.sh to exec make e2e (removed prior multi-step setup).

Sequence Diagram(s)

sequenceDiagram
    participant Ctrl as InfraClusterController
    participant Ens as ensureOpenStackCluster
    participant Sub as getDefaultSubnetFromMachines
    participant Rtr as getDefaultRouterFromSubnet
    participant KC as Kube API
    participant NC as OpenStack Network API

    Ctrl->>Ens: ensureOpenStackCluster(ctx, log)
    Ens->>Ens: validate PlatformStatus & LB type
    Ens->>Sub: getDefaultSubnetFromMachines(ctx,...)
    Sub->>KC: list control-plane Machines
    loop per machine
        Sub->>NC: list ports for instance
        Sub->>NC: map port -> subnet(s)
    end
    Sub-->>Ens: subnet or error
    Ens->>Rtr: getDefaultRouterFromSubnet(subnet)
    Rtr->>NC: find port for subnet gateway IP
    Rtr->>NC: fetch router & check external gateway
    Rtr-->>Ens: router or error
    rect rgb(220,235,220)
      Note over Ens: construct OpenStackCluster spec (Network, Router, ExternalNetwork, IdentityRef)
    end
    Ens->>KC: create/update OpenStackCluster resource
    Ens-->>Ctrl: OpenStackCluster object or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas: pkg/controllers/infracluster/openstack.go (discovery logic, OpenStack client interactions, error paths), getDefaultSubnetFromMachines (port→subnet mapping, CIDR checks), e2e/openstack_test.go (provider-spec assumptions, cleanup), and go.mod changes.

Poem

🐰 I hopped through ports and tunneled tracks,
I sniffed the subnets and traced routers back,
I stitched a spec with identity bright,
Tests hum, deps set — infra takes flight,
A little rabbit cheers into the night!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically identifies the main objective: migrating the OpenStack InfraCluster controller in-tree, aligning with the changeset's core purpose.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 16a833a and a2aa3f3.

⛔ Files ignored due to path filters (42)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/gophercloud/gophercloud/v2/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/endpoint_search.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/auth_env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/endpoint.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/endpoint_location.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/constants.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/constants.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/constants.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/constants.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/base_endpoint.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/choose_version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/discovery.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/provider_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/service_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (2)
  • e2e/go.mod (2 hunks)
  • go.mod (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • e2e/go.mod
  • go.mod

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 18, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign nrb for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/controllers/infracluster/powervs.go (1)

39-42: Shared errInvalidPlatformStatus sentinel is a reasonable consolidation

Switching to a package-level errInvalidPlatformStatus for the nil PlatformStatus case keeps behavior the same while making it easier to reuse and to assert on in tests. No functional issues spotted. If we end up using this sentinel from more controllers (as already done in the OpenStack path), consider moving it into a small shared errors.go in this package for discoverability.

Also applies to: 44-44, 74-76

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 5f7410a and ef23116.

⛔ Files ignored due to path filters (198)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/gofrs/uuid/v5/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/.pre-commit-config.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/codec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/error.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/generator.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/sql.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/uuid.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/auth_env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/endpoint_location.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/delegate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/base_endpoint.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/choose_version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/http.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/linked.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/marker.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/pager.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/pkg.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/single.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/client/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/client/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/env/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/env/env_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/gnocchi/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/gnocchi/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/internal/pkg.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/internal/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/AUTHORS is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/call.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/callset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/controller.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/matchers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/string.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/mockgen/model/model.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/compute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/compute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/network.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/volume.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/networking.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/volume.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/metrics/metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/mock.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/scope.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/openstack/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/openstack/microversion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/version/version.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (4)
  • go.mod (4 hunks)
  • pkg/controllers/infracluster/infracluster_controller.go (2 hunks)
  • pkg/controllers/infracluster/openstack.go (1 hunks)
  • pkg/controllers/infracluster/powervs.go (2 hunks)
🔇 Additional comments (3)
go.mod (1)

13-13: New OpenStack and testing dependencies look consistent with the new controller

The additions of gophercloud/v2, gophercloud/utils/v2, gofrs/uuid/v5, and go.uber.org/mock fit the new in-tree OpenStack InfraCluster controller and its tests; nothing stands out as problematic here. Please just make sure go.sum is updated and that these versions are compatible with the CAPO/OpenStack client versions you rely on in this repo.

Also applies to: 138-138, 152-152, 278-278

pkg/controllers/infracluster/infracluster_controller.go (1)

206-213: OpenStack and PowerVS branches in ensureInfraCluster are wired consistently

Delegating the OpenStack platform path to ensureOpenStackCluster and aligning the PowerVS error message with the other providers ("error getting InfraCluster object") keeps ensureInfraCluster uniform and pushes provider-specific logic into dedicated helpers. The control flow and error propagation here look sound.

Also applies to: 228-233

pkg/controllers/infracluster/openstack.go (1)

144-149: No explicit cleanup required — scope pattern is correct as-is

Verification confirms that openstackscope.NewFactory(...).NewClientScopeFromObject does not expose or require an explicit Close() call. The recommended usage pattern is to create a scope per reconciliation/operation (short-lived) and let it naturally go out of scope at the end of the controller reconcile. The current code follows this pattern correctly and requires no changes.

@stephenfin
Copy link
Contributor Author

stephenfin commented Nov 18, 2025

/retitle OSASINFRA-3960: Migrate OpenStack InfraCluster controller in-tree

@openshift-ci openshift-ci bot changed the title Migrate OpenStack InfraCluster controller in-tree OSASINFRA-3960: Migrate OpenStack InfraCluster controller in-tree Nov 18, 2025
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Nov 18, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 18, 2025

@stephenfin: This pull request references OSASINFRA-3960 which is a valid jira issue.

In response to this:

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • Improvements

  • Optimized OpenStack infrastructure cluster management with automated discovery and configuration of networking components.

  • Consolidated error handling for better consistency and clarity across platform-specific handlers.

  • Chores

  • Updated project dependencies to latest versions.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@stephenfin stephenfin force-pushed the migrate-openstack-infracluster-controller branch from ef23116 to 31fbbd1 Compare November 20, 2025 16:35
@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 20, 2025

@stephenfin: This pull request references OSASINFRA-3960 which is a valid jira issue.

In response to this:

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • New Features
  • Automatic OpenStack infrastructure discovery and configuration: networking primitives and identity wiring are inferred and applied for OpenStack clusters.
  • Improvements
  • More consistent and clearer platform error messages and handling across controllers.
  • Tests
  • Added end-to-end OpenStack MachineSet tests to validate provisioning and templates.
  • Chores
  • Updated project dependencies.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
pkg/controllers/infracluster/openstack.go (1)

156-163: Thread configurable MAPI namespace into getDefaultSubnetFromMachines (still effectively hard-coded)

getDefaultSubnetFromMachines currently always lists machines in defaultMAPINamespace:

if err := kubeclient.List(
    ctx,
    &mapiMachines,
    client.InNamespace(defaultMAPINamespace),
    client.MatchingLabels{"machine.openshift.io/cluster-api-machine-role": "master"},
); err != nil {
    ...
}

and ensureOpenStackCluster calls it without any namespace argument:

defaultSubnet, err := getDefaultSubnetFromMachines(ctx, log, r.Client, networkClient, platformStatus)

Even though other parts of the controller make the Machine API namespace configurable (via a MAPINamespace field / config), this helper bypasses that and will break OpenStack subnet discovery whenever MAPINamespace is overridden (tests, non‑standard installs, etc.). This is the same underlying issue that was previously flagged; only the literal string was replaced by a constant.

Consider passing the namespace through instead so discovery honors configuration, for example:

-func getDefaultSubnetFromMachines(ctx context.Context, log logr.Logger, kubeclient client.Client, networkClient openstackclients.NetworkClient, platformStatus *configv1.OpenStackPlatformStatus) (*subnets.Subnet, error) {
+func getDefaultSubnetFromMachines(
+	ctx context.Context,
+	log logr.Logger,
+	kubeclient client.Client,
+	networkClient openstackclients.NetworkClient,
+	platformStatus *configv1.OpenStackPlatformStatus,
+	machineNamespace string,
+) (*subnets.Subnet, error) {
@@
-	if err := kubeclient.List(
+	if err := kubeclient.List(
 		ctx,
 		&mapiMachines,
-		client.InNamespace(defaultMAPINamespace),
+		client.InNamespace(machineNamespace),
 		client.MatchingLabels{"machine.openshift.io/cluster-api-machine-role": "master"},
 	); err != nil {

and in ensureOpenStackCluster:

-	defaultSubnet, err := getDefaultSubnetFromMachines(ctx, log, r.Client, networkClient, platformStatus)
+	defaultSubnet, err := getDefaultSubnetFromMachines(ctx, log, r.Client, networkClient, platformStatus, r.MAPINamespace)

That keeps behavior identical for the default case while fixing configurations/tests that deliberately override MAPINamespace.

Also applies to: 235-245

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between ef23116 and 31fbbd1.

⛔ Files ignored due to path filters (199)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/gofrs/uuid/v5/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/.pre-commit-config.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/codec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/error.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/generator.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/sql.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/uuid.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/auth_env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/endpoint_location.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/delegate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/base_endpoint.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/choose_version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/http.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/linked.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/marker.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/pager.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/pkg.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/single.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/client/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/client/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/env/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/env/env_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/gnocchi/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/gnocchi/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/internal/pkg.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/internal/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/AUTHORS is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/call.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/callset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/controller.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/matchers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/string.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/mockgen/model/model.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/compute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/compute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/network.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/volume.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/networking.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/volume.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/metrics/metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/mock.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/scope.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/openstack/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/openstack/microversion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/version/version.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (6)
  • e2e/go.mod (2 hunks)
  • e2e/openstack_test.go (1 hunks)
  • go.mod (4 hunks)
  • pkg/controllers/infracluster/infracluster_controller.go (2 hunks)
  • pkg/controllers/infracluster/openstack.go (1 hunks)
  • pkg/controllers/infracluster/powervs.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/controllers/infracluster/infracluster_controller.go
🔇 Additional comments (3)
e2e/go.mod (1)

24-24: OpenStack e2e dependencies look consistent with the main module

Adding cluster-api-provider-openstack v0.12.4 and gophercloud/v2 v2.7.0 here matches the root module and aligns with the new OpenStack e2e coverage; no issues from a dependency-graph standpoint. Just ensure go mod tidy for ./e2e stays clean as follow‑ups land.

Also applies to: 67-67

go.mod (1)

13-13: New OpenStack and test support dependencies look appropriate

Direct gophercloud/v2 plus gophercloud/utils/v2, gofrs/uuid/v5, and go.uber.org/mock are all consistent with the new OpenStack infracluster controller and its tests; nothing stands out as problematic here. Just keep an eye on module tidy/upgrade drift as CAPO/gophercloud rev over time.

Also applies to: 138-138, 152-152, 278-278

pkg/controllers/infracluster/powervs.go (1)

38-42: Shared errInvalidPlatformStatus sentinel is a good consolidation

Switching the PowerVS PlatformStatus == nil path to reuse errInvalidPlatformStatus keeps behavior the same while giving you a reusable, comparable error across platforms (and matches the new OpenStack controller). No further changes needed here.

Also applies to: 74-76

@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 20, 2025

@stephenfin: This pull request references OSASINFRA-3960 which is a valid jira issue.

In response to this:

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • New Features
  • Automatic OpenStack infrastructure discovery and configuration: networking primitives and identity wiring inferred and applied for OpenStack clusters.
  • Improvements
  • Improved OpenStack validation and clearer, more consistent platform error handling.
  • Tests
  • Added end-to-end OpenStack MachineSet tests to validate provisioning and templates.
  • Chores
  • Updated project dependencies and simplified e2e test invocation.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@stephenfin
Copy link
Contributor Author

/test ci/prow/e2e-openstack-capi-techpreview

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 20, 2025

@stephenfin: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test build
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test images
/test lint
/test okd-scos-images
/test unit
/test vendor
/test verify-deps

The following commands are available to trigger optional jobs:

/test e2e-azure-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test okd-scos-e2e-aws-ovn
/test regression-clusterinfra-aws-ipi-techpreview-capi

Use /test all to run the following jobs that were automatically triggered:

pull-ci-openshift-cluster-capi-operator-main-build
pull-ci-openshift-cluster-capi-operator-main-images
pull-ci-openshift-cluster-capi-operator-main-lint
pull-ci-openshift-cluster-capi-operator-main-okd-scos-images
pull-ci-openshift-cluster-capi-operator-main-unit
pull-ci-openshift-cluster-capi-operator-main-vendor
pull-ci-openshift-cluster-capi-operator-main-verify-deps

In response to this:

/test ci/prow/e2e-openstack-capi-techpreview

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 20, 2025

@stephenfin: This pull request references OSASINFRA-3960 which is a valid jira issue.

In response to this:

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • New Features

  • Automatic OpenStack infrastructure discovery and configuration for clusters (networking primitives and identity wiring).

  • Improvements

  • Enhanced OpenStack validation and clearer, more consistent platform error handling (including PowerVS error messaging and platform-status validation).

  • Tests

  • Added end-to-end OpenStack MachineSet tests for provisioning and template validation.

  • Chores

  • Updated project dependencies and simplified e2e test invocation.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
e2e/openstack_test.go (1)

114-116: Add bounds check before accessing SecurityGroups[0].

The previous review identified that line 116 directly indexes mapiProviderSpec.SecurityGroups[0] without verifying the slice length, which will panic if SecurityGroups is empty. This issue remains unresolved.

Add a guard before line 116:

 // NOTE(stephenfin): We intentionally ignore additional security for now.
+Expect(len(mapiProviderSpec.SecurityGroups)).To(BeNumerically(">", 0))
 var securityGroupParam openstackv1.SecurityGroupParam
 securityGroup := mapiProviderSpec.SecurityGroups[0]
🧹 Nitpick comments (1)
e2e/openstack_test.go (1)

152-154: Remove or uncomment the DeferCleanup code.

Lines 152-154 contain commented-out cleanup code for the OpenStackMachineTemplate. If cleanup is intentionally deferred to the parent MachineSet deletion, remove these lines entirely. Otherwise, uncomment them to ensure proper resource cleanup.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 51c9832 and 5d3b5a7.

📒 Files selected for processing (1)
  • e2e/openstack_test.go (1 hunks)
🔇 Additional comments (1)
e2e/openstack_test.go (1)

95-112: Image handling now correctly addresses boot-from-volume case.

The previous review concern about the image field being empty when RootVolume is set has been resolved. Line 109 now correctly assigns image.ID = ptr.To(mapiProviderSpec.RootVolume.SourceUUID), ensuring the CAPO ImageParam is properly populated for boot-from-volume deployments.

@stephenfin stephenfin force-pushed the migrate-openstack-infracluster-controller branch from 5d3b5a7 to a831353 Compare November 20, 2025 18:09
@stephenfin
Copy link
Contributor Author

/test e2e-openstack-capi-techpreview

@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 20, 2025

@stephenfin: This pull request references OSASINFRA-3960 which is a valid jira issue.

In response to this:

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • New Features

  • Automatic OpenStack infrastructure discovery and configuration for clusters (networking primitives and identity wiring).

  • Improvements

  • Stronger OpenStack validation and clearer, consistent platform error handling (including PowerVS platform-status validation and message consistency).

  • Tests

  • Added end-to-end OpenStack MachineSet tests for provisioning and template validation.

  • Chores

  • Updated project dependencies and simplified e2e test invocation.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@stephenfin
Copy link
Contributor Author

/assign @mandre

@mandre
Copy link
Member

mandre commented Nov 21, 2025

/test e2e-openstack-capi-techpreview

err will always be nil in the context of this error.

Signed-off-by: Stephen Finucane <[email protected]>
Previously, this was managed out-of-tree in the openshift fork of
cluster-api-provider-openstack. This has proven difficult to maintain,
and other platforms have not followed suit. Time to change course and
align with what everyone else is doing.

Signed-off-by: Stephen Finucane <[email protected]>
Signed-off-by: Stephen Finucane <[email protected]>
Signed-off-by: Stephen Finucane <[email protected]>
Signed-off-by: Stephen Finucane <[email protected]>
@stephenfin stephenfin force-pushed the migrate-openstack-infracluster-controller branch from a831353 to 16a833a Compare November 21, 2025 17:23
@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 21, 2025

@stephenfin: This pull request references OSASINFRA-3960 which is a valid jira issue.

In response to this:

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • New Features

  • Automatic OpenStack infrastructure discovery and configuration for clusters (networking primitives and identity wiring).

  • Improvements

  • Stronger OpenStack validation and clearer, consistent platform error handling, including stricter PowerVS platform-status checks.

  • Tests

  • Added end-to-end OpenStack MachineSet tests for provisioning and template validation.

  • Chores

  • Updated project dependencies and simplified e2e test invocation.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
pkg/controllers/infracluster/openstack.go (1)

235-245: Honor configurable MAPI namespace instead of defaultMAPINamespace

getDefaultSubnetFromMachines currently lists control plane machines using client.InNamespace(defaultMAPINamespace). Elsewhere in this controller MAPINamespace is intentionally configurable (with defaultMAPINamespace only used as a fallback in SetupWithManager). Hard‑coding the default here means:

  • Tests that override r.MAPINamespace won’t be able to exercise this path.
  • Non‑standard deployments using a different machine namespace will fail OpenStack subnet discovery.

Consider threading the namespace through rather than using the constant, e.g.:

-func getDefaultSubnetFromMachines(ctx context.Context, log logr.Logger, kubeclient client.Client, networkClient openstackclients.NetworkClient, platformStatus *configv1.OpenStackPlatformStatus) (*subnets.Subnet, error) {
+func getDefaultSubnetFromMachines(
+	ctx context.Context,
+	log logr.Logger,
+	kubeclient client.Client,
+	networkClient openstackclients.NetworkClient,
+	platformStatus *configv1.OpenStackPlatformStatus,
+	machineNamespace string,
+) (*subnets.Subnet, error) {
@@
-	if err := kubeclient.List(
+	if err := kubeclient.List(
 		ctx,
 		&mapiMachines,
-		client.InNamespace(defaultMAPINamespace),
+		client.InNamespace(machineNamespace),
 		client.MatchingLabels{"machine.openshift.io/cluster-api-machine-role": "master"},
 	); err != nil {

and in ensureOpenStackCluster:

-	defaultSubnet, err := getDefaultSubnetFromMachines(ctx, log, r.Client, networkClient, platformStatus)
+	defaultSubnet, err := getDefaultSubnetFromMachines(ctx, log, r.Client, networkClient, platformStatus, r.MAPINamespace)

That keeps behavior identical in the default case while respecting the configurable namespace.

🧹 Nitpick comments (3)
pkg/controllers/infracluster/powervs.go (1)

38-42: Shared errInvalidPlatformStatus usage looks good

Using a single package‑level errInvalidPlatformStatus and reusing it here simplifies callers that want to special‑case “no PlatformStatus” and keeps the message consistent. If more platforms start using it (as OpenStack already does), consider moving it to a small shared errors.go in this package for discoverability, but this is purely cosmetic.

Also applies to: 74-76

pkg/controllers/infracluster/infracluster_controller.go (1)

206-233: OpenStack/PowerVS branches are wired correctly into ensureInfraCluster

Delegating OpenStack via ensureOpenStackCluster and aligning the PowerVS error wrapping with the other platforms is consistent and keeps the reconcile path uniform. The only nit is the slightly generic "error getting InfraCluster object" message, which now covers several provider‑specific ensure* helpers, but it’s acceptable as‑is.

pkg/controllers/infracluster/openstack.go (1)

91-106: Minor robustness improvements for OpenStack platform validation and discovery

The overall flow in ensureOpenStackCluster and the discovery helpers looks good, but a few small tweaks would make it more defensive without changing the behavior:

  1. Guard PlatformStatus.OpenStack explicitly

You already check r.Infra.Status.PlatformStatus != nil, but PlatformStatus.OpenStack could still be nil in theory. A quick guard avoids a potential nil dereference if the infra object is malformed:

-	platformStatus := r.Infra.Status.PlatformStatus.OpenStack
+	platformStatus := r.Infra.Status.PlatformStatus.OpenStack
+	if platformStatus == nil {
+		return nil, fmt.Errorf("%w: missing OpenStack platform status", errInvalidPlatformStatus)
+	}
  1. Handle malformed APIServerInternalIPs more explicitly

In getDefaultSubnetFromMachines, net.ParseIP returning nil will silently produce a “no matches” outcome. If you want clearer failure modes, you could either:

  • Drop invalid entries with a log line, or
  • Fail fast on the first malformed IP.

For example (drop invalid):

	for i, ipStr := range platformStatus.APIServerInternalIPs {
-		apiServerInternalIPs[i] = net.ParseIP(ipStr)
+		ip := net.ParseIP(ipStr)
+		if ip == nil {
+			log.V(2).Info("Skipping malformed APIServerInternalIP", "ip", ipStr)
+			continue
+		}
+		apiServerInternalIPs[i] = ip
	}
  1. Don’t hard‑fail on a single instance with no ports

Right now, the first control plane machine that has zero Neutron ports causes an error:

if len(ports) == 0 {
    return nil, fmt.Errorf("%w: no ports found for instance %s", errOpenStackNoDefaultSubnet, instanceID)
}

If one machine is misconfigured but others are fine, this prevents falling back to them. Consider logging and continue instead:

-		if len(ports) == 0 {
-			return nil, fmt.Errorf("%w: no ports found for instance %s", errOpenStackNoDefaultSubnet, instanceID)
-		}
+		if len(ports) == 0 {
+			log.V(3).Info("Skipping machine: no ports found", "instanceID", instanceID)
+			continue
+		}

The final "no matching subnets found" error still captures the overall failure while making the heuristic more tolerant of one-off anomalies.

None of these are blockers, but they would make the controller more resilient and easier to debug in odd environments.

Also applies to: 118-139, 141-175, 247-319

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a831353 and 16a833a.

⛔ Files ignored due to path filters (205)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/gofrs/uuid/v5/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/.pre-commit-config.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/codec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/error.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/generator.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/sql.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gofrs/uuid/v5/uuid.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/endpoint_search.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/auth_env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/common/extensions/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/attachinterfaces/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/availabilityzones/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/endpoint_location.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tenants/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imagedata/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/imageimport/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/image/v2/images/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/apiversions/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/listeners/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/pools/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/providers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/attributestags/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/delegate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets/urls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/base_endpoint.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/openstack/utils/choose_version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/http.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/linked.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/marker.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/pager.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/pkg.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/pagination/single.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/provider_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/service_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/gophercloud/v2/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/client/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/client/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/env/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/env/env_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/gnocchi/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/gnocchi/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/internal/pkg.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/internal/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/requests.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/results.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/gophercloud/utils/v2/openstack/clientconfig/utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/AUTHORS is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/call.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/callset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/controller.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/matchers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/gomock/string.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.uber.org/mock/mockgen/model/model.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/compute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/compute.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/image.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/network.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/mock/volume.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/networking.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/clients/volume.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/metrics/metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/mock.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/scope/scope.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/openstack/loadbalancer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/openstack/microversion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api-provider-openstack/version/version.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (7)
  • e2e/go.mod (2 hunks)
  • e2e/openstack_test.go (1 hunks)
  • go.mod (4 hunks)
  • hack/e2e-openstack.sh (1 hunks)
  • pkg/controllers/infracluster/infracluster_controller.go (2 hunks)
  • pkg/controllers/infracluster/openstack.go (1 hunks)
  • pkg/controllers/infracluster/powervs.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • hack/e2e-openstack.sh
  • e2e/openstack_test.go
  • e2e/go.mod
  • go.mod

v2.7.0 had issues with endpoint detection.

Signed-off-by: Stephen Finucane <[email protected]>
@stephenfin stephenfin force-pushed the migrate-openstack-infracluster-controller branch from 16a833a to a2aa3f3 Compare November 21, 2025 18:23
@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 21, 2025

@stephenfin: This pull request references OSASINFRA-3960 which is a valid jira issue.

In response to this:

This currently lives out-of-tree in the openshift directory of openshift/cluster-api-provider-openstack. While there were good reasons to pursue this approach initially, no one else has followed suit, leaving us (OpenStack) as the odd ones out. The current model also introduces dependency issues due to conflicts between the requires of the InfraCluster controller, CCAPIO, and CAPO itself.

The solution is to move the controller in-tree. This is broadly modeled on the existing controller - with some tweaks to align with the existing controllers. Reviewers will likely find it easiest to open the new controller module alongside the legacy one for visual diffing.

e2e tests will be added once this approach is confirmed as reasonable.

Summary by CodeRabbit

  • New Features

  • Automatic OpenStack infrastructure discovery and configuration for clusters (networking primitives and identity wiring).

  • Improvements

  • Stronger OpenStack validation with default subnet/router inference and clearer, consistent platform error handling; stricter PowerVS platform-status checks and unified error messages.

  • Tests

  • Added end-to-end OpenStack MachineSet tests for provisioning and template validation.

  • Chores

  • Updated project dependencies and simplified e2e test invocation.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 21, 2025

@stephenfin: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-openstack-capi-techpreview a831353 link true /test e2e-openstack-capi-techpreview
ci/prow/vendor a2aa3f3 link true /test vendor

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants