Skip to content

[PLT-4265] Harden upgrade-provisioner.py: ENIConfig auto-fix, --restore, activate-capa-machinepool-features.py - #942

Open
iamjanr wants to merge 8 commits into
masterfrom
PLT-4265-01
Open

[PLT-4265] Harden upgrade-provisioner.py: ENIConfig auto-fix, --restore, activate-capa-machinepool-features.py#942
iamjanr wants to merge 8 commits into
masterfrom
PLT-4265-01

Conversation

@iamjanr

@iamjanr iamjanr commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

PLT-4265 Harden upgrade-provisioner.py: ENIConfig auto-fix, --restore, activate-capa-machinepool-features.py

Description

Continuation of the PLT-4265 upgrade-path hardening work:

  • Abort the upgrade if cluster-operator CRDs cannot be pulled, instead of only warning.
  • Bump k8s_version inside the same critical section as the CAPI/CAPA upgrade, instead of as a separate later step.
  • Replace migrate-workers-to-machinepool.py with activate-capa-machinepool-features.py — a simpler, read-only script that only validates prerequisites (cluster-operator/CAPA versions, CAPA feature gates) instead of attempting a guided migration that never worked reliably (check_mp_ready()'s node-readiness heuristic was structurally broken for MachinePool).
  • Add a --restore flag to ecr_pull_through.py to roll back to the pre-upgrade backup on failure.
  • Auto-fix a stale ENIConfig security group in upgrade-provisioner.py's pre-flight checks: clusters created before the PLT-4509 fix (< 0.9.0-m.5) with pods_cidr configured carry an ENIConfig pointing at the VPC's literal "default" security group instead of the real cluster one. MachineDeployment nodes self-heal via CAPA's AWSMachine reconciler, but AWSManagedMachinePool has no equivalent, so a MachinePool added after the upgrade would inherit the stale SG and lose connectivity. The check compares the ENIConfig's security group against aws eks describe-cluster's real one and patches it if they differ — read-only until then, no live ENI is ever touched (no cluster upgrading from before 0.9.0 can have a MachinePool yet).
  • Remove the unused AWS_LOAD_BALANCER_CONTROLLER_CHART constant.
  • Drop a misleading "Phase 1" label from ecr_pull_through.py's output — no "Phase 2" exists anywhere in the script.

Type of Change

  • Bug fix

Related Pull Requests

  • PLT-4667 (Skind, docs): rewrites upgrade.adoc to reflect this same flow, including the mp_role_name requirement this branch's MachinePool testing depends on.

How Has This Been Tested?

  • activate-capa-machinepool-features.py: run for real (not dry-run, it's read-only) against two test EKS clusters, both RESULT: OK.
  • ENIConfig auto-fix: validated three times —
    1. Isolated harness (direct import, no container) against a test cluster with a known-stale ENIConfig, dry-run then real: detected and corrected the 3 stale ENIConfig objects.
    2. Full real upgrade run inside the actual cloud-provisioner-upgrade container against a test cluster (created on 0.7.5, upgraded to 0.9.0/k8s 1.35 end-to-end in ~33 minutes) — the check fired in the pre-flight step and fixed the ENIConfig without blocking the rest of the upgrade.
    3. Follow-up live test: added a new MachinePool to two upgraded test clusters after their ENIConfig fix — both came up with correct security groups on all ENIs from birth, no retroactive fix needed. Moved all critical controllers (capi/capa/cluster-operator/coredns/etc.) onto the MachinePool nodes on both clusters and confirmed real connectivity (nc to the ClusterIP, and the controllers themselves running healthy).

Checklist

  • [PR title] Title references a Jira ticket.
  • [PR desc] Summary of changes included.
  • [PR desc] Related PRs listed.
  • [PR labels] Correct labels applied — needs ai-assisted at minimum.
  • [Docs] Documentation PR referenced (PLT-4667).
  • [QA] No unit tests added for the ENIConfig check (shell-script style, no test harness in this file today).
  • Code follows project style guidelines.
  • Self-review performed.

Additional Notes

Unrelated, pre-existing finding surfaced during this testing (not fixed here, tracked separately): keoscluster-controller-manager intermittently crashes with no logs on Bottlerocket MachinePool nodes — reproduced once on one test cluster, did not reproduce on another under the same conditions. Also unrelated: a stale 0.0.0.0/0 blackhole route (NAT gateway deleted well before this session, unrelated to this branch) was found and fixed on a shared test VPC.

…ot just warn

apply_chart_crds() caught any exception from the whole pull+extract+apply
sequence and only ever printed a WARN before continuing. A missing chart
version in the configured helm repository (e.g. an outdated universe still
pointing at an old K8s line) silently skipped the CRD update, leaving the
upgraded cluster-operator running against a stale CRD schema.

Split the failure modes: a failed helm pull (chart/version not found,
unreachable repo) now raises and aborts the upgrade, since the CRDs are
unavailable outright. Applying an already-downloaded CRD file remains
best-effort, since a given CRD may have no real schema change in this
version.
Patch while the controller is stopped, in the same critical section as the
CAPI providers upgrade, with the controller started once at the very end —
the 2026-08-13 verified-working design. The real fix for the underlying
race lives in cluster-operator (branch PLT-4265-01).

Also: never skip an already-at-target chart while --ecr-pull-through is
enabled, since image path rewriting only happens on real chart upgrades.
…pa-machinepool-features.py

Validates cluster-operator/CAPA minimum versions and CAPA feature
gates required for MachinePool support. Read-only: it does not
upgrade anything or patch CAPA directly, both are handled by
upgrade-provisioner.py.
Restores the pre-upgrade state (CRDs, cluster-operator ConfigMap,
Helm repository, ecr_pull_through_cache_enabled) from the automatic
backup the script already creates before applying any change.
pods_cidr clusters created before the PLT-4509 fix carry an ENIConfig
with the VPC's literal "default" security group instead of the real
cluster one. MachineDeployment nodes self-heal via CAPA, MachinePool
does not, so a pool added after the upgrade inherits the stale SG.
No "Phase 2" exists anywhere in the script, so the label only implied
a multi-step flow that isn't there.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant