From a073f179b26c0d110aa6a8b7fc560ca061e4dc5c Mon Sep 17 00:00:00 2001
From: Kenny Woodson <kwoodson@redhat.com>
Date: Tue, 11 Aug 2015 15:52:38 -0400
Subject: Zabbix Idempotency

---
 roles/os_zabbix/library/__init__.py      |   0
 roles/os_zabbix/library/test.yml         |  92 ++++++++
 roles/os_zabbix/library/zbx_host.py      | 162 +++++++++++++
 roles/os_zabbix/library/zbx_hostgroup.py | 116 ++++++++++
 roles/os_zabbix/library/zbx_item.py      | 160 +++++++++++++
 roles/os_zabbix/library/zbx_mediatype.py | 149 ++++++++++++
 roles/os_zabbix/library/zbx_template.py  | 126 ++++++++++
 roles/os_zabbix/library/zbx_trigger.py   | 175 ++++++++++++++
 roles/os_zabbix/library/zbx_user.py      | 146 ++++++++++++
 roles/os_zabbix/library/zbx_usergroup.py | 160 +++++++++++++
 roles/os_zabbix/library/zbxapi.py        | 382 -------------------------------
 11 files changed, 1286 insertions(+), 382 deletions(-)
 create mode 100644 roles/os_zabbix/library/__init__.py
 create mode 100644 roles/os_zabbix/library/test.yml
 create mode 100644 roles/os_zabbix/library/zbx_host.py
 create mode 100644 roles/os_zabbix/library/zbx_hostgroup.py
 create mode 100644 roles/os_zabbix/library/zbx_item.py
 create mode 100644 roles/os_zabbix/library/zbx_mediatype.py
 create mode 100644 roles/os_zabbix/library/zbx_template.py
 create mode 100644 roles/os_zabbix/library/zbx_trigger.py
 create mode 100644 roles/os_zabbix/library/zbx_user.py
 create mode 100644 roles/os_zabbix/library/zbx_usergroup.py
 delete mode 100755 roles/os_zabbix/library/zbxapi.py

(limited to 'roles/os_zabbix/library')

diff --git a/roles/os_zabbix/library/__init__.py b/roles/os_zabbix/library/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/roles/os_zabbix/library/test.yml b/roles/os_zabbix/library/test.yml
new file mode 100644
index 000000000..f585bcbb2
--- /dev/null
+++ b/roles/os_zabbix/library/test.yml
@@ -0,0 +1,92 @@
+---
+# This is a test playbook to create one of each of the zabbix ansible modules.
+# ensure that the zbxapi module is installed
+# ansible-playbook test.yml
+- name: Test zabbix ansible module
+  hosts: localhost
+  gather_facts: no
+  vars:
+    zbx_server: http://localhost/zabbix/api_jsonrpc.php
+    zbx_user: Admin
+    zbx_password: zabbix
+
+  pre_tasks:
+  - name: Create a template
+    zbx_template:
+      server: "{{ zbx_server }}"
+      user: "{{ zbx_user }}"
+      password: "{{ zbx_password }}"
+      name: 'test template'
+    register: template_output
+
+  - debug: var=template_output
+
+  - name: Create an item
+    zbx_item:
+      server: "{{ zbx_server }}"
+      user: "{{ zbx_user }}"
+      password: "{{ zbx_password }}"
+      name: 'test item'
+      key: 'kenny.item.1'
+      template_name: "{{ template_output.results[0].host }}"
+    register: item_output
+
+  - debug: var=item_output
+
+  - name: Create an trigger
+    zbx_trigger:
+      server: "{{ zbx_server }}"
+      user: "{{ zbx_user }}"
+      password: "{{ zbx_password }}"
+      expression: '{test template:kenny.item.1.last()}>2'
+      desc: 'Kenny desc'
+    register: trigger_output
+
+  - debug: var=trigger_output
+
+  - name: Create a hostgroup
+    zbx_hostgroup:
+      server: "{{ zbx_server }}"
+      user: "{{ zbx_user }}"
+      password: "{{ zbx_password }}"
+      name: 'kenny hostgroup'
+    register: hostgroup_output
+
+  - debug: var=hostgroup_output
+
+  - name: Create a host
+    zbx_host:
+      server: "{{ zbx_server }}"
+      user: "{{ zbx_user }}"
+      password: "{{ zbx_password }}"
+      name: 'kenny host'
+      hostgroups:
+      -  'kenny hostgroup'
+    register: host_output
+
+  - debug: var=host_output
+
+  - name: Create a usergroup
+    zbx_usergroup:
+      server: "{{ zbx_server }}"
+      user: "{{ zbx_user }}"
+      password: "{{ zbx_password }}"
+      name: kenny usergroup
+      rights:
+      - 'kenny hostgroup': rw
+    register: usergroup_output
+
+  - debug: var=usergroup_output
+
+  - name: Create a user
+    zbx_user:
+      server: "{{ zbx_server }}"
+      user: "{{ zbx_user }}"
+      password: "{{ zbx_password }}"
+      alias: kenny user
+      passwd: zabbix
+      usergroups:
+      - kenny usergroup
+    register: user_output
+
+  - debug: var=user_output
diff --git a/roles/os_zabbix/library/zbx_host.py b/roles/os_zabbix/library/zbx_host.py
new file mode 100644
index 000000000..d75dfdea1
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_host.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+'''
+Zabbix host ansible module
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   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_group_ids(zapi, hostgroup_names):
+    '''
+    get hostgroups
+    '''
+    # Fetch groups by name
+    group_ids = []
+    for hgr in hostgroup_names:
+        content = zapi.get_content('hostgroup', 'get', {'search': {'name': hgr}})
+        if content.has_key('result'):
+            group_ids.append({'groupid': content['result'][0]['groupid']})
+
+    return group_ids
+
+def get_template_ids(zapi, template_names):
+    '''
+    get related templates
+    '''
+    template_ids = []
+    # Fetch templates by name
+    for template_name in template_names:
+        content = zapi.get_content('template', 'get', {'search': {'host': template_name}})
+        if content.has_key('result'):
+            template_ids.append({'templateid': content['results'][0]['templateid']})
+    return template_ids
+
+def main():
+    '''
+    Ansible module for zabbix host
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            name=dict(default=None, type='str'),
+            hostgroup_names=dict(default=[], type='list'),
+            template_names=dict(default=[], type='list'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+            interfaces=dict(default=[], type='list'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug']))
+
+    #Set the instance and the template for the rest of the calls
+    zbx_class_name = 'host'
+    idname = "hostid"
+    hname = module.params['name']
+    state = module.params['state']
+
+    # selectInterfaces doesn't appear to be working but is needed.
+    content = zapi.get_content(zbx_class_name,
+                               'get',
+                               {'search': {'host': hname},
+                                'selectGroups': 'groupid',
+                                'selectParentTemplates': 'templateid',
+                                'selectInterfaces': 'interfaceid',
+                               })
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'host': hname,
+                  'groups':  get_group_ids(zapi, module.params('hostgroup_names')),
+                  'templates':  get_template_ids(zapi, module.params('template_names')),
+                  'interfaces': module.params.get('interfaces', [{'type':  1,         # interface type, 1 = agent
+                                                                  'main':  1,         # default interface? 1 = true
+                                                                  'useip':  1,        # default interface? 1 = true
+                                                                  'ip':  '127.0.0.1', # default interface? 1 = true
+                                                                  'dns':  '',         # dns for host
+                                                                  'port':  '10050',   # port for interface? 10050
+                                                                 }])
+                 }
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        differences = {}
+        zab_results = content['result'][0]
+        for key, value in params.items():
+
+            if key == 'templates' and zab_results.has_key('parentTemplates'):
+                if zab_results['parentTemplates'] != value:
+                    differences[key] = value
+
+            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
+        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/os_zabbix/library/zbx_hostgroup.py b/roles/os_zabbix/library/zbx_hostgroup.py
new file mode 100644
index 000000000..a1eb875d4
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_hostgroup.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+''' Ansible module for hostgroup
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   Zabbix hostgroup 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 main():
+    ''' ansible module for hostgroup
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            name=dict(default=None, type='str'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug']))
+
+    #Set the instance and the template for the rest of the calls
+    zbx_class_name = 'hostgroup'
+    idname = "groupid"
+    hname = module.params['name']
+    state = module.params['state']
+
+    content = zapi.get_content(zbx_class_name,
+                               'get',
+                               {'search': {'name': hname},
+                               })
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'name': hname}
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        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/os_zabbix/library/zbx_item.py b/roles/os_zabbix/library/zbx_item.py
new file mode 100644
index 000000000..6cfb16d48
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_item.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+'''
+ Ansible module for zabbix items
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   Zabbix item 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_value_type(value_type):
+    '''
+    Possible values:
+    0 - numeric float;
+    1 - character;
+    2 - log;
+    3 - numeric unsigned;
+    4 - text
+    '''
+    vtype = 0
+    if 'int' in value_type:
+        vtype = 3
+    elif 'char' in value_type:
+        vtype = 1
+    elif 'str' in value_type:
+        vtype = 4
+
+    return vtype
+
+def main():
+    '''
+    ansible zabbix module for zbx_item
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            name=dict(default=None, type='str'),
+            key=dict(default=None, type='str'),
+            template_name=dict(default=None, type='str'),
+            zabbix_type=dict(default=2, type='int'),
+            value_type=dict(default='int', type='str'),
+            applications=dict(default=[], type='list'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug']))
+
+    #Set the instance and the template for the rest of the calls
+    zbx_class_name = 'item'
+    idname = "itemid"
+    state = module.params['state']
+    key = module.params['key']
+    template_name = module.params['template_name']
+
+    content = zapi.get_content('template', 'get', {'search': {'host': template_name}})
+    templateid = None
+    if content['result']:
+        templateid = content['result'][0]['templateid']
+    else:
+        module.exit_json(changed=False,
+                         results='Error: Could find template with name %s for item.' % template_name,
+                         state="Unkown")
+
+    content = zapi.get_content(zbx_class_name,
+                               'get',
+                               {'search': {'key_': key},
+                                'selectApplications': 'applicationid',
+                               })
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'name': module.params['name'],
+                  'key_': key,
+                  'hostid': templateid,
+                  'type': module.params['zabbix_type'],
+                  'value_type': get_value_type(module.params['value_type']),
+                  'applications': module.params['applications'],
+                 }
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        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/os_zabbix/library/zbx_mediatype.py b/roles/os_zabbix/library/zbx_mediatype.py
new file mode 100644
index 000000000..a49aecd0f
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_mediatype.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+'''
+ Ansible module for mediatype
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   Zabbix mediatype 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_mtype(mtype):
+    '''
+    Transport used by the media type.
+    Possible values:
+    0 - email;
+    1 - script;
+    2 - SMS;
+    3 - Jabber;
+    100 - Ez Texting.
+    '''
+    mtype = mtype.lower()
+    media_type = None
+    if mtype == 'script':
+        media_type = 1
+    elif mtype == 'sms':
+        media_type = 2
+    elif mtype == 'jabber':
+        media_type = 3
+    elif mtype == 'script':
+        media_type = 100
+    else:
+        media_type = 0
+
+    return media_type
+
+def main():
+    '''
+    Ansible zabbix module for mediatype
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            description=dict(default=None, type='str'),
+            mtype=dict(default=None, type='str'),
+            smtp_server=dict(default=None, type='str'),
+            smtp_helo=dict(default=None, type='str'),
+            smtp_email=dict(default=None, type='str'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug']))
+
+    #Set the instance and the template for the rest of the calls
+    zbx_class_name = 'mediatype'
+    idname = "mediatypeid"
+    description = module.params['description']
+    state = module.params['state']
+
+    content = zapi.get_content(zbx_class_name, 'get', {'search': {'description': description}})
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'description': description,
+                  'type': get_mtype(module.params['media_type']),
+                  'smtp_server': module.params['smtp_server'],
+                  'smtp_helo': module.params['smtp_helo'],
+                  'smtp_email': module.params['smtp_email'],
+                 }
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        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/os_zabbix/library/zbx_template.py b/roles/os_zabbix/library/zbx_template.py
new file mode 100644
index 000000000..676fa7e49
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_template.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+'''
+Ansible module for template
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   Zabbix template 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 main():
+    ''' Ansible module for template
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            name=dict(default=None, type='str'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+    zbc = ZabbixConnection(module.params['server'], user, passwd, module.params['debug'])
+    zapi = ZabbixAPI(zbc)
+
+    #Set the instance and the template for the rest of the calls
+    zbx_class_name = 'template'
+    idname = 'templateid'
+    tname = module.params['name']
+    state = module.params['state']
+    # get a template, see if it exists
+    content = zapi.get_content(zbx_class_name,
+                               'get',
+                               {'search': {'host': tname},
+                                'selectParentTemplates': 'templateid',
+                                'selectGroups': 'groupid',
+                                #'selectApplications': extend,
+                               })
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'groups': module.params.get('groups', [{'groupid': '1'}]),
+                  'host': tname,
+                 }
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        differences = {}
+        zab_results = content['result'][0]
+        for key, value in params.items():
+            if key == 'templates' and zab_results.has_key('parentTemplates'):
+                if zab_results['parentTemplates'] != value:
+                    differences[key] = value
+            elif zab_results[key] != str(value) and zab_results[key] != value:
+                differences[key] = value
+
+        if not differences:
+            module.exit_json(changed=False, results=content['result'], 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/os_zabbix/library/zbx_trigger.py b/roles/os_zabbix/library/zbx_trigger.py
new file mode 100644
index 000000000..7cc9356c8
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_trigger.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+'''
+ansible module for zabbix triggers
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   Zabbix trigger 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_deps(zapi, deps):
+    ''' get trigger dependencies
+    '''
+    results = []
+    for desc in deps:
+        content = zapi.get_content('trigger',
+                                   'get',
+                                   {'search': {'description': desc},
+                                    'expandExpression': True,
+                                    'selectDependencies': 'triggerid',
+                                   })
+        if content.has_key('result'):
+            results.append({'triggerid': content['result'][0]['triggerid']})
+
+    return results
+
+def main():
+    '''
+    Create a trigger in zabbix
+
+    Example:
+    "params": {
+        "description": "Processor load is too high on {HOST.NAME}",
+        "expression": "{Linux server:system.cpu.load[percpu,avg1].last()}>5",
+        "dependencies": [
+            {
+                "triggerid": "14062"
+            }
+        ]
+    },
+
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            expression=dict(default=None, type='str'),
+            description=dict(default=None, type='str'),
+            dependencies=dict(default=[], type='list'),
+            priority=dict(default='avg', type='str'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+
+    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug']))
+
+    #Set the instance and the template for the rest of the calls
+    zbx_class_name = 'trigger'
+    idname = "triggerid"
+    state = module.params['state']
+    description = module.params['description']
+
+    content = zapi.get_content(zbx_class_name,
+                               'get',
+                               {'search': {'description': description},
+                                'expandExpression': True,
+                                'selectDependencies': 'triggerid',
+                               })
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'description': description,
+                  'expression':  module.params['expression'],
+                  'dependencies': get_deps(zapi, module.params['dependencies']),
+                  'priority': get_priority(module.params['priority']),
+                 }
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        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/os_zabbix/library/zbx_user.py b/roles/os_zabbix/library/zbx_user.py
new file mode 100644
index 000000000..489023407
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_user.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+'''
+ansible module for zabbix users
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   Zabbix user 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_usergroups(zapi, usergroups):
+    ''' Get usergroups
+    '''
+    ugroups = []
+    for ugr in usergroups:
+        content = zapi.get_content('usergroup',
+                                   'get',
+                                   {'search': {'name': ugr},
+                                    #'selectUsers': 'userid',
+                                    #'getRights': 'extend'
+                                   })
+        if content['result']:
+            ugroups.append({'usrgrpid': content['result'][0]['usrgrpid']})
+
+    return ugroups
+
+def main():
+    '''
+    ansible zabbix module for users
+    '''
+
+    ##def user(self, name, state='present', params=None):
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            alias=dict(default=None, type='str'),
+            passwd=dict(default=None, type='str'),
+            usergroups=dict(default=None, type='list'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    password = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+    zbc = ZabbixConnection(module.params['server'], user, password, module.params['debug'])
+    zapi = ZabbixAPI(zbc)
+
+    ## before we can create a user media and users with media types we need media
+    zbx_class_name = 'user'
+    idname = "userid"
+    alias = module.params['alias']
+    state = module.params['state']
+
+    content = zapi.get_content(zbx_class_name,
+                               'get',
+                               {'output': 'extend',
+                                'search': {'alias': alias},
+                                "selectUsrgrps": 'usergrpid',
+                               })
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'alias': alias,
+                  'passwd': module.params['passwd'],
+                  'usrgrps': get_usergroups(zapi, module.params['usergroups']),
+                 }
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        differences = {}
+        zab_results = content['result'][0]
+        for key, value in params.items():
+            if key == 'passwd':
+                differences[key] = value
+
+            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
+        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/os_zabbix/library/zbx_usergroup.py b/roles/os_zabbix/library/zbx_usergroup.py
new file mode 100644
index 000000000..ede4c9df1
--- /dev/null
+++ b/roles/os_zabbix/library/zbx_usergroup.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+'''
+zabbix ansible module for usergroups
+'''
+# vim: expandtab:tabstop=4:shiftwidth=4
+#
+#   Zabbix usergroup 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_rights(zapi, rights):
+    '''Get rights
+    '''
+    perms = []
+    for right in rights:
+        hstgrp = right.keys()[0]
+        perm = right.values()[0]
+        content = zapi.get_content('hostgroup', 'get', {'search': {'name': hstgrp}})
+        if content['result']:
+            permission = 0
+            if perm == 'ro':
+                permission = 2
+            elif perm == 'rw':
+                permission = 3
+            perms.append({'id': content['result'][0]['groupid'],
+                          'permission': permission})
+    return perms
+
+def get_userids(zapi, users):
+    ''' Get userids from user aliases
+    '''
+    userids = []
+    for alias in users:
+        content = zapi.get_content('user', 'get', {'search': {'alias': alias}})
+        if content['result']:
+            userids.append(content['result'][0]['userid'])
+
+    return userids
+
+def main():
+    ''' Ansible module for usergroup
+    '''
+
+    ##def usergroup(self, name, rights=None, users=None, state='present', params=None):
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
+            user=dict(default=None, type='str'),
+            password=dict(default=None, type='str'),
+            name=dict(default=None, type='str'),
+            rights=dict(default=[], type='list'),
+            users=dict(default=[], type='list'),
+            debug=dict(default=False, type='bool'),
+            state=dict(default='present', type='str'),
+        ),
+        #supports_check_mode=True
+    )
+
+    user = module.params.get('user', os.environ['ZABBIX_USER'])
+    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD'])
+
+    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug']))
+
+    zbx_class_name = 'usergroup'
+    idname = "usrgrpid"
+    uname = module.params['name']
+    state = module.params['state']
+
+    content = zapi.get_content(zbx_class_name,
+                               'get',
+                               {'search': {'name': uname},
+                                'selectUsers': 'userid',
+                               })
+    if state == 'list':
+        module.exit_json(changed=False, results=content['result'], state="list")
+
+    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")
+
+    if state == 'present':
+        params = {'name': uname,
+                  'rights': get_rights(zapi, module.params['rights']),
+                  'userids': get_userids(zapi, module.params['users']),
+                 }
+
+        if not exists(content):
+            # if we didn't find it, create it
+            content = zapi.get_content(zbx_class_name, 'create', params)
+            module.exit_json(changed=True, results=content['result'], state='present')
+        # already exists, we need to update it
+        # let's compare properties
+        differences = {}
+        zab_results = content['result'][0]
+        for key, value in params.items():
+            if key == 'rights':
+                differences['rights'] = value
+
+            elif key == 'userids' and zab_results.has_key('users'):
+                if zab_results['users'] != value:
+                    differences['userids'] = value
+
+            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
+        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/os_zabbix/library/zbxapi.py b/roles/os_zabbix/library/zbxapi.py
deleted file mode 100755
index 48f294938..000000000
--- a/roles/os_zabbix/library/zbxapi.py
+++ /dev/null
@@ -1,382 +0,0 @@
-#!/usr/bin/env python
-# vim: expandtab:tabstop=4:shiftwidth=4
-'''
-   ZabbixAPI 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.
-#
-#  Purpose: An ansible module to communicate with zabbix.
-#
-
-# pylint: disable=line-too-long
-# Disabling line length for readability
-
-import json
-import httplib2
-import sys
-import os
-import re
-import copy
-
-class ZabbixAPIError(Exception):
-    '''
-        ZabbixAPIError
-        Exists to propagate errors up from the api
-    '''
-    pass
-
-class ZabbixAPI(object):
-    '''
-        ZabbixAPI class
-    '''
-    classes = {
-        'Action': ['create', 'delete', 'get', 'update'],
-        'Alert': ['get'],
-        'Application': ['create', 'delete', 'get', 'massadd', 'update'],
-        'Configuration': ['export', 'import'],
-        'Dcheck': ['get'],
-        'Dhost': ['get'],
-        'Drule': ['copy', 'create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Dservice': ['get'],
-        'Event': ['acknowledge', 'get'],
-        'Graph': ['create', 'delete', 'get', 'update'],
-        'Graphitem': ['get'],
-        'Graphprototype': ['create', 'delete', 'get', 'update'],
-        'History': ['get'],
-        'Hostgroup': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'],
-        'Hostinterface': ['create', 'delete', 'get', 'massadd', 'massremove', 'replacehostinterfaces', 'update'],
-        'Host': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'],
-        'Hostprototype': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Httptest': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Iconmap': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Image': ['create', 'delete', 'get', 'update'],
-        'Item': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Itemprototype': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Maintenance': ['create', 'delete', 'get', 'update'],
-        'Map': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Mediatype': ['create', 'delete', 'get', 'update'],
-        'Proxy': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Screen': ['create', 'delete', 'get', 'update'],
-        'Screenitem': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update', 'updatebyposition'],
-        'Script': ['create', 'delete', 'execute', 'get', 'getscriptsbyhosts', 'update'],
-        'Service': ['adddependencies', 'addtimes', 'create', 'delete', 'deletedependencies', 'deletetimes', 'get', 'getsla', 'isreadable', 'iswritable', 'update'],
-        'Template': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'],
-        'Templatescreen': ['copy', 'create', 'delete', 'get', 'isreadable', 'iswritable', 'update'],
-        'Templatescreenitem': ['get'],
-        'Trigger': ['adddependencies', 'create', 'delete', 'deletedependencies', 'get', 'isreadable', 'iswritable', 'update'],
-        'Triggerprototype': ['create', 'delete', 'get', 'update'],
-        'User': ['addmedia', 'create', 'delete', 'deletemedia', 'get', 'isreadable', 'iswritable', 'login', 'logout', 'update', 'updatemedia', 'updateprofile'],
-        'Usergroup': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massupdate', 'update'],
-        'Usermacro': ['create', 'createglobal', 'delete', 'deleteglobal', 'get', 'update', 'updateglobal'],
-        'Usermedia': ['get'],
-    }
-
-    def __init__(self, data=None):
-        if not data:
-            data = {}
-        self.server = data.get('server', None)
-        self.username = data.get('user', None)
-        self.password = data.get('password', None)
-        if any([value == None for value in [self.server, self.username, self.password]]):
-            print 'Please specify zabbix server url, username, and password.'
-            sys.exit(1)
-
-        self.verbose = data.get('verbose', False)
-        self.use_ssl = data.has_key('use_ssl')
-        self.auth = None
-
-        for cname, _ in self.classes.items():
-            setattr(self, cname.lower(), getattr(self, cname)(self))
-
-        # pylint: disable=no-member
-        # This method does not exist until the metaprogramming executed
-        results = self.user.login(user=self.username, password=self.password)
-
-        if results[0]['status'] == '200':
-            if results[1].has_key('result'):
-                self.auth = results[1]['result']
-            elif results[1].has_key('error'):
-                print "Unable to authenticate with zabbix server. {0} ".format(results[1]['error'])
-                sys.exit(1)
-        else:
-            print "Error in call to zabbix. Http status: {0}.".format(results[0]['status'])
-            sys.exit(1)
-
-    def perform(self, method, rpc_params):
-        '''
-        This method calls your zabbix server.
-
-        It requires the following parameters in order for a proper request to be processed:
-            jsonrpc - the version of the JSON-RPC protocol used by the API;
-                      the Zabbix API implements JSON-RPC version 2.0;
-            method - the API method being called;
-            rpc_params - parameters that will be passed to the API method;
-            id - an arbitrary identifier of the request;
-            auth - a user authentication token; since we don't have one yet, it's set to null.
-        '''
-        http_method = "POST"
-        jsonrpc = "2.0"
-        rid = 1
-
-        http = None
-        if self.use_ssl:
-            http = httplib2.Http()
-        else:
-            http = httplib2.Http(disable_ssl_certificate_validation=True,)
-
-        headers = {}
-        headers["Content-type"] = "application/json"
-
-        body = {
-            "jsonrpc": jsonrpc,
-            "method":  method,
-            "params":  rpc_params.get('params', {}),
-            "id":      rid,
-            'auth':    self.auth,
-        }
-
-        if method in ['user.login', 'api.version']:
-            del body['auth']
-
-        body = json.dumps(body)
-
-        if self.verbose:
-            print body
-            print method
-            print headers
-            httplib2.debuglevel = 1
-
-        response, content = http.request(self.server, http_method, body, headers)
-
-        if response['status'] not in ['200', '201']:
-            raise ZabbixAPIError('Error calling zabbix.  Zabbix returned %s' % response['status'])
-
-        if self.verbose:
-            print response
-            print content
-
-        try:
-            content = json.loads(content)
-        except ValueError as err:
-            content = {"error": err.message}
-
-        return response, content
-
-    @staticmethod
-    def meta(cname, method_names):
-        '''
-        This bit of metaprogramming is where the ZabbixAPI subclasses are created.
-        For each of ZabbixAPI.classes we create a class from the key and methods
-        from the ZabbixAPI.classes values.  We pass a reference to ZabbixAPI class
-        to each subclass in order for each to be able to call the perform method.
-        '''
-        def meta_method(_class, method_name):
-            '''
-            This meta method allows a class to add methods to it.
-            '''
-            # This template method is a stub method for each of the subclass
-            # methods.
-            def template_method(self, params=None, **rpc_params):
-                '''
-                This template method is a stub method for each of the subclass methods.
-                '''
-                if params:
-                    rpc_params['params'] = params
-                else:
-                    rpc_params['params'] = copy.deepcopy(rpc_params)
-
-                return self.parent.perform(cname.lower()+"."+method_name, rpc_params)
-
-            template_method.__doc__ = \
-              "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s/%s" % \
-              (cname.lower(), method_name)
-            template_method.__name__ = method_name
-            # this is where the template method is placed inside of the subclass
-            # e.g. setattr(User, "create", stub_method)
-            setattr(_class, template_method.__name__, template_method)
-
-        # This class call instantiates a subclass. e.g. User
-        _class = type(cname,
-                      (object,),
-                      {'__doc__': \
-                      "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s" % cname.lower()})
-        def __init__(self, parent):
-            '''
-            This init method gets placed inside of the _class
-            to allow it to be instantiated.  A reference to the parent class(ZabbixAPI)
-            is passed in to allow each class access to the perform method.
-            '''
-            self.parent = parent
-
-        # This attaches the init to the subclass. e.g. Create
-        setattr(_class, __init__.__name__, __init__)
-        # For each of our ZabbixAPI.classes dict values
-        # Create a method and attach it to our subclass.
-        # e.g.  'User': ['delete', 'get', 'updatemedia', 'updateprofile',
-        #                'update', 'iswritable', 'logout', 'addmedia', 'create',
-        #                'login', 'deletemedia', 'isreadable'],
-        # User.delete
-        # User.get
-        for method_name in method_names:
-            meta_method(_class, method_name)
-        # Return our subclass with all methods attached
-        return _class
-
-# Attach all ZabbixAPI.classes to ZabbixAPI class through metaprogramming
-for _class_name, _method_names in ZabbixAPI.classes.items():
-    setattr(ZabbixAPI, _class_name, ZabbixAPI.meta(_class_name, _method_names))
-
-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 diff_content(from_zabbix, from_user, ignore=None):
-    ''' Compare passed in object to results returned from zabbix
-    '''
-    terms = ['search', 'output', 'groups', 'select', 'expand', 'filter']
-    if ignore:
-        terms.extend(ignore)
-    regex = '(' + '|'.join(terms) + ')'
-    retval = {}
-    for key, value in from_user.items():
-        if re.findall(regex, key):
-            continue
-
-        # special case here for templates.  You query templates and
-        # the zabbix api returns parentTemplates.  These will obviously fail.
-        # So when its templates compare against parentTemplates.
-        if key == 'templates' and from_zabbix.has_key('parentTemplates'):
-            if from_zabbix['parentTemplates'] != value:
-                retval[key] = value
-
-        elif from_zabbix[key] != str(value):
-            retval[key] = str(value)
-
-    return retval
-
-def main():
-    '''
-    This main method runs the ZabbixAPI Ansible Module
-    '''
-
-    module = AnsibleModule(
-        argument_spec=dict(
-            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'),
-            user=dict(default=None, type='str'),
-            password=dict(default=None, type='str'),
-            zbx_class=dict(choices=ZabbixAPI.classes.keys()),
-            params=dict(),
-            debug=dict(default=False, type='bool'),
-            state=dict(default='present', type='str'),
-            ignore=dict(default=None, type='list'),
-        ),
-        #supports_check_mode=True
-    )
-
-    user = module.params.get('user', None)
-    if not user:
-        user = os.environ['ZABBIX_USER']
-
-    passwd = module.params.get('password', None)
-    if not passwd:
-        passwd = os.environ['ZABBIX_PASSWORD']
-
-
-
-    api_data = {
-        'user': user,
-        'password': passwd,
-        'server': module.params['server'],
-        'verbose': module.params['debug']
-    }
-
-    if not user or not passwd or not module.params['server']:
-        module.fail_json(msg='Please specify the user, password, and the zabbix server.')
-
-    zapi = ZabbixAPI(api_data)
-
-    ignore = module.params['ignore']
-    zbx_class = module.params.get('zbx_class')
-    rpc_params = module.params.get('params', {})
-    state = module.params.get('state')
-
-
-    # Get the instance we are trying to call
-    zbx_class_inst = zapi.__getattribute__(zbx_class.lower())
-
-    # perform get
-    # Get the instance's method we are trying to call
-
-    zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['get']
-    _, content = zbx_action_method(zbx_class_inst, rpc_params)
-
-    if state == 'list':
-        module.exit_json(changed=False, results=content['result'], state="list")
-
-    if state == 'absent':
-        if not exists(content):
-            module.exit_json(changed=False, state="absent")
-        # If we are coming from a query, we need to pass in the correct rpc_params for delete.
-        # specifically the zabbix class name + 'id'
-        # if rpc_params is a list then we need to pass it. (list of ids to delete)
-        idname = zbx_class.lower() + "id"
-        if not isinstance(rpc_params, list) and content['result'][0].has_key(idname):
-            rpc_params = [content['result'][0][idname]]
-
-        zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['delete']
-        _, content = zbx_action_method(zbx_class_inst, rpc_params)
-        module.exit_json(changed=True, results=content['result'], state="absent")
-
-    if state == 'present':
-    # It's not there, create it!
-        if not exists(content):
-            zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['create']
-            _, content = zbx_action_method(zbx_class_inst, rpc_params)
-            module.exit_json(changed=True, results=content['result'], state='present')
-
-    # It's there and the same, do nothing!
-        diff_params = diff_content(content['result'][0], rpc_params, ignore)
-        if not diff_params:
-            module.exit_json(changed=False, results=content['result'], state="present")
-
-        # Add the id to update with
-        idname = zbx_class.lower() + "id"
-        diff_params[idname] = content['result'][0][idname]
-
-
-        ## It's there and not the same, update it!
-        zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['update']
-        _, content = zbx_action_method(zbx_class_inst, diff_params)
-        module.exit_json(changed=True, results=content, 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()
-
-- 
cgit v1.2.3