Skip to main content
RunBook Academy

AnsibleXLVIII · Maintenance Windows and RollbackMaintenance windows and rollback

The reverse is part of the change

Advanced⏱ ~26 minansible-playbook

What you'll learn

  • Write a reverse procedure specific enough that a second operator could execute it
  • Identify the point of no return in a change and state it explicitly in the plan
  • Define objective abort criteria rather than criteria that depend on judgement under pressure
  • Apply the rule that a change with no written reverse does not get a window

Prerequisites

Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11

Not yet marked complete on this device.

Rollback is planned before execution, not improvised after it.

That is not a preference. It follows directly from the previous lesson: if Ansible has no undo, then the reverse of a change is something a person builds, and the two moments available for building it are before the window, when the change is understood and nobody is under pressure, or during the incident, when neither is true.

The industry default is the second one. This lesson is about making the first one non-optional.

The rule

A change with no written reverse does not get a maintenance window.

Not “should have one”. Does not get one. The reverse procedure is an entry gate, in the same way a peer review or a --syntax-check is an entry gate, and for the same reason: it catches a class of problem that is cheap to fix now and expensive to fix later.

The rule has a useful side effect that is arguably worth more than the artefact. Writing the reverse forces someone to think through what the change actually does, and that thinking regularly finds a problem in the forward plan. A change whose reverse cannot be written is usually a change that has not been understood.

What the artefact contains

Six fields. A change plan that has all six is executable by someone who did not write it, which is the whole test.

FieldThe question it answersFailure when it is missing
Reverse procedureExactly which commands, in order, on which hostsImprovised at 03:00 from memory
ExecutorWho is permitted to run it, and who is on callNobody feels authorised to pull the trigger
DurationHow long it takes end to endThe decision is made without knowing the cost
CostWhat the rollback itself breaks or interruptsThe reverse causes a second outage
Trigger criteriaThe objective conditions that mean roll backDebate during the incident
Point of no returnThe step after which forward is cheaper than backSomeone attempts a reverse that no longer exists

Reverse procedure

Specific to the point of being boring. Not “restore the config” but the actual invocation, with the actual limit, tested against the actual inventory.

Configuration changereverse procedure, as written in the change plan
# Step 1 - confirm what will be touched, changing nothing.
ansible-playbook -i inventories/prod site.yml \
--limit 'appservers:&batch_a' \
--tags rollback_config \
--check --diff --list-hosts

# Step 2 - restore the previous configuration.
ansible-playbook -i inventories/prod site.yml \
--limit 'appservers:&batch_a' \
--tags rollback_config

# Step 3 - validate. Exit non-zero means the rollback did not land.
ansible-playbook -i inventories/prod validate.yml \
--limit 'appservers:&batch_a'

Three properties make that usable under pressure: the commands are copyable, the host selection is identical to the forward change so there is nothing to re-derive, and step 3 tells the operator whether it worked rather than leaving them to decide.

Trigger criteria

The criteria must be objective, because the person applying them will be tired, invested in the change, and subject to the sunk-cost pull of “it is probably nearly working”.

Written like thisOr like this
“if performance degrades”“if p99 latency exceeds 400 ms for 5 consecutive minutes”
“if errors increase”“if the 5xx rate exceeds 1% of requests”
“if the canary looks unhealthy”“if the canary fails the validation play”
“if it takes too long”“if the window is not complete by 03:30”

The left column is not a criterion. It is a request for a judgement call under conditions that make judgement calls bad. The right column can be evaluated by someone who arrived ten minutes ago, and — more importantly — can be enforced mechanically, which is what lesson 5 is about.

The clock criterion deserves particular attention. Almost every change plan omits it, and time is the criterion that fires most often. A change that is still going at the end of the window has failed even if nothing is broken, because the next thing to happen is the business day.

Point of no return

Every change plan should name the step after which rolling back costs more than going forward. This single line prevents more damage than the rest of the document.

Consider a deployment with a forward-only schema migration:

StepReverse availableCost of reversing
1. Deploy new artefact to canaryYesSwap the symlink back, 30 s
2. Validate canaryYesSwap the symlink back, 30 s
3. Deploy to remaining batchesYesSwap symlinks back, 4 min
4. Run the schema migrationPoint of no returnRestore the database, 40 min, data loss
5. Enable the new feature flagForward onlyFix forward

Before step 4 the reverse is a symlink swap. After step 4 the reverse is a database restore with an RPO measured in minutes of lost writes. Those are not the same decision and the plan must not present them as one line called “rollback”.

Where the artefact lives

In the repository, next to the change, reviewed with the change. Not in a wiki page, not in a ticket comment, not in the head of the person who wrote the role.

changes/
  2026-08-14-app-2.5.0/
    plan.md              # forward steps, timings, approvers
    reverse.md           # the six fields above
    preflight.yml        # asserts run before the window opens
    validate.yml         # asserts run after each batch

Keeping it in the repository buys three things: it is reviewed by the same process as the code, it is versioned alongside the revision it reverses, and it is available to someone who was not in the planning meeting. That last one is the point — the artefact exists for the person who did not write the change.

Knowledge check

Knowledge check · 4 questions

  1. Q1. A deployment plan lists five steps, with a forward-only schema migration at step 4. At step 5 the application misbehaves and an operator runs the documented rollback, which swaps the release symlink back. What is the likely outcome?

  2. Q2. A rehearsal of a reverse procedure in pre-production catches which of these failures? Select all that apply.

  3. Q3. A change with no possible reverse may still be scheduled, provided the plan states that plainly and moves the mitigation to a rehearsed restore with its own RTO.

  4. Q4. Why are rollback tasks given the never tag rather than being kept in a separate playbook?

Passing score: 75%. Answers are checked in this browser.