I’ve encountered a challenging problem while working with Ansible and I wanted to ask for your help and advice.
While running an Ansible role that registers Windows hosts in Zabbix, Ansible insists on using PowerShell. This causes errors because PowerShell is not available on the Zabbix server.
Here is a fragment of the error log:
Task path: /runner/project/windows/roles/zabbix_register_windows_host/tasks/main.yml:12
fatal: [10.10.10.10 → zabbix server]: FAILED! => {
“changed”: false,
“module_stderr”: “/bin/sh: line 1: PowerShell: command not found\n”,
“module_stdout”: “”,
“msg”: “MODULE FAILURE\nSee stdout/stderr for the exact error”,
“rc”: 0
}
…ignoring
redirecting (type: connection) ansible.builtin.httpapi to ansible.netcommon.httpapi
ESTABLISH LOCAL CONNECTION FOR USER: root
EXEC /bin/sh -c 'PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand vAHQAIAAkAD8AKQAgAHsAIABJAGYAIAAoAEcAZQB0AC0AVgBhAHIAaQBhAGIAbABlACAATABBAFMAVABFAFgASQBUAEMATwBEAEUAIAAtAEUAcgBy…
Using module file /root/.ansible/collections/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py
PUT /root/.ansible/tmp/ansible-local-229g6e_e1u/tmp6dn9lqx6 TO /runner/project/.\AnsiballZ_zabbix_host.ps1
EXEC /bin/sh -c 'PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand UwBlABfAC4ASQBuAHYAbwBjAGEAdABpAG8AbgBJAG4AZgBvAC4AUABvAHMAaQB0AGkAbwBuAE0AZQBzAHMAYQBnAGUAKQAKAH0ACgBFAGwAcwBl…
What I’ve tried:
Setting ansible_shell_executable: /bin/bash and ansible_shell_type: cmd at the task’s level in the role:
name: Set API token
ansible.builtin.set_fact:
ansible_zabbix_auth_key: “{{ zabbix_auth_key }}”
ansible_zabbix_url: “{{ ansible_zabbix_url }}”
Unfortunately, none of these suggestions solved the problem. Ansible still tries to use PowerShell.
What is important to mention,
The playbook is run with ansible_shell_type: powershell at the playbook level and we cannot remove it, because the above role is part of a larger playbook where earlier tasks need to have the PowerShell shell set.
How can I work around this issue and what else can I check? Any help would be greatly appreciated!
just remove it from the task. The community.zabbix.zabbix_host: works against the http API of zabbix itself. There is no need that you leave your host/ansible controle node for that task.
This doesn’t “leave” the control node, it uses the network-style httpapi model where the module always runs on the control node but connects to the target host using HTTP. If they don’t delegate the task the module will try to connect to the original target host instead of the Zabbix host, which will not work.
redirecting (type: connection) ansible.builtin.httpapi to ansible.netcommon.httpapi
ESTABLISH LOCAL CONNECTION FOR USER: root
EXEC /bin/sh -c 'PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand
It’s using ansible.netcommon.httpapi, (see reply from @flowerysong), and code is to be executed on control node (note the “sh” command).
But for some reason it’s wrapping the actual task code as PowerShell.
I think what we are looking for is to force it to generate the bash code not PowerShell one, that’s why OP tried to override it with forcing shell type and executable.
Any idea why this didn’t work?
Or maybe we just set it in wrong place/way? What is the proper way to force Ansible to generate sh code?
I’m not familiar with zabbix or ansible.netcommon.httpapi, but have you confirmed the content of “ansible_zabbix_url”
- debug:
var: ansible_zabbix_url
Your set_fact line is putting the contents of ansible_zabbix_url back in the same variable, unless that is an error made only in your post, and not in your actual playbook.
If this is a bug as described, You can try running another play at the same point instead of doing the delegate_to. You’d then iterate through the windows hosts, which I assume are in a group of their own and add them that way. You can register a var to ensure you only add hosts that have completed the play up to that point. You’d have to modify your role to expect that the play is being run with the zabbix host as the original target. Example play without using a role.
- name:
hosts: <windows hosts>
tasks:
...
- ansible.builtin.set_fact:
host_up: true
- name: Add windows hosts to zabbix
hosts: <zabbix_host>
vars:
ansible_network_os: community.zabbix.zabbix
ansible_connection: httpapi
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
ansible_zabbix_url_path: “”
tasks:
- name: Register Windows host in Zabbix
when: 'hostvars[win_hostname]["host_up"] is defined'
community.zabbix.zabbix_host:
host_name: “{{ win_hostname }}”
visible_name: “{{ win_hostname }}”
host_groups:
- “Windows servers”
link_templates:
- “Windows by Zabbix agent”
…
status: enabled
state: present
ignore_errors: yes
become: false
loop: '{{ groups[<name of windows host groups>] }}'
loop_control:
loop_var: 'win_hostname'
- name: Start other tasks of the original play here
hosts: <windows hosts>
...
For parallelism, you can do the above with the windows hosts as the original target still, but change the ansible_shell_type for the var at the play level, and try to do the delegate_to again.
Since you are iterating through the Windows hosts, some of the connection variables could be getting used fot the connection to localhost. Can you post some sanitized inventory? This should not normally be a problem, unless you have explicitly added localhost to your inventory.