Problem
When running the ansible.playbook action and passing in "structure" data for extra_vars, Ansible is not interpreting them properly.
ansible_playbook_linux:
action: ansible.playbook
input:
playbook: "{{ _.playbook }}"
inventory_file: "{{ _.server }},"
extra_vars:
- wait_timeout: 2
wait_sleep: 2
wait_connect_timeout: 2
ansible_user: "user"
ansible_ssh_pass: "xxx"
ansible_ssh_extra_args: "-o StrictHostKeyChecking=no"
Looking at the output of ps -aef | grep ansible i see the following:
root 12711 2520 0 10:02 pts/0 00:00:00 sudo -E -- bash -c /opt/stackstorm/packs/ansible/actions/ansible_playbook.py --extra_vars='[{u'"'"'wait_sleep'"'"': 2, u'"'"'ansible_ssh_pass'"'"': u'"'"'xxx'"'"', u'"'"'ansible_user'"'"': u'"'"'user'"'"', u'"'"'wait_timeout'"'"': 2, u'"'"'wait_connect_timeout'"'"': 2}]' --inventory_file=host.domain.tld, -vvv /opt/encore/ansible/playbooks/wait_for_connection.yaml
root 12712 12711 0 10:02 pts/0 00:00:00 python /opt/stackstorm/packs/ansible/actions/ansible_playbook.py --extra_vars=[{u'wait_sleep': 2, u'ansible_ssh_pass': u'xxx', u'ansible_user': u'user', u'wait_timeout': 2, u'wait_connect_timeout': 2}] --inventory_file=host.domain.tld, -vvv /opt/encore/ansible/playbooks/wait_for_connection.yaml
root 12713 12712 12 10:02 pts/0 00:00:00 /opt/stackstorm/virtualenvs/ansible/bin/python /opt/stackstorm/virtualenvs/ansible/bin/ansible-playbook --inventory-file=host.domain.tld, -vvv /opt/encore/ansible/playbooks/wait_for_connection.yaml --extra-vars='{"wait_timeout": 2, "wait_connect_timeout": 2, "wait_sleep": 2, "ansible_user": "user", "ansible_ssh_pass": "xxx"}'
root 12726 12713 2 10:02 pts/0 00:00:00 /opt/stackstorm/virtualenvs/ansible/bin/python /opt/stackstorm/virtualenvs/ansible/bin/ansible-playbook --inventory-file=host.domain.tld, -vvv /opt/encore/ansible/playbooks/wait_for_connection.yaml --extra-vars='{"wait_timeout": 2, "wait_connect_timeout": 2, "wait_sleep": 2, "ansible_user": "user", "ansible_ssh_pass": "xxx"}'
This ansible command times out after the default 10 minutes for the playbook.
System Details
$ ansible --version
ansible 2.3.2.0
config file =
configured module search path = Default w/o overrides
python version = 2.7.5 (default, Nov 6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
$ st2 --version
st2 2.4.0
$ st2 pack get ansible
+-------------+--------------------------------------------------+
| Property | Value |
+-------------+--------------------------------------------------+
| name | ansible |
| version | 0.5.2 |
| author | StackStorm, Inc. |
| email | info@stackstorm.com |
| keywords | [ |
| | "ansible", |
| | "cfg management", |
| | "configuration management" |
| | ] |
| description | st2 content pack containing ansible integrations |
+-------------+--------------------------------------------------+
Debugging
Manually running the following command executes just, ansible logs in immediately and no timeouts.
/opt/stackstorm/virtualenvs/ansible/bin/python /opt/stackstorm/virtualenvs/ansible/bin/ansible-playbook --inventory-file=host.domain.tld, -vvv /opt/encore/ansible/playbooks/wait_for_connection.yaml --extra-vars='{"wait_timeout": 2, "wait_connect_timeout": 2, "wait_sleep": 2, "ansible_user": "user", "ansible_ssh_pass": "xxx"}'
However, running the following does NOT work (waits forever until a timeout).
sudo -E -- bash -c /opt/stackstorm/packs/ansible/actions/ansible_playbook.py --extra_vars='[{u'"'"'wait_sleep'"'"': 2, u'"'"'ansible_ssh_pass'"'"': u'"'"'xxx'"'"', u'"'"'ansible_user'"'"': u'"'"'user'"'"', u'"'"'wait_timeout'"'"': 2, u'"'"'wait_connect_timeout'"'"': 2}]' --inventory_file=host.domain.tld, -vvv /opt/encore/ansible/playbooks/wait_for_connection.yaml
I next added a print statement to my playbook
pre_tasks:
- name: Display all variables/facts
debug:
msg: "{{ vars | to_nice_json(indent=4) }}"
Now i compared the outputs from the first command to the second command.
Output from the first command that invokes ansible_playbook.py:
TASK [Display all variables/facts] ************************************************************************************
task path: /opt/encore/ansible/playbooks/wait_for_connection.yaml:13
ok: [host.domain.tld] => {
"msg": {
"_raw_params": "'{\"wait_timeout\": 2, \"wait_connect_timeout\": 2, \"wait_sleep\": 2, \"ansible_user\": \"user\", \"ansible_ssh_pass\": \"xxx\"}'",
"ansible_check_mode": false,
"ansible_play_batch": [
"host.domain.tld"
],
"ansible_play_hosts": [
"host.domain.tld"
],
....
"wait_connect_timeout": 5,
"wait_sleep": 1,
"wait_timeout": 600
}
}
Output from the second command that invoking ansible directly:
TASK [Display all variables/facts] ************************************************************************************
ok: [host.domain.tld] => {
"msg": {
"ansible_check_mode": false,
"ansible_play_batch": [
"host.domain.tld"
],
"ansible_play_hosts": [
"host.domain.tld"
],
"ansible_play_hosts_all": [
"host.domain.tld"
],
"ansible_playbook_python": "/opt/stackstorm/virtualenvs/ansible/bin/python",
"ansible_ssh_pass": "xxx",
"ansible_user": "user",
....
"wait_connect_timeout": 2,
"wait_sleep": 2,
"wait_timeout": 2
}
}
As you can see, when invoking ansible_playbook.py the variables are are not merged properly into the vars dict, causing the connection to fail repeatedly until the timeout of 10 minutes (default) occurs.
Conversely, when we invoke it from shell, the --extra-vars is merged properly with the vars dict and the connection works as expected.
Proposed Solution
The ansible-playbook is where the command is being executed here https://github.com/StackStorm-Exchange/stackstorm-ansible/blob/master/actions/lib/ansible_base.py#L105 .
If we change that line to use a shell, and convert the command from a list to a string (see below), then everything works as expected.
exit_code = subprocess.call(' '.join(self.cmd), env=os.environ.copy(), shell=True)
Problem
When running the
ansible.playbookaction and passing in "structure" data forextra_vars, Ansible is not interpreting them properly.Looking at the output of
ps -aef | grep ansiblei see the following:This ansible command times out after the default 10 minutes for the playbook.
System Details
Debugging
Manually running the following command executes just, ansible logs in immediately and no timeouts.
However, running the following does NOT work (waits forever until a timeout).
I next added a print statement to my playbook
Now i compared the outputs from the first command to the second command.
Output from the first command that invokes
ansible_playbook.py:Output from the second command that invoking ansible directly:
As you can see, when invoking
ansible_playbook.pythe variables are are not merged properly into thevarsdict, causing the connection to fail repeatedly until the timeout of 10 minutes (default) occurs.Conversely, when we invoke it from shell, the
--extra-varsis merged properly with thevarsdict and the connection works as expected.Proposed Solution
The
ansible-playbookis where the command is being executed here https://github.com/StackStorm-Exchange/stackstorm-ansible/blob/master/actions/lib/ansible_base.py#L105 .If we change that line to use a shell, and convert the command from a list to a string (see below), then everything works as expected.