summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
Diffstat (limited to 'roles')
-rw-r--r--roles/ansible_tower/tasks/main.yaml3
-rw-r--r--roles/lib_zabbix/library/zbx_action.py538
-rw-r--r--roles/lib_zabbix/library/zbx_discoveryrule.py36
-rw-r--r--roles/lib_zabbix/library/zbx_itemprototype.py61
-rw-r--r--roles/lib_zabbix/library/zbx_trigger.py18
-rw-r--r--roles/lib_zabbix/library/zbx_triggerprototype.py177
-rw-r--r--roles/lib_zabbix/library/zbx_user_media.py53
-rw-r--r--roles/lib_zabbix/tasks/create_template.yml41
-rwxr-xr-xroles/openshift_facts/library/openshift_facts.py2
-rw-r--r--roles/os_zabbix/vars/template_os_linux.yml29
10 files changed, 929 insertions, 29 deletions
diff --git a/roles/ansible_tower/tasks/main.yaml b/roles/ansible_tower/tasks/main.yaml
index c110a3b70..b7757214d 100644
--- a/roles/ansible_tower/tasks/main.yaml
+++ b/roles/ansible_tower/tasks/main.yaml
@@ -9,6 +9,7 @@
- ansible
- telnet
- ack
+ - pylint
- name: download Tower setup
get_url: url=http://releases.ansible.com/ansible-tower/setup/ansible-tower-setup-2.1.1.tar.gz dest=/opt/ force=no
@@ -38,5 +39,3 @@
regexp: "^({{ item.option }})( *)="
line: '\1\2= {{ item.value }}'
with_items: config_changes | default([], true)
-
-
diff --git a/roles/lib_zabbix/library/zbx_action.py b/roles/lib_zabbix/library/zbx_action.py
new file mode 100644
index 000000000..d64cebae1
--- /dev/null
+++ b/roles/lib_zabbix/library/zbx_action.py
@@ -0,0 +1,538 @@
+#!/usr/bin/env python
+'''
+ Ansible module for zabbix actions
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+# Zabbix action ansible module
+#
+#
+# Copyright 2015 Red Hat Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is in place because each module looks similar to each other.
+# These need duplicate code as their behavior is very similar
+# but different for each zabbix class.
+# pylint: disable=duplicate-code
+
+# pylint: disable=import-error
+from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection, ZabbixAPIError
+
+def exists(content, key='result'):
+ ''' Check if key exists in content or the size of content[key] > 0
+ '''
+ if not content.has_key(key):
+ return False
+
+ if not content[key]:
+ return False
+
+ return True
+
+def conditions_equal(zab_conditions, user_conditions):
+ '''Compare two lists of conditions'''
+ c_type = 'conditiontype'
+ _op = 'operator'
+ val = 'value'
+ if len(user_conditions) != len(zab_conditions):
+ return False
+
+ for zab_cond, user_cond in zip(zab_conditions, user_conditions):
+ if zab_cond[c_type] != str(user_cond[c_type]) or zab_cond[_op] != str(user_cond[_op]) or \
+ zab_cond[val] != str(user_cond[val]):
+ return False
+
+ return True
+
+def filter_differences(zabbix_filters, user_filters):
+ '''Determine the differences from user and zabbix for operations'''
+ rval = {}
+ for key, val in user_filters.items():
+
+ if key == 'conditions':
+ if not conditions_equal(zabbix_filters[key], val):
+ rval[key] = val
+
+ elif zabbix_filters[key] != str(val):
+ rval[key] = val
+
+ return rval
+
+# This logic is quite complex. We are comparing two lists of dictionaries.
+# The outer for-loops allow us to descend down into both lists at the same time
+# and then walk over the key,val pairs of the incoming user dict's changes
+# or updates. The if-statements are looking at different sub-object types and
+# comparing them. The other suggestion on how to write this is to write a recursive
+# compare function but for the time constraints and for complexity I decided to go
+# this route.
+# pylint: disable=too-many-branches
+def operation_differences(zabbix_ops, user_ops):
+ '''Determine the differences from user and zabbix for operations'''
+
+ # if they don't match, take the user options
+ if len(zabbix_ops) != len(user_ops):
+ return user_ops
+
+ rval = {}
+ for zab, user in zip(zabbix_ops, user_ops):
+ for key, val in user.items():
+ if key == 'opconditions':
+ for z_cond, u_cond in zip(zab[key], user[key]):
+ if not all([str(u_cond[op_key]) == z_cond[op_key] for op_key in \
+ ['conditiontype', 'operator', 'value']]):
+ rval[key] = val
+ break
+ elif key == 'opmessage':
+ # Verify each passed param matches
+ for op_msg_key, op_msg_val in val.items():
+ if zab[key][op_msg_key] != str(op_msg_val):
+ rval[key] = val
+ break
+
+ elif key == 'opmessage_grp':
+ zab_grp_ids = set([ugrp['usrgrpid'] for ugrp in zab[key]])
+ usr_grp_ids = set([ugrp['usrgrpid'] for ugrp in val])
+ if usr_grp_ids != zab_grp_ids:
+ rval[key] = val
+
+ elif key == 'opmessage_usr':
+ zab_usr_ids = set([usr['userid'] for usr in zab[key]])
+ usr_ids = set([usr['userid'] for usr in val])
+ if usr_ids != zab_usr_ids:
+ rval[key] = val
+
+ elif zab[key] != str(val):
+ rval[key] = val
+ return rval
+
+def get_users(zapi, users):
+ '''get the mediatype id from the mediatype name'''
+ rval_users = []
+
+ for user in users:
+ content = zapi.get_content('user',
+ 'get',
+ {'filter': {'alias': user}})
+ rval_users.append({'userid': content['result'][0]['userid']})
+
+ return rval_users
+
+def get_user_groups(zapi, groups):
+ '''get the mediatype id from the mediatype name'''
+ user_groups = []
+
+ content = zapi.get_content('usergroup',
+ 'get',
+ {'search': {'name': groups}})
+
+ for usr_grp in content['result']:
+ user_groups.append({'usrgrpid': usr_grp['usrgrpid']})
+
+ return user_groups
+
+def get_mediatype_id_by_name(zapi, m_name):
+ '''get the mediatype id from the mediatype name'''
+ content = zapi.get_content('mediatype',
+ 'get',
+ {'filter': {'description': m_name}})
+
+ return content['result'][0]['mediatypeid']
+
+def get_priority(priority):
+ ''' determine priority
+ '''
+ prior = 0
+ if 'info' in priority:
+ prior = 1
+ elif 'warn' in priority:
+ prior = 2
+ elif 'avg' == priority or 'ave' in priority:
+ prior = 3
+ elif 'high' in priority:
+ prior = 4
+ elif 'dis' in priority:
+ prior = 5
+
+ return prior
+
+def get_event_source(from_src):
+ '''Translate even str into value'''
+ choices = ['trigger', 'discovery', 'auto', 'internal']
+ rval = 0
+ try:
+ rval = choices.index(from_src)
+ except ValueError as _:
+ ZabbixAPIError('Value not found for event source [%s]' % from_src)
+
+ return rval
+
+def get_status(inc_status):
+ '''determine status for action'''
+ rval = 1
+ if inc_status == 'enabled':
+ rval = 0
+
+ return rval
+
+def get_condition_operator(inc_operator):
+ ''' determine the condition operator'''
+ vals = {'=': 0,
+ '<>': 1,
+ 'like': 2,
+ 'not like': 3,
+ 'in': 4,
+ '>=': 5,
+ '<=': 6,
+ 'not in': 7,
+ }
+
+ return vals[inc_operator]
+
+def get_host_id_by_name(zapi, host_name):
+ '''Get host id by name'''
+ content = zapi.get_content('host',
+ 'get',
+ {'filter': {'name': host_name}})
+
+ return content['result'][0]['hostid']
+
+def get_trigger_value(inc_trigger):
+ '''determine the proper trigger value'''
+ rval = 1
+ if inc_trigger == 'PROBLEM':
+ rval = 1
+ else:
+ rval = 0
+
+ return rval
+
+def get_template_id_by_name(zapi, t_name):
+ '''get the template id by name'''
+ content = zapi.get_content('template',
+ 'get',
+ {'filter': {'host': t_name}})
+
+ return content['result'][0]['templateid']
+
+
+def get_host_group_id_by_name(zapi, hg_name):
+ '''Get hostgroup id by name'''
+ content = zapi.get_content('hostgroup',
+ 'get',
+ {'filter': {'name': hg_name}})
+
+ return content['result'][0]['groupid']
+
+def get_condition_type(event_source, inc_condition):
+ '''determine the condition type'''
+ c_types = {}
+ if event_source == 'trigger':
+ c_types = {'host group': 0,
+ 'host': 1,
+ 'trigger': 2,
+ 'trigger name': 3,
+ 'trigger severity': 4,
+ 'trigger value': 5,
+ 'time period': 6,
+ 'host template': 13,
+ 'application': 15,
+ 'maintenance status': 16,
+ }
+
+ elif event_source == 'discovery':
+ c_types = {'host IP': 7,
+ 'discovered service type': 8,
+ 'discovered service port': 9,
+ 'discovery status': 10,
+ 'uptime or downtime duration': 11,
+ 'received value': 12,
+ 'discovery rule': 18,
+ 'discovery check': 19,
+ 'proxy': 20,
+ 'discovery object': 21,
+ }
+
+ elif event_source == 'auto':
+ c_types = {'proxy': 20,
+ 'host name': 22,
+ 'host metadata': 24,
+ }
+
+ elif event_source == 'internal':
+ c_types = {'host group': 0,
+ 'host': 1,
+ 'host template': 13,
+ 'application': 15,
+ 'event type': 23,
+ }
+ else:
+ raise ZabbixAPIError('Unkown event source %s' % event_source)
+
+ return c_types[inc_condition]
+
+def get_operation_type(inc_operation):
+ ''' determine the correct operation type'''
+ o_types = {'send message': 0,
+ 'remote command': 1,
+ 'add host': 2,
+ 'remove host': 3,
+ 'add to host group': 4,
+ 'remove from host group': 5,
+ 'link to template': 6,
+ 'unlink from template': 7,
+ 'enable host': 8,
+ 'disable host': 9,
+ }
+
+ return o_types[inc_operation]
+
+def get_action_operations(zapi, inc_operations):
+ '''Convert the operations into syntax for api'''
+ for operation in inc_operations:
+ operation['operationtype'] = get_operation_type(operation['operationtype'])
+ if operation['operationtype'] == 0: # send message. Need to fix the
+ operation['opmessage']['mediatypeid'] = \
+ get_mediatype_id_by_name(zapi, operation['opmessage']['mediatypeid'])
+ operation['opmessage_grp'] = get_user_groups(zapi, operation.get('opmessage_grp', []))
+ operation['opmessage_usr'] = get_users(zapi, operation.get('opmessage_usr', []))
+ if operation['opmessage']['default_msg']:
+ operation['opmessage']['default_msg'] = 1
+ else:
+ operation['opmessage']['default_msg'] = 0
+
+ # NOT supported for remote commands
+ elif operation['operationtype'] == 1:
+ continue
+
+ # Handle Operation conditions:
+ # Currently there is only 1 available which
+ # is 'event acknowledged'. In the future
+ # if there are any added we will need to pass this
+ # option to a function and return the correct conditiontype
+ if operation.has_key('opconditions'):
+ for condition in operation['opconditions']:
+ if condition['conditiontype'] == 'event acknowledged':
+ condition['conditiontype'] = 14
+
+ if condition['operator'] == '=':
+ condition['operator'] = 0
+
+ if condition['value'] == 'acknowledged':
+ condition['operator'] = 1
+ else:
+ condition['operator'] = 0
+
+
+ return inc_operations
+
+def get_operation_evaltype(inc_type):
+ '''get the operation evaltype'''
+ rval = 0
+ if inc_type == 'and/or':
+ rval = 0
+ elif inc_type == 'and':
+ rval = 1
+ elif inc_type == 'or':
+ rval = 2
+ elif inc_type == 'custom':
+ rval = 3
+
+ return rval
+
+def get_action_conditions(zapi, event_source, inc_conditions):
+ '''Convert the conditions into syntax for api'''
+
+ calc_type = inc_conditions.pop('calculation_type')
+ inc_conditions['evaltype'] = get_operation_evaltype(calc_type)
+ for cond in inc_conditions['conditions']:
+
+ cond['operator'] = get_condition_operator(cond['operator'])
+ # Based on conditiontype we need to set the proper value
+ # e.g. conditiontype = hostgroup then the value needs to be a hostgroup id
+ # e.g. conditiontype = host the value needs to be a host id
+ cond['conditiontype'] = get_condition_type(event_source, cond['conditiontype'])
+ if cond['conditiontype'] == 0:
+ cond['value'] = get_host_group_id_by_name(zapi, cond['value'])
+ elif cond['conditiontype'] == 1:
+ cond['value'] = get_host_id_by_name(zapi, cond['value'])
+ elif cond['conditiontype'] == 4:
+ cond['value'] = get_priority(cond['value'])
+
+ elif cond['conditiontype'] == 5:
+ cond['value'] = get_trigger_value(cond['value'])
+ elif cond['conditiontype'] == 13:
+ cond['value'] = get_template_id_by_name(zapi, cond['value'])
+ elif cond['conditiontype'] == 16:
+ cond['value'] = ''
+
+ return inc_conditions
+
+
+def get_send_recovery(send_recovery):
+ '''Get the integer value'''
+ rval = 0
+ if send_recovery:
+ rval = 1
+
+ return rval
+
+# The branches are needed for CRUD and error handling
+# pylint: disable=too-many-branches
+def main():
+ '''
+ ansible zabbix module for zbx_item
+ '''
+
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+ zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'),
+ zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'),
+ zbx_debug=dict(default=False, type='bool'),
+
+ name=dict(default=None, type='str'),
+ event_source=dict(default='trigger', choices=['trigger', 'discovery', 'auto', 'internal'], type='str'),
+ action_subject=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}", type='str'),
+ action_message=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}\r\n" +
+ "Last value: {ITEM.LASTVALUE}\r\n\r\n{TRIGGER.URL}", type='str'),
+ reply_subject=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}", type='str'),
+ reply_message=dict(default="Trigger: {TRIGGER.NAME}\r\nTrigger status: {TRIGGER.STATUS}\r\n" +
+ "Trigger severity: {TRIGGER.SEVERITY}\r\nTrigger URL: {TRIGGER.URL}\r\n\r\n" +
+ "Item values:\r\n\r\n1. {ITEM.NAME1} ({HOST.NAME1}:{ITEM.KEY1}): " +
+ "{ITEM.VALUE1}\r\n2. {ITEM.NAME2} ({HOST.NAME2}:{ITEM.KEY2}): " +
+ "{ITEM.VALUE2}\r\n3. {ITEM.NAME3} ({HOST.NAME3}:{ITEM.KEY3}): " +
+ "{ITEM.VALUE3}", type='str'),
+ send_recovery=dict(default=False, type='bool'),
+ status=dict(default=None, type='str'),
+ escalation_time=dict(default=60, type='int'),
+ conditions_filter=dict(default=None, type='dict'),
+ operations=dict(default=None, type='list'),
+ state=dict(default='present', type='str'),
+ ),
+ #supports_check_mode=True
+ )
+
+ zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'],
+ module.params['zbx_user'],
+ module.params['zbx_password'],
+ module.params['zbx_debug']))
+
+ #Set the instance and the template for the rest of the calls
+ zbx_class_name = 'action'
+ state = module.params['state']
+
+ content = zapi.get_content(zbx_class_name,
+ 'get',
+ {'search': {'name': module.params['name']},
+ 'selectFilter': 'extend',
+ 'selectOperations': 'extend',
+ })
+
+ #******#
+ # GET
+ #******#
+ if state == 'list':
+ module.exit_json(changed=False, results=content['result'], state="list")
+
+ #******#
+ # DELETE
+ #******#
+ if state == 'absent':
+ if not exists(content):
+ module.exit_json(changed=False, state="absent")
+
+ content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0]['itemid']])
+ module.exit_json(changed=True, results=content['result'], state="absent")
+
+ # Create and Update
+ if state == 'present':
+
+ conditions = get_action_conditions(zapi, module.params['event_source'], module.params['conditions_filter'])
+ operations = get_action_operations(zapi, module.params['operations'])
+ params = {'name': module.params['name'],
+ 'esc_period': module.params['escalation_time'],
+ 'eventsource': get_event_source(module.params['event_source']),
+ 'status': get_status(module.params['status']),
+ 'def_shortdata': module.params['action_subject'],
+ 'def_longdata': module.params['action_message'],
+ 'r_shortdata': module.params['reply_subject'],
+ 'r_longdata': module.params['reply_message'],
+ 'recovery_msg': get_send_recovery(module.params['send_recovery']),
+ 'filter': conditions,
+ 'operations': operations,
+ }
+
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
+ if not exists(content):
+ content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
+ module.exit_json(changed=True, results=content['result'], state='present')
+
+
+ ########
+ # UPDATE
+ ########
+ _ = params.pop('hostid', None)
+ differences = {}
+ zab_results = content['result'][0]
+ for key, value in params.items():
+
+ if key == 'operations':
+ ops = operation_differences(zab_results[key], value)
+ if ops:
+ differences[key] = ops
+
+ elif key == 'filter':
+ filters = filter_differences(zab_results[key], value)
+ if filters:
+ differences[key] = filters
+
+ elif zab_results[key] != value and zab_results[key] != str(value):
+ differences[key] = value
+
+ if not differences:
+ module.exit_json(changed=False, results=zab_results, state="present")
+
+ # We have differences and need to update.
+ # action update requires an id, filters, and operations
+ differences['actionid'] = zab_results['actionid']
+ differences['operations'] = params['operations']
+ differences['filter'] = params['filter']
+ content = zapi.get_content(zbx_class_name, 'update', differences)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
+ module.exit_json(changed=True, results=content['result'], state="present")
+
+ module.exit_json(failed=True,
+ changed=False,
+ results='Unknown state passed. %s' % state,
+ state="unknown")
+
+# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled
+# import module snippets. This are required
+from ansible.module_utils.basic import *
+
+main()
diff --git a/roles/lib_zabbix/library/zbx_discoveryrule.py b/roles/lib_zabbix/library/zbx_discoveryrule.py
index 71a0580c2..f52f350a5 100644
--- a/roles/lib_zabbix/library/zbx_discoveryrule.py
+++ b/roles/lib_zabbix/library/zbx_discoveryrule.py
@@ -85,6 +85,7 @@ def main():
Ansible module for zabbix discovery rules
'''
+
module = AnsibleModule(
argument_spec=dict(
zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
@@ -93,6 +94,7 @@ def main():
zbx_debug=dict(default=False, type='bool'),
name=dict(default=None, type='str'),
key=dict(default=None, type='str'),
+ description=dict(default=None, type='str'),
interfaceid=dict(default=None, type='int'),
ztype=dict(default='trapper', type='str'),
delay=dict(default=60, type='int'),
@@ -113,18 +115,27 @@ def main():
idname = "itemid"
dname = module.params['name']
state = module.params['state']
+ template = get_template(zapi, module.params['template_name'])
# selectInterfaces doesn't appear to be working but is needed.
content = zapi.get_content(zbx_class_name,
'get',
{'search': {'name': dname},
+ 'templateids': template['templateid'],
#'selectDServices': 'extend',
#'selectDChecks': 'extend',
#'selectDhosts': 'dhostid',
})
+
+ #******#
+ # GET
+ #******#
if state == 'list':
module.exit_json(changed=False, results=content['result'], state="list")
+ #******#
+ # DELETE
+ #******#
if state == 'absent':
if not exists(content):
module.exit_json(changed=False, state="absent")
@@ -132,24 +143,37 @@ def main():
content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]])
module.exit_json(changed=True, results=content['result'], state="absent")
+
+ # Create and Update
if state == 'present':
- template = get_template(zapi, module.params['template_name'])
params = {'name': dname,
'key_': module.params['key'],
'hostid': template['templateid'],
'interfaceid': module.params['interfaceid'],
'lifetime': module.params['lifetime'],
'type': get_type(module.params['ztype']),
+ 'description': module.params['description'],
}
if params['type'] in [2, 5, 7, 11]:
params.pop('interfaceid')
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
if not exists(content):
- # if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state='present')
- # already exists, we need to update it
- # let's compare properties
+
+ ########
+ # UPDATE
+ ########
differences = {}
zab_results = content['result'][0]
for key, value in params.items():
@@ -163,6 +187,10 @@ def main():
# We have differences and need to update
differences[idname] = zab_results[idname]
content = zapi.get_content(zbx_class_name, 'update', differences)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state="present")
module.exit_json(failed=True,
diff --git a/roles/lib_zabbix/library/zbx_itemprototype.py b/roles/lib_zabbix/library/zbx_itemprototype.py
index 24f85710d..4ec1b8e02 100644
--- a/roles/lib_zabbix/library/zbx_itemprototype.py
+++ b/roles/lib_zabbix/library/zbx_itemprototype.py
@@ -38,13 +38,14 @@ def exists(content, key='result'):
return True
-def get_rule_id(zapi, discoveryrule_name):
+def get_rule_id(zapi, discoveryrule_key, templateid):
'''get a discoveryrule by name
'''
content = zapi.get_content('discoveryrule',
'get',
- {'search': {'name': discoveryrule_name},
+ {'search': {'key_': discoveryrule_key},
'output': 'extend',
+ 'templateids': templateid,
})
if not content['result']:
return None
@@ -53,6 +54,9 @@ def get_rule_id(zapi, discoveryrule_name):
def get_template(zapi, template_name):
'''get a template by name
'''
+ if not template_name:
+ return None
+
content = zapi.get_content('template',
'get',
{'search': {'host': template_name},
@@ -134,6 +138,7 @@ def get_app_ids(zapi, application_names):
app_ids.append(content['result'][0]['applicationid'])
return app_ids
+# pylint: disable=too-many-branches
def main():
'''
Ansible module for zabbix discovery rules
@@ -147,16 +152,17 @@ def main():
zbx_debug=dict(default=False, type='bool'),
name=dict(default=None, type='str'),
key=dict(default=None, type='str'),
+ description=dict(default=None, type='str'),
interfaceid=dict(default=None, type='int'),
ztype=dict(default='trapper', type='str'),
value_type=dict(default='float', type='str'),
delay=dict(default=60, type='int'),
lifetime=dict(default=30, type='int'),
- template_name=dict(default=[], type='list'),
state=dict(default='present', type='str'),
status=dict(default='enabled', type='str'),
- discoveryrule_name=dict(default=None, type='str'),
applications=dict(default=[], type='list'),
+ template_name=dict(default=None, type='str'),
+ discoveryrule_key=dict(default=None, type='str'),
),
#supports_check_mode=True
)
@@ -169,20 +175,27 @@ def main():
#Set the instance and the template for the rest of the calls
zbx_class_name = 'itemprototype'
idname = "itemid"
- dname = module.params['name']
state = module.params['state']
+ template = get_template(zapi, module.params['template_name'])
# selectInterfaces doesn't appear to be working but is needed.
content = zapi.get_content(zbx_class_name,
'get',
- {'search': {'name': dname},
+ {'search': {'key_': module.params['key']},
'selectApplications': 'applicationid',
'selectDiscoveryRule': 'itemid',
- #'selectDhosts': 'dhostid',
+ 'templated': True,
})
+
+ #******#
+ # GET
+ #******#
if state == 'list':
module.exit_json(changed=False, results=content['result'], state="list")
+ #******#
+ # DELETE
+ #******#
if state == 'absent':
if not exists(content):
module.exit_json(changed=False, state="absent")
@@ -190,26 +203,39 @@ def main():
content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]])
module.exit_json(changed=True, results=content['result'], state="absent")
+ # Create and Update
if state == 'present':
- template = get_template(zapi, module.params['template_name'])
- params = {'name': dname,
+ params = {'name': module.params['name'],
'key_': module.params['key'],
'hostid': template['templateid'],
'interfaceid': module.params['interfaceid'],
- 'ruleid': get_rule_id(zapi, module.params['discoveryrule_name']),
+ 'ruleid': get_rule_id(zapi, module.params['discoveryrule_key'], template['templateid']),
'type': get_type(module.params['ztype']),
'value_type': get_value_type(module.params['value_type']),
'applications': get_app_ids(zapi, module.params['applications']),
+ 'description': module.params['description'],
}
+
if params['type'] in [2, 5, 7, 8, 11, 15]:
params.pop('interfaceid')
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
if not exists(content):
- # if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state='present')
- # already exists, we need to update it
- # let's compare properties
+
+ #******#
+ # UPDATE
+ #******#
differences = {}
zab_results = content['result'][0]
for key, value in params.items():
@@ -218,6 +244,11 @@ def main():
if value != zab_results['discoveryRule']['itemid']:
differences[key] = value
+ elif key == 'applications':
+ app_ids = [app['applicationid'] for app in zab_results[key]]
+ if set(app_ids) - set(value):
+ differences[key] = value
+
elif zab_results[key] != value and zab_results[key] != str(value):
differences[key] = value
@@ -227,6 +258,10 @@ def main():
# We have differences and need to update
differences[idname] = zab_results[idname]
content = zapi.get_content(zbx_class_name, 'update', differences)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=False, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state="present")
module.exit_json(failed=True,
diff --git a/roles/lib_zabbix/library/zbx_trigger.py b/roles/lib_zabbix/library/zbx_trigger.py
index a05de7e68..21d0fcfd2 100644
--- a/roles/lib_zabbix/library/zbx_trigger.py
+++ b/roles/lib_zabbix/library/zbx_trigger.py
@@ -74,6 +74,18 @@ def get_deps(zapi, deps):
return results
+
+def get_trigger_status(inc_status):
+ ''' Determine the trigger's status
+ 0 is enabled
+ 1 is disabled
+ '''
+ r_status = 0
+ if inc_status == 'disabled':
+ r_status = 1
+
+ return r_status
+
def main():
'''
Create a trigger in zabbix
@@ -103,6 +115,7 @@ def main():
dependencies=dict(default=[], type='list'),
priority=dict(default='avg', type='str'),
url=dict(default=None, type='str'),
+ status=dict(default=None, type='str'),
state=dict(default='present', type='str'),
),
#supports_check_mode=True
@@ -145,6 +158,7 @@ def main():
'dependencies': get_deps(zapi, module.params['dependencies']),
'priority': get_priority(module.params['priority']),
'url': module.params['url'],
+ 'status': get_trigger_status(module.params['status']),
}
# Remove any None valued params
@@ -156,6 +170,10 @@ def main():
if not exists(content):
# if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
module.exit_json(changed=True, results=content['result'], state='present')
########
diff --git a/roles/lib_zabbix/library/zbx_triggerprototype.py b/roles/lib_zabbix/library/zbx_triggerprototype.py
new file mode 100644
index 000000000..c1224b268
--- /dev/null
+++ b/roles/lib_zabbix/library/zbx_triggerprototype.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+'''
+ansible module for zabbix triggerprototypes
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+# Zabbix triggerprototypes ansible module
+#
+#
+# Copyright 2015 Red Hat Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is in place because each module looks similar to each other.
+# These need duplicate code as their behavior is very similar
+# but different for each zabbix class.
+# pylint: disable=duplicate-code
+
+# pylint: disable=import-error
+from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection
+
+def exists(content, key='result'):
+ ''' Check if key exists in content or the size of content[key] > 0
+ '''
+ if not content.has_key(key):
+ return False
+
+ if not content[key]:
+ return False
+
+ return True
+
+def get_priority(priority):
+ ''' determine priority
+ '''
+ prior = 0
+ if 'info' in priority:
+ prior = 1
+ elif 'warn' in priority:
+ prior = 2
+ elif 'avg' == priority or 'ave' in priority:
+ prior = 3
+ elif 'high' in priority:
+ prior = 4
+ elif 'dis' in priority:
+ prior = 5
+
+ return prior
+
+def get_trigger_status(inc_status):
+ ''' Determine the trigger's status
+ 0 is enabled
+ 1 is disabled
+ '''
+ r_status = 0
+ if inc_status == 'disabled':
+ r_status = 1
+
+ return r_status
+
+
+def main():
+ '''
+ Create a triggerprototype in zabbix
+ '''
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+ zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'),
+ zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'),
+ zbx_debug=dict(default=False, type='bool'),
+ name=dict(default=None, type='str'),
+ expression=dict(default=None, type='str'),
+ description=dict(default=None, type='str'),
+ priority=dict(default='avg', type='str'),
+ url=dict(default=None, type='str'),
+ status=dict(default=None, type='str'),
+ state=dict(default='present', type='str'),
+ ),
+ #supports_check_mode=True
+ )
+
+ zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'],
+ module.params['zbx_user'],
+ module.params['zbx_password'],
+ module.params['zbx_debug']))
+
+ #Set the instance and the template for the rest of the calls
+ zbx_class_name = 'triggerprototype'
+ idname = "triggerid"
+ state = module.params['state']
+ tname = module.params['name']
+
+ content = zapi.get_content(zbx_class_name,
+ 'get',
+ {'filter': {'description': tname},
+ 'expandExpression': True,
+ 'selectDependencies': 'triggerid',
+ })
+
+ # Get
+ if state == 'list':
+ module.exit_json(changed=False, results=content['result'], state="list")
+
+ # Delete
+ if state == 'absent':
+ if not exists(content):
+ module.exit_json(changed=False, state="absent")
+ content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]])
+ module.exit_json(changed=True, results=content['result'], state="absent")
+
+ # Create and Update
+ if state == 'present':
+ params = {'description': tname,
+ 'comments': module.params['description'],
+ 'expression': module.params['expression'],
+ 'priority': get_priority(module.params['priority']),
+ 'url': module.params['url'],
+ 'status': get_trigger_status(module.params['status']),
+ }
+
+ # Remove any None valued params
+ _ = [params.pop(key, None) for key in params.keys() if params[key] is None]
+
+ #******#
+ # CREATE
+ #******#
+ if not exists(content):
+ # if we didn't find it, create it
+ content = zapi.get_content(zbx_class_name, 'create', params)
+
+ if content.has_key('error'):
+ module.exit_json(failed=True, changed=True, results=content['error'], state="present")
+
+ module.exit_json(changed=True, results=content['result'], state='present')
+
+ ########
+ # UPDATE
+ ########
+ differences = {}
+ zab_results = content['result'][0]
+ for key, value in params.items():
+
+ if zab_results[key] != value and zab_results[key] != str(value):
+ differences[key] = value
+
+ if not differences:
+ module.exit_json(changed=False, results=zab_results, state="present")
+
+ # We have differences and need to update
+ differences[idname] = zab_results[idname]
+ content = zapi.get_content(zbx_class_name, 'update', differences)
+ module.exit_json(changed=True, results=content['result'], state="present")
+
+
+ module.exit_json(failed=True,
+ changed=False,
+ results='Unknown state passed. %s' % state,
+ state="unknown")
+
+# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled
+# import module snippets. This are required
+from ansible.module_utils.basic import *
+
+main()
diff --git a/roles/lib_zabbix/library/zbx_user_media.py b/roles/lib_zabbix/library/zbx_user_media.py
index 3f7760475..9ed838f81 100644
--- a/roles/lib_zabbix/library/zbx_user_media.py
+++ b/roles/lib_zabbix/library/zbx_user_media.py
@@ -54,8 +54,8 @@ def get_mtype(zapi, mtype):
except ValueError:
pass
- content = zapi.get_content('mediatype', 'get', {'search': {'description': mtype}})
- if content.has_key['result'] and content['result']:
+ content = zapi.get_content('mediatype', 'get', {'filter': {'description': mtype}})
+ if content.has_key('result') and content['result']:
return content['result'][0]['mediatypeid']
return None
@@ -63,7 +63,7 @@ def get_mtype(zapi, mtype):
def get_user(zapi, user):
''' Get userids from user aliases
'''
- content = zapi.get_content('user', 'get', {'search': {'alias': user}})
+ content = zapi.get_content('user', 'get', {'filter': {'alias': user}})
if content['result']:
return content['result'][0]
@@ -104,15 +104,17 @@ def find_media(medias, user_media):
''' Find the user media in the list of medias
'''
for media in medias:
- if all([media[key] == user_media[key] for key in user_media.keys()]):
+ if all([media[key] == str(user_media[key]) for key in user_media.keys()]):
return media
return None
-def get_active(in_active):
+def get_active(is_active):
'''Determine active value
+ 0 - enabled
+ 1 - disabled
'''
active = 1
- if in_active:
+ if is_active:
active = 0
return active
@@ -128,6 +130,21 @@ def get_mediatype(zapi, mediatype, mediatype_desc):
return mtypeid
+def preprocess_medias(zapi, medias):
+ ''' Insert the correct information when processing medias '''
+ for media in medias:
+ # Fetch the mediatypeid from the media desc (name)
+ if media.has_key('mediatype'):
+ media['mediatypeid'] = get_mediatype(zapi, mediatype=None, mediatype_desc=media.pop('mediatype'))
+
+ media['active'] = get_active(media.get('active'))
+ media['severity'] = int(get_severity(media['severity']))
+
+ return medias
+
+# Disabling branching as the logic requires branches.
+# I've also added a few safeguards which required more branches.
+# pylint: disable=too-many-branches
def main():
'''
Ansible zabbix module for mediatype
@@ -166,11 +183,17 @@ def main():
# User media is fetched through the usermedia.get
zbx_user_query = get_zbx_user_query_data(zapi, module.params['login'])
- content = zapi.get_content('usermedia', 'get', zbx_user_query)
-
+ content = zapi.get_content('usermedia', 'get',
+ {'userids': [uid for user, uid in zbx_user_query.items()]})
+ #####
+ # Get
+ #####
if state == 'list':
module.exit_json(changed=False, results=content['result'], state="list")
+ ########
+ # Delete
+ ########
if state == 'absent':
if not exists(content) or len(content['result']) == 0:
module.exit_json(changed=False, state="absent")
@@ -178,13 +201,14 @@ def main():
if not module.params['login']:
module.exit_json(failed=True, changed=False, results='Must specifiy a user login.', state="absent")
- content = zapi.get_content(zbx_class_name, 'deletemedia', [content['result'][0][idname]])
+ content = zapi.get_content(zbx_class_name, 'deletemedia', [res[idname] for res in content['result']])
if content.has_key('error'):
module.exit_json(changed=False, results=content['error'], state="absent")
module.exit_json(changed=True, results=content['result'], state="absent")
+ # Create and Update
if state == 'present':
active = get_active(module.params['active'])
mtypeid = get_mediatype(zapi, module.params['mediatype'], module.params['mediatype_desc'])
@@ -197,13 +221,21 @@ def main():
'severity': int(get_severity(module.params['severity'])),
'period': module.params['period'],
}]
+ else:
+ medias = preprocess_medias(zapi, medias)
params = {'users': [zbx_user_query],
'medias': medias,
'output': 'extend',
}
+ ########
+ # Create
+ ########
if not exists(content):
+ if not params['medias']:
+ module.exit_json(changed=False, results=content['result'], state='present')
+
# if we didn't find it, create it
content = zapi.get_content(zbx_class_name, 'addmedia', params)
@@ -216,6 +248,9 @@ def main():
# If user params exists, check to see if they already exist in zabbix
# if they exist, then return as no update
# elif they do not exist, then take user params only
+ ########
+ # Update
+ ########
diff = {'medias': [], 'users': {}}
_ = [diff['medias'].append(media) for media in params['medias'] if not find_media(content['result'], media)]
diff --git a/roles/lib_zabbix/tasks/create_template.yml b/roles/lib_zabbix/tasks/create_template.yml
index fd0cdd46f..62259b680 100644
--- a/roles/lib_zabbix/tasks/create_template.yml
+++ b/roles/lib_zabbix/tasks/create_template.yml
@@ -52,3 +52,44 @@
url: "{{ item.url | default(None, True) }}"
with_items: template.ztriggers
when: template.ztriggers is defined
+
+- name: Create Discoveryrules
+ zbx_discoveryrule:
+ zbx_server: "{{ server }}"
+ zbx_user: "{{ user }}"
+ zbx_password: "{{ password }}"
+ name: "{{ item.name }}"
+ key: "{{ item.key }}"
+ lifetime: "{{ item.lifetime }}"
+ template_name: "{{ template.name }}"
+ description: "{{ item.description | default('', True) }}"
+ with_items: template.zdiscoveryrules
+ when: template.zdiscoveryrules is defined
+
+- name: Create Item Prototypes
+ zbx_itemprototype:
+ zbx_server: "{{ server }}"
+ zbx_user: "{{ user }}"
+ zbx_password: "{{ password }}"
+ name: "{{ item.name }}"
+ key: "{{ item.key }}"
+ discoveryrule_key: "{{ item.discoveryrule_key }}"
+ value_type: "{{ item.value_type }}"
+ template_name: "{{ template.name }}"
+ applications: "{{ item.applications }}"
+ description: "{{ item.description | default('', True) }}"
+ with_items: template.zitemprototypes
+ when: template.zitemprototypes is defined
+
+- name: Create Trigger Prototypes
+ zbx_triggerprototype:
+ zbx_server: "{{ server }}"
+ zbx_user: "{{ user }}"
+ zbx_password: "{{ password }}"
+ name: "{{ item.name }}"
+ expression: "{{ item.expression }}"
+ url: "{{ item.url | default('', True) }}"
+ priority: "{{ item.priority | default('average', True) }}"
+ description: "{{ item.description | default('', True) }}"
+ with_items: template.ztriggerprototypes
+ when: template.ztriggerprototypes is defined
diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py
index 991b8da66..f708f9bac 100755
--- a/roles/openshift_facts/library/openshift_facts.py
+++ b/roles/openshift_facts/library/openshift_facts.py
@@ -644,7 +644,7 @@ def merge_facts(orig, new):
facts = dict()
for key, value in orig.iteritems():
if key in new:
- if isinstance(value, dict):
+ if isinstance(value, dict) and isinstance(new[key], dict):
facts[key] = merge_facts(value, new[key])
else:
facts[key] = copy.copy(new[key])
diff --git a/roles/os_zabbix/vars/template_os_linux.yml b/roles/os_zabbix/vars/template_os_linux.yml
index 3173c79b2..3c29c5d16 100644
--- a/roles/os_zabbix/vars/template_os_linux.yml
+++ b/roles/os_zabbix/vars/template_os_linux.yml
@@ -191,6 +191,35 @@ g_template_os_linux:
- Disk
value_type: float
+
+ zdiscoveryrules:
+ - name: disc.filesys
+ key: disc.filesys
+ lifetime: 1
+ template_name: Template OS Linux
+ description: "Dynamically register the filesystems"
+
+ zitemprototypes:
+ - discoveryrule_key: disc.filesys
+ template_name: Template OS Linux
+ name: "disc.filesys.full.{#OSO_FILESYS}"
+ key: "disc.filesys.full[{#OSO_FILESYS}]"
+ value_type: float
+ description: "PCP filesys.full option. This is the percent full returned from pcp filesys.full"
+ applications:
+ - Disk
+
+ ztriggerprototypes:
+ - name: 'Filesystem: {#OSO_FILESYS} has less than 10% free on {HOST.NAME}'
+ expression: '{Template OS Linux:disc.filesys.full[{#OSO_FILESYS}].last()}>90'
+ url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc'
+ priority: warn
+
+ - name: 'Filesystem: {#OSO_FILESYS} has less than 5% free on {HOST.NAME}'
+ expression: '{Template OS Linux:disc.filesys.full[{#OSO_FILESYS}].last()}>95'
+ url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc'
+ priority: high
+
ztriggers:
- name: 'Filesystem: / has less than 10% free on {HOST.NAME}'
expression: '{Template OS Linux:filesys.full.xvda2.last()}>90'