diff --git a/test/integration/targets/ansible-runner/aliases b/test/integration/targets/ansible-runner/aliases new file mode 100644 index 0000000000..802133bcf1 --- /dev/null +++ b/test/integration/targets/ansible-runner/aliases @@ -0,0 +1,4 @@ +shippable/posix/group3 +skip/python3 +skip/osx +skip/freebsd diff --git a/test/integration/targets/ansible-runner/files/adhoc_example1.py b/test/integration/targets/ansible-runner/files/adhoc_example1.py new file mode 100644 index 0000000000..3e0d841462 --- /dev/null +++ b/test/integration/targets/ansible-runner/files/adhoc_example1.py @@ -0,0 +1,26 @@ +import json +import os +import sys +import ansible_runner + +# the first positional arg should be where the artifacts live +output_dir = sys.argv[1] + +# this calls a single module directly, aka "adhoc" mode +r = ansible_runner.run( + private_data_dir=output_dir, + host_pattern='localhost', + module='shell', + module_args='whoami' +) + +data = { + 'rc': r.rc, + 'status': r.status, + 'events': [x['event'] for x in r.events], + 'stats': r.stats +} + +# insert this header for the flask controller +print('#STARTJSON') +json.dump(data, sys.stdout) diff --git a/test/integration/targets/ansible-runner/files/playbook_example1.py b/test/integration/targets/ansible-runner/files/playbook_example1.py new file mode 100644 index 0000000000..83cb19ff26 --- /dev/null +++ b/test/integration/targets/ansible-runner/files/playbook_example1.py @@ -0,0 +1,38 @@ +import json +import os +import sys +import ansible_runner + + +PLAYBOOK = ''' +- hosts: localhost + gather_facts: False + tasks: + - set_fact: + foo: bar +''' + +# the first positional arg should be where the artifacts live +output_dir = sys.argv[1] + +invdir = os.path.join(output_dir, 'inventory') +if not os.path.isdir(invdir): + os.makedirs(invdir) +with open(os.path.join(invdir, 'hosts'), 'w') as f: + f.write('localhost\n') +pbfile = os.path.join(output_dir, 'test.yml') +with open(pbfile, 'w') as f: + f.write(PLAYBOOK) + +r = ansible_runner.run(private_data_dir=output_dir, playbook='test.yml') + +data = { + 'rc': r.rc, + 'status': r.status, + 'events': [x['event'] for x in r.events], + 'stats': r.stats +} + +# insert this header for the flask controller +print('#STARTJSON') +json.dump(data, sys.stdout) diff --git a/test/integration/targets/ansible-runner/filter_plugins/parse.py b/test/integration/targets/ansible-runner/filter_plugins/parse.py new file mode 100644 index 0000000000..7842f6c64b --- /dev/null +++ b/test/integration/targets/ansible-runner/filter_plugins/parse.py @@ -0,0 +1,17 @@ +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import re +import json + + +def parse_json(value): + return json.dumps(json.loads(re.sub('^.*\n#STARTJSON\n', '', value, flags=re.DOTALL)), indent=4, sort_keys=True) + + +class FilterModule(object): + def filters(self): + return { + 'parse_json': parse_json, + } diff --git a/test/integration/targets/ansible-runner/tasks/adhoc_example1.yml b/test/integration/targets/ansible-runner/tasks/adhoc_example1.yml new file mode 100644 index 0000000000..e0767745b7 --- /dev/null +++ b/test/integration/targets/ansible-runner/tasks/adhoc_example1.yml @@ -0,0 +1,16 @@ +- name: execute the script + command: "'{{ ansible_python_interpreter }}' '{{ role_path }}/files/adhoc_example1.py' '{{ output_dir }}'" + environment: + AWX_LIB_DIRECTORY: "{{ callback_path }}" + register: script + +- name: parse script output + # work around for ansible-runner showing ansible warnings on stdout + set_fact: + adexec1_json: "{{ script.stdout | parse_json }}" + +- assert: + that: + - "adexec1_json.rc == 0" + - "adexec1_json.events|length == 2" + - "'localhost' in adexec1_json.stats.ok" diff --git a/test/integration/targets/ansible-runner/tasks/main.yml b/test/integration/targets/ansible-runner/tasks/main.yml new file mode 100644 index 0000000000..5608786b3f --- /dev/null +++ b/test/integration/targets/ansible-runner/tasks/main.yml @@ -0,0 +1,5 @@ +- block: + - include_tasks: setup.yml + - include_tasks: adhoc_example1.yml + - include_tasks: playbook_example1.yml + when: ansible_distribution in ('RedHat', 'CentOS') and ansible_distribution_major_version == '7' diff --git a/test/integration/targets/ansible-runner/tasks/playbook_example1.yml b/test/integration/targets/ansible-runner/tasks/playbook_example1.yml new file mode 100644 index 0000000000..7d8e7b7f9f --- /dev/null +++ b/test/integration/targets/ansible-runner/tasks/playbook_example1.yml @@ -0,0 +1,16 @@ +- name: execute the script + command: "'{{ ansible_python_interpreter }}' '{{ role_path }}/files/playbook_example1.py' '{{ output_dir }}'" + environment: + AWX_LIB_DIRECTORY: "{{ callback_path }}" + register: script + +- name: parse script output + # work around for ansible-runner showing ansible warnings on stdout + set_fact: + pbexec_json: "{{ script.stdout | parse_json }}" + +- assert: + that: + - "pbexec_json.rc == 0" + - "pbexec_json.events|length == 5" + - "'localhost' in pbexec_json.stats.ok" diff --git a/test/integration/targets/ansible-runner/tasks/setup.yml b/test/integration/targets/ansible-runner/tasks/setup.yml new file mode 100644 index 0000000000..32daf8372c --- /dev/null +++ b/test/integration/targets/ansible-runner/tasks/setup.yml @@ -0,0 +1,16 @@ +- name: Install docutils + pip: + name: docutils + +- name: Install ansible-runner + pip: + name: ansible-runner + +- name: Find location of ansible-runner installation + command: "'{{ ansible_python_interpreter }}' -c 'import os, ansible_runner; print(os.path.dirname(ansible_runner.__file__))'" + register: ansible_runner_path + +# work around for https://github.com/ansible/ansible-runner/issues/132 +- name: Set callback path to work around ansible-runner bug + set_fact: + callback_path: ":{{ ansible_runner_path.stdout }}/callbacks"