--- # The loop itself, kept separate from round.yml so the loop bounds (which encode the # RESUME logic) are readable in one place. # # RESUMABLE. Rounds are numbered from the on-node ledger, not counted from zero, so a # re-run after an interruption continues where it stopped and can never lose or duplicate # an earlier round. Already at or past the target count => nothing to do, and the run # collapses to a harvest. # # NOT AUTHORISED => NO REBOOTS. memattr_survey_reboots_authorised defaults false, which # makes the whole loop a no-op. Everything else (preflight, baseline probe, harvest, # analysis) still runs, so a dry run exercises the entire pipeline without touching a # single machine. - name: Announce the plan ansible.builtin.debug: msg: >- {{ inventory_hostname }}: {%- if not (memattr_survey_reboots_authorised | bool) %} DRY RUN — reboots not authorised (set memattr_survey_reboots_authorised=true to arm). {%- elif memattr_survey_status.completed_rounds | int >= memattr_survey_rounds | int %} already at {{ memattr_survey_status.completed_rounds }} rounds; nothing to do. {%- else %} rounds {{ memattr_survey_status.completed_rounds | int + 1 }}..{{ memattr_survey_rounds }} to run ({{ memattr_survey_rounds | int - memattr_survey_status.completed_rounds | int }} reboots). {%- endif %} - name: Survey round ansible.builtin.include_tasks: round.yml loop: >- {{ range(memattr_survey_status.completed_rounds | int + 1, memattr_survey_rounds | int + 1) | list }} loop_control: loop_var: memattr_survey_round label: "{{ inventory_hostname }} round {{ memattr_survey_round }}" # Evaluated per iteration, so the abort flag set by a rescue in one round skips every # round after it on THIS host and no others. when: - memattr_survey_reboots_authorised | bool - not (memattr_survey_aborted | bool)