Part XXVI covers what a Molecule scenario is, which files make it up on
Molecule 26.x, and how to run one while developing a role. This lesson
assumes that and asks the pipeline questions: which sequence a CI stage
should run, what each stage costs in wall-clock time, and how to choose a
test environment that does not manufacture confidence.
The sequence CI should run, and the ones it should not
molecule test runs the full lifecycle — destroy, create, converge,
idempotence, verify, destroy — and that is the right thing for a merge
gate. It is not the right thing for every stage, and the sub-commands
exist because the trade-offs differ.
Command
What it does
Where it belongs
molecule converge
Creates the instance if needed and applies the role, leaving it running
A developer’s inner loop. Fast, repeatable, and the instance survives for inspection.
molecule idempotence
Re-runs converge against the existing instance and fails if anything reports changed
Never alone in CI — it needs a converged instance to exist first
molecule verify
Runs the scenario’s assertions against the existing instance
Same; it is a step, not a gate
molecule test
The full sequence, destroying at both ends
The merge gate. It is the only one that proves the role works from nothing.
The distinction that matters: converge proves the role works against
whatever state the instance is in. test proves it works against a
freshly created instance. A role that has been converged eleven times
during development is being tested against a machine that already has
everything it needs, and that is precisely the machine on which a missing
dependency is invisible.
Why idempotence is the highest-value step
Of everything in this part, the idempotence step catches the defect class
that nothing else can reach.
ansible-lint can tell you that a shell task has no changed_when. It
cannot tell you whether your lineinfile regex matches the line it just
wrote, whether your template renders a timestamp, or whether the file mode
you set is the one the module then reports as different. Those are
run-time facts about the interaction between your task and the machine’s
actual state, and the only way to learn them is to run twice and compare.
The mechanism is exactly the “second run is a test” argument from Part
XXVI, automated: converge, converge again, fail if the second run reports
any changed.
What a failure there actually tells you is worth spelling out, because the
first reaction is usually to suppress it:
A command or shell with no creates, removes or changed_when.
It reports changed every time by contract. The fix is to describe when
it really changed something, not to add changed_when: false and move
on — that makes the task lie in the other direction.
A template that renders something non-deterministic. A timestamp, a
dictionary iterated in a varying order, a value derived from
ansible_date_time. The file genuinely differs on every run.
A regex that does not match what it wrote.lineinfile inserts a
line, and next run the regexp fails to recognise it, so it inserts
another. Left alone this appends a line per run indefinitely, and the
idempotence test is the only thing between you and a config file with
four hundred copies of the same directive.
Two tasks fighting. One sets a permission, another resets it. Both
report changed forever, and on a real fleet this shows up as a nightly
job that never reports zero changes, which is exactly the signal Part
XII wants you to be able to trust.
Choosing the environment from what the role touches
On Molecule 26.x there is one driver, and it is called default:
Read-only / Safethe driver list on Molecule 26.6.0— Real output. The historical per-provider drivers are gone; the scenario provisions its own instances.
$ molecule drivers
default
So “container driver versus VM driver” is no longer a configuration
setting — it is a property of what your scenario’s create.yml actually
provisions. The decision is the same one it always was; only the place you
express it has moved.
Make it from what the role touches:
The role manages
Container is honest
Needs a VM
Packages and config files
Yes
No
A user, a directory, file permissions
Yes
No
A systemd unit it enables and starts
Only with systemd as PID 1 in the image, and even then partially
Usually yes
Kernel parameters, modules, sysctl
No — the kernel is the host’s
Yes
Filesystems, LVM, mount points
No
Yes
Firewall rules, network interfaces, routing
No — the namespace is not the host’s
Yes
Anything requiring a reboot
No
Yes
Knowledge check
Knowledge check · 4 questions
Q1. Why should a merge gate run molecule test rather than molecule converge?
Q2. Which defects does the idempotence step catch that no static gate can? Select all that apply.
Q3. On Molecule 26.x, choosing between a container and a VM is a property of what the scenario create.yml provisions rather than a driver setting.
Q4. A role that manages a systemd unit passes every Molecule run in a container and fails on the first real host. What is the most likely cause, and the most useful fix?
Passing score: 75%. Answers are checked in this browser.