1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

YAML callback: do not remove non-ASCII Unicode from multi-line string output (#1522)

* Do not remove non-ASCII Unicode from multi-line string output.

* Added basic tests.

* Add Unicode test.

* Simplify tests, avoid later Jinja features.

* Refactor.

* Make use diy tests use callback test framework as well.

* Remove color codes.

* Work around stable-2.9 bug.

* Simplify again.
This commit is contained in:
Felix Fontein 2020-12-22 09:24:20 +01:00 committed by GitHub
parent 0d1417dcfa
commit 0a7ed3b019
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 322 additions and 255 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- "yaml callback plugin - do not remove non-ASCII Unicode characters from multiline string output (https://github.com/ansible-collections/community.general/issues/1519)."

View file

@ -50,7 +50,7 @@ def my_represent_scalar(self, tag, value, style=None):
# ...no trailing space # ...no trailing space
value = value.rstrip() value = value.rstrip()
# ...and non-printable characters # ...and non-printable characters
value = ''.join(x for x in value if x in string.printable) value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
# ...tabs prevent blocks from expanding # ...tabs prevent blocks from expanding
value = value.expandtabs() value = value.expandtabs()
# ...and odd bits of whitespace # ...and odd bits of whitespace

View file

@ -0,0 +1,96 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- block:
- name: Create temporary playbook files
tempfile:
state: file
suffix: temp
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: temporary_playbook_files
- name: Set temporary playbook file content
copy:
content: "{{ test.playbook }}"
dest: "{{ temporary_playbook_files.results[test_idx].path }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
index_var: test_idx
label: "{{ test.name }}"
- name: Collect outputs
command: "ansible-playbook -i {{ inventory }} {{ playbook }}"
environment: "{{ test.environment }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: outputs
changed_when: false
vars:
inventory: "{{ role_path }}/inventory.yml"
playbook: "
{%- for result in temporary_playbook_files.results -%}
{%- if result.test.name == test.name -%}
{{- result.path -}}
{%- endif -%}
{%- endfor -%}"
- name: Assert test output equals expected output
assert:
that: result.output.differences | length == 0
loop: "{{ results }}"
loop_control:
loop_var: result
label: "{{ result.name }}"
register: assertions
vars:
results: >-
{%- set results = [] -%}
{%- for result in outputs.results -%}
{%- set differences = [] -%}
{%- for i in range([result.test.expected_output | count, result.stdout_lines | count] | max) -%}
{%- set line = "line_%s" | format(i+1) -%}
{%- set test_line = result.stdout_lines[i] | default(none) -%}
{%- set expected_lines = result.test.expected_output[i] | default(none) -%}
{%- if expected_lines is not string and expected_lines is not none -%}
{%- if test_line not in expected_lines -%}
{{- differences.append({
line: {
'expected_one_of': expected_lines,
'got': test_line }}) -}}
{%- endif -%}
{%- else -%}
{%- if expected_lines != test_line -%}
{{- differences.append({
line: {
'expected': expected_lines,
'got': test_line }}) -}}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{{- results.append({
'name': result.test.name,
'output': {
'differences': differences,
'expected': result.test.expected_output,
'got': result.stdout_lines }}) -}}
{%- endfor -%}
{{- results -}}
always:
- name: Remove temporary playbooks
file:
path: "{{ temporary_file.path }}"
state: absent
loop: "{{ temporary_playbook_files.results }}"
loop_control:
loop_var: temporary_file
label: "{{ temporary_file.test.name }}: {{ temporary_file.path }}"

View file

@ -1,2 +1,2 @@
shippable/posix/group3 shippable/posix/group3
skip/aix needs/target/callback

View file

@ -1,9 +0,0 @@
- name: Remove temporary playbooks
file:
path: "{{ temporary_file.path }}"
state: absent
loop: "{{ temporary_playbook_files.results }}"
loop_control:
loop_var: temporary_file
label: "{{ temporary_file.test.name }}: {{ temporary_file.path }}"

View file

@ -3,13 +3,16 @@
# and should not be used as examples of how to write Ansible roles # # and should not be used as examples of how to write Ansible roles #
#################################################################### ####################################################################
- name: Set tests - name: Run tests
set_fact: include_role:
name: callback
vars:
tests: tests:
- name: Not using diy callback options - name: Not using diy callback options
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: | playbook: |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
@ -22,19 +25,20 @@
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"", "",
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m", "ok: [testhost] => {",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m", " \"msg\": \"sample debug msg\"",
"\u001b[0;32m}\u001b[0m", "}",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set playbook_on_start_msg callback using environment variable - name: Set playbook_on_start_msg callback using environment variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_CALLBACK_DIY_PLAYBOOK_ON_START_MSG="Sample output Sample playbook message" ANSIBLE_STDOUT_CALLBACK: community.general.diy
ANSIBLE_CALLBACK_DIY_PLAYBOOK_ON_START_MSG: "Sample output Sample playbook message"
playbook: | playbook: |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
@ -48,24 +52,25 @@
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"", "",
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m", "ok: [testhost] => {",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m", " \"msg\": \"sample debug msg\"",
"\u001b[0;32m}\u001b[0m", "}",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set playbook_on_play_start_msg callback using play variable - name: Set playbook_on_play_start_msg callback using play variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- name: Sample play name - name: Sample play name
hosts: testhost hosts: testhost
gather_facts: false gather_facts: false
vars: vars:
ansible_callback_diy_playbook_on_play_start_msg: Sample output \{\{ ansible_callback_diy.play.name \}\} ansible_callback_diy_playbook_on_play_start_msg: Sample output {{ ansible_callback_diy.play.name }}
tasks: tasks:
- name: Sample task name - name: Sample task name
debug: debug:
@ -74,23 +79,24 @@
"Sample output Sample play name", "Sample output Sample play name",
"", "",
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m", "ok: [testhost] => {",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m", " \"msg\": \"sample debug msg\"",
"\u001b[0;32m}\u001b[0m", "}",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set playbook_on_task_start_msg callback using play variable - name: Set playbook_on_task_start_msg callback using play variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
vars: vars:
ansible_callback_diy_playbook_on_task_start_msg: Sample output \{\{ ansible_callback_diy.task.name \}\} ansible_callback_diy_playbook_on_task_start_msg: Sample output {{ ansible_callback_diy.task.name }}
tasks: tasks:
- name: Sample task name - name: Sample task name
debug: debug:
@ -99,19 +105,20 @@
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"Sample output Sample task name", "Sample output Sample task name",
"\u001b[0;32mok: [testhost] => {\u001b[0m", "ok: [testhost] => {",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m", " \"msg\": \"sample debug msg\"",
"\u001b[0;32m}\u001b[0m", "}",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set playbook_on_task_start_msg callback using task variable - name: Set playbook_on_task_start_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
tasks: tasks:
@ -119,24 +126,25 @@
debug: debug:
msg: sample debug msg msg: sample debug msg
vars: vars:
ansible_callback_diy_playbook_on_task_start_msg: Sample output \{\{ ansible_callback_diy.task.name \}\} ansible_callback_diy_playbook_on_task_start_msg: Sample output {{ ansible_callback_diy.task.name }}
expected_output: [ expected_output: [
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"Sample output Sample task name", "Sample output Sample task name",
"\u001b[0;32mok: [testhost] => {\u001b[0m", "ok: [testhost] => {",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m", " \"msg\": \"sample debug msg\"",
"\u001b[0;32m}\u001b[0m", "}",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set runner_on_ok_msg callback using task variable - name: Set runner_on_ok_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
tasks: tasks:
@ -144,7 +152,7 @@
debug: debug:
msg: sample debug msg msg: sample debug msg
vars: vars:
ansible_callback_diy_runner_on_ok_msg: Sample output \{\{ ansible_callback_diy.result.output.msg \}\} ansible_callback_diy_runner_on_ok_msg: Sample output {{ ansible_callback_diy.result.output.msg }}
expected_output: [ expected_output: [
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
@ -153,13 +161,14 @@
"Sample output sample debug msg", "Sample output sample debug msg",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set runner_on_failed_msg callback using task variable - name: Set runner_on_failed_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: | playbook: |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
@ -179,14 +188,15 @@
"Sample output Sample failure message", "Sample output Sample failure message",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 \u001b[1;35mignored=1 \u001b[0m" "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1 "
] ]
- name: Set runner_on_skipped_msg callback using task variable - name: Set runner_on_skipped_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
tasks: tasks:
@ -195,7 +205,7 @@
msg: sample debug msg msg: sample debug msg
when: false when: false
vars: vars:
ansible_callback_diy_runner_on_skipped_msg: Sample output Skipped \{\{ ansible_callback_diy.task.name \}\} ansible_callback_diy_runner_on_skipped_msg: Sample output Skipped {{ ansible_callback_diy.task.name }}
expected_output: [ expected_output: [
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
@ -204,26 +214,27 @@
"Sample output Skipped Sample task name", "Sample output Skipped Sample task name",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : ok=0 changed=0 unreachable=0 failed=0 \u001b[0;36mskipped=1 \u001b[0m rescued=0 ignored=0 " "testhost : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 "
] ]
- name: Set runner_item_on_ok_msg callback using task variable - name: Set runner_item_on_ok_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
tasks: tasks:
- name: Sample task name - name: Sample task name
debug: debug:
msg: sample debug msg \{\{ item \}\} msg: sample debug msg {{ item }}
loop: loop:
- sample item 1 - sample item 1
- sample item 2 - sample item 2
- sample item 3 - sample item 3
vars: vars:
ansible_callback_diy_runner_item_on_ok_msg: Sample output Looping \{\{ ansible_callback_diy.result.output.msg \}\} ansible_callback_diy_runner_item_on_ok_msg: Sample output Looping {{ ansible_callback_diy.result.output.msg }}
expected_output: [ expected_output: [
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
@ -234,20 +245,21 @@
"Sample output Looping sample debug msg sample item 3", "Sample output Looping sample debug msg sample item 3",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set runner_item_on_failed_msg callback using task variable - name: Set runner_item_on_failed_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
tasks: tasks:
- name: Sample task name - name: Sample task name
debug: debug:
msg: sample debug msg \{\{ item \}\} msg: sample debug msg {{ item }}
loop: loop:
- sample item 1 - sample item 1
- sample item 2 - sample item 2
@ -261,93 +273,95 @@
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"", "",
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => (item=sample item 1) => {\u001b[0m", "ok: [testhost] => (item=sample item 1) => {",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 1\"\u001b[0m", " \"msg\": \"sample debug msg sample item 1\"",
"\u001b[0;32m}\u001b[0m", "}",
"Sample output Looping sample failure message", "Sample output Looping sample failure message",
"\u001b[0;32mok: [testhost] => (item=sample item 3) => {\u001b[0m", "ok: [testhost] => (item=sample item 3) => {",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 3\"\u001b[0m", " \"msg\": \"sample debug msg sample item 3\"",
"\u001b[0;32m}\u001b[0m", "}",
[ [
# Apparently a bug was fixed in Ansible, as before it ran through with "All items completed" # Apparently a bug was fixed in Ansible, as before it ran through with "All items completed"
"\u001b[0;31mfatal: [testhost]: FAILED! => {\"msg\": \"All items completed\"}\u001b[0m", "fatal: [testhost]: FAILED! => {\"msg\": \"All items completed\"}",
"\u001b[0;31mfatal: [testhost]: FAILED! => {\"msg\": \"One or more items failed\"}\u001b[0m", "fatal: [testhost]: FAILED! => {\"msg\": \"One or more items failed\"}",
], ],
"\u001b[0;36m...ignoring\u001b[0m", "...ignoring",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 \u001b[1;35mignored=1 \u001b[0m" "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1 "
] ]
- name: Set runner_item_on_skipped_msg callback using task variable - name: Set runner_item_on_skipped_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
tasks: tasks:
- name: Sample task name - name: Sample task name
debug: debug:
msg: sample debug msg \{\{ item \}\} msg: sample debug msg {{ item }}
loop: loop:
- sample item 1 - sample item 1
- sample item 2 - sample item 2
- sample item 3 - sample item 3
when: item != 'sample item 2' when: item != 'sample item 2'
vars: vars:
ansible_callback_diy_runner_item_on_skipped_msg: Sample output Looping Skipped \{\{ ansible_callback_diy.result.output.item \}\} ansible_callback_diy_runner_item_on_skipped_msg: Sample output Looping Skipped {{ ansible_callback_diy.result.output.item }}
expected_output: [ expected_output: [
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"", "",
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => (item=sample item 1) => {\u001b[0m", "ok: [testhost] => (item=sample item 1) => {",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 1\"\u001b[0m", " \"msg\": \"sample debug msg sample item 1\"",
"\u001b[0;32m}\u001b[0m", "}",
"Sample output Looping Skipped sample item 2", "Sample output Looping Skipped sample item 2",
"\u001b[0;32mok: [testhost] => (item=sample item 3) => {\u001b[0m", "ok: [testhost] => (item=sample item 3) => {",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 3\"\u001b[0m", " \"msg\": \"sample debug msg sample item 3\"",
"\u001b[0;32m}\u001b[0m", "}",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set playbook_on_stats_msg callback using play variable - name: Set playbook_on_stats_msg callback using play variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
vars: vars:
ansible_callback_diy_playbook_on_stats_msg: |+2 ansible_callback_diy_playbook_on_stats_msg: |+2
Sample output stats Sample output stats
=============================== ===============================
{\% for key in ansible_callback_diy.stats | sort %\} {% for key in ansible_callback_diy.stats | sort %}
{\% set color_one = "" %\} {% set color_one = "" %}
{\% set color_two = "" %\} {% set color_two = "" %}
{\% if ansible_callback_diy.stats[key] %\} {% if ansible_callback_diy.stats[key] %}
{\% if key == 'ok' %\} {% if key == 'ok' %}
{\% set prefix = ' ' %\} {% set prefix = ' ' %}
{\% set suffix = ' ' %\} {% set suffix = ' ' %}
{\% elif key == 'changed' %\} {% elif key == 'changed' %}
{\% set prefix = ' ' %\} {% set prefix = ' ' %}
{\% set suffix = ' ' %\} {% set suffix = ' ' %}
{\% elif key == 'processed' %\} {% elif key == 'processed' %}
{\% set prefix = ' ' %\} {% set prefix = ' ' %}
{\% set suffix = ' ' %\} {% set suffix = ' ' %}
{\% elif key == 'skipped' %\} {% elif key == 'skipped' %}
{\% set prefix = ' ' %\} {% set prefix = ' ' %}
{\% set suffix = ' ' %\} {% set suffix = ' ' %}
{\% else %\} {% else %}
{\% set prefix = "" %\} {% set prefix = "" %}
{\% set suffix = "" %\} {% set suffix = "" %}
{\% endif %\} {% endif %}
\{\{ color_one \}\}\{\{ "%s%s%s" | format(prefix,key,suffix) \}\}\{\{ color_two \}\}: \{\{ ansible_callback_diy.stats[key] | to_nice_yaml \}\} {{ color_one }}{{ "%s%s%s" | format(prefix,key,suffix) }}{{ color_two }}: {{ ansible_callback_diy.stats[key] | to_nice_yaml }}
{\% endif %\} {% endif %}
{\% endfor %\} {% endfor %}
tasks: tasks:
- name: Sample task name - name: Sample task name
debug: debug:
@ -357,9 +371,9 @@
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"", "",
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m", "ok: [testhost] => {",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m", " \"msg\": \"sample debug msg\"",
"\u001b[0;32m}\u001b[0m", "}",
" Sample output stats", " Sample output stats",
"===============================", "===============================",
" ok : testhost: 1", " ok : testhost: 1",
@ -368,9 +382,10 @@
] ]
- name: Suppress output on playbook_on_task_start_msg callback using task variable - name: Suppress output on playbook_on_task_start_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: | playbook: |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
@ -383,18 +398,19 @@
expected_output: [ expected_output: [
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m", "ok: [testhost] => {",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m", " \"msg\": \"sample debug msg\"",
"\u001b[0;32m}\u001b[0m", "}",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Suppress output on runner_on_ok_msg callback using task variable - name: Suppress output on runner_on_ok_msg callback using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: | playbook: |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
@ -411,14 +427,15 @@
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Set runner_on_ok_msg_color using task variable - name: Set runner_on_ok_msg_color using task variable
environment: >- environment:
ANSIBLE_FORCE_COLOR=True ANSIBLE_NOCOLOR: 'true'
ANSIBLE_STDOUT_CALLBACK=community.general.diy ANSIBLE_FORCE_COLOR: 'false'
playbook: | ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost - hosts: testhost
gather_facts: false gather_facts: false
tasks: tasks:
@ -426,116 +443,15 @@
debug: debug:
msg: sample debug msg msg: sample debug msg
vars: vars:
ansible_callback_diy_runner_on_ok_msg: Sample output \{\{ ansible_callback_diy.result.output.msg \}\} ansible_callback_diy_runner_on_ok_msg: Sample output {{ ansible_callback_diy.result.output.msg }}
ansible_callback_diy_runner_on_ok_msg_color: blue ansible_callback_diy_runner_on_ok_msg_color: blue
expected_output: [ expected_output: [
"", "",
"PLAY [testhost] ****************************************************************", "PLAY [testhost] ****************************************************************",
"", "",
"TASK [Sample task name] ********************************************************", "TASK [Sample task name] ********************************************************",
"\u001b[0;34mSample output sample debug msg\u001b[0m", "Sample output sample debug msg",
"", "",
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- when: ansible_distribution == 'FreeBSD' and ansible_distribution_version in ['11.1', '12.1']
name: Create temporary playbooks
block:
- name: Create temporary playbook files
tempfile:
state: file
suffix: temp
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: temporary_playbook_files
notify: Remove temporary playbooks
- name: Set temporary playbook file content
copy:
content: "{{ playbook }}"
dest: "{{ playbook_file }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
vars:
playbook_file: "{{ (temporary_playbook_files.results | selectattr('test.name', 'equalto', test.name) | list())[0].path }}"
playbook: "{{
test.playbook
| regex_replace('(\\\\{){2}(.*?)(\\\\}){2}', '{{\\2}}')
| regex_replace('({\\\\%)(.*?)(%\\\\})', '{%\\2%}')
}}"
- name: Collect outputs
shell: "{{ env }} ansible-playbook -i {{ inventory }} {{ playbook }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: outputs
changed_when: false
vars:
env: "{{ test.environment | regex_replace('(\\\\{){2}(.*?)(\\\\}){2}', '{{\\2}}') }}"
inventory: "{{ role_path }}/inventory.yml"
playbook: "
{%- if temporary_playbook_files is changed -%}
{%- for result in temporary_playbook_files.results -%}
{%- if result.test.name == test.name -%}
{{- result.path -}}
{%- endif -%}
{%- endfor -%}
{%- else -%}
{{- [
'/dev/fd/0 <<EOF',
(
test.playbook
| regex_replace('(\\\\{){2}(.*?)(\\\\}){2}', '{{\\2}}')
| regex_replace('({\\\\%)(.*?)(%\\\\})', '{%\\2%}')
)
] | join('\n') -}}
{%- endif -%}"
- name: Assert test output equals expected output
assert:
that: result.output.differences | length == 0
loop: "{{ results }}"
loop_control:
loop_var: result
label: "{{ result.name }}"
register: assertions
vars:
results: >-
{%- set results = [] -%}
{%- for result in outputs.results -%}
{%- set differences = [] -%}
{%- for i in range([result.test.expected_output | count, result.stdout_lines | count] | max) -%}
{%- set line = "line_%s" | format(i+1) -%}
{%- set test_line = result.stdout_lines[i] | default(none) -%}
{%- set expected_lines = result.test.expected_output[i] | default(none) -%}
{%- if expected_lines is not string -%}
{%- if test_line not in expected_lines -%}
{{- differences.append({
line: {
'expected_one_of': expected_lines,
'got': test_line }}) -}}
{%- endif -%}
{%- else -%}
{%- if expected_lines != test_line -%}
{{- differences.append({
line: {
'expected': expected_line,
'got': test_line }}) -}}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{{- results.append({
'name': result.test.name,
'output': {
'differences': differences,
'expected': result.test.expected_output,
'got': result.stdout_lines }}) -}}
{%- endfor -%}
{{- results -}}

View file

@ -0,0 +1,2 @@
shippable/posix/group1
needs/target/callback

View file

@ -0,0 +1,60 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Run tests
include_role:
name: callback
vars:
tests:
- name: Basic run
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: |
- hosts: testhost
gather_facts: false
tasks:
- name: Sample task name
debug:
msg: sample debug msg
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"ok: [testhost] => ",
" msg: sample debug msg",
"",
"PLAY RECAP *********************************************************************",
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Test umlauts in multiline
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: |
- hosts: testhost
gather_facts: false
tasks:
- name: Umlaut output
debug:
msg: "äöü\néêè\nßï☺"
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"",
"TASK [Umlaut output] ***********************************************************",
"ok: [testhost] => ",
" msg: |-",
" äöü",
" éêè",
" ßï☺",
"",
"PLAY RECAP *********************************************************************",
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]