Skip to content

Add pre-upgrade safety checks and reusable policy evaluation #2941

Open

Description

@tryambak2019

Current situation

  • Today, operators upgrade components one at a time using the upgrade runbook.
  • ate-setup does not check whether the version change is supported or whether earlier upgrade steps have finished before starting the next step.

An unsupported version or an update applied too early can leave components unable to work together, interrupting API calls or actor operations.

This issue proposes adding read-only checks after GA to catch these mistakes before the next update. Operators would still run the upgrade manually.

Failure cases and proposed checks

The following cases map the runbook and version-skew policy to checks that ate-setup could perform:

Failure case Proposed check
Unsupported version: The selected upgrade or rollback is not supported. Check the source and target releases against the policy. For rollback, establish which release the upgrade started from.
Wrong cluster or unclear state: The selected Kubernetes context differs from the expected context, the saved record differs from running versions, or versions cannot be established. Compare the selected and expected contexts. Report verifiable differences between recorded and running versions. Return unknown when evidence is missing.
Update started too early or with the wrong worker image: Earlier updates are unfinished, a worker rollout is paused before the control-plane step, or the proposed worker image is incorrect. Check prerequisites for the requested step, including rollout completion and worker pause status. When a proposed worker image is supplied, check its sandbox type and digest.

Proposed implementation

Slice 1: Policy evaluation

Add a Go package that validates upgrade and rollback transitions against the version-skew policy and returns reasons for rejected transitions.

Keep this logic separate from Cobra and deployment execution so other installation tools can reuse it.

Slice 2: Read-only ate-setup check

Add a command such as:

ate-setup upgrade check --from-config old.yaml --config new.yaml

The command would run the checks above and return ready, blocked, or unknown. It should identify the next manual step when the available evidence supports that conclusion.

Checks for a particular step or worker image need explicit inputs. The example above illustrates the entry point, not the final flag design.

Slice 3: Output for other installation tools

Provide human-readable and machine-readable results containing the observed state, decision, reasons, and missing evidence. Future Kustomize, Helm, provider, and CI workflows could consume these results without depending on ate-setup deploy.

Image digests and locally built images may not identify a release reliably. Until a reliable way to identify live component releases is agreed, report unknown. Additional workload metadata can be considered separately.

Acceptance criteria

  • Unit tests cover the documented release-transition rules.
  • Cluster-state tests cover the failure cases above, including missing evidence and partial upgrades.
  • The checker makes no cluster changes.
  • Human-readable and machine-readable output report the same decision.
  • The runbook explains when and how to run the checks.

Out of scope

  • Automatically executing the upgrade or rollback
  • Creating database backups
  • Maintaining a local upgrade-progress file
  • Preventing updates when the checker is bypassed
  • Selecting the permanent post-GA installer

Activity

  1. HavenXia commented on Oct 21, 2026

    @HavenXia
    Member

    Thanks, this matches what we discussed.

    In "Failure cases and proposed checks":

    Missing database settings: An API-server update could connect to bundled PostgreSQL instead of the existing external database.

    This is already handled, deploy apiserver already refuses the bundled database over an external one.

    I suggest we start small: a version check from old.yaml and new.yaml, as a function inside ate-setup, and leave the cluster-state checks and machine-readable output (helm and others) until something needs them.

  2. HavenXia commented on Oct 21, 2026

    @HavenXia
    Member

    One update: Steven Shriver (@stshrive) is drafting an installer redesign where every install path, including Helm and kustomize, runs an in-cluster ate-setup bootstrap Job first.

    The version check could run there, so it covers every path and can't be skipped. We can discuss more once that get finalized.

  3. tryambak2019 commented on Oct 21, 2026

    @tryambak2019
    Author

    Thank you very much, Haven Xia (@HavenXia) !

    I removed the database case from the issue description.

    Based on your feedback, I propose the following scope for the first milestone.

    Policy evaluation

    • Add a Go function inside ate-setup that evaluates the release transition between old.yaml and new.yaml.
    • Keep it separate from Cobra, deployment execution, and cluster operations.

    Acceptance criteria

    • Missing or invalid releases are rejected.
    • Upgrade and rollback decisions match the version-skew policy.

    This Go function can be implemented independently of Steven’s installer redesign. Its invocation point, including possible bootstrap Job integration, can be decided after redesign is finalized.

    Excluded for current implementation:

    • Read-only ate-setup checks for cluster state and upgrade sequencing
    • Human-readable and machine-readable output for other installation paths

    Please confirm that this captures the intended scope

  4. fiunchinho commented on Oct 29, 2026

    @fiunchinho

    One more case for the policy evaluation: refusing an upgrade whose source release is older than the oldest release the target can migrate from. Today an operator learns that from a failed ate-api start (or a silently unconverted row); with a check in the bootstrap Job it fails before any component moves. Happy to help with that case once the first milestone's shape is settled.

  5. HavenXia commented on Oct 29, 2026

    @HavenXia
    Member

    tk (@tryambak2019) sorry for the slow reply, that scope works.

    The runbook copies the record into old.yaml and new.yaml before step 1, so cluster.substrateVersion in the --config file is the release the upgrade started from. ParseFile skips that section today, so the check has to read it.

    It doesn't need to be in 1.0.0: the upgrade runs the new release's ate-setup, so the first skipped minor it can catch is 1.0 → 1.2.

    Jose Armesto (@fiunchinho) I think that's the skipped-minor rule: we have doc/version-skew-policy.md supporting one minor per upgrade because the schema evolution assumes it, so the previous minor is the oldest release a target accepts.

  6. fiunchinho commented on Oct 29, 2026

    @fiunchinho

    Makes sense 👍

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions