Task playbooks
Note
These playbooks ship with the collection and are played by
mise run integration on every run. This page is their README,
assembled here rather than copied.
Playbooks that run, not snippets that illustrate.
They live in playbooks/, the location Ansible recognises: once the collection
is installed, they are called by their fully qualified name, with no path.
Each one is played by mise run integration against a local emulator, on every
run of that target. An example nobody executes rots, and a wrong example in
documentation costs more than no documentation at all.
playbook |
what it shows |
|---|---|
what is wrong with a setup, all of it at once, before anything else fails halfway |
|
the whole fleet in one read-only command, and the zones it could not read named rather than counted as empty |
|
bringing a named group to a power state, twice a day, and refusing every target it was not given |
|
rebooting a named group in batches, waiting on what is observed and never on a duration |
|
listing a whole zone, split by state and by type |
|
the same module in unit read, and the |
|
stopping a named Instance, waiting for the target state, then reading it back |
Start here
ansible-playbook stephrobert.scaleway.doctor
It checks the ansible-core that will run the modules, the SDK the interpreter
can import, where the credentials come from, and whether the API answers. Every
check runs: finding one problem per run is how a first contact is spent on
nothing. It prints Ready. only when everything was checked and everything
passed, and it never prints a credential, only where it came from.
Recipes
Each one starts from a need rather than from a module. They are the shipped
playbooks, so what is written here is what runs: mise run integration plays
every one of them against an emulator on each run, and the real exercise plays
them against a Scaleway account.
Three of them are roles you can call from your own playbook. The playbook is the ergonomics, the role is the operation, and the module is the technical API. Where a recipe says so below, the same logic is available without copying it:
- ansible.builtin.include_role:
name: stephrobert.scaleway.rolling_reboot
vars:
scaleway_rolling_reboot_group: scw_tag_production
scaleway_rolling_reboot_batch_size: 2
The playbook and the role are never two implementations: the playbook calls the role and passes what the command line carried. A test refuses anything else, because two implementations of one operation always end up disagreeing.
One way of saying what to act on. The operations that act on machines take a selector: exactly one of a group, a name, or tags.
scaleway_rolling_reboot_selector:
tags: [production, web] # every machine carrying both
match: all # `all` is the default; `any` widens it
group: X on the command line is the shorthand for selector: {group: X}. An
ambiguous name is refused rather than settled, and an unknown key is refused
rather than quietly selecting nothing, because a typo and an empty fleet look
alike.
What every operation gives back. scaleway_operation holds a
machine-readable result: what it examined, what it changed, what it left alone,
what it refused and why, and what it could not read. A pipeline reads that
rather than the sentence, and a sentence gets reworded.
“My Scaleway setup does not work”
ansible-playbook stephrobert.scaleway.doctor
Reports the ansible-core that will run the modules, the SDK the interpreter can import, where the credentials come from, and whether the API answers in a zone. Every check runs, so one command names every problem rather than the first one.
Check before: nothing. This is the one to run before anything else.
What it does not do: it never prints a credential, only where it came from,
so its output can be pasted into a ticket. And it says Ready. only when
everything was checked and everything passed: an unreachable API is reported
as unverified, never as fine.
“I need to see the state of my fleet”
ansible-playbook stephrobert.scaleway.fleet_report
ansible-playbook stephrobert.scaleway.fleet_report -e output=json
ansible-playbook stephrobert.scaleway.fleet_report -e output=markdown -e zones=fr-par-1
Instances by state, by zone and by tag, plus the load balancers. Three outputs for three readers: a terminal, a pipeline, a ticket.
As a role: stephrobert.scaleway.fleet_report, with
scaleway_fleet_report_zones and scaleway_fleet_report_output. It leaves the
report in scaleway_fleet_report_result, so a calling playbook can act on it
rather than read it off the screen.
Check before: nothing. It is read-only, which is what makes it safe to run first on an account you do not know.
What it does not do: it never counts a zone it could not read. A zone that does not answer is named as unmeasured rather than contributing a zero, and when no zone answers it says so instead of printing a total.
“I want to know what is wrong with my fleet, every morning”
ansible-playbook stephrobert.scaleway.fleet_audit
ansible-playbook stephrobert.scaleway.fleet_audit -e output=json
ansible-playbook stephrobert.scaleway.fleet_audit -e @policy.yml
Judges the fleet against a policy and prints what it found, with a severity per
finding. rolling_reboot is used when you need it; this is the one that earns
its place in a schedule.
As a role: stephrobert.scaleway.fleet_audit. It leaves its findings in
scaleway_fleet_audit_findings, so a pipeline can open a ticket rather than
read a report.
Check before: nothing. It is read-only.
What it does not do: it never repairs what it finds. Terraform provisions
and Ansible operates, and an audit that corrected things would cross that line.
It never counts a zone it could not read as compliant, because a PASS over a
fleet nobody read would be worse than no audit: it would be believable. And the
shipped policy is a starting point made only of warnings, never an opinion about
your fleet: the severity of a public address depends on whether the machine is a
bastion or a database.
“I need to power the lab down tonight”
ansible-playbook stephrobert.scaleway.power_schedule \
-i production.scaleway.yml -e group=scw_tag_office_hours -e desired_state=off
Brings a named inventory group to a power state. Scheduled at 08:00 with
desired_state=on and at 20:00 with off, it is the command that pays for
itself twice a day.
As a role: stephrobert.scaleway.power_schedule, with
scaleway_power_schedule_group and scaleway_power_schedule_desired_state.
Check before: that the group holds what you think. ansible-inventory -i production.scaleway.yml --graph shows it, and --check lists what would move
without moving it.
What it does not do: it has no default target, so it never guesses which
machines to power off. A named group holding no host fails rather than exiting
quietly, and machines in starting, stopping or locked are named and left
alone. Running it twice changes nothing the second time, because it reads each
machine before acting rather than firing blind.
“I need to restart production progressively”
ansible-playbook stephrobert.scaleway.rolling_reboot \
-i production.scaleway.yml -e group=scw_tag_production -e batch_size=1
Reboots a named group in batches, waiting for each batch to come back before touching the next.
As a role: stephrobert.scaleway.rolling_reboot, with
scaleway_rolling_reboot_group, scaleway_rolling_reboot_batch_size and
scaleway_rolling_reboot_wait_timeout.
Check before: run it with --check first. It returns the batch plan and
reboots nothing.
What it does not do: it never waits on a duration. The machine is watched
leaving running and coming back, and a reboot that never starts is reported
rather than assumed to have worked. A machine that was already stopped is left
stopped: this reboots, it does not start. A batch that does not come back stops
the roll and names what was left to do.
“I need to look at one machine, or list a zone”
ansible-playbook stephrobert.scaleway.list_servers -e zone=fr-par-1
ansible-playbook stephrobert.scaleway.server_details -e zone=fr-par-1
ansible-playbook stephrobert.scaleway.stop_server -e zone=fr-par-1 -e server_id=<uuid>
server_details takes the first Instance in the zone when none is named, so it
can be tried without knowing anything in advance.
What they do not do: stop_server never chooses on its own which machine to
stop. Without -e server_id=<uuid> it does nothing and says so. A playbook that
decides for you is a trap, not documentation.
Running them
Against a real Scaleway account, with credentials in the environment or in the configuration file:
export SCW_ACCESS_KEY=... SCW_SECRET_KEY=...
ansible-playbook playbooks/list_servers.yml -e zone=fr-par-1
ansible-playbook stephrobert.scaleway.list_servers -e zone=fr-par-1
With no account and no spend, against a local emulator:
mise run integration # starts feint, seeds it, plays everything
What they do not show yet
These cover reading, acting and scheduling. The collection also ships state management modules, which read, compare and write only the difference: no shipped playbook demonstrates one yet, because a useful demonstration needs a sequence to hold rather than a single call to make.
The full set is exercised elsewhere: examples/playbooks/modules.yml in the
repository plays them against the same platform, on an emulator and on a real
account, and publishes what each run actually played. The collection’s own
README carries the counts, in a block that is recomputed rather than typed.
stop_server.yml never chooses on its own which machine to stop:
without -e server_id=<uuid> it does nothing and says so. An example playbook
that decides for you is a trap, not documentation.