ansible-junos-stdlib
ansible-junos-stdlib copied to clipboard
juniper.device.config fail silently
Issue Type
- Bug Report
Module Name
juniper.device.config
juniper.device collection and Python libraries version
ansible [core 2.11.2]
config file = /spine/spine/iac/ansible-runner/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.9/dist-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110]
jinja version = 3.0.1
libyaml = True
amqp==5.0.6
ansible-core==2.11.2
ansible-runner==2.0.1
asgiref==3.4.1
attrs==21.2.0
bcrypt==3.2.0
billiard==3.6.4.0
celery==5.1.2
certifi==2021.5.30
cffi==1.14.6
chardet==4.0.0
click==7.1.2
click-didyoumean==0.0.3
click-plugins==1.1.1
click-repl==0.2.0
colorama==0.4.4
configparser==5.2.0
coverage==5.5
cryptography==3.4.7
Django==3.2.5
django-celery-beat==2.2.1
django-celery-results==2.2.0
django-crispy-forms==1.12.0
django-debug-toolbar==3.2.1
django-extensions==3.1.3
django-guardian==2.4.0
django-guid==3.2.0
django-pgcrypto-fields==2.6.0
django-polymorphic==3.0.0
django-smuggler==1.0.3
django-timezone-field==4.2.1
djangorestframework==3.12.4
djangorestframework-guardian==0.3.0
docutils==0.17.1
elasticsearch==7.13.3
factory-boy==3.2.0
Faker==8.10.1
fluent-logger==0.10.0
fqdn==1.5.1
future==0.18.2
gitdb==4.0.7
GitPython==3.1.24
gunicorn==20.1.0
h11==0.12.0
icdiff==2.0.4
idna==2.10
inflection==0.5.1
iniconfig==1.1.1
Jinja2==3.0.1
jmespath==0.10.0
jsnapy==1.3.6
junos-eznc==2.6.3
jxmlease==1.0.3
kombu==5.1.0
lockfile==0.12.2
lxml==4.6.3
MarkupSafe==2.0.1
mixer==7.2.0
msgpack==1.0.2
ncclient==0.6.9
netaddr==0.8.0
packaging==21.0
paramiko==2.7.2
pexpect==4.8.0
pluggy==0.13.1
prompt-toolkit==3.0.19
psycopg2==2.9.1
ptyprocess==0.7.0
py==1.10.0
pycparser==2.20
PyNaCl==1.4.0
pyparsing==2.4.7
pyserial==3.5
pytest==6.2.4
pytest-celery==0.0.0
pytest-cov==2.12.1
pytest-django==4.4.0
pytest-factoryboy==2.1.0
pytest-mock==3.6.1
python-crontab==2.5.1
python-daemon==2.3.0
python-dateutil==2.8.1
pytz==2021.1
PyYAML==5.4.1
requests==2.25.1
resolvelib==0.5.4
scp==0.13.6
six==1.16.0
smmap==4.0.0
sqlparse==0.4.1
text-unidecode==1.3
toml==0.10.2
transitions==0.8.8
typing-extensions==3.10.0.2
urllib3==1.26.6
uvicorn==0.14.0
vine==5.0.0
wcwidth==0.2.5
xmltodict==0.12.0
yamlordereddictloader==0.4.0
zxcvbn==4.4.28
Collection Version
----------------- -------
ansible.netcommon 2.5.0
ansible.posix 1.3.0
ansible.utils 2.4.3
community.general 3.4.0
juniper.device 1.0.1
CALLBACKS_ENABLED(/xxx/xxx/iac/ansible-runner/ansible.cfg) = ['profile_tasks']
DEFAULT_JINJA2_NATIVE(/xxx/xxx/iac/ansible-runner/ansible.cfg) = True
HOST_KEY_CHECKING(/xxx/xxx/iac/ansible-runner/ansible.cfg) = False
INJECT_FACTS_AS_VARS(/xxx/xxx/iac/ansible-runner/ansible.cfg) = False
OS / Environment
ex4650-48y-8c 19.3R2-S4.5
Summary
Okay, it's quite tricky. I'm not sure it's related directly to the collection code but it's quite specific to this collection.
For the context:
- I have a container with Python and ansible installed
- Ansible playbooks are run through Python ansible-runner via Celery tasks
- We use PyCharm to run the container and debug Celery tasks
- Up until now, everything was working fine, we were using the "old" collection (https://galaxy.ansible.com/junipernetworks/junos)
- We changed to this collection and now the playbook fail silently but only when the docker compose is run through PyCharm
We could not identify any difference between the two environments. But I would like your help to figure out why the module fail silently without any stderr. If we had some kind of error message we could narrow the issue more precisely.
Steps to reproduce
It's quite tricky as the playbook is successful when running the container through docker compose directly but fail when the docker compose is run through PyCharm.
Expected results
Here's a successful run through a direct docker-compose
TASK [Apply config on Junos] ***************************************************
task path: /xxx/xxx/iac/subnets/project/tasks/apply_config.yml:2
Wednesday 22 December 2021 09:48:05 +0100 (0:00:00.255) 0:00:04.820 ****
<10.111.0.113> ESTABLISH LOCAL CONNECTION FOR USER: root
META: noop
<10.111.0.113> EXEC /bin/sh -c 'echo ~root && sleep 0'
<10.111.0.113> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1640162885.8019924-137-30247405225892 `" && echo ansible-tmp-1640162885.8019924-137-30247405225892="` echo /root/.ansible/tmp/ansible-tmp-1640162885.8019924-137-30247405225892 `" ) && sleep 0'
Including module_utils file ansible/__init__.py
Including module_utils file ansible/module_utils/__init__.py
Including module_utils file ansible/module_utils/basic.py
Including module_utils file ansible/module_utils/_text.py
Including module_utils file ansible/module_utils/common/_collections_compat.py
Including module_utils file ansible/module_utils/common/__init__.py
Including module_utils file ansible/module_utils/common/_json_compat.py
Including module_utils file ansible/module_utils/common/_utils.py
Including module_utils file ansible/module_utils/common/arg_spec.py
Including module_utils file ansible/module_utils/common/file.py
Including module_utils file ansible/module_utils/common/parameters.py
Including module_utils file ansible/module_utils/common/collections.py
Including module_utils file ansible/module_utils/common/process.py
Including module_utils file ansible/module_utils/common/sys_info.py
Including module_utils file ansible/module_utils/common/text/converters.py
Including module_utils file ansible/module_utils/common/text/__init__.py
Including module_utils file ansible/module_utils/common/text/formatters.py
Including module_utils file ansible/module_utils/common/validation.py
Including module_utils file ansible/module_utils/common/warnings.py
Including module_utils file ansible/module_utils/compat/selectors.py
Including module_utils file ansible/module_utils/compat/__init__.py
Including module_utils file ansible/module_utils/compat/_selectors2.py
Including module_utils file ansible/module_utils/compat/selinux.py
Including module_utils file ansible/module_utils/distro/__init__.py
Including module_utils file ansible/module_utils/distro/_distro.py
Including module_utils file ansible/module_utils/errors.py
Including module_utils file ansible/module_utils/parsing/convert_bool.py
Including module_utils file ansible/module_utils/parsing/__init__.py
Including module_utils file ansible/module_utils/pycompat24.py
Including module_utils file ansible/module_utils/six/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/module_utils/configuration.py
Including module_utils file ansible_collections/__init__.py
Including module_utils file ansible_collections/juniper/__init__.py
Including module_utils file ansible_collections/juniper/device/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/module_utils/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/module_utils/juniper_junos_common.py
Including module_utils file ansible/module_utils/connection.py
Including module_utils file ansible/module_utils/common/json.py
<ex> Attempting python interpreter discovery
<10.111.0.113> EXEC /bin/sh -c 'echo PLATFORM; uname; echo FOUND; command -v '"'"'/usr/bin/python'"'"'; command -v '"'"'python3.9'"'"'; command -v '"'"'python3.8'"'"'; command -v '"'"'python3.7'"'"'; command -v '"'"'python3.6'"'"'; command -v '"'"'python3.5'"'"'; command -v '"'"'python2.7'"'"'; command -v '"'"'python2.6'"'"'; command -v '"'"'/usr/libexec/platform-python'"'"'; command -v '"'"'/usr/bin/python3'"'"'; command -v '"'"'python'"'"'; echo ENDFOUND && sleep 0'
<10.111.0.113> EXEC /bin/sh -c '/usr/bin/python && sleep 0'
Using module file /root/.ansible/collections/ansible_collections/juniper/device/plugins/modules/config.py
<10.111.0.113> PUT /root/.ansible/tmp/ansible-local-281v4h5kp6/tmpcqwi7rim TO /root/.ansible/tmp/ansible-tmp-1640162885.8019924-137-30247405225892/AnsiballZ_config.py
<10.111.0.113> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1640162885.8019924-137-30247405225892/ /root/.ansible/tmp/ansible-tmp-1640162885.8019924-137-30247405225892/AnsiballZ_config.py && sleep 0'
<10.111.0.113> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1640162885.8019924-137-30247405225892/AnsiballZ_config.py && sleep 0'
<10.111.0.113> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1640162885.8019924-137-30247405225892/ > /dev/null 2>&1 && sleep 0'
[DEPRECATION WARNING]: Distribution debian 11 on host ex should use
/usr/bin/python3, but is using /usr/bin/python for backward compatibility with
prior Ansible releases. A future Ansible release will default to using the
discovered platform python for this host. See https://docs.ansible.com/ansible/
2.11/reference_appendices/interpreter_discovery.html for more information. This
feature will be removed in version 2.12. Deprecation warnings can be disabled
by setting deprecation_warnings=False in ansible.cfg.
ok: [ex] => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"invocation": {
"module_args": {
"attempts": null,
"baud": null,
"check": false,
"check_commit_wait": null,
"comment": null,
"commit": null,
"commit_empty_changes": false,
"config_mode": "private",
"confirmed": null,
"console": null,
"cs_passwd": null,
"cs_user": null,
"dest": null,
"dest_dir": null,
"diff": null,
"diffs_file": null,
"filter": null,
"format": null,
"host": "10.111.0.113",
"ignore_warning": [
"statement not found"
],
"level": null,
"lines": [
"set vlans 6e55324b-3e4e-4958-a7aa-82339338365b",
"set vlans 6e55324b-3e4e-4958-a7aa-82339338365b vlan-id 2001",
"set vlans 6e55324b-3e4e-4958-a7aa-82339338365b description \"Test COD 2\"",
"set groups 0005c4cf-419f-65a3-2864-9440c924a0b4 interfaces <xe-*> unit 0 family ethernet-switching vlan members 6e55324b-3e4e-4958-a7aa-82339338365b"
],
"load": "merge",
"logdir": null,
"logfile": null,
"mode": null,
"model": null,
"namespace": null,
"options": {},
"passwd": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 830,
"remove_ns": null,
"retrieve": null,
"return_output": true,
"rollback": null,
"src": null,
"ssh_config": null,
"ssh_private_key_file": null,
"template": null,
"timeout": 10,
"url": null,
"user": "antemeta",
"vars": null
}
},
"msg": "Configuration has been: opened, loaded, diffed, closed."
}
Actual results
Here's a failed silent run through a PyCharm triggered docker-compose
TASK [Apply config on Junos] ***************************************************
task path: /xxx/xxx/iac/subnets/project/tasks/apply_config.yml:2
Wednesday 22 December 2021 09:40:43 +0100 (0:00:01.067) 0:00:12.870 ****
<10.111.0.113> ESTABLISH LOCAL CONNECTION FOR USER: root
<10.111.0.113> EXEC /bin/sh -c 'echo ~root && sleep 0'
META: noop
<10.111.0.113> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1640162443.8914657-143-37148930553543 `" && echo ansible-tmp-1640162443.8914657-143-37148930553543="` echo /root/.ansible/tmp/ansible-tmp-1640162443.8914657-143-37148930553543 `" ) && sleep 0'
Including module_utils file ansible/__init__.py
Including module_utils file ansible/module_utils/__init__.py
Including module_utils file ansible/module_utils/basic.py
Including module_utils file ansible/module_utils/_text.py
Including module_utils file ansible/module_utils/common/_collections_compat.py
Including module_utils file ansible/module_utils/common/__init__.py
Including module_utils file ansible/module_utils/common/_json_compat.py
Including module_utils file ansible/module_utils/common/_utils.py
Including module_utils file ansible/module_utils/common/arg_spec.py
Including module_utils file ansible/module_utils/common/file.py
Including module_utils file ansible/module_utils/common/parameters.py
Including module_utils file ansible/module_utils/common/collections.py
Including module_utils file ansible/module_utils/common/process.py
Including module_utils file ansible/module_utils/common/sys_info.py
Including module_utils file ansible/module_utils/common/text/converters.py
Including module_utils file ansible/module_utils/common/text/__init__.py
Including module_utils file ansible/module_utils/common/text/formatters.py
Including module_utils file ansible/module_utils/common/validation.py
Including module_utils file ansible/module_utils/common/warnings.py
Including module_utils file ansible/module_utils/compat/selectors.py
Including module_utils file ansible/module_utils/compat/__init__.py
Including module_utils file ansible/module_utils/compat/_selectors2.py
Including module_utils file ansible/module_utils/compat/selinux.py
Including module_utils file ansible/module_utils/distro/__init__.py
Including module_utils file ansible/module_utils/distro/_distro.py
Including module_utils file ansible/module_utils/errors.py
Including module_utils file ansible/module_utils/parsing/convert_bool.py
Including module_utils file ansible/module_utils/parsing/__init__.py
Including module_utils file ansible/module_utils/pycompat24.py
Including module_utils file ansible/module_utils/six/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/module_utils/configuration.py
Including module_utils file ansible_collections/__init__.py
Including module_utils file ansible_collections/juniper/__init__.py
Including module_utils file ansible_collections/juniper/device/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/module_utils/__init__.py
Including module_utils file ansible_collections/juniper/device/plugins/module_utils/juniper_junos_common.py
Including module_utils file ansible/module_utils/connection.py
Including module_utils file ansible/module_utils/common/json.py
<ex> Attempting python interpreter discovery
<10.111.0.113> EXEC /bin/sh -c 'echo PLATFORM; uname; echo FOUND; command -v '"'"'/usr/bin/python'"'"'; command -v '"'"'python3.9'"'"'; command -v '"'"'python3.8'"'"'; command -v '"'"'python3.7'"'"'; command -v '"'"'python3.6'"'"'; command -v '"'"'python3.5'"'"'; command -v '"'"'python2.7'"'"'; command -v '"'"'python2.6'"'"'; command -v '"'"'/usr/libexec/platform-python'"'"'; command -v '"'"'/usr/bin/python3'"'"'; command -v '"'"'python'"'"'; echo ENDFOUND && sleep 0'
<10.111.0.113> EXEC /bin/sh -c '/usr/bin/python && sleep 0'
Using module file /root/.ansible/collections/ansible_collections/juniper/device/plugins/modules/config.py
<10.111.0.113> PUT /root/.ansible/tmp/ansible-local-34f1d58xfx/tmp99d45fpk TO /root/.ansible/tmp/ansible-tmp-1640162443.8914657-143-37148930553543/AnsiballZ_config.py
<10.111.0.113> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1640162443.8914657-143-37148930553543/ /root/.ansible/tmp/ansible-tmp-1640162443.8914657-143-37148930553543/AnsiballZ_config.py && sleep 0'
<10.111.0.113> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1640162443.8914657-143-37148930553543/AnsiballZ_config.py && sleep 0'
<10.111.0.113> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1640162443.8914657-143-37148930553543/ > /dev/null 2>&1 && sleep 0'
[DEPRECATION WARNING]: Distribution debian 11 on host ex should use
/usr/bin/python3, but is using /usr/bin/python for backward compatibility with
prior Ansible releases. A future Ansible release will default to using the
discovered platform python for this host. See https://docs.ansible.com/ansible/
2.11/reference_appendices/interpreter_discovery.html for more information. This
feature will be removed in version 2.12. Deprecation warnings can be disabled
by setting deprecation_warnings=False in ansible.cfg.
fatal: [ex]: FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"module_stderr": "",
"module_stdout": "\n{\"msg\": \"Configuration has been: opened, loaded, diffed, closed.\", \"changed\": false, \"failed\": false, \"invocation\": {\"module_args\": {\"lines\": [\"set vlans 6e55324b-3e4e-4958-a7aa-82339338365b\", \"set vlans 6e55324b-3e4e-4958-a7aa-82339338365b vlan-id 2001\", \"set vlans 6e55324b-3e4e-4958-a7aa-82339338365b description \\\"Test COD 2\\\"\", \"set groups 0005c4cf-419f-65a3-2864-9440c924a0b4 interfaces <xe-*> unit 0 family ethernet-switching vlan members 6e55324b-3e4e-4958-a7aa-82339338365b\"], \"config_mode\": \"private\", \"load\": \"merge\", \"ignore_warning\": [\"statement not found\"], \"check\": false, \"host\": \"10.111.0.113\", \"user\": \"antemeta\", \"passwd\": \"VALUE_SPECIFIED_IN_NO_LOG_PARAMETER\", \"timeout\": 10, \"return_output\": true, \"options\": {}, \"commit_empty_changes\": false, \"rollback\": null, \"src\": null, \"template\": null, \"vars\": null, \"url\": null, \"format\": null, \"model\": null, \"remove_ns\": null, \"namespace\": null, \"diff\": null, \"diffs_file\": null, \"dest_dir\": null, \"retrieve\": null, \"filter\": null, \"dest\": null, \"commit\": null, \"confirmed\": null, \"comment\": null, \"check_commit_wait\": null, \"cs_user\": null, \"cs_passwd\": null, \"ssh_private_key_file\": null, \"ssh_config\": null, \"mode\": null, \"console\": null, \"port\": 830, \"baud\": null, \"attempts\": null, \"logfile\": null, \"logdir\": null, \"level\": null}}}\u001b[0m\n\u001b[0m\u001b[0m",
"msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
"rc": 0
}
I can add that the issue is in the module_stdout string, that fails to parse as a json. Because of the trailing \u001b[0m\n\u001b[0m\u001b[0m.
It seems to be terminal configuration escape codes. But I fail to see why they are there.
This issue is similar to https://github.com/ansible/ansible/issues/13895
The solution was to introduce a newline before the json output
self.do_cleanup_files()
print('\n%s' % self.jsonify(kwargs))
sys.exit(0)
Similarly, we can add a newline after the json output. And the json output is successfully interpreted, the task succeeds.
self.do_cleanup_files()
print('\n%s\n' % self.jsonify(kwargs))
sys.exit(0)
We have nailed the issue to the jsnapy and colorama python modules being installed. As we don't need jsnapy, we removed it. I don't really understand why it is happening, because we don't use this module. But at the end of the juniper.device.config task, the colorama module is called and append these color control characters at the end of stdout.