Skip to content

fix: follow-ups to the CAPI v1.13.5 upgrade - #410

Merged
WassimKallel merged 15 commits into
mainfrom
fix/capi-v1.13-follow-ups
Sep 30, 2026
Merged

WassimKallel merged 15 commits into
mainfrom
fix/capi-v1.13-follow-ups

Conversation

@WassimKallel

@WassimKallel WassimKallel commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #398, addressing the gaps found while reviewing it. Each fix is a separate commit so they can be reviewed (or dropped) individually.

Based on main after #398 (squash-merged as 0462e1f).

Behaviour fixes

# Commit Summary
1 4b5e209 fix(controller): keep MachineProvisioned in step with provisioning Until the machine is provisioned, MachineProvisioned now shows Provisioning, or ProvisioningFailed with the step error, instead of keeping a stale WaitingForBootstrapData. That stale message is what hid the image-lookup failure in the #379/#398 e2e runs. A provisioned machine stays True on transient errors. Adds two reason constants and a unit test.
2 26db5b9 fix(cloud): requeue while the bootstrap secret is not found A NotFound bootstrap Secret returned (false, nil), so FinalizeMachineProvisioning could mark a worker provisioned before any server existed. It now requeues.
3 a3bc251 fix: restore the global rate limit for the provider controllers controller-runtime v0.23 (priority queue on by default) dropped the global 10 qps / 100 burst bucket from the default rate limiter. It is restored explicitly, one limiter per controller.
12 a3e1926 fix(cmd): move the initFlags doc comment back above initFlags Review fix for commit 3: controllerOptions was inserted between initFlags and its doc comment, so the comment documented the wrong function (Copilot review).
13 567cce1 fix(controller): reconcile IonosCloudMachines on Cluster unpause The machine controller didn't watch Clusters, so a machine whose reconcile saw a paused Cluster (e.g. a stale cache read right at unpause) waited for an unrelated event. This made the Quickstart finalizer resilience check flaky (one IonosCloudMachine never got its finalizer back). Now watches Clusters on paused transitions and infrastructure provisioned, as CAPD does.

Diagnostics

# Commit Summary
4 e42310a fix(cloud): report location and name filter in image lookup errors found 0 images matching selector … now also reports the location, the version name filter, and the count before the name filter.

Cleanups

# Commit Summary
5 0402862 refactor(cloud): use util.IsControlPlaneMachine again Drops the private copy of the upstream helper. network.go now matches main.
6 abf9140 test(e2e): use upstream's owner-reference and finalizer maps Replaces local copies of framework maps; the Secret rule clones upstream's and adds the IonosCloudCluster-owned credentials Secret.
7 2449ea4 test(e2e): build the quickstart owner-reference assertions once One assertion list and filter shared by all quickstart checks.
8 c0f652b refactor(scope): drop no-op string() around clusterv1.ReadyCondition ReadyCondition is untyped in v1beta2.
9 80a4882 docs(api): drop "(Severity=Info)" from condition reason comments Severity is a v1beta1 concept.

Tooling

# Commit Summary
10 b6e1190 chore(build): align tool versions with CAPI v1.13 controller-gen v0.20.0 (CRDs change only in their version stamp), envtest 1.36.0, setup-envtest v0.25.1 tag instead of a commit pin.

Documentation

# Commit Summary
11 453db57 docs: correct the Go version and unvalidated compatibility cells README said Go 1.26 while go.mod requires 1.27.1. v0.6 × CAPI v1.11, v0.7 × v1.11 and v0.7 × v1.12 were marked ✓ although no e2e run covers those pairs; now ☓ (not validated), per the table's legend.

Notes for reviewers

Testing

  • Every commit individually: golangci-lint 0 issues, unit tests pass.
  • Tip: make test passes (including the API integration suite on envtest 1.36.0), go vet -tags e2e ./test/e2e/... clean.
  • The e2e suite runs on this PR's CI.

🤖 Generated with Claude Code

mneverov
mneverov previously approved these changes Sep 29, 2026
Base automatically changed from feat/upgrade-cluster-api-v1.13.5 to main September 29, 2026 14:45
@WassimKallel
WassimKallel dismissed mneverov’s stale review September 29, 2026 14:45

The base branch was changed.

WassimKallel and others added 10 commits September 29, 2026 16:47
MachineProvisioned was only written while waiting for prerequisites
(WaitingForClusterInfrastructure / WaitingForBootstrapData) and once
provisioning finished. In between it kept the last "waiting" reason, so a
VM being created still showed "Waiting for bootstrap data secret", and a
failing step (e.g. an image lookup error) was only visible in the logs
while the stale message was mirrored up to the Machine, KCP and Cluster.

Until the machine is provisioned, set the condition to False/Provisioning
before the reconcile steps and to False/ProvisioningFailed with the step
error when one fails. A provisioned machine keeps its True condition, so a
transient error doesn't mark a running machine as unprovisioned.

Adds the MachineProvisioningReason and MachineProvisioningFailedReason
constants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ReconcileServer returned (false, nil) when the bootstrap data Secret
lookup was NotFound, so the step loop carried on. For a worker without a
failover IP, FinalizeMachineProvisioning then set
status.initialization.provisioned=true and MachineProvisioned=True before
any server existed. provisioned is one-way per the CAPI contract, so the
wrong signal sticks and hides later provisioning errors.

The Secret can be missing while dataSecretName is already set, e.g. before
it reaches the controller's cache. Requeue until it exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
controller-runtime v0.23 enables the priority queue by default, and with
it the default rate limiter is per-item exponential backoff only. The
previous default also had a global 10 qps / 100 burst token bucket. Without
it, a shared failure (IONOS Cloud API outage, revoked credentials) makes
retries against the API grow with the number of objects.

Pass workqueue.DefaultTypedControllerRateLimiter explicitly, one limiter
per controller as before. The priority queue itself stays on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
imageMatchError only printed the label selector. The lookup also filters
by the data center location and, with useMachineVersion (the default), by
an image name containing the Machine's Kubernetes version. An error like
'found 0 images matching selector "e2etest=capic"' doesn't say which
filter emptied the list.

Include the location, the version filter and the number of images that
matched the labels before the name filter, e.g.:

  found 0 images matching selector "e2etest=capic" in location "de/txl"
  with name containing "v1.34.11" (0 before the name filter)

where 0 before the name filter points at labels/visibility rather than
image naming.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
network.go carried a private copy of sigs.k8s.io/cluster-api/util
IsControlPlaneMachine, which still exists unchanged in CAPI v1.13.5.
Use the upstream helper, as main does, so the failover-IP decisions
don't drift from upstream's definition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
helpers.ExpOwnerReferenceAssertions and helpers.ExpFinalizersAssertion
were verbatim subsets of the framework's maps, and
helpers.KubernetesReferenceAssertions re-copied upstream's Secret and
ConfigMap rules only to accept one more Secret owner. Local copies don't
pick up upstream changes to ownership rules, which is how the v1.13
InfraCluster ownership change went unnoticed.

Use framework.ExpOwnerReferenceAssertions and framework.ExpFinalizersAssertion
directly (extra kinds such as MachinePool are only checked when present),
and build KubernetesReferenceAssertions from a clone of the framework map
whose Secret rule also accepts the IonosCloudCluster-owned credentials
Secret. The upstream rule is replaced rather than added in a second map
because AssertOwnerReferences runs every assertion registered for a kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ValidateOwnerReferencesResilience and ValidateOwnerReferencesOnUpdate took
identical lists of six assertion maps, so every change (like the
topologyManaged flag for the KubeadmControlPlane map) had to be made
twice. Build the list and the owner-graph filter once and share them with
both checks, the finalizer check and the resourceVersion check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
clusterv1.ReadyCondition is an untyped constant in v1beta2, so string()
does nothing, and next to the bare provider constants it suggests a type
conversion is needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Severity belongs to the deprecated v1beta1 conditions. These reasons are
only used with metav1.Condition now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- controller-gen v0.19.0 -> v0.20.0 (what CAPI v1.13.5 uses). The
  regenerated CRDs only change their version annotation.
- envtest Kubernetes 1.34.1 -> 1.36.0, matching CAPI v1.13.5 and the
  newest management version it supports.
- setup-envtest: replace the commit pin with the v0.25.1 tag. The pin's
  comment was waiting for Go 1.26; go.mod is on 1.27.1 now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 29, 2026 14:47
@WassimKallel
WassimKallel force-pushed the fix/capi-v1.13-follow-ups branch from bcf7d98 to b6e1190 Compare September 29, 2026 14:47
mneverov
mneverov previously approved these changes Sep 29, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The functional changes are coherent and tested; only a non-blocking misplaced documentation comment remains.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Follow-up fixes for the CAPI v1.13.5 upgrade, improving provisioning correctness, diagnostics, rate limiting, and test maintenance.

Changes:

  • Corrects machine provisioning state and bootstrap-secret requeue behavior.
  • Restores controller rate limiting and improves image lookup diagnostics.
  • Adopts upstream helpers and aligns development tools with CAPI v1.13.
File Description
api/​v1alpha1/​ionoscloudmachine_types.go Adds provisioning condition reasons and updates comments.
cmd/​main.go Configures per-controller global rate limiting.
Makefile Updates controller-gen and envtest versions.
internal/​controller/​ionoscloudmachine_controller.go Reports provisioning progress and failures.
internal/​controller/​ionoscloudmachine_controller_test.go Tests provisioning condition transitions.
internal/​service/​cloud/​server.go Requeues when the bootstrap Secret is unavailable.
internal/​service/​cloud/​server_test.go Updates missing-secret expectations.
internal/​service/​cloud/​image.go Expands image lookup diagnostics.
internal/​service/​cloud/​image_test.go Tests enhanced image errors.
internal/​service/​cloud/​network.go Uses CAPI’s control-plane helper.
scope/​machine.go Removes redundant condition conversion.
scope/​cluster.go Removes redundant condition conversion.
test/​e2e/​capic_test.go Reuses owner-reference assertions and filters.
test/​e2e/​helpers/​ownerreference.go Extends upstream owner-reference assertions.
test/​e2e/​helpers/​finalizers.go Removes duplicated experimental assertions.
config/​crd/​bases/​infrastructure.cluster.x-k8s.io_ionoscloudmachines.yaml Updates generator version stamp.
config/​crd/​bases/​infrastructure.cluster.x-k8s.io_ionoscloudmachinetemplates.yaml Updates generator version stamp.
config/​crd/​bases/​infrastructure.cluster.x-k8s.io_ionoscloudclusters.yaml Updates generator version stamp.
config/​crd/​bases/​infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml Updates generator version stamp.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cmd/main.go Resolved
- Go: go.mod requires 1.27.1, the README still said 1.26.
- CAPIC v0.6 x CAPI v1.11, v0.7 x v1.11 and v0.7 x v1.12 were marked as
  validated, but no e2e run covers these pairs: the PR e2e job only tests
  the local build, and the upgrade suite (#379) pairs v0.6.3 with v1.8.12
  and v0.7.0 with v1.10.10. Mark them as not validated, per the table's
  legend; the note below the table already says older releases may keep
  working with v1.11-v1.13 since the v1beta1 contract is still accepted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adding controllerOptions between the initFlags doc comment and the
function attached that comment to controllerOptions, so its godoc said it
parses the command line flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The IonosCloudMachine controller only watched IonosCloudMachines and
Machines. A reconcile that sees a paused Cluster, or one whose
infrastructure isn't provisioned yet, returns without requeueing, so the
machine waits for an unrelated event. If that reconcile read a stale
paused Cluster from the cache right as the Cluster was unpaused, nothing
woke the machine up again.

This made the Quickstart finalizer resilience check flaky: after the
framework paused the Cluster, removed all finalizers and unpaused it, one
IonosCloudMachine never got its finalizer back within 60s, while the
others were rescued by later Machine updates.

Watch Clusters and enqueue their IonosCloudMachines (selected by the
cluster-name label) on paused transitions or when the infrastructure
becomes provisioned, as CAPD does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@WassimKallel
WassimKallel enabled auto-merge (squash) September 30, 2026 08:21
@sonarqubecloud

Copy link
Copy Markdown

@WassimKallel
WassimKallel enabled auto-merge (squash) September 30, 2026 09:26
@WassimKallel
WassimKallel merged commit 5288ee4 into main Sep 30, 2026
10 checks passed
@WassimKallel
WassimKallel deleted the fix/capi-v1.13-follow-ups branch September 30, 2026 09:55

This branch was successfully deployed

1 active deployment
e2e — 896121ea Deployed Sep 30, 2026 by WassimKallel via e2e #685
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants