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 automated OpenStackCluster creation/population (network, router, external network, identity wiring).
  • Improvements

    • Enhanced OpenStack validation with default subnet/router inference and clearer, consistent platform error messages; stricter PowerVS platform-status checks.
    • Added image mapping to enable OpenStack controllers.
  • Tests

    • End-to-end OpenStack MachineSet integration test for provisioning and template validation.
  • Chores

    • Updated dependencies, simplified e2e script, and added credentials requests for OpenStack and PowerVS.

✏️ 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-specific infra discovery and OpenStackCluster creation to the InfraCluster controller, delegates OpenStack handling to a new ensureOpenStackCluster routine, implements subnet/router discovery from control-plane machines, adjusts PowerVS error handling, adds OpenStack e2e test and scheme registration, and updates images/manifests and dependencies.

Changes

Cohort / File(s) Summary
Dependency management
go.mod, e2e/go.mod
Added OpenStack-related dependencies: github.com/gophercloud/gophercloud/v2 v2.9.0 (direct), github.com/gophercloud/utils/v2 v2.0.0-... (indirect replace), github.com/gofrs/uuid/v5 v5.3.0 (indirect), go.uber.org/mock v0.5.2 (indirect); e2e/go.mod adds sigs.k8s.io/cluster-api-provider-openstack v0.12.4.
Infra controller changes
pkg/controllers/infracluster/infracluster_controller.go
Replaced inline OpenStackCluster retrieval with call to new ensureOpenStackCluster(ctx, log); removed unused OpenStack API import alias; normalized PowerVS error message text.
OpenStack infra logic (new)
pkg/controllers/infracluster/openstack.go
New file implementing ensureOpenStackCluster, subnet/router discovery helpers (getDefaultSubnetFromMachines, getDefaultRouterFromSubnet), error variables, OpenStack network/router/external-network wiring, identityRef assignment, resource create/update, and structured logging.
PowerVS error constant
pkg/controllers/infracluster/powervs.go
Added errInvalidPlatformStatus and replaced inline PlatformStatus nil error usage.
E2E tests & helpers
e2e/openstack_test.go, e2e/e2e_common.go, hack/e2e-openstack.sh
Added OpenStack e2e MachineSet test and helper functions; registered OpenStack API scheme in test init; simplified hack/e2e-openstack.sh to directly exec make e2e.
Images and manifests
dev-images.json, manifests/0000_30_cluster-api_01_images.configmap.yaml, manifests/image-references
Added image entry and mapping for openstack-cluster-api-controllers to dev-images, images.configmap, and image-references.
CAPI component customizer
pkg/controllers/capiinstaller/component_customizer.go
Added providerNameToImageKey case for "openstack" returning "openstack-cluster-api-controllers".

Sequence Diagram(s)

sequenceDiagram
    participant Ctrl as InfraClusterController
    participant Ens as ensureOpenStackCluster
    participant Sub as getDefaultSubnetFromMachines
    participant Rtr as getDefaultRouterFromSubnet
    participant KC as Kubernetes 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 ports → subnets
    end
    Sub-->>Ens: return subnet or error
    Ens->>Rtr: getDefaultRouterFromSubnet(subnet)
    Rtr->>NC: find port for subnet gateway IP
    Rtr->>NC: fetch router & verify external gateway
    Rtr-->>Ens: router or error
    Ens->>KC: create/update OpenStackCluster with Network/Router/ExternalNetwork/IdentityRef
    Ens-->>Ctrl: return OpenStackCluster object or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Files needing focused review:
    • pkg/controllers/infracluster/openstack.go — OpenStack API interactions, error handling, resource creation, and identityRef wiring.
    • pkg/controllers/infracluster/infracluster_controller.go — integration with new ensureOpenStackCluster flow.
    • getDefaultSubnetFromMachines logic — machine-to-port/subnet mapping and CIDR containment.
    • getDefaultRouterFromSubnet — router discovery and external gateway validation.
    • e2e/openstack_test.go and e2e/e2e_common.go — test correctness and scheme registration.
    • Manifest/image entries — image keys and credentials requests.

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, images set — infra wakes to light,
A tiny rabbit twitches whiskers in delight.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 title clearly references the main objective: migrating the OpenStack InfraCluster controller in-tree. It is specific, concise, and directly summarizes the primary change.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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.

Details

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.

Details

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.

Details

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
Details

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.

Details

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.

Details

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

Details

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

As noted inline, we actually want CAPO's OpenStackCluster controller to
reconcile our OpenStackCluster objects, since this is the thing that
populates the .Status attribute on same.

Signed-off-by: Stephen Finucane <[email protected]>
Align us with the other providers.

Signed-off-by: Stephen Finucane <[email protected]>
@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 28, 2025

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

Details

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 automated OpenStackCluster creation/population (network, router, external network, identity wiring).

  • Improvements

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

  • Added image mapping to select OpenStack controllers.

  • Tests

  • End-to-end OpenStack MachineSet integration test for provisioning and template validation.

  • Chores

  • Updated dependencies and simplified e2e test script; added credentials requests for OpenStack and PowerVS.

✏️ 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)

235-243: Hard-coded namespace breaks configurability.

Line 239 uses defaultMAPINamespace instead of the controller's configurable MAPINamespace field. This prevents the function from working correctly when MAPINamespace is overridden for tests or non-standard deployments.

As previously noted in past reviews, consider threading the namespace through as a parameter:

 func getDefaultSubnetFromMachines(
 	ctx context.Context,
 	log logr.Logger,
 	kubeclient client.Client,
 	networkClient openstackclients.NetworkClient,
 	platformStatus *configv1.OpenStackPlatformStatus,
+	machineNamespace string,
 ) (*subnets.Subnet, error) {
 	mapiMachines := mapiv1beta1.MachineList{}
 	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 update the caller on line 154:

-	defaultSubnet, err := getDefaultSubnetFromMachines(ctx, log, r.Client, networkClient, platformStatus)
+	defaultSubnet, err := getDefaultSubnetFromMachines(ctx, log, r.Client, networkClient, platformStatus, r.MAPINamespace)
📜 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 7deb04d and 2169beb.

📒 Files selected for processing (2)
  • e2e/openstack_test.go (1 hunks)
  • pkg/controllers/infracluster/openstack.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/openstack_test.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/controllers/infracluster/openstack.go (2)
pkg/controllers/infracluster/infracluster_controller.go (1)
  • InfraClusterController (74-83)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
🔇 Additional comments (6)
pkg/controllers/infracluster/openstack.go (6)

1-44: LGTM!

License, package declaration, and imports are appropriate for the OpenStack InfraCluster controller implementation.


60-107: LGTM!

The validation logic correctly checks for OpenStackCluster existence, validates platform status, ensures supported load balancer type, and verifies APIServerInternalIPs are present.


139-147: Reminder: Resolve the caCertificates FIXME.

Based on past review comments, this empty caCertificates initialization is pending confirmation from @mdbooth regarding whether it should be removed or properly sourced. The current implementation may cause issues with self-signed certificates.


154-171: LGTM!

The network discovery logic correctly retrieves the default subnet from control plane machines, derives the router from the subnet, and populates the OpenStackCluster spec with appropriate network, router, and external network references.


185-223: LGTM!

The router discovery logic correctly identifies the router by finding the port associated with the subnet's gateway IP, then validates the router has an external gateway. The documented gophercloud limitation is appropriately noted.


254-317: LGTM!

The subnet discovery logic correctly iterates through control plane machines, examines their network ports, and identifies the subnet whose CIDR contains the API server internal IPs. The detailed debug logging and comprehensive error handling are well-implemented.

We were doing this implicitly by not initialising the variable. Do so
explicitly instead.

Signed-off-by: Stephen Finucane <[email protected]>
@stephenfin stephenfin force-pushed the migrate-openstack-infracluster-controller branch from d0b7fd2 to a028609 Compare December 1, 2025 14:51
@openshift-ci-robot
Copy link

openshift-ci-robot commented Dec 1, 2025

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

Details

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 automated OpenStackCluster creation/population (network, router, external network, identity wiring).

  • Improvements

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

  • Added image mapping to enable OpenStack controllers.

  • Tests

  • End-to-end OpenStack MachineSet integration test for provisioning and template validation.

  • Chores

  • Updated dependencies, simplified e2e script, and added credentials requests for OpenStack and PowerVS.

✏️ 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-235: Use configurable r.MAPINamespace instead of defaultMAPINamespace.

The hard-coded defaultMAPINamespace constant bypasses the controller's configurable MAPINamespace field, which will break subnet discovery in test environments or non-standard deployments where the namespace is overridden.

Apply this diff to use the configurable namespace:

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

Alternative (simpler): Thread r.MAPINamespace as a parameter:

-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) {
 	mapiMachines := mapiv1beta1.MachineList{}
 	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 update the caller at line 150:

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

Based on learnings, this is a previously flagged issue that should be addressed to ensure the controller honors configured namespaces in all environments.

🧹 Nitpick comments (2)
pkg/controllers/infracluster/openstack.go (2)

75-85: Clarify whether API URL parsing is needed.

The FIXME comment indicates uncertainty about whether the API URL parsing logic (used by other providers) should be implemented for OpenStack. This commented-out code would extract host and port from r.Infra.Status.APIServerInternalURL, instead of the current hard-coded approach at lines 117-118.

If this is a known limitation to address before GA, consider opening a tracking issue.

Do you want me to open an issue to track this decision, or can you confirm the current hard-coded approach (using the first APIServerInternalIP and port 6443) is correct for OpenStack?


188-191: Consider adding a link to the gophercloud issue.

The XXX comment references a gophercloud limitation but doesn't link to the issue. Adding the issue URL would help future maintainers track when this workaround can be removed.

 				// XXX: We should search on both subnet and IP
 				// address here, but can't because of
-				// https://github.com/gophercloud/gophercloud/issues/2807
+				// https://github.com/gophercloud/gophercloud/issues/2807.
+				// Remove this workaround once the issue is resolved.
 				// SubnetID:  subnet.ID,
📜 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 2169beb and a028609.

📒 Files selected for processing (1)
  • pkg/controllers/infracluster/openstack.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/controllers/infracluster/openstack.go (2)
pkg/controllers/infracluster/infracluster_controller.go (1)
  • InfraClusterController (74-83)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
🔇 Additional comments (7)
pkg/controllers/infracluster/openstack.go (7)

1-51: LGTM!

The package declaration, imports, and sentinel error variables are well-structured and appropriate for OpenStack infrastructure cluster management.


95-98: LGTM – LoadBalancer type validation is appropriate.

Validating that only LoadBalancerTypeOpenShiftManagedDefault is supported ensures the subnet discovery heuristic (which relies on this load balancer type) will work correctly.


145-148: LGTM – Error message correctly identifies network client creation.

The error message accurately reflects that a network client (not compute) is being created. This addresses a previous review concern.


150-176: LGTM – Network discovery and cluster creation logic is sound.

The flow correctly discovers the default subnet from control plane machines, infers the router, and populates the OpenStackCluster spec before creating it. The comment at line 164-166 helpfully explains why ExternalNetworkID is set.


178-219: LGTM – Router discovery logic is correct.

The function correctly finds the router by locating the port with the subnet's gateway IP, extracting the router ID, and validating the external gateway. The error handling covers edge cases (no ports, multiple ports, missing gateway).


245-312: LGTM – Subnet discovery heuristic is sound.

The logic correctly iterates through control plane machines, retrieves their OpenStack ports, examines associated subnets, and identifies the subnet whose CIDR contains the API server internal IP. The nested iteration is acceptable given the small scale of control plane resources.


121-124: Verify hard-coded IdentityRef is correct for all OpenStack deployments.

The IdentityRef name and CloudName are hard-coded to "openstack-cloud-credentials" and "openstack" respectively. Confirm these values are consistent across all supported OpenStack environments, or if they should be sourced from configuration.

@stephenfin
Copy link
Contributor Author

/hold

I am re-testing this locally.

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Dec 1, 2025
@stephenfin
Copy link
Contributor Author

/unhold

All looks good locally.

@openshift-ci openshift-ci bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Dec 1, 2025
Copy link
Member

@mandre mandre left a comment

Choose a reason for hiding this comment

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

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Dec 1, 2025
@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/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
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@stephenfin
Copy link
Contributor Author

/test e2e-openstack-capi-techpreview

1 similar comment
@stephenfin
Copy link
Contributor Author

/test e2e-openstack-capi-techpreview

@damdo
Copy link
Member

damdo commented Dec 3, 2025

@stephenfin it looks like that job has been very red for a while now: https://prow.ci.openshift.org/job-history/gs/test-platform-results/pr-logs/directory/pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-capi-techpreview

Might be worth having a look if you can

@stephenfin
Copy link
Contributor Author

/test e2e-openstack-ovn-techpreview

I am still working on the fix for the e2e-openstack-capi-techpreview failure.

@mandre
Copy link
Member

mandre commented Dec 4, 2025

/test e2e-openstack-capi-techpreview

@stephenfin
Copy link
Contributor Author

/override e2e-azure-capi-techpreview
/override e2e-gcp-ovn-techpreview
/verified by CI
/label acknowledge-critical-fixes-only

We need this PR in to unblock the sync of github.com/openshift/cluster-api-provider-openstack with upstream this cycle. The azure and gcp issues are known and unrelated to this change. Let's get this in.

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Dec 4, 2025
@openshift-ci-robot
Copy link

@stephenfin: This PR has been marked as verified by CI.

Details

In response to this:

/override e2e-azure-capi-techpreview
/override e2e-gcp-ovn-techpreview
/verified by CI
/label acknowledge-critical-fixes-only

We need this PR in to unblock the sync of github.com/openshift/cluster-api-provider-openstack with upstream this cycle. The azure and gcp issues are known and unrelated to this change. Let's get this in.

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 openshift-ci bot added the acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. label Dec 4, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 4, 2025

@stephenfin: /override requires failed status contexts, check run or a prowjob name to operate on.
The following unknown contexts/checkruns were given:

  • e2e-azure-capi-techpreview
  • e2e-gcp-ovn-techpreview

Only the following failed contexts/checkruns were expected:

  • CodeRabbit
  • ci/prow/build
  • ci/prow/e2e-aws-capi-techpreview
  • ci/prow/e2e-aws-ovn
  • ci/prow/e2e-aws-ovn-serial-1of2
  • ci/prow/e2e-aws-ovn-serial-2of2
  • ci/prow/e2e-aws-ovn-techpreview
  • ci/prow/e2e-aws-ovn-techpreview-upgrade
  • ci/prow/e2e-azure-capi-techpreview
  • ci/prow/e2e-azure-ovn-techpreview
  • ci/prow/e2e-azure-ovn-techpreview-upgrade
  • ci/prow/e2e-gcp-capi-techpreview
  • ci/prow/e2e-gcp-ovn-techpreview
  • ci/prow/e2e-metal3-capi-techpreview
  • ci/prow/e2e-openstack-capi-techpreview
  • ci/prow/e2e-openstack-ovn-techpreview
  • ci/prow/e2e-vsphere-capi-techpreview
  • ci/prow/images
  • ci/prow/lint
  • ci/prow/okd-scos-images
  • ci/prow/regression-clusterinfra-aws-ipi-techpreview-capi
  • ci/prow/unit
  • ci/prow/vendor
  • ci/prow/verify-deps
  • pull-ci-openshift-cluster-capi-operator-main-build
  • pull-ci-openshift-cluster-capi-operator-main-e2e-aws-capi-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-aws-ovn
  • pull-ci-openshift-cluster-capi-operator-main-e2e-aws-ovn-serial-1of2
  • pull-ci-openshift-cluster-capi-operator-main-e2e-aws-ovn-serial-2of2
  • pull-ci-openshift-cluster-capi-operator-main-e2e-aws-ovn-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-aws-ovn-techpreview-upgrade
  • pull-ci-openshift-cluster-capi-operator-main-e2e-azure-capi-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-azure-ovn-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-azure-ovn-techpreview-upgrade
  • pull-ci-openshift-cluster-capi-operator-main-e2e-gcp-capi-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-gcp-ovn-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-metal3-capi-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-capi-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-ovn-techpreview
  • pull-ci-openshift-cluster-capi-operator-main-e2e-vsphere-capi-techpreview
  • 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-regression-clusterinfra-aws-ipi-techpreview-capi
  • 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
  • tide

If you are trying to override a checkrun that has a space in it, you must put a double quote on the context.

Details

In response to this:

/override e2e-azure-capi-techpreview
/override e2e-gcp-ovn-techpreview
/verified by CI
/label acknowledge-critical-fixes-only

We need this PR in to unblock the sync of github.com/openshift/cluster-api-provider-openstack with upstream this cycle. The azure and gcp issues are known and unrelated to this change. Let's get this in.

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.

@stephenfin
Copy link
Contributor Author

/override ci/prow/e2e-azure-capi-techpreview
/override ci/prow/e2e-gcp-ovn-techpreview

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 4, 2025

@stephenfin: Overrode contexts on behalf of stephenfin: ci/prow/e2e-azure-capi-techpreview, ci/prow/e2e-gcp-ovn-techpreview

Details

In response to this:

/override ci/prow/e2e-azure-capi-techpreview
/override ci/prow/e2e-gcp-ovn-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
Copy link
Contributor

openshift-ci bot commented Dec 4, 2025

@stephenfin: all tests passed!

Full PR test history. Your PR dashboard.

Details

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.

@openshift-merge-bot openshift-merge-bot bot merged commit cafd8d0 into openshift:main Dec 4, 2025
25 checks passed
@stephenfin stephenfin deleted the migrate-openstack-infracluster-controller branch December 4, 2025 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants