From 38b7c80217c4e72b1d8988eb1e60bb6e77334114 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 18 Apr 2024 07:52:22 +0200 Subject: Adding upstream version 9.4.0+dfsg. Signed-off-by: Daniel Baumann --- .../community/zabbix/scripts/inventory/zabbix.ini | 10 +- .../community/zabbix/scripts/inventory/zabbix.py | 215 ++++++++++++++------- 2 files changed, 153 insertions(+), 72 deletions(-) (limited to 'ansible_collections/community/zabbix/scripts') diff --git a/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini b/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini index ead19b62d..0d6bcab8d 100644 --- a/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini +++ b/ansible_collections/community/zabbix/scripts/inventory/zabbix.ini @@ -7,14 +7,20 @@ server = http://zabbix.example.com/zabbix # Login -username = admin +username = Admin password = zabbix +# Authentication token, if empty then username/password used to authenticate +auth_token = + # Verify the server's SSL certificate validate_certs = True +# Time to wait for API response +tiemout = 30 + # Read zabbix inventory per host read_host_inventory = True # Set ansible_ssh_host based on first interface settings -use_host_interface = True \ No newline at end of file +use_host_interface = True diff --git a/ansible_collections/community/zabbix/scripts/inventory/zabbix.py b/ansible_collections/community/zabbix/scripts/inventory/zabbix.py index 767012848..29ac11b93 100644 --- a/ansible_collections/community/zabbix/scripts/inventory/zabbix.py +++ b/ansible_collections/community/zabbix/scripts/inventory/zabbix.py @@ -38,134 +38,209 @@ from __future__ import print_function import os import sys import argparse -from ansible.module_utils.six.moves import configparser - -try: - from zabbix_api import ZabbixAPI -except Exception: - print("Error: Zabbix API library must be installed: pip install zabbix-api.", - file=sys.stderr) - sys.exit(1) - import json +import atexit +from ansible.module_utils.six.moves import configparser +from ansible.module_utils.compat.version import LooseVersion +from ansible.module_utils.urls import Request +from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError class ZabbixInventory(object): def read_settings(self): config = configparser.ConfigParser() - conf_path = './zabbix.ini' + conf_path = "./zabbix.ini" if not os.path.exists(conf_path): - conf_path = os.path.dirname(os.path.realpath(__file__)) + '/zabbix.ini' + conf_path = os.path.dirname(os.path.realpath(__file__)) + "/zabbix.ini" if os.path.exists(conf_path): config.read(conf_path) # server - if config.has_option('zabbix', 'server'): - self.zabbix_server = config.get('zabbix', 'server') + if config.has_option("zabbix", "server"): + self.zabbix_server = config.get("zabbix", "server") # login - if config.has_option('zabbix', 'username'): - self.zabbix_username = config.get('zabbix', 'username') - if config.has_option('zabbix', 'password'): - self.zabbix_password = config.get('zabbix', 'password') + if config.has_option("zabbix", "username"): + self.zabbix_username = config.get("zabbix", "username") + if config.has_option("zabbix", "password"): + self.zabbix_password = config.get("zabbix", "password") + if config.has_option("zabbix", "auth_token"): + self.auth_token = config.get("zabbix", "auth_token") # ssl certs - if config.has_option('zabbix', 'validate_certs'): - if config.get('zabbix', 'validate_certs') in ['false', 'False', False]: + if config.has_option("zabbix", "validate_certs"): + if config.get("zabbix", "validate_certs") in ["false", "False", False]: self.validate_certs = False + # timeout + if config.has_option("zabbix", "timeout"): + self.timeout = config.get("zabbix", "timeout") # host inventory - if config.has_option('zabbix', 'read_host_inventory'): - if config.get('zabbix', 'read_host_inventory') in ['true', 'True', True]: + if config.has_option("zabbix", "read_host_inventory"): + if config.get("zabbix", "read_host_inventory") in ["true", "True", True]: self.read_host_inventory = True # host interface - if config.has_option('zabbix', 'use_host_interface'): - if config.get('zabbix', 'use_host_interface') in ['false', 'False', False]: + if config.has_option("zabbix", "use_host_interface"): + if config.get("zabbix", "use_host_interface") in ["false", "False", False]: self.use_host_interface = False def read_cli(self): parser = argparse.ArgumentParser() - parser.add_argument('--host') - parser.add_argument('--list', action='store_true') + parser.add_argument("--host") + parser.add_argument("--list", action="store_true") self.options = parser.parse_args() def hoststub(self): return { - 'hosts': [] + "hosts": [] + } + + def api_request(self, method, params=None): + server_url = self.zabbix_server + validate_certs = self.validate_certs + timeout = self.timeout + + headers = {"Content-Type": "application/json-rpc"} + payload = { + "jsonrpc": "2.0", + "method": method, + "id": "1" } + if params is None: + payload["params"] = {} + else: + payload["params"] = params - def get_host(self, api, name): - api_query = {'output': 'extend', 'selectGroups': 'extend', "filter": {"host": [name]}} + if self.auth != "": + if (LooseVersion(self.zabbix_version) >= LooseVersion("6.4")): + headers["Authorization"] = "Bearer " + self.auth + else: + payload["auth"] = self.auth + + api_url = server_url + "/api_jsonrpc.php" + req = Request( + headers=headers, + timeout=timeout, + validate_certs=validate_certs + ) + try: + response = req.post(api_url, data=json.dumps(payload)) + except ValueError: + print("Error: Something went wrong with JSON loading.", file=sys.stderr) + sys.exit(1) + except (URLError, HTTPError) as error: + print(error, file=sys.stderr) + + return response + + def get_version(self): + response = self.api_request( + "apiinfo.version" + ) + res = json.load(response) + self.zabbix_version = res["result"] + + def login_zabbix(self): + auth_token = self.auth_token + if auth_token: + self.auth = auth_token + return + + atexit.register(self.logout_zabbix) + + login_user = self.zabbix_username + login_password = self.zabbix_password + response = self.api_request( + "user.login", + { + "username": login_user, + "password": login_password + } + ) + res = json.load(response) + self.auth = res["result"] + + def logout_zabbix(self): + self.api_request( + "user.logout", + [] + ) + + def get_host(self, name): + api_query = {"output": "extend", "selectGroups": "extend", "filter": {"host": [name]}} if self.use_host_interface: - api_query['selectInterfaces'] = ['useip', 'ip', 'dns'] + api_query["selectInterfaces"] = ["useip", "ip", "dns"] if self.read_host_inventory: - api_query['selectInventory'] = "extend" + api_query["selectInventory"] = "extend" - data = {'ansible_ssh_host': name} + data = {"ansible_ssh_host": name} if self.use_host_interface or self.read_host_inventory: - try: - hosts_data = api.host.get(api_query)[0] - # check if zabbix api returned a interfaces element - if 'interfaces' in hosts_data: + response = self.api_request("host.get", api_query) + response_obj = json.load(response) + if len(response_obj['result']) > 0: + host_data = response_obj['result'][0] + # check if zabbix api returned interfaces element + if "interfaces" in host_data: # check for a interfaces list that contains at least interface - if len(hosts_data['interfaces']) >= 1: + if len(host_data["interfaces"]) >= 1: # use first interface only - if hosts_data['interfaces'][0]['useip'] == 0: - data['ansible_ssh_host'] = hosts_data['interfaces'][0]['dns'] + if host_data["interfaces"][0]["useip"] == '0': + data["ansible_ssh_host"] = host_data["interfaces"][0]["dns"] else: - data['ansible_ssh_host'] = hosts_data['interfaces'][0]['ip'] - if ('inventory' in hosts_data) and (hosts_data['inventory']): - data.update(hosts_data['inventory']) - except IndexError: - # Host not found in zabbix - pass + data["ansible_ssh_host"] = host_data["interfaces"][0]["ip"] + if ("inventory" in host_data) and (host_data["inventory"]): + data.update(host_data["inventory"]) return data - def get_list(self, api): - api_query = {'output': 'extend', 'selectGroups': 'extend'} + def get_list(self): + api_query = {"output": "extend", "selectGroups": "extend"} if self.use_host_interface: - api_query['selectInterfaces'] = ['useip', 'ip', 'dns'] + api_query["selectInterfaces"] = ["useip", "ip", "dns"] if self.read_host_inventory: - api_query['selectInventory'] = "extend" - - hosts_data = api.host.get(api_query) - data = {'_meta': {'hostvars': {}}} + api_query["selectInventory"] = "extend" + response = self.api_request("host.get", api_query) + hosts_data = json.load(response)["result"] + data = {"_meta": {"hostvars": {}}} data[self.defaultgroup] = self.hoststub() for host in hosts_data: - hostname = host['name'] + hostname = host["name"] hostvars = dict() - data[self.defaultgroup]['hosts'].append(hostname) + data[self.defaultgroup]["hosts"].append(hostname) - for group in host['groups']: - groupname = group['name'] + for group in host["groups"]: + groupname = group["name"] if groupname not in data: data[groupname] = self.hoststub() - data[groupname]['hosts'].append(hostname) + data[groupname]["hosts"].append(hostname) # check if zabbix api returned a interfaces element - if 'interfaces' in host: + if "interfaces" in host: # check for a interfaces list that contains at least interface - if len(host['interfaces']) >= 1: + if len(host["interfaces"]) >= 1: # use first interface only - if host['interfaces'][0]['useip'] == 0: - hostvars['ansible_ssh_host'] = host['interfaces'][0]['dns'] + if host["interfaces"][0]["useip"] == 0: + hostvars["ansible_ssh_host"] = host["interfaces"][0]["dns"] else: - hostvars['ansible_ssh_host'] = host['interfaces'][0]['ip'] - if ('inventory' in host) and (host['inventory']): - hostvars.update(host['inventory']) - data['_meta']['hostvars'][hostname] = hostvars + hostvars["ansible_ssh_host"] = host["interfaces"][0]["ip"] + if ("inventory" in host) and (host["inventory"]): + hostvars.update(host["inventory"]) + data["_meta"]["hostvars"][hostname] = hostvars return data def __init__(self): - self.defaultgroup = 'group_all' + self.defaultgroup = "group_all" self.zabbix_server = None self.zabbix_username = None self.zabbix_password = None + self.auth_token = None + self.auth = "" self.validate_certs = True + self.timeout = 30 self.read_host_inventory = False self.use_host_interface = True + self.zabbix_version = "" self.meta = {} @@ -174,20 +249,20 @@ class ZabbixInventory(object): if self.zabbix_server and self.zabbix_username: try: - api = ZabbixAPI(server=self.zabbix_server, validate_certs=self.validate_certs) - api.login(user=self.zabbix_username, password=self.zabbix_password) + self.get_version() + self.login_zabbix() # zabbix_api tries to exit if it cannot parse what the zabbix server returned # so we have to use SystemExit here except (Exception, SystemExit) as e: - print("Error: Could not login to Zabbix server. Check your zabbix.ini.", file=sys.stderr) + print("Error: got the exception '%s'. Check your zabbix.ini." % e, file=sys.stderr) sys.exit(1) if self.options.host: - data = self.get_host(api, self.options.host) + data = self.get_host(self.options.host) print(json.dumps(data, indent=2)) elif self.options.list: - data = self.get_list(api) + data = self.get_list() print(json.dumps(data, indent=2)) else: -- cgit v1.2.3