Skip to content

Commit e1f0d86

Browse files
Merge pull request #348 from matburt/filtered_events
Allow limiting the ansible event datastructure Reviewed-by: https://github.com/apps/ansible-zuul
2 parents ee21c17 + 980ebb6 commit e1f0d86

File tree

5 files changed

+80
-26
lines changed

5 files changed

+80
-26
lines changed

ansible_runner/__main__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,22 @@ def main(sys_args=None):
307307
"Ansible output (default=False)"
308308
)
309309

310+
runner_group.add_argument(
311+
"--omit-event-data",
312+
action="store_true",
313+
help="Omits including extra event data in the callback payloads "
314+
"or the Runner payload data files "
315+
"(status and stdout still included)"
316+
)
317+
318+
runner_group.add_argument(
319+
"--only-failed-event-data",
320+
action="store_true",
321+
help="Only adds extra event data for failed tasks in the callback "
322+
"payloads or the Runner payload data files "
323+
"(status and stdout still included for other events)"
324+
)
325+
310326
runner_group.add_argument(
311327
"-q", "--quiet",
312328
action="store_true",
@@ -515,6 +531,8 @@ def main(sys_args=None):
515531
rotate_artifacts=args.rotate_artifacts,
516532
ignore_logging=False,
517533
json_mode=args.json,
534+
omit_event_data=args.omit_event_data,
535+
only_failed_event_data=args.only_failed_event_data,
518536
inventory=args.inventory,
519537
forks=args.forks,
520538
project_dir=args.project_dir,

ansible_runner/display_callback/events.py

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -134,40 +134,45 @@ def get(self):
134134
return ctx
135135

136136
def get_begin_dict(self):
137+
omit_event_data = os.getenv("RUNNER_OMIT_EVENTS", "False").lower() == "true"
138+
include_only_failed_event_data = os.getenv("RUNNER_ONLY_FAILED_EVENTS", "False").lower() == "true"
137139
event_data = self.get()
138-
# TODO: Need to rework these values
140+
event = event_data.pop('event', None)
141+
if not event:
142+
event = 'verbose'
143+
for key in ('debug', 'verbose', 'deprecated', 'warning', 'system_warning', 'error'):
144+
if event_data.get(key, False):
145+
event = key
146+
break
147+
event_dict = dict(event=event)
148+
should_process_event_data = (include_only_failed_event_data and event in ('runner_on_failed', 'runner_on_async_failed', 'runner_on_item_failed')) \
149+
or not include_only_failed_event_data
139150
if os.getenv('JOB_ID', ''):
140-
event_data['job_id'] = int(os.getenv('JOB_ID', '0'))
151+
event_dict['job_id'] = int(os.getenv('JOB_ID', '0'))
141152
if os.getenv('AD_HOC_COMMAND_ID', ''):
142-
event_data['ad_hoc_command_id'] = int(os.getenv('AD_HOC_COMMAND_ID', '0'))
153+
event_dict['ad_hoc_command_id'] = int(os.getenv('AD_HOC_COMMAND_ID', '0'))
143154
if os.getenv('PROJECT_UPDATE_ID', ''):
144-
event_data['project_update_id'] = int(os.getenv('PROJECT_UPDATE_ID', '0'))
145-
event_data.setdefault('pid', os.getpid())
146-
event_data.setdefault('uuid', str(uuid.uuid4()))
147-
event_data.setdefault('created', datetime.datetime.utcnow().isoformat())
155+
event_dict['project_update_id'] = int(os.getenv('PROJECT_UPDATE_ID', '0'))
156+
event_dict['pid'] = event_data.get('pid', os.getpid())
157+
event_dict['uuid'] = event_data.get('uuid', str(uuid.uuid4()))
158+
event_dict['created'] = event_data.get('created', datetime.datetime.utcnow().isoformat())
148159
if not event_data.get('parent_uuid', None):
149160
for key in ('task_uuid', 'play_uuid', 'playbook_uuid'):
150161
parent_uuid = event_data.get(key, None)
151162
if parent_uuid and parent_uuid != event_data.get('uuid', None):
152-
event_data['parent_uuid'] = parent_uuid
153-
break
154-
155-
event = event_data.pop('event', None)
156-
if not event:
157-
event = 'verbose'
158-
for key in ('debug', 'verbose', 'deprecated', 'warning', 'system_warning', 'error'):
159-
if event_data.get(key, False):
160-
event = key
163+
event_dict['parent_uuid'] = parent_uuid
161164
break
162-
max_res = int(os.getenv("MAX_EVENT_RES", 700000))
163-
if event not in ('playbook_on_stats',) and "res" in event_data and len(str(event_data['res'])) > max_res:
164-
event_data['res'] = {}
165-
event_dict = dict(event=event, event_data=event_data)
166-
for key in list(event_data.keys()):
167-
if key in ('job_id', 'ad_hoc_command_id', 'project_update_id', 'uuid', 'parent_uuid', 'created',):
168-
event_dict[key] = event_data.pop(key)
169-
elif key in ('verbosity', 'pid'):
170-
event_dict[key] = event_data[key]
165+
else:
166+
event_dict['parent_uuid'] = event_data.get('parent_uuid', None)
167+
if "verbosity" in event_data.keys():
168+
event_dict["verbosity"] = event_data.pop("verbosity")
169+
if not omit_event_data and should_process_event_data:
170+
max_res = int(os.getenv("MAX_EVENT_RES", 700000))
171+
if event not in ('playbook_on_stats',) and "res" in event_data and len(str(event_data['res'])) > max_res:
172+
event_data['res'] = {}
173+
else:
174+
event_data = dict()
175+
event_dict['event_data'] = event_data
171176
return event_dict
172177

173178
def get_end_dict(self):

ansible_runner/interface.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ def run(**kwargs):
124124
:param fact_cache: A string that will be used as the name for the subdirectory of the fact cache in artifacts directory.
125125
This is only used for 'jsonfile' type fact caches.
126126
:param fact_cache_type: A string of the type of fact cache to use. Defaults to 'jsonfile'.
127+
:param omit_event_data: Omits extra ansible event data from event payload (stdout and event still included)
128+
:param only_failed_event_data: Omits extra ansible event data unless it's a failed event (stdout and event still included)
127129
:type private_data_dir: str
128130
:type ident: str
129131
:type json_mode: bool
@@ -155,6 +157,8 @@ def run(**kwargs):
155157
:type directory_isolation_base_path: str
156158
:type fact_cache: str
157159
:type fact_cache_type: str
160+
:type omit_event_data: bool
161+
:type only_failed_event_data: bool
158162
159163
:returns: A :py:class:`ansible_runner.runner.Runner` object
160164
'''

ansible_runner/runner_config.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ def __init__(self,
7979
process_isolation=False, process_isolation_executable=None, process_isolation_path=None,
8080
process_isolation_hide_paths=None, process_isolation_show_paths=None, process_isolation_ro_paths=None,
8181
tags=None, skip_tags=None, fact_cache_type='jsonfile', fact_cache=None, project_dir=None,
82-
directory_isolation_base_path=None, envvars=None, forks=None, cmdline=None):
82+
directory_isolation_base_path=None, envvars=None, forks=None, cmdline=None, omit_event_data=False,
83+
only_failed_event_data=False):
8384
self.private_data_dir = os.path.abspath(private_data_dir)
8485
self.ident = str(ident)
8586
self.json_mode = json_mode
@@ -127,6 +128,8 @@ def __init__(self,
127128
self.envvars = envvars
128129
self.forks = forks
129130
self.cmdline_args = cmdline
131+
self.omit_event_data = omit_event_data
132+
self.only_failed_event_data = only_failed_event_data
130133

131134
def prepare(self):
132135
"""
@@ -200,6 +203,9 @@ def prepare(self):
200203
self.env['ANSIBLE_CACHE_PLUGIN'] = 'jsonfile'
201204
self.env['ANSIBLE_CACHE_PLUGIN_CONNECTION'] = self.fact_cache
202205

206+
self.env["RUNNER_OMIT_EVENTS"] = str(self.omit_event_data)
207+
self.env["RUNNER_ONLY_FAILED_EVENTS"] = str(self.only_failed_event_data)
208+
203209
def prepare_inventory(self):
204210
"""
205211
Prepares the inventory default under ``private_data_dir`` if it's not overridden by the constructor.

test/integration/test_events.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ def test_basic_events(is_run_async=False,g_facts=False):
3737

3838
okay_event = okay_events[0]
3939
assert "uuid" in okay_event and len(okay_event['uuid']) == 36
40+
assert "parent_uuid" in okay_event and len(okay_event['parent_uuid']) == 36
4041
assert "stdout" in okay_event and len(okay_event['stdout']) > 0
42+
assert "start_line" in okay_event and int(okay_event['start_line']) > 0
43+
assert "end_line" in okay_event and int(okay_event['end_line']) > 0
4144
assert "event_data" in okay_event and len(okay_event['event_data']) > 0
4245

4346

@@ -54,6 +57,24 @@ def test_basic_serializeable():
5457
json.dumps(events)
5558

5659

60+
def test_event_omission():
61+
tdir = tempfile.mkdtemp()
62+
r = run(private_data_dir=tdir,
63+
inventory="localhost ansible_connection=local",
64+
omit_event_data=True,
65+
playbook=[{'hosts': 'all', 'gather_facts': False, 'tasks': [{'debug': {'msg': "test"}}]}])
66+
assert not any([x['event_data'] for x in r.events])
67+
68+
69+
def test_event_omission_except_failed():
70+
tdir = tempfile.mkdtemp()
71+
r = run(private_data_dir=tdir,
72+
inventory="localhost ansible_connection=local",
73+
only_failed_event_data=True,
74+
playbook=[{'hosts': 'all', 'gather_facts': False, 'tasks': [{'fail': {'msg': "test"}}]}])
75+
all_event_datas = [x['event_data'] for x in r.events if x['event_data']]
76+
assert len(all_event_datas) == 1
77+
5778
@pytest.mark.skipif(LooseVersion(pkg_resources.get_distribution('ansible').version) < LooseVersion('2.8'),
5879
reason="Valid only on Ansible 2.8+")
5980
def test_runner_on_start(rc):

0 commit comments

Comments
 (0)