mirror of
https://github.com/ansible/awx.git
synced 2026-02-23 14:05:59 -03:30
remove old callback plugin code and tests
This commit is contained in:
@@ -1,353 +0,0 @@
|
|||||||
# Copyright (c) 2017 Ansible by Red Hat
|
|
||||||
# All Rights Reserved
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
# ansible uses `ANSIBLE_CALLBACK_PLUGINS` and `ANSIBLE_STDOUT_CALLBACK` to
|
|
||||||
# discover callback plugins; `ANSIBLE_CALLBACK_PLUGINS` is a list of paths to
|
|
||||||
# search for a plugin implementation (which should be named `CallbackModule`)
|
|
||||||
#
|
|
||||||
# this code modifies the Python path to make our
|
|
||||||
# `awx.lib.awx_display_callback` callback importable (because `awx.lib`
|
|
||||||
# itself is not a package)
|
|
||||||
#
|
|
||||||
# we use the `awx_display_callback` imports below within this file, but
|
|
||||||
# Ansible also uses them when it discovers this file in
|
|
||||||
# `ANSIBLE_CALLBACK_PLUGINS`
|
|
||||||
CALLBACK = os.path.splitext(os.path.basename(__file__))[0]
|
|
||||||
PLUGINS = os.path.dirname(__file__)
|
|
||||||
with mock.patch.dict(os.environ, {'ANSIBLE_STDOUT_CALLBACK': CALLBACK,
|
|
||||||
'ANSIBLE_CALLBACK_PLUGINS': PLUGINS}):
|
|
||||||
from ansible import __version__ as ANSIBLE_VERSION
|
|
||||||
from ansible.cli.playbook import PlaybookCLI
|
|
||||||
from ansible.executor.playbook_executor import PlaybookExecutor
|
|
||||||
from ansible.inventory.manager import InventoryManager
|
|
||||||
from ansible.parsing.dataloader import DataLoader
|
|
||||||
from ansible.vars.manager import VariableManager
|
|
||||||
|
|
||||||
# Add awx/lib to sys.path so we can use the plugin
|
|
||||||
path = os.path.abspath(os.path.join(PLUGINS, '..', '..', 'lib'))
|
|
||||||
if path not in sys.path:
|
|
||||||
sys.path.insert(0, path)
|
|
||||||
|
|
||||||
from awx_display_callback import AWXDefaultCallbackModule as CallbackModule # noqa
|
|
||||||
from awx_display_callback.events import event_context # noqa
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def cache(request):
|
|
||||||
class Cache(OrderedDict):
|
|
||||||
def set(self, key, value):
|
|
||||||
self[key] = value
|
|
||||||
local_cache = Cache()
|
|
||||||
patch = mock.patch.object(event_context, 'cache', local_cache)
|
|
||||||
patch.start()
|
|
||||||
request.addfinalizer(patch.stop)
|
|
||||||
return local_cache
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def executor(tmpdir_factory, request):
|
|
||||||
playbooks = request.node.callspec.params.get('playbook')
|
|
||||||
playbook_files = []
|
|
||||||
for name, playbook in playbooks.items():
|
|
||||||
filename = str(tmpdir_factory.mktemp('data').join(name))
|
|
||||||
with open(filename, 'w') as f:
|
|
||||||
f.write(playbook)
|
|
||||||
playbook_files.append(filename)
|
|
||||||
|
|
||||||
cli = PlaybookCLI(['', 'playbook.yml'])
|
|
||||||
cli.parse()
|
|
||||||
options = cli.parser.parse_args(['-v'])[0]
|
|
||||||
loader = DataLoader()
|
|
||||||
variable_manager = VariableManager(loader=loader)
|
|
||||||
inventory = InventoryManager(loader=loader, sources='localhost,')
|
|
||||||
variable_manager.set_inventory(inventory)
|
|
||||||
|
|
||||||
return PlaybookExecutor(playbooks=playbook_files, inventory=inventory,
|
|
||||||
variable_manager=variable_manager, loader=loader,
|
|
||||||
options=options, passwords={})
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('event', {'playbook_on_start',
|
|
||||||
'playbook_on_play_start',
|
|
||||||
'playbook_on_task_start', 'runner_on_ok',
|
|
||||||
'playbook_on_stats'})
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'helloworld.yml': '''
|
|
||||||
- name: Hello World Sample
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- name: Hello Message
|
|
||||||
debug:
|
|
||||||
msg: "Hello World!"
|
|
||||||
'''}, # noqa
|
|
||||||
{'results_included.yml': '''
|
|
||||||
- name: Run module which generates results list
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
vars:
|
|
||||||
results: ['foo', 'bar']
|
|
||||||
tasks:
|
|
||||||
- name: Generate results list
|
|
||||||
debug:
|
|
||||||
var: results
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
def test_callback_plugin_receives_events(executor, cache, event, playbook):
|
|
||||||
executor.run()
|
|
||||||
assert len(cache)
|
|
||||||
assert event in [task['event'] for task in cache.values()]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'no_log_on_ok.yml': '''
|
|
||||||
- name: args should not be logged when task-level no_log is set
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- shell: echo "SENSITIVE"
|
|
||||||
no_log: true
|
|
||||||
'''}, # noqa
|
|
||||||
{'no_log_on_fail.yml': '''
|
|
||||||
- name: failed args should not be logged when task-level no_log is set
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- shell: echo "SENSITIVE"
|
|
||||||
no_log: true
|
|
||||||
failed_when: true
|
|
||||||
ignore_errors: true
|
|
||||||
'''}, # noqa
|
|
||||||
{'no_log_on_skip.yml': '''
|
|
||||||
- name: skipped task args should be suppressed with no_log
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- shell: echo "SENSITIVE"
|
|
||||||
no_log: true
|
|
||||||
when: false
|
|
||||||
'''}, # noqa
|
|
||||||
{'no_log_on_play.yml': '''
|
|
||||||
- name: args should not be logged when play-level no_log set
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
no_log: true
|
|
||||||
tasks:
|
|
||||||
- shell: echo "SENSITIVE"
|
|
||||||
'''}, # noqa
|
|
||||||
{'async_no_log.yml': '''
|
|
||||||
- name: async task args should suppressed with no_log
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
no_log: true
|
|
||||||
tasks:
|
|
||||||
- async: 10
|
|
||||||
poll: 1
|
|
||||||
shell: echo "SENSITIVE"
|
|
||||||
no_log: true
|
|
||||||
'''}, # noqa
|
|
||||||
{'with_items.yml': '''
|
|
||||||
- name: with_items tasks should be suppressed with no_log
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- shell: echo {{ item }}
|
|
||||||
no_log: true
|
|
||||||
with_items: [ "SENSITIVE", "SENSITIVE-SKIPPED", "SENSITIVE-FAILED" ]
|
|
||||||
when: item != "SENSITIVE-SKIPPED"
|
|
||||||
failed_when: item == "SENSITIVE-FAILED"
|
|
||||||
ignore_errors: yes
|
|
||||||
'''}, # noqa, NOTE: with_items will be deprecated in 2.9
|
|
||||||
{'loop.yml': '''
|
|
||||||
- name: loop tasks should be suppressed with no_log
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- shell: echo {{ item }}
|
|
||||||
no_log: true
|
|
||||||
loop: [ "SENSITIVE", "SENSITIVE-SKIPPED", "SENSITIVE-FAILED" ]
|
|
||||||
when: item != "SENSITIVE-SKIPPED"
|
|
||||||
failed_when: item == "SENSITIVE-FAILED"
|
|
||||||
ignore_errors: yes
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
def test_callback_plugin_no_log_filters(executor, cache, playbook):
|
|
||||||
executor.run()
|
|
||||||
assert len(cache)
|
|
||||||
assert 'SENSITIVE' not in json.dumps(cache.items())
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'no_log_on_ok.yml': '''
|
|
||||||
- name: args should not be logged when no_log is set at the task or module level
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- shell: echo "PUBLIC"
|
|
||||||
- shell: echo "PRIVATE"
|
|
||||||
no_log: true
|
|
||||||
- uri: url=https://example.org username="PUBLIC" password="PRIVATE"
|
|
||||||
- copy: content="PRIVATE" dest="/tmp/tmp_no_log"
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
def test_callback_plugin_task_args_leak(executor, cache, playbook):
|
|
||||||
executor.run()
|
|
||||||
events = cache.values()
|
|
||||||
assert events[0]['event'] == 'playbook_on_start'
|
|
||||||
assert events[1]['event'] == 'playbook_on_play_start'
|
|
||||||
|
|
||||||
# task 1
|
|
||||||
assert events[2]['event'] == 'playbook_on_task_start'
|
|
||||||
assert events[3]['event'] == 'runner_on_ok'
|
|
||||||
|
|
||||||
# task 2 no_log=True
|
|
||||||
assert events[4]['event'] == 'playbook_on_task_start'
|
|
||||||
assert events[5]['event'] == 'runner_on_ok'
|
|
||||||
assert 'PUBLIC' in json.dumps(cache.items())
|
|
||||||
assert 'PRIVATE' not in json.dumps(cache.items())
|
|
||||||
# make sure playbook was successful, so all tasks were hit
|
|
||||||
assert not events[-1]['event_data']['failures'], 'Unexpected playbook execution failure'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'loop_with_no_log.yml': '''
|
|
||||||
- name: playbook variable should not be overwritten when using no log
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
gather_facts: no
|
|
||||||
tasks:
|
|
||||||
- command: "{{ item }}"
|
|
||||||
register: command_register
|
|
||||||
no_log: True
|
|
||||||
with_items:
|
|
||||||
- "echo helloworld!"
|
|
||||||
- debug: msg="{{ command_register.results|map(attribute='stdout')|list }}"
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
def test_callback_plugin_censoring_does_not_overwrite(executor, cache, playbook):
|
|
||||||
executor.run()
|
|
||||||
events = cache.values()
|
|
||||||
assert events[0]['event'] == 'playbook_on_start'
|
|
||||||
assert events[1]['event'] == 'playbook_on_play_start'
|
|
||||||
|
|
||||||
# task 1
|
|
||||||
assert events[2]['event'] == 'playbook_on_task_start'
|
|
||||||
# Ordering of task and item events may differ randomly
|
|
||||||
assert set(['runner_on_ok', 'runner_item_on_ok']) == set([data['event'] for data in events[3:5]])
|
|
||||||
|
|
||||||
# task 2 no_log=True
|
|
||||||
assert events[5]['event'] == 'playbook_on_task_start'
|
|
||||||
assert events[6]['event'] == 'runner_on_ok'
|
|
||||||
assert 'helloworld!' in events[6]['event_data']['res']['msg']
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'strip_env_vars.yml': '''
|
|
||||||
- name: sensitive environment variables should be stripped from events
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
tasks:
|
|
||||||
- shell: echo "Hello, World!"
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
def test_callback_plugin_strips_task_environ_variables(executor, cache, playbook):
|
|
||||||
executor.run()
|
|
||||||
assert len(cache)
|
|
||||||
for event in cache.values():
|
|
||||||
assert os.environ['PATH'] not in json.dumps(event)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'custom_set_stat.yml': '''
|
|
||||||
- name: custom set_stat calls should persist to the local disk so awx can save them
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
tasks:
|
|
||||||
- set_stats:
|
|
||||||
data:
|
|
||||||
foo: "bar"
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
def test_callback_plugin_saves_custom_stats(executor, cache, playbook):
|
|
||||||
try:
|
|
||||||
private_data_dir = tempfile.mkdtemp()
|
|
||||||
with mock.patch.dict(os.environ, {'AWX_PRIVATE_DATA_DIR': private_data_dir}):
|
|
||||||
executor.run()
|
|
||||||
artifacts_path = os.path.join(private_data_dir, 'artifacts', 'custom')
|
|
||||||
with open(artifacts_path, 'r') as f:
|
|
||||||
assert json.load(f) == {'foo': 'bar'}
|
|
||||||
finally:
|
|
||||||
shutil.rmtree(os.path.join(private_data_dir))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'handle_playbook_on_notify.yml': '''
|
|
||||||
- name: handle playbook_on_notify events properly
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
handlers:
|
|
||||||
- name: my_handler
|
|
||||||
debug: msg="My Handler"
|
|
||||||
tasks:
|
|
||||||
- debug: msg="My Task"
|
|
||||||
changed_when: true
|
|
||||||
notify:
|
|
||||||
- my_handler
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
@pytest.mark.skipif(ANSIBLE_VERSION < '2.5', reason="v2_playbook_on_notify doesn't work before ansible 2.5")
|
|
||||||
def test_callback_plugin_records_notify_events(executor, cache, playbook):
|
|
||||||
executor.run()
|
|
||||||
assert len(cache)
|
|
||||||
notify_events = [x[1] for x in cache.items() if x[1]['event'] == 'playbook_on_notify']
|
|
||||||
assert len(notify_events) == 1
|
|
||||||
assert notify_events[0]['event_data']['handler'] == 'my_handler'
|
|
||||||
assert notify_events[0]['event_data']['host'] == 'localhost'
|
|
||||||
assert notify_events[0]['event_data']['task'] == 'debug'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('playbook', [
|
|
||||||
{'no_log_module_with_var.yml': '''
|
|
||||||
- name: ensure that module-level secrets are redacted
|
|
||||||
connection: local
|
|
||||||
hosts: all
|
|
||||||
vars:
|
|
||||||
- pw: SENSITIVE
|
|
||||||
tasks:
|
|
||||||
- uri:
|
|
||||||
url: https://example.org
|
|
||||||
user: john-jacob-jingleheimer-schmidt
|
|
||||||
password: "{{ pw }}"
|
|
||||||
'''}, # noqa
|
|
||||||
])
|
|
||||||
def test_module_level_no_log(executor, cache, playbook):
|
|
||||||
# https://github.com/ansible/tower/issues/1101
|
|
||||||
# It's possible for `no_log=True` to be defined at the _module_ level,
|
|
||||||
# e.g., for the URI module password parameter
|
|
||||||
# This test ensures that we properly redact those
|
|
||||||
executor.run()
|
|
||||||
assert len(cache)
|
|
||||||
assert 'john-jacob-jingleheimer-schmidt' in json.dumps(cache.items())
|
|
||||||
assert 'SENSITIVE' not in json.dumps(cache.items())
|
|
||||||
@@ -191,18 +191,7 @@ def run_isolated_job(private_data_dir, secrets, logfile=sys.stdout):
|
|||||||
job_timeout = secrets.get('job_timeout', 10)
|
job_timeout = secrets.get('job_timeout', 10)
|
||||||
pexpect_timeout = secrets.get('pexpect_timeout', 5)
|
pexpect_timeout = secrets.get('pexpect_timeout', 5)
|
||||||
|
|
||||||
# Use local callback directory
|
|
||||||
callback_dir = os.getenv('AWX_LIB_DIRECTORY')
|
|
||||||
if callback_dir is None:
|
|
||||||
raise RuntimeError('Location for callbacks must be specified '
|
|
||||||
'by environment variable AWX_LIB_DIRECTORY.')
|
|
||||||
env['ANSIBLE_CALLBACK_PLUGINS'] = os.path.join(callback_dir, 'isolated_callbacks')
|
|
||||||
if 'AD_HOC_COMMAND_ID' in env:
|
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal'
|
|
||||||
else:
|
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
|
|
||||||
env['AWX_ISOLATED_DATA_DIR'] = private_data_dir
|
env['AWX_ISOLATED_DATA_DIR'] = private_data_dir
|
||||||
env['PYTHONPATH'] = env.get('PYTHONPATH', '') + callback_dir + ':'
|
|
||||||
|
|
||||||
venv_path = env.get('VIRTUAL_ENV')
|
venv_path = env.get('VIRTUAL_ENV')
|
||||||
if venv_path and not os.path.exists(venv_path):
|
if venv_path and not os.path.exists(venv_path):
|
||||||
|
|||||||
@@ -1354,7 +1354,6 @@ class RunJob(BaseTask):
|
|||||||
env['MAX_EVENT_RES'] = str(settings.MAX_EVENT_RES_DATA)
|
env['MAX_EVENT_RES'] = str(settings.MAX_EVENT_RES_DATA)
|
||||||
if not isolated:
|
if not isolated:
|
||||||
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_path
|
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_path
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
|
|
||||||
env['AWX_HOST'] = settings.TOWER_URL_BASE
|
env['AWX_HOST'] = settings.TOWER_URL_BASE
|
||||||
|
|
||||||
# Create a directory for ControlPath sockets that is unique to each
|
# Create a directory for ControlPath sockets that is unique to each
|
||||||
@@ -1632,7 +1631,6 @@ class RunProjectUpdate(BaseTask):
|
|||||||
env['TMP'] = settings.AWX_PROOT_BASE_PATH
|
env['TMP'] = settings.AWX_PROOT_BASE_PATH
|
||||||
env['PROJECT_UPDATE_ID'] = str(project_update.pk)
|
env['PROJECT_UPDATE_ID'] = str(project_update.pk)
|
||||||
env['ANSIBLE_CALLBACK_PLUGINS'] = self.get_path_to('..', 'plugins', 'callback')
|
env['ANSIBLE_CALLBACK_PLUGINS'] = self.get_path_to('..', 'plugins', 'callback')
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
def _build_scm_url_extra_vars(self, project_update, scm_username='', scm_password=''):
|
def _build_scm_url_extra_vars(self, project_update, scm_username='', scm_password=''):
|
||||||
@@ -2383,7 +2381,6 @@ class RunAdHocCommand(BaseTask):
|
|||||||
env['INVENTORY_HOSTVARS'] = str(True)
|
env['INVENTORY_HOSTVARS'] = str(True)
|
||||||
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_dir
|
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_dir
|
||||||
env['ANSIBLE_LOAD_CALLBACK_PLUGINS'] = '1'
|
env['ANSIBLE_LOAD_CALLBACK_PLUGINS'] = '1'
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal' # Hardcoded by Ansible for ad-hoc commands (either minimal or oneline).
|
|
||||||
env['ANSIBLE_SFTP_BATCH_MODE'] = 'False'
|
env['ANSIBLE_SFTP_BATCH_MODE'] = 'False'
|
||||||
|
|
||||||
# Specify empty SSH args (should disable ControlPersist entirely for
|
# Specify empty SSH args (should disable ControlPersist entirely for
|
||||||
|
|||||||
@@ -189,16 +189,11 @@ def test_run_isolated_job(private_data_dir, rsa_key):
|
|||||||
mgr.build_isolated_job_data()
|
mgr.build_isolated_job_data()
|
||||||
stdout = StringIO()
|
stdout = StringIO()
|
||||||
# Mock environment variables for callback module
|
# Mock environment variables for callback module
|
||||||
with mock.patch('os.getenv') as env_mock:
|
status, rc = run.run_isolated_job(private_data_dir, secrets, stdout)
|
||||||
env_mock.return_value = '/path/to/awx/lib'
|
|
||||||
status, rc = run.run_isolated_job(private_data_dir, secrets, stdout)
|
|
||||||
assert status == 'successful'
|
assert status == 'successful'
|
||||||
assert rc == 0
|
assert rc == 0
|
||||||
assert FILENAME in stdout.getvalue()
|
assert FILENAME in stdout.getvalue()
|
||||||
|
|
||||||
assert '/path/to/awx/lib' in env['PYTHONPATH']
|
|
||||||
assert env['ANSIBLE_STDOUT_CALLBACK'] == 'awx_display'
|
|
||||||
assert env['ANSIBLE_CALLBACK_PLUGINS'] == '/path/to/awx/lib/isolated_callbacks'
|
|
||||||
assert env['AWX_ISOLATED_DATA_DIR'] == private_data_dir
|
assert env['AWX_ISOLATED_DATA_DIR'] == private_data_dir
|
||||||
|
|
||||||
|
|
||||||
@@ -230,9 +225,6 @@ def test_run_isolated_adhoc_command(private_data_dir, rsa_key):
|
|||||||
# an ad-hoc command that runs `pwd` should print `private_data_dir` to stdout
|
# an ad-hoc command that runs `pwd` should print `private_data_dir` to stdout
|
||||||
assert private_data_dir in stdout.getvalue()
|
assert private_data_dir in stdout.getvalue()
|
||||||
|
|
||||||
assert '/path/to/awx/lib' in env['PYTHONPATH']
|
|
||||||
assert env['ANSIBLE_STDOUT_CALLBACK'] == 'minimal'
|
|
||||||
assert env['ANSIBLE_CALLBACK_PLUGINS'] == '/path/to/awx/lib/isolated_callbacks'
|
|
||||||
assert env['AWX_ISOLATED_DATA_DIR'] == private_data_dir
|
assert env['AWX_ISOLATED_DATA_DIR'] == private_data_dir
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
AWX_LIB=`/var/lib/awx/venv/awx/bin/python -c 'import os, awx; print os.path.dirname(awx.__file__)'`
|
|
||||||
. /var/lib/awx/venv/awx/bin/activate
|
|
||||||
exec env AWX_LIB_DIRECTORY=$AWX_LIB/lib /var/lib/awx/venv/awx/bin/python $AWX_LIB/main/expect/run.pyc "$@"
|
|
||||||
Reference in New Issue
Block a user