diff --git a/Sharepoint.yaml b/Sharepoint.yaml index b1dc836..c7a65bb 100644 --- a/Sharepoint.yaml +++ b/Sharepoint.yaml @@ -2,6 +2,7 @@ - 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') }}" @@ -13,44 +14,21 @@ job_id: "{{ tower_job_id | default('n/a') }}" job_name: "{{ tower_job_template_name | default('Patch run') }}" job_url: "{{ tower_job_url | default('') }}" - # If you track failure via workflow gating, you can also pass an explicit var. status: "{{ (tower_job_failed | default(false)) | ternary('failed','successful') }}" - # Example timestamps; prefer UTC/ISO8601 - run_start: "{{ tower_job_launch_time | default(ansible_date_time.iso8601) }}" - run_end: "{{ ansible_date_time.iso8601 }}" + # 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') }}" - # Example summary text (customize as needed) summary_text: >- Job {{ job_id }} {{ status }}. Template={{ job_name }}. URL={{ job_url }}. tasks: - - name: Verify siteId resolves - 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) - 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: true - -- name: Show lists (sanitized) - debug: - msg: "{{ (lists_probe.json.value | default([])) | map(attribute='displayName') | list }}" - 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 @@ -65,39 +43,97 @@ no_log: true failed_when: graph_token.status not in [200] - - name: Inspect columns (internal names) - uri: - url: "https://graph.microsoft.com/v1.0/sites/{{ site_id }}/lists/{{ list_id }}/columns?$select=name,displayName,columnType" - method: GET - headers: { Authorization: "Bearer {{ graph_token.json.access_token }}" } - return_content: true - status_code: 200 - register: cols_probe - no_log: true - -- name: Print internal names - debug: - var: cols_probe.json.value | map(attribute='name') | list - - - name: Create SharePoint list item (Graph) + - name: Verify siteId resolves + delegate_to: localhost + run_once: true uri: - url: "https://graph.microsoft.com/v1.0/sites/{{ site_id }}/lists/{{ list_id }}/items" - method: POST + url: "https://graph.microsoft.com/v1.0/sites/{{ site_id }}" + method: GET headers: Authorization: "Bearer {{ graph_token.json.access_token }}" - Content-Type: "application/json" - body_format: json - body: - fields: - Title: "{{ job_name }} ({{ job_id }})" - Status: "{{ status }}" # <-- make sure your list has 'Status' (or change to your internal name) - RunStart: "{{ run_start }}" # <-- DateTime column (internal name) - RunEnd: "{{ run_end }}" # <-- DateTime column (internal name) - Notes: "{{ summary_text }}" # <-- Multiple lines of text (internal name) - register: sp_create - failed_when: sp_create.status not in [200, 201] + return_content: true + status_code: 200 + register: site_probe no_log: true - - name: Show created list item id + - 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: true + + - name: Show lists (sanitized) + run_once: true debug: - var: sp_create.json.id \ No newline at end of file + 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,columnType" + method: GET + headers: + Authorization: "Bearer {{ graph_token.json.access_token }}" + return_content: true + status_code: 200 + register: cols_probe + no_log: true + + - name: Print internal names + run_once: true + debug: + var: cols_probe.json.value | 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 }}" + register: sp_create + no_log: true + + 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