Basics of Zabbix API with Python and PyZabbix

Zabbix API is the way to go when you need to manage Zabbix configurations or get data from Zabbix programmatically. For Python applications one of the community-based libraries is PyZabbix.

Note: There is also a package called py-zabbix. That is a different one, not handled in this post.

In this post I’ll show:

  • How to authenticate to the Zabbix API
  • How to get host information using the API.

I’ll start with creating a Python virtual environment and installing PyZabbix there:

markku@devel:~$ mkdir -p temp/pyzabbix-blog
markku@devel:~$ cd temp/pyzabbix-blog
markku@devel:~/temp/pyzabbix-blog$ python3 -m venv venv
markku@devel:~/temp/pyzabbix-blog$ . venv/bin/activate
(venv) markku@devel:~/temp/pyzabbix-blog$ pip install -U pip wheel
...
Successfully installed pip-22.2.2 wheel-0.37.1
(venv) markku@devel:~/temp/pyzabbix-blog$ pip install pyzabbix
...
Successfully installed certifi-2022.9.24 charset-normalizer-2.1.1 idna-3.4 packaging-21.3 pyparsing-3.0.9 pyzabbix-1.2.1 requests-2.28.1 urllib3-1.26.12
(venv) markku@devel:~/temp/pyzabbix-blog$

At the time of writing this it installed PyZabbix 1.2.1.

I have a fresh Zabbix 6.0 LTS server installation at hand. Let’s start using PyZabbix:

(venv) markku@devel:~/temp/pyzabbix-blog$ python3
Python 3.7.3 (default, Jan 22 2021, 20:04:44)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyzabbix
>>> zapi = pyzabbix.ZabbixAPI("https://zabbixtest.lein.io/zabbix")
>>> zapi.auth
''
>>> zapi.api_version()
'6.0.9'
>>>

What I did there is I created an object (zapi) to interact with my Zabbix server at the given URL. In the zapi object the authentication data is still empty as we didn’t authenticate in any way, but the .api_version() method already works and returns the Zabbix API version (which is identical to the Zabbix server version).

Let’s authenticate with the default Zabbix administrator credentials, entering the password interactively:

>>> import getpass
>>> zapi.login(user="Admin", password=getpass.getpass())
Password:
>>> zapi.auth
'91d904875648c64068829f6efabd02eb'
>>>

There was no output from calling the .login() method and that’s good in this case, and the .auth attribute got populated with a value, so our authentication was successful.

Does it work? Let’s try getting all the hosts from the Zabbix server:

>>> from pprint import pprint
>>> hosts = zapi.host.get()
>>> for host in hosts:
...     pprint(host)
...
{'auto_compress': '1',
 'custom_interfaces': '0',
 'description': '',
 'flags': '0',
 'host': 'Zabbix server',
 'hostid': '10084',
 'inventory_mode': '-1',
 'ipmi_authtype': '-1',
 'ipmi_password': '',
 'ipmi_privilege': '2',
 'ipmi_username': '',
 'lastaccess': '0',
 'maintenance_from': '0',
 'maintenance_status': '0',
 'maintenance_type': '0',
 'maintenanceid': '0',
 'name': 'Zabbix server',
 'proxy_address': '',
 'proxy_hostid': '0',
 'status': '0',
 'templateid': '0',
 'tls_accept': '1',
 'tls_connect': '1',
 'tls_issuer': '',
 'tls_subject': '',
 'uuid': ''}
>>> type(hosts)
<class 'list'>
>>> type(host)
<class 'dict'>
>>> host["host"]
'Zabbix server'
>>>

I used the Host API to get all the configured hosts, and pretty-printed all the data. As mentioned, this is a new Zabbix server install, so there is only one host, “Zabbix server”. The API call resulted in a list of dictionaries (even though the list only contained one host in this case).

Note: Whenever Zabbix API documentation talks about object, it means dictionary in our Python code.

Let’s complete this simple case with logging out of the API:

>>> zapi.user.logout()
True
>>> zapi.user.logout()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/markku/temp/pyzabbix-blog/venv/lib/python3.7/site-packages/pyzabbix/api.py", line 265, in __call__
    return self._parent.do_request(self._method, args or kwargs)["result"]
  File "/home/markku/temp/pyzabbix-blog/venv/lib/python3.7/site-packages/pyzabbix/api.py", line 239, in do_request
    error=error,
pyzabbix.api.ZabbixAPIException: ('Error -32602: Invalid params., Session terminated, re-login, please.', -32602)
>>>

The User API contains the logout call. As you see, calling it after already logged out raises ZabbixAPIException.

Starting from Zabbix version 5.4 it is also possible to use API tokens to authenticate to the API. Let’s use a token for the rest of this post. First, let’s create an API token in the GUI by logging in as the Admin user and going to User settings and API tokens, and then clicking Create API token:

In this example I time-limited the token, obviously in actual use cases it depends on the security requirements and operational practices how it should be configured.

By clicking Add it creates the token, and shows the token value on the screen:

Now, you need to copy that token value somewhere safe because it is not shown later anymore. I’ll save it in a Python variable, and then try it right away:

>>> my_token = "1c8d93a48fe10bae5a45e848676818e6984e87545d38e17c97f6ed56325c6c71"
>>> zapi.login(api_token=my_token)
>>> for host in zapi.host.get():
...     print(host["host"])
...
Zabbix server
>>> zapi.user.logout()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/markku/temp/pyzabbix-blog/venv/lib/python3.7/site-packages/pyzabbix/api.py", line 265, in __call__
    return self._parent.do_request(self._method, args or kwargs)["result"]
  File "/home/markku/temp/pyzabbix-blog/venv/lib/python3.7/site-packages/pyzabbix/api.py", line 239, in do_request
    error=error,
pyzabbix.api.ZabbixAPIException: ('Error -32602: Invalid params., Cannot log out.', -32602)
>>>

What happened? The API login was clearly successful because it was possible to get the host list again, but logout raised an error. No worries, the error text “Cannot log out” indicates that when using API token it is not possible (or needed) to log out.

Ok, now we can log in the API and get the hosts. For this “basics” post let’s do a couple of more things.

Earlier I printed out all the hosts and there was only one. For the sake of getting sensible outputs let’s go in Zabbix GUI and add another host:

Host name is “Testhost” and the group is “Linux servers”:

After adding the second host let’s verify we see both hosts:

>>> for host in zapi.host.get():
...     print(host["host"])
...
Zabbix server
Testhost
>>>

As you saw in the full host output earlier, there was no IP address shown for the “Zabbix server” host. That’s because the address (IP or DNS) is in the interface of the host, just like they are configured in the Zabbix GUI. So let’s demonstrate getting the IP address(es) of the host. I’ll start by searching for the host first, and then build on that:

>>> hosts = zapi.host.get(filter={"host":"Zabbix server"})
>>> len(hosts)
1
>>> host = hosts[0]
>>> host["host"]
'Zabbix server'
>>> host["hostid"]
'10084'
>>>

Using the host.get API method I filtered the host list with the specific host name, and then got the first item of the results list (as mentioned earlier, the result of that call is a list).

Getting the interfaces of that host is done by using the hostid property of the host when calling the hostinterface.get API method:

>>> interfaces = zapi.hostinterface.get(hostids=[host["hostid"]])
>>> for intf in interfaces:
...     pprint(intf)
...
{'available': '1',
 'details': [],
 'disable_until': '0',
 'dns': '',
 'error': '',
 'errors_from': '0',
 'hostid': '10084',
 'interfaceid': '1',
 'ip': '127.0.0.1',
 'main': '1',
 'port': '10050',
 'type': '1',
 'useip': '1'}
>>>

Or, just to get the list of IPs:

>>> for intf in zapi.hostinterface.get(hostids=[host["hostid"]]):
...     print(intf["ip"])
...
127.0.0.1
>>>

Note the useip field in the interface data. In this case it is “1”, which means that in the host interface configuration the “Connect to: IP” option is selected:

If “DNS” is selected instead, useip will be “0” in the API data.

The type field value “1” tells it is a Zabbix agent interface, the other possible values are documented in the host interface object documentation.

Getting the host group information for a host is similar to getting the interfaces, using the host ID:

>>> for hostgroup in zapi.hostgroup.get(hostids=[host["hostid"]]):
...     pprint(hostgroup)
...
{'flags': '0',
 'groupid': '4',
 'internal': '0',
 'name': 'Zabbix servers',
 'uuid': '6f6799aa69e844b4b3918f779f2abf08'}
>>>

That’s all for this basics post. From Python standpoint the key takeaways are:

  • The Zabbix API object method calls in Python pretty much match the Zabbix API methods in the documentation (eg. to use API method hostinterface.get you call zapi.hostinterface.get())
  • The parameters mentioned in the API method documentation are passed as arguments in the Python calls
  • “Objects” in the documentation are dictionaries in Python, “arrays” are lists.

Leave a Reply