1#!/usr/bin/env python 2 3# (c) 2013, Greg Buehler 4# (c) 2018, Filippo Ferrazini 5# 6# This file is part of Ansible, 7# 8# Ansible is free software: you can redistribute it and/or modify 9# it under the terms of the GNU General Public License as published by 10# the Free Software Foundation, either version 3 of the License, or 11# (at your option) any later version. 12# 13# Ansible is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU General Public License for more details. 17# 18# You should have received a copy of the GNU General Public License 19# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 20 21###################################################################### 22 23""" 24Zabbix Server external inventory script. 25======================================== 26 27Returns hosts and hostgroups from Zabbix Server. 28If you want to run with --limit against a host group with space in the 29name, use asterisk. For example --limit="Linux*servers". 30 31Configuration is read from `zabbix.ini`. 32 33Tested with Zabbix Server 2.0.6, 3.2.3 and 3.4. 34""" 35 36from __future__ import print_function 37 38import os 39import sys 40import argparse 41from ansible.module_utils.six.moves import configparser 42 43try: 44 from zabbix_api import ZabbixAPI 45except Exception: 46 print("Error: Zabbix API library must be installed: pip install zabbix-api.", 47 file=sys.stderr) 48 sys.exit(1) 49 50import json 51 52 53class ZabbixInventory(object): 54 55 def read_settings(self): 56 config = configparser.SafeConfigParser() 57 conf_path = './zabbix.ini' 58 if not os.path.exists(conf_path): 59 conf_path = os.path.dirname(os.path.realpath(__file__)) + '/zabbix.ini' 60 if os.path.exists(conf_path): 61 config.read(conf_path) 62 # server 63 if config.has_option('zabbix', 'server'): 64 self.zabbix_server = config.get('zabbix', 'server') 65 66 # login 67 if config.has_option('zabbix', 'username'): 68 self.zabbix_username = config.get('zabbix', 'username') 69 if config.has_option('zabbix', 'password'): 70 self.zabbix_password = config.get('zabbix', 'password') 71 # ssl certs 72 if config.has_option('zabbix', 'validate_certs'): 73 if config.get('zabbix', 'validate_certs') in ['false', 'False', False]: 74 self.validate_certs = False 75 # host inventory 76 if config.has_option('zabbix', 'read_host_inventory'): 77 if config.get('zabbix', 'read_host_inventory') in ['true', 'True', True]: 78 self.read_host_inventory = True 79 # host interface 80 if config.has_option('zabbix', 'use_host_interface'): 81 if config.get('zabbix', 'use_host_interface') in ['false', 'False', False]: 82 self.use_host_interface = False 83 84 def read_cli(self): 85 parser = argparse.ArgumentParser() 86 parser.add_argument('--host') 87 parser.add_argument('--list', action='store_true') 88 self.options = parser.parse_args() 89 90 def hoststub(self): 91 return { 92 'hosts': [] 93 } 94 95 def get_host(self, api, name): 96 api_query = {'output': 'extend', 'selectGroups': 'extend', "filter": {"host": [name]}} 97 if self.use_host_interface: 98 api_query['selectInterfaces'] = ['useip', 'ip', 'dns'] 99 if self.read_host_inventory: 100 api_query['selectInventory'] = "extend" 101 102 data = {'ansible_ssh_host': name} 103 if self.use_host_interface or self.read_host_inventory: 104 try: 105 hosts_data = api.host.get(api_query)[0] 106 if 'interfaces' in hosts_data: 107 # use first interface only 108 if hosts_data['interfaces'][0]['useip'] == 0: 109 data['ansible_ssh_host'] = hosts_data['interfaces'][0]['dns'] 110 else: 111 data['ansible_ssh_host'] = hosts_data['interfaces'][0]['ip'] 112 if ('inventory' in hosts_data) and (hosts_data['inventory']): 113 data.update(hosts_data['inventory']) 114 except IndexError: 115 # Host not found in zabbix 116 pass 117 return data 118 119 def get_list(self, api): 120 api_query = {'output': 'extend', 'selectGroups': 'extend'} 121 if self.use_host_interface: 122 api_query['selectInterfaces'] = ['useip', 'ip', 'dns'] 123 if self.read_host_inventory: 124 api_query['selectInventory'] = "extend" 125 126 hosts_data = api.host.get(api_query) 127 data = {'_meta': {'hostvars': {}}} 128 129 data[self.defaultgroup] = self.hoststub() 130 for host in hosts_data: 131 hostname = host['name'] 132 hostvars = dict() 133 data[self.defaultgroup]['hosts'].append(hostname) 134 135 for group in host['groups']: 136 groupname = group['name'] 137 138 if groupname not in data: 139 data[groupname] = self.hoststub() 140 141 data[groupname]['hosts'].append(hostname) 142 if 'interfaces' in host: 143 # use first interface only 144 if host['interfaces'][0]['useip'] == 0: 145 hostvars['ansible_ssh_host'] = host['interfaces'][0]['dns'] 146 else: 147 hostvars['ansible_ssh_host'] = host['interfaces'][0]['ip'] 148 if ('inventory' in host) and (host['inventory']): 149 hostvars.update(host['inventory']) 150 data['_meta']['hostvars'][hostname] = hostvars 151 152 return data 153 154 def __init__(self): 155 156 self.defaultgroup = 'group_all' 157 self.zabbix_server = None 158 self.zabbix_username = None 159 self.zabbix_password = None 160 self.validate_certs = True 161 self.read_host_inventory = False 162 self.use_host_interface = True 163 164 self.meta = {} 165 166 self.read_settings() 167 self.read_cli() 168 169 if self.zabbix_server and self.zabbix_username: 170 try: 171 api = ZabbixAPI(server=self.zabbix_server, validate_certs=self.validate_certs) 172 api.login(user=self.zabbix_username, password=self.zabbix_password) 173 # zabbix_api tries to exit if it cannot parse what the zabbix server returned 174 # so we have to use SystemExit here 175 except (Exception, SystemExit) as e: 176 print("Error: Could not login to Zabbix server. Check your zabbix.ini.", file=sys.stderr) 177 sys.exit(1) 178 179 if self.options.host: 180 data = self.get_host(api, self.options.host) 181 print(json.dumps(data, indent=2)) 182 183 elif self.options.list: 184 data = self.get_list(api) 185 print(json.dumps(data, indent=2)) 186 187 else: 188 print("usage: --list ..OR.. --host <hostname>", file=sys.stderr) 189 sys.exit(1) 190 191 else: 192 print("Error: Configuration of server and credentials are required. See zabbix.ini.", file=sys.stderr) 193 sys.exit(1) 194 195 196ZabbixInventory() 197