163 lines
6.3 KiB
YAML
163 lines
6.3 KiB
YAML
---
|
|
- name: Patching | Initialize Windows report state
|
|
ansible.builtin.set_fact:
|
|
_aim_patch_action_failed: false
|
|
_aim_patch_pre_reboot_performed: false
|
|
_aim_patch_any_reboot_performed: false
|
|
_aim_patch_preexisting_reboot_required: false
|
|
_aim_patch_preexisting_reboot_reasons: []
|
|
_aim_patch_reboot_deferred: false
|
|
_aim_patch_reboot_required_after: false
|
|
_aim_patch_blocked_reason: null
|
|
_aim_patch_continuation_required: false
|
|
_aim_patch_remaining_updates_known: false
|
|
_aim_patch_done: false
|
|
_aim_patch_cycles: 0
|
|
_aim_windows_update_runs: []
|
|
_aim_windows_searches: []
|
|
|
|
- name: Patching | Detect pending Windows reboot before patching
|
|
ansible.windows.win_reboot_info:
|
|
register: _aim_patch_pre_reboot_probe
|
|
|
|
- name: Patching | Record pre-existing Windows reboot state
|
|
ansible.builtin.set_fact:
|
|
_aim_patch_preexisting_reboot_required: '{{ _aim_patch_pre_reboot_probe.reboot_required | default(false) | bool }}'
|
|
_aim_patch_preexisting_reboot_reasons: '{{ _aim_patch_pre_reboot_probe.reboot_required_reasons | default([]) }}'
|
|
|
|
- name: Patching | Publish blocked Windows result when reboot is deferred
|
|
when:
|
|
- _aim_patch_preexisting_reboot_required | bool
|
|
- not (os_patching_reboot | bool)
|
|
block:
|
|
- name: Patching | Build blocked Windows patch report
|
|
ansible.builtin.set_fact:
|
|
_aim_patch_report: >-
|
|
{{ 'windows' | aim_report_patch_blocked(ansible_check_mode,
|
|
os_patching_reboot_delay_minutes | int,
|
|
os_patching_rescan_after_reboot | bool,
|
|
_aim_patch_preexisting_reboot_reasons) }}
|
|
- name: AIM | Publish blocked operation result
|
|
ansible.builtin.set_stats:
|
|
per_host: true
|
|
aggregate: false
|
|
data:
|
|
aim_output:
|
|
protocol: aim_output_v1
|
|
schema: patch_summary_v1
|
|
data: '{{ _aim_patch_report }}'
|
|
- name: Patching | Require reboot before continuing Windows patching
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
A reboot is already pending from a previous update or installation. Reboot the host first,
|
|
or rerun with "Reboot when required" enabled. No new Windows updates were started by this run.
|
|
|
|
- name: Patching | Clear pre-existing Windows reboot before patching
|
|
ansible.windows.win_reboot:
|
|
msg: '{{ os_patching_reboot_message }}'
|
|
pre_reboot_delay: '{{ [2, (os_patching_reboot_delay_minutes | int) * 60] | max }}'
|
|
reboot_timeout: '{{ os_patching_reboot_timeout | int }}'
|
|
register: _aim_patch_pre_reboot
|
|
when:
|
|
- _aim_patch_preexisting_reboot_required | bool
|
|
- os_patching_reboot | bool
|
|
- not ansible_check_mode
|
|
|
|
- name: Patching | Record pre-patch Windows reboot
|
|
ansible.builtin.set_fact:
|
|
_aim_patch_pre_reboot_performed: '{{ _aim_patch_pre_reboot.rebooted | default(false) | bool }}'
|
|
_aim_patch_any_reboot_performed: '{{ _aim_patch_pre_reboot.rebooted | default(false) | bool }}'
|
|
_aim_patch_done: >-
|
|
{{ (_aim_patch_pre_reboot.rebooted | default(false) | bool) and
|
|
not (os_patching_rescan_after_reboot | bool) }}
|
|
_aim_patch_continuation_required: >-
|
|
{{ (_aim_patch_pre_reboot.rebooted | default(false) | bool) and
|
|
not (os_patching_rescan_after_reboot | bool) }}
|
|
_aim_patch_remaining_updates_known: false
|
|
|
|
- name: Patching | Search Windows updates in check mode
|
|
ansible.windows.win_updates:
|
|
category_names: '{{ os_patching_windows_categories }}'
|
|
state: searched
|
|
reboot: false
|
|
register: _aim_windows_check_search
|
|
when:
|
|
- ansible_check_mode
|
|
- not (_aim_patch_done | bool)
|
|
|
|
- name: Patching | Record Windows check-mode search
|
|
ansible.builtin.set_fact:
|
|
_aim_windows_searches: '{{ [_aim_windows_check_search] }}'
|
|
_aim_patch_remaining_updates_known: true
|
|
_aim_patch_continuation_required: '{{ (_aim_windows_check_search.found_update_count | default(0) | int) > 0 }}'
|
|
_aim_patch_done: true
|
|
when:
|
|
- ansible_check_mode
|
|
- _aim_windows_check_search is defined
|
|
- not (_aim_windows_check_search.skipped | default(false) | bool)
|
|
|
|
- name: Patching | Process Windows patch waves
|
|
ansible.builtin.include_tasks: windows_wave.yml
|
|
loop: >-
|
|
{{ (range(1, 13) | list) if (os_patching_rescan_after_reboot | bool) else [1] }}
|
|
loop_control:
|
|
loop_var: _aim_patch_wave_number
|
|
label: 'Windows patch wave {{ _aim_patch_wave_number }}'
|
|
when:
|
|
- not ansible_check_mode
|
|
- not (_aim_patch_done | bool)
|
|
|
|
- name: Patching | Guard automatic continuation wave limit
|
|
ansible.builtin.set_fact:
|
|
_aim_patch_action_failed: true
|
|
_aim_patch_blocked_reason: cycle_limit_reached
|
|
_aim_patch_continuation_required: true
|
|
when:
|
|
- not ansible_check_mode
|
|
- os_patching_rescan_after_reboot | bool
|
|
- not (_aim_patch_done | bool)
|
|
|
|
- name: Patching | Normalize Windows update results
|
|
ansible.builtin.set_fact:
|
|
_aim_patch_report: >-
|
|
{{ _aim_windows_update_runs |
|
|
aim_report_patch_windows_runs(
|
|
_aim_windows_searches,
|
|
ansible_check_mode,
|
|
_aim_patch_preexisting_reboot_required | bool,
|
|
_aim_patch_any_reboot_performed | bool,
|
|
os_patching_reboot | bool,
|
|
os_patching_reboot_delay_minutes | int,
|
|
os_patching_rescan_after_reboot | bool,
|
|
_aim_patch_cycles | int,
|
|
_aim_patch_continuation_required | bool,
|
|
_aim_patch_remaining_updates_known | bool,
|
|
_aim_patch_reboot_deferred | bool,
|
|
_aim_patch_reboot_required_after,
|
|
_aim_patch_blocked_reason,
|
|
not (_aim_patch_action_failed | bool),
|
|
_aim_patch_preexisting_reboot_reasons
|
|
) }}
|
|
|
|
- name: Patching | Update summary
|
|
ansible.builtin.debug:
|
|
msg: '{{ _aim_patch_report }}'
|
|
|
|
- name: AIM | Publish operation result
|
|
ansible.builtin.set_stats:
|
|
per_host: true
|
|
aggregate: false
|
|
data:
|
|
aim_output:
|
|
protocol: aim_output_v1
|
|
schema: patch_summary_v1
|
|
data: '{{ _aim_patch_report }}'
|
|
|
|
- name: Patching | Preserve Windows update failure
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
Windows patching stopped before the approved patch wave completed. The structured result contains
|
|
successfully installed updates, bounded failed-update reasons when available, and whether another
|
|
operator-approved run is required. AIM did not replay the patch job automatically.
|
|
when: _aim_patch_action_failed | bool
|