Skip to content

Commit 4be5337

Browse files
Merge pull request #275 from AlanCoding/new_tests
Port old callback tests to integration folder Reviewed-by: https://github.com/ansible-zuul[bot]
2 parents 795ee7b + 8ca2c9d commit 4be5337

File tree

1 file changed

+301
-0
lines changed

1 file changed

+301
-0
lines changed
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
from __future__ import absolute_import
2+
3+
import json
4+
import os
5+
import yaml
6+
import six
7+
8+
from ansible import __version__ as ANSIBLE_VERSION
9+
10+
from ansible_runner.interface import init_runner
11+
12+
import pytest
13+
14+
15+
@pytest.fixture()
16+
def executor(tmpdir, request):
17+
private_data_dir = six.text_type(tmpdir.mkdir('foo'))
18+
19+
playbooks = request.node.callspec.params.get('playbook')
20+
playbook = list(playbooks.values())[0]
21+
22+
r = init_runner(
23+
private_data_dir=private_data_dir,
24+
inventory="localhost ansible_connection=local",
25+
playbook=yaml.safe_load(playbook)
26+
)
27+
28+
return r
29+
30+
31+
@pytest.mark.parametrize('event', {'playbook_on_start',
32+
'playbook_on_play_start',
33+
'playbook_on_task_start', 'runner_on_ok',
34+
'playbook_on_stats'})
35+
@pytest.mark.parametrize('playbook', [
36+
{'helloworld.yml': '''
37+
- name: Hello World Sample
38+
connection: local
39+
hosts: all
40+
gather_facts: no
41+
tasks:
42+
- name: Hello Message
43+
debug:
44+
msg: "Hello World!"
45+
'''}, # noqa
46+
{'results_included.yml': '''
47+
- name: Run module which generates results list
48+
connection: local
49+
hosts: all
50+
gather_facts: no
51+
vars:
52+
results: ['foo', 'bar']
53+
tasks:
54+
- name: Generate results list
55+
debug:
56+
var: results
57+
'''}, # noqa
58+
])
59+
def test_callback_plugin_receives_events(executor, event, playbook):
60+
executor.run()
61+
assert len(list(executor.events))
62+
assert event in [task['event'] for task in executor.events]
63+
64+
65+
66+
@pytest.mark.parametrize('playbook', [
67+
{'no_log_on_ok.yml': '''
68+
- name: args should not be logged when task-level no_log is set
69+
connection: local
70+
hosts: all
71+
gather_facts: no
72+
tasks:
73+
- shell: echo "SENSITIVE"
74+
no_log: true
75+
'''}, # noqa
76+
{'no_log_on_fail.yml': '''
77+
- name: failed args should not be logged when task-level no_log is set
78+
connection: local
79+
hosts: all
80+
gather_facts: no
81+
tasks:
82+
- shell: echo "SENSITIVE"
83+
no_log: true
84+
failed_when: true
85+
ignore_errors: true
86+
'''}, # noqa
87+
{'no_log_on_skip.yml': '''
88+
- name: skipped task args should be suppressed with no_log
89+
connection: local
90+
hosts: all
91+
gather_facts: no
92+
tasks:
93+
- shell: echo "SENSITIVE"
94+
no_log: true
95+
when: false
96+
'''}, # noqa
97+
{'no_log_on_play.yml': '''
98+
- name: args should not be logged when play-level no_log set
99+
connection: local
100+
hosts: all
101+
gather_facts: no
102+
no_log: true
103+
tasks:
104+
- shell: echo "SENSITIVE"
105+
'''}, # noqa
106+
{'async_no_log.yml': '''
107+
- name: async task args should suppressed with no_log
108+
connection: local
109+
hosts: all
110+
gather_facts: no
111+
no_log: true
112+
tasks:
113+
- async: 10
114+
poll: 1
115+
shell: echo "SENSITIVE"
116+
no_log: true
117+
'''}, # noqa
118+
{'with_items.yml': '''
119+
- name: with_items tasks should be suppressed with no_log
120+
connection: local
121+
hosts: all
122+
gather_facts: no
123+
tasks:
124+
- shell: echo {{ item }}
125+
no_log: true
126+
with_items: [ "SENSITIVE", "SENSITIVE-SKIPPED", "SENSITIVE-FAILED" ]
127+
when: item != "SENSITIVE-SKIPPED"
128+
failed_when: item == "SENSITIVE-FAILED"
129+
ignore_errors: yes
130+
'''}, # noqa, NOTE: with_items will be deprecated in 2.9
131+
{'loop.yml': '''
132+
- name: loop tasks should be suppressed with no_log
133+
connection: local
134+
hosts: all
135+
gather_facts: no
136+
tasks:
137+
- shell: echo {{ item }}
138+
no_log: true
139+
loop: [ "SENSITIVE", "SENSITIVE-SKIPPED", "SENSITIVE-FAILED" ]
140+
when: item != "SENSITIVE-SKIPPED"
141+
failed_when: item == "SENSITIVE-FAILED"
142+
ignore_errors: yes
143+
'''}, # noqa
144+
])
145+
def test_callback_plugin_no_log_filters(executor, playbook):
146+
executor.run()
147+
assert len(list(executor.events))
148+
assert 'SENSITIVE' not in json.dumps(list(executor.events))
149+
150+
151+
@pytest.mark.parametrize('playbook', [
152+
{'no_log_on_ok.yml': '''
153+
- name: args should not be logged when no_log is set at the task or module level
154+
connection: local
155+
hosts: all
156+
gather_facts: no
157+
tasks:
158+
- shell: echo "PUBLIC"
159+
- shell: echo "PRIVATE"
160+
no_log: true
161+
- uri: url=https://example.org username="PUBLIC" password="PRIVATE"
162+
- copy: content="PRIVATE" dest="/tmp/tmp_no_log"
163+
'''}, # noqa
164+
])
165+
def test_callback_plugin_task_args_leak(executor, playbook):
166+
executor.run()
167+
events = list(executor.events)
168+
assert events[0]['event'] == 'playbook_on_start'
169+
assert events[1]['event'] == 'playbook_on_play_start'
170+
171+
# task 1
172+
assert events[2]['event'] == 'playbook_on_task_start'
173+
assert events[3]['event'] == 'runner_on_ok'
174+
175+
# task 2 no_log=True
176+
assert events[4]['event'] == 'playbook_on_task_start'
177+
assert events[5]['event'] == 'runner_on_ok'
178+
assert 'PUBLIC' in json.dumps(events)
179+
assert 'PRIVATE' not in json.dumps(events)
180+
# make sure playbook was successful, so all tasks were hit
181+
assert not events[-1]['event_data']['failures'], 'Unexpected playbook execution failure'
182+
183+
184+
@pytest.mark.parametrize('playbook', [
185+
{'loop_with_no_log.yml': '''
186+
- name: playbook variable should not be overwritten when using no log
187+
connection: local
188+
hosts: all
189+
gather_facts: no
190+
tasks:
191+
- command: "{{ item }}"
192+
register: command_register
193+
no_log: True
194+
with_items:
195+
- "echo helloworld!"
196+
- debug: msg="{{ command_register.results|map(attribute='stdout')|list }}"
197+
'''}, # noqa
198+
])
199+
def test_callback_plugin_censoring_does_not_overwrite(executor, playbook):
200+
executor.run()
201+
events = list(executor.events)
202+
assert events[0]['event'] == 'playbook_on_start'
203+
assert events[1]['event'] == 'playbook_on_play_start'
204+
205+
# task 1
206+
assert events[2]['event'] == 'playbook_on_task_start'
207+
# Ordering of task and item events may differ randomly
208+
assert set(['runner_on_ok', 'runner_item_on_ok']) == set([data['event'] for data in events[3:5]])
209+
210+
# task 2 no_log=True
211+
assert events[5]['event'] == 'playbook_on_task_start'
212+
assert events[6]['event'] == 'runner_on_ok'
213+
assert 'helloworld!' in events[6]['event_data']['res']['msg']
214+
215+
216+
@pytest.mark.parametrize('playbook', [
217+
{'strip_env_vars.yml': '''
218+
- name: sensitive environment variables should be stripped from events
219+
connection: local
220+
hosts: all
221+
tasks:
222+
- shell: echo "Hello, World!"
223+
'''}, # noqa
224+
])
225+
def test_callback_plugin_strips_task_environ_variables(executor, playbook):
226+
executor.run()
227+
assert len(list(executor.events))
228+
for event in list(executor.events):
229+
assert os.environ['PATH'] not in json.dumps(event)
230+
231+
232+
@pytest.mark.parametrize('playbook', [
233+
{'custom_set_stat.yml': '''
234+
- name: custom set_stat calls should persist to the local disk so awx can save them
235+
connection: local
236+
hosts: all
237+
tasks:
238+
- set_stats:
239+
data:
240+
foo: "bar"
241+
'''}, # noqa
242+
])
243+
def test_callback_plugin_saves_custom_stats(executor, playbook):
244+
executor.run()
245+
for event in executor.events:
246+
event_data = event.get('event_data', {})
247+
if 'artifact_data' in event_data:
248+
assert event_data['artifact_data'] == {'foo': 'bar'}
249+
break
250+
else:
251+
raise Exception('Did not find expected artifact data in event data')
252+
253+
254+
@pytest.mark.parametrize('playbook', [
255+
{'handle_playbook_on_notify.yml': '''
256+
- name: handle playbook_on_notify events properly
257+
connection: local
258+
hosts: all
259+
handlers:
260+
- name: my_handler
261+
debug: msg="My Handler"
262+
tasks:
263+
- debug: msg="My Task"
264+
changed_when: true
265+
notify:
266+
- my_handler
267+
'''}, # noqa
268+
])
269+
@pytest.mark.skipif(ANSIBLE_VERSION < '2.5', reason="v2_playbook_on_notify doesn't work before ansible 2.5")
270+
def test_callback_plugin_records_notify_events(executor, playbook):
271+
executor.run()
272+
assert len(list(executor.events))
273+
notify_events = [x for x in executor.events if x['event'] == 'playbook_on_notify']
274+
assert len(notify_events) == 1
275+
assert notify_events[0]['event_data']['handler'] == 'my_handler'
276+
assert notify_events[0]['event_data']['host'] == 'localhost'
277+
assert notify_events[0]['event_data']['task'] == 'debug'
278+
279+
280+
@pytest.mark.parametrize('playbook', [
281+
{'no_log_module_with_var.yml': '''
282+
- name: ensure that module-level secrets are redacted
283+
connection: local
284+
hosts: all
285+
vars:
286+
- pw: SENSITIVE
287+
tasks:
288+
- uri:
289+
url: https://example.org
290+
user: john-jacob-jingleheimer-schmidt
291+
password: "{{ pw }}"
292+
'''}, # noqa
293+
])
294+
def test_module_level_no_log(executor, playbook):
295+
# It's possible for `no_log=True` to be defined at the _module_ level,
296+
# e.g., for the URI module password parameter
297+
# This test ensures that we properly redact those
298+
executor.run()
299+
assert len(list(executor.events))
300+
assert 'john-jacob-jingleheimer-schmidt' in json.dumps(list(executor.events))
301+
assert 'SENSITIVE' not in json.dumps(list(executor.events))

0 commit comments

Comments
 (0)