From 2a02f54ba737b6a77e30292b0c6b6bd1eeb5f63c Mon Sep 17 00:00:00 2001 From: mhorak Date: Thu, 14 Aug 2025 08:26:16 +0000 Subject: [PATCH] Update www-install-win-updates.yaml --- www-install-win-updates.yaml | 75 +++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/www-install-win-updates.yaml b/www-install-win-updates.yaml index 48570aa..ec07be5 100644 --- a/www-install-win-updates.yaml +++ b/www-install-win-updates.yaml @@ -6,7 +6,7 @@ - name: Get current timestamp set_fact: current_timestamp: "{{ lookup('pipe', 'date +%Y-%m-%dT%H:%M:%S') }}" - + - name: Check if KB updates report file exists win_stat: path: 'C:\Temp\windows_updates_with_kb.txt' @@ -24,17 +24,21 @@ - name: Extract KB numbers from report file set_fact: - kb_numbers: "{{ updates_content.stdout_lines | select('match', '.*KB: .*') | map('regex_replace', '.*KB: ([0-9,\\s]+).*', '\\1') | map('split', ',') | flatten | map('trim') | select('match', '^[0-9]+$') | list | unique }}" - when: + kb_numbers: "{{ updates_content.stdout_lines + | select('match', '.*KB: .*') + | map('regex_replace', '.*KB: ([0-9,\\s]+).*', '\\1') + | map('split', ',') | flatten | map('trim') + | select('match', '^[0-9]+$') | list | unique }}" + when: - kb_updates_file.stat.exists - updates_content.stdout_lines is defined - name: Display KB numbers to be installed debug: - msg: + msg: - "Found {{ kb_numbers | length }} unique KB numbers to install:" - "{{ kb_numbers | join(', ') }}" - when: + when: - kb_updates_file.stat.exists - kb_numbers is defined - kb_numbers | length > 0 @@ -51,6 +55,16 @@ - kb_numbers is defined - kb_numbers | length > 0 + - name: Mark host failed if any KB installs failed + set_fact: + patch_failed_host: "{{ (installation_result.failed_update_count | default(0) | int) > 0 }}" + patch_failed_count: "{{ installation_result.failed_update_count | default(0) | int }}" + when: + - kb_updates_file.stat.exists + - kb_numbers is defined + - kb_numbers | length > 0 + - installation_result is defined + - name: Display installation summary debug: msg: @@ -69,7 +83,7 @@ - name: Reboot if required win_reboot: reboot_timeout: 1800 - when: installation_result.reboot_required | default(false) + when: installation_result.reboot_required | default(false) - name: Create installation report set_fact: @@ -78,16 +92,16 @@ ================================= Host: {{ inventory_hostname }} Date: {{ current_timestamp }} - + Summary: -------- Total Updates Found: {{ installation_result.found_update_count | default(0) }} Successfully Installed: {{ installation_result.installed_update_count | default(0) }} Failed Installations: {{ installation_result.failed_update_count | default(0) }} Reboot Required: {{ installation_result.reboot_required | default('No') }} - + Requested KB Numbers: {{ kb_numbers | join(', ') }} - + {% if installation_result.updates is defined %} Installed Updates: ----------------- @@ -120,6 +134,8 @@ - kb_updates_file.stat.exists - (kb_numbers is not defined or kb_numbers | length == 0) +# ------------------------------------------------------------------------------ + - name: Post patching results to SharePoint (Graph) hosts: windows gather_facts: false @@ -135,14 +151,13 @@ job_id: "{{ tower_job_id | default('n/a') }}" job_name: "{{ tower_job_template_name | default('Patch run') }}" job_url: "{{ tower_job_url | default('') }}" - status: "{{ (tower_job_failed | default(false)) | ternary('failed','successful') }}" - # Timestamps (avoid ansible_date_time since gather_facts: false) + # Timestamps (works without gather_facts) run_start: "{{ lookup('pipe','date -u +%Y-%m-%dT%H:%M:%SZ') }}" run_end: "{{ lookup('pipe','date -u +%Y-%m-%dT%H:%M:%SZ') }}" summary_text: >- - Job {{ job_id }} {{ status }}. + Job {{ job_id }}. Template={{ job_name }}. URL={{ job_url }}. @@ -164,7 +179,7 @@ no_log: true failed_when: graph_token.status not in [200] - # --- Get recap from AWX and turn it into flat totals --- + # --- AWX recap (controller's tallies) --- - name: Fetch play recap (playbook_on_stats) delegate_to: localhost run_once: true @@ -200,15 +215,30 @@ OK={{ recap_ok | default(0) }}, Changed={{ recap_changed | default(0) }}, Failed={{ recap_failed | default(0) }}, - Skipped={{ recap_skipped | default(0) }}, Unreachable={{ recap_unreach | default(0) }} - - - name: Build final status from recap + + # --- Aggregate per-host patch failures set in the first play --- + - name: Aggregate per-host patch failures + run_once: true + delegate_to: localhost + vars: + flags: "{{ ansible_play_hosts_all + | map('extract', hostvars, 'patch_failed_host') + | map('default', false) | list }}" + set_fact: + any_patch_failed: "{{ (flags | select('equalto', true) | list | length) > 0 }}" + + - name: Build final status from recap + per-host flags run_once: true set_fact: - status_final: "{{ 'failed' if (recap_failed | int > 0 or recap_unreach | int > 0) else 'successful' }}" + status_final: >- + {{ 'failed' + if (any_patch_failed | default(false)) + or (recap_failed | int > 0) + or (recap_unreach | int > 0) + else 'successful' }} - # --- Create list item (no block/rescue; use ignore_errors + diagnostics) --- + # --- Create list item (Graph) --- - name: Create SharePoint list item (Graph) delegate_to: localhost run_once: true @@ -230,6 +260,13 @@ Notes: |- {{ summary_text }} Recap: {{ hostvars['localhost'].recap_line }} + Failed hosts: {% set first=true -%} + {%- for h in ansible_play_hosts_all -%} + {%- if hostvars[h].patch_failed_host | default(false) -%} + {{ '' if first else ', ' }}{{ h }}{% set first=false -%} + {%- endif -%} + {%- endfor -%} + {%- if first -%}None{%- endif -%} register: sp_create ignore_errors: true no_log: true @@ -260,4 +297,4 @@ run_once: true when: sp_create is succeeded debug: - var: sp_create.json.id \ No newline at end of file + var: sp_create.json.id