Files
AWX/Sharepoint.yaml
2025-08-14 07:29:26 +00:00

190 lines
6.6 KiB
YAML

---
- name: Post patching results to SharePoint (Graph)
hosts: windows
gather_facts: false
vars:
tenant_id: "{{ lookup('env', 'SP_TENANT_ID') }}"
client_id: "{{ lookup('env', 'SP_CLIENT_ID') }}"
client_secret: "{{ lookup('env', 'SP_CLIENT_SECRET') }}"
site_id: "{{ lookup('env', 'SP_SITE_ID') }}"
list_id: "{{ lookup('env', 'SP_LIST_ID') }}"
# Helpful AWX vars (exist in AWX/Controller job context)
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)
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 }}.
Template={{ job_name }}.
URL={{ job_url }}.
tasks:
- name: Acquire Graph token (client credentials)
delegate_to: localhost
run_once: true
uri:
url: "https://login.microsoftonline.com/{{ tenant_id }}/oauth2/v2.0/token"
method: POST
headers:
Content-Type: "application/x-www-form-urlencoded"
body: >
client_id={{ client_id }}
&client_secret={{ client_secret | urlencode }}
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&grant_type=client_credentials
register: graph_token
no_log: true
failed_when: graph_token.status not in [200]
# --- Get recap from AWX and turn it into flat totals ---
- name: Fetch play recap (playbook_on_stats)
delegate_to: localhost
run_once: true
uri:
url: "{{ lookup('env','AWX_API_URL') }}/api/v2/jobs/{{ tower_job_id }}/job_events/?event=playbook_on_stats"
method: GET
headers:
Authorization: "Bearer {{ lookup('env','AWX_API_TOKEN') }}"
Content-Type: "application/json"
return_content: true
status_code: 200
register: _recap
no_log: true
- name: Parse recap totals
run_once: true
vars:
stats: "{{ (_recap.json.results | default([])) | first | default({}) }}"
data: "{{ stats.event_data | default({}) }}"
# event_data keys are dicts {host: count}; sum values safely
sumdict: >-
{% set ns = namespace(t=0) -%}
{%- for v in (item | default({})).values() -%}{%- set ns.t = ns.t + (v|int) -%}{%- endfor -%}
{{ ns.t }}
set_fact:
recap_ok: "{{ sumdict | from_yaml(item=data.ok) }}"
recap_changed: "{{ sumdict | from_yaml(item=data.changed) }}"
recap_failed: "{{ sumdict | from_yaml(item=data.failures) }}"
recap_skipped: "{{ sumdict | from_yaml(item=data.skipped) }}"
recap_unreach: "{{ sumdict | from_yaml(item=data.dark) }}"
vars_prompt: [] # no prompts; just here to keep YAML tidy
- name: Build SharePoint recap line
run_once: true
set_fact:
recap_line: >-
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: Verify siteId resolves
delegate_to: localhost
run_once: true
uri:
url: "https://graph.microsoft.com/v1.0/sites/{{ site_id }}"
method: GET
headers:
Authorization: "Bearer {{ graph_token.json.access_token }}"
return_content: true
status_code: 200
register: site_probe
no_log: true
- name: List lists to confirm listId (name + id)
delegate_to: localhost
run_once: true
uri:
url: "https://graph.microsoft.com/v1.0/sites/{{ site_id }}/lists?$select=id,displayName"
method: GET
headers:
Authorization: "Bearer {{ graph_token.json.access_token }}"
return_content: true
status_code: 200
register: lists_probe
no_log: false
- name: Show lists (sanitized)
run_once: true
debug:
msg: "{{ (lists_probe.json.value | default([])) | map(attribute='displayName') | list }}"
- name: Inspect columns (internal names)
delegate_to: localhost
run_once: true
uri:
url: "https://graph.microsoft.com/v1.0/sites/{{ site_id }}/lists/{{ list_id }}/columns?$select=name,displayName"
method: GET
headers:
Authorization: "Bearer {{ graph_token.json.access_token }}"
return_content: true
status_code: 200
register: cols_probe
no_log: false
- name: Print internal names
run_once: true
debug:
var: cols_probe.json.value | map(attribute='name') | list
- name: Show internal column names (safe)
debug:
msg:
names: "{{ (cols_probe.json.value | default([])) | map(attribute='name') | list }}"
- name: Create SharePoint list item (Graph)
delegate_to: localhost
run_once: true
block:
- uri:
url: "https://graph.microsoft.com/v1.0/sites/{{ site_id }}/lists/{{ list_id }}/items"
method: POST
headers:
Authorization: "Bearer {{ graph_token.json.access_token }}"
Content-Type: "application/json"
body_format: json
return_content: true
status_code: [200, 201]
body:
fields:
Title: "{{ job_name }} ({{ job_id }})"
Status: "{{ status }}"
RunStart: "{{ run_start }}"
RunEnd: "{{ run_end }}"
Notes: |-
{{ summary_text }}
Recap: {{ recap_line }}
register: sp_create
no_log: false
rescue:
- name: Sanitize and print the error
run_once: true
vars:
_json: "{{ sp_create.json | default({}) }}"
debug:
msg:
status: "{{ sp_create.status | default('n/a') }}"
graph_error: >-
{{ _json.error.message
| default(_json.message
| default(sp_create.msg | default('Unknown error'))) }}
hint: >
400: column internal names; 401: scope/audience; 403: permissions;
404: siteId/listId.
- fail:
msg: "Failed to create SharePoint item (see previous message)."
- name: Show created list item id
run_once: true
debug:
var: sp_create.json.id