aim-web2.1.0rc9

This commit is contained in:
admin_rb
2026-09-22 19:23:17 +02:00
parent d095887d2e
commit 3dfc80b782
438 changed files with 31613 additions and 1510 deletions
@@ -0,0 +1,144 @@
- name: Patching | Initialize Debian report state
ansible.builtin.set_fact:
_aim_patch_action_failed: false
_aim_patch_pre_reboot_performed: false
_aim_patch_post_reboot_performed: false
- name: Patching | Detect pending Debian reboot before patching
become: true
ansible.builtin.stat:
path: /var/run/reboot-required
register: _aim_patch_pre_reboot_probe
- name: Patching | Record pre-existing Debian reboot state
ansible.builtin.set_fact:
_aim_patch_preexisting_reboot_required: '{{ _aim_patch_pre_reboot_probe.stat.exists | default(false) | bool }}'
- name: Patching | Publish blocked Debian result when reboot is deferred
when:
- _aim_patch_preexisting_reboot_required | bool
- not (os_patching_reboot | bool)
block:
- name: Patching | Build blocked Debian patch report
ansible.builtin.set_fact:
_aim_patch_report: >-
{{ 'debian' | aim_report_patch_blocked(ansible_check_mode,
os_patching_reboot_delay_minutes | int) }}
- 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 Debian 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 package upgrade was started by this run.
- name: Patching | Clear pre-existing Debian reboot before patching
become: true
ansible.builtin.reboot:
msg: '{{ os_patching_reboot_message }}'
pre_reboot_delay: '{{ (os_patching_reboot_delay_minutes | int) * 60 }}'
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 Debian reboot
ansible.builtin.set_fact:
_aim_patch_pre_reboot_performed: '{{ _aim_patch_pre_reboot.rebooted | default(false) | bool }}'
- name: Patching | Collect installed package facts before operation
ansible.builtin.package_facts:
manager: auto
- name: Patching | Snapshot installed package facts before operation
ansible.builtin.set_fact:
_aim_packages_before: '{{ ansible_facts.packages | default({}) }}'
- name: Patching | Apply native Debian updates
block:
- name: Update Debian-based host
become: true
ansible.builtin.apt:
upgrade: safe
update_cache: true
cache_valid_time: 3600
autoremove: true
- name: Check if Debian-based host requires reboot
become: true
ansible.builtin.stat:
path: /var/run/reboot-required
register: os_patching_reboot_required
rescue:
- name: Patching | Retain failed action for reporting
ansible.builtin.set_fact:
_aim_patch_action_failed: true
- name: Patching | Reboot Debian host after updates when required
become: true
ansible.builtin.reboot:
msg: '{{ os_patching_reboot_message }}'
pre_reboot_delay: '{{ (os_patching_reboot_delay_minutes | int) * 60 }}'
reboot_timeout: '{{ os_patching_reboot_timeout | int }}'
register: _aim_patch_post_reboot
when:
- os_patching_reboot | bool
- not ansible_check_mode
- os_patching_reboot_required.stat.exists | default(false) | bool
- name: Patching | Record post-update Debian reboot
ansible.builtin.set_fact:
_aim_patch_post_reboot_performed: '{{ _aim_patch_post_reboot.rebooted | default(false) | bool }}'
- name: Patching | Collect installed package facts after operation
ansible.builtin.package_facts:
manager: auto
- name: Patching | Snapshot installed package facts after operation
ansible.builtin.set_fact:
_aim_packages_after: '{{ ansible_facts.packages | default({}) }}'
- name: Patching | Compare package database snapshots
ansible.builtin.set_fact:
_aim_patch_report: >-
{{ _aim_packages_before |
aim_report_patch_linux(
_aim_packages_after,
'debian',
ansible_check_mode,
not _aim_patch_action_failed,
os_patching_reboot_required.stat.exists | default(none),
(_aim_patch_pre_reboot_performed | bool) or (_aim_patch_post_reboot_performed | bool),
_aim_patch_preexisting_reboot_required | bool,
os_patching_reboot | bool,
os_patching_reboot_delay_minutes | int
) }}
- name: Patching | Package change 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 native operation failure
ansible.builtin.fail:
msg: >-
The native Debian patch operation failed. Available observed package changes and reboot state
are in the structured result. If a reboot is reported as required, reboot before retrying.
when: _aim_patch_action_failed | bool
@@ -0,0 +1,167 @@
- name: Patching | Initialize RedHat report state
ansible.builtin.set_fact:
_aim_patch_action_failed: false
_aim_patch_pre_reboot_performed: false
_aim_patch_post_reboot_performed: false
_aim_patch_preexisting_reboot_required: false
- name: Patching | Detect existing needs-restarting command
ansible.builtin.command:
argv:
- /bin/sh
- -c
- command -v needs-restarting
register: _aim_needs_restarting_available
changed_when: false
failed_when: false
check_mode: false
- name: Patching | Detect pending RedHat reboot before patching
become: true
ansible.builtin.command:
cmd: needs-restarting -r
register: _aim_patch_pre_reboot_probe
changed_when: false
failed_when: _aim_patch_pre_reboot_probe.rc not in [0, 1]
when: _aim_needs_restarting_available.rc == 0
- name: Patching | Record pre-existing RedHat reboot state
ansible.builtin.set_fact:
_aim_patch_preexisting_reboot_required: >-
{{ (_aim_needs_restarting_available.rc == 0) and
(_aim_patch_pre_reboot_probe.rc | default(0) == 1) }}
- name: Patching | Publish blocked RedHat result when reboot is deferred
when:
- _aim_patch_preexisting_reboot_required | bool
- not (os_patching_reboot | bool)
block:
- name: Patching | Build blocked RedHat patch report
ansible.builtin.set_fact:
_aim_patch_report: >-
{{ 'redhat' | aim_report_patch_blocked(ansible_check_mode,
os_patching_reboot_delay_minutes | int) }}
- 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 RedHat 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 package upgrade was started by this run.
- name: Patching | Clear pre-existing RedHat reboot before patching
become: true
ansible.builtin.reboot:
msg: '{{ os_patching_reboot_message }}'
pre_reboot_delay: '{{ (os_patching_reboot_delay_minutes | int) * 60 }}'
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 RedHat reboot
ansible.builtin.set_fact:
_aim_patch_pre_reboot_performed: '{{ _aim_patch_pre_reboot.rebooted | default(false) | bool }}'
- name: Patching | Collect installed package facts before operation
ansible.builtin.package_facts:
manager: auto
- name: Patching | Snapshot installed package facts before operation
ansible.builtin.set_fact:
_aim_packages_before: '{{ ansible_facts.packages | default({}) }}'
- name: Patching | Apply native RedHat updates
block:
- name: Update RHEL-based host
become: true
ansible.builtin.dnf:
name: '*'
state: latest
update_only: true
- name: Ensure needs-restarting binary is present (yum-utils)
become: true
ansible.builtin.dnf:
name: yum-utils
state: present
- name: Check if RHEL-based host requires reboot
become: true
ansible.builtin.command:
cmd: needs-restarting -r
register: os_patching_reboot_required
changed_when: false
failed_when: os_patching_reboot_required.rc not in [0, 1]
rescue:
- name: Patching | Retain failed action for reporting
ansible.builtin.set_fact:
_aim_patch_action_failed: true
- name: Patching | Reboot RedHat host after updates when required
become: true
ansible.builtin.reboot:
msg: '{{ os_patching_reboot_message }}'
pre_reboot_delay: '{{ (os_patching_reboot_delay_minutes | int) * 60 }}'
reboot_timeout: '{{ os_patching_reboot_timeout | int }}'
register: _aim_patch_post_reboot
when:
- os_patching_reboot | bool
- not ansible_check_mode
- os_patching_reboot_required.rc | default(0) == 1
- name: Patching | Record post-update RedHat reboot
ansible.builtin.set_fact:
_aim_patch_post_reboot_performed: '{{ _aim_patch_post_reboot.rebooted | default(false) | bool }}'
- name: Patching | Collect installed package facts after operation
ansible.builtin.package_facts:
manager: auto
- name: Patching | Snapshot installed package facts after operation
ansible.builtin.set_fact:
_aim_packages_after: '{{ ansible_facts.packages | default({}) }}'
- name: Patching | Compare package database snapshots
ansible.builtin.set_fact:
_aim_patch_report: >-
{{ _aim_packages_before |
aim_report_patch_linux(
_aim_packages_after,
'redhat',
ansible_check_mode,
not _aim_patch_action_failed,
(os_patching_reboot_required.rc == 1) if os_patching_reboot_required.rc is defined else none,
(_aim_patch_pre_reboot_performed | bool) or (_aim_patch_post_reboot_performed | bool),
_aim_patch_preexisting_reboot_required | bool,
os_patching_reboot | bool,
os_patching_reboot_delay_minutes | int
) }}
- name: Patching | Package change 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 native operation failure
ansible.builtin.fail:
msg: >-
The native RedHat patch operation failed. Available observed package changes and reboot state
are in the structured result. If a reboot is reported as required, reboot before retrying.
when: _aim_patch_action_failed | bool
+33
View File
@@ -0,0 +1,33 @@
---
- name: Patching | Supported platform
ansible.builtin.assert:
that:
- ansible_facts.os_family in ['Windows', 'Debian', 'RedHat']
fail_msg: 'Supported patching families: Windows, Debian, RedHat. No legacy Python bootstrap is performed.'
quiet: true
- name: Patching | Validate options
ansible.builtin.assert:
that:
- (os_patching_reboot) is boolean or (os_patching_reboot | string | lower) in ['true', 'false']
- (os_patching_rescan_after_reboot) is boolean or (os_patching_rescan_after_reboot | string | lower) in ['true', 'false']
- os_patching_reboot_timeout | int > 0
- os_patching_reboot_delay_minutes | int >= 0
- os_patching_reboot_delay_minutes | int <= 1440
- os_patching_reboot_message is string
- os_patching_reboot_message | length > 0
- os_patching_reboot_message | length <= 512
- os_patching_windows_categories is sequence
- os_patching_windows_categories is not string
- os_patching_windows_categories | length > 0
fail_msg: Invalid patching settings. Reboot/rescan flags must be boolean, reboot delay must be 0-1440 minutes and the reboot message must be 1-512 characters.
quiet: true
- name: Patching | Windows
ansible.builtin.include_tasks: windows.yml
when: ansible_facts.os_family == 'Windows'
- name: Patching | Debian
ansible.builtin.include_tasks: linux_debian.yml
when: ansible_facts.os_family == 'Debian'
- name: Patching | RedHat
ansible.builtin.include_tasks: linux_redhat.yml
when: ansible_facts.os_family == 'RedHat'
@@ -0,0 +1,162 @@
---
- 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
@@ -0,0 +1,114 @@
---
- name: Patching | Start Windows patch cycle
ansible.builtin.set_fact:
_aim_patch_cycles: '{{ _aim_patch_cycle_number | int }}'
_aim_patch_cycle_stop: false
_aim_patch_cycle_reboot_performed: false
- name: Patching | Search available Windows updates for this wave
ansible.windows.win_updates:
category_names: '{{ os_patching_windows_categories }}'
state: searched
reboot: false
register: _aim_windows_cycle_search
- name: Patching | Record Windows update discovery
ansible.builtin.set_fact:
_aim_windows_searches: '{{ _aim_windows_searches + [_aim_windows_cycle_search] }}'
_aim_windows_update_queue: '{{ _aim_windows_cycle_search | aim_windows_update_queue }}'
- name: Patching | Reboot when discovery itself reports a required reboot
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_windows_search_reboot
when:
- _aim_windows_cycle_search.reboot_required | default(false) | bool
- os_patching_reboot | bool
- name: Patching | Record discovery-time reboot boundary
ansible.builtin.set_fact:
_aim_patch_cycle_stop: true
_aim_patch_cycle_reboot_performed: '{{ _aim_windows_search_reboot.rebooted | default(false) | bool }}'
_aim_patch_any_reboot_performed: >-
{{ (_aim_patch_any_reboot_performed | bool) or
(_aim_windows_search_reboot.rebooted | default(false) | bool) }}
_aim_patch_reboot_required_after: >-
{{ false if (_aim_windows_search_reboot.rebooted | default(false) | bool) else true }}
when:
- _aim_windows_search_reboot is defined
- not (_aim_windows_search_reboot.skipped | default(false) | bool)
- name: Patching | Defer discovery-time required reboot
ansible.builtin.set_fact:
_aim_patch_cycle_stop: true
_aim_patch_done: true
_aim_patch_reboot_deferred: true
_aim_patch_reboot_required_after: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: true
when:
- _aim_windows_cycle_search.reboot_required | default(false) | bool
- not (os_patching_reboot | bool)
- name: Patching | Finish when no updates are available
ansible.builtin.set_fact:
_aim_patch_done: true
_aim_patch_remaining_updates_known: true
_aim_patch_continuation_required: '{{ _aim_windows_cycle_search.reboot_required | default(false) | bool }}'
_aim_patch_reboot_required_after: '{{ _aim_windows_cycle_search.reboot_required | default(false) | bool }}'
when:
- (_aim_windows_update_queue | length) == 0
- not (_aim_patch_cycle_stop | bool)
- name: Patching | Install discovered Windows updates sequentially
ansible.builtin.include_tasks: windows_update_one.yml
loop: '{{ _aim_windows_update_queue }}'
loop_control:
loop_var: _aim_windows_update
label: '{{ _aim_windows_update.title }}'
when:
- not (_aim_patch_done | bool)
- not (_aim_patch_cycle_stop | bool)
- name: Patching | Final read-only discovery after completed non-reboot wave
ansible.windows.win_updates:
category_names: '{{ os_patching_windows_categories }}'
state: searched
reboot: false
register: _aim_windows_cycle_final_search
when:
- not (_aim_patch_done | bool)
- not (_aim_patch_cycle_stop | bool)
- not (_aim_patch_action_failed | bool)
- name: Patching | Record final non-reboot wave state
ansible.builtin.set_fact:
_aim_windows_searches: '{{ _aim_windows_searches + [_aim_windows_cycle_final_search] }}'
_aim_patch_remaining_updates_known: true
_aim_patch_continuation_required: '{{ (_aim_windows_cycle_final_search.found_update_count | default(0) | int) > 0 }}'
_aim_patch_reboot_required_after: '{{ _aim_windows_cycle_final_search.reboot_required | default(false) | bool }}'
_aim_patch_done: true
when:
- _aim_windows_cycle_final_search is defined
- not (_aim_windows_cycle_final_search.skipped | default(false) | bool)
- name: Patching | Stop after operator-approved reboot boundary by default
ansible.builtin.set_fact:
_aim_patch_done: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: false
when:
- _aim_patch_cycle_reboot_performed | bool
- not (os_patching_rescan_after_reboot | bool)
- name: Patching | Continue only when post-reboot rescan was explicitly enabled
ansible.builtin.debug:
msg: >-
AIM completed a reboot boundary and will start another Windows patch cycle because
os_patching_rescan_after_reboot is explicitly enabled.
when:
- _aim_patch_cycle_reboot_performed | bool
- os_patching_rescan_after_reboot | bool
- not (_aim_patch_action_failed | bool)
@@ -0,0 +1,87 @@
---
- name: Patching | Initialize single Windows update result
ansible.builtin.set_fact:
_aim_windows_single_result: {}
_aim_windows_single_task_failed: false
- name: Patching | Install one Windows update
block:
- name: 'Patching | Install {{ _aim_windows_update.title }}'
ansible.windows.win_updates:
category_names: '{{ os_patching_windows_categories }}'
state: installed
reboot: false
accept_list:
- '{{ _aim_windows_update.selector }}'
register: _aim_windows_single_result
rescue:
- name: Patching | Retain failed single-update result
ansible.builtin.set_fact:
_aim_windows_single_result: '{{ ansible_failed_result | default({}) }}'
_aim_windows_single_task_failed: true
- name: Patching | Append single-update evidence
ansible.builtin.set_fact:
_aim_windows_update_runs: >-
{{ _aim_windows_update_runs + [
{
'requested': _aim_windows_update,
'result': _aim_windows_single_result,
'task_failed': _aim_windows_single_task_failed | bool
}
] }}
- name: Patching | Classify single-update execution state
ansible.builtin.set_fact:
_aim_windows_single_failed: >-
{{ (_aim_windows_single_task_failed | bool) or
(_aim_windows_single_result | aim_windows_update_result_failed) }}
_aim_patch_reboot_required_after: '{{ _aim_windows_single_result.reboot_required | default(false) | bool }}'
- name: Patching | Stop this patch wave after an update failure
ansible.builtin.set_fact:
_aim_patch_action_failed: true
_aim_patch_cycle_stop: true
_aim_patch_done: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: false
_aim_patch_blocked_reason: '{{ _aim_windows_single_result | aim_windows_update_block_reason }}'
when: _aim_windows_single_failed | bool
- name: Patching | Reboot Windows at a sequential update boundary
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_windows_single_reboot
when:
- not (_aim_windows_single_failed | bool)
- _aim_windows_single_result.reboot_required | default(false) | bool
- os_patching_reboot | bool
- name: Patching | Record completed sequential reboot boundary
ansible.builtin.set_fact:
_aim_patch_cycle_stop: true
_aim_patch_cycle_reboot_performed: '{{ _aim_windows_single_reboot.rebooted | default(false) | bool }}'
_aim_patch_any_reboot_performed: >-
{{ (_aim_patch_any_reboot_performed | bool) or
(_aim_windows_single_reboot.rebooted | default(false) | bool) }}
_aim_patch_reboot_required_after: >-
{{ false if (_aim_windows_single_reboot.rebooted | default(false) | bool)
else (_aim_windows_single_result.reboot_required | default(false) | bool) }}
when:
- _aim_windows_single_reboot is defined
- not (_aim_windows_single_reboot.skipped | default(false) | bool)
- name: Patching | Defer required reboot and stop the current patch wave
ansible.builtin.set_fact:
_aim_patch_cycle_stop: true
_aim_patch_done: true
_aim_patch_reboot_deferred: true
_aim_patch_reboot_required_after: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: false
when:
- not (_aim_windows_single_failed | bool)
- _aim_windows_single_result.reboot_required | default(false) | bool
- not (os_patching_reboot | bool)
@@ -0,0 +1,124 @@
---
- name: Patching | Start Windows patch wave
ansible.builtin.set_fact:
_aim_patch_cycles: '{{ _aim_patch_wave_number | int }}'
_aim_patch_wave_task_failed: false
_aim_patch_wave_result: {}
_aim_patch_wave_failed: false
_aim_patch_wave_reboot_performed: false
- name: Patching | Install current Windows update wave
block:
- name: Patching | Install all currently selected Windows updates
ansible.windows.win_updates:
category_names: '{{ os_patching_windows_categories }}'
state: installed
reboot: false
register: _aim_patch_wave_result
rescue:
- name: Patching | Retain failed Windows update wave result
ansible.builtin.set_fact:
_aim_patch_wave_result: '{{ ansible_failed_result | default({}) }}'
_aim_patch_wave_task_failed: true
- name: Patching | Append Windows update wave evidence
ansible.builtin.set_fact:
_aim_windows_update_runs: >-
{{ _aim_windows_update_runs + [
{
'result': _aim_patch_wave_result,
'task_failed': _aim_patch_wave_task_failed | bool,
'wave': _aim_patch_wave_number | int
}
] }}
- name: Patching | Classify Windows update wave
ansible.builtin.set_fact:
_aim_patch_wave_failed: >-
{{ (_aim_patch_wave_task_failed | bool) or
(_aim_patch_wave_result | aim_windows_update_result_failed) }}
_aim_patch_reboot_required_after: '{{ _aim_patch_wave_result.reboot_required | default(false) | bool }}'
- name: Patching | Record Windows update wave failure
ansible.builtin.set_fact:
_aim_patch_action_failed: true
_aim_patch_done: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: false
_aim_patch_blocked_reason: '{{ _aim_patch_wave_result | aim_windows_update_block_reason }}'
when: _aim_patch_wave_failed | bool
- name: Patching | Reboot after the completed Windows update wave
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_wave_reboot
when:
- _aim_patch_wave_result.reboot_required | default(false) | bool
- os_patching_reboot | bool
- name: Patching | Record completed Windows wave reboot boundary
ansible.builtin.set_fact:
_aim_patch_wave_reboot_performed: '{{ _aim_patch_wave_reboot.rebooted | default(false) | bool }}'
_aim_patch_any_reboot_performed: >-
{{ (_aim_patch_any_reboot_performed | bool) or
(_aim_patch_wave_reboot.rebooted | default(false) | bool) }}
_aim_patch_reboot_required_after: >-
{{ false if (_aim_patch_wave_reboot.rebooted | default(false) | bool)
else (_aim_patch_wave_result.reboot_required | default(false) | bool) }}
when:
- _aim_patch_wave_reboot is defined
- not (_aim_patch_wave_reboot.skipped | default(false) | bool)
- name: Patching | Defer required reboot after Windows update wave
ansible.builtin.set_fact:
_aim_patch_done: true
_aim_patch_reboot_deferred: true
_aim_patch_reboot_required_after: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: false
when:
- not (_aim_patch_wave_failed | bool)
- _aim_patch_wave_result.reboot_required | default(false) | bool
- not (os_patching_reboot | bool)
- name: Patching | Stop after approved Windows reboot boundary by default
ansible.builtin.set_fact:
_aim_patch_done: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: false
when:
- _aim_patch_wave_reboot_performed | bool
- not (os_patching_rescan_after_reboot | bool)
- name: Patching | Stop automatic continuation after a failed Windows wave
ansible.builtin.set_fact:
_aim_patch_done: true
_aim_patch_continuation_required: true
_aim_patch_remaining_updates_known: false
when:
- _aim_patch_wave_failed | bool
- name: Patching | Final read-only discovery after completed non-reboot Windows wave
ansible.windows.win_updates:
category_names: '{{ os_patching_windows_categories }}'
state: searched
reboot: false
register: _aim_windows_wave_final_search
when:
- not (_aim_patch_done | bool)
- not (_aim_patch_wave_reboot_performed | bool)
- not (_aim_patch_wave_result.reboot_required | default(false) | bool)
- not (_aim_patch_wave_failed | bool)
- name: Patching | Record completed non-reboot Windows wave state
ansible.builtin.set_fact:
_aim_windows_searches: '{{ _aim_windows_searches + [_aim_windows_wave_final_search] }}'
_aim_patch_remaining_updates_known: true
_aim_patch_continuation_required: '{{ (_aim_windows_wave_final_search.found_update_count | default(0) | int) > 0 }}'
_aim_patch_reboot_required_after: '{{ _aim_windows_wave_final_search.reboot_required | default(false) | bool }}'
_aim_patch_done: true
when:
- _aim_windows_wave_final_search is defined
- not (_aim_windows_wave_final_search.skipped | default(false) | bool)