Created
October 11, 2019 14:26
-
-
Save q1x/d81641c82c791f75e6dbffeb85d35a8b to your computer and use it in GitHub Desktop.
Zabbix Item Cleanup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
# import needed modules. | |
# pyzabbix is needed, see https://github.com/lukecyca/pyzabbix | |
# | |
import argparse | |
import ConfigParser | |
import os | |
import os.path | |
import time | |
import sys | |
import logging | |
import distutils.util | |
from pprint import pprint | |
from pyzabbix import ZabbixAPI | |
logger = logging.getLogger(__name__) | |
logger.addHandler(logging.StreamHandler()) | |
logger.setLevel(logging.WARNING) | |
# define config helper function | |
def ConfigSectionMap(section): | |
dict1 = {} | |
options = Config.options(section) | |
for option in options: | |
try: | |
dict1[option] = Config.get(section, option) | |
if dict1[option] == -1: | |
DebugPrint("skip: %s" % option) | |
except: | |
print("exception on %s!" % option) | |
dict1[option] = None | |
return dict1 | |
# set default vars | |
defconf = os.getenv("HOME") + "/.zbx.conf" | |
username = "" | |
password = "" | |
api = "" | |
noverify = "" | |
# Define commandline arguments | |
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description='Disables polling items on hosts not responding to ping and re-enables polling items when they return.', epilog=""" | |
This program can use .ini style configuration files to retrieve the needed API connection information. | |
To use this type of storage, create a conf file (the default is $HOME/.zbx.conf) that contains at least the [Zabbix API] section and any of the other parameters: | |
[Zabbix API] | |
username=johndoe | |
password=verysecretpassword | |
api=https://zabbix.mycompany.com/path/to/zabbix/frontend/ | |
no_verify=true | |
""") | |
parser.add_argument('-u', '--username', help='User for the Zabbix api') | |
parser.add_argument('-p', '--password', help='Password for the Zabbix api user') | |
parser.add_argument('-a', '--api', help='Zabbix API URL') | |
parser.add_argument('--no-verify', help='Disables certificate validation when using a secure connection',action='store_true') | |
parser.add_argument('-c','--config', help='Config file location (defaults to $HOME/.zbx.conf)') | |
parser.add_argument('-v', '--verbose', help='Enables verbose output.',action='store_true') | |
parser.add_argument('-d', '--debug', help='Enables debug output.',action='store_true') | |
parser.add_argument('-n', '--noop', help='Verbose output will show what would be done, but no changes will be made.',action='store_true') | |
parser.add_argument('-t', '--trigger', help='Description of the trigger used to identify host online status, defaults to "Ping: {HOST.NAME} is not responding to requests"',default='Ping: {HOST.NAME} is not responding to requests',metavar='DESCRIPTION') | |
parser.add_argument('-A', '--alive', help='Alive period (in minutes) before a hosts polling items are enabled, defaults to 30.',metavar='[1-1440]', choices=range(1,1441),default=30, type=int) | |
parser.add_argument('-g', '--grace', help='Grace period (in minutes) before an offline hosts polling items are disabled, defaults to 60.',metavar='[1-1440]', choices=range(1,1441),default=60, type=int) | |
parser.add_argument('groups', help='List of groups to scan for hosts.', nargs='+') | |
args = parser.parse_args() | |
# load config module | |
Config = ConfigParser.ConfigParser() | |
Config | |
# if configuration argument is set, test the config file | |
if args.config: | |
if os.path.isfile(args.config) and os.access(args.config, os.R_OK): | |
Config.read(args.config) | |
# if not set, try default config file | |
else: | |
if os.path.isfile(defconf) and os.access(defconf, os.R_OK): | |
Config.read(defconf) | |
# try to load available settings from config file | |
try: | |
username=ConfigSectionMap("Zabbix API")['username'] | |
password=ConfigSectionMap("Zabbix API")['password'] | |
api=ConfigSectionMap("Zabbix API")['api'] | |
noverify=bool(distutils.util.strtobool(ConfigSectionMap("Zabbix API")["no_verify"])) | |
except: | |
pass | |
# override settings if they are provided as arguments | |
if args.username: | |
username = args.username | |
if args.password: | |
password = args.password | |
if args.api: | |
api = args.api | |
if args.no_verify: | |
noverify = args.no_verify | |
# test for needed params | |
if not username: | |
sys.exit("Error: API User not set") | |
if not password: | |
sys.exit("Error: API Password not set") | |
if not api: | |
sys.exit("Error: API URL is not set") | |
if args.verbose: | |
logger.setLevel(logging.INFO) | |
if args.debug: | |
logger.setLevel(logging.DEBUG) | |
if args.noop: | |
logger.info(" *** Running in NOOP mode, no changes will be made *** ") | |
# Setup Zabbix API connection | |
zapi = ZabbixAPI(api) | |
if noverify is True: | |
zapi.session.verify = False | |
# Login to the Zabbix API | |
zapi.login(username, password) | |
zapi.timeout=900 | |
################################## | |
# Start actual API logic | |
################################## | |
# Zabbix version | |
zversion=zapi.apiinfo.version() | |
logger.info("Zabbix API version: %s", str(zversion)) | |
timestamp = time.time() | |
gracestamp = timestamp-(args.grace*60) | |
alivestamp = timestamp-(args.alive*60) | |
disable = [] | |
enable = [] | |
item_types= [0,1,4,6,9,10,11,13,14,16] | |
# Find hostgroups to inspect | |
groups = zapi.hostgroup.get(**{"output": ["groupid","name"],"filter": {"name": args.groups }}) | |
if groups: | |
logger.debug("Found the following hostgroups: %s", groups) | |
groupids = [group['groupid'] for group in groups if 'groupid' in group] # we need a list of groupids | |
# Fetch matching hosts | |
hosts = zapi.host.get(**{"output" : "extend", | |
"groupids": groupids, | |
"selectGroups": "extend", | |
"selectTriggers": ['description','lastchange','state','status','value'], | |
"monitored_hosts": True, | |
"with_monitored_triggers": True | |
}) | |
if hosts: | |
logger.info("Inspecting %s host(s)...", len(hosts)) | |
for host in hosts: | |
trigger = [t for t in host['triggers'] if t['description'] == args.trigger] # Find trigger properties for the host status trigger | |
if trigger: | |
# If host has been down longer than the grace period, add it to the disable list. | |
if ( int(trigger[0]['status']) == 0 and | |
int(trigger[0]['state']) == 0 and | |
int(trigger[0]['value']) == 1 and | |
float(trigger[0]['lastchange']) < gracestamp): | |
logger.debug('%s (%s): Has been offline more than %s minute(s), disabling polling items.', host['host'], host['name'], args.grace) | |
disable.append(host['hostid']) | |
# If the host has been active for more than the alive threshold, add it to the enable list. | |
elif ( int(trigger[0]['status']) == 0 and | |
int(trigger[0]['state']) == 0 and | |
int(trigger[0]['value']) == 0 and | |
float(trigger[0]['lastchange']) < alivestamp): | |
logger.debug('%s (%s): Has been online more than %s minute(s), enabling polling items.', host['host'], host['name'], args.alive) | |
enable.append(host['hostid']) | |
else: | |
logger.info('%s (%s): Could not find trigger "%s" on this host!!!', host['host'], host['name'], args.trigger) | |
if len(disable) > 0: | |
# Disable items on offline hosts | |
items = [] | |
items = zapi.item.get(**{'hostids': disable, 'monitored': True, 'output': ['itemid','type'],'filter': {'status': u'0'}}) | |
disable_itemids = [item['itemid'] for item in items if int(item['type']) in item_types] | |
logger.info('Disabling %s item(s) on %s host(s).', len(disable_itemids), len(disable)) | |
if not args.noop: | |
for itemid in disable_itemids: | |
try: | |
response = zapi.item.update(**{'itemid': itemid, 'status': 1}) | |
except: | |
logger.error('Something went wrong trying to disable itemid %s".', itemid) | |
if len(enable) > 0: | |
# Enable items on online hosts | |
items = [] | |
items = zapi.item.get(**{'hostids': enable, 'output': ['itemid','type'],'filter': {'status': u'1'}}) | |
enable_itemids = [item['itemid'] for item in items if int(item['type']) in item_types] | |
logger.info('Enabling %s item(s) on %s host(s).', len(enable_itemids), len(enable)) | |
if not args.noop: | |
for itemid in enable_itemids: | |
try: | |
response = zapi.item.update(**{'itemid': itemid, 'status': 0}) | |
except: | |
logger.error('Something went wrong trying to enable itemid %s".', itemid) | |
if len(enable) == 0 and len(disable) == 0: | |
logger.info("No hosts found that need to be updated.") | |
else: | |
logger.info("No hosts found.") | |
else: | |
logger.error("Could not find any matching hostgroups.") | |
sys.exit(2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment