ansible-collections / community.zabbix

Zabbix Ansible modules
http://galaxy.ansible.com/community/zabbix
Other
315 stars 268 forks source link

API Usage in module changed with 2.0, no valid documentation #1073

Open solick opened 11 months ago

solick commented 11 months ago

I used to set templates to specific hosts with the zabbix_host module until 1.9.3 with out problems like this:


- name: add template to host
  community.zabbix.zabbix_host:  
    host_name: "{{ inventory_hostname }}"
    link_templates: "{{ template_list }}"
    server_url: "{{ zabbix_api_server_url }}"
    login_user: "{{ zabbix_api_login_user }}"
    login_password: "{{ zabbix_api_login_pass }}". 
  become: true

With change to 2.0 and 2.1 this does not work anymore and I cannot find any valid documentation how to do it now.

Could anyone please help out?

Thanks!

awsmaythem commented 11 months ago

i have the same problem but on adding tag am trying the httpapi connection but not working and the server url is on delegate_to: zabbix.example.com or ansible_host: zabbix.example.com and hosts: zabbix.example.com all not working


- name: zabbix add tag
  hosts: localhost
  become: false
  vars:
    ansible_network_os: community.zabbix.zabbix
    ansible_connection: httpapi
    ansible_httpapi_port: 443
    ansible_httpapi_use_ssl: false
    ansible_httpapi_validate_certs: false
    ansible_zabbix_url_path: "" 
    ansible_user: "{{ zbx_user }}"
    ansible_httpapi_pass: "{{ zbx_pass }}"
  tasks:
    - name: Adding Tag to the host 
      community.zabbix.zabbix_host:
        http_login_user: "{{ zbx_user }}"
        http_login_password: "{{ zbx_pass }}"
        host_name: "{{ zabbix_host_name }}"
        tags:
          - tag: IPA
            value: Joined
          - tag: Owner
            value: IT
          - tag: OS
            value: Linux
          - tag: Type
            value: Server
          - tag: Service
            value: "{{ service_tag }}"
      delegate_to: zabbix.example.com
AlexSSP commented 11 months ago

It seems that the parameter "server_url" was forgotten in the version above 2. Or it is supposed that on the Zabbix server it is necessary to install ansible with community.zabbix collection?

solick commented 10 months ago

does no one uses the collection like this? Ist surprising that the collection is at version 2.1 and we are the first to encounter the problem

BGmot commented 10 months ago

See EXAMPLES section here for zabbix_host (and for all other modules in respective files) https://github.com/ansible-collections/community.zabbix/blob/main/plugins/modules/zabbix_host.py#L337

solick commented 10 months ago

ok i understand I have to set those variables for the task to connect to the REST API now (which looks much more complicated than before. It would be helpful to understand the reason for this.

I know want to access th API with Token but get the error password is empty. From the error it looks like it tries to authenticate with ansible user and a not set password to the API. From the example it looks like not setting ansible user and password instead setting only the ansible_zabbix_auth_key as fact before the task would be enough. Anything else I need to do to force API Token Auth instead of user/password?

Here is my current task setting:

- name: Set API token
  set_fact:
    ansible_zabbix_auth_key: "{{ zabbix_api_token }}"

- name: add template to host
  vars:
    ansible_network_os: community.zabbix.zabbix
    ansible_connection: httpapi
    ansible_httpapi_port: 443
    ansible_httpapi_use_ssl: true  # Set to true for HTTPS
    ansible_httpapi_validate_certs: true  # For HTTPS et to true to validate server's certificate
    ansible_host: "{{ zabbix_api_server_host }}"
  community.zabbix.zabbix_host:
    host_name: "{{ inventory_hostname }}"
    link_templates: "{{ template_list }}"
  become: false  

And the error:

The error was: ansible.module_utils.connection.ConnectionError: REST API returned {'code': -32602, 'message': 'Invalid params.', 'data': 'Invalid parameter "/password": a character string is expected.'} when sending {"jsonrpc": "2.0", "method": "user.login", "id": "670aea31-6b3a-4325-8b3d-be03c4217636", "params": {"username": "XXX", "password": null}}
BGmot commented 10 months ago

try

- name: Set API token
  set_fact:
    ansible_zabbix_auth_key: "{{ zabbix_api_token }}"

- name: add template to host
  vars:
    gather_facts: false
    ansible_network_os: community.zabbix.zabbix
    ansible_connection: httpapi
    ansible_httpapi_port: 443
    ansible_httpapi_use_ssl: true
    ansible_httpapi_validate_certs: true
  community.zabbix.zabbix_host:
    host_name: "{{ inventory_hostname }}"
    link_templates: "{{ template_list }}"
  become: false
  delegate_to: "{{ zabbix_api_server_host }}"

When you set ansible_zabbix_auth_key then username and password are ignored. See real world example on how to invoke modules in general https://github.com/ansible-collections/community.zabbix/blob/main/roles/zabbix_agent/tasks/main.yml#L74

solick commented 10 months ago

@BGmot as you can see in my post before I exactly did set the auth key and still get the error.

BGmot commented 10 months ago

Are you sure you are on 2.1 version? Did you try my code? You missed crucial delegate_to and for some reason re-defined ansible_host. This functionality has been tested a lot and works as expected.

solick commented 10 months ago

@BGmot yes I checked that community.zabbix collection 2.1.0 is installed and copy pasted your code and tested. Same result: The task tries to authenticate with username and password where username is my current ansible user and password is empty.

I also tested with username / password like this:

- name: Set credentials to access Zabbix Server API
  set_fact:
    ansible_user: "{{ zabbix_api_login_user }}"
    ansible_httpapi_pass: "{{ zabbix_api_login_pass }}"

but still my standard ansible user and empty password is used with same error.

BGmot commented 10 months ago

Looks like I reproduced the issue, for some reason set_fact for ansible_zabbix_auth_key is not working. Following ways to define the key work.

  1. I'd recommend to put all Zabbix API related variables into group_vars, there are multiple ways of doing that, if you have one flat inventory file then it should be something like this:
    ---
    all:
    vars:
    ansible_network_os: community.zabbix.zabbix
    ansible_connection: httpapi
    ansible_httpapi_port: 8080
    ansible_httpapi_use_ssl: false
    ansible_httpapi_validate_certs: false
    ansible_zabbix_auth_key: "9c05f86dd0c17a83a827c0654df4381862588d9cf5c4e027acf6e07c8f00c544"
    ansible_zabbix_url_path: ""
    hosts:
    zabbix-server:
      ansible_host: 2.2.2.2
    some-host:
      ansible_host: 3.3.3.3
  2. You can define Zabbix API variables only for Zabbix host, there are multiple ways of doing that, if you have one flat inventory file then it should be something like this:
---
all:
  hosts:
    zabbix-server:
      ansible_host: 2.2.2.2
      ansible_network_os: community.zabbix.zabbix
      ansible_connection: httpapi
      ansible_httpapi_port: 8080
      ansible_httpapi_use_ssl: false
      ansible_httpapi_validate_certs: false
      ansible_zabbix_auth_key: "9c05f86dd0c17a83a827c0654df4381862588d9cf5c4e027acf6e07c8f00c544"
      ansible_zabbix_url_path: ""
    some-host:
      ansible_host: 3.3.3.3
  1. Define all the variables when you execute zabbix_host module:
    - hosts: all
    gather_facts: false
    tasks:
    - name: Create host in Zabbix
    vars:
      ansible_zabbix_auth_key: "9c05f86dd0c17a83a827c0654df4381862588d9cf5c4e027acf6e07c8f00c544"
      ansible_network_os: community.zabbix.zabbix
      ansible_connection: httpapi
      ansible_httpapi_port: 8080
      ansible_httpapi_use_ssl: false
      ansible_httpapi_validate_certs: false
      ansible_zabbix_url_path: ""
    community.zabbix.zabbix_host:
      host_name: "{{ ansible_host }}"
      link_templates: Linux by Zabbix agent
      host_groups: Linux servers
      interfaces:
        - type: 1
          main: 1
          useip: 1
          ip: "{{ ansible_host }}"
    become: false
    delegate_to: zabbix-server
solick commented 10 months ago

@BGmot I can confirm that setting the ansible_zabbix_auth_key as var directly in the task has worked for me. But really strange that the set_fact is not working.

BGmot commented 10 months ago

It is really strange, I'll dig further. Probably need to refresh my Ansible knowledge -(

BGmot commented 8 months ago

@solick I decided to come back and investigate further but can't reproduce any longer. set_fact: works as well as defining variables in vars:. Are you still having this problem? If yes then pleas share your full code.

evilhamsterman commented 8 months ago

ok i understand I have to set those variables for the task to connect to the REST API now (which looks much more complicated than before. It would be helpful to understand the reason for this.

I know want to access th API with Token but get the error password is empty. From the error it looks like it tries to authenticate with ansible user and a not set password to the API. From the example it looks like not setting ansible user and password instead setting only the ansible_zabbix_auth_key as fact before the task would be enough. Anything else I need to do to force API Token Auth instead of user/password?

Here is my current task setting:

- name: Set API token
  set_fact:
    ansible_zabbix_auth_key: "{{ zabbix_api_token }}"

- name: add template to host
  vars:
    ansible_network_os: community.zabbix.zabbix
    ansible_connection: httpapi
    ansible_httpapi_port: 443
    ansible_httpapi_use_ssl: true  # Set to true for HTTPS
    ansible_httpapi_validate_certs: true  # For HTTPS et to true to validate server's certificate
    ansible_host: "{{ zabbix_api_server_host }}"
  community.zabbix.zabbix_host:
    host_name: "{{ inventory_hostname }}"
    link_templates: "{{ template_list }}"
  become: false  

And the error:

The error was: ansible.module_utils.connection.ConnectionError: REST API returned {'code': -32602, 'message': 'Invalid params.', 'data': 'Invalid parameter "/password": a character string is expected.'} when sending {"jsonrpc": "2.0", "method": "user.login", "id": "670aea31-6b3a-4325-8b3d-be03c4217636", "params": {"username": "XXX", "password": null}}

It was because they wanted to drop the requirement on pyzabbix. I think that was the right move because pyzabbix had to be installed on the systems that you were managing rather than talking to the zabbix server. But they have fallen down on documenting the new way to do things

evilhamsterman commented 8 months ago

I think the big miss is that the writers of the docs and the roles misunderstand how the httpapi interface in Ansible is supposed to work. The httpapi interface is for defining a way of communicating with a system other than using SSH. For example you can manage an Arista switch using httpapi. But that isn't clearly documented here and many of the roles treat the calls to the zabbix server as if they are regular ansible calls and try to help you setup the httpapi connection by providing other variables that they assign to the various ansible_ variables internally, but that obscures flexibility for different connection options used with the httpapi plugin.

BGmot commented 8 months ago

First of all feel free to contribute to improve the docs. Some people complain about documentation but documentation for every module says exactly what variables you need to set to successfully execute the module. As of how you define these variables it is up to you - Ansible provides variety of ways to define them. Yes major difference from previous way is instead of delegating to localhost (Ansible controller) and providing Zabbix URL now you treat Zabbix server as a "host" from your inventory but instead of SSH use HTTP(S). That is it. And yes we did it to go away from depending on external dependency and align more with how things should be done in Ansible (lots of very respectable collections use httpapi).

evilhamsterman commented 8 months ago

@BGmot I agree completely with the switch to httpapi, that is much better than having to install python libraries on every device, I believe I actually did have some PRs around that change. But looking at the history of issues, many of them do come down to it not being very clear that the connection method changed significantly in 2.x, it's buried in the CHANGELOG. Yes people should review stuff like that on major updates, but it would also be helpful to make it obvious.

The porting guide is just a list of variables that were replaced with new variables in the changelog, and while variables are pretty well documented in modules and roles they are not for the collection as a whole. The various ansible_... variables are simply listed in examples in the README. There are a lot of ways to do things but general guidance on best practices is always helpful. I also think the set_fact example like in the README is just wrong and an odd way of doing it, and may be leading to some of the confusion. Why do you set_fact for one variable but just directly provide the others, plus it is associating the variable with the host you are running the task against not on the zabbix server host connection.

As to my statement about roles, I'm mostly referring to the zabbix_agent and zabbix_proxy roles which makes calls to the zabbix-server to register. This is good but they also try to deal with handling setting the connection variables on your behalf which confuses and complicates things, and for instance in my case took me a few hours to figure out how to use the ansible_zabbix_auth_key with them because they don't directly support the API token. Don't worry I'm working on a PR for that.

evilhamsterman commented 8 months ago

A good example of a collection that uses httpapi is the arista.eos collection https://ansible-arista-howto.readthedocs.io/en/latest/

BGmot commented 8 months ago

I also think the set_fact example like in the README is just wrong and an odd way of doing it

I did most of the coding to switch to httpapi and my Ansible knowledge is limited, so let's do it right, please propose new/right way of doing things.

took me a few hours to figure out how to use the ansible_zabbix_auth_key with them because they don't directly support the API token.

Not sure what you mean by then but will gladly take a look at your PR.

A good example of a collection that uses httpapi is the arista.eos collection https://ansible-arista-howto.readthedocs.io/en/latest/

We could probably do the docs on readthedocs.io but I aimed to provide all the documentation at docs.ansible.com and it is somewhat limited due to the fact that these docs generated from modules' code.